diff --git a/Makefile.am b/Makefile.am index 37925fd..2e65e4d 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.c \ src/image.h \ src/image.c \ src/fsource.h \ diff --git a/TODO b/TODO index 502d6cd..76680fb 100644 --- a/TODO +++ b/TODO @@ -11,6 +11,7 @@ TODO #00004 (fsource-h) -> Add a get_mime_type() function. #00005 (node.c) -> optimize iso_dir_iter_take. #00006 (libisofs.h) -> define more replace values when adding a node to a dir +#00007 (libisofs.h) -> expose iso_tree_add_new_file FIXME ===== diff --git a/src/libisofs.h b/src/libisofs.h index 40d3fc5..ff9647e 100644 --- a/src/libisofs.h +++ b/src/libisofs.h @@ -428,6 +428,73 @@ int iso_dir_iter_take(IsoDirIter *iter); */ int iso_dir_iter_remove(IsoDirIter *iter); +/** + * Get the destination of a node (in UTF-8). + * The returned string belongs to the node and should not be modified nor + * freed. Use strdup if you really need your own copy. + */ +const char *iso_symlink_get_dest(const IsoSymlink *link); + +/** + * Set the destination of a link. + */ +void iso_symlink_set_dest(IsoSymlink *link, const char *dest); + +/** + * Add a new directory to the iso tree. Permissions, owner and hidden atts + * are taken from parent, you can modify them later. + * + * @param parent + * the dir where the new directory will be created + * @param name + * name for the new dir. If a node with same name already exists on + * parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE. + * @param dir + * place where to store a pointer to the newly created dir. 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 or name are NULL + * ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists + * ISO_MEM_ERROR + */ +int iso_tree_add_new_dir(IsoDir *parent, const char *name, IsoDir **dir); + +/* +TODO #00007 expose Strem and thi function: +int iso_tree_add_new_file(IsoDir *parent, const char *name, stream, file) +*/ + +/** + * Add a new symlink to the directory tree. Permissions are set to 0777, + * owner and hidden atts are taken from parent. You can modify any of them + * later. + * + * @param parent + * the dir where the new symlink will be created + * @param name + * name for the new dir. If a node with same name already exists on + * parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE. + * @param dest + * destination of the link + * @param link + * place where to store a pointer to the newly created link. 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_MEM_ERROR + */ +int iso_tree_add_new_symlink(IsoDir *parent, const char *name, + const char *dest, IsoSymlink **link); + #define ISO_MSGS_MESSAGE_LEN 4096 /** diff --git a/src/node.c b/src/node.c index 9a4d53d..6f4eb2e 100644 --- a/src/node.c +++ b/src/node.c @@ -419,6 +419,25 @@ int iso_dir_iter_remove(IsoDirIter *iter) return iso_node_remove(pos); } +/** + * Get the destination of a node (in UTF-8). + * The returned string belongs to the node and should not be modified nor + * freed. Use strdup if you really need your own copy. + */ +const char *iso_symlink_get_dest(const IsoSymlink *link) +{ + return link->dest; +} + +/** + * Set the destination of a link. + */ +void iso_symlink_set_dest(IsoSymlink *link, const char *dest) +{ + free(link->dest); + link->dest = strdup(dest); +} + int iso_node_new_root(IsoDir **root) { IsoDir *dir; diff --git a/src/tree.c b/src/tree.c new file mode 100644 index 0000000..426e074 --- /dev/null +++ b/src/tree.c @@ -0,0 +1,182 @@ +/* + * 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. + */ + +/* + * Functions that act on the iso tree. + */ + +#include "libisofs.h" +#include "node.h" +#include "error.h" + +#include +#include +#include + +/** + * Add a new directory to the iso tree. + * + * @param parent + * the dir where the new directory will be created + * @param name + * name for the new dir. If a node with same name already exists on + * parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE. + * @param dir + * place where to store a pointer to the newly created dir. 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 dir if succes, < 0 otherwise + * Possible errors: + * ISO_NULL_POINTER, if parent or name are NULL + * ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists + */ +int iso_tree_add_new_dir(IsoDir *parent, const char *name, IsoDir **dir) +{ + IsoDir *node; + IsoNode **pos; + time_t now; + + if (parent == NULL || name == NULL) { + return ISO_NULL_POINTER; + } + + /* find place where to insert */ + pos = &(parent->children); + while (*pos != NULL && strcmp((*pos)->name, name) < 0) { + pos = &((*pos)->next); + } + if (*pos != NULL && !strcmp((*pos)->name, name)) { + /* a node with same name already exists */ + return ISO_NODE_NAME_NOT_UNIQUE; + } + + node = calloc(1, sizeof(IsoDir)); + if (node == NULL) { + return ISO_MEM_ERROR; + } + + node->node.refcount = 1; + node->node.type = LIBISO_DIR; + node->node.name = strdup(name); + if (node->node.name == NULL) { + free(node); + return ISO_MEM_ERROR; + } + + /* permissions from parent */ + node->node.mode = parent->node.mode; + node->node.uid = parent->node.uid; + node->node.gid = parent->node.gid; + node->node.hidden = parent->node.hidden; + + /* current time */ + now = time(NULL); + node->node.atime = now; + node->node.ctime = now; + node->node.mtime = now; + + /* add to dir */ + node->node.parent = parent; + node->node.next = (*pos)->next; + *pos = (IsoNode*)node; + + if (dir) { + *dir = node; + } + return ISO_SUCCESS; +} + +/** + * Add a new symlink to the directory tree. Permissions are set to 0777, + * owner and hidden atts are taken from parent. You can modify any of them + * later. + * + * @param parent + * the dir where the new symlink will be created + * @param name + * name for the new dir. If a node with same name already exists on + * parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE. + * @param dest + * destination of the link + * @param link + * place where to store a pointer to the newly created link. 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_MEM_ERROR + */ +int iso_tree_add_new_symlink(IsoDir *parent, const char *name, + const char *dest, IsoSymlink **link) +{ + IsoSymlink *node; + IsoNode **pos; + time_t now; + + if (parent == NULL || name == NULL || dest == NULL) { + return ISO_NULL_POINTER; + } + + /* find place where to insert */ + pos = &(parent->children); + while (*pos != NULL && strcmp((*pos)->name, name) < 0) { + pos = &((*pos)->next); + } + if (*pos != NULL && !strcmp((*pos)->name, name)) { + /* a node with same name already exists */ + return ISO_NODE_NAME_NOT_UNIQUE; + } + + node = calloc(1, sizeof(IsoSymlink)); + if (node == NULL) { + return ISO_MEM_ERROR; + } + + node->node.refcount = 1; + node->node.type = LIBISO_SYMLINK; + node->node.name = strdup(name); + if (node->node.name == NULL) { + free(node); + return ISO_MEM_ERROR; + } + + node->dest = strdup(dest); + if (node->dest == NULL) { + free(node->node.name); + free(node); + return ISO_MEM_ERROR; + } + + /* permissions from parent */ + node->node.mode = S_IFLNK | 0777; + node->node.uid = parent->node.uid; + node->node.gid = parent->node.gid; + node->node.hidden = parent->node.hidden; + + /* current time */ + now = time(NULL); + node->node.atime = now; + node->node.ctime = now; + node->node.mtime = now; + + /* add to dir */ + node->node.parent = parent; + node->node.next = (*pos)->next; + *pos = (IsoNode*)node; + + if (link) { + *link = node; + } + return ISO_SUCCESS; +}