diff --git a/doc/boot_sectors.txt b/doc/boot_sectors.txt index 7850b0f..26106fa 100644 --- a/doc/boot_sectors.txt +++ b/doc/boot_sectors.txt @@ -580,7 +580,7 @@ Basic data partition: a2 a0 d0 eb , e5 b9 , 33 44 , 87 c0 68 b6 b7 26 99 c7 HFS+ partition : 00 53 46 48 , 00 00 , aa 11 , aa 11 00 30 65 43 ec ac EFI System partition: 28 73 2a c1 , 1f f8 , d2 11 , ba 4b 00 a0 c9 3e c9 3b Note that the wikipedia list shows the first 32-bit word and the next two -16-bit words in little-endia interpretation. +16-bit words in little-endian interpretation. The partition table is an array of entries. Each has a size of 128 bytes. A partition table entry looks like: diff --git a/libisofs/ecma119.h b/libisofs/ecma119.h index 6c2983f..8006536 100644 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -768,8 +768,8 @@ struct ecma119_image /* Allocation block size of HFS+ May be defined to 512 or 2048 before hfsplus_writer_create(). */ - int hfsp_cat_node_size; /* 2 * apm_block_size */ - int hfsp_iso_block_fac; /* 2048 / apm_block_size */ + int hfsp_cat_node_size; /* 2 * hfsp_block_size */ + int hfsp_iso_block_fac; /* 2048 / hfsp_block_size */ /* Apple Partition Map description. To be composed during IsoImageWriter method ->compute_data_blocks() by calling iso_register_apm_entry(). diff --git a/libisofs/eltorito.c b/libisofs/eltorito.c index 6b0f5b1..119d4e2 100644 --- a/libisofs/eltorito.c +++ b/libisofs/eltorito.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2010 - 2013 Thomas Schmitt + * Copyright (c) 2010 - 2014 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 @@ -440,6 +440,8 @@ int create_image(IsoImage *image, const char *image_path, iso_node_ref(imgfile); /* get our ref */ boot->bootable = 1; boot->seems_boot_info_table = 0; + boot->seems_grub2_boot_info = 0; + boot->seems_isohybrid_capable = 0; boot->isolinux_options = 0; boot->type = boot_media_type; boot->partition_type = partition_type; diff --git a/libisofs/eltorito.h b/libisofs/eltorito.h index d26c01a..acfd43e 100644 --- a/libisofs/eltorito.h +++ b/libisofs/eltorito.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2010 Thomas Schmitt + * Copyright (c) 2010 - 2014 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 @@ -59,6 +59,10 @@ struct el_torito_boot_image { */ unsigned int seems_boot_info_table:1; unsigned int seems_grub2_boot_info:1; + /** + * Whether the boot image seems to be capable of isohybrid + */ + unsigned int seems_isohybrid_capable:1; /** * isolinux options * bit 0 -> whether to patch image diff --git a/libisofs/fs_image.c b/libisofs/fs_image.c index eedbff5..eb18fe5 100644 --- a/libisofs/fs_image.c +++ b/libisofs/fs_image.c @@ -26,6 +26,7 @@ #include "eltorito.h" #include "node.h" #include "aaip_0_2.h" +#include "system_area.h" #include #include @@ -3491,6 +3492,7 @@ int iso_image_eval_boot_info_table(IsoImage *image, struct iso_read_opts *opts, boot_file = boot->image; boot->seems_boot_info_table = 0; boot->seems_grub2_boot_info = 0; + boot->seems_isohybrid_capable = 0; img_size = iso_file_get_size(boot_file); if (img_size > Libisofs_boot_image_max_sizE || img_size < 64) continue; @@ -3565,6 +3567,10 @@ int iso_image_eval_boot_info_table(IsoImage *image, struct iso_read_opts *opts, if (blk == img_lba * 4 + Libisofs_grub2_elto_patch_offsT) boot->seems_grub2_boot_info = 1; } + if (img_size >= 68 && boot->seems_boot_info_table) + if (boot_image_buf[64] == 0xfb && boot_image_buf[65] == 0xc0 && + boot_image_buf[66] == 0x78 && boot_image_buf[67] == 0x70) + boot->seems_isohybrid_capable = 1; free(boot_image_buf); boot_image_buf = NULL; @@ -3594,6 +3600,1465 @@ void issue_collision_warning_summary(size_t failures) } } +/* Mark all non-matching combinations of head_per_cyl and sectors_per_head + in the matches bitmap. This is a brute force approach to find the common + intersections of up to 8 hyperbolas additionally intersected with the grid + of integer coordinates {1..255}x{1..63}. + Given the solution space size of only 14 bits, it seems inappropriate to + employ any algebra. +*/ +static +void iso_scan_hc_sh(uint32_t lba, int c, int h, int s, uint8_t *matches) +{ + int i, j; + uint32_t res; + +/* + fprintf(stderr, "iso_scan_hc_sh :%d = %4d/%3d/%2d :\n", lba, c, h, s); +*/ + if (lba == ((uint32_t) s) - 1 && c == 0 && h == 0) /* trivial solutions */ + return; + if (c == 1023 && h >= 254 && s == 63) /* Indicators for invalid CHS */ + return; + + /* matches(i=0,j=1) == 0 indicates presence of non-trivial equations */ + matches[0] &= ~1; + + for (i = 1; i <= 255; i++) { + for (j = 1; j <= 63; j++) { + res = ((c * i) + h) * j + (s - 1); + if (res != lba) { + matches[(i / 8) * 32 + (j - 1)] &= ~(1 << (i % 8)); +/* + } else { + if (matches[(i / 8) * 32 + (j - 1)] & (1 << (i % 8))) + fprintf(stderr, + "iso_scan_hc_sh :%d = %4d/%3d/%2d : H/C= %3d S/H= %2d\n", + lba, c, h, s, i, j); +*/ + } + } + } +} + +/* Pick a good remaining solution from the matches bitmap. +*/ +static +void iso_get_hc_sh(uint8_t *matches, uint32_t iso_image_size, + int *hc, int *sh, int flag) +{ + int i, j, k; + static int pref[][2] = {{64, 32}, {255, 63}}, prefs = 2; + + *hc = *sh = 0; + + if (matches[0] & 1) + return; /* Only trivial equations seen */ + + /* Look for preferred layouts */ + for (k = 0; k < prefs; k++) { + i = pref[k][0]; + j = pref[k][1]; + if ((uint32_t) (1024 / 4 * i * j) <= iso_image_size) + continue; + if (matches[(i / 8) * 32 + (j - 1)] & (1 << (i % 8))) { + *hc = i; + *sh = j; + return; + } + } + + /* Look for largest possible cylinder */ + for (i = 1; i <= 255; i++) { + for (j = 1; j <= 63; j++) { + if ((uint32_t) (1024 / 4 * i * j) <= iso_image_size) + continue; + if (matches[(i / 8) * 32 + (j - 1)] & (1 << (i % 8))) { + if( i * j < *hc * *sh) + continue; + *hc = i; + *sh = j; + } + } + } +} + +static +int iso_analyze_mbr_ptable(IsoImage *image, int flag) +{ + int i, j, ret, cyl_align_mode, part_after_image = 0; + uint32_t start_h, start_s, start_c, end_h, end_s, end_c, sph = 0, hpc = 0; + uint32_t start_lba, num_blocks, end_chs_lba, image_size, lba, cyl_size; + uint8_t *data, pstatus, ptype, *hc_sh = NULL; + struct iso_imported_sys_area *sai; + + /* Bitmap for finding head_per_cyl and sectors_per_head. */ + LIBISO_ALLOC_MEM(hc_sh, uint8_t, 32 * 63); + memset(hc_sh, 0xff, 32 * 63); + + sai = image->imported_sa_info; + image_size = sai->image_size; + for (i = 0; i < 4; i++) { + data = (uint8_t *) (image->system_area_data + 446 + 16 * i); + for (j = 0; j < 16; j++) + if (data[j]) + break; + if (j == 16) + continue; + pstatus = data[0]; + ptype = data[4]; + start_c = ((data[2] & 0xc0) << 2) | data[3]; + start_h = data[1]; + start_s = data[2] & 63; + end_c = ((data[6] & 0xc0) << 2) | data[7]; + end_h = data[5]; + end_s = data[6] & 63; + start_lba = iso_read_lsb(data + 8, 4); + num_blocks = iso_read_lsb(data + 12, 4); + if (num_blocks <= 0) + continue; + if (sph > 0) { + if (end_s != sph) + sph = 0xffffffff; + } else if (sph == 0) { + sph = end_s; + } + if (hpc > 0) { + if (end_h + 1 != hpc) + hpc = 0xffffffff; + } else if (hpc == 0) { + hpc = end_h + 1; + } + /* Check whether start_lba + num_blocks - 1 matches chs,hpc,spc */ + end_chs_lba = ((end_c * hpc) + end_h) * sph + end_s; + if (hpc > 0 && hpc < 0xffffffff && sph > 0 && sph < 0xffffffff) + if (end_chs_lba != start_lba + num_blocks) + hpc = sph = 0xffffffff; + /* In case that end CHS does not give cylinder layout */ + iso_scan_hc_sh(start_lba, start_c, start_h, start_s, hc_sh); + iso_scan_hc_sh(start_lba + num_blocks - 1, end_c, end_h, end_s, hc_sh); + + /* Register partition as iso_mbr_partition_request */ + if (sai->mbr_req == NULL) { + sai->mbr_req = calloc(ISO_MBR_ENTRIES_MAX, + sizeof(struct iso_mbr_partition_request)); + if (sai->mbr_req == NULL) + {ret = ISO_OUT_OF_MEM; goto ex;} + } + ret = iso_quick_mbr_entry(sai->mbr_req, &(sai->mbr_req_count), + (uint64_t) start_lba, (uint64_t) num_blocks, + ptype, pstatus, i + 1); + if (ret < 0) + goto ex; + if ((start_lba + num_blocks + 3) / 4 > image_size) + image_size = (start_lba + num_blocks + 3) / 4; + } + + if (hpc > 0 && hpc < 0xffffffff && sph > 0 && sph < 0xffffffff) { + sai->partition_secs_per_head = sph; + sai->partition_heads_per_cyl = hpc; + } else { + /* Look for the best C/H/S parameters caught in scan */ + iso_get_hc_sh(hc_sh, image_size, &(sai->partition_heads_per_cyl), + &(sai->partition_secs_per_head), 0); + } + + cyl_align_mode = 2; /* off */ + if (sai->partition_secs_per_head >0 && sai->partition_heads_per_cyl > 0 && + sai->mbr_req_count > 0) { + /* Check for cylinder alignment */ + for (i = 0; i < sai->mbr_req_count; i++) { + cyl_size = sai->partition_secs_per_head * + sai->partition_heads_per_cyl; + lba = sai->mbr_req[i]->start_block + sai->mbr_req[i]->block_count; + if (sai->mbr_req[i]->start_block >= sai->image_size) + part_after_image = 1; + end_c = lba / cyl_size; + if (end_c * cyl_size != lba) + break; + } + if (i == sai->mbr_req_count && part_after_image) + cyl_align_mode = 3; /* all */ + else if (i >= 1) + cyl_align_mode = 1; /* on */ + } + sai->system_area_options &= ~(3 << 8); + sai->system_area_options |= (cyl_align_mode << 8); + ret = 1; +ex: + LIBISO_FREE_MEM(hc_sh); + return ret; + +} + +/* @return 0= no hybrid detected + 1= ISOLINUX isohybrid (options & 2) + 2= GRUB2 MBR patching (options & (1 << 14)) +*/ +static +int iso_analyze_isohybrid(IsoImage *image, int flag) +{ + uint8_t *sad; + uint32_t eltorito_lba = 0; + uint64_t mbr_lba; + int i, section_count, ret; + ElToritoBootImage *boot; + struct iso_file_section *sections; + + sad = (uint8_t *) image->system_area_data; + + /* Learn LBA of boot image */; + if (image->bootcat == NULL) + return 0; + if (image->bootcat->num_bootimages < 1) + return 0; + boot = image->bootcat->bootimages[0]; + if (boot == NULL) + return 0; + ret = iso_file_get_old_image_sections(boot->image, §ion_count, + §ions, 0); + if (ret < 0) + return ret; + if (section_count > 0) + eltorito_lba = sections[0].block; + free(sections); + + /* Check MBR whether it is ISOLINUX and learn LBA to which it points */ + if (!boot->seems_isohybrid_capable) + goto try_grub2_mbr; + for (i= 0; i < 426; i++) + if(strncmp((char *) (sad + i), "isolinux", 8) == 0) + break; + if (i < 426) { /* search text was found */ + mbr_lba = iso_read_lsb(sad + 432, 4); + mbr_lba /= 4; + if (mbr_lba == eltorito_lba) + return 1; + goto try_grub2_mbr; + } + +try_grub2_mbr:; + /* Check for GRUB2 MBR patching */ + mbr_lba = iso_read_lsb64(sad + 0x1b0); + if (mbr_lba / 4 - 1 == eltorito_lba) + return 2; + + return 0; +} + +static +int iso_analyze_mbr(IsoImage *image, IsoDataSource *src, int flag) +{ + int sub_type = 2, ret, is_isohybrid = 0, is_grub2_mbr = 0; + int is_protective_label = 0; + char *sad; + off_t p_offset; + uint8_t *buf = NULL; + struct iso_imported_sys_area *sai; + struct iso_mbr_partition_request *part; + struct ecma119_pri_vol_desc *pvm; + + sad = image->system_area_data; + sai = image->imported_sa_info; + + /* Is it an MBR ? */ + if (((unsigned char *) sad)[510] != 0x55 || + ((unsigned char *) sad)[511] != 0xaa) + {ret = 0; goto ex;} + + ret = iso_analyze_mbr_ptable(image, 0); + if (ret <= 0) + goto ex; + + ret = iso_analyze_isohybrid(image, 0); + if (ret < 0) + goto ex; + if (ret == 1) { + sub_type = 0; + is_isohybrid = 1; + } else if(ret == 2) { + sub_type = 0; + is_grub2_mbr = 1; + } + + if (sai->mbr_req_count == 1 && !is_isohybrid) { + part = sai->mbr_req[0]; + if (part->start_block == 1 && + part->block_count + 1 == ((uint64_t) sai->image_size) * 4) { + /* libisofs protective msdos label for GRUB2 */ + is_protective_label = 1; + sub_type = 0; + } else if (part->start_block == 0 && + part->block_count <= ((uint64_t) sai->image_size) * 4 && + part->block_count + 600 >= ((uint64_t) sai->image_size) * 4 && + part->type_byte == 0x96) { + /* CHRP (possibly without padding) */ + sub_type = 1; + } else if (sai->mbr_req[0]->start_block > 0 && + (sai->mbr_req[0]->start_block % 4) == 0 && + (sai->mbr_req[0]->start_block + + sai->mbr_req[0]->block_count) / 4 <= sai->image_size && + part->type_byte == 0x41) { + /* mkisofs PReP partition */ + sai->prep_part_start = sai->mbr_req[0]->start_block / 4; + sai->prep_part_size = (sai->mbr_req[0]->block_count + 3) / 4; + sub_type = 0; + } + } else if (sai->mbr_req_count == 3 && !is_isohybrid) { + /* Check for libisofs PReP partitions : + 0xee or 0xcd from 0 to a-1 + 0x41 from a to b + 0x0c or 0xcd from b+1 to end + */ + if ((sai->mbr_req[0]->start_block == 0 && + (sai->mbr_req[0]->type_byte == 0xee || + sai->mbr_req[0]->type_byte == 0xcd)) && + sai->mbr_req[0]->block_count == sai->mbr_req[1]->start_block && + sai->mbr_req[1]->type_byte == 0x41 && + (sai->mbr_req[1]->start_block % 4) == 0 && + sai->mbr_req[1]->start_block + sai->mbr_req[1]->block_count == + sai->mbr_req[2]->start_block && + (sai->mbr_req[2]->type_byte == 0x0c || + sai->mbr_req[2]->type_byte == 0xcd) && + (sai->mbr_req[2]->start_block + sai->mbr_req[2]->block_count) / 4 + == sai->image_size) { + sai->prep_part_start = sai->mbr_req[1]->start_block / 4; + sai->prep_part_size = (sai->mbr_req[1]->block_count + 3) / 4; + sub_type = 0; + } + } + + /* Check for partition offset with extra set of meta data */ + if (sai->mbr_req_count > 0) { + part = sai->mbr_req[0]; + if ((part->status_byte == 0x80 || part->status_byte == 0) && + part->start_block >= 64 && part->block_count >= 72 && + part->start_block <= 2048 && + part->start_block % 4 == 0 && part->block_count % 4 == 0 && + (part->start_block + part->block_count) / 4 == sai->image_size) { + + /* Check for PVD at partition start with same end */ + LIBISO_ALLOC_MEM(buf, uint8_t, 2048); + p_offset = part->start_block / 4; + ret = src->read_block(src, p_offset + 16, buf); + if (ret > 0) { + pvm = (struct ecma119_pri_vol_desc *) buf; + if (strncmp((char*) pvm->std_identifier, "CD001", 5) == 0 && + pvm->vol_desc_type[0] == 1 && + pvm->vol_desc_version[0] == 1 && + pvm->file_structure_version[0] == 1 && + iso_read_lsb(pvm->vol_space_size, 4) + p_offset + == sai->image_size) + sai->partition_offset = p_offset; + } + } + } + + /* Set sa type 0, sub type as chosen */ + sai->system_area_options = (sai->system_area_options & 0xffff8300) | + is_protective_label | + (is_isohybrid << 1) | + (sub_type << 10) | + (is_grub2_mbr << 14); + ret = 1; +ex:; + LIBISO_FREE_MEM(buf); + return ret; +} + +static +int iso_seems_usable_gpt_head(uint8_t *head, int flag) +{ + uint32_t head_size, entry_size; + + if (strncmp((char *) head, "EFI PART", 8) != 0) /* signature */ + return 0; + if (head[8] || head[9] || head[10] != 1 || head[11]) /* revision */ + return 0; + head_size = iso_read_lsb(head + 12, 4); + if (head_size < 92) + return 0; + entry_size = iso_read_lsb(head + 84, 4); + if (entry_size != 128) + return 0; + return 1; +} + +static +int iso_analyze_gpt_backup(IsoImage *image, IsoDataSource *src, int flag) +{ + struct iso_imported_sys_area *sai; + uint64_t part_start; + uint32_t iso_block, found_crc, crc, entry_count, array_crc; + uint8_t *head, *part_array, *b_part, *m_part; + int ret, i, num_iso_blocks, l, j, entries_diff; + unsigned char *buf = NULL; + char *comments = NULL; + + sai = image->imported_sa_info; + LIBISO_ALLOC_MEM(buf, unsigned char, 34 * 1024); + LIBISO_ALLOC_MEM(comments, char, 4096); + + /* Read ISO block with backup head */ + if (sai->gpt_backup_lba >= ((uint64_t) sai->image_size) * 4) { + sprintf(comments + strlen(comments), "Implausible header LBA %.f, ", + (double) sai->gpt_backup_lba); + ret = 0; goto ex; + } + iso_block = sai->gpt_backup_lba / 4; + ret = src->read_block(src, iso_block, buf); + if (ret < 0) { + sprintf(comments + strlen(comments), + "Cannot read header block at 2k LBA %.f, ", + (double) iso_block); + goto ex; + } + head = buf + (sai->gpt_backup_lba % 4) * 512; + ret = iso_seems_usable_gpt_head(head, 0); + if (ret == 0) + strcat(comments, + "Not a GPT 1.0 header of 92 bytes for 128 bytes per entry, "); + if (ret <= 0) + goto ex; + + /* Check head CRC */ + found_crc = iso_read_lsb(head + 16, 4); + memset(head + 16, 0, 4); + crc = iso_crc32_gpt((unsigned char *) head, 92, 0); + if (found_crc != crc) { + sprintf(comments + strlen(comments), + "Head CRC 0x%8x wrong. Should be 0x%8x", + found_crc, crc); + crc = iso_crc32_gpt((unsigned char *) head, 512, 0); + if (found_crc == crc) { + strcat(comments, ". Matches all 512 block bytes, "); + } else { + strcat(comments, ", "); + ret = 0; goto ex; + } + } + for (i = 0; i < 16; i ++) + if (head[i + 56] != sai->gpt_disk_guid[i]) + break; + if (i < 16) { + sprintf(comments + strlen(comments), "Disk GUID differs ("); + iso_util_bin_to_hex(comments + strlen(comments), head + 56, 16, 0); + sprintf(comments + strlen(comments), "), "); + } + + /* Header content will possibly be overwritten now */ + array_crc = iso_read_lsb(head + 88, 4); + part_start = iso_read_lsb64(head + 72); + entry_count = iso_read_lsb(head + 80, 4); + head = NULL; + + /* Read backup array */ + if (entry_count != sai->gpt_max_entries) { + sprintf(comments + strlen(comments), + "Number of array entries %u differs from main GPT %u, ", + entry_count, sai->gpt_max_entries); + ret = 0; goto ex; + } + if (part_start >= ((uint64_t) sai->image_size) * 4) { + sprintf(comments + strlen(comments), "Implausible array LBA %.f, ", + (double) part_start); + ret = 0; goto ex; + } + iso_block = part_start / 4; + num_iso_blocks = (part_start + (entry_count + 3) / 4) / 4 - iso_block + 1; + for (i = 0; i < num_iso_blocks; i++) { + ret = src->read_block(src, iso_block + (uint32_t) i, buf + i * 2048); + if (ret < 0) { + sprintf(comments + strlen(comments), + "Cannot read array block at 2k LBA %.f, ", + (double) iso_block); + goto ex; + } + } + part_array = buf + (part_start % 4) * 512; + + crc = iso_crc32_gpt((unsigned char *) part_array, 128 * entry_count, 0); + if (crc != array_crc) { + sprintf(comments + strlen(comments), + "Array CRC 0x%8x wrong. Should be 0x%8x, ", array_crc, crc); + ret = 0; goto ex; + } + + /* Compare entries */ + entries_diff = 0; + for (i = 0; i < (int) entry_count; i++) { + b_part = part_array + 128 * i; + m_part = ((uint8_t *) image->system_area_data) + + sai->gpt_part_start * 512 + 128 * i; + for (j = 0; j < 128; j++) + if (b_part[j] != m_part[j]) + break; + if (j < 128) { + if (!entries_diff) { + strcat(comments, "Entries differ for partitions"); + entries_diff = 1; + } + sprintf(comments + strlen(comments), " %d", i + 1); + } + } + if (entries_diff) { + strcat(comments, ", "); + ret = 0; goto ex; + } + + ret = 1; +ex:; + if (comments != NULL) { + l = strlen(comments); + if (l > 2) + if (comments[l - 2] == ',' && comments[l - 1] == ' ') + comments[l - 2] = 0; + sai->gpt_backup_comments = strdup(comments); + if (sai->gpt_backup_comments == NULL) + ret = ISO_OUT_OF_MEM; + } + LIBISO_FREE_MEM(comments); + LIBISO_FREE_MEM(buf); + return ret; +} + +static +int iso_analyze_gpt_head(IsoImage *image, IsoDataSource *src, int flag) +{ + struct iso_imported_sys_area *sai; + uint8_t *head; + uint32_t crc; + uint64_t part_start; + int ret; + unsigned char *crc_buf = NULL; + + sai = image->imported_sa_info; + head = ((uint8_t *) image->system_area_data) + 512; + LIBISO_ALLOC_MEM(crc_buf, unsigned char, 512); + + /* Is this a GPT header with digestible parameters ? */ + ret = iso_seems_usable_gpt_head(head, 0); + if (ret <= 0) + goto ex; + memcpy(crc_buf, head, 512); + memset(crc_buf + 16, 0, 4); /* CRC is computed when head_crc is 0 */ + sai->gpt_head_crc_found = iso_read_lsb(head + 16, 4); + sai->gpt_head_crc_should = iso_crc32_gpt((unsigned char *) crc_buf, 92, 0); + if (sai->gpt_head_crc_found != sai->gpt_head_crc_should) { + /* There was a bug during libisofs-1.2.4 to libisofs-1.2.8 + (fixed in rev 1071). So accept the buggy CRC if it matches the + whole GPT header block. */ + crc = iso_crc32_gpt((unsigned char *) crc_buf, 512, 0); + if (sai->gpt_head_crc_found != crc) + {ret = 0; goto ex;} + } + part_start = iso_read_lsb64(head + 72); + sai->gpt_max_entries = iso_read_lsb(head + 80, 4); + if (part_start + (sai->gpt_max_entries + 3) / 4 > 64) + {ret = 0; goto ex;} + + /* Fetch desired information */ + memcpy(sai->gpt_disk_guid, head + 56, 16); + sai->gpt_part_start = part_start; + sai->gpt_backup_lba = iso_read_lsb64(head + 32); + sai->gpt_first_lba = iso_read_lsb64(head + 40); + sai->gpt_last_lba = iso_read_lsb64(head + 48); + sai->gpt_array_crc_found = iso_read_lsb(head + 88, 4); + sai->gpt_array_crc_should = + iso_crc32_gpt((unsigned char *) image->system_area_data + + sai->gpt_part_start * 512, + sai->gpt_max_entries * 128, 0); + + ret = iso_analyze_gpt_backup(image, src, 0); + if (ret < 0) + goto ex; + + ret = 1; +ex: + LIBISO_FREE_MEM(crc_buf); + return ret; +} + +static +int iso_analyze_gpt(IsoImage *image, IsoDataSource *src, int flag) +{ + int ret, i, j; + uint64_t start_block, block_count, flags, end_block, j_end, j_start; + uint8_t *part; + struct iso_imported_sys_area *sai; + + sai = image->imported_sa_info; + + ret = iso_analyze_gpt_head(image, src, 0); + if (ret <= 0) + return ret; + + for (i = 0; i < (int) sai->gpt_max_entries; i++) { + part = ((uint8_t *) image->system_area_data) + + sai->gpt_part_start * 512 + 128 * i; + for (j = 0; j < 128; j++) + if (part[j]) + break; + if (j >= 128) /* all zero, invalid entry */ + continue; + start_block = iso_read_lsb64(part + 32); + block_count = iso_read_lsb64(part + 40); + flags = iso_read_lsb64(part + 48); + if (block_count < start_block) + continue; + block_count = block_count + 1 - start_block; + if (sai->gpt_req == NULL) { + sai->gpt_req = calloc(ISO_GPT_ENTRIES_MAX, + sizeof(struct iso_gpt_partition_request)); + if (sai->gpt_req == NULL) + return ISO_OUT_OF_MEM; + } + ret = iso_quick_gpt_entry(sai->gpt_req, &(sai->gpt_req_count), + start_block, block_count, + part, part + 16, flags, part + 56); + if (ret < 0) + return ret; + sai->gpt_req[sai->gpt_req_count - 1]->idx = i + 1; + } + + /* sai->gpt_req_flags : + bit0= GPT partitions may overlap + >>> bit1= with bit0: neatly nested partitions + without : neatly divided disk + */ + for (i = 0; i < (int) sai->gpt_req_count && !(sai->gpt_req_flags & 1); + i++) { + if (sai->gpt_req[i]->block_count == 0) + continue; + start_block = sai->gpt_req[i]->start_block; + end_block = start_block + sai->gpt_req[i]->block_count; + for (j = i + 1; j < (int) sai->gpt_req_count; j++) { + if (sai->gpt_req[j]->block_count == 0) + continue; + j_start = sai->gpt_req[j]->start_block; + j_end = j_start + sai->gpt_req[j]->block_count; + if ((start_block <= j_start && j_start < end_block) || + (start_block <= j_end && j_end < end_block) || + (j_start <= start_block && start_block < j_end)) { + sai->gpt_req_flags |= 1; + break; + } + } + } + return 1; +} + + +static +int iso_analyze_apm_head(IsoImage *image, IsoDataSource *src, int flag) +{ + struct iso_imported_sys_area *sai; + char *sad; + uint32_t block_size; + + sai = image->imported_sa_info; + sad = image->system_area_data; + + if (sad[0] != 'E' || sad[1] != 'R') + return 0; + block_size = iso_read_msb(((uint8_t *) sad) + 2, 2); + if (block_size != 2048 && block_size != 512) + return 0; + sai->apm_block_size = block_size; + sai->apm_req_flags |= 4 | 2; /* start_block and block_count are in + block_size units, do not fill gaps */ + return 1; +} + +static +int iso_analyze_apm(IsoImage *image, IsoDataSource *src, int flag) +{ + int ret, i; + uint32_t map_entries, start_block, block_count, flags; + char *sad, *part, name[33], type_string[33]; + struct iso_imported_sys_area *sai; + + sai = image->imported_sa_info; + sad = image->system_area_data; + + ret = iso_analyze_apm_head(image, src, 0); + if (ret <= 0) + return ret; + + part = sad + sai->apm_block_size; + map_entries = iso_read_msb(((uint8_t *) part) + 4, 4); + for (i = 0; i < (int) map_entries; i++) { + part = sad + (i + 1) * sai->apm_block_size; + if (part[0] != 'P' || part[1] != 'M') + break; + flags = iso_read_msb(((uint8_t *) part) + 88, 4); + if (!(flags & 3)) + continue; + memcpy(type_string, part + 48, 32); + type_string[32] = 0; + if(strcmp(type_string, "Apple_partition_map") == 0) + continue; + start_block = iso_read_msb(((uint8_t *) part) + 8, 4); + block_count = iso_read_msb(((uint8_t *) part + 12), 4); + memcpy(name, part + 16, 32); + name[32] = 0; + if (sai->apm_req == NULL) { + sai->apm_req = calloc(ISO_APM_ENTRIES_MAX, + sizeof(struct iso_apm_partition_request)); + if (sai->apm_req == NULL) + return ISO_OUT_OF_MEM; + } + ret = iso_quick_apm_entry(sai->apm_req, &(sai->apm_req_count), + start_block, block_count, name, type_string); + if (ret <= 0) + return ret; + if (strncmp(name, "Gap", 3) == 0 && + strcmp(type_string, "ISO9660_data") == 0) { + if ('0' <= name[3] && name[3] <= '9' && (name[4] == 0 || + ('0' <= name[4] && name[4] <= '9' && name[5] == 0))) { + sai->apm_gap_count++; + sai->apm_req_flags &= ~2; + } + } + } + return 1; +} + +static +int iso_analyze_mips(IsoImage *image, IsoDataSource *src, int flag) +{ + int ret = 0, spt, bps, i, j, idx; + uint32_t magic, chk, head_chk; + char *sad; + uint8_t *usad, *upart; + struct iso_imported_sys_area *sai; + IsoNode *node; + + sai = image->imported_sa_info; + sad = image->system_area_data; + usad = (uint8_t *) sad; + + magic = iso_read_msb(usad, 4); + if (magic != 0x0be5a941) + return 0; + spt = iso_read_msb(usad + 38, 2); + bps = iso_read_msb(usad + 40, 2); + if (spt != 32 || bps != 512) + return 0; + chk = 0; + for (i = 0; i < 504; i += 4) + chk -= iso_read_msb(usad + i, 4); + head_chk = iso_read_msb(usad + 504, 4); + if (chk != head_chk) + return 0; + + /* Verify that partitions 1 to 8 are empty */ + for (j = 312; j < 408; j++) + if (sad[j]) + return 0; + + /* >>> verify that partitions 9 and 10 match the image size */; + + for (i = 0; i < 15; i++) { + upart = usad + 72 + 16 * i; + for (j = 0; j < 16; j++) + if (upart[j]) + break; + if (j == 16) + continue; + if (sai->mips_vd_entries == NULL) { + sai->mips_boot_file_paths = calloc(15, sizeof(char *)); + sai->mips_vd_entries = calloc(15, + sizeof(struct iso_mips_voldir_entry *)); + if (sai->mips_vd_entries == NULL || + sai->mips_boot_file_paths == NULL) + return ISO_OUT_OF_MEM; + sai->num_mips_boot_files = 0; + for (j = 0; j < 15; j++) { + sai->mips_boot_file_paths[j] = NULL; + sai->mips_vd_entries[j] = NULL; + } + } + + /* Assess boot file entry */ + if (sai->num_mips_boot_files >= 15) + return ISO_BOOT_TOO_MANY_MIPS; + idx = sai->num_mips_boot_files; + sai->mips_vd_entries[idx] = + calloc(1, sizeof(struct iso_mips_voldir_entry)); + if (sai->mips_vd_entries[idx] == NULL) + return ISO_OUT_OF_MEM; + memcpy(sai->mips_vd_entries[idx]->name, upart, 8); + sai->mips_vd_entries[idx]->name[8] = 0; + sai->mips_vd_entries[idx]->boot_block = iso_read_msb(upart + 8, 4); + sai->mips_vd_entries[idx]->boot_bytes = iso_read_msb(upart + 12, 4); + ret = iso_tree_get_node_of_block(image, NULL, + sai->mips_vd_entries[idx]->boot_block / 4, + &node, 0); + if (ret > 0) + sai->mips_boot_file_paths[idx] = iso_tree_get_node_path(node); + sai->num_mips_boot_files++; + } + if (sai->num_mips_boot_files > 0) + sai->system_area_options = (1 << 2);/* MIPS Big Endian Volume Header */ + + return ret; +} + +static +int iso_analyze_mipsel(IsoImage *image, IsoDataSource *src, int flag) +{ + int ret = 0, i, section_count; + char *sad; + uint8_t *usad; + uint32_t magic; + struct iso_imported_sys_area *sai; + IsoNode *node; + IsoFile *file; + struct iso_file_section *sections = NULL; + + sai = image->imported_sa_info; + sad = image->system_area_data; + usad = (uint8_t *) sad; + + for (i = 0; i < 8; i++) + if (sad[i]) + return 0; + magic = iso_read_lsb(usad + 8, 4); + if (magic != 0x0002757a) + return 0; + + sai->mipsel_p_vaddr = iso_read_lsb(usad + 16, 4); + sai->mipsel_e_entry = iso_read_lsb(usad + 20, 4); + sai->mipsel_p_filesz = iso_read_lsb(usad + 24, 4) * 512; + sai->mipsel_seg_start = iso_read_lsb(usad + 28, 4); + ret = iso_tree_get_node_of_block(image, NULL, sai->mipsel_seg_start / 4, + &node, 0); + if (ret > 0) { + sai->mipsel_boot_file_path = iso_tree_get_node_path(node); + file = (IsoFile *) node; + ret = iso_file_get_old_image_sections(file, §ion_count, + §ions, 0); + if (ret > 0 && section_count > 0) { + if (sections[0].block < (1 << 30) && + sections[0].block * 4 < sai->mipsel_seg_start) + sai->mipsel_p_offset = sai->mipsel_seg_start - + sections[0].block * 4; + free(sections); + } + } + /* DEC Boot Block for MIPS Little Endian */ + sai->system_area_options = (2 << 2); + + return 1; +} + +static +int iso_analyze_sun(IsoImage *image, IsoDataSource *src, int flag) +{ + int ret = 0, i, idx; + char *sad; + uint8_t *usad, checksum[2]; + uint16_t perms; + uint64_t last_core_block; + struct iso_imported_sys_area *sai; + IsoNode *node; + + sai = image->imported_sa_info; + sad = image->system_area_data; + usad = (uint8_t *) sad; + + if (iso_read_msb(usad + 128, 4) != 1 || + iso_read_msb(usad + 140, 2) != 8 || + iso_read_msb(usad + 188, 4) != 0x600ddeee || + iso_read_msb(usad + 430, 2) != 1 || + iso_read_msb(usad + 508, 2) != 0xdabe) + return 0; + if (iso_read_msb(usad + 142, 2) != 4 || + iso_read_msb(usad + 144, 2) != 0x10 || + iso_read_msb(usad + 444, 4) != 0 || + sai->image_size > 0x3fffffff || + iso_read_msb(usad + 448, 4) != sai->image_size * 4) + return 0; + checksum[0] = checksum[1] = 0; + for (i = 0; i < 510; i += 2) { + checksum[0] ^= usad[i]; + checksum[1] ^= usad[i + 1]; + } + if (checksum[0] != usad[510] || checksum[1] != usad[511]) + return 0; + + sai->sparc_disc_label = calloc(1, 129); + if (sai->sparc_disc_label == NULL) + return ISO_OUT_OF_MEM; + memcpy(sai->sparc_disc_label, sad, 128); + sai->sparc_disc_label[128] = 0; + sai->sparc_heads_per_cyl = iso_read_msb(usad + 436, 2); + sai->sparc_secs_per_head = iso_read_msb(usad + 438, 2); + + for (i = 0; i < 8; i++) { + perms = iso_read_msb(usad + 144 + 4 * i, 2); + if (perms == 0) + continue; + if (sai->sparc_entries == NULL) { + sai->sparc_entries = calloc(8, + sizeof(struct iso_sun_disk_label_entry)); + if (sai->sparc_entries == NULL) + return ISO_OUT_OF_MEM; + } + idx = sai->sparc_entry_count; + sai->sparc_entries[idx].idx = i + 1; + sai->sparc_entries[idx].id_tag = iso_read_msb(usad + 142 + 4 * i, 2); + sai->sparc_entries[idx].permissions = perms; + sai->sparc_entries[idx].start_cyl = + iso_read_msb(usad + 444 + 8 * i, 4); + sai->sparc_entries[idx].num_blocks = + iso_read_msb(usad + 448 + 8 * i, 4); + sai->sparc_entry_count++; + } + + /* GRUB2 SUN SPARC Core File Address */ + sai->sparc_grub2_core_adr = iso_read_msb64(usad + 552); + sai->sparc_grub2_core_size = iso_read_msb(usad + 560, 4); + last_core_block = (sai->sparc_grub2_core_adr + + sai->sparc_grub2_core_size + 2047) / 2048; + if (last_core_block > 0) + last_core_block--; + if (last_core_block > 17 && last_core_block < sai->image_size) { + ret = iso_tree_get_node_of_block(image, NULL, + (uint32_t) last_core_block, &node, 0); + if (ret > 0) { + iso_node_ref(node); + sai->sparc_core_node = (IsoFile *) node; + } + } else { + sai->sparc_grub2_core_adr = 0; + sai->sparc_grub2_core_size = 0; + } + + /* SUN Disk Label for SUN SPARC */ + sai->system_area_options = (3 << 2); + + return 1; +} + +static +int iso_analyze_hppa(IsoImage *image, IsoDataSource *src, int flag) +{ + int ret = 0, i, cmd_adr, cmd_len; + char *sad, *paths[4]; + uint8_t *usad; + uint16_t magic; + uint32_t adrs[4]; + struct iso_imported_sys_area *sai; + IsoNode *node; + + sai = image->imported_sa_info; + sad = image->system_area_data; + usad = (uint8_t *) sad; + + magic = iso_read_msb(usad, 2); + if (magic != 0x8000 || strncmp(sad + 2, "PALO", 5) != 0 || + sad[7] < 4 || sad[7] > 5) + return 0; + + sai->hppa_hdrversion = sad[7]; + if (sai->hppa_hdrversion == 4) { + cmd_len = 127; + cmd_adr = 24; + } else { + cmd_len = 1023; + cmd_adr = 1024; + } + sai->hppa_cmdline = calloc(1, cmd_len + 1); + if (sai->hppa_cmdline == NULL) + return ISO_OUT_OF_MEM; + memcpy(sai->hppa_cmdline, sad + cmd_adr, cmd_len); + sai->hppa_cmdline[cmd_len] = 0; + adrs[0] = sai->hppa_kern32_adr = iso_read_msb(usad + 8, 4); + sai->hppa_kern32_len = iso_read_msb(usad + 12, 4); + adrs[1] = sai->hppa_kern64_adr = iso_read_msb(usad + 232, 4); + sai->hppa_kern64_len = iso_read_msb(usad + 236, 4); + adrs[2] = sai->hppa_ramdisk_adr = iso_read_msb(usad + 16, 4); + sai->hppa_ramdisk_len = iso_read_msb(usad + 20, 4); + adrs[3] = sai->hppa_bootloader_adr = iso_read_msb(usad + 240, 4); + sai->hppa_bootloader_len = iso_read_msb(usad + 244, 4); + for (i = 0; i < 4; i++) { + paths[i] = NULL; + ret = iso_tree_get_node_of_block(image, NULL, adrs[i] / 2048, &node, 0); + if (ret > 0) + paths[i] = iso_tree_get_node_path(node); + } + sai->hppa_kernel_32 = paths[0]; + sai->hppa_kernel_64 = paths[1]; + sai->hppa_ramdisk = paths[2]; + sai->hppa_bootloader = paths[3]; + + if (sai->hppa_hdrversion == 5) + sai->hppa_ipl_entry = iso_read_msb(usad + 248, 4); + + /* HP-PA PALO boot sector version 4 or 5 for HP PA-RISC */ + sai->system_area_options = (sai->hppa_hdrversion << 2); + + return ret; +} + +static +void iso_impsysa_line(char *target, char *msg, int *len) +{ + if (target != NULL) + sprintf(target + *len, "%s\n", msg); + *len += strlen(msg) + 1; +} + +static +void iso_impsysa_report_text(char *target, char *msg, int *len, + char *path, int flag) +{ + if (strlen(msg) + strlen(path) >= ISO_MAX_SYSAREA_LINE_LENGTH) + sprintf(msg + strlen(msg), "(too long to show here)"); + else + strcat(msg, path); + iso_impsysa_line(target, msg, len); +} + +static +void iso_impsysa_report_blockpath(IsoImage *image, + char *target, char *msg, int *len, + uint32_t start_block, int flag) +{ + int ret; + char *path; + IsoNode *node; + + ret = iso_tree_get_node_of_block(image, NULL, start_block, &node, 0); + if (ret <= 0) + return; + path = iso_tree_get_node_path(node); + if (path != NULL) { + iso_impsysa_report_text(target, msg, len, path, 0); + free(path); + } +} + +static +int iso_impsysa_report(IsoImage *image, char *target, int flag) +{ + char *msg = NULL, *local_name = NULL, *path; + int i, j, len = 0, sa_type, sao, sa_sub, ret, idx; + size_t local_len; + struct iso_imported_sys_area *sai; + struct iso_mbr_partition_request *part; + struct iso_gpt_partition_request *gpt_entry; + struct iso_apm_partition_request *apm_entry; + static char *alignments[4] = {"auto", "on", "off", "all"}; + IsoWriteOpts *opts = NULL; + struct iso_sun_disk_label_entry *sparc_entry; + + sai = image->imported_sa_info; + + LIBISO_ALLOC_MEM(msg, char, ISO_MAX_SYSAREA_LINE_LENGTH); + + if (!sai->is_not_zero) + {ret = 0; goto ex;} + sao = sai->system_area_options; + sprintf(msg, "System area options: 0x%-8.8x", (unsigned int) sao); + iso_impsysa_line(target, msg, &len); + + /* Human readable form of system_area_options */ + sa_type = (sao >> 2) & 63; + sa_sub = (sao >> 10) & 15; + strcpy(msg, "System area summary:"); + if (sa_type == 0) { + if ((sao & 3) || sa_sub == 1 || sa_sub == 2) { + strcat(msg, " MBR"); + if (sao & 1) + strcat(msg, " protective-msdos-label"); + else if (sao & 2) + strcat(msg, " isohybrid"); + else if (sa_sub == 1) + strcat(msg, " CHRP"); + if ((sao & (1 << 14)) && !(sao & 2)) + strcat(msg, " grub2-mbr"); + sprintf(msg + strlen(msg), " cyl-align-%s", + alignments[(sao >> 8) & 3]); + } else if (sai->prep_part_start > 0 && sai->prep_part_size > 0) { + strcat(msg, " PReP"); + } else { + strcat(msg, " not-recognized"); + } + } else if (sa_type == 1) { + strcat(msg, " MIPS-Big-Endian"); + } else if (sa_type == 2) { + strcat(msg, " MIPS-Little-Endian"); + } else if (sa_type == 3) { + strcat(msg, " SUN-SPARC-Disk-Label"); + } else if (sa_type == 4 || sa_type == 5) { + sprintf(msg + strlen(msg), " HP-PA-PALO"); + } else { + sprintf(msg + strlen(msg), " unkown-system-area-type-%d", sa_type); + } + if (sai->gpt_req_count > 0) + strcat(msg, " GPT"); + if (sai->apm_req_count > 0) + strcat(msg, " APM"); + + iso_impsysa_line(target, msg, &len); /* System area summary */ + + sprintf(msg, "ISO image size/512 : %.f", + ((double) sai->image_size) * 4.0); + iso_impsysa_line(target, msg, &len); + if (sai->mbr_req_count > 0 && sa_type == 0) { + sprintf(msg, "Partition offset : %d", sai->partition_offset); + iso_impsysa_line(target, msg, &len); + } + if (sa_type >= 4 && sa_type <= 5) { + sprintf(msg, "PALO header version: %d", sai->hppa_hdrversion); + iso_impsysa_line(target, msg, &len); + sprintf(msg, "HP-PA cmdline : "); + iso_impsysa_report_text(target, msg, &len, sai->hppa_cmdline, 0); + sprintf(msg, "HP-PA boot files : ByteAddr ByteSize Path"); + iso_impsysa_line(target, msg, &len); + sprintf(msg, "HP-PA 32-bit kernel: %10u %10u ", + sai->hppa_kern32_adr, sai->hppa_kern32_len); + iso_impsysa_report_text(target, msg, &len, + sai->hppa_kernel_32 != NULL ? + sai->hppa_kernel_32 : "(not found in ISO)", 0); + sprintf(msg, "HP-PA 64-bit kernel: %10u %10u ", + sai->hppa_kern64_adr, sai->hppa_kern64_len); + iso_impsysa_report_text(target, msg, &len, + sai->hppa_kernel_64 != NULL ? + sai->hppa_kernel_64 : "(not found in ISO)", 0); + sprintf(msg, "HP-PA ramdisk : %10u %10u ", + sai->hppa_ramdisk_adr, sai->hppa_ramdisk_len); + iso_impsysa_report_text(target, msg, &len, + sai->hppa_ramdisk != NULL ? + sai->hppa_ramdisk : "(not found in ISO)", 0); + sprintf(msg, "HP-PA bootloader : %10u %10u ", + sai->hppa_bootloader_adr, sai->hppa_bootloader_len); + iso_impsysa_report_text(target, msg, &len, + sai->hppa_bootloader != NULL ? + sai->hppa_bootloader : "(not found in ISO)", 0); + } + if (sai->mbr_req_count > 0) { + sprintf(msg, "MBR heads per cyl : %d", sai->partition_heads_per_cyl); + iso_impsysa_line(target, msg, &len); + sprintf(msg, "MBR secs per head : %d", sai->partition_secs_per_head); + iso_impsysa_line(target, msg, &len); + sprintf(msg, + "MBR partition table: N Status Type Start Blocks"); + iso_impsysa_line(target, msg, &len); + } + for (i = 0; i < sai->mbr_req_count; i++) { + part = sai->mbr_req[i]; + sprintf(msg, "MBR partition : %d 0x%2.2x 0x%2.2x %11.f %11.f", + part->desired_slot, + (unsigned int) part->status_byte, + (unsigned int) part->type_byte, + (double) part->start_block, (double) part->block_count); + iso_impsysa_line(target, msg, &len); + } + for (i = 0; i < sai->mbr_req_count; i++) { + part = sai->mbr_req[i]; + if (part->block_count == 0) + continue; + sprintf(msg, "MBR partition path : %d ", part->desired_slot); + iso_impsysa_report_blockpath(image, target, msg, &len, + (uint32_t) (part->start_block / 4), 0); + } + if (sai->prep_part_start > 0 && sai->prep_part_size > 0) { + sprintf(msg, "PReP boot partition: %u %u", + sai->prep_part_start, sai->prep_part_size); + iso_impsysa_line(target, msg, &len); + } + + if (sa_type == 1) { + sprintf(msg, + "MIPS-BE volume dir : N Name Block Bytes"); + iso_impsysa_line(target, msg, &len); + for (i = 0; i < sai->num_mips_boot_files; i++) { + sprintf(msg, + "MIPS-BE boot entry : %2d %8s %10u %10u", + i + 1, sai->mips_vd_entries[i]->name, + sai->mips_vd_entries[i]->boot_block, + sai->mips_vd_entries[i]->boot_bytes); + iso_impsysa_line(target, msg, &len); + if (sai->mips_boot_file_paths[i] != NULL) { + sprintf(msg, "MIPS-BE boot path : %2d ", i + 1); + iso_impsysa_report_text(target, msg, &len, + sai->mips_boot_file_paths[i], 0); + } + } + } else if (sa_type == 2) { + sprintf(msg, + "MIPS-LE boot map : LoadAddr ExecAddr SegmentSize SegmentStart"); + iso_impsysa_line(target, msg, &len); + sprintf(msg, "MIPS-LE boot params: %10u %10u %10u %10u", + sai->mipsel_p_vaddr, sai->mipsel_e_entry, sai->mipsel_p_filesz, + sai->mipsel_seg_start); + iso_impsysa_line(target, msg, &len); + if (sai->mipsel_boot_file_path != NULL) { + sprintf(msg, "MIPS-LE boot path : "); + iso_impsysa_report_text(target, msg, &len, + sai->mipsel_boot_file_path, 0); + sprintf(msg, "MIPS-LE elf offset : %u", sai->mipsel_p_offset); + iso_impsysa_line(target, msg, &len); + } + } else if (sa_type == 3) { + sprintf(msg, "SUN SPARC disklabel: %s", sai->sparc_disc_label); + iso_impsysa_line(target, msg, &len); + sprintf(msg, "SUN SPARC secs/head: %d", sai->sparc_secs_per_head); + iso_impsysa_line(target, msg, &len); + sprintf(msg, "SUN SPARC heads/cyl: %d", sai->sparc_heads_per_cyl); + iso_impsysa_line(target, msg, &len); + sprintf(msg, + "SUN SPARC partmap : N IdTag Perms StartCyl NumBlocks"); + iso_impsysa_line(target, msg, &len); + for (i = 0; i < sai->sparc_entry_count; i++) { + sparc_entry = sai->sparc_entries + i; + sprintf(msg, + "SUN SPARC partition: %d 0x%4.4x 0x%4.4x %10u %10u", + sparc_entry->idx, + sparc_entry->id_tag, sparc_entry->permissions, + sparc_entry->start_cyl, sparc_entry->num_blocks); + iso_impsysa_line(target, msg, &len); + } + if (sai->sparc_grub2_core_adr > 0) { + sprintf(msg, "SPARC GRUB2 core : %.f %u", + (double) sai->sparc_grub2_core_adr, + sai->sparc_grub2_core_size); + iso_impsysa_line(target, msg, &len); + if (sai->sparc_core_node != NULL) { + path = iso_tree_get_node_path((IsoNode *) sai->sparc_core_node); + if (path != NULL) { + sprintf(msg, "SPARC GRUB2 path : "); + iso_impsysa_report_text(target, msg, &len, path, 0); + free(path); + } + } + } + } + + if (sai->gpt_req_count > 0) { + sprintf(msg, "GPT : N Info"); + iso_impsysa_line(target, msg, &len); + if (sai->gpt_head_crc_should != sai->gpt_head_crc_found) { + sprintf(msg, + "GPT CRC should be : 0x%8.8x to match first 92 GPT header block bytes", + sai->gpt_head_crc_should); + iso_impsysa_line(target, msg, &len); + sprintf(msg, + "GPT CRC found : 0x%8.8x matches all 512 bytes of GPT header block", + sai->gpt_head_crc_found); + iso_impsysa_line(target, msg, &len); + } + if (sai->gpt_array_crc_should != sai->gpt_array_crc_found) { + sprintf(msg, + "GPT array CRC wrong: should be 0x%8.8x , found 0x%8.8x", + sai->gpt_array_crc_should, sai->gpt_array_crc_found); + iso_impsysa_line(target, msg, &len); + } + if (sai->gpt_backup_comments != NULL) { + if (sai->gpt_backup_comments[0]) { + sprintf(msg, "GPT backup problems: "); + iso_impsysa_report_text(target, msg, &len, + sai->gpt_backup_comments, 0); + } + } + sprintf(msg, "GPT disk GUID : "); + iso_util_bin_to_hex(msg + 26, sai->gpt_disk_guid, 16, 0); + iso_impsysa_line(target, msg, &len); + sprintf(msg, "GPT entry array : %u %u %s", + (unsigned int) sai->gpt_part_start, + (unsigned int) sai->gpt_max_entries, + sai->gpt_req_flags & 1 ? "overlapping" : "separated"); + iso_impsysa_line(target, msg, &len); + sprintf(msg, "GPT lba range : %.f %.f %.f", + (double) sai->gpt_first_lba, (double) sai->gpt_last_lba, + (double) sai->gpt_backup_lba); + iso_impsysa_line(target, msg, &len); + ret = iso_write_opts_new(&opts, 0); + if (ret < 0) + goto ex; + ret = iso_write_opts_set_output_charset(opts, "UTF-16LE"); + if (ret < 0) + goto ex; + } + for (i = 0; i < sai->gpt_req_count; i++) { + gpt_entry = sai->gpt_req[i]; + idx = gpt_entry->idx; + + sprintf(msg, "GPT partition name : %3d ", idx); + for (j = 72; j >= 2; j -= 2) + if (gpt_entry->name[j - 2] || gpt_entry->name[j - 1]) + break; + iso_util_bin_to_hex(msg + 26, gpt_entry->name, j, 0); + iso_impsysa_line(target, msg, &len); + if (j > 0) + ret = iso_conv_name_chars(opts, (char *) gpt_entry->name, j, + &local_name, &local_len, 0 | 512 | (1 << 15)); + else + ret = 0; + if (ret == 1 && local_len <= 228) { + sprintf(msg, "GPT partname local : %3d ", idx); + memcpy(msg + 26, local_name, local_len); + LIBISO_FREE_MEM(local_name); local_name = NULL; + msg[26 + local_len] = 0; + iso_impsysa_line(target, msg, &len); + } + sprintf(msg, "GPT partition GUID : %3d ", idx); + iso_util_bin_to_hex(msg + 26, gpt_entry->partition_guid, 16, 0); + iso_impsysa_line(target, msg, &len); + sprintf(msg, "GPT type GUID : %3d ", idx); + iso_util_bin_to_hex(msg + 26, gpt_entry->type_guid, 16, 0); + iso_impsysa_line(target, msg, &len); + sprintf(msg, "GPT partition flags: %3d 0x%8.8x%8.8x", idx, + (unsigned int) ((gpt_entry->flags >> 32) & 0xffffffff), + (unsigned int) (gpt_entry->flags & 0xffffffff)); + iso_impsysa_line(target, msg, &len); + sprintf(msg, "GPT start and size : %3d %.f %.f", idx, + (double) gpt_entry->start_block, + (double) gpt_entry->block_count); + iso_impsysa_line(target, msg, &len); + if (gpt_entry->block_count == 0) + continue; + sprintf(msg, "GPT partition path : %3d ", idx); + iso_impsysa_report_blockpath(image, target, msg, &len, + (uint32_t) (gpt_entry->start_block / 4), 0); + } + + if (sai->apm_req_count > 0) { + sprintf(msg, "APM : N Info"); + iso_impsysa_line(target, msg, &len); + sprintf(msg, "APM block size : %u", sai->apm_block_size); + iso_impsysa_line(target, msg, &len); + sprintf(msg, "APM gap fillers : %d", sai->apm_gap_count); + iso_impsysa_line(target, msg, &len); + } + for (i = 0; i < sai->apm_req_count; i++) { + apm_entry = sai->apm_req[i]; + idx = i + 1; + sprintf(msg, "APM partition name : %2d %s", idx, apm_entry->name); + iso_impsysa_line(target, msg, &len); + sprintf(msg, "APM partition type : %2d %s", idx, apm_entry->type); + iso_impsysa_line(target, msg, &len); + sprintf(msg, "APM start and size : %2d %.f %.f", idx, + (double) apm_entry->start_block, + (double) apm_entry->block_count); + iso_impsysa_line(target, msg, &len); + if (apm_entry->block_count == 0) + continue; + sprintf(msg, "APM partition path : %2d ", idx); + iso_impsysa_report_blockpath(image, target, msg, &len, + (uint32_t) (apm_entry->start_block / + (2048 / sai->apm_block_size)), + 0); + } + + ret = len; +ex: + LIBISO_FREE_MEM(local_name); + if (opts != NULL) + iso_write_opts_free(opts); + LIBISO_FREE_MEM(msg); + return ret; +} + +/* API */ +int iso_image_report_system_area(IsoImage *image, char **target, int flag) +{ + int ret, i, count = 0; + static char *doc[] = {ISO_SYSAREA_REPORT_DOC}; + + if (flag & 1) { + for (i = 0; strcmp(doc[i], "@END_OF_DOC@") != 0; i++) + count += strlen(doc[i]) + 1; + *target = calloc(1, count); + if (*target == NULL) + return ISO_OUT_OF_MEM; + count = 0; + for (i = 0; strcmp(doc[i], "@END_OF_DOC@") != 0; i++) { + strcpy(*target + count, doc[i]); + count += strlen(doc[i]); + (*target)[count++] = '\n'; + } + return ISO_SUCCESS; + } + *target = NULL; + if (image->system_area_data == NULL) + return 0; + ret = iso_impsysa_report(image, NULL, 0); + if (ret < 0) + return ret; + *target = calloc(1, ret + 1); + if (*target == NULL) + return ISO_OUT_OF_MEM; + ret = iso_impsysa_report(image, *target, 0); + if (ret < 0) + return ret; + return ISO_SUCCESS; +} + + +static +int iso_analyze_system_area(IsoImage *image, IsoDataSource *src, + uint32_t image_size, int flag) +{ + int ret, i, sao, sa_type, sa_sub, is_mbr = 0; + + iso_imported_sa_unref(&(image->imported_sa_info), 0); + ret = iso_imported_sa_new(&(image->imported_sa_info), 0); + if (ret < 0) + goto ex; + + for (i = 0; i < 32768; i++) + if (image->system_area_data[i] != 0) + break; + if (i < 32768) + image->imported_sa_info->is_not_zero = 1; + + image->imported_sa_info->image_size = image_size; + + ret = iso_analyze_mbr(image, src, 0); + if (ret < 0) + goto ex; + is_mbr = (ret > 0); + ret = iso_analyze_gpt(image, src, 0); + if (ret < 0) + goto ex; + ret = iso_analyze_apm(image, src, 0); + if (ret < 0) + goto ex; + sao = image->imported_sa_info->system_area_options; + sa_type = (sao >> 2) & 0x3f; + sa_sub = (sao >> 10) & 0xf; + if (sa_type == 0 && !((sao & 3) || sa_sub == 1 || sa_sub == 2)) { + ret = iso_analyze_mips(image, src, 0); + if (ret < 0) + goto ex; + if (ret == 0) { + ret = iso_analyze_mipsel(image, src, 0); + if (ret < 0) + goto ex; + } + if (ret == 0) { + ret = iso_analyze_sun(image, src, 0); + if (ret < 0) + goto ex; + } + } + if (sa_type == 0 && !((sao & 3) || sa_sub == 1)) { + /* HP-PA PALO v5 can look like generic MBR */ + ret = iso_analyze_hppa(image, src, 0); + if (ret < 0) + goto ex; + } + + ret = ISO_SUCCESS; +ex:; + image->imported_sa_info->overall_return = ret; + return ret; +} int iso_image_import(IsoImage *image, IsoDataSource *src, struct iso_read_opts *opts, @@ -3902,6 +5367,16 @@ int iso_image_import(IsoImage *image, IsoDataSource *src, if (ret < 0) goto import_revert; + if (opts->load_system_area && image->system_area_data != NULL) { + ret = iso_analyze_system_area(image, src, data->nblocks, 0); + if (ret < 0) { + iso_msg_submit(-1, ISO_SYSAREA_PROBLEMS, 0, + "Problem encountered during inspection of System Area:"); + iso_msg_submit(-1, ISO_SYSAREA_PROBLEMS, 0, + iso_error_to_msg(ret)); + } + } + ret = ISO_SUCCESS; goto import_cleanup; diff --git a/libisofs/hfsplus.c b/libisofs/hfsplus.c index 0d0284f..3d4b07d 100644 --- a/libisofs/hfsplus.c +++ b/libisofs/hfsplus.c @@ -475,7 +475,8 @@ int hfsplus_tail_writer_compute_data_blocks(IsoImageWriter *writer) t->hfsp_total_blocks = hfsp_curblock - t->hfsp_part_start; - return iso_quick_apm_entry(t, t->hfsp_part_start / block_fac, + return iso_quick_apm_entry(t->apm_req, &(t->apm_req_count), + t->hfsp_part_start / block_fac, t->hfsp_total_blocks / block_fac + !!(t->hfsp_total_blocks % block_fac), "HFSPLUS_Hybrid", "Apple_HFS"); diff --git a/libisofs/image.c b/libisofs/image.c index 5e99701..c619489 100644 --- a/libisofs/image.c +++ b/libisofs/image.c @@ -22,6 +22,97 @@ #include #include + +int iso_imported_sa_new(struct iso_imported_sys_area **boots, int flag) +{ + struct iso_imported_sys_area *b; + + *boots = NULL; + b = calloc(1, sizeof(struct iso_imported_sys_area)); + if (b == NULL) + return ISO_OUT_OF_MEM; + + b->mbr_req = NULL; + b->apm_req = NULL; + + b->gpt_req = NULL; + b->gpt_backup_comments = NULL; + + b->mips_boot_file_paths = NULL; + b->mips_vd_entries = NULL; + + b->sparc_disc_label = NULL; + b->sparc_core_node = NULL; + b->sparc_entries = NULL; + + b->hppa_cmdline = NULL; + b->hppa_bootloader = NULL; + b->hppa_kernel_32 = NULL; + b->hppa_kernel_64 = NULL; + b->hppa_ramdisk = NULL; + + *boots = b; + return 1; +} + +int iso_imported_sa_unref(struct iso_imported_sys_area **boots, int flag) +{ + int i; + struct iso_imported_sys_area *b; + + b = *boots; + if (b == NULL) + return 2; + if (b->refcount > 0) + b->refcount--; + if (b->refcount > 0) + return 2; + + if (b->mbr_req != NULL) { + for (i = 0; i < b->mbr_req_count; i++) + LIBISO_FREE_MEM(b->mbr_req[i]); + LIBISO_FREE_MEM(b->mbr_req); + } + if (b->apm_req != NULL) { + for (i = 0; i < b->apm_req_count; i++) + LIBISO_FREE_MEM(b->apm_req[i]); + LIBISO_FREE_MEM(b->apm_req); + } + if (b->gpt_req != NULL) { + for (i = 0; i < b->gpt_req_count; i++) + LIBISO_FREE_MEM(b->gpt_req[i]); + LIBISO_FREE_MEM(b->gpt_req); + } + LIBISO_FREE_MEM(b->gpt_backup_comments); + + if (b->mips_boot_file_paths != NULL) { + for (i = 0; i < b->num_mips_boot_files; i++) + LIBISO_FREE_MEM(b->mips_boot_file_paths[i]); + LIBISO_FREE_MEM(b->mips_boot_file_paths); + } + if (b->mips_vd_entries != NULL) { + for (i = 0; i < b->num_mips_boot_files; i++) + LIBISO_FREE_MEM(b->mips_vd_entries[i]); + LIBISO_FREE_MEM(b->mips_vd_entries); + } + LIBISO_FREE_MEM(b->mipsel_boot_file_path); + + LIBISO_FREE_MEM(b->sparc_disc_label); + if (b->sparc_core_node != NULL) + iso_node_unref((IsoNode *) b->sparc_core_node); + LIBISO_FREE_MEM(b->sparc_entries); + + LIBISO_FREE_MEM(b->hppa_cmdline); + LIBISO_FREE_MEM(b->hppa_bootloader); + LIBISO_FREE_MEM(b->hppa_kernel_32); + LIBISO_FREE_MEM(b->hppa_kernel_64); + LIBISO_FREE_MEM(b->hppa_ramdisk); + LIBISO_FREE_MEM(b); + *boots = NULL; + return 1; +} + + /** * Create a new image, empty. * @@ -103,6 +194,7 @@ int iso_image_new(const char *name, IsoImage **image) for (i = 0; i < ISO_HFSPLUS_BLESS_MAX; i++) img->hfsplus_blessed[i] = NULL; img->collision_warnings = 0; + img->imported_sa_info = NULL; *image = img; return ISO_SUCCESS; @@ -165,6 +257,7 @@ void iso_image_unref(IsoImage *image) if (image->system_area_data != NULL) free(image->system_area_data); iso_image_free_checksums(image, 0); + iso_imported_sa_unref(&(image->imported_sa_info), 0); free(image); } } diff --git a/libisofs/image.h b/libisofs/image.h index 8d55fe8..f13c07a 100644 --- a/libisofs/image.h +++ b/libisofs/image.h @@ -212,6 +212,9 @@ struct Iso_Image /* Counts the name collisions while iso_image_import() */ size_t collision_warnings; + /* Contains the assessment of boot aspects of the loaded image */ + struct iso_imported_sys_area *imported_sa_info; + }; @@ -263,4 +266,125 @@ int iso_image_set_pvd_times(IsoImage *image, char *creation_time, char *modification_time, char *expiration_time, char *effective_time); + +/* Collects boot block information obtained from the system area of + imported images +*/ +struct iso_imported_sys_area { + + int refcount; + + /* Whether there was some System Area data at all */ + int is_not_zero; + + /* Giving the error number if the assessment ended by an error */ + int overall_return; + + /* Size of the imported ISO image */ + uint32_t image_size; + + /* see libisofs.h : iso_write_opts_set_system_area() */ + int system_area_options; + + /* The perceived MBR partitions */ + struct iso_mbr_partition_request **mbr_req; + int mbr_req_count; + + /* see ecma119.h : struct ecma119_image , struct iso_write_opts */ + /* Effective partition table parameter: 1 to 63, 0= disabled/default */ + int partition_secs_per_head; + /* 1 to 255, 0= disabled/default */ + int partition_heads_per_cyl; + + /* see ecma119.h : struct iso_write_opts */ + uint32_t partition_offset; + + /* 2048-byte start LBA and block count of PreP partition */ + uint32_t prep_part_start; + uint32_t prep_part_size; + + /* see ecma119.h : struct ecma119_image */ + struct iso_apm_partition_request **apm_req; + int apm_req_count; + int apm_req_flags; + /* Number of found "GapNN", "ISO9660_data" partitions in APM */ + int apm_gap_count; + + /* see ecma119.h : struct iso_write_opts */ + int apm_block_size; + + /* >>> see ecma119.h : struct iso_write_opts */ + int hfsp_block_size; + + /* see ecma119.h : struct ecma119_image */ + struct iso_gpt_partition_request **gpt_req; + int gpt_req_count; + int gpt_req_flags; + + /* see ecma119.h : struct ecma119_image */ + uint8_t gpt_disk_guid[16]; + /* Start of GPT entries in System Area, block size 512 */ + uint64_t gpt_part_start; + uint32_t gpt_max_entries; + uint64_t gpt_first_lba; + uint64_t gpt_last_lba; + uint64_t gpt_backup_lba; + char *gpt_backup_comments; + uint32_t gpt_head_crc_found; + uint32_t gpt_head_crc_should; + uint32_t gpt_array_crc_found; + uint32_t gpt_array_crc_should; + + /* see image.h : struct Iso_Image */ + int num_mips_boot_files; + char **mips_boot_file_paths; /* ISO 9660 Rock Ridge Paths */ + struct iso_mips_voldir_entry **mips_vd_entries; + + /* see ecma119.h : struct ecma119_image */ + /* Memorized ELF parameters from MIPS Little Endian boot file */ + uint32_t mipsel_e_entry; + uint32_t mipsel_p_offset; + uint32_t mipsel_p_vaddr; + uint32_t mipsel_p_filesz; + uint32_t mipsel_seg_start; + char *mipsel_boot_file_path; + + /* see image.h : struct Iso_Image */ + char *sparc_disc_label; + int sparc_secs_per_head; + int sparc_heads_per_cyl; + struct iso_sun_disk_label_entry *sparc_entries; + int sparc_entry_count; + + /* grub2-sparc-core : a node in the ISO image + published at bytes 0x228 to 0x233 + */ + uint64_t sparc_grub2_core_adr; + uint32_t sparc_grub2_core_size; + IsoFile *sparc_core_node; + + /* see image.h : struct Iso_Image */ + int hppa_hdrversion; + char *hppa_cmdline; + uint32_t hppa_kern32_adr; + uint32_t hppa_kern32_len; + uint32_t hppa_kern64_adr; + uint32_t hppa_kern64_len; + uint32_t hppa_ramdisk_adr; + uint32_t hppa_ramdisk_len; + uint32_t hppa_bootloader_adr; + uint32_t hppa_bootloader_len; + uint32_t hppa_ipl_entry; + char *hppa_kernel_32; + char *hppa_kernel_64; + char *hppa_ramdisk; + char *hppa_bootloader; + +}; + +int iso_imported_sa_new(struct iso_imported_sys_area **sa_info, int flag); + +int iso_imported_sa_unref(struct iso_imported_sys_area **sa_info, int flag); + + #endif /*LIBISO_IMAGE_H_*/ diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 73efb63..7711ef4 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -2164,14 +2164,15 @@ int iso_write_opts_set_fifo_size(IsoWriteOpts *opts, size_t fifo_size); * that one partition is defined which begins at the second * 512-byte block of the image and ends where the image ends. * This works with and without system_area_data. + * Modern GRUB2 system areas get also treated by bit14. See below. * bit1= Only with System area type 0 = MBR * Apply isohybrid MBR patching to the system area. * This works only with system area data from SYSLINUX plus an - * ISOLINUX boot image (see iso_image_set_boot_image()) and - * only if not bit0 is set. + * ISOLINUX boot image as first submitted boot image + * (see iso_image_set_boot_image()) and only if not bit0 is set. * bit2-7= System area type * 0= with bit0 or bit1: MBR - * else: unspecified type which will be used unaltered. + * else: type depends on bits bit10-13: System area sub type * 1= MIPS Big Endian Volume Header * @since 0.6.38 * Submit up to 15 MIPS Big Endian boot files by @@ -2216,15 +2217,17 @@ int iso_write_opts_set_fifo_size(IsoWriteOpts *opts, size_t fifo_size); * @since 1.2.4 * With type 0 = MBR: * Gets overridden by bit0 and bit1. - * 0 = no particular sub type + * 0 = no particular sub type, use unaltered * 1 = CHRP: A single MBR partition of type 0x96 covers the * ISO image. Not compatible with any other feature * which needs to have own MBR partition entries. + * 2 = generic MBR @since 1.3.8 * bit14= Only with System area type 0 = MBR * GRUB2 boot provisions: * @since 1.3.0 - * Patch system area at byte 92 to 99 with 512-block address + 1 - * of the first boot image file. Little-endian 8-byte. + * Patch system area at byte 0x1b0 to 0x1b7 with + * (512-block address + 4) of the first boot image file. + * Little-endian 8-byte. * Should be combined with options bit0. * Will not be in effect if options bit1 is set. * @param flag @@ -3665,6 +3668,219 @@ void el_torito_patch_isolinux_image(ElToritoBootImage *bootimg); int iso_image_get_system_area(IsoImage *img, char data[32768], int *options, int flag); +/** + * The maximum length of a single line in the output of function + * iso_image_report_system_area(). This number includes the trailing 0. + * @since 1.3.8 + */ +#define ISO_MAX_SYSAREA_LINE_LENGTH 4096 + +/** + * Text which describes the output format of iso_image_report_system_area(). + * It is publicly defined here only as part of the API description. + * Do not use it as macro in your application but rather call + * iso_image_report_system_area() with flag bit0. + */ +#define ISO_SYSAREA_REPORT_DOC \ +"Report format for recognized System Area data:", \ +"", \ +"No text will be reported if no System Area was loaded or if it was", \ +"entirely filled with 0-bytes.", \ +"Else there will be at least these two lines:", \ +" System area options: hex", \ +" see libisofs.h, parameter of iso_write_opts_set_system_area().", \ +" System area summary: word ... word", \ +" human readable interpretation of system area options and other info", \ +" The words are from the set:", \ +" { MBR, protective-msdos-label, isohybrid, CHRP, grub2-mbr,", \ +" cyl-align-{auto,on,off,all}, PReP, MIPS-Big-Endian,", \ +" MIPS-Little-Endian, SUN-SPARC-Disk-Label, HP-PA-PALO,", \ +" not-recognized,", \ +" GPT, APM }", \ +"", \ +"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.", \ +" ISO image size/512 : decimal", \ +" size of ISO image in MBR block units of 512 bytes.", \ +" MBR heads per cyl : decimal", \ +" conversion factor between MBR C/H/S address and LBA. 0=inconsistent.", \ +" MBR secs per head : decimal", \ +" conversion factor between MBR C/H/S address and LBA. 0=inconsistent.", \ +" MBR partition table: N Status Type Start Blocks", \ +" headline for MBR partition table.", \ +" MBR partition : X hex hex decimal decimal", \ +" gives partition number, status byte, type byte, start block,", \ +" and number of blocks. 512 bytes per block.", \ +" MBR partition path : X path", \ +" the path of a file in the ISO image which begins at the partition", \ +" start block of partition X.", \ +" PReP boot partition: decimal decimal", \ +" gives start block and size of a PReP boot partition in ISO 9660", \ +" block units of 2048 bytes.", \ +"", \ +"GUID Partition Table can coexist with MBR:", \ +" GPT : N Info", \ +" headline for GPT partition table. The fields are too wide for a", \ +" neat table. So they are listed with a partition number and a text.", \ +" GPT CRC should be : to match first 92 GPT header block bytes", \ +" GPT CRC found : matches all 512 bytes of GPT header block", \ +" libisofs-1.2.4 to 1.2.8 had a bug with the GPT header CRC. So", \ +" libisofs is willing to recognize GPT with the buggy CRC. These", \ +" two lines inform that most partition editors will not accept it.", \ +" GPT array CRC wrong: should be , found ", \ +" GPT entry arrays are accepted even if their CRC does not match.", \ +" In this case, both CRCs are reported by this line.", \ +" GPT backup problems: text", \ +" reports about inconsistencies between main GPT and backup GPT.", \ +" The statements are comma separated:", \ +" Implausible header LBA ", \ +" Cannot read header block at 2k LBA ", \ +" Not a GPT 1.0 header of 92 bytes for 128 bytes per entry", \ +" Head CRC wrong. Should be ", \ +" Head CRC wrong. Should be . Matches all 512 block bytes", \ +" Disk GUID differs ()", \ +" Cannot read array block at 2k LBA ", \ +" Array CRC wrong. Should be ", \ +" Entries differ for partitions [... ]", \ +" GPT disk GUID : hex_digits", \ +" 32 hex digits giving the byte string of the disk's GUID", \ +" GPT entry array : decimal decimal word", \ +" start block of partition entry array and number of entries. 512 bytes", \ +" per block. The word may be \"separated\" if partitions are disjoint,", \ +" \"overlapping\" if they are not. In future there may be \"nested\"", \ +" as special case where all overlapping partitions are superset and", \ +" subset, and \"covering\" as special case of disjoint partitions", \ +" covering the whole GPT block range for partitions.", \ +" GPT lba range : decimal decimal decimal", \ +" addresses of first payload block, last payload block, and of the", \ +" GPT backup header block. 512 bytes per block.", \ +" GPT partition name : X hex_digits", \ +" up to 144 hex digits giving the UTF-16LE name byte string of", \ +" partition X. Trailing 16 bit 0-characters are omitted.", \ +" GPT partname local : X text", \ +" the name of partition X converted to the local character set.", \ +" This line may be missing if the name cannot be converted, or is", \ +" empty.", \ +" GPT partition GUID : X hex_digits", \ +" 32 hex digits giving the byte string of the GUID of partition X.", \ +" GPT type GUID : X hex_digits", \ +" 32 hex digits giving the byte string of the type GUID of partition X.", \ +" GPT partition flags: X hex", \ +" 64 flag bits of partition X in hex representation.", \ +" Known bit meanings are:", \ +" bit0 = \"System Partition\" Do not alter.", \ +" bit2 = Legacy BIOS bootable (MBR partition type 0x80)", \ +" bit60= read-only", \ +" GPT start and size : X decimal decimal", \ +" start block and number of blocks of partition X. 512 bytes per block.", \ +" GPT partition path : X path", \ +" the path of a file in the ISO image which begins at the partition", \ +" start block of partition X.", \ +"", \ +"Apple partition map can coexist with MBR:", \ +" APM : N Info", \ +" headline for human readers.", \ +" APM block size : decimal", \ +" block size of Apple Partition Map. 512 or 2048. This applies to", \ +" start address and size of all partitions in the APM.", \ +" APM gap fillers : decimal", \ +" tells the number of partitions with name \"Gap[0-9[0-9]]\" and type", \ +" \"ISO9660_data\".", \ +" APM partition name : X text", \ +" the name of partition X. Up to 32 characters.", \ +" APM partition type : X text", \ +" the type string of partition X. Up to 32 characters.", \ +" APM start and size : X decimal decimal", \ +" start block and number of blocks of partition X.", \ +" APM partition path : X path", \ +" the path of a file in the ISO image which begins at the partition", \ +" start block of partition X.", \ +"", \ +"If a MIPS Big Endian Volume Header is detected, there may be:", \ +" MIPS-BE volume dir : N Name Block Bytes", \ +" headline for human readers.", \ +" MIPS-BE boot entry : X upto8chr decimal decimal", \ +" tells name, 512-byte block address, and byte count of boot entry X.", \ +" MIPS-BE boot path : X path", \ +" tells the path to the boot image file in the ISO image which belongs", \ +" to the block address given by boot entry X.", \ +"", \ +"If a DEC Boot Block for MIPS Little Endian is detected, there may be:", \ +" MIPS-LE boot map : LoadAddr ExecAddr SegmentSize SegmentStart", \ +" headline for human readers.", \ +" MIPS-LE boot params: decimal decimal decimal decimal", \ +" tells four numbers which are originally derived from the ELF header", \ +" of the boot file. The first two are counted in bytes, the other two", \ +" are counted in blocks of 512 bytes.", \ +" MIPS-LE boot path : path", \ +" tells the path to the boot file in the ISO image which belongs to the", \ +" address given by SegmentStart.", \ +" MIPS-LE elf offset : decimal", \ +" tells the relative 512-byte block offset inside the boot file:", \ +" SegmentStart - FileStartBlock", \ +"", \ +"If a SUN SPARC Disk Label is present:", \ +" SUN SPARC disklabel: text", \ +" tells the disk label text.", \ +" SUN SPARC secs/head: decimal", \ +" tells the number of sectors per head.", \ +" SUN SPARC heads/cyl: decimal", \ +" tells the number of heads per cylinder.", \ +" SPARC GRUB2 core : decimal decimal", \ +" tells byte address and byte count of the GRUB2 SPARC core file.", \ +" SPARC GRUB2 path : path", \ +" tells the path to the data file in the ISO image which belongs to the", \ +" address given by core.", \ +"", \ +"If a HP-PA PALO boot sector version 4 or 5 is present:", \ +" PALO header version: decimal", \ +" tells the PALO header version: 4 or 5.", \ +" HP-PA cmdline : text", \ +" tells the command line for the kernels.", \ +" HP-PA boot files : ByteAddr ByteSize Path", \ +" headline for human readers.", \ +" HP-PA 32-bit kernel: decimal decimal path", \ +" tells start byte, byte count, and file path of the 32-bit kernel.", \ +" HP-PA 64-bit kernel: decimal decimal path", \ +" tells the same for the 64-bit kernel.", \ +" HP-PA ramdisk : decimal decimal path", \ +" tells the same for the ramdisk file.", \ +" HP-PA bootloader : decimal decimal path", \ +" tells the same for the bootloader file.", \ +"@END_OF_DOC@" + +/** + * Obtain a text describing the detected properties of the eventually loaded + * System Area. + * The text will be NULL if no System Area was loaded. It will be empty but + * non-NULL if the System Area was loaded and contains only 0-bytes. + * Else it will consist of lines as descibed in ISO_SYSAREA_REPORT_DOC above. + * + * File paths and other long texts are reported as "(too long to show here)" + * if their length plus preceeding text plus trailing 0-byte exceeds the + * line length limit of ISO_MAX_SYSAREA_LINE_LENGTH bytes. + * + * @param image + * The image to be inquired. + * @param reply + * Will return the allocated result text or NULL. Dispose a non-NULL + * reply by free() when no longer needed. + * Be prepared for a long text with up to ISO_MAX_SYSAREA_LINE_LENGTH + * characters per line. + * @param flag + * Bitfield for control purposes + * bit0= do not report system area but rather reply a copy of + * above text ISO_SYSAREA_REPORT_DOC. + * With this bit it is permissible to submit image as NULL. + * @return + * 1 on success, 0 if no System Area was loaded, < 0 error. + * @since 1.3.8 + */ +int iso_image_report_system_area(IsoImage *image, char **reply, int flag); + /** * Add a MIPS boot file path to the image. * Up to 15 such files can be written into a MIPS Big Endian Volume Header @@ -4736,8 +4952,8 @@ int iso_file_get_old_image_lba(IsoFile *file, uint32_t *lba, int flag); * @since 0.6.8 */ int iso_file_get_old_image_sections(IsoFile *file, int *section_count, - struct iso_file_section **sections, - int flag); + struct iso_file_section **sections, + int flag); /* * Like iso_file_get_old_image_lba(), but take an IsoNode. @@ -5361,7 +5577,7 @@ int iso_ring_buffer_get_status(struct burn_source *b, size_t *size, * * @param queue_severity Gives the minimum limit for messages to be queued. * Default: "NEVER". If you queue messages then you - * must consume them by iso_msgs_obtain(). + * must consume them by iso_obtain_msgs(). * @param print_severity Does the same for messages to be printed directly * to stderr. * @param print_id A text prefix to be printed before the message. @@ -7209,13 +7425,14 @@ int iso_image_hfsplus_get_blessed(IsoImage *img, IsoNode ***blessed_nodes, * @param flag * Bitfield for control purposes. * bit0-bit7= Name space - * 0= generic (to_charset is valid, + * 0= generic (output charset is used, * no reserved characters, no length limits) - * 1= Rock Ridge (to_charset is valid) - * 2= Joliet (to_charset gets overridden by UCS-2 or UTF-16) - * 3= ECMA-119 (to_charset gets overridden by the + * 1= Rock Ridge (output charset is used) + * 2= Joliet (output charset gets overridden by UCS-2 or + * UTF-16) + * 3= ECMA-119 (output charset gets overridden by the * dull ISO 9660 subset of ASCII) - * 4= HFS+ (to_charset gets overridden by UTF-16BE) + * 4= HFS+ (output charset gets overridden by UTF-16BE) * bit8= Treat input text as directory name * (matters for Joliet and ECMA-119) * bit9= Do not issue error messages @@ -7694,6 +7911,10 @@ int iso_conv_name_chars(IsoWriteOpts *opts, char *name, size_t name_len, /** HP-PA PALO command line too long (FAILURE, HIGH, -402) */ #define ISO_HPPA_PALO_CMDLEN 0xE830FE6E +/** Problems encountered during inspection of System Area (WARN, HIG, -403) */ +#define ISO_SYSAREA_PROBLEMS 0xD030FE6D + + /* Internal developer note: Place new error codes directly above this comment. diff --git a/libisofs/libisofs.ver b/libisofs/libisofs.ver index c0df07d..159b2b0 100644 --- a/libisofs/libisofs.ver +++ b/libisofs/libisofs.ver @@ -116,6 +116,7 @@ iso_image_import; iso_image_new; iso_image_ref; iso_image_remove_boot_image; +iso_image_report_system_area; iso_image_set_abstract_file_id; iso_image_set_app_use; iso_image_set_application_id; diff --git a/libisofs/make_isohybrid_mbr.c b/libisofs/make_isohybrid_mbr.c index 0a453c1..a65ded6 100644 --- a/libisofs/make_isohybrid_mbr.c +++ b/libisofs/make_isohybrid_mbr.c @@ -50,7 +50,7 @@ license from above stem licenses, typically from LGPL. In case its generosity is needed, here is the 2-clause BSD license: make_isohybrid_mbr.c is copyright 2002-2008 H. Peter Anvin - and 2008-2012 Thomas Schmitt + and 2008-2014 Thomas Schmitt 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. @@ -435,9 +435,10 @@ int assess_isohybrid_gpt_apm(Ecma119Image *t, int *gpt_count, int gpt_idx[128], for (j = 0; j < t->bootsrc[i]->nsections; j++) block_count += t->bootsrc[i]->sections[j].size / 2048; ret = iso_quick_gpt_entry( - t, t->bootsrc[i]->sections[0].block, - block_count, uuid, zero_uuid, gpt_flags, - (uint8_t *) gpt_name); + t->gpt_req, &(t->gpt_req_count), + ((uint64_t) t->bootsrc[i]->sections[0].block) * 4, + ((uint64_t) block_count) * 4, + uuid, zero_uuid, gpt_flags, (uint8_t *) gpt_name); if (ret < 0) return ret; } @@ -449,7 +450,8 @@ int assess_isohybrid_gpt_apm(Ecma119Image *t, int *gpt_count, int gpt_idx[128], block_count = 0; for (j = 0; j < t->bootsrc[i]->nsections; j++) block_count += t->bootsrc[i]->sections[j].size / 2048; - ret = iso_quick_apm_entry(t, t->bootsrc[i]->sections[0].block, + ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count), + t->bootsrc[i]->sections[0].block, block_count, "EFI", "Apple_HFS"); if (ret < 0) return ret; @@ -466,7 +468,8 @@ int assess_isohybrid_gpt_apm(Ecma119Image *t, int *gpt_count, int gpt_idx[128], iso_ascii_utf_16le(gpt_name); /* Let it be open ended. iso_write_gpt() will truncate it as needed. */ block_count = 0xffffffff; - ret = iso_quick_gpt_entry(t, (uint32_t) 0, block_count, + ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count), + (uint64_t) 0, ((uint64_t) block_count) * 4, basic_data_uuid, zero_uuid, gpt_flags, (uint8_t *) gpt_name); if (ret < 0) diff --git a/libisofs/messages.c b/libisofs/messages.c index d513042..f5a6289 100644 --- a/libisofs/messages.c +++ b/libisofs/messages.c @@ -515,6 +515,8 @@ const char *iso_error_to_msg(int errcode) return "HP-PA PALO file is not a data file"; case ISO_HPPA_PALO_CMDLEN: return "HP-PA PALO command line too long"; + case ISO_SYSAREA_PROBLEMS: + return "Problems encountered during inspection of System Area"; default: return "Unknown error"; } diff --git a/libisofs/system_area.c b/libisofs/system_area.c index badd741..cc5555c 100644 --- a/libisofs/system_area.c +++ b/libisofs/system_area.c @@ -902,8 +902,10 @@ static int make_hppa_palo_sector(Ecma119Image *t, uint8_t *buf, int hdrversion, /* Convenience frontend for iso_register_apm_entry(). name and type are 0-terminated strings. */ -int iso_quick_apm_entry(Ecma119Image *t, - uint32_t start_block, uint32_t block_count, char *name, char *type) +int iso_quick_apm_entry(struct iso_apm_partition_request **req_array, + int *apm_req_count, + uint32_t start_block, uint32_t block_count, + char *name, char *type) { int ret; struct iso_apm_partition_request *entry; @@ -915,7 +917,7 @@ int iso_quick_apm_entry(Ecma119Image *t, entry->block_count = block_count; strncpy((char *) entry->name, name, 32); strncpy((char *) entry->type, type, 32); - ret = iso_register_apm_entry(t, entry, 0); + ret = iso_register_apm_entry(req_array, apm_req_count, entry, 0); free(entry); return ret; } @@ -924,8 +926,9 @@ int iso_quick_apm_entry(Ecma119Image *t, /* Convenience frontend for iso_register_gpt_entry(). name has to be already encoded as UTF-16LE. */ -int iso_quick_gpt_entry(Ecma119Image *t, - uint32_t start_block, uint32_t block_count, +int iso_quick_gpt_entry(struct iso_gpt_partition_request **req_array, + int *gpt_req_count, + uint64_t start_block, uint64_t block_count, uint8_t type_guid[16], uint8_t partition_guid[16], uint64_t flags, uint8_t name[72]) { @@ -941,13 +944,14 @@ int iso_quick_gpt_entry(Ecma119Image *t, memcpy(entry->partition_guid, partition_guid, 16); entry->flags = flags; memcpy(entry->name, name, 72); - ret = iso_register_gpt_entry(t, entry, 0); + ret = iso_register_gpt_entry(req_array, gpt_req_count, entry, 0); free(entry); return ret; } -int iso_quick_mbr_entry(Ecma119Image *t, +int iso_quick_mbr_entry(struct iso_mbr_partition_request **req_array, + int *mbr_req_count, uint64_t start_block, uint64_t block_count, uint8_t type_byte, uint8_t status_byte, int desired_slot) @@ -955,7 +959,7 @@ int iso_quick_mbr_entry(Ecma119Image *t, int ret; struct iso_mbr_partition_request *entry; - ret = iso_mbr_entry_slot_is_free(t, desired_slot); + ret = iso_mbr_entry_slot_is_free(req_array, *mbr_req_count, desired_slot); if (ret < 0) desired_slot = 0; else if (ret == 0) @@ -969,13 +973,14 @@ int iso_quick_mbr_entry(Ecma119Image *t, entry->type_byte = type_byte; entry->status_byte = status_byte; entry->desired_slot = desired_slot; - ret = iso_register_mbr_entry(t, entry, 0); + ret = iso_register_mbr_entry(req_array, mbr_req_count, entry, 0); free(entry); return ret; } -int iso_mbr_entry_slot_is_free(Ecma119Image *t, int slot) +int iso_mbr_entry_slot_is_free(struct iso_mbr_partition_request **req_array, + int mbr_req_count, int slot) { int i; @@ -983,8 +988,8 @@ int iso_mbr_entry_slot_is_free(Ecma119Image *t, int slot) return -1; if (slot == 0) return 1; - for (i = 0; i < t->mbr_req_count; i++) - if (t->mbr_req[i]->desired_slot == slot) + for (i = 0; i < mbr_req_count; i++) + if (req_array[i]->desired_slot == slot) return 0; return 1; } @@ -997,8 +1002,8 @@ static int cmp_partition_request(const void *f1, const void *f2) { struct iso_partition_request { - uint32_t start_block; - uint32_t block_count; + uint64_t start_block; + uint64_t block_count; } *r1, *r2; r1 = *((struct iso_partition_request **) f1); @@ -1046,10 +1051,10 @@ static int iso_write_apm_entry(Ecma119Image *t, int apm_block_size, iso_msb(wpt, (uint32_t) map_entries, 4); wpt += 4; /* Physical block start of partition */ - iso_msb(wpt, req->start_block * block_fac, 4); + iso_msb(wpt, (uint32_t) (req->start_block * block_fac), 4); wpt += 4; /* Physical block count of partition */ - iso_msb(wpt, req->block_count * block_fac, 4); + iso_msb(wpt, (uint32_t) (req->block_count * block_fac), 4); wpt += 4; /* Partition name */ memcpy(wpt, req->name, 32); @@ -1058,10 +1063,10 @@ static int iso_write_apm_entry(Ecma119Image *t, int apm_block_size, memcpy(wpt, req->type, 32); wpt += 32; /* Logical block start */ - iso_msb(wpt, 0, 4); + iso_msb(wpt, (uint32_t) 0, 4); wpt += 4; /* Logical block count */ - iso_msb(wpt, req->block_count * block_fac, 4); + iso_msb(wpt, (uint32_t) (req->block_count * block_fac), 4); wpt += 4; /* Status flags : bit0= entry is valid , bit1= entry is allocated bit4= partition is readable , bit5= partition is writable @@ -1103,7 +1108,8 @@ static int fill_apm_gaps(Ecma119Image *t, uint32_t img_blocks) break; } if (i >= t->apm_req_count) { - ret = iso_quick_apm_entry(t, 1, 0, "Apple", "Apple_partition_map"); + ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count), + 1, 0, "Apple", "Apple_partition_map"); if (ret < 0) return ret; } @@ -1115,7 +1121,7 @@ static int fill_apm_gaps(Ecma119Image *t, uint32_t img_blocks) 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; + goal = (uint32_t) t->apm_req[i]->start_block; else goal = img_blocks * block_fac; if (i == 1) { @@ -1141,7 +1147,8 @@ static int fill_apm_gaps(Ecma119Image *t, uint32_t img_blocks) 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, + ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count), + part_end, goal - part_end, gap_name, "ISO9660_data"); if (ret < 0) return ret; @@ -1167,15 +1174,18 @@ static int rectify_apm(Ecma119Image *t) /* <<< ts B20526 : Dummy mock-up */ if (t->apm_req_count <= 0) { /* - ret = iso_quick_apm_entry(t, 16, 20, "Test1_name_16_20", "Test1_type"); + ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count), + 16, 20, "Test1_name_16_20", "Test1_type"); / * >>> Caution: Size 90 causes intentional partition overlap error * / - ret = iso_quick_apm_entry(t, 30, 90, "BAD_30_90_BAD", "Test1_type"); + ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count), + 30, 90, "BAD_30_90_BAD", "Test1_type"); */ - ret = iso_quick_apm_entry(t, 30, 20, "Test1_name_30_20", "Test1_type"); + ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count), + 30, 20, "Test1_name_30_20", "Test1_type"); if (ret < 0) return ret; - ret = iso_quick_apm_entry(t, 100, 400, "Test2_name_100_400", - "Test2_type"); + ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count), + 100, 400, "Test2_name_100_400", "Test2_type"); if (ret < 0) return ret; } @@ -1280,10 +1290,12 @@ static int iso_write_mbr(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) /* <<< Dummy mock-up */ if (t->mbr_req_count <= 0) { - ret = iso_quick_mbr_entry(t, (uint64_t) 0, (uint64_t) 0, 0xee, 0, 0); + ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count), + (uint64_t) 0, (uint64_t) 0, 0xee, 0, 0); if (ret < 0) return ret; - ret = iso_quick_mbr_entry(t, ((uint64_t) 100) * 4, (uint64_t) 0, + ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count), + ((uint64_t) 100) * 4, (uint64_t) 0, 0x0c, 0x80, 1); if (ret < 0) return ret; @@ -1491,8 +1503,8 @@ static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 }; - uint32_t p_arr_crc = 0, part_end, goal, next_end; - uint64_t start_lba, end_lba; + uint32_t p_arr_crc = 0; + uint64_t start_lba, end_lba, goal, part_end, next_end, backup_end_lba; int ret, i, gap_counter = 0, up_to; struct iso_gpt_partition_request *req; uint8_t gpt_name[72]; @@ -1513,12 +1525,12 @@ static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) if (i < up_to - 1) { goal = t->gpt_req[i]->start_block; } else { - goal = img_blocks; + goal = ((uint64_t) img_blocks) * 4; } if (i == 0) { - if (goal <= 16) + if (goal <= 16 * 4) continue; - next_end = 16; + next_end = 16 * 4; } else { next_end = t->gpt_req[i - 1]->start_block + t->gpt_req[i - 1]->block_count; @@ -1528,8 +1540,8 @@ static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) if (part_end > goal) { if (!(t->gpt_req_flags & 1)) { iso_msg_submit(t->image->id, ISO_BOOT_GPT_OVERLAP, 0, - "Program error: GPT partitions %d and %d overlap by %lu blocks", - i - 1, i, part_end - goal); + "Program error: GPT partitions %d and %d overlap by %.f blocks", + i - 1, i, (double) (part_end - goal)); return ISO_BOOT_GPT_OVERLAP; } } else if (part_end < goal) { @@ -1537,7 +1549,8 @@ static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) sprintf((char *) gpt_name, "Gap%d", gap_counter); iso_ascii_utf_16le(gpt_name); gap_counter++; - ret = iso_quick_gpt_entry(t, part_end, goal - part_end, + ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count), + part_end, goal - part_end, basic_data_uuid, zero_uuid, gpt_flags, gpt_name); if (ret < 0) @@ -1554,11 +1567,13 @@ static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) /* Write the GPT entries to buf */ for (i = 0; i < t->gpt_req_count; i++) { req = t->gpt_req[i]; - start_lba = ((uint64_t) req->start_block) * 4; - end_lba = ((uint64_t) req->start_block) + req->block_count; - if (end_lba > t->gpt_backup_end - t->gpt_backup_size) - end_lba = t->gpt_backup_end - t->gpt_backup_size; - end_lba = end_lba * 4 - 1; + start_lba = req->start_block; + end_lba = req->start_block + req->block_count; + backup_end_lba = ((uint64_t) t->gpt_backup_end - t->gpt_backup_size) * + 4; + if (end_lba > backup_end_lba) + end_lba = backup_end_lba; + end_lba = end_lba - 1; 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); @@ -1929,56 +1944,58 @@ ex:; } -int iso_register_apm_entry(Ecma119Image *t, +int iso_register_apm_entry(struct iso_apm_partition_request **req_array, + int *apm_req_count, struct iso_apm_partition_request *req, int flag) { struct iso_apm_partition_request *entry; - if (t->apm_req_count >= ISO_APM_ENTRIES_MAX) + if (*apm_req_count >= ISO_APM_ENTRIES_MAX) return ISO_BOOT_TOO_MANY_APM; entry = calloc(1, sizeof(struct iso_apm_partition_request)); if (entry == NULL) return ISO_OUT_OF_MEM; memcpy(entry, req, sizeof(struct iso_apm_partition_request)); - t->apm_req[t->apm_req_count] = entry; - t->apm_req_count++; + req_array[*apm_req_count] = entry; + (*apm_req_count)++; return ISO_SUCCESS; } -int iso_register_mbr_entry(Ecma119Image *t, +int iso_register_mbr_entry(struct iso_mbr_partition_request **req_array, + int *mbr_req_count, struct iso_mbr_partition_request *req, int flag) { struct iso_mbr_partition_request *entry; - if (t->mbr_req_count >= ISO_MBR_ENTRIES_MAX) + if (*mbr_req_count >= ISO_MBR_ENTRIES_MAX) return ISO_BOOT_TOO_MANY_MBR; entry = calloc(1, sizeof(struct iso_mbr_partition_request)); if (entry == NULL) return ISO_OUT_OF_MEM; memcpy(entry, req, sizeof(struct iso_mbr_partition_request)); - t->mbr_req[t->mbr_req_count] = entry; - t->mbr_req_count++; + req_array[*mbr_req_count] = entry; + (*mbr_req_count)++; return ISO_SUCCESS; } - -int iso_register_gpt_entry(Ecma119Image *t, +int iso_register_gpt_entry(struct iso_gpt_partition_request **req_array, + int *gpt_req_count, struct iso_gpt_partition_request *req, int flag) { struct iso_gpt_partition_request *entry; - if (t->gpt_req_count >= ISO_GPT_ENTRIES_MAX) + if (*gpt_req_count >= ISO_GPT_ENTRIES_MAX) return ISO_BOOT_TOO_MANY_GPT; entry = calloc(1, sizeof(struct iso_gpt_partition_request)); if (entry == NULL) return ISO_OUT_OF_MEM; memcpy(entry, req, sizeof(struct iso_gpt_partition_request)); - t->gpt_req[t->gpt_req_count] = entry; - t->gpt_req_count++; + req_array[*gpt_req_count] = entry; + (*gpt_req_count)++; return ISO_SUCCESS; } @@ -2185,19 +2202,26 @@ static int precompute_gpt(Ecma119Image *t) strcpy((char *) gpt_name, "GPT Test 1"); iso_ascii_utf_16le(gpt_name); /* - ret = iso_quick_gpt_entry(t, 16, 20, hfs_uuid, zero_uuid, - gpt_flags, gpt_name); + ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count), + (uint64_t) (16 * 4), (uint64_t) (20 * 4), + 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, + ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count), + (uint64_t) (30 * 4), (uint64_t) (90 * 4), + hfs_uuid, zero_uuid, gpt_flags, gpt_name); */ - ret = iso_quick_gpt_entry(t, 30, 40, hfs_uuid, zero_uuid, + ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count), + (uint64_t) (30 * 4), (uint64_t) (40 * 4), + hfs_uuid, zero_uuid, gpt_flags, gpt_name); if (ret < 0) return ret; strcpy((char *) gpt_name, "GPT Test 2"); iso_ascii_utf_16le(gpt_name); - ret = iso_quick_gpt_entry(t, 110, 60, basic_data_uuid, zero_uuid, + ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count), + (uint64_t) (110 * 4), (uint64_t) (60 * 4), + basic_data_uuid, zero_uuid, gpt_flags, gpt_name); if (ret < 0) return ret; @@ -2406,7 +2430,9 @@ static int partprepend_writer_compute_data_blocks(IsoImageWriter *writer) memset(gpt_name, 0, 72); strcpy((char *) gpt_name, "EFI boot partition"); iso_ascii_utf_16le(gpt_name); - ret = iso_quick_gpt_entry(t, t->curblock, t->efi_boot_part_size, + ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count), + ((uint64_t) t->curblock) * 4, + ((uint64_t) t->efi_boot_part_size) * 4, efi_sys_uuid, zero_uuid, gpt_flags, gpt_name); if (ret < 0) return ret; @@ -2418,8 +2444,8 @@ static int partprepend_writer_compute_data_blocks(IsoImageWriter *writer) if (t->opts->prep_partition != NULL || t->opts->fat || will_have_gpt || t->mbr_req_count > 0) return ISO_BOOT_MBR_OVERLAP; - ret = iso_quick_mbr_entry(t, (uint64_t) 0, (uint64_t) 0, - 0x96, 0x80, 0); + ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count), + (uint64_t) 0, (uint64_t) 0, 0x96, 0x80, 0); if (ret < 0) return ret; return ISO_SUCCESS; @@ -2433,7 +2459,8 @@ static int partprepend_writer_compute_data_blocks(IsoImageWriter *writer) } if (t->prep_part_size > 0 || t->opts->fat || will_have_gpt) { /* Protecting MBR entry for ISO start or whole ISO */ - ret = iso_quick_mbr_entry(t, will_have_gpt ? (uint64_t) 1 : + ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count), + will_have_gpt ? (uint64_t) 1 : ((uint64_t) t->opts->partition_offset) * 4, (uint64_t) 0, will_have_gpt ? 0xee : 0xcd, 0, 0); @@ -2441,7 +2468,8 @@ static int partprepend_writer_compute_data_blocks(IsoImageWriter *writer) return ret; } if (t->prep_part_size > 0) { - ret = iso_quick_mbr_entry(t, ((uint64_t) t->curblock) * 4, + ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count), + ((uint64_t) t->curblock) * 4, ((uint64_t) t->prep_part_size) * 4, 0x41, 0, 0); if (ret < 0) @@ -2450,8 +2478,8 @@ static int partprepend_writer_compute_data_blocks(IsoImageWriter *writer) } if (t->prep_part_size > 0 || t->opts->fat) { /* FAT partition or protecting MBR entry for ISO end */ - ret = iso_quick_mbr_entry(t, ((uint64_t) t->curblock) * 4, - (uint64_t) 0, + ret = iso_quick_mbr_entry(t->mbr_req, &(t->mbr_req_count), + ((uint64_t) t->curblock) * 4, (uint64_t) 0, t->opts->fat ? 0x0c : 0xcd, 0, 0); if (ret < 0) return ret; diff --git a/libisofs/system_area.h b/libisofs/system_area.h index c45b9c2..7177cdd 100644 --- a/libisofs/system_area.h +++ b/libisofs/system_area.h @@ -108,13 +108,15 @@ struct iso_mbr_partition_request { I.e. after the call the submitted storage of req can be disposed or re-used. Submit 0 as value flag. */ -int iso_register_mbr_entry(Ecma119Image *t, +int iso_register_mbr_entry(struct iso_mbr_partition_request **req_array, + int *mbr_req_count, struct iso_mbr_partition_request *req, int flag); /* Convenience frontend for iso_register_mbr_entry(). name and type are 0-terminated strings, which may get silently truncated. */ -int iso_quick_mbr_entry(Ecma119Image *t, +int iso_quick_mbr_entry(struct iso_mbr_partition_request **req_array, + int *mbr_req_count, uint64_t start_block, uint64_t block_count, uint8_t type_byte, uint8_t status_byte, int desired_slot); @@ -125,12 +127,13 @@ int iso_quick_mbr_entry(Ecma119Image *t, 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); +int iso_mbr_entry_slot_is_free(struct iso_mbr_partition_request **req_array, + int mbr_req_count, int slot); /* The parameter struct for production of a single Apple Partition Map entry. See also the partial APM description in doc/boot_sectors.txt. - The list of entries is stored in Ecma119Image.apm_req. + The list of entries is stored e.g. in Ecma119Image.apm_req, .apm_req_count. The size of a block can be chosen by setting Ecma119Image.apm_block_size. If an entry has start_block <=1, then its block_count will be adjusted to the final size of the partition map. @@ -144,8 +147,8 @@ struct iso_apm_partition_request { /* Given in blocks of 2 KiB unless (Ecma119Image.apm_req_flags & 4). Written to the ISO image according to Ecma119Image.apm_block_size. */ - uint32_t start_block; - uint32_t block_count; + uint64_t start_block; + uint64_t block_count; /* All 32 bytes get copied to the system area. Take care to pad up short strings by 0. @@ -158,14 +161,17 @@ struct iso_apm_partition_request { I.e. after the call the submitted storage of req can be disposed or re-used. Submit 0 as value flag. */ -int iso_register_apm_entry(Ecma119Image *t, +int iso_register_apm_entry(struct iso_apm_partition_request **req_array, + int *apm_req_count, struct iso_apm_partition_request *req, int flag); /* Convenience frontend for iso_register_apm_entry(). name and type are 0-terminated strings, which may get silently truncated. */ -int iso_quick_apm_entry(Ecma119Image *t, - uint32_t start_block, uint32_t block_count, char *name, char *type); +int iso_quick_apm_entry(struct iso_apm_partition_request **req_array, + int *apm_req_count, + uint32_t start_block, uint32_t block_count, + char *name, char *type); /* CRC-32 as of GPT and Ethernet. @@ -206,11 +212,10 @@ void iso_random_uuid(Ecma119Image *t, uint8_t uuid[16]); */ struct iso_gpt_partition_request { - /* Always given in blocks of 2 KiB. - Written to the ISO image in blocks of 512. + /* Always given in blocks of 512 bytes. */ - uint32_t start_block; - uint32_t block_count; + uint64_t start_block; + uint64_t block_count; /* The registered GUID which defines the partition type */ uint8_t type_guid[16]; @@ -231,20 +236,26 @@ struct iso_gpt_partition_request { Take care to pad up short strings by 0. */ uint8_t name[72]; + + /* Only if read from imported image: Table index of partition (first = 1) + */ + uint32_t idx; }; /* Copies the content of req and registers it in t.gpt_req[]. I.e. after the call the submitted storage of req can be disposed or re-used. Submit 0 as value flag. */ -int iso_register_gpt_entry(Ecma119Image *t, +int iso_register_gpt_entry(struct iso_gpt_partition_request **req_array, + int *gpt_req_count, struct iso_gpt_partition_request *req, int flag); /* Convenience frontend for iso_register_gpt_entry(). name has to be already encoded as UTF-16LE. */ -int iso_quick_gpt_entry(Ecma119Image *t, - uint32_t start_block, uint32_t block_count, +int iso_quick_gpt_entry(struct iso_gpt_partition_request **req_array, + int *gpt_req_count, + uint64_t start_block, uint64_t block_count, uint8_t type_guid[16], uint8_t partition_guid[16], uint64_t flags, uint8_t name[72]); @@ -255,6 +266,23 @@ 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); +/* The description of a loaded MIPS Big Endian Volume Directory Entry +*/ +struct iso_mips_voldir_entry { + char name[9]; + uint32_t boot_block; + uint32_t boot_bytes; +}; + +/* The description of a loaded SUN Disk Label partition */ +struct iso_sun_disk_label_entry { + int idx; + uint16_t id_tag; + uint16_t permissions; + uint32_t start_cyl; + uint32_t num_blocks; +}; + /* Creates the Partition Prepend writer. */ int partprepend_writer_create(Ecma119Image *target); diff --git a/libisofs/tree.c b/libisofs/tree.c index b519ae5..e04bfb7 100644 --- a/libisofs/tree.c +++ b/libisofs/tree.c @@ -1187,6 +1187,55 @@ ex:; return path; } +/* Note: No reference is taken to the found node. + @param flag bit0= recursion +*/ +int iso_tree_get_node_of_block(IsoImage *image, IsoDir *dir, uint32_t block, + IsoNode **found, int flag) +{ + int ret, section_count, i; + IsoDirIter *iter = NULL; + IsoNode *node; + IsoDir *subdir; + IsoFile *file; + struct iso_file_section *sections = NULL; + + if (dir == NULL) + dir = image->root; + + ret = iso_dir_get_children(dir, &iter); + while (iso_dir_iter_next(iter, &node) == 1 ) { + + if (ISO_NODE_IS_FILE(node)) { + file = (IsoFile *) node; + ret = iso_file_get_old_image_sections(file, §ion_count, + §ions, 0); + if (ret <= 0) + continue; + for (i = 0; i < section_count; i++) { + if (sections[i].block <= block && + block - sections[i].block < + (((off_t) sections[i].size) + 2047) / 2048) { + *found = node; + ret = 1; goto ex; + } + } + free(sections); sections = NULL; + } else if (ISO_NODE_IS_DIR(node)) { + subdir = (IsoDir *) node; + ret = iso_tree_get_node_of_block(image, subdir, block, found, 1); + if (ret != 0) + goto ex; + } + } + ret = 0; +ex: + if (sections != NULL) + free(sections); + return ret; +} + + /* ------------------------- tree cloning ------------------------------ */ static diff --git a/libisofs/tree.h b/libisofs/tree.h index f184792..6301919 100644 --- a/libisofs/tree.h +++ b/libisofs/tree.h @@ -19,4 +19,9 @@ */ int iso_add_dir_src_rec(IsoImage *image, IsoDir *parent, IsoFileSource *dir); + +int iso_tree_get_node_of_block(IsoImage *image, IsoDir *dir, uint32_t block, + IsoNode **found, int flag); + + #endif /*LIBISO_IMAGE_TREE_H_*/ diff --git a/libisofs/util.c b/libisofs/util.c index ee91864..89ca8b4 100644 --- a/libisofs/util.c +++ b/libisofs/util.c @@ -1534,6 +1534,26 @@ uint32_t iso_read_bb(const uint8_t *buf, int bytes, int *error) return v1; } +uint64_t iso_read_lsb64(const uint8_t *buf) +{ + int i; + uint64_t ret = 0; + + for (i=0; i < 8; i++) + ret += ((uint64_t) buf[i]) << (i * 8); + return ret; +} + +uint64_t iso_read_msb64(const uint8_t *buf) +{ + int i; + uint64_t ret = 0; + + for (i=0; i < 8; i++) + ret += ((uint64_t) buf[7 - i]) << (i * 8); + return ret; +} + void iso_datetime_7(unsigned char *buf, time_t t, int always_gmt) { static int tzsetup = 0; @@ -2011,6 +2031,17 @@ int iso_util_dec_to_uint32(char *dec, uint32_t *value, int flag) } +int iso_util_bin_to_hex(char *target, uint8_t *bytes, int num_bytes, int flag) +{ + int i; + + for (i = 0; i < num_bytes; i++) + sprintf(target + 2 * i, "%-2.2x", bytes[i]); + target[2 * num_bytes] = 0; + return 1; +} + + int iso_util_hex_to_bin(char *hex, char *bin, int bin_size, int *bin_count, int flag) { diff --git a/libisofs/util.h b/libisofs/util.h index d1eae35..cb73e41 100644 --- a/libisofs/util.h +++ b/libisofs/util.h @@ -273,6 +273,9 @@ uint32_t iso_read_msb(const uint8_t *buf, int bytes); */ uint32_t iso_read_bb(const uint8_t *buf, int bytes, int *error); +uint64_t iso_read_lsb64(const uint8_t *buf); +uint64_t iso_read_msb64(const uint8_t *buf); + /** * Records the date/time into a 7 byte buffer (ECMA-119, 9.1.5) * @@ -544,6 +547,12 @@ int iso_util_eval_md5_tag(char *block, int desired, uint32_t lba, int iso_util_tag_magic(int tag_type, char **tag_magic, int *len, int flag); +int iso_util_bin_to_hex(char *target, uint8_t *bytes, int num_bytes, int flag); + +int iso_util_hex_to_bin(char *hex, char *bin, int bin_size, int *bin_count, + int flag); + + /* ------------------------------------------------------------------------- */ /* In md5.h these function prototypes would be neighbors of (Ecma119Image *)