From 041858360a9fcb36697ea17d526bab778e3b1ab3 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Sun, 23 Dec 2007 17:11:32 +0100 Subject: [PATCH] Handle reallocation of directories. --- demo/ecma119_tree.c | 4 ++ src/ecma119.c | 1 + src/ecma119.h | 1 + src/ecma119_tree.c | 147 +++++++++++++++++++++++++++++++++++++++++++- src/ecma119_tree.h | 4 +- 5 files changed, 154 insertions(+), 3 deletions(-) diff --git a/demo/ecma119_tree.c b/demo/ecma119_tree.c index 5ab28a4..9984ab2 100644 --- a/demo/ecma119_tree.c +++ b/demo/ecma119_tree.c @@ -72,6 +72,10 @@ print_dir(Ecma119Node *dir, int level) printf("%s-[S] ", sp); print_permissions(iso_node_get_permissions(child->node)); printf(" %s\n", child->iso_name); + } else if (child->type == ECMA119_PLACEHOLDER) { + printf("%s-[RD] ", sp); + print_permissions(iso_node_get_permissions(child->node)); + printf(" %s\n", child->iso_name); } else { printf("%s-[????] ", sp); } diff --git a/src/ecma119.c b/src/ecma119.c index fa0fdf7..908b771 100644 --- a/src/ecma119.c +++ b/src/ecma119.c @@ -632,6 +632,7 @@ int ecma119_image_new(IsoImage *src, Ecma119WriteOpts *opts, target->iso_level = opts->level; target->rockridge = 1; //TODO target->omit_version_numbers = opts->omit_version_numbers; + target->allow_deep_paths = 0; //TODO target->sort_files = opts->sort_files; target->now = time(NULL); diff --git a/src/ecma119.h b/src/ecma119.h index cfe9981..f8f4bd7 100644 --- a/src/ecma119.h +++ b/src/ecma119.h @@ -34,6 +34,7 @@ struct ecma119_image { /* relaxed constraints */ unsigned int omit_version_numbers:1; + unsigned int allow_deep_paths:1; // int relaxed_constraints; /**< see ecma119_relaxed_constraints_flag */ // diff --git a/src/ecma119_tree.c b/src/ecma119_tree.c index 5129a80..2028e5c 100644 --- a/src/ecma119_tree.c +++ b/src/ecma119_tree.c @@ -229,8 +229,8 @@ int create_tree(Ecma119Image *image, IsoNode *iso, Ecma119Node **tree, return ret; } max_path = pathlen + 1 + (iso_name ? strlen(iso_name) : 0); - if (!image->rockridge) { //TODO !rockridge && !relaxed_paths - if (depth > 8 || max_path > 255) { + if (!image->rockridge && !image->allow_deep_paths) { + if ((iso->type == LIBISO_DIR && depth > 8) || max_path > 255) { iso_msg_note(image->image, LIBISO_FILE_IGNORED, "File \"%s\" can't be added, because depth > 8 " "or path length over 255", iso->name); @@ -553,6 +553,144 @@ int mangle_tree(Ecma119Image *img) return mangle_dir(img, img->root, max_file, max_dir); } +/** + * Create a new ECMA-119 node representing a placeholder for a relocated + * dir. + * + * See IEEE P1282, section 4.1.5 for details + */ +static +int create_placeholder(Ecma119Node *parent, + Ecma119Node *real, Ecma119Node **node) +{ + Ecma119Node *ret; + + ret = calloc(1, sizeof(Ecma119Node)); + if (ret == NULL) { + return ISO_MEM_ERROR; + } + + /* + * TODO + * If real is a dir, while placeholder is a file, ISO name restricctions + * are different, what to do? + */ + ret->iso_name = strdup(real->iso_name); + if (ret->iso_name == NULL) { + free(ret); + return ISO_MEM_ERROR; + } + + /* take a ref to the IsoNode */ + ret->node = real->node; + iso_node_ref(real->node); + ret->parent = parent; + ret->type = ECMA119_PLACEHOLDER; + ret->info.real_me = real; + + *node = ret; + return ISO_SUCCESS; +} + +static +size_t max_child_name_len(Ecma119Node *dir) +{ + size_t ret = 0, i; + for (i = 0; i < dir->info.dir.nchildren; i++) { + size_t len = strlen(dir->info.dir.children[i]->iso_name); + ret = MAX(ret, len); + } + return ret; +} + +/** + * Relocates a directory, as specified in Rock Ridge Specification + * (see IEEE P1282, section 4.1.5). This is needed when the number of levels + * on a directory hierarchy exceeds 8, or the length of a path is higher + * than 255 characters, as specified in ECMA-119, section 6.8.2.1 + */ +static +int reparent(Ecma119Node *child, Ecma119Node *parent) +{ + int ret; + size_t i; + Ecma119Node *placeholder; + + /* replace the child in the original parent with a placeholder */ + for ( i = 0; i < child->parent->info.dir.nchildren; i++) { + if (child->parent->info.dir.children[i] == child) { + ret = create_placeholder(child->parent, child, &placeholder); + if (ret < 0) { + return ret; + } + child->parent->info.dir.children[i] = placeholder; + break; + } + } + + /* just for debug, this should never happen... */ + if (i == child->parent->info.dir.nchildren) { + return ISO_ERROR; + } + + /* add the child to its new parent */ + child->parent = parent; + parent->info.dir.nchildren++; + parent->info.dir.children = realloc( parent->info.dir.children, + sizeof(void*) * parent->info.dir.nchildren ); + parent->info.dir.children[parent->info.dir.nchildren - 1] = child; + return ISO_SUCCESS; +} + +/** + * Reorder the tree, if necessary, to ensure that + * - the depth is at most 8 + * - each path length is at most 255 characters + * This restriction is imposed by ECMA-119 specification (ECMA-119, 6.8.2.1). + * + * @param dir + * Dir we are currently processing + * @param level + * Level of the directory in the hierarchy + * @param pathlen + * Length of the path until dir, including it + * @return + * 1 success, < 0 error + */ +static +int reorder_tree(Ecma119Image *img, Ecma119Node *dir, int level, int pathlen) +{ + int ret; + size_t max_path; + + max_path = pathlen + 1 + max_child_name_len(dir); + + if (level > 8 || max_path > 255) { + ret = reparent(dir, img->root); + if (ret < 0) { + return ret; + } + + /* + * we are appended to the root's children now, so there is no + * need to recurse (the root will hit us again) + */ + } else { + size_t i; + + for (i = 0; i < dir->info.dir.nchildren; i++) { + Ecma119Node *child = dir->info.dir.children[i]; + if (child->type == ECMA119_DIR) { + int newpathlen = pathlen + 1 + strlen(child->iso_name); + ret = reorder_tree(img, child, level + 1, newpathlen); + if (ret < 0) { + return ret; + } + } + } + } + return ISO_SUCCESS; +} int ecma119_tree_create(Ecma119Image *img) { @@ -578,6 +716,11 @@ int ecma119_tree_create(Ecma119Image *img) return ret; } + if (img->rockridge && !img->allow_deep_paths) { + /* reorder the tree, acording to RRIP, 4.1.5 */ + reorder_tree(img, img->root, 1, 0); + } + /* * TODO * - reparent if RR diff --git a/src/ecma119_tree.h b/src/ecma119_tree.h index 17ed884..d609414 100644 --- a/src/ecma119_tree.h +++ b/src/ecma119_tree.h @@ -47,11 +47,13 @@ struct ecma119_node IsoNode *node; /*< reference to the iso node */ - /**< file, symlink, directory or placeholder */ + /**< file, symlink, special, directory or placeholder */ enum ecma119_node_type type; union { IsoFileSrc *file; struct ecma119_dir_info dir; + /** this field points to the relocated directory. */ + Ecma119Node *real_me; } info; };