From 48d76e844ef3d8cd9b70cffdf0ec8dae43a62c76 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Thu, 24 Aug 2006 19:23:37 +0000 Subject: [PATCH] First pinch of libisofs rewrite --- Makefile.am | 33 +- libisofs/Makefile.am | 23 +- libisofs/ecma119.c | 2042 +++++++++++++----------------------------- libisofs/ecma119.h | 303 ++++--- libisofs/libisofs.h | 126 +-- libisofs/rockridge.c | 163 ++-- libisofs/rockridge.h | 30 +- libisofs/susp.c | 216 ++--- libisofs/susp.h | 47 +- libisofs/tree.c | 512 ++++------- libisofs/tree.h | 232 ++--- libisofs/util.c | 632 +++++-------- libisofs/util.h | 163 ++-- libisofs/volume.c | 76 +- libisofs/volume.h | 26 +- test/iso.c | 51 +- 16 files changed, 1610 insertions(+), 3065 deletions(-) diff --git a/Makefile.am b/Makefile.am index c393a5f..5b35539 100644 --- a/Makefile.am +++ b/Makefile.am @@ -59,23 +59,22 @@ libburn_libburn_la_SOURCES = \ libisofs_libisofs_la_LDFLAGS = \ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) libisofs_libisofs_la_SOURCES = \ - libisofs/errors.h \ - libisofs/errors.c \ - libisofs/tree.h \ - libisofs/tree.c \ - libisofs/volume.h \ - libisofs/volume.c \ - libisofs/util.h \ - libisofs/util.c \ - libisofs/ecma119.c \ - libisofs/ecma119.h \ - libisofs/struct.h \ - libisofs/struct.c \ - libisofs/susp.h \ - libisofs/susp.c \ - libisofs/rockridge.h \ - libisofs/rockridge.c \ - libisofs/libisofs.h + libisofs/tree.h \ + libisofs/tree.c \ + libisofs/volume.h \ + libisofs/volume.c \ + libisofs/util.h \ + libisofs/util.c \ + libisofs/ecma119.c \ + libisofs/ecma119.h \ + libisofs/ecma119_tree.c \ + libisofs/ecma119_tree.h \ + libisofs/susp.h \ + libisofs/susp.c \ + libisofs/rockridge.h \ + libisofs/rockridge.c \ + libisofs/joliet.c \ + libisofs/joliet.h libinclude_HEADERS = \ libburn/libburn.h \ diff --git a/libisofs/Makefile.am b/libisofs/Makefile.am index 4430507..e2f197e 100755 --- a/libisofs/Makefile.am +++ b/libisofs/Makefile.am @@ -1,11 +1,11 @@ pkgconfigdir=$(libdir)/pkgconfig libincludedir=$(includedir)/libburn +##bin_PROGRAMS = test + lib_LTLIBRARIES = libisofs.la libisofs_la_SOURCES = \ - errors.h \ - errors.c \ tree.h \ tree.c \ volume.h \ @@ -14,20 +14,25 @@ libisofs_la_SOURCES = \ util.c \ ecma119.c \ ecma119.h \ - struct.h \ - struct.c \ + ecma119_tree.c \ + ecma119_tree.h \ susp.h \ susp.c \ rockridge.h \ - rockridge.c + rockridge.c \ + joliet.c \ + joliet.h libinclude_HEADERS = libisofs.h -noinst_PROGRAMS = test -test_SOURCES = test.c -test_LDADD = $(libisofs_la_OBJECTS) +##test_SOURCES = test.c +##test_LDADD = libisofs.la -INCLUDES = -I.. +##noinst_PROGRAMS = test +##test_SOURCES = test.c +##test_LDADD = $(libisofs_la_OBJECTS) + +##INCLUDES = -I../burn/libburn ## ========================================================================= ## indent_files = $(libisofs_la_SOURCES) diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index 6df65eb..8fb3150 100755 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -1,779 +1,680 @@ +/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */ /* vim: set noet ts=8 sts=8 sw=8 : */ -#include "tree.h" -#include "ecma119.h" -#include "volume.h" -#include "util.h" -#include "struct.h" -#include "rockridge.h" -#include "libisofs.h" -#include "libburn/libburn.h" -#include -#include -#include -#include -#include -#include #include -#include #include +#include +#include +#include +#include -const char* const ecma119_standard_id = "CD001"; +#include "ecma119.h" +#include "ecma119_tree.h" +#include "susp.h" +#include "rockridge.h" +#include "joliet.h" +#include "volume.h" +#include "tree.h" +#include "util.h" +#include "libisofs.h" +#include "libburn.h" -/* Format definitions */ -const char* const ecma119_vol_fmt = "B5bB"; /* common between all vol descs */ +/* burn-source compatible stuff */ +static int +bs_read(struct burn_source *bs, unsigned char *buf, int size); +static off_t +bs_get_size(struct burn_source *bs); +static void +bs_free_data(struct burn_source *bs); -const char* const ecma119_privol_fmt = - "B" /* volume desc type */ - "5b" /* standard id */ - "B" /* volume desc version */ - "x" - "32b" /* system id */ - "32b" /* volume id */ - "8x" - "=L" /* volume space size */ - "32x" - "=H" /* volume set size */ - "=H" /* volume sequence number */ - "=H" /* block size */ - "=L" /* path table size */ - "L" /* m path table 1 */ - ">L" /* m path table 2 */ - "34B" /* root directory record */ - "128b" /* volume id */ - "128b" /* publisher id */ - "128b" /* data preparer id */ - "128b" /* application id */ - "37b" /* copyright file id */ - "37b" /* abstract file id */ - "37b" /* bibliographic file id */ - "T" /* creation timestamp */ - "T" /* modification timestamp */ - "T" /* expiration timestamp */ - "T" /* effective timestamp */ - "B" /* file structure version */ - "x" - "512x" /* Application Use */ - "653x"; /* reserved */ +typedef void (*write_fn)(struct ecma119_write_target*, uint8_t*); -const char* const ecma119_supvol_joliet_fmt = - "B" /* volume desc type */ - "5b" /* standard id */ - "B" /* volume desc version */ - "B" /* volume flags */ - "16h" /* system id */ - "16h" /* volume id */ - "8x" - "=L" /* volume space size */ - "32b" /* escape sequences */ - "=H" /* volume set size */ - "=H" /* volume sequence number */ - "=H" /* block size */ - "=L" /* path table size */ - "L" /* m path table 1 */ - ">L" /* m path table 2 */ - "34B" /* root directory record */ - "64h" /* volume id */ - "64h" /* publisher id */ - "64h" /* data preparer id */ - "64h" /* application id */ - "18hx" /* copyright file id */ - "18hx" /* abstract file id */ - "18hx" /* bibliographic file id */ - "T" /* creation timestamp */ - "T" /* modification timestamp */ - "T" /* expiration timestamp */ - "T" /* effective timestamp */ - "B" /* file structure version */ - "x" - "512x" /* Application Use */ - "653x"; /* reserved */ +/* return true if the given state is only required for Joliet volumes */ +static int +is_joliet_state(enum ecma119_write_state); -const char* const ecma119_dir_record_fmt = - "B" /* dir record length */ - "B" /* extended attribute length */ - "=L" /* block */ - "=L" /* size */ - "S" - "B" /* file flags */ - "B" /* file unit size */ - "B" /* interleave gap size */ - "=H" /* volume sequence number */ - "B"; /* name length */ - /* file id ansa SU field have variable length, so they don't get defined - * yet. */ +static void +next_state(struct ecma119_write_target *t); -/* abstract string functions away from char* to make Joliet stuff easier */ -typedef void (*copy_string)(unsigned char *dest, void *str, int maxlen); -typedef int (*node_namelen)(struct iso_tree_node *node); -typedef const void* (*node_getname)(struct iso_tree_node *node); +/* write t->state_data to the buf, one block at a time */ +static void +write_data_chunk(struct ecma119_write_target *t, uint8_t *buf); -/* because we don't write SUSP fields in the Joliet Directory Records, it helps - * to abstract away the task of getting the non_CE_len of a susp_info. - */ -typedef int (*susp_len)(struct susp_info*); -typedef int (*total_dirent_len)(struct iso_tree_node*); +/* writing functions. All these functions assume the buf is large enough */ +static void +write_pri_vol_desc(struct ecma119_write_target *t, uint8_t *buf); +static void +write_vol_desc_terminator(struct ecma119_write_target *t, uint8_t *buf); +static void +write_path_table(struct ecma119_write_target *t, int l_type, uint8_t *buf); +static void +write_l_path_table(struct ecma119_write_target *t, uint8_t *buf); +static void +write_m_path_table(struct ecma119_write_target *t, uint8_t *buf); +static void +write_one_dir_record(struct ecma119_write_target *t, + struct ecma119_tree_node *dir, + int file_id, + uint8_t *buf); +static void +write_one_dir(struct ecma119_write_target *t, + struct ecma119_tree_node *dir, + uint8_t *buf); +static void +write_dirs(struct ecma119_write_target *t, uint8_t *buf); -const char application_id[] = "LIBBURN SUITE (C) 2002 D.FOREMAN/B.JANSENS"; -const char system_id[] = "LINUX"; +/* wrapper functions for writing */ +static void wr_system_area(struct ecma119_write_target*, uint8_t*); +static void wr_pri_vol_desc(struct ecma119_write_target*, uint8_t*); +static void wr_vol_desc_term(struct ecma119_write_target*, uint8_t*); +static void wr_l_path_table(struct ecma119_write_target*, uint8_t*); +static void wr_m_path_table(struct ecma119_write_target*, uint8_t*); +static void wr_dir_records(struct ecma119_write_target*, uint8_t*); +static void wr_files(struct ecma119_write_target*, uint8_t*); -const uint16_t* application_id_joliet = (uint16_t*) "\0j\0a\0p\0p\0i\0d\0\0"; -const uint16_t* system_id_joliet = (uint16_t*) "\0j\0s\0y\0s\0i\0d\0\0"; - -/* since we have to pass things by address to iso_struct_pack, this makes - * it easier. */ -const uint8_t zero = 0; -const uint8_t one = 1; - -enum RecordType { - RECORD_TYPE_SELF, - RECORD_TYPE_PARENT, - RECORD_TYPE_NORMAL, - RECORD_TYPE_ROOT +static const write_fn writers[] = +{ + NULL, + wr_system_area, + wr_pri_vol_desc, + joliet_wr_sup_vol_desc, + wr_vol_desc_term, + wr_l_path_table, + wr_m_path_table, + joliet_wr_l_path_table, + joliet_wr_m_path_table, + wr_dir_records, + joliet_wr_dir_records, + wr_files }; -/* layout functions */ -static void ecma119_reorganize_heirarchy(struct ecma119_write_target *target, - struct iso_tree_dir *dir); -static void ecma119_alloc_writer_data(struct ecma119_write_target *target, - struct iso_tree_dir *dir); -static void ecma119_setup_path_tables_iso(struct ecma119_write_target*); -static void ecma119_setup_path_tables_joliet(struct ecma119_write_target*); - -/* burn_source functions */ -static int ecma119_read(struct burn_source*, unsigned char*, int); -static int ecma119_get_size(struct burn_source*); -static void ecma119_free_data(struct burn_source*); - -/* Writers for the different write_states. */ -static void ecma119_write_system_area(struct ecma119_write_target*, - unsigned char *buf); -static void ecma119_write_privol_desc(struct ecma119_write_target*, - unsigned char *buf); -static void ecma119_write_supvol_desc_joliet(struct ecma119_write_target*, - unsigned char *buf); -static void ecma119_write_vol_desc_terminator(struct ecma119_write_target*, - unsigned char *buf); -static void ecma119_write_path_table(struct ecma119_write_target*, - unsigned char *buf, - int flags, - int m_type); -static void ecma119_write_dir_records(struct ecma119_write_target*, - unsigned char *buf, - int flags); -static void ecma119_write_files(struct ecma119_write_target*, - unsigned char *buf); - -/* helpers for the writers */ -static void ecma119_write_path_table_full(struct ecma119_write_target*, - unsigned char *buf, - int flags, - int mtype); -static unsigned char *ecma119_write_dir(struct ecma119_write_target*, - int flags, - struct iso_tree_dir*); -static void ecma119_write_dir_record(struct ecma119_write_target*, - unsigned char *, - int flags, - struct iso_tree_node*, - enum RecordType); -static void ecma119_write_dir_record_iso(struct ecma119_write_target *t, - uint8_t *buf, - struct iso_tree_node *node, - enum RecordType type); -static void ecma119_write_dir_record_joliet(struct ecma119_write_target *t, - uint8_t *buf, - struct iso_tree_node *node, - enum RecordType type); -static void ecma119_write_dir_record_noname(struct ecma119_write_target *t, - uint8_t *buf, - struct iso_tree_node *node, - enum RecordType type, - uint32_t block, - uint32_t size, - int joliet); - - -/* name-mangling routines */ - -/* return a newly allocated array of pointers to all the children, in - * in alphabetical order and with mangled names. */ -static struct iso_tree_node **ecma119_mangle_names(struct iso_tree_dir *dir); - -/* mangle a single filename according to where the last '.' is: - * \param name the name to mangle - * \param num_change the number of characters to mangle - * \param seq_num the string ("%0d", seq_num) to which it should - * be mangled +/* When a writer is created, we + * 1) create an ecma119 tree + * 2) add SUSP fields (if necessary) + * 3) calculate the size and position of all nodes in the tree + * 4) finalize SUSP fields (if necessary) */ -static void ecma119_mangle_name(char *name, - int num_change, - int seq_num); -/* mangle a single filename based on the explicit positions passed. That is, - * the difference between this and ecma119_mangle_name_iso is that this one - * doesn't look for the '.' character; it changes the character at the - * beginning of name. */ -static void ecma119_mangle_name_priv(char *name, - int num_change, - int seq_num); - -/* return a newly allocated array of pointers to all the children, in - * alphabetical order. The difference between this and ecma119_mangle_names - * is that this function sorts the files according to joliet names and it - * doesn't mangle the names. */ -static struct iso_tree_node **ecma119_sort_joliet(struct iso_tree_dir *dir); - -/* string abstraction functions */ -static int node_namelen_iso(struct iso_tree_node *node) +static void +add_susp_fields_rec(struct ecma119_write_target *t, + struct ecma119_tree_node *node) { - return strlen(iso_tree_node_get_name(node, ISO_NAME_ISO)); -} + size_t i; -static int node_namelen_joliet(struct iso_tree_node *node) -{ - const char *name = iso_tree_node_get_name(node, ISO_NAME_JOLIET); - - /* return length in bytes, not length in characters */ - return ucslen((uint16_t*)name) * 2; -} - -static const void *node_getname_iso(struct iso_tree_node *node) -{ - return iso_tree_node_get_name(node, ISO_NAME_ISO); -} - -static const void *node_getname_joliet(struct iso_tree_node *node) -{ - return iso_tree_node_get_name(node, ISO_NAME_JOLIET); -} - -static int susp_len_iso(struct susp_info *s) -{ - return s->non_CE_len; -} - -static int susp_len_joliet(struct susp_info *s) -{ - return 0; -} - -static int dirent_len_iso(struct iso_tree_node *n) -{ - return n->dirent_len + GET_NODE_INF(n)->susp.non_CE_len; -} - -static int dirent_len_joliet(struct iso_tree_node *n) -{ - return 34 + node_namelen_joliet(n); -} - -static void print_dir_info(struct iso_tree_dir *dir, - struct ecma119_write_target *t, - int spaces) -{ - struct dir_write_info *inf = GET_DIR_INF(dir); - int i; - - for (i=0; inon_CE_len=%d, " - "parent->non_CE_len=%d, len=%d, blk=%d, jblk=%d\n", - inf->susp.non_CE_len, - inf->susp.CE_len, - inf->self_susp.non_CE_len, - inf->parent_susp.non_CE_len, - inf->len, - (int)dir->block, - (int)inf->joliet_block); -} - -static void print_file_info(struct iso_tree_file *file, - struct ecma119_write_target *t, - int spaces) -{ - struct file_write_info *inf = GET_FILE_INF(file); - int i; - - for (i=0; idirent_len, - inf->susp.non_CE_len, - inf->susp.CE_len, - (int)file->attrib.st_size, - (int)file->block); -} - -static struct iso_tree_node **ecma119_mangle_names(struct iso_tree_dir *dir) -{ - size_t retsize = dir->nfiles + dir->nchildren; - struct iso_tree_node **ret = calloc(1, sizeof(void*) * retsize); - int i, j, k; - - j = 0; - for (i=0; infiles; i++) { - ret[j++] = ISO_NODE(dir->files[i]); - } - for (i=0; inchildren; i++) { - ret[j++] = ISO_NODE(dir->children[i]); - } - - qsort(ret, retsize, sizeof(void*), iso_node_cmp_iso); - - for (i=0; i= 10) { + if (!node->iso_self) return; - } - overwritten = name[num_change]; - sprintf(fmt, "%%0%1dd", num_change); - sprintf(name, fmt, seq_num); - name[num_change] = overwritten; + 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); + } + 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 struct iso_tree_node **ecma119_sort_joliet(struct iso_tree_dir *dir) +static void +add_susp_fields(struct ecma119_write_target *t) { - struct dir_write_info *inf = GET_DIR_INF(dir); - size_t retsize = dir->nfiles + inf->real_nchildren; - struct iso_tree_node **ret = malloc(retsize * sizeof(void*)); - int i, j; - - j = 0; - for (i=0; infiles; i++) { - ret[j++] = ISO_NODE(dir->files[i]); - } - for (i=0; ireal_nchildren; i++) { - ret[j++] = ISO_NODE(inf->real_children[i]); - } - qsort(ret, retsize, sizeof(void*), iso_node_cmp_joliet); - - return ret; + susp_add_SP(t, t->root); + rrip_add_ER(t, t->root); + add_susp_fields_rec(t, t->root); } -struct ecma119_write_target *ecma119_target_new(struct iso_volset *volset, - int volnum) +/** + * Fill out the dir.len and dir.CE_len fields for each + * ecma119_tree_node that is a directory. Also calculate the total number of + * directories and the number of files for which we need to write out data. + * (dirlist_len and filelist_len) + */ +static void +calc_dir_size(struct ecma119_write_target *t, + struct ecma119_tree_node *dir) { - struct ecma119_write_target *t; + size_t i; - assert(volnum < volset->volset_size); + assert(dir->type == ECMA119_DIR); - t = calloc(1, sizeof(struct ecma119_write_target)); + 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->dir.len += ch->dirent_len + ch->susp.non_CE_len; + dir->dir.CE_len += ch->susp.CE_len; + } + t->total_dir_size += round_up(dir->dir.len + dir->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; + 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++; + } + } +} + +/** + * Fill out the block field in each ecma119_tree_node that is a directory and + * fill out t->dirlist. + */ +static void +calc_dir_pos(struct ecma119_write_target *t, + struct ecma119_tree_node *dir) +{ + size_t i; + + 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); + t->dirlist[t->curfile++] = dir; + for (i = 0; i < dir->dir.nchildren; i++) { + struct ecma119_tree_node *ch = dir->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; + } +} + +/** + * Fill out the block field for each ecma119_tree_node that is a file and fill + * out t->filelist. + */ +static void +calc_file_pos(struct ecma119_write_target *t, + struct ecma119_tree_node *dir) +{ + size_t i; + + assert(dir->type == ECMA119_DIR); + + 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; + + 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; + } + } + + 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); + } + + /* reset curfile when we're finished */ + if (!dir->parent) { + t->curfile = 0; + } +} + +struct ecma119_write_target* +ecma119_target_new(struct iso_volset *volset, + int volnum, + int level, + int flags) +{ + 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; + + volset->refcount++; + t->root = ecma119_tree_create(t, iso_root); + t->joliet = (flags & ECMA119_JOLIET) ? 1 : 0; + 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; - iso_tree_sort(TARGET_ROOT(t)); - ecma119_alloc_writer_data(t, TARGET_ROOT(t)); - ecma119_reorganize_heirarchy(t, TARGET_ROOT(t)); + 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->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); + + /* fill out the pathlist */ + t->pathlist[0] = t->root; + t->path_table_size = 10; /* root directory record */ + 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]; + if (ch->type == ECMA119_DIR) { + size_t len = 8 + strlen(ch->name); + t->pathlist[cur++] = ch; + t->path_table_size += len + len % 2; + } + } + } + + t->curblock = 16 /* system area */ + + 1 /* volume desc */ + + 1; /* volume desc terminator */ + + if (t->joliet) /* supplementary vol desc */ + t->curblock += div_up (2048, t->block_size); + + t->l_path_table_pos = t->curblock; + t->curblock += div_up(t->path_table_size, t->block_size); + t->m_path_table_pos = t->curblock; + t->curblock += div_up(t->path_table_size, t->block_size); + if (t->joliet) { + joliet_prepare_path_tables(t); + t->l_path_table_pos_joliet = t->curblock; + t->curblock += div_up(t->path_table_size_joliet, t->block_size); + t->m_path_table_pos_joliet = t->curblock; + t->curblock += div_up(t->path_table_size_joliet, t->block_size); + } + + calc_dir_pos(t, t->root); + if (t->joliet) + joliet_calc_dir_pos(t, t->joliet_root); + calc_file_pos(t, t->root); + + if (t->rockridge) { + susp_finalize(t, t->root); + rrip_finalize(t, t->root); + } + + t->total_size = t->curblock * t->block_size; + t->vol_space_size = t->curblock; + + /* prepare for writing */ + t->curblock = 0; + t->state = ECMA119_WRITE_SYSTEM_AREA; return t; } -/** - * Write create all necessary SUSP fields for the given directory and - * initialise them. Any SUSP fields that require an offset won't be completed - * yet. Ensure that the size fields in the susp_info structs are correct. - */ -static void ecma119_susp_dir_layout(struct ecma119_write_target *target, - struct iso_tree_dir *dir, - int flags) +static int +is_joliet_state(enum ecma119_write_state state) { - struct dir_write_info *inf = GET_DIR_INF(dir); - struct susp_info *susp = &inf->susp; - susp->n_susp_fields = 0; - susp->susp_fields = NULL; - - if (!target->rockridge) { - /* since Rock Ridge is the only SUSP extension supported, - * no need to continue. */ - return; - } - - if (dir->depth == 1) { - susp_add_SP(target, dir); - susp_add_ER(target, dir); - } else { - rrip_add_NM(target, ISO_NODE(dir)); - rrip_add_TF(target, ISO_NODE(dir)); - } - rrip_add_PX_dir(target, dir); - - if (inf->real_parent != dir->parent) { - rrip_add_RE(target, ISO_NODE(dir)); - rrip_add_PL(target, dir); - } - susp_add_CE(target, ISO_NODE(dir)); + return state == ECMA119_WRITE_SUP_VOL_DESC_JOLIET + || state == ECMA119_WRITE_L_PATH_TABLE_JOLIET + || state == ECMA119_WRITE_M_PATH_TABLE_JOLIET + || state == ECMA119_WRITE_DIR_RECORDS_JOLIET; } -/** - * Write create all necessary SUSP fields for the given file and - * initialise them. Any SUSP fields that require an offset won't be completed - * yet. Ensure that the size fields in the susp_info structs are correct. - */ -static void ecma119_susp_file_layout(struct ecma119_write_target *target, - struct iso_tree_file *file) +static void +next_state(struct ecma119_write_target *t) { - struct file_write_info *inf = GET_FILE_INF(file); + t->state++; + while (!t->joliet && is_joliet_state(t->state)) + t->state++; - if (!target->rockridge) { - return; - } - - rrip_add_PX(target, ISO_NODE(file)); - rrip_add_NM(target, ISO_NODE(file)); - rrip_add_TF(target, ISO_NODE(file)); - - if (inf->real_me) { - rrip_add_CL(target, ISO_NODE(file)); - } - if (S_ISLNK(file->attrib.st_mode)) { - rrip_add_SL(target, ISO_NODE(file)); - } - if (S_ISCHR(file->attrib.st_mode) || S_ISBLK(file->attrib.st_mode)) { - rrip_add_PN(target, ISO_NODE(file)); - } - susp_add_CE(target, ISO_NODE(file)); + printf ("now in state %d, curblock=%d\n", (int)t->state, (int)t->curblock); } -/** - * Recursively allocate the writer_data pointer for each node in the tree. - * Also, save the current state of the tree in the inf->real_XXX pointers. - */ -static void ecma119_alloc_writer_data(struct ecma119_write_target *target, - struct iso_tree_dir *dir) +static void +wr_system_area(struct ecma119_write_target *t, uint8_t *buf) { - struct dir_write_info *inf; - int i; - - inf = calloc(1, sizeof(struct dir_write_info)); - inf->real_parent = dir->parent; - inf->real_nchildren = dir->nchildren; - inf->real_children = malloc(sizeof(void*) * dir->nchildren); - memcpy(inf->real_children, dir->children, dir->nchildren*sizeof(void*)); - inf->real_depth = dir->depth; - - dir->writer_data = inf; - - for (i=0; inchildren; i++) { - ecma119_alloc_writer_data(target, dir->children[i]); + memset(buf, 0, t->block_size); + if (t->curblock == 15) { + next_state(t); } - for (i=0; infiles; i++) { - dir->files[i]->writer_data = - calloc(1, sizeof(struct file_write_info)); +} +static void +wr_pri_vol_desc(struct ecma119_write_target *t, uint8_t *buf) +{ + ecma119_start_chunking(t, write_pri_vol_desc, 2048, buf); +} + +static void +wr_vol_desc_term(struct ecma119_write_target *t, uint8_t *buf) +{ + ecma119_start_chunking(t, write_vol_desc_terminator, 2048, buf); +} + +static void +wr_l_path_table(struct ecma119_write_target *t, uint8_t *buf) +{ + ecma119_start_chunking(t, write_l_path_table, t->path_table_size, buf); +} + +static void +wr_m_path_table(struct ecma119_write_target *t, uint8_t *buf) +{ + ecma119_start_chunking(t, write_m_path_table, t->path_table_size, buf); +} + +static void +wr_dir_records(struct ecma119_write_target *t, uint8_t *buf) +{ + ecma119_start_chunking(t, write_dirs, t->total_dir_size, buf); +} + +static void +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; + + if (!f_st->fd) { + f_st->data_len = f->iso_self->attrib.st_size; + f_st->fd = fopen(path, "r"); + if (!f_st->fd) + err(1, "couldn't open %s for reading", path); + assert(t->curblock == f->block); + } + + nread = fread(buf, 1, t->block_size, f_st->fd); + f_st->pos += t->block_size; + if (nread < 0) + warn("problem reading from %s", path); + else if (nread != t->block_size && f_st->pos < f_st->data_len) + warnx("incomplete read from %s", path); + if (f_st->pos >= f_st->data_len) { + fclose(f_st->fd); + f_st->fd = 0; + f_st->pos = 0; + f_st->file++; + if (f_st->file >= t->filelist_len) + next_state(t); } } -/* ensure that the maximum height of the directory tree is 8, repositioning - * directories as necessary */ -static void ecma119_reorganize_heirarchy(struct ecma119_write_target *target, - struct iso_tree_dir *dir) +static void +write_pri_vol_desc(struct ecma119_write_target *t, uint8_t *buf) { - struct dir_write_info *inf = GET_DIR_INF(dir); - struct iso_tree_dir *root = TARGET_ROOT(target); - struct iso_tree_file *file; - struct file_write_info *finf; + struct ecma119_pri_vol_desc *vol = (struct ecma119_pri_vol_desc*)buf; + struct iso_volume *volume = t->volset->volume[t->volnum]; + char *vol_id = wcstoascii(volume->volume_id); + char *pub_id = wcstoascii(volume->publisher_id); + char *data_id = wcstoascii(volume->data_preparer_id); + char *volset_id = wcstoascii(t->volset->volset_id); - /* save this now in case a recursive call modifies this value */ - int nchildren = dir->nchildren; - int i; + vol->vol_desc_type[0] = 1; + memcpy(vol->std_identifier, "CD001", 5); + vol->vol_desc_version[0] = 1; + memcpy(vol->system_id, "SYSID", 5); + if (vol_id) + strncpy((char*)vol->volume_id, vol_id, 32); + iso_bb(vol->vol_space_size, t->vol_space_size, 4); + iso_bb(vol->vol_set_size, t->volset->volset_size, 2); + iso_bb(vol->vol_seq_number, t->volnum + 1, 2); + iso_bb(vol->block_size, t->block_size, 2); + iso_bb(vol->path_table_size, t->path_table_size, 4); + iso_lsb(vol->l_path_table_pos, t->l_path_table_pos, 4); + iso_msb(vol->m_path_table_pos, t->m_path_table_pos, 4); - if (dir == root) { - dir->depth = 1; - } else { - dir->depth = dir->parent->depth + 1; + write_one_dir_record(t, t->root, 3, vol->root_dir_record); - assert(dir->depth <= 9); - if (dir->depth == 9) { - dir->depth = 2; - dir->parent = root; - root->nchildren++; - root->children = realloc(root->children, - root->nchildren * sizeof(void*)); - root->children[root->nchildren-1] = dir; + strncpy((char*)vol->vol_set_id, volset_id, 128); + strncpy((char*)vol->publisher_id, pub_id, 128); + strncpy((char*)vol->data_prep_id, data_id, 128); + strncpy((char*)vol->application_id, "APPID", 128); - /* no need to reshuffle the siblings since we know that - * _every_ sibling will also be relocated. */ - inf->real_parent->nchildren--; - if (!inf->real_parent->nchildren) { - free(inf->real_parent->children); - inf->real_parent->children = NULL; - } - /* insert a placeholder file for the CL field */ - file = iso_tree_add_new_file(inf->real_parent, - dir->name.full); - finf = calloc(1, sizeof(struct file_write_info)); - finf->real_me = dir; - file->writer_data = finf; - } - } - for (i=0; ichildren[i]); + 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); + vol->file_structure_version[0] = 1; + + free(vol_id); + free(volset_id); + free(pub_id); + free(data_id); +} + +static void +write_vol_desc_terminator(struct ecma119_write_target *t, uint8_t *buf) +{ + struct ecma119_vol_desc_terminator *vol = + (struct ecma119_vol_desc_terminator*) buf; + + vol->vol_desc_type[0] = 255; + memcpy(vol->std_identifier, "CD001", 5); + vol->vol_desc_version[0] = 1; +} + +static void +write_path_table(struct ecma119_write_target *t, int l_type, uint8_t *buf) +{ + void (*write_int)(uint8_t*, uint32_t, int) = l_type ? iso_lsb + : iso_msb; + size_t i; + struct ecma119_path_table_record *rec; + struct ecma119_tree_node *dir; + int parent = 0; + + for (i = 0; i < t->dirlist_len; i++) { + dir = t->pathlist[i]; + 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_xa[0] = 0; + write_int(rec->block, dir->block, 4); + write_int(rec->parent, parent + 1, 2); + if (dir->parent) + memcpy(rec->dir_id, dir->name, rec->len_di[0]); + buf += 8 + rec->len_di[0] + (rec->len_di[0] % 2); } } -/* set directory sizes recursively. Also fill out the dirlist_len and - * filelist_len fields in the ecma119 writer. - */ -static void ecma119_target_rsize(struct ecma119_write_target *t, - struct iso_tree_dir *dir) +static void +write_l_path_table(struct ecma119_write_target *t, uint8_t *buf) { - int i; - struct dir_write_info *inf = GET_DIR_INF(dir); - struct node_write_info *cinf; - - t->dirlist_len++; - - /* work out the size of the dirents */ - if (dir->depth == 1) { - dir->dirent_len = 34; - } else { - dir->dirent_len = 33 + node_namelen_iso(ISO_NODE(dir)); - } - dir->dirent_len += dir->dirent_len % 2; - - for (i=0; infiles; i++) { - dir->files[i]->dirent_len = 33 + node_namelen_iso( - ISO_NODE(dir->files[i])); - dir->files[i]->dirent_len += dir->files[i]->dirent_len % 2; - - if (dir->files[i]->path && dir->files[i]->attrib.st_size) { - t->filelist_len++; - } - } - - /* layout all the susp entries and calculate the total size */ - ecma119_susp_dir_layout(t, dir, 0); - - inf->len = 34 + inf->self_susp.non_CE_len /* for "." and ".." */ - + 34 + inf->parent_susp.non_CE_len; - inf->susp_len = inf->susp.CE_len - + inf->self_susp.CE_len - + inf->parent_susp.CE_len; - - for (i=0; infiles; i++) { - ecma119_susp_file_layout(t, dir->files[i]); - cinf = GET_NODE_INF(dir->files[i]); - inf->len += dir->files[i]->dirent_len + cinf->susp.non_CE_len; - inf->susp_len += cinf->susp.CE_len; - } - for (i=0; inchildren; i++) { - ecma119_target_rsize(t, dir->children[i]); - cinf = GET_NODE_INF(dir->children[i]); - inf->len += dir->children[i]->dirent_len +cinf->susp.non_CE_len; - inf->susp_len += cinf->susp.CE_len; - } - dir->attrib.st_size = inf->len; /* the actual size of the data is - * inf->len + inf->susp_len because we - * append the CE data to the end of the - * directory. But the ISO volume - * doesn't need to know. - */ + write_path_table(t, 1, buf); } -static void ecma119_target_rsize_joliet(struct ecma119_write_target *t, - struct iso_tree_dir *dir) +static void +write_m_path_table(struct ecma119_write_target *t, uint8_t *buf) { - struct dir_write_info *inf = GET_DIR_INF(dir); - int i; - - inf->joliet_len = 34 + 34; /* for "." and ".." */ - for (i=0; infiles; i++) { - /* don't count files that are placeholders for Rock Ridge - * relocated directories */ - if (!GET_FILE_INF(dir->files[i])->real_me) { - inf->joliet_len += - dirent_len_joliet(ISO_NODE(dir->files[i])); - } - } - for (i=0; ireal_nchildren; i++) { - struct iso_tree_node *ch = ISO_NODE(inf->real_children[i]); - inf->joliet_len += dirent_len_joliet(ch); - ecma119_target_rsize_joliet(t, inf->real_children[i]); - } + write_path_table(t, 0, buf); } -/* set directory positions recursively. Also fill out the dirlist in the - * ecma119_write_target */ -static void ecma119_target_dir_layout(struct ecma119_write_target *t, - struct iso_tree_dir *dir) +/* if file_id is >= 0, we use it instead of the filename. As a magic number, + * file_id == 3 means that we are writing the root directory record (in order + * to distinguish it from the "." entry in the root directory) */ +static void +write_one_dir_record(struct ecma119_write_target *t, + struct ecma119_tree_node *node, + int file_id, + uint8_t *buf) { - struct dir_write_info *inf = GET_DIR_INF(dir); - int i; - - t->dirlist[t->curfile++] = dir; - dir->block = t->curblock; - t->curblock += DIV_UP(inf->len + inf->susp_len, 2048); - - for (i=0; inchildren; i++) { - ecma119_target_dir_layout(t, dir->children[i]); - } -} - -/* same as ecma119_target_dir_layout, but for Joliet. */ -static void ecma119_target_dir_layout_joliet(struct ecma119_write_target *t, - struct iso_tree_dir *dir) -{ - struct dir_write_info *inf = GET_DIR_INF(dir); - int i; - - t->dirlist_joliet[t->curfile++] = dir; - inf->joliet_block = t->curblock; - t->curblock += DIV_UP(inf->joliet_len, 2048); - - for (i=0; ireal_nchildren; i++) { - ecma119_target_dir_layout_joliet(t, inf->real_children[i]); - } -} - -/* set file positions recursively. Also fill in the filelist in the - * ecma119_write_target */ -static void ecma119_target_file_layout(struct ecma119_write_target *t, - struct iso_tree_dir *dir) -{ - int i; - - for (i=0; infiles; i++) { - if (dir->files[i]->path && dir->files[i]->attrib.st_size) { - t->filelist[t->curfile++] = dir->files[i]; - } - dir->files[i]->block = t->curblock; - t->curblock += DIV_UP(dir->files[i]->attrib.st_size, 2048); - } - for (i=0; inchildren; i++) { - ecma119_target_file_layout(t, dir->children[i]); - } -} - -void ecma119_target_layout(struct ecma119_write_target *t) -{ - ecma119_target_rsize(t, TARGET_ROOT(t)); - if (t->joliet) { - ecma119_target_rsize_joliet(t, TARGET_ROOT(t)); - } - ecma119_setup_path_tables_iso(t); - t->curblock = 16 /* for the system area */ - + 1 /* volume desc */ - + 1; /* volume desc terminator */ - if (t->joliet) { - t->curblock++; /* joliet supplementary volume desc */ - } - - t->l_path_table_pos = t->curblock; - t->curblock += DIV_UP(t->path_table_size, 2048); - t->m_path_table_pos = t->curblock; - t->curblock += DIV_UP(t->path_table_size, 2048); - - if (t->joliet) { - ecma119_setup_path_tables_joliet(t); - t->l_path_table_pos_joliet = t->curblock; - t->curblock += DIV_UP(t->path_table_size_joliet, 2048); - t->m_path_table_pos_joliet = t->curblock; - t->curblock += DIV_UP(t->path_table_size_joliet, 2048); - } - - t->dirlist = calloc(1, sizeof(void*) * t->dirlist_len); - t->filelist = calloc(1, sizeof(void*) * t->filelist_len); - t->curfile = 0; - ecma119_target_dir_layout(t, TARGET_ROOT(t)); - - if (t->joliet) { - t->curfile = 0; - t->dirlist_joliet = calloc(1, sizeof(void*) * t->dirlist_len); - ecma119_target_dir_layout_joliet(t, TARGET_ROOT(t)); - } - - t->curfile = 0; - ecma119_target_file_layout(t, TARGET_ROOT(t)); - t->total_size = t->curblock * 2048; - t->vol_space_size = t->curblock; + uint8_t len_dr = (file_id >= 0) ? 34 : node->dirent_len; + uint8_t len_fi = (file_id >= 0) ? 1 : strlen(node->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; + struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf; + /* we don't write out susp fields for the root node */ if (t->rockridge) { - susp_finalize(t, TARGET_ROOT(t)); - rrip_finalize(t, TARGET_ROOT(t)); + if (file_id == 0) { + susp_write(t, &node->dir.self_susp, &buf[len_dr]); + len_dr += node->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; + } else if (file_id < 0) { + susp_write(t, &node->susp, &buf[len_dr]); + len_dr += node->susp.non_CE_len; + } + } + 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, len, 4); + iso_datetime_7(rec->recording_time, t->now); + rec->flags[0] = (node->type == ECMA119_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); +} + +static void +write_one_dir(struct ecma119_write_target *t, + struct ecma119_tree_node *dir, + uint8_t *buf) +{ + size_t i; + uint8_t *orig_buf = buf; + + assert(dir->type == ECMA119_DIR); + /* write the "." and ".." entries first */ + write_one_dir_record(t, dir, 0, buf); + buf += ((struct ecma119_dir_record*) buf)->len_dr[0]; + + 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); + buf += ((struct ecma119_dir_record*) buf)->len_dr[0]; } - iso_tree_print_verbose(TARGET_ROOT(t), - (print_dir_callback)print_dir_info, - (print_file_callback)print_file_info, - t, 0); + /* 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; + } + } + assert (buf - orig_buf == dir->dir.len + dir->dir.CE_len); +} - /* prepare for writing */ - t->curblock = -1; - t->state = ECMA119_WRITE_SYSTEM_AREA; +static void +write_dirs(struct ecma119_write_target *t, uint8_t *buf) +{ + size_t i; + struct ecma119_tree_node *dir; + 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); + } +} + +void +ecma119_start_chunking(struct ecma119_write_target *t, + write_fn writer, + off_t data_size, + uint8_t *buf) +{ + if (data_size > t->state_data_size) { + data_size = round_up(data_size, t->block_size); + t->state_data = realloc(t->state_data, data_size); + t->state_data_size = data_size; + } + memset(t->state_data, 0, t->state_data_size); + t->state_data_off = 0; + t->state_data_valid = 1; + writer(t, t->state_data); + write_data_chunk(t, buf); +} + +static void +write_data_chunk(struct ecma119_write_target *t, uint8_t *buf) +{ + memcpy(buf, t->state_data + t->state_data_off, t->block_size); + t->state_data_off += t->block_size; + if (t->state_data_off >= t->state_data_size) { + assert (t->state_data_off <= t->state_data_size); + t->state_data_valid = 0; + next_state(t); + } +} + +static int +bs_read(struct burn_source *bs, unsigned char *buf, int size) +{ + struct ecma119_write_target *t = (struct ecma119_write_target*)bs->data; + if (size != t->block_size) { + warnx("you must read data in block-sized chunks (%d bytes)", + (int)t->block_size); + return 0; + } else if (t->curblock >= t->vol_space_size) { + return 0; + } + if (t->state_data_valid) + write_data_chunk(t, buf); + else + writers[t->state](t, buf); + t->curblock++; + return size; +} + +static off_t +bs_get_size(struct burn_source *bs) +{ + struct ecma119_write_target *t = (struct ecma119_write_target*)bs->data; + return t->total_size; +} + +static void +bs_free_data(struct burn_source *bs) +{ + struct ecma119_write_target *t = (struct ecma119_write_target*)bs->data; + ecma119_tree_free(t->root); + free(t->dirlist); + free(t->pathlist); + free(t->dirlist_joliet); + free(t->pathlist_joliet); + free(t->filelist); + free(t->state_data); + if (t->state_files.fd) + fclose(t->state_files.fd); } struct burn_source *iso_source_new_ecma119(struct iso_volset *volset, @@ -781,726 +682,11 @@ struct burn_source *iso_source_new_ecma119(struct iso_volset *volset, int level, int flags) { - struct burn_source *src = calloc(1, sizeof(struct burn_source)); - struct ecma119_write_target *t = ecma119_target_new(volset, volnum); - struct iso_volume *vol = volset->volume[volnum]; - - t->iso_level = level; - t->rockridge = (flags & ECMA119_ROCKRIDGE) ? 1:0; - t->joliet = (flags & ECMA119_JOLIET) ? 1:0; - - vol->iso_level = t->iso_level; - vol->rockridge = t->rockridge; - vol->joliet = t->joliet; - - ecma119_target_layout(t); - src->read = ecma119_read; - src->read_sub = NULL; - src->get_size = ecma119_get_size; - src->free_data = ecma119_free_data; - src->data = t; - return src; -} - -static int ecma119_read(struct burn_source *src, - unsigned char *data, - int size) -{ - struct ecma119_write_target *t = src->data; - - assert( src->read == ecma119_read && src->get_size == ecma119_get_size - && src->free_data == ecma119_free_data - && size == 2048); - - t->curblock++; - memset(data, 0, size); - switch(t->state) { - case ECMA119_WRITE_SYSTEM_AREA: - ecma119_write_system_area(t, data); - break; - case ECMA119_WRITE_PRI_VOL_DESC: - ecma119_write_privol_desc(t, data); - break; - case ECMA119_WRITE_SUP_VOL_DESC_JOLIET: - ecma119_write_supvol_desc_joliet(t, data); - break; - case ECMA119_WRITE_VOL_DESC_TERMINATOR: - ecma119_write_vol_desc_terminator(t, data); - break; - case ECMA119_WRITE_L_PATH_TABLE: - ecma119_write_path_table(t, data, 0, 0); - break; - case ECMA119_WRITE_M_PATH_TABLE: - ecma119_write_path_table(t, data, 0, 1); - break; - case ECMA119_WRITE_L_PATH_TABLE_JOLIET: - ecma119_write_path_table(t, data, ECMA119_JOLIET, 0); - break; - case ECMA119_WRITE_M_PATH_TABLE_JOLIET: - ecma119_write_path_table(t, data, ECMA119_JOLIET, 1); - break; - case ECMA119_WRITE_DIR_RECORDS: - ecma119_write_dir_records(t, data, 0); - break; - case ECMA119_WRITE_DIR_RECORDS_JOLIET: - ecma119_write_dir_records(t, data, ECMA119_JOLIET); - break; - case ECMA119_WRITE_FILES: - ecma119_write_files(t, data); - break; - case ECMA119_WRITE_DONE: - return 0; - default: - assert(0); - } - - return 2048; -} - -static int ecma119_get_size(struct burn_source *src) -{ - struct ecma119_write_target *t = src->data; - - assert( src->read == ecma119_read && src->get_size == ecma119_get_size - && src->free_data == ecma119_free_data); - - return t->total_size; -} - -/* free writer_data fields recursively */ -static void ecma119_free_writer_data(struct ecma119_write_target *t, - struct iso_tree_dir *dir) -{ - struct dir_write_info *inf = GET_DIR_INF(dir); - int i; - - susp_free_fields(&inf->susp); - susp_free_fields(&inf->self_susp); - susp_free_fields(&inf->parent_susp); - - if (inf->real_children) { - free(inf->real_children); - } - - for (i=0; infiles; i++) { - struct file_write_info *finf = GET_FILE_INF(dir->files[i]); - susp_free_fields(&finf->susp); - } - for (i=0; inchildren; i++) { - ecma119_free_writer_data(t, dir->children[i]); - } -} - -static void ecma119_free_data(struct burn_source *src) -{ - struct ecma119_write_target *t = src->data; - - assert( src->read == ecma119_read && src->get_size == ecma119_get_size - && src->free_data == ecma119_free_data); - - if (t->filelist) free(t->filelist); - if (t->dirlist) free(t->dirlist); - if (t->pathlist) free(t->pathlist); - if (t->dirlist_joliet) free(t->dirlist_joliet); - if (t->pathlist_joliet) free(t->pathlist_joliet); - - ecma119_free_writer_data(t, TARGET_ROOT(t)); - - free(t); - src->data = NULL; - src->read = NULL; - src->get_size = NULL; - src->free_data = NULL; -} - -/*============================================================================*/ -/* Writing functions */ -/*============================================================================*/ - -static void ecma119_write_system_area(struct ecma119_write_target *t, - unsigned char *buf) -{ - if (t->curblock == 15) { - t->state = ECMA119_WRITE_PRI_VOL_DESC; - } -} - -static void ecma119_write_privol_desc(struct ecma119_write_target *t, - unsigned char *buf) -{ - struct iso_tree_node *root = ISO_NODE(TARGET_ROOT(t)); - struct iso_volume *vol = t->volset->volume[t->volnum]; - uint8_t one = 1; /* so that we can take &one */ - uint32_t zero = 0; - time_t never = -1; - uint8_t dir_record[34]; - - ecma119_write_dir_record(t, dir_record, 0, root, RECORD_TYPE_ROOT); - iso_struct_pack(ecma119_privol_fmt, buf, - &one, - "CD001", - &one, - system_id, - vol->volume_id.cstr, - &t->vol_space_size, - &t->volset->volset_size, - &t->volnum, - &t->block_size, - &t->path_table_size, - &t->l_path_table_pos, - &zero, - &t->m_path_table_pos, - &zero, - dir_record, - t->volset->volset_id.cstr, - vol->publisher_id.cstr, - vol->data_preparer_id.cstr, - application_id, - "", - "", - "", - &t->now, - &t->now, - &never, - &t->now, - &one); - - t->state = (t->joliet) ? ECMA119_WRITE_SUP_VOL_DESC_JOLIET : - ECMA119_WRITE_VOL_DESC_TERMINATOR; -} - -static void ecma119_write_supvol_desc_joliet(struct ecma119_write_target *t, - unsigned char *buf) -{ struct iso_tree_node *root = ISO_NODE(TARGET_ROOT(t)); - struct iso_volume *vol = t->volset->volume[t->volnum]; - uint8_t one = 1; /* so that we can take &one */ - uint8_t two = 2; - uint32_t zero = 0; - time_t never = -1; - uint8_t dir_record[34]; - - ecma119_write_dir_record(t, dir_record, ECMA119_JOLIET, - root, RECORD_TYPE_ROOT); - iso_struct_pack(ecma119_supvol_joliet_fmt, buf, - &two, - "CD001", - &one, - &zero, - system_id_joliet, - vol->volume_id.jstr, - &t->vol_space_size, - "%/E", - &t->volset->volset_size, - &t->volnum, - &t->block_size, - &t->path_table_size_joliet, - &t->l_path_table_pos_joliet, - &zero, - &t->m_path_table_pos_joliet, - &zero, - dir_record, - t->volset->volset_id.jstr, - vol->publisher_id.jstr, - vol->data_preparer_id.jstr, - application_id_joliet, - &zero, - &zero, - &zero, - &t->now, - &t->now, - &never, - &t->now, - &one); - - t->state = ECMA119_WRITE_VOL_DESC_TERMINATOR; -} - -static void ecma119_write_vol_desc_terminator(struct ecma119_write_target *t, - unsigned char *buf) -{ - buf[0] = 255; - strcpy((char*)&buf[1], "CD001"); - buf[6] = 1; - - t->state = ECMA119_WRITE_L_PATH_TABLE; -} - -/** - * Write a full path table to the buffer (it is assumed to be large enough). - * The path table will be broken into 2048-byte chunks later is necessary. - */ -static void ecma119_write_path_table_full(struct ecma119_write_target *t, - unsigned char *buf, - int flags, - int m_type) -{ - void (*write_int)(uint8_t*, uint32_t, int); - struct iso_tree_dir *dir; - const char *name; - int len, parent, i; - size_t off; - - node_namelen namelen; - node_getname getname; - off_t root_block; - struct iso_tree_dir **pathlist; - - if (flags & ECMA119_JOLIET) { - namelen = node_namelen_joliet; - getname = node_getname_joliet; - pathlist = t->pathlist_joliet; - root_block = GET_DIR_INF(pathlist[0])->joliet_block; - } else { - namelen = node_namelen_iso; - getname = node_getname_iso; - pathlist = t->pathlist; - root_block = pathlist[0]->block; - } - - write_int = m_type ? iso_msb : iso_lsb; - - /* write the root directory */ - buf[0] = 1; - buf[1] = 0; - write_int(&buf[2], root_block, 4); - write_int(&buf[6], 1, 2); - - /* write the rest */ - off = 10; - for (i=1; idirlist_len; i++) { - struct iso_tree_dir *dirparent; - off_t block; - - dir = pathlist[i]; - name = getname(ISO_NODE(dir)); - len = namelen(ISO_NODE(dir)); - if (flags & ECMA119_JOLIET) { - dirparent = GET_DIR_INF(dir)->real_parent; - block = GET_DIR_INF(dir)->joliet_block; - } else { - dirparent = dir->parent; - block = dir->block; - } - - for (parent=0; parentstate_data.path_table -static void ecma119_write_path_table(struct ecma119_write_target *t, - unsigned char *buf, - int flags, - int m_type) -{ - int path_table_size; - - if (flags & ECMA119_JOLIET) { - path_table_size = t->path_table_size_joliet; - } else { - path_table_size = t->path_table_size; - } - - if (!SDATA.data) { - SDATA.data = calloc(1, ROUND_UP(path_table_size, 2048)); - ecma119_write_path_table_full(t, SDATA.data, flags, m_type); - } - - memcpy(buf, SDATA.data + SDATA.blocks*2048, 2048); - SDATA.blocks++; - - if (SDATA.blocks*2048 >= path_table_size) { - free(SDATA.data); - SDATA.data = NULL; - SDATA.blocks = 0; - if (!t->joliet && m_type) { - t->state = ECMA119_WRITE_DIR_RECORDS; - } else { - t->state++; - } - } -} -#undef SDATA - -#define SDATA t->state_data.dir_records -static void ecma119_write_dir_records(struct ecma119_write_target *t, - unsigned char *buf, - int flags) -{ - struct iso_tree_dir **dirlist; - - if (flags & ECMA119_JOLIET) { - dirlist = t->dirlist_joliet; - } else { - dirlist = t->dirlist; - } - - if (!SDATA.data) { - struct iso_tree_dir *dir = dirlist[SDATA.dir++]; - struct dir_write_info *inf = GET_DIR_INF(dir); - - SDATA.data = ecma119_write_dir(t, flags, dir); - SDATA.pos = 0; - - if (flags & ECMA119_JOLIET) { - SDATA.data_len = inf->joliet_len; - } else { - SDATA.data_len = inf->len + inf->susp_len; - } - } - - memcpy(buf, SDATA.data + SDATA.pos, 2048); - SDATA.pos += 2048; - - if (SDATA.pos >= SDATA.data_len) { - free(SDATA.data); - SDATA.data = 0; - SDATA.pos = 0; - SDATA.data_len = 0; - if (SDATA.dir == t->dirlist_len) { - SDATA.dir = 0; - if (!t->joliet || (flags & ECMA119_JOLIET)) { - t->state = t->filelist_len ? ECMA119_WRITE_FILES - : ECMA119_WRITE_DONE; - } else { - t->state = ECMA119_WRITE_DIR_RECORDS_JOLIET; - } - } - } -} -#undef SDATA - -#define SDATA t->state_data.files -static void ecma119_write_files(struct ecma119_write_target *t, - unsigned char *buf) -{ - int numread; - - if (!SDATA.fd) { - struct iso_tree_file *f = t->filelist[SDATA.file++]; - assert(t->curblock == f->block); - SDATA.fd = fopen(f->path, "r"); - SDATA.data_len = f->attrib.st_size; - if (!SDATA.fd) { - fprintf(stderr, "Error: couldn't open file %s: %s\n", - f->path, strerror(errno)); - } - } - - if (SDATA.fd) { - numread = fread(buf, 1, 2048, SDATA.fd); - } else { - numread = t->block_size; - } - if (numread == -1) { - fprintf(stderr, "Error reading file: %s\n", strerror(errno)); - return; - } - SDATA.pos += numread; - - if (!SDATA.pos || SDATA.pos >= SDATA.data_len) { - fclose(SDATA.fd); - SDATA.data_len = 0; - SDATA.fd = NULL; - SDATA.pos = 0; - if (SDATA.file == t->filelist_len) { - SDATA.file = 0; - t->state = ECMA119_WRITE_DONE; - } - } -} -#undef SDATA - -static unsigned char *ecma119_write_dir(struct ecma119_write_target *t, - int flags, - struct iso_tree_dir *dir) -{ - struct dir_write_info *inf = GET_DIR_INF(dir); - int len = ROUND_UP(inf->susp_len + inf->len, 2048); - unsigned char *buf; - int i, pos; - struct iso_tree_node *ch; - - susp_len slen; - total_dirent_len dlen; - struct iso_tree_node **children; - int nchildren; - - assert ( ((flags & ECMA119_JOLIET) && t->curblock == inf->joliet_block) - || t->curblock == dir->block ); - - if (flags & ECMA119_JOLIET) { - children = ecma119_sort_joliet(dir); - nchildren = inf->real_nchildren + dir->nfiles; - len = ROUND_UP(inf->joliet_len, 2048); - slen = susp_len_joliet; - dlen = dirent_len_joliet; - } else { - children = ecma119_mangle_names(dir); - nchildren = dir->nchildren + dir->nfiles; - len = ROUND_UP(inf->susp_len + inf->len, 2048); - slen = susp_len_iso; - dlen = dirent_len_iso; - } - - buf = calloc(1, len); - pos = 0; - - /* write all the dir records */ - ecma119_write_dir_record(t, buf+pos, flags, ISO_NODE(dir), - RECORD_TYPE_SELF); - pos += 34 + slen(&inf->self_susp); - ecma119_write_dir_record(t, buf+pos, flags, ISO_NODE(dir), - RECORD_TYPE_PARENT); - pos += 34 + slen(&inf->parent_susp); - - for (i=0; iattrib.st_mode ) - && GET_FILE_INF(ch)->real_me) { - continue; - } - ecma119_write_dir_record(t, buf+pos, flags, ch, - RECORD_TYPE_NORMAL); - pos += dlen(ch); - } - - if (flags & ECMA119_JOLIET) { - free(children); - return buf; - } - - /* write all the SUSP continuation areas */ - susp_write_CE(t, &inf->self_susp, buf+pos); - pos += inf->self_susp.CE_len; - susp_write_CE(t, &inf->parent_susp, buf+pos); - pos += inf->parent_susp.CE_len; - for (i=0; isusp, buf+pos); - pos += ninf->susp.CE_len; - } - free(children); - return buf; -} - -static void ecma119_write_dir_record(struct ecma119_write_target *t, - unsigned char *buf, - int flags, - struct iso_tree_node *node, - enum RecordType type) -{ - if (flags & ECMA119_JOLIET) { - ecma119_write_dir_record_joliet(t, buf, node, type); - } else { - ecma119_write_dir_record_iso(t, buf, node, type); - } -} - -static void ecma119_write_dir_record_iso(struct ecma119_write_target *t, - uint8_t *buf, - struct iso_tree_node *node, - enum RecordType type) -{ - struct node_write_info *inf = GET_NODE_INF(node); - uint8_t len_dr, len_fi, flags; - uint8_t vol_seq_num = t->volnum; - - if (type == RECORD_TYPE_NORMAL) { - len_fi = node_namelen_iso(node); - len_dr = 33 + len_fi + 1 - len_fi%2 + inf->susp.non_CE_len; - flags = (S_ISDIR(node->attrib.st_mode)) ? 2 : 0; - iso_struct_pack(ecma119_dir_record_fmt, buf, - &len_dr, - &zero, - &node->block, - &node->attrib.st_size, - &t->now, - &flags, - &zero, - &zero, - &vol_seq_num, - &len_fi); - iso_struct_pack_long(&buf[33], len_fi, '<', 'B', 0, 0, 0, - node_getname_iso(node)); - susp_write(t, &inf->susp, &buf[len_dr - inf->susp.non_CE_len]); - } else if (type == RECORD_TYPE_PARENT && node->parent) { - ecma119_write_dir_record_noname(t, buf, node, type, - node->parent->block, - node->parent->attrib.st_size, 0); - susp_write(t, &GET_DIR_INF(node)->parent_susp, &buf[34]); - } else { - ecma119_write_dir_record_noname(t, buf, node, type, - node->block, - node->attrib.st_size, 0); - if (type != RECORD_TYPE_ROOT) { - susp_write(t, &GET_DIR_INF(node)->self_susp, &buf[34]); - } - } -} - -static void ecma119_write_dir_record_joliet(struct ecma119_write_target *t, - uint8_t *buf, - struct iso_tree_node *node, - enum RecordType type) -{ - uint8_t len_dr, len_fi, flags; - uint8_t vol_seq_num = t->volnum; - uint32_t block, size; - - if (type == RECORD_TYPE_NORMAL) { - if (S_ISDIR(node->attrib.st_mode)) { - block = GET_DIR_INF(node)->joliet_block; - size = GET_DIR_INF(node)->joliet_len; - flags = 2; - } else { - block = node->block; - size = node->attrib.st_size; - flags = 0; - } - len_fi = node_namelen_joliet(node); - len_dr = 34 + len_fi; - iso_struct_pack(ecma119_dir_record_fmt, buf, - &len_dr, - &zero, - &block, - &size, - &t->now, - &flags, - &zero, - &zero, - &vol_seq_num, - &len_fi); - iso_struct_pack_long(&buf[33], len_fi, '<', 'B', 0, 0, 0, - node->name.joliet); - } else if (type == RECORD_TYPE_PARENT && node->parent) { - struct iso_tree_dir *p = GET_DIR_INF(node)->real_parent; - struct dir_write_info *inf = GET_DIR_INF(p); - ecma119_write_dir_record_noname(t, buf, node, type, - inf->joliet_block, - inf->joliet_len, - 1); - } else { - struct dir_write_info *inf = GET_DIR_INF(node); - ecma119_write_dir_record_noname(t, buf, node, type, - inf->joliet_block, - inf->joliet_len, - 1); - } -} - -/* this writes a directory record for a file whose RecordType is not - * RECORD_TYPE_NORMAL. Since this implies that we don't need to write a file - * id, the only difference between Joliet and non-Joliet records is whetheror - * not we write the SUSP fields. */ -static void ecma119_write_dir_record_noname(struct ecma119_write_target *t, - uint8_t *buf, - struct iso_tree_node *node, - enum RecordType type, - uint32_t block, - uint32_t size, - int joliet) -{ - int file_id; - uint8_t len_dr; - uint8_t flags = 2; - uint8_t len_fi = 1; - uint8_t zero = 0; - struct dir_write_info *inf = GET_DIR_INF(node); - - assert( type != RECORD_TYPE_NORMAL ); - switch(type) { - case RECORD_TYPE_ROOT: - file_id = 0; - len_dr = 34; - break; - case RECORD_TYPE_SELF: - file_id = 0; - len_dr = 34 + (joliet ? 0 : inf->self_susp.non_CE_len); - break; - case RECORD_TYPE_PARENT: - file_id = 1; - len_dr = 34 + (joliet ? 0 : inf->parent_susp.non_CE_len); - break; - case RECORD_TYPE_NORMAL: /* shut up warning */ - assert(0); - } - - assert(iso_struct_calcsize(ecma119_dir_record_fmt) == 33); - iso_struct_pack(ecma119_dir_record_fmt, buf, - &len_dr, - &zero, - &block, - &size, - &t->now, - &flags, /* file flags */ - &zero, - &zero, - &len_fi, /* vol seq number */ - &len_fi); /* len_fi */ - buf[33] = file_id; -} - -static void ecma119_setup_path_tables_iso(struct ecma119_write_target *t) -{ - int i, j, cur; - struct iso_tree_node **children; - - t->pathlist = calloc(1, sizeof(void*) * t->dirlist_len); - t->pathlist[0] = TARGET_ROOT(t); - t->path_table_size = 10; /* root directory record */ - - cur = 1; - for (i=0; idirlist_len; i++) { - struct iso_tree_dir *dir = t->pathlist[i]; - children = ecma119_mangle_names(dir); - for (j=0; jnchildren + dir->nfiles; j++) { - if (S_ISDIR(children[j]->attrib.st_mode)) { - int len = 8 + node_namelen_iso(children[j]); - t->pathlist[cur++] = ISO_DIR(children[j]); - t->path_table_size += len + len % 2; - } - } - free(children); - } -} - -static void ecma119_setup_path_tables_joliet(struct ecma119_write_target *t) -{ - int i, j, cur; - struct iso_tree_node **children; - - t->pathlist_joliet = calloc(1, sizeof(void*) * t->dirlist_len); - t->pathlist_joliet[0] = TARGET_ROOT(t); - t->path_table_size_joliet = 10; /* root directory record */ - - cur = 1; - for (i=0; idirlist_len; i++) { - struct iso_tree_dir *dir = t->pathlist_joliet[i]; - struct dir_write_info *inf = GET_DIR_INF(dir); - children = ecma119_sort_joliet(dir); - for (j=0; jreal_nchildren + dir->nfiles; j++) { - if (S_ISDIR(children[j]->attrib.st_mode)) { - int len = 8 + node_namelen_joliet(children[j]); - t->pathlist_joliet[cur++] = - ISO_DIR(children[j]); - t->path_table_size_joliet += len + len % 2; - } - } - } + struct burn_source *ret = calloc(1, sizeof(struct burn_source)); + ret->refcount = 1; + ret->read = bs_read; + ret->get_size = bs_get_size; + ret->free_data = bs_free_data; + ret->data = ecma119_target_new(volset, volnum, level, flags); + return ret; } diff --git a/libisofs/ecma119.h b/libisofs/ecma119.h index bda01ad..7950550 100755 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -1,3 +1,4 @@ +/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */ /* vim: set noet ts=8 sts=8 sw=8 : */ /** @@ -7,70 +8,17 @@ * volume. */ -#ifndef __ISO_ECMA119 -#define __ISO_ECMA119 +#ifndef LIBISO_ECMA119_H +#define LIBISO_ECMA119_H -#include #include +#include +#include /* for FILE */ +#include #include "susp.h" -/** - * Persistent data for writing directories according to the ecma119 standard. - */ -struct dir_write_info -{ - struct susp_info susp; /**< \see node_write_info */ - struct susp_info self_susp; /**< SUSP data for this directory's - * "." entry. - */ - struct susp_info parent_susp; /**< SUSP data for this directory's - * ".." entry. - */ - - int len; /**< The combined length of all children's - * Directory Record lengths. This includes - * the System Use areas. - */ - int susp_len; /**< The combined length of all children's - * SUSP Continuation Areas. - */ - - /* the parent/child information prior to relocation */ - struct iso_tree_dir *real_parent; - int real_nchildren; - struct iso_tree_dir **real_children; - int real_depth; - - /* joliet information */ - int joliet_block; /**< The block at which the Joliet version of - * this directory will be written. - */ - int joliet_len; /**< The combined length of all children's - * Joliet Directory Record lengths. - */ -}; - -/** - * Persistent data for writing files according to the ecma119 standard. - */ -struct file_write_info -{ - struct susp_info susp; /**< \see node_write_info */ - - struct iso_tree_dir *real_me; /**< If this is non-NULL, the file is - * a placeholder for a relocated - * directory and this field points to - * that relocated directory. - */ -}; - -/** - * The fields in common between file_write_info and dir_write_info. - */ -struct node_write_info -{ - struct susp_info susp; /**< The SUSP data for this file. */ -}; +struct ecma119_tree_node; +struct joliet_tree_node; /** * The possible states that the ecma119 writer can be in. @@ -100,11 +48,13 @@ enum ecma119_write_state */ struct ecma119_write_target { + struct ecma119_tree_node *root; + struct joliet_tree_node *joliet_root; struct iso_volset *volset; int volnum; time_t now; /**< Time at which writing began. */ - int total_size; /**< Total size of the output. This only + off_t total_size; /**< Total size of the output. This only * includes the current volume. */ uint32_t vol_space_size; @@ -120,73 +70,63 @@ struct ecma119_write_target uint32_t m_path_table_pos; uint32_t l_path_table_pos_joliet; uint32_t m_path_table_pos_joliet; + uint32_t total_dir_size; + uint32_t total_dir_size_joliet; - struct iso_tree_dir **dirlist; /* A pre-order list of directories + struct ecma119_tree_node **dirlist; + /**< A pre-order list of directories * (this is the order in which we write * out directory records). */ - struct iso_tree_dir **pathlist; /* A breadth-first list of directories. - * This is used for writing out the path - * tables. + struct ecma119_tree_node **pathlist; + /**< A breadth-first list of + * directories. This is used for + * writing out the path tables. */ - int dirlist_len; /* The length of the previous 2 lists. + size_t dirlist_len; /**< The length of the previous 2 lists. */ - struct iso_tree_file **filelist;/* A pre-order list of files with + struct ecma119_tree_node **filelist; + /**< A pre-order list of files with * non-NULL paths and non-zero sizes. */ - int filelist_len; /* Length of the previous list. */ + size_t filelist_len; /* Length of the previous list. */ - int curfile; /* Used as a helper field for writing + int curfile; /**< Used as a helper field for writing out filelist and dirlist */ /* Joliet versions of the above lists. Since Joliet doesn't require - * directory relocation, the order of these list might be different from - * the lists above. */ - struct iso_tree_dir **dirlist_joliet; - struct iso_tree_dir **pathlist_joliet; + * directory relocation, the order of these lists might be different + * from the lists above (but they will be the same length). + */ + struct joliet_tree_node **dirlist_joliet; + struct joliet_tree_node **pathlist_joliet; enum ecma119_write_state state; /* The current state of the writer. */ - /* persistent data for the various states. Each struct should not be - * touched except for the writer of the relevant stage. When the writer - * of the relevant stage is finished, it should set all fields to 0. + /* Most writers work by + * 1) making sure state_data is big enough for their data + * 2) writing _all_ their data into state_data + * 3) relying on write_data_chunk to write the data block + * by block. */ - union - { - struct - { - int blocks; - unsigned char *data; - } path_table; - struct - { - size_t pos; /* The number of bytes we have written - * so far in the current directory. - */ - size_t data_len;/* The number of bytes in the current - * directory. - */ - unsigned char *data; /* The data (combined Directory - * Records and susp_CE areas) of the - * current directory. - */ - int dir; /* The index in dirlist that we are - * currently writing. */ - } dir_records; - struct - { - size_t pos; /* The number of bytes we have written - * so far in the current file. - */ - size_t data_len;/* The number of bytes in the currently - * open file. - */ - FILE *fd; /* The currently open file. */ - int file; /* The index in filelist that we are - * currently writing. */ - } files; - } state_data; + uint8_t *state_data; + off_t state_data_size; + off_t state_data_off; + int state_data_valid; + + /* for writing out files */ + struct state_files { + off_t pos; /* The number of bytes we have written + * so far in the current file. + */ + off_t data_len;/* The number of bytes in the currently + * open file. + */ + FILE *fd; /* The currently open file. */ + int file; /* The index in filelist that we are + * currently writing (or about to write). */ + } state_files; }; /** @@ -198,23 +138,130 @@ struct ecma119_write_target * \post The directory heirarchy has been reorganised to be ecma119-compatible. */ struct ecma119_write_target *ecma119_target_new(struct iso_volset *volset, - int volnum); + int volnum, + int level, + int flags); -/** Macros to help with casting between node_write_info and dir/file_write_info. +#define BP(a,b) [(b) - (a) + 1] + +struct ecma119_pri_vol_desc +{ + uint8_t vol_desc_type BP(1, 1); + uint8_t std_identifier BP(2, 6); + uint8_t vol_desc_version BP(7, 7); + uint8_t unused1 BP(8, 8); + uint8_t system_id BP(9, 40); + uint8_t volume_id BP(41, 72); + uint8_t unused2 BP(73, 80); + uint8_t vol_space_size BP(81, 88); + uint8_t unused3 BP(89, 120); + uint8_t vol_set_size BP(121, 124); + uint8_t vol_seq_number BP(125, 128); + uint8_t block_size BP(129, 132); + uint8_t path_table_size BP(133, 140); + uint8_t l_path_table_pos BP(141, 144); + uint8_t opt_l_path_table_pos BP(145, 148); + uint8_t m_path_table_pos BP(149, 152); + uint8_t opt_m_path_table_pos BP(153, 156); + uint8_t root_dir_record BP(157, 190); + uint8_t vol_set_id BP(191, 318); + uint8_t publisher_id BP(319, 446); + uint8_t data_prep_id BP(447, 574); + uint8_t application_id BP(575, 702); + uint8_t copyright_file_id BP(703, 739); + uint8_t abstract_file_id BP(740, 776); + uint8_t bibliographic_file_id BP(777, 813); + uint8_t vol_creation_time BP(814, 830); + uint8_t vol_modification_time BP(831, 847); + uint8_t vol_expiration_time BP(848, 864); + uint8_t vol_effective_time BP(865, 881); + uint8_t file_structure_version BP(882, 882); + uint8_t reserved1 BP(883, 883); + uint8_t app_use BP(884, 1395); + uint8_t reserved2 BP(1396, 2048); +}; + +struct ecma119_sup_vol_desc +{ + uint8_t vol_desc_type BP(1, 1); + uint8_t std_identifier BP(2, 6); + uint8_t vol_desc_version BP(7, 7); + uint8_t vol_flags BP(8, 8); + uint8_t system_id BP(9, 40); + uint8_t volume_id BP(41, 72); + uint8_t unused2 BP(73, 80); + uint8_t vol_space_size BP(81, 88); + uint8_t esc_sequences BP(89, 120); + uint8_t vol_set_size BP(121, 124); + uint8_t vol_seq_number BP(125, 128); + uint8_t block_size BP(129, 132); + uint8_t path_table_size BP(133, 140); + uint8_t l_path_table_pos BP(141, 144); + uint8_t opt_l_path_table_pos BP(145, 148); + uint8_t m_path_table_pos BP(149, 152); + uint8_t opt_m_path_table_pos BP(153, 156); + uint8_t root_dir_record BP(157, 190); + uint8_t vol_set_id BP(191, 318); + uint8_t publisher_id BP(319, 446); + uint8_t data_prep_id BP(447, 574); + uint8_t application_id BP(575, 702); + uint8_t copyright_file_id BP(703, 739); + uint8_t abstract_file_id BP(740, 776); + uint8_t bibliographic_file_id BP(777, 813); + uint8_t vol_creation_time BP(814, 830); + uint8_t vol_modification_time BP(831, 847); + uint8_t vol_expiration_time BP(848, 864); + uint8_t vol_effective_time BP(865, 881); + uint8_t file_structure_version BP(882, 882); + uint8_t reserved1 BP(883, 883); + uint8_t app_use BP(884, 1395); + uint8_t reserved2 BP(1396, 2048); +}; + +struct ecma119_vol_desc_terminator +{ + uint8_t vol_desc_type BP(1, 1); + uint8_t std_identifier BP(2, 6); + uint8_t vol_desc_version BP(7, 7); + uint8_t reserved BP(8, 2048); +}; + +struct ecma119_dir_record +{ + uint8_t len_dr BP(1, 1); + uint8_t len_xa BP(2, 2); + uint8_t block BP(3, 10); + uint8_t length BP(11, 18); + uint8_t recording_time BP(19, 25); + uint8_t flags BP(26, 26); + uint8_t file_unit_size BP(27, 27); + uint8_t interleave_gap_size BP(28, 28); + uint8_t vol_seq_number BP(29, 32); + uint8_t len_fi BP(33, 33); + uint8_t file_id BP(34, 34); /* 34 to 33+len_fi */ + /* padding field (if len_fi is even) */ + /* system use (len_dr - len_su + 1 to len_dr) */ +}; + +struct ecma119_path_table_record +{ + uint8_t len_di BP(1, 1); + uint8_t len_xa BP(2, 2); + uint8_t block BP(3, 6); + uint8_t parent BP(7, 8); + uint8_t dir_id BP(9, 9); /* 9 to 8+len_di */ + /* padding field (if len_di is odd) */ +}; + +/** + * A utility function for writers that want to write their data all at once + * rather than block-by-block. This creates a buffer of size \p size, passes + * it to the given writer, then hands out block-sized chunks. */ -#define DIR_INF(a) ( (struct dir_write_info*) (a) ) -#define FILE_INF(a) ( (struct file_write_info*) (a) ) -#define NODE_INF(a) ( (struct node_write_info*) (a) ) +void +ecma119_start_chunking(struct ecma119_write_target *t, + void (*)(struct ecma119_write_target*, uint8_t*), + off_t size, + uint8_t *buf); -#define GET_DIR_INF(a) ( (struct dir_write_info*) (a)->writer_data ) -#define GET_FILE_INF(a) ( (struct file_write_info*) (a)->writer_data ) -#define GET_NODE_INF(a) ( (struct node_write_info*) (a)->writer_data ) - -#define TARGET_ROOT(t) ( (t)->volset->volume[(t)->volnum]->root ) - -#define NODE_NAMELEN(n,i) strlen(iso_tree_node_get_name(ISO_NODE(n), i)) -#define NODE_JOLLEN(n) ucslen(iso_tree_node_get_name(ISO_NODE(n), \ - ISO_NAME_JOLIET)) - - -#endif /* __ISO_ECMA119 */ +#endif /* LIBISO_ECMA119_H */ diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 064b03e..8bfdab3 100755 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -9,10 +9,11 @@ * - Write the volume to a file or create a burn source for use with Libburn. */ -#ifndef __LIBISOFS -#define __LIBISOFS +#ifndef LIBISO_LIBISOFS_H +#define LIBISO_LIBISOFS_H -#include "libburn/libburn.h" +/* #include */ +struct burn_source; /** * Data volume. @@ -27,35 +28,11 @@ struct iso_volume; struct iso_volset; /** - * Directory on a volume. - * @see tree.h for details. - */ -struct iso_tree_dir; - -/** - * File on a volume. - * @see tree.h for details. - */ -struct iso_tree_file; - -/** - * Either a file or a directory. + * A node in the filesystem tree. * \see tree.h */ struct iso_tree_node; -/** - * Possible versions of a file or directory name or identifier. - */ -enum iso_name_version { - ISO_NAME_FULL, /**< In the current locale. */ - ISO_NAME_ISO, /**< Current ISO level identifier. */ - ISO_NAME_ISO_L1, /**< ISO level 1 identifier. */ - ISO_NAME_ISO_L2, /**< ISO level 2 identifier. */ - ISO_NAME_ROCKRIDGE, /**< Rock Ridge file or directory name. */ - ISO_NAME_JOLIET /**< Joliet identifier. */ -}; - enum ecma119_extension_flag { ECMA119_ROCKRIDGE = (1<<0), ECMA119_JOLIET = (1<<1) @@ -69,6 +46,11 @@ struct iso_volume *iso_volume_new(const char *volume_id, const char *publisher_id, const char *data_preparer_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); + /** * Free a volume. */ @@ -77,7 +59,7 @@ void iso_volume_free(struct iso_volume *volume); /** * Get the root directory for a volume. */ -struct iso_tree_dir *iso_volume_get_root(const struct iso_volume *volume); +struct iso_tree_node *iso_volume_get_root(const struct iso_volume *volume); /** * Fill in the volume identifier for a volume. @@ -97,37 +79,6 @@ void iso_volume_set_publisher_id(struct iso_volume *volume, void iso_volume_set_data_preparer_id(struct iso_volume *volume, const char *data_preparer_id); -/** - * Get the current ISO level for a volume. - */ -int iso_volume_get_iso_level(const struct iso_volume *volume); - -/** - * Set the current ISO level for a volume. - * ISO level must be 1 or 2. - */ -void iso_volume_set_iso_level(struct iso_volume *volume, int level); - -/** - * See if Rock Ridge (POSIX) is enabled for a volume. - */ -int iso_volume_get_rockridge(const struct iso_volume *volume); - -/** - * Enable or disable Rock Ridge (POSIX) for a volume. - */ -void iso_volume_set_rockridge(struct iso_volume *volume, int rockridge); - -/** - * See if Joliet (Unicode) is enabled for a volume. - */ -int iso_volume_get_joliet(const struct iso_volume *volume); - -/** - * Enable or disable Joliet (Unicode) for a volume. - */ -void iso_volume_set_joliet(struct iso_volume *volume, int joliet); - /** * Create a new Volume Set consisting of only one volume. * @param volume The first and only volume for the volset to contain. @@ -142,28 +93,14 @@ struct iso_volset *iso_volset_new(struct iso_volume *volume, * * \param path The path, on the local filesystem, of the file. * - * \pre \p parent is non-NULL + * \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 * filesystem. - * \return An iso_tree_file whose path is \p path and whose parent is \p parent. + * \return An iso_tree_node whose path is \p path and whose parent is \p parent. */ -struct iso_tree_file *iso_tree_add_file(struct iso_tree_dir *parent, +struct iso_tree_node *iso_tree_add_node(struct iso_tree_node *parent, const char *path); -/** - * Add a directory from the local filesystem to the tree. - * Warning: this only adds the directory itself, no files or subdirectories. - * - * \param path The path, on the local filesystem, of the 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_dir *iso_tree_add_dir(struct iso_tree_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. @@ -172,18 +109,18 @@ struct iso_tree_dir *iso_tree_add_dir(struct iso_tree_dir *parent, * * \param path The path, on the local filesystem, of the directory to add. * - * \pre \p parent is non-NULL + * \pre \p parent is NULL or is a directory. * \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_dir *iso_tree_radd_dir(struct iso_tree_dir *parent, - const char *path); +struct iso_tree_node *iso_tree_radd_dir(struct iso_tree_node *parent, + const char *path); /** * Creates a new, empty directory on the volume. * - * \pre \p parent is non-NULL + * \pre \p parent is NULL or is a directory. * \pre \p name is unique among the children and files belonging to \p parent. * Also, it doesn't contain '/' characters. * @@ -191,35 +128,20 @@ struct iso_tree_dir *iso_tree_radd_dir(struct iso_tree_dir *parent, * POSIX attributes are the same as \p parent's. * \return a pointer to the newly created directory. */ -struct iso_tree_dir *iso_tree_add_new_dir(struct iso_tree_dir *parent, - const char *name); +struct iso_tree_node *iso_tree_add_new_dir(struct iso_tree_node *parent, + const char *name); /** - * Get the name of a node. + * Set the name of a file (using the current locale). */ -const char *iso_tree_node_get_name(const struct iso_tree_node *node, - enum iso_name_version ver); - -/** - * Set the name of a file. - * The name you input here will be the full name and will be used to derive the - * ISO, RockRidge and Joliet names. - */ -void iso_tree_file_set_name(struct iso_tree_file *file, const char *name); - -/** - * Set the name of a directory. - * The name you input here will be the full name and will be used to derive the - * ISO, RockRidge and Joliet names. - */ -void iso_tree_dir_set_name(struct iso_tree_dir *dir, const char *name); +void iso_tree_node_set_name(struct iso_tree_node *file, const char *name); /** * Recursively print a directory to stdout. * \param spaces The initial number of spaces on the left. Set to 0 if you * supply a root directory. */ -void iso_tree_print(const struct iso_tree_dir *root, int spaces); +void iso_tree_print(const struct iso_tree_node *root, int spaces); /** Create a burn_source which can be used as a data source for a track * @@ -240,4 +162,4 @@ struct burn_source* iso_source_new_ecma119 (struct iso_volset *volumeset, int level, int flags); -#endif /* __LIBISOFS */ +#endif /* LIBISO_LIBISOFS_H */ diff --git a/libisofs/rockridge.c b/libisofs/rockridge.c index d6bab25..3662ac6 100755 --- a/libisofs/rockridge.c +++ b/libisofs/rockridge.c @@ -1,10 +1,10 @@ /* vim: set noet ts=8 sts=8 sw=8 : */ #include "rockridge.h" -#include "tree.h" #include "util.h" -#include "volume.h" #include "ecma119.h" +#include "ecma119_tree.h" +#include "tree.h" #include "susp.h" #include @@ -15,53 +15,50 @@ #include /* create a PX field from the permissions on the current node. */ -unsigned char *rrip_make_PX(struct ecma119_write_target *t, - struct iso_tree_node *node) +uint8_t *rrip_make_PX(struct ecma119_write_target *t, + struct ecma119_tree_node *node) { - unsigned char *PX = malloc(44); + uint8_t *PX = malloc(44); PX[0] = 'P'; PX[1] = 'X'; PX[2] = 44; PX[3] = 1; - 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); + 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); return PX; } /** See IEEE 1282 4.1.1 */ -void rrip_add_PX(struct ecma119_write_target *t, struct iso_tree_node *node) +void rrip_add_PX(struct ecma119_write_target *t, struct ecma119_tree_node *node) { - susp_append(t, node, rrip_make_PX(t, 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)); + } } -void rrip_add_PX_dir(struct ecma119_write_target *t, struct iso_tree_dir *dir) +void rrip_add_PN(struct ecma119_write_target *t, struct ecma119_tree_node *node) { - susp_append(t, ISO_NODE(dir), rrip_make_PX(t, ISO_NODE(dir))); - susp_append_self(t, dir, rrip_make_PX(t, ISO_NODE(dir))); - susp_append_parent(t, dir, rrip_make_PX(t, ISO_NODE(dir))); -} - -void rrip_add_PN(struct ecma119_write_target *t, struct iso_tree_node *node) -{ - unsigned char *PN = malloc(20); + uint8_t *PN = malloc(20); PN[0] = 'P'; PN[1] = 'N'; PN[2] = 20; PN[3] = 1; - iso_bb(&PN[4], node->attrib.st_dev >> 32, 4); - iso_bb(&PN[12], node->attrib.st_dev & 0xffffffff, 4); - susp_append(t, node, PN); + iso_bb(&PN[4], node->iso_self->attrib.st_dev >> 32, 4); + iso_bb(&PN[12], node->iso_self->attrib.st_dev & 0xffffffff, 4); + susp_append(t, &node->susp, PN); } -static void rrip_SL_append_comp(int *n, unsigned char ***comps, +static void rrip_SL_append_comp(int *n, uint8_t ***comps, char *s, int size, char fl) { - unsigned char *comp = malloc(size + 2); + uint8_t *comp = malloc(size + 2); (*n)++; comp[0] = fl; @@ -75,7 +72,7 @@ static void rrip_SL_append_comp(int *n, unsigned char ***comps, } static void rrip_SL_add_component(char *prev, char *cur, int *n_comp, - unsigned char ***comps) + uint8_t ***comps) { int size = cur - prev; @@ -103,24 +100,24 @@ static void rrip_SL_add_component(char *prev, char *cur, int *n_comp, rrip_SL_append_comp(n_comp, comps, prev, size, 0); } -void rrip_add_SL(struct ecma119_write_target *t, struct iso_tree_node *node) +void rrip_add_SL(struct ecma119_write_target *t, struct ecma119_tree_node *node) { int ret, pathsize = 0; char *path = NULL, *cur, *prev; - struct iso_tree_file *file = (struct iso_tree_file *)node; int i, j; - unsigned char **comp = NULL; + uint8_t **comp = NULL; int n_comp = 0; int total_comp_len = 0; int written = 0, pos; - unsigned char *SL; + uint8_t *SL; do { pathsize += 128; path = realloc(path, pathsize); - ret = readlink(file->path, 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", @@ -156,7 +153,7 @@ void rrip_add_SL(struct ecma119_write_target *t, struct iso_tree_node *node) memcpy(&SL[pos], comp[j], comp[j][2]); pos += comp[j][2]; } - susp_append(t, node, SL); + susp_append(t, &node->susp, SL); written = i - 1; total_comp_len = comp[i][1]; } @@ -173,7 +170,7 @@ void rrip_add_SL(struct ecma119_write_target *t, struct iso_tree_node *node) memcpy(&SL[pos], comp[j], comp[j][1] + 2); pos += comp[j][1] + 2; } - susp_append(t, node, SL); + susp_append(t, &node->susp, SL); free(path); /* free the components */ @@ -184,10 +181,10 @@ void rrip_add_SL(struct ecma119_write_target *t, struct iso_tree_node *node) } static void rrip_add_NM_single(struct ecma119_write_target *t, - struct iso_tree_node *node, + struct susp_info *susp, char *name, int size, int flags) { - unsigned char *NM = malloc(size + 5); + uint8_t *NM = malloc(size + 5); NM[0] = 'N'; NM[1] = 'M'; @@ -197,103 +194,107 @@ static void rrip_add_NM_single(struct ecma119_write_target *t, if (size) { memcpy(&NM[5], name, size); } - susp_append(t, node, NM); + susp_append(t, susp, NM); } -void rrip_add_NM(struct ecma119_write_target *t, struct iso_tree_node *node) +void +rrip_add_NM(struct ecma119_write_target *t, struct ecma119_tree_node *node) { - struct iso_tree_file *file = (struct iso_tree_file *)node; - int len = strlen(file->name.rockridge); - char *pos = file->name.rockridge; + char *name = iso_p_fileid(node->iso_self->name); + int len = name ? strlen(name) : 0; + char *pos = name; - if (len == 1 && pos[0] == '.') { - rrip_add_NM_single(t, node, pos, 0, 1 << 1); - return; - } - if (len == 2 && !strncmp(pos, "..", 2)) { - rrip_add_NM_single(t, node, pos, 0, 1 << 2); + if (!len) 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); } while (len > 250) { - rrip_add_NM_single(t, node, pos, 250, 1); + rrip_add_NM_single(t, &node->susp, pos, 250, 1); len -= 250; pos += 250; } - rrip_add_NM_single(t, node, pos, len, 0); + rrip_add_NM_single(t, &node->susp, pos, len, 0); } -void rrip_add_CL(struct ecma119_write_target *t, struct iso_tree_node *node) +void rrip_add_CL(struct ecma119_write_target *t, struct ecma119_tree_node *node) { - unsigned char *CL = calloc(1, 12); + uint8_t *CL = calloc(1, 12); CL[0] = 'C'; CL[1] = 'L'; CL[2] = 12; CL[3] = 1; - susp_append(t, node, CL); + susp_append(t, &node->susp, CL); } -void rrip_add_PL(struct ecma119_write_target *t, struct iso_tree_dir *node) +void +rrip_add_PL(struct ecma119_write_target *t, struct ecma119_tree_node *node) { - unsigned char *PL = calloc(1, 12); + uint8_t *PL = calloc(1, 12); PL[0] = 'P'; PL[1] = 'L'; PL[2] = 12; PL[3] = 1; - susp_append_parent(t, node, PL); + susp_append(t, &node->dir.parent_susp, PL); } -void rrip_add_RE(struct ecma119_write_target *t, struct iso_tree_node *node) +void +rrip_add_RE(struct ecma119_write_target *t, struct ecma119_tree_node *node) { - unsigned char *RE = malloc(4); + uint8_t *RE = malloc(4); RE[0] = 'R'; RE[1] = 'E'; RE[2] = 4; RE[3] = 1; - susp_append(t, node, RE); + susp_append(t, &node->susp, RE); } -void rrip_add_TF(struct ecma119_write_target *t, struct iso_tree_node *node) +void +rrip_add_TF(struct ecma119_write_target *t, struct ecma119_tree_node *node) { - unsigned char *TF = malloc(5 + 3 * 17); + uint8_t *TF = malloc(5 + 3 * 7); TF[0] = 'T'; TF[1] = 'F'; - TF[2] = 5 + 3 * 17; + TF[2] = 5 + 3 * 7; TF[3] = 1; TF[4] = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 7); - iso_datetime_17(&TF[5], node->attrib.st_mtime); - iso_datetime_17(&TF[22], node->attrib.st_atime); - iso_datetime_17(&TF[39], node->attrib.st_ctime); - susp_append(t, node, TF); + 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); + susp_append(t, &node->susp, TF); } -void rrip_finalize(struct ecma119_write_target *t, struct iso_tree_dir *dir) +void +rrip_finalize(struct ecma119_write_target *t, struct ecma119_tree_node *dir) { - struct dir_write_info *inf; - struct file_write_info *finf; int i; - inf = dir->writer_data; - if (dir->parent != inf->real_parent) { - unsigned char *PL = susp_find(&inf->parent_susp, "PL"); + assert(dir->type == ECMA119_DIR); - iso_bb(&PL[4], inf->real_parent->block, 4); + if (dir->parent != dir->dir.real_parent) { + uint8_t *PL = susp_find(&dir->dir.parent_susp, "PL"); + + assert(PL); + iso_bb(&PL[4], dir->dir.real_parent->block, 4); } - for (i = 0; i < dir->nfiles; i++) { - finf = dir->files[i]->writer_data; - if (finf->real_me) { - unsigned char *CL = susp_find(&finf->susp, "CL"); + for (i = 0; i < dir->dir.nchildren; i++) { + struct ecma119_tree_node *ch = dir->dir.children[i]; - iso_bb(&CL[4], finf->real_me->block, 4); + if (ch->type == ECMA119_FILE && ch->file.real_me) { + uint8_t *CL = susp_find(&ch->susp, "CL"); + + assert(CL); + iso_bb(&CL[4], ch->file.real_me->block, 4); + } else if (ch->type == ECMA119_DIR) { + rrip_finalize(t, ch); } } - - for (i = 0; i < dir->nchildren; i++) { - rrip_finalize(t, dir->children[i]); - } } diff --git a/libisofs/rockridge.h b/libisofs/rockridge.h index ba8e894..7909a0c 100755 --- a/libisofs/rockridge.h +++ b/libisofs/rockridge.h @@ -2,29 +2,25 @@ /** Functions and structures used for Rock Ridge support. */ -#ifndef __ISO_ROCKRIDGE -#define __ISO_ROCKRIDGE +#ifndef ISO_ROCKRIDGE_H +#define ISO_ROCKRIDGE_H struct ecma119_write_target; -struct iso_tree_node; -struct iso_tree_dir; +struct ecma119_tree_node; -void rrip_add_PX(struct ecma119_write_target *, struct iso_tree_node *); -void rrip_add_PN(struct ecma119_write_target *, struct iso_tree_node *); -void rrip_add_SL(struct ecma119_write_target *, struct iso_tree_node *); -void rrip_add_NM(struct ecma119_write_target *, struct iso_tree_node *); -void rrip_add_CL(struct ecma119_write_target *, struct iso_tree_node *); -void rrip_add_RE(struct ecma119_write_target *, struct iso_tree_node *); -void rrip_add_TF(struct ecma119_write_target *, struct iso_tree_node *); +void rrip_add_PX(struct ecma119_write_target *, struct ecma119_tree_node *); +void rrip_add_PN(struct ecma119_write_target *, struct ecma119_tree_node *); +void rrip_add_SL(struct ecma119_write_target *, struct ecma119_tree_node *); +void rrip_add_NM(struct ecma119_write_target *, struct ecma119_tree_node *); +void rrip_add_CL(struct ecma119_write_target *, struct ecma119_tree_node *); +void rrip_add_RE(struct ecma119_write_target *, struct ecma119_tree_node *); +void rrip_add_TF(struct ecma119_write_target *, struct ecma119_tree_node *); /* This is special because it doesn't modify the susp fields of the directory * that gets passed to it; it modifies the susp fields of the ".." entry in * that directory. */ -void rrip_add_PL(struct ecma119_write_target *, struct iso_tree_dir *); +void rrip_add_PL(struct ecma119_write_target *, struct ecma119_tree_node *); -/* Add a PX field to the susp, self_susp and parent_susp entries */ -void rrip_add_PX_dir(struct ecma119_write_target *, struct iso_tree_dir *); +void rrip_finalize(struct ecma119_write_target *, struct ecma119_tree_node *); -void rrip_finalize(struct ecma119_write_target *, struct iso_tree_dir *); - -#endif /* __ISO_ROCKRIDGE */ +#endif /* ISO_ROCKRIDGE_H */ diff --git a/libisofs/susp.c b/libisofs/susp.c index e67d39f..0d2d6c5 100755 --- a/libisofs/susp.c +++ b/libisofs/susp.c @@ -1,20 +1,25 @@ /* vim: set noet ts=8 sts=8 sw=8 : */ #include "susp.h" -#include "tree.h" #include "util.h" #include "ecma119.h" +#include "ecma119_tree.h" #include #include #include -static void susp_insert_direct(struct ecma119_write_target *t, - struct susp_info *susp, unsigned char *data, - int pos) +void susp_insert(struct ecma119_write_target *t, + struct susp_info *susp, + uint8_t *data, + int pos) { int i; + if (pos < 0) { + pos = susp->n_susp_fields; + } + assert(pos <= susp->n_susp_fields); susp->n_susp_fields++; susp->susp_fields = realloc(susp->susp_fields, @@ -27,60 +32,13 @@ static void susp_insert_direct(struct ecma119_write_target *t, } void susp_append(struct ecma119_write_target *t, - struct iso_tree_node *node, unsigned char *data) + struct susp_info *susp, + uint8_t *data) { - struct dir_write_info *inf = node->writer_data; - struct susp_info *susp = &inf->susp; - - susp_insert_direct(t, susp, data, susp->n_susp_fields); + susp_insert(t, susp, data, susp->n_susp_fields); } -void susp_append_self(struct ecma119_write_target *t, - struct iso_tree_dir *dir, unsigned char *data) -{ - struct dir_write_info *inf = dir->writer_data; - struct susp_info *susp = &inf->self_susp; - - susp_insert_direct(t, susp, data, susp->n_susp_fields); -} - -void susp_append_parent(struct ecma119_write_target *t, - struct iso_tree_dir *dir, unsigned char *data) -{ - struct dir_write_info *inf = dir->writer_data; - struct susp_info *susp = &inf->parent_susp; - - susp_insert_direct(t, susp, data, susp->n_susp_fields); -} - -void susp_insert(struct ecma119_write_target *t, - struct iso_tree_node *node, unsigned char *data, int pos) -{ - struct dir_write_info *inf = node->writer_data; - struct susp_info *susp = &inf->susp; - - susp_insert_direct(t, susp, data, pos); -} - -void susp_insert_self(struct ecma119_write_target *t, - struct iso_tree_dir *dir, unsigned char *data, int pos) -{ - struct dir_write_info *inf = dir->writer_data; - struct susp_info *susp = &inf->self_susp; - - susp_insert_direct(t, susp, data, pos); -} - -void susp_insert_parent(struct ecma119_write_target *t, - struct iso_tree_dir *dir, unsigned char *data, int pos) -{ - struct dir_write_info *inf = dir->writer_data; - struct susp_info *susp = &inf->parent_susp; - - susp_insert_direct(t, susp, data, pos); -} - -unsigned char *susp_find(struct susp_info *susp, const char *name) +uint8_t *susp_find(struct susp_info *susp, const char *name) { int i; @@ -92,11 +50,15 @@ unsigned char *susp_find(struct susp_info *susp, const char *name) return NULL; } -/* utility function for susp_add_CE because susp_add_CE needs to act 3 times - * on directories (for the "." and ".." entries. */ +/** Utility function for susp_add_CE because susp_add_CE needs to act 3 times + * on directories (for the "." and ".." entries. + * + * \param len The amount of space available for the System Use area. + */ #define CE_LEN 28 static unsigned char *susp_add_single_CE(struct ecma119_write_target *t, - struct susp_info *susp, int len) + struct susp_info *susp, + int len) { int susp_length = 0, tmp_len; int i; @@ -138,33 +100,36 @@ static unsigned char *susp_add_single_CE(struct ecma119_write_target *t, return NULL; } +static void +try_add_CE(struct ecma119_write_target *t, + struct susp_info *susp, + size_t dirent_len) +{ + uint8_t *CE = susp_add_single_CE(t, susp, 255 - dirent_len); + if (CE) + susp_insert(t, susp, CE, susp->n_fields_fit - 1); +} + /** See IEEE P1281 Draft Version 1.12/5.2. Because this function depends on the * length of the other SUSP fields, it should always be calculated last. */ -void susp_add_CE(struct ecma119_write_target *t, struct iso_tree_node *node) +void +susp_add_CE(struct ecma119_write_target *t, struct ecma119_tree_node *node) { - struct dir_write_info *inf = node->writer_data; - unsigned char *CE; - - CE = susp_add_single_CE(t, &inf->susp, 255 - node->dirent_len); - if (CE) - susp_insert(t, node, CE, inf->susp.n_fields_fit - 1); - if (S_ISDIR(node->attrib.st_mode)) { - CE = susp_add_single_CE(t, &inf->self_susp, 255 - 34); - if (CE) - susp_insert_self(t, (struct iso_tree_dir *)node, CE, - inf->self_susp.n_fields_fit - 1); - CE = susp_add_single_CE(t, &inf->parent_susp, 255 - 34); - if (CE) - susp_insert_parent(t, (struct iso_tree_dir *)node, CE, - inf->parent_susp.n_fields_fit - 1); + 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); } } /** See IEEE P1281 Draft Version 1.12/5.3 */ -void susp_add_SP(struct ecma119_write_target *t, struct iso_tree_dir *dir) +void +susp_add_SP(struct ecma119_write_target *t, struct ecma119_tree_node *dir) { unsigned char *SP = malloc(7); + assert(dir->type == ECMA119_DIR); + SP[0] = 'S'; SP[1] = 'P'; SP[2] = (char)7; @@ -172,7 +137,7 @@ void susp_add_SP(struct ecma119_write_target *t, struct iso_tree_dir *dir) SP[4] = 0xbe; SP[5] = 0xef; SP[6] = 0; - susp_append_self(t, dir, SP); + susp_append(t, &dir->dir.self_susp, SP); } #if 0 @@ -190,11 +155,14 @@ static void susp_add_ST(struct ecma119_write_target *t, } #endif -/** See IEEE P1281 Draft Version 1.12/5.5 */ -void susp_add_ER(struct ecma119_write_target *t, struct iso_tree_dir *dir) +/** See IEEE P1281 Draft Version 1.12/5.5 FIXME: this is rockridge */ +void +rrip_add_ER(struct ecma119_write_target *t, struct ecma119_tree_node *dir) { unsigned char *ER = malloc(182); + assert(dir->type == ECMA119_DIR); + ER[0] = 'E'; ER[1] = 'R'; ER[2] = 182; @@ -208,71 +176,71 @@ void susp_add_ER(struct ecma119_write_target *t, struct iso_tree_dir *dir) "FILE SYSTEM SEMANTICS.", 72); memcpy(&ER[89], "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, " "PISCATAWAY, NJ, USA FOR THE 1282 SPECIFICATION.", 93); - susp_append_self(t, dir, ER); + susp_append(t, &dir->dir.self_susp, ER); +} + +/* calculate the location of the CE areas. Since CE areas don't need to be + * aligned to a block boundary, we contatenate all CE areas from a single + * 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) + */ +static void +susp_fin_1_CE(struct ecma119_write_target *t, + struct susp_info *susp, + size_t block, + size_t *offset) +{ + uint8_t *CE = susp->susp_fields[susp->n_fields_fit - 1]; + + if (!susp->CE_len) { + return; + } + iso_bb(&CE[4], block + (*offset) / t->block_size, 4); + iso_bb(&CE[12], (*offset) % t->block_size, 4); + *offset += susp->CE_len; } static void susp_fin_CE(struct ecma119_write_target *t, - struct iso_tree_dir *dir) + struct ecma119_tree_node *dir) { - struct dir_write_info *inf = (struct dir_write_info *) - dir->writer_data; - struct node_write_info *cinf; - unsigned char *CE; int i; - int CE_offset = inf->len; + size_t CE_offset = dir->dir.len; - if (inf->self_susp.CE_len) { - CE = inf->self_susp.susp_fields[inf->self_susp.n_fields_fit - - 1]; - iso_bb(&CE[4], dir->block + CE_offset / 2048, 4); - iso_bb(&CE[12], CE_offset % 2048, 4); - CE_offset += inf->self_susp.CE_len; - } - if (inf->parent_susp.CE_len) { - CE = inf->parent_susp.susp_fields[inf->parent_susp. - n_fields_fit - 1]; - iso_bb(&CE[4], dir->block + CE_offset / 2048, 4); - iso_bb(&CE[12], CE_offset % 2048, 4); - CE_offset += inf->parent_susp.CE_len; - } + assert(dir->type == ECMA119_DIR); - for (i = 0; i < dir->nchildren; i++) { - cinf = dir->children[i]->writer_data; - if (!cinf->susp.CE_len) { - continue; - } - CE = cinf->susp.susp_fields[cinf->susp.n_fields_fit - 1]; - iso_bb(&CE[4], dir->block + CE_offset / 2048, 4); - iso_bb(&CE[12], CE_offset % 2048, 4); - CE_offset += cinf->susp.CE_len; + 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); + + 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->nfiles; i++) { - cinf = dir->files[i]->writer_data; - if (!cinf->susp.CE_len) { - continue; - } - CE = cinf->susp.susp_fields[cinf->susp.n_fields_fit - 1]; - iso_bb(&CE[4], dir->block + CE_offset / 2048, 4); - iso_bb(&CE[12], CE_offset % 2048, 4); - CE_offset += cinf->susp.CE_len; - } - assert(CE_offset == inf->len + inf->susp_len); + assert(CE_offset == dir->dir.len + dir->dir.CE_len); } -void susp_finalize(struct ecma119_write_target *t, struct iso_tree_dir *dir) +void +susp_finalize(struct ecma119_write_target *t, struct ecma119_tree_node *dir) { int i; - if (dir->depth != 1) { + assert(dir->type = ECMA119_DIR); + + if (dir->dir.depth != 1) { susp_fin_CE(t, dir); } - for (i = 0; i < dir->nchildren; i++) { - susp_finalize(t, dir->children[i]); + for (i = 0; i < dir->dir.nchildren; i++) { + if (dir->dir.children[i]->type == ECMA119_DIR) + susp_finalize(t, dir->dir.children[i]); } } -void susp_write(struct ecma119_write_target *t, struct susp_info *susp, +void susp_write(struct ecma119_write_target *t, + struct susp_info *susp, unsigned char *buf) { int i; diff --git a/libisofs/susp.h b/libisofs/susp.h index 7894581..31dd2cf 100755 --- a/libisofs/susp.h +++ b/libisofs/susp.h @@ -6,17 +6,18 @@ #ifndef __ISO_SUSP #define __ISO_SUSP +#include + /* SUSP is only present in standard ecma119 */ struct ecma119_write_target; -struct iso_tree_node; -struct iso_tree_dir; +struct ecma119_tree_node; /** This contains the information that needs to go in the SUSP area of a file. */ struct susp_info { int n_susp_fields; /**< Number of SUSP fields */ - unsigned char **susp_fields; /**< Data for each SUSP field */ + uint8_t **susp_fields; /**< Data for each SUSP field */ /* the next 3 relate to CE and are filled out by susp_add_CE. */ int n_fields_fit; /**< How many of the above SUSP fields fit @@ -27,48 +28,34 @@ struct susp_info * will go in a CE area. */ }; -void susp_add_CE(struct ecma119_write_target *, struct iso_tree_node *); +void susp_add_CE(struct ecma119_write_target *, struct ecma119_tree_node *); /* these next 2 are special because they don't modify the susp fields of the - * directory that gets passed to them; they modify the susp fields of the + * directory; they modify the susp fields of the * "." entry in the directory. */ -void susp_add_SP(struct ecma119_write_target *, struct iso_tree_dir *); -void susp_add_ER(struct ecma119_write_target *, struct iso_tree_dir *); +void susp_add_SP(struct ecma119_write_target *, struct ecma119_tree_node *); +void rrip_add_ER(struct ecma119_write_target *, struct ecma119_tree_node *); /** Once all the directories and files are laid out, recurse through the tree * and finalize all SUSP CE entries. */ -void susp_finalize(struct ecma119_write_target *, struct iso_tree_dir *); +void susp_finalize(struct ecma119_write_target *, struct ecma119_tree_node *); void susp_append(struct ecma119_write_target *, - struct iso_tree_node *, - unsigned char *); -void susp_append_self(struct ecma119_write_target *, - struct iso_tree_dir *, - unsigned char *); -void susp_append_parent(struct ecma119_write_target *, - struct iso_tree_dir *, - unsigned char *); + struct susp_info *, + uint8_t *); void susp_insert(struct ecma119_write_target *, - struct iso_tree_node *, - unsigned char *, + struct susp_info *, + uint8_t *, int pos); -void susp_insert_self(struct ecma119_write_target *, - struct iso_tree_dir *, - unsigned char *, - int pos); -void susp_insert_parent(struct ecma119_write_target *, - struct iso_tree_dir *, - unsigned char *, - int pos); -unsigned char *susp_find(struct susp_info *, - const char *); +uint8_t *susp_find(struct susp_info *, + const char *); void susp_write(struct ecma119_write_target *, struct susp_info *, - unsigned char *); + uint8_t *); void susp_write_CE(struct ecma119_write_target *, struct susp_info *, - unsigned char *); + uint8_t *); void susp_free_fields(struct susp_info *); diff --git a/libisofs/tree.c b/libisofs/tree.c index 1d5c486..e4b7ef7 100755 --- a/libisofs/tree.c +++ b/libisofs/tree.c @@ -1,409 +1,217 @@ -/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */ /* vim: set noet ts=8 sts=8 sw=8 : */ -#include -#include +/** + * \file tree.c + * + * Implement filesystem trees. + */ + +#include #include #include -#include -#include #include -#include +#include +#include +#include +#include +#include #include +#include +#include -#include "libisofs.h" #include "tree.h" #include "util.h" #include "volume.h" -struct iso_tree_dir *iso_tree_new_root(struct iso_volume *volume) +static void +set_default_stat(struct stat *s) { - struct iso_tree_dir *dir; + time_t now = time(NULL); - assert(volume); - - dir = calloc(1, sizeof(struct iso_tree_dir)); - dir->attrib.st_mode = S_IFDIR; - dir->volume = volume; - - return dir; + memset(s, 0, sizeof(struct stat)); + s->st_mode = 0777 | S_IFREG; + s->st_atime = s->st_mtime = s->st_ctime = now; } -void iso_tree_free(struct iso_tree_dir *root) +static struct stat +get_attrib(const struct iso_tree_node *node) { - int i; - - assert(root); - - /* Free names. */ - free(root->name.full); - free(root->name.iso1); - free(root->name.iso2); - free(root->name.rockridge); - free(root->name.joliet); - - /* Free the children. */ - for (i = 0; i < root->nchildren; i++) - iso_tree_free(root->children[i]); - free(root->children); - - /* Free all files. */ - for (i = 0; i < root->nfiles; i++) { - struct iso_tree_file *file = root->files[i]; - - free(file->path); - free(file->name.full); - free(file->name.iso1); - free(file->name.iso2); - free(file->name.rockridge); - free(file->name.joliet); - free(file); - } - free(root->files); - - if (root->writer_data) { - fprintf(stderr, "Warning: freeing a directory with non-NULL " - "writer_data\n"); - } - - /* Free ourself. */ - free(root); -} - -struct iso_tree_file *iso_tree_add_new_file(struct iso_tree_dir *parent, - const char *name) -{ - struct iso_tree_file *file; - - assert(parent && name); - - file = calloc(1, sizeof(struct iso_tree_file)); - file->path = calloc(1, 1); - file->parent = parent; - file->volume = parent->volume; - file->attrib = parent->attrib; - file->attrib.st_mode &= ~S_IFMT; - file->attrib.st_mode |= S_IFREG; - file->attrib.st_size = 0; - iso_tree_file_set_name(file, name); - - /* Add the new file to the parent directory */ - parent->nfiles++; - parent->files = realloc(parent->files, sizeof(void *) * parent->nfiles); - parent->files[parent->nfiles - 1] = file; - - return file; -} - -struct iso_tree_file *iso_tree_add_file(struct iso_tree_dir *parent, - const char *path) -{ - struct iso_tree_file *file; struct stat st; - int statret; - const char *name; - assert( parent != NULL && path != NULL ); - statret = lstat(path, &st); - if (statret == -1) { - fprintf(stderr, "couldn't stat file %s: %s\n", - path, strerror(errno)); - return NULL; + if (node) { + return node->attrib; } - - /* Set up path, parent and volume. */ - file = calloc(1, sizeof(struct iso_tree_file)); - file->path = strdup(path); - file->parent = parent; - file->volume = parent->volume; - file->attrib = st; - - /* find the last component in the path */ - name = strrchr(path, '/'); - if (name == NULL) { - name = path; - } else { - name++; - } - iso_tree_file_set_name(file, name); - - if (!S_ISREG(st.st_mode)) { - file->attrib.st_size = 0; - } - - /* Add the new file to the parent directory */ - parent->nfiles++; - parent->files = realloc(parent->files, sizeof(void *) * parent->nfiles); - parent->files[parent->nfiles - 1] = file; - - return file; + set_default_stat(&st); + return st; } -struct iso_tree_dir *iso_tree_add_dir(struct iso_tree_dir *parent, - const char *path) +static void +append_node(struct iso_tree_node *parent, + struct iso_tree_node *child) { - struct iso_tree_dir *dir; - struct stat st; - int statret; - char *pathcpy; - char *name; - - assert( parent && path ); - statret = stat(path, &st); - if (statret == -1) { - fprintf(stderr, "couldn't stat directory %s: %s\n", - path, strerror(errno)); - return NULL; - } - - dir = calloc(1, sizeof(struct iso_tree_dir)); - dir->parent = parent; - dir->volume = parent->volume; - dir->attrib = st; - - /* find the last component in the path. We need to copy the path because - * we modify it if there is a trailing slash. */ - pathcpy = strdup(path); - name = strrchr(pathcpy, '/'); - if (name == &pathcpy[strlen(pathcpy) - 1]) { - /* get rid of the trailing slash */ - *name = '\0'; - name = strrchr(pathcpy, '/'); - } - if (name == NULL) { - name = pathcpy; - } else { - name++; - } - iso_tree_dir_set_name(dir, name); - free(pathcpy); - + assert((!parent || S_ISDIR(parent->attrib.st_mode)) && child); + if (!parent) + return; parent->nchildren++; - parent->children = realloc(parent->children, - parent->nchildren * sizeof(void*)); - parent->children[parent->nchildren - 1] = dir; - - return dir; + parent->children = + realloc(parent->children, parent->nchildren * sizeof(void*)); + parent->children[parent->nchildren-1] = child; } -struct iso_tree_dir *iso_tree_radd_dir(struct iso_tree_dir *parent, - const char *path) +struct iso_tree_node* +iso_tree_new_root(struct iso_volume *vol) { - struct iso_tree_dir *nparent; + 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 ? towcs(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) +{ + char *p; struct stat st; - int statret; + struct iso_tree_node *ret; + + assert((!parent || S_ISDIR(parent->attrib.st_mode)) && path); + + if (lstat(path, &st) == -1) + return NULL; + + 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); + free(p); + + return ret; +} + +struct iso_tree_node* +iso_tree_radd_dir (struct iso_tree_node *parent, const char *path) +{ + struct iso_tree_node *new; DIR *dir; struct dirent *ent; - assert( parent && path ); - statret = stat(path, &st); + assert((!parent || S_ISDIR(parent->attrib.st_mode)) && path); - nparent = iso_tree_add_dir(parent, path); + new = iso_tree_add_node(parent, path); + if (!new || !S_ISDIR(new->attrib.st_mode)) { + return new; + } - /* Open the directory for reading and iterate over the directory - entries. */ dir = opendir(path); - if (!dir) { - fprintf(stderr, "couldn't open directory %s: %s\n", - path, strerror(errno)); - return NULL; + warn("couldn't open directory %s: %s\n", path, strerror(errno)); + return new; } while ((ent = readdir(dir))) { - char *child; + char child[strlen(ent->d_name) + strlen(path) + 2]; - /* Skip current and parent directory entries. */ if (strcmp(ent->d_name, ".") == 0 || - strcmp(ent->d_name, "..") == 0) + strcmp(ent->d_name, "..") == 0) continue; - /* Build the child's full pathname. */ - child = iso_pathname(path, ent->d_name); - - /* Skip to the next entry on errors. */ - if (stat(child, &st) != 0) - continue; - - if (S_ISDIR(st.st_mode)) { - iso_tree_radd_dir(nparent, child); - } else { - iso_tree_add_file(nparent, child); - } - - free(child); + sprintf(child, "%s/%s", path, ent->d_name); + iso_tree_radd_dir(new, child); } - closedir(dir); - return nparent; + return new; } -struct iso_tree_dir *iso_tree_add_new_dir(struct iso_tree_dir *parent, - const char *name) +void +iso_tree_free(struct iso_tree_node *root) { - struct iso_tree_dir *dir; + size_t i; - assert( parent && name ); - - dir = calloc(1, sizeof(struct iso_tree_dir)); - dir->parent = parent; - dir->volume = parent->volume; - - iso_tree_dir_set_name(dir, name); - - dir->attrib = parent->attrib; - dir->attrib.st_mtime = time(NULL); - dir->attrib.st_atime = time(NULL); - dir->attrib.st_ctime = time(NULL); - - - /* add the new directory to parent */ - parent->nchildren++; - parent->children = realloc(parent->children, - parent->nchildren * sizeof(void*)); - parent->children[parent->nchildren - 1] = dir; - - return dir; -} - -void iso_tree_file_set_name(struct iso_tree_file *file, const char *name) -{ - file->name.full = strdup(name); - file->name.iso1 = iso_1_fileid(name); - file->name.iso2 = iso_2_fileid(name); - file->name.rockridge = iso_p_filename(name); - file->name.joliet = iso_j_id(file->name.full); -} - -char *iso_tree_node_get_name_nconst(const struct iso_tree_node *node, - enum iso_name_version ver) -{ - if (ver == ISO_NAME_ISO) { - if (node->volume->iso_level == 1) { - return node->name.iso1; - } else { - return node->name.iso2; - } + for (i=0; i < root->nchildren; i++) { + iso_tree_free(root->children[i]); } - - switch (ver) { - case ISO_NAME_FULL: - return node->name.full; - case ISO_NAME_ISO: - if (node->volume->iso_level == 1) { - return node->name.iso1; - } else { - return node->name.iso2; - } - case ISO_NAME_ISO_L1: - return node->name.iso1; - case ISO_NAME_ISO_L2: - return node->name.iso2; - case ISO_NAME_ROCKRIDGE: - return node->name.rockridge; - case ISO_NAME_JOLIET: - return (char*) node->name.joliet; - } - - assert(0); - return NULL; /* just to shut up warnings */ + free(root->name); + free(root->children); + free(root); } -const char *iso_tree_node_get_name(const struct iso_tree_node *node, - enum iso_name_version ver) +void +iso_tree_print(const struct iso_tree_node *root, int spaces) { - return iso_tree_node_get_name_nconst(node, ver); -} + size_t i; + char sp[spaces+1]; -void iso_tree_dir_set_name(struct iso_tree_dir *dir, const char *name) -{ - dir->name.full = strdup(name); - /* Level 1 directory is a string of d-characters of maximum size 8. */ - dir->name.iso1 = iso_d_str(name, 8, 0); - /* Level 2 directory is a string of d-characters of maximum size 31. */ - dir->name.iso2 = iso_d_str(name, 31, 0); - dir->name.rockridge = iso_p_dirname(name); - dir->name.joliet = iso_j_id(dir->name.full); -} + memset(sp, ' ', spaces); + sp[spaces] = '\0'; -/* Compares file names for use with qsort. */ -int iso_node_cmp(const void *v1, const void *v2) -{ - struct iso_tree_node **f1 = (struct iso_tree_node **)v1; - struct iso_tree_node **f2 = (struct iso_tree_node **)v2; - - return strcmp(iso_tree_node_get_name(*f1, ISO_NAME_FULL), - iso_tree_node_get_name(*f2, ISO_NAME_FULL)); -} - -int iso_node_cmp_iso(const void *v1, const void *v2) -{ - struct iso_tree_node **f1 = (struct iso_tree_node **)v1; - struct iso_tree_node **f2 = (struct iso_tree_node **)v2; - - return strcmp(iso_tree_node_get_name(*f1, ISO_NAME_ISO), - iso_tree_node_get_name(*f2, ISO_NAME_ISO)); -} - -int iso_node_cmp_joliet(const void *v1, const void *v2) -{ - struct iso_tree_node **f1 = (struct iso_tree_node **)v1; - struct iso_tree_node **f2 = (struct iso_tree_node **)v2; - - return ucscmp((uint16_t*)iso_tree_node_get_name(*f1, ISO_NAME_JOLIET), - (uint16_t*)iso_tree_node_get_name(*f2, ISO_NAME_JOLIET)); -} - -void iso_tree_sort(struct iso_tree_dir *root) -{ - int i; - - qsort(root->files, root->nfiles, sizeof(struct iso_tree_file *), - iso_node_cmp); - - qsort(root->children, root->nchildren, sizeof(struct iso_tree_dir *), - iso_node_cmp); - - for (i = 0; i < root->nchildren; i++) - iso_tree_sort(root->children[i]); -} - -void iso_tree_print(const struct iso_tree_dir *root, int spaces) -{ - iso_tree_print_verbose(root, NULL, NULL, NULL, spaces); -} - -void iso_tree_print_verbose(const struct iso_tree_dir *root, - print_dir_callback dc, print_file_callback fc, - void *data, int spaces) -{ - int i, j; - - for (i = 0; i < spaces; i++) - printf(" "); - - /* Root directory doesn't have a name. */ - if (root->name.full != NULL) - printf("%s", iso_tree_node_get_name(ISO_NODE(root), - ISO_NAME_ISO)); - printf("/\n"); - if (dc) dc(root, data, spaces); - - spaces += 2; - - for (j = 0; j < root->nchildren; j++) { - iso_tree_print_verbose(root->children[j], dc, fc, data, - spaces); - } - - for (j = 0; j < root->nfiles; j++) { - for (i = 0; i < spaces; i++) - printf(" "); - printf("%s\n", - iso_tree_node_get_name(ISO_NODE(root->files[j]), - ISO_NAME_ISO)); - if (fc) fc(root->files[j], data, spaces); + printf("%s%ls\n", sp, root->name); + for (i=0; i < root->nchildren; i++) { + iso_tree_print(root->children[i], spaces+2); } } + +void +iso_tree_print_verbose(const struct iso_tree_node *root, + print_dir_callback dir, + print_file_callback file, + 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); + } +} + +void +iso_tree_node_set_name(struct iso_tree_node *file, const char *name) +{ + free(file->name); + file->name = towcs(name); +} diff --git a/libisofs/tree.h b/libisofs/tree.h index 34d9240..db215f8 100755 --- a/libisofs/tree.h +++ b/libisofs/tree.h @@ -1,169 +1,104 @@ -/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */ /* vim: set noet ts=8 sts=8 sw=8 : */ /** * \file tree.h * - * Extra declarations for use with the iso_tree_dir and iso_tree_file - * structures. + * Declare the structure of a libisofs filesystem tree. The files in this + * tree can come from either the local filesystem or from another .iso image + * (for multisession). + * + * This tree preserves as much information as it can about the files; names + * are stored in wchar_t and we preserve POSIX attributes. This tree does + * *not* include information that is necessary for writing out, for example, + * an ISO level 1 tree. That information will go in a different tree because + * the structure is sufficiently different. */ -#ifndef __ISO_TREE -#define __ISO_TREE +#ifndef LIBISO_TREE_H +#define LIBISO_TREE_H #include #include -#include #include +#include #include "libisofs.h" -/** - * File or directory names or identifiers. - */ -struct iso_names -{ - char *full; /**< Full version: either part of the path or - user input. */ - char *iso1; /**< ISO level 1 identifier. */ - char *iso2; /**< ISO level 2 identifier. */ - char *rockridge; /**< Rock Ridge file or directory name. */ - uint16_t *joliet; /**< Joliet identifier. */ +enum file_location { + LIBISO_FILESYS, + LIBISO_PREVSESSION, + LIBISO_NONE /**< for files/dirs that were added with + * iso_tree_add_new_XXX. */ }; /** - * Directory on a volume. + * 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_tree_dir +struct iso_file_location { - struct iso_tree_dir *parent; /**< \see iso_tree_node */ - struct iso_volume *volume; /**< \see iso_tree_node */ - struct iso_names name; /**< \see iso_tree_node */ - struct stat attrib; /**< \see iso_tree_node */ - off_t block; /**< \see iso_tree_node */ - uint8_t dirent_len; /**< \see iso_tree_node */ - void *writer_data; /**< \see iso_tree_node */ - - int depth; /**< The depth of this directory in the - * Directory Heirarchy. This is 1 for - * the root directory. - */ - - int nchildren; /**< Number of child directories. */ - int nfiles; /**< Number of files in this directory. - */ - struct iso_tree_dir **children; /**< Child directories. */ - struct iso_tree_file **files; /**< Files in this directory. */ + enum file_location type; + /* union {*/ + char *path; /* in the current locale */ + uint32_t block; + /* };*/ }; /** - * File on a volume. - */ -struct iso_tree_file -{ - struct iso_tree_dir *parent; /**< \see iso_tree_node */ - struct iso_volume *volume; /**< \see iso_tree_node */ - struct iso_names name; /**< \see iso_tree_node */ - struct stat attrib; /**< \see iso_tree_node */ - off_t block; /**< \see iso_tree_node */ - uint8_t dirent_len; /**< \see iso_tree_node */ - void *writer_data; /**< \see iso_tree_node */ - - char *path; /**< Location of the file in the - * local filesystem. This can be a - * full or relative path. If this is - * NULL, then the file doesn't exist - * in the local filesystem and its - * size must be zero. - * - * FIXME: Allow references to files - * on other volumes belonging to the - * same volset as this file. - */ -}; - -/** - * Fields in common between iso_tree_file and iso_tree_dir. + * A node in the filesystem tree. */ struct iso_tree_node { - struct iso_tree_dir *parent; /**< The parent of this node. Must be - * non-NULL unless we are the - * root directory on a volume. - */ - struct iso_volume *volume; /**< The volume to which this node - * belongs. - */ - struct iso_names name; /**< The name of this node in its parent - * directory. Must be non-NULL unless - * we are the root directory on a - * volume. - */ - struct stat attrib; /**< The POSIX attributes of this - * node as documented in "man 2 stat". - * - * Any node that is not a regular - * file or a directory must have - * \p attrib.st_size set to zero. Any - * node that is a directory will have - * \p attrib.st_size filled out by the - * writer. - */ + struct iso_volume *volume; + struct iso_tree_node *parent; + wchar_t *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). */ - /* information used for writing */ - off_t block; /**< The block at which this node's - * data will be written. - */ - uint8_t dirent_len; /**< The size of this node's - * Directory Record in its parent. - * This does not include System Use - * fields, if present. - */ - void *writer_data; /**< This is writer-specific data. It - * must be set to NULL when a node - * is created and it should be NULL - * again when the node is freed. - */ + 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 + * reside on disk. We store this here as + * well as in the various mangled trees + * because many different trees might point + * to the same file and they need to share the + * block location. */ }; -/** A macro to simplify casting between nodes and files/directories. */ -#define ISO_NODE(a) ( (struct iso_tree_node*) (a) ) - -/** A macro to simplify casting between nodes and directories. */ -#define ISO_DIR(a) ( (struct iso_tree_dir*) (a) ) - -/** A macro to simplify casting between nodes and files. */ -#define ISO_FILE(a) ( (struct iso_tree_file*) (a) ) - /** * Create a new root directory for a volume. * - * \param volume The volume for which to create a new root directory. + * \param vol The volume for which to create a new root directory. * - * \pre \p volume is non-NULL. - * \post \p volume has a non-NULL, empty root directory. - * \return \p volume's new non-NULL, empty 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. */ -struct iso_tree_dir *iso_tree_new_root(struct iso_volume *volume); +struct iso_tree_node *iso_tree_new_root(struct iso_volume *vol); /** * Create a new, empty, file. * - * \param parent The parent of the new 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 parent is non-NULL. * \pre \p name is non-NULL and it does not match any other file or directory - * name in \p parent. - * \post \p parent contains a file with the following properties: - * - the file's (full) name is \p name - * - the file's POSIX permissions are the same as \p parent's - * - the file is a regular file - * - the file is empty + * 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. */ -struct iso_tree_file *iso_tree_add_new_file(struct iso_tree_dir *parent, +struct iso_tree_node *iso_tree_add_new_file(struct iso_tree_node *parent, const char *name); /** @@ -173,37 +108,7 @@ struct iso_tree_file *iso_tree_add_new_file(struct iso_tree_dir *parent, * * \pre \p root is non-NULL. */ -void iso_tree_free(struct iso_tree_dir *root); - -/** - * Recursively sort all the files and child directories in a directory. - * - * \param root The root of the directory heirarchy to sort. - * - * \pre \p root is non-NULL. - * \post For each directory \p dir in the directory heirarchy descended fro - * root, the fields in \p dir.children and \p dir.files are alphabetically - * sorted according to \p name.full. - * - * \see iso_names - */ -void iso_tree_sort(struct iso_tree_dir *root); - -/** - * Compare the names of 2 nodes, \p *v1 and \p *v2. This is compatible with - * qsort. - */ -int iso_node_cmp(const void *v1, const void *v2); - -/** - * Compare the joliet names of 2 nodes, compatible with qsort. - */ -int iso_node_cmp_joliet(const void *v1, const void *v2); - -/** - * Compare the iso names of 2 nodes, compatible with qsort. - */ -int iso_node_cmp_iso(const void *v1, const void *v2); +void iso_tree_free(struct iso_tree_node *root); /** * A function that prints verbose information about a directory. @@ -214,7 +119,7 @@ int iso_node_cmp_iso(const void *v1, const void *v2); * * \see iso_tree_print_verbose */ -typedef void (*print_dir_callback) (const struct iso_tree_dir *dir, +typedef void (*print_dir_callback) (const struct iso_tree_node *dir, void *data, int spaces); /** @@ -226,7 +131,7 @@ typedef void (*print_dir_callback) (const struct iso_tree_dir *dir, * * \see iso_tree_print_verbose */ -typedef void (*print_file_callback) (const struct iso_tree_file *file, +typedef void (*print_file_callback) (const struct iso_tree_node *file, void *data, int spaces); @@ -243,17 +148,12 @@ typedef void (*print_file_callback) (const struct iso_tree_file *file, * \pre \p root is not NULL. * \pre Neither of the callback functions modifies the directory heirarchy. */ -void iso_tree_print_verbose(const struct iso_tree_dir *root, +void iso_tree_print_verbose(const struct iso_tree_node *root, print_dir_callback dir, print_file_callback file, void *callback_data, int spaces); -/** - * Get a non-const version of the node name. This is used for name-mangling - * iso names. It should only be used internally in libisofs; all other users - * should only access the const name. - */ -char *iso_tree_node_get_name_nconst(const struct iso_tree_node *node, - enum iso_name_version ver); -#endif /* __ISO_TREE */ +#define ISO_ISDIR(n) S_ISDIR(n->attrib.st_mode) + +#endif /* LIBISO_TREE_H */ diff --git a/libisofs/util.c b/libisofs/util.c index 0295ac8..44bb928 100755 --- a/libisofs/util.c +++ b/libisofs/util.c @@ -1,136 +1,190 @@ /* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */ -/* vim: set ts=8 sts=8 sw=8 noet : */ +/* vim: set noet ts=8 sts=8 sw=8 : */ -#include +/** + * Utility functions for the Libisofs library. + */ + +#include #include #include -#include -#include +#include #include #include #include -#include +#include #include "util.h" -int valid_d_char(char c) +int div_up(int n, int div) +{ + return (n + div - 1) / div; +} + +int round_up(int n, int mul) +{ + return div_up(n, mul) * mul; +} + +wchar_t *towcs(const char *str) +{ + size_t len = strlen(str); + wchar_t *ret = malloc(sizeof(wchar_t) * (len + 1)); + mbstate_t ps; + size_t n; + + memset(&ps, 0, sizeof(ps)); + n = mbsrtowcs(ret, &str, len, &ps); + ret[len] = '\0'; + + if (n != len) { + free(ret); + return NULL; + } + return ret; +} + +char *wcstoascii(const wchar_t *wsrc) +{ + if (!wsrc) + return NULL; + + iconv_t conv = iconv_open("ASCII", "WCHAR_T"); + size_t outbytes = wcslen(wsrc); + size_t inbytes = outbytes * sizeof(wchar_t); + char src_[inbytes + sizeof(wchar_t)]; + char *src = src_; + char *ret_, *ret; + size_t n; + + if (conv == (iconv_t)-1) + return NULL; + + memcpy(src, wsrc, inbytes + sizeof(wchar_t)); + ret = malloc(outbytes+1); + ret[outbytes] = '\0'; + ret_ = ret; + + n = iconv(conv, &src, &inbytes, &ret, &outbytes); + if (n == -1) { + free(ret_); + return NULL; + } + return ret_; +} + +/* FIXME: C&P */ +uint16_t *wcstoucs(const wchar_t *wsrc) +{ + if (!wsrc) + return calloc(2, 1); /* empty UCS string */ + + iconv_t conv = iconv_open("UCS-2BE", "WCHAR_T"); + size_t outbytes = wcslen(wsrc) * 2; + size_t inbytes = outbytes * sizeof(wchar_t) / 2; + char src_[inbytes + sizeof(wchar_t)]; + char *src = src_; + char *ret_, *ret; + size_t n; + + if (conv == (iconv_t)-1) + return calloc(2, 1); + + memcpy(src, wsrc, inbytes + sizeof(wchar_t)); + ret = malloc(outbytes + sizeof(wchar_t)); + ret[outbytes] = 0; + ret[outbytes+1] = 0; + ret_ = ret; + + n = iconv(conv, &src, &inbytes, &ret, &outbytes); + if (n == -1) { + perror ("error in iconv conversion"); + free(ret_); + return calloc(2, 1); + } + return (uint16_t*)ret_; +} + +static int valid_d_char(char c) { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c == '_'); } -int valid_a_char(char c) +static int valid_a_char(char c) { - return (c >= ' ' && c <= '"') || (c >= '%' && c <= '?') || (c >= 'A' && - c <= 'Z') - || (c == '_'); + return (c >= ' ' && c <= '"') || (c >= '%' && c <= '?') + || (c >= 'A' && c <= 'Z') + || (c == '_'); } -int valid_j_char(char msb, char lsb) +static int valid_j_char(uint16_t c) { - return !(msb == '\0' && - (lsb < ' ' || lsb == '*' || lsb == '/' || lsb == ':' || - lsb == ';' || lsb == '?' || lsb == '\\')); + return !(c < (uint16_t)' ' || c == (uint16_t)'*' || c == (uint16_t)'/' + || c == (uint16_t)':' || c == (uint16_t)';' + || c == (uint16_t)'?' || c == (uint16_t)'\\'); } -int valid_p_char(char c) +/* FIXME: where are these documented? */ +static int valid_p_char(char c) { - return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && - c <= 'z') - || (c == '.') || (c == '_') || (c == '-'); + return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') + || (c >= 'a' && c <= 'z') + || (c == '.') || (c == '_') || (c == '-'); } -char *iso_d_str(const char *src, int size, int pad) +static char *iso_dirid(const wchar_t *src, int size) { - char *dest = strlen(src) > size || - pad ? malloc(size + 1) : malloc(strlen(src) + 1); - int i; + char *ret = wcstoascii(src); + size_t len, i; - /* Try converting to upper-case before validating. */ - for (i = 0; i < size && src[i]; i++) { - char c = toupper(src[i]); - - dest[i] = valid_d_char(c) ? c : '_'; - } - - /* Optionally pad with spaces and terminate with NULL. */ - if (pad) - while (i < size) - dest[i++] = ' '; - dest[i] = '\0'; - - return dest; -} - -char *iso_a_str(const char *src, int size) -{ - char *dest = malloc(size + 1); - int i; - - for (i = 0; i < size && src[i]; i++) { - char c = toupper(src[i]); - - dest[i] = valid_a_char(c) ? c : '_'; - } - while (i < size) - dest[i++] = ' '; - dest[i] = '\0'; - - return dest; -} - -uint16_t *iso_j_str(const char *src) -{ - int size = strlen(src) * 2; - uint16_t *dest = malloc(size + 2); - char *cpy, *in, *out; - size_t inleft, outleft; - iconv_t cd; - - /* If the conversion is unavailable, return NULL. Obviously, - nl_langinfo(..) requires the locale to be set correctly. */ - cd = iconv_open("UCS-2BE", nl_langinfo(CODESET)); - if (cd == (iconv_t) - 1) { - free(dest); + if (!ret) return NULL; + + len = strlen(ret); + if (len > size) { + ret[size] = '\0'; + len = size; + } + for (i = 0; i < len; i++) { + char c = toupper(ret[i]); + ret[i] = valid_d_char(c) ? c : '_'; } - /* In, out, inleft and outleft will be updated by iconv, that's why we - need separate variables. */ - cpy = strdup(src); /* iconv doesn't take const * chars, so we need our - * own copy. */ - in = cpy; - out = (char*)dest; - inleft = strlen(cpy); - outleft = size; - iconv(cd, &in, &inleft, &out, &outleft); - - /* Since we need to pad with NULLs, we can pad up to and including the - terminating NULLs. */ - outleft += 2; - while (outleft) { - *out++ = '\0'; - outleft--; - } - iconv_close(cd); - free(cpy); - - return dest; + return ret; } -char *iso_1_fileid(const char *src) +char *iso_1_dirid(const wchar_t *src) { - char *dest = malloc(15); /* 15 = 8 (name) + 1 (.) + 3 (ext) + 2 - (;1) + 1 (\0) */ - char *dot = strrchr(src, '.'); /* Position of the last dot in the + return iso_dirid(src, 8); +} + +char *iso_2_dirid(const wchar_t *src) +{ + return iso_dirid(src, 31); +} + +char *iso_1_fileid(const wchar_t *wsrc) +{ + char *src = wcstoascii(wsrc); + char *dest; + char *dot; /* Position of the last dot in the filename, will be used to calculate lname and lext. */ int lname, lext, pos, i; + if (!src) + return NULL; + + dest = malloc(15); /* 15 = 8 (name) + 1 (.) + 3 (ext) + 2 + (;1) + 1 (\0) */ + dot = strrchr(src, '.'); + lext = dot ? strlen(dot + 1) : 0; lname = strlen(src) - lext - (dot ? 1 : 0); /* If we can't build a filename, return NULL. */ if (lname == 0 && lext == 0) { + free(src); free(dest); return NULL; } @@ -156,16 +210,24 @@ char *iso_1_fileid(const char *src) dest[pos] = '\0'; dest = (char *)realloc(dest, pos + 1); + free(src); return dest; } -char *iso_2_fileid(const char *src) +char *iso_2_fileid(const wchar_t *wsrc) { - char *dest = malloc(34); /* 34 = 30 (name + ext) + 1 (.) + 2 - (;1) + 1 (\0) */ - char *dot = strrchr(src, '.'); + char *src = wcstoascii(wsrc); + char *dest; + char *dot; int lname, lext, lnname, lnext, pos, i; + if (!src) + return NULL; + + dest = malloc(34); /* 34 = 30 (name + ext) + 1 (.) + 2 + (;1) + 1 (\0) */ + dot = strrchr(src, '.'); + /* Since the maximum length can be divided freely over the name and extension, we need to calculate their new lengths (lnname and lnext). If the original filename is too long, we start by trimming @@ -177,12 +239,13 @@ char *iso_2_fileid(const char *src) } else { lext = strlen(dot + 1); lname = strlen(src) - lext - 1; - lnext = (strlen(src) > 31 && - lext > 3) ? (lname < 27 ? 30 - lname : 3) : lext; + lnext = (strlen(src) > 31 && lext > 3) + ? (lname < 27 ? 30 - lname : 3) : lext; lnname = (strlen(src) > 31) ? 30 - lnext : lname; } if (lnname == 0 && lnext == 0) { + free(src); free(dest); return NULL; } @@ -206,276 +269,43 @@ char *iso_2_fileid(const char *src) dest[pos] = '\0'; dest = (char *)realloc(dest, pos + 1); + free(src); return dest; } -uint16_t *iso_j_id(char *src) +char * +iso_p_fileid(const wchar_t *src) { - char *dest = malloc(136); /* 136 = 128 (name + ext) + 2 (\0 .) + - 4 (\0 ; \0 1) + 2 (\0 \0) */ - char *dot = strrchr(src, '.'); - int lname, lext, lcname, lcext, lnname, lnext, pos, i; - size_t inleft, outleft; - char *cname, *cext, *in, *out; - iconv_t cd; + char *ret = wcstoascii(src); + size_t i, len; - if (dot == NULL || dot == src || *(dot + 1) == '\0') { - lname = strlen(src); - lext = 0; - } else { - lext = strlen(dot + 1); - lname = strlen(src) - lext - 1; - } - - if (lname == 0 && lext == 0) { - free(dest); + if (!ret) return NULL; - } - - cd = iconv_open("UCS-2BE", nl_langinfo(CODESET)); - if (cd == (iconv_t) - 1) { - free(dest); - return NULL; - } - - /* We need to convert the name and extension first, in order to - calculate the number of characters they have. */ - cname = malloc(lname * 2); - in = src; - out = cname; - inleft = lname; - outleft = lname * 2; - iconv(cd, &in, &inleft, &out, &outleft); - lcname = (lname * 2) - outleft; - iconv_close(cd); - - if (lext) { - cd = iconv_open("UCS-2BE", nl_langinfo(CODESET)); - if (cd == (iconv_t) - 1) { - free(dest); - free(cname); - return NULL; + len = strlen(ret); + for (i = 0; i < len; i++) { + if (!valid_p_char(ret[i])) { + ret[i] = (uint16_t)'_'; } - cext = malloc(lext * 2); - in = dot + 1; - out = cext; - inleft = lext; - outleft = lext * 2; - iconv(cd, &in, &inleft, &out, &outleft); - lcext = (lext * 2) - outleft; - iconv_close(cd); - } else - lcext = 0; - - /* Again, divide the available characters over name and extension, but - keep a minimum of three characters for the new extension. */ - lnext = (lcname + lcext > 128 && - lcext > 6) ? (lcname < 122 ? 128 - lcname : 6) : lcext; - lnname = (lcname + lcext > 128) ? 128 - lnext : lcname; - - pos = 0; - /* Copy up to lnname bytes from the converted filename. */ - for (i = 0; i < lnname; i = i + 2) - if (valid_j_char(cname[i], cname[i + 1])) { - dest[pos++] = cname[i]; - dest[pos++] = cname[i + 1]; - } else { - dest[pos++] = '\0'; - dest[pos++] = '_'; - } - /* Dot is now a 16 bit separator. */ - dest[pos++] = '\0'; - dest[pos++] = '.'; - /* Copy up to lnext bytes from the converted extension, if any. */ - for (i = 0; i < lnext; i = i + 2) - if (valid_j_char(cext[i], cext[i + 1])) { - dest[pos++] = cext[i]; - dest[pos++] = cext[i + 1]; - } else { - dest[pos++] = '\0'; - dest[pos++] = '_'; - } - /* Again, 2 bytes per character. */ - dest[pos++] = '\0'; - dest[pos++] = ';'; - dest[pos++] = '\0'; - dest[pos++] = '1'; - dest[pos++] = '\0'; - dest[pos] = '\0'; - - dest = (char *)realloc(dest, pos + 1); - free(cname); - if (lext) - free(cext); - - /* Fill in the size in bytes (including the terminating NULLs) of the - destination string. */ - return (uint16_t *) dest; + } + return ret; } -char *iso_p_filename(const char *src) +uint16_t * +iso_j_id(const wchar_t *src) { - char *dest = malloc(251); /* We can fit up to 250 characters in - a Rock Ridge name entry. */ - char *dot = strrchr(src, '.'); - int lname, lext, lnname, lnext, pos, i; + uint16_t *j_str = wcstoucs(src); + size_t len = ucslen(j_str); + size_t n; - if (dot == NULL || dot == src || *(dot + 1) == '\0') { - lname = strlen(src); - lnname = (lname > 250) ? 250 : lname; - lext = lnext = 0; - } else { - lext = strlen(dot + 1); - lname = strlen(src) - lext - 1; - lnext = (strlen(src) > 250 && - lext > 3) ? (lname < 246 ? 249 - lname : 3) : lext; - lnname = (strlen(src) > 250) ? 249 - lnext : lname; + if (len > 128) { + j_str[128] = '\0'; + len = 128; } - if (lnname == 0 && lnext == 0) { - free(dest); - return NULL; - } - - pos = 0; - for (i = 0; i < lnname; i++) - dest[pos++] = valid_p_char(src[i]) ? src[i] : '_'; - if (lnext) { - dest[pos++] = '.'; - for (i = 0; i < lnext; i++) - dest[pos++] = - valid_p_char(src[lname + 1 + i]) ? - src[lname + 1 + i] : '_'; - } - dest[pos] = '\0'; - dest = (char *)realloc(dest, pos + 1); - - return dest; -} - -char *iso_p_dirname(const char *src) -{ - char *dest = strlen(src) > 250 ? malloc(251) : malloc(strlen(src) + 1); - int i; - - if (strlen(src) == 0) { - free(dest); - return NULL; - } - - for (i = 0; i < 250 && src[i]; i++) - dest[i] = valid_p_char(src[i]) ? src[i] : '_'; - dest[i] = '\0'; - - return dest; -} - -char *iso_pathname(const char *dir, const char *file) -{ - char *path = malloc(strlen(dir) + strlen(file) + 2); - - strcpy(path, dir); - path[strlen(dir)] = '/'; - strcpy(path + strlen(dir) + 1, file); - - return path; -} - -void iso_a_strcpy(unsigned char *dest, int size, const char *src) -{ - int i = 0, d = 0; - - if (src) - for (; i < size && *src; ++i, ++src) { - char s = toupper(*src); - - if (valid_a_char(s)) - dest[d++] = s; - else - dest[d++] = '_'; - } - for (; i < size; ++i) { - /* pad with spaces */ - dest[d++] = ' '; - } -} - -void iso_d_strcpy(unsigned char *dest, int size, const char *src) -{ - int i = 0, d = 0; - - if (src) - for (; i < size && *src; ++i, ++src) { - char s = toupper(*src); - - if (valid_d_char(s)) - dest[d++] = s; - else - dest[d++] = '_'; - } - for (; i < size; ++i) { - /* pad with spaces */ - dest[d++] = ' '; - } -} - -char *iso_a_strndup(const char *src, int size) -{ - int i, d; - char *out; - - out = malloc(size + 1); - for (i = d = 0; i < size && *src; ++i, ++src) { - char s = toupper(*src); - - if (valid_a_char(s)) - out[d++] = s; - else - out[d++] = '_'; - } - out[d++] = '\0'; - out = realloc(out, d); /* shrink the buffer to what we used */ - return out; -} - -char *iso_d_strndup(const char *src, int size) -{ - int i, d; - char *out; - - out = malloc(size + 1); - for (i = d = 0; i < size && *src; ++i, ++src) { - char s = toupper(*src); - - if (valid_d_char(s)) - out[d++] = s; - else - out[d++] = '_'; - } - out[d++] = '\0'; - out = realloc(out, d); /* shrink the buffer to what we used */ - return out; -} - -char *iso_strconcat(char sep, const char *a, const char *b) -{ - char *out; - int la, lb; - - la = strlen(a); - lb = strlen(b); - out = malloc(la + lb + 1 + (sep ? 1 : 0)); - memcpy(out, a, la); - memcpy(out + la + (sep ? 1 : 0), b, lb); - if (sep) - out[la] = sep; - out[la + lb + (sep ? 1 : 0)] = '\0'; - return out; -} - -char *iso_strdup(const char *src) -{ - return src ? strdup(src) : NULL; + for (n = 0; n < len; n++) + if (!valid_j_char(j_str[n])) + j_str[n] = '_'; + return j_str; } void iso_lsb(uint8_t *buf, uint32_t num, int bytes) @@ -551,7 +381,6 @@ void iso_datetime_17(unsigned char *buf, time_t t) static int tzsetup = 0; static int tzoffset; struct tm tm; - char c[5]; if (t == (time_t) - 1) { /* unspecified time */ @@ -570,27 +399,13 @@ void iso_datetime_17(unsigned char *buf, time_t t) localtime_r(&t, &tm); - /* year */ - sprintf(c, "%04d", tm.tm_year + 1900); - memcpy(&buf[0], c, 4); - /* month */ - sprintf(c, "%02d", tm.tm_mon + 1); - memcpy(&buf[4], c, 2); - /* day */ - sprintf(c, "%02d", tm.tm_mday); - memcpy(&buf[6], c, 2); - /* hour */ - sprintf(c, "%02d", tm.tm_hour); - memcpy(&buf[8], c, 2); - /* minute */ - sprintf(c, "%02d", tm.tm_min); - memcpy(&buf[10], c, 2); - /* second */ - sprintf(c, "%02d", MIN(59, tm.tm_sec)); - memcpy(&buf[12], c, 2); - /* hundreths */ + sprintf((char*)&buf[0], "%04d", tm.tm_year + 1900); + sprintf((char*)&buf[4], "%02d", tm.tm_mon + 1); + sprintf((char*)&buf[6], "%02d", tm.tm_mday); + sprintf((char*)&buf[8], "%02d", tm.tm_hour); + sprintf((char*)&buf[10], "%02d", tm.tm_min); + sprintf((char*)&buf[12], "%02d", MIN(59, tm.tm_sec)); memcpy(&buf[14], "00", 2); - /* timezone */ buf[16] = tzoffset; } } @@ -611,47 +426,6 @@ time_t iso_datetime_read_17(const uint8_t *buf) return mktime(&tm) - buf[16] * 60 * 60; } -void iso_split_filename(char *name, char **ext) -{ - char *r; - - r = strrchr(name, '.'); - if (r) { - *r = '\0'; - *ext = r + 1; - } else - *ext = ""; -} - -void iso_filecpy(unsigned char *buf, int size, const char *name, int version) -{ - char v[6]; - int nl, vl; - - assert(version >= 0); - assert(version < 0x8000); - - nl = strlen(name); - - memcpy(buf, name, nl); - - if (!version) - assert(size >= strlen(name)); - else { - sprintf(v, "%d", version); - vl = strlen(v); - assert(size >= nl + vl + 1); - - buf[nl] = ';'; - memcpy(&buf[nl + 1], v, vl); - - nl += vl + 1; - } - /* pad with spaces */ - if (nl < size) - memset(&buf[nl], ' ', size - nl); -} - size_t ucslen(const uint16_t *str) { int i; @@ -661,20 +435,30 @@ size_t ucslen(const uint16_t *str) return i; } +/** + * Although each character is 2 bytes, we actually compare byte-by-byte + * (thats what the spec says). + */ int ucscmp(const uint16_t *s1, const uint16_t *s2) { - int i; + const char *s = (const char*)s1; + const char *t = (const char*)s2; + size_t len1 = ucslen(s1); + size_t len2 = ucslen(s2); + size_t i, len = MIN(len1, len2) * 2; - for (i=0; 1; i++) { - if (s1[i] < s2[i]) { + for (i=0; i < len; i++) { + if (s[i] < t[i]) { return -1; - } else if (s1[i] > s2[i]) { + } else if (s[i] > t[i]) { return 1; - } else if (s1[i] == 0 && s2[i] == 0) { - break; } } + if (len1 < len2) + return -1; + else if (len1 > len2) + return 1; return 0; } diff --git a/libisofs/util.h b/libisofs/util.h index a4ac6f5..03099fa 100755 --- a/libisofs/util.h +++ b/libisofs/util.h @@ -1,122 +1,95 @@ /* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */ +/* vim: set noet ts=8 sts=8 sw=8 : */ /** * Utility functions for the Libisofs library. */ -#ifndef __ISO_UTIL -#define __ISO_UTIL +#ifndef LIBISO_UTIL_H +#define LIBISO_UTIL_H #include +#include +#include + +#ifndef MAX +# define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef MIN +# define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +extern inline int div_up(int n, int div) +{ + return (n + div - 1) / div; +} + +extern inline int round_up(int n, int mul) +{ + return div_up(n, mul) * mul; +} + +wchar_t *towcs(const char *); +char *wcstoascii(const wchar_t *); +uint16_t *wcstoucs(const wchar_t*); /** - * Checks if the given character is a valid d-character. + * Create a level 1 directory identifier. */ -int valid_d_char(char c); +char *iso_1_dirid(const wchar_t *src); /** - * Checks if the given character is a valid a-character. + * Create a level 2 directory identifier. */ -int valid_a_char(char c); +char *iso_2_dirid(const wchar_t *src); /** - * Checks if the given character is part of the Joliet Allowed Character Set. - */ -int valid_j_char(char msb, char lsb); - -/** - * Checks if the given character is part of the POSIX Portable Filename Character Set. - */ -int valid_p_char(char c); - -/** - * Build a string of d-characters of maximum size 'size', optionally padded with spaces if necessary. - * Can be used to create directory identifiers if padding is turned off. - */ -char *iso_d_str(const char *src, int size, int pad); - -/** - * Build a string of a-characters of maximum size 'size', padded with spaces if necessary. - */ -char *iso_a_str(const char *src, int size); - -/** - * Build a string of j-characters of maximum size 'size', padded with NULLs if necessary. - * Requires the locale to be set correctly. - * @return NULL if the conversion from the current codeset to UCS-2BE is not available. - */ -uint16_t *iso_j_str(const char *src); - -/** - * Create a level 1 file identifier that consists of a name, extension and version number. - * The resulting string will have a file name of maximum length 8, followed by a separator (.), - * an optional extension of maximum length 3, followed by a separator (;) and a version number (digit 1). + * Create a level 1 file identifier that consists of a name, extension and + * version number. The resulting string will have a file name of maximum + * length 8, followed by a separator (.), an optional extension of maximum + * 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 wchar_t *src); /** - * Create a level 2 file identifier that consists of a name, extension and version number. - * The combined file name and extension length will not exceed 30, the name and extension will be separated (.), - * and the extension will be followed by a separator (;) and a version number (digit 1). + * Create a level 2 file identifier that consists of a name, extension and + * version number. The combined file name and extension length will not exceed + * 30, the name and extension will be separated (.), and the extension will be + * 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 wchar_t *src); /** - * Create a Joliet file or directory identifier that consists of a name, extension and version number. - * The combined name and extension length will not exceed 128 bytes, the name and extension will be separated (.), - * and the extension will be followed by a separator (;) and a version number (digit 1). - * All characters consist of 2 bytes and the resulting string is NULL-terminated by a 2-byte NULL. - * Requires the locale to be set correctly. + * Create a Joliet file or directory identifier that consists of a name, + * extension and version number. The combined name and extension length will + * not exceed 128 bytes, the name and extension will be separated (.), + * and the extension will be followed by a separator (;) and a version number + * (digit 1). All characters consist of 2 bytes and the resulting string is + * NULL-terminated by a 2-byte NULL. Requires the locale to be set correctly. + * * @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(char *src); +uint16_t *iso_j_id(const wchar_t *src); /** + * FIXME: what are the requirements for these next two? Is this for RR? + * * Create a POSIX portable file name that consists of a name and extension. * 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_filename(const char *src); +char *iso_p_fileid(const wchar_t *src); /** * Create a POSIX portable directory name. * The resulting directory name will not exceed 250 characters. * @return NULL if the original name is of length 0. */ -char *iso_p_dirname(const char *src); - -/** - * Build a pathname out of a directory and file name. - */ -char *iso_pathname(const char *dir, const char *file); - -#include - -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) - -/** Copy a string of a-characters, padding the unused part of the - destination buffer */ -void iso_a_strcpy(unsigned char *dest, int size, const char *src); - -/** Copy a string of d-characters, padding the unused part of the - destination buffer */ -void iso_d_strcpy(unsigned char *dest, int size, const char *src); - -/** Returns a null terminated string containing the first 'size' a-characters - from the source */ -char *iso_a_strndup(const char *src, int size); - -/** Returns a null terminated string containing the first 'size' d-characters - from the source */ -char *iso_d_strndup(const char *src, int size); - -char *iso_strconcat(char sep, const char *a, const char *b); - -char *iso_strdup(const char *src); +char *iso_p_dirid(const wchar_t *src); void iso_lsb(uint8_t *buf, uint32_t num, int bytes); void iso_msb(uint8_t *buf, uint32_t num, int bytes); @@ -127,30 +100,22 @@ uint32_t iso_read_msb(const uint8_t *buf, int bytes); uint32_t iso_read_bb(const uint8_t *buf, int bytes); /** Records the date/time into a 7 byte buffer (9.1.5) */ -void iso_datetime_7(unsigned char *buf, time_t t); +void iso_datetime_7(uint8_t *buf, time_t t); /** Records the date/time into a 17 byte buffer (8.4.26.1) */ -void iso_datetime_17(unsigned char *buf, time_t t); +void iso_datetime_17(uint8_t *buf, time_t t); time_t iso_datetime_read_7(const uint8_t *buf); time_t iso_datetime_read_17(const uint8_t *buf); -/** Removes the extension from the name, and returns the extension. The - returned extension should _not_ be freed! */ -void iso_split_filename(char *name, char **ext); +/** + * Like strlen, but for Joliet strings. + */ +size_t ucslen(const uint16_t *str); -void iso_filecpy(unsigned char *buf, int size, const char *name, int version); +/** + * Like strcmp, but for Joliet strings. + */ +int ucscmp(const uint16_t *s1, const uint16_t *s2); -int iso_filename_len(const char *name, int iso_level); - -/* replacement for strlen for joliet names (wcslen doesn't work on machines - * with 32-bit wchar_t */ -size_t ucslen(const uint16_t *); - -/* replacement for strcmp for joliet names */ -int ucscmp(const uint16_t*, const uint16_t*); - -#define DIV_UP(n,div) ( ((n)+(div)-1) / (div) ) -#define ROUND_UP(n,mul) ( DIV_UP(n,mul) * (mul) ) - -#endif /* __ISO_UTIL */ +#endif /* LIBISO_UTIL_H */ diff --git a/libisofs/volume.c b/libisofs/volume.c index 15a86b4..9fddb72 100755 --- a/libisofs/volume.c +++ b/libisofs/volume.c @@ -2,50 +2,71 @@ /* vim: set ts=8 sts=8 sw=8 noet : */ #include +#include #include "libisofs.h" #include "tree.h" #include "util.h" #include "volume.h" -#include -struct iso_volset *iso_volset_new(struct iso_volume *vol, const char *id) +struct iso_volset* +iso_volset_new(struct iso_volume *vol, const char *id) { struct iso_volset *volset = calloc(1, sizeof(struct iso_volset)); volset->volset_size = 1; + volset->refcount = 1; volset->volume = malloc(sizeof(void *)); volset->volume[0] = vol; - volset->volset_id.cstr = strdup(id); - volset->volset_id.jstr = iso_j_str(id); + volset->volset_id = towcs(id); + + vol->refcount++; return volset; } -struct iso_volume *iso_volume_new(const char *volume_id, - const char *publisher_id, - const char *data_preparer_id) +void +iso_volset_free(struct iso_volset *volset) +{ + if (--volset->refcount < 1) { + int i; + for (i = 0; i < volset->volset_size; i++) { + iso_volume_free(volset->volume[i]); + } + free(volset->volume); + free(volset->volset_id); + } +} + +struct iso_volume* +iso_volume_new(const char *volume_id, + const char *publisher_id, + const char *data_preparer_id) +{ + return iso_volume_new_with_root(volume_id, + publisher_id, + data_preparer_id, + NULL); +} + +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_volume *volume; volume = calloc(1, sizeof(struct iso_volume)); volume->refcount = 1; - /* Get a new root directory. */ - volume->root = iso_tree_new_root(volume); + volume->root = root ? root : iso_tree_new_root(volume); - /* Set these fields, if given. */ - if (volume_id != NULL) { - volume->volume_id.cstr = strdup(volume_id); - volume->volume_id.jstr = iso_j_str(volume_id); - } - if (publisher_id != NULL) { - volume->publisher_id.cstr = strdup(publisher_id); - volume->publisher_id.jstr = iso_j_str(publisher_id); - } - if (data_preparer_id != NULL) { - volume->data_preparer_id.cstr = strdup(data_preparer_id); - volume->data_preparer_id.jstr = iso_j_str(data_preparer_id); - } + if (volume_id != NULL) + volume->volume_id = towcs(volume_id); + if (publisher_id != NULL) + volume->publisher_id = towcs(publisher_id); + if (data_preparer_id != NULL) + volume->data_preparer_id = towcs(data_preparer_id); return volume; } @@ -55,18 +76,15 @@ void iso_volume_free(struct iso_volume *volume) if (--volume->refcount < 1) { iso_tree_free(volume->root); - free(volume->volume_id.cstr); - free(volume->volume_id.jstr); - free(volume->publisher_id.cstr); - free(volume->publisher_id.jstr); - free(volume->data_preparer_id.cstr); - free(volume->data_preparer_id.jstr); + free(volume->volume_id); + free(volume->publisher_id); + free(volume->data_preparer_id); free(volume); } } -struct iso_tree_dir *iso_volume_get_root(const struct iso_volume *volume) +struct iso_tree_node *iso_volume_get_root(const struct iso_volume *volume) { return volume->root; } diff --git a/libisofs/volume.h b/libisofs/volume.h index db53aff..d310df6 100755 --- a/libisofs/volume.h +++ b/libisofs/volume.h @@ -5,35 +5,25 @@ * Extra declarations for use with the iso_volume structure. */ -#ifndef __ISO_VOLUME -#define __ISO_VOLUME +#ifndef LIBISO_VOLUME_H +#define LIBISO_VOLUME_H #include "libisofs.h" -struct iso_string -{ - char *cstr; - uint16_t *jstr; -}; - /** * Data volume. */ struct iso_volume { - int refcount; /**< Number of used references to th + int refcount; /**< Number of used references to this volume. */ - struct iso_tree_dir *root; /**< Root of the directory tree for the + struct iso_tree_node *root; /**< Root of the directory tree for the volume. */ - unsigned rockridge:1; - unsigned joliet:1; - unsigned iso_level:2; - - struct iso_string volume_id; /**< Volume identifier. */ - struct iso_string publisher_id; /**< Volume publisher. */ - struct iso_string data_preparer_id; /**< Volume data preparer. */ + wchar_t *volume_id; /**< Volume identifier. */ + wchar_t *publisher_id; /**< Volume publisher. */ + wchar_t *data_preparer_id; /**< Volume data preparer. */ }; /** @@ -48,7 +38,7 @@ struct iso_volset int volset_size; /**< The number of volumes in this volume set. */ - struct iso_string volset_id; /**< The id of this volume set, encoded + wchar_t *volset_id; /**< The id of this volume set, encoded in the current locale. */ }; diff --git a/test/iso.c b/test/iso.c index ff74099..e0c7913 100644 --- a/test/iso.c +++ b/test/iso.c @@ -3,8 +3,8 @@ #define _GNU_SOURCE -#include "libisofs/libisofs.h" -#include "libburn/libburn.h" +#include "libisofs.h" +#include "libburn.h" #include #include #include @@ -16,7 +16,7 @@ #include #include #include -#include +#include #define SECSIZE 2048 @@ -44,13 +44,12 @@ int main(int argc, char **argv) { struct iso_volset *volset; struct iso_volume *volume; + struct iso_tree_node *root; struct burn_source *src; unsigned char buf[2048]; FILE *fd; int c; int level=1, flags=0; - DIR *dir; - struct dirent *ent; while ((c = getopt(argc, argv, optstring)) != -1) { switch(c) { @@ -87,45 +86,15 @@ int main(int argc, char **argv) } fd = fopen(argv[optind+1], "w"); if (!fd) { - perror("error opening output file"); - exit(1); + err(1, "error opening output file"); } - volume = iso_volume_new( "VOLID", "PUBID", "PREPID" ); + root = iso_tree_radd_dir(NULL, argv[optind]); + if (!root) { + err(1, "error opening input directory"); + } + volume = iso_volume_new_with_root( "VOLID", "PUBID", "PREPID", root ); volset = iso_volset_new( volume, "VOLSETID" ); - dir = opendir(argv[optind]); - if (!dir) { - perror("error opening input directory"); - exit(1); - } - - while ( (ent = readdir(dir)) ) { - struct stat st; - char *name; - - if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) { - continue; - } - - name = malloc(strlen(argv[optind]) + strlen(ent->d_name) + 2); - strcpy(name, argv[optind]); - strcat(name, "/"); - strcat(name, ent->d_name); - if (lstat(name, &st) == -1) { - fprintf(stderr, "error opening file %s: %s\n", - name, strerror(errno)); - exit(1); - } - - if (S_ISDIR(st.st_mode)) { - iso_tree_radd_dir(iso_volume_get_root(volume), name); - } else { - iso_tree_add_file(iso_volume_get_root(volume), name); - } - free(name); - } - - iso_tree_print(iso_volume_get_root(volume), 0); src = iso_source_new_ecma119(volset, 0, level, flags);