diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index e5c698c..290020e 100644 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -107,7 +107,7 @@ void ecma119_image_free(Ecma119Image *t) free(t->writers); if (t->partition_root != NULL) ecma119_node_free(t->partition_root); - for (i = 0; i < 4; i++) + for (i = 0; i < ISO_MAX_PARTITIONS; i++) if (t->appended_partitions[i] != NULL) free(t->appended_partitions[i]); @@ -1299,13 +1299,20 @@ static int finish_libjte(Ecma119Image *target) static int write_mbr_partition_file(Ecma119Image *target, char *path, - uint32_t blocks, int flag) + uint32_t prepad, uint32_t blocks, int flag) { FILE *fp = NULL; uint32_t i; uint8_t buf[BLOCK_SIZE]; int ret; + memset(buf, 0, BLOCK_SIZE); + for (i = 0; i < prepad; i++) { + ret = iso_write(target, buf, BLOCK_SIZE); + if (ret < 0) + return ret; + } + fp = fopen(path, "rb"); if (fp == NULL) return ISO_BAD_PARTITION_FILE; @@ -1325,8 +1332,8 @@ static int write_mbr_partition_file(Ecma119Image *target, char *path, return ret; } } - - fclose(fp); + if (fp != NULL) + fclose(fp); return ISO_SUCCESS; } @@ -1334,7 +1341,7 @@ static int write_mbr_partition_file(Ecma119Image *target, char *path, static void *write_function(void *arg) { - int res; + int res, first_partition = 1, last_partition = 0, sa_type; size_t i; IsoImageWriter *writer; @@ -1358,16 +1365,26 @@ void *write_function(void *arg) } /* Append partition data */ - for (i = 0; i < 4; i++) { + sa_type = (target->system_area_options >> 2) & 0x3f; + if (sa_type == 0) { /* MBR */ + first_partition = 1; + last_partition = 4; + } else if (sa_type == 3) { /* SUN Disk Label */ + first_partition = 2; + last_partition = 8; + } + for (i = first_partition - 1; i <= last_partition - 1; i++) { if (target->appended_partitions[i] == NULL) + continue; + if (target->appended_partitions[i][0] == 0) continue; res = write_mbr_partition_file(target, target->appended_partitions[i], + target->appended_part_prepad[i], target->appended_part_size[i], 0); if (res < 0) goto write_error; } - /* Transplant checksum buffer from Ecma119Image to IsoImage */ transplant_checksum_buffer(target, 0); @@ -1520,6 +1537,7 @@ static int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) { int ret, i, voldesc_size, nwriters, image_checksums_mad = 0, tag_pos; + int sa_type; Ecma119Image *target; IsoImageWriter *writer; int el_torito_writer_index = -1, file_src_writer_index = -1; @@ -1615,8 +1633,9 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) } else { system_area_options = opts->system_area_options & 0xfc; } - if ((system_area_options & 0xfc) != 0) - for (i = 0; i < 4; i++) + sa_type = (system_area_options >> 2) & 0x3f; + if (sa_type != 0 && sa_type != 3) + for (i = 0; i < ISO_MAX_PARTITIONS; i++) if (opts->appended_partitions[i] != NULL) return ISO_NON_MBR_SYS_AREA; @@ -1708,7 +1727,8 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) target->mipsel_p_vaddr = 0; target->mipsel_p_filesz = 0; - for (i = 0; i < 4; i++) { + for (i = 0; i < ISO_MAX_PARTITIONS; i++) { + target->appended_partitions[i] = NULL; if (opts->appended_partitions[i] != NULL) { target->appended_partitions[i] = strdup(opts->appended_partitions[i]); @@ -1716,9 +1736,10 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) return ISO_OUT_OF_MEM; target->appended_part_types[i] = opts->appended_part_types[i]; } + target->appended_part_prepad[i] = 0; target->appended_part_start[i] = target->appended_part_size[i] = 0; } - + strcpy(target->ascii_disc_label, opts->ascii_disc_label); /* * 2. Based on those options, create needed writers: iso, joliet... @@ -2306,8 +2327,9 @@ int iso_write_opts_new(IsoWriteOpts **opts, int profile) #endif /* Libisofs_with_libjtE */ wopts->tail_blocks = 0; - for (i = 0; i < 4; i++) + for (i = 0; i < ISO_MAX_PARTITIONS; i++) wopts->appended_partitions[i] = NULL; + wopts->ascii_disc_label[0] = 0; *opts = wopts; return ISO_SUCCESS; @@ -2323,7 +2345,7 @@ void iso_write_opts_free(IsoWriteOpts *opts) free(opts->output_charset); if (opts->system_area_data != NULL) free(opts->system_area_data); - for (i = 0; i < 4; i++) + for (i = 0; i < ISO_MAX_PARTITIONS; i++) if (opts->appended_partitions[i] != NULL) free(opts->appended_partitions[i]); @@ -2806,7 +2828,7 @@ int iso_write_opts_set_tail_blocks(IsoWriteOpts *opts, uint32_t num_blocks) int iso_write_opts_set_partition_img(IsoWriteOpts *opts, int partition_number, uint8_t partition_type, char *image_path, int flag) { - if (partition_number < 1 || partition_number > 4) + if (partition_number < 1 || partition_number > ISO_MAX_PARTITIONS) return ISO_BAD_PARTITION_NO; if (opts->appended_partitions[partition_number - 1] != NULL) @@ -2819,3 +2841,10 @@ int iso_write_opts_set_partition_img(IsoWriteOpts *opts, int partition_number, return ISO_SUCCESS; } +int iso_write_opts_set_disc_label(IsoWriteOpts *opts, char *label) +{ + strncpy(opts->ascii_disc_label, label, ISO_DISC_LABEL_SIZE - 1); + opts->ascii_disc_label[ISO_DISC_LABEL_SIZE - 1] = 0; + return ISO_SUCCESS; +} + diff --git a/libisofs/ecma119.h b/libisofs/ecma119.h index 1ed525a..dc907c8 100644 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -32,6 +32,26 @@ */ #define ISO_EXTENT_SIZE 0xFFFFF800 +/* + * The maximum number of partition images that can be registered. Depending + * on the system area type, the effectively usable number may be smaller or + * even 0. + */ +#define ISO_MAX_PARTITIONS 8 + +/* + * The cylindersize with SUN Disk Label + * (512 bytes/sector, 640 sectors/head, 1 head/cyl = 320 KiB). + * Expressed in ECMA-119 blocks of 2048 bytes/block. + */ +#define ISO_SUN_CYL_SIZE 160 + +/* + * Maximum length of a disc label text plus 1. + */ +#define ISO_DISC_LABEL_SIZE 129 + + /** * Holds the options for the image generation. */ @@ -337,8 +357,12 @@ struct iso_write_opts { /* Eventual disk file paths of prepared images which shall be appended after the ISO image and described by partiton table entries in a MBR */ - char *appended_partitions[4]; - uint8_t appended_part_types[4]; + char *appended_partitions[ISO_MAX_PARTITIONS]; + uint8_t appended_part_types[ISO_MAX_PARTITIONS]; + + /* Eventual name of the non-ISO aspect of the image. E.g. SUN ASCII label. + */ + char ascii_disc_label[ISO_DISC_LABEL_SIZE]; }; typedef struct ecma119_image Ecma119Image; @@ -601,11 +625,14 @@ struct ecma119_image uint32_t mipsel_p_vaddr; uint32_t mipsel_p_filesz; - char *appended_partitions[4]; - uint8_t appended_part_types[4]; + char *appended_partitions[ISO_MAX_PARTITIONS]; + uint8_t appended_part_types[ISO_MAX_PARTITIONS]; /* Counted in blocks of 2048 */ - uint32_t appended_part_start[4]; - uint32_t appended_part_size[4]; + uint32_t appended_part_prepad[ISO_MAX_PARTITIONS]; + uint32_t appended_part_start[ISO_MAX_PARTITIONS]; + uint32_t appended_part_size[ISO_MAX_PARTITIONS]; + + char ascii_disc_label[ISO_DISC_LABEL_SIZE]; }; diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index ddb26b8..bf3036c 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -1751,6 +1751,9 @@ int iso_write_opts_set_fifo_size(IsoWriteOpts *opts, size_t fifo_size); * * If system area data are given or options bit0 is set, then bit1 of * el_torito_set_isolinux_options() is automatically disabled. + * + * @param opts + * The option set to be manipulated. * @param data * Either NULL or 32 kB of data. Do not submit less bytes ! * @param options @@ -1780,6 +1783,13 @@ int iso_write_opts_set_fifo_size(IsoWriteOpts *opts, size_t fifo_size); * iso_image_add_mips_boot_file() will be activated. * This will overwrite the first 512 bytes of the submitted * data. + * @since 0.6.40 + * 3= SUN Disk Label for SUN SPARC + * Submit up to 7 SPARC boot images by + * iso_write_opts_set_partition_img() for partition numbers 2 + * to 8. + * This will overwrite the first 512 bytes of the submitted + * data. * @param flag * bit0 = invalidate any attached system area data. Same as data == NULL * (This re-activates eventually loaded image System Area data. @@ -1787,12 +1797,28 @@ int iso_write_opts_set_fifo_size(IsoWriteOpts *opts, size_t fifo_size); * bit1 = keep data unaltered * bit2 = keep options unaltered * @return - * ISO_SUCCESS or error + * ISO_SUCCESS or error * @since 0.6.30 */ int iso_write_opts_set_system_area(IsoWriteOpts *opts, char data[32768], int options, int flag); +/** + * Set a name for the system area. This setting is ignored unless system area + * type 3 "SUN Disk Label" is in effect by iso_write_opts_set_system_area(). + * In this case it will replace the default text at the start of the image: + * "CD-ROM Disc with Sun sparc boot created by libisofs" + * + * @param opts + * The option set to be manipulated. + * @param label + * A text of up to 128 characters. + * @return + * ISO_SUCCESS or error + * @since 0.6.40 +*/ +int iso_write_opts_set_disc_label(IsoWriteOpts *opts, char *label); + /** * Explicitely set the four timestamps of the emerging Primary Volume * Descriptor. Default with all parameters is 0. @@ -1936,24 +1962,33 @@ int iso_write_opts_detach_jte(IsoWriteOpts *opts, void **libjte_handle); */ int iso_write_opts_set_tail_blocks(IsoWriteOpts *opts, uint32_t num_blocks); + /** * Cause an arbitrary data file to be appended to the ISO image and to be - * described by a partition table entry in an MBR at the start of the - * ISO image. + * described by a partition table entry in an MBR or SUN Disk Label at the + * start of the ISO image. * The partition entry will bear the size of the image file rounded up to * the next multiple of 2048 bytes. + * MBR or SUN Disk Label are selected by iso_write_opts_set_system_area() + * system area type: 0 selects MBR partition table. 3 selects a SUN partition + * table with 320 kB start alignment. + * * @param opts * The option set to be manipulated. * @param partition_number * Depicts the partition table entry which shall describe the - * appended image. Range 1 to 4. - * 1 will cause the whole ISO image to be unclaimable space before - * partition 1. + * appended image. + * Range with MBR: 1 to 4. 1 will cause the whole ISO image to be + * unclaimable space before partition 1. + * Range with SUN Disk Label: 2 to 8. * @param image_path * File address in the local file system. + * With SUN Disk Label: an empty name causes the partition to become + * a copy of the next lower partition. * @param image_type - * The partition type. E.g. FAT12 = 0x01 , FAT16 = 0x06, + * The MBR partition type. E.g. FAT12 = 0x01 , FAT16 = 0x06, * Linux Native Partition = 0x83. See fdisk command L. + * This parameter is ignored with SUN Disk Label. * @return * ISO_SUCCESS or error * diff --git a/libisofs/libisofs.ver b/libisofs/libisofs.ver index 8de9482..c9b25dd 100644 --- a/libisofs/libisofs.ver +++ b/libisofs/libisofs.ver @@ -266,6 +266,7 @@ iso_write_opts_set_default_gid; iso_write_opts_set_default_timestamp; iso_write_opts_set_default_uid; iso_write_opts_set_dir_rec_mtime; +iso_write_opts_set_disc_label; iso_write_opts_set_fifo_size; iso_write_opts_set_hardlinks; iso_write_opts_set_iso1999; diff --git a/libisofs/system_area.c b/libisofs/system_area.c index de7f902..ef02a7e 100644 --- a/libisofs/system_area.c +++ b/libisofs/system_area.c @@ -19,6 +19,7 @@ #include "ecma119_tree.h" #include "image.h" #include "messages.h" +#include "ecma119.h" #include #include @@ -79,13 +80,16 @@ void iso_compute_cyl_head_sec(uint32_t *img_blocks, int hpc, int sph, */ int iso_compute_append_partitions(Ecma119Image *t, int flag) { - int ret, i; - uint32_t pos, size; + int ret, i, sa_type; + uint32_t pos, size, add_pos = 0; struct stat stbuf; + sa_type = (t->system_area_options >> 2) & 0x3f; pos = (t->vol_space_size + t->ms_block); - for (i = 0; i < 4; i++) { + for (i = 0; i < ISO_MAX_PARTITIONS; i++) { if (t->appended_partitions[i] == NULL) + continue; + if (t->appended_partitions[i][0] == 0) continue; ret = stat(t->appended_partitions[i], &stbuf); if (ret == -1) @@ -93,10 +97,13 @@ int iso_compute_append_partitions(Ecma119Image *t, int flag) if (! S_ISREG(stbuf.st_mode)) return ISO_BAD_PARTITION_FILE; size = ((stbuf.st_size + 2047) / 2048); - t->appended_part_start[i] = pos; + if (sa_type == 3 && (pos % ISO_SUN_CYL_SIZE)) + add_pos = ISO_SUN_CYL_SIZE - (pos % ISO_SUN_CYL_SIZE); + t->appended_part_prepad[i] = add_pos; + t->appended_part_start[i] = pos + add_pos; t->appended_part_size[i] = size; - pos += size; - t->total_size += size * 2048; + pos += add_pos + size; + t->total_size += (add_pos + size) * 2048; } return ISO_SUCCESS; } @@ -565,9 +572,122 @@ static int make_mipsel_boot_block(Ecma119Image *t, uint8_t *buf, int flag) } +/* The following two functions were implemented according to + doc/boot_sectors.txt section "SUN Disk Label and boot images" which + was derived by Thomas Schmitt from + cdrtools-2.01.01a77/mkisofs/sunlabel.h + cdrtools-2.01.01a77/mkisofs/mkisofs.8 + by Joerg Schilling + + Both functions are entirely under copyright (C) 2010 Thomas Schmitt. +*/ + +/* @parm flag bit0= copy from next lower valid partition table entry + */ +static int write_sun_partition_entry(int partition_number, + char *appended_partitions[], + uint32_t partition_offset[], uint32_t partition_size[], + uint32_t cyl_size, uint8_t *buf, int flag) +{ + uint8_t *wpt; + int read_idx, i; + + if (partition_number < 1 || partition_number > 8) + return ISO_ASSERT_FAILURE; + + /* 142 - 173 | ========== | 8 partition entries of 4 bytes */ + wpt = buf + 142 + (partition_number - 1) * 4; + if (partition_number == 1) + iso_msb(wpt, 4, 2); /* 4 = User partition */ + else + iso_msb(wpt, 2, 2); /* 2 = Root partition with boot image */ + iso_msb(wpt + 2, 0x10, 2); /* Permissions: 0x10 = read-only */ + + /* 444 - 507 | ========== | Partition table */ + wpt = buf + 444 + (partition_number - 1) * 8; + read_idx = partition_number - 1; + if (flag & 1) { + /* Search next lower valid partition table entry. #1 is default */ + for (read_idx = partition_number - 2; read_idx > 0; read_idx--) + if (appended_partitions[read_idx] != NULL) + if (appended_partitions[read_idx][0] != 0) + break; + } + iso_msb(wpt, partition_offset[read_idx] / (uint32_t) ISO_SUN_CYL_SIZE, 4); + iso_msb(wpt + 4, partition_size[read_idx] * 4, 4); + + /* 510 - 511 | checksum | The result of exoring 2-byte words 0 to 254 */ + buf[510] = buf[511] = 0; + for (i = 0; i < 510; i += 2) { + buf[510] ^= buf[i]; + buf[511] ^= buf[i + 1]; + } + + return ISO_SUCCESS; +} + +/** + * Write SUN Disk Label with ISO in partition 1 and unused 2 to 8 + */ +static int make_sun_disk_label(Ecma119Image *t, uint8_t *buf, int flag) +{ + int ret; + + /* Bytes 512 to 32767 may come from image or external file */ + memset(buf, 0, 512); + + /* 0 - 127 | label | ASCII Label */ + if (t->ascii_disc_label[0]) + strncpy((char *) buf, t->ascii_disc_label, 128); + else + strcpy((char *) buf, + "CD-ROM Disc with Sun sparc boot created by libisofs"); + + /* 128 - 131 | 1 | Layout version */ + iso_msb(buf + 128, 1, 4); + + /* 140 - 141 | 8 | Number of partitions */ + iso_msb(buf + 140, 8, 2); + + /* 188 - 191 | 0x600ddeee | vtoc sanity */ + iso_msb(buf + 188, 0x600ddeee, 4); + + /* 420 - 421 | 350 | Rotations per minute */ + iso_msb(buf + 420, 350, 2); + + /* 422 - 423 | 2048 | Number of physical cylinders (fixely 640 MB) */ + iso_msb(buf + 422, 2048, 2); + + /* 430 - 431 | 1 | interleave factor */ + iso_msb(buf + 430, 1, 2); + + /* 432 - 433 | 2048 | Number of data cylinders (fixely 640 MB) */ + iso_msb(buf + 432, 2048, 2); + + /* 436 - 437 | 1 | Number of heads per cylinder (1 cyl = 320 kB)*/ + iso_msb(buf + 436, 1, 2); + + /* 438 - 439 | 640 | Number of sectors per head (1 head = 320 kB) */ + iso_msb(buf + 438, 640, 2); + + /* 508 - 509 | 0xdabe | Magic Number */ + iso_msb(buf + 508, 0xdabe, 2); + + /* Set partition 1 to describe ISO image and compute checksum */ + t->appended_part_start[0] = 0; + t->appended_part_size[0] = t->curblock; + ret = write_sun_partition_entry(1, t->appended_partitions, + t->appended_part_start, t->appended_part_size, + ISO_SUN_CYL_SIZE, buf, 0); + + return ISO_SUCCESS; +} + + int iso_write_system_area(Ecma119Image *t, uint8_t *buf) { int ret, int_img_blocks, sa_type, i, will_append = 0; + int first_partition = 1, last_partition = 4; uint32_t img_blocks; if ((t == NULL) || (buf == NULL)) { @@ -578,7 +698,11 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) memset(buf, 0, 16 * BLOCK_SIZE); sa_type = (t->system_area_options >> 2) & 0x3f; - for (i = 0; i < 4; i++) + if (sa_type == 3) { + first_partition = 2; + last_partition = 8; + } + for (i = first_partition - 1; i <= last_partition - 1; i++) if (t->appended_partitions[i] != NULL) { will_append = 1; break; @@ -648,6 +772,10 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) if (ret < 0) return ret; } + } else if (sa_type == 3) { + ret = make_sun_disk_label(t, buf, 0); + if (ret != ISO_SUCCESS) + return ret; } if (t->partition_offset > 0 && sa_type == 0) { @@ -661,13 +789,20 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) } /* This eventually overwrites the partition table entries made so far */ - for (i = 0; i < 4; i++) { + for (i = first_partition - 1; i <= last_partition - 1; i++) { if (t->appended_partitions[i] == NULL) continue; - ret = write_mbr_partition_entry(i + 1, t->appended_part_types[i], + if (sa_type == 3) { + ret = write_sun_partition_entry(i + 1, t->appended_partitions, + t->appended_part_start, t->appended_part_size, + ISO_SUN_CYL_SIZE, + buf, t->appended_partitions[i][0] == 0); + } else { + ret = write_mbr_partition_entry(i + 1, t->appended_part_types[i], t->appended_part_start[i], t->appended_part_size[i], t->partition_secs_per_head, t->partition_heads_per_cyl, buf, 0); + } if (ret < 0) return ret; }