diff --git a/.bzrignore b/.bzrignore index 011722e..382935d 100644 --- a/.bzrignore +++ b/.bzrignore @@ -32,3 +32,4 @@ demo/iso demo/catbuffer demo/isoread demo/isocat +demo/isomodify diff --git a/Makefile.am b/Makefile.am index 4e82110..1cefbc9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -15,6 +15,7 @@ src_libisofs_la_SOURCES = \ src/error.h \ src/node.h \ src/node.c \ + src/tree.h \ src/tree.c \ src/image.h \ src/image.c \ @@ -58,7 +59,8 @@ noinst_PROGRAMS = \ demo/ecma119tree \ demo/iso \ demo/isoread \ - demo/isocat + demo/isocat \ + demo/isomodify demo_lsl_CPPFLAGS = -Isrc demo_lsl_LDADD = $(src_libisofs_la_OBJECTS) $(THREAD_LIBS) @@ -92,6 +94,10 @@ demo_isocat_CPPFLAGS = -Isrc demo_isocat_LDADD = $(src_libisofs_la_OBJECTS) $(THREAD_LIBS) demo_isocat_SOURCES = demo/iso_cat.c +demo_isomodify_CPPFLAGS = -Isrc +demo_isomodify_LDADD = $(src_libisofs_la_OBJECTS) $(THREAD_LIBS) +demo_isomodify_SOURCES = demo/iso_modify.c + ## Build unit test diff --git a/demo/iso_cat.c b/demo/iso_cat.c index bec54e2..cfe7bc8 100644 --- a/demo/iso_cat.c +++ b/demo/iso_cat.c @@ -27,6 +27,7 @@ int main(int argc, char **argv) IsoFileSource *file; struct stat info; IsoDataSource *src; + struct libiso_msgs *messenger; struct iso_read_opts opts = { 0, /* block */ 0, /* norock */ @@ -35,7 +36,6 @@ int main(int argc, char **argv) 0, /* uid; */ 0, /* gid; */ 0, /* mode */ - NULL, /* messenger */ "UTF-8" /* input_charset */ }; @@ -44,12 +44,12 @@ int main(int argc, char **argv) return 1; } - res = libiso_msgs_new(&opts.messenger, 0); + res = libiso_msgs_new(&messenger, 0); if (res <= 0) { printf ("Can't create messenger\n"); return 1; } - libiso_msgs_set_severities(opts.messenger, LIBISO_MSGS_SEV_NEVER, + libiso_msgs_set_severities(messenger, LIBISO_MSGS_SEV_NEVER, LIBISO_MSGS_SEV_ALL, "", 0); res = iso_data_source_new_from_file(argv[1], &src); @@ -58,7 +58,7 @@ int main(int argc, char **argv) return 1; } - res = iso_image_filesystem_new(src, &opts, &fs); + res = iso_image_filesystem_new(src, &opts, messenger, &fs); if (res < 0) { printf ("Error creating filesystem\n"); return 1; @@ -99,6 +99,6 @@ int main(int argc, char **argv) iso_file_source_unref(file); iso_filesystem_unref(fs); iso_data_source_unref(src); - libiso_msgs_destroy(&opts.messenger, 0); + libiso_msgs_destroy(&messenger, 0); return 0; } diff --git a/demo/iso_modify.c b/demo/iso_modify.c new file mode 100644 index 0000000..7914511 --- /dev/null +++ b/demo/iso_modify.c @@ -0,0 +1,116 @@ +/* + * Little program to show how to modify an iso image. + */ + +#include "libisofs.h" +#include "libburn/libburn.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +void usage(char **argv) +{ + printf("%s [OPTIONS] IMAGE DIRECTORY OUTPUT\n", argv[0]); +} + +int main(int argc, char **argv) +{ + int result; + IsoImage *image; + IsoDataSource *src; + struct burn_source *burn_src; + unsigned char buf[2048]; + FILE *fd; + Ecma119WriteOpts opts = { + 1, /* level */ + 1, /* rockridge */ + 0, /* omit_version_numbers */ + 0, /* allow_deep_paths */ + 0, /* sort files */ + 0, /* replace_dir_mode */ + 0, /* replace_file_mode */ + 0, /* replace_uid */ + 0, /* replace_gid */ + 0, /* dir_mode */ + 0, /* file_mode */ + 0, /* uid */ + 0, /* gid */ + NULL /* output charset */ + }; + struct iso_read_opts ropts = { + 0, /* block */ + 0, /* norock */ + 0, /* nojoliet */ + 0, /* preferjoliet */ + 0, /* uid; */ + 0, /* gid; */ + 0, /* mode */ + "UTF-8" /* input_charset */ + }; + + if (argc < 4) { + usage(argv); + return 1; + } + + fd = fopen(argv[3], "w"); + if (!fd) { + err(1, "error opening output file"); + } + + /* create the data source to accesss previous image */ + result = iso_data_source_new_from_file(argv[1], &src); + if (result < 0) { + printf ("Error creating data source\n"); + return 1; + } + + /* create the image context */ + result = iso_image_new("volume_id", &image); + if (result < 0) { + printf ("Error creating image\n"); + return 1; + } + iso_image_set_msgs_severities(image, "NEVER", "ALL", ""); + iso_tree_set_follow_symlinks(image, 0); + iso_tree_set_ignore_hidden(image, 0); + iso_tree_set_stop_on_error(image, 0); + + /* import previous image */ + result = iso_image_import(image, src, &ropts, NULL); + iso_data_source_unref(src); + if (result < 0) { + printf ("Error importing previous session %d\n", result); + return 1; + } + + /* add new dir */ + result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[2]); + if (result < 0) { + printf ("Error adding directory %d\n", result); + return 1; + } + + /* generate a new image with both previous and added contents */ + result = iso_image_create(image, &opts, &burn_src); + if (result < 0) { + printf ("Cant create image, error %d\n", result); + return 1; + } + + while (burn_src->read(burn_src, buf, 2048) == 2048) { + fwrite(buf, 1, 2048, fd); + } + fclose(fd); + burn_src->free_data(burn_src); + free(burn_src); + + iso_image_unref(image); + return 0; +} diff --git a/demo/iso_read.c b/demo/iso_read.c index 3ba3781..a4213ae 100644 --- a/demo/iso_read.c +++ b/demo/iso_read.c @@ -111,6 +111,7 @@ int main(int argc, char **argv) IsoImageFilesystem *fs; IsoDataSource *src; IsoFileSource *root; + struct libiso_msgs *messenger; struct iso_read_opts opts = { 0, /* block */ 0, /* norock */ @@ -119,7 +120,6 @@ int main(int argc, char **argv) 0, /* uid; */ 0, /* gid; */ 0, /* mode */ - NULL, /* messenger */ "UTF-8" /* input_charset */ }; @@ -128,12 +128,12 @@ int main(int argc, char **argv) return 1; } - result = libiso_msgs_new(&opts.messenger, 0); + result = libiso_msgs_new(&messenger, 0); if (result <= 0) { printf ("Can't create messenger\n"); return 1; } - libiso_msgs_set_severities(opts.messenger, LIBISO_MSGS_SEV_NEVER, + libiso_msgs_set_severities(messenger, LIBISO_MSGS_SEV_NEVER, LIBISO_MSGS_SEV_ALL, "", 0); result = iso_data_source_new_from_file(argv[1], &src); @@ -142,7 +142,7 @@ int main(int argc, char **argv) return 1; } - result = iso_image_filesystem_new(src, &opts, &fs); + result = iso_image_filesystem_new(src, &opts, messenger, &fs); if (result < 0) { printf ("Error creating filesystem\n"); return 1; @@ -160,6 +160,6 @@ int main(int argc, char **argv) fs->close(fs); iso_filesystem_unref((IsoFilesystem*)fs); iso_data_source_unref(src); - libiso_msgs_destroy(&opts.messenger, 0); - return 0; + libiso_msgs_destroy(&messenger, 0); + return 0; } diff --git a/src/fs_image.c b/src/fs_image.c index 7ebcbe6..a1e7d41 100644 --- a/src/fs_image.c +++ b/src/fs_image.c @@ -16,11 +16,14 @@ #include "ecma119.h" #include "messages.h" #include "rockridge.h" +#include "image.h" +#include "tree.h" #include #include #include #include +#include static int ifs_fs_open(IsoImageFilesystem *fs); @@ -334,7 +337,7 @@ int read_dir(ImageFileSourceData *data) } /* add to the child list */ - { + if (ret != 0) { struct child_list *node; node = malloc(sizeof(struct child_list)); if (node == NULL) { @@ -368,7 +371,7 @@ int ifs_open(IsoFileSource *src) return ISO_NULL_POINTER; } data = (ImageFileSourceData*)src->data; - + if (data->opened) { return ISO_FILE_ALREADY_OPENNED; } @@ -561,7 +564,7 @@ int ifs_readdir(IsoFileSource *src, IsoFileSource **child) /* free the first element of the list */ data->data.content = children->next; free(children); - + return ISO_SUCCESS; } @@ -891,6 +894,8 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, } } + //TODO convert link destinatiion to needed charset + } else { /* RR extensions are not read / used */ atts.st_mode = fsdata->mode; @@ -943,7 +948,7 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, ret = iso_file_source_new_ifs(fs, parent, (struct ecma119_dir_record*) buffer, src); - if (ret < 0) { + if (ret <= 0) { return ret; } @@ -1257,6 +1262,7 @@ void ifs_fs_free(IsoFilesystem *fs) free(data->biblio_file_id); free(data->input_charset); + free(data->local_charset); free(data); } @@ -1442,6 +1448,7 @@ int read_pvm(_ImageFsData *data, uint32_t block) } int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts, + struct libiso_msgs *messenger, IsoImageFilesystem **fs) { int ret; @@ -1477,7 +1484,7 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts, data->gid = opts->gid; data->uid = opts->uid; data->mode = opts->mode & ~S_IFMT; - data->messenger = opts->messenger; + data->messenger = messenger; data->input_charset = strdup(opts->input_charset); @@ -1608,3 +1615,273 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts, free(ifs); return ret; } + +static +int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image, + IsoFileSource *src, IsoNode **node) +{ + int result; + struct stat info; + IsoNode *new; + char *name; + ImageFileSourceData *data; + + if (builder == NULL || src == NULL || node == NULL || src->data == NULL) { + return ISO_NULL_POINTER; + } + + data = (ImageFileSourceData*)src->data; + + name = iso_file_source_get_name(src); + + /* get info about source */ + result = iso_file_source_lstat(src, &info); + if (result < 0) { + return result; + } + + new = NULL; + switch (info.st_mode & S_IFMT) { + case S_IFREG: + { + /* source is a regular file */ + IsoStream *stream; + IsoFile *file; + result = iso_file_source_stream_new(src, &stream); + if (result < 0) { + free(name); + return result; + } + /* take a ref to the src, as stream has taken our ref */ + iso_file_source_ref(src); + file = calloc(1, sizeof(IsoFile)); + if (file == NULL) { + free(name); + iso_stream_unref(stream); + return ISO_MEM_ERROR; + } + + /* the msblock is taken from the image */ + file->msblock = data->block; + + /* + * and we set the sort weight based on the block on image, to + * improve performance on image modifying. + */ + file->sort_weight = INT_MAX - data->block; + + file->stream = stream; + file->node.type = LIBISO_FILE; + new = (IsoNode*) file; + } + break; + case S_IFDIR: + { + /* source is a directory */ + new = calloc(1, sizeof(IsoDir)); + if (new == NULL) { + free(name); + return ISO_MEM_ERROR; + } + new->type = LIBISO_DIR; + } + break; + case S_IFLNK: + { + /* source is a symbolic link */ + char dest[PATH_MAX]; + IsoSymlink *link; + + result = iso_file_source_readlink(src, dest, PATH_MAX); + if (result < 0) { + free(name); + return result; + } + link = malloc(sizeof(IsoSymlink)); + if (link == NULL) { + free(name); + return ISO_MEM_ERROR; + } + link->dest = strdup(dest); + link->node.type = LIBISO_SYMLINK; + new = (IsoNode*) link; + } + break; + case S_IFSOCK: + case S_IFBLK: + case S_IFCHR: + case S_IFIFO: + { + /* source is an special file */ + IsoSpecial *special; + special = malloc(sizeof(IsoSpecial)); + if (special == NULL) { + free(name); + return ISO_MEM_ERROR; + } + special->dev = info.st_rdev; + special->node.type = LIBISO_SPECIAL; + new = (IsoNode*) special; + } + break; + } + + /* fill fields */ + new->refcount = 1; + new->name = name; + new->mode = info.st_mode; + new->uid = info.st_uid; + new->gid = info.st_gid; + new->atime = info.st_atime; + new->mtime = info.st_mtime; + new->ctime = info.st_ctime; + + new->hidden = 0; + + new->parent = NULL; + new->next = NULL; + + *node = new; + return ISO_SUCCESS; +} + +/** + * Create a new builder, that is exactly a copy of an old builder, but where + * create_node() function has been replaced by image_builder_create_node. + */ +int iso_image_builder_new(IsoNodeBuilder *old, IsoNodeBuilder **builder) +{ + IsoNodeBuilder *b; + + if (builder == NULL) { + return ISO_NULL_POINTER; + } + + b = malloc(sizeof(IsoNodeBuilder)); + if (b == NULL) { + return ISO_MEM_ERROR; + } + + b->refcount = 1; + b->create_file_data = old->create_file_data; + b->create_node_data = old->create_node_data; + b->create_file = old->create_file; + b->create_node = image_builder_create_node; + b->free = old->free; + + *builder = b; + return ISO_SUCCESS; +} + +int iso_image_import(IsoImage *image, IsoDataSource *src, + struct iso_read_opts *opts, + struct iso_read_image_features *features) +{ + int ret; + IsoImageFilesystem *fs; + IsoFilesystem *fsback; + IsoNodeBuilder *blback; + IsoDir *oldroot; + IsoFileSource *newroot; + + if (image == NULL || src == NULL || opts == NULL) { + return ISO_NULL_POINTER; + } + + ret = iso_image_filesystem_new(src, opts, image->messenger, &fs); + if (ret < 0) { + return ret; + } + + /* get root from filesystem */ + ret = fs->fs.get_root((IsoFilesystem*)fs, &newroot); + if (ret < 0) { + return ret; + } + + /* backup image filesystem, builder and root */ + fsback = image->fs; + blback = image->builder; + oldroot = image->root; + + /* create new builder */ + ret = iso_image_builder_new(blback, &image->builder); + if (ret < 0) { + goto import_revert; + } + + image->fs = (IsoFilesystem*)fs; + + /* create new root, and set root attributes from source */ + ret = iso_node_new_root(&image->root); + if (ret < 0) { + goto import_revert; + } + { + struct stat info; + + /* I know this will not fail */ + iso_file_source_lstat(newroot, &info); + image->root->node.mode = info.st_mode; + image->root->node.uid = info.st_uid; + image->root->node.gid = info.st_gid; + image->root->node.atime = info.st_atime; + image->root->node.mtime = info.st_mtime; + image->root->node.ctime = info.st_ctime; + } + + /* recursively add image */ + ret = iso_add_dir_src_rec(image, image->root, newroot); + + iso_node_builder_unref(image->builder); + + /* error during recursive image addition? */ + if (ret <= 0) { + goto import_revert; + } + + /* free old root */ + iso_node_unref((IsoNode*)oldroot); + + /* recover backed fs and builder */ + image->fs = fsback; + image->builder = blback; + + { + _ImageFsData *data; + data = fs->fs.data; + + /* set volume attributes */ + iso_image_set_volset_id(image, data->volset_id); + iso_image_set_volume_id(image, data->volume_id); + iso_image_set_publisher_id(image, data->publisher_id); + iso_image_set_data_preparer_id(image, data->data_preparer_id); + iso_image_set_system_id(image, data->system_id); + iso_image_set_application_id(image, data->application_id); + iso_image_set_copyright_file_id(image, data->copyright_file_id); + iso_image_set_abstract_file_id(image, data->abstract_file_id); + iso_image_set_biblio_file_id(image, data->biblio_file_id); + + if (features != NULL) { + features->hasJoliet = data->joliet; + features->hasRR = data->rr_version != 0; + features->size = data->nblocks; + } + } + + ret = ISO_SUCCESS; + goto import_cleanup; + + import_revert:; + + image->root = oldroot; + image->fs = fsback; + + import_cleanup:; + + iso_file_source_unref(newroot); + fs->close(fs); + iso_filesystem_unref((IsoFilesystem*)fs); + + return ret; +} diff --git a/src/fs_image.h b/src/fs_image.h index 6cb0dad..cb5a49b 100644 --- a/src/fs_image.h +++ b/src/fs_image.h @@ -12,67 +12,7 @@ #include "libisofs.h" #include "fsource.h" -/** - * Options for image reading. - * There are four kind of options: - * - Related to multisession support. - * In most cases, an image begins at LBA 0 of the data source. However, - * in multisession discs, the later image begins in the last session on - * disc. The block option can be used to specify the start of that last - * session. - * - Related to the tree that will be read. - * As default, when Rock Ridge extensions are present in the image, that - * will be used to get the tree. If RR extensions are not present, libisofs - * will use the Joliet extensions if available. Finally, the plain ISO-9660 - * tree is used if neither RR nor Joliet extensions are available. With - * norock, nojoliet, and preferjoliet options, you can change this - * default behavior. - * - Related to default POSIX attributes. - * When Rock Ridege extensions are not used, libisofs can't figure out what - * are the the permissions, uid or gid for the files. You should supply - * default values for that. - * - Return information for image. - * Both size, hasRR and hasJoliet will be filled by libisofs with suitable values. - * Also, error is set to non-0 if some error happens (error codes are - * private now) - */ -struct iso_read_opts -{ - /** - * Block where the image begins, usually 0, can be different on a - * multisession disc. - */ - uint32_t block; - - unsigned int norock : 1; /*< Do not read Rock Ridge extensions */ - unsigned int nojoliet : 1; /*< Do not read Joliet extensions */ - - /** - * When both Joliet and RR extensions are present, the RR tree is used. - * If you prefer using Joliet, set this to 1. - */ - unsigned int preferjoliet : 1; - - uid_t uid; /**< Default uid when no RR */ - gid_t gid; /**< Default uid when no RR */ - mode_t mode; /**< Default mode when no RR (only permissions) */ - //TODO differ file and dir mode - //option to convert names to lower case? - - struct libiso_msgs *messenger; - - char *input_charset; - -/* modified by the function */ -// unsigned int hasRR:1; /*< It will be set to 1 if RR extensions are present, -// to 0 if not. */ -// unsigned int hasJoliet:1; /*< It will be set to 1 if Joliet extensions are -// present, to 0 if not. */ -// uint32_t size; /**< Will be filled with the size (in 2048 byte block) of -// * the image, as reported in the PVM. */ -//int error; -}; - +struct libiso_msgs; typedef struct Iso_Image_Filesystem IsoImageFilesystem; /** @@ -104,6 +44,7 @@ struct Iso_Image_Filesystem }; int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts, + struct libiso_msgs *messenger, IsoImageFilesystem **fs); #endif /*LIBISO_FS_IMAGE_H_*/ diff --git a/src/libisofs.h b/src/libisofs.h index f3b2ec1..b4d479e 100644 --- a/src/libisofs.h +++ b/src/libisofs.h @@ -202,6 +202,72 @@ struct Iso_Data_Source { void *data; }; +/** + * Options for image reading. + * There are four kind of options: + * - Related to multisession support. + * In most cases, an image begins at LBA 0 of the data source. However, + * in multisession discs, the later image begins in the last session on + * disc. The block option can be used to specify the start of that last + * session. + * - Related to the tree that will be read. + * As default, when Rock Ridge extensions are present in the image, that + * will be used to get the tree. If RR extensions are not present, libisofs + * will use the Joliet extensions if available. Finally, the plain ISO-9660 + * tree is used if neither RR nor Joliet extensions are available. With + * norock, nojoliet, and preferjoliet options, you can change this + * default behavior. + * - Related to default POSIX attributes. + * When Rock Ridege extensions are not used, libisofs can't figure out what + * are the the permissions, uid or gid for the files. You should supply + * default values for that. + */ +struct iso_read_opts +{ + /** + * Block where the image begins, usually 0, can be different on a + * multisession disc. + */ + uint32_t block; + + unsigned int norock : 1; /*< Do not read Rock Ridge extensions */ + unsigned int nojoliet : 1; /*< Do not read Joliet extensions */ + + /** + * When both Joliet and RR extensions are present, the RR tree is used. + * If you prefer using Joliet, set this to 1. + */ + unsigned int preferjoliet : 1; + + uid_t uid; /**< Default uid when no RR */ + gid_t gid; /**< Default uid when no RR */ + mode_t mode; /**< Default mode when no RR (only permissions) */ + //TODO differ file and dir mode + //option to convert names to lower case? + + char *input_charset; +}; + +/** + * Return information for image. + * Both size, hasRR and hasJoliet will be filled by libisofs with suitable + * values. + */ +struct iso_read_image_features +{ + /** It will be set to 1 if RR extensions are present, to 0 if not. */ + unsigned int hasRR:1; + + /** It will be set to 1 if Joliet extensions are present, to 0 if not. */ + unsigned int hasJoliet:1; + + /** + * Will be filled with the size (in 2048 byte block) of the image, as + * reported in the PVM. + */ + uint32_t size; +}; + /** * Create a new image, empty. * @@ -223,6 +289,28 @@ int iso_image_new(const char *name, IsoImage **image); int iso_image_create(IsoImage *image, Ecma119WriteOpts *opts, struct burn_source **burn_src); +/** + * Import a previous session or image, for growing or modify. + * + * @param image + * The image context to which old image will be imported. Note that all + * files added to image, and image attributes, will be replaced with the + * contents of the old image. TODO support for merging old image files + * @param src + * Data Source from which old image will be read. A extra reference is + * added, so you still need to iso_data_source_unref() yours. + * @param opts + * Options for image import + * @param features + * Will be filled with the features of the old image. You can pass NULL + * if you're not interested on them. + * @return + * 1 on success, < 0 on error + */ +int iso_image_import(IsoImage *image, IsoDataSource *src, + struct iso_read_opts *opts, + struct iso_read_image_features *features); + /** * Increments the reference counting of the given image. */ diff --git a/src/tree.c b/src/tree.c index b80af75..0bbfb62 100644 --- a/src/tree.c +++ b/src/tree.c @@ -17,6 +17,7 @@ #include "fsource.h" #include "builder.h" #include "messages.h" +#include "tree.h" #include #include @@ -446,11 +447,12 @@ int check_hidden(IsoImage *image, const char *name) } /** + * Recursively add a given directory to the image tree. + * * @return * 1 continue, 0 stop, < 0 error */ -static -int iso_add_dir_aux(IsoImage *image, IsoDir *parent, IsoFileSource *dir) +int iso_add_dir_src_rec(IsoImage *image, IsoDir *parent, IsoFileSource *dir) { int result; int action; /* 1 add, 2 skip, 3 stop, < 0 error */ @@ -564,7 +566,7 @@ int iso_add_dir_aux(IsoImage *image, IsoDir *parent, IsoFileSource *dir) /* finally, if the node is a directory we need to recurse */ if (new->type == LIBISO_DIR) { - result = iso_add_dir_aux(image, (IsoDir*)new, file); + result = iso_add_dir_src_rec(image, (IsoDir*)new, file); iso_file_source_unref(file); if (result < 0) { /* error */ @@ -631,7 +633,7 @@ int iso_tree_add_dir_rec(IsoImage *image, IsoDir *parent, const char *dir) iso_file_source_unref(file); return ISO_FILE_IS_NOT_DIR; } - result = iso_add_dir_aux(image, parent, file); + result = iso_add_dir_src_rec(image, parent, file); iso_file_source_unref(file); return result; } diff --git a/src/tree.h b/src/tree.h new file mode 100644 index 0000000..9c5347c --- /dev/null +++ b/src/tree.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2007 Vreixo Formoso + * + * 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 as + * published by the Free Software Foundation. See COPYING file for details. + */ +#ifndef LIBISO_IMAGE_TREE_H_ +#define LIBISO_IMAGE_TREE_H_ + +#include "image.h" + +/** + * Recursively add a given directory to the image tree. + * + * @return + * 1 continue, 0 stop, < 0 error + */ +int iso_add_dir_src_rec(IsoImage *image, IsoDir *parent, IsoFileSource *dir); + +#endif /*LIBISO_IMAGE_TREE_H_*/