From d455f9b5403f8d4646b86bf9210638570b1e5648 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Sat, 8 Mar 2008 21:45:19 +0100 Subject: [PATCH] Add support for cut-out files. --- libisofs/builder.c | 5 +- libisofs/builder.h | 3 +- libisofs/libisofs.h | 46 ++++++++++- libisofs/stream.c | 190 +++++++++++++++++++++++++++++++++++++++++++- libisofs/stream.h | 10 +++ libisofs/tree.c | 86 +++++++++++++++++++- 6 files changed, 331 insertions(+), 9 deletions(-) diff --git a/libisofs/builder.c b/libisofs/builder.c index 9dbea87..1b00dfd 100644 --- a/libisofs/builder.c +++ b/libisofs/builder.c @@ -52,12 +52,13 @@ int default_create_file(IsoNodeBuilder *builder, IsoImage *image, if (ret < 0) { return ret; } + + /* take a ref to the src, as stream has taken our ref */ + iso_file_source_ref(src); name = iso_file_source_get_name(src); ret = iso_node_new_file(name, stream, &node); if (ret < 0) { - /* the stream has taken our ref to src, so we need to add one */ - iso_file_source_ref(src); iso_stream_unref(stream); free(name); return ret; diff --git a/libisofs/builder.h b/libisofs/builder.h index e0d3ff1..34bc6e5 100644 --- a/libisofs/builder.h +++ b/libisofs/builder.h @@ -34,8 +34,7 @@ struct Iso_Node_Builder * In that case, if the implementation can't do the conversion, it * should fail propertly. * - * On sucess, the ref. to src will be owned by file, so you musn't - * unref it. + * Note that the src is never unref, so you need to free it. * * @return * 1 on success, < 0 on error diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 848bf70..e2decce 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -2805,6 +2805,44 @@ int iso_tree_add_node(IsoImage *image, IsoDir *parent, const char *path, int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name, const char *path, IsoNode **node); +/** + * Add a new node to the image tree, from an existing file, and with the + * given name, that must not exist on dir. The node will be cut-out to the + * submitted size, and its contents will be read from the given offset. This + * function is thus suitable for adding only a piece of a file to the image. + * + * @param image + * The image + * @param parent + * The directory in the image tree where the node will be added. + * @param name + * The name that the node will have on image. + * @param path + * The path of the file to add in the filesystem. For now only regular + * files and symlinks to regular files are supported. + * @param offset + * Offset on the given file from where to start reading data. + * @param size + * Max size of the file. + * @param node + * place where to store a pointer to the newly added file. No + * extra ref is addded, so you will need to call iso_node_ref() if you + * really need it. You can pass NULL in this parameter if you don't need + * the pointer. + * @return + * number of nodes in parent if success, < 0 otherwise + * Possible errors: + * ISO_NULL_POINTER, if image, parent or path are NULL + * ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists + * ISO_OUT_OF_MEM + * + * @since 0.6.4 + */ +int iso_tree_add_new_cut_out_node(IsoImage *image, IsoDir *parent, + const char *name, const char *path, + off_t offset, off_t size, + IsoNode **node); + /** * Add the contents of a dir to a given directory of the iso tree. * @@ -3639,10 +3677,16 @@ void iso_stream_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id, /** * File path break specification constraints and will be ignored - * (HINT,MEDIUM, -141) + * (HINT,MEDIUM, -144) */ #define ISO_FILE_IMGPATH_WRONG 0xC020FF70 +/** + * Offset greater than file size (FAILURE,HIGH, -145) + * @since 0.6.4 + */ +#define ISO_FILE_OFFSET_TOO_BIG 0xE830FF6A + /** Charset conversion error (FAILURE,HIGH, -256) */ #define ISO_CHARSET_CONV_ERROR 0xE830FF00 diff --git a/libisofs/stream.c b/libisofs/stream.c index 6058e89..dd747cf 100644 --- a/libisofs/stream.c +++ b/libisofs/stream.c @@ -17,6 +17,7 @@ ino_t serial_id = (ino_t)1; ino_t mem_serial_id = (ino_t)1; +ino_t cut_out_serial_id = (ino_t)1; typedef struct { @@ -175,7 +176,7 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream) return ISO_OUT_OF_MEM; } data = malloc(sizeof(FSrcStreamData)); - if (str == NULL) { + if (data == NULL) { free(str); return ISO_OUT_OF_MEM; } @@ -212,6 +213,193 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream) return ISO_SUCCESS; } +struct cut_out_stream +{ + IsoFileSource *src; + + /* key for file identification inside filesystem */ + dev_t dev_id; + ino_t ino_id; + off_t offset; /**< offset where read begins */ + off_t size; /**< size of this file */ + off_t pos; /* position on the file for read */ +}; + +static +int cut_out_open(IsoStream *stream) +{ + int ret; + struct stat info; + IsoFileSource *src; + struct cut_out_stream *data; + + if (stream == NULL) { + return ISO_NULL_POINTER; + } + + data = stream->data; + src = data->src; + ret = iso_file_source_stat(data->src, &info); + if (ret < 0) { + return ret; + } + ret = iso_file_source_open(src); + if (ret < 0) { + return ret; + } + + { + off_t ret; + if (data->offset > info.st_size) { + /* file is smaller than expected */ + ret = iso_file_source_lseek(src, info.st_size, 0); + } else { + ret = iso_file_source_lseek(src, data->offset, 0); + } + if (ret < 0) { + return (int) ret; + } + } + data->pos = 0; + if (data->offset + data->size > info.st_size) { + return 3; /* file smaller than expected */ + } else { + return ISO_SUCCESS; + } +} + +static +int cut_out_close(IsoStream *stream) +{ + IsoFileSource *src; + if (stream == NULL) { + return ISO_NULL_POINTER; + } + src = ((struct cut_out_stream*)stream->data)->src; + return iso_file_source_close(src); +} + +static +off_t cut_out_get_size(IsoStream *stream) +{ + struct cut_out_stream *data = stream->data; + return data->size; +} + +static +int cut_out_read(IsoStream *stream, void *buf, size_t count) +{ + struct cut_out_stream *data = stream->data; + count = (size_t)MIN(data->size - data->pos, count); + if (count == 0) { + return 0; + } + return iso_file_source_read(data->src, buf, count); +} + +static +int cut_out_is_repeatable(IsoStream *stream) +{ + /* reg files are always repeatable */ + return 1; +} + +static +void cut_out_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id, + ino_t *ino_id) +{ + FSrcStreamData *data; + IsoFilesystem *fs; + + data = (FSrcStreamData*)stream->data; + fs = iso_file_source_get_filesystem(data->src); + + *fs_id = fs->get_id(fs); + *dev_id = data->dev_id; + *ino_id = data->ino_id; +} + +static +void cut_out_free(IsoStream *stream) +{ + struct cut_out_stream *data = stream->data; + iso_file_source_unref(data->src); + free(data); +} + +IsoStreamIface cut_out_stream_class = { + 0, + "cout", + cut_out_open, + cut_out_close, + cut_out_get_size, + cut_out_read, + cut_out_is_repeatable, + cut_out_get_id, + cut_out_free +}; + +int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size, + IsoStream **stream) +{ + int r; + struct stat info; + IsoStream *str; + struct cut_out_stream *data; + + if (src == NULL || stream == NULL) { + return ISO_NULL_POINTER; + } + if (size == 0) { + return ISO_WRONG_ARG_VALUE; + } + + r = iso_file_source_stat(src, &info); + if (r < 0) { + return r; + } + if (!S_ISREG(info.st_mode)) { + return ISO_WRONG_ARG_VALUE; + } + if (offset > info.st_size) { + return ISO_FILE_OFFSET_TOO_BIG; + } + + /* check for read access to contents */ + r = iso_file_source_access(src); + if (r < 0) { + return r; + } + + str = malloc(sizeof(IsoStream)); + if (str == NULL) { + return ISO_OUT_OF_MEM; + } + data = malloc(sizeof(struct cut_out_stream)); + if (data == NULL) { + free(str); + return ISO_OUT_OF_MEM; + } + + /* take a new ref to IsoFileSource */ + data->src = src; + iso_file_source_ref(src); + + data->offset = offset; + data->size = MIN(info.st_size - offset, size); + + /* get the id numbers */ + data->dev_id = (dev_t) 0; + data->ino_id = cut_out_serial_id++; + + str->refcount = 1; + str->data = data; + str->class = &cut_out_stream_class; + + *stream = str; + return ISO_SUCCESS; +} + typedef struct diff --git a/libisofs/stream.h b/libisofs/stream.h index 804faf1..3893785 100644 --- a/libisofs/stream.h +++ b/libisofs/stream.h @@ -33,6 +33,16 @@ void iso_stream_get_file_name(IsoStream *stream, char *name); */ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream); +/** + * Create a new stream to read a chunk of an IsoFileSource.. + * The stream will add a ref. to the IsoFileSource. + * + * @return + * 1 sucess, < 0 error + */ +int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size, + IsoStream **stream); + /** * Create a stream for reading from a arbitrary memory buffer. * When the Stream refcount reach 0, the buffer is free(3). diff --git a/libisofs/tree.c b/libisofs/tree.c index a53e62d..624539a 100644 --- a/libisofs/tree.c +++ b/libisofs/tree.c @@ -582,13 +582,14 @@ int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name, } result = image->builder->create_node(image->builder, image, file, &new); - if (result < 0) { - return result; - } /* free the file */ iso_file_source_unref(file); + if (result < 0) { + return result; + } + result = iso_node_set_name(new, name); if (result < 0) { iso_node_unref(new); @@ -603,6 +604,85 @@ int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name, return iso_dir_insert(parent, new, pos, ISO_REPLACE_NEVER); } +int iso_tree_add_new_cut_out_node(IsoImage *image, IsoDir *parent, + const char *name, const char *path, + off_t offset, off_t size, + IsoNode **node) +{ + int result; + struct stat info; + IsoFilesystem *fs; + IsoFileSource *src; + IsoFile *new; + IsoNode **pos; + IsoStream *stream; + + if (image == NULL || parent == NULL || name == NULL || path == NULL) { + return ISO_NULL_POINTER; + } + + if (node) { + *node = NULL; + } + + /* find place where to insert */ + result = iso_dir_exists(parent, name, &pos); + if (result) { + /* a node with same name already exists */ + return ISO_NODE_NAME_NOT_UNIQUE; + } + + fs = image->fs; + result = fs->get_by_path(fs, path, &src); + if (result < 0) { + return result; + } + + result = iso_file_source_stat(src, &info); + if (result < 0) { + iso_file_source_unref(src); + return result; + } + if (!S_ISREG(info.st_mode)) { + return ISO_WRONG_ARG_VALUE; + } + if (offset >= info.st_size) { + return ISO_WRONG_ARG_VALUE; + } + + /* force regular file */ + result = image->builder->create_file(image->builder, image, src, &new); + + /* free the file */ + iso_file_source_unref(src); + + if (result < 0) { + return result; + } + + /* replace file iso stream with a cut-out-stream */ + result = iso_cut_out_stream_new(src, offset, size, &stream); + if (result < 0) { + iso_node_unref((IsoNode*)new); + return result; + } + iso_stream_unref(new->stream); + new->stream = stream; + + result = iso_node_set_name((IsoNode*)new, name); + if (result < 0) { + iso_node_unref((IsoNode*)new); + return result; + } + + if (node) { + *node = (IsoNode*)new; + } + + /* finally, add node to parent */ + return iso_dir_insert(parent, (IsoNode*)new, pos, ISO_REPLACE_NEVER); +} + static int check_excludes(IsoImage *image, const char *path) {