diff --git a/demo/iso_read.c b/demo/iso_read.c index de30717..63deb49 100644 --- a/demo/iso_read.c +++ b/demo/iso_read.c @@ -39,7 +39,7 @@ print_type(mode_t mode) case S_IFREG: printf("[R] "); break; case S_IFBLK: printf("[B] "); break; case S_IFDIR: printf("[D] "); break; - case S_IFIFO: printf("[F] "); break; + case S_IFIFO: printf("[F] "); break; } } @@ -51,6 +51,7 @@ print_file_src(IsoFileSource *file) iso_file_source_lstat(file, &info); print_type(info.st_mode); print_permissions(info.st_mode); + printf(" %10llu ", info.st_size); //printf(" {%ld,%ld} ", (long)info.st_dev, (long)info.st_ino); name = iso_file_source_get_name(file); printf(" %s", name); @@ -116,7 +117,7 @@ int main(int argc, char **argv) iso_init(); iso_set_msgs_severities("NEVER", "ALL", ""); - + result = iso_data_source_new_from_file(argv[1], &src); if (result < 0) { printf ("Error creating data source\n"); @@ -134,10 +135,10 @@ int main(int argc, char **argv) printf ("Error creating filesystem\n"); return 1; } - + printf("\nVOLUME INFORMATION\n"); printf("==================\n\n"); - + printf("Vol. id: %s\n", iso_image_fs_get_volume_id(fs)); printf("Publisher: %s\n", iso_image_fs_get_publisher_id(fs)); printf("Data preparer: %s\n", iso_image_fs_get_data_preparer_id(fs)); @@ -149,7 +150,7 @@ int main(int argc, char **argv) printf("\nDIRECTORY TREE\n"); printf("==============\n"); - + result = fs->get_root(fs, &root); if (result < 0) { printf ("Can't get root %d\n", result); @@ -158,7 +159,7 @@ int main(int argc, char **argv) //print_file_src(root); print_dir(root, 0); iso_file_source_unref(root); - + fs->close(fs); iso_filesystem_unref((IsoFilesystem*)fs); iso_data_source_unref(src); diff --git a/doc/devel/cookbook/Multi-Extent.txt b/doc/devel/cookbook/Multi-Extent.txt new file mode 100644 index 0000000..6b267af --- /dev/null +++ b/doc/devel/cookbook/Multi-Extent.txt @@ -0,0 +1,58 @@ +=============================================================================== + ISO-9660 Level 3 Cookbook +=============================================================================== + +Creation date: 2008-Aug-17 +Author: Vreixo Formoso +_______________________________________________________________________________ + +Contents: +--------- + +1. References +2. General +3. OS Support +4. Implementation + + +------------------------------------------------------------------------------- +1. References: + +ECMA-119 "Volume and File Structure of CDROM for Information Interchange" + + +------------------------------------------------------------------------------- +2. General + +In ECMA-119 standard, the size of a file section cannot be bigger than 4GB - 1, +because the Data Length field of the Directory Record is just 32 bits (9.1.4). + +However, "each file shall consist of one or more File Sections" (6.5.1), and +that way we can store files greater than 4GB in a ECMA-119 image. Such image, +with multiple File Sections, is only supported at Level 3 (10.3), as Level 2 +(10.2) states that "each file shall consist of only one File Section". + +On disc, each file section is stored in a Extent (6.4.2), i.e. a set of +contiguous Logical Blocks. + + +------------------------------------------------------------------------------- +3. OS Support + +Wikipedia states that "Microsoft Windows XP supports this, while Mac OS X +(as of 10.4.8) does not handle this case properly. In the case of Mac OS X, +the driver appears not to support file fragmentation at all (i.e. it only +supports ISO 9660 Level 2 but not Level 3). Linux supports multiple extents. +FreeBSD only shows and reads the last extent of a multi-extent file." + +------------------------------------------------------------------------------- +4. Implementation + +Each File Section will have its own Directory Record (6.5.1). So, for files +greater than 4 GB, we need to store several directory records, that will have +the same File Identifier, and stored in the order of the File Sections they +refer (9.3). + +All but the last Directory Record must have the Multi-Extent flag set (9.1.6) + + diff --git a/libisofs/buffer.c b/libisofs/buffer.c index c59bad1..a5d528b 100644 --- a/libisofs/buffer.c +++ b/libisofs/buffer.c @@ -1,19 +1,19 @@ /* * Copyright (c) 2007 Vreixo Formoso - * - * This file is part of the libisofs project; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as + * + * This file is part of the libisofs project; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. See COPYING file for details. */ /* * Synchronized ring buffer, works with a writer thread and a read thread. - * + * * TODO #00010 : optimize ring buffer * - write/read at the end of buffer requires a second mutex_lock, even if * there's enought space/data at the beginning * - pre-buffer for writes < BLOCK_SIZE - * + * */ #include "buffer.h" @@ -30,13 +30,13 @@ struct iso_ring_buffer { uint8_t *buf; - + /* * Max number of bytes in buffer */ size_t cap; - /* + /* * Number of bytes available. */ size_t size; @@ -45,11 +45,11 @@ struct iso_ring_buffer size_t rpos; size_t wpos; - /* + /* * flags to report if read or writer threads ends execution - * 0 not finished, 1 finished ok, 2 finish with error + * 0 not finished, 1 finished ok, 2 finish with error */ - unsigned int rend :2; + unsigned int rend :2; unsigned int wend :2; /* just for statistical purposes */ @@ -63,9 +63,9 @@ struct iso_ring_buffer /** * Create a new buffer. - * + * * The created buffer should be freed with iso_ring_buffer_free() - * + * * @param size * Number of blocks in buffer. You should supply a number >= 32, otherwise * size will be ignored and 32 will be used by default, which leads to a @@ -85,14 +85,14 @@ int iso_ring_buffer_new(size_t size, IsoRingBuffer **rbuf) if (buffer == NULL) { return ISO_OUT_OF_MEM; } - + buffer->cap = (size > 32 ? size : 32) * BLOCK_SIZE; buffer->buf = malloc(buffer->cap); if (buffer->buf == NULL) { free(buffer); return ISO_OUT_OF_MEM; } - + buffer->size = 0; buffer->wpos = 0; buffer->rpos = 0; @@ -126,7 +126,7 @@ void iso_ring_buffer_free(IsoRingBuffer *buf) /** * Write count bytes into buffer. It blocks until all bytes where written or * reader close the buffer. - * + * * @param buf * the buffer * @param data @@ -189,7 +189,7 @@ int iso_ring_buffer_write(IsoRingBuffer *buf, uint8_t *data, size_t count) * bytes has been read. If the writer finishes before outputting enought * bytes, 0 (EOF) is returned, the number of bytes already read remains * unknown. - * + * * @return * 1 success, 0 EOF, < 0 error */ @@ -252,7 +252,7 @@ void iso_ring_buffer_writer_close(IsoRingBuffer *buf, int error) void iso_ring_buffer_reader_close(IsoRingBuffer *buf, int error) { pthread_mutex_lock(&buf->mutex); - + if (buf->rend) { /* reader already closed */ pthread_mutex_unlock(&buf->mutex); @@ -285,9 +285,9 @@ unsigned int iso_ring_buffer_get_times_empty(IsoRingBuffer *buf) /** * Get the status of the buffer used by a burn_source. - * + * * @param b - * A burn_source previously obtained with + * A burn_source previously obtained with * iso_image_create_burn_source(). * @param size * Will be filled with the total size of the buffer, in bytes @@ -302,7 +302,7 @@ unsigned int iso_ring_buffer_get_times_empty(IsoRingBuffer *buf) * 6="ended" : consumption has ended without input error * 7="aborted" : consumption has ended after input error */ -int iso_ring_buffer_get_status(struct burn_source *b, size_t *size, +int iso_ring_buffer_get_status(struct burn_source *b, size_t *size, size_t *free_bytes) { int ret; @@ -311,7 +311,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) { @@ -322,7 +322,7 @@ int iso_ring_buffer_get_status(struct burn_source *b, size_t *size, } ret = (buf->rend ? 4 : 0) + (buf->wend + 1); - + pthread_mutex_unlock(&buf->mutex); return ret; } diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index e49ad8c..973191e 100644 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -1,9 +1,9 @@ /* * Copyright (c) 2007 Vreixo Formoso * Copyright (c) 2007 Mario Danic - * - * This file is part of the libisofs project; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as + * + * This file is part of the libisofs project; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. See COPYING file for details. */ @@ -90,10 +90,10 @@ size_t calc_dirent_len(Ecma119Image *t, Ecma119Node *n) /** * Computes the total size of all directory entries of a single dir, * acording to ECMA-119 6.8.1.1 - * + * * This also take into account the size needed for RR entries and * SUSP continuation areas (SUSP, 5.1). - * + * * @param ce * Will be filled with the size needed for Continuation Areas * @return @@ -117,24 +117,29 @@ size_t calc_dir_size(Ecma119Image *t, Ecma119Node *dir, size_t *ce) for (i = 0; i < dir->info.dir->nchildren; ++i) { size_t remaining; + int section, nsections; Ecma119Node *child = dir->info.dir->children[i]; - size_t dirent_len = calc_dirent_len(t, child); - if (t->rockridge) { - dirent_len += rrip_calc_len(t, child, 0, 255 - dirent_len, &ce_len); - *ce += ce_len; - } - remaining = BLOCK_SIZE - (len % BLOCK_SIZE); - if (dirent_len > remaining) { - /* child directory entry doesn't fit on block */ - len += remaining + dirent_len; - } else { - len += dirent_len; + + nsections = (child->type == ECMA119_FILE) ? child->info.file->nsections : 1; + for (section = 0; section < nsections; ++section) { + size_t dirent_len = calc_dirent_len(t, child); + if (t->rockridge) { + dirent_len += rrip_calc_len(t, child, 0, 255 - dirent_len, &ce_len); + *ce += ce_len; + } + remaining = BLOCK_SIZE - (len % BLOCK_SIZE); + if (dirent_len > remaining) { + /* child directory entry doesn't fit on block */ + len += remaining + dirent_len; + } else { + len += dirent_len; + } } } - + /* - * The size of a dir is always a multiple of block size, as we must add - * the size of the unused space after the last directory record + * The size of a dir is always a multiple of block size, as we must add + * the size of the unused space after the last directory record * (ECMA-119, 6.8.1.3) */ len = ROUND_UP(len, BLOCK_SIZE); @@ -222,24 +227,26 @@ int ecma119_writer_compute_data_blocks(IsoImageWriter *writer) /** * Write a single directory record (ECMA-119, 9.1) - * + * * @param file_id * if >= 0, we use it instead of the filename (for "." and ".." entries). * @param len_fi * Computed length of the file identifier. Total size of the directory * entry will be len + 33 + padding if needed (ECMA-119, 9.1.12) * @param info - * SUSP entries for the given directory record. It will be NULL for the - * root directory record in the PVD (ECMA-119, 8.4.18) (in order to + * SUSP entries for the given directory record. It will be NULL for the + * root directory record in the PVD (ECMA-119, 8.4.18) (in order to * distinguish it from the "." entry in the root directory) */ static void write_one_dir_record(Ecma119Image *t, Ecma119Node *node, int file_id, - uint8_t *buf, size_t len_fi, struct susp_info *info) + uint8_t *buf, size_t len_fi, struct susp_info *info, + int extent) { uint32_t len; uint32_t block; uint8_t len_dr; /*< size of dir entry without SUSP fields */ + int multi_extend = 0; uint8_t *name = (file_id >= 0) ? (uint8_t*)&file_id : (uint8_t*)node->iso_name; @@ -260,12 +267,13 @@ void write_one_dir_record(Ecma119Image *t, Ecma119Node *node, int file_id, len = node->info.dir->len; block = node->info.dir->block; } else if (node->type == ECMA119_FILE) { - len = iso_file_src_get_size(node->info.file); - block = node->info.file->block; + block = node->info.file->sections[extent].block; + len = node->info.file->sections[extent].size; + multi_extend = (node->info.file->nsections - 1 == extent) ? 0 : 1; } else { - /* - * for nodes other than files and dirs, we set both - * len and block to 0 + /* + * for nodes other than files and dirs, we set both + * len and block to 0 */ len = 0; block = 0; @@ -281,11 +289,13 @@ void write_one_dir_record(Ecma119Image *t, Ecma119Node *node, int file_id, iso_bb(rec->block, block, 4); iso_bb(rec->length, len, 4); iso_datetime_7(rec->recording_time, t->now, t->always_gmt); - rec->flags[0] = (node->type == ECMA119_DIR) ? 2 : 0; + rec->flags[0] = ((node->type == ECMA119_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0); iso_bb(rec->vol_seq_number, 1, 2); rec->len_fi[0] = len_fi; - /* and finally write the SUSP fields */ + /* + * and finally write the SUSP fields. + */ if (info != NULL) { rrip_write_susp_fields(t, info, buf + len_dr); } @@ -365,7 +375,7 @@ int ecma119_writer_write_vol_desc(IsoImageWriter *writer) 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); + 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); @@ -410,14 +420,14 @@ int write_one_dir(Ecma119Image *t, Ecma119Node *dir) /* initialize buffer with 0s */ memset(buffer, 0, BLOCK_SIZE); - /* + /* * set susp_info to 0's, this way code for both plain ECMA-119 and * RR is very similar */ memset(&info, 0, sizeof(struct susp_info)); if (t->rockridge) { /* initialize the ce_block, it might be needed */ - info.ce_block = dir->info.dir->block + DIV_UP(dir->info.dir->len, + info.ce_block = dir->info.dir->block + DIV_UP(dir->info.dir->len, BLOCK_SIZE); } @@ -429,7 +439,7 @@ int write_one_dir(Ecma119Image *t, Ecma119Node *dir) } } len = 34 + info.suf_len; - write_one_dir_record(t, dir, 0, buf, 1, &info); + write_one_dir_record(t, dir, 0, buf, 1, &info, 0); buf += len; if (t->rockridge) { @@ -439,40 +449,46 @@ int write_one_dir(Ecma119Image *t, Ecma119Node *dir) } } len = 34 + info.suf_len; - write_one_dir_record(t, dir, 1, buf, 1, &info); + write_one_dir_record(t, dir, 1, buf, 1, &info, 0); buf += len; for (i = 0; i < dir->info.dir->nchildren; i++) { + int section, nsections; Ecma119Node *child = dir->info.dir->children[i]; - /* compute len of directory entry */ fi_len = strlen(child->iso_name); - len = fi_len + 33 + (fi_len % 2 ? 0 : 1); - if (need_version_number(t, child)) { - len += 2; - } - /* get the SUSP fields if rockridge is enabled */ - if (t->rockridge) { - ret = rrip_get_susp_fields(t, child, 0, 255 - len, &info); - if (ret < 0) { - return ret; - } - len += info.suf_len; - } + nsections = (child->type == ECMA119_FILE) ? child->info.file->nsections : 1; + for (section = 0; section < nsections; ++section) { - if ( (buf + len - buffer) > BLOCK_SIZE) { - /* dir doesn't fit in current block */ - ret = iso_write(t, buffer, BLOCK_SIZE); - if (ret < 0) { - return ret; + /* compute len of directory entry */ + len = fi_len + 33 + (fi_len % 2 ? 0 : 1); + if (need_version_number(t, child)) { + len += 2; } - memset(buffer, 0, BLOCK_SIZE); - buf = buffer; + + /* get the SUSP fields if rockridge is enabled */ + if (t->rockridge) { + ret = rrip_get_susp_fields(t, child, 0, 255 - len, &info); + if (ret < 0) { + return ret; + } + len += info.suf_len; + } + + if ( (buf + len - buffer) > BLOCK_SIZE) { + /* dir doesn't fit in current block */ + ret = iso_write(t, buffer, BLOCK_SIZE); + if (ret < 0) { + return ret; + } + memset(buffer, 0, BLOCK_SIZE); + buf = buffer; + } + /* write the directory entry in any case */ + write_one_dir_record(t, child, -1, buf, fi_len, &info, section); + buf += len; } - /* write the directory entry in any case */ - write_one_dir_record(t, child, -1, buf, fi_len, &info); - buf += len; } /* write the last block */ @@ -709,7 +725,7 @@ int pad_writer_write_data(IsoImageWriter *writer) return ISO_ASSERT_FAILURE; } t = writer->target; - + if (t->pad_blocks == 0) { return ISO_SUCCESS; } @@ -820,7 +836,7 @@ void *write_function(void *arg) iso_msg_submit(target->image->id, ISO_IMAGE_WRITE_CANCELED, 0, NULL); } else { /* image write error */ - iso_msg_submit(target->image->id, ISO_WRITE_ERROR, res, + iso_msg_submit(target->image->id, ISO_WRITE_ERROR, res, "Image write error"); } iso_ring_buffer_writer_close(target->buffer, 1); @@ -855,7 +871,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) target->iso1999 = opts->iso1999; target->always_gmt = opts->always_gmt; target->ino = 0; - target->omit_version_numbers = opts->omit_version_numbers + target->omit_version_numbers = opts->omit_version_numbers | opts->max_37_char_filenames; target->allow_deep_paths = opts->allow_deep_paths; target->allow_longer_paths = opts->allow_longer_paths; @@ -882,7 +898,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) target->appendable = opts->appendable; target->replace_timestamps = opts->replace_timestamps ? 1 : 0; - target->timestamp = opts->replace_timestamps == 2 ? + target->timestamp = opts->replace_timestamps == 2 ? opts->timestamp : target->now; /* el-torito? */ @@ -909,10 +925,10 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) return ISO_OUT_OF_MEM; } - /* + /* * 2. Based on those options, create needed writers: iso, joliet... * Each writer inits its structures and stores needed info into - * target. + * target. * If the writer needs an volume descriptor, it increments image * current block. * Finally, create Writer for files. @@ -944,7 +960,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) if (ret < 0) { goto target_cleanup; } - + /* create writer for El-Torito */ if (target->eltorito) { ret = eltorito_writer_create(target); @@ -952,7 +968,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) goto target_cleanup; } } - + /* create writer for Joliet structure */ if (target->joliet) { ret = joliet_writer_create(target); @@ -960,7 +976,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) goto target_cleanup; } } - + /* create writer for ISO 9660:1999 structure */ if (target->iso1999) { ret = iso1999_writer_create(target); @@ -970,11 +986,11 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) } voldesc_size = target->curblock - target->ms_block - 16; - + /* Volume Descriptor Set Terminator */ target->curblock++; - /* + /* * Create the writer for possible padding to ensure that in case of image * growing we can safety overwrite the first 64 KiB of image. */ @@ -990,7 +1006,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) } /* - * 3. + * 3. * Call compute_data_blocks() in each Writer. * That function computes the size needed by its structures and * increments image current block propertly. @@ -1130,14 +1146,14 @@ static void bs_free_data(struct burn_source *bs) if (st < 4) { /* forces writer to stop if it is still running */ iso_ring_buffer_reader_close(target->buffer, 0); - + /* wait until writer thread finishes */ pthread_join(target->wthread, NULL); iso_msg_debug(target->image->id, "Writer thread joined"); } - - iso_msg_debug(target->image->id, - "Ring buffer was %d times full and %d times empty", + + iso_msg_debug(target->image->id, + "Ring buffer was %d times full and %d times empty", iso_ring_buffer_get_times_full(target->buffer), iso_ring_buffer_get_times_empty(target->buffer)); @@ -1153,9 +1169,9 @@ int bs_cancel(struct burn_source *bs) Ecma119Image *target = (Ecma119Image*)bs->data; st = iso_ring_buffer_get_status(bs, &cap, &free); - + if (free == cap && (st == 2 || st == 3)) { - /* image was already consumed */ + /* image was already consumed */ iso_ring_buffer_reader_close(target->buffer, 0); } else { iso_msg_debug(target->image->id, "Reader thread being cancelled"); @@ -1176,7 +1192,7 @@ int bs_set_size(struct burn_source *bs, off_t size) { Ecma119Image *target = (Ecma119Image*)bs->data; - /* + /* * just set the value to be returned by get_size. This is not used at * all by libisofs, it is here just for helping libburn to correctly pad * the image if needed. @@ -1235,12 +1251,12 @@ int iso_write(Ecma119Image *target, void *buf, size_t count) if (ret > 0 && (target->total_size != (off_t) 0)){ unsigned int kbw, kbt; int percent; - + target->bytes_written += (off_t) count; kbw = (unsigned int) (target->bytes_written >> 10); kbt = (unsigned int) (target->total_size >> 10); percent = (kbw * 100) / kbt; - + /* only report in 5% chunks */ if (percent >= target->percent_written + 5) { iso_msg_debug(target->image->id, "Processed %u of %u KB (%d %%)", @@ -1248,32 +1264,32 @@ int iso_write(Ecma119Image *target, void *buf, size_t count) target->percent_written = percent; } } - + return ret; } int iso_write_opts_new(IsoWriteOpts **opts, int profile) { IsoWriteOpts *wopts; - + if (opts == NULL) { return ISO_NULL_POINTER; } if (profile < 0 || profile > 2) { return ISO_WRONG_ARG_VALUE; } - + wopts = calloc(1, sizeof(IsoWriteOpts)); if (wopts == NULL) { return ISO_OUT_OF_MEM; } - + switch (profile) { case 0: wopts->level = 1; break; case 1: - wopts->level = 2; + wopts->level = 3; wopts->rockridge = 1; break; case 2: @@ -1305,7 +1321,7 @@ void iso_write_opts_free(IsoWriteOpts *opts) if (opts == NULL) { return; } - + free(opts->output_charset); free(opts); } @@ -1315,7 +1331,7 @@ int iso_write_opts_set_iso_level(IsoWriteOpts *opts, int level) if (opts == NULL) { return ISO_NULL_POINTER; } - if (level != 1 && level != 2) { + if (level != 1 && level != 2 && level != 3) { return ISO_WRONG_ARG_VALUE; } opts->level = level; diff --git a/libisofs/ecma119.h b/libisofs/ecma119.h index ffb1611..a4022ad 100644 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -1,8 +1,8 @@ /* * Copyright (c) 2007 Vreixo Formoso - * - * This file is part of the libisofs project; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as + * + * This file is part of the libisofs project; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. See COPYING file for details. */ @@ -18,6 +18,18 @@ #define BLOCK_SIZE 2048 +/* + * Maximum file section size. Set to 4GB - 1 = 0xffffffff + */ +#define MAX_ISO_FILE_SECTION_SIZE 0xffffffff + +/* + * When a file need to be splitted in several sections, the maximum size + * of such sections, but the last one. Set to a multiple of BLOCK_SIZE. + * Default to 4GB - 2048 = 0xFFFFF800 + */ +#define ISO_EXTENT_SIZE 0xFFFFF800 + /** * Holds the options for the image generation. */ @@ -33,11 +45,11 @@ struct iso_write_opts { /* allways write timestamps in GMT */ unsigned int always_gmt :1; - /* + /* * Relaxed constraints. Setting any of these to 1 break the specifications, - * but it is supposed to work on most moderns systems. Use with caution. + * but it is supposed to work on most moderns systems. Use with caution. */ - + /** * Omit the version number (";1") at the end of the ISO-9660 identifiers. * Version numbers are usually not used. @@ -45,7 +57,7 @@ struct iso_write_opts { unsigned int omit_version_numbers :1; /** - * Allow ISO-9660 directory hierarchy to be deeper than 8 levels. + * Allow ISO-9660 directory hierarchy to be deeper than 8 levels. */ unsigned int allow_deep_paths :1; @@ -64,30 +76,30 @@ struct iso_write_opts { /** * ISO-9660 forces filenames to have a ".", that separates file name from - * extension. libisofs adds it if original filename doesn't has one. Set + * extension. libisofs adds it if original filename doesn't has one. Set * this to 1 to prevent this behavior */ unsigned int no_force_dots :1; - + /** - * Allow lowercase characters in ISO-9660 filenames. By default, only - * uppercase characters, numbers and a few other characters are allowed. + * Allow lowercase characters in ISO-9660 filenames. By default, only + * uppercase characters, numbers and a few other characters are allowed. */ unsigned int allow_lowercase :1; - + /** * Allow all ASCII characters to be appear on an ISO-9660 filename. Note * that "/" and "\0" characters are never allowed, even in RR names. */ unsigned int allow_full_ascii :1; - + /** * Allow all characters to be part of Volume and Volset identifiers on * the Primary Volume Descriptor. This breaks ISO-9660 contraints, but * should work on modern systems. */ unsigned int relaxed_vol_atts :1; - + /** * Allow paths in the Joliet tree to have more than 240 characters. */ @@ -102,7 +114,7 @@ struct iso_write_opts { * If 0, the corresponding attribute will be kept as setted in the IsoNode. * Unless you have changed it, it corresponds to the value on disc, so it * is suitable for backup purposes. If set to 1, the corresponding attrib. - * will be changed by a default suitable value. Finally, if you set it to + * will be changed by a default suitable value. Finally, if you set it to * 2, the attrib. will be changed with the value specified in the options * below. Note that for mode attributes, only the permissions are set, the * file type remains unchanged. @@ -133,62 +145,62 @@ struct iso_write_opts { /** * This flags control the type of the image to create. Libisofs support - * two kind of images: stand-alone and appendable. - * + * two kind of images: stand-alone and appendable. + * * A stand-alone image is an image that is valid alone, and that can be * mounted by its own. This is the kind of image you will want to create * in most cases. A stand-alone image can be burned in an empty CD or DVD, * or write to an .iso file for future burning or distribution. - * + * * On the other side, an appendable image is not self contained, it refers * to serveral files that are stored outside the image. Its usage is for - * multisession discs, where you add data in a new session, while the - * previous session data can still be accessed. In those cases, the old + * multisession discs, where you add data in a new session, while the + * previous session data can still be accessed. In those cases, the old * data is not written again. Instead, the new image refers to it, and thus * it's only valid when appended to the original. Note that in those cases * the image will be written after the original, and thus you will want - * to use a ms_block greater than 0. - * - * Note that if you haven't import a previous image (by means of + * to use a ms_block greater than 0. + * + * Note that if you haven't import a previous image (by means of * iso_image_import()), the image will always be a stand-alone image, as * there is no previous data to refer to. */ unsigned int appendable : 1; - + /** * Start block of the image. It is supposed to be the lba where the first * block of the image will be written on disc. All references inside the * ISO image will take this into account, thus providing a mountable image. - * - * For appendable images, that are written to a new session, you should + * + * For appendable images, that are written to a new session, you should * pass here the lba of the next writable address on disc. - * - * In stand alone images this is usually 0. However, you may want to + * + * In stand alone images this is usually 0. However, you may want to * provide a different ms_block if you don't plan to burn the image in the * first session on disc, such as in some CD-Extra disc whether the data - * image is written in a new session after some audio tracks. + * image is written in a new session after some audio tracks. */ uint32_t ms_block; /** - * When not NULL, it should point to a buffer of at least 64KiB, where + * When not NULL, it should point to a buffer of at least 64KiB, where * libisofs will write the contents that should be written at the beginning * of a overwriteable media, to grow the image. The growing of an image is * a way, used by first time in growisofs by Andy Polyakov, to allow the * appending of new data to non-multisession media, such as DVD+RW, in the * same way you append a new session to a multisession disc, i.e., without - * need to write again the contents of the previous image. - * + * need to write again the contents of the previous image. + * * Note that if you want this kind of image growing, you will also need to * set appendable to "1" and provide a valid ms_block after the previous * image. - * - * You should initialize the buffer either with 0s, or with the contents of - * the first blocks of the image you're growing. In most cases, 0 is good + * + * You should initialize the buffer either with 0s, or with the contents of + * the first blocks of the image you're growing. In most cases, 0 is good * enought. */ uint8_t *overwrite; - + /** * Size, in number of blocks, of the FIFO buffer used between the writer * thread and the burn_source. You have to provide at least a 32 blocks @@ -228,13 +240,13 @@ struct ecma119_image unsigned int no_force_dots :1; unsigned int allow_lowercase :1; unsigned int allow_full_ascii :1; - + unsigned int relaxed_vol_atts : 1; - + /** Allow paths on Joliet tree to be larger than 240 bytes */ unsigned int joliet_longer_paths :1; - /* + /* * Mode replace. If one of these flags is set, the correspodent values are * replaced with values below. */ @@ -251,7 +263,7 @@ struct ecma119_image time_t timestamp; /** - * if sort files or not. Sorting is based of the weight of each file + * if sort files or not. Sorting is based of the weight of each file */ int sort_files; @@ -282,7 +294,7 @@ struct ecma119_image */ uint32_t curblock; - /* + /* * number of dirs in ECMA-119 tree, computed together with dir position, * and needed for path table computation in a efficient way */ @@ -290,7 +302,7 @@ struct ecma119_image uint32_t path_table_size; uint32_t l_path_table_pos; uint32_t m_path_table_pos; - + /* * Joliet related information */ @@ -299,7 +311,7 @@ struct ecma119_image uint32_t joliet_path_table_size; uint32_t joliet_l_path_table_pos; uint32_t joliet_m_path_table_pos; - + /* * ISO 9660:1999 related information */ @@ -308,7 +320,7 @@ struct ecma119_image uint32_t iso1999_path_table_size; uint32_t iso1999_l_path_table_pos; uint32_t iso1999_m_path_table_pos; - + /* * El-Torito related information */ @@ -322,10 +334,10 @@ struct ecma119_image * data. These padding blocks are added by libisofs to improve the handling * of image growing. The idea is that the first blocks in the image are * overwritten with the volume descriptors of the new image. These first - * blocks usually correspond to the volume descriptors and directory - * structure of the old image, and can be safety overwritten. However, - * with very small images they might correspond to valid data. To ensure - * this never happens, what we do is to add padding bytes, to ensure no + * blocks usually correspond to the volume descriptors and directory + * structure of the old image, and can be safety overwritten. However, + * with very small images they might correspond to valid data. To ensure + * this never happens, what we do is to add padding bytes, to ensure no * file data is written in the first 64 KiB, that are the bytes we usually * overwrite. */ diff --git a/libisofs/ecma119_tree.c b/libisofs/ecma119_tree.c index d65e3de..d56b4fc 100644 --- a/libisofs/ecma119_tree.c +++ b/libisofs/ecma119_tree.c @@ -161,7 +161,7 @@ int create_file(Ecma119Image *img, IsoFile *iso, Ecma119Node **node) off_t size; size = iso_stream_get_size(iso->stream); - if (size > (off_t)0xffffffff) { + if (size > (off_t)MAX_ISO_FILE_SECTION_SIZE && img->iso_level != 3) { char *ipath = iso_tree_get_node_path(ISO_NODE(iso)); ret = iso_msg_submit(img->image->id, ISO_FILE_TOO_BIG, 0, "File \"%s\" can't be added to image because " diff --git a/libisofs/eltorito.c b/libisofs/eltorito.c index 441b5c1..7462bea 100644 --- a/libisofs/eltorito.c +++ b/libisofs/eltorito.c @@ -1,8 +1,8 @@ /* * Copyright (c) 2007 Vreixo Formoso - * - * This file is part of the libisofs project; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as + * + * This file is part of the libisofs project; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. See COPYING file for details. */ @@ -26,7 +26,7 @@ struct boot_info_table { uint8_t bi_file BP(5, 8); /* LBA of boot file */ uint8_t bi_length BP(9, 12); /* Length of boot file */ uint8_t bi_csum BP(13, 16); /* Checksum of boot file */ - uint8_t bi_reserved BP(17, 56); /* Reserved */ + uint8_t bi_reserved BP(17, 56); /* Reserved */ }; /** @@ -67,7 +67,7 @@ void el_torito_set_load_seg(ElToritoBootImage *bootimg, short segment) /** * Sets the number of sectors (512b) to be load at load segment during - * the initial boot procedure. This is only for no emulation boot images, + * the initial boot procedure. This is only for no emulation boot images, * and is a NOP for other image types. */ void el_torito_set_load_size(ElToritoBootImage *bootimg, short sectors) @@ -109,7 +109,7 @@ int iso_tree_add_boot_node(IsoDir *parent, const char *name, IsoBoot **boot) if (boot) { *boot = NULL; } - + /* check if the name is valid */ if (!iso_node_is_valid_name(name)) { return ISO_WRONG_ARG_VALUE; @@ -162,7 +162,7 @@ int iso_tree_add_boot_node(IsoDir *parent, const char *name, IsoBoot **boot) } -static +static int create_image(IsoImage *image, const char *image_path, enum eltorito_boot_media_type type, struct el_torito_boot_image **bootimg) @@ -182,18 +182,18 @@ int create_image(IsoImage *image, const char *image_path, if (ret == 0) { return ISO_NODE_DOESNT_EXIST; } - + if (imgfile->type != LIBISO_FILE) { return ISO_BOOT_IMAGE_NOT_VALID; } - + stream = ((IsoFile*)imgfile)->stream; - + /* we need to read the image at least two times */ if (!iso_stream_is_repeatable(stream)) { return ISO_BOOT_IMAGE_NOT_VALID; } - + switch (type) { case ELTORITO_FLOPPY_EMUL: switch (iso_stream_get_size(stream)) { @@ -211,9 +211,9 @@ int create_image(IsoImage *image, const char *image_path, "Invalid image size %d Kb. Must be one of 1.2, 1.44" "or 2.88 Mb", iso_stream_get_size(stream) / 1024); return ISO_BOOT_IMAGE_NOT_VALID; - break; + break; } - /* it seems that for floppy emulation we need to load + /* it seems that for floppy emulation we need to load * a single sector (512b) */ load_sectors = 1; break; @@ -222,7 +222,7 @@ int create_image(IsoImage *image, const char *image_path, size_t i; struct hard_disc_mbr mbr; int used_partition; - + /* read the MBR on disc and get the type of the partition */ ret = iso_stream_open(stream); if (ret < 0) { @@ -237,14 +237,14 @@ int create_image(IsoImage *image, const char *image_path, "Can't read MBR from image file."); return ret < 0 ? ret : ISO_FILE_READ_ERROR; } - + /* check valid MBR signature */ if ( mbr.sign1 != 0x55 || mbr.sign2 != 0xAA ) { iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0, "Invalid MBR. Wrong signature."); return ISO_BOOT_IMAGE_NOT_VALID; } - + /* ensure single partition */ used_partition = -1; for (i = 0; i < 4; ++i) { @@ -252,7 +252,7 @@ int create_image(IsoImage *image, const char *image_path, /* it's an used partition */ if (used_partition != -1) { iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0, - "Invalid MBR. At least 2 partitions: %d and " + "Invalid MBR. At least 2 partitions: %d and " "%d, are being used\n", used_partition, i); return ISO_BOOT_IMAGE_NOT_VALID; } else @@ -262,15 +262,15 @@ int create_image(IsoImage *image, const char *image_path, partition_type = mbr.partition[used_partition].type; } boot_media_type = 4; - + /* only load the MBR */ load_sectors = 1; break; case ELTORITO_NO_EMUL: boot_media_type = 0; - break; + break; } - + boot = calloc(1, sizeof(struct el_torito_boot_image)); if (boot == NULL) { return ISO_OUT_OF_MEM; @@ -281,11 +281,11 @@ int create_image(IsoImage *image, const char *image_path, boot->type = boot_media_type; boot->load_size = load_sectors; boot->partition_type = partition_type; - + if (bootimg) { *bootimg = boot; } - + return ISO_SUCCESS; } @@ -298,14 +298,14 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path, struct el_torito_boot_catalog *catalog; ElToritoBootImage *boot_image= NULL; IsoBoot *cat_node= NULL; - + if (image == NULL || image_path == NULL || catalog_path == NULL) { return ISO_NULL_POINTER; } if (image->bootcat != NULL) { return ISO_IMAGE_ALREADY_BOOTABLE; } - + /* create the node for the catalog */ { IsoDir *parent; @@ -314,8 +314,8 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path, if (catdir == NULL) { return ISO_OUT_OF_MEM; } - - /* get both the dir and the name */ + + /* get both the dir and the name */ catname = strrchr(catdir, '/'); if (catname == NULL) { free(catdir); @@ -345,13 +345,13 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path, return ret; } } - + /* create the boot image */ ret = create_image(image, image_path, type, &boot_image); if (ret < 0) { goto boot_image_cleanup; } - + /* creates the catalog with the given image */ catalog = malloc(sizeof(struct el_torito_boot_catalog)); if (catalog == NULL) { @@ -362,13 +362,13 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path, catalog->node = cat_node; iso_node_ref((IsoNode*)cat_node); image->bootcat = catalog; - + if (boot) { *boot = boot_image; } - + return ISO_SUCCESS; - + boot_image_cleanup:; if (cat_node) { iso_node_take((IsoNode*)cat_node); @@ -383,32 +383,32 @@ boot_image_cleanup:; /** * Get El-Torito boot image of an ISO image, if any. - * + * * This can be useful, for example, to check if a volume read from a previous * session or an existing image is bootable. It can also be useful to get - * the image and catalog tree nodes. An application would want those, for + * the image and catalog tree nodes. An application would want those, for * example, to prevent the user removing it. - * + * * Both nodes are owned by libisofs and should not be freed. You can get your - * own ref with iso_node_ref(). You can can also check if the node is already - * on the tree by getting its parent (note that when reading El-Torito info - * from a previous image, the nodes might not be on the tree even if you haven't - * removed them). Remember that you'll need to get a new ref - * (with iso_node_ref()) before inserting them again to the tree, and probably + * own ref with iso_node_ref(). You can can also check if the node is already + * on the tree by getting its parent (note that when reading El-Torito info + * from a previous image, the nodes might not be on the tree even if you haven't + * removed them). Remember that you'll need to get a new ref + * (with iso_node_ref()) before inserting them again to the tree, and probably * you will also need to set the name or permissions. - * + * * @param image * The image from which to get the boot image. * @param boot - * If not NULL, it will be filled with a pointer to the boot image, if - * any. That object is owned by the IsoImage and should not be freed by + * If not NULL, it will be filled with a pointer to the boot image, if + * any. That object is owned by the IsoImage and should not be freed by * the user, nor dereferenced once the last reference to the IsoImage was * disposed via iso_image_unref(). - * @param imgnode + * @param imgnode * When not NULL, it will be filled with the image tree node. No extra ref * is added, you can use iso_node_ref() to get one if you need it. - * @param catnode - * When not NULL, it will be filled with the catnode tree node. No extra + * @param catnode + * When not NULL, it will be filled with the catnode tree node. No extra * ref is added, you can use iso_node_ref() to get one if you need it. * @return * 1 on success, 0 is the image is not bootable (i.e., it has no El-Torito @@ -423,7 +423,7 @@ int iso_image_get_boot_image(IsoImage *image, ElToritoBootImage **boot, if (image->bootcat == NULL) { return 0; } - + /* ok, image is bootable */ if (boot) { *boot = image->bootcat->image; @@ -438,8 +438,8 @@ int iso_image_get_boot_image(IsoImage *image, ElToritoBootImage **boot, } /** - * Removes the El-Torito bootable image. - * + * Removes the El-Torito bootable image. + * * The IsoBoot node that acts as placeholder for the catalog is also removed * for the image tree, if there. * If the image is not bootable (don't have el-torito boot image) this function @@ -449,13 +449,13 @@ void iso_image_remove_boot_image(IsoImage *image) { if (image == NULL || image->bootcat == NULL) return; - - /* - * remove catalog node from its parent - * (the reference will be disposed next) + + /* + * remove catalog node from its parent + * (the reference will be disposed next) */ iso_node_take((IsoNode*)image->bootcat->node); - + /* free boot catalog and image, including references to nodes */ el_torito_boot_catalog_free(image->bootcat); image->bootcat = NULL; @@ -464,11 +464,11 @@ void iso_image_remove_boot_image(IsoImage *image) void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat) { struct el_torito_boot_image *image; - + if (cat == NULL) { return; } - + image = cat->image; iso_node_unref((IsoNode*)image->image); free(image); @@ -486,19 +486,19 @@ struct catalog_stream int offset; /* -1 if stream is not openned */ }; -static void +static void write_validation_entry(uint8_t *buf) { size_t i; int checksum; - - struct el_torito_validation_entry *ve = + + struct el_torito_validation_entry *ve = (struct el_torito_validation_entry*)buf; ve->header_id[0] = 1; ve->platform_id[0] = 0; /* 0: 80x86, 1: PowerPC, 2: Mac */ ve->key_byte1[0] = 0x55; ve->key_byte2[0] = 0xAA; - + /* calculate the checksum, to ensure sum of all words is 0 */ checksum = 0; for (i = 0; i < sizeof(struct el_torito_validation_entry); i += 2) { @@ -515,9 +515,9 @@ static void write_section_entry(uint8_t *buf, Ecma119Image *t) { struct el_torito_boot_image *img; - struct el_torito_section_entry *se = + struct el_torito_section_entry *se = (struct el_torito_section_entry*)buf; - + img = t->catalog->image; se->boot_indicator[0] = img->bootable ? 0x88 : 0x00; @@ -525,7 +525,7 @@ write_section_entry(uint8_t *buf, Ecma119Image *t) iso_lsb(se->load_seg, img->load_seg, 2); se->system_type[0] = img->partition_type; iso_lsb(se->sec_count, img->load_size, 2); - iso_lsb(se->block, t->bootimg->block, 4); + iso_lsb(se->block, t->bootimg->sections[0].block, 4); } static @@ -536,13 +536,13 @@ int catalog_open(IsoStream *stream) return ISO_NULL_POINTER; } data = stream->data; - + if (data->offset != -1) { return ISO_FILE_ALREADY_OPENED; } - + memset(data->buffer, 0, BLOCK_SIZE); - + /* fill the buffer with the catalog contents */ write_validation_entry(data->buffer); @@ -561,7 +561,7 @@ int catalog_close(IsoStream *stream) return ISO_NULL_POINTER; } data = stream->data; - + if (data->offset == -1) { return ISO_FILE_NOT_OPENED; } @@ -587,11 +587,11 @@ int catalog_read(IsoStream *stream, void *buf, size_t count) return ISO_WRONG_ARG_VALUE; } data = stream->data; - + if (data->offset == -1) { return ISO_FILE_NOT_OPENED; } - + len = MIN(count, BLOCK_SIZE - data->offset); memcpy(buf, data->buffer + data->offset, len); return len; @@ -606,7 +606,7 @@ int catalog_is_repeatable(IsoStream *stream) /** * fs_id will be the id reserved for El-Torito * dev_id will be 0 for catalog, 1 for boot image (if needed) - * we leave ino_id for future use when we support multiple boot images + * we leave ino_id for future use when we support multiple boot images */ static void catalog_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id, @@ -636,7 +636,7 @@ IsoStreamIface catalog_stream_class = { }; /** - * Create an IsoStream for writing El-Torito catalog for a given target. + * Create an IsoStream for writing El-Torito catalog for a given target. */ static int catalog_stream_new(Ecma119Image *target, IsoStream **stream) @@ -675,17 +675,17 @@ int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src) int ret; IsoFileSrc *file; IsoStream *stream; - + if (target == NULL || src == NULL || target->catalog == NULL) { return ISO_OUT_OF_MEM; } - + if (target->cat != NULL) { /* catalog file src already created */ *src = target->cat; return ISO_SUCCESS; } - + file = malloc(sizeof(IsoFileSrc)); if (file == NULL) { return ISO_OUT_OF_MEM; @@ -696,10 +696,11 @@ int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src) free(file); return ret; } - + /* fill fields */ file->prev_img = 0; /* TODO allow copy of old img catalog???? */ - file->block = 0; /* to be filled later */ + file->nsections = 0; /* to be filled later */ + file->sections = NULL; file->sort_weight = 1000; /* slightly high */ file->stream = stream; @@ -746,34 +747,34 @@ 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->block, 4); - + iso_lsb(vol.boot_catalog, t->cat->sections[0].block, 4); + return iso_write(t, &vol, sizeof(struct ecma119_boot_rec_vol_desc)); } /** * Patch an isolinux boot image. - * + * * @return * 1 on success, 0 error (but continue), < 0 error */ -static +static int patch_boot_image(uint8_t *buf, Ecma119Image *t, size_t imgsize) { struct boot_info_table *info; uint32_t checksum; size_t offset; - + if (imgsize < 64) { return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0, "Isolinux image too small. We won't patch it."); } - + /* compute checksum, as the the sum of all 32 bit words in boot image * from offset 64 */ checksum = 0; offset = (size_t) 64; - + while (offset <= imgsize - 4) { checksum += iso_read_lsb(buf + offset, 4); offset += 4; @@ -783,12 +784,12 @@ int patch_boot_image(uint8_t *buf, Ecma119Image *t, size_t imgsize) return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0, "Unexpected isolinux image length. Patch might not work."); } - + /* patch boot info table */ info = (struct boot_info_table*)(buf + 8); /*memset(info, 0, sizeof(struct boot_info_table));*/ iso_lsb(info->bi_pvd, t->ms_block + 16, 4); - iso_lsb(info->bi_file, t->bootimg->block, 4); + iso_lsb(info->bi_file, t->bootimg->sections[0].block, 4); iso_lsb(info->bi_length, imgsize, 4); iso_lsb(info->bi_csum, checksum, 4); return ISO_SUCCESS; @@ -799,7 +800,7 @@ int eltorito_writer_write_data(IsoImageWriter *writer) { /* * We have nothing to write, but if we need to patch an isolinux image, - * this is a good place to do so. + * this is a good place to do so. */ Ecma119Image *t; int ret; @@ -809,7 +810,7 @@ int eltorito_writer_write_data(IsoImageWriter *writer) } t = writer->target; - + if (t->catalog->image->isolinux) { /* we need to patch the image */ size_t size; @@ -830,13 +831,13 @@ int eltorito_writer_write_data(IsoImageWriter *writer) if (ret != size) { return (ret < 0) ? ret : ISO_FILE_READ_ERROR; } - + /* ok, patch the read buffer */ ret = patch_boot_image(buf, t, size); if (ret < 0) { return ret; } - + /* replace the original stream with a memory stream that reads from * the patched buffer */ ret = iso_memory_stream_new(buf, size, &new); @@ -878,7 +879,7 @@ int eltorito_writer_create(Ecma119Image *target) /* add this writer to image */ target->writers[target->nwriters++] = writer; - /* + /* * get catalog and image file sources. * Note that the catalog may be already added, when creating the low * level ECMA-119 tree. @@ -895,7 +896,7 @@ int eltorito_writer_create(Ecma119Image *target) return ret; } target->bootimg = src; - + /* if we have selected to patch the image, it needs to be copied always */ if (target->catalog->image->isolinux) { src->prev_img = 0; diff --git a/libisofs/filesrc.c b/libisofs/filesrc.c index 2c57ce5..d7e79b7 100644 --- a/libisofs/filesrc.c +++ b/libisofs/filesrc.c @@ -1,8 +1,8 @@ /* * Copyright (c) 2007 Vreixo Formoso - * - * This file is part of the libisofs project; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as + * + * This file is part of the libisofs project; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. See COPYING file for details. */ @@ -61,20 +61,45 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src) iso_stream_get_id(file->stream, &fs_id, &dev_id, &ino_id); - fsrc = malloc(sizeof(IsoFileSrc)); + fsrc = calloc(1, sizeof(IsoFileSrc)); if (fsrc == NULL) { return ISO_OUT_OF_MEM; } /* fill key and other atts */ - fsrc->prev_img = file->msblock ? 1 : 0; - fsrc->block = file->msblock; + fsrc->prev_img = file->from_old_session; + if (file->from_old_session && img->appendable) { + /* + * On multisession discs we keep file sections from old image. + */ + int ret = iso_file_get_old_image_sections(file, &(fsrc->nsections), + &(fsrc->sections), 0); + if (ret < 0) { + free(fsrc); + return ISO_OUT_OF_MEM; + } + } else { + + /* + * For new files, or for image copy, we compute our own file sections. + * Block and size of each section will be filled later. + */ + off_t section_size = iso_stream_get_size(file->stream); + if (section_size > (off_t) MAX_ISO_FILE_SECTION_SIZE) { + fsrc->nsections = DIV_UP(section_size - (off_t) MAX_ISO_FILE_SECTION_SIZE, + (off_t)ISO_EXTENT_SIZE) + 1; + } else { + fsrc->nsections = 1; + } + fsrc->sections = calloc(fsrc->nsections, sizeof(struct iso_file_section)); + } fsrc->sort_weight = file->sort_weight; fsrc->stream = file->stream; /* insert the filesrc in the tree */ ret = iso_rbtree_insert(img->files, fsrc, (void**)src); if (ret <= 0) { + free(fsrc->sections); free(fsrc); return ret; } @@ -84,12 +109,12 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src) /** * Add a given IsoFileSrc to the given image target. - * - * The IsoFileSrc will be cached in a tree to prevent the same file for + * + * The IsoFileSrc will be cached in a tree to prevent the same file for * being written several times to image. If you call again this function * with a node that refers to the same source file, the previously * created one will be returned. - * + * * @param img * The image where this file is to be written * @param new @@ -97,7 +122,7 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src) * @param src * Will be filled with a pointer to the IsoFileSrc really present in * the tree. It could be different than new if the same file already - * exists in the tree. + * exists in the tree. * @return * 1 on success, 0 if file already exists on tree, < 0 error */ @@ -108,7 +133,7 @@ int iso_file_src_add(Ecma119Image *img, IsoFileSrc *new, IsoFileSrc **src) if (img == NULL || new == NULL || src == NULL) { return ISO_NULL_POINTER; } - + /* insert the filesrc in the tree */ ret = iso_rbtree_insert(img->files, new, (void**)src); return ret; @@ -117,6 +142,7 @@ int iso_file_src_add(Ecma119Image *img, IsoFileSrc *new, IsoFileSrc **src) void iso_file_src_free(void *node) { iso_stream_unref(((IsoFileSrc*)node)->stream); + free(((IsoFileSrc*)node)->sections); free(node); } @@ -160,7 +186,7 @@ int filesrc_writer_compute_data_blocks(IsoImageWriter *writer) } else { inc_item = NULL; } - + /* store the filesrcs in a array */ filelist = (IsoFileSrc**)iso_rbtree_to_array(t->files, inc_item, &size); if (filelist == NULL) { @@ -174,8 +200,23 @@ int filesrc_writer_compute_data_blocks(IsoImageWriter *writer) /* fill block value */ for (i = 0; i < size; ++i) { + int extent = 0; IsoFileSrc *file = filelist[i]; - file->block = t->curblock; + + off_t section_size = iso_stream_get_size(file->stream); + for (extent = 0; extent < file->nsections - 1; ++extent) { + file->sections[extent].block = t->curblock + extent * + (ISO_EXTENT_SIZE / BLOCK_SIZE); + file->sections[extent].size = ISO_EXTENT_SIZE; + section_size -= (off_t) ISO_EXTENT_SIZE; + } + + /* + * final section + */ + file->sections[extent].block = t->curblock + extent * (ISO_EXTENT_SIZE / BLOCK_SIZE); + file->sections[extent].size = (uint32_t)section_size; + t->curblock += DIV_UP(iso_file_src_get_size(file), BLOCK_SIZE); } @@ -259,22 +300,17 @@ int filesrc_writer_write_data(IsoImageWriter *writer) i = 0; while ((file = filelist[i++]) != NULL) { - /* - * TODO WARNING - * when we allow files greater than 4GB, current DIV_UP implementation - * can overflow!! - */ uint32_t nblocks = DIV_UP(iso_file_src_get_size(file), BLOCK_SIZE); res = filesrc_open(file); iso_stream_get_file_name(file->stream, name); if (res < 0) { - /* + /* * UPS, very ugly error, the best we can do is just to write * 0's to image */ iso_report_errfile(name, ISO_FILE_CANT_WRITE, 0, 0); - res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, res, + res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, res, "File \"%s\" can't be opened. Filling with 0s.", name); if (res < 0) { return res; /* aborted due to error severity */ @@ -290,7 +326,7 @@ int filesrc_writer_write_data(IsoImageWriter *writer) continue; } else if (res > 1) { iso_report_errfile(name, ISO_FILE_CANT_WRITE, 0, 0); - res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, 0, + res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, 0, "Size of file \"%s\" has changed. It will be %s", name, (res == 2 ? "truncated" : "padded with 0's")); if (res < 0) { @@ -338,7 +374,7 @@ int filesrc_writer_write_data(IsoImageWriter *writer) if (res < 0) { return res; /* aborted due error severity */ } - + /* fill with 0s */ iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, 0, "Filling with 0"); diff --git a/libisofs/filesrc.h b/libisofs/filesrc.h index 5a3c03c..88e4760 100644 --- a/libisofs/filesrc.h +++ b/libisofs/filesrc.h @@ -1,8 +1,8 @@ /* * Copyright (c) 2007 Vreixo Formoso - * - * This file is part of the libisofs project; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as + * + * This file is part of the libisofs project; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. See COPYING file for details. */ #ifndef LIBISO_FILESRC_H_ @@ -17,7 +17,11 @@ struct Iso_File_Src { unsigned int prev_img :1; /**< if the file comes from a previous image */ - uint32_t block; /**< Block where this file will be written on image */ + + /** File Sections of the file in the image */ + struct iso_file_section *sections; + int nsections; + int sort_weight; IsoStream *stream; }; @@ -26,12 +30,12 @@ int iso_file_src_cmp(const void *n1, const void *n2); /** * Create a new IsoFileSrc to get data from a specific IsoFile. - * - * The IsoFileSrc will be cached in a tree to prevent the same file for + * + * The IsoFileSrc will be cached in a tree to prevent the same file for * being written several times to image. If you call again this function * with a node that refers to the same source file, the previously * created one will be returned. No new IsoFileSrc is created in that case. - * + * * @param img * The image where this file is to be written * @param file @@ -45,12 +49,12 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src); /** * Add a given IsoFileSrc to the given image target. - * - * The IsoFileSrc will be cached in a tree to prevent the same file for + * + * The IsoFileSrc will be cached in a tree to prevent the same file for * being written several times to image. If you call again this function * with a node that refers to the same source file, the previously * created one will be returned. - * + * * @param img * The image where this file is to be written * @param new @@ -58,7 +62,7 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src); * @param src * Will be filled with a pointer to the IsoFileSrc really present in * the tree. It could be different than new if the same file already - * exists in the tree. + * exists in the tree. * @return * 1 on success, 0 if file already exists on tree, < 0 error */ @@ -76,7 +80,7 @@ off_t iso_file_src_get_size(IsoFileSrc *file); /** * Create a Writer for file contents. - * + * * It takes care of written the files in the correct order. */ int iso_file_src_writer_create(Ecma119Image *target); diff --git a/libisofs/fs_image.c b/libisofs/fs_image.c index 3387c65..4190580 100644 --- a/libisofs/fs_image.c +++ b/libisofs/fs_image.c @@ -1,8 +1,8 @@ /* * Copyright (c) 2007 Vreixo Formoso - * - * This file is part of the libisofs project; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as + * + * This file is part of the libisofs project; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. See COPYING file for details. */ @@ -48,8 +48,8 @@ */ struct iso_read_opts { - /** - * Block where the image begins, usually 0, can be different on a + /** + * Block where the image begins, usually 0, can be different on a * multisession disc. */ uint32_t block; @@ -58,18 +58,18 @@ struct iso_read_opts unsigned int nojoliet : 1; /*< Do not read Joliet extensions */ unsigned int noiso1999 : 1; /*< Do not read ISO 9660:1999 enhanced tree */ - /** - * When both Joliet and RR extensions are present, the RR tree is used. - * If you prefer using Joliet, set this to 1. + /** + * When both Joliet and RR extensions are present, the RR tree is used. + * If you prefer using Joliet, set this to 1. */ - unsigned int preferjoliet : 1; - + unsigned int preferjoliet : 1; + uid_t uid; /**< Default uid when no RR */ gid_t gid; /**< Default uid when no RR */ mode_t dir_mode; /**< Default mode when no RR (only permissions) */ mode_t file_mode; /* TODO #00024 : option to convert names to lower case for iso reading */ - + /** * Input charset for RR file names. NULL to use default locale charset. */ @@ -78,14 +78,14 @@ struct iso_read_opts /** * Return information for image. - * Both size, hasRR and hasJoliet will be filled by libisofs with suitable + * Both size, hasRR and hasJoliet will be filled by libisofs with suitable * values. */ struct iso_read_image_features { - /** - * Will be filled with the size (in 2048 byte block) of the image, as - * reported in the PVM. + /** + * Will be filled with the size (in 2048 byte block) of the image, as + * reported in the PVM. */ uint32_t size; @@ -95,9 +95,9 @@ struct iso_read_image_features /** It will be set to 1 if Joliet extensions are present, to 0 if not. */ unsigned int hasJoliet :1; - /** + /** * It will be set to 1 if the image is an ISO 9660:1999, i.e. it has - * a version 2 Enhanced Volume Descriptor. + * a version 2 Enhanced Volume Descriptor. */ unsigned int hasIso1999 :1; @@ -107,8 +107,8 @@ struct iso_read_image_features static int ifs_fs_open(IsoImageFilesystem *fs); static int ifs_fs_close(IsoImageFilesystem *fs); -static int iso_file_source_new_ifs(IsoImageFilesystem *fs, - IsoFileSource *parent, struct ecma119_dir_record *record, +static int iso_file_source_new_ifs(IsoImageFilesystem *fs, + IsoFileSource *parent, struct ecma119_dir_record *record, IsoFileSource **src); /** unique identifier for each image */ @@ -130,14 +130,14 @@ typedef struct { /** DataSource from where data will be read */ IsoDataSource *src; - + /** unique id for the each image (filesystem instance) */ unsigned int id; - /** + /** * Counter of the times the filesystem has been openned still pending of - * close. It is used to keep track of when we need to actually open or - * close the IsoDataSource. + * close. It is used to keep track of when we need to actually open or + * close the IsoDataSource. */ unsigned int open_count; @@ -151,7 +151,7 @@ typedef struct char *input_charset; /**< Input charset for RR names */ char *local_charset; /**< For RR names, will be set to the locale one */ - /** + /** * Will be filled with the block lba of the extend for the root directory * of the hierarchy that will be read, either from the PVD (ISO, RR) or * from the SVD (Joliet) @@ -177,14 +177,14 @@ typedef struct uint32_t evd_root_block; /** - * If we need to read RR extensions. i.e., if the image contains RR - * extensions, and the user wants to read them. + * If we need to read RR extensions. i.e., if the image contains RR + * extensions, and the user wants to read them. */ enum read_rr_ext rr; /** - * Bytes skipped within the System Use field of a directory record, before - * the beginning of the SUSP system user entries. See IEEE 1281, SUSP. 5.3. + * Bytes skipped within the System Use field of a directory record, before + * the beginning of the SUSP system user entries. See IEEE 1281, SUSP. 5.3. */ uint8_t len_skp; @@ -206,10 +206,10 @@ typedef struct * 0 no RR extension, 1 RRIP 1.10, 2 RRIP 1.12 */ enum read_rr_ext rr_version; - + /** If Joliet extensions are available on image */ unsigned int joliet : 1; - + /** If ISO 9660:1999 is available on image */ unsigned int iso1999 : 1; @@ -236,18 +236,23 @@ struct image_fs_data { IsoImageFilesystem *fs; /**< reference to the image it belongs to */ IsoFileSource *parent; /**< reference to the parent (NULL if root) */ - + struct stat info; /**< filled struct stat */ char *name; /**< name of this file */ - - uint32_t block; /**< block of the extend */ + + /** + * Location of file extents. + */ + struct iso_file_section *sections; + int nsections; + unsigned int opened : 2; /**< 0 not opened, 1 opened file, 2 opened dir */ - + /* info for content reading */ - struct + struct { /** - * - For regular files, once opened it points to a temporary data + * - For regular files, once opened it points to a temporary data * buffer of 2048 bytes. * - For dirs, once opened it points to a IsoFileSource* array with * its children @@ -285,7 +290,7 @@ char* ifs_get_path(IsoFileSource *src) { ImageFileSourceData *data; data = src->data; - + if (data->parent == NULL) { return strdup(""); } else { @@ -324,15 +329,15 @@ static int ifs_stat(IsoFileSource *src, struct stat *info) { ImageFileSourceData *data; - + if (src == NULL || info == NULL || src->data == NULL) { return ISO_NULL_POINTER; } data = (ImageFileSourceData*)src->data; - + if (S_ISLNK(data->info.st_mode)) { - /* TODO #00012 : support follow symlinks on image filesystem */ + /* TODO #00012 : support follow symlinks on image filesystem */ return ISO_FILE_BAD_PATH; } *info = data->info; @@ -349,7 +354,7 @@ int ifs_access(IsoFileSource *src) /** * Read all directory records in a directory, and creates an IsoFileSource for * each of them, storing them in the data field of the IsoFileSource for the - * given dir. + * given dir. */ static int read_dir(ImageFileSourceData *data) @@ -372,7 +377,8 @@ int read_dir(ImageFileSourceData *data) fs = data->fs; fsdata = fs->data; - block = data->block; + /* a dir has always a single extent */ + block = data->sections[0].block; ret = fsdata->src->read_block(fsdata->src, block, buffer); if (ret < 0) { return ret; @@ -393,9 +399,9 @@ int read_dir(ImageFileSourceData *data) record = (struct ecma119_dir_record *)(buffer + pos); if (pos == 2048 || record->len_dr[0] == 0) { - /* + /* * The directory entries are splitted in several blocks - * read next block + * read next block */ ret = fsdata->src->read_block(fsdata->src, ++block, buffer); if (ret < 0) { @@ -415,12 +421,12 @@ int read_dir(ImageFileSourceData *data) /* * For a extrange reason, mkisofs relocates directories under * a RR_MOVED dir. It seems that it is only used for that purposes, - * and thus it should be removed from the iso tree before + * and thus it should be removed from the iso tree before * generating a new image with libisofs, that don't uses it. */ if (data->parent == NULL && record->len_fi[0] == 8 && !strncmp((char*)record->file_id, "RR_MOVED", 8)) { - + iso_msg_debug(fsdata->msgid, "Skipping RR_MOVE entry."); tlen += record->len_dr[0]; @@ -429,16 +435,26 @@ int read_dir(ImageFileSourceData *data) } /* - * We pass a NULL parent instead of dir, to prevent the circular + * We pass a NULL parent instead of dir, to prevent the circular * reference from child to parent. */ ret = iso_file_source_new_ifs(fs, NULL, record, &child); if (ret < 0) { + if (child) { + /* + * This can only happen with multi-extent files. + */ + ImageFileSourceData *ifsdata = child->data; + free(ifsdata->sections); + free(ifsdata->name); + free(ifsdata); + free(child); + } return ret; } /* add to the child list */ - if (ret != 0) { + if (ret == 1) { struct child_list *node; node = malloc(sizeof(struct child_list)); if (node == NULL) { @@ -453,8 +469,9 @@ int read_dir(ImageFileSourceData *data) node->next = data->data.content; node->file = child; data->data.content = node; + child = NULL; } - + tlen += record->len_dr[0]; pos += record->len_dr[0]; } @@ -467,7 +484,7 @@ int ifs_open(IsoFileSource *src) { int ret; ImageFileSourceData *data; - + if (src == NULL || src->data == NULL) { return ISO_NULL_POINTER; } @@ -476,29 +493,29 @@ int ifs_open(IsoFileSource *src) if (data->opened) { return ISO_FILE_ALREADY_OPENED; } - + if (S_ISDIR(data->info.st_mode)) { /* ensure fs is openned */ ret = data->fs->open(data->fs); if (ret < 0) { return ret; } - - /* - * Cache all directory entries. + + /* + * Cache all directory entries. * This can waste more memory, but improves as disc is read in much more * sequencially way, thus reducing jump between tracks on disc */ ret = read_dir(data); data->fs->close(data->fs); - + if (ret < 0) { /* free probably allocated children */ child_list_free((struct child_list*)data->data.content); } else { data->opened = 2; } - + return ret; } else if (S_ISREG(data->info.st_mode)) { /* ensure fs is openned */ @@ -523,20 +540,20 @@ static int ifs_close(IsoFileSource *src) { ImageFileSourceData *data; - + if (src == NULL || src->data == NULL) { return ISO_NULL_POINTER; } data = (ImageFileSourceData*)src->data; - + if (!data->opened) { return ISO_FILE_NOT_OPENED; } - + if (data->opened == 2) { - /* + /* * close a dir, free all pending pre-allocated children. - * not that we don't need to close the filesystem, it was already + * not that we don't need to close the filesystem, it was already * closed */ child_list_free((struct child_list*) data->data.content); @@ -552,19 +569,89 @@ int ifs_close(IsoFileSource *src) /* TODO only dirs and files supported for now */ return ISO_ERROR; } - + return ISO_SUCCESS; } +/** + * Computes the block where the given offset should start. + */ +static +uint32_t block_from_offset(int nsections, struct iso_file_section *sections, + off_t offset) +{ + int section = 0; + off_t bytes = 0; + + do { + if ( (offset - bytes) < (off_t) sections[section].size ) { + return sections[section].block + (offset - bytes) / BLOCK_SIZE; + } else { + bytes += (off_t) sections[section].size; + section++; + } + + } while(section < nsections); + return 0; /* should never happen */ +} + +/** + * Get the size available for reading on the corresponding block + */ +static +uint32_t size_available(int nsections, struct iso_file_section *sections, + off_t offset) +{ + int section = 0; + off_t bytes = 0; + + do { + if ( (offset - bytes) < (off_t) sections[section].size ) { + uint32_t curr_section_offset = (uint32_t)(offset - bytes); + uint32_t curr_section_left = sections[section].size - curr_section_offset; + uint32_t available = BLOCK_SIZE - curr_section_offset % BLOCK_SIZE; + return MIN(curr_section_left, available); + } else { + bytes += (off_t) sections[section].size; + section++; + } + + } while(section < nsections); + return 0; /* should never happen */ +} + +/** + * Get the block offset for reading the given file offset + */ +static +uint32_t block_offset(int nsections, struct iso_file_section *sections, + off_t offset) +{ + int section = 0; + off_t bytes = 0; + + + do { + if ( (offset - bytes) < (off_t) sections[section].size ) { + return (uint32_t)(offset - bytes) % BLOCK_SIZE; + } else { + bytes += (off_t) sections[section].size; + section++; + } + + } while(section < nsections); + return 0; /* should never happen */ +} + /** * Attempts to read up to count bytes from the given source into * the buffer starting at buf. - * - * The file src must be open() before calling this, and close() when no + * + * The file src must be open() before calling this, and close() when no * more needed. Not valid for dirs. On symlinks it reads the destination * file. - * - * @return + * + * @return * number of bytes read, 0 if EOF, < 0 on error * Error codes: * ISO_FILE_ERROR @@ -580,7 +667,7 @@ int ifs_read(IsoFileSource *src, void *buf, size_t count) int ret; ImageFileSourceData *data; uint32_t read = 0; - + if (src == NULL || src->data == NULL || buf == NULL) { return ISO_NULL_POINTER; } @@ -588,43 +675,44 @@ int ifs_read(IsoFileSource *src, void *buf, size_t count) return ISO_WRONG_ARG_VALUE; } data = (ImageFileSourceData*)src->data; - + if (!data->opened) { return ISO_FILE_NOT_OPENED; } else if (data->opened != 1) { return ISO_FILE_IS_DIR; } - + while (read < count && data->data.offset < data->info.st_size) { size_t bytes; uint8_t *orig; - - if (data->data.offset % BLOCK_SIZE == 0) { + + if (block_offset(data->nsections, data->sections, data->data.offset) == 0) { /* we need to buffer next block */ uint32_t block; _ImageFsData *fsdata; - + if (data->data.offset >= data->info.st_size) { /* EOF */ break; } fsdata = data->fs->data; - block = data->block + (data->data.offset / BLOCK_SIZE); - ret = fsdata->src->read_block(fsdata->src, block, + block = block_from_offset(data->nsections, data->sections, + data->data.offset); + ret = fsdata->src->read_block(fsdata->src, block, data->data.content); if (ret < 0) { return ret; } } - + /* how much can I read */ - bytes = MIN(BLOCK_SIZE - (data->data.offset % BLOCK_SIZE), + bytes = MIN(size_available(data->nsections, data->sections, data->data.offset), count - read); if (data->data.offset + (off_t)bytes > data->info.st_size) { bytes = data->info.st_size - data->data.offset; } orig = data->data.content; - orig += data->data.offset % BLOCK_SIZE; + orig += block_offset(data->nsections, data->sections, data->data.offset); memcpy((uint8_t*)buf + read, orig, bytes); read += bytes; data->data.offset += (off_t)bytes; @@ -643,9 +731,9 @@ off_t ifs_lseek(IsoFileSource *src, off_t offset, int flag) if (offset < (off_t)0) { return (off_t)ISO_WRONG_ARG_VALUE; } - + data = src->data; - + if (!data->opened) { return (off_t)ISO_FILE_NOT_OPENED; } else if (data->opened != 1) { @@ -666,17 +754,22 @@ off_t ifs_lseek(IsoFileSource *src, off_t offset, int flag) default: return (off_t)ISO_WRONG_ARG_VALUE; } - - if (data->data.offset % BLOCK_SIZE != 0) { + + /* + * We check for block_offset != 0 because if it is already 0, the block + * will be read from image in the read function + */ + if (block_offset(data->nsections, data->sections, data->data.offset) != 0) { /* we need to buffer the block */ uint32_t block; _ImageFsData *fsdata; - + if (data->data.offset < data->info.st_size) { int ret; fsdata = data->fs->data; - block = data->block + (data->data.offset / BLOCK_SIZE); - ret = fsdata->src->read_block(fsdata->src, block, + block = block_from_offset(data->nsections, data->sections, + data->data.offset); + ret = fsdata->src->read_block(fsdata->src, block, data->data.content); if (ret < 0) { return (off_t)ret; @@ -691,31 +784,31 @@ int ifs_readdir(IsoFileSource *src, IsoFileSource **child) { ImageFileSourceData *data, *cdata; struct child_list *children; - + if (src == NULL || src->data == NULL || child == NULL) { return ISO_NULL_POINTER; } data = (ImageFileSourceData*)src->data; - + if (!data->opened) { return ISO_FILE_NOT_OPENED; } else if (data->opened != 2) { return ISO_FILE_IS_NOT_DIR; } - + /* return the first child and free it */ if (data->data.content == NULL) { return 0; /* EOF */ } - + children = (struct child_list*)data->data.content; *child = children->file; cdata = (ImageFileSourceData*)(*child)->data; - + /* set the ref to the parent */ cdata->parent = src; iso_file_source_ref(src); - + /* free the first element of the list */ data->data.content = children->next; free(children); @@ -726,14 +819,14 @@ int ifs_readdir(IsoFileSource *src, IsoFileSource **child) /** * Read the destination of a symlink. You don't need to open the file * to call this. - * - * @param buf - * allocated buffer of at least bufsiz bytes. + * + * @param buf + * allocated buffer of at least bufsiz bytes. * The dest. will be copied there, and it will be NULL-terminated * @param bufsiz * characters to be copied. Destination link will be truncated if * it is larger than given size. This include the \0 character. - * @return + * @return * 1 on success, < 0 on error * Error codes: * ISO_FILE_ERROR @@ -743,7 +836,7 @@ int ifs_readdir(IsoFileSource *src, IsoFileSource **child) * ISO_OUT_OF_MEM * ISO_FILE_BAD_PATH * ISO_FILE_DOESNT_EXIST - * + * */ static int ifs_readlink(IsoFileSource *src, char *buf, size_t bufsiz) @@ -751,30 +844,30 @@ int ifs_readlink(IsoFileSource *src, char *buf, size_t bufsiz) char *dest; size_t len; ImageFileSourceData *data; - + if (src == NULL || buf == NULL || src->data == NULL) { return ISO_NULL_POINTER; } - + if (bufsiz <= 0) { return ISO_WRONG_ARG_VALUE; } - + data = (ImageFileSourceData*)src->data; - + if (!S_ISLNK(data->info.st_mode)) { return ISO_FILE_IS_NOT_SYMLINK; } - + dest = (char*)data->data.content; len = strlen(dest); if (bufsiz <= len) { len = bufsiz - 1; } - + strncpy(buf, dest, len); buf[len] = '\0'; - + return ISO_SUCCESS; } @@ -811,11 +904,13 @@ void ifs_free(IsoFileSource *src) if (data->parent != NULL) { iso_file_source_unref(data->parent); } + + free(data->sections); free(data->name); free(data); } -IsoFileSourceIface ifs_class = { +IsoFileSourceIface ifs_class = { 0, /* version */ ifs_get_path, ifs_get_name, @@ -857,9 +952,9 @@ char *get_name(_ImageFsData *fsdata, const char *str, size_t len) /* fallback */ } } - + /* we reach here when the charset conversion is not needed or has failed */ - + name = malloc(len + 1); if (name == NULL) { return NULL; @@ -870,14 +965,18 @@ char *get_name(_ImageFsData *fsdata, const char *str, size_t len) } /** - * + * + * @param src + * if not-NULL, it points to a multi-extent file returned by a previous + * call to this function. * @return + * 2 node is still incomplete (multi-extent) * 1 success, 0 record ignored (not an error, can be a relocated dir), * < 0 error */ static -int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, - struct ecma119_dir_record *record, +int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, + struct ecma119_dir_record *record, IsoFileSource **src) { int ret; @@ -886,38 +985,29 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, _ImageFsData *fsdata; IsoFileSource *ifsrc = NULL; ImageFileSourceData *ifsdata = NULL; - + int namecont = 0; /* 1 if found a NM with CONTINUE flag */ char *name = NULL; - /* 1 if found a SL with CONTINUE flag, + /* 1 if found a SL with CONTINUE flag, * 2 if found a component with continue flag */ - int linkdestcont = 0; + int linkdestcont = 0; char *linkdest = NULL; - + uint32_t relocated_dir = 0; - + if (fs == NULL || fs->data == NULL || record == NULL || src == NULL) { return ISO_NULL_POINTER; } fsdata = (_ImageFsData*)fs->data; - + memset(&atts, 0, sizeof(struct stat)); - + /* * First of all, check for unsupported ECMA-119 features */ - /* check for unsupported multiextend */ - if (record->flags[0] & 0x80) { - iso_msg_submit(fsdata->msgid, ISO_UNSUPPORTED_ECMA119, 0, - "Unsupported image. This image makes use of Multi-Extend" - " features, that are not supported at this time. If you " - "need support for that, please request us this feature."); - return ISO_UNSUPPORTED_ECMA119; - } - /* check for unsupported interleaved mode */ if (record->file_unit_size[0] || record->interleave_gap_size[0]) { iso_msg_submit(fsdata->msgid, ISO_UNSUPPORTED_ECMA119, 0, @@ -927,7 +1017,7 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, "Please contact libisofs developers, so we can fix this."); return ISO_UNSUPPORTED_ECMA119; } - + /* * Check for extended attributes, that are not supported. Note that even * if we don't support them, it is easy to ignore them. @@ -939,32 +1029,107 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, return ISO_UNSUPPORTED_ECMA119; } - /* TODO #00013 : check for unsupported flags when reading a dir record */ - + /* TODO #00013 : check for unsupported flags when reading a dir record */ + + /* + * If src is not-NULL, it refers to more extents of this file. We ensure + * name matches, otherwise it means we are dealing with wrong image + */ + if (*src != NULL) { + ImageFileSourceData* data = (*src)->data; + char* new_name = get_name(fsdata, (char*)record->file_id, record->len_fi[0]); + if (new_name == NULL) { + iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0, + "Can't retrieve file name"); + return ISO_WRONG_ECMA119; + } + if (strcmp(new_name, data->name)) { + iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0, + "Multi-extent file lacks last entry."); + free(new_name); + return ISO_WRONG_ECMA119; + } + free(new_name); + } + + /* check for multi-extent */ + if (record->flags[0] & 0x80) { + iso_msg_debug(fsdata->msgid, "Found multi-extent file"); + + /* + * Directory entries can only have one section (ECMA-119, 6.8.1) + */ + if (record->flags[0] & 0x02) { + iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0, + "Directories with more than one section are not allowed."); + return ISO_WRONG_ECMA119; + } + + if (*src == NULL) { + ifsdata = calloc(1, sizeof(ImageFileSourceData)); + if (ifsdata == NULL) { + ret = ISO_OUT_OF_MEM; + goto ifs_cleanup; + } + ifsrc = calloc(1, sizeof(IsoFileSource)); + if (ifsrc == NULL) { + ret = ISO_OUT_OF_MEM; + goto ifs_cleanup; + } + ifsrc->data = ifsdata; + ifsdata->name = get_name(fsdata, (char*)record->file_id, record->len_fi[0]); + if (ifsdata->name == NULL) { + iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0, + "Can't retrieve file name"); + ret = ISO_WRONG_ECMA119; + goto ifs_cleanup; + } + + *src = ifsrc; + } else { + ifsdata = (*src)->data; + } + + /* store current extent */ + ifsdata->sections = realloc(ifsdata->sections, + (1 + ifsdata->nsections) * sizeof(struct iso_file_section)); + if (ifsdata->sections == NULL) { + free(ifsdata->name); + ret = ISO_OUT_OF_MEM; + goto ifs_cleanup; + } + ifsdata->sections[ifsdata->nsections].block = iso_read_bb(record->block, 4, NULL); + ifsdata->sections[ifsdata->nsections].size = iso_read_bb(record->length, 4, NULL); + + ifsdata->info.st_size += (off_t) ifsdata->sections[ifsdata->nsections].size; + ifsdata->nsections++; + return 2; + } + /* * The idea is to read all the RR entries (if we want to do that and RR - * extensions exist on image), storing the info we want from that. + * extensions exist on image), storing the info we want from that. * Then, we need some sanity checks. * Finally, we select what kind of node it is, and set values properly. */ - + if (fsdata->rr) { struct susp_sys_user_entry *sue; SuspIterator *iter; - - iter = susp_iter_new(fsdata->src, record, fsdata->len_skp, + + iter = susp_iter_new(fsdata->src, record, fsdata->len_skp, fsdata->msgid); if (iter == NULL) { return ISO_OUT_OF_MEM; } - + while ((ret = susp_iter_next(iter, &sue)) > 0) { - + /* ignore entries from different version */ if (sue->version[0] != 1) - continue; - + continue; + if (SUSP_SIG(sue, 'P', 'X')) { ret = read_rr_PX(sue, &atts); if (ret < 0) { @@ -1008,7 +1173,7 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, "Invalid SL entry"); } } else if (SUSP_SIG(sue, 'R', 'E')) { - /* + /* * this directory entry refers to a relocated directory. * We simply ignore it, as it will be correctly handled * when found the CL @@ -1020,8 +1185,8 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, /* * This entry is a placeholder for a relocated dir. * We need to ignore other entries, with the exception of NM. - * Then we create a directory node that represents the - * relocated dir, and iterate over its children. + * Then we create a directory node that represents the + * relocated dir, and iterate over its children. */ relocated_dir = iso_read_bb(sue->data.CL.child_loc, 4, NULL); if (relocated_dir == 0) { @@ -1044,7 +1209,7 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, /* TODO I've seen this RR on mkisofs images. what's this? */ continue; } else if (SUSP_SIG(sue, 'S', 'P')) { - /* + /* * Ignore this, to prevent the hint message, if we are dealing * with root node (SP is only valid in "." of root node) */ @@ -1056,7 +1221,7 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, } continue; } else if (SUSP_SIG(sue, 'E', 'R')) { - /* + /* * Ignore this, to prevent the hint message, if we are dealing * with root node (ER is only valid in "." of root node) */ @@ -1072,11 +1237,11 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, "Unhandled SUSP entry %c%c.", sue->sig[0], sue->sig[1]); } } - + susp_iter_free(iter); - + /* check for RR problems */ - + if (ret < 0) { /* error was already submitted above */ iso_msg_debug(fsdata->msgid, "Error parsing RR entries"); @@ -1095,12 +1260,12 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, "Incomplete link destination, last SL entry continues"); } } - + if (ret < 0) { free(name); return ret; } - + /* convert name to needed charset */ if (strcmp(fsdata->input_charset, fsdata->local_charset) && name) { /* we need to convert name charset */ @@ -1111,7 +1276,7 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, /* its just a hint message */ ret = iso_msg_submit(fsdata->msgid, ISO_FILENAME_WRONG_CHARSET, ret, "Charset conversion error. Can't " - "convert %s from %s to %s", name, + "convert %s from %s to %s", name, fsdata->input_charset, fsdata->local_charset); free(newname); if (ret < 0) { @@ -1123,17 +1288,17 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, name = newname; } } - - /* convert link destination to needed charset */ + + /* convert link destination to needed charset */ if (strcmp(fsdata->input_charset, fsdata->local_charset) && linkdest) { /* we need to convert name charset */ char *newlinkdest = NULL; - ret = strconv(linkdest, fsdata->input_charset, + ret = strconv(linkdest, fsdata->input_charset, fsdata->local_charset, &newlinkdest); if (ret < 0) { ret = iso_msg_submit(fsdata->msgid, ISO_FILENAME_WRONG_CHARSET, ret, "Charset conversion error. Can't " - "convert %s from %s to %s", name, + "convert %s from %s to %s", name, fsdata->input_charset, fsdata->local_charset); free(newlinkdest); if (ret < 0) { @@ -1145,7 +1310,7 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, linkdest = newlinkdest; } } - + } else { /* RR extensions are not read / used */ atts.st_gid = fsdata->gid; @@ -1156,14 +1321,14 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, atts.st_mode = S_IFREG | fsdata->file_mode; } } - - /* + + /* * if we haven't RR extensions, or no NM entry is present, * we use the name in directory record */ if (!name) { size_t len; - + if (record->len_fi[0] == 1 && record->file_id[0] == 0) { /* "." entry, we can call this for root node, so... */ if (!(atts.st_mode & S_IFDIR)) { @@ -1177,12 +1342,12 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, return iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0, "Can't retrieve file name"); } - + /* remove trailing version number */ len = strlen(name); if (len > 2 && name[len-2] == ';' && name[len-1] == '1') { if (len > 3 && name[len-3] == '.') { - /* + /* * the "." is mandatory, so in most cases is included only * for standard compliance */ @@ -1195,25 +1360,25 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, } if (relocated_dir) { - + /* * We are dealing with a placeholder for a relocated dir. - * Thus, we need to read attributes for this directory from the "." + * Thus, we need to read attributes for this directory from the "." * entry of the relocated dir. */ uint8_t buffer[BLOCK_SIZE]; - + ret = fsdata->src->read_block(fsdata->src, relocated_dir, buffer); if (ret < 0) { return ret; } - + ret = iso_file_source_new_ifs(fs, parent, (struct ecma119_dir_record*) buffer, src); if (ret <= 0) { return ret; } - + /* but the real name is the name of the placeholder */ ifsdata = (ImageFileSourceData*) (*src)->data; ifsdata->name = name; @@ -1231,8 +1396,8 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, atts.st_nlink = 1; } } - - /* + + /* * if we haven't RR extensions, or a needed TF time stamp is not present, * we use plain iso recording time */ @@ -1246,15 +1411,15 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, if (atts.st_mtime == (time_t) 0) { atts.st_mtime = recorded; } - + /* the size is read from iso directory record */ atts.st_size = iso_read_bb(record->length, 4, NULL); - + /* Fill last entries */ atts.st_dev = fsdata->id; atts.st_blksize = BLOCK_SIZE; atts.st_blocks = DIV_UP(atts.st_size, BLOCK_SIZE); - + /* TODO #00014 : more sanity checks to ensure dir record info is valid */ if (S_ISLNK(atts.st_mode) && (linkdest == NULL)) { ret = iso_msg_submit(fsdata->msgid, ISO_WRONG_RR, 0, @@ -1262,19 +1427,26 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, free(name); return ret; } - + /* ok, we can now create the file source */ - ifsdata = calloc(1, sizeof(ImageFileSourceData)); - if (ifsdata == NULL) { - ret = ISO_OUT_OF_MEM; - goto ifs_cleanup; + if (*src == NULL) { + ifsdata = calloc(1, sizeof(ImageFileSourceData)); + if (ifsdata == NULL) { + ret = ISO_OUT_OF_MEM; + goto ifs_cleanup; + } + ifsrc = calloc(1, sizeof(IsoFileSource)); + if (ifsrc == NULL) { + ret = ISO_OUT_OF_MEM; + goto ifs_cleanup; + } + } else { + ifsdata = (*src)->data; + ifsrc = (*src); + free(ifsdata->name); /* we will assign a new one */ + atts.st_size += (off_t)ifsdata->info.st_size; } - ifsrc = calloc(1, sizeof(IsoFileSource)); - if (ifsrc == NULL) { - ret = ISO_OUT_OF_MEM; - goto ifs_cleanup; - } - + /* fill data */ ifsdata->fs = fs; iso_filesystem_ref(fs); @@ -1284,19 +1456,30 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, } ifsdata->info = atts; ifsdata->name = name; - ifsdata->block = iso_read_bb(record->block, 4, NULL); - + + /* save extents */ + ifsdata->sections = realloc(ifsdata->sections, + (1 + ifsdata->nsections) * sizeof(struct iso_file_section)); + if (ifsdata->sections == NULL) { + free(ifsdata->name); + ret = ISO_OUT_OF_MEM; + goto ifs_cleanup; + } + ifsdata->sections[ifsdata->nsections].block = iso_read_bb(record->block, 4, NULL); + ifsdata->sections[ifsdata->nsections].size = iso_read_bb(record->length, 4, NULL); + ifsdata->nsections++; + if (S_ISLNK(atts.st_mode)) { ifsdata->data.content = linkdest; } - + ifsrc->class = &ifs_class; ifsrc->data = ifsdata; ifsrc->refcount = 1; - + *src = ifsrc; return ISO_SUCCESS; - + ifs_cleanup: ; free(name); free(linkdest); @@ -1332,6 +1515,7 @@ int ifs_get_root(IsoFilesystem *fs, IsoFileSource **root) } /* get root attributes from "." entry */ + *root = NULL; ret = iso_file_source_new_ifs((IsoImageFilesystem*)fs, NULL, (struct ecma119_dir_record*) buffer, root); @@ -1341,7 +1525,7 @@ int ifs_get_root(IsoFilesystem *fs, IsoFileSource **root) /** * Find a file inside a node. - * + * * @param file * it is not modified if requested file is not found * @return @@ -1383,7 +1567,7 @@ int ifs_get_by_path(IsoFilesystem *fs, const char *path, IsoFileSource **file) if (fs == NULL || fs->data == NULL || path == NULL || file == NULL) { return ISO_NULL_POINTER; } - + if (path[0] != '/') { /* only absolute paths supported */ return ISO_FILE_BAD_PATH; @@ -1396,7 +1580,7 @@ int ifs_get_by_path(IsoFilesystem *fs, const char *path, IsoFileSource **file) if (ret < 0) { return ret; } - + ret = ifs_get_root(fs, &src); if (ret < 0) { return ret; @@ -1414,11 +1598,11 @@ int ifs_get_by_path(IsoFilesystem *fs, const char *path, IsoFileSource **file) ret = ISO_OUT_OF_MEM; goto get_path_exit; } - + component = strtok_r(ptr, "/", &brk_info); while (component) { IsoFileSource *child = NULL; - + ImageFileSourceData *fdata; fdata = src->data; if (!S_ISDIR(fdata->info.st_mode)) { @@ -1431,7 +1615,7 @@ int ifs_get_by_path(IsoFilesystem *fs, const char *path, IsoFileSource **file) if (ret <= 0) { break; } - + src = child; component = strtok_r(NULL, "/", &brk_info); } @@ -1529,13 +1713,13 @@ void ifs_fs_free(IsoFilesystem *fs) } /** - * Read the SUSP system user entries of the "." entry of the root directory, + * Read the SUSP system user entries of the "." entry of the root directory, * indentifying when Rock Ridge extensions are being used. - * + * * @return * 1 success, 0 ignored, < 0 error */ -static +static int read_root_susp_entries(_ImageFsData *data, uint32_t block) { int ret; @@ -1548,10 +1732,10 @@ int read_root_susp_entries(_ImageFsData *data, uint32_t block) if (ret < 0) { return ret; } - + /* record will be the "." directory entry for the root record */ record = (struct ecma119_dir_record *)buffer; - + /* * TODO #00015 : take care of CD-ROM XA discs when reading SP entry * SUSP specification claims that for CD-ROM XA the SP entry @@ -1563,7 +1747,7 @@ int read_root_susp_entries(_ImageFsData *data, uint32_t block) if (iter == NULL) { return ISO_OUT_OF_MEM; } - + /* first entry must be an SP system use entry */ ret = susp_iter_next(iter, &sue); if (ret < 0) { @@ -1575,7 +1759,7 @@ int read_root_susp_entries(_ImageFsData *data, uint32_t block) susp_iter_free(iter); return ISO_SUCCESS; } - + /* it is a SP system use entry */ if (sue->version[0] != 1 || sue->data.SP.be[0] != 0xBE || sue->data.SP.ef[0] != 0xEF) { @@ -1585,9 +1769,9 @@ int read_root_susp_entries(_ImageFsData *data, uint32_t block) "SUSP SP system use entry seems to be wrong. " "Ignoring Rock Ridge Extensions."); } - + iso_msg_debug(data->msgid, "SUSP/RR is being used."); - + /* * The LEN_SKP field, defined in IEEE 1281, SUSP. 5.3, specifies the * number of bytes to be skipped within each System Use field. @@ -1595,13 +1779,13 @@ int read_root_susp_entries(_ImageFsData *data, uint32_t block) * feature is easy... */ data->len_skp = sue->data.SP.len_skp[0]; - + /* * Ok, now search for ER entry. * Just notice that the attributes for root dir are read elsewhere. - * - * TODO #00016 : handle non RR ER entries - * + * + * TODO #00016 : handle non RR ER entries + * * if several ER are present, we need to identify the position of * what refers to RR, and then look for corresponding ES entry in * each directory record. I have not implemented this (it's not used, @@ -1609,13 +1793,13 @@ int read_root_susp_entries(_ImageFsData *data, uint32_t block) * the iterator, transparently for the rest of the code. */ while ((ret = susp_iter_next(iter, &sue)) > 0) { - + /* ignore entries from different version */ if (sue->version[0] != 1) - continue; - + continue; + if (SUSP_SIG(sue, 'E', 'R')) { - + if (data->rr_version) { ret = iso_msg_submit(data->msgid, ISO_SUSP_MULTIPLE_ER, 0, "More than one ER has found. This is not supported. " @@ -1626,23 +1810,23 @@ int read_root_susp_entries(_ImageFsData *data, uint32_t block) } } - /* + /* * it seems that Rock Ridge can be identified with any - * of the following + * of the following */ - if ( sue->data.ER.len_id[0] == 10 && + if ( sue->data.ER.len_id[0] == 10 && !strncmp((char*)sue->data.ER.ext_id, "RRIP_1991A", 10) ) { - - iso_msg_debug(data->msgid, + + iso_msg_debug(data->msgid, "Suitable Rock Ridge ER found. Version 1.10."); data->rr_version = RR_EXT_110; - - } else if ( (sue->data.ER.len_id[0] == 10 && - !strncmp((char*)sue->data.ER.ext_id, "IEEE_P1282", 10)) - || (sue->data.ER.len_id[0] == 9 && + + } else if ( (sue->data.ER.len_id[0] == 10 && + !strncmp((char*)sue->data.ER.ext_id, "IEEE_P1282", 10)) + || (sue->data.ER.len_id[0] == 9 && !strncmp((char*)sue->data.ER.ext_id, "IEEE_1282", 9)) ) { - - iso_msg_debug(data->msgid, + + iso_msg_debug(data->msgid, "Suitable Rock Ridge ER found. Version 1.12."); data->rr_version = RR_EXT_112; } else { @@ -1656,13 +1840,13 @@ int read_root_susp_entries(_ImageFsData *data, uint32_t block) } } } - - susp_iter_free(iter); - - if (ret < 0) { + + susp_iter_free(iter); + + if (ret < 0) { return ret; } - + return ISO_SUCCESS; } @@ -1711,9 +1895,9 @@ int read_pvm(_ImageFsData *data, uint32_t block) /* * TODO #00017 : take advantage of other atts of PVD - * PVD has other things that could be interesting, but that don't have a - * member in IsoImage, such as creation date. In a multisession disc, we - * could keep the creation date and update the modification date, for + * PVD has other things that could be interesting, but that don't have a + * member in IsoImage, such as creation date. In a multisession disc, we + * could keep the creation date and update the modification date, for * example. */ @@ -1736,30 +1920,30 @@ int read_el_torito_boot_catalog(_ImageFsData *data, uint32_t block) if (ret < 0) { return ret; } - + ve = (struct el_torito_validation_entry*)buffer; - + /* check if it is a valid catalog (TODO: check also the checksum)*/ - if ( (ve->header_id[0] != 1) || (ve->key_byte1[0] != 0x55) + if ( (ve->header_id[0] != 1) || (ve->key_byte1[0] != 0x55) || (ve->key_byte2[0] != 0xAA) ) { - + return iso_msg_submit(data->msgid, ISO_WRONG_EL_TORITO, 0, "Wrong or damaged El-Torito Catalog. El-Torito info " "will be ignored."); } - + /* check for a valid platform */ if (ve->platform_id[0] != 0) { return iso_msg_submit(data->msgid, ISO_UNSUPPORTED_EL_TORITO, 0, "Unsupported El-Torito platform. Only 80x86 is " "supported. El-Torito info will be ignored."); } - + /* ok, once we are here we assume it is a valid catalog */ - + /* parse the default entry */ entry = (struct el_torito_default_entry *)(buffer + 32); - + data->eltorito = 1; data->bootable = entry->boot_indicator[0] ? 1 : 0; data->type = entry->boot_media_type[0]; @@ -1804,14 +1988,14 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts, /* get an id for the filesystem */ data->id = ++fs_dev_id; - + /* fill data from opts */ data->gid = opts->gid; data->uid = opts->uid; data->file_mode = opts->file_mode & ~S_IFMT; data->dir_mode = opts->dir_mode & ~S_IFMT; data->msgid = msgid; - + setlocale(LC_CTYPE, ""); data->local_charset = strdup(nl_langinfo(CODESET)); if (data->local_charset == NULL) { @@ -1858,12 +2042,12 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts, /* some sanity checks */ if (strncmp((char*)vol->std_identifier, "CD001", 5) - || vol->vol_desc_version[0] != 1 - || strncmp((char*)vol->boot_sys_id, + || vol->vol_desc_version[0] != 1 + || strncmp((char*)vol->boot_sys_id, "EL TORITO SPECIFICATION", 23)) { - ret = iso_msg_submit(data->msgid, - ISO_UNSUPPORTED_EL_TORITO, 0, + ret = iso_msg_submit(data->msgid, + ISO_UNSUPPORTED_EL_TORITO, 0, "Unsupported Boot Vol. Desc. Only El-Torito " "Specification, Version 1.0 Volume " "Descriptors are supported. Ignoring boot info"); @@ -1884,14 +2068,14 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts, { struct ecma119_sup_vol_desc *sup; struct ecma119_dir_record *root; - + sup = (struct ecma119_sup_vol_desc*)buffer; - if (sup->esc_sequences[0] == 0x25 && + if (sup->esc_sequences[0] == 0x25 && sup->esc_sequences[1] == 0x2F && (sup->esc_sequences[2] == 0x40 || sup->esc_sequences[2] == 0x43 || sup->esc_sequences[2] == 0x45) ) { - + /* it's a Joliet Sup. Vol. Desc. */ iso_msg_debug(data->msgid, "Found Joliet extensions"); data->joliet = 1; @@ -1901,7 +2085,7 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts, /* TODO #00020 : handle RR info in Joliet tree */ } else if (sup->vol_desc_version[0] == 2) { /* - * It is an Enhanced Volume Descriptor, image is an + * It is an Enhanced Volume Descriptor, image is an * ISO 9660:1999 */ iso_msg_debug(data->msgid, "Found ISO 9660:1999"); @@ -1919,7 +2103,7 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts, } break; case 255: - /* + /* * volume set terminator * ignore, as it's checked in loop end condition */ @@ -1940,7 +2124,7 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts, if (ret < 0) { goto fs_cleanup; } - + /* user doesn't want to read RR extensions */ if (opts->norock) { data->rr = RR_EXT_NO; @@ -1992,7 +2176,7 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts, ret = ISO_OUT_OF_MEM; goto fs_cleanup; } - + /* and finally return. Note that we keep the DataSource opened */ *fs = ifs; @@ -2034,9 +2218,10 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image, { /* source is a regular file */ _ImageFsData *fsdata = data->fs->data; - - if (fsdata->eltorito && data->block == fsdata->catblock) { - + + /* El-Torito images have only one section */ + if (fsdata->eltorito && data->sections[0].block == fsdata->catblock) { + if (image->bootcat->node != NULL) { ret = iso_msg_submit(image->id, ISO_EL_TORITO_WARN, 0, "More than one catalog node has been found. " @@ -2047,7 +2232,7 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image, } iso_node_unref((IsoNode*)image->bootcat->node); } - + /* we create a placeholder for the catalog instead of * a regular file */ new = calloc(1, sizeof(IsoBoot)); @@ -2056,7 +2241,7 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image, free(name); return ret; } - + /* and set the image node */ image->bootcat->node = (IsoBoot*)new; new->type = LIBISO_BOOT; @@ -2064,7 +2249,7 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image, } else { IsoStream *stream; IsoFile *file; - + ret = iso_file_source_stream_new(src, &stream); if (ret < 0) { free(name); @@ -2079,22 +2264,22 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image, iso_stream_unref(stream); return ISO_OUT_OF_MEM; } - - /* the msblock is taken from the image */ - file->msblock = data->block; - - /* + + /* mark file as from old session */ + file->from_old_session = 1; + + /* * and we set the sort weight based on the block on image, to * improve performance on image modifying. - */ - file->sort_weight = INT_MAX - data->block; - + */ + file->sort_weight = INT_MAX - data->sections[0].block; + file->stream = stream; file->node.type = LIBISO_FILE; new = (IsoNode*) file; new->refcount = 0; - - if (fsdata->eltorito && data->block == fsdata->imgblock) { + + if (fsdata->eltorito && data->sections[0].block == fsdata->imgblock) { /* it is boot image node */ if (image->bootcat->image->image != NULL) { ret = iso_msg_submit(image->id, ISO_EL_TORITO_WARN, 0, @@ -2217,7 +2402,7 @@ int iso_image_builder_new(IsoNodeBuilder *old, IsoNodeBuilder **builder) /** * Create a file source to access the El-Torito boot image, when it is not - * accessible from the ISO filesystem. + * accessible from the ISO filesystem. */ static int create_boot_img_filesrc(IsoImageFilesystem *fs, IsoFileSource **src) @@ -2227,31 +2412,31 @@ int create_boot_img_filesrc(IsoImageFilesystem *fs, IsoFileSource **src) _ImageFsData *fsdata; IsoFileSource *ifsrc = NULL; ImageFileSourceData *ifsdata = NULL; - + if (fs == NULL || fs->data == NULL || src == NULL) { return ISO_NULL_POINTER; } fsdata = (_ImageFsData*)fs->data; - + memset(&atts, 0, sizeof(struct stat)); atts.st_mode = S_IFREG; atts.st_ino = fsdata->imgblock; /* not the best solution, but... */ atts.st_nlink = 1; - /* + /* * this is the greater problem. We don't know the size. For now, we * just use a single block of data. In a future, maybe we could figure out * a better idea. Another alternative is to use several blocks, that way - * is less probable that we throw out valid data. + * is less probable that we throw out valid data. */ atts.st_size = (off_t)BLOCK_SIZE; - + /* Fill last entries */ atts.st_dev = fsdata->id; atts.st_blksize = BLOCK_SIZE; atts.st_blocks = DIV_UP(atts.st_size, BLOCK_SIZE); - + /* ok, we can now create the file source */ ifsdata = calloc(1, sizeof(ImageFileSourceData)); if (ifsdata == NULL) { @@ -2263,22 +2448,31 @@ int create_boot_img_filesrc(IsoImageFilesystem *fs, IsoFileSource **src) ret = ISO_OUT_OF_MEM; goto boot_fs_cleanup; } - + + ifsdata->sections = malloc(sizeof(struct iso_file_section)); + if (ifsdata->sections == NULL) { + ret = ISO_OUT_OF_MEM; + goto boot_fs_cleanup; + } + /* fill data */ ifsdata->fs = fs; iso_filesystem_ref(fs); ifsdata->parent = NULL; ifsdata->info = atts; ifsdata->name = NULL; - ifsdata->block = fsdata->imgblock; + + ifsdata->sections[0].block = fsdata->imgblock; + ifsdata->sections[0].size = BLOCK_SIZE; + ifsdata->nsections = 1; ifsrc->class = &ifs_class; ifsrc->data = ifsdata; ifsrc->refcount = 1; - + *src = ifsrc; return ISO_SUCCESS; - + boot_fs_cleanup: ; free(ifsdata); free(ifsrc); @@ -2287,7 +2481,7 @@ boot_fs_cleanup: ; int iso_image_import(IsoImage *image, IsoDataSource *src, - struct iso_read_opts *opts, + struct iso_read_opts *opts, IsoReadImageFeatures **features) { int ret; @@ -2298,37 +2492,37 @@ int iso_image_import(IsoImage *image, IsoDataSource *src, IsoFileSource *newroot; _ImageFsData *data; struct el_torito_boot_catalog *oldbootcat; - + if (image == NULL || src == NULL || opts == NULL) { return ISO_NULL_POINTER; } - + ret = iso_image_filesystem_new(src, opts, image->id, &fs); if (ret < 0) { return ret; } data = fs->data; - + /* get root from filesystem */ ret = fs->get_root(fs, &newroot); if (ret < 0) { return ret; } - + /* backup image filesystem, builder and root */ fsback = image->fs; blback = image->builder; oldroot = image->root; oldbootcat = image->bootcat; /* could be NULL */ - + image->bootcat = NULL; - + /* create new builder */ ret = iso_image_builder_new(blback, &image->builder); if (ret < 0) { goto import_revert; } - + image->fs = fs; /* create new root, and set root attributes from source */ @@ -2348,12 +2542,12 @@ int iso_image_import(IsoImage *image, IsoDataSource *src, image->root->node.mtime = info.st_mtime; image->root->node.ctime = info.st_ctime; } - + /* if old image has el-torito, add a new catalog */ if (data->eltorito) { struct el_torito_boot_catalog *catalog; ElToritoBootImage *boot_image= NULL; - + boot_image = calloc(1, sizeof(ElToritoBootImage)); if (boot_image == NULL) { ret = ISO_OUT_OF_MEM; @@ -2364,7 +2558,7 @@ int iso_image_import(IsoImage *image, IsoDataSource *src, boot_image->partition_type = data->partition_type; boot_image->load_seg = data->load_seg; boot_image->load_size = data->load_size; - + catalog = calloc(1, sizeof(struct el_torito_boot_catalog)); if (catalog == NULL) { ret = ISO_OUT_OF_MEM; @@ -2399,9 +2593,9 @@ int iso_image_import(IsoImage *image, IsoDataSource *src, goto import_revert; } image->bootcat->image->image = (IsoFile*)node; - + /* warn about hidden images */ - iso_msg_submit(image->id, ISO_EL_TORITO_HIDDEN, 0, + iso_msg_submit(image->id, ISO_EL_TORITO_HIDDEN, 0, "Found hidden El-Torito image. Its size could not " "be figure out, so image modify or boot image " "patching may lead to bad results."); @@ -2420,7 +2614,7 @@ int iso_image_import(IsoImage *image, IsoDataSource *src, } iso_node_builder_unref(image->builder); - + /* free old root */ iso_node_unref((IsoNode*)oldroot); @@ -2450,7 +2644,7 @@ int iso_image_import(IsoImage *image, IsoDataSource *src, (*features)->hasElTorito = data->eltorito; (*features)->size = data->nblocks; } - + ret = ISO_SUCCESS; goto import_cleanup; @@ -2467,11 +2661,11 @@ int iso_image_import(IsoImage *image, IsoDataSource *src, /* recover backed fs and builder */ image->fs = fsback; image->builder = blback; - + iso_file_source_unref(newroot); fs->close(fs); iso_filesystem_unref(fs); - + return ret; } @@ -2533,19 +2727,19 @@ const char *iso_image_fs_get_biblio_file_id(IsoImageFilesystem *fs) int iso_read_opts_new(IsoReadOpts **opts, int profile) { IsoReadOpts *ropts; - + if (opts == NULL) { return ISO_NULL_POINTER; } if (profile != 0) { return ISO_WRONG_ARG_VALUE; } - + ropts = calloc(1, sizeof(IsoReadOpts)); if (ropts == NULL) { return ISO_OUT_OF_MEM; } - + ropts->file_mode = 0444; ropts->dir_mode = 0555; *opts = ropts; @@ -2557,7 +2751,7 @@ void iso_read_opts_free(IsoReadOpts *opts) if (opts == NULL) { return; } - + free(opts->input_charset); free(opts); } @@ -2656,7 +2850,7 @@ void iso_read_image_features_destroy(IsoReadImageFeatures *f) } /** - * Get the size (in 2048 byte block) of the image, as reported in the PVM. + * Get the size (in 2048 byte block) of the image, as reported in the PVM. */ uint32_t iso_read_image_features_get_size(IsoReadImageFeatures *f) { @@ -2681,7 +2875,7 @@ int iso_read_image_features_has_joliet(IsoReadImageFeatures *f) /** * Whether the image is recorded according to ISO 9660:1999, i.e. it has - * a version 2 Enhanced Volume Descriptor. + * a version 2 Enhanced Volume Descriptor. */ int iso_read_image_features_has_iso1999(IsoReadImageFeatures *f) { @@ -2695,3 +2889,54 @@ int iso_read_image_features_has_eltorito(IsoReadImageFeatures *f) { return f->hasElTorito; } + + +/** + * Get the start addresses and the sizes of the data extents of a file node + * if it was imported from an old image. + * + * @param file + * The file + * @param section_count + * Returns the number of extent entries in sections arrays + * @param sections + * Returns the array of file sections. Apply free() to dispose it. + * @param flag + * Reserved for future usage, submit 0 + * @return + * 1 if there are valid extents (file comes from old image), + * 0 if file was newly added, i.e. it does not come from an old image, + * < 0 error + */ +int iso_file_get_old_image_sections(IsoFile *file, int *section_count, + struct iso_file_section **sections, + int flag) +{ + if (file == NULL || section_count == NULL || sections == NULL) { + return ISO_NULL_POINTER; + } + if (flag != 0) { + return ISO_WRONG_ARG_VALUE; + } + if (file->from_old_session != 0) { + + /* + * When file is from old session, we retrieve the original IsoFileSource + * to get the sections. This break encapsultation, but safes memory as + * we don't need to store the sections in the IsoFile node. + */ + FSrcStreamData *data = file->stream->data; + ImageFileSourceData *ifsdata = data->src->data; + + *section_count = ifsdata->nsections; + *sections = malloc(ifsdata->nsections * + sizeof(struct iso_file_section)); + if (*sections == NULL) { + return ISO_OUT_OF_MEM; + } + memcpy(*sections, ifsdata->sections, + ifsdata->nsections * sizeof(struct iso_file_section)); + return 1; + } + return 0; +} diff --git a/libisofs/iso1999.c b/libisofs/iso1999.c index fe62597..bc38ab6 100644 --- a/libisofs/iso1999.c +++ b/libisofs/iso1999.c @@ -117,7 +117,7 @@ int create_node(Ecma119Image *t, IsoNode *iso, Iso1999Node **node) IsoFile *file = (IsoFile*) iso; size = iso_stream_get_size(file->stream); - if (size > (off_t)0xffffffff) { + if (size > (off_t)MAX_ISO_FILE_SECTION_SIZE && t->iso_level != 3) { char *ipath = iso_tree_get_node_path(iso); ret = iso_msg_submit(t->image->id, ISO_FILE_TOO_BIG, 0, "File \"%s\" can't be added to image because is " @@ -557,14 +557,19 @@ size_t calc_dir_size(Ecma119Image *t, Iso1999Node *dir) for (i = 0; i < dir->info.dir->nchildren; ++i) { size_t remaining; + int section, nsections; Iso1999Node *child = dir->info.dir->children[i]; size_t dirent_len = calc_dirent_len(t, child); - remaining = BLOCK_SIZE - (len % BLOCK_SIZE); - if (dirent_len > remaining) { - /* child directory entry doesn't fit on block */ - len += remaining + dirent_len; - } else { - len += dirent_len; + + nsections = (child->type == ISO1999_FILE) ? child->info.file->nsections : 1; + for (section = 0; section < nsections; ++section) { + remaining = BLOCK_SIZE - (len % BLOCK_SIZE); + if (dirent_len > remaining) { + /* child directory entry doesn't fit on block */ + len += remaining + dirent_len; + } else { + len += dirent_len; + } } } @@ -663,11 +668,12 @@ int iso1999_writer_compute_data_blocks(IsoImageWriter *writer) */ static void write_one_dir_record(Ecma119Image *t, Iso1999Node *node, int file_id, - uint8_t *buf, size_t len_fi) + uint8_t *buf, size_t len_fi, int extent) { uint32_t len; uint32_t block; uint8_t len_dr; /*< size of dir entry */ + int multi_extend = 0; uint8_t *name = (file_id >= 0) ? (uint8_t*)&file_id : (uint8_t*)node->name; @@ -682,8 +688,9 @@ void write_one_dir_record(Ecma119Image *t, Iso1999Node *node, int file_id, len = node->info.dir->len; block = node->info.dir->block; } else if (node->type == ISO1999_FILE) { - len = iso_file_src_get_size(node->info.file); - block = node->info.file->block; + block = node->info.file->sections[extent].block; + len = node->info.file->sections[extent].size; + multi_extend = (node->info.file->nsections - 1 == extent) ? 0 : 1; } else { /* * for nodes other than files and dirs, we set both @@ -703,7 +710,7 @@ void write_one_dir_record(Ecma119Image *t, Iso1999Node *node, int file_id, iso_bb(rec->block, block, 4); iso_bb(rec->length, len, 4); iso_datetime_7(rec->recording_time, t->now, t->always_gmt); - rec->flags[0] = (node->type == ISO1999_DIR) ? 2 : 0; + rec->flags[0] = ((node->type == ISO1999_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0); iso_bb(rec->vol_seq_number, 1, 2); rec->len_fi[0] = len_fi; } @@ -762,7 +769,7 @@ int iso1999_writer_write_vol_desc(IsoImageWriter *writer) iso_lsb(vol.l_path_table_pos, t->iso1999_l_path_table_pos, 4); iso_msb(vol.m_path_table_pos, t->iso1999_m_path_table_pos, 4); - write_one_dir_record(t, t->iso1999_root, 0, vol.root_dir_record, 1); + write_one_dir_record(t, t->iso1999_root, 0, vol.root_dir_record, 1, 0); strncpy_pad((char*)vol.vol_set_id, volset_id, 128); strncpy_pad((char*)vol.publisher_id, pub_id, 128); @@ -809,30 +816,34 @@ int write_one_dir(Ecma119Image *t, Iso1999Node *dir) memset(buffer, 0, BLOCK_SIZE); /* write the "." and ".." entries first */ - write_one_dir_record(t, dir, 0, buf, 1); + write_one_dir_record(t, dir, 0, buf, 1, 0); buf += 34; - write_one_dir_record(t, dir, 1, buf, 1); + write_one_dir_record(t, dir, 1, buf, 1, 0); buf += 34; for (i = 0; i < dir->info.dir->nchildren; i++) { + int section, nsections; Iso1999Node *child = dir->info.dir->children[i]; /* compute len of directory entry */ fi_len = strlen(child->name); len = fi_len + 33 + (fi_len % 2 ? 0 : 1); - if ( (buf + len - buffer) > BLOCK_SIZE) { - /* dir doesn't fit in current block */ - ret = iso_write(t, buffer, BLOCK_SIZE); - if (ret < 0) { - return ret; + nsections = (child->type == ISO1999_FILE) ? child->info.file->nsections : 1; + for (section = 0; section < nsections; ++section) { + if ( (buf + len - buffer) > BLOCK_SIZE) { + /* dir doesn't fit in current block */ + ret = iso_write(t, buffer, BLOCK_SIZE); + if (ret < 0) { + return ret; + } + memset(buffer, 0, BLOCK_SIZE); + buf = buffer; } - memset(buffer, 0, BLOCK_SIZE); - buf = buffer; + /* write the directory entry in any case */ + write_one_dir_record(t, child, -1, buf, fi_len, section); + buf += len; } - /* write the directory entry in any case */ - write_one_dir_record(t, child, -1, buf, fi_len); - buf += len; } /* write the last block */ diff --git a/libisofs/joliet.c b/libisofs/joliet.c index d3053b9..f1d17f0 100644 --- a/libisofs/joliet.c +++ b/libisofs/joliet.c @@ -111,7 +111,7 @@ int create_node(Ecma119Image *t, IsoNode *iso, JolietNode **node) IsoFile *file = (IsoFile*) iso; size = iso_stream_get_size(file->stream); - if (size > (off_t)0xffffffff) { + if (size > (off_t)MAX_ISO_FILE_SECTION_SIZE && t->iso_level != 3) { char *ipath = iso_tree_get_node_path(iso); free(joliet); ret = iso_msg_submit(t->image->id, ISO_FILE_TOO_BIG, 0, @@ -590,14 +590,19 @@ size_t calc_dir_size(Ecma119Image *t, JolietNode *dir) for (i = 0; i < dir->info.dir->nchildren; ++i) { size_t remaining; + int section, nsections; JolietNode *child = dir->info.dir->children[i]; size_t dirent_len = calc_dirent_len(t, child); - remaining = BLOCK_SIZE - (len % BLOCK_SIZE); - if (dirent_len > remaining) { - /* child directory entry doesn't fit on block */ - len += remaining + dirent_len; - } else { - len += dirent_len; + + nsections = (child->type == JOLIET_FILE) ? child->info.file->nsections : 1; + for (section = 0; section < nsections; ++section) { + remaining = BLOCK_SIZE - (len % BLOCK_SIZE); + if (dirent_len > remaining) { + /* child directory entry doesn't fit on block */ + len += remaining + dirent_len; + } else { + len += dirent_len; + } } } @@ -696,11 +701,12 @@ int joliet_writer_compute_data_blocks(IsoImageWriter *writer) */ static void write_one_dir_record(Ecma119Image *t, JolietNode *node, int file_id, - uint8_t *buf, size_t len_fi) + uint8_t *buf, size_t len_fi, int extent) { uint32_t len; uint32_t block; uint8_t len_dr; /*< size of dir entry */ + int multi_extend = 0; uint8_t *name = (file_id >= 0) ? (uint8_t*)&file_id : (uint8_t*)node->name; @@ -723,8 +729,9 @@ void write_one_dir_record(Ecma119Image *t, JolietNode *node, int file_id, len = node->info.dir->len; block = node->info.dir->block; } else if (node->type == JOLIET_FILE) { - len = iso_file_src_get_size(node->info.file); - block = node->info.file->block; + block = node->info.file->sections[extent].block; + len = node->info.file->sections[extent].size; + multi_extend = (node->info.file->nsections - 1 == extent) ? 0 : 1; } else { /* * for nodes other than files and dirs, we set both @@ -744,7 +751,7 @@ void write_one_dir_record(Ecma119Image *t, JolietNode *node, int file_id, iso_bb(rec->block, block, 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; + rec->flags[0] = ((node->type == JOLIET_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0); iso_bb(rec->vol_seq_number, 1, 2); rec->len_fi[0] = len_fi; } @@ -827,7 +834,7 @@ int joliet_writer_write_vol_desc(IsoImageWriter *writer) 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); + 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); @@ -874,12 +881,13 @@ int write_one_dir(Ecma119Image *t, JolietNode *dir) memset(buffer, 0, BLOCK_SIZE); /* write the "." and ".." entries first */ - write_one_dir_record(t, dir, 0, buf, 1); + write_one_dir_record(t, dir, 0, buf, 1, 0); buf += 34; - write_one_dir_record(t, dir, 1, buf, 1); + write_one_dir_record(t, dir, 1, buf, 1, 0); buf += 34; for (i = 0; i < dir->info.dir->nchildren; i++) { + int section, nsections; JolietNode *child = dir->info.dir->children[i]; /* compute len of directory entry */ @@ -889,18 +897,23 @@ int write_one_dir(Ecma119Image *t, JolietNode *dir) len += 4; } - if ( (buf + len - buffer) > BLOCK_SIZE) { - /* dir doesn't fit in current block */ - ret = iso_write(t, buffer, BLOCK_SIZE); - if (ret < 0) { - return ret; + nsections = (child->type == JOLIET_FILE) ? child->info.file->nsections : 1; + + for (section = 0; section < nsections; ++section) { + + if ( (buf + len - buffer) > BLOCK_SIZE) { + /* dir doesn't fit in current block */ + ret = iso_write(t, buffer, BLOCK_SIZE); + if (ret < 0) { + return ret; + } + memset(buffer, 0, BLOCK_SIZE); + buf = buffer; } - memset(buffer, 0, BLOCK_SIZE); - buf = buffer; + /* write the directory entry in any case */ + write_one_dir_record(t, child, -1, buf, fi_len, section); + buf += len; } - /* write the directory entry in any case */ - write_one_dir_record(t, child, -1, buf, fi_len); - buf += len; } /* write the last block */ diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index cff2416..891925a 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -107,6 +107,17 @@ enum IsoNodeType { #define ISO_NODE(n) ((IsoNode*)n) +/** + * File section in an old image. + * + * @since 0.6.8 + */ +struct iso_file_section +{ + uint32_t block; + uint32_t size; +}; + /** * Context for iterate on directory children. * @see iso_dir_get_children() @@ -917,7 +928,7 @@ int iso_lib_is_compatible(int major, int minor, int micro); * start point from which to set your custom options. * ---> 1 [BACKUP] * POSIX compatibility for backup. Simple settings, ISO level is set to - * 2 and RR extensions are enabled. Useful for backup purposes. + * 3 and RR extensions are enabled. Useful for backup purposes. * ---> 2 [DISTRIBUTION] * Setting for information distribution. Both RR and Joliet are enabled * to maximize compatibility with most systems. Permissions are set to @@ -943,6 +954,7 @@ void iso_write_opts_free(IsoWriteOpts *opts); * -> 1 for higher compatibility with old systems. With this level * filenames are restricted to 8.3 characters. * -> 2 to allow up to 31 filename characters. + * -> 3 to allow files greater than 4GB * @return * 1 success, < 0 error * @@ -2551,9 +2563,35 @@ IsoStream *iso_file_get_stream(IsoFile *file); * added, i.e. it does not come from an old image, < 0 error * * @since 0.6.4 + * + * @deprecated Use iso_file_get_old_image_sections(), as this function does + * not work with multi-extend files. */ int iso_file_get_old_image_lba(IsoFile *file, uint32_t *lba, int flag); +/** + * Get the start addresses and the sizes of the data extents of a file node + * if it was imported from an old image. + * + * @param file + * The file + * @param section_count + * Returns the number of extent entries in sections array. + * @param sections + * Returns the array of file sections. Apply free() to dispose it. + * @param flag + * Reserved for future usage, submit 0 + * @return + * 1 if there are valid extents (file comes from old image), + * 0 if file was newly added, i.e. it does not come from an old image, + * < 0 error + * + * @since 0.6.8 + */ +int iso_file_get_old_image_sections(IsoFile *file, int *section_count, + struct iso_file_section **sections, + int flag); + /* * Like iso_file_get_old_image_lba(), but take an IsoNode. * diff --git a/libisofs/node.c b/libisofs/node.c index f1b26f9..3345adf 100644 --- a/libisofs/node.c +++ b/libisofs/node.c @@ -1,8 +1,8 @@ /* * Copyright (c) 2007 Vreixo Formoso - * - * This file is part of the libisofs project; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as + * + * This file is part of the libisofs project; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. See COPYING file for details. */ @@ -16,12 +16,12 @@ #include struct dir_iter_data -{ +{ /* points to the last visited child, to NULL before start */ IsoNode *pos; - + /* Some control flags. - * bit 0 -> 1 if next called, 0 reseted at start or on deletion + * bit 0 -> 1 if next called, 0 reseted at start or on deletion */ int flag; }; @@ -74,7 +74,7 @@ void iso_node_unref(IsoNode *node) IsoExtendedInfo *info = node->xinfo; while (info != NULL) { IsoExtendedInfo *tmp = info->next; - + /* free extended info */ info->process(info->data, 1); free(info); @@ -87,17 +87,17 @@ void iso_node_unref(IsoNode *node) } /** - * Add extended information to the given node. Extended info allows + * Add extended information to the given node. Extended info allows * applications (and libisofs itself) to add more information to an IsoNode. * You can use this facilities to associate new information with a given * node. - * + * * Each node keeps a list of added extended info, meaning you can add several * extended info data to each node. Each extended info you add is identified * by the proc parameter, a pointer to a function that knows how to manage * the external info data. Thus, in order to add several types of extended * info, you need to define a "proc" function for each type. - * + * * @param node * The node where to add the extended info * @param proc @@ -125,7 +125,7 @@ int iso_node_add_xinfo(IsoNode *node, iso_node_xinfo_func proc, void *data) } pos = pos->next; } - + info = malloc(sizeof(IsoExtendedInfo)); if (info == NULL) { return ISO_OUT_OF_MEM; @@ -140,8 +140,8 @@ int iso_node_add_xinfo(IsoNode *node, iso_node_xinfo_func proc, void *data) /** * Remove the given extended info (defined by the proc function) from the * given node. - * - * @return + * + * @return * 1 on success, 0 if node does not have extended info of the requested * type, < 0 on error */ @@ -152,14 +152,14 @@ int iso_node_remove_xinfo(IsoNode *node, iso_node_xinfo_func proc) if (node == NULL || proc == NULL) { return ISO_NULL_POINTER; } - + prev = NULL; pos = node->xinfo; while (pos != NULL) { if (pos->process == proc) { /* this is the extended info we want to remove */ pos->process(pos->data, 1); - + if (prev != NULL) { prev->next = pos->next; } else { @@ -172,17 +172,17 @@ int iso_node_remove_xinfo(IsoNode *node, iso_node_xinfo_func proc) pos = pos->next; } /* requested xinfo not found */ - return 0; + return 0; } /** * Get the given extended info (defined by the proc function) from the * given node. - * + * * @param data * Will be filled with the extended info corresponding to the given proc * function - * @return + * @return * 1 on success, 0 if node does not have extended info of the requested * type, < 0 on error */ @@ -193,7 +193,7 @@ int iso_node_get_xinfo(IsoNode *node, iso_node_xinfo_func proc, void **data) if (node == NULL || proc == NULL || data == NULL) { return ISO_NULL_POINTER; } - + pos = node->xinfo; while (pos != NULL) { if (pos->process == proc) { @@ -204,7 +204,7 @@ int iso_node_get_xinfo(IsoNode *node, iso_node_xinfo_func proc, void **data) pos = pos->next; } /* requested xinfo not found */ - return 0; + return 0; } /** @@ -217,7 +217,7 @@ enum IsoNodeType iso_node_get_type(IsoNode *node) /** * Set the name of a node. - * + * * @param name The name in UTF-8 encoding */ int iso_node_set_name(IsoNode *node, const char *name) @@ -228,7 +228,7 @@ int iso_node_set_name(IsoNode *node, const char *name) /* you can't change name of the root node */ return ISO_WRONG_ARG_VALUE; } - + /* check if the name is valid */ if (!iso_node_is_valid_name(name)) { return ISO_WRONG_ARG_VALUE; @@ -272,10 +272,10 @@ const char *iso_node_get_name(const IsoNode *node) } /** - * Set the permissions for the node. This attribute is only useful when + * Set the permissions for the node. This attribute is only useful when * Rock Ridge extensions are enabled. - * - * @param mode + * + * @param mode * bitmask with the permissions of the node, as specified in 'man 2 stat'. * The file type bitfields will be ignored, only file permissions will be * modified. @@ -285,15 +285,15 @@ void iso_node_set_permissions(IsoNode *node, mode_t mode) node->mode = (node->mode & S_IFMT) | (mode & ~S_IFMT); } -/** - * Get the permissions for the node +/** + * Get the permissions for the node */ mode_t iso_node_get_permissions(const IsoNode *node) { return node->mode & ~S_IFMT; } -/** +/** * Get the mode of the node, both permissions and file type, as specified in * 'man 2 stat'. */ @@ -303,7 +303,7 @@ mode_t iso_node_get_mode(const IsoNode *node) } /** - * Set the user id for the node. This attribute is only useful when + * Set the user id for the node. This attribute is only useful when * Rock Ridge extensions are enabled. */ void iso_node_set_uid(IsoNode *node, uid_t uid) @@ -320,7 +320,7 @@ uid_t iso_node_get_uid(const IsoNode *node) } /** - * Set the group id for the node. This attribute is only useful when + * Set the group id for the node. This attribute is only useful when * Rock Ridge extensions are enabled. */ void iso_node_set_gid(IsoNode *node, gid_t gid) @@ -336,7 +336,7 @@ gid_t iso_node_get_gid(const IsoNode *node) return node->gid; } -/** +/** * Set the time of last modification of the file */ void iso_node_set_mtime(IsoNode *node, time_t time) @@ -344,7 +344,7 @@ void iso_node_set_mtime(IsoNode *node, time_t time) node->mtime = time; } -/** +/** * Get the time of last modification of the file */ time_t iso_node_get_mtime(const IsoNode *node) @@ -352,7 +352,7 @@ time_t iso_node_get_mtime(const IsoNode *node) return node->mtime; } -/** +/** * Set the time of last access to the file */ void iso_node_set_atime(IsoNode *node, time_t time) @@ -360,24 +360,24 @@ void iso_node_set_atime(IsoNode *node, time_t time) node->atime = time; } -/** - * Get the time of last access to the file +/** + * Get the time of last access to the file */ time_t iso_node_get_atime(const IsoNode *node) { return node->atime; } -/** - * Set the time of last status change of the file +/** + * Set the time of last status change of the file */ void iso_node_set_ctime(IsoNode *node, time_t time) { node->ctime = time; } -/** - * Get the time of last status change of the file +/** + * Get the time of last status change of the file */ time_t iso_node_get_ctime(const IsoNode *node) { @@ -397,21 +397,21 @@ void iso_node_set_hidden(IsoNode *node, int hide_attrs) * the node, so you don't need to free it, it will be automatically freed * when the dir is deleted. Of course, if you want to keep using the node * after the dir life, you need to iso_node_ref() it. - * - * @param dir + * + * @param dir * the dir where to add the node - * @param child + * @param child * the node to add. You must ensure that the node hasn't previously added * to other dir, and that the node name is unique inside the child. * Otherwise this function will return a failure, and the child won't be * inserted. * @param replace * if the dir already contains a node with the same name, whether to - * replace or not the old node with this. + * replace or not the old node with this. * @return * number of nodes in dir if succes, < 0 otherwise */ -int iso_dir_add_node(IsoDir *dir, IsoNode *child, +int iso_dir_add_node(IsoDir *dir, IsoNode *child, enum iso_replace_mode replace) { IsoNode **pos; @@ -423,7 +423,7 @@ int iso_dir_add_node(IsoDir *dir, IsoNode *child, return ISO_WRONG_ARG_VALUE; } - /* + /* * check if child is already added to another dir, or if child * is the root node, where parent == itself */ @@ -437,17 +437,17 @@ int iso_dir_add_node(IsoDir *dir, IsoNode *child, /** * Locate a node inside a given dir. - * + * * @param name * The name of the node * @param node - * Location for a pointer to the node, it will filled with NULL if the dir + * Location for a pointer to the node, it will filled with NULL if the dir * doesn't have a child with the given name. * The node will be owned by the dir and shouldn't be unref(). Just call * iso_node_ref() to get your own reference to the node. * Note that you can pass NULL is the only thing you want to do is check * if a node with such name already exists on dir. - * @return + * @return * 1 node found, 0 child has no such node, < 0 error * Possible errors: * ISO_NULL_POINTER, if dir or name are NULL @@ -476,7 +476,7 @@ int iso_dir_get_node(IsoDir *dir, const char *name, IsoNode **node) /** * Get the number of children of a directory. - * + * * @return * >= 0 number of items, < 0 error * Possible errors: @@ -497,12 +497,12 @@ int iter_next(IsoDirIter *iter, IsoNode **node) if (iter == NULL || node == NULL) { return ISO_NULL_POINTER; } - + data = iter->data; - + /* clear next flag */ data->flag &= ~0x01; - + if (data->pos == NULL) { /* we are at the beginning */ data->pos = iter->dir->children; @@ -529,12 +529,12 @@ int iter_next(IsoDirIter *iter, IsoNode **node) data->pos = data->pos->next; } } - + /* ok, take a ref to the current position, to prevent internal errors * if deleted somewhere */ iso_node_ref(data->pos); data->flag |= 0x01; /* set next flag */ - + /* return pointed node */ *node = data->pos; return ISO_SUCCESS; @@ -542,7 +542,7 @@ int iter_next(IsoDirIter *iter, IsoNode **node) /** * Check if there're more children. - * + * * @return * 1 dir has more elements, 0 no, < 0 error * Possible errors: @@ -589,8 +589,8 @@ static IsoNode** iso_dir_find_node(IsoDir *dir, IsoNode *node) * The child is not freed, so you will become the owner of the node. Later * you can add the node to another dir (calling iso_dir_add_node), or free * it if you don't need it (with iso_node_unref). - * - * @return + * + * @return * 1 on success, < 0 error */ int iso_node_take(IsoNode *node) @@ -610,10 +610,10 @@ int iso_node_take(IsoNode *node) /* should never occur */ return ISO_ASSERT_FAILURE; } - + /* notify iterators just before remove */ - iso_notify_dir_iters(node, 0); - + iso_notify_dir_iters(node, 0); + *pos = node->next; node->parent = NULL; node->next = NULL; @@ -626,8 +626,8 @@ int iso_node_take(IsoNode *node) * If you want to keep the child alive, you need to iso_node_ref() it * before this call, but in that case iso_node_take() is a better * alternative. - * - * @return + * + * @return * 1 on success, < 0 error */ int iso_node_remove(IsoNode *node) @@ -644,10 +644,10 @@ int iso_node_remove(IsoNode *node) * Get the parent of the given iso tree node. No extra ref is added to the * returned directory, you must take your ref. with iso_node_ref() if you * need it. - * + * * If node is the root node, the same node will be returned as its parent. - * - * This returns NULL if the node doesn't pertain to any tree + * + * This returns NULL if the node doesn't pertain to any tree * (it was removed/take). */ IsoDir *iso_node_get_parent(IsoNode *node) @@ -663,20 +663,20 @@ int iter_take(IsoDirIter *iter) if (iter == NULL) { return ISO_NULL_POINTER; } - + data = iter->data; - + if (!(data->flag & 0x01)) { return ISO_ERROR; /* next not called or end of dir */ } - + if (data->pos == NULL) { return ISO_ASSERT_FAILURE; } - + /* clear next flag */ data->flag &= ~0x01; - + return iso_node_take(data->pos); } @@ -686,13 +686,13 @@ int iter_remove(IsoDirIter *iter) int ret; IsoNode *pos; struct dir_iter_data *data; - + if (iter == NULL) { return ISO_NULL_POINTER; } data = iter->data; pos = data->pos; - + ret = iter_take(iter); if (ret == ISO_SUCCESS) { /* remove node */ @@ -706,8 +706,8 @@ void iter_notify_child_taken(IsoDirIter *iter, IsoNode *node) IsoNode *pos, *pre; struct dir_iter_data *data; data = iter->data; - - if (data->pos == node) { + + if (data->pos == node) { pos = iter->dir->children; pre = NULL; while (pos != NULL && pos != data->pos) { @@ -717,10 +717,10 @@ void iter_notify_child_taken(IsoDirIter *iter, IsoNode *node) if (pos == NULL || pos != data->pos) { return; } - + /* dispose iterator reference */ iso_node_unref(data->pos); - + if (pre == NULL) { /* node is a first position */ iter->dir->children = pos->next; @@ -766,7 +766,7 @@ int iso_dir_get_children(const IsoDir *dir, IsoDirIter **iter) data->pos = NULL; data->flag = 0x00; it->data = data; - + if (iso_dir_iter_register(it) < 0) { free(it); return ISO_OUT_OF_MEM; @@ -808,7 +808,7 @@ int iso_dir_iter_take(IsoDirIter *iter) if (iter == NULL) { return ISO_NULL_POINTER; } - return iter->class->take(iter); + return iter->class->take(iter); } int iso_dir_iter_remove(IsoDirIter *iter) @@ -816,7 +816,7 @@ int iso_dir_iter_remove(IsoDirIter *iter) if (iter == NULL) { return ISO_NULL_POINTER; } - return iter->class->remove(iter); + return iter->class->remove(iter); } /** @@ -851,13 +851,13 @@ int iso_symlink_set_dest(IsoSymlink *link, const char *dest) /** * Sets the order in which a node will be written on image. High weihted files * will be written first, so in a disc them will be written near the center. - * - * @param node - * The node which weight will be changed. If it's a dir, this function - * will change the weight of all its children. For nodes other that dirs + * + * @param node + * The node which weight will be changed. If it's a dir, this function + * will change the weight of all its children. For nodes other that dirs * or regular files, this function has no effect. - * @param w - * The weight as a integer number, the greater this value is, the + * @param w + * The weight as a integer number, the greater this value is, the * closer from the begining of image the file will be written. */ void iso_node_set_sort_weight(IsoNode *node, int w) @@ -881,8 +881,8 @@ int iso_file_get_sort_weight(IsoFile *file) return file->sort_weight; } -/** - * Get the size of the file, in bytes +/** + * Get the size of the file, in bytes */ off_t iso_file_get_size(IsoFile *file) { @@ -891,9 +891,9 @@ off_t iso_file_get_size(IsoFile *file) /** * Get the IsoStream that represents the contents of the given IsoFile. - * + * * If you open() the stream, it should be close() before image generation. - * + * * @return * The IsoStream. No extra ref is added, so the IsoStream belong to the * IsoFile, and it may be freed together with it. Add your own ref with @@ -921,7 +921,7 @@ dev_t iso_special_get_dev(IsoSpecial *special) /** * Get the block lba of a file node, if it was imported from an old image. - * + * * @param file * The file * @param lba @@ -930,31 +930,39 @@ dev_t iso_special_get_dev(IsoSpecial *special) * Reserved for future usage, submit 0 * @return * 1 if lba is valid (file comes from old image), 0 if file was newly - * added, i.e. it does not come from an old image, < 0 error + * added, i.e. it does not come from an old image, < 0 error * * @since 0.6.4 */ int iso_file_get_old_image_lba(IsoFile *file, uint32_t *lba, int flag) { + int ret; + int section_count; + struct iso_file_section *sections; if (file == NULL || lba == NULL) { return ISO_NULL_POINTER; } - if (flag != 0) { + ret = iso_file_get_old_image_sections(file, §ion_count, §ions, flag); + if (ret <= 0) { + return ret; + } + if (section_count != 1) { + free(sections); return ISO_WRONG_ARG_VALUE; } - if (file->msblock != 0) { - *lba = file->msblock; - return 1; - } + *lba = sections[0].block; + free(sections); return 0; } + + /* * Like iso_file_get_old_image_lba(), but take an IsoNode. - * + * * @return * 1 if lba is valid (file comes from old image), 0 if file was newly - * added, i.e. it does not come from an old image, 2 node type has no + * added, i.e. it does not come from an old image, 2 node type has no * LBA (no regular file), < 0 error * * @since 0.6.4 @@ -973,7 +981,7 @@ int iso_node_get_old_image_lba(IsoNode *node, uint32_t *lba, int flag) /** * Check if a given name is valid for an iso node. - * + * * @return * 1 if yes, 0 if not */ @@ -1003,7 +1011,7 @@ int iso_node_is_valid_name(const char *name) /** * Check if a given path is valid for the destination of a link. - * + * * @return * 1 if yes, 0 if not */ @@ -1021,18 +1029,18 @@ int iso_node_is_valid_link_dest(const char *dest) if (dest[0] == '\0' || strlen(dest) > PATH_MAX) { return 0; } - + /* check that all components are valid */ if (!strcmp(dest, "/")) { /* "/" is a valid component */ return 1; } - + ptr = strdup(dest); if (ptr == NULL) { return 0; } - + ret = 1; component = strtok_r(ptr, "/", &brk_info); while (component) { @@ -1054,13 +1062,13 @@ void iso_dir_find(IsoDir *dir, const char *name, IsoNode ***pos) *pos = &(dir->children); while (**pos != NULL && strcmp((**pos)->name, name) < 0) { *pos = &((**pos)->next); - } + } } int iso_dir_exists(IsoDir *dir, const char *name, IsoNode ***pos) { IsoNode **node; - + iso_dir_find(dir, name, &node); if (pos) { *pos = node; @@ -1068,7 +1076,7 @@ int iso_dir_exists(IsoDir *dir, const char *name, IsoNode ***pos) return (*node != NULL && !strcmp((*node)->name, name)) ? 1 : 0; } -int iso_dir_insert(IsoDir *dir, IsoNode *node, IsoNode **pos, +int iso_dir_insert(IsoDir *dir, IsoNode *node, IsoNode **pos, enum iso_replace_mode replace) { if (*pos != NULL && !strcmp((*pos)->name, node->name)) { @@ -1100,7 +1108,7 @@ int iso_dir_insert(IsoDir *dir, IsoNode *node, IsoNode **pos, /* CAN'T HAPPEN */ return ISO_ASSERT_FAILURE; } - + /* if we are reach here we have to replace */ node->next = (*pos)->next; (*pos)->parent = NULL; @@ -1130,7 +1138,7 @@ struct iter_reg_node *iter_reg = NULL; /** * Add a new iterator to the registry. The iterator register keeps track of - * all iterators being used, and are notified when directory structure + * all iterators being used, and are notified when directory structure * changes. */ int iso_dir_iter_register(IsoDirIter *iter) @@ -1163,7 +1171,7 @@ void iso_dir_iter_unregister(IsoDirIter *iter) } } -void iso_notify_dir_iters(IsoNode *node, int flag) +void iso_notify_dir_iters(IsoNode *node, int flag) { struct iter_reg_node *pos = iter_reg; while (pos != NULL) { @@ -1197,11 +1205,11 @@ int iso_node_new_root(IsoDir **root) int iso_node_new_dir(char *name, IsoDir **dir) { IsoDir *new; - + if (dir == NULL || name == NULL) { return ISO_NULL_POINTER; } - + /* check if the name is valid */ if (!iso_node_is_valid_name(name)) { return ISO_WRONG_ARG_VALUE; @@ -1222,11 +1230,11 @@ int iso_node_new_dir(char *name, IsoDir **dir) int iso_node_new_file(char *name, IsoStream *stream, IsoFile **file) { IsoFile *new; - + if (file == NULL || name == NULL || stream == NULL) { return ISO_NULL_POINTER; } - + /* check if the name is valid */ if (!iso_node_is_valid_name(name)) { return ISO_WRONG_ARG_VALUE; @@ -1249,16 +1257,16 @@ int iso_node_new_file(char *name, IsoStream *stream, IsoFile **file) int iso_node_new_symlink(char *name, char *dest, IsoSymlink **link) { IsoSymlink *new; - + if (link == NULL || name == NULL || dest == NULL) { return ISO_NULL_POINTER; } - + /* check if the name is valid */ if (!iso_node_is_valid_name(name)) { return ISO_WRONG_ARG_VALUE; } - + /* check if destination is valid */ if (!iso_node_is_valid_link_dest(dest)) { /* guard against null or empty dest */ @@ -1278,18 +1286,18 @@ int iso_node_new_symlink(char *name, char *dest, IsoSymlink **link) return ISO_SUCCESS; } -int iso_node_new_special(char *name, mode_t mode, dev_t dev, +int iso_node_new_special(char *name, mode_t mode, dev_t dev, IsoSpecial **special) { IsoSpecial *new; - + if (special == NULL || name == NULL) { return ISO_NULL_POINTER; } if (S_ISLNK(mode) || S_ISREG(mode) || S_ISDIR(mode)) { return ISO_WRONG_ARG_VALUE; } - + /* check if the name is valid */ if (!iso_node_is_valid_name(name)) { return ISO_WRONG_ARG_VALUE; diff --git a/libisofs/node.h b/libisofs/node.h index 993051c..7d5471b 100644 --- a/libisofs/node.h +++ b/libisofs/node.h @@ -1,8 +1,8 @@ /* * Copyright (c) 2007 Vreixo Formoso - * - * This file is part of the libisofs project; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as + * + * This file is part of the libisofs project; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. See COPYING file for details. */ #ifndef LIBISO_NODE_H_ @@ -22,12 +22,12 @@ /** * The extended information is a way to attach additional information to each - * IsoNode. External applications may want to use this extension system to + * IsoNode. External applications may want to use this extension system to * store application speficic information related to each node. On the other * side, libisofs may make use of this struct to attach information to nodes in * some particular, uncommon, cases, without incrementing the size of the * IsoNode struct. - * + * * It is implemented like a chained list. */ typedef struct iso_extended_info IsoExtendedInfo; @@ -37,23 +37,23 @@ struct iso_extended_info { * Next struct in the chain. NULL if it is the last item */ IsoExtendedInfo *next; - + /** * Function to handle this particular extended information. The function * pointer acts as an identifier for the type of the information. Structs * with same information type must use the same function. - * + * * @param data * Attached data * @param flag - * What to do with the data. At this time the following values are + * What to do with the data. At this time the following values are * defined: * -> 1 the data must be freed * @return * 1 */ iso_node_xinfo_func process; - + /** * Pointer to information specific data. */ @@ -61,15 +61,15 @@ struct iso_extended_info { }; /** - * + * */ struct Iso_Node { /* * Initilized to 1, originally owned by user, until added to another node. - * Then it is owned by the parent node, so the user must take his own ref + * Then it is owned by the parent node, so the user must take his own ref * if needed. With the exception of the creation functions, none of the - * other libisofs functions that return an IsoNode increment its + * other libisofs functions that return an IsoNode increment its * refcount. This is responsablity of the client, if (s)he needs it. */ int refcount; @@ -115,14 +115,11 @@ struct Iso_File { IsoNode node; - /** - * Location of a file extent in a ms disc, 0 for newly added file - */ - uint32_t msblock; + unsigned int from_old_session : 1; - /** + /** * It sorts the order in which the file data is written to the CD image. - * Higher weighting files are written at the beginning of image + * Higher weighting files are written at the beginning of image */ int sort_weight; IsoStream *stream; @@ -143,18 +140,18 @@ struct Iso_Special struct iso_dir_iter_iface { - + int (*next)(IsoDirIter *iter, IsoNode **node); int (*has_next)(IsoDirIter *iter); void (*free)(IsoDirIter *iter); - + int (*take)(IsoDirIter *iter); int (*remove)(IsoDirIter *iter); - - /** + + /** * This is called just before remove a node from a directory. The iterator * may want to update its internal state according to this. */ @@ -167,37 +164,37 @@ struct iso_dir_iter_iface struct Iso_Dir_Iter { struct iso_dir_iter_iface *class; - + /* the directory this iterator iterates over */ IsoDir *dir; - + void *data; }; int iso_node_new_root(IsoDir **root); /** - * Create a new IsoDir. Attributes, uid/gid, timestamps, etc are set to + * Create a new IsoDir. Attributes, uid/gid, timestamps, etc are set to * default (0) values. You must set them. - * + * * @param name - * Name for the node. It is not strdup() so you shouldn't use this - * reference when this function returns successfully. NULL is not + * Name for the node. It is not strdup() so you shouldn't use this + * reference when this function returns successfully. NULL is not * allowed. * @param dir - * + * * @return * 1 on success, < 0 on error. */ int iso_node_new_dir(char *name, IsoDir **dir); /** - * Create a new file node. Attributes, uid/gid, timestamps, etc are set to + * Create a new file node. Attributes, uid/gid, timestamps, etc are set to * default (0) values. You must set them. - * + * * @param name - * Name for the node. It is not strdup() so you shouldn't use this - * reference when this function returns successfully. NULL is not + * Name for the node. It is not strdup() so you shouldn't use this + * reference when this function returns successfully. NULL is not * allowed. * @param stream * Source for file contents. The reference is taken by the node, @@ -210,14 +207,14 @@ int iso_node_new_file(char *name, IsoStream *stream, IsoFile **file); /** * Creates a new IsoSymlink node. Attributes, uid/gid, timestamps, etc are set * to default (0) values. You must set them. - * + * * @param name - * name for the new symlink. It is not strdup() so you shouldn't use this - * reference when this function returns successfully. NULL is not + * name for the new symlink. It is not strdup() so you shouldn't use this + * reference when this function returns successfully. NULL is not * allowed. * @param dest - * destination of the link. It is not strdup() so you shouldn't use this - * reference when this function returns successfully. NULL is not + * destination of the link. It is not strdup() so you shouldn't use this + * reference when this function returns successfully. NULL is not * allowed. * @param link * place where to store a pointer to the newly created link. @@ -231,22 +228,22 @@ int iso_node_new_symlink(char *name, char *dest, IsoSymlink **link); * an special file is a block device, a character device, a FIFO (named pipe) * or a socket. You can choose the specific kind of file you want to add * by setting mode propertly (see man 2 stat). - * - * Note that special files are only written to image when Rock Ridge + * + * Note that special files are only written to image when Rock Ridge * extensions are enabled. Moreover, a special file is just a directory entry * in the image tree, no data is written beyond that. - * - * Owner and hidden atts are taken from parent. You can modify any of them + * + * Owner and hidden atts are taken from parent. You can modify any of them * later. - * + * * @param name - * name for the new special file. It is not strdup() so you shouldn't use - * this reference when this function returns successfully. NULL is not + * name for the new special file. It is not strdup() so you shouldn't use + * this reference when this function returns successfully. NULL is not * allowed. * @param mode * file type and permissions for the new node. Note that you can't * specify any kind of file here, only special types are allowed. i.e, - * S_IFSOCK, S_IFBLK, S_IFCHR and S_IFIFO are valid types; S_IFLNK, + * S_IFSOCK, S_IFBLK, S_IFCHR and S_IFIFO are valid types; S_IFLNK, * S_IFREG and S_IFDIR aren't. * @param dev * device ID, equivalent to the st_rdev field in man 2 stat. @@ -255,12 +252,12 @@ int iso_node_new_symlink(char *name, char *dest, IsoSymlink **link); * @return * 1 on success, < 0 otherwise */ -int iso_node_new_special(char *name, mode_t mode, dev_t dev, +int iso_node_new_special(char *name, mode_t mode, dev_t dev, IsoSpecial **special); /** * Check if a given name is valid for an iso node. - * + * * @return * 1 if yes, 0 if not */ @@ -268,7 +265,7 @@ int iso_node_is_valid_name(const char *name); /** * Check if a given path is valid for the destination of a link. - * + * * @return * 1 if yes, 0 if not */ @@ -276,7 +273,7 @@ int iso_node_is_valid_link_dest(const char *dest); /** * Find the position where to insert a node - * + * * @param dir * A valid dir. It can't be NULL * @param name @@ -288,7 +285,7 @@ void iso_dir_find(IsoDir *dir, const char *name, IsoNode ***pos); /** * Check if a node with the given name exists in a dir. - * + * * @param dir * A valid dir. It can't be NULL * @param name @@ -303,26 +300,26 @@ int iso_dir_exists(IsoDir *dir, const char *name, IsoNode ***pos); /** * Inserts a given node in a dir, at the specified position. - * + * * @param dir * Dir where to insert. It can't be NULL * @param node * The node to insert. It can't be NULL * @param pos * Position where the node will be inserted. It is a pointer previously - * obtained with a call to iso_dir_exists() or iso_dir_find(). + * obtained with a call to iso_dir_exists() or iso_dir_find(). * It can't be NULL. - * @param replace + * @param replace * Whether to replace an old node with the same name with the new node. * @return - * If success, number of children in dir. < 0 on error + * If success, number of children in dir. < 0 on error */ -int iso_dir_insert(IsoDir *dir, IsoNode *node, IsoNode **pos, +int iso_dir_insert(IsoDir *dir, IsoNode *node, IsoNode **pos, enum iso_replace_mode replace); /** * Add a new iterator to the registry. The iterator register keeps track of - * all iterators being used, and are notified when directory structure + * all iterators being used, and are notified when directory structure * changes. */ int iso_dir_iter_register(IsoDirIter *iter); diff --git a/libisofs/stream.c b/libisofs/stream.c index dd747cf..2f0a752 100644 --- a/libisofs/stream.c +++ b/libisofs/stream.c @@ -1,8 +1,8 @@ /* * Copyright (c) 2007 Vreixo Formoso - * - * This file is part of the libisofs project; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as + * + * This file is part of the libisofs project; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. See COPYING file for details. */ @@ -19,16 +19,6 @@ ino_t serial_id = (ino_t)1; ino_t mem_serial_id = (ino_t)1; ino_t cut_out_serial_id = (ino_t)1; -typedef struct -{ - IsoFileSource *src; - - /* key for file identification inside filesystem */ - dev_t dev_id; - ino_t ino_id; - off_t size; /**< size of this file */ -} FSrcStreamData; - static int fsrc_open(IsoStream *stream) { @@ -116,7 +106,7 @@ void fsrc_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id, { FSrcStreamData *data; IsoFilesystem *fs; - + data = (FSrcStreamData*)stream->data; fs = iso_file_source_get_filesystem(data->src); @@ -164,7 +154,7 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream) if (S_ISDIR(info.st_mode)) { return ISO_FILE_IS_DIR; } - + /* check for read access to contents */ r = iso_file_source_access(src); if (r < 0) { @@ -184,7 +174,7 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream) /* take the ref to IsoFileSource */ data->src = src; data->size = info.st_size; - + /* get the id numbers */ { IsoFilesystem *fs; @@ -193,7 +183,7 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream) fs_id = fs->get_id(fs); if (fs_id == 0) { - /* + /* * the filesystem implementation is unable to provide valid * st_dev and st_ino fields. Use serial_id. */ @@ -232,11 +222,11 @@ int cut_out_open(IsoStream *stream) struct stat info; IsoFileSource *src; struct cut_out_stream *data; - + if (stream == NULL) { return ISO_NULL_POINTER; } - + data = stream->data; src = data->src; ret = iso_file_source_stat(data->src, &info); @@ -247,7 +237,7 @@ int cut_out_open(IsoStream *stream) if (ret < 0) { return ret; } - + { off_t ret; if (data->offset > info.st_size) { @@ -310,7 +300,7 @@ void cut_out_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id, { FSrcStreamData *data; IsoFilesystem *fs; - + data = (FSrcStreamData*)stream->data; fs = iso_file_source_get_filesystem(data->src); @@ -339,7 +329,7 @@ IsoStreamIface cut_out_stream_class = { cut_out_free }; -int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size, +int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size, IsoStream **stream) { int r; @@ -364,7 +354,7 @@ int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size, if (offset > info.st_size) { return ISO_FILE_OFFSET_TOO_BIG; } - + /* check for read access to contents */ r = iso_file_source_access(src); if (r < 0) { @@ -384,10 +374,10 @@ int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size, /* take a new ref to IsoFileSource */ data->src = src; iso_file_source_ref(src); - + data->offset = offset; data->size = MIN(info.st_size - offset, size); - + /* get the id numbers */ data->dev_id = (dev_t) 0; data->ino_id = cut_out_serial_id++; @@ -461,15 +451,15 @@ int mem_read(IsoStream *stream, void *buf, size_t count) return ISO_WRONG_ARG_VALUE; } data = stream->data; - + if (data->offset == -1) { return ISO_FILE_NOT_OPENED; } - + if (data->offset >= data->size) { return 0; /* EOF */ } - + len = MIN(count, data->size - data->offset); memcpy(buf, data->buf + data->offset, len); data->offset += len; @@ -517,7 +507,7 @@ IsoStreamIface mem_stream_class = { /** * Create a stream for reading from a arbitrary memory buffer. * When the Stream refcount reach 0, the buffer is free(3). - * + * * @return * 1 sucess, < 0 error */ @@ -607,11 +597,12 @@ void iso_stream_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id, void iso_stream_get_file_name(IsoStream *stream, char *name) { char *type = stream->class->type; - + if (!strncmp(type, "fsrc", 4)) { FSrcStreamData *data = stream->data; char *path = iso_file_source_get_path(data->src); strncpy(name, path, PATH_MAX); + free(path); } else if (!strncmp(type, "boot", 4)) { strcpy(name, "BOOT CATALOG"); } else if (!strncmp(type, "mem ", 4)) { diff --git a/libisofs/stream.h b/libisofs/stream.h index 3893785..0f394cf 100644 --- a/libisofs/stream.h +++ b/libisofs/stream.h @@ -1,8 +1,8 @@ /* * Copyright (c) 2007 Vreixo Formoso - * - * This file is part of the libisofs project; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as + * + * This file is part of the libisofs project; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. See COPYING file for details. */ #ifndef LIBISO_STREAM_H_ @@ -13,9 +13,19 @@ */ #include "fsource.h" +typedef struct +{ + IsoFileSource *src; + + /* key for file identification inside filesystem */ + dev_t dev_id; + ino_t ino_id; + off_t size; /**< size of this file */ +} FSrcStreamData; + /** * Get an identifier for the file of the source, for debug purposes - * @param name + * @param name * Should provide at least PATH_MAX bytes */ void iso_stream_get_file_name(IsoStream *stream, char *name); @@ -25,28 +35,28 @@ void iso_stream_get_file_name(IsoStream *stream, char *name); * The stream will take the ref. to the IsoFileSource, so after a successfully * exectution of this function, you musn't unref() the source, unless you * take an extra ref. - * + * * @return * 1 sucess, < 0 error * Possible errors: - * + * */ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream); /** * Create a new stream to read a chunk of an IsoFileSource.. * The stream will add a ref. to the IsoFileSource. - * + * * @return * 1 sucess, < 0 error */ -int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size, +int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size, IsoStream **stream); /** * Create a stream for reading from a arbitrary memory buffer. * When the Stream refcount reach 0, the buffer is free(3). - * + * * @return * 1 sucess, < 0 error */ diff --git a/test/test_rockridge.c b/test/test_rockridge.c index 0a3d411..93aee0e 100644 --- a/test/test_rockridge.c +++ b/test/test_rockridge.c @@ -1,6 +1,6 @@ /* * Unit test for util.h - * + * * This test utiliy functions */ #include "test.h" @@ -16,51 +16,51 @@ static void test_rrip_calc_len_file() Ecma119Node *node; Ecma119Image t; size_t sua_len = 0, ce_len = 0; - + memset(&t, 0, sizeof(Ecma119Image)); t.input_charset = "UTF-8"; t.output_charset = "UTF-8"; - + file = malloc(sizeof(IsoFile)); CU_ASSERT_PTR_NOT_NULL_FATAL(file); - file->msblock = 0; + file->from_old_session = 0; file->sort_weight = 0; file->stream = NULL; /* it is not needed here */ file->node.type = LIBISO_FILE; - + node = malloc(sizeof(Ecma119Node)); CU_ASSERT_PTR_NOT_NULL_FATAL(node); node->node = (IsoNode*)file; node->parent = (Ecma119Node*)0x55555555; /* just to make it not NULL */ - node->info.file = NULL; /* it is not needed here */ + node->info.file = NULL; /* it is not needed here */ node->type = ECMA119_FILE; - + /* Case 1. Name fit in System Use field */ file->node.name = "a small name.txt"; node->iso_name = "A_SMALL_.TXT"; - + sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len); CU_ASSERT_EQUAL(ce_len, 0); CU_ASSERT_EQUAL(sua_len, 44 + (5 + 16) + (5 + 3*7) + 1); - + /* Case 2. Name fits exactly */ file->node.name = "a big name, with 133 characters, that it is the max " "that fits in System Use field of the directory record " "PADPADPADADPADPADPADPAD.txt"; node->iso_name = "A_BIG_NA.TXT"; - + sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len); CU_ASSERT_EQUAL(ce_len, 0); /* note that 254 is the max length of a directory record, as it needs to * be an even number */ CU_ASSERT_EQUAL(sua_len, 254 - 46); - + /* case 3. A name just 1 character too big to fit in SUA */ file->node.name = "a big name, with 133 characters, that it is the max " "that fits in System Use field of the directory record " "PADPADPADADPADPADPADPAD1.txt"; node->iso_name = "A_BIG_NA.TXT"; - + sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len); /* 28 (the chars moved to include the CE entry) + 5 (header of NM in CE) + * 1 (the char that originally didn't fit) */ @@ -68,21 +68,21 @@ static void test_rrip_calc_len_file() /* note that 254 is the max length of a directory record, as it needs to * be an even number */ CU_ASSERT_EQUAL(sua_len, 254 - 46); - + /* case 4. A 255 characters name */ file->node.name = "a big name, with 255 characters, that it is the max " "that a POSIX filename can have. PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP" "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP" "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"; node->iso_name = "A_BIG_NA.TXT"; - + sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len); /* 150 + 5 (header + characters that don't fit in sua) */ CU_ASSERT_EQUAL(ce_len, 150 + 5); /* note that 254 is the max length of a directory record, as it needs to * be an even number */ CU_ASSERT_EQUAL(sua_len, 254 - 46); - + free(node); free(file); } @@ -93,31 +93,31 @@ static void test_rrip_calc_len_symlink() Ecma119Node *node; Ecma119Image t; size_t sua_len = 0, ce_len = 0; - + memset(&t, 0, sizeof(Ecma119Image)); t.input_charset = "UTF-8"; t.output_charset = "UTF-8"; - + link = malloc(sizeof(IsoSymlink)); CU_ASSERT_PTR_NOT_NULL_FATAL(link); link->node.type = LIBISO_SYMLINK; - + node = malloc(sizeof(Ecma119Node)); CU_ASSERT_PTR_NOT_NULL_FATAL(node); node->node = (IsoNode*)link; node->parent = (Ecma119Node*)0x55555555; /* just to make it not NULL */ node->type = ECMA119_SYMLINK; - + /* Case 1. Name and dest fit in System Use field */ link->node.name = "a small name.txt"; link->dest = "/three/components"; node->iso_name = "A_SMALL_.TXT"; - + sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len); CU_ASSERT_EQUAL(ce_len, 0); - CU_ASSERT_EQUAL(sua_len, 44 + (5 + 16) + (5 + 3*7) + 1 + + CU_ASSERT_EQUAL(sua_len, 44 + (5 + 16) + (5 + 3*7) + 1 + (5 + 2 + (2+5) + (2+10)) ); - + /* case 2. name + dest fits exactly */ link->node.name = "this name will have 74 characters as it is the max " "that fits in the SU.txt"; @@ -136,7 +136,7 @@ static void test_rrip_calc_len_symlink() sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len); CU_ASSERT_EQUAL(ce_len, 60); CU_ASSERT_EQUAL(sua_len, 44 + (5 + 74) + (5 + 3*7) + 1 + 28); - + /* 3.b extra byte in name */ link->node.name = "this name will have 75 characters as it is the max " "that fits in the SUx.txt"; @@ -145,10 +145,10 @@ static void test_rrip_calc_len_symlink() sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len); CU_ASSERT_EQUAL(ce_len, 59); CU_ASSERT_EQUAL(sua_len, 44 + (5 + 75) + (5 + 3*7) + 28); - - /* case 4. name seems to fit, but SL no, and when CE is added NM + + /* case 4. name seems to fit, but SL no, and when CE is added NM * doesn't fit too */ - /* 4.a it just fits */ + /* 4.a it just fits */ link->node.name = "this name will have 105 characters as it is just the " "max that fits in the SU once we add the CE entry.txt"; link->dest = "./and/../a/./big/destination/with/10/components"; @@ -156,8 +156,8 @@ static void test_rrip_calc_len_symlink() sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len); CU_ASSERT_EQUAL(ce_len, 59); CU_ASSERT_EQUAL(sua_len, 254 - 46); - - /* 4.b it just fits, the the component ends in '/' */ + + /* 4.b it just fits, the the component ends in '/' */ link->node.name = "this name will have 105 characters as it is just the " "max that fits in the SU once we add the CE entry.txt"; link->dest = "./and/../a/./big/destination/with/10/components/"; @@ -165,8 +165,8 @@ static void test_rrip_calc_len_symlink() sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len); CU_ASSERT_EQUAL(ce_len, 59); CU_ASSERT_EQUAL(sua_len, 254 - 46); - - /* 4.c extra char in name, that forces it to be divided */ + + /* 4.c extra char in name, that forces it to be divided */ link->node.name = "this name will have 105 characters as it is just the " "max that fits in the SU once we add the CE entryc.txt"; link->dest = "./and/../a/./big/destination/with/10/components"; @@ -174,7 +174,7 @@ static void test_rrip_calc_len_symlink() sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len); CU_ASSERT_EQUAL(ce_len, 59 + 6); CU_ASSERT_EQUAL(sua_len, 254 - 46); - + /* 5 max destination length to fit in a single SL entry (250) */ link->node.name = "this name will have 74 characters as it is the max " "that fits in the SU.txt"; @@ -186,7 +186,7 @@ static void test_rrip_calc_len_symlink() sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len); CU_ASSERT_EQUAL(ce_len, 255); CU_ASSERT_EQUAL(sua_len, 44 + (5 + 74) + (5 + 3*7) + 1 + 28); - + /* 6 min destination length to need two SL entries (251) */ link->node.name = "this name will have 74 characters as it is the max " "that fits in the SU.txt"; @@ -198,8 +198,8 @@ static void test_rrip_calc_len_symlink() sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len); CU_ASSERT_EQUAL(ce_len, 261); CU_ASSERT_EQUAL(sua_len, 44 + (5 + 74) + (5 + 3*7) + 1 + 28); - - /* 7 destination with big component that need to be splited + + /* 7 destination with big component that need to be splited * in two SL entries */ /* 7.a just fits in one */ link->node.name = "this name will have 74 characters as it is the max " @@ -213,7 +213,7 @@ static void test_rrip_calc_len_symlink() sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len); CU_ASSERT_EQUAL(ce_len, 255); CU_ASSERT_EQUAL(sua_len, 44 + (5 + 74) + (5 + 3*7) + 1 + 28); - + /* 7.b doesn't fits by one character */ link->node.name = "this name will have 74 characters as it is the max " "that fits in the SU.txt"; @@ -226,7 +226,7 @@ static void test_rrip_calc_len_symlink() sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len); CU_ASSERT_EQUAL(ce_len, 255 + (5+2+1)); CU_ASSERT_EQUAL(sua_len, 44 + (5 + 74) + (5 + 3*7) + 1 + 28); - + /* 7.c several components before, such as it has just the right len * to fit in the SL entry plus another one */ link->node.name = "this name will have 74 characters as it is the max " @@ -244,8 +244,8 @@ static void test_rrip_calc_len_symlink() sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len); CU_ASSERT_EQUAL(ce_len, 255 + 255); CU_ASSERT_EQUAL(sua_len, 44 + (5 + 74) + (5 + 3*7) + 1 + 28); - - /* + + /* * 7.d several components before, and then a big component that doesn't * fit in the 1st SL entry and another one. That case needs a 3rd SL entry, * but instead of divide the component in 2 entries, we put it in 2, @@ -275,12 +275,12 @@ static void susp_info_free(struct susp_info *susp) { size_t i; - + for (i = 0; i < susp->n_susp_fields; ++i) { free(susp->susp_fields[i]); } free(susp->susp_fields); - + for (i = 0; i < susp->n_ce_susp_fields; ++i) { free(susp->ce_susp_fields[i]); } @@ -296,14 +296,14 @@ void test_rrip_get_susp_fields_file() struct susp_info susp; Ecma119Image t; uint8_t *entry; - + memset(&t, 0, sizeof(Ecma119Image)); t.input_charset = "UTF-8"; t.output_charset = "UTF-8"; - + file = malloc(sizeof(IsoFile)); CU_ASSERT_PTR_NOT_NULL_FATAL(file); - file->msblock = 0; + file->from_old_session = 0; file->sort_weight = 0; file->stream = NULL; /* it is not needed here */ file->node.type = LIBISO_FILE; @@ -313,20 +313,20 @@ void test_rrip_get_susp_fields_file() file->node.mtime = 675757578; file->node.atime = 546462546; file->node.ctime = 323245342; - + node = malloc(sizeof(Ecma119Node)); CU_ASSERT_PTR_NOT_NULL_FATAL(node); node->node = (IsoNode*)file; node->parent = (Ecma119Node*)0x55555555; /* just to make it not NULL */ - node->info.file = NULL; /* it is not needed here */ + node->info.file = NULL; /* it is not needed here */ node->type = ECMA119_FILE; node->nlink = 1; node->ino = 0x03447892; - + /* Case 1. Name fit in System Use field */ file->node.name = "a small name.txt"; node->iso_name = "A_SMALL_.TXT"; - + memset(&susp, 0, sizeof(struct susp_info)); ret = rrip_get_susp_fields(&t, node, 0, 255 - 46, &susp); CU_ASSERT_EQUAL(ret, 1); @@ -334,7 +334,7 @@ void test_rrip_get_susp_fields_file() CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 0); CU_ASSERT_EQUAL(susp.n_susp_fields, 3); /* PX + TF + NM */ CU_ASSERT_EQUAL(susp.suf_len, 44 + (5 + 16) + (5 + 3*7) + 1); - + /* PX is the first entry */ entry = susp.susp_fields[0]; CU_ASSERT_PTR_NOT_NULL(entry); @@ -352,7 +352,7 @@ void test_rrip_get_susp_fields_file() CU_ASSERT_EQUAL(iso_read_msb(entry + 32, 4), 654); CU_ASSERT_EQUAL(iso_read_lsb(entry + 36, 4), 0x03447892); CU_ASSERT_EQUAL(iso_read_msb(entry + 40, 4), 0x03447892); - + /* TF is the second entry */ entry = susp.susp_fields[1]; CU_ASSERT_PTR_NOT_NULL(entry); @@ -364,7 +364,7 @@ void test_rrip_get_susp_fields_file() CU_ASSERT_EQUAL(iso_datetime_read_7(entry + 5), 675757578); CU_ASSERT_EQUAL(iso_datetime_read_7(entry + 12), 546462546); CU_ASSERT_EQUAL(iso_datetime_read_7(entry + 19), 323245342); - + /* NM is the last entry */ entry = susp.susp_fields[2]; CU_ASSERT_PTR_NOT_NULL(entry); @@ -374,24 +374,24 @@ void test_rrip_get_susp_fields_file() CU_ASSERT_EQUAL(entry[3], 1); CU_ASSERT_EQUAL(entry[4], 0); CU_ASSERT_NSTRING_EQUAL(entry + 5, "a small name.txt", 16); - + susp_info_free(&susp); - + /* Case 2. Name fits exactly */ file->node.name = "a big name, with 133 characters, that it is the max " "that fits in System Use field of the directory record " "PADPADPADADPADPADPADPAD.txt"; node->iso_name = "A_BIG_NA.TXT"; - + memset(&susp, 0, sizeof(struct susp_info)); ret = rrip_get_susp_fields(&t, node, 0, 255 - 46, &susp); CU_ASSERT_EQUAL(ret, 1); CU_ASSERT_EQUAL(susp.ce_len, 0); CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 0); CU_ASSERT_EQUAL(susp.suf_len, 254 - 46); - + CU_ASSERT_EQUAL(susp.n_susp_fields, 3); /* PX + TF + NM */ - + /* NM is the last entry */ entry = susp.susp_fields[2]; CU_ASSERT_PTR_NOT_NULL(entry); @@ -403,24 +403,24 @@ void test_rrip_get_susp_fields_file() CU_ASSERT_NSTRING_EQUAL(entry + 5, "a big name, with 133 characters, that " "it is the max that fits in System Use field of the " "directory record PADPADPADADPADPADPADPAD.txt", 133); - + susp_info_free(&susp); - + /* case 3. A name just 1 character too big to fit in SUA */ file->node.name = "a big name, with 133 characters, that it is the max " "that fits in System Use field of the directory record " "PADPADPADADPADPADPADPAD1.txt"; node->iso_name = "A_BIG_NA.TXT"; - + memset(&susp, 0, sizeof(struct susp_info)); ret = rrip_get_susp_fields(&t, node, 0, 255 - 46, &susp); CU_ASSERT_EQUAL(ret, 1); CU_ASSERT_EQUAL(susp.ce_len, 28 + 5 + 1); CU_ASSERT_EQUAL(susp.suf_len, 254 - 46); - + CU_ASSERT_EQUAL(susp.n_susp_fields, 4); /* PX + TF + NM + CE */ CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 1); /* NM */ - + /* test NM entry */ entry = susp.susp_fields[2]; CU_ASSERT_PTR_NOT_NULL(entry); @@ -432,7 +432,7 @@ void test_rrip_get_susp_fields_file() CU_ASSERT_NSTRING_EQUAL(entry + 5, "a big name, with 133 characters, that " "it is the max that fits in System Use field of the " "directory record", 105); - + /* and CE entry */ entry = susp.susp_fields[3]; CU_ASSERT_PTR_NOT_NULL(entry); @@ -446,7 +446,7 @@ void test_rrip_get_susp_fields_file() CU_ASSERT_EQUAL(iso_read_msb(entry + 16, 4), 0); CU_ASSERT_EQUAL(iso_read_lsb(entry + 20, 4), 34); CU_ASSERT_EQUAL(iso_read_msb(entry + 24, 4), 34); - + /* and check Continuation area */ entry = susp.ce_susp_fields[0]; CU_ASSERT_PTR_NOT_NULL(entry); @@ -456,16 +456,16 @@ void test_rrip_get_susp_fields_file() CU_ASSERT_EQUAL(entry[3], 1); CU_ASSERT_EQUAL(entry[4], 0); CU_ASSERT_NSTRING_EQUAL(entry + 5, " PADPADPADADPADPADPADPAD1.txt", 29); - + susp_info_free(&susp); - + /* case 4. A 255 characters name */ file->node.name = "a big name, with 255 characters, that it is the max " "that a POSIX filename can have. PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP" "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP" "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"; node->iso_name = "A_BIG_NA.TXT"; - + memset(&susp, 0, sizeof(struct susp_info)); susp.ce_block = 12; susp.ce_len = 456; @@ -473,7 +473,7 @@ void test_rrip_get_susp_fields_file() CU_ASSERT_EQUAL(ret, 1); CU_ASSERT_EQUAL(susp.ce_len, 150 + 5 + 456); CU_ASSERT_EQUAL(susp.suf_len, 254 - 46); - + CU_ASSERT_EQUAL(susp.n_susp_fields, 4); /* PX + TF + NM + CE */ CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 1); /* NM */ @@ -488,7 +488,7 @@ void test_rrip_get_susp_fields_file() CU_ASSERT_NSTRING_EQUAL(entry + 5, "a big name, with 255 characters, that " "it is the max that a POSIX filename can have. PPP" "PPPPPPPPPPPPPPPPPP", 105); - + /* and CE entry */ entry = susp.susp_fields[3]; CU_ASSERT_PTR_NOT_NULL(entry); @@ -517,9 +517,9 @@ void test_rrip_get_susp_fields_file() "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP" "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP" "PPPPPPPPPPPPPP", 150); - + susp_info_free(&susp); - + free(node); free(file); } @@ -532,11 +532,11 @@ static void test_rrip_get_susp_fields_symlink() int ret; struct susp_info susp; uint8_t *entry; - + memset(&t, 0, sizeof(Ecma119Image)); t.input_charset = "UTF-8"; t.output_charset = "UTF-8"; - + link = malloc(sizeof(IsoSymlink)); CU_ASSERT_PTR_NOT_NULL_FATAL(link); link->node.type = LIBISO_SYMLINK; @@ -546,7 +546,7 @@ static void test_rrip_get_susp_fields_symlink() link->node.mtime = 675757578; link->node.atime = 546462546; link->node.ctime = 323245342; - + node = malloc(sizeof(Ecma119Node)); CU_ASSERT_PTR_NOT_NULL_FATAL(node); node->node = (IsoNode*)link; @@ -554,21 +554,21 @@ static void test_rrip_get_susp_fields_symlink() node->type = ECMA119_SYMLINK; node->nlink = 1; node->ino = 0x03447892; - + /* Case 1. Name and dest fit in System Use field */ link->node.name = "a small name.txt"; link->dest = "/three/components"; node->iso_name = "A_SMALL_.TXT"; - + memset(&susp, 0, sizeof(struct susp_info)); ret = rrip_get_susp_fields(&t, node, 0, 255 - 46, &susp); CU_ASSERT_EQUAL(ret, 1); CU_ASSERT_EQUAL(susp.ce_len, 0); CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 0); CU_ASSERT_EQUAL(susp.n_susp_fields, 4); /* PX + TF + NM + SL */ - CU_ASSERT_EQUAL(susp.suf_len, 44 + (5 + 16) + (5 + 3*7) + 1 + CU_ASSERT_EQUAL(susp.suf_len, 44 + (5 + 16) + (5 + 3*7) + 1 + (5 + 2 + (2 + 5) + (2 + 10))); - + /* PX is the first entry */ entry = susp.susp_fields[0]; CU_ASSERT_PTR_NOT_NULL(entry); @@ -586,7 +586,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(iso_read_msb(entry + 32, 4), 654); CU_ASSERT_EQUAL(iso_read_lsb(entry + 36, 4), 0x03447892); CU_ASSERT_EQUAL(iso_read_msb(entry + 40, 4), 0x03447892); - + /* TF is the second entry */ entry = susp.susp_fields[1]; CU_ASSERT_PTR_NOT_NULL(entry); @@ -598,7 +598,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(iso_datetime_read_7(entry + 5), 675757578); CU_ASSERT_EQUAL(iso_datetime_read_7(entry + 12), 546462546); CU_ASSERT_EQUAL(iso_datetime_read_7(entry + 19), 323245342); - + /* NM is the 3rd entry */ entry = susp.susp_fields[2]; CU_ASSERT_PTR_NOT_NULL(entry); @@ -617,7 +617,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[2], 5 + 2 + (2 + 5) + (2 + 10)); CU_ASSERT_EQUAL(entry[3], 1); CU_ASSERT_EQUAL(entry[4], 0); - + /* first component */ CU_ASSERT_EQUAL(entry[5], 0x8); /* root */ CU_ASSERT_EQUAL(entry[6], 0); @@ -626,14 +626,14 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[7], 0); CU_ASSERT_EQUAL(entry[8], 5); CU_ASSERT_NSTRING_EQUAL(entry + 9, "three", 5); - + /* 3rd component */ CU_ASSERT_EQUAL(entry[14], 0); CU_ASSERT_EQUAL(entry[15], 10); CU_ASSERT_NSTRING_EQUAL(entry + 16, "components", 10); - + susp_info_free(&susp); - + /* case 2. name + dest fits exactly */ link->node.name = "this name will have 74 characters as it is the max " "that fits in the SU.txt"; @@ -647,7 +647,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 0); CU_ASSERT_EQUAL(susp.n_susp_fields, 4); /* PX + TF + NM + SL */ CU_ASSERT_EQUAL(susp.suf_len, 254 - 46); - + /* NM is the 3rd entry */ entry = susp.susp_fields[2]; CU_ASSERT_PTR_NOT_NULL(entry); @@ -667,7 +667,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[2], 5 + 2 + 5 + 2 + 3 + 2 + 5 + 13 + 6 + 4 + 12); CU_ASSERT_EQUAL(entry[3], 1); CU_ASSERT_EQUAL(entry[4], 0); - + /* first component */ CU_ASSERT_EQUAL(entry[5], 0x2); /* current */ CU_ASSERT_EQUAL(entry[6], 0); @@ -676,7 +676,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[7], 0); CU_ASSERT_EQUAL(entry[8], 3); CU_ASSERT_NSTRING_EQUAL(entry + 9, "and", 3); - + /* 3rd component */ CU_ASSERT_EQUAL(entry[12], 0x4); /* parent */ CU_ASSERT_EQUAL(entry[13], 0); @@ -685,7 +685,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[14], 0); CU_ASSERT_EQUAL(entry[15], 1); CU_ASSERT_EQUAL(entry[16], 'a'); - + /* 5th component */ CU_ASSERT_EQUAL(entry[17], 0x2); /* current */ CU_ASSERT_EQUAL(entry[18], 0); @@ -716,7 +716,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_NSTRING_EQUAL(entry + 49, "components", 10); susp_info_free(&susp); - + /* case 3. name fits, dest is one byte larger to fit */ /* 3.a extra byte in dest */ link->node.name = "this name will have 74 characters as it is the max " @@ -738,7 +738,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[0], 'P'); CU_ASSERT_EQUAL(entry[1], 'X'); CU_ASSERT_EQUAL(entry[2], 44); - + /* TF is the second entry */ entry = susp.susp_fields[1]; CU_ASSERT_PTR_NOT_NULL(entry); @@ -770,7 +770,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(iso_read_msb(entry + 16, 4), 0); CU_ASSERT_EQUAL(iso_read_lsb(entry + 20, 4), 60); CU_ASSERT_EQUAL(iso_read_msb(entry + 24, 4), 60); - + /* finally, SL is the single entry in CE */ entry = susp.ce_susp_fields[0]; @@ -780,7 +780,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[2], 60); CU_ASSERT_EQUAL(entry[3], 1); CU_ASSERT_EQUAL(entry[4], 0); - + /* first component */ CU_ASSERT_EQUAL(entry[5], 0x2); /* current */ CU_ASSERT_EQUAL(entry[6], 0); @@ -789,7 +789,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[7], 0); CU_ASSERT_EQUAL(entry[8], 3); CU_ASSERT_NSTRING_EQUAL(entry + 9, "and", 3); - + /* 3rd component */ CU_ASSERT_EQUAL(entry[12], 0x4); /* parent */ CU_ASSERT_EQUAL(entry[13], 0); @@ -798,7 +798,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[14], 0); CU_ASSERT_EQUAL(entry[15], 1); CU_ASSERT_EQUAL(entry[16], 'a'); - + /* 5th component */ CU_ASSERT_EQUAL(entry[17], 0x2); /* current */ CU_ASSERT_EQUAL(entry[18], 0); @@ -827,7 +827,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[47], 0); CU_ASSERT_EQUAL(entry[48], 11); CU_ASSERT_NSTRING_EQUAL(entry + 49, "componentsk", 11); - + susp_info_free(&susp); /* 3.b extra byte in name */ @@ -868,7 +868,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(iso_read_msb(entry + 16, 4), 0); CU_ASSERT_EQUAL(iso_read_lsb(entry + 20, 4), 59); CU_ASSERT_EQUAL(iso_read_msb(entry + 24, 4), 59); - + /* finally, SL is the single entry in CE */ entry = susp.ce_susp_fields[0]; @@ -878,7 +878,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[2], 59); CU_ASSERT_EQUAL(entry[3], 1); CU_ASSERT_EQUAL(entry[4], 0); - + /* first component */ CU_ASSERT_EQUAL(entry[5], 0x2); /* current */ CU_ASSERT_EQUAL(entry[6], 0); @@ -887,7 +887,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[7], 0); CU_ASSERT_EQUAL(entry[8], 3); CU_ASSERT_NSTRING_EQUAL(entry + 9, "and", 3); - + /* 3rd component */ CU_ASSERT_EQUAL(entry[12], 0x4); /* parent */ CU_ASSERT_EQUAL(entry[13], 0); @@ -896,7 +896,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[14], 0); CU_ASSERT_EQUAL(entry[15], 1); CU_ASSERT_EQUAL(entry[16], 'a'); - + /* 5th component */ CU_ASSERT_EQUAL(entry[17], 0x2); /* current */ CU_ASSERT_EQUAL(entry[18], 0); @@ -925,12 +925,12 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[47], 0); CU_ASSERT_EQUAL(entry[48], 10); CU_ASSERT_NSTRING_EQUAL(entry + 49, "components", 10); - + susp_info_free(&susp); - - /* case 4. name seems to fit, but SL no, and when CE is added NM + + /* case 4. name seems to fit, but SL no, and when CE is added NM * doesn't fit too */ - /* 4.a it just fits */ + /* 4.a it just fits */ link->node.name = "this name will have 105 characters as it is just the " "max that fits in the SU once we add the CE entry.txt"; link->dest = "./and/../a/./big/destination/with/10/components"; @@ -978,7 +978,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[2], 59); CU_ASSERT_EQUAL(entry[3], 1); CU_ASSERT_EQUAL(entry[4], 0); - + /* first component */ CU_ASSERT_EQUAL(entry[5], 0x2); /* current */ CU_ASSERT_EQUAL(entry[6], 0); @@ -987,7 +987,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[7], 0); CU_ASSERT_EQUAL(entry[8], 3); CU_ASSERT_NSTRING_EQUAL(entry + 9, "and", 3); - + /* 3rd component */ CU_ASSERT_EQUAL(entry[12], 0x4); /* parent */ CU_ASSERT_EQUAL(entry[13], 0); @@ -996,7 +996,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[14], 0); CU_ASSERT_EQUAL(entry[15], 1); CU_ASSERT_EQUAL(entry[16], 'a'); - + /* 5th component */ CU_ASSERT_EQUAL(entry[17], 0x2); /* current */ CU_ASSERT_EQUAL(entry[18], 0); @@ -1025,10 +1025,10 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[47], 0); CU_ASSERT_EQUAL(entry[48], 10); CU_ASSERT_NSTRING_EQUAL(entry + 49, "components", 10); - + susp_info_free(&susp); - - /* 4.b it just fits, the the component ends in '/' */ + + /* 4.b it just fits, the the component ends in '/' */ link->node.name = "this name will have 105 characters as it is just the " "max that fits in the SU once we add the CE entry.txt"; link->dest = "./and/../a/./big/destination/with/10/components/"; @@ -1076,7 +1076,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[2], 59); CU_ASSERT_EQUAL(entry[3], 1); CU_ASSERT_EQUAL(entry[4], 0); - + /* first component */ CU_ASSERT_EQUAL(entry[5], 0x2); /* current */ CU_ASSERT_EQUAL(entry[6], 0); @@ -1085,7 +1085,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[7], 0); CU_ASSERT_EQUAL(entry[8], 3); CU_ASSERT_NSTRING_EQUAL(entry + 9, "and", 3); - + /* 3rd component */ CU_ASSERT_EQUAL(entry[12], 0x4); /* parent */ CU_ASSERT_EQUAL(entry[13], 0); @@ -1094,7 +1094,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[14], 0); CU_ASSERT_EQUAL(entry[15], 1); CU_ASSERT_EQUAL(entry[16], 'a'); - + /* 5th component */ CU_ASSERT_EQUAL(entry[17], 0x2); /* current */ CU_ASSERT_EQUAL(entry[18], 0); @@ -1123,10 +1123,10 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[47], 0); CU_ASSERT_EQUAL(entry[48], 10); CU_ASSERT_NSTRING_EQUAL(entry + 49, "components", 10); - + susp_info_free(&susp); - - /* 4.c extra char in name, that forces it to be divided */ + + /* 4.c extra char in name, that forces it to be divided */ link->node.name = "this name will have 106 characters as it is just the " "max that fits in the SU once we add the CE entryc.txt"; link->dest = "./and/../a/./big/destination/with/10/components"; @@ -1175,7 +1175,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[3], 1); CU_ASSERT_EQUAL(entry[4], 0); CU_ASSERT_EQUAL(entry[5], 't'); - + /* finally, SL is the single entry in CE */ entry = susp.ce_susp_fields[1]; CU_ASSERT_PTR_NOT_NULL(entry); @@ -1184,7 +1184,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[2], 59); CU_ASSERT_EQUAL(entry[3], 1); CU_ASSERT_EQUAL(entry[4], 0); - + /* first component */ CU_ASSERT_EQUAL(entry[5], 0x2); /* current */ CU_ASSERT_EQUAL(entry[6], 0); @@ -1193,7 +1193,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[7], 0); CU_ASSERT_EQUAL(entry[8], 3); CU_ASSERT_NSTRING_EQUAL(entry + 9, "and", 3); - + /* 3rd component */ CU_ASSERT_EQUAL(entry[12], 0x4); /* parent */ CU_ASSERT_EQUAL(entry[13], 0); @@ -1202,7 +1202,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[14], 0); CU_ASSERT_EQUAL(entry[15], 1); CU_ASSERT_EQUAL(entry[16], 'a'); - + /* 5th component */ CU_ASSERT_EQUAL(entry[17], 0x2); /* current */ CU_ASSERT_EQUAL(entry[18], 0); @@ -1231,9 +1231,9 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[47], 0); CU_ASSERT_EQUAL(entry[48], 10); CU_ASSERT_NSTRING_EQUAL(entry + 49, "components", 10); - + susp_info_free(&susp); - + /* 5 max destination length to fit in a single SL entry (250) */ link->node.name = "this name will have 74 characters as it is the max " "that fits in the SU.txt"; @@ -1259,7 +1259,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[2], 255); CU_ASSERT_EQUAL(entry[3], 1); CU_ASSERT_EQUAL(entry[4], 0); - + /* first component */ CU_ASSERT_EQUAL(entry[5], 0x2); /* current */ CU_ASSERT_EQUAL(entry[6], 0); @@ -1268,7 +1268,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[7], 0); CU_ASSERT_EQUAL(entry[8], 3); CU_ASSERT_NSTRING_EQUAL(entry + 9, "and", 3); - + /* 3rd component */ CU_ASSERT_EQUAL(entry[12], 0x4); /* parent */ CU_ASSERT_EQUAL(entry[13], 0); @@ -1277,7 +1277,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[14], 0); CU_ASSERT_EQUAL(entry[15], 1); CU_ASSERT_EQUAL(entry[16], 'a'); - + /* 5th component */ CU_ASSERT_EQUAL(entry[17], 0x2); /* current */ CU_ASSERT_EQUAL(entry[18], 0); @@ -1301,7 +1301,7 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[43], 0); CU_ASSERT_EQUAL(entry[44], 4); CU_ASSERT_NSTRING_EQUAL(entry + 45, "with", 4); - + /* 10th component */ CU_ASSERT_EQUAL(entry[49], 0); CU_ASSERT_EQUAL(entry[50], 2); @@ -1316,59 +1316,59 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_EQUAL(entry[65], 0); CU_ASSERT_EQUAL(entry[66], 4); CU_ASSERT_NSTRING_EQUAL(entry + 67, "that", 4); - + /* 13th component */ CU_ASSERT_EQUAL(entry[71], 0); CU_ASSERT_EQUAL(entry[72], 8); CU_ASSERT_NSTRING_EQUAL(entry + 73, "conforms", 8); - + /* 14th component */ CU_ASSERT_EQUAL(entry[81], 0); CU_ASSERT_EQUAL(entry[82], 3); CU_ASSERT_NSTRING_EQUAL(entry + 83, "the", 3); - + /* 15th component */ CU_ASSERT_EQUAL(entry[86], 0); CU_ASSERT_EQUAL(entry[87], 3); CU_ASSERT_NSTRING_EQUAL(entry + 88, "max", 3); - + /* 16th component */ CU_ASSERT_EQUAL(entry[91], 0); CU_ASSERT_EQUAL(entry[92], 4); CU_ASSERT_NSTRING_EQUAL(entry + 93, "that", 4); - + /* 17th component */ CU_ASSERT_EQUAL(entry[97], 0); CU_ASSERT_EQUAL(entry[98], 4); CU_ASSERT_NSTRING_EQUAL(entry + 99, "fits", 4); - + /* 18th component */ CU_ASSERT_EQUAL(entry[103], 0); CU_ASSERT_EQUAL(entry[104], 2); CU_ASSERT_NSTRING_EQUAL(entry + 105, "in", 2); - + /* 19th component */ CU_ASSERT_EQUAL(entry[107], 0); CU_ASSERT_EQUAL(entry[108], 11); CU_ASSERT_NSTRING_EQUAL(entry + 109, "a single SL", 11); - + /* 20th component */ CU_ASSERT_EQUAL(entry[120], 0); CU_ASSERT_EQUAL(entry[121], 38); CU_ASSERT_NSTRING_EQUAL(entry + 122, "entry as it takes " "just two hundred and", 38); - + /* 21th component */ CU_ASSERT_EQUAL(entry[160], 0); CU_ASSERT_EQUAL(entry[161], 29); CU_ASSERT_NSTRING_EQUAL(entry + 162, "fifty bytes bytes bytes bytes", 29); - + /* 22th component */ CU_ASSERT_EQUAL(entry[191], 0); CU_ASSERT_EQUAL(entry[192], 53); CU_ASSERT_NSTRING_EQUAL(entry + 193, "bytes bytes bytes bytes bytes bytes" " bytes bytes bytes", 53); - + /* 23th component */ CU_ASSERT_EQUAL(entry[246], 0x4); /* parent */ CU_ASSERT_EQUAL(entry[247], 0); @@ -1379,15 +1379,15 @@ static void test_rrip_get_susp_fields_symlink() CU_ASSERT_NSTRING_EQUAL(entry + 250, "bytes", 5); susp_info_free(&susp); - + free(node); free(link); } -void add_rockridge_suite() +void add_rockridge_suite() { CU_pSuite pSuite = CU_add_suite("RockRidge Suite", NULL, NULL); - + CU_add_test(pSuite, "rrip_calc_len(file)", test_rrip_calc_len_file); CU_add_test(pSuite, "rrip_calc_len(symlink)", test_rrip_calc_len_symlink); CU_add_test(pSuite, "rrip_get_susp_fields(file)", test_rrip_get_susp_fields_file);