From 017dcb39f2a4b78a5100d5e20f3d5fab01bd6784 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Sun, 5 Sep 2010 12:43:48 +0200 Subject: [PATCH] New API function iso_write_opts_set_part_offset() controls creation of an MBR with a first partiton table entry that bears non-zero start address. A second set of volume descriptors and directory tree+tables gets created which can be used to mount the image at the partition start. Not yet implemented for second set: ISO 9660:1999, MD5 checksums. --- libisofs/buffer.c | 61 +++-- libisofs/buffer.h | 22 ++ libisofs/ecma119.c | 482 ++++++++++++++++++++++++++++++++++------ libisofs/ecma119.h | 36 ++- libisofs/ecma119_tree.c | 35 ++- libisofs/eltorito.c | 8 +- libisofs/joliet.c | 122 ++++++++-- libisofs/joliet.h | 6 + libisofs/libisofs.h | 82 ++++++- libisofs/libisofs.ver | 1 + libisofs/messages.c | 6 + libisofs/rockridge.c | 12 +- libisofs/system_area.c | 156 ++++++++++--- 13 files changed, 879 insertions(+), 150 deletions(-) diff --git a/libisofs/buffer.c b/libisofs/buffer.c index d566550..100e981 100644 --- a/libisofs/buffer.c +++ b/libisofs/buffer.c @@ -293,7 +293,51 @@ unsigned int iso_ring_buffer_get_times_empty(IsoRingBuffer *buf) } -/** +/** Internal via buffer.h + * + * Get the status of a ring buffer. + * + * @param buf + * The ring buffer object to inquire + * @param size + * Will be filled with the total size of the buffer, in bytes + * @param free_bytes + * Will be filled with the bytes currently available in buffer + * @return + * < 0 error, > 0 state: + * 1="active" : input and consumption are active + * 2="ending" : input has ended without error + * 3="failing" : input had error and ended, + * 5="abandoned" : consumption has ended prematurely + * 6="ended" : consumption has ended without input error + * 7="aborted" : consumption has ended after input error + */ +int iso_ring_buffer_get_buf_status(IsoRingBuffer *buf, size_t *size, + size_t *free_bytes) +{ + int ret; + + if (buf == NULL) { + return ISO_NULL_POINTER; + } + + /* get mutex */ + pthread_mutex_lock(&buf->mutex); + if (size) { + *size = buf->cap; + } + if (free_bytes) { + *free_bytes = buf->cap - buf->size; + } + + ret = (buf->rend ? 4 : 0) + (buf->wend + 1); + + pthread_mutex_unlock(&buf->mutex); + return ret; +} + +/** API via libisofs.h + * * Get the status of the buffer used by a burn_source. * * @param b @@ -321,18 +365,7 @@ int iso_ring_buffer_get_status(struct burn_source *b, size_t *size, return ISO_NULL_POINTER; } buf = ((Ecma119Image*)(b->data))->buffer; - - /* get mutex */ - pthread_mutex_lock(&buf->mutex); - if (size) { - *size = buf->cap; - } - if (free_bytes) { - *free_bytes = buf->cap - buf->size; - } - - ret = (buf->rend ? 4 : 0) + (buf->wend + 1); - - pthread_mutex_unlock(&buf->mutex); + ret = iso_ring_buffer_get_buf_status(buf, size, free_bytes); return ret; } + diff --git a/libisofs/buffer.h b/libisofs/buffer.h index 9d5a31b..b5afa39 100644 --- a/libisofs/buffer.h +++ b/libisofs/buffer.h @@ -63,6 +63,28 @@ int iso_ring_buffer_write(IsoRingBuffer *buf, uint8_t *data, size_t count); */ int iso_ring_buffer_read(IsoRingBuffer *buf, uint8_t *dest, size_t count); +/** Backend of API call iso_ring_buffer_get_status() + * + * Get the status of a ring buffer. + * + * @param buf + * The ring buffer object to inquire + * @param size + * Will be filled with the total size of the buffer, in bytes + * @param free_bytes + * Will be filled with the bytes currently available in buffer + * @return + * < 0 error, > 0 state: + * 1="active" : input and consumption are active + * 2="ending" : input has ended without error + * 3="failing" : input had error and ended, + * 5="abandoned" : consumption has ended prematurely + * 6="ended" : consumption has ended without input error + * 7="aborted" : consumption has ended after input error + */ +int iso_ring_buffer_get_buf_status(IsoRingBuffer *buf, size_t *size, + size_t *free_bytes); + /** * Close the buffer (to be called by the writer). * You have to explicity close the buffer when you don't have more data to diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index a872e8a..a1970ec 100644 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -85,6 +85,9 @@ void ecma119_image_free(Ecma119Image *t) free(t->checksum_buffer); if (t->writers != NULL) free(t->writers); + if (t->partition_root != NULL) + ecma119_node_free(t->partition_root); + t->partition_root = NULL; free(t); } @@ -231,6 +234,7 @@ int ecma119_writer_compute_data_blocks(IsoImageWriter *writer) { Ecma119Image *target; uint32_t path_table_size; + size_t ndirs; if (writer == NULL) { return ISO_ASSERT_FAILURE; @@ -253,6 +257,25 @@ int ecma119_writer_compute_data_blocks(IsoImageWriter *writer) target->m_path_table_pos = target->curblock; target->curblock += DIV_UP(path_table_size, BLOCK_SIZE); target->path_table_size = path_table_size; + + if (target->partition_offset > 0) { + /* TWINTREE: take into respect second directory tree */ + ndirs = target->ndirs; + target->ndirs = 0; + calc_dir_pos(target, target->partition_root); + if (target->ndirs != ndirs) { + iso_msg_submit(target->image->id, ISO_ASSERT_FAILURE, 0, + "Number of directories differs in ECMA-119 partiton_tree"); + return ISO_ASSERT_FAILURE; + } + /* TWINTREE: take into respect second set of path tables */ + path_table_size = calc_path_table_size(target->partition_root); + target->partition_l_table_pos = target->curblock; + target->curblock += DIV_UP(path_table_size, BLOCK_SIZE); + target->partition_m_table_pos = target->curblock; + target->curblock += DIV_UP(path_table_size, BLOCK_SIZE); + } + if (target->md5_session_checksum) { /* Account for tree checksum tag */ target->checksum_tree_tag_pos = target->curblock; @@ -323,7 +346,8 @@ void write_one_dir_record(Ecma119Image *t, Ecma119Node *node, int file_id, node = node->parent; rec->len_dr[0] = len_dr + (info != NULL ? info->suf_len : 0); - iso_bb(rec->block, block, 4); + /* TWINTREE: - t->eff_partition_offset */ + iso_bb(rec->block, block - t->eff_partition_offset, 4); iso_bb(rec->length, len, 4); if (t->dir_rec_mtime) { iso= node->node; @@ -411,15 +435,29 @@ int ecma119_writer_write_vol_desc(IsoImageWriter *writer) vol.vol_desc_version[0] = 1; strncpy_pad((char*)vol.system_id, system_id, 32); strncpy_pad((char*)vol.volume_id, vol_id, 32); - iso_bb(vol.vol_space_size, t->vol_space_size, 4); + + /* TWINTREE: - t->eff_partition_offset */ + iso_bb(vol.vol_space_size, t->vol_space_size - t->eff_partition_offset, + 4); + iso_bb(vol.vol_set_size, (uint32_t) 1, 2); iso_bb(vol.vol_seq_number, (uint32_t) 1, 2); iso_bb(vol.block_size, (uint32_t) BLOCK_SIZE, 2); iso_bb(vol.path_table_size, t->path_table_size, 4); - iso_lsb(vol.l_path_table_pos, t->l_path_table_pos, 4); - iso_msb(vol.m_path_table_pos, t->m_path_table_pos, 4); - write_one_dir_record(t, t->root, 0, vol.root_dir_record, 1, NULL, 0); + if (t->eff_partition_offset > 0) { + /* TWINTREE: point to second tables and second root */ + iso_lsb(vol.l_path_table_pos, + t->partition_l_table_pos - t->eff_partition_offset, 4); + iso_msb(vol.m_path_table_pos, + t->partition_m_table_pos - t->eff_partition_offset, 4); + write_one_dir_record(t, t->partition_root, 0, + vol.root_dir_record, 1, NULL, 0); + } else { + iso_lsb(vol.l_path_table_pos, t->l_path_table_pos, 4); + iso_msb(vol.m_path_table_pos, t->m_path_table_pos, 4); + write_one_dir_record(t, t->root, 0, vol.root_dir_record, 1, NULL, 0); + } strncpy_pad((char*)vol.vol_set_id, volset_id, 128); strncpy_pad((char*)vol.publisher_id, pub_id, 128); @@ -637,7 +675,9 @@ int write_path_table(Ecma119Image *t, Ecma119Node **pathlist, int l_type) rec = (struct ecma119_path_table_record*) buf; rec->len_di[0] = dir->parent ? (uint8_t) strlen(dir->iso_name) : 1; rec->len_xa[0] = 0; - write_int(rec->block, dir->info.dir->block, 4); + /* TWINTREE: - t->eff_partition_offset */ + write_int(rec->block, dir->info.dir->block - t->eff_partition_offset, + 4); write_int(rec->parent, parent + 1, 2); if (dir->parent) { memcpy(rec->dir_id, dir->iso_name, rec->len_di[0]); @@ -676,7 +716,13 @@ int write_path_tables(Ecma119Image *t) if (pathlist == NULL) { return ISO_OUT_OF_MEM; } - pathlist[0] = t->root; + + /* TWINTREE: t->partition_root */ + if (t->eff_partition_offset > 0) { + pathlist[0] = t->partition_root; + } else { + pathlist[0] = t->root; + } cur = 1; for (i = 0; i < t->ndirs; i++) { @@ -703,11 +749,54 @@ int write_path_tables(Ecma119Image *t) return ret; } + /** - * Write both the directory structure (ECMA-119, 6.8) and the L and M + * Write the directory structure (ECMA-119, 6.8) and the L and M * Path Tables (ECMA-119, 6.9). */ static +int ecma119_writer_write_dirs(IsoImageWriter *writer) +{ + int ret; + Ecma119Image *t; + Ecma119Node *root; + + t = writer->target; + + /* first of all, we write the directory structure */ + /* TWINTREE: t->root -> root */ + if (t->eff_partition_offset > 0) { + root = t->partition_root; + } else { + root = t->root; + } + ret = write_dirs(t, root, root); + if (ret < 0) { + return ret; + } + + /* and write the path tables */ + ret = write_path_tables(t); + if (ret < 0) + return ret; + if (t->md5_session_checksum) { + /* Write tree checksum tag */ + if (t->eff_partition_offset > 0) { + /* >>> TWINTREE: >>> For now, checksums and tags are only for the + first session */; + } else { + ret = iso_md5_write_tag(t, 3); + } + } + return ret; +} + +/** + * Write directory structure and Path Tables of the ECMA-119 tree. + * This happens eventually a second time for the duplicates which use + * addresses with partition offset. + */ +static int ecma119_writer_write_data(IsoImageWriter *writer) { int ret; @@ -718,21 +807,19 @@ int ecma119_writer_write_data(IsoImageWriter *writer) } t = writer->target; - /* first of all, we write the directory structure */ - ret = write_dirs(t, t->root, t->root); - if (ret < 0) { - return ret; - } - - /* and write the path tables */ - ret = write_path_tables(t); + ret = ecma119_writer_write_dirs(writer); if (ret < 0) return ret; - if (t->md5_session_checksum) { - /* Write tree checksum tag */ - ret = iso_md5_write_tag(t, 3); + + if (t->partition_offset > 0) { + /* TWINTREE: */ + t->eff_partition_offset = t->partition_offset; + ret = ecma119_writer_write_dirs(writer); + t->eff_partition_offset = 0; + if (ret < 0) + return ret; } - return ret; + return ISO_SUCCESS; } static @@ -768,6 +855,16 @@ int ecma119_writer_create(Ecma119Image *target) return ret; } + /* TWINTREE: */ + if(target->partition_offset > 0) { + /* Create second tree */ + target->eff_partition_offset = target->partition_offset; + ret = ecma119_tree_create(target); + target->eff_partition_offset = 0; + if (ret < 0) + return ret; + } + /* we need the volume descriptor */ target->curblock++; return ISO_SUCCESS; @@ -867,12 +964,157 @@ int transplant_checksum_buffer(Ecma119Image *target, int flag) return 1; } +static +int write_vol_desc_terminator(Ecma119Image *target) +{ + int res; + uint8_t buf[BLOCK_SIZE]; + struct ecma119_vol_desc_terminator *vol; + + vol = (struct ecma119_vol_desc_terminator *) buf; + + vol->vol_desc_type[0] = 255; + memcpy(vol->std_identifier, "CD001", 5); + vol->vol_desc_version[0] = 1; + + res = iso_write(target, buf, BLOCK_SIZE); + return res; +} + + +/* @param flag bit0= initialize system area by target->opts_overwrite + bit1= fifo is not yet draining. Inquire write_count from fifo. +*/ +static +int write_head_part1(Ecma119Image *target, int *write_count, int flag) +{ + int res, i; + uint8_t sa[16 * BLOCK_SIZE]; + IsoImageWriter *writer; + size_t buffer_size = 0, buffer_free = 0, buffer_start_free = 0; + + iso_ring_buffer_get_buf_status(target->buffer, &buffer_size, + &buffer_start_free); + *write_count = 0; + /* Write System Area (ECMA-119, 6.2.1) */ + if ((flag & 1) && target->opts_overwrite != NULL) + memcpy(sa, target->opts_overwrite, 16 * BLOCK_SIZE); + res = iso_write_system_area(target, sa); + if (res < 0) + goto write_error; + res = iso_write(target, sa, 16 * BLOCK_SIZE); + if (res < 0) + goto write_error; + *write_count = 16; + + /* write volume descriptors, one per writer */ + iso_msg_debug(target->image->id, "Write volume descriptors"); + for (i = 0; i < target->nwriters; ++i) { + writer = target->writers[i]; + res = writer->write_vol_desc(writer); + if (res < 0) + goto write_error; + } + + /* write Volume Descriptor Set Terminator (ECMA-119, 8.3) */ + res = write_vol_desc_terminator(target); + if (res < 0) + goto write_error; + + if(flag & 2) { + iso_ring_buffer_get_buf_status(target->buffer, &buffer_size, + &buffer_free); + *write_count = ( buffer_start_free - buffer_free ) / BLOCK_SIZE; + } else { + *write_count = target->bytes_written / BLOCK_SIZE; + } + + return ISO_SUCCESS; +write_error:; + return res; +} + +static +int write_head_part2(Ecma119Image *target, int *write_count, int flag) +{ + int res, i; + uint8_t buf[BLOCK_SIZE]; + IsoImageWriter *writer; + + if (target->partition_offset <= 0) + return ISO_SUCCESS; + + /* TWINTREE: write padding up to target->partition_offset + 16 */ + memset(buf, 0, 2048); + for(; *write_count < target->partition_offset + 16; (*write_count)++) { + res = iso_write(target, buf, BLOCK_SIZE); + if (res < 0) + goto write_error; + } + + /* TWINTREE: write volume descriptors subtracting + target->partiton_offset from any LBA pointer. + */ + target->eff_partition_offset = target->partition_offset; + for (i = 0; i < target->nwriters; ++i) { + writer = target->writers[i]; + /* TWINTREE: + Not all writers have an entry in the partion volume descriptor set. + It must be guaranteed that they write exactly one block. + */ + /* >>> TWINTREE: Enhance ISO1999 writer and add it here */ + if(writer->write_vol_desc != ecma119_writer_write_vol_desc && + writer->write_vol_desc != joliet_writer_write_vol_desc) + continue; + res = writer->write_vol_desc(writer); + if (res < 0) + goto write_error; + (*write_count)++; + } + res = write_vol_desc_terminator(target); + if (res < 0) + goto write_error; + (*write_count)++; + target->eff_partition_offset = 0; + + /* >>> TWINTREE: Postponed for now: + Write second superblock checksum tag */; + + return ISO_SUCCESS; +write_error:; + return res; +} + +static +int write_head_part(Ecma119Image *target, int flag) +{ + int res, write_count = 0; + + /* System area and volume descriptors */ + res = write_head_part1(target, &write_count, 0); + if (res < 0) + return res; + + /* Write superblock checksum tag */ + if (target->md5_session_checksum && target->checksum_ctx != NULL) { + res = iso_md5_write_tag(target, 2); + if (res < 0) + return res; + write_count++; + } + + /* Second set of system area and volume descriptors for partition_offset */ + res = write_head_part2(target, &write_count, 0); + if (res < 0) + return res; + return ISO_SUCCESS; +} + static void *write_function(void *arg) { int res; size_t i; - uint8_t buf[BLOCK_SIZE]; IsoImageWriter *writer; Ecma119Image *target = (Ecma119Image*)arg; @@ -881,50 +1123,9 @@ void *write_function(void *arg) target->bytes_written = (off_t) 0; target->percent_written = 0; - /* Write System Area (ECMA-119, 6.2.1) */ - { - uint8_t sa[16 * BLOCK_SIZE]; - res = iso_write_system_area(target, sa); - if (res < 0) { - goto write_error; - } - res = iso_write(target, sa, 16 * BLOCK_SIZE); - if (res < 0) { - goto write_error; - } - } - - /* write volume descriptors, one per writer */ - iso_msg_debug(target->image->id, "Write volume descriptors"); - for (i = 0; i < target->nwriters; ++i) { - writer = target->writers[i]; - res = writer->write_vol_desc(writer); - if (res < 0) { - goto write_error; - } - } - - /* write Volume Descriptor Set Terminator (ECMA-119, 8.3) */ - { - struct ecma119_vol_desc_terminator *vol; - vol = (struct ecma119_vol_desc_terminator *) buf; - - vol->vol_desc_type[0] = 255; - memcpy(vol->std_identifier, "CD001", 5); - vol->vol_desc_version[0] = 1; - - res = iso_write(target, buf, BLOCK_SIZE); - if (res < 0) { - goto write_error; - } - } - - /* Write superblock checksum tag */ - if (target->md5_session_checksum && target->checksum_ctx != NULL) { - res = iso_md5_write_tag(target, 2); - if (res < 0) - goto write_error; - } + res = write_head_part(target, 0); + if (res < 0) + goto write_error; /* write data for each writer */ for (i = 0; i < target->nwriters; ++i) { @@ -947,6 +1148,10 @@ void *write_function(void *arg) #endif write_error: ; + + /* TWINTREE: */ + target->eff_partition_offset = 0; + if (res == ISO_CANCELED) { /* canceled */ iso_msg_submit(target->image->id, ISO_IMAGE_WRITE_CANCELED, 0, NULL); @@ -1064,15 +1269,20 @@ int checksum_prepare_nodes(Ecma119Image *target, IsoNode *node, int flag) return ISO_SUCCESS; } +/* +*/ +#define Libisofs_twintreE yes static int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) { int ret, i, voldesc_size, nwriters, image_checksums_mad = 0, tag_pos; Ecma119Image *target; + IsoImageWriter *writer; int el_torito_writer_index = -1, file_src_writer_index = -1; int system_area_options = 0; char *system_area = NULL; + int write_count = 0, write_count_mem; /* 1. Allocate target and copy opts there */ target = calloc(1, sizeof(Ecma119Image)); @@ -1172,6 +1382,18 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) target->vol_effective_time = opts->vol_effective_time; strcpy(target->vol_uuid, opts->vol_uuid); + /* TWINTREE: */ + target->partition_offset = opts->partition_offset; + target->partition_secs_per_head = opts->partition_secs_per_head; + target->partition_heads_per_cyl = opts->partition_heads_per_cyl; + target->eff_partition_offset = 0; + target->partition_root = NULL; + target->partition_l_table_pos = 0; + target->partition_m_table_pos = 0; + target->j_part_root = NULL; + target->j_part_l_path_table_pos = 0; + target->j_part_m_path_table_pos = 0; + target->input_charset = strdup(iso_get_local_charset(0)); if (target->input_charset == NULL) { ret = ISO_OUT_OF_MEM; @@ -1203,7 +1425,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) target->checksum_array_pos = 0; target->checksum_range_start = 0; target->checksum_range_size = 0; - target->opts_overwrite = 0; + target->opts_overwrite = NULL; /* * 2. Based on those options, create needed writers: iso, joliet... @@ -1215,6 +1437,13 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) */ target->curblock = target->ms_block + 16; + if (opts->overwrite != NULL && target->ms_block != 0 && + target->ms_block < target->partition_offset + 32) { + /* TWINTREE: not enough room for superblock relocation */ + ret = ISO_OVWRT_MS_TOO_SMALL; + goto target_cleanup; + } + /* the number of writers is dependent of the extensions */ nwriters = 1 + 1 + 1; /* ECMA-119 + padding + files */ @@ -1306,6 +1535,37 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) if (ret < 0) goto target_cleanup; } + + if (target->partition_offset > 0) { + /* >>> TWINTREE: After volume descriptors and superblock tag are + accounted for: account for second volset */ + + if (target->ms_block + target->partition_offset + 16 + < target->curblock) { + /* TWINTREE: Overflow of partition system area */ + ret = ISO_PART_OFFST_TOO_SMALL; + goto target_cleanup; + } + target->curblock = target->ms_block + target->partition_offset + 16; + + /* TWINTREE: Account for partition tree volume descriptors */ + for (i = 0; i < target->nwriters; ++i) { + /* Not all writers have an entry in the partition + volume descriptor set. + */ + writer = target->writers[i]; + /* >>> TWINTREE: Enhance ISO1999 writer and add it here */ + if(writer->write_vol_desc != ecma119_writer_write_vol_desc && + writer->write_vol_desc != joliet_writer_write_vol_desc) + continue; + target->curblock++; + } + target->curblock++; /* + Terminator */ + + /* >>> TWINTREE: eventually later : second superblock checksum tag */; + + } + /* * 3. @@ -1345,13 +1605,54 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) #endif /* Libisofs_patch_ticket_145 */ /* create the ring buffer */ + if (opts->overwrite != NULL && + opts->fifo_size / 2048 < 32 + target->partition_offset) { + /* TWINTREE: + The ring buffer must be large enough to take opts->overwrite + */ + ret = ISO_OVWRT_FIFO_TOO_SMALL; + } ret = iso_ring_buffer_new(opts->fifo_size, &target->buffer); if (ret < 0) { goto target_cleanup; } /* check if we need to provide a copy of volume descriptors */ - if (opts->overwrite) { + if (opts->overwrite != NULL) { + + /* >>> TWINTREE: >>> + opts->overwrite must be larger by partion_offset + This storage is provided by the application. + */ + + +#ifdef Libisofs_twintreE + + /* + * In the PVM to be written in the 16th sector of the disc, we + * need to specify the full size. + */ + target->vol_space_size = target->curblock; + + /* System area and volume descriptors */ + target->opts_overwrite = (char *) opts->overwrite; + ret = write_head_part1(target, &write_count, 1 | 2); + target->opts_overwrite = NULL; + if (ret < 0) + goto target_cleanup; + + /* copy the volume descriptors to the overwrite buffer... */ + voldesc_size *= BLOCK_SIZE; + ret = iso_ring_buffer_read(target->buffer, opts->overwrite, + write_count * BLOCK_SIZE); + if (ret < 0) { + iso_msg_debug(target->image->id, + "Error reading overwrite volume descriptors"); + goto target_cleanup; + } + +#else /* Libisofs_twintreE */ + /* * Get a copy of the volume descriptors to be written in a DVD+RW * disc @@ -1378,7 +1679,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) } } - /* write the system area */ + /* write the system area to the start of the overwrite buffer */ ret = iso_write_system_area(target, opts->overwrite); if (ret < 0) { iso_msg_debug(target->image->id, @@ -1386,11 +1687,9 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) goto target_cleanup; } - /* skip the first 16 blocks (system area) */ + /* copy the volume descriptors to the overwrite buffer... */ buf = opts->overwrite + 16 * BLOCK_SIZE; voldesc_size *= BLOCK_SIZE; - - /* copy the volume descriptors to the overwrite buffer... */ ret = iso_ring_buffer_read(target->buffer, buf, voldesc_size); if (ret < 0) { iso_msg_debug(target->image->id, @@ -1405,6 +1704,11 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) memcpy(vol->std_identifier, "CD001", 5); vol->vol_desc_version[0] = 1; + write_count = voldesc_size / BLOCK_SIZE + 16; + write_count_mem= write_count; + +#endif /* ! Libisofs_twintreE */ + /* Write relocated superblock checksum tag */ tag_pos = voldesc_size / BLOCK_SIZE + 16 + 1; if (target->md5_session_checksum) { @@ -1422,9 +1726,10 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) goto target_cleanup; } tag_pos++; + write_count++; } - /* Clean out eventual checksum tags */ + /* Clean out eventual obsolete checksum tags */ for (i = tag_pos; i < 32; i++) { int tag_type; uint32_t pos, range_start, range_size, next_tag; @@ -1436,6 +1741,22 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) if (ret > 0) opts->overwrite[i * 2048] = 0; } + + /* TWINTREE: Write second set of volume descriptors */ + write_count_mem= write_count; + ret = write_head_part2(target, &write_count, 0); + if (ret < 0) + goto target_cleanup; + + /* TWINTREE: read written data into opts->overwrite */ + ret = iso_ring_buffer_read(target->buffer, + opts->overwrite + write_count_mem * BLOCK_SIZE, + (write_count - write_count_mem) * BLOCK_SIZE); + if (ret < 0) { + iso_msg_debug(target->image->id, + "Error reading overwrite volume descriptors"); + goto target_cleanup; + } } /* @@ -1702,7 +2023,10 @@ int iso_write_opts_new(IsoWriteOpts **opts, int profile) wopts->vol_modification_time = 0; wopts->vol_expiration_time = 0; wopts->vol_effective_time = 0; - wopts->vol_uuid[0]= 0; + wopts->vol_uuid[0] = 0; + wopts->partition_offset = 0; + wopts->partition_secs_per_head = 0; + wopts->partition_heads_per_cyl = 0; *opts = wopts; return ISO_SUCCESS; @@ -2130,3 +2454,15 @@ int iso_write_opts_set_pvd_times(IsoWriteOpts *opts, return ISO_SUCCESS; } +int iso_write_opts_set_part_offset(IsoWriteOpts *opts, + uint32_t block_offset_2k, + int secs_512_per_head, int heads_per_cyl) +{ + if (block_offset_2k > 0 && block_offset_2k < 16) + return ISO_PART_OFFST_TOO_SMALL; + opts->partition_offset = block_offset_2k; + opts->partition_secs_per_head = secs_512_per_head; + opts->partition_heads_per_cyl = heads_per_cyl; + return ISO_SUCCESS; +} + diff --git a/libisofs/ecma119.h b/libisofs/ecma119.h index e738ac2..c512e46 100644 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -314,6 +314,15 @@ struct iso_write_opts { */ char vol_uuid[17]; + /* TWINTREE: The number of unclaimed 2K blocks before + start of partition 1 as of the MBR in system area. + Must be 0 or >= 16. (Actually >= #voldescr + checksum tag) */ + uint32_t partition_offset; + /* TWINTREE: Partition table parameter: 1 to 63, 0= disabled/default */ + int partition_secs_per_head; + /* TWINTREE: 1 to 255, 0= disabled/default */ + int partition_heads_per_cyl; + }; typedef struct ecma119_image Ecma119Image; @@ -404,8 +413,9 @@ struct ecma119_image off_t total_size; uint32_t vol_space_size; - /* Bytes already written, just for progress notification */ + /* Bytes already written to image output */ off_t bytes_written; + /* just for progress notification */ int percent_written; /* @@ -531,6 +541,30 @@ struct ecma119_image * by unconverted string with timezone 0 */ char vol_uuid[17]; + + /* TWINTREE: The number of unclaimed 2K blocks before + start of partition 1 as of the MBR in system area. */ + uint32_t partition_offset; + /* TWINTREE: Partition table parameter: 1 to 63, 0= disabled/default */ + int partition_secs_per_head; + /* TWINTREE: 1 to 255, 0= disabled/default */ + int partition_heads_per_cyl; + + /* TWINTREE: The currently applicable LBA offset. To be subtracted from + any LBA that is mentioned in volume descriptors or + ECMA-119 tree. Either 0 or .partition_offset */ + uint32_t eff_partition_offset; + + /* TWINTREE: The second ECMA-119 directory tree and path tables */ + Ecma119Node *partition_root; + uint32_t partition_l_table_pos; + uint32_t partition_m_table_pos; + + /* TWINTREE: The second Joliet directory tree and path tables */ + JolietNode *j_part_root; + uint32_t j_part_l_path_table_pos; + uint32_t j_part_m_path_table_pos; + }; #define BP(a,b) [(b) - (a) + 1] diff --git a/libisofs/ecma119_tree.c b/libisofs/ecma119_tree.c index 1723cf6..729962e 100644 --- a/libisofs/ecma119_tree.c +++ b/libisofs/ecma119_tree.c @@ -714,6 +714,7 @@ static int mangle_tree(Ecma119Image *img, int recurse) { int max_file, max_dir; + Ecma119Node *root; if (img->max_37_char_filenames) { max_file = max_dir = 37; @@ -723,10 +724,16 @@ int mangle_tree(Ecma119Image *img, int recurse) } else { max_file = max_dir = 31; } - if (recurse) { - return mangle_dir(img, img->root, max_file, max_dir); + /* TWINTREE: */ + if (img->eff_partition_offset > 0) { + root = img->partition_root; } else { - return mangle_single_dir(img, img->root, max_file, max_dir); + root = img->root; + } + if (recurse) { + return mangle_dir(img, root, max_file, max_dir); + } else { + return mangle_single_dir(img, root, max_file, max_dir); } } @@ -844,11 +851,18 @@ int reorder_tree(Ecma119Image *img, Ecma119Node *dir, int level, int pathlen) { int ret; size_t max_path; + Ecma119Node *root; max_path = pathlen + 1 + max_child_name_len(dir); if (level > 8 || max_path > 255) { - ret = reparent(dir, img->root); + /* TWINTREE: */ + if (img->eff_partition_offset > 0) { + root = img->partition_root; + } else { + root = img->root; + } + ret = reparent(dir, root); if (ret < 0) { return ret; } @@ -1055,10 +1069,16 @@ int ecma119_tree_create(Ecma119Image *img) } return ret; } - img->root = root; + /* TWINTREE: */ + if (img->eff_partition_offset > 0) { + img->partition_root = root; + } else { + img->root = root; + } iso_msg_debug(img->image->id, "Matching hardlinks..."); - ret = match_hardlinks(img, img->root, 0); + /* TWINTREE: img->root -> root */ + ret = match_hardlinks(img, root, 0); if (ret < 0) { return ret; } @@ -1075,7 +1095,8 @@ int ecma119_tree_create(Ecma119Image *img) if (img->rockridge && !img->allow_deep_paths) { /* reorder the tree, acording to RRIP, 4.1.5 */ - ret = reorder_tree(img, img->root, 1, 0); + /* TWINTREE: img->root -> root */ + ret = reorder_tree(img, root, 1, 0); if (ret < 0) { return ret; } diff --git a/libisofs/eltorito.c b/libisofs/eltorito.c index 70f4b88..b8890b8 100644 --- a/libisofs/eltorito.c +++ b/libisofs/eltorito.c @@ -942,7 +942,7 @@ int catalog_stream_new(Ecma119Image *target, IsoStream **stream) return ISO_OUT_OF_MEM; } data = calloc(1, sizeof(struct catalog_stream)); - if (str == NULL) { + if (data == NULL) { free(str); return ISO_OUT_OF_MEM; } @@ -1107,6 +1107,7 @@ int eltorito_writer_compute_data_blocks(IsoImageWriter *writer) } ret = iso_stream_open(original); if (ret < 0) { + free(buf); return ret; } ret = iso_stream_read(original, buf, size); @@ -1157,7 +1158,10 @@ int eltorito_writer_write_vol_desc(IsoImageWriter *writer) memcpy(vol.std_identifier, "CD001", 5); vol.vol_desc_version[0] = 1; memcpy(vol.boot_sys_id, "EL TORITO SPECIFICATION", 23); - iso_lsb(vol.boot_catalog, t->cat->sections[0].block, 4); + + /* TWINTREE: t->cat->sections[0].block - t->eff_partition_offset */ + iso_lsb(vol.boot_catalog, + t->cat->sections[0].block - t->eff_partition_offset, 4); return iso_write(t, &vol, sizeof(struct ecma119_boot_rec_vol_desc)); } diff --git a/libisofs/joliet.c b/libisofs/joliet.c index 0993e93..7cefccc 100644 --- a/libisofs/joliet.c +++ b/libisofs/joliet.c @@ -556,17 +556,20 @@ int joliet_tree_create(Ecma119Image *t) } /* the Joliet tree is stored in Ecma119Image target */ - t->joliet_root = root; + /* TWINTREE: */ + if (t->eff_partition_offset > 0) { + t->j_part_root = root; + } else { + t->joliet_root = root; + } iso_msg_debug(t->image->id, "Sorting the Joliet tree..."); sort_tree(root); iso_msg_debug(t->image->id, "Mangling Joliet names..."); - ret = mangle_tree(t, t->joliet_root); - if (ret < 0) { + ret = mangle_tree(t, root); + if (ret < 0) return ret; - } - return ISO_SUCCESS; } @@ -673,6 +676,7 @@ int joliet_writer_compute_data_blocks(IsoImageWriter *writer) { Ecma119Image *t; uint32_t path_table_size; + size_t ndirs; if (writer == NULL) { return ISO_OUT_OF_MEM; @@ -696,6 +700,24 @@ int joliet_writer_compute_data_blocks(IsoImageWriter *writer) t->curblock += DIV_UP(path_table_size, BLOCK_SIZE); t->joliet_path_table_size = path_table_size; + if (t->partition_offset > 0) { + /* TWINTREE: take into respect second directory tree */ + ndirs = t->joliet_ndirs; + t->joliet_ndirs = 0; + calc_dir_pos(t, t->j_part_root); + if (t->joliet_ndirs != ndirs) { + iso_msg_submit(t->image->id, ISO_ASSERT_FAILURE, 0, + "Number of directories differs in Joliet partiton_tree"); + return ISO_ASSERT_FAILURE; + } + /* TWINTREE: take into respect second set of path tables */ + path_table_size = calc_path_table_size(t->j_part_root); + t->j_part_l_path_table_pos = t->curblock; + t->curblock += DIV_UP(path_table_size, BLOCK_SIZE); + t->j_part_m_path_table_pos = t->curblock; + t->curblock += DIV_UP(path_table_size, BLOCK_SIZE); + } + return ISO_SUCCESS; } @@ -758,7 +780,8 @@ void write_one_dir_record(Ecma119Image *t, JolietNode *node, int file_id, node = node->parent; rec->len_dr[0] = len_dr; - iso_bb(rec->block, block, 4); + /* TWINTREE: - t->eff_partition_offset */ + iso_bb(rec->block, block - t->eff_partition_offset, 4); iso_bb(rec->length, len, 4); iso_datetime_7(rec->recording_time, t->now, t->always_gmt); rec->flags[0] = ((node->type == JOLIET_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0); @@ -794,7 +817,6 @@ void ucsncpy_pad(uint16_t *dest, const uint16_t *src, size_t max) } } -static int joliet_writer_write_vol_desc(IsoImageWriter *writer) { IsoImage *image; @@ -836,15 +858,27 @@ int joliet_writer_write_vol_desc(IsoImageWriter *writer) /* make use of UCS-2 Level 3 */ memcpy(vol.esc_sequences, "%/E", 3); - iso_bb(vol.vol_space_size, t->vol_space_size, 4); + /* TWINTREE: - t->eff_partition_offset */ + iso_bb(vol.vol_space_size, t->vol_space_size - t->eff_partition_offset, + 4); + iso_bb(vol.vol_set_size, (uint32_t) 1, 2); iso_bb(vol.vol_seq_number, (uint32_t) 1, 2); iso_bb(vol.block_size, (uint32_t) BLOCK_SIZE, 2); iso_bb(vol.path_table_size, t->joliet_path_table_size, 4); - iso_lsb(vol.l_path_table_pos, t->joliet_l_path_table_pos, 4); - iso_msb(vol.m_path_table_pos, t->joliet_m_path_table_pos, 4); - write_one_dir_record(t, t->joliet_root, 0, vol.root_dir_record, 1, 0); + if (t->eff_partition_offset > 0) { + /* TWINTREE: point to second tables and second root */ + iso_lsb(vol.l_path_table_pos, + t->j_part_l_path_table_pos - t->eff_partition_offset, 4); + iso_msb(vol.m_path_table_pos, + t->j_part_m_path_table_pos - t->eff_partition_offset, 4); + write_one_dir_record(t, t->j_part_root, 0, vol.root_dir_record, 1, 0); + } else { + iso_lsb(vol.l_path_table_pos, t->joliet_l_path_table_pos, 4); + iso_msb(vol.m_path_table_pos, t->joliet_m_path_table_pos, 4); + write_one_dir_record(t, t->joliet_root, 0, vol.root_dir_record, 1, 0); + } ucsncpy_pad((uint16_t*)vol.vol_set_id, volset_id, 128); ucsncpy_pad((uint16_t*)vol.publisher_id, pub_id, 128); @@ -984,7 +1018,9 @@ int write_path_table(Ecma119Image *t, JolietNode **pathlist, int l_type) rec = (struct ecma119_path_table_record*) buf; rec->len_di[0] = dir->parent ? (uint8_t) ucslen(dir->name) * 2 : 1; rec->len_xa[0] = 0; - write_int(rec->block, dir->info.dir->block, 4); + /* TWINTREE: - t->eff_partition_offset */ + write_int(rec->block, dir->info.dir->block - t->eff_partition_offset, + 4); write_int(rec->parent, parent + 1, 2); if (dir->parent) { memcpy(rec->dir_id, dir->name, rec->len_di[0]); @@ -1023,7 +1059,13 @@ int write_path_tables(Ecma119Image *t) if (pathlist == NULL) { return ISO_OUT_OF_MEM; } - pathlist[0] = t->joliet_root; + + /* TWINTREE: t->partition_root */ + if (t->eff_partition_offset > 0) { + pathlist[0] = t->j_part_root; + } else { + pathlist[0] = t->joliet_root; + } cur = 1; for (i = 0; i < t->joliet_ndirs; i++) { @@ -1051,18 +1093,22 @@ int write_path_tables(Ecma119Image *t) } static -int joliet_writer_write_data(IsoImageWriter *writer) +int joliet_writer_write_dirs(IsoImageWriter *writer) { int ret; Ecma119Image *t; + JolietNode *root; - if (writer == NULL) { - return ISO_NULL_POINTER; - } t = writer->target; /* first of all, we write the directory structure */ - ret = write_dirs(t, t->joliet_root); + /* TWINTREE: t->root -> root */ + if (t->eff_partition_offset > 0) { + root = t->j_part_root; + } else { + root = t->joliet_root; + } + ret = write_dirs(t, root); if (ret < 0) { return ret; } @@ -1073,12 +1119,41 @@ int joliet_writer_write_data(IsoImageWriter *writer) return ret; } +static +int joliet_writer_write_data(IsoImageWriter *writer) +{ + int ret; + Ecma119Image *t; + + if (writer == NULL) { + return ISO_NULL_POINTER; + } + t = writer->target; + + ret = joliet_writer_write_dirs(writer); + if (ret < 0) + return ret; + + if (t->partition_offset > 0) { + /* TWINTREE: */ + t->eff_partition_offset = t->partition_offset; + ret = joliet_writer_write_dirs(writer); + t->eff_partition_offset = 0; + if (ret < 0) + return ret; + } + return ISO_SUCCESS; +} + static int joliet_writer_free_data(IsoImageWriter *writer) { /* free the Joliet tree */ Ecma119Image *t = writer->target; joliet_node_free(t->joliet_root); + if (t->j_part_root != NULL) + joliet_node_free(t->j_part_root); + t->j_part_root = NULL; return ISO_SUCCESS; } @@ -1109,6 +1184,17 @@ int joliet_writer_create(Ecma119Image *target) /* add this writer to image */ target->writers[target->nwriters++] = writer; + /* TWINTREE: */ + if(target->partition_offset > 0) { + /* Create second tree */ + target->eff_partition_offset = target->partition_offset; + ret = joliet_tree_create(target); + if (ret < 0) { + return ret; + } + target->eff_partition_offset = 0; + } + /* we need the volume descriptor */ target->curblock++; return ISO_SUCCESS; diff --git a/libisofs/joliet.h b/libisofs/joliet.h index 6954879..de8e357 100644 --- a/libisofs/joliet.h +++ b/libisofs/joliet.h @@ -54,4 +54,10 @@ struct joliet_node */ int joliet_writer_create(Ecma119Image *target); + +/* TWINTREE: Not to be called but only for comparison with target->writers[i] +*/ +int joliet_writer_write_vol_desc(IsoImageWriter *writer); + + #endif /* LIBISO_JOLIET_H */ diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 269a556..a78f77b 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -1693,9 +1693,12 @@ int iso_write_opts_set_ms_block(IsoWriteOpts *opts, uint32_t ms_block); * - Together with iso_write_opts_set_appendable(opts, 0) the buffer allows * to write the first session on overwriteable media to start addresses * other than 0. + * This address must not be smaller than 32 blocks plus the eventual + * partition offset as defined by iso_write_opts_set_part_offset(). * libisoburn in most cases writes the first session on overwriteable media - * and disk files to LBA 32 in order to preserve its descriptors from the - * subsequent overwriting by the descriptor buffer of later sessions. + * and disk files to LBA (32 + partition_offset) in order to preserve its + * descriptors from the subsequent overwriting by the descriptor buffer of + * later sessions. * * @param opts * The option set to be manipulated. @@ -1713,7 +1716,7 @@ int iso_write_opts_set_ms_block(IsoWriteOpts *opts, uint32_t ms_block); int iso_write_opts_set_overwrite_buf(IsoWriteOpts *opts, uint8_t *overwrite); /** - * Set the size, in number of blocks, of the FIFO buffer used between the + * Set the size, in number of blocks, of the ring buffer used between the * writer thread and the burn_source. You have to provide at least a 32 * blocks buffer. Default value is set to 2MB, if that is ok for you, you * don't need to call this function. @@ -1761,6 +1764,8 @@ int iso_write_opts_set_system_area(IsoWriteOpts *opts, char data[32768], * Explicitely set the four timestamps of the emerging Primary Volume * Descriptor. Default with all parameters is 0. * ECMA-119 defines them as: + * @param opts + * The option set to be manipulated. * @param vol_creation_time * When "the information in the volume was created." * A value of 0 means that the timepoint of write start is to be used. @@ -1782,6 +1787,8 @@ int iso_write_opts_set_system_area(IsoWriteOpts *opts, char data[32768], * is fully predictable and free of timezone pitfalls. * It should express a reasonable time in form YYYYMMDDhhmmsscc * E.g.: "2010040711405800" = 7 Apr 2010 11:40:58 (+0 centiseconds) + * @return + * ISO_SUCCESS or error * * @since 0.6.30 */ @@ -1791,6 +1798,44 @@ int iso_write_opts_set_pvd_times(IsoWriteOpts *opts, char *vol_uuid); +/* CAUTION : Not yet completely implemented for checksums in the second tree + * set and not yet tested for multi-session with overwrite buffer. + * Already usable for single session including bootability and + * Joliet directory tree. + * + * Control production of a second set of volume descriptors (superblock) + * and directory trees, together with a partition table entry in the MBR which + * has non-zero start address. + * The second volume descriptor set and trees will allow to mount the ISO image + * at the start of the first partition, while it is still possible to mount it + * via the normal first volume descriptor set and tree at the start of the + * image resp. storage device. + * This makes few sense on optical media. But on USB sticks it creates a + * conventional partition table which makes it mountable on e.g. Linux via + * /dev/sdb and /dev/sdb1 alike. + * + * @param opts + * The option set to be manipulated. + * @param block_offset_2k + * The offset of the partition start relative to device start. + * This is counted in 2 kB blocks. The partition table will show the + * according number of 512 byte sectors. + * Default is 0 which causes no second set and trees. + * If it is not 0 then it must not be smaller than 16. + * @param secs_512_per_head + * Number of 512 byte sectors per head. 1 to 63. 0=automatic. + * @param heads_per_cyl + * Number of heads per cylinder. 1 to 255. 0=automatic. + * @return + * ISO_SUCCESS or error + * + * @since 0.6.36 + */ +int iso_write_opts_set_part_offset(IsoWriteOpts *opts, + uint32_t block_offset_2k, + int secs_512_per_head, int heads_per_cyl); + + /** * Inquire the start address of the file data blocks after having used * IsoWriteOpts with iso_image_create_burn_source(). @@ -6071,8 +6116,35 @@ int iso_md5_match(char first_md5[16], char second_md5[16]); */ #define ISO_SCDBACKUP_TAG_NOT_0 0xD030FE99 +/** + * The setting of iso_write_opts_set_ms_block() leaves not enough room + * for the prescibed size of iso_write_opts_set_overwrite_buf(). + * (FAILURE, HIGH, -360) + * @since 0.6.36 + */ +#define ISO_OVWRT_MS_TOO_SMALL 0xE830FE98 -/* ! PLACE NEW ERROR CODES HERE ! */ +/** + * The partition offset is not 0 and leaves not not enough room for + * system area, volume descriptors, and checksum tags of the first tree. + * (FAILURE, HIGH, -361) + */ +#define ISO_PART_OFFST_TOO_SMALL 0xE830FE97 + +/** + * The ring buffer is smaller than 64 kB + partition offset. + * (FAILURE, HIGH, -362) + */ +#define ISO_OVWRT_FIFO_TOO_SMALL 0xE830FE96 + + +/* Internal developer note: + Place new error codes directly above this comment. + Newly introduced errors must get a message entry in + libisofs/message.c, function iso_error_to_msg() +*/ + +/* ! PLACE NEW ERROR CODES ABOVE. NOT AFTER THIS LINE ! */ /** Read error occured with IsoDataSource (SORRY,HIGH, -513) */ @@ -6088,7 +6160,7 @@ int iso_md5_match(char first_md5[16], char second_md5[16]); #define ISO_DATA_SOURCE_FATAL 0xF030FCFF -/* ! PLACE NEW ERROR CODES ABOVE. NOT HERE ! */ +/* ! PLACE NEW ERROR CODES SEVERAL LINES ABOVE. NOT HERE ! */ /* ------------------------------------------------------------------------- */ diff --git a/libisofs/libisofs.ver b/libisofs/libisofs.ver index 3bc6aa0..6acc13c 100644 --- a/libisofs/libisofs.ver +++ b/libisofs/libisofs.ver @@ -272,6 +272,7 @@ iso_write_opts_set_no_force_dots; iso_write_opts_set_omit_version_numbers; iso_write_opts_set_output_charset; iso_write_opts_set_overwrite_buf; +iso_write_opts_set_part_offset; iso_write_opts_set_pvd_times; iso_write_opts_set_record_md5; iso_write_opts_set_relaxed_vol_atts; diff --git a/libisofs/messages.c b/libisofs/messages.c index 69c0066..4011580 100644 --- a/libisofs/messages.c +++ b/libisofs/messages.c @@ -286,6 +286,12 @@ const char *iso_error_to_msg(int errcode) return "Session does not start at LBA 0. scdbackup checksum tag not written."; case ISO_BOOT_NO_CATALOG: return "No boot catalog created yet"; + case ISO_OVWRT_MS_TOO_SMALL: + return "Multi-session offset too small for overwrite buffer"; + case ISO_PART_OFFST_TOO_SMALL: + return "Partition offset too small for first tree root."; + case ISO_OVWRT_FIFO_TOO_SMALL: + return "The ring buffer is too small for overwrite buffer"; default: return "Unknown error"; } diff --git a/libisofs/rockridge.c b/libisofs/rockridge.c index abad37c..1e489ad 100644 --- a/libisofs/rockridge.c +++ b/libisofs/rockridge.c @@ -184,7 +184,9 @@ int rrip_add_PL(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp) PL[3] = 1; /* write the location of the real parent, already computed */ - iso_bb(&PL[4], n->info.dir->real_parent->info.dir->block, 4); + /* TWINTREE: - t->eff_partition_offset */ + iso_bb(&PL[4], + n->info.dir->real_parent->info.dir->block - t->eff_partition_offset, 4); return susp_append(t, susp, PL); } @@ -277,7 +279,9 @@ int rrip_add_CL(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp) CL[1] = 'L'; CL[2] = 12; CL[3] = 1; - iso_bb(&CL[4], n->info.real_me->info.dir->block, 4); + /* TWINTREE: - t->eff_partition_offset */ + iso_bb(&CL[4], n->info.real_me->info.dir->block - t->eff_partition_offset, + 4); return susp_append(t, susp, CL); } @@ -697,7 +701,9 @@ int susp_add_CE(Ecma119Image *t, size_t ce_len, struct susp_info *susp) CE[1] = 'E'; CE[2] = 28; CE[3] = 1; - iso_bb(&CE[4], susp->ce_block, 4); + + /* TWINTREE: susp->ce_block - t->eff_partition_offset */ + iso_bb(&CE[4], susp->ce_block - t->eff_partition_offset, 4); iso_bb(&CE[12], susp->ce_len, 4); iso_bb(&CE[20], (uint32_t) ce_len, 4); diff --git a/libisofs/system_area.c b/libisofs/system_area.c index 20f8467..236d68b 100644 --- a/libisofs/system_area.c +++ b/libisofs/system_area.c @@ -32,12 +32,42 @@ int make_isohybrid_mbr(int bin_lba, int *img_blocks, char *mbr, int flag); * Be cautious with changing parameters. Only few combinations are tested. * */ -int make_isolinux_mbr(int32_t *img_blocks, uint32_t boot_lba, +int make_isolinux_mbr(uint32_t *img_blocks, uint32_t boot_lba, uint32_t mbr_id, int head_count, int sector_count, int part_offset, int part_number, int fs_type, uint8_t *buf, int flag); +/* + * @param flag bit0= img_blocks is start address rather than end address: + do not subtract 1 + */ +static +void iso_compute_cyl_head_sec(uint32_t *img_blocks, int hpc, int sph, + uint32_t *end_lba, uint32_t *end_sec, + uint32_t *end_head, uint32_t *end_cyl, int flag) +{ + uint32_t secs; + + /* Partition table unit is 512 bytes per sector, ECMA-119 unit is 2048 */ + if (*img_blocks >= 0x40000000) + *img_blocks = 0x40000000 - 1; /* truncate rather than roll over */ + if (flag & 1) + secs = *end_lba = *img_blocks * 4; /* first valid 512-lba */ + else + secs = *end_lba = *img_blocks * 4 - 1; /* last valid 512-lba */ + *end_cyl = secs / (sph * hpc); + secs -= *end_cyl * sph * hpc; + *end_head = secs / sph; + *end_sec = secs - *end_head * sph + 1; /* Sector count starts by 1 */ + if (*end_cyl >= 1024) { + *end_cyl = 1023; + *end_head = hpc - 1; + *end_sec = sph; + } +} + + /* This is the gesture of grub-mkisofs --protective-msdos-label as explained by Vladimir Serbinenko , 2 April 2010, on grub-devel@gnu.org "Currently we use first and not last entry. You need to: @@ -53,38 +83,35 @@ int make_isolinux_mbr(int32_t *img_blocks, uint32_t boot_lba, should go into bytes 458-461. But with a start lba of 1, this is the same number. See also http://en.wikipedia.org/wiki/Master_boot_record + + flag bit0= do not write 0x55, 0xAA to 510,511 + bit1= do not mark partition as bootable */ static -int make_grub_msdos_label(int img_blocks, uint8_t *buf, int flag) +int make_grub_msdos_label(uint32_t img_blocks, uint8_t *buf, int flag) { uint8_t *wpt; - unsigned long end_lba, secs, end_sec, end_head, end_cyl; + uint32_t end_lba, end_sec, end_head, end_cyl; int sph = 63, hpc = 255, i; - /* Partition table unit is 512 bytes per sector, ECMA-119 unit is 2048 */ - if (img_blocks >= 0x40000000) - img_blocks = 0x40000000 - 1; /* truncate rather than roll over */ - secs = end_lba = img_blocks * 4 - 1; /* last valid 512-lba */ - end_cyl = secs / (sph * hpc); - secs -= end_cyl * sph * hpc; - end_head = secs / sph; - end_sec = secs - end_head * sph + 1; /* Sector count starts by 1 */ - if (end_cyl >= 1024) { - end_cyl = 1023; - end_head = hpc - 1; - end_sec = sph; - } + iso_compute_cyl_head_sec(&img_blocks, hpc, sph, + &end_lba, &end_sec, &end_head, &end_cyl, 0); /* 1) Zero-fill 446-510 */ wpt = buf + 446; memset(wpt, 0, 64); - /* 2) Put 0x55, 0xAA into 510-512 (actually 510-511) */ - buf[510] = 0x55; - buf[511] = 0xAA; - - /* 3) Put 0x80 (for bootable partition), */ - *(wpt++) = 0x80; + if (!(flag & 1)) { + /* 2) Put 0x55, 0xAA into 510-512 (actually 510-511) */ + buf[510] = 0x55; + buf[511] = 0xAA; + } + if (!(flag & 2)) { + /* 3) Put 0x80 (for bootable partition), */ + *(wpt++) = 0x80; + } else { + *(wpt++) = 0; + } /* 0, 2, 0 (C/H/S of the start), */ *(wpt++) = 0; @@ -120,10 +147,63 @@ int make_grub_msdos_label(int img_blocks, uint8_t *buf, int flag) } +static +int iso_offset_partition_start(uint32_t img_blocks, uint32_t partition_offset, + int sph_in, int hpc_in, uint8_t *buf, int flag) +{ + uint8_t *wpt; + uint32_t end_lba, end_sec, end_head, end_cyl; + uint32_t start_lba, start_sec, start_head, start_cyl; + int sph = 63, hpc = 255, i; + + if (sph_in > 0) + sph = sph_in; + if (hpc_in > 0) + hpc = hpc_in; + iso_compute_cyl_head_sec(&partition_offset, hpc, sph, + &start_lba, &start_sec, &start_head, &start_cyl, 1); + iso_compute_cyl_head_sec(&img_blocks, hpc, sph, + &end_lba, &end_sec, &end_head, &end_cyl, 0); + wpt = buf + 446; + + wpt++; + + /* C/H/S of the start */ + *(wpt++) = start_head; + *(wpt++) = start_sec | ((start_cyl & 0x300) >> 2); + *(wpt++) = end_cyl & 0xff; + + /* (partition type) */ + wpt++; + + /* 3 bytes of C/H/S end */ + *(wpt++) = end_head; + *(wpt++) = end_sec | ((end_cyl & 0x300) >> 2); + *(wpt++) = end_cyl & 0xff; + + /* LBA start in little endian */ + for (i = 0; i < 4; i++) + *(wpt++) = (start_lba >> (8 * i)) & 0xff; + + /* Number of sectors in partition, little endian */ + end_lba = end_lba - start_lba + 1; + for (i = 0; i < 4; i++) + *(wpt++) = (end_lba >> (8 * i)) & 0xff; + + /* at 446-462 */ + if (wpt - buf != 462) { + fprintf(stderr, + "libisofs: program error in iso_offset_partition_start: \"assert 462\"\n"); + return ISO_ASSERT_FAILURE; + } + return ISO_SUCCESS; +} + + int iso_write_system_area(Ecma119Image *t, uint8_t *buf) { - int ret; - int img_blocks; + int ret, int_img_blocks; + uint32_t img_blocks; if ((t == NULL) || (buf == NULL)) { return ISO_NULL_POINTER; @@ -142,8 +222,13 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) /* Check for isolinux image with magic number of 3.72 and produce an MBR from our built-in template. (Deprecated since 31 Mar 2010) */ + if (img_blocks < 0x80000000) { + int_img_blocks= img_blocks; + } else { + int_img_blocks= 0x7ffffff0; + } ret = make_isohybrid_mbr(t->bootsrc[0]->sections[0].block, - &img_blocks, (char*)buf, 0); + &int_img_blocks, (char*)buf, 0); if (ret != 1) { /* error, it should never happen */ return ISO_ASSERT_FAILURE; @@ -151,9 +236,9 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) return ISO_SUCCESS; } if (t->system_area_options & 1) { - /* Write GRUB protective msdos label, i.e. a isimple partition table */ + /* Write GRUB protective msdos label, i.e. a simple partition table */ ret = make_grub_msdos_label(img_blocks, buf, 0); - if (ret != 1) /* error should never happen */ + if (ret != ISO_SUCCESS) /* error should never happen */ return ISO_ASSERT_FAILURE; } else if(t->system_area_options & 2) { /* Patch externally provided system area as isohybrid MBR */ @@ -167,6 +252,23 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) (uint32_t) 0, 64, 32, 0, 1, 0x17, buf, 1); if (ret != 1) return ret; + } else if(t->partition_offset > 0) { + /* Write a simple partition table. */ + /* >>> TWINTREE: ??? Shall the partition stay marked as bootable ? */ + ret = make_grub_msdos_label(img_blocks, buf, 2); + if (ret != ISO_SUCCESS) /* error should never happen */ + return ISO_ASSERT_FAILURE; } + + if (t->partition_offset > 0) { + /* TWINTREE: adjust partition table to partition offset */ + img_blocks = t->curblock; /* value might be altered */ + ret = iso_offset_partition_start(img_blocks, t->partition_offset, + t->partition_secs_per_head, + t->partition_heads_per_cyl, buf, 0); + if (ret != ISO_SUCCESS) /* error should never happen */ + return ISO_ASSERT_FAILURE; + } + return ISO_SUCCESS; }