Provisory new pseudo path for El Torito boot images:

--interval:appened_partition_N:all::
This commit is contained in:
Thomas Schmitt 2015-12-30 18:56:32 +01:00
parent 93f3cb1823
commit ec35bb21c0
7 changed files with 220 additions and 60 deletions

View File

@ -104,6 +104,8 @@ void ecma119_image_free(Ecma119Image *t)
free(t->output_charset);
if (t->bootsrc != NULL)
free(t->bootsrc);
if (t->boot_appended_idx != NULL)
free(t->boot_appended_idx);
if (t->system_area_data != NULL)
free(t->system_area_data);
if (t->checksum_ctx != NULL) { /* dispose checksum context */
@ -567,8 +569,13 @@ int ecma119_writer_write_vol_desc(IsoImageWriter *writer)
vol.vol_desc_version[0] = 1;
strncpy_pad((char*)vol.system_id, system_id, 32);
strncpy_pad((char*)vol.volume_id, vol_id, 32);
iso_bb(vol.vol_space_size, t->vol_space_size - t->eff_partition_offset,
4);
if (t->pvd_size_is_total_size) {
iso_bb(vol.vol_space_size,
t->total_size / 2048 - t->eff_partition_offset, 4);
} else {
iso_bb(vol.vol_space_size,
t->vol_space_size - t->eff_partition_offset, 4);
}
iso_bb(vol.vol_set_size, (uint32_t) 1, 2);
iso_bb(vol.vol_seq_number, (uint32_t) 1, 2);
iso_bb(vol.block_size, (uint32_t) BLOCK_SIZE, 2);
@ -2376,12 +2383,16 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *in_opts, Ecma119Image **img)
target->num_bootsrc = target->catalog->num_bootimages;
target->bootsrc = calloc(target->num_bootsrc + 1,
sizeof(IsoFileSrc *));
if (target->bootsrc == NULL) {
target->boot_appended_idx = calloc(target->num_bootsrc + 1,
sizeof(int));
if (target->bootsrc == NULL || target->boot_appended_idx == NULL) {
ret = ISO_OUT_OF_MEM;
goto target_cleanup;
}
for (i= 0; i < target->num_bootsrc; i++)
for (i= 0; i < target->num_bootsrc; i++) {
target->bootsrc[i] = NULL;
target->boot_appended_idx[i] = -1;
}
} else {
target->num_bootsrc = 0;
target->bootsrc = NULL;
@ -2448,6 +2459,10 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *in_opts, Ecma119Image **img)
goto target_cleanup;
}
target->total_size = 0;
target->vol_space_size = 0;
target->pvd_size_is_total_size = 0;
target->checksum_idx_counter = 0;
target->checksum_ctx = NULL;
target->checksum_counter = 0;

View File

