diff --git a/libisofs/branches/thomas/Makefile.am b/libisofs/branches/thomas/Makefile.am index f992d25c..6101ec9c 100644 --- a/libisofs/branches/thomas/Makefile.am +++ b/libisofs/branches/thomas/Makefile.am @@ -55,6 +55,8 @@ libisofs_libisofs_la_SOURCES = \ libisofs/iso1999.h \ libisofs/iso1999.c \ libisofs/data_source.c +libisofs_libisofs_la_LIBADD= \ + $(THREAD_LIBS) libinclude_HEADERS = \ libisofs/libisofs.h diff --git a/libisofs/branches/thomas/libisofs/find.c b/libisofs/branches/thomas/libisofs/find.c index 02881130..797ef881 100644 --- a/libisofs/branches/thomas/libisofs/find.c +++ b/libisofs/branches/thomas/libisofs/find.c @@ -93,13 +93,20 @@ int find_iter_remove(IsoDirIter *iter) return iso_dir_iter_remove(data->iter); } +void find_notify_child_taken(IsoDirIter *iter, IsoNode *node) +{ + /* nothing to do */ + return; +} + static struct iso_dir_iter_iface find_iter_class = { find_iter_next, find_iter_has_next, find_iter_free, find_iter_take, - find_iter_remove + find_iter_remove, + find_notify_child_taken }; int iso_dir_find_children(IsoDir* dir, IsoFindCondition *cond, @@ -134,6 +141,11 @@ int iso_dir_find_children(IsoDir* dir, IsoFindCondition *cond, data->iter = children; data->cond = cond; it->data = data; + + if (iso_dir_iter_register(it) < 0) { + free(it); + return ISO_OUT_OF_MEM; + } *iter = it; return ISO_SUCCESS; diff --git a/libisofs/branches/thomas/libisofs/libisofs.h b/libisofs/branches/thomas/libisofs/libisofs.h index a48666d7..a5bd199b 100644 --- a/libisofs/branches/thomas/libisofs/libisofs.h +++ b/libisofs/branches/thomas/libisofs/libisofs.h @@ -2731,6 +2731,35 @@ void iso_tree_set_report_callback(IsoImage *image, int iso_tree_add_node(IsoImage *image, IsoDir *parent, 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. + * + * @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. + * @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_node(IsoImage *image, IsoDir *parent, const char *name, + const char *path, IsoNode **node); + /** * Add the contents of a dir to a given directory of the iso tree. * diff --git a/libisofs/branches/thomas/libisofs/node.c b/libisofs/branches/thomas/libisofs/node.c index 22f46d73..95a0095e 100644 --- a/libisofs/branches/thomas/libisofs/node.c +++ b/libisofs/branches/thomas/libisofs/node.c @@ -485,6 +485,10 @@ int iso_node_take(IsoNode *node) /* should never occur */ return ISO_ASSERT_FAILURE; } + + /* notify iterators just before remove */ + iso_notify_dir_iters(node, 0); + *pos = node->next; node->parent = NULL; node->next = NULL; @@ -531,7 +535,6 @@ static int iter_take(IsoDirIter *iter) { struct dir_iter_data *data; - IsoNode *pos, *pre; if (iter == NULL) { return ISO_NULL_POINTER; } @@ -549,38 +552,7 @@ int iter_take(IsoDirIter *iter) /* clear next flag */ data->flag &= ~0x01; - pos = iter->dir->children; - pre = NULL; - while (pos != NULL && pos != data->pos) { - pre = pos; - pos = pos->next; - } - if (pos == NULL) { - return ISO_ERROR; /* node not in dir */ - } - - if (pos != data->pos) { - return ISO_ASSERT_FAILURE; - } - - /* dispose iterator reference */ - iso_node_unref(data->pos); - - if (pre == NULL) { - /* node is a first position */ - iter->dir->children = pos->next; - data->pos = NULL; - } else { - pre->next = pos->next; - data->pos = pre; - iso_node_ref(pre); /* take iter ref */ - } - - /* take pos */ - pos->parent = NULL; - pos->next = NULL; - iter->dir->nchildren--; - return ISO_SUCCESS; + return iso_node_take(data->pos); } static @@ -601,19 +573,49 @@ int iter_remove(IsoDirIter *iter) /* remove node */ iso_node_unref(pos); } - if (data->pos == pos) { - return ISO_ERROR; - } return ret; } +void iter_notify_child_taken(IsoDirIter *iter, IsoNode *node) +{ + IsoNode *pos, *pre; + struct dir_iter_data *data; + data = iter->data; + + if (data->pos == node) { + pos = iter->dir->children; + pre = NULL; + while (pos != NULL && pos != data->pos) { + pre = pos; + pos = pos->next; + } + if (pos == NULL || pos != data->pos) { + return; + } + + /* dispose iterator reference */ + iso_node_unref(data->pos); + + if (pre == NULL) { + /* node is a first position */ + iter->dir->children = pos->next; + data->pos = NULL; + } else { + pre->next = pos->next; + data->pos = pre; + iso_node_ref(pre); /* take iter ref */ + } + } +} + static struct iso_dir_iter_iface iter_class = { iter_next, iter_has_next, iter_free, iter_take, - iter_remove + iter_remove, + iter_notify_child_taken }; int iso_dir_get_children(const IsoDir *dir, IsoDirIter **iter) @@ -639,6 +641,11 @@ int iso_dir_get_children(const IsoDir *dir, IsoDirIter **iter) data->pos = NULL; data->flag = 0x00; it->data = data; + + if (iso_dir_iter_register(it) < 0) { + free(it); + return ISO_OUT_OF_MEM; + } *iter = it; return ISO_SUCCESS; @@ -663,6 +670,7 @@ int iso_dir_iter_has_next(IsoDirIter *iter) void iso_dir_iter_free(IsoDirIter *iter) { if (iter != NULL) { + iso_dir_iter_unregister(iter); iter->class->free(iter); free(iter); } @@ -970,6 +978,63 @@ int iso_dir_insert(IsoDir *dir, IsoNode *node, IsoNode **pos, return ++dir->nchildren; } +/* iterators are stored in a linked list */ +struct iter_reg_node { + IsoDirIter *iter; + struct iter_reg_node *next; +}; + +/* list header */ +static +struct iter_reg_node *iter_reg = NULL; + +/** + * Add a new iterator to the registry. The iterator register keeps track of + * all iterators being used, and are notified when directory structure + * changes. + */ +int iso_dir_iter_register(IsoDirIter *iter) +{ + struct iter_reg_node *new; + new = malloc(sizeof(struct iter_reg_node)); + if (new == NULL) { + return ISO_OUT_OF_MEM; + } + new->iter = iter; + new->next = iter_reg; + iter_reg = new; + return ISO_SUCCESS; +} + +/** + * Unregister a directory iterator. + */ +void iso_dir_iter_unregister(IsoDirIter *iter) +{ + struct iter_reg_node **pos; + pos = &iter_reg; + while (*pos != NULL && (*pos)->iter != iter) { + pos = &(*pos)->next; + } + if (*pos) { + struct iter_reg_node *tmp = (*pos)->next; + free(*pos); + *pos = tmp; + } +} + +void iso_notify_dir_iters(IsoNode *node, int flag) +{ + struct iter_reg_node *pos = iter_reg; + while (pos != NULL) { + IsoDirIter *iter = pos->iter; + if (iter->dir == node->parent) { + iter->class->notify_child_taken(iter, node); + } + pos = pos->next; + } +} + int iso_node_new_root(IsoDir **root) { IsoDir *dir; diff --git a/libisofs/branches/thomas/libisofs/node.h b/libisofs/branches/thomas/libisofs/node.h index a1fc96d3..dd13469f 100644 --- a/libisofs/branches/thomas/libisofs/node.h +++ b/libisofs/branches/thomas/libisofs/node.h @@ -161,6 +161,11 @@ struct iso_dir_iter_iface int (*remove)(IsoDirIter *iter); + /** + * This is called just before remove a node from a directory. The iterator + * may want to update its internal state according to this. + */ + void (*notify_child_taken)(IsoDirIter *iter, IsoNode *node); }; /** @@ -322,4 +327,18 @@ int iso_dir_exists(IsoDir *dir, const char *name, IsoNode ***pos); int iso_dir_insert(IsoDir *dir, IsoNode *node, IsoNode **pos, enum iso_replace_mode replace); +/** + * Add a new iterator to the registry. The iterator register keeps track of + * all iterators being used, and are notified when directory structure + * changes. + */ +int iso_dir_iter_register(IsoDirIter *iter); + +/** + * Unregister a directory iterator. + */ +void iso_dir_iter_unregister(IsoDirIter *iter); + +void iso_notify_dir_iters(IsoNode *node, int flag); + #endif /*LIBISO_NODE_H_*/ diff --git a/libisofs/branches/thomas/libisofs/tree.c b/libisofs/branches/thomas/libisofs/tree.c index 5dc360ed..420b6113 100644 --- a/libisofs/branches/thomas/libisofs/tree.c +++ b/libisofs/branches/thomas/libisofs/tree.c @@ -475,6 +475,59 @@ int iso_tree_add_node(IsoImage *image, IsoDir *parent, const char *path, return result; } +int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name, + const char *path, IsoNode **node) +{ + int result; + IsoFilesystem *fs; + IsoFileSource *file; + IsoNode *new; + IsoNode **pos; + + if (image == NULL || parent == NULL || name == NULL || path == NULL) { + return ISO_NULL_POINTER; + } + + if (node) { + *node = NULL; + } + + fs = image->fs; + result = fs->get_by_path(fs, path, &file); + if (result < 0) { + return result; + } + + /* find place where to insert */ + result = iso_dir_exists(parent, name, &pos); + if (result) { + /* a node with same name already exists */ + iso_file_source_unref(file); + return ISO_NODE_NAME_NOT_UNIQUE; + } + + result = image->builder->create_node(image->builder, image, file, &new); + if (result < 0) { + return result; + } + + /* free the file */ + iso_file_source_unref(file); + + result = iso_node_set_name(new, name); + if (result < 0) { + iso_node_unref(new); + return result; + } + + if (node) { + *node = new; + } + + /* finally, add node to parent */ + return iso_dir_insert(parent, new, pos, ISO_REPLACE_NEVER); +} + static int check_excludes(IsoImage *image, const char *path) {