Implement function to recursively add a dir to an iso tree.
This commit also to the following changes: - create_node() on builder never frees the IsoFileSource, it is responsability of the caller to free it. - Recursive addition options added to IsoImage (not exposed to public API yet) - create_node() takes care about follow_symlinks - Added little demo program to test it.
This commit is contained in:
parent
0306bb5daf
commit
d10ed353e2
@ -26,3 +26,4 @@ test/iso
|
||||
test/test
|
||||
demo/lsl
|
||||
demo/cat
|
||||
demo/tree
|
||||
|
@ -35,7 +35,8 @@ libinclude_HEADERS = \
|
||||
## Build demo applications
|
||||
noinst_PROGRAMS = \
|
||||
demo/lsl \
|
||||
demo/cat
|
||||
demo/cat \
|
||||
demo/tree
|
||||
|
||||
demo_lsl_CPPFLAGS = -Isrc
|
||||
demo_lsl_LDADD = $(src_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
@ -45,6 +46,10 @@ demo_cat_CPPFLAGS = -Isrc
|
||||
demo_cat_LDADD = $(src_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_cat_SOURCES = demo/cat.c
|
||||
|
||||
demo_tree_CPPFLAGS = -Isrc
|
||||
demo_tree_LDADD = $(src_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_tree_SOURCES = demo/tree.c
|
||||
|
||||
|
||||
## Build unit test
|
||||
|
||||
|
105
demo/tree.c
Normal file
105
demo/tree.c
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Little program that reads an existing ISO image and prints its
|
||||
* contents to stdout.
|
||||
*/
|
||||
|
||||
#include "libisofs.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void
|
||||
print_permissions(mode_t mode)
|
||||
{
|
||||
char perm[10];
|
||||
|
||||
//TODO suid, sticky...
|
||||
|
||||
perm[9] = '\0';
|
||||
perm[8] = mode & S_IXOTH ? 'x' : '-';
|
||||
perm[7] = mode & S_IWOTH ? 'w' : '-';
|
||||
perm[6] = mode & S_IROTH ? 'r' : '-';
|
||||
perm[5] = mode & S_IXGRP ? 'x' : '-';
|
||||
perm[4] = mode & S_IWGRP ? 'w' : '-';
|
||||
perm[3] = mode & S_IRGRP ? 'r' : '-';
|
||||
perm[2] = mode & S_IXUSR ? 'x' : '-';
|
||||
perm[1] = mode & S_IWUSR ? 'w' : '-';
|
||||
perm[0] = mode & S_IRUSR ? 'r' : '-';
|
||||
printf("[%s]",perm);
|
||||
}
|
||||
|
||||
static void
|
||||
print_dir(IsoDir *dir, int level)
|
||||
{
|
||||
int i;
|
||||
IsoDirIter *iter;
|
||||
IsoNode *node;
|
||||
char sp[level * 2 + 1];
|
||||
|
||||
for (i = 0; i < level * 2; i += 2) {
|
||||
sp[i] = '|';
|
||||
sp[i+1] = ' ';
|
||||
}
|
||||
|
||||
sp[level * 2-1] = '-';
|
||||
sp[level * 2] = '\0';
|
||||
|
||||
iso_dir_get_children(dir, &iter);
|
||||
while (iso_dir_iter_next(iter, &node) == 1) {
|
||||
|
||||
if (iso_node_get_type(node) == LIBISO_DIR) {
|
||||
printf("%s+[D] ", sp);
|
||||
print_permissions(iso_node_get_permissions(node));
|
||||
printf(" %s\n", iso_node_get_name(node));
|
||||
print_dir((IsoDir*)node, level+1);
|
||||
} else if (iso_node_get_type(node) == LIBISO_FILE) {
|
||||
printf("%s-[F] ", sp);
|
||||
print_permissions(iso_node_get_permissions(node));
|
||||
printf(" %s\n", iso_node_get_name(node) );
|
||||
} else if (iso_node_get_type(node) == LIBISO_SYMLINK) {
|
||||
printf("%s-[L] ", sp);
|
||||
print_permissions(iso_node_get_permissions(node));
|
||||
printf(" %s -> %s \n", iso_node_get_name(node),
|
||||
iso_symlink_get_dest((IsoSymlink*)node) );
|
||||
} else {
|
||||
printf("%s-[C] ", sp);
|
||||
print_permissions(iso_node_get_permissions(node));
|
||||
printf(" %s\n", iso_node_get_name(node) );
|
||||
}
|
||||
}
|
||||
iso_dir_iter_free(iter);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int result;
|
||||
IsoImage *image;
|
||||
|
||||
if (argc != 2) {
|
||||
printf ("You need to specify a valid path\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
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", "");
|
||||
|
||||
result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[1]);
|
||||
if (result < 0) {
|
||||
printf ("Error adding directory %d\n", result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("================= IMAGE =================\n");
|
||||
print_dir(iso_image_get_root(image), 0);
|
||||
printf("\n\n");
|
||||
|
||||
iso_image_unref(image);
|
||||
return 0;
|
||||
}
|
@ -10,6 +10,7 @@
|
||||
#include "error.h"
|
||||
#include "node.h"
|
||||
#include "fsource.h"
|
||||
#include "image.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -98,7 +99,11 @@ int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
|
||||
name = src->get_name(src);
|
||||
|
||||
/* get info about source */
|
||||
result = src->lstat(src, &info);
|
||||
if (image->recOpts->follow_symlinks) {
|
||||
result = src->stat(src, &info);
|
||||
} else {
|
||||
result = src->lstat(src, &info);
|
||||
}
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
@ -114,6 +119,8 @@ int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
|
||||
if (result < 0) {
|
||||
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) {
|
||||
iso_stream_unref(stream);
|
||||
@ -134,7 +141,6 @@ int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
|
||||
return ISO_MEM_ERROR;
|
||||
}
|
||||
new->type = LIBISO_DIR;
|
||||
iso_file_source_unref(src);
|
||||
}
|
||||
break;
|
||||
case S_IFLNK:
|
||||
@ -154,7 +160,6 @@ int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
|
||||
link->dest = strdup(dest);
|
||||
link->node.type = LIBISO_SYMLINK;
|
||||
new = (IsoNode*) link;
|
||||
iso_file_source_unref(src);
|
||||
}
|
||||
break;
|
||||
case S_IFSOCK:
|
||||
@ -171,7 +176,6 @@ int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
|
||||
special->dev = info.st_rdev;
|
||||
special->node.type = LIBISO_SPECIAL;
|
||||
new = (IsoNode*) special;
|
||||
iso_file_source_unref(src);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -48,8 +48,7 @@ struct Iso_Node_Builder
|
||||
* created is determined from the type of the file source. Name,
|
||||
* permissions and other attributes are taken from source file.
|
||||
*
|
||||
* On sucess, the ref. to src will be owned by node, 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
|
||||
|
10
src/image.c
10
src/image.c
@ -77,6 +77,16 @@ int iso_image_new(const char *name, IsoImage **image)
|
||||
return res;
|
||||
}
|
||||
img->refcount = 1;
|
||||
img->recOpts = calloc(1,sizeof(IsoImageRecOpts));
|
||||
if (img->recOpts == NULL) {
|
||||
libiso_msgs_destroy(&img->messenger, 0);
|
||||
iso_node_builder_unref(img->builder);
|
||||
iso_filesystem_unref(img->fs);
|
||||
iso_node_unref((IsoNode*)img->root);
|
||||
free(img);
|
||||
return ISO_MEM_ERROR;
|
||||
}
|
||||
|
||||
if (name != NULL) {
|
||||
img->volset_id = strdup(name);
|
||||
img->volume_id = strdup(name);
|
||||
|
64
src/image.h
64
src/image.h
@ -21,6 +21,8 @@
|
||||
* (Usefull, for example, in Multiple-Document-Interface GUI apps.
|
||||
* [The stuff we have in init belongs really to image!]
|
||||
*/
|
||||
|
||||
typedef struct Iso_Image_Rec_Opts IsoImageRecOpts;
|
||||
|
||||
struct Iso_Image {
|
||||
|
||||
@ -51,6 +53,68 @@ struct Iso_Image {
|
||||
* Default builder to use when adding files to the image tree.
|
||||
*/
|
||||
IsoNodeBuilder *builder;
|
||||
|
||||
/**
|
||||
* Options for recursive directory addition
|
||||
*/
|
||||
IsoImageRecOpts *recOpts;
|
||||
};
|
||||
|
||||
/**
|
||||
* Options for recursive directory addition
|
||||
*/
|
||||
struct Iso_Image_Rec_Opts {
|
||||
|
||||
/**
|
||||
* Whether to follow symlinks or just add them as symlinks
|
||||
*/
|
||||
unsigned int follow_symlinks;
|
||||
|
||||
/**
|
||||
* Whether to skip hidden files
|
||||
*/
|
||||
unsigned int ignore_hidden;
|
||||
|
||||
/**
|
||||
* Whether to stop on an error. Some errors, such as memory errors,
|
||||
* always cause a stop
|
||||
*/
|
||||
unsigned int stop_on_error;
|
||||
|
||||
/**
|
||||
* Files to exclude
|
||||
* TODO add wildcard support
|
||||
*/
|
||||
char** excludes;
|
||||
|
||||
/**
|
||||
* if the dir already contains a node with the same name, whether to
|
||||
* replace or not the old node with the new.
|
||||
* - 0 not replace
|
||||
* - 1 replace
|
||||
* TODO #00006 define more values
|
||||
* to replace only if both are the same kind of file
|
||||
* if both are dirs, add contents (and what to do with conflicts?)
|
||||
*/
|
||||
int replace;
|
||||
|
||||
/**
|
||||
* When this is not NULL, it is a pointer to a function that will
|
||||
* be called just before a file will be added, or when an error occurs.
|
||||
* You can overwrite some of the above options by returning suitable
|
||||
* values.
|
||||
*
|
||||
* @param action
|
||||
* 1 file will be added
|
||||
* 2 file will be skipped
|
||||
* < 0 error adding file (return 3 to stop, 1 to continue)
|
||||
* @param flag
|
||||
* 0 no problem
|
||||
* 1 file with same name already exists
|
||||
* @return
|
||||
* 1 add/continue, 2 skip, 3 stop
|
||||
*/
|
||||
int (*report)(IsoFileSource *src, int action, int flag);
|
||||
};
|
||||
|
||||
#endif /*LIBISO_IMAGE_H_*/
|
||||
|
@ -638,6 +638,22 @@ int iso_tree_add_new_special(IsoDir *parent, const char *name, mode_t mode,
|
||||
int iso_tree_add_node(IsoImage *image, IsoDir *parent, const char *path,
|
||||
IsoNode **node);
|
||||
|
||||
/**
|
||||
* Add the contents of a dir to a given directory of the iso tree.
|
||||
*
|
||||
* TODO comment Builder and Filesystem related issues when exposing both
|
||||
*
|
||||
* @param image
|
||||
* TODO expose dir rec options and explain that here
|
||||
* @param parent
|
||||
* Directory on the image tree where to add the contents of the dir
|
||||
* @param dir
|
||||
* Path to a dir in the filesystem
|
||||
* @return
|
||||
* number of nodes in parent if success, < 0 otherwise
|
||||
*/
|
||||
int iso_tree_add_dir_rec(IsoImage *image, IsoDir *parent, const char *dir);
|
||||
|
||||
/**
|
||||
* Locate a node by its path on image.
|
||||
*
|
||||
|
215
src/tree.c
215
src/tree.c
@ -16,10 +16,13 @@
|
||||
#include "image.h"
|
||||
#include "fsource.h"
|
||||
#include "builder.h"
|
||||
#include "messages.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/**
|
||||
* Add a new directory to the iso tree.
|
||||
@ -356,6 +359,218 @@ int iso_tree_add_node(IsoImage *image, IsoDir *parent, const char *path,
|
||||
}
|
||||
result = iso_tree_add_node_builder(image, parent, file, image->builder,
|
||||
node);
|
||||
/* free the file */
|
||||
iso_file_source_unref(file);
|
||||
return result;
|
||||
}
|
||||
|
||||
static
|
||||
int check_excludes(IsoImage *image, const char *path)
|
||||
{
|
||||
char **exclude;
|
||||
if (image->recOpts->excludes == NULL) {
|
||||
return 0;
|
||||
}
|
||||
exclude = image->recOpts->excludes;
|
||||
while (*exclude) {
|
||||
if (strcmp(*exclude, path) == 0) {
|
||||
return 1;
|
||||
}
|
||||
++exclude;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int check_hidden(IsoImage *image, const char *name)
|
||||
{
|
||||
return (image->recOpts->ignore_hidden && name[0] == '.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* 1 continue, 0 stop, < 0 error
|
||||
*/
|
||||
static
|
||||
int iso_add_dir_aux(IsoImage *image, IsoDir *parent, IsoFileSource *dir)
|
||||
{
|
||||
int result;
|
||||
int action; /* 1 add, 2 skip, 3 stop, < 0 error */
|
||||
IsoNodeBuilder *builder;
|
||||
IsoFileSource *file;
|
||||
IsoNode **pos;
|
||||
|
||||
result = dir->open(dir);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
builder = image->builder;
|
||||
action = 1;
|
||||
while ( (result = dir->readdir(dir, &file)) == 1) {
|
||||
int flag;
|
||||
char *name;
|
||||
IsoNode *new;
|
||||
|
||||
{
|
||||
char msg[PATH_MAX];
|
||||
sprintf(msg, "Adding file %s\n", file->get_path(file));
|
||||
iso_msg_debug(image, msg);
|
||||
}
|
||||
|
||||
name = file->get_name(file);
|
||||
|
||||
if (check_excludes(image, file->get_path(file))) {
|
||||
action = 2;
|
||||
} else if (check_hidden(image, name)) {
|
||||
action = 2;
|
||||
} else {
|
||||
action = 1;
|
||||
}
|
||||
|
||||
/* find place where to insert */
|
||||
flag = 0;
|
||||
pos = &(parent->children);
|
||||
while (*pos != NULL && strcmp((*pos)->name, name) < 0) {
|
||||
pos = &((*pos)->next);
|
||||
}
|
||||
if (*pos != NULL && !strcmp((*pos)->name, name)) {
|
||||
flag = 1;
|
||||
if (action == 1 && image->recOpts->replace == 0) {
|
||||
action = 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* ask user if callback has been set */
|
||||
if (image->recOpts->report) {
|
||||
action = image->recOpts->report(file, action, flag);
|
||||
}
|
||||
|
||||
if (action == 2) {
|
||||
/* skip file */
|
||||
iso_file_source_unref(file);
|
||||
continue;
|
||||
} else if (action == 3) {
|
||||
/* stop */
|
||||
iso_file_source_unref(file);
|
||||
break;
|
||||
}
|
||||
|
||||
/* ok, file will be added */
|
||||
result = builder->create_node(builder, image, file, &new);
|
||||
if (result < 0) {
|
||||
|
||||
{
|
||||
char msg[PATH_MAX];
|
||||
sprintf(msg, "Error %d when adding file %s\n", result,
|
||||
file->get_path(file));
|
||||
iso_msg_debug(image, msg);
|
||||
}
|
||||
|
||||
if (image->recOpts->report) {
|
||||
action = image->recOpts->report(file, result, flag);
|
||||
} else {
|
||||
action = image->recOpts->stop_on_error ? 3 : 1;
|
||||
}
|
||||
|
||||
/* free file */
|
||||
iso_file_source_unref(file);
|
||||
|
||||
if (action == 3) {
|
||||
result = 1; /* prevent error to be passing up */
|
||||
break;
|
||||
} else {
|
||||
/* TODO check that action is 1!!! */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* ok, node has correctly created, we need to add it */
|
||||
if (flag) {
|
||||
/* replace node */
|
||||
new->next = (*pos)->next;
|
||||
(*pos)->parent = NULL;
|
||||
(*pos)->next = NULL;
|
||||
iso_node_unref(*pos);
|
||||
*pos = new;
|
||||
new->parent = parent;
|
||||
} else {
|
||||
/* just add */
|
||||
new->next = *pos;
|
||||
*pos = new;
|
||||
new->parent = parent;
|
||||
++parent->nchildren;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
iso_file_source_unref(file);
|
||||
if (result < 0) {
|
||||
/* error */
|
||||
if (image->recOpts->stop_on_error) {
|
||||
action = 3; /* stop */
|
||||
result = 1; /* prevent error to be passing up */
|
||||
break;
|
||||
}
|
||||
} else if (result == 0) {
|
||||
/* stop */
|
||||
action = 3;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
iso_file_source_unref(file);
|
||||
}
|
||||
}
|
||||
|
||||
if (result < 0) {
|
||||
// TODO printf message
|
||||
action = result;
|
||||
}
|
||||
|
||||
result = dir->close(dir);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
if (action < 0) {
|
||||
return action; /* error */
|
||||
} else if (action == 3) {
|
||||
return 0; /* stop */
|
||||
} else {
|
||||
return 1; /* continue */
|
||||
}
|
||||
}
|
||||
|
||||
int iso_tree_add_dir_rec(IsoImage *image, IsoDir *parent, const char *dir)
|
||||
{
|
||||
int result;
|
||||
struct stat info;
|
||||
IsoFilesystem *fs;
|
||||
IsoFileSource *file;
|
||||
|
||||
if (image == NULL || parent == NULL || dir == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
fs = image->fs;
|
||||
result = fs->get_by_path(fs, dir, &file);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/* we also allow dir path to be a symlink to a dir */
|
||||
result = file->stat(file, &info);
|
||||
if (result < 0) {
|
||||
iso_file_source_unref(file);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!S_ISDIR(info.st_mode)) {
|
||||
iso_file_source_unref(file);
|
||||
return ISO_FILE_IS_NOT_DIR;
|
||||
}
|
||||
result = iso_add_dir_aux(image, parent, file);
|
||||
iso_file_source_unref(file);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user