Implemented support for eltorito on MS discs

This commit is contained in:
Mario Danic 2007-09-01 20:35:53 +00:00
parent 0746d622e4
commit d60193e2d5
20 changed files with 842 additions and 299 deletions

5
TODO
View File

@ -10,9 +10,12 @@ FEATURES
[ok] Joliet [ok] Joliet
Merge RR and Joliet trees Merge RR and Joliet trees
[ok] User options to customize reading [ok] User options to customize reading
Read El-Torito info [ok] Read El-Torito info
[ok] Multisession [ok] Multisession
[ok] DVD+RW image growing [ok] DVD+RW image growing
El-Torito images from previous session
Add new el-torito image from prev. session file
Path for isolinux from prev. session
UDF UDF
[ok] ISO relaxed contraints [ok] ISO relaxed contraints
ISO 9660:1998 ISO 9660:1998

View File

@ -184,15 +184,9 @@ calc_dir_size(struct ecma119_write_target *t,
for (i = 0; i < dir->info.dir.nchildren; i++) { for (i = 0; i < dir->info.dir.nchildren; i++) {
struct ecma119_tree_node *ch = dir->info.dir.children[i]; struct ecma119_tree_node *ch = dir->info.dir.children[i];
//struct iso_tree_node *iso = ch->iso_self;
if (ch->type == ECMA119_DIR) { if (ch->type == ECMA119_DIR) {
calc_dir_size(t, ch); calc_dir_size(t, ch);
} }
// else if (iso && iso->attrib.st_size
// && iso->loc.type == LIBISO_FILESYS
// && iso->loc.path) {
// t->filelist_len++;
// }
} }
} }
@ -231,12 +225,11 @@ cmp_file(const void *f1, const void *f2)
* Fill out the block field for each file and fill out t->filelist. * Fill out the block field for each file and fill out t->filelist.
*/ */
static void static void
calc_file_pos(struct ecma119_write_target *t, calc_file_pos(struct ecma119_write_target *t)
struct ecma119_tree_node *dir)
{ {
size_t i; size_t i;
assert(dir->type == ECMA119_DIR); assert(t);
t->filelist = calloc(1, sizeof(struct iso_file *) * t->file_table->count); t->filelist = calloc(1, sizeof(struct iso_file *) * t->file_table->count);
@ -338,7 +331,17 @@ ecma119_target_new(struct iso_volset *volset,
t->catalog = volset->volume[opts->volnum]->bootcat; t->catalog = volset->volume[opts->volnum]->bootcat;
t->eltorito = t->catalog ? 1 : 0; t->eltorito = t->catalog ? 1 : 0;
t->write_eltorito = opts->copy_eltorito;
if (t->eltorito && (!t->ms_block || !t->catalog->proc) ) {
/*
* For new and modified images we always need to write el-torito.
* For ms images, if the boot catalog was newly added, we also need
* to write it!
*/
t->write_eltorito = 1;
}
/* create the trees */
t->root = ecma119_tree_create(t, iso_root); t->root = ecma119_tree_create(t, iso_root);
if (t->joliet) if (t->joliet)
t->joliet_root = joliet_tree_create(t, iso_root); t->joliet_root = joliet_tree_create(t, iso_root);
@ -377,8 +380,8 @@ ecma119_target_new(struct iso_volset *volset,
t->curblock = t->ms_block /* nwa for ms, usually 0 */ t->curblock = t->ms_block /* nwa for ms, usually 0 */
+ 16 /* system area */ + 16 /* system area */
+ 1 /* volume desc */ + 1 /* primary volume desc */
+ 1; /* volume desc terminator */ + 1; /* volume desc terminator */
if (t->eltorito) if (t->eltorito)
t->curblock += 1; /* boot record volume descriptor */ t->curblock += 1; /* boot record volume descriptor */
@ -411,17 +414,24 @@ ecma119_target_new(struct iso_volset *volset,
/* el-torito? */ /* el-torito? */
if (t->eltorito) { if (t->eltorito) {
if (t->write_eltorito) {
/* add catalog block */
t->catblock = t->curblock;
t->curblock += div_up(2048, t->block_size);
/* add catalog block */ /* add img block */
t->catalog->file->block = t->curblock; t->imgblock = t->curblock;
t->curblock += div_up(2048, t->block_size); t->curblock += div_up(t->catalog->image->node->node.attrib.st_size,
el_torito_get_image_files(t); t->block_size);
} else {
assert(t->ms_block);
assert(t->catalog->proc);
t->catblock = t->catalog->node->loc.block;
t->imgblock = t->catalog->image->node->loc.block;
}
} }
calc_file_pos(t, t->root); calc_file_pos(t);
if (t->eltorito)
el_torito_patch_image_files(t);
if (t->rockridge) { if (t->rockridge) {
susp_finalize(t, t->root); susp_finalize(t, t->root);
@ -438,9 +448,6 @@ ecma119_target_new(struct iso_volset *volset,
*/ */
uint8_t *buf; uint8_t *buf;
/* set the 32 block buffer to 0 */
memset(opts->overwrite, 0, 32 * t->block_size);
/* skip the first 16 blocks (system area) */ /* skip the first 16 blocks (system area) */
buf = opts->overwrite + 16 * t->block_size; buf = opts->overwrite + 16 * t->block_size;
@ -494,16 +501,15 @@ is_eltorito_state(enum ecma119_write_state state)
static void static void
next_state(struct ecma119_write_target *t) next_state(struct ecma119_write_target *t)
{ {
char msg[42];
t->state++; t->state++;
while ( (!t->joliet && is_joliet_state(t->state)) while ( (!t->joliet && is_joliet_state(t->state))
||(!t->eltorito && is_eltorito_state(t->state)) ) ||(!t->eltorito && is_eltorito_state(t->state))
||(!t->write_eltorito && t->state == ECMA119_WRITE_ELTORITO_CATALOG) )
t->state++; t->state++;
{
char msg[42];
sprintf(msg, "Now in state %d, curblock=%d.", t->state, t->curblock); sprintf(msg, "Now in state %d, curblock=%d.", t->state, t->curblock);
iso_msg_debug(msg); iso_msg_debug(msg);
}
} }
static void static void
@ -556,13 +562,14 @@ wr_files(struct ecma119_write_target *t, uint8_t *buf)
assert( !t->ms_block && t->src ); assert( !t->ms_block && t->src );
/** /**
* f->block block where file read begins * f->block block where file write begins
* t->curblock block we're writting now * t->curblock block we're writting now
* f->real_ino initial block for file on source * f->real_ino initial block for file on source
*/ */
block = t->curblock - f->block; block = t->curblock - f->block;
if ( t->src->read_block(t->src, f->real_ino + block, buf) ) { if ( t->src->read_block(t->src, f->real_ino + block, buf) ) {
warn("problem reading from previous image"); iso_msg_sorry(LIBISO_CANT_READ_IMG,
"Problem reading file from previous image");
} }
if ( f->size <= (off_t) (block+1) * t->block_size ) { if ( f->size <= (off_t) (block+1) * t->block_size ) {
f_st->file++; f_st->file++;
@ -581,6 +588,8 @@ wr_files(struct ecma119_write_target *t, uint8_t *buf)
f_st->data_len = f->size; f_st->data_len = f->size;
f_st->fd = fopen(path, "r"); f_st->fd = fopen(path, "r");
if (!f_st->fd) { if (!f_st->fd) {
//FIXME instead of exit, just print a msg error and
//skip file (what about reading from /dev/zero? instead)
err(1, "couldn't open %s for reading", path); err(1, "couldn't open %s for reading", path);
} }
assert(t->curblock + t->ms_block == f->block); assert(t->curblock + t->ms_block == f->block);
@ -588,10 +597,15 @@ wr_files(struct ecma119_write_target *t, uint8_t *buf)
nread = fread(buf, 1, t->block_size, f_st->fd); nread = fread(buf, 1, t->block_size, f_st->fd);
f_st->pos += t->block_size; f_st->pos += t->block_size;
if (nread < 0) if (nread < 0) {
warn("problem reading from %s", path); char msg[PATH_MAX + 32];
else if (nread != t->block_size && f_st->pos < f_st->data_len) sprintf(msg, "Problem reading from %s", path);
warnx("incomplete read from %s", path); iso_msg_sorry(LIBISO_CANT_READ_FILE, msg);
} else if (nread != t->block_size && f_st->pos < f_st->data_len) {
char msg[PATH_MAX + 32];
sprintf(msg, "Incomplete read from %s", path);
iso_msg_sorry(LIBISO_CANT_READ_FILE, msg);
}
if (f_st->pos >= f_st->data_len) { if (f_st->pos >= f_st->data_len) {
fclose(f_st->fd); fclose(f_st->fd);
f_st->fd = 0; f_st->fd = 0;
@ -743,6 +757,16 @@ write_one_dir_record(struct ecma119_write_target *t,
} else if (node->type == ECMA119_FILE) { } else if (node->type == ECMA119_FILE) {
len = node->info.file->size; len = node->info.file->size;
block = node->info.file->block; block = node->info.file->block;
} else if (node->type == ECMA119_BOOT) {
assert(t->eltorito);
if (node->info.boot_img) {
block = t->imgblock;
len = t->catalog->image->node->node.attrib.st_size;
} else {
/* we always assume 2048 as catalog len */
block = t->catblock;
len = 2048;
}
} else { } else {
/* for nodes other than files and dirs, we set both len and block to 0 */ /* for nodes other than files and dirs, we set both len and block to 0 */
len = 0; len = 0;
@ -872,11 +896,10 @@ static int
bs_read(struct burn_source *bs, unsigned char *buf, int size) bs_read(struct burn_source *bs, unsigned char *buf, int size)
{ {
struct ecma119_write_target *t = (struct ecma119_write_target*)bs->data; struct ecma119_write_target *t = (struct ecma119_write_target*)bs->data;
if (size != t->block_size) {
warnx("you must read data in block-sized chunks (%d bytes)", assert(size == t->block_size);
(int)t->block_size);
return 0; if (t->curblock >= t->vol_space_size) {
} else if (t->curblock >= t->vol_space_size + t->ms_block) {
return 0; return 0;
} }
if (t->state_data_valid) if (t->state_data_valid)

View File

@ -65,9 +65,22 @@ struct ecma119_write_target
unsigned int iso_level:2; unsigned int iso_level:2;
unsigned int eltorito:1; unsigned int eltorito:1;
int relaxed_constraints; /**< see ecma119_relaxed_constraints_flag */ unsigned int write_eltorito:1;
/**<
* In multisession discs, select whether to copy el-torito catalog
* and boot image. Copy is needed for isolinux images, that need to
* be patched. However, it can lead to problems when the image is
* not present in the iso filesystem, because we can't figure out
* its size. In those cases, we only copy 1 block of data.
* When modifying images, we always need to copy data. Thus, this is
* always 1 for both new and modified images.
*/
struct el_torito_boot_catalog *catalog; struct el_torito_boot_catalog *catalog;
uint32_t catblock; /**< location of the boot catalog in the new image */
uint32_t imgblock; /**< location of the boot image in the new image */
int relaxed_constraints; /**< see ecma119_relaxed_constraints_flag */
int replace_mode; /**< Replace ownership and modes of files int replace_mode; /**< Replace ownership and modes of files
* *

View File

@ -28,6 +28,7 @@
#include "volume.h" #include "volume.h"
#include "tree.h" #include "tree.h"
#include "messages.h" #include "messages.h"
#include "eltorito.h"
#define BLOCK_SIZE 2048 #define BLOCK_SIZE 2048
@ -35,6 +36,121 @@ static int
iso_read_dir(struct iso_read_info *info, struct iso_tree_node_dir *parent, iso_read_dir(struct iso_read_info *info, struct iso_tree_node_dir *parent,
uint32_t block); uint32_t block);
static struct el_torito_boot_catalog *
read_el_torito_boot_catalog(struct iso_read_info *info, uint32_t block)
{
struct el_torito_validation_entry *ve;
struct el_torito_default_entry *entry;
struct el_torito_boot_catalog *catalog;
struct el_torito_boot_image *image;
unsigned char buffer[BLOCK_SIZE];
if ( info->src->read_block(info->src, block, buffer) < 0 ) {
info->error = LIBISOFS_READ_FAILURE;
return NULL;
}
ve = (struct el_torito_validation_entry*)buffer;
/* check if it is a valid catalog (TODO: check also the checksum)*/
if ( (ve->header_id[0] != 1) || (ve->key_byte1[0] != 0x55)
|| (ve->key_byte2[0] != 0xAA) ) {
iso_msg_sorry(LIBISO_EL_TORITO_WRONG, "Wrong or damaged El-Torito "
"Catalog.\n El-Torito info will be ignored.");
return NULL;
}
/* check for a valid platform */
if (ve->platform_id[0] != 0) {
iso_msg_hint(LIBISO_EL_TORITO_UNHANLED, "Unsupported El-Torito platform.\n"
"Only 80x86 si supported. El-Torito info will be ignored.");
}
/* ok, once we are here we assume it is a valid catalog */
catalog = malloc(sizeof(struct el_torito_boot_catalog));
image = calloc(1, sizeof(struct el_torito_boot_image));
catalog->image = image;
catalog->proc = LIBISO_PREVIMG;
{
/*
* Create the placeholder.
* Note that this could be modified later if we find a directory entry
* for the catalog in the iso tree.
*/
struct iso_tree_node_boot *boot;
boot = calloc(1, sizeof(struct iso_tree_node_boot));
boot->node.refcount = 1;
boot->node.attrib.st_mode = S_IFREG | 0777;
boot->node.attrib.st_atime = boot->node.attrib.st_mtime
= boot->node.attrib.st_ctime = time(NULL);
boot->node.attrib.st_size = 2048;
boot->node.type = LIBISO_NODE_BOOT;
boot->node.procedence = LIBISO_PREVIMG;
boot->node.name = NULL;
boot->loc.block = block;
catalog->node = boot;
}
/* parse the default entry */
entry = (struct el_torito_default_entry *)(buffer + 32);
image->bootable = entry->boot_indicator[0] ? 1 : 0;
//FIXME we need a way to handle patch_isolinux in ms images!!!
image->isolinux = 0;
image->type = entry->boot_media_type[0];
image->partition_type = entry->system_type[0];
image->load_seg = iso_read_lsb(entry->load_seg, 2);
image->load_size = iso_read_lsb(entry->sec_count, 2);
{
/*
* Create the placeholder.
* Note that this could be modified later if we find a directory entry
* for the image in the iso tree.
*/
struct iso_tree_node_boot *boot;
boot = calloc(1, sizeof(struct iso_tree_node_boot));
boot->node.refcount = 1;
boot->node.attrib.st_mode = S_IFREG | 0777;
boot->node.attrib.st_atime = boot->node.attrib.st_mtime
= boot->node.attrib.st_ctime = time(NULL);
boot->node.attrib.st_size = 2048;
boot->node.type = LIBISO_NODE_BOOT;
boot->node.procedence = LIBISO_PREVIMG;
boot->node.name = NULL;
boot->img = 1;
boot->loc.block = iso_read_lsb(entry->block, 4);
image->node = boot;
}
//TODO how can we check if there are more entries?
return catalog;
}
static struct el_torito_boot_catalog *
read_el_torito_vol_desc(struct iso_read_info *info, unsigned char *buf)
{
struct ecma119_boot_rec_vol_desc *vol;
vol = (struct ecma119_boot_rec_vol_desc*)buf;
/* some sanity checks */
if ( strncmp((char*)vol->std_identifier, "CD001", 5)
|| vol->vol_desc_version[0] != 1
|| strncmp((char*)vol->boot_sys_id, "EL TORITO SPECIFICATION", 23)) {
iso_msg_hint(LIBISO_BOOT_VD_UNHANLED, "Unsupported Boot Vol. Desc.\n"
"Only El-Torito Specification, Version 1.0 Volume "
"Descriptors are supported. Ignoring boot info");
return NULL;
}
return read_el_torito_boot_catalog(info, iso_read_lsb(vol->boot_catalog, 4));
}
/** /**
* This reads the "." directory entry, and set the properties of the * This reads the "." directory entry, and set the properties of the
* given directory propertly. * given directory propertly.
@ -248,12 +364,22 @@ iso_read_single_directory_record(struct iso_read_info *info,
break; break;
case S_IFREG: case S_IFREG:
{ {
node = calloc(1, sizeof(struct iso_tree_node_file)); uint32_t block;
node->type = LIBISO_NODE_FILE; block = iso_read_bb(record->block, 4, NULL);
/* set block with extend */ if (info->bootcat && block == info->bootcat->node->loc.block) {
((struct iso_tree_node_file*)node)->loc.block = /* it is the boot catalog */
iso_read_bb(record->block, 4, NULL); node = (struct iso_tree_node*)info->bootcat->node;
} else if (info->bootcat && block == info->bootcat->image->node->loc.block) {
/* it is the boot image */
node = (struct iso_tree_node*)info->bootcat->image->node;
} else {
/* it is a file */
node = calloc(1, sizeof(struct iso_tree_node_file));
node->type = LIBISO_NODE_FILE;
/* set block with extend */
((struct iso_tree_node_file*)node)->loc.block = block;
}
} }
break; break;
case S_IFLNK: case S_IFLNK:
@ -272,7 +398,7 @@ iso_read_single_directory_record(struct iso_read_info *info,
node->name = name; node->name = name;
node->attrib = atts; node->attrib = atts;
node->refcount = 1; node->refcount++; /* 1 for news, 2 for boot nodes */
node->procedence = LIBISO_PREVIMG; node->procedence = LIBISO_PREVIMG;
iso_tree_add_child(parent, node); iso_tree_add_child(parent, node);
@ -520,7 +646,6 @@ read_root_susp_entries(struct iso_read_info *info,
return 0; return 0;
} }
static struct iso_volset * static struct iso_volset *
read_pvm(struct iso_read_info *info, uint32_t block) read_pvm(struct iso_read_info *info, uint32_t block)
{ {
@ -628,6 +753,7 @@ iso_volset_read(struct data_source *src, struct ecma119_read_opts *opts)
info.gid = opts->gid; info.gid = opts->gid;
info.mode = opts->mode & ~S_IFMT; info.mode = opts->mode & ~S_IFMT;
info.size = &opts->size; info.size = &opts->size;
info.bootcat = NULL;
root_dir_block = 0; root_dir_block = 0;
/* read primary volume description */ /* read primary volume description */
@ -642,13 +768,16 @@ iso_volset_read(struct data_source *src, struct ecma119_read_opts *opts)
do { do {
if ( info.src->read_block(info.src, block, buffer) < 0 ) { if ( info.src->read_block(info.src, block, buffer) < 0 ) {
info.error = LIBISOFS_READ_FAILURE; info.error = LIBISOFS_READ_FAILURE;
iso_volset_free(volset); /* cleanup and exit */
return NULL; goto read_cleanup;
} }
switch (buffer[0]) { switch (buffer[0]) {
case 0: case 0:
/* boot record */ /*
//TODO handle el-torito * This is a boot record
* Here we handle el-torito
*/
info.bootcat = read_el_torito_vol_desc(&info, buffer);
break; break;
case 2: case 2:
/* suplementary volume descritor */ /* suplementary volume descritor */
@ -735,11 +864,25 @@ iso_volset_read(struct data_source *src, struct ecma119_read_opts *opts)
if ( iso_read_dir(&info, volset->volume[0]->root, root_dir_block) ) { if ( iso_read_dir(&info, volset->volume[0]->root, root_dir_block) ) {
/* error, cleanup and return */ /* error, cleanup and return */
iso_volset_free(volset); goto read_cleanup;
return NULL;
} }
// TODO merge tree info // TODO merge tree info
/* Add El-Torito info to the volume */
if (info.bootcat) {
/* ok, add the bootcat to the volume */
iso_msg_debug("Found El-Torito bootable volume");
volset->volume[0]->bootcat = info.bootcat;
}
return volset; return volset;
read_cleanup:;
if (info.bootcat) {
el_torito_boot_catalog_free(info.bootcat);
}
iso_volset_free(volset);
return NULL;
} }

View File

@ -66,6 +66,9 @@ struct iso_read_info {
unsigned int hasJoliet:1; /*< It will be set to 1 if Joliet ext are present, unsigned int hasJoliet:1; /*< It will be set to 1 if Joliet ext are present,
to 0 if not. */ to 0 if not. */
uint32_t *size; uint32_t *size;
/* place for el-torito boot catalog */
struct el_torito_boot_catalog *bootcat;
}; };

View File

@ -259,37 +259,29 @@ create_symlink(struct ecma119_write_target *t,
} }
/** /**
* Create a new ECMA-119 node representing a boot catalog. This is like a * Create a new ECMA-119 node representing a boot catalog or image.
* regular file, but its contents are taken from a El-Torito boot catalog, * This will be treated as a normal file when written the directory record,
* and not from a file in the local filesystem. * but its contents are written in a different way.
* *
* See "El Torito" Bootable CD-ROM Format Specification Version 1.0 for * See "El Torito" Bootable CD-ROM Format Specification Version 1.0 for
* more details. * more details.
*/ */
static struct ecma119_tree_node* static struct ecma119_tree_node*
create_boot_catalog(struct ecma119_write_target *t, create_boot(struct ecma119_write_target *t,
struct ecma119_tree_node *parent, struct ecma119_tree_node *parent,
struct iso_tree_node_boot_catalog *iso) struct iso_tree_node_boot *iso)
{ {
struct ecma119_tree_node *ret; struct ecma119_tree_node *ret;
struct iso_file *file;
assert(t && iso && parent && parent->type == ECMA119_DIR); assert(t && iso && parent && parent->type == ECMA119_DIR);
/*
* This will simply create a ECMA119 file, with the only difference
* that the iso_file is not taken from table, but from boot catalog
*/
ret = create_ecma119_node(t, parent, (struct iso_tree_node*) iso); ret = create_ecma119_node(t, parent, (struct iso_tree_node*) iso);
ret->type = ECMA119_FILE; ret->type = ECMA119_BOOT;
file = iso->catalog->file; ret->info.boot_img = iso->img;
file->ino = ++t->ino;
ret->attrib.st_nlink = file->nlink; ret->attrib.st_nlink = 1;
ret->attrib.st_ino = file->ino; ret->attrib.st_ino = ++t->ino;
ret->info.file = file;
return ret; return ret;
} }
@ -334,9 +326,8 @@ create_tree(struct ecma119_write_target *t,
} }
} }
break; break;
case LIBISO_NODE_BOOTCATALOG: case LIBISO_NODE_BOOT:
ret = create_boot_catalog(t, parent, ret = create_boot(t, parent, (struct iso_tree_node_boot*)iso);
(struct iso_tree_node_boot_catalog*)iso);
break; break;
default: default:
/* should never happen */ /* should never happen */

View File

@ -21,7 +21,8 @@ enum ecma119_node_type {
ECMA119_FILE, ECMA119_FILE,
ECMA119_SYMLINK, ECMA119_SYMLINK,
ECMA119_DIR, ECMA119_DIR,
ECMA119_PLACEHOLDER /**< placeholder for a relocated dir. */ ECMA119_PLACEHOLDER, /**< placeholder for a relocated dir. */
ECMA119_BOOT
}; };
struct ecma119_dir_info { struct ecma119_dir_info {
@ -72,6 +73,10 @@ struct ecma119_tree_node
struct ecma119_tree_node *real_me; /**< this field points to struct ecma119_tree_node *real_me; /**< this field points to
* the relocated directory. * the relocated directory.
*/ */
unsigned int boot_img:1; /** For boot nodes, it identifies if this
* corresponds to image(1) or catalog(0).
* The block is stored in ecma119_write_target
*/
} info; } info;
}; };

View File

@ -3,6 +3,7 @@
#include "eltorito.h" #include "eltorito.h"
#include "volume.h" #include "volume.h"
#include "util.h" #include "util.h"
#include "messages.h"
#include <assert.h> #include <assert.h>
#include <malloc.h> #include <malloc.h>
@ -15,46 +16,6 @@
#include <fcntl.h> #include <fcntl.h>
struct el_torito_validation_entry {
uint8_t header_id BP(1, 1);
uint8_t platform_id BP(2, 2);
uint8_t reserved BP(3, 4);
uint8_t id_string BP(5, 28);
uint8_t checksum BP(29, 30);
uint8_t key_byte1 BP(31, 31);
uint8_t key_byte2 BP(32, 32);
};
struct el_torito_default_entry {
uint8_t boot_indicator BP(1, 1);
uint8_t boot_media_type BP(2, 2);
uint8_t load_seg BP(3, 4);
uint8_t system_type BP(5, 5);
uint8_t unused1 BP(6, 6);
uint8_t sec_count BP(7, 8);
uint8_t block BP(9, 12);
uint8_t unused2 BP(13, 32);
};
struct el_torito_section_header_entry {
uint8_t header_indicator BP(1, 1);
uint8_t platform_id BP(2, 2);
uint8_t number BP(3, 4);
uint8_t character BP(5, 32);
};
struct el_torito_section_entry {
uint8_t boot_indicator BP(1, 1);
uint8_t boot_media_type BP(2, 2);
uint8_t load_seg BP(3, 4);
uint8_t system_type BP(5, 5);
uint8_t unused1 BP(6, 6);
uint8_t sec_count BP(7, 8);
uint8_t block BP(9, 12);
uint8_t selec_criteria BP(13, 13);
uint8_t vendor_sc BP(14, 32);
};
/** /**
* This table should be written with accuracy values at offset * This table should be written with accuracy values at offset
* 8 of boot image, when used ISOLINUX boot loader * 8 of boot image, when used ISOLINUX boot loader
@ -85,18 +46,67 @@ struct hard_disc_mbr {
uint8_t sign2; uint8_t sign2;
}; };
static void
el_torito_image_free(struct el_torito_boot_image *image)
{
assert(image);
/* unref image node */
iso_tree_free((struct iso_tree_node*)image->node);
free(image);
}
static struct iso_tree_node_boot*
create_boot_image_node(struct iso_tree_node_file *image)
{
struct iso_tree_node_boot *boot;
struct iso_tree_node_dir *parent;
assert(image);
boot = calloc(1, sizeof(struct iso_tree_node_boot));
boot->node.attrib = image->node.attrib;
boot->node.type = LIBISO_NODE_BOOT;
boot->node.name = strdup(image->node.name);
boot->node.hide_flags = image->node.hide_flags;
boot->node.refcount = 2; /* mine and tree */
boot->loc.path = strdup(image->loc.path);
boot->img = 1; /* it refers to image */
/* replace iso_tree_node_file with the image */
parent = image->node.parent;
iso_tree_node_remove(parent, (struct iso_tree_node*)image);
iso_tree_add_child(parent, (struct iso_tree_node*) boot);
return boot;
}
static struct el_torito_boot_image * static struct el_torito_boot_image *
create_image(struct iso_tree_node *image, create_image(const char *path,
enum eltorito_boot_media_type type) enum eltorito_boot_media_type type)
{ {
struct stat attrib;
struct el_torito_boot_image *boot; struct el_torito_boot_image *boot;
int boot_media_type = 0; int boot_media_type = 0;
int load_sectors = 0; /* number of sector to load */ int load_sectors = 0; /* number of sector to load */
unsigned char partition_type = 0; unsigned char partition_type = 0;
if (stat(path, &attrib)) {
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG, "Can't access file.");
libisofs_errno = NO_FILE;
return NULL;
}
if ( !S_ISREG(attrib.st_mode) ) {
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG,
"We can only create boot images from regular files");
libisofs_errno = ELTORITO_WRONG_IMAGE;
return NULL;
}
switch (type) { switch (type) {
case ELTORITO_FLOPPY_EMUL: case ELTORITO_FLOPPY_EMUL:
switch (image->attrib.st_size) { switch (attrib.st_size) {
case 1200 * 1024: case 1200 * 1024:
boot_media_type = 1; /* 1.2 meg diskette */ boot_media_type = 1; /* 1.2 meg diskette */
break; break;
@ -107,10 +117,14 @@ create_image(struct iso_tree_node *image,
boot_media_type = 3; /* 2.88 meg diskette */ boot_media_type = 3; /* 2.88 meg diskette */
break; break;
default: default:
fprintf(stderr, "Invalid image size %d Kb. Must be one of 1.2, 1.44" {
"or 2.88 Mb", (int) image->attrib.st_size / 1024); char msg[72];
sprintf(msg, "Invalid image size %d Kb. Must be one of 1.2, 1.44"
"or 2.88 Mb", (int) attrib.st_size / 1024);
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG, msg);
libisofs_errno = ELTORITO_WRONG_IMAGE_SIZE; libisofs_errno = ELTORITO_WRONG_IMAGE_SIZE;
return NULL; return NULL;
}
break; break;
} }
/* it seems that for floppy emulation we need to load /* it seems that for floppy emulation we need to load
@ -125,13 +139,16 @@ create_image(struct iso_tree_node *image,
int used_partition; int used_partition;
/* read the MBR on disc and get the type of the partition */ /* read the MBR on disc and get the type of the partition */
fd = open(((struct iso_tree_node_file*)image)->loc.path, O_RDONLY); fd = open(path, O_RDONLY);
if ( fd == -1 ) { if ( fd == -1 ) {
fprintf(stderr, "Can't open image file\n"); iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG, "Can't open image file.");
libisofs_errno = NO_READ_ACCESS;
return NULL; return NULL;
} }
if ( read(fd, &mbr, sizeof(mbr)) ) { if ( read(fd, &mbr, sizeof(mbr)) ) {
fprintf(stderr, "Can't read MBR from image file\n"); iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG,
"Can't read MBR from image file.");
libisofs_errno = ELTORITO_WRONG_IMAGE;
close(fd); close(fd);
return NULL; return NULL;
} }
@ -139,7 +156,9 @@ create_image(struct iso_tree_node *image,
/* check valid MBR signature */ /* check valid MBR signature */
if ( mbr.sign1 != 0x55 || mbr.sign2 != 0xAA ) { if ( mbr.sign1 != 0x55 || mbr.sign2 != 0xAA ) {
fprintf(stderr, "Invalid MBR. Wrong signature.\n"); iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG,
"Invalid MBR. Wrong signature.");
libisofs_errno = ELTORITO_WRONG_IMAGE;
return NULL; return NULL;
} }
@ -149,8 +168,11 @@ create_image(struct iso_tree_node *image,
if (mbr.partition[i].type != 0) { if (mbr.partition[i].type != 0) {
/* it's an used partition */ /* it's an used partition */
if (used_partition != -1) { if (used_partition != -1) {
fprintf(stderr, "Invalid MBR. At least 2 partitions: %d and " char msg[72];
sprintf(msg, "Invalid MBR. At least 2 partitions: %d and "
"%d, are being used\n", used_partition, i); "%d, are being used\n", used_partition, i);
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG, msg);
libisofs_errno = ELTORITO_WRONG_IMAGE;
return NULL; return NULL;
} else } else
used_partition = i; used_partition = i;
@ -170,67 +192,180 @@ create_image(struct iso_tree_node *image,
boot = calloc(1, sizeof(struct el_torito_boot_image)); boot = calloc(1, sizeof(struct el_torito_boot_image));
boot->bootable = 1; boot->bootable = 1;
boot->image = (struct iso_tree_node_file *) image;
boot->type = boot_media_type; boot->type = boot_media_type;
boot->load_size = load_sectors; boot->load_size = load_sectors;
boot->partition_type = partition_type; boot->partition_type = partition_type;
return boot; return boot;
} }
static struct iso_tree_node_boot_catalog* /* parent and name can be null */
static struct iso_tree_node_boot*
create_boot_catalog_node(struct iso_tree_node_dir *parent, create_boot_catalog_node(struct iso_tree_node_dir *parent,
const char *name) const char *name)
{ {
struct iso_tree_node_boot_catalog *boot; struct iso_tree_node_boot *boot;
assert( parent && name ); assert( (parent && name) || (!parent && !name) );
boot = calloc(1, sizeof(struct iso_tree_node_boot_catalog)); boot = calloc(1, sizeof(struct iso_tree_node_boot));
boot->node.attrib.st_mode = S_IFREG | 0444; boot->node.attrib.st_mode = S_IFREG | 0444;
boot->node.attrib.st_atime = boot->node.attrib.st_atime =
boot->node.attrib.st_mtime = boot->node.attrib.st_mtime =
boot->node.attrib.st_ctime = time(NULL); boot->node.attrib.st_ctime = time(NULL);
boot->node.type = LIBISO_NODE_BOOTCATALOG; boot->node.attrib.st_size = 2048;
boot->node.name = strdup(name); boot->node.type = LIBISO_NODE_BOOT;
iso_tree_add_child(parent, (struct iso_tree_node*) boot); boot->node.name = name ? strdup(name) : NULL;
boot->node.refcount = 1; /* mine */
if (parent) {
boot->node.refcount++; /* add tree ref */
iso_tree_add_child(parent, (struct iso_tree_node*) boot);
}
return boot; return boot;
} }
struct el_torito_boot_image * struct el_torito_boot_image*
iso_volume_create_boot_catalog(struct iso_volume *volume, iso_volume_set_boot_image(struct iso_volume *volume,
struct iso_tree_node *image, struct iso_tree_node *image,
enum eltorito_boot_media_type type, enum eltorito_boot_media_type type,
struct iso_tree_node_dir *dir, struct iso_tree_node_dir *dir,
char *name) char *name)
{ {
struct el_torito_boot_image *boot_image; struct el_torito_boot_image *boot_image;
struct iso_tree_node_boot_catalog *boot_node; struct iso_tree_node_boot *cat_node;
struct el_torito_boot_catalog *catalog; struct el_torito_boot_catalog *catalog;
struct iso_tree_node_file *imgfile;
assert( volume && !volume->bootcat); assert(volume && !volume->bootcat);
assert( image && ISO_ISREG(image) && dir && name); assert(image && ISO_ISREG(image));
assert(dir && name);
boot_image = create_image(image, type); imgfile = (struct iso_tree_node_file*)image;
if (image->procedence == LIBISO_PREVIMG) {
/* FIXME mmm, what to do here? */
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG, "Can't use prev. image files "
"as boot images");
return NULL;
}
boot_image = create_image(imgfile->loc.path, type);
if ( !boot_image ) if ( !boot_image )
return NULL; return NULL;
/* create image node */
boot_image->node = create_boot_image_node(imgfile);
/* creates the catalog with the given default image */ /* creates the catalog with the given default image */
catalog = malloc(sizeof(struct el_torito_boot_catalog)); catalog = malloc(sizeof(struct el_torito_boot_catalog));
catalog->nentries = 1; if (!catalog) {
catalog->entries = malloc(sizeof(struct el_torito_boot_image *)); el_torito_image_free(boot_image);
catalog->entries[0] = boot_image; return NULL;
catalog->file = malloc(sizeof(struct iso_file)); }
catalog->file->size = 2048; catalog->image = boot_image;
/* add catalog file */ /* add catalog file */
boot_node = create_boot_catalog_node(dir, name); cat_node = create_boot_catalog_node(dir, name);
boot_node->catalog = catalog; catalog->node = cat_node;
volume->bootcat = catalog; volume->bootcat = catalog;
return boot_image; return boot_image;
} }
struct el_torito_boot_image*
iso_volume_set_boot_image_hidden(struct iso_volume *volume, const char* path,
enum eltorito_boot_media_type type)
{
struct el_torito_boot_image *boot_image;
struct iso_tree_node_boot *cat_node;
struct el_torito_boot_catalog *catalog;
assert(volume && !volume->bootcat);
assert(path);
boot_image = create_image(path, type);
if ( !boot_image )
return NULL;
/* create image node */
{
struct iso_tree_node_boot *boot;
boot = calloc(1, sizeof(struct iso_tree_node_boot));
/* we assume the stat won't fail, as we already stat the same file above */
stat(path, &boot->node.attrib);
boot->node.type = LIBISO_NODE_BOOT;
boot->node.refcount = 1; /* mine */
boot->loc.path = strdup(path);
boot->img = 1; /* it refers to image */
boot_image->node = boot;
}
/* creates the catalog with the given default image */
catalog = malloc(sizeof(struct el_torito_boot_catalog));
if (!catalog) {
el_torito_image_free(boot_image);
return NULL;
}
catalog->image = boot_image;
/* add catalog file */
cat_node = create_boot_catalog_node(NULL, NULL);
catalog->node = cat_node;
volume->bootcat = catalog;
return boot_image;
}
struct el_torito_boot_image*
iso_volume_get_boot_image(struct iso_volume *volume,
struct iso_tree_node **imgnode,
struct iso_tree_node **catnode)
{
struct el_torito_boot_catalog *catalog;
assert(volume);
catalog = volume->bootcat;
if (!catalog)
return NULL;
if (imgnode)
*imgnode = (struct iso_tree_node*)catalog->image->node;
if (catnode)
*catnode = (struct iso_tree_node*)catalog->node;
return catalog->image;
}
void
iso_volume_remove_boot_image(struct iso_volume *volume)
{
struct el_torito_boot_catalog *catalog;
struct iso_tree_node *catnode;
struct iso_tree_node *imgnode;
assert(volume);
catalog = volume->bootcat;
if (!catalog)
return;
/* remove node from tree */
catnode = (struct iso_tree_node*)catalog->node;
if (catnode->parent)
iso_tree_node_remove(catnode->parent, catnode);
/* remove image from tree */
imgnode = (struct iso_tree_node*)catalog->image->node;
if (imgnode->parent)
iso_tree_node_remove(imgnode->parent, imgnode);
/* remove catalog */
el_torito_boot_catalog_free(catalog);
volume->bootcat = NULL;
}
void void
el_torito_set_load_seg(struct el_torito_boot_image *bootimg, int segment) el_torito_set_load_seg(struct el_torito_boot_image *bootimg, int segment)
{ {
@ -254,43 +389,20 @@ el_torito_set_no_bootable(struct el_torito_boot_image *bootimg)
} }
void void
el_torito_set_write_boot_info(struct el_torito_boot_image *bootimg) el_torito_patch_isolinux_image(struct el_torito_boot_image *bootimg)
{ {
bootimg->patch_isolinux = 1; bootimg->isolinux = 1;
} }
void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat) void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat)
{ {
size_t i;
assert(cat); assert(cat);
for(i = 0; i < cat->nentries; ++i) { el_torito_image_free(cat->image);
free(cat->entries[i]); iso_tree_free((struct iso_tree_node*)cat->node);
}
free(cat->entries);
free(cat->file);
free(cat); free(cat);
} }
void el_torito_get_image_files(struct ecma119_write_target *t)
{
size_t i;
struct el_torito_boot_catalog *cat = t->catalog;
assert(cat);
for(i = 0; i < cat->nentries; ++i) {
struct iso_tree_node_file *image = cat->entries[i]->image;
struct iso_file *file = iso_file_table_lookup(t->file_table, image);
if ( file == NULL ) {
file = iso_file_new(image);
iso_file_table_add_file(t->file_table, file);
}
cat->entries[i]->file = file;
}
}
/** /**
* Write the Boot Record Volume Descriptor * Write the Boot Record Volume Descriptor
*/ */
@ -307,7 +419,7 @@ el_torito_write_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
memcpy(vol->std_identifier, "CD001", 5); memcpy(vol->std_identifier, "CD001", 5);
vol->vol_desc_version[0] = 1; vol->vol_desc_version[0] = 1;
memcpy(vol->boot_sys_id, "EL TORITO SPECIFICATION", 23); memcpy(vol->boot_sys_id, "EL TORITO SPECIFICATION", 23);
iso_lsb(vol->boot_catalog, cat->file->block, 4); iso_lsb(vol->boot_catalog, t->catblock, 4);
} }
static void static void
@ -333,104 +445,139 @@ write_validation_entry(struct ecma119_write_target *t, uint8_t *buf)
} }
static void static void
patch_boot_file(struct el_torito_boot_image *img) patch_boot_image(uint8_t *buf, struct ecma119_write_target *t, ssize_t imgsize)
{ {
struct boot_info_table info; struct boot_info_table *info;
int fd;
uint32_t checksum; uint32_t checksum;
ssize_t len; ssize_t offset;
uint8_t buf[4];
memset(&info, 0, sizeof(info)); memset(&info, 0, sizeof(info));
/* open image */
fd = open(img->image->loc.path, O_RDWR);
if ( fd == -1 ) {
//TODO what do do? exit or just continue?
fprintf(stderr, "Can't patch boot image %s\n", img->image->loc.path);
close(fd);
return;
}
/* compute checksum, as the the sum of all 32 bit words in boot image /* compute checksum, as the the sum of all 32 bit words in boot image
* from offset 64 */ * from offset 64 */
checksum = 0; checksum = 0;
lseek(fd, (off_t) 64, SEEK_SET); offset = (ssize_t) 64;
//TODO this can (must) be optimizied by reading to a longer buffer while (offset < imgsize) {
while ( (len = read(fd, buf, 4) ) == 4 ) { checksum += iso_read_lsb(buf + offset, 4);
checksum += iso_read_lsb(buf, 4); offset += 4;
} }
if ( len != 0 ) { if (offset != imgsize) {
/* error reading file, or file length not multiple of 4 */ /* file length not multiple of 4 */
//TODO what do do? exit or just continue? iso_msg_warn(LIBISO_ISOLINUX_CANT_PATCH,
fprintf(stderr, "Can't patch boot image %s\n", img->image->loc.path); "Unexpected isolinux image length. Patch might not work.");
close(fd);
return;
} }
/* fill boot info table */ /* patch boot info table */
iso_lsb(info.bi_pvd, 16, 4); //FIXME this should be changed when we implement ms info = (struct boot_info_table*)(buf + 8);
iso_lsb(info.bi_file, img->file->block, 4); memset(info, 0, sizeof(struct boot_info_table));
iso_lsb(info.bi_length, img->image->node.attrib.st_size, 4); iso_lsb(info->bi_pvd, t->ms_block + 16, 4);
iso_lsb(info.bi_csum, checksum, 4); iso_lsb(info->bi_file, t->imgblock, 4);
iso_lsb(info->bi_length, imgsize, 4);
/* patch file */ iso_lsb(info->bi_csum, checksum, 4);
lseek(fd, (off_t) 8, SEEK_SET);
write(fd, &info, sizeof(info));
close(fd);
} }
void static void
el_torito_patch_image_files(struct ecma119_write_target *t) write_boot_image(uint8_t *buf, struct ecma119_write_target *t)
{ {
size_t i; ssize_t imgsize;
struct el_torito_boot_catalog *cat = t->catalog; struct el_torito_boot_image *image;
assert(cat);
for (i = 0; i < cat->nentries; ++i) { image = t->catalog->image;
struct el_torito_boot_image *img = cat->entries[i]; imgsize= image->node->node.attrib.st_size;
if ( img->patch_isolinux )
patch_boot_file(img); /* copy image contents to memory buffer */
if (image->node->node.procedence == LIBISO_PREVIMG) {
int block, nblocks;
uint8_t *memloc;
assert(t->src);
block = 0;
memloc = buf;
nblocks = imgsize ? div_up(imgsize, 2048) : 1;
while (block < nblocks) {
if (t->src->read_block(t->src,
image->node->loc.block + block, memloc)) {
iso_msg_sorry(LIBISO_CANT_READ_IMG,
"Unable to read boot image from previous image.");
break; /* exit loop */
}
memloc += 2048;
++block;
}
} else {
int fd;
ssize_t nread, tread;
uint8_t *memloc;
const char *path = image->node->loc.path;
memloc = buf;
fd = open(path, O_RDONLY);
if (fd == -1) {
iso_msg_sorry(LIBISO_CANT_READ_FILE,
"Can't open boot image file for reading. Skipping");
return;
}
tread = 0;
while (tread < imgsize) {
nread = read(fd, memloc, t->block_size);
if (nread <= 0) {
iso_msg_sorry(LIBISO_CANT_READ_FILE,
"Problem reading boot image file. Skipping");
break; /* exit loop */
}
tread += nread;
memloc += nread;
}
close(fd);
}
if (image->isolinux) {
/* we need to patch the image */
patch_boot_image(buf, t, imgsize);
} }
} }
/** /**
* Write one section entry. * Write one section entry.
* Currently this is used for both default and other entries since we * Currently this is used only for default image (the only supported just now)
* put selection criteria no 0 (no sel. criteria)
*/ */
static void static void
write_section_entry(uint8_t *buf, struct el_torito_boot_image *img) write_section_entry(uint8_t *buf, struct ecma119_write_target *t)
{ {
struct el_torito_boot_image *img;
struct el_torito_section_entry *se = struct el_torito_section_entry *se =
(struct el_torito_section_entry*)buf; (struct el_torito_section_entry*)buf;
img = t->catalog->image;
assert(img);
se->boot_indicator[0] = img->bootable ? 0x88 : 0x00; se->boot_indicator[0] = img->bootable ? 0x88 : 0x00;
se->boot_media_type[0] = img->type; se->boot_media_type[0] = img->type;
iso_lsb(se->load_seg, img->load_seg, 2); iso_lsb(se->load_seg, img->load_seg, 2);
se->system_type[0] = 0; //TODO need to get the partition type se->system_type[0] = img->partition_type;
iso_lsb(se->sec_count, img->load_size, 2); iso_lsb(se->sec_count, img->load_size, 2);
iso_lsb(se->block, img->file->block, 4); iso_lsb(se->block, t->imgblock, 4);
} }
/** /**
* Write El-Torito Boot Catalog * Write El-Torito Boot Catalog plus image
*/ */
static void static void
write_catalog(struct ecma119_write_target *t, uint8_t *buf) write_catalog(struct ecma119_write_target *t, uint8_t *buf)
{ {
struct el_torito_boot_catalog *cat = t->catalog; struct el_torito_boot_catalog *cat = t->catalog;
assert(cat); assert(cat);
assert(cat->nentries >= 1 && cat->nentries < 63); assert(cat->image);
write_validation_entry(t, buf); write_validation_entry(t, buf);
/* write default entry */ /* write default entry */
write_section_entry(buf + 32, cat->entries[0]); write_section_entry(buf + 32, t);
//TODO write all images write_boot_image(buf + 2048, t);
} }
void void
@ -446,9 +593,27 @@ el_torito_wr_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
void void
el_torito_wr_catalog(struct ecma119_write_target *t, uint8_t *buf) el_torito_wr_catalog(struct ecma119_write_target *t, uint8_t *buf)
{ {
off_t size;
off_t imgsize;
assert(t->catalog); assert(t->catalog);
/*
* Note that when this is called, we need to write el-torito info to
* image. Note, however, that the image could come from a previous session
* and maybe we don't know its size
*/
imgsize = t->catalog->image->node->node.attrib.st_size;
if (imgsize == 0) {
iso_msg_warn(LIBISO_EL_TORITO_BLIND_COPY,
"Can get boot image size, only one block will be copied");
imgsize = 2048;
}
size = 2048 + div_up(imgsize, t->block_size);
ecma119_start_chunking(t, ecma119_start_chunking(t,
write_catalog, write_catalog,
2048, size,
buf); buf);
} }

