From 0c8ae84e598fff7b40ca2958dc46dc31fe08ad9a Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Sun, 9 Mar 2008 14:42:15 +0000 Subject: [PATCH] Switch to Vreixo development branch 386 --- libisofs/branches/thomas/libisofs/builder.c | 5 +- libisofs/branches/thomas/libisofs/builder.h | 3 +- libisofs/branches/thomas/libisofs/fs_image.c | 57 +++++- libisofs/branches/thomas/libisofs/fs_local.c | 49 ++++- libisofs/branches/thomas/libisofs/fsource.c | 6 + libisofs/branches/thomas/libisofs/libisofs.h | 125 +++++++++++- libisofs/branches/thomas/libisofs/stream.c | 190 ++++++++++++++++++- libisofs/branches/thomas/libisofs/stream.h | 10 + libisofs/branches/thomas/libisofs/tree.c | 161 +++++++++++++++- 9 files changed, 588 insertions(+), 18 deletions(-) diff --git a/libisofs/branches/thomas/libisofs/builder.c b/libisofs/branches/thomas/libisofs/builder.c index 9dbea875..1b00dfd8 100644 --- a/libisofs/branches/thomas/libisofs/builder.c +++ b/libisofs/branches/thomas/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/branches/thomas/libisofs/builder.h b/libisofs/branches/thomas/libisofs/builder.h index e0d3ff10..34bc6e54 100644 --- a/libisofs/branches/thomas/libisofs/builder.h +++ b/libisofs/branches/thomas/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/branches/thomas/libisofs/fs_image.c b/libisofs/branches/thomas/libisofs/fs_image.c index 8394cfda..cbe991f0 100644 --- a/libisofs/branches/thomas/libisofs/fs_image.c +++ b/libisofs/branches/thomas/libisofs/fs_image.c @@ -632,6 +632,60 @@ int ifs_read(IsoFileSource *src, void *buf, size_t count) return read; } +static +off_t ifs_lseek(IsoFileSource *src, off_t offset, int flag) +{ + ImageFileSourceData *data; + + if (src == NULL) { + return (off_t)ISO_NULL_POINTER; + } + if (offset < (off_t)0) { + return (off_t)ISO_WRONG_ARG_VALUE; + } + + data = src->data; + + if (!data->opened) { + return (off_t)ISO_FILE_NOT_OPENED; + } else if (data->opened != 1) { + return (off_t)ISO_FILE_IS_DIR; + } + + switch (flag) { + case 0: /* SEEK_SET */ + data->data.offset = offset; + break; + case 1: /* SEEK_CUR */ + data->data.offset += offset; + break; + case 2: /* SEEK_END */ + /* do this make sense? */ + data->data.offset = data->info.st_size + offset; + break; + default: + return (off_t)ISO_WRONG_ARG_VALUE; + } + + if (data->data.offset % BLOCK_SIZE != 0) { + /* we need to buffer the block */ + uint32_t block; + _ImageFsData *fsdata; + + if (data->data.offset < data->info.st_size) { + int ret; + fsdata = data->fs->data; + block = data->block + (data->data.offset / BLOCK_SIZE); + ret = fsdata->src->read_block(fsdata->src, block, + data->data.content); + if (ret < 0) { + return (off_t)ret; + } + } + } + return data->data.offset; +} + static int ifs_readdir(IsoFileSource *src, IsoFileSource **child) { @@ -774,7 +828,8 @@ IsoFileSourceIface ifs_class = { ifs_readdir, ifs_readlink, ifs_get_filesystem, - ifs_free + ifs_free, + ifs_lseek }; /** diff --git a/libisofs/branches/thomas/libisofs/fs_local.c b/libisofs/branches/thomas/libisofs/fs_local.c index bf37337f..43a2a930 100644 --- a/libisofs/branches/thomas/libisofs/fs_local.c +++ b/libisofs/branches/thomas/libisofs/fs_local.c @@ -304,6 +304,52 @@ int lfs_read(IsoFileSource *src, void *buf, size_t count) } } +static +off_t lfs_lseek(IsoFileSource *src, off_t offset, int flag) +{ + _LocalFsFileSource *data; + int whence; + + if (src == NULL) { + return (off_t)ISO_NULL_POINTER; + } + switch (flag) { + case 0: + whence = SEEK_SET; break; + case 1: + whence = SEEK_CUR; break; + case 2: + whence = SEEK_END; break; + default: + return (off_t)ISO_WRONG_ARG_VALUE; + } + + data = src->data; + switch (data->openned) { + case 1: /* not dir */ + { + off_t ret; + ret = lseek(data->info.fd, offset, whence); + if (ret < 0) { + /* error on read */ + switch (errno) { + case ESPIPE: + ret = (off_t)ISO_FILE_ERROR; + break; + default: + ret = (off_t)ISO_ERROR; + break; + } + } + return ret; + } + case 2: /* directory */ + return (off_t)ISO_FILE_IS_DIR; + default: + return (off_t)ISO_FILE_NOT_OPENED; + } +} + static int lfs_readdir(IsoFileSource *src, IsoFileSource **child) { @@ -433,7 +479,8 @@ IsoFileSourceIface lfs_class = { lfs_readdir, lfs_readlink, lfs_get_filesystem, - lfs_free + lfs_free, + lfs_lseek }; /** diff --git a/libisofs/branches/thomas/libisofs/fsource.c b/libisofs/branches/thomas/libisofs/fsource.c index b6e5c5f6..4b743501 100644 --- a/libisofs/branches/thomas/libisofs/fsource.c +++ b/libisofs/branches/thomas/libisofs/fsource.c @@ -92,6 +92,12 @@ int iso_file_source_read(IsoFileSource *src, void *buf, size_t count) return src->class->read(src, buf, count); } +inline +off_t iso_file_source_lseek(IsoFileSource *src, off_t offset, int flag) +{ + return src->class->lseek(src, offset, flag); +} + inline int iso_file_source_readdir(IsoFileSource *src, IsoFileSource **child) { diff --git a/libisofs/branches/thomas/libisofs/libisofs.h b/libisofs/branches/thomas/libisofs/libisofs.h index a5bd199b..30338f1c 100644 --- a/libisofs/branches/thomas/libisofs/libisofs.h +++ b/libisofs/branches/thomas/libisofs/libisofs.h @@ -622,6 +622,26 @@ struct IsoFileSource_Iface * Use iso_file_source_unref() instead. */ void (*free)(IsoFileSource *src); + + /** + * Repositions the offset of the IsoFileSource (must be opened) to the + * given offset according to the value of flag. + * + * @param offset + * in bytes + * @param flag + * 0 The offset is set to offset bytes (SEEK_SET) + * 1 The offset is set to its current location plus offset bytes + * (SEEK_CUR) + * 2 The offset is set to the size of the file plus offset bytes + * (SEEK_END). + * @return + * Absolute offset posistion on the file, or < 0 on error. Cast the + * returning value to int to get a valid libisofs error. + * + * @since 0.6.4 + */ + off_t (*lseek)(IsoFileSource *src, off_t offset, int flag); /* * TODO #00004 Add a get_mime_type() function. @@ -2131,8 +2151,8 @@ void iso_dir_iter_free(IsoDirIter *iter); * It's like iso_node_take(), but to be used during a directory iteration. * The node removed will be the last returned by the iteration. * - * The behavior on two call to this function without calling iso_dir_iter_next - * between then is undefined, and should never occur. (TODO protect against this?) + * 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. * * @return * 1 on succes, < 0 error @@ -2150,8 +2170,8 @@ int iso_dir_iter_take(IsoDirIter *iter); * 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. * - * The behavior on two call to this function without calling iso_tree_iter_next - * between then is undefined, and should never occur. (TODO protect against this?) + * 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. * * @return * 1 on succes, < 0 error @@ -2469,10 +2489,36 @@ int iso_node_get_old_image_lba(IsoNode *node, uint32_t *lba, int flag); */ int iso_tree_add_new_dir(IsoDir *parent, const char *name, IsoDir **dir); -/* - TODO #00007 expose Stream and this function: - int iso_tree_add_new_file(IsoDir *parent, const char *name, stream, file) +/** + * Add a new regular file to the iso tree. Permissions are set to 0444, + * owner and hidden atts are taken from parent. You can modify any of them + * later. + * + * @param parent + * the dir where the new file will be created + * @param name + * name for the new file. If a node with same name already exists on + * parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE. + * @param stream + * IsoStream for the contents of the file. The reference will be taken + * by the newly created file, you will need to take an extra ref to it + * if you need it. + * @param file + * place where to store a pointer to the newly created 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 parent, name or dest 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_file(IsoDir *parent, const char *name, IsoStream *stream, + IsoFile **file); /** * Add a new symlink to the directory tree. Permissions are set to 0777, @@ -2760,6 +2806,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. * @@ -3190,6 +3274,25 @@ int iso_file_source_close(IsoFileSource *src); */ int iso_file_source_read(IsoFileSource *src, void *buf, size_t count); +/** + * Repositions the offset of the given IsoFileSource (must be opened) to the + * given offset according to the value of flag. + * + * @param offset + * in bytes + * @param flag + * 0 The offset is set to offset bytes (SEEK_SET) + * 1 The offset is set to its current location plus offset bytes + * (SEEK_CUR) + * 2 The offset is set to the size of the file plus offset bytes + * (SEEK_END). + * @return + * Absolute offset posistion on the file, or < 0 on error. Cast the + * returning value to int to get a valid libisofs error. + * @since 0.6.4 + */ +off_t iso_file_source_lseek(IsoFileSource *src, off_t offset, int flag); + /** * Read a directory. * @@ -3575,10 +3678,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/branches/thomas/libisofs/stream.c b/libisofs/branches/thomas/libisofs/stream.c index 6058e894..dd747cf2 100644 --- a/libisofs/branches/thomas/libisofs/stream.c +++ b/libisofs/branches/thomas/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/branches/thomas/libisofs/stream.h b/libisofs/branches/thomas/libisofs/stream.h index 804faf14..38937859 100644 --- a/libisofs/branches/thomas/libisofs/stream.h +++ b/libisofs/branches/thomas/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/branches/thomas/libisofs/tree.c b/libisofs/branches/thomas/libisofs/tree.c index 420b6113..624539a0 100644 --- a/libisofs/branches/thomas/libisofs/tree.c +++ b/libisofs/branches/thomas/libisofs/tree.c @@ -256,6 +256,81 @@ int iso_tree_add_new_special(IsoDir *parent, const char *name, mode_t mode, return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER); } +/** + * Add a new regular file to the iso tree. Permissions are set to 0444, + * owner and hidden atts are taken from parent. You can modify any of them + * later. + * + * @param parent + * the dir where the new file will be created + * @param name + * name for the new file. If a node with same name already exists on + * parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE. + * @param stream + * IsoStream for the contents of the file + * @param file + * place where to store a pointer to the newly created 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 parent, name or dest 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_file(IsoDir *parent, const char *name, IsoStream *stream, + IsoFile **file) +{ + int ret; + char *n; + IsoFile *node; + IsoNode **pos; + time_t now; + + if (parent == NULL || name == NULL || stream == NULL) { + return ISO_NULL_POINTER; + } + if (file) { + *file = NULL; + } + + /* find place where to insert */ + if (iso_dir_exists(parent, name, &pos)) { + /* a node with same name already exists */ + return ISO_NODE_NAME_NOT_UNIQUE; + } + + n = strdup(name); + ret = iso_node_new_file(n, stream, &node); + if (ret < 0) { + free(n); + return ret; + } + + /* permissions from parent */ + iso_node_set_permissions((IsoNode*)node, 0444); + iso_node_set_uid((IsoNode*)node, parent->node.uid); + iso_node_set_gid((IsoNode*)node, parent->node.gid); + iso_node_set_hidden((IsoNode*)node, parent->node.hidden); + + /* current time */ + now = time(NULL); + iso_node_set_atime((IsoNode*)node, now); + iso_node_set_ctime((IsoNode*)node, now); + iso_node_set_mtime((IsoNode*)node, now); + + if (file) { + *file = node; + } + + /* add to dir */ + return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER); +} + /** * Set whether to follow or not symbolic links when added a file from a source * to IsoImage. @@ -507,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); @@ -528,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) {