diff --git a/src/error.h b/src/error.h index 0c93ba8..e5a6ca8 100644 --- a/src/error.h +++ b/src/error.h @@ -23,6 +23,7 @@ #define ISO_NODE_ALREADY_ADDED -50 #define ISO_NODE_NAME_NOT_UNIQUE -51 +#define ISO_NODE_NOT_ADDED_TO_DIR -52 #define ISO_FILE_ERROR -100 #define ISO_FILE_ALREADY_OPENNED -101 diff --git a/src/libisofs.h b/src/libisofs.h index e190ae3..8e87386 100644 --- a/src/libisofs.h +++ b/src/libisofs.h @@ -198,4 +198,29 @@ int iso_dir_iter_has_next(IsoDirIter *iter); */ void iso_dir_iter_free(IsoDirIter *iter); +/** + * Removes a child from a directory. + * The child is not freed, so you will become the owner of the node. Later + * you can add the node to another dir (calling iso_dir_add_node), or free + * it if you don't need it (with iso_node_unref). + * + * @return + * 1 on success, < 0 error + * Possible errors: + * ISO_NULL_POINTER, if node is NULL + * ISO_NODE_NOT_ADDED_TO_DIR, if node doesn't belong to a dir + */ +int iso_node_take(IsoNode *node); + +/** + * Removes a child from a directory and free (unref) it. + * If you want to keep the child alive, you need to iso_node_ref() it + * before this call, but in that case iso_node_take() is a better + * alternative. + * + * @return + * 1 on success, < 0 error + */ +int iso_node_remove(IsoNode *node); + #endif /*LIBISO_LIBISOFS_H_*/ diff --git a/src/node.c b/src/node.c index 0efb1e7..42590fc 100644 --- a/src/node.c +++ b/src/node.c @@ -29,7 +29,21 @@ void iso_node_ref(IsoNode *node) void iso_node_unref(IsoNode *node) { if (--node->refcount == 0) { - /* TODO #00002 handle deletion of each kind of node */ + switch(node->type) { + case LIBISO_DIR: + { + IsoNode *child = ((IsoDir*)node)->children; + while (child != NULL) { + IsoNode *tmp = child->next; + iso_node_unref(child); + child = tmp; + } + } + break; + default: + /* TODO #00002 handle deletion of each kind of node */ + break; + } free(node->name); free(node); } @@ -268,3 +282,66 @@ int iso_dir_iter_has_next(IsoDirIter *iter) } return iter->pos == NULL ? 0 : 1; } + +static IsoNode** +iso_dir_find_node(IsoDir *dir, IsoNode *node) +{ + IsoNode **pos; + pos = &(dir->children); + while (*pos != NULL && *pos != node) { + pos = &((*pos)->next); + } + return pos; +} + +/** + * Removes a child from a directory. + * The child is not freed, so you will become the owner of the node. Later + * you can add the node to another dir (calling iso_dir_add_node), or free + * it if you don't need it (with iso_node_unref). + * + * @return + * 1 on success, < 0 error + */ +int iso_node_take(IsoNode *node) +{ + IsoNode **pos; + IsoDir* dir; + + if (node == NULL) { + return ISO_NULL_POINTER; + } + dir = node->parent; + if (dir == NULL) { + return ISO_NODE_NOT_ADDED_TO_DIR; + } + pos = iso_dir_find_node(dir, node); + if (pos == NULL) { + /* should never occur */ + return ISO_ERROR; + } + *pos = node->next; + node->parent = NULL; + node->next = NULL; + dir->nchildren--; + return ISO_SUCCESS; +} + +/** + * Removes a child from a directory and free (unref) it. + * If you want to keep the child alive, you need to iso_node_ref() it + * before this call, but in that case iso_node_take() is a better + * alternative. + * + * @return + * 1 on success, < 0 error + */ +int iso_node_remove(IsoNode *node) +{ + int ret; + ret = iso_node_take(node); + if (ret == ISO_SUCCESS) { + iso_node_unref(node); + } + return ret; +}