View File

@ -5,52 +5,66 @@
#include "file.h" #include "file.h"
#include "ecma119.h" #include "ecma119.h"
/**
* Location of the boot catalog
*/
struct iso_tree_node_boot_catalog
{
struct iso_tree_node node;
struct el_torito_boot_catalog *catalog;
};
struct el_torito_boot_catalog { struct el_torito_boot_catalog {
int nentries; struct iso_tree_node_boot *node; /* node of the catalog */
struct el_torito_boot_image **entries; struct el_torito_boot_image *image; /* default boot image */
struct iso_file *file; /**< The catalog file */ enum tree_node_from proc; /* whether the catalog is new or read from a
* prev session/image */
}; };
struct el_torito_boot_image { struct el_torito_boot_image {
unsigned char bootable; /**< If the entry is bootable. */ struct iso_tree_node_boot *node;
unsigned char patch_isolinux; /**< If the image will be patched */
unsigned int bootable:1; /**< If the entry is bootable. */
unsigned int isolinux:1; /**< If the image will be patched */
unsigned char type; /**< The type of image */ unsigned char type; /**< The type of image */
unsigned char partition_type; /**< type of partition for HD-emul images */ unsigned char partition_type; /**< type of partition for HD-emul images */
short load_seg; /**< Load segment for the initial boot image. */ short load_seg; /**< Load segment for the initial boot image. */
short load_size; /**< Number of sector to load. */ short load_size; /**< Number of sector to load. */
struct iso_tree_node_file *image;
struct iso_file *file;
}; };
/*struct el_torito_boot_entry * struct el_torito_validation_entry {
el_torito_add_boot_entry(struct el_torito_boot_catalog *cat, uint8_t header_id BP(1, 1);
struct iso_tree_node_file *image); uint8_t platform_id BP(2, 2);
*/ uint8_t reserved BP(3, 4);
uint8_t id_string BP(5, 28);
uint8_t checksum BP(29, 30);
uint8_t key_byte1 BP(31, 31);
uint8_t key_byte2 BP(32, 32);
};
struct el_torito_default_entry {
uint8_t boot_indicator BP(1, 1);
uint8_t boot_media_type BP(2, 2);
uint8_t load_seg BP(3, 4);
uint8_t system_type BP(5, 5);
uint8_t unused1 BP(6, 6);
uint8_t sec_count BP(7, 8);
uint8_t block BP(9, 12);
uint8_t unused2 BP(13, 32);
};
struct el_torito_section_header_entry {
uint8_t header_indicator BP(1, 1);
uint8_t platform_id BP(2, 2);
uint8_t number BP(3, 4);
uint8_t character BP(5, 32);
};
struct el_torito_section_entry {
uint8_t boot_indicator BP(1, 1);
uint8_t boot_media_type BP(2, 2);
uint8_t load_seg BP(3, 4);
uint8_t system_type BP(5, 5);
uint8_t unused1 BP(6, 6);
uint8_t sec_count BP(7, 8);
uint8_t block BP(9, 12);
uint8_t selec_criteria BP(13, 13);
uint8_t vendor_sc BP(14, 32);
};
void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat); void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat);
/**
* For each boot image file, this gets the related iso_file object.
* In most cases, the file is already in the hash table. However, if the
* boot record is hidden in both ISO/RR and joliet trees, this ensures
* that boot images will be written to image.
*/
void el_torito_get_image_files(struct ecma119_write_target *t);
/**
* Patch image files if selected. This is needed for isolinux boot images
*/
void el_torito_patch_image_files(struct ecma119_write_target *t);
/** /**
* Write the Boot Record Volume Descriptor * Write the Boot Record Volume Descriptor
*/ */
@ -60,6 +74,9 @@ el_torito_write_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf);
void void
el_torito_wr_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf); el_torito_wr_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf);
/**
* Write catalog + image
*/
void void
el_torito_wr_catalog(struct ecma119_write_target *t, uint8_t *buf); el_torito_wr_catalog(struct ecma119_write_target *t, uint8_t *buf);

