From ff7fd10e25f5f68a3454c92103cfc5102ccb16ac Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Thu, 31 May 2007 04:25:39 +0000 Subject: [PATCH] Changed tree, re-implemented and fixed a lot of problematic areas --- libisofs/trunk/Makefile.am | 4 +- libisofs/trunk/libisofs/ecma119.c | 307 ++++++++++++--------- libisofs/trunk/libisofs/ecma119.h | 40 ++- libisofs/trunk/libisofs/ecma119_tree.c | 329 ++++++++++++++++++----- libisofs/trunk/libisofs/ecma119_tree.h | 44 +-- libisofs/trunk/libisofs/exclude.c | 32 +-- libisofs/trunk/libisofs/exclude.h | 29 +- libisofs/trunk/libisofs/joliet.c | 222 +++++++++------- libisofs/trunk/libisofs/joliet.h | 32 ++- libisofs/trunk/libisofs/libisofs.h | 156 ++++++++--- libisofs/trunk/libisofs/rockridge.c | 71 +++-- libisofs/trunk/libisofs/susp.c | 36 +-- libisofs/trunk/libisofs/tree.c | 353 +++++++++++++++++-------- libisofs/trunk/libisofs/tree.h | 113 ++++---- libisofs/trunk/libisofs/util.c | 155 +++++++---- libisofs/trunk/libisofs/util.h | 24 +- libisofs/trunk/libisofs/volume.c | 198 +++++++------- libisofs/trunk/libisofs/volume.h | 2 +- libisofs/trunk/test/iso.c | 6 +- 19 files changed, 1397 insertions(+), 756 deletions(-) diff --git a/libisofs/trunk/Makefile.am b/libisofs/trunk/Makefile.am index 3597005f..37d2e723 100644 --- a/libisofs/trunk/Makefile.am +++ b/libisofs/trunk/Makefile.am @@ -29,7 +29,9 @@ libisofs_libisofs_la_SOURCES = \ libisofs/exclude.c \ libisofs/exclude.h \ libisofs/hash.h \ - libisofs/hash.c + libisofs/hash.c \ + libisofs/file.h \ + libisofs/file.c libinclude_HEADERS = \ libisofs/libisofs.h diff --git a/libisofs/trunk/libisofs/ecma119.c b/libisofs/trunk/libisofs/ecma119.c index 0f484ce8..6b534693 100755 --- a/libisofs/trunk/libisofs/ecma119.c +++ b/libisofs/trunk/libisofs/ecma119.c @@ -16,6 +16,7 @@ #include "volume.h" #include "tree.h" #include "util.h" +#include "file.h" #include "libisofs.h" #include "libburn/libburn.h" @@ -101,30 +102,35 @@ add_susp_fields_rec(struct ecma119_write_target *t, { size_t i; - if (!node->iso_self) - return; - rrip_add_PX(t, node); rrip_add_NM(t, node); rrip_add_TF(t, node); - if (node->iso_self->attrib.st_rdev) - rrip_add_PN(t, node); - if (S_ISLNK(node->iso_self->attrib.st_mode)) - rrip_add_SL(t, node); - if (node->type == ECMA119_FILE && node->file.real_me) - rrip_add_CL(t, node); - if (node->type == ECMA119_DIR - && node->dir.real_parent != node->parent) { - rrip_add_RE(t, node); - rrip_add_PL(t, node); + + switch (node->type) { + case ECMA119_FILE: + break; + case ECMA119_SYMLINK: + rrip_add_SL(t, node); + break; + case ECMA119_DIR: + if (node->info.dir.real_parent != node->parent) { + rrip_add_RE(t, node); + rrip_add_PL(t, node); + } + for (i = 0; i < node->info.dir.nchildren; i++) { + add_susp_fields_rec(t, node->info.dir.children[i]); + } + break; + case ECMA119_PLACEHOLDER: + rrip_add_CL(t, node); + break; + default: + // FIXME support for device blocks by uncommenting this + //if (node->iso_self->attrib.st_rdev) + // rrip_add_PN(t, node); + break; } susp_add_CE(t, node); - - if (node->type == ECMA119_DIR) { - for (i = 0; i < node->dir.nchildren; i++) { - add_susp_fields_rec(t, node->dir.children[i]); - } - } } static void @@ -151,35 +157,35 @@ calc_dir_size(struct ecma119_write_target *t, assert(dir->type == ECMA119_DIR); t->dirlist_len++; - dir->dir.len = 34 + dir->dir.self_susp.non_CE_len - + 34 + dir->dir.parent_susp.non_CE_len; - dir->dir.CE_len = dir->dir.self_susp.CE_len - + dir->dir.parent_susp.CE_len; - for (i = 0; i < dir->dir.nchildren; i++) { - struct ecma119_tree_node *ch = dir->dir.children[i]; + dir->info.dir.len = 34 + dir->info.dir.self_susp.non_CE_len + + 34 + dir->info.dir.parent_susp.non_CE_len; + dir->info.dir.CE_len = dir->info.dir.self_susp.CE_len + + dir->info.dir.parent_susp.CE_len; + for (i = 0; i < dir->info.dir.nchildren; ++i) { + struct ecma119_tree_node *ch = dir->info.dir.children[i]; - newlen = dir->dir.len + ch->dirent_len + ch->susp.non_CE_len; - if ((newlen % 2048) < (dir->dir.len % 2048)) { - dir->dir.len = newlen + (2048 - (dir->dir.len % 2048)); + newlen = dir->info.dir.len + ch->dirent_len + ch->susp.non_CE_len; + if ((newlen % 2048) < (dir->info.dir.len % 2048)) { + dir->info.dir.len = newlen + (2048 - (dir->info.dir.len % 2048)); + } else { + dir->info.dir.len += ch->dirent_len + ch->susp.non_CE_len; } - else { - dir->dir.len += ch->dirent_len + ch->susp.non_CE_len; - } - dir->dir.CE_len += ch->susp.CE_len; + dir->info.dir.CE_len += ch->susp.CE_len; } - t->total_dir_size += round_up(dir->dir.len + dir->dir.CE_len, + t->total_dir_size += round_up(dir->info.dir.len + dir->info.dir.CE_len, t->block_size); - for (i = 0; i < dir->dir.nchildren; i++) { - struct ecma119_tree_node *ch = dir->dir.children[i]; - struct iso_tree_node *iso = ch->iso_self; + for (i = 0; i < dir->info.dir.nchildren; i++) { + struct ecma119_tree_node *ch = dir->info.dir.children[i]; + //struct iso_tree_node *iso = ch->iso_self; if (ch->type == ECMA119_DIR) { calc_dir_size(t, ch); - } else if (iso && iso->attrib.st_size - && iso->loc.type == LIBISO_FILESYS - && iso->loc.path) { - t->filelist_len++; - } + } +// else if (iso && iso->attrib.st_size +// && iso->loc.type == LIBISO_FILESYS +// && iso->loc.path) { +// t->filelist_len++; +// } } } @@ -195,26 +201,27 @@ calc_dir_pos(struct ecma119_write_target *t, assert(dir->type == ECMA119_DIR); - /* we don't need to set iso_self->block since each tree writes - * its own directories */ - dir->block = t->curblock; - t->curblock += div_up(dir->dir.len + dir->dir.CE_len, t->block_size); + dir->info.dir.block = t->curblock; + t->curblock += div_up(dir->info.dir.len + dir->info.dir.CE_len, t->block_size); t->dirlist[t->curfile++] = dir; - for (i = 0; i < dir->dir.nchildren; i++) { - struct ecma119_tree_node *ch = dir->dir.children[i]; + for (i = 0; i < dir->info.dir.nchildren; i++) { + struct ecma119_tree_node *ch = dir->info.dir.children[i]; if (ch->type == ECMA119_DIR) calc_dir_pos(t, ch); } +} - /* reset curfile when we're finished */ - if (!dir->parent) { - t->curfile = 0; - } +static int +cmp_file(const void *f1, const void *f2) +{ + struct iso_file *f = *((struct iso_file**)f1); + struct iso_file *g = *((struct iso_file**)f2); + /* higher weighted first */ + return g->sort_weight - f->sort_weight; } /** - * Fill out the block field for each ecma119_tree_node that is a file and fill - * out t->filelist. + * Fill out the block field for each file and fill out t->filelist. */ static void calc_file_pos(struct ecma119_write_target *t, @@ -223,31 +230,40 @@ calc_file_pos(struct ecma119_write_target *t, size_t i; assert(dir->type == ECMA119_DIR); + + t->filelist = calloc(1, sizeof(struct iso_file *) * t->file_table->count); - for (i = 0; i < dir->dir.nchildren; i++) { - struct ecma119_tree_node *ch = dir->dir.children[i]; - if (ch->type == ECMA119_FILE && ch->iso_self) { - struct iso_tree_node *iso = ch->iso_self; - off_t size = iso->attrib.st_size; + for (i = 0; i < FILE_HASH_NODES; ++i) { + + struct iso_file_hash_node *node; - iso->block = ch->block = t->curblock; - t->curblock += div_up(size, t->block_size); - if (size && iso->loc.type == LIBISO_FILESYS - && iso->loc.path) - t->filelist[t->curfile++] = ch; - } + node = t->file_table->table[i]; + if (!node) + continue; + + do { + struct iso_file *file = node->file; + if (file->size) + t->filelist[t->curfile++] = file; + node = node->next; + } while (node); } - - for (i = 0; i < dir->dir.nchildren; i++) { - struct ecma119_tree_node *ch = dir->dir.children[i]; - if (ch->type == ECMA119_DIR) - calc_file_pos(t, ch); + + t->filelist_len = t->curfile; + + /* sort */ + if ( t->sort_files ) + qsort(t->filelist, t->filelist_len, sizeof(void*), cmp_file); + + /* fill block value */ + for ( i = 0; i < t->filelist_len; ++i) { + struct iso_file *file = t->filelist[i]; + file->block = t->curblock; + t->curblock += div_up(file->size, t->block_size); } - + /* reset curfile when we're finished */ - if (!dir->parent) { - t->curfile = 0; - } + t->curfile = 0; } struct ecma119_write_target* @@ -259,33 +275,48 @@ ecma119_target_new(struct iso_volset *volset, struct ecma119_write_target *t = calloc(1, sizeof(struct ecma119_write_target)); size_t i, j, cur; - struct iso_tree_node *iso_root = volset->volume[volnum]->root; + struct iso_tree_node *iso_root = + (struct iso_tree_node*) volset->volume[volnum]->root; + //TODO default values here, need an API for this + t->cache_inodes = 1; + t->replace_mode = 1; + t->dir_mode = 0555; + t->file_mode = 0444; + t->gid = 0; + t->uid = 0; + t->input_charset = "UTF-8"; + t->ouput_charset = "UTF-8"; + t->sort_files = 1; + + t->file_table = iso_file_table_new(t->cache_inodes); volset->refcount++; - t->root = ecma119_tree_create(t, iso_root); + t->iso_level = level; + t->block_size = 2048; + + t->rockridge = (flags & ECMA119_ROCKRIDGE) ? 1 : 0; t->joliet = (flags & ECMA119_JOLIET) ? 1 : 0; + + t->root = ecma119_tree_create(t, iso_root); if (t->joliet) t->joliet_root = joliet_tree_create(t, iso_root); t->volset = volset; t->volnum = volnum; t->now = time(NULL); - t->rockridge = (flags & ECMA119_ROCKRIDGE) ? 1 : 0; - t->iso_level = level; - t->block_size = 2048; - if (t->rockridge) add_susp_fields(t); + calc_dir_size(t, t->root); if (t->joliet) { joliet_calc_dir_size(t, t->joliet_root); - t->pathlist_joliet = calloc(1, sizeof(void*) * t->dirlist_len); - t->dirlist_joliet = calloc(1, sizeof(void*) * t->dirlist_len); + t->pathlist_joliet = calloc(1, sizeof(void*) * t->dirlist_len_joliet); + t->dirlist_joliet = calloc(1, sizeof(void*) * t->dirlist_len_joliet); } t->dirlist = calloc(1, sizeof(void*) * t->dirlist_len); t->pathlist = calloc(1, sizeof(void*) * t->dirlist_len); - t->filelist = calloc(1, sizeof(void*) * t->filelist_len); + //t->filelist = calloc(1, sizeof(void*) * t->filelist_len); /* fill out the pathlist */ t->pathlist[0] = t->root; @@ -293,10 +324,10 @@ ecma119_target_new(struct iso_volset *volset, cur = 1; for (i = 0; i < t->dirlist_len; i++) { struct ecma119_tree_node *dir = t->pathlist[i]; - for (j = 0; j < dir->dir.nchildren; j++) { - struct ecma119_tree_node *ch = dir->dir.children[j]; + for (j = 0; j < dir->info.dir.nchildren; j++) { + struct ecma119_tree_node *ch = dir->info.dir.children[j]; if (ch->type == ECMA119_DIR) { - size_t len = 8 + strlen(ch->name); + size_t len = 8 + strlen(ch->iso_name); t->pathlist[cur++] = ch; t->path_table_size += len + len % 2; } @@ -323,11 +354,19 @@ ecma119_target_new(struct iso_volset *volset, } calc_dir_pos(t, t->root); - if (t->joliet) + + /* reset curfile when we're finished */ + t->curfile = 0; + if (t->joliet) { + joliet_calc_dir_pos(t, t->joliet_root); + + /* reset curfile when we're finished */ + t->curfile = 0; + } calc_file_pos(t, t->root); - if (t->joliet) - joliet_update_file_pos (t, t->joliet_root); + //if (t->joliet) + // joliet_update_file_pos (t, t->joliet_root); if (t->rockridge) { susp_finalize(t, t->root); @@ -406,11 +445,13 @@ wr_files(struct ecma119_write_target *t, uint8_t *buf) { struct state_files *f_st = &t->state_files; size_t nread; - struct ecma119_tree_node *f = t->filelist[f_st->file]; - const char *path = f->iso_self->loc.path; + struct iso_file *f = t->filelist[f_st->file]; + const char *path = f->path; + if (!f_st->fd) { - f_st->data_len = f->iso_self->attrib.st_size; + printf("Writing file %s\n", path); + f_st->data_len = f->size; f_st->fd = fopen(path, "r"); if (!f_st->fd) err(1, "couldn't open %s for reading", path); @@ -438,16 +479,16 @@ write_pri_vol_desc(struct ecma119_write_target *t, uint8_t *buf) { struct ecma119_pri_vol_desc *vol = (struct ecma119_pri_vol_desc*)buf; struct iso_volume *volume = t->volset->volume[t->volnum]; - char *vol_id = str2d_char(volume->volume_id); - char *pub_id = str2a_char(volume->publisher_id); - char *data_id = str2a_char(volume->data_preparer_id); - char *volset_id = str2d_char(t->volset->volset_id); + char *vol_id = str2d_char(volume->volume_id, t->input_charset); + char *pub_id = str2a_char(volume->publisher_id, t->input_charset); + char *data_id = str2a_char(volume->data_preparer_id, t->input_charset); + char *volset_id = str2d_char(t->volset->volset_id, t->input_charset); - char *system_id = str2a_char(volume->system_id); - char *application_id = str2a_char(volume->application_id); - char *copyright_file_id = str2d_char(volume->copyright_file_id); - char *abstract_file_id = str2d_char(volume->abstract_file_id); - char *biblio_file_id = str2d_char(volume->biblio_file_id); + char *system_id = str2a_char(volume->system_id, t->input_charset); + char *application_id = str2a_char(volume->application_id, t->input_charset); + char *copyright_file_id = str2d_char(volume->copyright_file_id, t->input_charset); + char *abstract_file_id = str2d_char(volume->abstract_file_id, t->input_charset); + char *biblio_file_id = str2d_char(volume->biblio_file_id, t->input_charset); vol->vol_desc_type[0] = 1; memcpy(vol->std_identifier, "CD001", 5); @@ -522,17 +563,18 @@ write_path_table(struct ecma119_write_target *t, int l_type, uint8_t *buf) for (i = 0; i < t->dirlist_len; i++) { dir = t->pathlist[i]; + assert(dir->type == ECMA119_DIR); while ((i) && t->pathlist[parent] != dir->parent) parent++; assert(parent < i || i == 0); rec = (struct ecma119_path_table_record*) buf; - rec->len_di[0] = dir->parent ? (uint8_t) strlen(dir->name) : 1; + rec->len_di[0] = dir->parent ? (uint8_t) strlen(dir->iso_name) : 1; rec->len_xa[0] = 0; - write_int(rec->block, dir->block, 4); + write_int(rec->block, dir->info.dir.block, 4); write_int(rec->parent, parent + 1, 2); if (dir->parent) - memcpy(rec->dir_id, dir->name, rec->len_di[0]); + memcpy(rec->dir_id, dir->iso_name, rec->len_di[0]); buf += 8 + rec->len_di[0] + (rec->len_di[0] % 2); } } @@ -558,22 +600,36 @@ write_one_dir_record(struct ecma119_write_target *t, int file_id, uint8_t *buf) { + uint32_t len; + uint32_t block; uint8_t len_dr = (file_id >= 0) ? 34 : node->dirent_len; - uint8_t len_fi = (file_id >= 0) ? 1 : strlen(node->name); + uint8_t len_fi = (file_id >= 0) ? 1 : strlen(node->iso_name); uint8_t f_id = (uint8_t) ((file_id == 3) ? 0 : file_id); - uint8_t *name = (file_id >= 0) ? &f_id : (uint8_t*)node->name; - uint32_t len = (node->type == ECMA119_DIR) ? node->dir.len - : node->file.real_me ? 0 : node->iso_self->attrib.st_size; + uint8_t *name = (file_id >= 0) ? &f_id : (uint8_t*)node->iso_name; struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf; - + + if (node->type == ECMA119_DIR) { + len = node->info.dir.len; + block = node->info.dir.block; + } else if (node->type == ECMA119_FILE) { + len = node->info.file->size; + block = node->info.file->block; + } else { + /* for nodes other than files and dirs, we set both len and block to 0 */ + len = 0; + block = 0; + } + /* we don't write out susp fields for the root node */ if (t->rockridge) { if (file_id == 0) { - susp_write(t, &node->dir.self_susp, &buf[len_dr]); - len_dr += node->dir.self_susp.non_CE_len; + assert(node->type == ECMA119_DIR); + susp_write(t, &node->info.dir.self_susp, &buf[len_dr]); + len_dr += node->info.dir.self_susp.non_CE_len; } else if (file_id == 1) { - susp_write(t, &node->dir.parent_susp, &buf[len_dr]); - len_dr += node->dir.parent_susp.non_CE_len; + assert(node->type == ECMA119_DIR); + susp_write(t, &node->info.dir.parent_susp, &buf[len_dr]); + len_dr += node->info.dir.parent_susp.non_CE_len; } else if (file_id < 0) { susp_write(t, &node->susp, &buf[len_dr]); len_dr += node->susp.non_CE_len; @@ -583,7 +639,7 @@ write_one_dir_record(struct ecma119_write_target *t, node = node->parent; rec->len_dr[0] = len_dr; - iso_bb(rec->block, node->block, 4); + iso_bb(rec->block, block, 4); iso_bb(rec->length, len, 4); iso_datetime_7(rec->recording_time, t->now); rec->flags[0] = (node->type == ECMA119_DIR) ? 2 : 0; @@ -611,8 +667,8 @@ write_one_dir(struct ecma119_write_target *t, write_one_dir_record(t, dir, 1, buf); buf += ((struct ecma119_dir_record*) buf)->len_dr[0]; - for (i = 0; i < dir->dir.nchildren; i++) { - write_one_dir_record(t, dir->dir.children[i], -1, buf); + for (i = 0; i < dir->info.dir.nchildren; i++) { + write_one_dir_record(t, dir->info.dir.children[i], -1, buf); len = ((struct ecma119_dir_record*) buf)->len_dr[0]; if ((buf + len - prior_buf) >= 2048) { for (j = len - 1; j >= 0; j--) { @@ -629,16 +685,16 @@ write_one_dir(struct ecma119_write_target *t, /* write the susp continuation areas */ if (t->rockridge) { - susp_write_CE(t, &dir->dir.self_susp, buf); - buf += dir->dir.self_susp.CE_len; - susp_write_CE(t, &dir->dir.parent_susp, buf); - buf += dir->dir.parent_susp.CE_len; - for (i = 0; i < dir->dir.nchildren; i++) { - susp_write_CE(t, &dir->dir.children[i]->susp, buf); - buf += dir->dir.children[i]->susp.CE_len; + susp_write_CE(t, &dir->info.dir.self_susp, buf); + buf += dir->info.dir.self_susp.CE_len; + susp_write_CE(t, &dir->info.dir.parent_susp, buf); + buf += dir->info.dir.parent_susp.CE_len; + for (i = 0; i < dir->info.dir.nchildren; i++) { + susp_write_CE(t, &dir->info.dir.children[i]->susp, buf); + buf += dir->info.dir.children[i]->susp.CE_len; } } - assert (buf - orig_buf == dir->dir.len + dir->dir.CE_len); + assert (buf - orig_buf == dir->info.dir.len + dir->info.dir.CE_len); } static void @@ -649,7 +705,7 @@ write_dirs(struct ecma119_write_target *t, uint8_t *buf) for (i = 0; i < t->dirlist_len; i++) { dir = t->dirlist[i]; write_one_dir(t, dir, buf); - buf += round_up(dir->dir.len + dir->dir.CE_len, t->block_size); + buf += round_up(dir->info.dir.len + dir->info.dir.CE_len, t->block_size); } } @@ -714,6 +770,9 @@ bs_free_data(struct burn_source *bs) { struct ecma119_write_target *t = (struct ecma119_write_target*)bs->data; ecma119_tree_free(t->root); + iso_file_table_clear(t->file_table); + + //FIXME free joliet tree free(t->dirlist); free(t->pathlist); free(t->dirlist_joliet); diff --git a/libisofs/trunk/libisofs/ecma119.h b/libisofs/trunk/libisofs/ecma119.h index 79505509..800b9192 100755 --- a/libisofs/trunk/libisofs/ecma119.h +++ b/libisofs/trunk/libisofs/ecma119.h @@ -61,6 +61,35 @@ struct ecma119_write_target unsigned int rockridge:1; unsigned int joliet:1; unsigned int iso_level:2; + + int replace_mode; /**< Replace ownership and modes of files + * + * 0. filesystem values + * 1. useful values + * bits 1-4 bitmask: + * 2 - replace dir + * 3 - replace file + * 4 - replace gid + * 5 - replace uid + */ + mode_t dir_mode; + mode_t file_mode; + gid_t gid; + uid_t uid; + + char *input_charset; + char *ouput_charset; + + int cache_inodes; + + int sort_files; /**< if sort files or not. Sorting is based of + * the weight of each file */ + + /** + * In the CD, each file must have an unique inode number. So each + * time we add a new file, this is incremented. + */ + ino_t ino; int curblock; uint16_t block_size; @@ -86,10 +115,13 @@ struct ecma119_write_target size_t dirlist_len; /**< The length of the previous 2 lists. */ - struct ecma119_tree_node **filelist; - /**< A pre-order list of files with - * non-NULL paths and non-zero sizes. + + struct iso_file_table *file_table; + /**< + * A hash table with info about all files */ + + struct iso_file **filelist; /**< A pre-order list of files.*/ size_t filelist_len; /* Length of the previous list. */ int curfile; /**< Used as a helper field for writing @@ -101,6 +133,8 @@ struct ecma119_write_target */ struct joliet_tree_node **dirlist_joliet; struct joliet_tree_node **pathlist_joliet; + + size_t dirlist_len_joliet; enum ecma119_write_state state; /* The current state of the writer. */ diff --git a/libisofs/trunk/libisofs/ecma119_tree.c b/libisofs/trunk/libisofs/ecma119_tree.c index 0cbd387a..88359f04 100644 --- a/libisofs/trunk/libisofs/ecma119_tree.c +++ b/libisofs/trunk/libisofs/ecma119_tree.c @@ -12,54 +12,191 @@ static size_t calc_dirent_len(struct ecma119_tree_node *n) { - int ret = n->name ? strlen(n->name) + 33 : 34; + int ret = n->iso_name ? strlen(n->iso_name) + 33 : 34; if (ret % 2) ret++; return ret; } +static void +replace_node_mode(struct ecma119_write_target *t, struct stat *st) +{ + if ( S_ISDIR(st->st_mode) ) { + if ( t->replace_mode & 0x02 ) { + /* replace dir mode with specific */ + st->st_mode &= S_IFMT; + st->st_mode |= t->dir_mode; + } else if (t->replace_mode & 0x01) { + /* replace dir mode with default */ + /* read perm */ + mode_t new_mode = (st->st_mode & S_IFMT) | 0444; + /* search bit if any */ + if ( st->st_mode & 0111) + new_mode |= 0111; + st->st_mode = new_mode; + } + } else { + if ( t->replace_mode & 0x04 ) { + /* replace file mode with specific */ + st->st_mode &= S_IFMT; + st->st_mode |= t->file_mode; + } else if (t->replace_mode & 0x01) { + /* replace file mode with default */ + /* read perm */ + mode_t new_mode = (st->st_mode & S_IFMT) | 0444; + /* execute bit if any */ + if ( st->st_mode & 0111) + new_mode |= 0111; + st->st_mode = new_mode; + } + + } + if ( t->replace_mode & 0x08 ) { + /* replace gid mode with specific */ + st->st_gid = t->gid; + } else if (t->replace_mode & 0x01) { + st->st_gid = 0; + } + if ( t->replace_mode & 0x10 ) { + /* replace gid mode with specific */ + st->st_uid = t->uid; + } else if (t->replace_mode & 0x01) { + st->st_uid = 0; + } +} + +static struct ecma119_tree_node* +create_ecma119_node(struct ecma119_write_target *t, + struct ecma119_tree_node *parent, + struct iso_tree_node *iso) +{ + struct ecma119_tree_node *ret; + char *(*iso_name)(const char *, const char *) = ISO_ISDIR(iso) ? + ((t->iso_level == 1) ? iso_1_dirid : iso_2_dirid) + : ((t->iso_level == 1) ? iso_1_fileid : iso_2_fileid); + + assert(t && (!parent || parent->type == ECMA119_DIR) && iso ); + + ret = calloc(1, sizeof(struct ecma119_tree_node)); + + ret->iso_name = iso->name ? iso_name(iso->name, t->input_charset) : NULL; + ret->dirent_len = calc_dirent_len(ret); + ret->attrib = iso->attrib; + if ( t->rockridge && t->replace_mode ) + replace_node_mode(t, &ret->attrib); + + if (!iso->name) + ret->full_name = NULL; + else if ( strcmp(t->input_charset,t->ouput_charset) ) + ret->full_name = convert_str(iso->name, t->input_charset, + t->ouput_charset); + else + ret->full_name = strdup(iso->name); + ret->target = t; + ret->parent = parent; + return ret; +} + static struct ecma119_tree_node* create_dir(struct ecma119_write_target *t, struct ecma119_tree_node *parent, - struct iso_tree_node *iso) + struct iso_tree_node_dir *iso) { struct ecma119_tree_node *ret; assert(t && (!parent || parent->type == ECMA119_DIR) - && iso && S_ISDIR(iso->attrib.st_mode)); + && iso && S_ISDIR(iso->node.attrib.st_mode)); - ret = calloc(1, sizeof(struct ecma119_tree_node)); - ret->name = iso->name ? ((t->iso_level == 1) ? iso_1_dirid(iso->name) - : iso_2_dirid(iso->name)) - : NULL; - ret->dirent_len = calc_dirent_len(ret); - ret->iso_self = iso; - ret->target = t; + ret = create_ecma119_node(t, parent, (struct iso_tree_node*) iso); ret->type = ECMA119_DIR; - ret->parent = ret->dir.real_parent = parent; - ret->dir.depth = parent ? parent->dir.depth + 1 : 1; - ret->dir.nchildren = iso->nchildren; - ret->dir.children = calloc(1, sizeof(void*) * iso->nchildren); + ret->info.dir.real_parent = parent; + ret->info.dir.depth = parent ? parent->info.dir.depth + 1 : 1; + ret->info.dir.nchildren = 0; + ret->info.dir.children = calloc(1, sizeof(void*) * iso->nchildren); return ret; } static struct ecma119_tree_node* create_file(struct ecma119_write_target *t, struct ecma119_tree_node *parent, - struct iso_tree_node *iso) + struct iso_tree_node_file *iso) +{ + struct ecma119_tree_node *ret; + struct iso_file *file; + + assert(t && iso && parent && parent->type == ECMA119_DIR); + + ret = create_ecma119_node(t, parent, (struct iso_tree_node*) iso); + ret->type = ECMA119_FILE; + + /* get iso_file struct */ + file = iso_file_table_lookup(t->file_table, iso); + if ( file == NULL ) { + file = iso_file_new(iso); + iso_file_table_add_file(t->file_table, file); + file->ino = ++t->ino; + } else { + /* increment number of hard-links */ + file->nlink++; + } + + ret->attrib.st_nlink = file->nlink; + ret->attrib.st_ino = file->ino; + ret->info.file = file; + return ret; +} + +static struct ecma119_tree_node* +create_placeholder(struct ecma119_write_target *t, + struct ecma119_tree_node *parent, + struct ecma119_tree_node *real) +{ + struct ecma119_tree_node *ret; + + assert(t && real && real->type == ECMA119_DIR + && parent && parent->type == ECMA119_DIR); + + ret = calloc(1, sizeof(struct ecma119_tree_node)); + ret->iso_name = real->iso_name; /* TODO strdup? */ + /* FIXME + * if we strdup above, if name changes in mangle_all, + * this probably keeps as original. + * if not, both change, but we need to update dirent_len. + * I think that attributes of a placeholder must be taken from + * real_me, not keept here. + * FIXME + * Another question is that real is a dir, while placeholder is + * a file, and ISO name restricctions are different, what to do? + */ + ret->dirent_len = real->dirent_len; + ret->attrib = real->attrib; + ret->full_name = strdup(real->full_name); + ret->target = t; + ret->parent = parent; + ret->type = ECMA119_PLACEHOLDER; + ret->info.real_me = real; + ret->attrib.st_nlink = 1; + ret->attrib.st_ino = ++t->ino; + return ret; +} + +static struct ecma119_tree_node* +create_symlink(struct ecma119_write_target *t, + struct ecma119_tree_node *parent, + struct iso_tree_node_symlink *iso) { struct ecma119_tree_node *ret; assert(t && iso && parent && parent->type == ECMA119_DIR); - ret = calloc(1, sizeof(struct ecma119_tree_node)); - ret->name = iso->name ? ((t->iso_level == 1) ? iso_1_fileid(iso->name) - : iso_2_fileid(iso->name)) + ret = create_ecma119_node(t, parent, (struct iso_tree_node*) iso); + ret->iso_name = iso->node.name ? ((t->iso_level == 1) ? + iso_1_fileid(iso->node.name, t->input_charset) + : iso_2_fileid(iso->node.name, t->input_charset)) : NULL; - ret->dirent_len = calc_dirent_len(ret); - ret->parent = parent; - ret->iso_self = iso; - ret->target = t; - ret->type = ECMA119_FILE; + ret->type = ECMA119_SYMLINK; + ret->info.dest = iso->dest; /* TODO strdup? */ + ret->attrib.st_nlink = 1; + ret->attrib.st_ino = ++t->ino; return ret; } @@ -68,15 +205,41 @@ create_tree(struct ecma119_write_target *t, struct ecma119_tree_node *parent, struct iso_tree_node *iso) { - struct ecma119_tree_node *ret; - size_t i; + struct ecma119_tree_node *ret = NULL; assert(t && iso); - - ret = (S_ISDIR(iso->attrib.st_mode) ? create_dir : create_file) - (t, parent, iso); - for (i = 0; i < iso->nchildren; i++) { - ret->dir.children[i] = create_tree(t, ret, iso->children[i]); + + if ( iso->hide_flags & LIBISO_HIDE_ON_RR ) + return NULL; + + switch (iso->attrib.st_mode & S_IFMT) { + case S_IFREG: + ret = create_file(t, parent, (struct iso_tree_node_file*)iso); + break; + case S_IFLNK: + if ( !t->rockridge ) + printf("Can't add symlinks to a non ISO tree. Skipping %s \n", + iso->name); + else + ret = create_symlink(t, parent, (struct iso_tree_node_symlink*)iso); + break; + case S_IFDIR: + { + size_t i; + struct iso_tree_node_dir *dir = (struct iso_tree_node_dir*)iso; + ret = create_dir(t, parent, dir); + for (i = 0; i < dir->nchildren; i++) { + struct ecma119_tree_node *child; + child = create_tree(t, ret, dir->children[i]); + if (child) + ret->info.dir.children[ret->info.dir.nchildren++] = child; + } + } + break; + default: + /* should never happen */ + assert( 0 ); + break; } return ret; } @@ -87,12 +250,13 @@ ecma119_tree_free(struct ecma119_tree_node *root) size_t i; if (root->type == ECMA119_DIR) { - for (i=0; i < root->dir.nchildren; i++) { - ecma119_tree_free(root->dir.children[i]); + for (i=0; i < root->info.dir.nchildren; i++) { + ecma119_tree_free(root->info.dir.children[i]); } - free(root->dir.children); + free(root->info.dir.children); } - free(root->name); + free(root->iso_name); + free(root->full_name); free(root); } @@ -102,8 +266,8 @@ max_child_name_len(struct ecma119_tree_node *root) size_t ret = 0, i; assert(root->type == ECMA119_DIR); - for (i=0; i < root->dir.nchildren; i++) { - size_t len = strlen(root->dir.children[i]->name); + for (i=0; i < root->info.dir.nchildren; i++) { + size_t len = strlen(root->info.dir.children[i]->iso_name); ret = MAX(ret, len); } return ret; @@ -120,13 +284,11 @@ reparent(struct ecma119_tree_node *child, assert(child && parent && parent->type == ECMA119_DIR && child->parent); /* replace the child in the original parent with a placeholder */ - for (i=0; i < child->parent->dir.nchildren; i++) { - if (child->parent->dir.children[i] == child) { - placeholder = create_file(child->target, - child->parent, - child->iso_self); - placeholder->file.real_me = child; - child->parent->dir.children[i] = placeholder; + for (i=0; i < child->parent->info.dir.nchildren; i++) { + if (child->parent->info.dir.children[i] == child) { + placeholder = create_placeholder(child->target, + child->parent, child); + child->parent->info.dir.children[i] = placeholder; found = 1; break; } @@ -135,10 +297,10 @@ reparent(struct ecma119_tree_node *child, /* add the child to its new parent */ child->parent = parent; - parent->dir.nchildren++; - parent->dir.children = realloc( parent->dir.children, - sizeof(void*) * parent->dir.nchildren ); - parent->dir.children[parent->dir.nchildren-1] = child; + parent->info.dir.nchildren++; + parent->info.dir.children = realloc( parent->info.dir.children, + sizeof(void*) * parent->info.dir.nchildren ); + parent->info.dir.children[parent->info.dir.nchildren-1] = child; } /** @@ -147,28 +309,50 @@ reparent(struct ecma119_tree_node *child, * - each path length is at most 255 characters */ static void -reorder_tree(struct ecma119_tree_node *root, +reorder_tree(struct ecma119_write_target *t, + struct ecma119_tree_node *root, struct ecma119_tree_node *cur) { size_t max_path; assert(root && cur && cur->type == ECMA119_DIR); - cur->dir.depth = cur->parent ? cur->parent->dir.depth + 1 : 1; - cur->dir.path_len = cur->parent ? cur->parent->dir.path_len - + strlen(cur->name) : 0; - max_path = cur->dir.path_len + cur->dir.depth + max_child_name_len(cur); + cur->info.dir.depth = cur->parent ? cur->parent->info.dir.depth + 1 : 1; + cur->info.dir.path_len = cur->parent ? cur->parent->info.dir.path_len + + strlen(cur->iso_name) : 0; + max_path = cur->info.dir.path_len + cur->info.dir.depth + + max_child_name_len(cur); - if (cur->dir.depth > 8 || max_path > 255) { - reparent(cur, root); - /* we are appended to the root's children now, so there is no - * need to recurse (the root will hit us again) */ + if (cur->info.dir.depth > 8 || max_path > 255) { + + if (t->rockridge) { + reparent(cur, root); + /* we are appended to the root's children now, so there is no + * need to recurse (the root will hit us again) */ + } else { + /* we need to delete cur */ + size_t i,j; + struct ecma119_tree_node *parent = cur->parent; + + printf("Can't dirs deeper than 8 without RR. Skipping %s\n", + cur->full_name); + for (i=0; i < parent->info.dir.nchildren; ++i) { + if (parent->info.dir.children[i] == cur) { + break; + } + } + assert ( i < parent->info.dir.nchildren); + for ( j = i; j < parent->info.dir.nchildren - 1; ++j) + parent->info.dir.children[j] = parent->info.dir.children[j+1]; + parent->info.dir.nchildren--; + ecma119_tree_free(cur); + } } else { size_t i; - for (i=0; i < cur->dir.nchildren; i++) { - if (cur->dir.children[i]->type == ECMA119_DIR) - reorder_tree(root, cur->dir.children[i]); + for (i=0; i < cur->info.dir.nchildren; i++) { + if (cur->info.dir.children[i]->type == ECMA119_DIR) + reorder_tree(t, root, cur->info.dir.children[i]); } } } @@ -178,7 +362,7 @@ cmp_node(const void *f1, const void *f2) { struct ecma119_tree_node *f = *((struct ecma119_tree_node**)f1); struct ecma119_tree_node *g = *((struct ecma119_tree_node**)f2); - return strcmp(f->name, g->name); + return strcmp(f->iso_name, g->iso_name); } static void @@ -188,10 +372,11 @@ sort_tree(struct ecma119_tree_node *root) assert(root && root->type == ECMA119_DIR); - qsort(root->dir.children, root->dir.nchildren, sizeof(void*), cmp_node); - for (i=0; i < root->dir.nchildren; i++) { - if (root->dir.children[i]->type == ECMA119_DIR) - sort_tree(root->dir.children[i]); + qsort(root->info.dir.children, root->info.dir.nchildren, + sizeof(void*), cmp_node); + for (i=0; i < root->info.dir.nchildren; i++) { + if (root->info.dir.children[i]->type == ECMA119_DIR) + sort_tree(root->info.dir.children[i]); } } @@ -246,7 +431,7 @@ static void mangle_all(struct ecma119_tree_node *dir) { size_t i, j, k; - struct ecma119_dir_info d = dir->dir; + struct ecma119_dir_info d = dir->info.dir; size_t n_change; int changed; @@ -257,8 +442,8 @@ mangle_all(struct ecma119_tree_node *dir) /* find the number of consecutive equal names */ j = 1; while ( i+j < d.nchildren && - !strcmp(d.children[i]->name, - d.children[i+j]->name) ) + !strcmp(d.children[i]->iso_name, + d.children[i+j]->iso_name) ) j++; if (j == 1) continue; @@ -266,7 +451,7 @@ mangle_all(struct ecma119_tree_node *dir) changed = 1; n_change = j / 10 + 1; for (k=0; k < j; k++) { - mangle_name(&(d.children[i+k]->name), + mangle_name(&(d.children[i+k]->iso_name), n_change, dir->target->iso_level, k); @@ -290,7 +475,7 @@ ecma119_tree_create(struct ecma119_write_target *t, struct iso_tree_node *iso_root) { t->root = create_tree(t, NULL, iso_root); - reorder_tree(t->root, t->root); + reorder_tree(t, t->root, t->root); sort_tree(t->root); mangle_all(t->root); return t->root; @@ -305,8 +490,8 @@ ecma119_tree_print(struct ecma119_tree_node *root, int spaces) memset(sp, ' ', spaces); sp[spaces] = '\0'; - printf("%s%s\n", sp, root->name); + printf("%s%s\n", sp, root->iso_name); if (root->type == ECMA119_DIR) - for (i=0; i < root->dir.nchildren; i++) - ecma119_tree_print(root->dir.children[i], spaces+2); + for (i=0; i < root->info.dir.nchildren; i++) + ecma119_tree_print(root->info.dir.children[i], spaces+2); } diff --git a/libisofs/trunk/libisofs/ecma119_tree.h b/libisofs/trunk/libisofs/ecma119_tree.h index 1d6023b8..a1409246 100644 --- a/libisofs/trunk/libisofs/ecma119_tree.h +++ b/libisofs/trunk/libisofs/ecma119_tree.h @@ -10,11 +10,18 @@ #ifndef LIBISO_ECMA119_TREE_H #define LIBISO_ECMA119_TREE_H +#include + +#include "file.h" + struct ecma119_write_target; +struct iso_tree_node; enum { ECMA119_FILE, - ECMA119_DIR + ECMA119_SYMLINK, + ECMA119_DIR, + ECMA119_PLACEHOLDER /**< placeholder for a relocated dir. */ }; struct ecma119_dir_info { @@ -25,6 +32,7 @@ struct ecma119_dir_info { * Directory Records (including SU) */ size_t CE_len; /**< sum of the lengths of children's * SUSP CE areas */ + size_t block; int depth; size_t path_len; /**< The length of a path up to, and @@ -37,39 +45,35 @@ struct ecma119_dir_info { /**< The parent before relocation */ }; -struct ecma119_file_info -{ - struct ecma119_tree_node *real_me; - /**< If this is non-NULL, the file is - * a placeholder for a relocated - * directory and this field points to - * that relocated directory. - */ -}; - /** * A node for a tree containing all the information necessary for writing * an ISO9660 volume. */ struct ecma119_tree_node { - char *name; /**< in ASCII, conforming to the - * current ISO level. */ + char *iso_name; /**< in ASCII, conforming to the + * current ISO level. */ + char *full_name; /**< full name, in current locale (TODO put this in UTF-8?) */ size_t dirent_len; /**< Length of the directory record, - * not including SU. */ - size_t block; + * not including SU. */ struct ecma119_tree_node *parent; - struct iso_tree_node *iso_self; + /*struct iso_tree_node *iso_self;*/ struct ecma119_write_target *target; + struct stat attrib; + struct susp_info susp; - int type; /**< file or directory */ - /* union {*/ + int type; /**< file, symlink, directory or placeholder */ + union { + struct iso_file *file; + char *dest; struct ecma119_dir_info dir; - struct ecma119_file_info file; - /* };*/ + struct ecma119_tree_node *real_me; /**< this field points to + * the relocated directory. + */ + } info; }; /** diff --git a/libisofs/trunk/libisofs/exclude.c b/libisofs/trunk/libisofs/exclude.c index 48e7fa21..f4e245a3 100644 --- a/libisofs/trunk/libisofs/exclude.c +++ b/libisofs/trunk/libisofs/exclude.c @@ -1,42 +1,38 @@ -#include "hash.h" #include "exclude.h" -static struct iso_hash_node *table[HASH_NODES]={0,}; -static int num=0; - void -iso_exclude_add_path(const char *path) +iso_exclude_add_path(struct iso_hash_table *table, const char *path) { if (!path) return; - num += iso_hash_insert(table, path); + table->num += iso_hash_insert(table->table, path); } -void -iso_exclude_remove_path(const char *path) +/*void +iso_exclude_remove_path(struct iso_hash_table *table, const char *path) { - if (!num || !path) + if (!table->num || !path) return; - num -= iso_hash_remove(table, path); -} + table->num -= iso_hash_remove(table->table, path); +}*/ void -iso_exclude_empty(void) +iso_exclude_empty(struct iso_hash_table *table) { - if (!num) + if (!table->num) return; - iso_hash_empty(table); - num=0; + iso_hash_empty(table->table); + table->num=0; } int -iso_exclude_lookup(const char *path) +iso_exclude_lookup(struct iso_hash_table *table, const char *path) { - if (!num || !path) + if (!table->num || !path) return 0; - return iso_hash_lookup(table, path); + return iso_hash_lookup(table->table, path); } diff --git a/libisofs/trunk/libisofs/exclude.h b/libisofs/trunk/libisofs/exclude.h index 319c4189..30a9a011 100644 --- a/libisofs/trunk/libisofs/exclude.h +++ b/libisofs/trunk/libisofs/exclude.h @@ -1,12 +1,37 @@ #ifndef ISO_EXCLUDE_H #define ISO_EXCLUDE_H +#include "hash.h" + +struct iso_hash_table { + struct iso_hash_node *table[HASH_NODES]; + int num; +}; + /** * Add a path to ignore when adding a directory recursively. * * \param path The path, on the local filesystem, of the file. */ -int -iso_exclude_lookup(const char *path); +int iso_exclude_lookup(struct iso_hash_table *table, const char *path); + +/** + * Add the path of a file or directory to ignore when adding a directory recursively. + * + * \param path The path, on the local filesystem, of the file. + */ +void iso_exclude_add_path(struct iso_hash_table *table, const char *path); + +/** + * Remove a path that was set to be ignored when adding a directory recusively. + * + * \param path The path, on the local filesystem, of the file. + */ +//void iso_exclude_remove_path(struct iso_hash_table *table, const char *path); + +/** + * Remove all paths that were set to be ignored when adding a directory recusively. + */ +void iso_exclude_empty(struct iso_hash_table *table); #endif /* ISO_EXCLUDE */ diff --git a/libisofs/trunk/libisofs/joliet.c b/libisofs/trunk/libisofs/joliet.c index 34be4d18..5447a48a 100644 --- a/libisofs/trunk/libisofs/joliet.c +++ b/libisofs/trunk/libisofs/joliet.c @@ -19,33 +19,66 @@ create_node(struct ecma119_write_target *t, struct joliet_tree_node *ret = calloc(1, sizeof(struct joliet_tree_node)); - ret->name = iso_j_id(iso->name); + ret->name = iso_j_id(iso->name, t->input_charset); ret->dirent_len = 34 + (ret->name ? ucslen(ret->name) * 2 : 0); - ret->len = iso->attrib.st_size; /* for dirs, we'll change this */ - ret->block = iso->block; /* only actually for files, not dirs */ ret->parent = parent; - ret->iso_self = iso; ret->target = t; - ret->nchildren = iso->nchildren; - if (ret->nchildren) - ret->children = calloc(sizeof(void*), ret->nchildren); + + if ( ISO_ISDIR(iso) ) { + struct iso_tree_node_dir *dir = (struct iso_tree_node_dir *) iso; + ret->info.dir.children = calloc(sizeof(void*), dir->nchildren); + ret->type = JOLIET_DIR; + } else { + /* it's a file */ + struct iso_tree_node_file *iso_f = (struct iso_tree_node_file *) iso; + struct iso_file *file; + file = iso_file_table_lookup(t->file_table, iso_f); + if ( file == NULL ) { + file = iso_file_new(iso_f); + iso_file_table_add_file(t->file_table, file); + } + ret->info.file = file; + ret->type = JOLIET_FILE; + } + return ret; } static struct joliet_tree_node* create_tree(struct ecma119_write_target *t, struct joliet_tree_node *parent, - struct iso_tree_node *iso_root) -{ - struct joliet_tree_node *root = create_node(t, parent, iso_root); - size_t i; - - for (i = 0; i < root->nchildren; i++) { - struct iso_tree_node *iso_ch = iso_root->children[i]; - if (ISO_ISDIR(iso_ch)) - root->children[i] = create_tree(t, root, iso_ch); - else - root->children[i] = create_node(t, root, iso_ch); + struct iso_tree_node *iso) +{ + struct joliet_tree_node *root; + assert(t && iso); + + if ( iso->hide_flags & LIBISO_HIDE_ON_JOLIET ) + return NULL; + + switch (iso->attrib.st_mode & S_IFMT) { + case S_IFREG: + root = create_node(t, parent, iso); + break; + case S_IFDIR: + { + size_t i; + struct joliet_tree_node *node; + struct iso_tree_node_dir *dir; + root = create_node(t, parent, iso); + dir = (struct iso_tree_node_dir*)iso; + for (i = 0; i < dir->nchildren; ++i) { + node = create_tree(t, root, dir->children[i]); + if ( node != NULL ) { + root->info.dir.children[root->info.dir.nchildren++] = node; + } + } + } + break; + default: + //TODO replace this printf + printf("Can't add this kind of node to a Joliet tree"); + return NULL; + break; } return root; } @@ -63,12 +96,15 @@ sort_tree(struct joliet_tree_node *root) { size_t i; - assert(root && ISO_ISDIR(root->iso_self)); + assert(root && (root->type == JOLIET_DIR)); - qsort(root->children, root->nchildren, sizeof(void*), cmp_node); - for (i = 0; i < root->nchildren; i++) - if (ISO_ISDIR(root->children[i]->iso_self)) - sort_tree(root->children[i]); + qsort(root->info.dir.children, root->info.dir.nchildren, + sizeof(void*), cmp_node); + for (i = 0; i < root->info.dir.nchildren; i++) { + struct joliet_tree_node *child = root->info.dir.children[i]; + if ( child->type == JOLIET_DIR ) + sort_tree(child); + } } void @@ -80,11 +116,11 @@ joliet_prepare_path_tables(struct ecma119_write_target *t) t->path_table_size_joliet = 10; /* root directory record */ cur = 1; - for (i = 0; i < t->dirlist_len; i++) { + for (i = 0; i < t->dirlist_len_joliet; i++) { struct joliet_tree_node *dir = t->pathlist_joliet[i]; - for (j = 0; j < dir->nchildren; j++) { - struct joliet_tree_node *ch = dir->children[j]; - if (ISO_ISDIR(ch->iso_self)) { + for (j = 0; j < dir->info.dir.nchildren; j++) { + struct joliet_tree_node *ch = dir->info.dir.children[j]; + if (ch->type == JOLIET_DIR) { size_t len = 8 + ucslen(ch->name)*2; t->pathlist_joliet[cur++] = ch; t->path_table_size_joliet += len; @@ -104,22 +140,22 @@ joliet_calc_dir_size(struct ecma119_write_target *t, size_t newlen; struct joliet_tree_node *ch; - assert(root && ISO_ISDIR(root->iso_self)); + assert(root && (root->type == JOLIET_DIR) ); - root->len = 68; /* for "." and ".." entries */ - for (i = 0; i < root->nchildren; i++) { - ch = root->children[i]; - newlen = root->len + ch->dirent_len; - if ((newlen % 2048) < (root->len % 2048)) { - root->len = newlen + (2048 - (root->len % 2048)); + t->dirlist_len_joliet++; + root->info.dir.len = 68; /* for "." and ".." entries */ + for (i = 0; i < root->info.dir.nchildren; ++i) { + ch = root->info.dir.children[i]; + newlen = root->info.dir.len + ch->dirent_len; + if ((newlen % 2048) < (root->info.dir.len % 2048)) { + root->info.dir.len = newlen + (2048 - (root->info.dir.len % 2048)); + } else { + root->info.dir.len += ch->dirent_len; } - else { - root->len += ch->dirent_len; - } - if (ISO_ISDIR(ch->iso_self)) + if (ch->type == JOLIET_DIR) joliet_calc_dir_size(t, ch); } - t->total_dir_size_joliet += round_up (root->len, t->block_size); + t->total_dir_size_joliet += round_up (root->info.dir.len, t->block_size); } /** @@ -132,45 +168,17 @@ joliet_calc_dir_pos(struct ecma119_write_target *t, size_t i; struct joliet_tree_node *ch; - assert(root && ISO_ISDIR(root->iso_self)); + assert(root && (root->type == JOLIET_DIR)); - root->block = t->curblock; - t->curblock += div_up(root->len, t->block_size); + root->info.dir.block = t->curblock; + t->curblock += div_up(root->info.dir.len, t->block_size); t->dirlist_joliet[t->curfile++] = root; - for (i = 0; i < root->nchildren; i++) { - ch = root->children[i]; - if (ISO_ISDIR(ch->iso_self)) + for (i = 0; i < root->info.dir.nchildren; i++) { + ch = root->info.dir.children[i]; + if (ch->type == JOLIET_DIR) joliet_calc_dir_pos(t, ch); } - - /* reset curfile when we're finished */ - if (!root->parent) - t->curfile = 0; -} - -void -joliet_update_file_pos(struct ecma119_write_target *t, - struct joliet_tree_node *dir) -{ - size_t i; - - assert(dir && ISO_ISDIR(dir->iso_self)); - for (i = 0; i < dir->nchildren; i++) { - struct joliet_tree_node *ch; - ch = dir->children[i]; - - if (!ISO_ISDIR (ch->iso_self)) { - struct iso_tree_node *iso = ch->iso_self; - ch->block = iso->block; - } - else - joliet_update_file_pos(t, ch); - } - - /* reset curfile when we're finished */ - if (!dir->parent) - t->curfile = 0; } struct joliet_tree_node* @@ -192,7 +200,7 @@ write_path_table(struct ecma119_write_target *t, void (*write_int)(uint8_t*, uint32_t, int) = l_type ? iso_lsb : iso_msb; - size_t i; + size_t i; struct ecma119_path_table_record *rec; struct joliet_tree_node *dir; int parent = 0; @@ -209,7 +217,7 @@ write_path_table(struct ecma119_write_target *t, rec->len_di[0] = dir->parent ? (uint8_t) ucslen(dir->name) * 2 : 1; rec->len_xa[0] = 0; - write_int(rec->block, dir->block, 4); + write_int(rec->block, dir->info.dir.block, 4); write_int(rec->parent, parent + 1, 2); if (dir->parent) memcpy(rec->dir_id, dir->name, rec->len_di[0]); @@ -227,20 +235,31 @@ write_one_dir_record(struct ecma119_write_target *t, int file_id, uint8_t *buf) { + uint32_t len; + uint32_t block; uint8_t len_dr = (file_id >= 0) ? 34 : node->dirent_len; uint8_t len_fi = (file_id >= 0) ? 1 : ucslen(node->name) * 2; uint8_t f_id = (uint8_t) ((file_id == 3) ? 0 : file_id); uint8_t *name = (file_id >= 0) ? &f_id : (uint8_t*)node->name; struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf; + if (node->type == JOLIET_DIR) { + len = node->info.dir.len; + block = node->info.dir.block; + } else { + /* file */ + len = node->info.file->size; + block = node->info.file->block; + } + if (file_id == 1 && node->parent) node = node->parent; rec->len_dr[0] = len_dr; - iso_bb(rec->block, node->block, 4); - iso_bb(rec->length, node->len, 4); + iso_bb(rec->block, block, 4); + iso_bb(rec->length, len, 4); iso_datetime_7(rec->recording_time, t->now); - rec->flags[0] = ISO_ISDIR(node->iso_self) ? 2 : 0; + rec->flags[0] = (node->type == JOLIET_DIR) ? 2 : 0; iso_bb(rec->vol_seq_number, t->volnum + 1, 2); rec->len_fi[0] = len_fi; memcpy(rec->file_id, name, len_fi); @@ -263,14 +282,25 @@ write_sup_vol_desc(struct ecma119_write_target *t, uint8_t *buf) { struct ecma119_sup_vol_desc *vol = (struct ecma119_sup_vol_desc*)buf; struct iso_volume *volume = t->volset->volume[t->volnum]; - uint16_t *vol_id = str2ucs(volume->volume_id); - uint16_t *pub_id = str2ucs(volume->publisher_id); - uint16_t *data_id = str2ucs(volume->data_preparer_id); - uint16_t *volset_id = str2ucs(t->volset->volset_id); + uint16_t *vol_id = str2ucs(volume->volume_id, t->input_charset); + uint16_t *pub_id = str2ucs(volume->publisher_id, t->input_charset); + uint16_t *data_id = str2ucs(volume->data_preparer_id, t->input_charset); + uint16_t *volset_id = str2ucs(t->volset->volset_id, t->input_charset); int vol_id_len = MIN(32, ucslen(vol_id) * 2); int pub_id_len = MIN(128, ucslen(pub_id) * 2); int data_id_len = MIN(128, ucslen(data_id) * 2); int volset_id_len = MIN(128, ucslen(volset_id) * 2); + + uint16_t *system_id = str2ucs(volume->system_id, t->input_charset); + uint16_t *application_id = str2ucs(volume->application_id, t->input_charset); + uint16_t *copyright_file_id = str2ucs(volume->copyright_file_id, t->input_charset); + uint16_t *abstract_file_id = str2ucs(volume->abstract_file_id, t->input_charset); + uint16_t *biblio_file_id = str2ucs(volume->biblio_file_id, t->input_charset); + int system_id_len = MIN(32, ucslen(system_id) * 2); + int application_id_len = MIN(128, ucslen(application_id) * 2); + int copyright_file_id_len = MIN(37, ucslen(copyright_file_id) * 2); + int abstract_file_id_len = MIN(37, ucslen(abstract_file_id) * 2); + int biblio_file_id_len = MIN(37, ucslen(biblio_file_id) * 2); vol->vol_desc_type[0] = 2; memcpy(vol->std_identifier, "CD001", 5); @@ -292,8 +322,13 @@ write_sup_vol_desc(struct ecma119_write_target *t, uint8_t *buf) memcpy(vol->vol_set_id, volset_id, volset_id_len); memcpy(vol->publisher_id, pub_id, pub_id_len); memcpy(vol->data_prep_id, data_id, data_id_len); - /*memcpy(vol->application_id, "APPID", app_id_len);*/ - + + memcpy(vol->system_id, system_id, system_id_len); + memcpy(vol->application_id, "APPID", application_id_len); + memcpy(vol->copyright_file_id, copyright_file_id, copyright_file_id_len); + memcpy(vol->abstract_file_id, abstract_file_id, abstract_file_id_len); + memcpy(vol->bibliographic_file_id, biblio_file_id, biblio_file_id_len); + iso_datetime_17(vol->vol_creation_time, t->now); iso_datetime_17(vol->vol_modification_time, t->now); iso_datetime_17(vol->vol_effective_time, t->now); @@ -303,6 +338,11 @@ write_sup_vol_desc(struct ecma119_write_target *t, uint8_t *buf) free(volset_id); free(pub_id); free(data_id); + free(system_id); + free(application_id); + free(copyright_file_id); + free(abstract_file_id); + free(biblio_file_id); } @@ -317,7 +357,7 @@ write_one_dir(struct ecma119_write_target *t, uint8_t *orig_buf = buf; uint8_t *prior_buf = buf; - assert(ISO_ISDIR (dir->iso_self)); + assert(dir->type == JOLIET_DIR); /* write the "." and ".." entries first */ write_one_dir_record(t, dir, 0, buf); buf += ((struct ecma119_dir_record*) buf)->len_dr[0]; @@ -325,8 +365,8 @@ write_one_dir(struct ecma119_write_target *t, write_one_dir_record(t, dir, 1, buf); buf += ((struct ecma119_dir_record*) buf)->len_dr[0]; - for (i = 0; i < dir->nchildren; i++) { - write_one_dir_record(t, dir->children[i], -1, buf); + for (i = 0; i < dir->info.dir.nchildren; i++) { + write_one_dir_record(t, dir->info.dir.children[i], -1, buf); len = ((struct ecma119_dir_record*) buf)->len_dr[0]; if ((buf + len - prior_buf) >= 2048) { for (j = len - 1; j >= 0; j--) { @@ -341,7 +381,7 @@ write_one_dir(struct ecma119_write_target *t, } } - assert (buf - orig_buf == dir->len); + assert (buf - orig_buf == dir->info.dir.len); } static void @@ -350,11 +390,11 @@ write_dirs(struct ecma119_write_target *t, uint8_t *buf) size_t i; struct joliet_tree_node *dir; - assert (t->curblock == t->dirlist_joliet[0]->block); - for (i = 0; i < t->dirlist_len; i++) { + assert (t->curblock == t->dirlist_joliet[0]->info.dir.block); + for (i = 0; i < t->dirlist_len_joliet; i++) { dir = t->dirlist_joliet[i]; write_one_dir(t, dir, buf); - buf += round_up(dir->len, t->block_size); + buf += round_up(dir->info.dir.len, t->block_size); } } diff --git a/libisofs/trunk/libisofs/joliet.h b/libisofs/trunk/libisofs/joliet.h index e5b7582d..cce7c89c 100644 --- a/libisofs/trunk/libisofs/joliet.h +++ b/libisofs/trunk/libisofs/joliet.h @@ -17,19 +17,34 @@ struct ecma119_write_target; struct iso_tree_node; +enum { + JOLIET_FILE, + JOLIET_DIR +}; + +struct joliet_dir_info { + struct joliet_tree_node **children; + size_t nchildren; + size_t len; + size_t block; +}; + struct joliet_tree_node { uint16_t *name; /**< In UCS-2BE. */ size_t dirent_len; - size_t len; - size_t block; + //size_t len;?? + /*size_t block;*/ struct joliet_tree_node *parent; - struct iso_tree_node *iso_self; + /* struct iso_tree_node *iso_self; */ struct ecma119_write_target *target; - - struct joliet_tree_node **children; - size_t nchildren; + + int type; + union { + struct iso_file *file; + struct joliet_dir_info dir; + } info; }; /** @@ -55,9 +70,10 @@ joliet_calc_dir_pos(struct ecma119_write_target *t, struct joliet_tree_node*); /** * Update the position of each file in the joliet hierarchy (to be called * AFTER the file positions in the iso tree have been set). + * TODO not needed, block info is kept away in hash table */ -void -joliet_update_file_pos(struct ecma119_write_target *t, struct joliet_tree_node*); +//void +//joliet_update_file_pos(struct ecma119_write_target *t, struct joliet_tree_node*); /** * Calculate the size of the joliet path table and fill in the list of diff --git a/libisofs/trunk/libisofs/libisofs.h b/libisofs/trunk/libisofs/libisofs.h index 088a2ca0..537b01a0 100755 --- a/libisofs/trunk/libisofs/libisofs.h +++ b/libisofs/trunk/libisofs/libisofs.h @@ -33,11 +33,44 @@ struct iso_volset; */ struct iso_tree_node; +/** + * A directory in the filesystem tree. + * The first member of this is an iso_tree_node. + * \see tree.h + */ +struct iso_tree_node_dir; + enum ecma119_extension_flag { ECMA119_ROCKRIDGE = (1<<0), ECMA119_JOLIET = (1<<1) }; +/** + * This will hold the error code for some functions, if them fail. + */ +int libisofs_errno; + +/* an unexpected internal error */ +#define INTERNAL_ERROR -1 +/* file don't exists, or can't be stat'ed */ +#define NO_FILE 1 +/* user haven't read access to file */ +#define NO_READ_ACCESS 2 +/* unexpected file type, eg., passing a dir instead of a regular file */ +#define UNEXPECTED_FILE_TYPE 3 + +/** + * Controls the bahavior of iso_tree_radd_dir function + */ +struct iso_tree_radd_dir_behavior { + char** excludes; /**< List of paths (file or directory) to be ignored. */ + //int follow_sym_link; + int stop_on_error; /**< Stop when an error was found?. */ + int error; /**< set to 1 on error */ + //int notify_errors; + //char** errors; +}; + /** * Create a new volume. * The parameters can be set to NULL if you wish to set them later. @@ -49,7 +82,7 @@ struct iso_volume *iso_volume_new(const char *volume_id, struct iso_volume *iso_volume_new_with_root(const char *volume_id, const char *publisher_id, const char *data_preparer_id, - struct iso_tree_node *root); + struct iso_tree_node_dir *root); /** * Free a volume. @@ -64,7 +97,7 @@ void iso_volset_free(struct iso_volset *volume); /** * Get the root directory for a volume. */ -struct iso_tree_node *iso_volume_get_root(const struct iso_volume *volume); +struct iso_tree_node_dir *iso_volume_get_root(const struct iso_volume *volume); /** * Fill in the volume identifier for a volume. @@ -126,7 +159,7 @@ void iso_volume_set_biblio_file_id(struct iso_volume *volume, * \return The node found or NULL. * */ -struct iso_tree_node *iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path); +//struct iso_tree_node *iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path); /** * Add a file or a directory (recursively) to a volume by specifying its path on the volume. @@ -137,9 +170,9 @@ struct iso_tree_node *iso_tree_volume_path_to_node(struct iso_volume *volume, co * * \return The node for the file or NULL if the parent doesn't exists on the disc. */ -struct iso_tree_node *iso_tree_volume_add_path(struct iso_volume *volume, - const char *disc_path, - const char *path); +//struct iso_tree_node *iso_tree_volume_add_path(struct iso_volume *volume, +// const char *disc_path, +// const char *path); /** * Creates a new, empty directory on the volume. @@ -149,8 +182,8 @@ struct iso_tree_node *iso_tree_volume_add_path(struct iso_volume *volume, * * \return A pointer to the newly created directory. */ -struct iso_tree_node *iso_tree_volume_add_new_dir(struct iso_volume *volume, - const char *disc_path); +//struct iso_tree_node *iso_tree_volume_add_new_dir(struct iso_volume *volume, +// const char *disc_path); /** * Create a new Volume Set consisting of only one volume. @@ -161,54 +194,96 @@ struct iso_tree_node *iso_tree_volume_add_new_dir(struct iso_volume *volume, struct iso_volset *iso_volset_new(struct iso_volume *volume, const char *volset_id); + +/** + * Creates a new root dir for a filesystem tree + */ +struct iso_tree_node_dir *iso_tree_new_root(); + +/** + * Add a file to a directory. + * + * \param path The path, on the local filesystem, of the file. + * + * \pre \p parent is non-NULL. + * \pre \p path is non-NULL. + * \return An iso_tree_node_file whose path is \p path and whose parent is + * \p parent. + * On error, returns NULL and libisofs_errno is set appropriately: + * NO_FILE if path doesn't point to a valid file. + * NO_READ_ACCESS if user haven't read access on file + * UNEXPECTED_FILE_TYPE if path doesn't point to a regular file + */ +struct iso_tree_node *iso_tree_add_file(struct iso_tree_node_dir *parent, + const char *path); + +/** + * Add a symbolic link to a directory. + * + * \param name The name of the symbolic link + * \param dest The distination of the link, i.e., the file this link points + * to + * + * \pre \p parent, name and dest are non-NULL. + * + * \return An iso_tree_node_symlink + */ +struct iso_tree_node *iso_tree_add_symlink(struct iso_tree_node_dir *parent, + const char *name, const char *dest); + +/** + * Add a new, empty directory to the tree. + * + * \pre \p parent is non-NULL. + * \pre \p name is unique among the children and files belonging to \p parent. + * Also, it doesn't contain '/' characters. + * + * \post \p parent contains a child directory whose name is \p name and whose + * POSIX attributes are the same as \p parent's. + * \return a pointer to the newly created directory. + */ +struct iso_tree_node_dir *iso_tree_add_dir(struct iso_tree_node_dir *parent, + const char *name); + +/* TODO iso_tree_new_special */ + /** * Add a file to a directory. * * \param path The path, on the local filesystem, of the file. * - * \pre \p parent is NULL or is a directory. - * \pre \p path is non-NULL and is a valid path to a non-directory on the local + * \pre \p parent is non-NULL. + * \pre \p path is non-NULL and is a valid path to a file or directory on the local * filesystem. * \return An iso_tree_node whose path is \p path and whose parent is \p parent. + * On error, returns NULL and libisofs_errno is set appropriately: + * NO_FILE if path doesn't point to a valid file. + * NO_READ_ACCESS if user haven't read access on file + * UNEXPECTED_FILE_TYPE if path refers to non supported file type + * (at the momment, only dirs, symlinks and regular + * files are supported). */ -struct iso_tree_node *iso_tree_add_node(struct iso_tree_node *parent, +struct iso_tree_node *iso_tree_add_node(struct iso_tree_node_dir *parent, const char *path); /** * Recursively add an existing directory to the tree. * Warning: when using this, you'll lose pointers to files or subdirectories. * If you want to have pointers to all files and directories, - * use iso_tree_add_file and iso_tree_add_dir. + * use iso_tree_add_file, iso_tree_add_node and iso_tree_add_dir. * * \param path The path, on the local filesystem, of the directory to add. * - * \pre \p parent is NULL or is a directory. + * \pre \p parent is non-NULL. * \pre \p path is non-NULL and is a valid path to a directory on the local * filesystem. * \return a pointer to the newly created directory. */ -struct iso_tree_node *iso_tree_radd_dir(struct iso_tree_node *parent, - const char *path); +struct iso_tree_node_dir *iso_tree_radd_dir(struct iso_tree_node_dir *parent, + const char *path, struct iso_tree_radd_dir_behavior *behavior); - -/** - * Add the path of a file or directory to ignore when adding a directory recursively. - * - * \param path The path, on the local filesystem, of the file. - */ -void iso_exclude_add_path(const char *path); - -/** - * Remove a path that was set to be ignored when adding a directory recusively. - * - * \param path The path, on the local filesystem, of the file. - */ -void iso_exclude_remove_path(const char *path); - -/** - * Remove all paths that were set to be ignored when adding a directory recusively. - */ -void iso_exclude_empty(void); +//struct iso_tree_node *iso_tree_radd_dir(struct iso_tree_node *parent, +// const char *path); /** * Creates a new, empty directory on the volume. @@ -221,13 +296,18 @@ void iso_exclude_empty(void); * POSIX attributes are the same as \p parent's. * \return a pointer to the newly created directory. */ -struct iso_tree_node *iso_tree_add_new_dir(struct iso_tree_node *parent, - const char *name); +/*struct iso_tree_node *iso_tree_add_new_dir(struct iso_tree_node *parent, + const char *name);*/ /** - * Set the name of a file (using the current locale). + * Set the name of a tree node (using the current locale). */ -void iso_tree_node_set_name(struct iso_tree_node *file, const char *name); +void iso_tree_node_set_name(struct iso_tree_node *node, const char *name); + +/** + * Set if the node will be hidden in RR/ISO tree, Joliet tree or both. + */ +void iso_tree_node_set_hidden(struct iso_tree_node *node, int hide_attrs); /** * Recursively print a directory to stdout. diff --git a/libisofs/trunk/libisofs/rockridge.c b/libisofs/trunk/libisofs/rockridge.c index 3662ac65..65313012 100755 --- a/libisofs/trunk/libisofs/rockridge.c +++ b/libisofs/trunk/libisofs/rockridge.c @@ -24,11 +24,11 @@ uint8_t *rrip_make_PX(struct ecma119_write_target *t, PX[1] = 'X'; PX[2] = 44; PX[3] = 1; - iso_bb(&PX[4], node->iso_self->attrib.st_mode, 4); - iso_bb(&PX[12], node->iso_self->attrib.st_nlink, 4); - iso_bb(&PX[20], node->iso_self->attrib.st_uid, 4); - iso_bb(&PX[28], node->iso_self->attrib.st_gid, 4); - iso_bb(&PX[36], node->iso_self->attrib.st_ino, 4); + iso_bb(&PX[4], node->attrib.st_mode, 4); + iso_bb(&PX[12], node->attrib.st_nlink, 4); + iso_bb(&PX[20], node->attrib.st_uid, 4); + iso_bb(&PX[28], node->attrib.st_gid, 4); + iso_bb(&PX[36], node->attrib.st_ino, 4); return PX; } @@ -37,8 +37,8 @@ void rrip_add_PX(struct ecma119_write_target *t, struct ecma119_tree_node *node) { susp_append(t, &node->susp, rrip_make_PX(t, node)); if (node->type == ECMA119_DIR) { - susp_append(t, &node->dir.self_susp, rrip_make_PX(t, node)); - susp_append(t, &node->dir.parent_susp, rrip_make_PX(t, node)); + susp_append(t, &node->info.dir.self_susp, rrip_make_PX(t, node)); + susp_append(t, &node->info.dir.parent_susp, rrip_make_PX(t, node)); } } @@ -50,8 +50,8 @@ void rrip_add_PN(struct ecma119_write_target *t, struct ecma119_tree_node *node) PN[1] = 'N'; PN[2] = 20; PN[3] = 1; - iso_bb(&PN[4], node->iso_self->attrib.st_dev >> 32, 4); - iso_bb(&PN[12], node->iso_self->attrib.st_dev & 0xffffffff, 4); + iso_bb(&PN[4], node->attrib.st_dev >> 32, 4); + iso_bb(&PN[12], node->attrib.st_dev & 0xffffffff, 4); susp_append(t, &node->susp, PN); } @@ -102,7 +102,7 @@ static void rrip_SL_add_component(char *prev, char *cur, int *n_comp, void rrip_add_SL(struct ecma119_write_target *t, struct ecma119_tree_node *node) { - int ret, pathsize = 0; + int path_size; char *path = NULL, *cur, *prev; int i, j; @@ -113,19 +113,9 @@ void rrip_add_SL(struct ecma119_write_target *t, struct ecma119_tree_node *node) uint8_t *SL; - do { - pathsize += 128; - path = realloc(path, pathsize); - /* FIXME: what if the file is not on the local fs? */ - ret = readlink(node->iso_self->loc.path, path, pathsize); - } while (ret == pathsize); - if (ret == -1) { - fprintf(stderr, "Error: couldn't read symlink: %s\n", - strerror(errno)); - return; - } - path[ret] = '\0'; - + path = node->info.dest; + path_size = strlen(path); + prev = path; for (cur = strchr(path, '/'); cur && *cur; cur = strchr(cur, '/')) { rrip_SL_add_component(prev, cur, &n_comp, &comp); @@ -134,8 +124,8 @@ void rrip_add_SL(struct ecma119_write_target *t, struct ecma119_tree_node *node) } /* if there was no trailing '/', we need to add the last component. */ - if (prev == path || prev != &path[ret - 1]) { - rrip_SL_add_component(prev, &path[ret], &n_comp, &comp); + if (prev == path || prev != &path[path_size - 1]) { + rrip_SL_add_component(prev, &path[path_size], &n_comp, &comp); } for (i = 0; i < n_comp; i++) { @@ -172,7 +162,6 @@ void rrip_add_SL(struct ecma119_write_target *t, struct ecma119_tree_node *node) } susp_append(t, &node->susp, SL); - free(path); /* free the components */ for (i = 0; i < n_comp; i++) { free(comp[i]); @@ -200,7 +189,7 @@ static void rrip_add_NM_single(struct ecma119_write_target *t, void rrip_add_NM(struct ecma119_write_target *t, struct ecma119_tree_node *node) { - char *name = iso_p_fileid(node->iso_self->name); + char *name = node->full_name; int len = name ? strlen(name) : 0; char *pos = name; @@ -208,8 +197,8 @@ rrip_add_NM(struct ecma119_write_target *t, struct ecma119_tree_node *node) return; if (node->type == ECMA119_DIR) { - rrip_add_NM_single(t, &node->dir.self_susp, pos, 0, 1 << 1); - rrip_add_NM_single(t, &node->dir.parent_susp, pos, 0, 1 << 2); + rrip_add_NM_single(t, &node->info.dir.self_susp, pos, 0, 1 << 1); + rrip_add_NM_single(t, &node->info.dir.parent_susp, pos, 0, 1 << 2); } while (len > 250) { @@ -240,7 +229,7 @@ rrip_add_PL(struct ecma119_write_target *t, struct ecma119_tree_node *node) PL[1] = 'L'; PL[2] = 12; PL[3] = 1; - susp_append(t, &node->dir.parent_susp, PL); + susp_append(t, &node->info.dir.parent_susp, PL); } void @@ -264,10 +253,10 @@ rrip_add_TF(struct ecma119_write_target *t, struct ecma119_tree_node *node) TF[1] = 'F'; TF[2] = 5 + 3 * 7; TF[3] = 1; - TF[4] = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 7); - iso_datetime_7(&TF[5], node->iso_self->attrib.st_mtime); - iso_datetime_7(&TF[12], node->iso_self->attrib.st_atime); - iso_datetime_7(&TF[19], node->iso_self->attrib.st_ctime); + TF[4] = (1 << 1) | (1 << 2) | (1 << 3); + iso_datetime_7(&TF[5], node->attrib.st_mtime); + iso_datetime_7(&TF[12], node->attrib.st_atime); + iso_datetime_7(&TF[19], node->attrib.st_ctime); susp_append(t, &node->susp, TF); } @@ -278,21 +267,21 @@ rrip_finalize(struct ecma119_write_target *t, struct ecma119_tree_node *dir) assert(dir->type == ECMA119_DIR); - if (dir->parent != dir->dir.real_parent) { - uint8_t *PL = susp_find(&dir->dir.parent_susp, "PL"); + if (dir->parent != dir->info.dir.real_parent) { + uint8_t *PL = susp_find(&dir->info.dir.parent_susp, "PL"); assert(PL); - iso_bb(&PL[4], dir->dir.real_parent->block, 4); + iso_bb(&PL[4], dir->info.dir.real_parent->info.dir.block, 4); } - for (i = 0; i < dir->dir.nchildren; i++) { - struct ecma119_tree_node *ch = dir->dir.children[i]; + for (i = 0; i < dir->info.dir.nchildren; i++) { + struct ecma119_tree_node *ch = dir->info.dir.children[i]; - if (ch->type == ECMA119_FILE && ch->file.real_me) { + if (ch->type == ECMA119_PLACEHOLDER) { uint8_t *CL = susp_find(&ch->susp, "CL"); assert(CL); - iso_bb(&CL[4], ch->file.real_me->block, 4); + iso_bb(&CL[4], ch->info.real_me->info.dir.block, 4); } else if (ch->type == ECMA119_DIR) { rrip_finalize(t, ch); } diff --git a/libisofs/trunk/libisofs/susp.c b/libisofs/trunk/libisofs/susp.c index 0d2d6c5b..a29d8b3f 100755 --- a/libisofs/trunk/libisofs/susp.c +++ b/libisofs/trunk/libisofs/susp.c @@ -117,8 +117,8 @@ susp_add_CE(struct ecma119_write_target *t, struct ecma119_tree_node *node) { try_add_CE(t, &node->susp, node->dirent_len); if (node->type == ECMA119_DIR) { - try_add_CE(t, &node->dir.self_susp, 34); - try_add_CE(t, &node->dir.parent_susp, 34); + try_add_CE(t, &node->info.dir.self_susp, 34); + try_add_CE(t, &node->info.dir.parent_susp, 34); } } @@ -137,7 +137,7 @@ susp_add_SP(struct ecma119_write_target *t, struct ecma119_tree_node *dir) SP[4] = 0xbe; SP[5] = 0xef; SP[6] = 0; - susp_append(t, &dir->dir.self_susp, SP); + susp_append(t, &dir->info.dir.self_susp, SP); } #if 0 @@ -176,7 +176,7 @@ rrip_add_ER(struct ecma119_write_target *t, struct ecma119_tree_node *dir) "FILE SYSTEM SEMANTICS.", 72); memcpy(&ER[89], "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, " "PISCATAWAY, NJ, USA FOR THE 1282 SPECIFICATION.", 93); - susp_append(t, &dir->dir.self_susp, ER); + susp_append(t, &dir->info.dir.self_susp, ER); } /* calculate the location of the CE areas. Since CE areas don't need to be @@ -184,9 +184,9 @@ rrip_add_ER(struct ecma119_write_target *t, struct ecma119_tree_node *dir) * directory and dump them immediately after all the directory records. * * Requires that the following be known: - * - position of the current directory (dir->block) - * - length of the current directory (dir->dir.len) - * - sum of the children's CE lengths (dir->dir.CE_len) + * - position of the current directory (dir->info.dir.block) + * - length of the current directory (dir->info.dir.len) + * - sum of the children's CE lengths (dir->info.dir.CE_len) */ static void susp_fin_1_CE(struct ecma119_write_target *t, @@ -208,18 +208,18 @@ static void susp_fin_CE(struct ecma119_write_target *t, struct ecma119_tree_node *dir) { int i; - size_t CE_offset = dir->dir.len; + size_t CE_offset = dir->info.dir.len; assert(dir->type == ECMA119_DIR); - susp_fin_1_CE(t, &dir->dir.self_susp, dir->block, &CE_offset); - susp_fin_1_CE(t, &dir->dir.parent_susp, dir->block, &CE_offset); + susp_fin_1_CE(t, &dir->info.dir.self_susp, dir->info.dir.block, &CE_offset); + susp_fin_1_CE(t, &dir->info.dir.parent_susp, dir->info.dir.block, &CE_offset); - for (i = 0; i < dir->dir.nchildren; i++) { - struct ecma119_tree_node *ch = dir->dir.children[i]; - susp_fin_1_CE(t, &ch->susp, dir->block, &CE_offset); + for (i = 0; i < dir->info.dir.nchildren; i++) { + struct ecma119_tree_node *ch = dir->info.dir.children[i]; + susp_fin_1_CE(t, &ch->susp, dir->info.dir.block, &CE_offset); } - assert(CE_offset == dir->dir.len + dir->dir.CE_len); + assert(CE_offset == dir->info.dir.len + dir->info.dir.CE_len); } void @@ -229,13 +229,13 @@ susp_finalize(struct ecma119_write_target *t, struct ecma119_tree_node *dir) assert(dir->type = ECMA119_DIR); - if (dir->dir.depth != 1) { + if (dir->info.dir.depth != 1) { susp_fin_CE(t, dir); } - for (i = 0; i < dir->dir.nchildren; i++) { - if (dir->dir.children[i]->type == ECMA119_DIR) - susp_finalize(t, dir->dir.children[i]); + for (i = 0; i < dir->info.dir.nchildren; i++) { + if (dir->info.dir.children[i]->type == ECMA119_DIR) + susp_finalize(t, dir->info.dir.children[i]); } } diff --git a/libisofs/trunk/libisofs/tree.c b/libisofs/trunk/libisofs/tree.c index 8e6f6cd2..7880845d 100755 --- a/libisofs/trunk/libisofs/tree.c +++ b/libisofs/trunk/libisofs/tree.c @@ -20,8 +20,6 @@ #include #include "tree.h" -#include "util.h" -#include "volume.h" #include "exclude.h" static void @@ -30,117 +28,223 @@ set_default_stat(struct stat *s) time_t now = time(NULL); memset(s, 0, sizeof(struct stat)); - s->st_mode = 0777 | S_IFREG; + s->st_mode = 0555; s->st_atime = s->st_mtime = s->st_ctime = now; } -static struct stat -get_attrib(const struct iso_tree_node *node) -{ - struct stat st; - - if (node) { - return node->attrib; - } - set_default_stat(&st); - return st; -} - static void -append_node(struct iso_tree_node *parent, +append_node(struct iso_tree_node_dir *parent, struct iso_tree_node *child) { - assert((!parent || S_ISDIR(parent->attrib.st_mode)) && child); - if (!parent) - return; - + assert( parent && child); + parent->nchildren++; parent->children = realloc(parent->children, parent->nchildren * sizeof(void*)); parent->children[parent->nchildren-1] = child; + child->parent = parent; +} + +struct iso_tree_node_dir* +iso_tree_new_root() +{ + struct iso_tree_node_dir *root; + + root = calloc(1, sizeof(struct iso_tree_node_dir)); + + set_default_stat(&root->node.attrib); + root->node.attrib.st_mode = S_IFDIR | 0777; + return root; } struct iso_tree_node* -iso_tree_new_root(struct iso_volume *vol) -{ - assert(vol); - - if (vol->root) { - iso_tree_free(vol->root); - } - - vol->root = calloc(1, sizeof(struct iso_tree_node)); - vol->root->volume = vol; - set_default_stat(&vol->root->attrib); - vol->root->attrib.st_mode = S_IFDIR | 0777; - vol->root->loc.type = LIBISO_NONE; - return vol->root; -} - -struct iso_tree_node* -iso_tree_add_new_file(struct iso_tree_node *parent, const char *name) -{ - struct iso_tree_node *f = calloc(1, sizeof(struct iso_tree_node)); - - assert((!parent || S_ISDIR(parent->attrib.st_mode)) && name); - - f->volume = parent ? parent->volume : NULL; - f->parent = parent; - f->name = parent ? strdup(name) : NULL; - f->attrib = get_attrib(parent); - f->attrib.st_mode = 0777 | S_IFREG; - f->loc.type = LIBISO_NONE; - append_node(parent, f); - return f; -} - -struct iso_tree_node* -iso_tree_add_new_dir(struct iso_tree_node *parent, const char *name) -{ - struct iso_tree_node *d = iso_tree_add_new_file(parent, name); - - assert((!parent || S_ISDIR(parent->attrib.st_mode)) && name); - - d->attrib.st_mode = (d->attrib.st_mode & ~S_IFMT) | S_IFDIR; - return d; -} - -struct iso_tree_node* -iso_tree_add_node(struct iso_tree_node *parent, const char *path) +iso_tree_add_file(struct iso_tree_node_dir *parent, const char *path) { + struct iso_tree_node_file *f; char *p; struct stat st; - struct iso_tree_node *ret; - - assert((!parent || S_ISDIR(parent->attrib.st_mode)) && path); - - if (lstat(path, &st) == -1) + + assert( parent && path); + + if (lstat(path, &st) == -1) { + libisofs_errno = NO_FILE; return NULL; - + } + + if ( !S_ISREG(st.st_mode) ) { + libisofs_errno = UNEXPECTED_FILE_TYPE; + return NULL; + } + + if ( access(path, R_OK) ) { + libisofs_errno = NO_READ_ACCESS; + return NULL; + } + + f = calloc(1, sizeof(struct iso_tree_node_file)); + + /* fill fields */ + f->node.attrib = st; + f->path = strdup(path); + p = strdup(path); /* because basename() might modify its arg */ - - /* it doesn't matter if we add a file or directory since we modify - * attrib anyway. */ - ret = iso_tree_add_new_file(parent, basename(p)); - ret->attrib = st; - ret->loc.type = LIBISO_FILESYS; - ret->loc.path = strdup(path); + f->node.name = strdup( basename(p) ); free(p); - - return ret; + + /* add to parent (this also sets f->node->parent) */ + append_node(parent, (struct iso_tree_node*) f); + + return (struct iso_tree_node*) f; } struct iso_tree_node* -iso_tree_radd_dir (struct iso_tree_node *parent, const char *path) +iso_tree_add_symlink(struct iso_tree_node_dir *parent, + const char *name, const char *dest) +{ + struct iso_tree_node_symlink *link; + + assert( parent && name && dest); + + link = calloc(1, sizeof(struct iso_tree_node_symlink)); + + /* fill fields */ + set_default_stat(&link->node.attrib); + link->node.attrib.st_mode |= S_IFLNK; + link->node.name = strdup(name); + link->dest = strdup(dest); + + /* add to parent (this also sets link->node->parent) */ + append_node(parent, (struct iso_tree_node*) link); + + return (struct iso_tree_node*) link; +} + +struct iso_tree_node_dir* +iso_tree_add_dir(struct iso_tree_node_dir *parent, + const char *name) +{ + struct iso_tree_node_dir *dir; + + assert( parent && name ); + + dir = calloc(1, sizeof(struct iso_tree_node_dir)); + + dir->node.attrib = parent->node.attrib; + dir->node.name = strdup(name); + + append_node(parent, (struct iso_tree_node*) dir); + return dir; +} + +void +iso_tree_node_set_name(struct iso_tree_node *node, const char *name) +{ + free(node->name); + node->name = strdup(name); +} + +void +iso_tree_node_set_hidden(struct iso_tree_node *node, int hide_attrs) +{ + node->hide_flags = hide_attrs; +} + +struct iso_tree_node* +iso_tree_add_node(struct iso_tree_node_dir *parent, + const char *path) +{ + struct stat st; + struct iso_tree_node *node; + + assert( parent && path); + + if (lstat(path, &st) == -1) { + libisofs_errno = NO_FILE; + return NULL; + } + + if ( access(path, R_OK) ) { + libisofs_errno = NO_READ_ACCESS; + return NULL; + } + + switch (st.st_mode & S_IFMT) { + case S_IFREG: + /* regular file */ + node = iso_tree_add_file(parent, path); + break; + case S_IFLNK: + /* symlink */ + { + char dest[PATH_MAX]; + char *p; + int n; + + n = readlink(path, dest, PATH_MAX); + if ( n == -1 ) { + libisofs_errno = INTERNAL_ERROR; + return NULL; + } + dest[n] = '\0'; + p = strdup(path); /* because basename() might modify its arg */ + node = iso_tree_add_symlink(parent, basename(p), dest); + free(p); + node->attrib = st; + } + break; + case S_IFDIR: + /* directory */ + { + char *p; + p = strdup(path); /* because basename() might modify its arg */ + node = (struct iso_tree_node*) iso_tree_add_dir(parent, basename(p)); + free(p); + node->attrib = st; + } + break; + default: + libisofs_errno = UNEXPECTED_FILE_TYPE; + node = NULL; + break; + } + return node; +} + +void +iso_tree_free(struct iso_tree_node *root) +{ + if ( ISO_ISDIR(root) ) { + size_t i; + struct iso_tree_node_dir *dir; + dir = (struct iso_tree_node_dir *) root; + for (i=0; i < dir->nchildren; i++) { + iso_tree_free(dir->children[i]); + } + free(dir->children); + } else if ( ISO_ISLNK(root) ) { + struct iso_tree_node_symlink *link; + link = (struct iso_tree_node_symlink *) root; + free(link->dest); + } else if ( ISO_ISREG(root) ) { + struct iso_tree_node_file *file; + file = (struct iso_tree_node_file *) root; + free(file->path); + } + free(root->name); + free(root); +} + +static struct iso_tree_node* +iso_tree_radd_dir_aux(struct iso_tree_node_dir *parent, const char *path, + struct iso_tree_radd_dir_behavior *behavior, + struct iso_hash_table *excludes) { struct iso_tree_node *new; DIR *dir; struct dirent *ent; - assert((!parent || S_ISDIR(parent->attrib.st_mode)) && path); - new = iso_tree_add_node(parent, path); - if (!new || !S_ISDIR(new->attrib.st_mode)) { + if (!new || !ISO_ISDIR(new)) { return new; } @@ -157,44 +261,74 @@ iso_tree_radd_dir (struct iso_tree_node *parent, const char *path) strcmp(ent->d_name, "..") == 0) continue; + //check if path already finished in '/' sprintf(child, "%s/%s", path, ent->d_name); /* see if this child is excluded. */ - if (iso_exclude_lookup(child)) + if (iso_exclude_lookup(excludes, child)) continue; - iso_tree_radd_dir(new, child); + if ( !iso_tree_radd_dir_aux( (struct iso_tree_node_dir *) new, child, + behavior, excludes) ) { + /* error */ + behavior->error = 1; + if (behavior->stop_on_error) + break; + } } closedir(dir); return new; } -void -iso_tree_free(struct iso_tree_node *root) +struct iso_tree_node_dir* +iso_tree_radd_dir(struct iso_tree_node_dir *parent, const char *path, + struct iso_tree_radd_dir_behavior *behavior) { - size_t i; - - for (i=0; i < root->nchildren; i++) { - iso_tree_free(root->children[i]); + struct iso_tree_node_dir *dir; + struct iso_hash_table table = { {0,}, 0}; + + assert ( parent && path ); + + behavior->error = 0; + + /* initialize exclude hash_table */ + if ( behavior->excludes ) { + char *exclude; + int i = 0; + while ( (exclude = behavior->excludes[i++]) ) { + iso_exclude_add_path(&table, exclude); + } } - free(root->name); - free(root->children); - free(root); + + /* recurse into dir */ + dir = (struct iso_tree_node_dir*) iso_tree_radd_dir_aux( + parent, path, behavior, &table); + + /* clear hashtable */ + iso_exclude_empty(&table); + + return dir; } void iso_tree_print(const struct iso_tree_node *root, int spaces) { - size_t i; char sp[spaces+1]; memset(sp, ' ', spaces); sp[spaces] = '\0'; printf("%s%s\n", sp, root->name); - for (i=0; i < root->nchildren; i++) { - iso_tree_print(root->children[i], spaces+2); + + if ( ISO_ISDIR(root) ) { + size_t i; + struct iso_tree_node_dir *dir; + + dir = (struct iso_tree_node_dir *) root; + for (i=0; i < dir->nchildren; i++) { + iso_tree_print(dir->children[i], spaces+2); + } } } @@ -205,19 +339,18 @@ iso_tree_print_verbose(const struct iso_tree_node *root, void *callback_data, int spaces) { - size_t i; (S_ISDIR(root->attrib.st_mode) ? dir : file) (root, callback_data, spaces); - for (i=0; i < root->nchildren; i++) { - iso_tree_print_verbose(root->children[i], dir, - file, callback_data, spaces+2); + + if ( ISO_ISDIR(root) ) { + size_t i; + struct iso_tree_node_dir *dir_node; + + dir_node = (struct iso_tree_node_dir *) root; + for (i=0; i < dir_node->nchildren; i++) { + iso_tree_print_verbose(dir_node->children[i], dir, + file, callback_data, spaces+2); + } } } - -void -iso_tree_node_set_name(struct iso_tree_node *file, const char *name) -{ - free(file->name); - file->name = strdup(name); -} diff --git a/libisofs/trunk/libisofs/tree.h b/libisofs/trunk/libisofs/tree.h index e0e04609..ec8c0d29 100755 --- a/libisofs/trunk/libisofs/tree.h +++ b/libisofs/trunk/libisofs/tree.h @@ -24,46 +24,46 @@ #include "libisofs.h" -enum file_location { - LIBISO_FILESYS, - LIBISO_PREVSESSION, - LIBISO_NONE /**< for files/dirs that were added with - * iso_tree_add_new_XXX. */ +//enum file_location { +// LIBISO_FILESYS, +// LIBISO_PREVSESSION, +// LIBISO_NONE /**< for files/dirs that were added with +// * iso_tree_add_new_XXX. */ +//}; + +enum hide_node { + LIBISO_HIDE_ON_RR = 1 << 0, + LIBISO_HIDE_ON_JOLIET = 1 << 1 }; /** * This tells us where to read the data from a file. Either we read from the * local filesystem or we just point to the block on a previous session. */ -struct iso_file_location -{ - enum file_location type; - /* union {*/ - char *path; /* in the current locale */ - uint32_t block; - /* };*/ -}; +//struct iso_file_location +//{ +// enum file_location type; +// /* union {*/ +// char *path; /* in the current locale */ +// uint32_t block; +// /* };*/ +//}; /** * A node in the filesystem tree. */ struct iso_tree_node { - struct iso_volume *volume; - struct iso_tree_node *parent; + /*struct iso_volume *volume; TODO not needed? */ + struct iso_tree_node_dir *parent; char *name; struct stat attrib; /**< The POSIX attributes of this node as * documented in "man 2 stat". */ - struct iso_file_location loc; - /**< Only used for regular files and symbolic - * links (ie. files for which we might have to - * copy data). */ + + int hide_flags; /**< If the node is to be hidden in RR/ISO or + * Joilet tree */ - size_t nchildren; /**< The number of children of this - * directory (if this is a directory). */ - struct iso_tree_node **children; - - size_t block; /**< The block at which this file will + /*size_t block;*/ /**< The block at which this file will * reside on disk. We store this here as * well as in the various mangled trees * because many different trees might point @@ -72,34 +72,49 @@ struct iso_tree_node }; /** - * Create a new root directory for a volume. - * - * \param vol The volume for which to create a new root directory. - * - * \pre \p vol is non-NULL. - * \post \p vol has a non-NULL, empty root directory with permissions 777. - * \return \p vol's new non-NULL, empty root directory. + * A node in the filesystem tree that represents a regular file */ -struct iso_tree_node *iso_tree_new_root(struct iso_volume *vol); +struct iso_tree_node_file +{ + struct iso_tree_node node; + + char *path; /**< the path of the file on local filesystem */ + int sort_weight; /**< 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 */ + + /* when read from an existing ISO image, we need to store the + * block where file contents are written, and not the path. + * Maybe instead of a char *path we will need to go back to + * struct iso_file_location loc; + */ + /* struct iso_file_location loc; */ + /**< Only used for regular files and symbolic + * links (ie. files for which we might have to + * copy data). */ +}; /** - * Create a new, empty, file. - * - * \param parent The parent directory of the new file. If this is null, create - * and return a new file node without adding it to any tree. - * \param name The name of the new file, encoded in the current locale. - * \pre \p name is non-NULL and it does not match any other file or directory - * name in \p parent. - * \post \p parent (if non-NULL) contains a file with the following properties: - * - the file's name is \p name (converted to wchar_t) - * - the file's POSIX permissions are the same as \p parent's - * - the file is a regular file - * - the file is empty - * - * \return \p parent's newly created file. + * A node in the filesystem tree that represents a symbolic link */ -struct iso_tree_node *iso_tree_add_new_file(struct iso_tree_node *parent, - const char *name); +struct iso_tree_node_symlink +{ + struct iso_tree_node node; + + char *dest; /**< Destination of the link */ +}; + +/** + * A directory on the filesystem tree + */ +struct iso_tree_node_dir +{ + struct iso_tree_node node; + + size_t nchildren; /**< The number of children of this + * directory (if this is a directory). */ + struct iso_tree_node **children; +}; /** * Recursively free a directory. @@ -155,5 +170,7 @@ void iso_tree_print_verbose(const struct iso_tree_node *root, int spaces); #define ISO_ISDIR(n) S_ISDIR(n->attrib.st_mode) +#define ISO_ISREG(n) S_ISREG(n->attrib.st_mode) +#define ISO_ISLNK(n) S_ISLNK(n->attrib.st_mode) #endif /* LIBISO_TREE_H */ diff --git a/libisofs/trunk/libisofs/util.c b/libisofs/trunk/libisofs/util.c index b7eb547a..d4e8d26a 100755 --- a/libisofs/trunk/libisofs/util.c +++ b/libisofs/trunk/libisofs/util.c @@ -16,7 +16,8 @@ #include #include #include -#include +#include +#include #include "util.h" @@ -35,6 +36,53 @@ int round_up(int n, int mul) return div_up(n, mul) * mul; } + +/** + * Convert a string between charsets. + * This assumes '\0' means end-of-string, what is not necessarily true, + * but given there are lots of strdup around there, it will fail in other + * places anyway... + */ +char * +convert_str(const char *str, const char *icharset, const char *ocharset) +{ + char *ret; + size_t inbytes; + size_t outbytes; + + inbytes = strlen(str); + outbytes = (inbytes+1) * MB_LEN_MAX; + { + /* ensure enought space */ + char out[outbytes]; + char *src; + size_t n; + + iconv_t conv = iconv_open(ocharset, icharset); + if (conv == (iconv_t)(-1)) { + printf("Can't convert from %s to %s\n", icharset, ocharset); + return NULL; + } + src = (char *)str; + ret = (char *)out; + + n = iconv(conv, &src, &inbytes, &ret, &outbytes); + if (n == -1) { + /* error just return input stream */ + perror("Convert error."); + printf("Maybe string %s is not encoded in %s\n", str, icharset); + + iconv_close(conv); + return strdup(str); + } + iconv_close(conv); + *ret = '\0'; + + ret = strdup(out); + } + return ret; +} + /** * Convert a str in a specified codeset to WCHAR_T. * The result must be free() when no more needed @@ -64,17 +112,22 @@ static wchar_t *str2wchar(const char *str, const char *codeset) src = (char *)str; n = iconv(conv, &src, &inbytes, &ret, &outbytes); - if (n == -1) { - /* error, should never occur */ - /* - * FIXME - * The above assumption is not always true, because the str could - * actually not be encoded in specified codeset. This can lead to - * problems if, for example, a file is not in UTF-8. You should - * take care about this in a way like str2ascii - */ - perror("Convert error\n"); - return NULL; + while (n == -1) { + + if( errno != EINVAL ) { + /* error, should never occur */ + iconv_close(conv); + perror("Convert error\n"); + return NULL; + } + + /* invalid input string charset, just log and ignore */ + printf("String %s is not encoded in %s\n", str, codeset); + inbytes--; + + if(!inbytes) + break; + n = iconv(conv, &src, &inbytes, &ret, &outbytes); } iconv_close(conv); @@ -85,7 +138,7 @@ static wchar_t *str2wchar(const char *str, const char *codeset) /* this function must always return a name * since the caller never checks if a NULL * is returned. It also avoids some warnings. */ -char *str2ascii(const char *src_arg) +char *str2ascii(const char *src_arg, const char *icharset) { wchar_t *wsrc_; char *ret; @@ -97,6 +150,8 @@ char *str2ascii(const char *src_arg) size_t inbytes; size_t n; + assert(icharset); + if (!src_arg) return NULL; @@ -108,7 +163,7 @@ char *str2ascii(const char *src_arg) * this later. */ - wsrc_ = str2wchar(src_arg, "UTF-8"); + wsrc_ = str2wchar(src_arg, icharset); if (!wsrc_) return NULL; @@ -172,13 +227,12 @@ char *str2ascii(const char *src_arg) } /* FIXME: C&P */ -uint16_t *str2ucs(const char *src_arg) +uint16_t *str2ucs(const char *src_arg, const char *icharset) { - wchar_t wsrc_[NAME_BUFFER_SIZE]; - char *src = (char*)wsrc_; + wchar_t *wsrc_; + char *src; char *ret_; char *ret; - mbstate_t state; iconv_t conv; size_t outbytes; size_t numchars; @@ -188,13 +242,17 @@ uint16_t *str2ucs(const char *src_arg) if (!src_arg) return calloc(2, 1); /* empty UCS string */ + /* convert the string to a wide character string. Note: outbytes * is in fact the number of characters in the string and doesn't - * include the last NULL character. */ - memset(&state, 0, sizeof(state)); - numchars = mbsrtowcs(wsrc_, &src_arg, NAME_BUFFER_SIZE-1, &state); - if (numchars < 0) + * include the last NULL character. + */ + + wsrc_ = str2wchar(src_arg, icharset); + if (!wsrc_) return calloc(2, 1); /* empty UCS string */ + src = (char*)wsrc_; + numchars = wcslen(wsrc_); inbytes = numchars * sizeof(wchar_t); @@ -276,14 +334,14 @@ static int valid_p_char(char c) || (c == '.') || (c == '_') || (c == '-'); } -char *str2d_char(const char *str) { +char *str2d_char(const char *str, const char *icharset) { char *ret; size_t len, i; if (!str) return NULL; - ret = str2ascii(str); + ret = str2ascii(str, icharset); len = strlen(ret); for (i = 0; i < len; ++i) { @@ -294,14 +352,14 @@ char *str2d_char(const char *str) { return ret; } -char *str2a_char(const char *str) { +char *str2a_char(const char *str, const char *icharset) { char *ret; size_t len, i; if (!str) return NULL; - ret = str2ascii(str); + ret = str2ascii(str, icharset); len = strlen(ret); for (i = 0; i < len; ++i) { @@ -312,9 +370,9 @@ char *str2a_char(const char *str) { return ret; } -static char *iso_dirid(const char *src, int size) +static char *iso_dirid(const char *src, int size, const char *icharset) { - char *ret = str2ascii(src); + char *ret = str2ascii(src, icharset); size_t len, i; if (!ret) @@ -333,19 +391,19 @@ static char *iso_dirid(const char *src, int size) return ret; } -char *iso_1_dirid(const char *src) +char *iso_1_dirid(const char *src, const char *icharset) { - return iso_dirid(src, 8); + return iso_dirid(src, 8, icharset); } -char *iso_2_dirid(const char *src) +char *iso_2_dirid(const char *src, const char *icharset) { - return iso_dirid(src, 31); + return iso_dirid(src, 31, icharset); } -char *iso_1_fileid(const char *src_arg) +char *iso_1_fileid(const char *src_arg, const char *icharset) { - char *src = str2ascii(src_arg); + char *src = str2ascii(src_arg, icharset); char *dest; char *dot; /* Position of the last dot in the filename, will be used to calculate @@ -394,9 +452,9 @@ char *iso_1_fileid(const char *src_arg) return dest; } -char *iso_2_fileid(const char *src_arg) +char *iso_2_fileid(const char *src_arg, const char *icharset) { - char *src = str2ascii(src_arg); + char *src = str2ascii(src_arg, icharset); char *dest; char *dot; int lname, lext, lnname, lnext, pos, i; @@ -454,9 +512,9 @@ char *iso_2_fileid(const char *src_arg) } char * -iso_p_fileid(const char *src) +iso_p_fileid(const char *src, const char *icharset) { - char *ret = str2ascii(src); + char *ret = str2ascii(src, icharset); size_t i, len; if (!ret) @@ -471,9 +529,9 @@ iso_p_fileid(const char *src) } uint16_t * -iso_j_id(const char *src_arg) +iso_j_id(const char *src_arg, const char *icharset) { - uint16_t *j_str = str2ucs(src_arg); + uint16_t *j_str = str2ucs(src_arg, icharset); size_t len = ucslen(j_str); size_t n; @@ -514,7 +572,6 @@ void iso_bb(uint8_t *buf, uint32_t num, int bytes) iso_msb(buf+bytes, num, bytes); } - void iso_datetime_7(unsigned char *buf, time_t t) { static int tzsetup = 0; @@ -535,12 +592,12 @@ void iso_datetime_7(unsigned char *buf, time_t t) buf[4] = tm.tm_min; buf[5] = tm.tm_sec; #ifdef HAVE_TM_GMTOFF - tzoffset = -tm.tm_gmtoff / 60 / 15; + tzoffset = tm.tm_gmtoff / 60 / 15; #else - tzoffset = -timezone / 60 / 15; + tzoffset = timezone / 60 / 15; #endif - if (tzoffset < -48) - tzoffset += 101; + if (tzoffset > 52) + tzoffset -= 101; buf[6] = tzoffset; } @@ -584,12 +641,12 @@ void iso_datetime_17(unsigned char *buf, time_t t) sprintf((char*)&buf[12], "%02d", MIN(59, tm.tm_sec)); memcpy(&buf[14], "00", 2); #ifdef HAVE_TM_GMTOFF - tzoffset = -tm.tm_gmtoff / 60 / 15; + tzoffset = tm.tm_gmtoff / 60 / 15; #else - tzoffset = -timezone / 60 / 15; + tzoffset = timezone / 60 / 15; #endif - if (tzoffset < -48) - tzoffset += 101; + if (tzoffset > 52) + tzoffset -= 101; buf[16] = tzoffset; } } diff --git a/libisofs/trunk/libisofs/util.h b/libisofs/trunk/libisofs/util.h index c8f50d10..6bc1eb55 100755 --- a/libisofs/trunk/libisofs/util.h +++ b/libisofs/trunk/libisofs/util.h @@ -30,22 +30,24 @@ extern inline int round_up(int n, int mul) return div_up(n, mul) * mul; } -wchar_t *towcs(const char *); -char *str2ascii(const char*); -uint16_t *str2ucs(const char*); +char *convert_str(const char *str, const char *icharset, const char *ocharset); -char *str2d_char(const char*); -char *str2a_char(const char*); +wchar_t *towcs(const char *); +char *str2ascii(const char*, const char *); +uint16_t *str2ucs(const char *, const char *); + +char *str2d_char(const char*, const char *); +char *str2a_char(const char*, const char *); /** * Create a level 1 directory identifier. */ -char *iso_1_dirid(const char *src); +char *iso_1_dirid(const char *src, const char *); /** * Create a level 2 directory identifier. */ -char *iso_2_dirid(const char *src); +char *iso_2_dirid(const char *src, const char *); /** * Create a level 1 file identifier that consists of a name, extension and @@ -54,7 +56,7 @@ char *iso_2_dirid(const char *src); * length 3, followed by a separator (;) and a version number (digit 1). * @return NULL if the original name and extension both are of length 0. */ -char *iso_1_fileid(const char *src); +char *iso_1_fileid(const char *src, const char *); /** * Create a level 2 file identifier that consists of a name, extension and @@ -63,7 +65,7 @@ char *iso_1_fileid(const char *src); * followed by a separator (;) and a version number (digit 1). * @return NULL if the original name and extension both are of length 0. */ -char *iso_2_fileid(const char *src); +char *iso_2_fileid(const char *src, const char *); /** * Create a Joliet file or directory identifier that consists of a name, @@ -76,7 +78,7 @@ char *iso_2_fileid(const char *src); * @param size will be set to the size (in bytes) of the identifier. * @return NULL if the original name and extension both are of length 0 or the conversion from the current codeset to UCS-2BE is not available. */ -uint16_t *iso_j_id(const char *src); +uint16_t *iso_j_id(const char *src, const char *icharset); /** * FIXME: what are the requirements for these next two? Is this for RR? @@ -85,7 +87,7 @@ uint16_t *iso_j_id(const char *src); * The resulting file name will not exceed 250 characters. * @return NULL if the original name and extension both are of length 0. */ -char *iso_p_fileid(const char *src); +char *iso_p_fileid(const char *src, const char *); /** * Create a POSIX portable directory name. diff --git a/libisofs/trunk/libisofs/volume.c b/libisofs/trunk/libisofs/volume.c index d87b7d15..a06e6eef 100755 --- a/libisofs/trunk/libisofs/volume.c +++ b/libisofs/trunk/libisofs/volume.c @@ -52,14 +52,14 @@ struct iso_volume* iso_volume_new_with_root(const char *volume_id, const char *publisher_id, const char *data_preparer_id, - struct iso_tree_node *root) + struct iso_tree_node_dir *root) { struct iso_volume *volume; volume = calloc(1, sizeof(struct iso_volume)); volume->refcount = 1; - volume->root = root ? root : iso_tree_new_root(volume); + volume->root = root ? root : iso_tree_new_root(); if (volume_id != NULL) volume->volume_id = strdup(volume_id); @@ -75,7 +75,7 @@ iso_volume_free(struct iso_volume *volume) { /* Only free if no references are in use. */ if (--volume->refcount < 1) { - iso_tree_free(volume->root); + iso_tree_free( (struct iso_tree_node*) volume->root); free(volume->volume_id); free(volume->publisher_id); @@ -85,7 +85,7 @@ iso_volume_free(struct iso_volume *volume) } } -struct iso_tree_node * +struct iso_tree_node_dir * iso_volume_get_root(const struct iso_volume *volume) { return volume->root; @@ -139,98 +139,98 @@ void iso_volume_set_biblio_file_id(struct iso_volume *volume, volume->biblio_file_id = strdup(biblio_file_id); } -struct iso_tree_node * -iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path) -{ - struct iso_tree_node *node; - char *ptr, *brk_info, *component; - - /* get the first child at the root of the volume - * that is "/" */ - node=iso_volume_get_root(volume); - if (!strcmp (path, "/")) - return node; - - if (!node->nchildren) - return NULL; - - /* the name of the nodes is in wide characters so first convert path - * into wide characters. */ - ptr = strdup(path); - - /* get the first component of the path */ - component=strtok_r(ptr, "/", &brk_info); - while (component) { - size_t max; - size_t i; - - /* search among all the children of this directory if this path component exists */ - max=node->nchildren; - for (i=0; i < max; i++) { - if (!strcmp(component, node->children[i]->name)) { - node=node->children[i]; - break; - } - } - - /* see if a node could be found */ - if (i==max) { - node=NULL; - break; - } - - component=strtok_r(NULL, "/", &brk_info); - } - - free(ptr); - return node; -} - -struct iso_tree_node * -iso_tree_volume_add_path(struct iso_volume *volume, - const char *disc_path, - const char *path) -{ - char *tmp; - struct iso_tree_node *node; - struct iso_tree_node *parent_node; - - tmp=strdup(disc_path); - parent_node = iso_tree_volume_path_to_node(volume, dirname(tmp)); - free(tmp); - - if (!parent_node) - return NULL; - - node = iso_tree_radd_dir(parent_node, path); - if (!node) - return NULL; - - tmp=strdup(disc_path); - iso_tree_node_set_name(node, basename(tmp)); - free(tmp); - - return node; -} - -struct iso_tree_node * -iso_tree_volume_add_new_dir(struct iso_volume *volume, - const char *disc_path) -{ - char *tmp; - struct iso_tree_node *node; - struct iso_tree_node *parent_node; - - tmp=strdup(disc_path); - parent_node = iso_tree_volume_path_to_node(volume, dirname(tmp)); - free(tmp); - - if (!parent_node) - return NULL; - - tmp=strdup(disc_path); - node = iso_tree_add_new_dir(parent_node, basename(tmp)); - free(tmp); - - return node; -} +//struct iso_tree_node * +//iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path) +//{ +// struct iso_tree_node *node; +// char *ptr, *brk_info, *component; +// +// /* get the first child at the root of the volume +// * that is "/" */ +// node=iso_volume_get_root(volume); +// if (!strcmp (path, "/")) +// return node; +// +// if (!node->nchildren) +// return NULL; +// +// /* the name of the nodes is in wide characters so first convert path +// * into wide characters. */ +// ptr = strdup(path); +// +// /* get the first component of the path */ +// component=strtok_r(ptr, "/", &brk_info); +// while (component) { +// size_t max; +// size_t i; +// +// /* search among all the children of this directory if this path component exists */ +// max=node->nchildren; +// for (i=0; i < max; i++) { +// if (!strcmp(component, node->children[i]->name)) { +// node=node->children[i]; +// break; +// } +// } +// +// /* see if a node could be found */ +// if (i==max) { +// node=NULL; +// break; +// } +// +// component=strtok_r(NULL, "/", &brk_info); +// } +// +// free(ptr); +// return node; +//} +// +//struct iso_tree_node * +//iso_tree_volume_add_path(struct iso_volume *volume, +// const char *disc_path, +// const char *path) +//{ +// char *tmp; +// struct iso_tree_node *node; +// struct iso_tree_node *parent_node; +// +// tmp=strdup(disc_path); +// parent_node = iso_tree_volume_path_to_node(volume, dirname(tmp)); +// free(tmp); +// +// if (!parent_node) +// return NULL; +// +// node = iso_tree_radd_dir(parent_node, path); +// if (!node) +// return NULL; +// +// tmp=strdup(disc_path); +// iso_tree_node_set_name(node, basename(tmp)); +// free(tmp); +// +// return node; +//} +// +//struct iso_tree_node * +//iso_tree_volume_add_new_dir(struct iso_volume *volume, +// const char *disc_path) +//{ +// char *tmp; +// struct iso_tree_node *node; +// struct iso_tree_node *parent_node; +// +// tmp=strdup(disc_path); +// parent_node = iso_tree_volume_path_to_node(volume, dirname(tmp)); +// free(tmp); +// +// if (!parent_node) +// return NULL; +// +// tmp=strdup(disc_path); +// node = iso_tree_add_new_dir(parent_node, basename(tmp)); +// free(tmp); +// +// return node; +//} diff --git a/libisofs/trunk/libisofs/volume.h b/libisofs/trunk/libisofs/volume.h index 79178b5f..64f835b5 100755 --- a/libisofs/trunk/libisofs/volume.h +++ b/libisofs/trunk/libisofs/volume.h @@ -18,7 +18,7 @@ struct iso_volume int refcount; /**< Number of used references to this volume. */ - struct iso_tree_node *root; /**< Root of the directory tree for the + struct iso_tree_node_dir *root; /**< Root of the directory tree for the volume. */ char *volume_id; /**< Volume identifier. */ diff --git a/libisofs/trunk/test/iso.c b/libisofs/trunk/test/iso.c index 0c09fa8c..34018d4f 100644 --- a/libisofs/trunk/test/iso.c +++ b/libisofs/trunk/test/iso.c @@ -44,11 +44,12 @@ int main(int argc, char **argv) { struct iso_volset *volset; struct iso_volume *volume; - struct iso_tree_node *root; + struct iso_tree_node_dir *root; struct burn_source *src; unsigned char buf[2048]; FILE *fd; int c; + struct iso_tree_radd_dir_behavior behav = {0,0,0}; int level=1, flags=0; while ((c = getopt(argc, argv, optstring)) != -1) { @@ -89,7 +90,8 @@ int main(int argc, char **argv) err(1, "error opening output file"); } - root = iso_tree_radd_dir(NULL, argv[optind]); + root = iso_tree_new_root(); + iso_tree_radd_dir(root, argv[optind], &behav); if (!root) { err(1, "error opening input directory"); }