From 59d143c1f0a44f57f99e04c5f582577e37fa8a0f Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Thu, 22 Apr 2010 14:04:51 +0200 Subject: [PATCH] Added support for multiple boot images. New API calls iso_image_add_boot_image() , iso_image_get_all_boot_imgs(), el_torito_get_boot_platform_id(), el_torito_get_load_seg(), el_torito_get_load_size(), el_torito_get_bootable() --- libisofs/ecma119.c | 14 ++- libisofs/ecma119.h | 5 +- libisofs/eltorito.c | 214 ++++++++++++++++++++++++++++++++--------- libisofs/eltorito.h | 17 ++-- libisofs/fs_image.c | 154 ++++++++++++++++++++--------- libisofs/libisofs.h | 127 ++++++++++++++++++++++-- libisofs/messages.c | 2 + libisofs/system_area.c | 6 +- 8 files changed, 431 insertions(+), 108 deletions(-) diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index 4444224..d2cc8a6 100644 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2007 Vreixo Formoso * Copyright (c) 2007 Mario Danic - * Copyright (c) 2009 Thomas Schmitt + * Copyright (c) 2009 - 2010 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -72,7 +72,8 @@ void ecma119_image_free(Ecma119Image *t) free(t->input_charset); if (t->output_charset != NULL) free(t->output_charset); - + if (t->bootsrc != NULL) + free(t->bootsrc); if (t->system_area_data != NULL) free(t->system_area_data); @@ -1166,6 +1167,15 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) /* el-torito? */ target->eltorito = (src->bootcat == NULL ? 0 : 1); target->catalog = src->bootcat; + target->num_bootsrc = target->catalog->num_bootimages; + target->bootsrc = calloc(target->num_bootsrc + 1, + sizeof(IsoFileSrc *)); + if (target->bootsrc == NULL) { + ret = ISO_OUT_OF_MEM; + goto target_cleanup; + } + for (i= 0; i < target->num_bootsrc; i++) + target->bootsrc[i] = NULL; if (opts->system_area_data != NULL) { system_area = opts->system_area_data; diff --git a/libisofs/ecma119.h b/libisofs/ecma119.h index dcdc43b..a48db53 100644 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -454,7 +454,10 @@ struct ecma119_image */ struct el_torito_boot_catalog *catalog; IsoFileSrc *cat; /**< location of the boot catalog in the new image */ - IsoFileSrc *bootimg; /**< location of the boot image in the new image */ + + /* ts B00420 */ + int num_bootsrc; + IsoFileSrc **bootsrc; /* location of the boot images in the new image */ /* * System Area related information diff --git a/libisofs/eltorito.c b/libisofs/eltorito.c index 734d480..9ef4a87 100644 --- a/libisofs/eltorito.c +++ b/libisofs/eltorito.c @@ -18,6 +18,7 @@ #include #include +#include /** * This table should be written with the actual values at offset @@ -63,6 +64,12 @@ int el_torito_set_boot_platform_id(ElToritoBootImage *bootimg, uint8_t id) return 1; } +/* API */ +int el_torito_get_boot_platform_id(ElToritoBootImage *bootimg) +{ + return bootimg->platform_id; +} + /** * Sets the load segment for the initial boot image. This is only for * no emulation boot images, and is a NOP for other image types. @@ -74,6 +81,14 @@ void el_torito_set_load_seg(ElToritoBootImage *bootimg, short segment) bootimg->load_seg = segment; } +/* API */ +int el_torito_get_load_seg(ElToritoBootImage *bootimg) +{ + if (bootimg->load_seg < 0) + return 0xffff - bootimg->load_seg; + return bootimg->load_seg; +} + /** * Sets the number of sectors (512b) to be load at load segment during * the initial boot procedure. This is only for no emulation boot images, @@ -86,6 +101,14 @@ void el_torito_set_load_size(ElToritoBootImage *bootimg, short sectors) bootimg->load_size = sectors; } +/* API */ +int el_torito_get_load_size(ElToritoBootImage *bootimg) +{ + if (bootimg->load_size < 0) + return 0xffff - bootimg->load_size; + return bootimg->load_size; +} + /** * Marks the specified boot image as not bootable */ @@ -94,6 +117,12 @@ void el_torito_set_no_bootable(ElToritoBootImage *bootimg) bootimg->bootable = 0; } +/* API */ +int el_torito_get_bootable(ElToritoBootImage *bootimg) +{ + return !!bootimg->bootable; +} + /** * 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. @@ -360,7 +389,7 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path, const char *catalog_path, ElToritoBootImage **boot) { - int ret; + int ret, i; struct el_torito_boot_catalog *catalog; ElToritoBootImage *boot_image= NULL; IsoBoot *cat_node= NULL; @@ -424,7 +453,10 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path, ret = ISO_OUT_OF_MEM; goto boot_image_cleanup; } - catalog->image = boot_image; + catalog->num_bootimages = 1; + catalog->bootimages[0] = boot_image; + for (i = 1; i < Libisofs_max_boot_imageS; i++) + catalog->bootimages[i] = NULL; catalog->node = cat_node; catalog->sort_weight = 1000; /* slightly high */ iso_node_ref((IsoNode*)cat_node); @@ -449,7 +481,7 @@ boot_image_cleanup:; } /** - * Get El-Torito boot image of an ISO image, if any. + * Get the boot catalog and the El-Torito default boot image of an ISO image. * * 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 @@ -493,10 +525,10 @@ int iso_image_get_boot_image(IsoImage *image, ElToritoBootImage **boot, /* ok, image is bootable */ if (boot) { - *boot = image->bootcat->image; + *boot = image->bootcat->bootimages[0]; } if (imgnode) { - *imgnode = image->bootcat->image->image; + *imgnode = image->bootcat->bootimages[0]->image; } if (catnode) { *catnode = image->bootcat->node; @@ -504,6 +536,40 @@ int iso_image_get_boot_image(IsoImage *image, ElToritoBootImage **boot, return ISO_SUCCESS; } +int iso_image_get_all_boot_imgs(IsoImage *image, int *num_boots, + ElToritoBootImage ***boots, IsoFile ***bootnodes, int flag) +{ + int i; + struct el_torito_boot_catalog *cat; + + if (image == NULL) + return ISO_NULL_POINTER; + if (image->bootcat == NULL) + return 0; + cat = image->bootcat; + *num_boots = cat->num_bootimages; + *boots = NULL; + *bootnodes = NULL; + if (*num_boots <= 0) + return 0; + *boots = calloc(*num_boots, sizeof(ElToritoBootImage *)); + *bootnodes = calloc(*num_boots, sizeof(IsoFile *)); + if(*boots == NULL || *bootnodes == NULL) { + if (*boots != NULL) + free(*boots); + if (*bootnodes != NULL) + free(*bootnodes); + *boots = NULL; + *bootnodes = NULL; + return ISO_OUT_OF_MEM; + } + for (i = 0; i < *num_boots; i++) { + (*boots)[i] = cat->bootimages[i]; + (*bootnodes)[i] = image->bootcat->bootimages[i]->image; + } + return 1; +} + /** * Removes the El-Torito bootable image. * @@ -528,6 +594,28 @@ void iso_image_remove_boot_image(IsoImage *image) image->bootcat = NULL; } +/* ts B00420 */ +/* future API */ +int iso_image_add_boot_image(IsoImage *image, const char *image_path, + enum eltorito_boot_media_type type, int flag, + ElToritoBootImage **boot) +{ + int ret; + struct el_torito_boot_catalog *catalog = image->bootcat; + ElToritoBootImage *boot_img; + + if (catalog->num_bootimages >= Libisofs_max_boot_imageS) + return ISO_BOOT_IMAGE_OVERFLOW; + ret = create_image(image, image_path, type, &boot_img); + if (ret < 0) + return ret; + catalog->bootimages[catalog->num_bootimages] = boot_img; + catalog->num_bootimages++; + if (boot != NULL) + *boot = boot_img; + return 1; +} + /* API */ int iso_image_set_boot_catalog_weight(IsoImage *image, int sort_weight) { @@ -540,14 +628,19 @@ int iso_image_set_boot_catalog_weight(IsoImage *image, int sort_weight) void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat) { struct el_torito_boot_image *image; + int i; if (cat == NULL) { return; } - image = cat->image; - iso_node_unref((IsoNode*)image->image); - free(image); + for (i = 0; i < Libisofs_max_boot_imageS; i++) { + image = cat->bootimages[i]; + if (image == NULL) + continue; + iso_node_unref((IsoNode*)image->image); + free(image); + } iso_node_unref((IsoNode*)cat->node); free(cat); } @@ -560,11 +653,6 @@ struct catalog_stream Ecma119Image *target; uint8_t buffer[BLOCK_SIZE]; int offset; /* -1 if stream is not opened */ - - /* ts B00419 */ - /* Byte 1 of Validation Entry: 0= 80x86, 1= PowerPC, 2= Mac, 0xef= EFI */ - uint8_t platform_id; - }; static void @@ -576,7 +664,6 @@ write_validation_entry(uint8_t *buf, uint8_t platform_id) struct el_torito_validation_entry *ve = (struct el_torito_validation_entry*)buf; ve->header_id[0] = 1; - /* 0: 80x86, 1: PowerPC, 2: Mac, 0xef: EFI */ ve->platform_id[0] = platform_id; ve->key_byte1[0] = 0x55; ve->key_byte2[0] = 0xAA; @@ -589,31 +676,58 @@ write_validation_entry(uint8_t *buf, uint8_t platform_id) iso_lsb(ve->checksum, checksum, 2); } +static void +write_section_header(uint8_t *buf, Ecma119Image *t, int idx) { + int pi; + char *id_string; + + struct el_torito_section_header *e = + (struct el_torito_section_header *) buf; + + /* 0x90 = more section headers follow , 0x91 = final section */ + e->header_indicator[0] = 0x90 + (idx == t->catalog->num_bootimages - 1); + pi= e->platform_id[0] = t->catalog->bootimages[idx]->platform_id; + e->num_entries[0] = 1; + e->num_entries[1] = 0; + id_string = (char *) e->id_string; + memset(id_string, 0, sizeof(e->id_string)); + +/* >>> ??? + El-Torito 1.0 , chapter 2.3 : + "If the BIOS understands the ID, string it may choose to boot + the system using one of these entries ..." +*/ + +} + /** * Write one section entry. - * Currently this is used only for default image (the only supported just now) + * Usable for the Default Entry + * and for Section Entries with Selection criteria type == 0 */ static void -write_section_entry(uint8_t *buf, Ecma119Image *t) +write_section_entry(uint8_t *buf, Ecma119Image *t, int idx) { struct el_torito_boot_image *img; struct el_torito_section_entry *se = (struct el_torito_section_entry*)buf; - img = t->catalog->image; + img = t->catalog->bootimages[idx]; se->boot_indicator[0] = img->bootable ? 0x88 : 0x00; se->boot_media_type[0] = img->type; iso_lsb(se->load_seg, img->load_seg, 2); se->system_type[0] = img->partition_type; iso_lsb(se->sec_count, img->load_size, 2); - iso_lsb(se->block, t->bootimg->sections[0].block, 4); + iso_lsb(se->block, t->bootsrc[idx]->sections[0].block, 4); } static int catalog_open(IsoStream *stream) { + int i; struct catalog_stream *data; + if (stream == NULL) { return ISO_NULL_POINTER; } @@ -626,11 +740,18 @@ int catalog_open(IsoStream *stream) memset(data->buffer, 0, BLOCK_SIZE); /* fill the buffer with the catalog contents */ - write_validation_entry(data->buffer, data->platform_id); + write_validation_entry(data->buffer, + data->target->catalog->bootimages[0]->platform_id); - /* write default entry */ - write_section_entry(data->buffer + 32, data->target); + /* write default entry = first boot image */ + write_section_entry(data->buffer + 32, data->target, 0); + /* ts B00420 */ + /* (The maximum number of boot images must fit into BLOCK_SIZE) */ + for (i = 1; i < data->target->catalog->num_bootimages; i++) { + write_section_header(data->buffer + i * 64, data->target, i); + write_section_entry(data->buffer + i * 64 + 32, data->target, i); + } data->offset = 0; return ISO_SUCCESS; } @@ -743,7 +864,6 @@ int catalog_stream_new(Ecma119Image *target, IsoStream **stream) /* fill data */ data->target = target; data->offset = -1; - data->platform_id = target->catalog->image->platform_id; str->refcount = 1; str->data = data; @@ -807,7 +927,7 @@ int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src) * 1 on success, 0 error (but continue), < 0 error */ static -int patch_boot_image(uint8_t *buf, Ecma119Image *t, size_t imgsize) +int patch_boot_image(uint8_t *buf, Ecma119Image *t, size_t imgsize, int idx) { struct boot_info_table *info; uint32_t checksum; @@ -840,7 +960,7 @@ int patch_boot_image(uint8_t *buf, Ecma119Image *t, size_t imgsize) info = (struct boot_info_table*)(buf + 8); /*memset(info, 0, sizeof(struct boot_info_table));*/ iso_lsb(info->bi_pvd, t->ms_block + 16, 4); - iso_lsb(info->bi_file, t->bootimg->sections[0].block, 4); + iso_lsb(info->bi_file, t->bootsrc[idx]->sections[0].block, 4); iso_lsb(info->bi_length, imgsize, 4); iso_lsb(info->bi_csum, checksum, 4); return ISO_SUCCESS; @@ -854,7 +974,11 @@ int eltorito_writer_compute_data_blocks(IsoImageWriter *writer) * this is a good place to do so. */ Ecma119Image *t; - int ret; + int ret, idx; + size_t size; + uint8_t *buf; + IsoStream *new = NULL; + IsoStream *original = NULL; if (writer == NULL) { return ISO_NULL_POINTER; @@ -862,12 +986,12 @@ int eltorito_writer_compute_data_blocks(IsoImageWriter *writer) t = writer->target; - if (t->catalog->image->isolinux_options & 0x01) { - /* we need to patch the image */ - size_t size; - uint8_t *buf; - IsoStream *new = NULL; - IsoStream *original = t->bootimg->stream; + /* ts B00420 : now in loop */ + /* Patch the boot image info tables if indicated */ + for (idx = 0; idx < t->catalog->num_bootimages; idx++) { + if (!(t->catalog->bootimages[idx]->isolinux_options & 0x01)) + continue; + original = t->bootsrc[idx]->stream; size = (size_t) iso_stream_get_size(original); buf = calloc(1, size); if (buf == NULL) { @@ -884,7 +1008,7 @@ int eltorito_writer_compute_data_blocks(IsoImageWriter *writer) } /* ok, patch the read buffer */ - ret = patch_boot_image(buf, t, size); + ret = patch_boot_image(buf, t, size, idx); if (ret < 0) { return ret; } @@ -895,7 +1019,7 @@ int eltorito_writer_compute_data_blocks(IsoImageWriter *writer) if (ret < 0) { return ret; } - t->bootimg->stream = new; + t->bootsrc[idx]->stream = new; iso_stream_unref(original); } return ISO_SUCCESS; @@ -946,7 +1070,7 @@ int eltorito_writer_free_data(IsoImageWriter *writer) int eltorito_writer_create(Ecma119Image *target) { - int ret; + int ret, idx; IsoImageWriter *writer; IsoFile *bootimg; IsoFileSrc *src; @@ -977,16 +1101,20 @@ int eltorito_writer_create(Ecma119Image *target) return ret; } } - bootimg = target->catalog->image->image; - ret = iso_file_src_create(target, bootimg, &src); - if (ret < 0) { - return ret; - } - target->bootimg = src; - /* if we have selected to patch the image, it needs to be copied always */ - if (target->catalog->image->isolinux_options & 0x01) { - src->prev_img = 0; + /* ts B00420 : now in a loop */ + for (idx = 0; idx < target->catalog->num_bootimages; idx++) { + bootimg = target->catalog->bootimages[idx]->image; + ret = iso_file_src_create(target, bootimg, &src); + if (ret < 0) { + return ret; + } + target->bootsrc[idx] = src; + + /* For patching an image, it needs to be copied always */ + if (target->catalog->bootimages[idx]->isolinux_options & 0x01) { + src->prev_img = 0; + } } /* we need the bootable volume descriptor */ diff --git a/libisofs/eltorito.h b/libisofs/eltorito.h index b0078ba..d63b99c 100644 --- a/libisofs/eltorito.h +++ b/libisofs/eltorito.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso + * Copyright (c) 2010 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -27,16 +28,20 @@ struct Iso_Boot IsoNode node; }; +/* Not more than 32 so that all entries fit into 2048 bytes */ +#define Libisofs_max_boot_imageS 32 + struct el_torito_boot_catalog { IsoBoot *node; /* node of the catalog */ - struct el_torito_boot_image *image; /* default boot image */ + + /* ts B00419 */ + int num_bootimages; + struct el_torito_boot_image *bootimages[Libisofs_max_boot_imageS]; + /* [0]= default boot image */ /* ts B00419 */ /* Weight value for image sorting */ int sort_weight; - - /* >>> ts B00419 : List of further boot images */ - }; struct el_torito_boot_image { @@ -88,8 +93,8 @@ struct el_torito_default_entry { struct el_torito_section_header { 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); + uint8_t num_entries BP(3, 4); + uint8_t id_string BP(5, 32); }; /** El-Torito, 2.4 */ diff --git a/libisofs/fs_image.c b/libisofs/fs_image.c index 0bb1762..b0dee63 100644 --- a/libisofs/fs_image.c +++ b/libisofs/fs_image.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2009 Thomas Schmitt + * Copyright (c) 2009 - 2010 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -279,12 +279,19 @@ typedef struct /* el-torito information */ unsigned int eltorito : 1; /* is el-torito available */ - unsigned int bootable:1; /**< If the entry is bootable. */ - unsigned char type; /**< The type of image */ - unsigned char partition_type; /**< type of partition for HD-emul images */ - short load_seg; /**< Load segment for the initial boot image. */ - short load_size; /**< Number of sectors to load. */ - uint32_t imgblock; /**< Block for El-Torito boot image */ + /* ts B00419 */ + int num_bootimgs; + unsigned char platform_ids[Libisofs_max_boot_imageS]; + unsigned char boot_flags[Libisofs_max_boot_imageS]; /* bit0= bootable */ + unsigned char media_types[Libisofs_max_boot_imageS]; + unsigned char partition_types[Libisofs_max_boot_imageS]; + short load_segs[Libisofs_max_boot_imageS]; + short load_sizes[Libisofs_max_boot_imageS]; + /** Block addresses of for El-Torito boot images. + Needed to recognize them when the get read from the directory tree. + */ + uint32_t bootblocks[Libisofs_max_boot_imageS]; + uint32_t catblock; /**< Block for El-Torito catalog */ /* Whether inode numbers from PX entries shall be discarded */ @@ -2191,9 +2198,10 @@ int read_pvm(_ImageFsData *data, uint32_t block) static int read_el_torito_boot_catalog(_ImageFsData *data, uint32_t block) { - int ret; + int ret, i, rx, last_done, idx; struct el_torito_validation_entry *ve; - struct el_torito_default_entry *entry; + struct el_torito_section_header *sh; + struct el_torito_section_entry *entry; /* also usable as default_entry */ unsigned char buffer[BLOCK_SIZE]; ret = data->src->read_block(data->src, block, buffer); @@ -2223,17 +2231,47 @@ int read_el_torito_boot_catalog(_ImageFsData *data, uint32_t block) /* ok, once we are here we assume it is a valid catalog */ /* parse the default entry */ - entry = (struct el_torito_default_entry *)(buffer + 32); + entry = (struct el_torito_section_entry *)(buffer + 32); data->eltorito = 1; - data->bootable = entry->boot_indicator[0] ? 1 : 0; - data->type = entry->boot_media_type[0]; - data->partition_type = entry->system_type[0]; - data->load_seg = iso_read_lsb(entry->load_seg, 2); - data->load_size = iso_read_lsb(entry->sec_count, 2); - data->imgblock = iso_read_lsb(entry->block, 4); + /* ts B00420 */ + /* The Default Entry is declared mandatory */ + data->num_bootimgs = 1; + data->platform_ids[0] = ve->platform_id[0]; + data->boot_flags[0] = entry->boot_indicator[0] ? 1 : 0; + data->media_types[0] = entry->boot_media_type[0]; + data->partition_types[0] = entry->system_type[0]; + data->load_segs[0] = iso_read_lsb(entry->load_seg, 2); + data->load_sizes[0] = iso_read_lsb(entry->sec_count, 2); + data->bootblocks[0] = iso_read_lsb(entry->block, 4); - /* TODO #00018 : check if there are more entries in the boot catalog */ + /* ts B00420 : Read eventual more entries from the boot catalog */ + last_done = 0; + for (rx = 64; (buffer[rx] & 0xfe) == 0x90 && !last_done; rx += 32) { + last_done = buffer[rx] & 1; + /* Read Section Header */ + sh = (struct el_torito_section_header *) (buffer + rx); + for (i = 0; i < sh->num_entries[0]; i++) { + rx += 32; + if (data->num_bootimgs >= Libisofs_max_boot_imageS) { + ret = iso_msg_submit(data->msgid, ISO_EL_TORITO_WARN, 0, + "Too many boot images found. List truncated."); + goto after_bootblocks; + } + /* Read bootblock from section entry */ + entry = (struct el_torito_section_entry *)(buffer + rx); + idx = data->num_bootimgs; + data->platform_ids[idx] = sh->platform_id[0]; + data->boot_flags[idx] = entry->boot_indicator[0] ? 1 : 0; + data->media_types[idx] = entry->boot_media_type[0]; + data->partition_types[idx] = entry->system_type[0]; + data->load_segs[idx] = iso_read_lsb(entry->load_seg, 2); + data->load_sizes[idx] = iso_read_lsb(entry->sec_count, 2); + data->bootblocks[idx] = iso_read_lsb(entry->block, 4); + data->num_bootimgs++; + } + } +after_bootblocks:; return ISO_SUCCESS; } @@ -2318,7 +2356,7 @@ ex: int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts, int msgid, IsoImageFilesystem **fs) { - int ret; + int ret, i; uint32_t block; IsoImageFilesystem *ifs; _ImageFsData *data; @@ -2357,9 +2395,13 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts, data->md5_load = !opts->nomd5; data->aaip_version = -1; data->make_new_ino = opts->make_new_ino; + data->num_bootimgs = 0; + for (i = 0; i < Libisofs_max_boot_imageS; i++) + data->bootblocks[i] = 0; data->inode_counter = 0; data->px_ino_status = 0; + data->local_charset = strdup(iso_get_local_charset(0)); if (data->local_charset == NULL) { ret = ISO_OUT_OF_MEM; @@ -2608,7 +2650,7 @@ static int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image, IsoFileSource *src, IsoNode **node) { - int ret; + int ret, idx; struct stat info; IsoNode *new; char *name; @@ -2720,11 +2762,17 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image, new = (IsoNode*) file; new->refcount = 0; - if (fsdata->eltorito && data->sections[0].block == fsdata->imgblock) { + /* ts B00419 */ + for (idx = 0; idx < fsdata->num_bootimgs; idx++) + if (fsdata->eltorito && data->sections[0].block == + fsdata->bootblocks[idx]) + break; + if (idx < fsdata->num_bootimgs) { /* it is boot image node */ - if (image->bootcat->image->image != NULL) { + + if (image->bootcat->bootimages[idx]->image != NULL) { ret = iso_msg_submit(image->id, ISO_EL_TORITO_WARN, 0, - "More than one image node has been found."); + "More than one ISO node has been found for the same boot image."); if (ret < 0) { free(name); iso_stream_unref(stream); @@ -2732,7 +2780,7 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image, } } else { /* and set the image node */ - image->bootcat->image->image = file; + image->bootcat->bootimages[idx]->image = file; new->refcount++; } } @@ -2872,7 +2920,7 @@ int iso_image_builder_new(IsoNodeBuilder *old, IsoNodeBuilder **builder) * accessible from the ISO filesystem. */ static -int create_boot_img_filesrc(IsoImageFilesystem *fs, IsoImage *image, +int create_boot_img_filesrc(IsoImageFilesystem *fs, IsoImage *image, int idx, IsoFileSource **src) { int ret; @@ -2930,7 +2978,8 @@ int create_boot_img_filesrc(IsoImageFilesystem *fs, IsoImage *image, ifsdata->info = atts; ifsdata->name = NULL; - ifsdata->sections[0].block = fsdata->imgblock; + /* ts B00420 */ + ifsdata->sections[0].block = fsdata->bootblocks[idx]; ifsdata->sections[0].size = BLOCK_SIZE; ifsdata->nsections = 1; @@ -2952,7 +3001,7 @@ int iso_image_import(IsoImage *image, IsoDataSource *src, struct iso_read_opts *opts, IsoReadImageFeatures **features) { - int ret, hflag, i; + int ret, hflag, i, idx; IsoImageFilesystem *fs; IsoFilesystem *fsback; IsoNodeBuilder *blback; @@ -2961,6 +3010,8 @@ int iso_image_import(IsoImage *image, IsoDataSource *src, _ImageFsData *data; struct el_torito_boot_catalog *oldbootcat; uint8_t *rpt; + IsoFileSource *boot_src; + IsoNode *node; #ifdef Libisofs_with_checksumS uint32_t old_checksum_start_lba; @@ -3066,23 +3117,32 @@ int iso_image_import(IsoImage *image, IsoDataSource *src, struct el_torito_boot_catalog *catalog; ElToritoBootImage *boot_image= NULL; - boot_image = calloc(1, sizeof(ElToritoBootImage)); - if (boot_image == NULL) { - ret = ISO_OUT_OF_MEM; - goto import_revert; - } - boot_image->bootable = data->bootable; - boot_image->type = data->type; - boot_image->partition_type = data->partition_type; - boot_image->load_seg = data->load_seg; - boot_image->load_size = data->load_size; - catalog = calloc(1, sizeof(struct el_torito_boot_catalog)); if (catalog == NULL) { ret = ISO_OUT_OF_MEM; goto import_revert; } - catalog->image = boot_image; + + /* ts B00421 */ + catalog->num_bootimages = 0; + for (idx = 0; idx < data->num_bootimgs; idx++) { + boot_image = calloc(1, sizeof(ElToritoBootImage)); + if (boot_image == NULL) { + ret = ISO_OUT_OF_MEM; + goto import_revert; + } + boot_image->bootable = data->boot_flags[idx] & 1; + boot_image->type = data->media_types[idx]; + boot_image->partition_type = data->partition_types[idx]; + boot_image->load_seg = data->load_segs[idx]; + boot_image->load_size = data->load_sizes[idx]; + boot_image->platform_id = data->platform_ids[idx]; + + catalog->bootimages[catalog->num_bootimages] = boot_image; + catalog->num_bootimages++; + } + for ( ; idx < Libisofs_max_boot_imageS; idx++) + catalog->bootimages[idx] = NULL; image->bootcat = catalog; } @@ -3116,21 +3176,25 @@ int iso_image_import(IsoImage *image, IsoDataSource *src, } if (data->eltorito) { - /* if catalog and image nodes were not filled, we create them here */ - if (image->bootcat->image->image == NULL) { - IsoFileSource *src; - IsoNode *node; - ret = create_boot_img_filesrc(fs, image, &src); + /* if catalog and boot image nodes were not filled, + we create them here */ + + /* ts B00419 : now in a loop */ + for (idx = 0; idx < image->bootcat->num_bootimages; idx++) { + if (image->bootcat->bootimages[idx]->image != NULL) + continue; + ret = create_boot_img_filesrc(fs, image, idx, &boot_src); if (ret < 0) { iso_node_builder_unref(image->builder); goto import_revert; } - ret = image_builder_create_node(image->builder, image, src, &node); + ret = image_builder_create_node(image->builder, image, boot_src, + &node); if (ret < 0) { iso_node_builder_unref(image->builder); goto import_revert; } - image->bootcat->image->image = (IsoFile*)node; + image->bootcat->bootimages[idx]->image = (IsoFile*)node; /* warn about hidden images */ iso_msg_submit(image->id, ISO_EL_TORITO_HIDDEN, 0, diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 7a8b8aa..3be6c13 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2007-2008 Vreixo Formoso, Mario Danic - * Copyright (c) 2009 Thomas Schmitt + * Copyright (c) 2009-2010 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -2283,16 +2283,15 @@ void iso_image_set_biblio_file_id(IsoImage *image, const char *biblio_file_id); const char *iso_image_get_biblio_file_id(const IsoImage *image); /** - * Create a bootable image by adding a El-Torito boot image. - * - * This also add a catalog boot node to the image filesystem tree. + * Create a new set of El-Torito bootable images by adding a boot catalog + * and the default boot image. + * Further boot images may then be added by iso_image_add_boot_image(). * * @param image * The image to make bootable. If it was already bootable this function * returns an error and the image remains unmodified. * @param image_path - * The absolute path on the image tree of a regular file to use as - * default boot image. + * The absolute path of a IsoFile to be used as default boot image. * @param type * The boot media type. This can be one of 3 types: * - Floppy emulation: Boot image file must be exactly @@ -2325,10 +2324,36 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path, const char *catalog_path, ElToritoBootImage **boot); +/** + * Add a further boot image to the set of El-Torito bootable images. + * This set has already to be created by iso_image_set_boot_image(). + * Up to 31 further boot images may be added. + * + * @param image + * The image to which the boot image shall be added. + * returns an error and the image remains unmodified. + * @param image_path + * The absolute path of a IsoFile to be used as default boot image. + * @param type + * The boot media type. See iso_image_set_boot_image + * @param flag + * Bitfield for control purposes. Unused yet. Submit 0. + * @param boot + * Location where a pointer to the added boot image will be stored. + * See iso_image_set_boot_image + * @return + * 1 on success, < 0 on error + * + * @since 0.6.32 + */ +int iso_image_add_boot_image(IsoImage *image, const char *image_path, + enum eltorito_boot_media_type type, int flag, + ElToritoBootImage **boot); + /* TODO #00026 : add support for "hidden" bootable images. */ /** - * Get El-Torito boot image of an ISO image, if any. + * Get the El-Torito boot catalog and the default boot image of an ISO image. * * 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 @@ -2365,6 +2390,34 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path, int iso_image_get_boot_image(IsoImage *image, ElToritoBootImage **boot, IsoFile **imgnode, IsoBoot **catnode); +/** + * Get all El-Torito boot images of an ISO image. + * + * The first of these boot images is the same as returned by + * iso_image_get_boot_image(). The others are alternative boot images. + * + * @param image + * The image from which to get the boot images. + * @param num_boots + * The number of available array elements in boots and bootnodes. + * @param boots + * Returns NULL or an allocated array of pointers to boot images. + * Apply system call free(boots) to dispose it. + * @param bootnodes + * Returns NULL or an allocated array of pointers to the IsoFile nodes + * which bear the content of the boot images in boots. + * @param flag + * Bitfield for control purposes. Unused yet. Submit 0. + * @return + * 1 on success, 0 no El-Torito catalog and boot image attached, + * < 0 error. + * + * @since 0.6.32 + */ +int iso_image_get_all_boot_imgs(IsoImage *image, int *num_boots, + ElToritoBootImage ***boots, IsoFile ***bootnodes, int flag); + + /** * Removes the El-Torito bootable image. * @@ -2382,7 +2435,7 @@ void iso_image_remove_boot_image(IsoImage *image); * * For the meaning of sort weights see iso_node_set_sort_weight(). * That function cannot be applied to the emerging boot catalog because - * it is not represented by an IsoNode. + * it is not represented by an IsoFile. * * @param image * The image to manipulate. @@ -2415,6 +2468,19 @@ int iso_image_set_boot_catalog_weight(IsoImage *image, int sort_weight); */ int el_torito_set_boot_platform_id(ElToritoBootImage *bootimg, uint8_t id); +/** + * Get the platform ID value. See el_torito_set_boot_platform_id(). + * + * @param bootimg + * The image to inquire + * @return + * 0 - 255 : The platform ID + * < 0 : error + * + * @since 0.6.32 + */ +int el_torito_get_boot_platform_id(ElToritoBootImage *bootimg); + /** * Sets the load segment for the initial boot image. This is only for * no emulation boot images, and is a NOP for other image types. @@ -2423,6 +2489,19 @@ int el_torito_set_boot_platform_id(ElToritoBootImage *bootimg, uint8_t id); */ void el_torito_set_load_seg(ElToritoBootImage *bootimg, short segment); +/** + * Get the load segment value. See el_torito_set_load_seg(). + * + * @param bootimg + * The image to inquire + * @return + * 0 - 65535 : The load segment value + * < 0 : error + * + * @since 0.6.32 + */ +int el_torito_get_load_seg(ElToritoBootImage *bootimg); + /** * Sets the number of sectors (512b) to be load at load segment during * the initial boot procedure. This is only for @@ -2432,6 +2511,19 @@ void el_torito_set_load_seg(ElToritoBootImage *bootimg, short segment); */ void el_torito_set_load_size(ElToritoBootImage *bootimg, short sectors); +/** + * Get the load size. See el_torito_set_load_size(). + * + * @param bootimg + * The image to inquire + * @return + * 0 - 65535 : The load size value + * < 0 : error + * + * @since 0.6.32 + */ +int el_torito_get_load_size(ElToritoBootImage *bootimg); + /** * Marks the specified boot image as not bootable * @@ -2439,6 +2531,18 @@ void el_torito_set_load_size(ElToritoBootImage *bootimg, short sectors); */ void el_torito_set_no_bootable(ElToritoBootImage *bootimg); +/** + * Get the bootability flag. See el_torito_set_no_bootable(). + * + * @param bootimg + * The image to inquire + * @return + * 0 = not bootable, 1 = bootable , <0 = error + * + * @since 0.6.32 + */ +int el_torito_get_bootable(ElToritoBootImage *bootimg); + /** * Specifies that this image needs to be patched. This involves the writing * of a 56 bytes boot information table at offset 8 of the boot image file. @@ -2454,6 +2558,10 @@ void el_torito_patch_isolinux_image(ElToritoBootImage *bootimg); * Specifies options for ISOLINUX or GRUB boot images. This should only be used * if the type of boot image is known. * + * Regrettably there is no unambigous way to detect the presence of a boot + * info table in a boot image or the relation of a boot image to the System + * Area and its eventual MBR. + * * @param options * bitmask style flag. The following values are defined: * @@ -5479,6 +5587,9 @@ int iso_md5_match(char first_md5[16], char second_md5[16]); /** Trying to use an invalid file as boot image (FAILURE,HIGH, -68) */ #define ISO_BOOT_IMAGE_NOT_VALID 0xE830FFBB +/** Too many boot images (FAILURE,HIGH, -69) */ +#define ISO_BOOT_IMAGE_OVERFLOW 0xE830FFBA + /** * Error on file operation (FAILURE,HIGH, -128) * (take a look at more specified error codes below) diff --git a/libisofs/messages.c b/libisofs/messages.c index 75674dc..1ec8bfe 100644 --- a/libisofs/messages.c +++ b/libisofs/messages.c @@ -153,6 +153,8 @@ const char *iso_error_to_msg(int errcode) return "Try to set the boot image of an already bootable image"; case ISO_BOOT_IMAGE_NOT_VALID: return "Trying to use an invalid file as boot image"; + case ISO_BOOT_IMAGE_OVERFLOW: + return "Too many boot images added"; case ISO_FILE_ERROR: return "Error on file operation"; case ISO_FILE_ALREADY_OPENED: diff --git a/libisofs/system_area.c b/libisofs/system_area.c index 24beaee..e1d332a 100644 --- a/libisofs/system_area.c +++ b/libisofs/system_area.c @@ -134,11 +134,11 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) memcpy(buf, t->system_area_data, 16 * BLOCK_SIZE); } else if (t->catalog != NULL && - (t->catalog->image->isolinux_options & 0x0a) == 0x02) { + (t->catalog->bootimages[0]->isolinux_options & 0x0a) == 0x02) { /* Check for isolinux image with magic number of 3.72 and produce an MBR from our built-in template. (Deprecated since 31 Mar 2010) */ - ret = make_isohybrid_mbr(t->bootimg->sections[0].block, + ret = make_isohybrid_mbr(t->bootsrc[0]->sections[0].block, &img_blocks, (char*)buf, 0); if (ret != 1) { /* error, it should never happen */ @@ -159,7 +159,7 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) */ return ISO_ISOLINUX_CANT_PATCH; } - ret = make_isolinux_mbr(&img_blocks, t->bootimg->sections[0].block, + ret = make_isolinux_mbr(&img_blocks, t->bootsrc[0]->sections[0].block, (uint32_t) 0, 64, 32, 0, 1, 0x17, buf, 1); if (ret != 1) return ret;