@ -554,10 +554,19 @@ struct ecma119_image
time_t now; /**< Time at which writing began. */
/** Total size of the output. This only includes the current volume. */
/* Total size of the output. Counted in bytes.
* Includes ISO filesystem and appended data.
*/
off_t total_size;
/** Size actually governed by the ISO filesystem part of the output */
uint32_t vol_space_size;
/* 1= write the total size into the PVD of the ISO,
* 0= write vol_space_size
*/
int pvd_size_is_total_size;
/* Bytes already written to image output */
off_t bytes_written;
/* just for progress notification */
@ -640,6 +649,8 @@ struct ecma119_image
int num_bootsrc;
IsoFileSrc **bootsrc; /* location of the boot images in the new image */
int *boot_appended_idx; /* Appended partition which serve as boot images */
/*
* System Area related information
*/

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2007 Vreixo Formoso
* Copyright (c) 2010 - 2014 Thomas Schmitt
* Copyright (c) 2010 - 2015 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
@ -19,6 +19,7 @@
#include "image.h"
#include "messages.h"
#include "writer.h"
#include "ecma119.h"
#include <stdlib.h>
#include <string.h>
@ -323,36 +324,61 @@ int create_image(IsoImage *image, const char *image_path,
struct el_torito_boot_image *boot;
int boot_media_type = 0;
int load_sectors = 0; /* number of sector to load */
int part_idx = -1;
unsigned char partition_type = 0;
off_t size;
IsoNode *imgfile;
IsoStream *stream;
IsoNode *imgfile = NULL;
IsoStream *stream = NULL;
*bootnode = NULL;
ret = iso_tree_path_to_node(image, image_path, &imgfile);
if (ret < 0) {
return ret;
}
if (ret == 0) {
iso_msg_submit(image->id, ISO_NODE_DOESNT_EXIST, 0,
if (strncmp(image_path, "--interval:appended_partition_", 30) == 0) {
/* --interval:appended_partition_N... */
if (type != ELTORITO_NO_EMUL) {
/* >>> ??? lift this ban by making a temporary IsoStream from
partition source, determine size,
and read ELTORITO_HARD_DISC_EMUL MBR ?
*/
iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
"Appended partition cannot serve as El Torito boot image with FD/HD emulation");
return ISO_BOOT_IMAGE_NOT_VALID;
}
sscanf(image_path + 30, "%d", &part_idx);
if (part_idx < 1 || part_idx > ISO_MAX_PARTITIONS) {
iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
"Appended partition index for El Torito boot image is out of range");
return ISO_BOOT_IMAGE_NOT_VALID;
}
part_idx--;
size = 1;
} else {
ret = iso_tree_path_to_node(image, image_path, &imgfile);
if (ret < 0) {
return ret;
}
if (ret == 0) {
iso_msg_submit(image->id, ISO_NODE_DOESNT_EXIST, 0,
"El Torito boot image file missing in ISO image: '%s'",
image_path);
return ISO_NODE_DOESNT_EXIST;
return ISO_NODE_DOESNT_EXIST;
}
if (imgfile->type != LIBISO_FILE) {
return ISO_BOOT_IMAGE_NOT_VALID;
}
*bootnode = (IsoFile *) imgfile;
stream = ((IsoFile*)imgfile)->stream;
/* we need to read the image at least two times */
if (!iso_stream_is_repeatable(stream)) {
return ISO_BOOT_IMAGE_NOT_VALID;
}
size = iso_stream_get_size(stream);
}
if (imgfile->type != LIBISO_FILE) {
return ISO_BOOT_IMAGE_NOT_VALID;
}
*bootnode = (IsoFile *) imgfile;
stream = ((IsoFile*)imgfile)->stream;
/* we need to read the image at least two times */
if (!iso_stream_is_repeatable(stream)) {
return ISO_BOOT_IMAGE_NOT_VALID;
}
size = iso_stream_get_size(stream);
if (size <= 0) {
iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
"Boot image file is empty");
@ -441,7 +467,9 @@ int create_image(IsoImage *image, const char *image_path,
return ISO_OUT_OF_MEM;
}
boot->image = (IsoFile*)imgfile;
iso_node_ref(imgfile); /* get our ref */
boot->appended_idx = part_idx;
if (imgfile != NULL)
iso_node_ref(imgfile); /* get our ref */
boot->bootable = 1;
boot->seems_boot_info_table = 0;
boot->seems_grub2_boot_info = 0;
@ -538,8 +566,9 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path,
catalog->bootimages[i] = NULL;
catalog->node = cat_node;
catalog->sort_weight = 1000000000; /* very high */
if (!(boot_node->explicit_weight || boot_node->from_old_session))
boot_node->sort_weight = 2;
if (boot_node != NULL)
if (!(boot_node->explicit_weight || boot_node->from_old_session))
boot_node->sort_weight = 2;
iso_node_ref((IsoNode*)cat_node);
image->bootcat = catalog;
@ -555,7 +584,8 @@ boot_image_cleanup:;
iso_node_unref((IsoNode*)cat_node);
}
if (boot_image) {
iso_node_unref((IsoNode*)boot_image->image);
if (boot_image->image != NULL)
iso_node_unref((IsoNode*)boot_image->image);
free(boot_image);
}
return ret;
@ -719,8 +749,9 @@ int iso_image_add_boot_image(IsoImage *image, const char *image_path,
ret = create_image(image, image_path, type, &boot_img, &boot_node);
if (ret < 0)
return ret;
if (!(boot_node->explicit_weight || boot_node->from_old_session))
boot_node->sort_weight = 2;
if (boot_node != NULL)
if (!(boot_node->explicit_weight || boot_node->from_old_session))
boot_node->sort_weight = 2;
catalog->bootimages[catalog->num_bootimages] = boot_img;
catalog->num_bootimages++;
if (boot != NULL)
@ -827,12 +858,13 @@ write_section_header(uint8_t *buf, Ecma119Image *t, int idx, int num_entries)
* Usable for the Default Entry
* and for Section Entries with Selection criteria type == 0
*/
static void
write_section_entry(uint8_t *buf, Ecma119Image *t, int idx)
static
int 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;
int app_idx;
img = t->catalog->bootimages[idx];
@ -840,16 +872,37 @@ write_section_entry(uint8_t *buf, Ecma119Image *t, int idx)
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->bootsrc[idx]->sections[0].block, 4);
if (t->boot_appended_idx[idx] >= 0) {
app_idx = t->boot_appended_idx[idx];
if (t->appended_part_size[app_idx] * 4 > 65535) {
if (img->platform_id == 0xef)
iso_lsb(se->sec_count, 0, 2);
else
iso_lsb(se->sec_count, 65535, 2);
} else {
if (t->appended_part_size[app_idx] == 0) {
iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
"Appended partition which shall serve as boot image does not exist");
return ISO_BOOT_IMAGE_NOT_VALID;
}
iso_lsb(se->sec_count, t->appended_part_size[app_idx] * 4, 2);
}
iso_lsb(se->block, t->appended_part_start[app_idx], 4);
} else {
iso_lsb(se->sec_count, img->load_size, 2);
iso_lsb(se->block, t->bootsrc[idx]->sections[0].block, 4);
}
se->selec_criteria[0] = img->selection_crit[0];
memcpy(se->vendor_sc, img->selection_crit + 1, 19);
return ISO_SUCCESS;
}
static
int catalog_open(IsoStream *stream)
{
int i, j, k, num_entries;
int i, j, k, num_entries, ret;
struct catalog_stream *data;
uint8_t *wpt;
struct el_torito_boot_catalog *cat;
@ -873,7 +926,9 @@ int catalog_open(IsoStream *stream)
boots[0]->platform_id, boots[0]->id_string);
/* write default entry = first boot image */
write_section_entry(data->buffer + 32, data->target, 0);
ret = write_section_entry(data->buffer + 32, data->target, 0);
if (ret < 0)
return ret;
/* IMPORTANT: The maximum number of boot images must fit into BLOCK_SIZE */
wpt = data->buffer + 64;
@ -894,7 +949,9 @@ int catalog_open(IsoStream *stream)
write_section_header(wpt, data->target, i, num_entries);
wpt += 32;
for (j = 0; j < num_entries; j++) {
write_section_entry(wpt, data->target, i);
ret = write_section_entry(wpt, data->target, i);
if (ret < 0)
return ret;
wpt += 32;
i++;
}
@ -1132,6 +1189,9 @@ int patch_boot_info_table(uint8_t *buf, Ecma119Image *t,
return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
"Isolinux image too small. We won't patch it.");
}
if (t->bootsrc[idx] == NULL)
return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
"Cannot apply ISOLINUX patching outside of ISO 9660 filesystem.");
ret = make_boot_info_table(buf, t->opts->ms_block + (uint32_t) 16,
t->bootsrc[idx]->sections[0].block,
(uint32_t) imgsize);
@ -1151,7 +1211,10 @@ int patch_grub2_boot_image(uint8_t *buf, Ecma119Image *t,
if (imgsize < pos + 8)
return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
"Isolinux image too small for GRUB2. Will not patch it.");
"Boot image too small for GRUB2. Will not patch it.");
if (t->bootsrc[idx] == NULL)
return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
"Cannot apply GRUB2 patching outside of ISO 9660 filesystem.");
blk = ((uint64_t) t->bootsrc[idx]->sections[0].block) * 4 + offst;
iso_lsb((buf + pos), blk & 0xffffffff, 4);
iso_lsb((buf + pos + 4), blk >> 32, 4);
@ -1174,6 +1237,10 @@ int iso_patch_eltoritos(Ecma119Image *t)
for (idx = 0; idx < t->catalog->num_bootimages; idx++) {
if (!(t->catalog->bootimages[idx]->isolinux_options & 0x201))
continue;
if (t->bootsrc[idx] == NULL)
return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
"Cannot apply boot image patching outside of ISO 9660 filesystem");
original = t->bootsrc[idx]->stream;
size = (size_t) iso_stream_get_size(original);
if (size > Libisofs_elto_max_patchablE)
@ -1281,8 +1348,8 @@ int eltorito_writer_create(Ecma119Image *target)
{
int ret, idx, outsource_efi = 0;
IsoImageWriter *writer;
IsoFile *bootimg;
IsoFileSrc *src;
IsoFile *bootimg = NULL;
IsoFileSrc *src = NULL;
writer = calloc(1, sizeof(IsoImageWriter));
if (writer == NULL) {
@ -1315,6 +1382,19 @@ int eltorito_writer_create(Ecma119Image *target)
if (strcmp(target->opts->efi_boot_partition, "--efi-boot-image") == 0)
outsource_efi = 1;
for (idx = 0; idx < target->catalog->num_bootimages; idx++) {
target->bootsrc[idx] = NULL;
if (target->catalog->bootimages[idx]->appended_idx >= 0) {
/* Use an appended partition as boot image rather than IsoFile */
target->boot_appended_idx[idx] =
target->catalog->bootimages[idx]->appended_idx;
if (((target->system_area_options >> 2) & 0x3f) == 0 &&
(target->system_area_options & 3) == 1) {
/* ISO will not be a partition. It can span the whole image. */
target->pvd_size_is_total_size = 1;
}
continue;
}
bootimg = target->catalog->bootimages[idx]->image;
ret = iso_file_src_create(target, bootimg, &src);
if (ret < 0) {

View File

@ -53,6 +53,9 @@ struct el_torito_boot_catalog {
struct el_torito_boot_image {
IsoFile *image;
/* Overrides .image if >= 0 : array index of appended partition */
int appended_idx;
unsigned int bootable:1; /**< If the entry is bootable. */
/**
* Whether the boot image seems to contain a boot_info_table

View File

@ -3402,6 +3402,9 @@ int iso_image_get_pvd_times(IsoImage *image,
* returns an error and the image remains unmodified.
* @param image_path
* The absolute path of a IsoFile to be used as default boot image.
>>> or --interval:appended_partition_$number...
* @param type
* The boot media type. This can be one of 3 types:
* - Floppy emulation: Boot image file must be exactly
@ -3443,7 +3446,10 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path,
* 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.
* The absolute path of a IsoFile to be used as boot image.
>>> or --interval:appended_partition_$number...
* @param type
* The boot media type. See iso_image_set_boot_image
* @param flag
@ -3488,6 +3494,9 @@ int iso_image_add_boot_image(IsoImage *image, const char *image_path,
* @param imgnode
* When not NULL, it will be filled with the image tree node. No extra ref
* is added, you can use iso_node_ref() to get one if you need it.
>>> The returned value is NULL if the boot image source is no IsoFile.
* @param catnode
* When not NULL, it will be filled with the catnode tree node. No extra
* ref is added, you can use iso_node_ref() to get one if you need it.
@ -3545,6 +3554,11 @@ int iso_image_get_bootcat(IsoImage *image, IsoBoot **catnode, uint32_t *lba,
* @param bootnodes
* Returns NULL or an allocated array of pointers to the IsoFile nodes
* which bear the content of the boot images in boots.
>>> An array entry is NULL if the boot image source is no IsoFile.
>>> Need getter for partition index
* @param flag
* Bitfield for control purposes. Unused yet. Submit 0.
* @return

View File

@ -37,6 +37,8 @@
#include "ecma119.h"
#include "eltorito.h"
#include "system_area.h"
#include "image.h"
#include "messages.h"
/* This code stems from syslinux-3.72/utils/isohybrid, a perl script
@ -60,7 +62,7 @@ license from above stem licenses, typically from LGPL.
In case its generosity is needed, here is the 2-clause BSD license:
make_isohybrid_mbr.c is copyright 2002-2008 H. Peter Anvin
and 2008-2014 Thomas Schmitt
and 2008-2015 Thomas Schmitt
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
@ -408,6 +410,7 @@ int assess_isohybrid_gpt_apm(Ecma119Image *t, int *gpt_count, int gpt_idx[128],
{
int i, ilx_opts, j, ret, num_img;
uint32_t block_count;
uint64_t start_block;
uint8_t gpt_name[72];
static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uint8_t basic_data_uuid[16] = {
@ -430,11 +433,13 @@ int assess_isohybrid_gpt_apm(Ecma119Image *t, int *gpt_count, int gpt_idx[128],
num_img = 0;
for (i = 0; i < num_img; i++) {
ilx_opts = t->catalog->bootimages[i]->isolinux_options;
if (((ilx_opts >> 2) & 63) == 1 || ((ilx_opts >> 2) & 63) == 2) {
if ((((ilx_opts >> 2) & 63) == 1 || ((ilx_opts >> 2) & 63) == 2) &&
!(t->boot_appended_idx[i] >= 0 && t->opts->appended_as_gpt)) {
if (*gpt_count < 128)
gpt_idx[*gpt_count]= i;
(*gpt_count)++;
if ((flag & 1) && t->bootsrc[i] != NULL) {
if ((flag & 1) &&
(t->bootsrc[i] != NULL || t->boot_appended_idx[i] >= 0)) {
/* Register GPT entry */
memset(gpt_name, 0, 72);
sprintf((char *) gpt_name, "ISOHybrid%d", *gpt_count);
@ -443,13 +448,21 @@ int assess_isohybrid_gpt_apm(Ecma119Image *t, int *gpt_count, int gpt_idx[128],
uuid = hfs_uuid;
else
uuid = basic_data_uuid;
block_count = 0;
for (j = 0; j < t->bootsrc[i]->nsections; j++)
block_count += t->bootsrc[i]->sections[j].size / 2048;
if (t->boot_appended_idx[i] >= 0) {
block_count = t->appended_part_size[
t->boot_appended_idx[i]];
start_block = ((uint64_t) t->appended_part_start[
t->boot_appended_idx[i]]) * 4;
} else {
block_count = 0;
for (j = 0; j < t->bootsrc[i]->nsections; j++)
block_count += t->bootsrc[i]->sections[j].size / 2048;
start_block = ((uint64_t) t->bootsrc[i]->sections[0].block)
* 4;
}
ret = iso_quick_gpt_entry(
t->gpt_req, &(t->gpt_req_count),
((uint64_t) t->bootsrc[i]->sections[0].block) * 4,
((uint64_t) block_count) * 4,
start_block, ((uint64_t) block_count) * 4,
uuid, zero_uuid, gpt_flags, (uint8_t *) gpt_name);
if (ret < 0)
return ret;
@ -457,13 +470,22 @@ int assess_isohybrid_gpt_apm(Ecma119Image *t, int *gpt_count, int gpt_idx[128],
}
if ((ilx_opts & 256) && !(flag & 2)) {
(*apm_count)++;
if ((flag & 1) && t->bootsrc[i] != NULL) {
if ((flag & 1) &&
(t->bootsrc[i] != NULL || t->boot_appended_idx[i] >= 0)) {
/* Register APM entry */
block_count = 0;
for (j = 0; j < t->bootsrc[i]->nsections; j++)
block_count += t->bootsrc[i]->sections[j].size / 2048;
if (t->boot_appended_idx[i] >= 0) {
block_count = t->appended_part_size[
t->boot_appended_idx[i]];
start_block = t->appended_part_start[
t->boot_appended_idx[i]];
} else {
block_count = 0;
for (j = 0; j < t->bootsrc[i]->nsections; j++)
block_count += t->bootsrc[i]->sections[j].size / 2048;
start_block = t->bootsrc[i]->sections[0].block;
}
ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
t->bootsrc[i]->sections[0].block,
(uint32_t) start_block,
block_count, "EFI", "Apple_HFS");
if (ret < 0)
return ret;
@ -546,13 +568,18 @@ static int gpt_images_as_mbr_partitions(Ecma119Image *t, char *wpt,
0xfe, 0xff, 0xff,
};
if (t->bootsrc[gpt_idx[*gpt_cursor]] == NULL) {
(*gpt_cursor)++;
return 2;
}
wpt[0] = 0;
memcpy(wpt + 1, dummy_chs, 3);
ilx_opts = t->catalog->bootimages[gpt_idx[*gpt_cursor]]->isolinux_options;
if (((ilx_opts >> 2) & 63) == 2)
wpt[4] = 0x00; /* HFS gets marked as "Empty" */
else
((unsigned char *) wpt)[4] = 0xef; /* "EFI (FAT-12/16/" */
((unsigned char *) wpt)[4] = 0xef; /* "EFI (FAT-12/16)" */
memcpy(wpt + 5, dummy_chs, 3);
@ -589,6 +616,10 @@ int make_isolinux_mbr(uint32_t *img_blocks, Ecma119Image *t,
struct timeval tv;
struct timezone tz;
if (t->bootsrc[0] == NULL)
return iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
"Cannot refer by isohybrid MBR to data outside of ISO 9660 filesystem.");
if (flag & 2) {
part_number = 1;
part_offset = 1;

View File

@ -1820,6 +1820,9 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf)
/* Check for isolinux image with magic number of 3.72 and produce
an MBR from our built-in template. (Deprecated since 31 Mar 2010)
*/
if (t->bootsrc[0] == NULL)
return iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
"Cannot refer by isohybrid MBR to data outside of ISO 9660 filesystem.");
if (img_blocks < 0x80000000) {
int_img_blocks= img_blocks;
} else {
@ -2062,6 +2065,9 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf)
if (sa_type == 0 && (t->system_area_options & 0x4000) && !do_isohybrid) {
/* Patch MBR for GRUB2 */
if (t->bootsrc[0] == NULL)
return iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
"Cannot refer by GRUB2 MBR to data outside of ISO 9660 filesystem.");
blk = t->bootsrc[0]->sections[0].block * 4 +
Libisofs_grub2_mbr_patch_offsT;
wpt = buf + Libisofs_grub2_mbr_patch_poS;