diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index 1db605e..a65ff6e 100644 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -4416,6 +4416,16 @@ int iso_write_opts_set_iso_type_guid(IsoWriteOpts *opts, uint8_t guid[16], return ISO_SUCCESS; } +int iso_write_opts_set_gpt_with_gaps(IsoWriteOpts *opts, int with_gaps, + int with_gaps_no_sort, int with_gaps_no_iso) +{ + opts->iso_gpt_flag &= ~(2 | 4 | 8); + opts->iso_gpt_flag |= (!!with_gaps) << 1; + opts->iso_gpt_flag |= (!!with_gaps_no_sort) << 2; + opts->iso_gpt_flag |= (!!with_gaps_no_iso) << 3; + 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 f318b22..fa141a3 100644 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -515,6 +515,9 @@ struct iso_write_opts { */ uint8_t iso_gpt_type_guid[16]; /* bit0= iso_gpt_type_guid is valid + bit1= gaps in the image coverage are allowed + bit2= with bit1: do not sort GPT partition array by start block + bit3= with bit1: do not create partition 1 for ISO filesystem */ int iso_gpt_flag; diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 0915001..ef6fddf 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -2845,6 +2845,41 @@ int iso_write_opts_set_appended_as_gpt(IsoWriteOpts *opts, int gpt); int iso_write_opts_set_part_type_guid(IsoWriteOpts *opts, int partition_number, uint8_t guid[16], int valid); +/** + * Control whether the GPT partition table is allowed to leave some parts of + * the emerging ISO image uncovered, whether the partition entries in the + * GPT get sorted by their start block addresses, and whether partition 1 + * gets created to represent the ISO 9660 filesystem. + * Default is that the partition entries get sorted and all gaps get filled + * by additional GPT partition entries. Partition 1 is by default created for + * the ISO filesystem if partition offset is 16, no partition 1 was created for + * other reasons, and no other partition overlaps with the range from LBA 16 to + * the end of the ISO 9660 filesystem. + * + * Note that GPT for ISOLINUX isohybrid does not get gaps filled, anyways. + * + * @param opts + * The option set to be manipulated. + * @param with_gaps + * If 0, fill gaps. + * If 1, do not fill gaps. + * @param with_gaps_no_sort + * In case that with_gaps is 1: + * If 0, sort partitions by start block addresses. + * If 1, do not sort partitions. + * @param with_gaps_no_iso + * In case that with_gaps is 1: + * If 0, create partition 1 for the ISO filesystem if possible. + * If 1, do not create partition for the ISO filesystem if not already + * created for other reasons. + * @return + * ISO_SUCCESS or error + * + * @since 1.5.8 + */ +int iso_write_opts_set_gpt_with_gaps(IsoWriteOpts *opts, int with_gaps, + int with_gaps_no_sort, int with_gaps_no_iso); + /** * Control whether partitions created by iso_write_opts_set_partition_img() * are to be represented in Apple Partition Map. diff --git a/libisofs/libisofs.ver b/libisofs/libisofs.ver index 87af30b..4247776 100644 --- a/libisofs/libisofs.ver +++ b/libisofs/libisofs.ver @@ -398,5 +398,6 @@ iso_util_decode_lfa_flags; iso_util_encode_lfa_flags; iso_util_get_effective_lfa_mask; iso_util_get_lfa_masks; +iso_write_opts_set_gpt_with_gaps; } LIBISOFS6; diff --git a/libisofs/system_area.c b/libisofs/system_area.c index 6e97632..b90954e 100644 --- a/libisofs/system_area.c +++ b/libisofs/system_area.c @@ -1757,16 +1757,67 @@ static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) ret = iso_copy_apmhfs_to_gpt(t, 0); if (ret <= 0) return ret; - + + if (t->opts->partition_offset == 16 && (t->opts->iso_gpt_flag & 2) && + !(t->opts->iso_gpt_flag & 8)) { + /* If there is no appended partition number 1, the space between + t->opts->partition_offset and t->vol_space_size is uncovered, + and t->opts->partition_offset == 16: + Create ISO9660 partitition (see below) + */ + for (i = 0; i < t->gpt_req_count; i++) { + if (t->gpt_req[i]->desired_slot == 1) + break; + if (t->gpt_req[i]->start_block < t->vol_space_size * (uint64_t) 4 + && + t->gpt_req[i]->start_block + t->gpt_req[i - 1]->block_count > + t->opts->partition_offset * (uint64_t) 4) + break; + } + if (i >= t->gpt_req_count) { + /* Create ISO 9660 partition */ + memset(gpt_name, 0, 72); + type_guid = basic_data_uuid; + eff_gpt_flags= gpt_flags; + sprintf((char *) gpt_name, "ISO9660"); + type_guid = basic_data_uuid; + if (t->opts->iso_gpt_flag & 1) + type_guid = t->opts->iso_gpt_type_guid; + if (t->system_area_options & (1 << 16)) + eff_gpt_flags|= 4; /* Legacy BIOS bootable */ + if (t->system_area_options & (1 << 17)) + eff_gpt_flags&= ~(((uint64_t) 1) << 60);/* Not read-only */ + iso_ascii_utf_16le(gpt_name); + ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count), + t->opts->partition_offset * (uint64_t) 4, + (t->vol_space_size - + t->opts->partition_offset) * (uint64_t) 4, + type_guid, zero_uuid, + eff_gpt_flags, gpt_name); + if (ret < 0) + return ret; + t->gpt_req[t->gpt_req_count - 1]->desired_slot = 1; + /* Make new partition the first one */ + req= t->gpt_req[t->gpt_req_count - 1]; + for (i = t->gpt_req_count - 2; i >= 0; i--) + t->gpt_req[i + 1]= t->gpt_req[i]; + t->gpt_req[0]= req; + } + } + /* Sort and fill gaps */ - qsort(t->gpt_req, t->gpt_req_count, - sizeof(struct iso_gpt_partition_request *), cmp_partition_request); + + /* Sort if not gap filling is disabled or not sorting is disabled */ + if (!((t->opts->iso_gpt_flag & 2) && (t->opts->iso_gpt_flag & 4))) { + qsort(t->gpt_req, t->gpt_req_count, + sizeof(struct iso_gpt_partition_request *), cmp_partition_request); + } /* t->gpt_req_count will grow during the loop */ up_to = t->gpt_req_count + 1; goal = 0; part_end = 0; - if (t->opts->part_like_isohybrid) + if (t->opts->part_like_isohybrid || t->opts->iso_gpt_flag & 2) up_to = 0; /* No gap filling */ for (i = 0; i < up_to; i++) { @@ -1822,9 +1873,11 @@ static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) t->gpt_req[t->gpt_req_count - 1]->req_status |= 1; } } - /* Merge list of gap partitions with list of already sorted entries */ - qsort(t->gpt_req, t->gpt_req_count, - sizeof(struct iso_gpt_partition_request *), cmp_partition_request); + if (!((t->opts->iso_gpt_flag & 2) && (t->opts->iso_gpt_flag & 4))) { + /* Merge list of gap partitions with list of already sorted entries */ + qsort(t->gpt_req, t->gpt_req_count, + sizeof(struct iso_gpt_partition_request *), cmp_partition_request); + } if ((int) t->gpt_max_entries < t->gpt_req_count) return ISO_BOOT_TOO_MANY_GPT;