From 76f2a5f4d3a09f388f807867ffe4a960923682d5 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Fri, 9 Mar 2012 19:59:51 +0100 Subject: [PATCH] New API call iso_write_opts_set_rr_reloc() --- libisofs/ecma119.c | 130 +++++++++++++++++++++++++++++++++++++++- libisofs/ecma119.h | 26 +++++++- libisofs/ecma119_tree.c | 67 +++++++++++++++++---- libisofs/libisofs.h | 44 ++++++++++++++ libisofs/libisofs.ver | 1 + libisofs/rockridge.c | 36 ++++++++--- 6 files changed, 283 insertions(+), 21 deletions(-) diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index 0197837..73f5229 100644 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2007 Vreixo Formoso * Copyright (c) 2007 Mario Danic - * Copyright (c) 2009 - 2011 Thomas Schmitt + * Copyright (c) 2009 - 2012 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -89,6 +89,14 @@ void ecma119_image_free(Ecma119Image *t) writer->free_data(writer); free(writer); } + +#ifdef Libisofs_with_rr_reloc_diR + + if (t->rr_reloc_dir != NULL) + free(t->rr_reloc_dir); + +#endif /* Libisofs_with_rr_reloc_diR */ + if (t->input_charset != NULL) free(t->input_charset); if (t->output_charset != NULL) @@ -1673,6 +1681,22 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) target->rrip_1_10_px_ino = opts->rrip_1_10_px_ino; target->aaip_susp_1_10 = opts->aaip_susp_1_10; target->dir_rec_mtime = opts->dir_rec_mtime; + +#ifdef Libisofs_with_rr_reloc_diR + + target->rr_reloc_dir = NULL; + if (opts->rr_reloc_dir != NULL) { + target->rr_reloc_dir = strdup(opts->rr_reloc_dir); + if (target->rr_reloc_dir == NULL) { + ret = ISO_OUT_OF_MEM; + goto target_cleanup; + } + } + target->rr_reloc_flags = opts->rr_reloc_flags; + target->rr_reloc_node = NULL; + +#endif /* Libisofs_with_rr_reloc_diR */ + target->sort_files = opts->sort_files; target->replace_uid = opts->replace_uid ? 1 : 0; @@ -2310,6 +2334,69 @@ int bs_set_size(struct burn_source *bs, off_t size) return 1; } +#ifdef Libisofs_with_rr_reloc_diR + +static +int dive_to_depth_8(IsoDir *dir, int depth) +{ + int ret; + IsoNode *pos; + + if (depth >= 8) + return 1; + pos = dir->children; + for (pos = dir->children; pos != NULL; pos = pos->next) { + if (pos->type != LIBISO_DIR) + continue; + ret = dive_to_depth_8((IsoDir *) pos, depth + 1); + if (ret != 0) + return ret; + } + return 0; +} + +static +int make_reloc_dir_if_needed(IsoImage *img, IsoWriteOpts *opts, int flag) +{ + int ret; + IsoDir *dir; + + /* Two forms to express the root directory */ + if (opts->rr_reloc_dir == NULL) + return 1; + if (opts->rr_reloc_dir[0] == 0) + return 1; + + if (strchr(opts->rr_reloc_dir, '/') != NULL) + return 0; + + /* Check existence of opts->rr_reloc_dir */ + ret = iso_dir_get_node(img->root, opts->rr_reloc_dir, NULL); + if (ret > 0) + return 1; + if (ret < 0) + return ret; + + /* Check whether there is a directory of depth 8 (root is depth 1) */ + ret = dive_to_depth_8(img->root, 1); + if (ret < 0) + return ret; + if (ret == 0) + return 1; + + /* Make IsoDir with same permissions as root directory */ + ret = iso_tree_add_new_dir(img->root, opts->rr_reloc_dir, &dir); + if (ret < 0) + return ret; + + opts->rr_reloc_flags |= 2; /* Auto-created relocation directory */ + + return 1; +} + +#endif /* Libisofs_with_rr_reloc_diR */ + + int iso_image_create_burn_source(IsoImage *image, IsoWriteOpts *opts, struct burn_source **burn_src) { @@ -2326,6 +2413,16 @@ int iso_image_create_burn_source(IsoImage *image, IsoWriteOpts *opts, return ISO_OUT_OF_MEM; } +#ifdef Libisofs_with_rr_reloc_diR + + if (!opts->allow_deep_paths) { + ret = make_reloc_dir_if_needed(image, opts, 0); + if (ret < 0) + return ret; + } + +#endif /* Libisofs_with_rr_reloc_diR */ + ret = ecma119_image_new(image, opts, &target); if (ret < 0) { free(source); @@ -2434,6 +2531,13 @@ int iso_write_opts_new(IsoWriteOpts **opts, int profile) wopts->fifo_size = 1024; /* 2 MB buffer */ wopts->sort_files = 1; /* file sorting is always good */ +#ifdef Libisofs_with_rr_reloc_diR + + wopts->rr_reloc_dir = NULL; + wopts->rr_reloc_flags = 0; + +#endif /* Libisofs_with_rr_reloc_diR */ + wopts->system_area_data = NULL; wopts->system_area_options = 0; wopts->vol_creation_time = 0; @@ -2470,6 +2574,14 @@ void iso_write_opts_free(IsoWriteOpts *opts) return; } free(opts->output_charset); + +#ifdef Libisofs_with_rr_reloc_diR + + if (opts->rr_reloc_dir != NULL) + free(opts->rr_reloc_dir); + +#endif /* Libisofs_with_rr_reloc_diR */ + if (opts->system_area_data != NULL) free(opts->system_area_data); for (i = 0; i < ISO_MAX_PARTITIONS; i++) @@ -2711,6 +2823,22 @@ int iso_write_opts_set_dir_rec_mtime(IsoWriteOpts *opts, int allow) return ISO_SUCCESS; } +int iso_write_opts_set_rr_reloc(IsoWriteOpts *opts, char *name, int flags) +{ + if (opts->rr_reloc_dir != name) { + if (opts->rr_reloc_dir != NULL) + free(opts->rr_reloc_dir); + opts->rr_reloc_dir = NULL; + if (name != NULL) { + opts->rr_reloc_dir = strdup(name); + if (opts->rr_reloc_dir == NULL) + return ISO_OUT_OF_MEM; + } + } + opts->rr_reloc_flags = flags & 1; + return ISO_SUCCESS; +} + int iso_write_opts_set_sort_files(IsoWriteOpts *opts, int sort) { if (opts == NULL) { diff --git a/libisofs/ecma119.h b/libisofs/ecma119.h index 425db65..97d6f3a 100644 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2009 - 2011 Thomas Schmitt + * Copyright (c) 2009 - 2012 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -206,6 +206,24 @@ struct iso_write_opts { */ unsigned int dir_rec_mtime :3; + /** + * This describes the directory where to store Rock Ridge relocated + * directories. + * If not relaxation "allow_deep_paths" is in effect, it is necessary to + * relocate directories so that no ECMA-119 file path has more than + * 8 components. For Rock Ridge the relocated directories are linked forth + * and back to a placeholder at their original position in path level 8 + * (entries CL and PL). Directories marked by entry RE are to be considered + * artefacts of relocation and shall not be read into a Rock Ridge tree. + * For plain ECMA-119, the relocation directory is just a normal directory + * which contains normal files and directories. + */ + char *rr_reloc_dir; /* IsoNode name in root directory */ + int rr_reloc_flags; /* bit0= mark auto-created rr_reloc_dir by RE + bit1= directory was auto-created + (cannot be set via API) + */ + /** * Compute MD5 checksum for the whole session and record it as index 0 of * the checksum blocks after the data area of the session. The layout and @@ -482,6 +500,12 @@ struct ecma119_image */ unsigned int dir_rec_mtime :3; + /* The ECMA-119 directory where to store Rock Ridge relocated directories. + */ + char *rr_reloc_dir; /* IsoNode name in root directory */ + int rr_reloc_flags; + Ecma119Node *rr_reloc_node; /* Directory node in ecma119_image */ + unsigned int md5_session_checksum :1; unsigned int md5_file_checksums :2; diff --git a/libisofs/ecma119_tree.c b/libisofs/ecma119_tree.c index 2e80216..f8de49c 100644 --- a/libisofs/ecma119_tree.c +++ b/libisofs/ecma119_tree.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2009 Thomas Schmitt + * Copyright (c) 2009 - 2012 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -434,6 +434,20 @@ int create_tree(Ecma119Image *image, IsoNode *iso, Ecma119Node **tree, if (ret < 0) { goto ex; } + +#ifdef Libisofs_with_rr_reloc_diR + + if (depth == 1) { /* root is default */ + image->rr_reloc_node = node; + } else if (depth == 2) { /* directories in root may be used */ + if (image->rr_reloc_dir != NULL) + if (strcmp(iso->name, image->rr_reloc_dir) == 0) + image->rr_reloc_node = node; + } + +#endif /* Libisofs_with_rr_reloc_diR */ + + } ret = ISO_SUCCESS; pos = dir->children; @@ -750,7 +764,7 @@ int mangle_dir(Ecma119Image *img, Ecma119Node *dir, int max_file_len, } static -int mangle_tree(Ecma119Image *img, int recurse) +int mangle_tree(Ecma119Image *img, Ecma119Node *dir, int recurse) { int max_file, max_dir; Ecma119Node *root; @@ -765,7 +779,9 @@ int mangle_tree(Ecma119Image *img, int recurse) } else { max_file = max_dir = 31; } - if (img->eff_partition_offset > 0) { + if (dir != NULL) { + root = dir; + } else if (img->eff_partition_offset > 0) { root = img->partition_root; } else { root = img->root; @@ -891,17 +907,34 @@ int reorder_tree(Ecma119Image *img, Ecma119Node *dir, int level, int pathlen) { int ret; size_t max_path; - Ecma119Node *root; + Ecma119Node *reloc; max_path = pathlen + 1 + max_child_name_len(dir); if (level > 8 || max_path > 255) { - if (img->eff_partition_offset > 0) { - root = img->partition_root; - } else { - root = img->root; + +#ifdef Libisofs_with_rr_reloc_diR + + reloc = img->rr_reloc_node; + if (reloc == NULL) { + if (img->eff_partition_offset > 0) { + reloc = img->partition_root; + } else { + reloc = img->root; + } } - ret = reparent(dir, root); + +#else + + if (img->eff_partition_offset > 0) { + reloc = img->partition_root; + } else { + reloc = img->root; + } + +#endif /* ! Libisofs_with_rr_reloc_diR */ + + ret = reparent(dir, reloc); if (ret < 0) { return ret; } @@ -1115,6 +1148,8 @@ int ecma119_tree_create(Ecma119Image *img) img->root = root; } + /* >>> ts B20307 : Shouldn't relocation be done here ? */ + iso_msg_debug(img->image->id, "Matching hardlinks..."); ret = match_hardlinks(img, root, 0); if (ret < 0) { @@ -1125,14 +1160,14 @@ int ecma119_tree_create(Ecma119Image *img) sort_tree(root); iso_msg_debug(img->image->id, "Mangling names..."); - ret = mangle_tree(img, 1); + ret = mangle_tree(img, NULL, 1); if (ret < 0) { return ret; } if (img->rockridge && !img->allow_deep_paths) { - /* reorder the tree, acording to RRIP, 4.1.5 */ + /* Relocate deep directories, acording to RRIP, 4.1.5 */ ret = reorder_tree(img, root, 1, 0); if (ret < 0) { return ret; @@ -1143,7 +1178,15 @@ int ecma119_tree_create(Ecma119Image *img) * above could insert new directories into the root. * Note that recurse = 0, as we don't need to recurse. */ - ret = mangle_tree(img, 0); + + /* >>> ts B20307 : Shouldn't one mangle _after_ relocating ? */ + +#ifdef Libisofs_with_rr_reloc_diR + ret = mangle_tree(img, img->rr_reloc_node, 0); +#else + ret = mangle_tree(img, NULL, 0); +#endif + if (ret < 0) { return ret; } diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index c9ba83b..e9d3e0a 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -1536,6 +1536,45 @@ int iso_write_opts_set_omit_version_numbers(IsoWriteOpts *opts, int omit); */ int iso_write_opts_set_allow_deep_paths(IsoWriteOpts *opts, int allow); +/** + * This call describes the directory where to store Rock Ridge relocated + * directories. + * If not iso_write_opts_set_allow_deep_paths(,1) is in effect, then it is + * necessary to relocate directories so that no ECMA-119 file path + * has more than 8 components. These directories are grafted into either + * the root directory of the ISO image or into a dedicated relocation + * directory. + * For Rock Ridge, the relocated directories are linked forth and back to + * placeholders at their original positions in path level 8. Directories + * marked by Rock Ridge entry RE are to be considered artefacts of relocation + * and shall not be read into a Rock Ridge tree. Instead they are to be read + * via their placeholders and their links. + * For plain ECMA-119, the relocation directory and the relocated directories + * are just normal directories which contain normal files and directories. + * @param opts + * The option set to be manipulated. + * @param name + * The name of the relocation directory in the root directory. Do not + * prepend "/". An empty name or NULL will direct relocated directories + * into the root directory. This is the default. + * If the given name does not exist in the root directory when + * iso_image_create_burn_source() is called, and if there are directories + * at path level 8, then directory /name will be created automatically. + * The name given by this call will be compared with iso_node_get_name() + * of the directories in the root directory, not with the final ECMA-119 + * names of those directories. + * @parm flags + * Bitfield for control purposes. + * bit0= Mark the relocation directory by a Rock Ridge RE entry, if it + * gets created during iso_image_create_burn_source(). This will + * make it invisible for most Rock Ridge readers. + * bit1= not settable via API (used internally) + * @return + * 1 success, < 0 error + * @since 1.2.2 +*/ +int iso_write_opts_set_rr_reloc(IsoWriteOpts *opts, char *name, int flags); + /** * Allow path in the ISO-9660 tree to have more than 255 characters. * This breaks ECMA-119 specification. Use with caution. @@ -7170,6 +7209,11 @@ struct burn_source { /* currently none being tested */ +/* Perform the operations promised by iso_write_opts_set_rr_reloc() */ +#define Libisofs_with_rr_reloc_diR yes + + + /* ---------------------------- Experiments ---------------------------- */ diff --git a/libisofs/libisofs.ver b/libisofs/libisofs.ver index a6b6363..c894ba2 100644 --- a/libisofs/libisofs.ver +++ b/libisofs/libisofs.ver @@ -301,6 +301,7 @@ iso_write_opts_set_relaxed_vol_atts; iso_write_opts_set_replace_mode; iso_write_opts_set_replace_timestamps; iso_write_opts_set_rockridge; +iso_write_opts_set_rr_reloc; iso_write_opts_set_rrip_1_10_px_ino; iso_write_opts_set_rrip_version_1_10; iso_write_opts_set_scdbackup_tag; diff --git a/libisofs/rockridge.c b/libisofs/rockridge.c index 659e5ce..39e8875 100644 --- a/libisofs/rockridge.c +++ b/libisofs/rockridge.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2007 Vreixo Formoso * Copyright (c) 2007 Mario Danic - * Copyright (c) 2009 - 2011 Thomas Schmitt + * Copyright (c) 2009 - 2012 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -406,12 +406,15 @@ int rrip_SL_append_comp(size_t *n, uint8_t ***comps, char *s, int size, char fl) #ifdef Libisofs_with_rrip_rR /** - * Add to the given tree node a RR System Use Entry. This is an obsolete - * entry from before RRIP-1.10. Nevertheless mkisofs produces it and there - * is the suspicion that Solaris takes it as indication for Rock Ridge. + * Add a RR System Use Entry to the given tree node. This is an obsolete + * entry from before RRIP-1.10. Nevertheless mkisofs produces it. There + * is the suspicion that some operating systems could take it as indication + * for Rock Ridge. * - * I once saw a copy of a RRIP spec which mentioned RR. Here i just use - * the same constant 5 bytes as produced by mkisofs. + * The meaning of the payload byte is documented e.g. in + * /usr/src/linux/fs/isofs/rock.h + * It announces the presence of entries PX, PN, SL, NM, CL, PL, RE, TF + * by payload byte bits 0 to 7. */ static int rrip_add_RR(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp) @@ -426,7 +429,14 @@ int rrip_add_RR(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp) RR[1] = 'R'; RR[2] = 5; RR[3] = 1; - RR[4] = 0201; + + /* <<< ts B20307 : Not all directories have NM, many files have more entries */ + RR[4] = 0x89; /* TF, NM , PX */ + + /* >>> ts B20307 : find out whether n carries + PX, PN, SL, NM, CL, PL, RE, TF and mark by bit0 to bit7 in RR[4] + */ + return susp_append(t, susp, RR); } @@ -1422,6 +1432,18 @@ int rrip_get_susp_fields(Ecma119Image *t, Ecma119Node *n, int type, goto add_susp_cleanup; } } + +#ifdef Libisofs_with_rr_reloc_diR + + } else if(t->rr_reloc_node == n && n != t->root && + (t->rr_reloc_flags & 3) == 3) { + /* The dedicated relocation directory shall be marked by RE */ + ret = rrip_add_RE(t, node, info); + if (ret < 0) + goto add_susp_cleanup; + +#endif /* Libisofs_with_rr_reloc_diR */ + } } else if (n->type == ECMA119_SPECIAL) { if (S_ISBLK(n->node->mode) || S_ISCHR(n->node->mode)) {