diff --git a/.cdtproject b/.cdtproject index 785b166..8282bc0 100644 --- a/.cdtproject +++ b/.cdtproject @@ -54,5 +54,16 @@ + + + +make + +check +false +true + + + diff --git a/src/error.h b/src/error.h index f646837..0c93ba8 100644 --- a/src/error.h +++ b/src/error.h @@ -21,6 +21,9 @@ #define ISO_INTERRUPTED -5 #define ISO_WRONG_ARG_VALUE -6 +#define ISO_NODE_ALREADY_ADDED -50 +#define ISO_NODE_NAME_NOT_UNIQUE -51 + #define ISO_FILE_ERROR -100 #define ISO_FILE_ALREADY_OPENNED -101 #define ISO_FILE_ACCESS_DENIED -102 diff --git a/src/libisofs.h b/src/libisofs.h index 056e54f..5c21556 100644 --- a/src/libisofs.h +++ b/src/libisofs.h @@ -84,4 +84,44 @@ void iso_node_set_gid(IsoNode *node, gid_t gid); */ gid_t iso_node_get_gid(const IsoNode *node); +/** + * Add a new node to a dir. Note that this function don't add a new ref to + * the node, so you don't need to free it, it will be automatically freed + * when the dir is deleted. Of course, if you want to keep using the node + * after the dir life, you need to iso_node_ref() it. + * + * @param dir + * the dir where to add the node + * @param child + * the node to add. You must ensure that the node hasn't previously added + * to other dir, and that the node name is unique inside the child. + * Otherwise this function will return a failure, and the child won't be + * inserted. + * @return + * number of nodes in dir if succes, < 0 otherwise + * Possible errors: + * ISO_NULL_POINTER, if dir or child are NULL + * ISO_NODE_ALREADY_ADDED, if child is already added to other dir + * ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists + * ISO_WRONG_ARG_VALUE, if child == dir + */ +int iso_dir_add_node(IsoDir *dir, IsoNode *child); + +/** + * Locate a node inside a given dir. + * + * @param name + * The name of the node + * @param node + * Location for a pointer to the node, it will filled with NULL if the dir + * doesn't have a child with the given name. + * The node will be owned by the dir and shouldn't be unref(). Just call + * iso_node_ref() to get your own reference to the node. + * @return + * 1 node found, 0 child has no such node, < 0 error + * Possible errors: + * ISO_NULL_POINTER, if dir, node or name are NULL + */ +int iso_dir_get_node(IsoDir *dir, const char *name, IsoNode **node); + #endif /*LIBISO_LIBISOFS_H_*/ diff --git a/src/node.c b/src/node.c index 66a4b42..74a53bc 100644 --- a/src/node.c +++ b/src/node.c @@ -6,8 +6,9 @@ * published by the Free Software Foundation. See COPYING file for details. */ -#include "node.h" #include "libisofs.h" +#include "node.h" +#include "error.h" #include #include @@ -120,3 +121,80 @@ gid_t iso_node_get_gid(const IsoNode *node) { return node->gid; } + +/** + * Add a new node to a dir. Note that this function don't add a new ref to + * the node, so you don't need to free it, it will be automatically freed + * when the dir is deleted. Of course, if you want to keep using the node + * after the dir life, you need to iso_node_ref() it. + * + * @param dir + * the dir where to add the node + * @param child + * the node to add. You must ensure that the node hasn't previously added + * to other dir, and that the node name is unique inside the child. + * Otherwise this function will return a failure, and the child won't be + * inserted. + * @return + * number of nodes in dir if succes, < 0 otherwise + */ +int iso_dir_add_node(IsoDir *dir, IsoNode *child) +{ + IsoNode **pos; + + if (dir == NULL || child == NULL) { + return ISO_NULL_POINTER; + } + if ((IsoNode*)dir == child) { + return ISO_WRONG_ARG_VALUE; + } + if (child->parent != NULL) { + return ISO_NODE_ALREADY_ADDED; + } + + pos = &(dir->children); + while (*pos != NULL && strcmp((*pos)->name, child->name) < 0) { + pos = &((*pos)->next); + } + if (*pos != NULL && !strcmp((*pos)->name, child->name)) { + return ISO_NODE_NAME_NOT_UNIQUE; + } + + child->next = *pos; + *pos = child; + child->parent = dir; + + return ++dir->nchildren; +} + +/** + * Locate a node inside a given dir. + * + * @param name + * The name of the node + * @param node + * Location for a pointer to the node, it will filled with NULL if the dir + * doesn't have a child with the given name. + * @return + * 1 node found, 0 child has no such node, < 0 error + */ +int iso_dir_get_node(IsoDir *dir, const char *name, IsoNode **node) +{ + IsoNode *pos; + if (dir == NULL || name == NULL || node == NULL) { + return ISO_NULL_POINTER; + } + + pos = dir->children; + while (pos != NULL && strcmp(pos->name, name) < 0) { + pos = pos->next; + } + + if (pos == NULL || strcmp(pos->name, name)) { + *node = NULL; + return 0; /* node not found */ + } + + *node = pos; + return 1; +} diff --git a/src/node.h b/src/node.h index faacdac..d8af7e5 100644 --- a/src/node.h +++ b/src/node.h @@ -69,7 +69,7 @@ struct Iso_Node int hidden; /**< whether the node will be hidden, see IsoHideNodeFlag */ - struct IsoDir *parent; /**< parent node, NULL for root */ + IsoDir *parent; /**< parent node, NULL for root */ /* * Pointers to the doubled linked list of children in a dir. @@ -85,7 +85,7 @@ struct Iso_Dir IsoNode node; size_t nchildren; /**< The number of children of this directory. */ - struct IsoNode *children; /**< list of children. ptr to first child */ + IsoNode *children; /**< list of children. ptr to first child */ }; struct Iso_File diff --git a/test/test_node.c b/test/test_node.c index 6fa664f..b73edc0 100644 --- a/test/test_node.c +++ b/test/test_node.c @@ -5,9 +5,177 @@ #include "libisofs.h" #include "node.h" #include "test.h" +#include "error.h" + +#include + +static +void test_iso_dir_add_node() +{ + int result; + IsoDir *dir; + IsoNode *node1, *node2, *node3, *node4, *node5; + + /* init dir with default values, not all field need to be initialized */ + dir = malloc(sizeof(IsoDir)); + dir->children = NULL; + dir->nchildren = 0; + + /* 1st node to be added */ + node1 = calloc(1, sizeof(IsoNode)); + node1->name = "Node1"; + + /* addition of node to an empty dir */ + result = iso_dir_add_node(dir, node1); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_EQUAL(dir->nchildren, 1); + CU_ASSERT_PTR_EQUAL(dir->children, node1); + CU_ASSERT_PTR_NULL(node1->next); + CU_ASSERT_PTR_EQUAL(node1->parent, dir); + + /* addition of a node, to be inserted before */ + node2 = calloc(1, sizeof(IsoNode)); + node2->name = "A node to be added first"; + + result = iso_dir_add_node(dir, node2); + CU_ASSERT_EQUAL(result, 2); + CU_ASSERT_EQUAL(dir->nchildren, 2); + CU_ASSERT_PTR_EQUAL(dir->children, node2); + CU_ASSERT_PTR_EQUAL(node2->next, node1); + CU_ASSERT_PTR_NULL(node1->next); + CU_ASSERT_PTR_EQUAL(node2->parent, dir); + + /* addition of a node, to be inserted last */ + node3 = calloc(1, sizeof(IsoNode)); + node3->name = "This node will be inserted last"; + + result = iso_dir_add_node(dir, node3); + CU_ASSERT_EQUAL(result, 3); + CU_ASSERT_EQUAL(dir->nchildren, 3); + CU_ASSERT_PTR_EQUAL(dir->children, node2); + CU_ASSERT_PTR_EQUAL(node2->next, node1); + CU_ASSERT_PTR_EQUAL(node1->next, node3); + CU_ASSERT_PTR_NULL(node3->next); + CU_ASSERT_PTR_EQUAL(node3->parent, dir); + + /* force some failures */ + result = iso_dir_add_node(NULL, node3); + CU_ASSERT_EQUAL(result, ISO_NULL_POINTER); + result = iso_dir_add_node(dir, NULL); + CU_ASSERT_EQUAL(result, ISO_NULL_POINTER); + + result = iso_dir_add_node(dir, (IsoNode*)dir); + CU_ASSERT_EQUAL(result, ISO_WRONG_ARG_VALUE); + + /* a node with same name */ + node4 = calloc(1, sizeof(IsoNode)); + node4->name = "This node will be inserted last"; + result = iso_dir_add_node(dir, node4); + CU_ASSERT_EQUAL(result, ISO_NODE_NAME_NOT_UNIQUE); + CU_ASSERT_EQUAL(dir->nchildren, 3); + CU_ASSERT_PTR_EQUAL(dir->children, node2); + CU_ASSERT_PTR_EQUAL(node2->next, node1); + CU_ASSERT_PTR_EQUAL(node1->next, node3); + CU_ASSERT_PTR_NULL(node3->next); + CU_ASSERT_PTR_NULL(node4->parent); + + /* a node already added to another dir should fail */ + node5 = calloc(1, sizeof(IsoNode)); + node5->name = "other node"; + node5->parent = (IsoDir*)node4; + result = iso_dir_add_node(dir, node5); + CU_ASSERT_EQUAL(result, ISO_NODE_ALREADY_ADDED); + + free(node1); + free(node2); + free(node3); + free(node4); + free(node5); + free(dir); +} + +static +void test_iso_dir_get_node() +{ + int result; + IsoDir *dir; + IsoNode *node1, *node2, *node3; + IsoNode *node; + + /* init dir with default values, not all field need to be initialized */ + dir = malloc(sizeof(IsoDir)); + dir->children = NULL; + dir->nchildren = 0; + + /* try to find a node in an empty dir */ + result = iso_dir_get_node(dir, "a inexistent name", &node); + CU_ASSERT_EQUAL(result, 0); + CU_ASSERT_PTR_NULL(node); + + /* add a node */ + node1 = calloc(1, sizeof(IsoNode)); + node1->name = "Node1"; + result = iso_dir_add_node(dir, node1); + + /* try to find a node not existent */ + result = iso_dir_get_node(dir, "a inexistent name", &node); + CU_ASSERT_EQUAL(result, 0); + CU_ASSERT_PTR_NULL(node); + + /* and an existing one */ + result = iso_dir_get_node(dir, "Node1", &node); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(node, node1); + + /* add another node */ + node2 = calloc(1, sizeof(IsoNode)); + node2->name = "A node to be added first"; + result = iso_dir_add_node(dir, node2); + + /* try to find a node not existent */ + result = iso_dir_get_node(dir, "a inexistent name", &node); + CU_ASSERT_EQUAL(result, 0); + CU_ASSERT_PTR_NULL(node); + + /* and the two existing */ + result = iso_dir_get_node(dir, "Node1", &node); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(node, node1); + result = iso_dir_get_node(dir, "A node to be added first", &node); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(node, node2); + + /* insert another node */ + node3 = calloc(1, sizeof(IsoNode)); + node3->name = "This node will be inserted last"; + result = iso_dir_add_node(dir, node3); + + /* get again */ + result = iso_dir_get_node(dir, "a inexistent name", &node); + CU_ASSERT_EQUAL(result, 0); + CU_ASSERT_PTR_NULL(node); + result = iso_dir_get_node(dir, "This node will be inserted last", &node); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(node, node3); + + /* force some failures */ + result = iso_dir_get_node(NULL, "asas", &node); + CU_ASSERT_EQUAL(result, ISO_NULL_POINTER); + result = iso_dir_get_node(dir, NULL, &node); + CU_ASSERT_EQUAL(result, ISO_NULL_POINTER); + result = iso_dir_get_node(dir, "asas", NULL); + CU_ASSERT_EQUAL(result, ISO_NULL_POINTER); + + free(node1); + free(node2); + free(node3); + free(dir); +} void add_node_suite() { CU_pSuite pSuite = CU_add_suite("Node Test Suite", NULL, NULL); + CU_add_test(pSuite, "iso_dir_add_node()", test_iso_dir_add_node); + CU_add_test(pSuite, "iso_dir_get_node()", test_iso_dir_get_node); }