From a3eeda3d23fb185b14d6a4bf40232cddf8a344a4 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Tue, 25 Jan 2011 10:50:37 +0100 Subject: [PATCH] Yet incomplete implementation of IsoNode cloning. (Commited to avoid tangling with upcomming iso_write_opts_set_no_dummy_block_adr()) --- libisofs/ecma119.h | 14 ++-- libisofs/filters/external.c | 35 ++++++++- libisofs/filters/gzip.c | 40 ++++++++-- libisofs/filters/zisofs.c | 63 ++++++++++++++-- libisofs/fs_image.c | 98 +++++++++++++++++++++++- libisofs/fsource.h | 11 ++- libisofs/libisofs.h | 144 ++++++++++++++++++++++++++++++------ libisofs/libisofs.ver | 3 + libisofs/messages.c | 3 + libisofs/node.c | 32 +++++++- libisofs/node.h | 3 +- libisofs/rockridge_read.c | 4 +- libisofs/stream.c | 100 ++++++++++++++++++++++++- libisofs/stream.h | 18 ++++- libisofs/tree.c | 98 ++++++++++++++++++++++++ 15 files changed, 613 insertions(+), 53 deletions(-) diff --git a/libisofs/ecma119.h b/libisofs/ecma119.h index b9844a4..b44f26e 100644 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -239,6 +239,11 @@ struct iso_write_opts { unsigned int replace_uid :2; unsigned int replace_gid :2; + mode_t dir_mode; /** Mode to use on dirs when replace_dir_mode == 2. */ + mode_t file_mode; /** Mode to use on files when replace_file_mode == 2. */ + uid_t uid; /** uid to use when replace_uid == 2. */ + gid_t gid; /** gid to use when replace_gid == 2. */ + /** * Extra Caution: This option breaks any assumptions about names that * are supported by ECMA-119 specifications. @@ -254,11 +259,6 @@ struct iso_write_opts { */ unsigned int untranslated_name_len; - mode_t dir_mode; /** Mode to use on dirs when replace_dir_mode == 2. */ - mode_t file_mode; /** Mode to use on files when replace_file_mode == 2. */ - uid_t uid; /** uid to use when replace_uid == 2. */ - gid_t gid; /** gid to use when replace_gid == 2. */ - /** * 0 to use IsoNode timestamps, 1 to use recording time, 2 to use * values from timestamp field. This has only meaning if RR extensions @@ -479,14 +479,14 @@ struct ecma119_image unsigned int replace_dir_mode :1; unsigned int replace_timestamps :1; - unsigned int untranslated_name_len; - uid_t uid; gid_t gid; mode_t file_mode; mode_t dir_mode; time_t timestamp; + unsigned int untranslated_name_len; + /** * if sort files or not. Sorting is based of the weight of each file */ diff --git a/libisofs/filters/external.c b/libisofs/filters/external.c index 1105ec5..1b6f72f 100644 --- a/libisofs/filters/external.c +++ b/libisofs/filters/external.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009 Thomas Schmitt + * Copyright (c) 2009 - 2011 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 @@ -20,6 +20,7 @@ #include "../libisofs.h" #include "../filter.h" #include "../fsource.h" +#include "../stream.h" #include #include @@ -598,6 +599,33 @@ IsoStream *extf_get_input_stream(IsoStream *stream, int flag) return data->orig; } +static +int extf_clone_stream(IsoStream *old_stream, IsoStream **new_stream, int flag) +{ + int ret; + IsoStream *new_input_stream, *stream; + ExternalFilterStreamData *stream_data, *old_stream_data; + + stream_data = calloc(1, sizeof(ExternalFilterStreamData)); + if (stream_data == NULL) + return ISO_OUT_OF_MEM; + ret = iso_stream_clone_filter_common(old_stream, &stream, + &new_input_stream, 0); + if (ret < 0) { + free((char *) stream_data); + return ret; + } + old_stream_data = (ExternalFilterStreamData *) old_stream->data; + stream_data->id = ++extf_ino_id; + stream_data->orig = new_input_stream; + stream_data->cmd = old_stream_data->cmd; + stream_data->cmd->refcount++; + stream_data->size = old_stream_data->size; + stream_data->running = NULL; + stream->data = stream_data; + *new_stream = stream; + return ISO_SUCCESS; +} static int extf_cmp_ino(IsoStream *s1, IsoStream *s2); @@ -605,7 +633,7 @@ int extf_cmp_ino(IsoStream *s1, IsoStream *s2); IsoStreamIface extf_stream_class = { - 3, + 4, "extf", extf_stream_open, extf_stream_close, @@ -616,7 +644,8 @@ IsoStreamIface extf_stream_class = { extf_stream_free, extf_update_size, extf_get_input_stream, - extf_cmp_ino + extf_cmp_ino, + extf_clone_stream }; diff --git a/libisofs/filters/gzip.c b/libisofs/filters/gzip.c index de73696..a610e12 100644 --- a/libisofs/filters/gzip.c +++ b/libisofs/filters/gzip.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009 Thomas Schmitt + * Copyright (c) 2009 - 2011 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 @@ -25,6 +25,7 @@ #include "../filter.h" #include "../fsource.h" #include "../util.h" +#include "../stream.h" #include #include @@ -153,6 +154,7 @@ static int gzip_compression_level = 6; /* * The data payload of an individual Gzip Filter IsoStream */ +/* IMPORTANT: Any change must be reflected by >>> _clone() */ typedef struct { IsoStream *orig; @@ -529,12 +531,38 @@ IsoStream *gzip_get_input_stream(IsoStream *stream, int flag) } +static +int gzip_clone_stream(IsoStream *old_stream, IsoStream **new_stream, int flag) +{ + int ret; + IsoStream *new_input_stream, *stream; + GzipFilterStreamData *stream_data, *old_stream_data; + + stream_data = calloc(1, sizeof(GzipFilterStreamData)); + if (stream_data == NULL) + return ISO_OUT_OF_MEM; + ret = iso_stream_clone_filter_common(old_stream, &stream, + &new_input_stream, 0); + if (ret < 0) { + free((char *) stream_data); + return ret; + } + old_stream_data = (GzipFilterStreamData *) old_stream->data; + stream_data->orig = new_input_stream; + stream_data->size = old_stream_data->size; + stream_data->running = NULL; + stream_data->id = ++gzip_ino_id; + stream->data = stream_data; + *new_stream = stream; + return ISO_SUCCESS; +} + static int gzip_cmp_ino(IsoStream *s1, IsoStream *s2); IsoStreamIface gzip_stream_compress_class = { - 3, + 4, "gzip", gzip_stream_open, gzip_stream_close, @@ -545,12 +573,13 @@ IsoStreamIface gzip_stream_compress_class = { gzip_stream_free, gzip_update_size, gzip_get_input_stream, - gzip_cmp_ino + gzip_cmp_ino, + gzip_clone_stream }; IsoStreamIface gzip_stream_uncompress_class = { - 3, + 4, "pizg", gzip_stream_open, gzip_stream_close, @@ -561,7 +590,8 @@ IsoStreamIface gzip_stream_uncompress_class = { gzip_stream_free, gzip_update_size, gzip_get_input_stream, - gzip_cmp_ino + gzip_cmp_ino, + gzip_clone_stream }; diff --git a/libisofs/filters/zisofs.c b/libisofs/filters/zisofs.c index ee5d6a7..a3e2d88 100644 --- a/libisofs/filters/zisofs.c +++ b/libisofs/filters/zisofs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009 Thomas Schmitt + * Copyright (c) 2009 - 2011 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 @@ -22,6 +22,7 @@ #include "../filter.h" #include "../fsource.h" #include "../util.h" +#include "../stream.h" #include #include @@ -167,6 +168,7 @@ static int ziso_compression_level = 6; /* * The common data payload of an individual Zisofs Filter IsoStream + * IMPORTANT: Any change must be reflected by ziso_clone_stream. */ typedef struct { @@ -183,6 +185,7 @@ typedef struct /* * The data payload of an individual Zisofs Filter Compressor IsoStream + * IMPORTANT: Any change must be reflected by ziso_clone_stream. */ typedef struct { @@ -198,6 +201,7 @@ typedef struct /* * The data payload of an individual Zisofs Filter Uncompressor IsoStream + * IMPORTANT: Any change must be reflected by ziso_clone_stream. */ typedef struct { @@ -779,13 +783,60 @@ IsoStream *ziso_get_input_stream(IsoStream *stream, int flag) return data->orig; } +static +int ziso_clone_stream(IsoStream *old_stream, IsoStream **new_stream, int flag) +{ + int ret; + IsoStream *new_input_stream = NULL, *stream = NULL; + ZisofsFilterStreamData *stream_data, *old_stream_data; + ZisofsUncomprStreamData *uncompr, *old_uncompr; + ZisofsComprStreamData *compr, *old_compr; + + ret = iso_stream_clone_filter_common(old_stream, &stream, + &new_input_stream, 0); + if (ret < 0) + return ret; + + if (old_stream->class->read == &ziso_stream_uncompress) { + uncompr = calloc(1, sizeof(ZisofsUncomprStreamData)); + if (uncompr == NULL) + goto no_mem; + stream_data = (ZisofsFilterStreamData *) uncompr; + old_uncompr = (ZisofsUncomprStreamData *) old_stream->data; + uncompr->header_size_div4 = old_uncompr->header_size_div4; + uncompr->block_size_log2 = old_uncompr->block_size_log2; + } else { + compr = calloc(1, sizeof(ZisofsComprStreamData)); + if (compr == NULL) + goto no_mem; + stream_data = (ZisofsFilterStreamData *) compr; + old_compr = (ZisofsComprStreamData *) old_stream->data; + compr->orig_size = old_compr->orig_size; + compr->block_pointers = NULL; + } + old_stream_data = (ZisofsFilterStreamData *) old_stream->data; + stream_data->orig = new_input_stream; + stream_data->size = old_stream_data->size; + stream_data->running = NULL; + stream_data->id = ++ziso_ino_id; + stream->data = stream_data; + *new_stream = stream; + return ISO_SUCCESS; +no_mem: + if (new_input_stream != NULL) + iso_stream_unref(new_input_stream); + if (stream != NULL) + iso_stream_unref(stream); + return ISO_OUT_OF_MEM; +} + static int ziso_cmp_ino(IsoStream *s1, IsoStream *s2); IsoStreamIface ziso_stream_compress_class = { - 3, + 4, "ziso", ziso_stream_open, ziso_stream_close, @@ -796,12 +847,13 @@ IsoStreamIface ziso_stream_compress_class = { ziso_stream_free, ziso_update_size, ziso_get_input_stream, - ziso_cmp_ino + ziso_cmp_ino, + ziso_clone_stream }; IsoStreamIface ziso_stream_uncompress_class = { - 3, + 4, "osiz", ziso_stream_open, ziso_stream_close, @@ -812,7 +864,8 @@ IsoStreamIface ziso_stream_uncompress_class = { ziso_stream_free, ziso_update_size, ziso_get_input_stream, - ziso_cmp_ino + ziso_cmp_ino, + ziso_clone_stream }; diff --git a/libisofs/fs_image.c b/libisofs/fs_image.c index d9903b3..666cca0 100644 --- a/libisofs/fs_image.c +++ b/libisofs/fs_image.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2009 - 2010 Thomas Schmitt + * Copyright (c) 2009 - 2011 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 @@ -317,6 +317,7 @@ typedef struct typedef struct image_fs_data ImageFileSourceData; +/* IMPORTANT: Any change must be reflected by iso_ifs_source_clone */ struct image_fs_data { IsoImageFilesystem *fs; /**< reference to the image it belongs to */ @@ -1987,6 +1988,101 @@ void ifs_fs_free(IsoFilesystem *fs) free(data); } +int iso_ifs_source_clone(IsoFileSource *old_source, + IsoFileSource **new_source, int flag) +{ + IsoFileSource *src = NULL; + ImageFileSourceData *old_data, *new_data = NULL; + char *new_name = NULL; + struct iso_file_section *new_sections = NULL; + unsigned char *new_aa_string; + size_t aa_size; + int i, new_aa_length = 0; + + old_data = (ImageFileSourceData *) old_source->data; + *new_source = NULL; + src = calloc(1, sizeof(IsoFileSource)); + if (src == NULL) + goto no_mem; + new_data = calloc(1, sizeof(ImageFileSourceData)); + if (new_data == NULL) + goto no_mem; + new_name = strdup(old_data->name); + if (new_name == NULL) { + free((char *) src); + free((char *) new_data); + return ISO_OUT_OF_MEM; + } + if (old_data->nsections > 0) { + new_sections = calloc(old_data->nsections, + sizeof(struct iso_file_section)); + if (new_sections == NULL) + goto no_mem; + } + if (old_data->aa_string != NULL) { + aa_size = aaip_count_bytes(old_data->aa_string, 0); + if (aa_size > 0) { + new_aa_string = calloc(1, aa_size); + if (new_aa_string == NULL) + goto no_mem; + } + } + + new_data->fs = old_data->fs; + iso_filesystem_ref(new_data->fs); + + /* Re-using the directory structure of the original image tree is + supposed to not spoil independence of the cloned IsoFileSource because + that directory structure does not change as long as the loaded + image exists. + The .readdir() method of IsoFileSourceIface will not list the clones + but rather the originals. + It is unclear anyway, how it should work with the root of a cloned + IsoNode tree which would need to be implanted fakely into the + IsoFilesystem. + + Currently there is the technical problem that a new parent would have + to be passed through the IsoStream cloning call, which cannot have + knowledge of a newly created IsoSource parent. + */ + new_data->parent = old_data->parent; + iso_file_source_ref(new_data->parent); + + memcpy(&(new_data->info), &(old_data->info), sizeof(struct stat)); + new_data->name = new_name; + new_data->sections = new_sections; + new_data->nsections = old_data->nsections; + for (i = 0; i < new_data->nsections; i++) + memcpy(new_data->sections + i, old_data->sections + i, + sizeof(struct iso_file_section)); + new_data->opened = old_data->opened; +#ifdef Libisofs_with_zliB + new_data->header_size_div4 = old_data->header_size_div4; + new_data->block_size_log2 = old_data->block_size_log2; + new_data->uncompressed_size = old_data->uncompressed_size; +#endif + new_data->data.content = NULL; + if (new_aa_length > 0) + memcpy(new_aa_string, old_data->aa_string, new_aa_length); + new_data->aa_string = new_aa_string; + + *new_source = src; + return ISO_SUCCESS; +no_mem:; + if (src != NULL) + free((char *) src); + if (new_data != NULL) + free((char *) new_data); + if (new_name != NULL) + free(new_name); + if (new_sections != NULL) + free((char *) new_sections); + if (new_aa_string != NULL) + free((char *) new_aa_string); + return ISO_OUT_OF_MEM; +} + + /** * Read the SUSP system user entries of the "." entry of the root directory, * indentifying when Rock Ridge extensions are being used. diff --git a/libisofs/fsource.h b/libisofs/fsource.h index 6014237..1640c90 100644 --- a/libisofs/fsource.h +++ b/libisofs/fsource.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2009 Thomas Schmitt + * Copyright (c) 2009 - 2011 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 @@ -33,9 +33,16 @@ int iso_local_filesystem_new(IsoFilesystem **fs); -/* Rank two IsoFileSource by their eventual old image LBAs. +/* Rank two IsoFileSource of ifs_class by their eventual old image LBAs. Other IsoFileSource classes will be ranked only roughly. */ int iso_ifs_sections_cmp(IsoFileSource *s1, IsoFileSource *s2, int flag); + +/* Create an independent copy of an ifs_class IsoFileSource. +*/ +int iso_ifs_source_clone(IsoFileSource *old_source, IsoFileSource **new_source, + int flag); + + #endif /*LIBISO_FSOURCE_H_*/ diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 563127c..bf80ed4 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -807,6 +807,8 @@ struct IsoStream_Iface * get_input_stream() added. A filter stream must have version 2. * Version 3 (since 0.6.20) * compare() added. A filter stream should have version 3. + * Version 4 (since 1.0.2) + * clone_stream() added. */ int version; @@ -913,7 +915,7 @@ struct IsoStream_Iface * @param stream * The eventual filter stream to be inquired. * @param flag - * Bitfield for control purposes. Submit 0 for now. + * Bitfield for control purposes. 0 means normal behavior. * @return * The input stream, if one exists. Elsewise NULL. * No extra reference to the stream is taken by this call. @@ -928,33 +930,32 @@ struct IsoStream_Iface * produce the same output. If in any doubt, then this comparison should * indicate no match. A match might allow hardlinking of IsoFile objects. * - * This function has to establish an equivalence and order relation: + * If this function cannot accept one of the given stream types, then + * the decision must be delegated to + * iso_stream_cmp_ino(s1, s2, 1); + * This is also appropriate if one has reason to implement stream.cmp_ino() + * without having an own special comparison algorithm. + * + * With filter streams the decision whether the underlying chains of + * streams match should be delegated to + * iso_stream_cmp_ino(iso_stream_get_input_stream(s1, 0), + * iso_stream_get_input_stream(s2, 0), 0); + * + * The stream.cmp_ino() function has to establish an equivalence and order + * relation: * cmp_ino(A,A) == 0 * cmp_ino(A,B) == -cmp_ino(B,A) * if cmp_ino(A,B) == 0 && cmp_ino(B,C) == 0 then cmp_ino(A,C) == 0 * if cmp_ino(A,B) < 0 && cmp_ino(B,C) < 0 then cmp_ino(A,C) < 0 * * A big hazard to the last constraint are tests which do not apply to some - * types of streams. In this case for any A that is applicable and any B - * that is not applicable, cmp_ino(A,B) must have the same non-zero - * result. I.e. a pair of applicable and non-applicable streams must - * return that non-zero result before the test for a pair of applicable - * streams would happen. + * types of streams.Thus it is mandatory to let iso_stream_cmp_ino(s1,s2,1) + * decide in this case. * * A function s1.(*cmp_ino)() must only accept stream s2 if function * s2.(*cmp_ino)() would accept s1. Best is to accept only the own stream * type or to have the same function for a family of similar stream types. * - * If the function cannot accept one of the given stream types, then - * the decision must be delegated to - * iso_stream_cmp_ino(s1, s2, 1); - * This is also appropriate if one has reason to implement stream.cmp_ino() - * without special comparison algorithm. - * With filter streams the decision whether the underlying chains of - * streams match should be delegated to - * iso_stream_cmp_ino(iso_stream_get_input_stream(s1, 0), - * iso_stream_get_input_stream(s2, 0), 0); - * * @param s1 * The first stream to compare. Expect foreign stream types. * @param s2 @@ -967,6 +968,23 @@ struct IsoStream_Iface */ int (*cmp_ino)(IsoStream *s1, IsoStream *s2); + /** + * Produce a copy of a stream. It must be possible to operate both stream + * objects concurrently. + * + * @param old_stream + * The existing stream object to be copied + * @param new_stream + * Will return a pointer to the copy + * @param flag + * Bitfield for control purposes. 0 means normal behavior. + * + * @since 1.0.2 + * Present if .version is 4 or higher. + */ + int (*clone_stream)(IsoStream *old_stream, IsoStream **new_stream, + int flag); + }; #ifndef __cplusplus @@ -3639,23 +3657,39 @@ int iso_dir_iter_take(IsoDirIter *iter); /** * Removes a child from a directory during an iteration and unref() it. - * It's like iso_node_remove(), but to be used during a directory iteration. - * The node removed will be the last returned by the iteration. + * Like iso_node_remove(), but to be used during a directory iteration. + * The node removed will be the one returned by the previous iteration. * - * If you call this function twice without calling iso_dir_iter_next between - * them is not allowed and you will get an ISO_ERROR in second call. + * It is not allowed to call this function twice without calling + * iso_dir_iter_next inbetween. * * @return * 1 on succes, < 0 error * Possible errors: * ISO_NULL_POINTER, if iter is NULL - * ISO_ERROR, on wrong iter usage, for example by call this before + * ISO_ERROR, on wrong iter usage, for example by calling this before * iso_dir_iter_next. * * @since 0.6.2 */ int iso_dir_iter_remove(IsoDirIter *iter); +/** + * Removes a node by iso_node_remove() or iso_dir_iter_remove(). If the node + * is a directory then the whole tree of nodes underneath is removed too. + * + * @param node + * The node to be removed. + * @param iter + * If not NULL, then the node will be removed by iso_dir_iter_remove(iter) + * else it will be removed by iso_node_remove(node). + * @return + * 1 is success, <0 indicates error + * + * @since 1.0.2 + */ +int iso_node_remove_tree(IsoNode *node, IsoDirIter *boss_iter); + /** * @since 0.6.4 @@ -4392,6 +4426,45 @@ int iso_tree_add_new_cut_out_node(IsoImage *image, IsoDir *parent, off_t offset, off_t size, IsoNode **node); +/** + * >>> INCOMPLETLY IMPLEMENTED YET. DO NOT USE ! + * + * Create a copy of the given node under a different path. If the node is + * actually a directory then clone its whole subtree. + * This call may fail because an IsoFile is encountered which gets fed by an + * IsoStream which cannot be cloned. See also IsoStream_Iface method + * clone_stream(). + * Surely clonable node types are: + * IsoDir, + * >>> IsoSymlink, + * >>> IsoSpecial, + * IsoFile from a loaded ISO image without filter streams, + * >>> IsoFile referring to local filesystem files without filter streams. + * Silently ignored are nodes of type IsoBoot. + * An IsoFile node with filter streams can be cloned if all those filters + * are clonable and the node would be clonable without filter. + * Clonable filter streams are created by: + * iso_file_add_zisofs_filter() + * iso_file_add_gzip_filter() + * iso_file_add_external_filter() + * + * @param node + * The node to be cloned. + * @param new_parent + * The existing directory node where to insert the cloned node. + * @param new_name + * The name for the cloned node. It must not yet exist in new_parent. + * @param new_node + * Will return a reference to the newly created clone. + * @param flag + * Unused yet. Submit 0. + * + * @since 1.0.2 + */ +int iso_tree_clone(IsoNode *node, + IsoDir *new_parent, char *new_name, IsoNode **new_node, + int flag); + /** * Add the contents of a dir to a given directory of the iso tree. * @@ -5191,6 +5264,30 @@ char *iso_stream_get_source_path(IsoStream *stream, int flag); */ int iso_stream_cmp_ino(IsoStream *s1, IsoStream *s2, int flag); + +/** + * Produce a copy of a stream. It must be possible to operate both stream + * objects concurrently. The success of this function depends on the + * existence of a IsoStream_Iface.clone_stream() method with the stream + * and with its eventual subordinate streams. + * See iso_tree_clone() for a list of surely clonable built-in streams. + * + * @param old_stream + * The existing stream object to be copied + * @param new_stream + * Will return a pointer to the copy + * @param flag + * Bitfield for control purposes. Submit 0 for now. + * @return + * >0 means success + * ISO_STREAM_NO_CLONE is issued if no .clone_stream() exists + * other error return values < 0 may occur depending on kind of stream + * + * @since 1.0.2 + */ +int iso_stream_clone(IsoStream *old_stream, IsoStream **new_stream, int flag); + + /* --------------------------------- AAIP --------------------------------- */ /** @@ -6496,6 +6593,9 @@ int iso_md5_match(char first_md5[16], char second_md5[16]); (FAILURE, HIGH, -373) */ #define ISO_NAME_NEEDS_TRANSL 0xE830FE8B +/** Data file input stream object offers no cloning method + (FAILURE, HIGH, -374) */ +#define ISO_STREAM_NO_CLONE 0xE830FE8A /* Internal developer note: Place new error codes directly above this comment. diff --git a/libisofs/libisofs.ver b/libisofs/libisofs.ver index 3a5789d..c79dff4 100644 --- a/libisofs/libisofs.ver +++ b/libisofs/libisofs.ver @@ -166,6 +166,7 @@ iso_node_get_xinfo; iso_node_lookup_attr; iso_node_ref; iso_node_remove; +iso_node_remove_tree; iso_node_remove_xinfo; iso_node_set_acl_text; iso_node_set_atime; @@ -210,6 +211,7 @@ iso_set_local_charset; iso_set_msgs_severities; iso_sev_to_text; iso_special_get_dev; +iso_stream_clone; iso_stream_close; iso_stream_cmp_ino; iso_stream_get_external_filter; @@ -235,6 +237,7 @@ iso_tree_add_new_node; iso_tree_add_new_special; iso_tree_add_new_symlink; iso_tree_add_node; +iso_tree_clone; iso_tree_get_follow_symlinks; iso_tree_get_ignore_hidden; iso_tree_get_ignore_special; diff --git a/libisofs/messages.c b/libisofs/messages.c index aa5c5af..d86885b 100644 --- a/libisofs/messages.c +++ b/libisofs/messages.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso + * Copyright (c) 2009 - 2011 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 @@ -363,6 +364,8 @@ const char *iso_error_to_msg(int errcode) return "Displacement offset leads outside 32 bit range"; case ISO_NAME_NEEDS_TRANSL: return "File name cannot be written into ECMA-119 untranslated"; + case ISO_STREAM_NO_CLONE: + return "Data file input stream object offers no cloning method"; default: return "Unknown error"; } diff --git a/libisofs/node.c b/libisofs/node.c index 6d09ad5..b953bbb 100644 --- a/libisofs/node.c +++ b/libisofs/node.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2009 Thomas Schmitt + * Copyright (c) 2009 - 2011 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 @@ -686,6 +686,36 @@ int iso_node_remove(IsoNode *node) return ret; } +/* API */ +int iso_node_remove_tree(IsoNode *node, IsoDirIter *boss_iter) +{ + IsoDirIter *iter = NULL; + IsoNode *sub_node; + int ret; + + if (node->type != LIBISO_DIR) { + ret = iso_dir_get_children((IsoDir *) node, &iter); + if (ret < 0) + goto ex; + while(1) { + ret = iso_dir_iter_next(iter, &sub_node); + if (ret == 0) + break; + ret = iso_node_remove_tree(sub_node, iter); + if (ret < 0) + goto ex; + } + } + if (boss_iter != NULL) + ret = iso_dir_iter_remove(boss_iter); + else + ret = iso_node_remove(node); +ex:; + if (iter != NULL) + iso_dir_iter_free(iter); + return ret; +} + /* * Get the parent of the given iso tree node. No extra ref is added to the * returned directory, you must take your ref. with iso_node_ref() if you diff --git a/libisofs/node.h b/libisofs/node.h index 431ae3d..2cd431f 100644 --- a/libisofs/node.h +++ b/libisofs/node.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2009 Thomas Schmitt + * Copyright (c) 2009 - 2011 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 @@ -121,6 +121,7 @@ struct Iso_Dir IsoNode *children; /**< list of children. ptr to first child */ }; +/* IMPORTANT: Any change must be reflected by iso_tree_clone_file. */ struct Iso_File { IsoNode node; diff --git a/libisofs/rockridge_read.c b/libisofs/rockridge_read.c index b150922..495e357 100644 --- a/libisofs/rockridge_read.c +++ b/libisofs/rockridge_read.c @@ -443,7 +443,7 @@ int read_rr_PN(struct susp_sys_user_entry *pn, struct stat *st) } -/* AA is the field signature of AAIP versions < 2.0 +/* AA is the obsolete field signature of AAIP versions < 2.0 */ int read_aaip_AA(struct susp_sys_user_entry *sue, unsigned char **aa_string, size_t *aa_size, size_t *aa_len, @@ -514,7 +514,7 @@ int read_aaip_AA(struct susp_sys_user_entry *sue, } -/* AL is the obsolete field signature of AAIP versions >= 2.0 +/* AL is the field signature of AAIP versions >= 2.0 */ int read_aaip_AL(struct susp_sys_user_entry *sue, unsigned char **aa_string, size_t *aa_size, size_t *aa_len, diff --git a/libisofs/stream.c b/libisofs/stream.c index a0b13cc..5d5a59e 100644 --- a/libisofs/stream.c +++ b/libisofs/stream.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2009 Thomas Schmitt + * Copyright (c) 2009 - 2011 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 @@ -157,8 +157,60 @@ int fsrc_update_size(IsoStream *stream) return ISO_SUCCESS; } +IsoStream *fsrc_get_input_stream(IsoStream *stream, int flag) +{ + return NULL; +} + +int fsrc_cmp_ino(IsoStream *s1, IsoStream *s2) +{ + int ret; + + /* <<< provisory */ + ret = iso_stream_cmp_ino(s1, s2, 1); + + /* >>> find out whether both streams point to the same image file */; + + return ret; +} + +int fsrc_clone_stream(IsoStream *old_stream, IsoStream **new_stream, + int flag) +{ + FSrcStreamData *data, *new_data; + IsoStream *stream; + int ret; + + *new_stream = NULL; + stream = calloc(1, sizeof(IsoStream)); + if (stream == NULL) + return ISO_OUT_OF_MEM; + new_data = calloc(1, sizeof(FSrcStreamData)); + if (new_data == NULL) { + free((char *) stream); + return ISO_OUT_OF_MEM; + } + *new_stream = stream; + data = (FSrcStreamData*) old_stream->data; + stream->class = old_stream->class; + stream->refcount = 1; + stream->data = new_data; + + ret = iso_ifs_source_clone(data->src, &(new_data->src), 0); + if (ret < 0) { + free((char *) stream); + free((char *) new_data); + return ret; + } + new_data->dev_id = data->dev_id; + new_data->ino_id = data->ino_id; + new_data->size = data->size; + + return ISO_SUCCESS; +} + IsoStreamIface fsrc_stream_class = { - 1, /* update_size is defined for this stream */ + 4, /* .clone_stream() is defined for this stream */ "fsrc", fsrc_open, fsrc_close, @@ -167,7 +219,10 @@ IsoStreamIface fsrc_stream_class = { fsrc_is_repeatable, fsrc_get_id, fsrc_free, - fsrc_update_size + fsrc_update_size, + fsrc_get_input_stream, + fsrc_cmp_ino, + fsrc_clone_stream }; int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream) @@ -924,3 +979,42 @@ ex:; iso_md5_end(&ctx, md5); return res; } + +/* API */ +int iso_stream_clone(IsoStream *old_stream, IsoStream **new_stream, int flag) +{ + int ret; + + if (old_stream->class->version < 4) + return ISO_STREAM_NO_CLONE; + ret = old_stream->class->clone_stream(old_stream, new_stream, 0); + return ret; +} + +int iso_stream_clone_filter_common(IsoStream *old_stream, + IsoStream **new_stream, + IsoStream **new_input, int flag) +{ + IsoStream *stream, *input_stream; + int ret; + + *new_stream = NULL; + *new_input = NULL; + input_stream = iso_stream_get_input_stream(old_stream, 0); + if (input_stream == NULL) + return ISO_STREAM_NO_CLONE; + stream = calloc(1, sizeof(IsoStream)); + if (stream == NULL) + return ISO_OUT_OF_MEM; + ret = iso_stream_clone(input_stream, new_input, 0); + if (ret < 0) { + free((char *) stream); + return ret; + } + stream->class = old_stream->class; + stream->refcount = 1; + stream->data = NULL; + *new_stream = stream; + return ISO_SUCCESS; +} + diff --git a/libisofs/stream.h b/libisofs/stream.h index 8bc43e0..590a8f2 100644 --- a/libisofs/stream.h +++ b/libisofs/stream.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2009 Thomas Schmitt + * Copyright (c) 2009 - 2011 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 @@ -15,6 +15,7 @@ */ #include "fsource.h" +/* IMPORTANT: Any change must be reflected by fsrc_clone_stream */ typedef struct { IsoFileSource *src; @@ -94,5 +95,20 @@ int iso_stream_read_buffer(IsoStream *stream, char *buf, size_t count, int iso_stream_make_md5(IsoStream *stream, char md5[16], int flag); +/** + * Create a clone of the input stream of old_stream and a roughly initialized + * clone of old_stream which has the same class and refcount 1. Its data + * pointer will be NULL and needs to be filled by an expert which knows how + * to clone the data of old_stream. + * @param old_stream The existing stream which is in process of cloning + * @param new_stream Will return the uninitialized memory object which shall + * later become the clone of old_stream. + * @param new_input The clone of the input stream of old stream. + * @param flag Submit 0 for now. + * @return ISO_SUCCESS or an error code <0 + */ +int iso_stream_clone_filter_common(IsoStream *old_stream, + IsoStream **new_stream, + IsoStream **new_input, int flag); #endif /*STREAM_H_*/ diff --git a/libisofs/tree.c b/libisofs/tree.c index fb98dfd..d0558cf 100644 --- a/libisofs/tree.c +++ b/libisofs/tree.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso + * Copyright (c) 2011 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 @@ -993,3 +994,100 @@ char *iso_tree_get_node_path(IsoNode *node) return strdup(path); } } + +/* ------------------------- tree cloning ------------------------------ */ + +static +int iso_tree_clone_dir(IsoDir *old_dir, + IsoDir *new_parent, char *new_name, IsoNode **new_node, + int flag) +{ + IsoDir *new_dir = NULL; + IsoNode *sub_node = NULL, *new_sub_node = NULL; + IsoDirIter *iter = NULL; + int ret; + + *new_node = NULL; + + ret = iso_tree_add_new_dir(new_parent, new_name, &new_dir); + if (ret < 0) + return ret; + *new_node = (IsoNode *) new_dir; + + ret = iso_dir_get_children(old_dir, &iter); + if (ret < 0) + goto ex; + while(1) { + ret = iso_dir_iter_next(iter, &sub_node); + if (ret == 0) + break; + ret = iso_tree_clone(sub_node, new_dir, sub_node->name, &new_sub_node, + 0); + if (ret < 0) + goto ex; + } + ret = ISO_SUCCESS; +ex:; + if (iter != NULL) + iso_dir_iter_free(iter); + if (ret < 0 && new_dir != NULL) { + iso_node_remove_tree((IsoNode *) new_dir, NULL); + *new_node = NULL; + } + return ret; +} + +static +int iso_tree_clone_file(IsoFile *old_file, + IsoDir *new_parent, char *new_name, IsoNode **new_node, + int flag) +{ + IsoStream *new_stream = NULL; + IsoFile *new_file = NULL; + int ret; + + *new_node = NULL; + + ret = iso_stream_clone(old_file->stream, &new_stream, 0); + if (ret < 0) + return ret; + + ret = iso_tree_add_new_file(new_parent, new_name, new_stream, &new_file); + if (ret < 0) + goto ex; + new_file->sort_weight = old_file->sort_weight; + *new_node = (IsoNode *) new_file; + ret = ISO_SUCCESS; +ex:; + if (new_stream != NULL) + iso_stream_unref(new_stream); + return ret; +} + +/* API */ +int iso_tree_clone(IsoNode *node, + IsoDir *new_parent, char *new_name, IsoNode **new_node, + int flag) +{ + int ret = ISO_SUCCESS; + + if (iso_dir_get_node(new_parent, new_name, NULL) == 1) + return ISO_NODE_NAME_NOT_UNIQUE; + + /* >>> clone particular node types */; + if (node->type == LIBISO_DIR) { + ret = iso_tree_clone_dir((IsoDir *) node, new_parent, new_name, + new_node, 0); + } else if (node->type == LIBISO_FILE) { + ret = iso_tree_clone_file((IsoFile *) node, new_parent, new_name, + new_node, 0); + } else if (node->type == LIBISO_SYMLINK) { + /* >>> */; + } else if (node->type == LIBISO_SPECIAL) { + /* >>> */; + } else if (node->type == LIBISO_BOOT) { + ret = ISO_SUCCESS; /* API says they are silently ignored */ + } + return ret; +} +