Second stage of implementation of GPT production.

It implements the writer class for the backup GPT.
This commit is contained in:
Thomas Schmitt 2012-06-04 20:39:34 +02:00
parent 21109ffcf1
commit 36502f8ae3
4 changed files with 363 additions and 145 deletions

View File

@ -1251,10 +1251,11 @@ static
int write_head_part1(Ecma119Image *target, int *write_count, int flag) int write_head_part1(Ecma119Image *target, int *write_count, int flag)
{ {
int res, i; int res, i;
uint8_t sa[16 * BLOCK_SIZE]; uint8_t *sa;
IsoImageWriter *writer; IsoImageWriter *writer;
size_t buffer_size = 0, buffer_free = 0, buffer_start_free = 0; 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, iso_ring_buffer_get_buf_status(target->buffer, &buffer_size,
&buffer_start_free); &buffer_start_free);
*write_count = 0; *write_count = 0;
@ -1884,15 +1885,14 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
if (target->hfsplus_blessed[i] != NULL) if (target->hfsplus_blessed[i] != NULL)
iso_node_ref(target->hfsplus_blessed[i]); 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; target->apm_block_size = 512;
for (i = 0; i < ISO_APM_ENTRIES_MAX; i++) for (i = 0; i < ISO_APM_ENTRIES_MAX; i++)
target->apm_req[i] = NULL; target->apm_req[i] = NULL;
for (i = 0; i < ISO_GPT_ENTRIES_MAX; i++) for (i = 0; i < ISO_GPT_ENTRIES_MAX; i++)
target->gpt_req[i] = NULL; 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... * 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) { if (target->iso1999) {
nwriters++; nwriters++;
} }
nwriters++; /* GPT backup tail writer */
nwriters++; /* Tail padding writer */ nwriters++; /* Tail padding writer */
if ((target->md5_file_checksums & 1) || target->md5_session_checksum) { if ((target->md5_file_checksums & 1) || target->md5_session_checksum) {
nwriters++; 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 */ /* IMPORTANT: This must be the last writer before the checksum writer */
ret = zero_writer_create(target, target->tail_blocks, 1); ret = zero_writer_create(target, target->tail_blocks, 1);
if (ret < 0) if (ret < 0)

View File

@ -805,6 +805,8 @@ struct ecma119_image
/* Apple Partition Map description. To be composed during IsoImageWriter /* Apple Partition Map description. To be composed during IsoImageWriter
method ->compute_data_blocks() by calling iso_register_apm_entry(). 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]; struct iso_apm_partition_request *apm_req[ISO_APM_ENTRIES_MAX];
int apm_req_count; int apm_req_count;
@ -813,10 +815,26 @@ struct ecma119_image
/* GPT description. To be composed during IsoImageWriter /* GPT description. To be composed during IsoImageWriter
method ->compute_data_blocks() by calling iso_register_gpt_entry(). 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]; struct iso_gpt_partition_request *gpt_req[ISO_GPT_ENTRIES_MAX];
int gpt_req_count; 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] #define BP(a,b) [(b) - (a) + 1]

View File

@ -20,6 +20,7 @@
#include "image.h" #include "image.h"
#include "messages.h" #include "messages.h"
#include "ecma119.h" #include "ecma119.h"
#include "writer.h"
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
@ -824,11 +825,102 @@ static int iso_write_apm_entry(Ecma119Image *t, int apm_block_size,
return ISO_SUCCESS; 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; int i, ret, gap_counter = 0, up_to;
uint32_t part_end, goal; uint32_t part_end, goal;
char gap_name[33]; 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 /* This is a micro mick-up of an APM Block0
and also harmless x86 machine code. 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) if (t->apm_req_count <= 0)
return 2; return 2;
/* Find out whether an entry with start_block == 1 is requested */ /* Adjust last partition to img_size. This size was not known when the
for (i = 0; i < t->apm_req_count; i++) { number of APM partitions was determined.
if (t->apm_req[i]->start_block <= 1) */
break; 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 block size is larger than 512, then not all 63 entries will fit */
if ((t->apm_req_count + 1) * t->apm_block_size > 32768) if ((t->apm_req_count + 1) * t->apm_block_size > 32768)
return ISO_BOOT_TOO_MANY_APM; return ISO_BOOT_TOO_MANY_APM;
/* Block 1 describes the APM itself */
t->apm_req[0]->start_block = 1; 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; t->apm_req[0]->block_count = t->apm_req_count;
/* Write APM block 0. Very sparse, not to overwrite much of possible MBR.*/ /* 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 */ /* Own LBA high 32 */
iso_lsb_to_buf(&wpt, 0, 4, 0); iso_lsb_to_buf(&wpt, 0, 4, 0);
/* Backup LBA is 1 hd block before image end */ /* Backup header LBA is 1 hd block before backup GPT area end */
back_lba = img_blocks * 4 - 1; 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 & 0xffffffff), 4, 1);
iso_lsb_to_buf(&wpt, (uint32_t) (back_lba >> 32), 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, part_start + max_entries / 4, 4, 0);
iso_lsb_to_buf(&wpt, 0, 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, 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, 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 */ /* Disk GUID */
/* >>> Make adjustable */ /* >>> 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-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; wpt = ((char *) buf) + 16;
iso_lsb_to_buf(&wpt, crc, 4, 0); iso_lsb_to_buf(&wpt, crc, 4, 0);
@ -1068,18 +1112,14 @@ static void poor_man_s_utf_16le(uint8_t gap_name[72])
} }
/* static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf)
>>> 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 uint8_t basic_data_uuid[16] = { static uint8_t basic_data_uuid[16] = {
0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44, 0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44,
0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 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; uint64_t start_lba, end_lba;
int ret, i, gap_counter = 0, up_to; int ret, i, gap_counter = 0, up_to;
struct iso_gpt_partition_request *req; 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 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; 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) if (t->gpt_req_count == 0)
return 2; 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 */ /* Sort and fill gaps */
qsort(t->gpt_req, t->gpt_req_count, qsort(t->gpt_req, t->gpt_req_count,
sizeof(struct iso_gpt_partition_request *), cmp_partition_request); 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, qsort(t->gpt_req, t->gpt_req_count,
sizeof(struct iso_gpt_partition_request *), cmp_partition_request); 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; return ISO_BOOT_TOO_MANY_GPT;
/* Write the GPT entries to buf */ /* 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]; req = t->gpt_req[i];
start_lba = ((uint64_t) req->start_block) * 4; start_lba = ((uint64_t) req->start_block) * 4;
end_lba = ((uint64_t) start_lba) + req->block_count * 4 - 1; 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, req->type_guid, req->partition_guid,
start_lba, end_lba, req->flags, req->name); start_lba, end_lba, req->flags, req->name);
} }
for (; i < (int) max_entries; i++) for (; i < (int) t->gpt_max_entries; i++)
memset(buf + 512 * part_start + 128 * i, 0, 128); memset(buf + 512 * t->gpt_part_start + 128 * i, 0, 128);
p_arr_crc = iso_crc32_gpt((unsigned char *) buf + 512 * part_start, p_arr_crc = iso_crc32_gpt((unsigned char *) buf + 512 * t->gpt_part_start,
128 * max_entries, 0); 128 * t->gpt_max_entries, 0);
ret = iso_write_gpt_header_block(t, img_blocks, buf + 512, max_entries, ret = iso_write_gpt_header_block(t, img_blocks, buf + 512,
part_start, p_arr_crc); t->gpt_max_entries,
t->gpt_part_start, p_arr_crc);
if (ret < 0) if (ret < 0)
return ret; return ret;
/* >>> Memorize GPT copy for backup writer at tail */;
return ISO_SUCCESS; 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 ret, int_img_blocks, sa_type, i, will_append = 0;
int first_partition = 1, last_partition = 4; int first_partition = 1, last_partition = 4;
uint32_t img_blocks, gpt_part_start; uint32_t img_blocks;
if ((t == NULL) || (buf == NULL)) { if ((t == NULL) || (buf == NULL)) {
return ISO_NULL_POINTER; 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 >>> A sa_type, that does this, will have to adjust the last APM entry
>>> if exactness matters. >>> 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); ret = iso_write_apm(t, img_blocks, buf);
if (ret < 0) { if (ret < 0) {
iso_msg_submit(t->image->id, ret, 0, iso_msg_submit(t->image->id, ret, 0,
"Cannot set up Apple Partition Map"); "Cannot set up Apple Partition Map");
return ret; return ret;
} }
gpt_part_start = 0; ret = iso_write_gpt(t, img_blocks, buf);
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);
if (ret < 0) { if (ret < 0) {
iso_msg_submit(t->image->id, ret, 0, "Cannot set up GPT"); iso_msg_submit(t->image->id, ret, 0, "Cannot set up GPT");
return ret; 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;
}

View File

@ -190,4 +190,9 @@ int iso_write_gpt_header_block(Ecma119Image *t, uint32_t img_blocks,
uint8_t *buf, uint32_t max_entries, uint8_t *buf, uint32_t max_entries,
uint32_t part_start, uint32_t p_arr_crc); 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_ */ #endif /* SYSTEM_AREA_H_ */