diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index 3bf800e..977c304 100644 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -1251,10 +1251,11 @@ static int write_head_part1(Ecma119Image *target, int *write_count, int flag) { int res, i; - uint8_t sa[16 * BLOCK_SIZE]; + uint8_t *sa; IsoImageWriter *writer; size_t buffer_size = 0, buffer_free = 0, buffer_start_free = 0; + sa = target->sys_area_as_written; iso_ring_buffer_get_buf_status(target->buffer, &buffer_size, &buffer_start_free); *write_count = 0; @@ -1884,15 +1885,14 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) if (target->hfsplus_blessed[i] != NULL) iso_node_ref(target->hfsplus_blessed[i]); } - /* Note: Set apm_block_size to 2048, if desired, before pthread_create() - at the end of this function. - Register any Apple Partition Map entries before pthread_create(). - */ target->apm_block_size = 512; for (i = 0; i < ISO_APM_ENTRIES_MAX; i++) target->apm_req[i] = NULL; for (i = 0; i < ISO_GPT_ENTRIES_MAX; i++) target->gpt_req[i] = NULL; + target->gpt_part_start = 0; + target->gpt_backup_end = 0; + target->gpt_max_entries = 0; /* * 2. Based on those options, create needed writers: iso, joliet... @@ -1926,6 +1926,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) if (target->iso1999) { nwriters++; } + nwriters++; /* GPT backup tail writer */ nwriters++; /* Tail padding writer */ if ((target->md5_file_checksums & 1) || target->md5_session_checksum) { nwriters++; @@ -2022,6 +2023,16 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) } } + /* This writer has to be added to the list after any writer which might + request production of APM or GPT partition entries by its + compute_data_blocks() method. Its compute_data_blocks() fills the gaps + in APM requests. It determines the position of primary GPT and + backup GPT. Further it reserves blocks for the backup GPT. + */ + ret = gpt_tail_writer_ecma119_writer_create(target); + if (ret < 0) + goto target_cleanup; + /* IMPORTANT: This must be the last writer before the checksum writer */ ret = zero_writer_create(target, target->tail_blocks, 1); if (ret < 0) diff --git a/libisofs/ecma119.h b/libisofs/ecma119.h index 8a03274..9b2dc47 100644 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -805,6 +805,8 @@ struct ecma119_image /* Apple Partition Map description. To be composed during IsoImageWriter method ->compute_data_blocks() by calling iso_register_apm_entry(). + Make sure that the composing writers get registered before the + gpt_tail_writer. */ struct iso_apm_partition_request *apm_req[ISO_APM_ENTRIES_MAX]; int apm_req_count; @@ -813,10 +815,26 @@ struct ecma119_image /* GPT description. To be composed during IsoImageWriter method ->compute_data_blocks() by calling iso_register_gpt_entry(). + Make sure that the composing writers get registered before the + gpt_tail_writer. */ struct iso_gpt_partition_request *gpt_req[ISO_GPT_ENTRIES_MAX]; int gpt_req_count; + /* Messages from gpt_tail_writer_compute_data_blocks() to + iso_write_system_area(). + */ + /* Start of GPT entries in System Area, block size 512 */ + uint32_t gpt_part_start; + /* The ISO block number after the backup GPT header , block size 2048 */ + uint32_t gpt_backup_end; + uint32_t gpt_max_entries; + + /* Message from write_head_part1()/iso_write_system_area() to the + write_data() methods of the writers. + */ + uint8_t sys_area_as_written[16 * BLOCK_SIZE]; + }; #define BP(a,b) [(b) - (a) + 1] diff --git a/libisofs/system_area.c b/libisofs/system_area.c index d221c3b..a153bd0 100644 --- a/libisofs/system_area.c +++ b/libisofs/system_area.c @@ -20,6 +20,7 @@ #include "image.h" #include "messages.h" #include "ecma119.h" +#include "writer.h" #include #include @@ -824,11 +825,102 @@ static int iso_write_apm_entry(Ecma119Image *t, int apm_block_size, return ISO_SUCCESS; } -static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) + +/* Sort and fill gaps in requested APM */ +static int fill_apm_gaps(Ecma119Image *t, uint32_t img_blocks) { int i, ret, gap_counter = 0, up_to; uint32_t part_end, goal; char gap_name[33]; + + /* Find out whether an entry with start_block <= 1 is requested */ + for (i = 0; i < t->apm_req_count; i++) { + if (t->apm_req[i]->start_block <= 1) + break; + } + if (i >= t->apm_req_count) { + ret = iso_quick_apm_entry(t, 1, 0, "Apple", "Apple_partition_map"); + if (ret < 0) + return ret; + } + + qsort(t->apm_req, t->apm_req_count, + sizeof(struct iso_apm_partition_request *), cmp_partition_request); + + /* t->apm_req_count will grow during the loop */ + up_to = t->apm_req_count + 1; + for (i = 1; i < up_to; i++) { + if (i < up_to - 1) + goal = t->apm_req[i]->start_block; + else + goal = img_blocks; + if (i == 1) { + /* Description of APM itself */ + /* Actual APM size is not yet known. Protection begins at PVD */ + part_end = 16; + if (goal < 16 && goal> 1) + part_end = goal; + } else { + part_end = t->apm_req[i - 1]->start_block + + t->apm_req[i - 1]->block_count; + } + if (part_end > goal) { + iso_msg_submit(t->image->id, ISO_BOOT_APM_OVERLAP, 0, + "Program error: APM partitions %d and %d overlap by %lu blocks", + i - 1, i, part_end - goal); + return ISO_BOOT_APM_OVERLAP; + } + if (part_end < goal || i == up_to - 1) { /* Always add a final entry */ + sprintf(gap_name, "Gap%d", gap_counter); + gap_counter++; + ret = iso_quick_apm_entry(t, part_end, goal - part_end, + gap_name, "ISO9660_data"); + if (ret < 0) + return ret; + } + } + + /* Merge list of gap partitions with list of already sorted entries */ + qsort(t->apm_req, t->apm_req_count, + sizeof(struct iso_apm_partition_request *), cmp_partition_request); + + return 1; +} + + +static int rectify_apm(Ecma119Image *t) +{ + int ret; + + if (t->apm_req_count == 0) + return 1; + + /* These are the only APM block sizes which can be processed here */ + if (t->apm_block_size > 1536) + t->apm_block_size = 2048; + else if (t->apm_block_size > 768) + t->apm_block_size = 1024; + else + t->apm_block_size = 512; + if (t->gpt_req_count > 0 && + t->apm_block_size != 2048 && t->apm_req_count > 0) { + t->apm_block_size = 2048; + iso_msgs_submit(0, + "GPT and APM requested. Had to force APM Block size to 2048.", + 0, "DEBUG", 0); + } + if (t->apm_req_count > 0) { + ret = fill_apm_gaps(t, t->curblock); + if (ret < 0) + return ret; + } + return 1; +} + + +static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) +{ + int i, ret; /* This is a micro mick-up of an APM Block0 and also harmless x86 machine code. */ @@ -859,72 +951,23 @@ static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) if (t->apm_req_count <= 0) return 2; - /* Find out whether an entry with start_block == 1 is requested */ - for (i = 0; i < t->apm_req_count; i++) { - if (t->apm_req[i]->start_block <= 1) - break; + /* Adjust last partition to img_size. This size was not known when the + number of APM partitions was determined. + */ + t->apm_req[t->apm_req_count - 1]->block_count = + img_blocks - t->apm_req[t->apm_req_count - 1]->start_block; + /* If it is still empty, remove it */ + if(t->apm_req[t->apm_req_count - 1]->block_count == 0) { + free(t->apm_req[t->apm_req_count - 1]); + t->apm_req_count--; } - if (i >= t->apm_req_count) { - ret = iso_quick_apm_entry(t, 1, 0, "Apple", "Apple_partition_map"); - if (ret < 0) - return ret; - } - - /* Sort and fill gaps */ - qsort(t->apm_req, t->apm_req_count, - sizeof(struct iso_apm_partition_request *), cmp_partition_request); - /* t->apm_req_count will grow during the loop */ - up_to = t->apm_req_count + 1; - for (i = 1; i < up_to; i++) { - if (i < up_to - 1) - goal = t->apm_req[i]->start_block; - else - goal = img_blocks; - if (i == 1) { - /* Description of APM itself */ - /* Actual APM size is not yet known. Protection begins at PVD */ - part_end = 16; - if (goal < 16 && goal> 1) - part_end = goal; - } else { - part_end = t->apm_req[i - 1]->start_block + - t->apm_req[i - 1]->block_count; - } - if (part_end > goal) { - iso_msg_submit(t->image->id, ISO_BOOT_APM_OVERLAP, 0, - "Program error: APM partitions %d and %d overlap by %lu blocks", - i - 1, i, part_end - goal); - return ISO_BOOT_APM_OVERLAP; - } - if (part_end < goal) { - sprintf(gap_name, "Gap%d", gap_counter); - gap_counter++; - ret = iso_quick_apm_entry(t, part_end, goal - part_end, - gap_name, "ISO9660_data"); - if (ret < 0) - return ret; - } - } - - /* Merge list of gap partitions with list of already sorted entries */ - qsort(t->apm_req, t->apm_req_count, - sizeof(struct iso_apm_partition_request *), cmp_partition_request); - - /* These are the only APM block sizes which can be processed here */ - if (t->apm_block_size > 1536) - t->apm_block_size = 2048; - else if (t->apm_block_size > 768) - t->apm_block_size = 1024; - else - t->apm_block_size = 512; /* If block size is larger than 512, then not all 63 entries will fit */ if ((t->apm_req_count + 1) * t->apm_block_size > 32768) return ISO_BOOT_TOO_MANY_APM; + /* Block 1 describes the APM itself */ t->apm_req[0]->start_block = 1; - - /* >>> ts B20526 : ??? isohybrid has 16. Logical block count is 10. Why ?*/ t->apm_req[0]->block_count = t->apm_req_count; /* Write APM block 0. Very sparse, not to overwrite much of possible MBR.*/ @@ -1005,8 +1048,8 @@ int iso_write_gpt_header_block(Ecma119Image *t, uint32_t img_blocks, /* Own LBA high 32 */ iso_lsb_to_buf(&wpt, 0, 4, 0); - /* Backup LBA is 1 hd block before image end */ - back_lba = img_blocks * 4 - 1; + /* Backup header LBA is 1 hd block before backup GPT area end */ + back_lba = t->gpt_backup_end * 4 - 1; iso_lsb_to_buf(&wpt, (uint32_t) (back_lba & 0xffffffff), 4, 1); iso_lsb_to_buf(&wpt, (uint32_t) (back_lba >> 32), 4, 1); @@ -1014,11 +1057,12 @@ int iso_write_gpt_header_block(Ecma119Image *t, uint32_t img_blocks, iso_lsb_to_buf(&wpt, part_start + max_entries / 4, 4, 0); iso_lsb_to_buf(&wpt, 0, 4, 0); - /* Last usable LBA for partitions */ + /* Last usable LBA for partitions is 1 hd block before first backup entry*/ iso_lsb_to_buf(&wpt, - (uint32_t) ((back_lba - max_entries / 4) & 0xffffffff), 4, 1); + (uint32_t) ((back_lba - max_entries / 4 - 1) & 0xffffffff), + 4, 1); iso_lsb_to_buf(&wpt, - (uint32_t) ((back_lba - max_entries / 4) >> 32), 4, 1); + (uint32_t) ((back_lba - max_entries / 4 - 1) >> 32), 4, 1); /* Disk GUID */ /* >>> Make adjustable */ @@ -1048,7 +1092,7 @@ int iso_write_gpt_header_block(Ecma119Image *t, uint32_t img_blocks, } /* CRC-32 of this header while head_crc is 0 */ - crc = iso_crc32_gpt((unsigned char *) buf, 128, 0); + crc = iso_crc32_gpt((unsigned char *) buf, 512, 0); wpt = ((char *) buf) + 16; iso_lsb_to_buf(&wpt, crc, 4, 0); @@ -1068,18 +1112,14 @@ static void poor_man_s_utf_16le(uint8_t gap_name[72]) } -/* - >>> Need to memorize GPT copy for backup writer at tail -*/ -static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, - uint8_t *buf, uint32_t part_start) +static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) { static uint8_t basic_data_uuid[16] = { 0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44, 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 }; - uint32_t p_arr_crc = 0, max_entries, part_end, goal; + uint32_t p_arr_crc = 0, part_end, goal; uint64_t start_lba, end_lba; int ret, i, gap_counter = 0, up_to; struct iso_gpt_partition_request *req; @@ -1087,53 +1127,9 @@ static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; static uint64_t gpt_flags = (((uint64_t) 1) << 60) | 1; -#ifdef NIX - /* Disabled */ - - /* <<< ts B20526 : Dummy mock-up */ - if (t->gpt_req_count <= 0) { - - /* <<< ??? Move to system_area.h and publish as macro ? - Or to make_isohybrid_mbr.c ? - */ - static uint8_t hfs_uuid[16] = { - 0x00, 0x53, 0x46, 0x48, 0x00, 0x00, 0xaa, 0x11, - 0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac - }; - - memset(gpt_name, 0, 72); - gpt_name[0] = 'T'; gpt_name[2] = '1'; - strcpy((char *) gpt_name, "GPT Test 1"); - poor_man_s_utf_16le(gpt_name); - /* - ret = iso_quick_gpt_entry(t, 16, 20, hfs_uuid, zero_uuid, - gpt_flags, gpt_name); - / * >>> Caution: Size 90 causes intentional partition overlap error * / - ret = iso_quick_gpt_entry(t, 30, 90, hfs_uuid, zero_uuid, - gpt_flags, gpt_name); - */ - ret = iso_quick_gpt_entry(t, 30, 40, hfs_uuid, zero_uuid, - gpt_flags, gpt_name); - if (ret < 0) - return ret; - strcpy((char *) gpt_name, "GPT Test 2"); - poor_man_s_utf_16le(gpt_name); - ret = iso_quick_gpt_entry(t, 110, 60, basic_data_uuid, zero_uuid, - gpt_flags, gpt_name); - if (ret < 0) - return ret; - } -#endif /* NIX */ - - if (t->gpt_req_count == 0) return 2; - /* Maximum number of GPT entries of 128 bytes until ISO PVD is reached */ - if (part_start >= 64) - return ISO_ASSERT_FAILURE; /* miscomputation of part_start */ - max_entries = (64 - part_start) * 4; - /* Sort and fill gaps */ qsort(t->gpt_req, t->gpt_req_count, sizeof(struct iso_gpt_partition_request *), cmp_partition_request); @@ -1174,7 +1170,7 @@ static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, qsort(t->gpt_req, t->gpt_req_count, sizeof(struct iso_gpt_partition_request *), cmp_partition_request); - if ((int) max_entries < t->gpt_req_count) + if ((int) t->gpt_max_entries < t->gpt_req_count) return ISO_BOOT_TOO_MANY_GPT; /* Write the GPT entries to buf */ @@ -1182,19 +1178,23 @@ static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, req = t->gpt_req[i]; start_lba = ((uint64_t) req->start_block) * 4; end_lba = ((uint64_t) start_lba) + req->block_count * 4 - 1; - iso_write_gpt_entry(t, buf + 512 * part_start + 128 * i, + iso_write_gpt_entry(t, buf + 512 * t->gpt_part_start + 128 * i, req->type_guid, req->partition_guid, start_lba, end_lba, req->flags, req->name); } - for (; i < (int) max_entries; i++) - memset(buf + 512 * part_start + 128 * i, 0, 128); + for (; i < (int) t->gpt_max_entries; i++) + memset(buf + 512 * t->gpt_part_start + 128 * i, 0, 128); - p_arr_crc = iso_crc32_gpt((unsigned char *) buf + 512 * part_start, - 128 * max_entries, 0); - ret = iso_write_gpt_header_block(t, img_blocks, buf + 512, max_entries, - part_start, p_arr_crc); + p_arr_crc = iso_crc32_gpt((unsigned char *) buf + 512 * t->gpt_part_start, + 128 * t->gpt_max_entries, 0); + ret = iso_write_gpt_header_block(t, img_blocks, buf + 512, + t->gpt_max_entries, + t->gpt_part_start, p_arr_crc); if (ret < 0) return ret; + + /* >>> Memorize GPT copy for backup writer at tail */; + return ISO_SUCCESS; } @@ -1203,7 +1203,7 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) { int ret, int_img_blocks, sa_type, i, will_append = 0; int first_partition = 1, last_partition = 4; - uint32_t img_blocks, gpt_part_start; + uint32_t img_blocks; if ((t == NULL) || (buf == NULL)) { return ISO_NULL_POINTER; @@ -1259,27 +1259,13 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) >>> A sa_type, that does this, will have to adjust the last APM entry >>> if exactness matters. */ - if (t->gpt_req_count > 0 && - t->apm_block_size != 2048 && t->apm_req_count > 0) { - t->apm_block_size = 2048; - iso_msgs_submit(0, - "GPT and APM requested. Had to force APM Block size to 2048.", - 0, "DEBUG", 0); - } ret = iso_write_apm(t, img_blocks, buf); if (ret < 0) { iso_msg_submit(t->image->id, ret, 0, "Cannot set up Apple Partition Map"); return ret; } - gpt_part_start = 0; - if (t->apm_req_count > 0) - gpt_part_start = (t->apm_req_count + 1) * (t->apm_block_size / 512); - if (gpt_part_start < 2) - gpt_part_start = 2; - else if (gpt_part_start >= 64) - return ISO_BOOT_TOO_MANY_GPT; - ret = iso_write_gpt(t, img_blocks, buf, gpt_part_start); + ret = iso_write_gpt(t, img_blocks, buf); if (ret < 0) { iso_msg_submit(t->image->id, ret, 0, "Cannot set up GPT"); return ret; @@ -1649,3 +1635,201 @@ void iso_random_8byte(Ecma119Image *t, uint8_t result[8]) } } + +static int gpt_tail_writer_compute_data_blocks(IsoImageWriter *writer) +{ + Ecma119Image *t; + uint32_t gpt_part_start, gpt_size; + int ret; + + if (writer == NULL) { + return ISO_ASSERT_FAILURE; + } + t = writer->target; + + /* Rectify APM requests early in order to learn the size of GPT. + iso_write_apm() relies on this being already done here. + So perform even if no GPT is required. + */ + ret = rectify_apm(t); + if (ret < 0) + return ret; + +#ifdef NIX + /* Disabled */ + + /* <<< ts B20526 : Dummy mock-up */ + if (t->gpt_req_count <= 0) { + + /* <<< ??? Move to system_area.h and publish as macro ? + Or to make_isohybrid_mbr.c ? + */ + static uint8_t hfs_uuid[16] = { + 0x00, 0x53, 0x46, 0x48, 0x00, 0x00, 0xaa, 0x11, + 0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac + }; + static uint8_t basic_data_uuid[16] = { + 0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44, + 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 + }; + + 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 uint64_t gpt_flags = (((uint64_t) 1) << 60) | 1; + + memset(gpt_name, 0, 72); + gpt_name[0] = 'T'; gpt_name[2] = '1'; + strcpy((char *) gpt_name, "GPT Test 1"); + poor_man_s_utf_16le(gpt_name); + /* + ret = iso_quick_gpt_entry(t, 16, 20, hfs_uuid, zero_uuid, + gpt_flags, gpt_name); + / * >>> Caution: Size 90 causes intentional partition overlap error * / + ret = iso_quick_gpt_entry(t, 30, 90, hfs_uuid, zero_uuid, + gpt_flags, gpt_name); + */ + ret = iso_quick_gpt_entry(t, 30, 40, hfs_uuid, zero_uuid, + gpt_flags, gpt_name); + if (ret < 0) + return ret; + strcpy((char *) gpt_name, "GPT Test 2"); + poor_man_s_utf_16le(gpt_name); + ret = iso_quick_gpt_entry(t, 110, 60, basic_data_uuid, zero_uuid, + gpt_flags, gpt_name); + if (ret < 0) + return ret; + } +#endif /* NIX */ + + /* Is a GPT requested ? */ + t->gpt_backup_end = 0; + t->gpt_max_entries = 0; + if (t->gpt_req_count == 0) + return ISO_SUCCESS; + + /* Determine GPT partition start in System Area, */ + gpt_part_start = 0; + if (t->apm_req_count > 0) + gpt_part_start = (t->apm_req_count + 1) * (t->apm_block_size / 512); + if (gpt_part_start < 2) + gpt_part_start = 2; + else if (gpt_part_start >= 64) + return ISO_BOOT_TOO_MANY_GPT; + t->gpt_part_start = gpt_part_start; + + /* Necessary number of 2K blocks */ + t->gpt_max_entries = (64 - t->gpt_part_start) * 4; + gpt_size = (t->gpt_max_entries / 4 + 1) * 512; + t->curblock += gpt_size / 2048; + if (gpt_size % 2048) + t->curblock++; + /* 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) +{ + return ISO_SUCCESS; +} + + +static int gpt_tail_writer_write_data(IsoImageWriter *writer) +{ + Ecma119Image *t; + uint8_t *head, *new_head, *entries; + uint8_t *backup_buf = NULL; + uint32_t gpt_size, crc, i; + uint64_t part_start; + int ret; + + t = writer->target; + if (t->gpt_backup_end == 0 || t->gpt_max_entries == 0) + return ISO_SUCCESS; /* No backup GPT area reserved by compute_data() */ + + gpt_size = (t->gpt_max_entries / 4 + 1) * 512; + gpt_size = gpt_size / 2048 + !!(gpt_size % 2048); + backup_buf = calloc(1, gpt_size * 2048); + if (backup_buf == NULL) + return ISO_OUT_OF_MEM; + memset(backup_buf, 0, gpt_size * 2048); + + /* Check whether GPT header block came through */ + head = t->sys_area_as_written + 512; + if (strncmp((char *) head, "EFI PART", 8) != 0) { +tampered_head:; + /* Send error message but do not prevent further image production */ + iso_msgs_submit(0, + "GPT header block was altered before writing to System Area.", + 0, "FAILURE", 0); + goto write_zeros; + } + for (i = 92; i < 512; i++) + if (head[i]) + goto tampered_head; + + /* Patch memorized header block */ + new_head = backup_buf + gpt_size * 2048 - 512; + memcpy(new_head, head, 512); + /* Exchange "Location of this header" and "Location of header backup" */ + memcpy(new_head + 24, head + 32, 8); + memcpy(new_head + 32, head + 24, 8); + /* Point to the backup partition entries */ + part_start = ((uint64_t) t->gpt_backup_end) * 4 + - 1 - t->gpt_max_entries / 4; + iso_lsb(new_head + 72, part_start & 0xffffffff, 4); + iso_lsb(new_head + 76, (part_start >> 32) & 0xffffffff, 4); + + /* Compute new header CRC */ + memset(new_head + 16, 0, 4); + crc = iso_crc32_gpt((unsigned char *) new_head, 512, 0); + iso_lsb(new_head + 16, crc, 4); + + /* Copy GPT entries */ + entries = t->sys_area_as_written + t->gpt_part_start * 512; + memcpy(new_head - t->gpt_max_entries * 128, + entries, t->gpt_max_entries * 128); + + ret = iso_write(t, backup_buf, gpt_size * 2048); + free(backup_buf); + if (ret < 0) + return ret; + return ISO_SUCCESS; + +write_zeros:; + ret = iso_write(t, backup_buf, gpt_size * 2048); + free(backup_buf); + if (ret < 0) + return ret; + return ISO_SUCCESS; +} + + +static int gpt_tail_writer_free_data(IsoImageWriter *writer) +{ + return ISO_SUCCESS; +} + + +int gpt_tail_writer_ecma119_writer_create(Ecma119Image *target) +{ + IsoImageWriter *writer; + + writer = calloc(1, sizeof(IsoImageWriter)); + if (writer == NULL) { + return ISO_OUT_OF_MEM; + } + writer->compute_data_blocks = gpt_tail_writer_compute_data_blocks; + writer->write_vol_desc = gpt_tail_writer_write_vol_desc; + writer->write_data = gpt_tail_writer_write_data; + writer->free_data = gpt_tail_writer_free_data; + writer->data = NULL; + writer->target = target; + + /* add this writer to image */ + target->writers[target->nwriters++] = writer; + + return ISO_SUCCESS; +} + diff --git a/libisofs/system_area.h b/libisofs/system_area.h index 3b5cbe9..293e45f 100644 --- a/libisofs/system_area.h +++ b/libisofs/system_area.h @@ -190,4 +190,9 @@ int iso_write_gpt_header_block(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf, uint32_t max_entries, uint32_t part_start, uint32_t p_arr_crc); +/* Creates the GPT backup tail writer. +*/ +int gpt_tail_writer_ecma119_writer_create(Ecma119Image *target); + + #endif /* SYSTEM_AREA_H_ */