Making an educated guess whether the boot images contain a boot info table.

New API call el_torito_seems_boot_info_table() publishes this guess.
This commit is contained in:
Thomas Schmitt 2010-04-29 15:10:18 +02:00
parent 3d9367d52a
commit e4cf93665a
4 changed files with 252 additions and 25 deletions

View File

@ -153,8 +153,14 @@ int el_torito_get_selection_crit(ElToritoBootImage *bootimg, uint8_t crit[20])
return 1;
}
/* API */
int el_torito_seems_boot_info_table(ElToritoBootImage *bootimg, int flag)
{
return bootimg->seems_boot_info_table;
}
/**
* Specifies that this image needs to be patched. This involves the writting
* 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.
* The original boot image file won't be modified.
* This is needed for isolinux boot images.
@ -173,7 +179,7 @@ void el_torito_patch_isolinux_image(ElToritoBootImage *bootimg)
* bitmask style flag. The following values are defined:
*
* bit 0 -> 1 to path the image, 0 to not
* Patching the image involves the writting of a 56 bytes
* Patching the image involves the writing of a 56 bytes
* boot information table at offset 8 of the boot image file.
* The original boot image file won't be modified. This is needed
* to allow isolinux images to be bootable.
@ -405,6 +411,7 @@ int create_image(IsoImage *image, const char *image_path,
boot->image = (IsoFile*)imgfile;
iso_node_ref(imgfile); /* get our ref */
boot->bootable = 1;
boot->seems_boot_info_table = 0;
boot->isolinux_options = 0;
boot->type = boot_media_type;
boot->partition_type = partition_type;
@ -677,10 +684,12 @@ void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat)
image = cat->bootimages[i];
if (image == NULL)
continue;
iso_node_unref((IsoNode*)image->image);
if ((IsoNode*)image->image != NULL)
iso_node_unref((IsoNode*)image->image);
free(image);
}
iso_node_unref((IsoNode*)cat->node);
if ((IsoNode*)cat->node != NULL)
iso_node_unref((IsoNode*)cat->node);
free(cat);
}
@ -981,6 +990,50 @@ int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src)
/******************* EL-TORITO WRITER *******************************/
/**
* Insert boot info table content into buf.
*
* @return
* 1 on success, 0 error (but continue), < 0 error
*/
int make_boot_info_table(uint8_t *buf, uint32_t pvd_lba,
uint32_t boot_lba, uint32_t imgsize)
{
struct boot_info_table *info;
uint32_t checksum;
uint32_t offset;
info = (struct boot_info_table *) (buf + 8);
if (imgsize < 64)
return ISO_ISOLINUX_CANT_PATCH;
/* compute checksum, as the the sum of all 32 bit words in boot image
* from offset 64 */
checksum = 0;
offset = 64;
while (offset <= imgsize - 4) {
checksum += iso_read_lsb(buf + offset, 4);
offset += 4;
}
if (offset != imgsize) {
/*
* file length not multiple of 4
* empty space in isofs is padded with zero;
* assume same for last dword
*/
checksum += iso_read_lsb(buf + offset, imgsize - offset);
}
/*memset(info, 0, sizeof(struct boot_info_table));*/
iso_lsb(info->bi_pvd, pvd_lba, 4);
iso_lsb(info->bi_file, boot_lba, 4);
iso_lsb(info->bi_length, imgsize, 4);
iso_lsb(info->bi_csum, checksum, 4);
memset(buf + 24, 0, 40);
return ISO_SUCCESS;
}
/**
* Patch an isolinux boot image.
*
@ -990,6 +1043,24 @@ int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src)
static
int patch_boot_image(uint8_t *buf, Ecma119Image *t, size_t imgsize, int idx)
{
/* >>> ts B00428 BOOT : make this the default case */
#define Libisofs_new_patch_boot_imagE 1
#ifdef Libisofs_new_patch_boot_imagE
int ret;
if (imgsize < 64) {
return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
"Isolinux image too small. We won't patch it.");
}
ret = make_boot_info_table(buf, t->ms_block + (uint32_t) 16,
t->bootsrc[idx]->sections[0].block,
(uint32_t) imgsize);
return ret;
#else /* Libisofs_new_patch_boot_imagE */
struct boot_info_table *info;
uint32_t checksum;
size_t offset;
@ -1024,7 +1095,11 @@ int patch_boot_image(uint8_t *buf, Ecma119Image *t, size_t imgsize, int idx)
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);
memset(buf + 24, 0, 40);
return ISO_SUCCESS;
#endif /* ! Libisofs_new_patch_boot_imagE */
}
static
@ -1054,6 +1129,10 @@ int eltorito_writer_compute_data_blocks(IsoImageWriter *writer)
continue;
original = t->bootsrc[idx]->stream;
size = (size_t) iso_stream_get_size(original);
/* >>> BOOT ts B00428 :
check whether size is not too large for buffering */;
buf = calloc(1, size);
if (buf == NULL) {
return ISO_OUT_OF_MEM;

View File

@ -48,6 +48,10 @@ struct el_torito_boot_image {
IsoFile *image;
unsigned int bootable:1; /**< If the entry is bootable. */
/**
* Whether the boot image seems to contain a boot_info_table
*/
unsigned int seems_boot_info_table:1;
/**
* isolinux options
* bit 0 -> whether to patch image
@ -126,4 +130,14 @@ int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src);
*/
int eltorito_writer_create(Ecma119Image *target);
/**
* Insert boot info table content into buf.
*
* @return
* 1 on success, 0 error (but continue), < 0 error
*/
int make_boot_info_table(uint8_t *buf, uint32_t pvd_lba,
uint32_t boot_lba, uint32_t imgsize);
#endif /* LIBISO_ELTORITO_H */

View File

@ -2121,19 +2121,15 @@ int read_root_susp_entries(_ImageFsData *data, uint32_t block)
}
static
int read_pvm(_ImageFsData *data, uint32_t block)
int read_pvd_block(IsoDataSource *src, uint32_t block, uint8_t *buffer,
uint32_t *image_size)
{
int ret;
struct ecma119_pri_vol_desc *pvm;
struct ecma119_dir_record *rootdr;
uint8_t buffer[BLOCK_SIZE];
/* read PVM */
ret = data->src->read_block(data->src, block, buffer);
if (ret < 0) {
ret = src->read_block(src, block, buffer);
if (ret < 0)
return ret;
}
pvm = (struct ecma119_pri_vol_desc *)buffer;
/* sanity checks */
@ -2143,8 +2139,24 @@ int read_pvm(_ImageFsData *data, uint32_t block)
return ISO_WRONG_PVD;
}
if (image_size != NULL)
*image_size = iso_read_bb(pvm->vol_space_size, 4, NULL);
return ISO_SUCCESS;
}
static
int read_pvm(_ImageFsData *data, uint32_t block)
{
int ret;
struct ecma119_pri_vol_desc *pvm;
struct ecma119_dir_record *rootdr;
uint8_t buffer[BLOCK_SIZE];
ret = read_pvd_block(data->src, block, buffer, NULL);
if (ret < 0)
return ret;
/* ok, it is a valid PVD */
pvm = (struct ecma119_pri_vol_desc *)buffer;
/* fill volume attributes */
/* TODO take care of input charset */
@ -2206,6 +2218,7 @@ int read_el_torito_boot_catalog(_ImageFsData *data, uint32_t block)
struct el_torito_section_entry *entry; /* also usable as default_entry */
unsigned char buffer[BLOCK_SIZE];
data->num_bootimgs = 0;
ret = data->src->read_block(data->src, block, buffer);
if (ret < 0) {
return ret;
@ -2281,7 +2294,6 @@ int read_el_torito_boot_catalog(_ImageFsData *data, uint32_t block)
}
}
after_bootblocks:;
return ISO_SUCCESS;
}
@ -3005,6 +3017,105 @@ boot_fs_cleanup: ;
return ret;
}
/** ??? ts B00428 : should the max size become public ? */
#define Libisofs_boot_image_max_sizE (4096*1024)
/** ts B00428 BOOT : perform boot-info-table detection
*/
static
int iso_image_eval_boot_info_table(IsoImage *image, struct iso_read_opts *opts,
IsoDataSource *src, uint32_t iso_image_size, int flag)
{
int i, ret, section_count, todo, chunk;
uint32_t img_lba, img_size, boot_pvd_found, image_pvd, alleged_size;
struct iso_file_section *sections = NULL;
struct el_torito_boot_image *boot;
uint8_t *boot_image_buf = NULL, boot_info_found[16], buf[BLOCK_SIZE];
IsoStream *stream = NULL;
IsoFile *boot_file;
if (image->bootcat == NULL)
return ISO_SUCCESS;
for (i = 0; i < image->bootcat->num_bootimages; i++) {
boot = image->bootcat->bootimages[i];
boot_file = boot->image;
boot->seems_boot_info_table = 0;
img_size = iso_file_get_size(boot_file);
if (img_size > Libisofs_boot_image_max_sizE || img_size < 64)
continue;
img_lba = 0;
sections = NULL;
ret = iso_file_get_old_image_sections(boot_file,
&section_count, &sections, 0);
if (ret == 1 && section_count > 0)
img_lba = sections[0].block;
if (sections != NULL) {
free(sections);
sections = NULL;
}
if(img_lba == 0)
continue;
boot_image_buf = calloc(1, img_size);
if (boot_image_buf == NULL) {
ret = ISO_OUT_OF_MEM;
goto ex;
}
stream = iso_file_get_stream(boot_file);
ret = iso_stream_open(stream);
if (ret < 0) {
stream = NULL;
goto ex;
}
for (todo = img_size; todo > 0; ) {
if (todo > BLOCK_SIZE)
chunk = BLOCK_SIZE;
else
chunk = todo;
ret = iso_stream_read(stream, boot_image_buf + (img_size - todo),
chunk);
if (ret != chunk) {
ret = (ret < 0) ? ret : ISO_FILE_READ_ERROR;
goto ex;
}
todo -= chunk;
}
iso_stream_close(stream);
stream = NULL;
memcpy(boot_info_found, boot_image_buf + 8, 16);
boot_pvd_found = iso_read_lsb(boot_info_found, 4);
image_pvd = (uint32_t) (opts->block + 16);
/* Accomodate to eventually relocated superblock */
if (image_pvd != boot_pvd_found &&
image_pvd == 16 && boot_pvd_found < iso_image_size) {
/* Check whether there is a PVD at boot_pvd_found
and whether it bears the same image size
*/
ret = read_pvd_block(src, boot_pvd_found, buf, &alleged_size);
if (ret == 1 &&
alleged_size + boot_pvd_found == iso_image_size + image_pvd)
image_pvd = boot_pvd_found;
}
ret = make_boot_info_table(boot_image_buf, image_pvd,
img_lba, img_size);
if (ret < 0)
goto ex;
if (memcmp(boot_image_buf + 8, boot_info_found, 16) == 0)
boot->seems_boot_info_table = 1;
free(boot_image_buf);
boot_image_buf = NULL;
}
ret = 1;
ex:;
if (boot_image_buf != NULL)
free(boot_image_buf);
if (stream != NULL)
iso_stream_close(stream);
return ret;
}
int iso_image_import(IsoImage *image, IsoDataSource *src,
struct iso_read_opts *opts,
@ -3140,6 +3251,7 @@ int iso_image_import(IsoImage *image, IsoDataSource *src,
ret = ISO_OUT_OF_MEM;
goto import_revert;
}
boot_image->image = NULL;
boot_image->bootable = data->boot_flags[idx] & 1;
boot_image->type = data->media_types[idx];
boot_image->partition_type = data->partition_types[idx];
@ -3314,6 +3426,11 @@ int iso_image_import(IsoImage *image, IsoDataSource *src,
#endif /* Libisofs_with_checksumS */
/* ts B00428 */
ret = iso_image_eval_boot_info_table(image, opts, src, data->nblocks, 0);
if (ret < 0)
goto import_revert;
ret = ISO_SUCCESS;
goto import_cleanup;

View File

@ -2631,35 +2631,41 @@ int el_torito_set_selection_crit(ElToritoBootImage *bootimg, uint8_t crit[20]);
*/
int el_torito_get_selection_crit(ElToritoBootImage *bootimg, uint8_t crit[20]);
/**
* 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.
* The original boot image file won't be modified.
* This is needed for isolinux boot images.
* Makes a guess whether the boot image was patched by a boot information
* table. It is advisable to patch such boot images if their content gets
* copied to a new location. See el_torito_set_isolinux_options().
* Note: The reply can be positive only if the boot image was imported
* from an existing ISO image.
*
* @since 0.6.2
* @deprecated Use el_torito_set_isolinux_options() instead
* @param bootimg
* The image to inquire
* @return
* 1 = seems to contain oot info table , 0 = quite surely not
* @since 0.6.32
*/
void el_torito_patch_isolinux_image(ElToritoBootImage *bootimg);
int el_torito_seems_boot_info_table(ElToritoBootImage *bootimg, int flag);
/**
* 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:
*
* bit 0 -> 1 to patch the boot info table of the boot image.
* 1 does the same as mkisofs option -boot-info-table.
* Needed for ISOLINUX and for GRUB rescue boot images.
* Needed for ISOLINUX or GRUB boot images with platform ID 0.
* The table is located at byte 8 of the boot image file.
* Its size is 56 bytes.
* The original boot image file on disk will not be modified.
*
* One may use el_torito_seems_boot_info_table() for a
* qualified guess whether a boot info table is present in
* the boot image. If the result is 1 then it should get bit0
* set if its content gets copied to a new LBA.
*
* bit 1 -> 1 to generate a ISOLINUX isohybrid image with MBR.
* ----------------------------------------------------------
* @deprecated since 31 Mar 2010:
@ -2695,6 +2701,17 @@ int el_torito_set_isolinux_options(ElToritoBootImage *bootimg,
*/
int el_torito_get_isolinux_options(ElToritoBootImage *bootimg, int flag);
/** Deprecated:
* Specifies that this image needs to be patched. This involves the writing
* of a 16 bytes boot information table at offset 8 of the boot image file.
* The original boot image file won't be modified.
* This is needed for isolinux boot images.
*
* @since 0.6.2
* @deprecated Use el_torito_set_isolinux_options() instead
*/
void el_torito_patch_isolinux_image(ElToritoBootImage *bootimg);
/**
* Obtain a copy of the eventually loaded first 32768 bytes of the imported
* session, the System Area.