View File

@ -8,6 +8,7 @@
#include "util.h" #include "util.h"
#include "volume.h" #include "volume.h"
#include "eltorito.h" #include "eltorito.h"
#include "messages.h"
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
@ -40,14 +41,14 @@ create_node(struct ecma119_write_target *t,
} }
ret->info.file = file; ret->info.file = file;
ret->type = JOLIET_FILE; ret->type = JOLIET_FILE;
} else { } else if (ISO_ISBOOT(iso)) {
/* it's boot catalog info */ /* it's boot catalog info */
struct iso_tree_node_boot_catalog *iso_b = struct iso_tree_node_boot *boot = (struct iso_tree_node_boot*) iso;
(struct iso_tree_node_boot_catalog *) iso; ret->info.boot_img = boot->img;
struct iso_file *file; ret->type = JOLIET_BOOT;
file = iso_b->catalog->file; } else {
ret->info.file = file; /* this should never happen */
ret->type = JOLIET_FILE; assert(0);
} }
return ret; return ret;
@ -66,7 +67,7 @@ create_tree(struct ecma119_write_target *t,
switch (iso->type) { switch (iso->type) {
case LIBISO_NODE_FILE: case LIBISO_NODE_FILE:
case LIBISO_NODE_BOOTCATALOG: case LIBISO_NODE_BOOT:
root = create_node(t, parent, iso); root = create_node(t, parent, iso);
break; break;
case LIBISO_NODE_DIR: case LIBISO_NODE_DIR:
@ -85,9 +86,13 @@ create_tree(struct ecma119_write_target *t,
} }
break; break;
default: default:
//TODO replace this printf {
printf("Can't add this kind of node to a Joliet tree"); char msg[512];
sprintf(msg, "Can't add %s to Joliet tree. This kind of files "
"can only be added to a Rock Ridget tree. Skipping", iso->name);
iso_msg_note(LIBISO_JOLIET_WRONG_FILE_TYPE, msg);
return NULL; return NULL;
}
break; break;
} }
return root; return root;
@ -271,8 +276,19 @@ write_one_dir_record(struct ecma119_write_target *t,
if (node->type == JOLIET_DIR) { if (node->type == JOLIET_DIR) {
len = node->info.dir.len; len = node->info.dir.len;
block = node->info.dir.block; block = node->info.dir.block;
} else if (node->type == JOLIET_BOOT) {
assert(t->eltorito);
if (node->info.boot_img) {
block = t->imgblock;
len = t->catalog->image->node->node.attrib.st_size;
} else {
/* we always assume 2048 as catalog len */
block = t->catblock;
len = 2048;
}
} else { } else {
/* file */ /* file */
assert(node->type == JOLIET_FILE);
len = node->info.file->size; len = node->info.file->size;
block = node->info.file->block; block = node->info.file->block;
} }

View File

@ -19,7 +19,8 @@ struct iso_tree_node;
enum joliet_node_type { enum joliet_node_type {
JOLIET_FILE, JOLIET_FILE,
JOLIET_DIR JOLIET_DIR,
JOLIET_BOOT
}; };
struct joliet_dir_info { struct joliet_dir_info {
@ -41,6 +42,10 @@ struct joliet_tree_node
union { union {
struct iso_file *file; struct iso_file *file;
struct joliet_dir_info dir; struct joliet_dir_info dir;
unsigned int boot_img:1; /** For boot nodes, it identifies if this
* corresponds to image(1) or catalog(0).
* The block is stored in ecma119_write_target
*/
} info; } info;
}; };

View File

@ -382,17 +382,35 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
Range "vreixo" : 0x00030000 to 0x0003ffff Range "vreixo" : 0x00030000 to 0x0003ffff
General:
0x00031001 (SORRY,HIGH) = Can't read file (ignored)
0x00031002 (FATAL,HIGH) = Can't read file (operation canceled)
Image reading: Image reading:
0x00031000 (FATAL,HIGH) = Unsupported ISO-9660 image 0x00031000 (FATAL,HIGH) = Unsupported ISO-9660 image
0x00031001 (HINT,MEDIUM) = Unsupported Vol Desc that will be ignored 0x00031001 (HINT,MEDIUM) = Unsupported Vol Desc that will be ignored
0x00031002 (FATAL,HIGH) = Damaged ISO-9660 image 0x00031002 (FATAL,HIGH) = Damaged ISO-9660 image
0x00031003 (SORRY,HIGH) = Can't read previous image file
Rock-Ridge:
0x00030101 (HINT,MEDIUM) = Unsupported SUSP entry that will be ignored 0x00030101 (HINT,MEDIUM) = Unsupported SUSP entry that will be ignored
0x00030102 (SORRY,HIGH) = Wrong/damaged SUSP entry 0x00030102 (SORRY,HIGH) = Wrong/damaged SUSP entry
0x00030103 (WARNING,MEDIUM)= Multiple SUSP ER entries where found 0x00030103 (WARNING,MEDIUM)= Multiple SUSP ER entries where found
0x00030111 (SORRY,HIGH) = Unsupported RR feature 0x00030111 (SORRY,HIGH) = Unsupported RR feature
0x00030112 (SORRY,HIGH) = Error in a Rock Ridge entry 0x00030112 (SORRY,HIGH) = Error in a Rock Ridge entry
El-Torito:
0x00030201 (HINT,MEDIUM) = Unsupported Boot Vol Desc that will be ignored
0x00030202 (SORRY,HIGH) = Wrong El-Torito catalog
0x00030203 (HINT,MEDIUM) = Unsupported El-Torito feature
0x00030204 (SORRY,HIGH) = Invalid file to be an El-Torito image
0x00030205 (WARNING,MEDIUM)= Can't properly patch isolinux image
0x00030206 (WARNING,MEDIUM)= Copying El-Torito from a previous image without
enought info about it
Joliet:
0x00030301 (NOTE,MEDIUM) = Unsupported file type for Joliet tree
------------------------------------------------------------------------------ ------------------------------------------------------------------------------

View File

@ -64,7 +64,7 @@ enum iso_tree_node_type {
LIBISO_NODE_DIR, LIBISO_NODE_DIR,
LIBISO_NODE_FILE, LIBISO_NODE_FILE,
LIBISO_NODE_SYMLINK, LIBISO_NODE_SYMLINK,
LIBISO_NODE_BOOTCATALOG LIBISO_NODE_BOOT
}; };
#define LIBISO_ISDIR(n) (iso_tree_node_get_type(n) == LIBISO_NODE_DIR) #define LIBISO_ISDIR(n) (iso_tree_node_get_type(n) == LIBISO_NODE_DIR)
@ -89,13 +89,12 @@ struct iso_tree_node_file;
struct iso_tree_node_symlink; struct iso_tree_node_symlink;
/** /**
* A node that represents a boot catalog * A node that represents an El-Torito file.
* FIXME I'm not very sure how this should be treated.
*/ */
struct iso_tree_node_boot_catalog; struct iso_tree_node_boot;
/** /**
* El-Torito boot image * Information about El-Torito boot image.
* \see eltorito.h * \see eltorito.h
*/ */
struct el_torito_boot_image; struct el_torito_boot_image;
@ -213,6 +212,16 @@ struct ecma119_source_opts {
int level; /**< ISO level to write at. */ int level; /**< ISO level to write at. */
int flags; /**< Which extensions to support. */ int flags; /**< Which extensions to support. */
int relaxed_constraints; /**< see ecma119_relaxed_constraints_flag */ int relaxed_constraints; /**< see ecma119_relaxed_constraints_flag */
unsigned int copy_eltorito:1;
/**<
* In multisession discs, select whether to copy el-torito catalog
* and boot image. Copy is needed for isolinux images, that need to
* be patched. However, it can lead to problems when the image is
* not present in the iso filesystem, because we can't figure out
* its size. In those cases, we only copy 1 block of data.
*/
unsigned int no_cache_inodes:1; unsigned int no_cache_inodes:1;
/**< If use inode caching or not. Set it to 1 to prevent /**< If use inode caching or not. Set it to 1 to prevent
* inode caching. * inode caching.
@ -283,6 +292,9 @@ struct ecma119_source_opts {
* 64KiB, where libisofs will write the contents that should * 64KiB, where libisofs will write the contents that should
* be written at the beginning of a overwriteable media, to * be written at the beginning of a overwriteable media, to
* grow the image. * grow the image.
* You shoudl initialize the buffer either with 0s, or with
* the contents of the first blocks of the image you're
* growing. In most cases, 0 is good enought.
*/ */
}; };
@ -386,6 +398,8 @@ int libisofs_errno;
#define UNEXPECTED_FILE_TYPE 3 #define UNEXPECTED_FILE_TYPE 3
/* invalid boot image size */ /* invalid boot image size */
#define ELTORITO_WRONG_IMAGE_SIZE 4 #define ELTORITO_WRONG_IMAGE_SIZE 4
/* invalid image */
#define ELTORITO_WRONG_IMAGE 5
/** /**
* Controls the bahavior of iso_tree_radd_dir function * Controls the bahavior of iso_tree_radd_dir function
@ -553,6 +567,10 @@ const char *iso_volume_get_biblio_file_id(struct iso_volume *volume);
/** /**
* Create a bootable volume by adding a El-Torito boot image. * Create a bootable volume by adding a El-Torito boot image.
* *
* This also add a catalog tree node to the image filesystem tree. The tree
* node for the image will be replaced with a iso_tree_node_boot node, that
* acts as a placeholder for the real image.
*
* \param volume The volume to make bootable. * \param volume The volume to make bootable.
* \param image The tree node with the file to use as default boot image. * \param image The tree node with the file to use as default boot image.
* \param type The boot media type. This can be one of 3 types: * \param type The boot media type. This can be one of 3 types:
@ -573,16 +591,60 @@ const char *iso_volume_get_biblio_file_id(struct iso_volume *volume);
* *
* \pre \p volume is a volume without any boot catalog yet * \pre \p volume is a volume without any boot catalog yet
* \pre \p image is a file tree node already inserted in the volume tree. * \pre \p image is a file tree node already inserted in the volume tree.
* \pre \p image is a file tree node that refers to a newly added file, not
* one from a previous session. FIXME allow prev session files too
* \pre \p dir is a directory node already inserted in the volume tree. * \pre \p dir is a directory node already inserted in the volume tree.
* \pre \p name There isn't any dir child with the same name. * \pre \p name There isn't any dir child with the same name.
* *
*/ */
struct el_torito_boot_image * struct el_torito_boot_image*
iso_volume_create_boot_catalog(struct iso_volume *volume, iso_volume_set_boot_image(struct iso_volume *volume,
struct iso_tree_node *image, struct iso_tree_node *image,
enum eltorito_boot_media_type type, enum eltorito_boot_media_type type,
struct iso_tree_node_dir *dir, struct iso_tree_node_dir *dir,
char *name); char *name);
struct el_torito_boot_image*
iso_volume_set_boot_image_hidden(struct iso_volume *volume,
const char* path,
enum eltorito_boot_media_type type);
/**
* Get El-Torito boot image of the volume, if any.
*
* This can be useful, for example, to check if a volume read from a previous
* session or an existing image is bootable. It can also be useful to get
* the image and catalog tree nodes. An application would want those, for
* example, to prevent the user removing it.
*
* Both tree nodes are owned by libisofs and should not be freed. You can check
* if the node is already on the tree by getting its parent (note that when
* reading El-Torito info from a previous image, the nodes might not be on
* the tree even if you haven't removed them). Remember that you'll need to
* get a new ref (with iso_tree_node_ref()) before inserting them again to the
* tree, and probably you will also need to set the name or permissions.
*
* \param imgnode When not NULL, it will be filled with the image tree node, if
* any.
* \param catnode When not NULL, it will be filled with the catalog tree node,
* if any.
*
* \return The default El-Torito bootable image, or NULL is the volume is not
* bootable.
*/
struct el_torito_boot_image*
iso_volume_get_boot_image(struct iso_volume *volume,
struct iso_tree_node **imgnode,
struct iso_tree_node **catnode);
/**
* Removes the El-Torito bootable image. Both the catalog and image tree nodes
* are also removed from the image filesystem tree, if there.
* If the volume is not bootable (don't have el-torito image) this function is
* a nop.
*/
void
iso_volume_remove_boot_image(struct iso_volume *volume);
/** /**
* Sets the load segment for the initial boot image. This is only for * Sets the load segment for the initial boot image. This is only for
@ -608,12 +670,11 @@ el_torito_set_no_bootable(struct el_torito_boot_image *bootimg);
/** /**
* Specifies that this image needs to be patched. This involves the writting * Specifies that this image needs to be patched. This involves the writting
* of a 56 bytes boot information table at offset 8 of the boot image file. * of a 56 bytes boot information table at offset 8 of the boot image file.
* Be aware that libisofs will modify original boot image file, so do a backup * The original boot image file won't be modified.
* if needed.
* This is needed for isolinux boot images. * This is needed for isolinux boot images.
*/ */
void void
el_torito_set_write_boot_info(struct el_torito_boot_image *bootimg); el_torito_patch_isolinux_image(struct el_torito_boot_image *bootimg);
/** /**
* Locate a node by its path on disc. * Locate a node by its path on disc.

View File

@ -29,6 +29,13 @@ void iso_msg_debug(char *msg_text)
msg_text, 0, 0); msg_text, 0, 0);
} }
void iso_msg_note(int error_code, char *msg_text)
{
libdax_msgs_submit(libdax_messenger, -1, error_code,
LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_MEDIUM,
msg_text, 0, 0);
}
void iso_msg_hint(int error_code, char *msg_text) void iso_msg_hint(int error_code, char *msg_text)
{ {
libdax_msgs_submit(libdax_messenger, -1, error_code, libdax_msgs_submit(libdax_messenger, -1, error_code,

View File

@ -7,12 +7,19 @@
#include "libdax_msgs.h" #include "libdax_msgs.h"
/** Can't read file (ignored) */
#define LIBISO_CANT_READ_FILE 0x00031001
/** Can't read file (operation canceled) */
#define LIBISO_FILE_READ_ERROR 0x00031002
/** Unsupported image feature */ /** Unsupported image feature */
#define LIBISO_IMG_UNSUPPORTED 0x00031000 #define LIBISO_IMG_UNSUPPORTED 0x00031000
/** Unsupported Vol Desc that will be ignored */ /** Unsupported Vol Desc that will be ignored */
#define LIBISO_UNSUPPORTED_VD 0x00031001 #define LIBISO_UNSUPPORTED_VD 0x00031001
/** damaged image */ /** damaged image */
#define LIBISO_WRONG_IMG 0x00031002 #define LIBISO_WRONG_IMG 0x00031002
/** Can't read previous image file */
#define LIBISO_CANT_READ_IMG 0x00031003
/* Unsupported SUSP entry */ /* Unsupported SUSP entry */
#define LIBISO_SUSP_UNHANLED 0x00030101 #define LIBISO_SUSP_UNHANLED 0x00030101
@ -25,8 +32,26 @@
/** Error in a Rock Ridge entry. */ /** Error in a Rock Ridge entry. */
#define LIBISO_RR_ERROR 0x00030112 #define LIBISO_RR_ERROR 0x00030112
/** Unsupported boot vol desc. */
#define LIBISO_BOOT_VD_UNHANLED 0x00030201
/** Wrong or damaged el-torito catalog */
#define LIBISO_EL_TORITO_WRONG 0x00030202
/** Unsupproted el-torito feature */
#define LIBISO_EL_TORITO_UNHANLED 0x00030203
/** Trying to add an invalid file as a El-Torito image */
#define LIBISO_EL_TORITO_WRONG_IMG 0x00030204
/** Can't properly patch isolinux image */
#define LIBISO_ISOLINUX_CANT_PATCH 0x00030205
/** Copying El-Torito from a previous image without enought info about it */
#define LIBISO_EL_TORITO_BLIND_COPY 0x00030206
/** Unsupported file type for Joliet tree */
#define LIBISO_JOLIET_WRONG_FILE_TYPE 0x00030301
void iso_msg_debug(char *msg_text); void iso_msg_debug(char *msg_text);
void iso_msg_note(int error_code, char *msg_text);
void iso_msg_hint(int error_code, char *msg_text); void iso_msg_hint(int error_code, char *msg_text);
void iso_msg_warn(int error_code, char *msg_text); void iso_msg_warn(int error_code, char *msg_text);

