From 85bedae639249dfdae86dba50a8cd1a8de387a68 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Thu, 21 Jun 2012 12:29:00 +0200 Subject: [PATCH] Introduced opportunity to choose an MBR partition number with struct iso_mbr_partition_request and iso_quick_mbr_entry(). --- libisofs/system_area.c | 75 +++++++++++++++++++++++++++++++++--------- libisofs/system_area.h | 25 ++++++++++++-- 2 files changed, 82 insertions(+), 18 deletions(-) diff --git a/libisofs/system_area.c b/libisofs/system_area.c index f6019c2..8fa2b24 100644 --- a/libisofs/system_area.c +++ b/libisofs/system_area.c @@ -776,11 +776,18 @@ int iso_quick_gpt_entry(Ecma119Image *t, int iso_quick_mbr_entry(Ecma119Image *t, uint32_t start_block, uint32_t block_count, - uint8_t type_byte, uint8_t status_byte) + uint8_t type_byte, uint8_t status_byte, + int desired_slot) { int ret; struct iso_mbr_partition_request *entry; + ret = iso_mbr_entry_slot_is_free(t, desired_slot); + if (ret < 0) + desired_slot = 0; + else if (ret == 0) + return ISO_BOOT_MBR_COLLISION; + entry = calloc(1, sizeof(struct iso_mbr_partition_request)); if (entry == NULL) return ISO_OUT_OF_MEM; @@ -788,14 +795,30 @@ int iso_quick_mbr_entry(Ecma119Image *t, entry->block_count = block_count; entry->type_byte = type_byte; entry->status_byte = status_byte; + entry->desired_slot = desired_slot; ret = iso_register_mbr_entry(t, entry, 0); free(entry); return ret; } +int iso_mbr_entry_slot_is_free(Ecma119Image *t, int slot) +{ + int i; + + if (slot < 0 || slot > ISO_MBR_ENTRIES_MAX) + return -1; + if (slot == 0) + return 1; + for (i = 0; i < t->mbr_req_count; i++) + if (t->mbr_req[i]->desired_slot == slot) + return 0; + return 1; +} + + /** - * Compare the start_sectors of two iso_apm_partition_request + * Compare the block interval positions of two iso_apm_partition_request */ static int cmp_partition_request(const void *f1, const void *f2) @@ -1067,17 +1090,17 @@ static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf, static int iso_write_mbr(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) { - int i, ret; + int i, ret, req_of_slot[ISO_MBR_ENTRIES_MAX], q, j; #ifdef NIX /* Disabled */ /* <<< Dummy mock-up */ if (t->mbr_req_count <= 0) { - ret = iso_quick_mbr_entry(t, 0, 0, 0xee, 0); + ret = iso_quick_mbr_entry(t, 0, 0, 0xee, 0, 0); if (ret < 0) return ret; - ret = iso_quick_mbr_entry(t, 100, 0, 0x0c, 0x80); + ret = iso_quick_mbr_entry(t, 100, 0, 0x0c, 0x80, 1); if (ret < 0) return ret; } @@ -1110,22 +1133,43 @@ static int iso_write_mbr(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) t->mbr_req[i]->start_block; } - /* >>> Permutate ? */ + /* Assign requested entries to slot numbers */ + for (i = 0; i < ISO_MBR_ENTRIES_MAX; i++) + req_of_slot[i] = -1; + for (i = 0; i < t->mbr_req_count; i++) { + if (t->mbr_req[i]->desired_slot < 1 || + t->mbr_req[i]->desired_slot > ISO_MBR_ENTRIES_MAX) + continue; + if (req_of_slot[t->mbr_req[i]->desired_slot - 1] >= 0) + return ISO_BOOT_MBR_COLLISION; + req_of_slot[t->mbr_req[i]->desired_slot - 1] = i; + } + for (i = 0; i < t->mbr_req_count; i++) { + if (t->mbr_req[i]->desired_slot > 0) + continue; + for (j = 0; j < ISO_MBR_ENTRIES_MAX; j++) + if (req_of_slot[j] < 0) + break; + if (j >= ISO_MBR_ENTRIES_MAX) + return ISO_BOOT_TOO_MANY_MBR; + req_of_slot[j] = i; + } /* Write partition slots */ for (i = 0; i < ISO_MBR_ENTRIES_MAX; i++) { memset(buf + 446 + i * 16, 0, 16); - if (i >= t->mbr_req_count) + q = req_of_slot[i]; + if (q < 0) continue; - if (t->mbr_req[i]->block_count == 0) + if (t->mbr_req[q]->block_count == 0) continue; - ret = write_mbr_partition_entry(i + 1, (int) t->mbr_req[i]->type_byte, - t->mbr_req[i]->start_block, t->mbr_req[i]->block_count, + ret = write_mbr_partition_entry(i + 1, (int) t->mbr_req[q]->type_byte, + t->mbr_req[q]->start_block, t->mbr_req[q]->block_count, t->partition_secs_per_head, t->partition_heads_per_cyl, buf, 0); if (ret < 0) return ret; - buf[446 + i * 16] = t->mbr_req[i]->status_byte; + buf[446 + i * 16] = t->mbr_req[q]->status_byte; } return ISO_SUCCESS; } @@ -2152,7 +2196,7 @@ static int partprepend_writer_compute_data_blocks(IsoImageWriter *writer) if (t->prep_partition != NULL || t->fat || will_have_gpt || t->mbr_req_count > 0) return ISO_BOOT_MBR_OVERLAP; - ret = iso_quick_mbr_entry(t, (uint32_t) 0, (uint32_t) 0, 0x96, 0); + ret = iso_quick_mbr_entry(t, (uint32_t) 0, (uint32_t) 0, 0x96, 0, 0); if (ret < 0) return ret; return ISO_SUCCESS; @@ -2167,12 +2211,13 @@ static int partprepend_writer_compute_data_blocks(IsoImageWriter *writer) if (t->prep_part_size > 0 || t->fat || will_have_gpt) { /* Protecting MBR entry for ISO start or whole ISO */ ret = iso_quick_mbr_entry(t, (uint32_t) t->partition_offset, - (uint32_t) 0, will_have_gpt ? 0xee : 0xcd, 0); + (uint32_t) 0, will_have_gpt ? 0xee : 0xcd, 0, 0); if (ret < 0) return ret; } if (t->prep_part_size > 0) { - ret = iso_quick_mbr_entry(t, t->curblock, t->prep_part_size, 0x41, 0); + ret = iso_quick_mbr_entry(t, t->curblock, t->prep_part_size, 0x41, + 0, 0); if (ret < 0) return ret; t->curblock += t->prep_part_size; @@ -2180,7 +2225,7 @@ static int partprepend_writer_compute_data_blocks(IsoImageWriter *writer) if (t->prep_part_size > 0 || t->fat) { /* FAT partition or protecting MBR entry for ISO end */ ret = iso_quick_mbr_entry(t, (uint32_t) t->curblock, (uint32_t) 0, - t->fat ? 0x0c : 0xcd, 0); + t->fat ? 0x0c : 0xcd, 0, 0); if (ret < 0) return ret; } diff --git a/libisofs/system_area.h b/libisofs/system_area.h index 38345cc..598aea9 100644 --- a/libisofs/system_area.h +++ b/libisofs/system_area.h @@ -67,7 +67,9 @@ int iso_compute_append_partitions(Ecma119Image *t, int flag); /* The parameter struct for production of a single MBR partition entry. See also the description of MBR in doc/boot_sectors.txt. - No sorting and gap filling is done before the System Area gets written. + No sorting by start sector and gap filling is done before the System Area + gets written. But the entries may get assigned to a desired slot number + in the table. Requested entries with block_count == 0 get expanded to the start of the next requested entry resp. to image end, if no entry follows. start_block of a follwing entry must be at least a high as the sum of @@ -90,7 +92,15 @@ struct iso_mbr_partition_request { /* 0x80 = bootable */ uint8_t status_byte; - /* >>> Is a permutation of entries needed ? */ + /* If >= 1 && <= 4 : The partition slot number in MBR. + If more than one partition desires the same slot, then an error + ISO_BOOT_MBR_COLLISION occurs at registration time. + Use iso_mbr_entry_slot_is_free() to detect this in advance. + If desired_slot is 0, then the partition entry is put into the + lowest MBR slot that is not occupied by an entry with desired_slot > 0 + or by an entry that was registered before this entry. + */ + int desired_slot; }; @@ -106,7 +116,16 @@ int iso_register_mbr_entry(Ecma119Image *t, */ int iso_quick_mbr_entry(Ecma119Image *t, uint32_t start_block, uint32_t block_count, - uint8_t type_byte, uint8_t status_byte); + uint8_t type_byte, uint8_t status_byte, + int desired_slot); + +/* Peek in advance whether a desired slot number is already occupied by a + registered MBR entry. + Parameter slot may be between 0 and 4. 0 always returns "free". + Return value is 0 if occupied, 1 if free, and -1 if the slot number is + out of range. +*/ +int iso_mbr_entry_slot_is_free(Ecma119Image *t, int slot); /* The parameter struct for production of a single Apple Partition Map entry.