diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index 9911345..cdee22a 100644 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -1108,7 +1108,35 @@ int zero_writer_free_data(IsoImageWriter *writer) } static -int zero_writer_create(Ecma119Image *target, uint32_t num_blocks) +int tail_writer_compute_data_blocks(IsoImageWriter *writer) +{ + int ret; + Ecma119Image *target; + struct iso_zero_writer_data_struct *data; + + target = writer->target; + ret = iso_align_isohybrid(target, 0); + if (ret < 0) + return ret; + data = (struct iso_zero_writer_data_struct *) writer->data; + if (data->num_blocks != target->tail_blocks) { + iso_msg_debug(target->image->id, + "Aligned image size for isohybrid by %d blocks", + target->tail_blocks - data->num_blocks); + data->num_blocks = target->tail_blocks; + } + if (target->tail_blocks <= 0) + return ISO_SUCCESS; + ret = zero_writer_compute_data_blocks(writer); + return ret; +} + +/* + @param flag bit0= use tail_writer_compute_data_blocks rather than + zero_writer_compute_data_blocks +*/ +static +int zero_writer_create(Ecma119Image *target, uint32_t num_blocks, int flag) { IsoImageWriter *writer; struct iso_zero_writer_data_struct *data; @@ -1124,7 +1152,11 @@ int zero_writer_create(Ecma119Image *target, uint32_t num_blocks) } data->num_blocks = num_blocks; - writer->compute_data_blocks = zero_writer_compute_data_blocks; + if (flag & 1) { + writer->compute_data_blocks = tail_writer_compute_data_blocks; + } else { + writer->compute_data_blocks = zero_writer_compute_data_blocks; + } writer->write_vol_desc = zero_writer_write_vol_desc; writer->write_data = zero_writer_write_data; writer->free_data = zero_writer_free_data; @@ -1695,9 +1727,9 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) target->partition_secs_per_head = opts->partition_secs_per_head; target->partition_heads_per_cyl = opts->partition_heads_per_cyl; if (target->partition_secs_per_head == 0) - target->partition_secs_per_head = 63; + target->partition_secs_per_head = 32; if (target->partition_heads_per_cyl == 0) - target->partition_heads_per_cyl = 255; + target->partition_heads_per_cyl = 64; target->eff_partition_offset = 0; target->partition_root = NULL; target->partition_l_table_pos = 0; @@ -1893,11 +1925,9 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) /* IMPORTANT: This must be the last writer before the checksum writer */ - if (target->tail_blocks > 0) { - ret = zero_writer_create(target, target->tail_blocks); - if (ret < 0) - goto target_cleanup; - } + ret = zero_writer_create(target, target->tail_blocks, 1); + if (ret < 0) + goto target_cleanup; if ((target->md5_file_checksums & 1) || target->md5_session_checksum) { ret = checksum_writer_create(target); @@ -1951,8 +1981,8 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) if (i == el_torito_writer_index) continue; - /* Exposing address of data start to IsoWriteOpts iand memorizing - this address for for all files which have no block address: + /* Exposing address of data start to IsoWriteOpts and memorizing + this address for all files which have no block address: symbolic links, device files, empty data files. filesrc_writer_compute_data_blocks() and filesrc_writer_write_data() will account resp. write this single block. diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index ca8e9e1..e0a1b73 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -3120,6 +3120,8 @@ 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. * + * @param bootimg + * The image to set options on * @param options * bitmask style flag. The following values are defined: * @@ -3147,8 +3149,6 @@ int el_torito_seems_boot_info_table(ElToritoBootImage *bootimg, int flag); * For that you need isolinux.bin from SYSLINUX 3.72 or later. * IMPORTANT: The application has to take care that the image * on media gets padded up to the next full MB. - * @param bootimg - * The image to set options on * @param flag * Reserved for future usage, set to 0. * @return diff --git a/libisofs/make_isohybrid_mbr.c b/libisofs/make_isohybrid_mbr.c index a26d809..e544fcc 100644 --- a/libisofs/make_isohybrid_mbr.c +++ b/libisofs/make_isohybrid_mbr.c @@ -386,21 +386,19 @@ int make_isolinux_mbr(int32_t *img_blocks, uint32_t boot_lba, int part_offset, int part_number, int fs_type, uint8_t *buf, int flag) { - uint32_t spc, id, part, nominal_part_size; + uint32_t id, part, nominal_part_size; off_t hd_img_blocks, hd_boot_lba; char *wpt; /* For generating a weak random number */ struct timeval tv; struct timezone tz; - /* Pad image_size to a multiple of sector_count*head_count - */ - spc = head_count * sector_count; hd_img_blocks = ((off_t) *img_blocks) * (off_t) 4; - if (hd_img_blocks % spc) { - hd_img_blocks += spc - (hd_img_blocks % spc); - *img_blocks = hd_img_blocks / 4 + !!(hd_img_blocks % 4); - } + + /* Padding of image_size to a multiple of sector_count*head_count + happens already at compute time and is implemented by + an appropriate increase of Ecma119Image->tail_blocks. + */ wpt = (char *) buf + 432; diff --git a/libisofs/system_area.c b/libisofs/system_area.c index ef02a7e..396abe7 100644 --- a/libisofs/system_area.c +++ b/libisofs/system_area.c @@ -809,3 +809,100 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) return ISO_SUCCESS; } + +/* Choose *heads_per_cyl so that + - *heads_per_cyl * secs_per_head * 1024 >= imgsize / 512 + - *heads_per_cyl * secs_per_head is divisible by 4 + - it is as small as possible (to reduce aligment overhead) + - it is <= 255 + @return 1= success , 0= cannot achieve goals +*/ +static +int try_sph(off_t imgsize, int secs_per_head, int *heads_per_cyl, int flag) +{ + off_t hd_blocks, hpc; + + hd_blocks= imgsize / 512; + hpc = hd_blocks / secs_per_head / 1024; + if (hpc * secs_per_head * 1024 < hd_blocks) + hpc++; + if ((secs_per_head % 4) == 0) { + ; + } else if ((secs_per_head % 2) == 0) { + hpc += (hpc % 2); + } else if(hpc % 4) { + hpc += 4 - (hpc % 4); + } + if (hpc > 255) + return 0; + *heads_per_cyl = hpc; + return 1; +} + +int iso_align_isohybrid(Ecma119Image *t, int flag) +{ + int sa_type, ret; + uint32_t img_blocks; + off_t imgsize, cylsize = 0, frac; + + sa_type = (t->system_area_options >> 2) & 0x3f; + if (sa_type != 0) + return ISO_SUCCESS; + + img_blocks = t->curblock; + imgsize = ((off_t) img_blocks) * (off_t) 2048; + if ((t->system_area_options & 3) + && (off_t) (t->partition_heads_per_cyl * t->partition_secs_per_head + * 1024) * (off_t) 512 < imgsize) { + /* Choose small values which can represent the image size */ + /* First try 32 sectors per head */ + ret = try_sph(imgsize, 32, &(t->partition_heads_per_cyl), 0); + if (ret == 1) { + t->partition_secs_per_head = 32; + } else { + /* Did not work with 32. Try 63 */ + t->partition_secs_per_head = 63; + ret = try_sph(imgsize, 63, &(t->partition_heads_per_cyl), 0); + if (ret != 1) + t->partition_heads_per_cyl = 255; + } + cylsize = t->partition_heads_per_cyl * t->partition_secs_per_head *512; + frac = imgsize % cylsize; + iso_msg_debug(t->image->id, + "Automatically adjusted MBR geometry to %d/%d/%d", + (int) (imgsize / cylsize + !!frac), + t->partition_heads_per_cyl, t->partition_secs_per_head); + } + + cylsize = 0; + if (sa_type == 0 && t->catalog != NULL && + (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) + */ + if (img_blocks >= 0x40000000) + return ISO_SUCCESS; + cylsize = 64 * 32 * 512; + } else if (sa_type == 0 && (t->system_area_options & 2)) { + /* Patch externally provided system area as isohybrid MBR */ + if (t->catalog == NULL || t->system_area_data == NULL) { + /* isohybrid makes only sense together with ISOLINUX boot image + and externally provided System Area. + */ + return ISO_ISOLINUX_CANT_PATCH; + } + cylsize = t->partition_heads_per_cyl * t->partition_secs_per_head + * 512; + } + if (cylsize == 0) + return ISO_SUCCESS; + + frac = imgsize % cylsize; + imgsize += (frac > 0 ? cylsize - frac : 0); + + frac = imgsize - ((off_t) img_blocks) * (off_t) 2048; + if (frac == 0) + return ISO_SUCCESS; + t->tail_blocks += frac / 2048 + !!(frac % 2048); + return ISO_SUCCESS; +} diff --git a/libisofs/system_area.h b/libisofs/system_area.h index cdf1a2e..444f8b7 100644 --- a/libisofs/system_area.h +++ b/libisofs/system_area.h @@ -46,6 +46,11 @@ int make_isohybrid_mbr(int bin_lba, int *img_blocks, char *mbr, int flag); */ int iso_write_system_area(Ecma119Image *t, uint8_t *buf); +/** + * Adjust t->tail_blocks to the eventual alignment needs of isohybrid booting. + */ +int iso_align_isohybrid(Ecma119Image *t, int flag); + /** * Read the necessary ELF information from the first MIPS boot file.