View File

@ -469,6 +469,8 @@ iso_tree_node_ref(struct iso_tree_node *node)
void void
iso_tree_free(struct iso_tree_node *root) iso_tree_free(struct iso_tree_node *root)
{ {
if (!root)
return;
if (--root->refcount < 1) { if (--root->refcount < 1) {
if ( ISO_ISDIR(root) ) { if ( ISO_ISDIR(root) ) {
size_t i; size_t i;
@ -487,6 +489,11 @@ iso_tree_free(struct iso_tree_node *root)
file = (struct iso_tree_node_file *) root; file = (struct iso_tree_node_file *) root;
if (root->procedence == LIBISO_NEW) if (root->procedence == LIBISO_NEW)
free(file->loc.path); free(file->loc.path);
} else if ( ISO_ISBOOT(root) ) {
struct iso_tree_node_boot *boot;
boot = (struct iso_tree_node_boot *) root;
if (root->procedence == LIBISO_NEW && boot->img)
free(boot->loc.path);
} }
free(root->name); free(root->name);
free(root); free(root);

View File

@ -95,6 +95,20 @@ struct iso_tree_node_dir
struct iso_tree_node **children; struct iso_tree_node **children;
}; };
/**
* Tree node that corresponds to some El-Torito artifact.
* This can be either the boot catalog or a bootable image.
*/
struct iso_tree_node_boot
{
struct iso_tree_node node;
unsigned int img:1; /*< 1 if img, 0 if catalog */
union {
char *path; /**< the path of the file on local filesystem */
uint32_t block; /**< If the file is from a previous session.*/
} loc;
};
/** /**
* An iterator for directory children. * An iterator for directory children.
*/ */
@ -151,5 +165,6 @@ void iso_tree_print_verbose(const struct iso_tree_node *root,
#define ISO_ISDIR(n) (n->type == LIBISO_NODE_DIR) #define ISO_ISDIR(n) (n->type == LIBISO_NODE_DIR)
#define ISO_ISREG(n) (n->type == LIBISO_NODE_FILE) #define ISO_ISREG(n) (n->type == LIBISO_NODE_FILE)
#define ISO_ISLNK(n) (n->type == LIBISO_NODE_SYMLINK) #define ISO_ISLNK(n) (n->type == LIBISO_NODE_SYMLINK)
#define ISO_ISBOOT(n) (n->type == LIBISO_NODE_BOOT)
#endif /* LIBISO_TREE_H */ #endif /* LIBISO_TREE_H */

View File

@ -119,10 +119,14 @@ int main(int argc, char **argv)
if (!img) { if (!img) {
err(1, "boot image patch is not valid"); err(1, "boot image patch is not valid");
} }
bootimg = iso_volume_create_boot_catalog(volume, img, ELTORITO_NO_EMUL, bootimg = iso_volume_set_boot_image(volume, img, ELTORITO_NO_EMUL,
boot, "boot.cat"); boot, "boot.cat");
el_torito_set_load_size(bootimg, 4); el_torito_set_load_size(bootimg, 4);
el_torito_set_write_boot_info(bootimg); el_torito_patch_isolinux_image(bootimg);
/* Or just this for hidden img
* iso_volume_set_boot_image_hidden(volume, boot_img, ELTORITO_NO_EMUL);
*/
} }
volset = iso_volset_new( volume, "VOLSETID" ); volset = iso_volset_new( volume, "VOLSETID" );
@ -138,8 +142,8 @@ int main(int argc, char **argv)
memset(&opts, 0, sizeof(struct ecma119_source_opts)); memset(&opts, 0, sizeof(struct ecma119_source_opts));
opts.level = level; opts.level = level;
opts.flags = flags; opts.flags = flags;
opts.relaxed_constraints = 0;//constraints; opts.relaxed_constraints = 0;
opts.input_charset = NULL;//"UTF-8"; opts.input_charset = NULL;
opts.ouput_charset = "UTF-8"; opts.ouput_charset = "UTF-8";
src = iso_source_new_ecma119(volset, &opts); src = iso_source_new_ecma119(volset, &opts);

View File

@ -165,8 +165,9 @@ int main(int argc, char **argv)
wopts.relaxed_constraints = 0; wopts.relaxed_constraints = 0;
wopts.input_charset = "UTF-8"; wopts.input_charset = "UTF-8";
wopts.ouput_charset = "UTF-8"; wopts.ouput_charset = "UTF-8";
wopts.ms_block = ropts.size; /* round up to 32kb aligment = 16 block*/
wopts.overwrite = malloc(32*2048); wopts.ms_block = ((ropts.size + 15) / 16 ) * 16;
wopts.overwrite = calloc(32, 2048);
wsrc = iso_source_new_ecma119(volset, &wopts); wsrc = iso_source_new_ecma119(volset, &wopts);
@ -193,7 +194,7 @@ int main(int argc, char **argv)
burn_write_opts_set_underrun_proof(burn_options, 1); burn_write_opts_set_underrun_proof(burn_options, 1);
//mmm, check for 32K alignment? //mmm, check for 32K alignment?
burn_write_opts_set_start_byte(burn_options, ropts.size * 2048); burn_write_opts_set_start_byte(burn_options, wopts.ms_block * 2048);
if (burn_write_opts_auto_write_type(burn_options, target_disc, if (burn_write_opts_auto_write_type(burn_options, target_disc,
reasons, 0) == BURN_WRITE_NONE) { reasons, 0) == BURN_WRITE_NONE) {

View File

@ -64,11 +64,30 @@ print_dir(struct iso_tree_node_dir *dir, int level)
print_permissions(iso_tree_node_get_permissions(node)); print_permissions(iso_tree_node_get_permissions(node));
printf(" %s -> %s \n", iso_tree_node_get_name(node), printf(" %s -> %s \n", iso_tree_node_get_name(node),
iso_tree_node_symlink_get_dest((struct iso_tree_node_symlink*)node) ); iso_tree_node_symlink_get_dest((struct iso_tree_node_symlink*)node) );
} else {
/* boot catalog */
printf("%s-[C] ", sp);
print_permissions(iso_tree_node_get_permissions(node));
printf(" %s\n", iso_tree_node_get_name(node) );
} }
} }
iso_tree_iter_free(iter); iso_tree_iter_free(iter);
} }
static void
check_el_torito(struct iso_volume *volume)
{
struct iso_tree_node *cat, *img;
if (iso_volume_get_boot_image(volume, &img, &cat)) {
printf("\nEL-TORITO INFORMATION\n");
printf("=====================\n\n");
printf("Catalog: %s\n", iso_tree_node_get_name(cat) );
printf("Image: %s\n", iso_tree_node_get_name(img) );
}
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
struct ecma119_read_opts opts; struct ecma119_read_opts opts;
@ -131,6 +150,8 @@ int main(int argc, char **argv)
print_dir(iso_volume_get_root(volume), 0); print_dir(iso_volume_get_root(volume), 0);
check_el_torito(volume);
printf("\n\n"); printf("\n\n");
data_source_free(src); data_source_free(src);