diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index 628a49d..644d394 100644 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -1920,7 +1920,10 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) if (target->hfsplus_blessed[i] != NULL) iso_node_ref(target->hfsplus_blessed[i]); } - target->apm_block_size = 512; + target->apm_block_size = opts->apm_block_size; + target->hfsp_block_size = opts->hfsp_block_size; + target->hfsp_cat_node_size = 0; + target->hfsp_iso_block_fac = 0; target->apm_req_count = 0; target->apm_req_flags = 0; for (i = 0; i < ISO_APM_ENTRIES_MAX; i++) @@ -2356,6 +2359,13 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) iso_image_free_checksums(target->image, 0); image_checksums_mad = 0; + if (target->apm_block_size == 0) { + if (target->gpt_req_count) + target->apm_block_size = 2048; /* Combinable with GPT */ + else + target->apm_block_size = 512; /* Mountable on Linux */ + } + /* ensure the thread is created joinable */ pthread_attr_init(&(target->th_attr)); pthread_attr_setdetachstate(&(target->th_attr), PTHREAD_CREATE_JOINABLE); @@ -2739,6 +2749,8 @@ int iso_write_opts_new(IsoWriteOpts **opts, int profile) wopts->untranslated_name_len = 0; for (i = 0; i < 8; i++) wopts->hfsp_serial_number[i] = 0; + wopts->apm_block_size = 0; + wopts->hfsp_block_size = 0; *opts = wopts; return ISO_SUCCESS; @@ -3403,4 +3415,18 @@ int iso_write_opts_set_hfsp_serial_number(IsoWriteOpts *opts, memcpy(opts->hfsp_serial_number, serial_number, 8); return ISO_SUCCESS; } + +int iso_write_opts_set_hfsp_block_size(IsoWriteOpts *opts, + int hfsp_block_size, int apm_block_size) +{ + if (hfsp_block_size != 0 && hfsp_block_size != 512 && + hfsp_block_size != 2048) + return ISO_BOOT_HFSP_BAD_BSIZE; + opts->hfsp_block_size = hfsp_block_size; + if (apm_block_size != 0 && apm_block_size != 512 && apm_block_size != 2048) + return ISO_BOOT_HFSP_BAD_BSIZE; + opts->apm_block_size = apm_block_size; + return ISO_SUCCESS; +} + diff --git a/libisofs/ecma119.h b/libisofs/ecma119.h index 16752af..5b60149 100644 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -477,6 +477,14 @@ struct iso_write_opts { */ uint8_t hfsp_serial_number[8]; + /* Allocation block size of HFS+ : 0= auto , 512, or 2048 + */ + int hfsp_block_size; + + /* Block size of and in APM : 0= auto , 512, or 2048 + */ + int apm_block_size; + }; typedef struct ecma119_image Ecma119Image; @@ -819,6 +827,22 @@ struct ecma119_image /* See IsoImage and libisofs.h */ IsoNode *hfsplus_blessed[ISO_HFSPLUS_BLESS_MAX]; + /* Block sizes come from write options. + Only change a block size if it is 0. Set only to 512 or 2048. + If it stays 0 then it will become 512 or 2048 in time. + */ + /* Blocksize of Apple Partition Map + May be defined to 512 or 2048 before writer thread starts. + */ + int apm_block_size; + + /* Allocation block size of HFS+ + May be defined to 512 or 2048 before hfsplus_writer_create(). + */ + int hfsp_block_size; + int hfsp_cat_node_size; /* 2 * apm_block_size */ + int hfsp_iso_block_fac; /* 2048 / apm_block_size */ + /* Apple Partition Map description. To be composed during IsoImageWriter method ->compute_data_blocks() by calling iso_register_apm_entry(). Make sure that the composing writers get registered before the @@ -826,9 +850,10 @@ struct ecma119_image */ struct iso_apm_partition_request *apm_req[ISO_APM_ENTRIES_MAX]; int apm_req_count; - /* 512 by default. May be changed to 2048 before writer thread starts. */ - int apm_block_size; - /* bit1= Do not fill gaps in Apple Partition Map */ + /* bit1= Do not fill gaps in Apple Partition Map + bit2= apm_req entries use apm_block_size in start_block and block_count. + Normally these two parameters are counted in 2 KiB blocks. + */ int apm_req_flags; /* MBR partition table description. To be composed during IsoImageWriter diff --git a/libisofs/hfsplus.c b/libisofs/hfsplus.c index fef2e84..5e75d88 100644 --- a/libisofs/hfsplus.c +++ b/libisofs/hfsplus.c @@ -20,6 +20,16 @@ #define Libisofs_ts_debuG yes +/* Do not fill gaps in APM. + <<< provisory , rather not + # define Libisofs_hfsplus_no_gap_filL yes +*/ + +/* Avoid ISO block padding in hfsplus_tail_writer + <<< provisory , rather not + # define Libisofs_apm_flags_bit2 yes +*/ + #ifdef HAVE_CONFIG_H #include "../config.h" @@ -41,10 +51,16 @@ #include #include -#define HFSPLUS_BLOCK_SIZE 2048 -#define HFSPLUS_CAT_NODE_SIZE (2 * HFSPLUS_BLOCK_SIZE) +/* To be used if Ecma119.hfsplus_block_size == 0 in hfsplus_writer_create(). + It cannot be larger than 2048 because filesrc_writer aligns data file + content start to 2048. +*/ +#define HFSPLUS_DEFAULT_BLOCK_SIZE 2048 + +/* To be used with storage allocation. +*/ +#define HFSPLUS_MAX_BLOCK_SIZE 2048 -#define HFSPLUS_ISO_BLOCK_FAC (2048 / HFSPLUS_BLOCK_SIZE) #include /* For these prototypes: @@ -311,8 +327,8 @@ int create_tree(Ecma119Image *t, IsoNode *iso, uint32_t parent_id) if (t->hfsplus_blessed[i] == iso) { #ifdef Libisofs_ts_debuG -iso_msg_debug(t->image->id, "hfsplus bless %d to cat_id %u ('%s')", - i, cat_id, iso->name); + iso_msg_debug(t->image->id, "hfsplus bless %d to cat_id %u ('%s')", + i, cat_id, iso->name); #endif /* Libisofs_ts_debuG */ t->hfsp_bless_id[i] = cat_id; @@ -417,100 +433,141 @@ cmp_node(const void *f1, const void *f2) return ucscmp(a, b); } + static int hfsplus_tail_writer_compute_data_blocks(IsoImageWriter *writer) { Ecma119Image *t; - uint32_t hfsp_size; - + uint32_t hfsp_size, hfsp_curblock, block_fac, block_size; + if (writer == NULL) { return ISO_OUT_OF_MEM; } t = writer->target; + block_size = t->hfsp_block_size; + block_fac = t->hfsp_iso_block_fac; #ifdef Libisofs_ts_debuG -iso_msg_debug(t->image->id, "hfsplus tail writer start = %.f", - ((double) t->curblock) * 2048.0); + iso_msg_debug(t->image->id, "hfsplus tail writer start = %.f", + ((double) t->curblock) * 2048.0); #endif - hfsp_size = t->curblock * HFSPLUS_ISO_BLOCK_FAC - t->hfsp_part_start + 1; + hfsp_curblock = t->curblock * block_fac; + hfsp_size = hfsp_curblock - t->hfsp_part_start + 1; /* We need one bit for every block. */ /* So if we allocate x blocks we have to satisfy: - 8 * HFSPLUS_BLOCK_SIZE * x >= total_size + x - (8 * HFSPLUS_BLOCK_SIZE - 1) * x >= total_size + 8 * block_size * x >= total_size + x + (8 * block_size - 1) * x >= total_size */ - t->hfsp_allocation_blocks = hfsp_size - / (8 * HFSPLUS_BLOCK_SIZE - 1) + 1; - t->hfsp_allocation_file_start = t->curblock * HFSPLUS_ISO_BLOCK_FAC; - t->curblock += t->hfsp_allocation_blocks / HFSPLUS_ISO_BLOCK_FAC; - if (t->hfsp_allocation_blocks % HFSPLUS_ISO_BLOCK_FAC) + t->hfsp_allocation_blocks = hfsp_size / (8 * block_size - 1) + 1; + t->hfsp_allocation_file_start = hfsp_curblock; + hfsp_curblock += t->hfsp_allocation_blocks; + +#ifdef Libisofs_apm_flags_bit2 + + /* Superblock always occupies 2K */ + hfsp_curblock += block_fac; + + /* write_data() will need to pad up ISO block after superblock copy */ + t->curblock = hfsp_curblock / block_fac; + if (hfsp_curblock % block_fac) t->curblock++; + +#else /* Libisofs_apm_flags_bit2 */ + + /* write_data() will need to pad up ISO block before superblock copy */ + t->curblock = hfsp_curblock / block_fac; + if (hfsp_curblock % block_fac) + t->curblock++; + hfsp_curblock = t->curblock * block_fac; + + /* Superblock always occupies 2K */ + hfsp_curblock += block_fac; t->curblock++; +#endif /* ! Libisofs_apm_flags_bit4 */ + #ifdef Libisofs_ts_debuG -iso_msg_debug(t->image->id, "hfsplus tail writer end = %.f", - ((double) t->curblock) * 2048.0); + iso_msg_debug(t->image->id, "hfsplus tail writer end = %.f", + ((double) hfsp_curblock) * block_size); #endif - t->hfsp_total_blocks = t->curblock * HFSPLUS_ISO_BLOCK_FAC - - t->hfsp_part_start; - t->apm_block_size = HFSPLUS_BLOCK_SIZE; - return iso_quick_apm_entry(t, t->hfsp_part_start / HFSPLUS_ISO_BLOCK_FAC, - t->hfsp_total_blocks / HFSPLUS_ISO_BLOCK_FAC + - !!(t->hfsp_total_blocks % HFSPLUS_ISO_BLOCK_FAC), + t->hfsp_total_blocks = hfsp_curblock - t->hfsp_part_start; + +#ifdef Libisofs_hfsplus_no_gap_filL + /* <<< test B20625 : leave out gap filling */ + t->apm_req_flags |= 2; +#endif /* Libisofs_hfsplus_no_gap_filL */ + +#ifdef Libisofs_apm_flags_bit2 + + t->apm_req_flags |= 4; + return iso_quick_apm_entry(t, t->hfsp_part_start, + t->hfsp_total_blocks, "HFSPLUS_Hybrid", "Apple_HFS"); + +#else /* Libisofs_apm_flags_bit2 */ + + return iso_quick_apm_entry(t, t->hfsp_part_start / block_fac, + t->hfsp_total_blocks / block_fac + + !!(t->hfsp_total_blocks % block_fac), + "HFSPLUS_Hybrid", "Apple_HFS"); + +#endif /* ! Libisofs_apm_flags_bit2 */ + } + static int hfsplus_writer_compute_data_blocks(IsoImageWriter *writer) { Ecma119Image *t; - uint32_t i, link_blocks; + uint32_t i, link_blocks, hfsp_curblock; + uint32_t block_fac, cat_node_size, block_size; if (writer == NULL) { return ISO_OUT_OF_MEM; } t = writer->target; + block_size = t->hfsp_block_size; + block_fac = t->hfsp_iso_block_fac; + cat_node_size = t->hfsp_cat_node_size; iso_msg_debug(t->image->id, "(b) curblock=%d, nodes =%d", t->curblock, t->hfsp_nnodes); - t->hfsp_part_start = t->curblock * HFSPLUS_ISO_BLOCK_FAC; + t->hfsp_part_start = t->curblock * block_fac; - t->curblock++; + hfsp_curblock = t->curblock * block_fac; - t->hfsp_catalog_file_start = t->curblock * HFSPLUS_ISO_BLOCK_FAC; + /* Superblock always occupies 2K */ + hfsp_curblock += block_fac; -/* ts B20623 was: - t->curblock += 2 * t->hfsp_nnodes; + t->hfsp_catalog_file_start = hfsp_curblock; + +/* + hfsp_curblock += (t->hfsp_nnodes * cat_node_size + block_size - 1) / block_size; */ - t->curblock += (t->hfsp_nnodes * HFSPLUS_CAT_NODE_SIZE + 2047) / 2048; + hfsp_curblock += 2 * t->hfsp_nnodes; - t->hfsp_extent_file_start = t->curblock * HFSPLUS_ISO_BLOCK_FAC; - t->curblock++; + t->hfsp_extent_file_start = hfsp_curblock; + hfsp_curblock++; - iso_msg_debug(t->image->id, "(d) curblock=%d, nodes =%d", t->curblock, t->hfsp_nnodes); + iso_msg_debug(t->image->id, "(d) hfsp_curblock=%d, nodes =%d", hfsp_curblock, t->hfsp_nnodes); link_blocks = 0; for (i = 0; i < t->hfsp_nleafs; i++) if (t->hfsp_leafs[i].unix_type == UNIX_SYMLINK) { - /* ts B20623 : was: - t->hfsp_leafs[i].symlink_block = t->curblock; - t->curblock += (t->hfsp_leafs[i].symlink_size + HFSPLUS_BLOCK_SIZE - 1) / HFSPLUS_BLOCK_SIZE; - */ + t->hfsp_leafs[i].symlink_block = hfsp_curblock; + hfsp_curblock += (t->hfsp_leafs[i].symlink_size + block_size - 1) / block_size; - t->hfsp_leafs[i].symlink_block = - t->curblock * HFSPLUS_ISO_BLOCK_FAC + link_blocks; - link_blocks += (t->hfsp_leafs[i].symlink_size + - HFSPLUS_BLOCK_SIZE - 1) / HFSPLUS_BLOCK_SIZE; } - /* ts B20623 */ - t->curblock += link_blocks / HFSPLUS_ISO_BLOCK_FAC; - if (link_blocks % HFSPLUS_ISO_BLOCK_FAC) + t->curblock = hfsp_curblock / block_fac; + if (hfsp_curblock % block_fac) t->curblock++; iso_msg_debug(t->image->id, "(a) curblock=%d, nodes =%d", t->curblock, t->hfsp_nnodes); @@ -518,6 +575,7 @@ int hfsplus_writer_compute_data_blocks(IsoImageWriter *writer) return ISO_SUCCESS; } + static void set_time (uint32_t *tm, uint32_t t) { iso_msb ((uint8_t *) tm, t + 2082844800, 4); @@ -570,9 +628,12 @@ write_sb (Ecma119Image *t) static char buffer[1024]; int ret; int i; + uint32_t block_size; iso_msg_debug(t->image->id, "Write HFS+ superblock"); + block_size = t->hfsp_block_size; + memset (buffer, 0, sizeof (buffer)); ret = iso_write(t, buffer, 1024); if (ret < 0) @@ -592,28 +653,28 @@ write_sb (Ecma119Image *t) set_time (&sb.fsck_time, t->now); iso_msb ((uint8_t *) &sb.file_count, t->hfsp_nfiles, 4); iso_msb ((uint8_t *) &sb.folder_count, t->hfsp_ndirs - 1, 4); - iso_msb ((uint8_t *) &sb.blksize, HFSPLUS_BLOCK_SIZE, 4); + iso_msb ((uint8_t *) &sb.blksize, block_size, 4); iso_msb ((uint8_t *) &sb.catalog_node_id, t->hfsp_cat_id, 4); - iso_msb ((uint8_t *) &sb.rsrc_clumpsize, HFSPLUS_BLOCK_SIZE, 4); - iso_msb ((uint8_t *) &sb.data_clumpsize, HFSPLUS_BLOCK_SIZE, 4); + iso_msb ((uint8_t *) &sb.rsrc_clumpsize, block_size, 4); + iso_msb ((uint8_t *) &sb.data_clumpsize, block_size, 4); iso_msb ((uint8_t *) &sb.total_blocks, t->hfsp_total_blocks, 4); iso_msb ((uint8_t *) &sb.encodings_bitmap + 4, 1, 4); iso_msb ((uint8_t *) &sb.allocations_file.size + 4, t->hfsp_allocation_size, 4); - iso_msb ((uint8_t *) &sb.allocations_file.clumpsize, HFSPLUS_BLOCK_SIZE, 4); - iso_msb ((uint8_t *) &sb.allocations_file.blocks, (t->hfsp_allocation_size + HFSPLUS_BLOCK_SIZE - 1) / HFSPLUS_BLOCK_SIZE, 4); + iso_msb ((uint8_t *) &sb.allocations_file.clumpsize, block_size, 4); + iso_msb ((uint8_t *) &sb.allocations_file.blocks, (t->hfsp_allocation_size + block_size - 1) / block_size, 4); iso_msb ((uint8_t *) &sb.allocations_file.extents[0].start, t->hfsp_allocation_file_start - t->hfsp_part_start, 4); - iso_msb ((uint8_t *) &sb.allocations_file.extents[0].count, (t->hfsp_allocation_size + HFSPLUS_BLOCK_SIZE - 1) / HFSPLUS_BLOCK_SIZE, 4); + iso_msb ((uint8_t *) &sb.allocations_file.extents[0].count, (t->hfsp_allocation_size + block_size - 1) / block_size, 4); - iso_msb ((uint8_t *) &sb.extents_file.size + 4, HFSPLUS_BLOCK_SIZE, 4); - iso_msb ((uint8_t *) &sb.extents_file.clumpsize, HFSPLUS_BLOCK_SIZE, 4); + iso_msb ((uint8_t *) &sb.extents_file.size + 4, block_size, 4); + iso_msb ((uint8_t *) &sb.extents_file.clumpsize, block_size, 4); iso_msb ((uint8_t *) &sb.extents_file.blocks, 1, 4); iso_msb ((uint8_t *) &sb.extents_file.extents[0].start, t->hfsp_extent_file_start - t->hfsp_part_start, 4); iso_msb ((uint8_t *) &sb.extents_file.extents[0].count, 1, 4); iso_msg_debug(t->image->id, "extent_file_start = %d\n", (int)t->hfsp_extent_file_start); - iso_msb ((uint8_t *) &sb.catalog_file.size + 4, HFSPLUS_BLOCK_SIZE * 2 * t->hfsp_nnodes, 4); - iso_msb ((uint8_t *) &sb.catalog_file.clumpsize, HFSPLUS_BLOCK_SIZE * 2, 4); + iso_msb ((uint8_t *) &sb.catalog_file.size + 4, block_size * 2 * t->hfsp_nnodes, 4); + iso_msb ((uint8_t *) &sb.catalog_file.clumpsize, block_size * 2, 4); iso_msb ((uint8_t *) &sb.catalog_file.blocks, 2 * t->hfsp_nnodes, 4); iso_msb ((uint8_t *) &sb.catalog_file.extents[0].start, t->hfsp_catalog_file_start - t->hfsp_part_start, 4); iso_msb ((uint8_t *) &sb.catalog_file.extents[0].count, 2 * t->hfsp_nnodes, 4); @@ -625,8 +686,8 @@ write_sb (Ecma119Image *t) t->hfsp_bless_id[i], 4); #ifdef Libisofs_ts_debuG -iso_msg_debug(t->image->id, "hfsplus bless %d written for cat_id %u", - i, t->hfsp_bless_id[i]); + iso_msg_debug(t->image->id, "hfsplus bless %d written for cat_id %u", + i, t->hfsp_bless_id[i]); #endif /* Libisofs_ts_debuG */ } @@ -642,18 +703,21 @@ static int hfsplus_writer_write_data(IsoImageWriter *writer) { int ret; - static char buffer[2 * HFSPLUS_BLOCK_SIZE]; + static char buffer[2 * HFSPLUS_MAX_BLOCK_SIZE]; Ecma119Image *t; struct hfsplus_btnode *node_head; struct hfsplus_btheader *tree_head; int level; - uint32_t curpos = 1, i; + uint32_t curpos = 1, i, block_fac, cat_node_size, block_size; if (writer == NULL) { return ISO_NULL_POINTER; } t = writer->target; + block_size = t->hfsp_block_size; + block_fac = t->hfsp_iso_block_fac; + cat_node_size = t->hfsp_cat_node_size; iso_msg_debug(t->image->id, "(b) %d written", (int) t->bytes_written / 0x800); @@ -675,27 +739,27 @@ int hfsplus_writer_write_data(IsoImageWriter *writer) iso_msb ((uint8_t *) &tree_head->leaf_records, t->hfsp_nleafs, 4); iso_msb ((uint8_t *) &tree_head->first_leaf_node, t->hfsp_nnodes - t->hfsp_levels[0].level_size, 4); iso_msb ((uint8_t *) &tree_head->last_leaf_node, t->hfsp_nnodes - 1, 4); - iso_msb ((uint8_t *) &tree_head->nodesize, HFSPLUS_CAT_NODE_SIZE, 2); + iso_msb ((uint8_t *) &tree_head->nodesize, cat_node_size, 2); iso_msb ((uint8_t *) &tree_head->keysize, 6 + 2 * LIBISO_HFSPLUS_NAME_MAX, 2); iso_msb ((uint8_t *) &tree_head->total_nodes, t->hfsp_nnodes, 4); iso_msb ((uint8_t *) &tree_head->free_nodes, 0, 4); - iso_msb ((uint8_t *) &tree_head->clump_size, HFSPLUS_CAT_NODE_SIZE, 4); + iso_msb ((uint8_t *) &tree_head->clump_size, cat_node_size, 4); tree_head->key_compare = 0xcf; iso_msb ((uint8_t *) &tree_head->attributes, 2 | 4, 4); memset (buffer + 0xf8, -1, t->hfsp_nnodes / 8); buffer[0xf8 + (t->hfsp_nnodes / 8)] = 0xff00 >> (t->hfsp_nnodes % 8); - buffer[HFSPLUS_CAT_NODE_SIZE - 1] = sizeof (*node_head); - buffer[HFSPLUS_CAT_NODE_SIZE - 3] = sizeof (*node_head) + sizeof (*tree_head); - buffer[HFSPLUS_CAT_NODE_SIZE - 5] = (char) 0xf8; - buffer[HFSPLUS_CAT_NODE_SIZE - 7] = (char) ((HFSPLUS_CAT_NODE_SIZE - 8) & 0xff); - buffer[HFSPLUS_CAT_NODE_SIZE - 8] = (HFSPLUS_CAT_NODE_SIZE - 8) >> 8; + buffer[cat_node_size - 1] = sizeof (*node_head); + buffer[cat_node_size - 3] = sizeof (*node_head) + sizeof (*tree_head); + buffer[cat_node_size - 5] = (char) 0xf8; + buffer[cat_node_size - 7] = (char) ((cat_node_size - 8) & 0xff); + buffer[cat_node_size - 8] = (cat_node_size - 8) >> 8; #ifdef Libisofs_hfsplus_verbose_debuG iso_msg_debug(t->image->id, "Write\n"); #endif - ret = iso_write(t, buffer, HFSPLUS_CAT_NODE_SIZE); + ret = iso_write(t, buffer, cat_node_size); if (ret < 0) return ret; @@ -720,7 +784,7 @@ int hfsplus_writer_write_data(IsoImageWriter *writer) curoff = sizeof (struct hfsplus_btnode); for (j = 0; j < t->hfsp_levels[level].nodes[i].cnt; j++) { - iso_msb ((uint8_t *) buffer + HFSPLUS_CAT_NODE_SIZE - j * 2 - 2, curoff, 2); + iso_msb ((uint8_t *) buffer + cat_node_size - j * 2 - 2, curoff, 2); iso_msb ((uint8_t *) buffer + curoff, 2 * t->hfsp_levels[level - 1].nodes[curnode].strlen + 6, 2); iso_msb ((uint8_t *) buffer + curoff + 2, t->hfsp_levels[level - 1].nodes[curnode].parent_id, 4); @@ -732,13 +796,13 @@ int hfsplus_writer_write_data(IsoImageWriter *writer) curoff += 4; curnode++; } - iso_msb ((uint8_t *) buffer + HFSPLUS_CAT_NODE_SIZE - j * 2 - 2, curoff, 2); + iso_msb ((uint8_t *) buffer + cat_node_size - j * 2 - 2, curoff, 2); #ifdef Libisofs_hfsplus_verbose_debuG iso_msg_debug(t->image->id, "Write\n"); #endif - ret = iso_write(t, buffer, HFSPLUS_CAT_NODE_SIZE); + ret = iso_write(t, buffer, cat_node_size); if (ret < 0) return ret; @@ -766,7 +830,7 @@ int hfsplus_writer_write_data(IsoImageWriter *writer) curoff = sizeof (struct hfsplus_btnode); for (j = 0; j < t->hfsp_levels[level].nodes[i].cnt; j++) { - iso_msb ((uint8_t *) buffer + HFSPLUS_CAT_NODE_SIZE - j * 2 - 2, curoff, 2); + iso_msb ((uint8_t *) buffer + cat_node_size - j * 2 - 2, curoff, 2); #ifdef Libisofs_hfsplus_verbose_debuG @@ -920,16 +984,16 @@ iso_msg_debug(t->image->id, &blk, &sz); if (ret <= 0) return ret; - blk *= HFSPLUS_ISO_BLOCK_FAC; + blk *= block_fac; } if (sz == 0) blk = t->hfsp_part_start; iso_msb ((uint8_t *) &data_fork->size, sz >> 32, 4); iso_msb ((uint8_t *) &data_fork->size + 4, sz, 4); - iso_msb ((uint8_t *) &data_fork->clumpsize, HFSPLUS_BLOCK_SIZE, 4); - iso_msb ((uint8_t *) &data_fork->blocks, (sz + HFSPLUS_BLOCK_SIZE - 1) / HFSPLUS_BLOCK_SIZE, 4); + iso_msb ((uint8_t *) &data_fork->clumpsize, block_size, 4); + iso_msb ((uint8_t *) &data_fork->blocks, (sz + block_size - 1) / block_size, 4); iso_msb ((uint8_t *) &data_fork->extents[0].start, blk - t->hfsp_part_start, 4); - iso_msb ((uint8_t *) &data_fork->extents[0].count, (sz + HFSPLUS_BLOCK_SIZE - 1) / HFSPLUS_BLOCK_SIZE, 4); + iso_msb ((uint8_t *) &data_fork->extents[0].count, (sz + block_size - 1) / block_size, 4); curoff += sizeof (*data_fork) * 2; /* FIXME: resource fork */ @@ -939,13 +1003,13 @@ iso_msg_debug(t->image->id, } curnode++; } - iso_msb ((uint8_t *) buffer + HFSPLUS_CAT_NODE_SIZE - j * 2 - 2, curoff, 2); + iso_msb ((uint8_t *) buffer + cat_node_size - j * 2 - 2, curoff, 2); #ifdef Libisofs_hfsplus_verbose_debuG iso_msg_debug(t->image->id, "Write\n"); #endif - ret = iso_write(t, buffer, HFSPLUS_CAT_NODE_SIZE); + ret = iso_write(t, buffer, cat_node_size); if (ret < 0) return ret; } @@ -953,38 +1017,30 @@ iso_msg_debug(t->image->id, } memset (buffer, 0, sizeof (buffer)); - ret = pad_up_block(t); - if (ret < 0) - return ret; - iso_msg_debug(t->image->id, "real extent_file_start = %d\n", (int)t->bytes_written / 2048); node_head = (struct hfsplus_btnode *) buffer; node_head->type = 1; iso_msb ((uint8_t *) &node_head->count, 3, 2); tree_head = (struct hfsplus_btheader *) (node_head + 1); - iso_msb ((uint8_t *) &tree_head->nodesize, HFSPLUS_BLOCK_SIZE, 2); + iso_msb ((uint8_t *) &tree_head->nodesize, block_size, 2); iso_msb ((uint8_t *) &tree_head->keysize, 10, 2); iso_msb ((uint8_t *) &tree_head->total_nodes, 1, 4); iso_msb ((uint8_t *) &tree_head->free_nodes, 0, 4); - iso_msb ((uint8_t *) &tree_head->clump_size, HFSPLUS_BLOCK_SIZE, 4); + iso_msb ((uint8_t *) &tree_head->clump_size, block_size, 4); iso_msb ((uint8_t *) &tree_head->attributes, 2, 4); buffer[0xf8] = (char) 0x80; - buffer[HFSPLUS_BLOCK_SIZE - 1] = sizeof (*node_head); - buffer[HFSPLUS_BLOCK_SIZE - 3] = sizeof (*node_head) + sizeof (*tree_head); - buffer[HFSPLUS_BLOCK_SIZE - 5] = (char) 0xf8; - buffer[HFSPLUS_BLOCK_SIZE - 7] = (char) ((HFSPLUS_BLOCK_SIZE - 8) & 0xff); - buffer[HFSPLUS_BLOCK_SIZE - 8] = (HFSPLUS_BLOCK_SIZE - 8) >> 8; + buffer[block_size - 1] = sizeof (*node_head); + buffer[block_size - 3] = sizeof (*node_head) + sizeof (*tree_head); + buffer[block_size - 5] = (char) 0xf8; + buffer[block_size - 7] = (char) ((block_size - 8) & 0xff); + buffer[block_size - 8] = (block_size - 8) >> 8; - ret = iso_write(t, buffer, HFSPLUS_BLOCK_SIZE); + ret = iso_write(t, buffer, block_size); if (ret < 0) return ret; - ret = pad_up_block(t); - if (ret < 0) - return ret; - iso_msg_debug(t->image->id, "(d) %d written", (int) t->bytes_written / 0x800); memset (buffer, 0, sizeof (buffer)); for (i = 0; i < t->hfsp_nleafs; i++) @@ -995,14 +1051,15 @@ iso_msg_debug(t->image->id, ret = iso_write(t, sym->dest, t->hfsp_leafs[i].symlink_size); if (ret < 0) return ret; - overhead = t->hfsp_leafs[i].symlink_size % HFSPLUS_BLOCK_SIZE; + overhead = t->hfsp_leafs[i].symlink_size % block_size; if (overhead) - overhead = HFSPLUS_BLOCK_SIZE - overhead; + overhead = block_size - overhead; ret = iso_write(t, buffer, overhead); if (ret < 0) return ret; } + /* Need to align for start of next writer */ ret = pad_up_block(t); if (ret < 0) return ret; @@ -1015,8 +1072,8 @@ static int hfsplus_tail_writer_write_data(IsoImageWriter *writer) { int ret; - static char buffer[2 * HFSPLUS_BLOCK_SIZE]; - uint32_t complete_blocks, remaining_blocks; + static char buffer[2 * HFSPLUS_MAX_BLOCK_SIZE]; + uint32_t complete_blocks, remaining_blocks, block_size; int over; Ecma119Image *t; @@ -1025,28 +1082,29 @@ int hfsplus_tail_writer_write_data(IsoImageWriter *writer) } t = writer->target; + block_size = t->hfsp_block_size; #ifdef Libisofs_ts_debuG -iso_msg_debug(t->image->id, "hfsplus tail writer writes at = %.f", - (double) t->bytes_written); + iso_msg_debug(t->image->id, "hfsplus tail writer writes at = %.f", + (double) t->bytes_written); #endif memset (buffer, -1, sizeof (buffer)); - complete_blocks = (t->hfsp_allocation_size - 1) / HFSPLUS_BLOCK_SIZE; + complete_blocks = (t->hfsp_allocation_size - 1) / block_size; remaining_blocks = t->hfsp_allocation_blocks - complete_blocks; while (complete_blocks--) { - ret = iso_write(t, buffer, HFSPLUS_BLOCK_SIZE); + ret = iso_write(t, buffer, block_size); if (ret < 0) return ret; } - over = (t->hfsp_allocation_size - 1) % HFSPLUS_BLOCK_SIZE; + over = (t->hfsp_allocation_size - 1) % block_size; if (over) { memset (buffer + over, 0, sizeof (buffer) - over); buffer[over] = 0xff00 >> (t->hfsp_total_blocks % 8); - ret = iso_write(t, buffer, HFSPLUS_BLOCK_SIZE); + ret = iso_write(t, buffer, block_size); if (ret < 0) return ret; remaining_blocks--; @@ -1055,29 +1113,32 @@ iso_msg_debug(t->image->id, "hfsplus tail writer writes at = %.f", /* When we have both FAT and HFS+ we may to overestimate needed blocks a bit. */ while (remaining_blocks--) { - ret = iso_write(t, buffer, HFSPLUS_BLOCK_SIZE); + ret = iso_write(t, buffer, block_size); if (ret < 0) return ret; } +#ifndef Libisofs_apm_flags_bit2 ret = pad_up_block(t); if (ret < 0) return ret; +#endif /* ! Libisofs_apm_flags_bit2 */ iso_msg_debug(t->image->id, "%d written", (int) t->bytes_written); -#ifdef Libisofs_ts_debuG -iso_msg_debug(t->image->id, "hfsplus tail writer writes sb at = %.f", - (double) t->bytes_written); -#endif - ret = write_sb (t); #ifdef Libisofs_ts_debuG -iso_msg_debug(t->image->id, "hfsplus tail writer ends at = %.f", - (double) t->bytes_written); + iso_msg_debug(t->image->id, "hfsplus tail writer ends at = %.f", + (double) t->bytes_written); #endif +#ifdef Libisofs_apm_flags_bit2 + ret = pad_up_block(t); + if (ret < 0) + return ret; +#endif /* Libisofs_apm_flags_bit2 */ + return ret; } @@ -1117,6 +1178,7 @@ int hfsplus_writer_create(Ecma119Image *target) IsoNode *pos; IsoDir *dir; int i; + uint32_t cat_node_size; writer = malloc(sizeof(IsoImageWriter)); if (writer == NULL) { @@ -1126,6 +1188,12 @@ int hfsplus_writer_create(Ecma119Image *target) make_hfsplus_decompose_pages(); make_hfsplus_class_pages(); + if (target->hfsp_block_size == 0) + target->hfsp_block_size = HFSPLUS_DEFAULT_BLOCK_SIZE; + target->hfsp_cat_node_size = 2 * target->hfsp_block_size; + target->hfsp_iso_block_fac = 2048 / target->hfsp_block_size; + cat_node_size = target->hfsp_cat_node_size; + writer->compute_data_blocks = hfsplus_writer_compute_data_blocks; writer->write_vol_desc = nop_writer_write_vol_desc; writer->write_data = hfsplus_writer_write_data; @@ -1205,7 +1273,7 @@ int hfsplus_writer_create(Ecma119Image *target) { uint32_t last_start = 0; uint32_t i; - unsigned bytes_rem = HFSPLUS_CAT_NODE_SIZE - sizeof (struct hfsplus_btnode) - 2; + unsigned bytes_rem = cat_node_size - sizeof (struct hfsplus_btnode) - 2; target->hfsp_levels[level].nodes = malloc ((target->hfsp_nleafs + 1) * sizeof (target->hfsp_levels[level].nodes[0])); if (!target->hfsp_levels[level].nodes) @@ -1231,7 +1299,7 @@ int hfsplus_writer_create(Ecma119Image *target) target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].parent_id = target->hfsp_leafs[last_start].parent_id; target->hfsp_levels[level].level_size++; last_start = i; - bytes_rem = HFSPLUS_CAT_NODE_SIZE - sizeof (struct hfsplus_btnode) - 2; + bytes_rem = cat_node_size - sizeof (struct hfsplus_btnode) - 2; } bytes_rem -= target->hfsp_leafs[i].used_size; } @@ -1258,7 +1326,7 @@ int hfsplus_writer_create(Ecma119Image *target) uint32_t last_start = 0; uint32_t i; uint32_t last_size; - unsigned bytes_rem = HFSPLUS_CAT_NODE_SIZE - sizeof (struct hfsplus_btnode) - 2; + unsigned bytes_rem = cat_node_size - sizeof (struct hfsplus_btnode) - 2; last_size = target->hfsp_levels[level].level_size; @@ -1283,7 +1351,7 @@ int hfsplus_writer_create(Ecma119Image *target) target->hfsp_levels[level].nodes[target->hfsp_levels[level].level_size].parent_id = target->hfsp_levels[level - 1].nodes[last_start].parent_id; target->hfsp_levels[level].level_size++; last_start = i; - bytes_rem = HFSPLUS_CAT_NODE_SIZE - sizeof (struct hfsplus_btnode) - 2; + bytes_rem = cat_node_size - sizeof (struct hfsplus_btnode) - 2; } bytes_rem -= used_size; } @@ -1299,7 +1367,7 @@ int hfsplus_writer_create(Ecma119Image *target) target->hfsp_nlevels = level + 1; - if (target->hfsp_nnodes > (HFSPLUS_CAT_NODE_SIZE - 0x100) * 8) + if (target->hfsp_nnodes > (cat_node_size - 0x100) * 8) { return iso_msg_submit(target->image->id, ISO_MANGLE_TOO_MUCH_FILES, 0, "HFS+ map nodes aren't implemented"); diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index c6422c7..61708ab 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -1467,6 +1467,27 @@ int iso_write_opts_set_fat(IsoWriteOpts *opts, int enable); int iso_write_opts_set_hfsp_serial_number(IsoWriteOpts *opts, uint8_t serial_number[8]); +/** + * Set the block size for Apple Partition Map and for HFS+. + * + * @param opts + * The option set to be manipulated. + * @param hfsp_block_size + * The allocation block size to be used by the HFS+ fileystem. + * 0, 512, or 2048 + * @param hfsp_block_size + * The block size to be used for and within the Apple Partition Map. + * 0, 512, or 2048. + * Size 512 is not compatible with options which produce GPT. + * @return + * 1 success, < 0 error + * + * @since 1.2.4 + */ +int iso_write_opts_set_hfsp_block_size(IsoWriteOpts *opts, + int hfsp_block_size, int apm_block_size); + + /** * Whether to use newer ISO-9660:1999 version. * @@ -7343,6 +7364,11 @@ int iso_image_hfsplus_get_blessed(IsoImage *img, IsoNode ***blessed_nodes, (FAILURE, HIGH, -390) */ #define ISO_BOOT_NO_EFI_ELTO 0xE830FE7A +/** Not a supported HFS+ or APM block size (FAILURE, HIGH, -391) */ +#define ISO_BOOT_HFSP_BAD_BSIZE 0xE830FE79 + +/** APM block size prevents coexistence with GPT (FAILURE, HIGH, -392) */ +#define ISO_BOOT_APM_GPT_BSIZE 0xE830FE78 /* Internal developer note: diff --git a/libisofs/libisofs.ver b/libisofs/libisofs.ver index 3e3a56e..f921b19 100644 --- a/libisofs/libisofs.ver +++ b/libisofs/libisofs.ver @@ -289,6 +289,7 @@ iso_write_opts_set_efi_bootp; iso_write_opts_set_fat; iso_write_opts_set_fifo_size; iso_write_opts_set_hardlinks; +iso_write_opts_set_hfsp_block_size; iso_write_opts_set_hfsp_serial_number; iso_write_opts_set_hfsplus; iso_write_opts_set_iso1999; diff --git a/libisofs/messages.c b/libisofs/messages.c index bc4cb65..e849ae5 100644 --- a/libisofs/messages.c +++ b/libisofs/messages.c @@ -490,6 +490,10 @@ const char *iso_error_to_msg(int errcode) return "Attempt to use an MBR partition entry twice"; case ISO_BOOT_NO_EFI_ELTO: return "No suitable El Torito EFI boot image for exposure as GPT partition"; + case ISO_BOOT_HFSP_BAD_BSIZE: + return "Not a supported HFS+ or APM block size"; + case ISO_BOOT_APM_GPT_BSIZE: + return "APM block size prevents coexistence with GPT"; default: return "Unknown error"; } diff --git a/libisofs/system_area.c b/libisofs/system_area.c index 4622577..c7c6712 100644 --- a/libisofs/system_area.c +++ b/libisofs/system_area.c @@ -856,12 +856,11 @@ static int iso_write_apm_entry(Ecma119Image *t, int apm_block_size, uint32_t flags; int block_fac; - if (flag & 1) + if ((flag & 1) || (t->apm_req_flags & 4)) block_fac = 1; else block_fac = 2048 / apm_block_size; - memset(buf, apm_block_size, 0); wpt = buf; @@ -916,9 +915,12 @@ static int iso_write_apm_entry(Ecma119Image *t, int apm_block_size, static int fill_apm_gaps(Ecma119Image *t, uint32_t img_blocks) { int i, ret, gap_counter = 0, up_to; - uint32_t part_end, goal; + uint32_t part_end, goal, block_fac = 1; char gap_name[33]; + if (t->apm_req_flags & 4) + block_fac = 2048 / t->apm_block_size; + /* Find out whether an entry with start_block <= 1 is requested */ for (i = 0; i < t->apm_req_count; i++) { if (t->apm_req[i]->start_block <= 1) @@ -939,12 +941,12 @@ static int fill_apm_gaps(Ecma119Image *t, uint32_t img_blocks) if (i < up_to - 1) goal = t->apm_req[i]->start_block; else - goal = img_blocks; + goal = img_blocks * block_fac; if (i == 1) { /* Description of APM itself */ /* Actual APM size is not yet known. Protection begins at PVD */ - part_end = 16; - if (goal < 16 && goal> 1) + part_end = 16 * block_fac; + if (goal < part_end && goal> 1) part_end = goal; } else { part_end = t->apm_req[i - 1]->start_block + @@ -983,45 +985,6 @@ static int rectify_apm(Ecma119Image *t) { int ret; - if (t->apm_req_count == 0) - return 1; - - /* These are the only APM block sizes which can be processed here */ - if (t->apm_block_size > 1536) - t->apm_block_size = 2048; - else if (t->apm_block_size > 768) - t->apm_block_size = 1024; - else - t->apm_block_size = 512; - if (t->gpt_req_count > 0 && - t->apm_block_size != 2048 && t->apm_req_count > 0) { - t->apm_block_size = 2048; - iso_msgs_submit(0, - "GPT and APM requested. Had to force APM Block size to 2048.", - 0, "DEBUG", 0); - } - if (t->apm_req_count > 0) { - ret = fill_apm_gaps(t, t->curblock); - if (ret < 0) - return ret; - } - return 1; -} - - -/* flag bit0= do not write Block0 -*/ -static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf, - int flag) -{ - int i, ret; - /* This is a micro mick-up of an APM Block0 - and also harmless x86 machine code. - */ - static uint8_t block0_template[8] = { - 0x45, 0x52, 0x02, 0x00, 0xeb, 0x02, 0xff, 0xff - }; - #ifdef NIX /* Disabled */ @@ -1042,6 +1005,42 @@ static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf, } #endif /* NIX */ + if (t->apm_req_count == 0) + return 1; + + if (t->gpt_req_count > 0 && + t->apm_block_size != 2048 && t->apm_req_count > 0) { + iso_msgs_submit(0, + "GPT and APM requested. APM block size would have to be 2048.", + 0, "FAILURE", 0); + return ISO_BOOT_APM_GPT_BSIZE; + } + if (t->apm_req_count > 0) { + ret = fill_apm_gaps(t, t->curblock); + if (ret < 0) + return ret; + } + return 1; +} + + +/* flag bit0= do not write Block0 +*/ +static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf, + int flag) +{ + int i, ret; + uint32_t block_fac = 1; + /* This is a micro mock-up of an APM Block0 + and also harmless x86 machine code. + */ + static uint8_t block0_template[8] = { + 0x45, 0x52, 0x02, 0x00, 0xeb, 0x02, 0xff, 0xff + }; + + if (t->apm_req_flags & 4) + block_fac = 2048 / t->apm_block_size; + if (t->apm_req_count <= 0) return 2; @@ -1051,7 +1050,7 @@ static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf, number of APM partitions was determined. */ t->apm_req[t->apm_req_count - 1]->block_count = - img_blocks - t->apm_req[t->apm_req_count - 1]->start_block; + img_blocks * block_fac - t->apm_req[t->apm_req_count - 1]->start_block; /* If it is still empty, remove it */ if(t->apm_req[t->apm_req_count - 1]->block_count == 0) { free(t->apm_req[t->apm_req_count - 1]); diff --git a/libisofs/system_area.h b/libisofs/system_area.h index 598aea9..2be6da4 100644 --- a/libisofs/system_area.h +++ b/libisofs/system_area.h @@ -141,7 +141,7 @@ int iso_mbr_entry_slot_is_free(Ecma119Image *t, int slot); */ struct iso_apm_partition_request { - /* Always given in blocks of 2 KiB. + /* 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;