diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index 1176e81..f3e5e60 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 - 2013 Thomas Schmitt + * Copyright (c) 2009 - 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 @@ -1318,12 +1318,18 @@ ex: static int write_head_part1(Ecma119Image *target, int *write_count, int flag) { - int res, i; - uint8_t *sa; + int res, i, ret; + uint8_t *sa, *sa_local = NULL; IsoImageWriter *writer; size_t buffer_size = 0, buffer_free = 0, buffer_start_free = 0; - sa = target->sys_area_as_written; + if (target->sys_area_already_written) { + LIBISO_ALLOC_MEM(sa_local, uint8_t, 16 * BLOCK_SIZE); + sa = sa_local; + } else { + sa = target->sys_area_as_written; + target->sys_area_already_written = 1; + } iso_ring_buffer_get_buf_status(target->buffer, &buffer_size, &buffer_start_free); *write_count = 0; @@ -1360,9 +1366,16 @@ int write_head_part1(Ecma119Image *target, int *write_count, int flag) *write_count = target->bytes_written / BLOCK_SIZE; } - return ISO_SUCCESS; + ret = ISO_SUCCESS; + goto ex; + write_error:; - return res; + ret = res; + goto ex; + +ex: + LIBISO_FREE_MEM(sa_local); + return ret; } static @@ -1483,6 +1496,10 @@ int iso_write_partition_file(Ecma119Image *target, char *path, goto ex; } +/* >>> need opportunity to read from input ISO image + resp. to just mark a partition in the older sessions +*/; + fp = fopen(path, "rb"); if (fp == NULL) {ret = ISO_BAD_PARTITION_FILE; goto ex;} @@ -1528,8 +1545,10 @@ void issue_ucs2_warning_summary(size_t failures) static void *write_function(void *arg) { - int res, first_partition = 1, last_partition = 0, sa_type; - int i; + int res, i; +#ifndef Libisofs_appended_partitions_inlinE + int first_partition = 1, last_partition = 0, sa_type; +#endif IsoImageWriter *writer; Ecma119Image *target = (Ecma119Image*)arg; @@ -1545,12 +1564,17 @@ void *write_function(void *arg) /* write data for each writer */ for (i = 0; i < (int) target->nwriters; ++i) { writer = target->writers[i]; + if (target->gpt_backup_outside && + writer->write_vol_desc == gpt_tail_writer_write_vol_desc) + continue; res = writer->write_data(writer); if (res < 0) { goto write_error; } } +#ifndef Libisofs_appended_partitions_inlinE + /* Append partition data */ sa_type = (target->system_area_options >> 2) & 0x3f; if (sa_type == 0) { /* MBR */ @@ -1573,6 +1597,19 @@ void *write_function(void *arg) goto write_error; } +#endif /* ! Libisofs_appended_partitions_inlinE */ + + if (target->gpt_backup_outside) { + for (i = 0; i < (int) target->nwriters; ++i) { + writer = target->writers[i]; + if (writer->write_vol_desc != gpt_tail_writer_write_vol_desc) + continue; + res = writer->write_data(writer); + if (res < 0) + goto write_error; + } + } + /* Transplant checksum buffer from Ecma119Image to IsoImage */ transplant_checksum_buffer(target, 0); @@ -1927,6 +1964,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *in_opts, Ecma119Image **img) target->appended_part_prepad[i] = 0; target->appended_part_start[i] = target->appended_part_size[i] = 0; } + target->have_appended_partitions = 0; for (i = 0; i < ISO_HFSPLUS_BLESS_MAX; i++) { target->hfsplus_blessed[i] = src->hfsplus_blessed[i]; if (target->hfsplus_blessed[i] != NULL) @@ -1946,6 +1984,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *in_opts, Ecma119Image **img) target->gpt_req[i] = NULL; target->gpt_req_count = 0; target->gpt_req_flags = 0; + target->gpt_backup_outside = 0; target->gpt_disk_guid_set = 0; target->gpt_part_start = 0; target->gpt_backup_end = 0; @@ -1953,11 +1992,23 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *in_opts, Ecma119Image **img) target->gpt_max_entries = 0; target->gpt_is_computed = 0; + target->sys_area_already_written = 0; + target->filesrc_start = 0; target->filesrc_blocks = 0; target->joliet_ucs2_failures = 0; + /* If partitions get appended, then the backup GPT cannot be part of + the ISO filesystem. + */ + for (i = 0; i < ISO_MAX_PARTITIONS; i++) + if (target->opts->appended_partitions[i] != NULL) { + target->gpt_backup_outside = 1; + target->have_appended_partitions = 1; + break; + } + /* * 2. Based on those options, create needed writers: iso, joliet... * Each writer inits its structures and stores needed info into @@ -1991,6 +2042,13 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *in_opts, Ecma119Image **img) if (opts->hfsplus || opts->fat) { nwriters+= 2; } + +#ifdef Libisofs_appended_partitions_inlinE + + nwriters++; /* Inline Partition Append Writer */ + +#endif + nwriters++; /* GPT backup tail writer */ nwriters++; /* Tail padding writer */ if ((opts->md5_file_checksums & 1) || opts->md5_session_checksum) { @@ -2139,6 +2197,14 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *in_opts, Ecma119Image **img) #endif /* Libisofs_checksums_before_paddinG */ +#ifdef Libisofs_appended_partitions_inlinE + + ret = partappend_writer_create(target); + if (ret < 0) + goto target_cleanup; + +#endif /* Libisofs_appended_partitions_inlinE */ + #ifdef Libisofs_gpt_writer_lasT /* This writer shall be the last one in the list, because it protects the image on media which are seen as GPT partitioned. @@ -2204,6 +2270,10 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *in_opts, Ecma119Image **img) for (i = 0; i < (int) target->nwriters; ++i) { IsoImageWriter *writer = target->writers[i]; + if (target->gpt_backup_outside && + writer->write_vol_desc == gpt_tail_writer_write_vol_desc) + continue; + /* 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. @@ -2220,6 +2290,14 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *in_opts, Ecma119Image **img) if (ret < 0) { goto target_cleanup; } + +#ifdef Libisofs_appended_partitions_inlinE + + target->vol_space_size = target->curblock - opts->ms_block; + target->total_size = (off_t) target->vol_space_size * BLOCK_SIZE; + +#endif + } ret = iso_patch_eltoritos(target); @@ -2231,6 +2309,8 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *in_opts, Ecma119Image **img) goto target_cleanup; } +#ifndef Libisofs_appended_partitions_inlinE + /* * The volume space size is just the size of the last session, in * case of ms images. @@ -2243,6 +2323,20 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *in_opts, Ecma119Image **img) if (ret < 0) goto target_cleanup; +#endif /* ! Libisofs_appended_partitions_inlinE */ + + if (target->gpt_backup_outside) { + for (i = 0; i < (int) target->nwriters; ++i) { + IsoImageWriter *writer = target->writers[i]; + + if (writer->write_vol_desc != gpt_tail_writer_write_vol_desc) + continue; + ret = writer->compute_data_blocks(writer); + if (ret < 0) + goto target_cleanup; + } + } + /* create the ring buffer */ if (opts->overwrite != NULL && opts->fifo_size < 32 + opts->partition_offset) { @@ -2732,6 +2826,7 @@ int iso_write_opts_new(IsoWriteOpts **opts, int profile) wopts->efi_boot_partition = NULL; for (i = 0; i < ISO_MAX_PARTITIONS; i++) wopts->appended_partitions[i] = NULL; + wopts->appended_as_gpt = 0; wopts->ascii_disc_label[0] = 0; wopts->will_cancel = 0; wopts->allow_dir_id_ext = 0; @@ -3445,6 +3540,12 @@ int iso_write_opts_set_partition_img(IsoWriteOpts *opts, int partition_number, return ISO_SUCCESS; } +int iso_write_opts_set_appended_as_gpt(IsoWriteOpts *opts, int gpt) +{ + opts->appended_as_gpt = !!gpt; + return ISO_SUCCESS; +} + int iso_write_opts_set_disc_label(IsoWriteOpts *opts, char *label) { strncpy(opts->ascii_disc_label, label, ISO_DISC_LABEL_SIZE - 1); diff --git a/libisofs/ecma119.h b/libisofs/ecma119.h index a9968e8..f151bce 100644 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2009 - 2013 Thomas Schmitt + * Copyright (c) 2009 - 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 @@ -480,6 +480,10 @@ struct iso_write_opts { char *appended_partitions[ISO_MAX_PARTITIONS]; uint8_t appended_part_types[ISO_MAX_PARTITIONS]; + /* If 1: With appended partitions: create protective MBR and mark by GPT + */ + int appended_as_gpt; + /* Eventual name of the non-ISO aspect of the image. E.g. SUN ASCII label. */ char ascii_disc_label[ISO_DISC_LABEL_SIZE]; @@ -756,6 +760,7 @@ struct ecma119_image uint32_t appended_part_prepad[ISO_MAX_PARTITIONS]; uint32_t appended_part_start[ISO_MAX_PARTITIONS]; uint32_t appended_part_size[ISO_MAX_PARTITIONS]; + int have_appended_partitions; /* See IsoImage and libisofs.h */ IsoNode *hfsplus_blessed[ISO_HFSPLUS_BLESS_MAX]; @@ -802,6 +807,9 @@ struct ecma119_image /* bit0= GPT partitions may overlap */ int gpt_req_flags; + /* Whether the eventual backup GPT is not part of the ISO filesystem */ + int gpt_backup_outside; + uint32_t efi_boot_part_size; IsoFileSrc *efi_boot_part_filesrc; /* Just a pointer. Do not free. */ @@ -822,6 +830,7 @@ struct ecma119_image write_data() methods of the writers. */ uint8_t sys_area_as_written[16 * BLOCK_SIZE]; + int sys_area_already_written; /* Size of the filesrc_writer area (data file content). This is available before any IsoImageWriter.compute_data_blocks() diff --git a/libisofs/fs_image.c b/libisofs/fs_image.c index ced92db..45c4089 100644 --- a/libisofs/fs_image.c +++ b/libisofs/fs_image.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2009 - 2014 Thomas Schmitt + * Copyright (c) 2009 - 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 @@ -4014,7 +4014,7 @@ int iso_analyze_gpt_backup(IsoImage *image, IsoDataSource *src, int flag) if (sai->gpt_backup_lba >= ((uint64_t) sai->image_size) * 4 && (sai->mbr_req_count < 1 || sai->mbr_req[0]->start_block + sai->mbr_req[0]->block_count - != sai->gpt_backup_lba + 1)) + > sai->gpt_backup_lba + 1)) sprintf(comments + strlen(comments), "Implausible header LBA %.f, ", (double) sai->gpt_backup_lba); iso_block = sai->gpt_backup_lba / 4; @@ -4254,6 +4254,26 @@ int iso_analyze_gpt(IsoImage *image, IsoDataSource *src, int flag) } } } + + /* Check first GPT partition for ISO partition offset */ + if (sai->partition_offset == 0 && sai->mbr_req_count > 0 && + sai->gpt_req_count > 0) { + if (sai->mbr_req[0]->type_byte == 0xee && + sai->mbr_req[0]->start_block == 1) { /* protective MBR */ + start_block = sai->gpt_req[0]->start_block; + block_count = sai->gpt_req[0]->block_count; + if (start_block >= 64 && block_count >= 72 && + start_block <= 2048 && start_block % 4 == 0 && + block_count % 4 == 0 && + (start_block + block_count) / 4 == sai->image_size) { + + ret = iso_analyze_partition_offset(image, src, start_block, 0); + if (ret < 0) + return ret; + } + } + } + return 1; } diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index b195489..1db3448 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -4,7 +4,7 @@ /* * Copyright (c) 2007-2008 Vreixo Formoso, Mario Danic - * Copyright (c) 2009-2014 Thomas Schmitt + * Copyright (c) 2009-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 @@ -2502,6 +2502,24 @@ int iso_write_opts_set_efi_bootp(IsoWriteOpts *opts, char *image_path, int iso_write_opts_set_partition_img(IsoWriteOpts *opts, int partition_number, uint8_t partition_type, char *image_path, int flag); +/** + * Control whether partitions created by iso_write_opts_set_partition_img() + * are to be represented in MBR or as GPT partitions. + * + * @param opts + * The option set to be manipulated. + * @param gpt + * 0= represent as MBR partition; as GPT only if other GPT partitions + * are present + * 1= represent as GPT partition and cause protective MBR with a single + * partition which covers the whole output data. + * This may fail if other settings demand MBR partitions. + * @return + * ISO_SUCCESS or error + * + * @since 1.4.0 + */ +int iso_write_opts_set_appended_as_gpt(IsoWriteOpts *opts, int gpt); /** * Inquire the start address of the file data blocks after having used @@ -3730,8 +3748,8 @@ int iso_image_get_system_area(IsoImage *img, char data[32768], "If an MBR is detected, with at least one partition entry of non-zero size,", \ "then there may be:", \ " Partition offset : decimal", \ -" if not 0 then a second ISO 9660 superblock was found to which MBR", \ -" partition 1 is pointing.", \ +" if not 0 then a second ISO 9660 superblock was found to which", \ +" MBR partition 1 or GPT partition 1 is pointing.", \ " MBR heads per cyl : decimal", \ " conversion factor between MBR C/H/S address and LBA. 0=inconsistent.", \ " MBR secs per head : decimal", \ diff --git a/libisofs/libisofs.ver b/libisofs/libisofs.ver index 1a8248e..85bd801 100644 --- a/libisofs/libisofs.ver +++ b/libisofs/libisofs.ver @@ -290,6 +290,7 @@ iso_write_opts_set_allow_longer_paths; iso_write_opts_set_allow_lowercase; iso_write_opts_set_always_gmt; iso_write_opts_set_appendable; +iso_write_opts_set_appended_as_gpt; iso_write_opts_set_default_dir_mode; iso_write_opts_set_default_file_mode; iso_write_opts_set_default_gid; diff --git a/libisofs/make_isohybrid_mbr.c b/libisofs/make_isohybrid_mbr.c index fd6d02d..b137950 100644 --- a/libisofs/make_isohybrid_mbr.c +++ b/libisofs/make_isohybrid_mbr.c @@ -1,3 +1,13 @@ +/* + * Copyright (c) 2008 - 2015 Thomas Schmitt + * with special credits to H. Peter Anvin for isohybrid + * and to Matthew Garrett for isohybrid with GPT and APM + * + * 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 + * or later as published by the Free Software Foundation. + * See COPYING file for details. + */ #ifdef HAVE_CONFIG_H #include "../config.h" @@ -559,6 +569,7 @@ static int gpt_images_as_mbr_partitions(Ecma119Image *t, char *wpt, /* * @param flag bit0= make own random MBR Id from current time + * bit1= create protective MBR as of UEFI/GPT specs */ int make_isolinux_mbr(uint32_t *img_blocks, Ecma119Image *t, int part_offset, int part_number, int fs_type, @@ -574,6 +585,11 @@ int make_isolinux_mbr(uint32_t *img_blocks, Ecma119Image *t, struct timeval tv; struct timezone tz; + if (flag & 2) { + part_number = 1; + part_offset = 1; + } + hd_img_blocks = ((off_t) *img_blocks) * (off_t) 4; boot_lba = t->bootsrc[0]->sections[0].block; @@ -639,14 +655,17 @@ int make_isolinux_mbr(uint32_t *img_blocks, Ecma119Image *t, wpt+= 16; continue; } - /* write byte 0x80 + /* write byte 0x80 if bootable write LBA_to_CHS(partition_offset) write byte filesystem_type write LBA_to_CHS(image_size-1) write dword partition_offset write dword image_size */ - lsb_to_buf(&wpt, 0x80, 8, 0); + if (flag & 2) + lsb_to_buf(&wpt, 0x00, 8, 0); + else + lsb_to_buf(&wpt, 0x80, 8, 0); lba512chs_to_buf(&wpt, part_offset, head_count, sector_count); lsb_to_buf(&wpt, fs_type, 8, 0); lba512chs_to_buf(&wpt, hd_img_blocks - 1, head_count, sector_count); diff --git a/libisofs/system_area.c b/libisofs/system_area.c index 2c228b3..f158d88 100644 --- a/libisofs/system_area.c +++ b/libisofs/system_area.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2008 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 @@ -128,6 +128,7 @@ static uint32_t compute_partition_size(char *disk_path, uint32_t *size, } /* Compute size and position of appended partitions. + @param flag bit0= Partitions inside ISO : update t->curblock */ int iso_compute_append_partitions(Ecma119Image *t, int flag) { @@ -170,6 +171,8 @@ int iso_compute_append_partitions(Ecma119Image *t, int flag) t->appended_part_size[i] = size; pos += add_pos + size; t->total_size += (add_pos + size) * 2048; + if (flag & 1) + t->curblock = pos; } return ISO_SUCCESS; } @@ -312,6 +315,7 @@ int make_grub_msdos_label(uint32_t img_blocks, int sph, int hpc, /* @param flag bit0= zeroize partitions entries 2, 3, 4 + bit0= UEFI protective MBR: start LBA = 1 */ static int iso_offset_partition_start(uint32_t img_blocks, uint32_t partition_offset, @@ -326,6 +330,11 @@ int iso_offset_partition_start(uint32_t img_blocks, uint32_t partition_offset, &start_lba, &start_sec, &start_head, &start_cyl, 1); iso_compute_cyl_head_sec((uint64_t) img_blocks, hpc, sph, &end_lba, &end_sec, &end_head, &end_cyl, 0); + if (flag & 2) { + start_lba = 1; + start_sec = 2; + start_head = start_cyl = 0; + } wpt = buf + 446; /* Let pass only legal bootability values */ @@ -1552,7 +1561,11 @@ static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) } } else if (part_end < goal) { memset(gpt_name, 0, 72); - sprintf((char *) gpt_name, "Gap%d", gap_counter); + if (goal == t->vol_space_size * (uint64_t) 4 && + part_end == t->opts->partition_offset * (uint64_t) 4) + sprintf((char *) gpt_name, "ISO9660"); + else + sprintf((char *) gpt_name, "Gap%d", gap_counter); iso_ascii_utf_16le(gpt_name); gap_counter++; ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count), @@ -1577,6 +1590,9 @@ static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) end_lba = req->start_block + req->block_count; backup_end_lba = ((uint64_t) t->gpt_backup_end - t->gpt_backup_size) * 4; + if (req->start_block == t->opts->partition_offset * ((uint64_t) 4) && + req->block_count == ((uint64_t) 4) * 0xffffffff) + end_lba = t->vol_space_size * 4; if (end_lba > backup_end_lba) end_lba = backup_end_lba; end_lba = end_lba - 1; @@ -1601,9 +1617,10 @@ static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) int iso_write_system_area(Ecma119Image *t, uint8_t *buf) { int ret, int_img_blocks, sa_type, i, will_append = 0, do_isohybrid = 0; - int first_partition = 1, last_partition = 4, apm_flag, part_type; - int gpt_count = 0, gpt_idx[128], apm_count = 0; - uint32_t img_blocks; + int first_partition = 1, last_partition = 4, apm_flag, part_type = 0; + int gpt_count = 0, gpt_idx[128], apm_count = 0, no_boot_mbr = 0; + int offset_flag = 0; + uint32_t img_blocks, gpt_blocks, mbrp1_blocks; uint64_t blk; uint8_t *wpt; @@ -1695,7 +1712,12 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) } if (t->mbr_req_count > 0 && sa_type != 0) return ISO_NON_MBR_SYS_AREA; - ret = iso_write_gpt(t, img_blocks, buf); + + if (t->gpt_backup_outside) + gpt_blocks = t->total_size / 2048; + else + gpt_blocks = img_blocks; + ret = iso_write_gpt(t, gpt_blocks, buf); if (ret < 0) { iso_msg_submit(t->image->id, ret, 0, "Cannot set up GPT"); return ret; @@ -1724,12 +1746,19 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) else part_type = 0x17; + if (t->opts->appended_as_gpt && t->have_appended_partitions) { + part_type = 0xee; + img_blocks = gpt_blocks; + no_boot_mbr = 2; + } + /* >>> ??? Why is partition_offset 0 here ? It gets adjusted later by iso_offset_partition_start() Would it harm to give the real offset here ? */; - ret = make_isolinux_mbr(&img_blocks, t, 0, 1, part_type, buf, 1); + ret = make_isolinux_mbr(&img_blocks, t, 0, 1, part_type, buf, + 1 | no_boot_mbr); if (ret != 1) return ret; } else if (sa_type == 1) { @@ -1773,9 +1802,17 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) With t->mbr_req_count > 0 this has already been done, */ img_blocks = t->curblock; /* value might be altered */ - ret = iso_offset_partition_start(img_blocks, t->opts->partition_offset, + if (part_type == 0xee) { + mbrp1_blocks = t->total_size / 2048; + offset_flag |= 2 | 1; /* protective MBR, no other partitions */ + } else { + mbrp1_blocks = img_blocks; + } + ret = iso_offset_partition_start(mbrp1_blocks, + t->opts->partition_offset, t->partition_secs_per_head, - t->partition_heads_per_cyl, buf, 0); + t->partition_heads_per_cyl, buf, + offset_flag); if (ret != ISO_SUCCESS) /* error should never happen */ return ISO_ASSERT_FAILURE; } @@ -1783,27 +1820,29 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) /* This eventually overwrites the non-mbr_req partition table entries made so far. Overwriting those from t->mbr_req is not allowed. */ - for (i = first_partition - 1; i <= last_partition - 1; i++) { - if (t->opts->appended_partitions[i] == NULL) - continue; - if (i < t->mbr_req_count) - return ISO_BOOT_MBR_COLLISION; - if (sa_type == 3) { - ret = write_sun_partition_entry(i + 1, + if (sa_type == 3 || !t->opts->appended_as_gpt) { + for (i = first_partition - 1; i <= last_partition - 1; i++) { + if (t->opts->appended_partitions[i] == NULL) + continue; + if (i < t->mbr_req_count) + return ISO_BOOT_MBR_COLLISION; + if (sa_type == 3) { + ret = write_sun_partition_entry(i + 1, t->opts->appended_partitions, t->appended_part_start, t->appended_part_size, ISO_SUN_CYL_SIZE, buf, t->opts->appended_partitions[i][0] == 0); - } else { - ret = write_mbr_partition_entry(i + 1, + } else { + ret = write_mbr_partition_entry(i + 1, t->opts->appended_part_types[i], (uint64_t) t->appended_part_start[i], (uint64_t) t->appended_part_size[i], t->partition_secs_per_head, t->partition_heads_per_cyl, buf, 0); + } + if (ret < 0) + return ret; } - if (ret < 0) - return ret; } if (sa_type == 0 && (t->system_area_options & 0x4000) && !do_isohybrid) { @@ -1860,10 +1899,12 @@ int iso_align_isohybrid(Ecma119Image *t, int flag) {ret = ISO_SUCCESS; goto ex;} always_align = (t->system_area_options >> 8) & 3; - /* Take into account the backup GPT */; - ret = precompute_gpt(t); - if (ret < 0) - goto ex; + if (!t->gpt_backup_outside) { + /* Take into account the backup GPT */; + ret = precompute_gpt(t); + if (ret < 0) + goto ex; + } img_blocks = t->curblock + t->opts->tail_blocks + t->gpt_backup_size; imgsize = ((off_t) img_blocks) * (off_t) 2048; @@ -2137,6 +2178,53 @@ fallback:; } +int assess_appended_gpt(Ecma119Image *t, int flag) +{ + static uint8_t basic_data_uuid[16] = { + 0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44, + 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 + }; + static uint8_t efi_sys_uuid[16] = { + 0x28, 0x73, 0x2a, 0xc1, 0x1f, 0xf8, 0xd2, 0x11, + 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b + }; + static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + int i, ret; + uint8_t gpt_name[72], *type_uuid; + +#ifndef Libisofs_appended_partitions_inlinE + if (!t->gpt_backup_outside) + return 2; +#endif + + /* Represent in GPT only if other GPT partitions are already registered + or if appended partitions are explicitely desired for GPT-only. + */ + if (t->gpt_req_count == 0 && + !(t->have_appended_partitions && t->opts->appended_as_gpt)) + return 2; + + /* Represent appended partitions */ + for (i = 0; i <= 3; i++) { + if (t->opts->appended_partitions[i] == NULL) + continue; + memset(gpt_name, 0, 72); + sprintf((char *) gpt_name, "Appended%d", i + 1); + iso_ascii_utf_16le(gpt_name); + if (t->opts->appended_part_types[i] == 0xef) + type_uuid = efi_sys_uuid; + else + type_uuid = basic_data_uuid; + ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count), + ((uint64_t) t->appended_part_start[i]) * 4, + ((uint64_t) t->appended_part_size[i]) * 4, + type_uuid, zero_uuid, + (uint64_t) 0, gpt_name); + if (ret < 0) + return ret; + } + return ISO_SUCCESS; +} /* Probably already called by tail_writer_compute_data_blocks via iso_align_isohybrid @@ -2181,6 +2269,9 @@ static int precompute_gpt(Ecma119Image *t) if (ret < 0) return ret; + /* Assess impact of appended partitions on GPT */ + ret = assess_appended_gpt(t, 0); + #ifdef NIX /* Disabled */ @@ -2262,7 +2353,7 @@ static int precompute_gpt(Ecma119Image *t) } -static int gpt_tail_writer_compute_data_blocks(IsoImageWriter *writer) +int gpt_tail_writer_compute_data_blocks(IsoImageWriter *writer) { Ecma119Image *t; int ret; @@ -2276,15 +2367,22 @@ static int gpt_tail_writer_compute_data_blocks(IsoImageWriter *writer) if (ret < 0) return ret; } - t->curblock += t->gpt_backup_size; - /* The ISO block number after the backup GPT header */ - t->gpt_backup_end = t->curblock; + + if (t->gpt_backup_outside) { + t->total_size += t->gpt_backup_size * 2048; + /* The ISO block number after the backup GPT header */ + t->gpt_backup_end = t->total_size / 2048; + } else { + t->curblock += t->gpt_backup_size; + /* The ISO block number after the backup GPT header */ + t->gpt_backup_end = t->curblock; + } return ISO_SUCCESS; } -static int gpt_tail_writer_write_vol_desc(IsoImageWriter *writer) +int gpt_tail_writer_write_vol_desc(IsoImageWriter *writer) { return ISO_SUCCESS; } @@ -2348,6 +2446,12 @@ tampered_head:; free(backup_buf); if (ret < 0) return ret; + + if (!t->gpt_backup_outside) { + + /* >>> Why isn't t->curblock updated ? */; + + } return ISO_SUCCESS; write_zeros:; @@ -2560,3 +2664,87 @@ int partprepend_writer_create(Ecma119Image *target) } +#ifdef Libisofs_appended_partitions_inlinE + +/* ----------------- Inline Partition Append Writer ------------------ */ + + +static int partappend_writer_compute_data_blocks(IsoImageWriter *writer) +{ + int ret; + + ret = iso_compute_append_partitions(writer->target, 1); + return ret; +} + + +static int partappend_writer_write_vol_desc(IsoImageWriter *writer) +{ + return ISO_SUCCESS; +} + + +static int partappend_writer_write_data(IsoImageWriter *writer) +{ + Ecma119Image *target; + int res, first_partition = 1, last_partition = 0, sa_type; + int i; + + target = writer->target; + + /* Append partition data */ + sa_type = (target->system_area_options >> 2) & 0x3f; + if (sa_type == 0) { /* MBR */ + first_partition = 1; + last_partition = 4; + } else if (sa_type == 3) { /* SUN Disk Label */ + first_partition = 2; + last_partition = 8; + } + for (i = first_partition - 1; i <= last_partition - 1; i++) { + if (target->opts->appended_partitions[i] == NULL) + continue; + if (target->opts->appended_partitions[i][0] == 0) + continue; + res = iso_write_partition_file(target, + target->opts->appended_partitions[i], + target->appended_part_prepad[i], + target->appended_part_size[i], 0); + if (res < 0) + return res; + target->curblock += target->appended_part_size[i]; + } + return ISO_SUCCESS; +} + + +static int partappend_writer_free_data(IsoImageWriter *writer) +{ + return ISO_SUCCESS; +} + + +int partappend_writer_create(Ecma119Image *target) +{ + IsoImageWriter *writer; + + writer = calloc(1, sizeof(IsoImageWriter)); + if (writer == NULL) { + return ISO_OUT_OF_MEM; + } + + writer->compute_data_blocks = partappend_writer_compute_data_blocks; + writer->write_vol_desc = partappend_writer_write_vol_desc; + writer->write_data = partappend_writer_write_data; + writer->free_data = partappend_writer_free_data; + writer->data = NULL; + writer->target = target; + + /* add this writer to image */ + target->writers[target->nwriters++] = writer; + + return ISO_SUCCESS; +} + +#endif /* Libisofs_appended_partitions_inlinE */ + diff --git a/libisofs/system_area.h b/libisofs/system_area.h index 70f3736..fa89b67 100644 --- a/libisofs/system_area.h +++ b/libisofs/system_area.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2008 Vreixo Formoso - * Copyright (c) 2012 Thomas Schmitt + * Copyright (c) 2012 - 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 @@ -281,10 +281,20 @@ struct iso_sun_disk_label_entry { */ int partprepend_writer_create(Ecma119Image *target); +/* Creates the Inline Partition Append Writer +*/ +int partappend_writer_create(Ecma119Image *target); + /* Creates the GPT backup tail writer. */ int gpt_tail_writer_create(Ecma119Image *target); +/* Not for execution but only to identify the writer by + ( writer->write_vol_desc == gpt_tail_writer_write_vol_desc ) +*/ +int gpt_tail_writer_write_vol_desc(IsoImageWriter *writer); + + /* Only for up to 36 characters ISO-8859-1 (or ASCII) input */ void iso_ascii_utf_16le(uint8_t gap_name[72]); @@ -301,4 +311,10 @@ void iso_ascii_utf_16le(uint8_t gap_name[72]); #define Libisofs_grub2_sparc_patch_adr_poS 0x228 #define Libisofs_grub2_sparc_patch_size_poS 0x230 + +/* >>> It is unclear whether there is a use case for appended partitions + inside the ISO filesystem range. + # define Libisofs_appended_partitions_inlinE yes +*/ + #endif /* SYSTEM_AREA_H_ */