From b9331ba5c1860c3780d1531320cae756e962a59f Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Sat, 1 Mar 2008 15:57:12 +0100 Subject: [PATCH 01/29] Fix bug in iso_dir_iter_remove(), ticket #127. --- libisofs/node.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libisofs/node.c b/libisofs/node.c index 187e40a..45eafbb 100644 --- a/libisofs/node.c +++ b/libisofs/node.c @@ -522,7 +522,7 @@ int iso_dir_iter_remove(IsoDirIter *iter) if (iter->pos == pos) { return ISO_ERROR; } - while (pos != NULL && pos->next == iter->pos) { + while (pos != NULL && pos->next != iter->pos) { pos = pos->next; } if (pos == NULL) { From 241a7295ba22b4b12b67fe72538d8ee5b4b8275b Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Sat, 1 Mar 2008 16:16:12 +0100 Subject: [PATCH 02/29] Ticket #127 also affects iso_dir_iter_take(). Fixed. --- libisofs/libisofs.h | 2 +- libisofs/node.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 2531f35..c39b6d7 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -2062,7 +2062,7 @@ IsoDir *iso_node_get_parent(IsoNode *node); * you should free the iterator with iso_dir_iter_free. * You musn't delete a child of the same dir, using iso_node_take() or * iso_node_remove(), while you're using the iterator. You can use - * iso_node_take_iter() or iso_node_remove_iter() instead. + * iso_dir_iter_take() or iso_dir_iter_remove() instead. * * You can use the iterator in the way like this * diff --git a/libisofs/node.c b/libisofs/node.c index 45eafbb..96993ba 100644 --- a/libisofs/node.c +++ b/libisofs/node.c @@ -503,7 +503,7 @@ int iso_dir_iter_take(IsoDirIter *iter) if (iter->pos == pos) { return ISO_ERROR; } - while (pos != NULL && pos->next == iter->pos) { + while (pos != NULL && pos->next != iter->pos) { pos = pos->next; } if (pos == NULL) { From b3ef67feb69f84f86939f6f3d410930c370c15f8 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Sat, 1 Mar 2008 16:27:54 +0100 Subject: [PATCH 03/29] Test case for iso_dir_iter_take(). --- test/test_node.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/test/test_node.c b/test/test_node.c index 6c2084a..a638861 100644 --- a/test/test_node.c +++ b/test/test_node.c @@ -527,6 +527,128 @@ void test_iso_dir_get_children() free(dir); } +void test_iso_dir_iter_take() +{ + int result; + IsoDirIter *iter; + IsoDir *dir; + IsoNode *node, *node1, *node2; + + /* init dir with default values, not all field need to be initialized */ + dir = malloc(sizeof(IsoDir)); + dir->children = NULL; + dir->nchildren = 0; + + result = iso_dir_get_children(dir, &iter); + CU_ASSERT_EQUAL(result, 1); + + /* remove on empty dir! */ + result = iso_dir_iter_take(iter); + CU_ASSERT_TRUE(result < 0); /* should fail */ + + iso_dir_iter_free(iter); + + /* 1st node to be added */ + node1 = calloc(1, sizeof(IsoNode)); + node1->name = "Node1"; + result = iso_dir_add_node(dir, node1, 0); + CU_ASSERT_EQUAL(dir->nchildren, 1); + + /* test iteration again */ + result = iso_dir_get_children(dir, &iter); + CU_ASSERT_EQUAL(result, 1); + + /* remove before iso_dir_iter_next() */ + result = iso_dir_iter_take(iter); + CU_ASSERT_TRUE(result < 0); /* should fail */ + + result = iso_dir_iter_next(iter, &node); + + /* this should remove the child */ + result = iso_dir_iter_take(iter); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_EQUAL(dir->nchildren, 0); + CU_ASSERT_PTR_NULL(dir->children); + + result = iso_dir_iter_has_next(iter); + CU_ASSERT_EQUAL(result, 0); + + iso_dir_iter_free(iter); + + /* add two node */ + result = iso_dir_add_node(dir, node1, 0); + CU_ASSERT_EQUAL(dir->nchildren, 1); + + node2 = calloc(1, sizeof(IsoNode)); + node2->name = "A node to be added first"; + result = iso_dir_add_node(dir, node2, 0); + CU_ASSERT_EQUAL(result, 2); + + result = iso_dir_get_children(dir, &iter); + CU_ASSERT_EQUAL(result, 1); + + /* remove before iso_dir_iter_next() */ + result = iso_dir_iter_take(iter); + CU_ASSERT_TRUE(result < 0); /* should fail */ + + /* iter should have two items... */ + result = iso_dir_iter_next(iter, &node); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(node, node2); + + /* remove node 2 */ + result = iso_dir_iter_take(iter); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_EQUAL(dir->nchildren, 1); + CU_ASSERT_PTR_EQUAL(dir->children, node1); + + /* next should still work */ + result = iso_dir_iter_next(iter, &node); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(node, node1); + + /* ...and no more */ + result = iso_dir_iter_has_next(iter); + CU_ASSERT_EQUAL(result, 0); + + result = iso_dir_iter_next(iter, &node); + CU_ASSERT_EQUAL(result, 0); + CU_ASSERT_PTR_NULL(node); + iso_dir_iter_free(iter); + + /* now remove only last child */ + result = iso_dir_add_node(dir, node2, 0); + CU_ASSERT_EQUAL(result, 2); + + result = iso_dir_get_children(dir, &iter); + CU_ASSERT_EQUAL(result, 1); + result = iso_dir_iter_next(iter, &node); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(node, node2); + + result = iso_dir_iter_next(iter, &node); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(node, node1); + + /* take last child */ + result = iso_dir_iter_take(iter); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_EQUAL(dir->nchildren, 1); + CU_ASSERT_PTR_EQUAL(dir->children, node2); + + result = iso_dir_iter_has_next(iter); + CU_ASSERT_EQUAL(result, 0); + + result = iso_dir_iter_next(iter, &node); + CU_ASSERT_EQUAL(result, 0); + CU_ASSERT_PTR_NULL(node); + iso_dir_iter_free(iter); + + free(node1); + free(node2); + free(dir); +} + void test_iso_node_take() { int result; @@ -685,6 +807,7 @@ void add_node_suite() 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); CU_add_test(pSuite, "iso_dir_get_children()", test_iso_dir_get_children); + CU_add_test(pSuite, "iso_dir_iter_take()", test_iso_dir_iter_take); CU_add_test(pSuite, "iso_node_take()", test_iso_node_take); CU_add_test(pSuite, "iso_node_set_name()", test_iso_node_set_name); } From 31a92bd8bd8a5f401586552b4485a7bb02c332ed Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Sat, 1 Mar 2008 17:12:27 +0100 Subject: [PATCH 04/29] Ensure filters are only applied to repeatable Streams. --- libisofs/filter.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libisofs/filter.c b/libisofs/filter.c index 90f2b84..a7f2be6 100644 --- a/libisofs/filter.c +++ b/libisofs/filter.c @@ -33,6 +33,12 @@ int iso_file_add_filter(IsoFile *file, FilterContext *filter, int flag) } original = file->stream; + + if (!iso_stream_is_repeatable(original)) { + /* TODO use custom error */ + return ISO_WRONG_ARG_VALUE; + } + ret = filter->get_filter(filter, original, &filtered); if (ret < 0) { return ret; From 061dce1ec2dff1ebca5513800acde47058fa69d5 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Sat, 1 Mar 2008 17:12:44 +0100 Subject: [PATCH 05/29] s/openned/opened. Deprecate incorrectly spelled errors. --- libisofs/data_source.c | 6 +++--- libisofs/eltorito.c | 6 +++--- libisofs/fs_image.c | 10 +++++----- libisofs/fs_local.c | 8 ++++---- libisofs/libisofs.h | 24 +++++++++++++++--------- libisofs/messages.c | 8 ++++---- libisofs/stream.c | 6 +++--- test/test_stream.c | 4 ++-- 8 files changed, 39 insertions(+), 33 deletions(-) diff --git a/libisofs/data_source.c b/libisofs/data_source.c index 98515c6..4d7c3cc 100644 --- a/libisofs/data_source.c +++ b/libisofs/data_source.c @@ -57,7 +57,7 @@ int ds_open(IsoDataSource *src) data = (struct file_data_src*) src->data; if (data->fd != -1) { - return ISO_FILE_ALREADY_OPENNED; + return ISO_FILE_ALREADY_OPENED; } fd = open(data->path, O_RDONLY); @@ -81,7 +81,7 @@ int ds_close(IsoDataSource *src) data = (struct file_data_src*) src->data; if (data->fd == -1) { - return ISO_FILE_NOT_OPENNED; + return ISO_FILE_NOT_OPENED; } /* close can fail if fd is not valid, but that should never happen */ @@ -102,7 +102,7 @@ static int ds_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer) data = (struct file_data_src*) src->data; if (data->fd == -1) { - return ISO_FILE_NOT_OPENNED; + return ISO_FILE_NOT_OPENED; } /* goes to requested block */ diff --git a/libisofs/eltorito.c b/libisofs/eltorito.c index c7d95e3..441b5c1 100644 --- a/libisofs/eltorito.c +++ b/libisofs/eltorito.c @@ -538,7 +538,7 @@ int catalog_open(IsoStream *stream) data = stream->data; if (data->offset != -1) { - return ISO_FILE_ALREADY_OPENNED; + return ISO_FILE_ALREADY_OPENED; } memset(data->buffer, 0, BLOCK_SIZE); @@ -563,7 +563,7 @@ int catalog_close(IsoStream *stream) data = stream->data; if (data->offset == -1) { - return ISO_FILE_NOT_OPENNED; + return ISO_FILE_NOT_OPENED; } data->offset = -1; return ISO_SUCCESS; @@ -589,7 +589,7 @@ int catalog_read(IsoStream *stream, void *buf, size_t count) data = stream->data; if (data->offset == -1) { - return ISO_FILE_NOT_OPENNED; + return ISO_FILE_NOT_OPENED; } len = MIN(count, BLOCK_SIZE - data->offset); diff --git a/libisofs/fs_image.c b/libisofs/fs_image.c index 817668d..8394cfd 100644 --- a/libisofs/fs_image.c +++ b/libisofs/fs_image.c @@ -474,7 +474,7 @@ int ifs_open(IsoFileSource *src) data = (ImageFileSourceData*)src->data; if (data->opened) { - return ISO_FILE_ALREADY_OPENNED; + return ISO_FILE_ALREADY_OPENED; } if (S_ISDIR(data->info.st_mode)) { @@ -530,7 +530,7 @@ int ifs_close(IsoFileSource *src) data = (ImageFileSourceData*)src->data; if (!data->opened) { - return ISO_FILE_NOT_OPENNED; + return ISO_FILE_NOT_OPENED; } if (data->opened == 2) { @@ -569,7 +569,7 @@ int ifs_close(IsoFileSource *src) * Error codes: * ISO_FILE_ERROR * ISO_NULL_POINTER - * ISO_FILE_NOT_OPENNED + * ISO_FILE_NOT_OPENED * ISO_FILE_IS_DIR * ISO_OUT_OF_MEM * ISO_INTERRUPTED @@ -590,7 +590,7 @@ int ifs_read(IsoFileSource *src, void *buf, size_t count) data = (ImageFileSourceData*)src->data; if (!data->opened) { - return ISO_FILE_NOT_OPENNED; + return ISO_FILE_NOT_OPENED; } else if (data->opened != 1) { return ISO_FILE_IS_DIR; } @@ -644,7 +644,7 @@ int ifs_readdir(IsoFileSource *src, IsoFileSource **child) data = (ImageFileSourceData*)src->data; if (!data->opened) { - return ISO_FILE_NOT_OPENNED; + return ISO_FILE_NOT_OPENED; } else if (data->opened != 2) { return ISO_FILE_IS_NOT_DIR; } diff --git a/libisofs/fs_local.c b/libisofs/fs_local.c index e9a28b7..bf37337 100644 --- a/libisofs/fs_local.c +++ b/libisofs/fs_local.c @@ -190,7 +190,7 @@ int lfs_open(IsoFileSource *src) data = src->data; if (data->openned) { - return ISO_FILE_ALREADY_OPENNED; + return ISO_FILE_ALREADY_OPENED; } /* is a file or a dir ? */ @@ -251,7 +251,7 @@ int lfs_close(IsoFileSource *src) ret = closedir(data->info.dir) == 0 ? ISO_SUCCESS : ISO_FILE_ERROR; break; default: - ret = ISO_FILE_NOT_OPENNED; + ret = ISO_FILE_NOT_OPENED; break; } if (ret == ISO_SUCCESS) { @@ -300,7 +300,7 @@ int lfs_read(IsoFileSource *src, void *buf, size_t count) case 2: /* directory */ return ISO_FILE_IS_DIR; default: - return ISO_FILE_NOT_OPENNED; + return ISO_FILE_NOT_OPENED; } } @@ -341,7 +341,7 @@ int lfs_readdir(IsoFileSource *src, IsoFileSource **child) return ret; } default: - return ISO_FILE_NOT_OPENNED; + return ISO_FILE_NOT_OPENED; } } diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index c39b6d7..ac8f70d 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -519,7 +519,7 @@ struct IsoFileSource_Iface * Opens the source. * @return 1 on success, < 0 on error * Error codes: - * ISO_FILE_ALREADY_OPENNED + * ISO_FILE_ALREADY_OPENED * ISO_FILE_ACCESS_DENIED * ISO_FILE_BAD_PATH * ISO_FILE_DOESNT_EXIST @@ -535,7 +535,7 @@ struct IsoFileSource_Iface * Error codes: * ISO_FILE_ERROR * ISO_NULL_POINTER - * ISO_FILE_NOT_OPENNED + * ISO_FILE_NOT_OPENED */ int (*close)(IsoFileSource *src); @@ -552,7 +552,7 @@ struct IsoFileSource_Iface * Error codes: * ISO_FILE_ERROR * ISO_NULL_POINTER - * ISO_FILE_NOT_OPENNED + * ISO_FILE_NOT_OPENED * ISO_WRONG_ARG_VALUE -> if count == 0 * ISO_FILE_IS_DIR * ISO_OUT_OF_MEM @@ -578,7 +578,7 @@ struct IsoFileSource_Iface * Error codes: * ISO_FILE_ERROR * ISO_NULL_POINTER - * ISO_FILE_NOT_OPENNED + * ISO_FILE_NOT_OPENED * ISO_FILE_IS_NOT_DIR * ISO_OUT_OF_MEM */ @@ -2893,7 +2893,7 @@ int iso_file_source_stat(IsoFileSource *src, struct stat *info); * Opens the source. * @return 1 on success, < 0 on error * Error codes: - * ISO_FILE_ALREADY_OPENNED + * ISO_FILE_ALREADY_OPENED * ISO_FILE_ACCESS_DENIED * ISO_FILE_BAD_PATH * ISO_FILE_DOESNT_EXIST @@ -2911,7 +2911,7 @@ int iso_file_source_open(IsoFileSource *src); * Error codes: * ISO_FILE_ERROR * ISO_NULL_POINTER - * ISO_FILE_NOT_OPENNED + * ISO_FILE_NOT_OPENED * * @since 0.6.2 */ @@ -2937,7 +2937,7 @@ int iso_file_source_close(IsoFileSource *src); * Error codes: * ISO_FILE_ERROR * ISO_NULL_POINTER - * ISO_FILE_NOT_OPENNED + * ISO_FILE_NOT_OPENED * ISO_WRONG_ARG_VALUE -> if count == 0 * ISO_FILE_IS_DIR * ISO_OUT_OF_MEM @@ -2965,7 +2965,7 @@ int iso_file_source_read(IsoFileSource *src, void *buf, size_t count); * Error codes: * ISO_FILE_ERROR * ISO_NULL_POINTER - * ISO_FILE_NOT_OPENNED + * ISO_FILE_NOT_OPENED * ISO_FILE_IS_NOT_DIR * ISO_OUT_OF_MEM * @@ -3280,6 +3280,9 @@ void iso_stream_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id, #define ISO_FILE_ERROR 0xE830FF80 /** Trying to open an already openned file (FAILURE,HIGH, -129) */ +#define ISO_FILE_ALREADY_OPENED 0xE830FF7F + +/* @deprecated use ISO_FILE_ALREADY_OPENED instead */ #define ISO_FILE_ALREADY_OPENNED 0xE830FF7F /** Access to file is not allowed (FAILURE,HIGH, -130) */ @@ -3292,7 +3295,10 @@ void iso_stream_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id, #define ISO_FILE_DOESNT_EXIST 0xE830FF7C /** Trying to read or close a file not openned (FAILURE,HIGH, -133) */ -#define ISO_FILE_NOT_OPENNED 0xE830FF7B +#define ISO_FILE_NOT_OPENED 0xE830FF7B + +/* @deprecated use ISO_FILE_NOT_OPENED instead */ +#define ISO_FILE_NOT_OPENNED ISO_FILE_NOT_OPENED /** Directory used where no dir is expected (FAILURE,HIGH, -134) */ #define ISO_FILE_IS_DIR 0xE830FF7A diff --git a/libisofs/messages.c b/libisofs/messages.c index 44416ff..8b55b45 100644 --- a/libisofs/messages.c +++ b/libisofs/messages.c @@ -136,16 +136,16 @@ const char *iso_error_to_msg(int errcode) return "Trying to use an invalid file as boot image"; case ISO_FILE_ERROR: return "Error on file operation"; - case ISO_FILE_ALREADY_OPENNED: - return "Trying to open an already openned file"; + case ISO_FILE_ALREADY_OPENED: + return "Trying to open an already opened file"; case ISO_FILE_ACCESS_DENIED: return "Access to file is not allowed"; case ISO_FILE_BAD_PATH: return "Incorrect path to file"; case ISO_FILE_DOESNT_EXIST: return "The file does not exist in the filesystem"; - case ISO_FILE_NOT_OPENNED: - return "Trying to read or close a file not openned"; + case ISO_FILE_NOT_OPENED: + return "Trying to read or close a file not opened"; case ISO_FILE_IS_DIR: return "Directory used where no dir is expected"; case ISO_FILE_READ_ERROR: diff --git a/libisofs/stream.c b/libisofs/stream.c index aa84208..6058e89 100644 --- a/libisofs/stream.c +++ b/libisofs/stream.c @@ -231,7 +231,7 @@ int mem_open(IsoStream *stream) } data = (MemStreamData*)stream->data; if (data->offset != -1) { - return ISO_FILE_ALREADY_OPENNED; + return ISO_FILE_ALREADY_OPENED; } data->offset = 0; return ISO_SUCCESS; @@ -246,7 +246,7 @@ int mem_close(IsoStream *stream) } data = (MemStreamData*)stream->data; if (data->offset == -1) { - return ISO_FILE_NOT_OPENNED; + return ISO_FILE_NOT_OPENED; } data->offset = -1; return ISO_SUCCESS; @@ -275,7 +275,7 @@ int mem_read(IsoStream *stream, void *buf, size_t count) data = stream->data; if (data->offset == -1) { - return ISO_FILE_NOT_OPENNED; + return ISO_FILE_NOT_OPENED; } if (data->offset >= data->size) { diff --git a/test/test_stream.c b/test/test_stream.c index 35e1466..a2c3543 100644 --- a/test/test_stream.c +++ b/test/test_stream.c @@ -43,13 +43,13 @@ void test_mem_open() /* try to open an already opened stream */ ret = iso_stream_open(stream); - CU_ASSERT_EQUAL(ret, ISO_FILE_ALREADY_OPENNED); + CU_ASSERT_EQUAL(ret, ISO_FILE_ALREADY_OPENED); ret = iso_stream_close(stream); CU_ASSERT_EQUAL(ret, 1); ret = iso_stream_close(stream); - CU_ASSERT_EQUAL(ret, ISO_FILE_NOT_OPENNED); + CU_ASSERT_EQUAL(ret, ISO_FILE_NOT_OPENED); iso_stream_unref(stream); } From 955f2f9c24711c8aff5b550b15e66e9aece3d2b0 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Sun, 2 Mar 2008 17:08:59 +0100 Subject: [PATCH 06/29] Added a test case that shows 2nd bug found by Thomas in ticket #126. --- test/test_node.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/test/test_node.c b/test/test_node.c index a638861..8b59fb6 100644 --- a/test/test_node.c +++ b/test/test_node.c @@ -532,7 +532,7 @@ void test_iso_dir_iter_take() int result; IsoDirIter *iter; IsoDir *dir; - IsoNode *node, *node1, *node2; + IsoNode *node, *node1, *node2, *node3; /* init dir with default values, not all field need to be initialized */ dir = malloc(sizeof(IsoDir)); @@ -644,8 +644,35 @@ void test_iso_dir_iter_take() CU_ASSERT_PTR_NULL(node); iso_dir_iter_free(iter); + /* Ok, now another situation. Modification of dir during iteration */ + result = iso_dir_add_node(dir, node1, 0); + CU_ASSERT_EQUAL(result, 2); + + result = iso_dir_get_children(dir, &iter); + CU_ASSERT_EQUAL(result, 1); + result = iso_dir_iter_next(iter, &node); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(node, node2); + + /* returned dir is node2, it should be the node taken next, but + * let's insert a node after node2 and before node1 */ + node3 = calloc(1, sizeof(IsoNode)); + node3->name = "A node to be added second"; + result = iso_dir_add_node(dir, node3, 0); + CU_ASSERT_EQUAL(dir->nchildren, 3); + + /* is the node 2 the removed one? */ + result = iso_dir_iter_take(iter); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_EQUAL(dir->nchildren, 2); + CU_ASSERT_PTR_EQUAL(dir->children, node3); + CU_ASSERT_PTR_EQUAL(node3->next, node1); + + iso_dir_iter_free(iter); + free(node1); free(node2); + free(node3); free(dir); } From 6d633caadbfb9f8cbe9f80795d2bc4e98896b8f0 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Sun, 2 Mar 2008 18:20:19 +0100 Subject: [PATCH 07/29] Improved DirIter implementation. --- libisofs/node.c | 130 +++++++++++++++++++++++-------- libisofs/node.h | 9 ++- test/test_node.c | 193 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 296 insertions(+), 36 deletions(-) diff --git a/libisofs/node.c b/libisofs/node.c index 96993ba..9ba1c66 100644 --- a/libisofs/node.c +++ b/libisofs/node.c @@ -366,8 +366,9 @@ int iso_dir_get_children(const IsoDir *dir, IsoDirIter **iter) return ISO_OUT_OF_MEM; } - it->dir = dir; - it->pos = dir->children; + it->dir = (IsoDir*)dir; + it->pos = NULL; + it->flag = 0x00; *iter = it; return ISO_SUCCESS; @@ -375,21 +376,47 @@ int iso_dir_get_children(const IsoDir *dir, IsoDirIter **iter) int iso_dir_iter_next(IsoDirIter *iter, IsoNode **node) { - IsoNode *n; if (iter == NULL || node == NULL) { return ISO_NULL_POINTER; } - n = iter->pos; - if (n == NULL) { - *node = NULL; - return 0; + + /* clear next flag */ + iter->flag &= ~0x01; + + if (iter->pos == NULL) { + /* we are at the beginning */ + iter->pos = iter->dir->children; + if (iter->pos == NULL) { + /* empty dir */ + *node = NULL; + return 0; + } + } else { + if (iter->pos->parent != iter->dir) { + /* this can happen if the node has been moved to another dir */ + /* TODO specific error */ + return ISO_ERROR; + } + if (iter->pos->next == NULL) { + /* no more children */ + *node = NULL; + return 0; + } else { + /* free reference to current position */ + iso_node_unref(iter->pos); /* it is never last ref!! */ + + /* advance a position */ + iter->pos = iter->pos->next; + } } - if (n->parent != iter->dir) { - /* this can happen if the node has been moved to another dir */ - return ISO_ERROR; - } - *node = n; - iter->pos = n->next; + + /* ok, take a ref to the current position, to prevent internal errors + * if deleted somewhere */ + iso_node_ref(iter->pos); + iter->flag |= 0x01; /* set next flag */ + + /* return pointed node */ + *node = iter->pos; return ISO_SUCCESS; } @@ -406,11 +433,18 @@ int iso_dir_iter_has_next(IsoDirIter *iter) if (iter == NULL) { return ISO_NULL_POINTER; } - return iter->pos == NULL ? 0 : 1; + if (iter->pos == NULL) { + return iter->dir->children == NULL ? 0 : 1; + } else { + return iter->pos->next == NULL ? 0 : 1; + } } void iso_dir_iter_free(IsoDirIter *iter) { + if (iter->pos != NULL) { + iso_node_unref(iter->pos); + } free(iter); } @@ -448,7 +482,7 @@ int iso_node_take(IsoNode *node) pos = iso_dir_find_node(dir, node); if (pos == NULL) { /* should never occur */ - return ISO_ERROR; + return ISO_ASSERT_FAILURE; } *pos = node->next; node->parent = NULL; @@ -494,41 +528,75 @@ IsoDir *iso_node_get_parent(IsoNode *node) /* TODO #00005 optimize iso_dir_iter_take */ int iso_dir_iter_take(IsoDirIter *iter) { - IsoNode *pos; + IsoNode *pos, *pre; if (iter == NULL) { return ISO_NULL_POINTER; } - - pos = iter->dir->children; - if (iter->pos == pos) { - return ISO_ERROR; + + if (!(iter->flag & 0x01)) { + return ISO_ERROR; /* next not called or end of dir */ } - while (pos != NULL && pos->next != iter->pos) { + + if (iter->pos == NULL) { + return ISO_ASSERT_FAILURE; + } + + /* clear next flag */ + iter->flag &= ~0x01; + + pos = iter->dir->children; + pre = NULL; + while (pos != NULL && pos != iter->pos) { + pre = pos; pos = pos->next; } if (pos == NULL) { - return ISO_ERROR; + return ISO_ERROR; /* node not in dir */ } - return iso_node_take(pos); + + if (pos != iter->pos) { + return ISO_ASSERT_FAILURE; + } + + /* dispose iterator reference */ + iso_node_unref(iter->pos); + + if (pre == NULL) { + /* node is a first position */ + iter->dir->children = pos->next; + iter->pos = NULL; + } else { + pre->next = pos->next; + iter->pos = pre; + iso_node_ref(pre); /* take iter ref */ + } + + /* take pos */ + pos->parent = NULL; + pos->next = NULL; + iter->dir->nchildren--; + return ISO_SUCCESS; } int iso_dir_iter_remove(IsoDirIter *iter) { + int ret; IsoNode *pos; + if (iter == NULL) { return ISO_NULL_POINTER; } - pos = iter->dir->children; + pos = iter->pos; + + ret = iso_dir_iter_take(iter); + if (ret == ISO_SUCCESS) { + /* remove node */ + iso_node_unref(pos); + } if (iter->pos == pos) { return ISO_ERROR; } - while (pos != NULL && pos->next != iter->pos) { - pos = pos->next; - } - if (pos == NULL) { - return ISO_ERROR; - } - return iso_node_remove(pos); + return ret; } /** diff --git a/libisofs/node.h b/libisofs/node.h index b2764f9..0a77169 100644 --- a/libisofs/node.h +++ b/libisofs/node.h @@ -153,8 +153,15 @@ struct Iso_Special */ struct Iso_Dir_Iter { - const IsoDir *dir; + IsoDir *dir; + + /* points to the last visited child, to NULL before start */ IsoNode *pos; + + /* Some control flags. + * bit 0 -> 1 if next called, 0 reseted at start or on deletion + */ + int flag; }; int iso_node_new_root(IsoDir **root); diff --git a/test/test_node.c b/test/test_node.c index 8b59fb6..7c05d8f 100644 --- a/test/test_node.c +++ b/test/test_node.c @@ -410,6 +410,7 @@ void test_iso_dir_get_node() free(dir); } +static void test_iso_dir_get_children() { int result; @@ -436,6 +437,7 @@ void test_iso_dir_get_children() /* 1st node to be added */ node1 = calloc(1, sizeof(IsoNode)); node1->name = "Node1"; + node1->refcount = 1; result = iso_dir_add_node(dir, node1, 0); CU_ASSERT_EQUAL(dir->nchildren, 1); @@ -461,6 +463,7 @@ void test_iso_dir_get_children() /* add another node */ node2 = calloc(1, sizeof(IsoNode)); node2->name = "A node to be added first"; + node2->refcount = 1; result = iso_dir_add_node(dir, node2, 0); CU_ASSERT_EQUAL(result, 2); @@ -490,6 +493,7 @@ void test_iso_dir_get_children() /* addition of a 3rd node, to be inserted last */ node3 = calloc(1, sizeof(IsoNode)); node3->name = "This node will be inserted last"; + node3->refcount = 1; result = iso_dir_add_node(dir, node3, 0); CU_ASSERT_EQUAL(result, 3); @@ -520,13 +524,18 @@ void test_iso_dir_get_children() CU_ASSERT_EQUAL(result, 0); CU_ASSERT_PTR_NULL(node); iso_dir_iter_free(iter); - + + /* assert correct refcount */ + CU_ASSERT_EQUAL(node1->refcount, 1); free(node1); + CU_ASSERT_EQUAL(node2->refcount, 1); free(node2); + CU_ASSERT_EQUAL(node3->refcount, 1); free(node3); free(dir); } +static void test_iso_dir_iter_take() { int result; @@ -551,6 +560,7 @@ void test_iso_dir_iter_take() /* 1st node to be added */ node1 = calloc(1, sizeof(IsoNode)); node1->name = "Node1"; + node1->refcount = 1; result = iso_dir_add_node(dir, node1, 0); CU_ASSERT_EQUAL(dir->nchildren, 1); @@ -563,7 +573,7 @@ void test_iso_dir_iter_take() CU_ASSERT_TRUE(result < 0); /* should fail */ result = iso_dir_iter_next(iter, &node); - + /* this should remove the child */ result = iso_dir_iter_take(iter); CU_ASSERT_EQUAL(result, 1); @@ -581,6 +591,7 @@ void test_iso_dir_iter_take() node2 = calloc(1, sizeof(IsoNode)); node2->name = "A node to be added first"; + node2->refcount = 1; result = iso_dir_add_node(dir, node2, 0); CU_ASSERT_EQUAL(result, 2); @@ -658,6 +669,7 @@ void test_iso_dir_iter_take() * let's insert a node after node2 and before node1 */ node3 = calloc(1, sizeof(IsoNode)); node3->name = "A node to be added second"; + node3->refcount = 1; result = iso_dir_add_node(dir, node3, 0); CU_ASSERT_EQUAL(dir->nchildren, 3); @@ -669,13 +681,178 @@ void test_iso_dir_iter_take() CU_ASSERT_PTR_EQUAL(node3->next, node1); iso_dir_iter_free(iter); - + + /* assert correct refcount */ + CU_ASSERT_EQUAL(node1->refcount, 1); free(node1); + CU_ASSERT_EQUAL(node2->refcount, 1); free(node2); + CU_ASSERT_EQUAL(node3->refcount, 1); free(node3); free(dir); } +static +void test_iso_dir_iter_remove() +{ + int result; + IsoDirIter *iter; + IsoDir *dir; + IsoNode *node, *node1, *node2, *node3; + + /* init dir with default values, not all field need to be initialized */ + dir = malloc(sizeof(IsoDir)); + dir->children = NULL; + dir->nchildren = 0; + + result = iso_dir_get_children(dir, &iter); + CU_ASSERT_EQUAL(result, 1); + + /* remove on empty dir! */ + result = iso_dir_iter_remove(iter); + CU_ASSERT_TRUE(result < 0); /* should fail */ + + iso_dir_iter_free(iter); + + /* 1st node to be added */ + node1 = calloc(1, sizeof(IsoNode)); + node1->name = "Node1"; + node1->refcount = 2; + result = iso_dir_add_node(dir, node1, 0); + CU_ASSERT_EQUAL(dir->nchildren, 1); + + /* test iteration again */ + result = iso_dir_get_children(dir, &iter); + CU_ASSERT_EQUAL(result, 1); + + /* remove before iso_dir_iter_next() */ + result = iso_dir_iter_remove(iter); + CU_ASSERT_TRUE(result < 0); /* should fail */ + + result = iso_dir_iter_next(iter, &node); + + /* this should remove the child */ + result = iso_dir_iter_remove(iter); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_EQUAL(dir->nchildren, 0); + CU_ASSERT_PTR_NULL(dir->children); + + result = iso_dir_iter_has_next(iter); + CU_ASSERT_EQUAL(result, 0); + + iso_dir_iter_free(iter); + + /* add two node */ + node1->refcount++; /* was removed above */ + result = iso_dir_add_node(dir, node1, 0); + CU_ASSERT_EQUAL(dir->nchildren, 1); + + node2 = calloc(1, sizeof(IsoNode)); + node2->name = "A node to be added first"; + node2->refcount = 2; + result = iso_dir_add_node(dir, node2, 0); + CU_ASSERT_EQUAL(result, 2); + + result = iso_dir_get_children(dir, &iter); + CU_ASSERT_EQUAL(result, 1); + + /* remove before iso_dir_iter_next() */ + result = iso_dir_iter_remove(iter); + CU_ASSERT_TRUE(result < 0); /* should fail */ + + /* iter should have two items... */ + result = iso_dir_iter_next(iter, &node); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(node, node2); + + /* remove node 2 */ + result = iso_dir_iter_remove(iter); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_EQUAL(dir->nchildren, 1); + CU_ASSERT_PTR_EQUAL(dir->children, node1); + + /* next should still work */ + result = iso_dir_iter_next(iter, &node); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(node, node1); + + /* ...and no more */ + result = iso_dir_iter_has_next(iter); + CU_ASSERT_EQUAL(result, 0); + + result = iso_dir_iter_next(iter, &node); + CU_ASSERT_EQUAL(result, 0); + CU_ASSERT_PTR_NULL(node); + iso_dir_iter_free(iter); + + /* now remove only last child */ + node2->refcount++; /* was removed above */ + result = iso_dir_add_node(dir, node2, 0); + CU_ASSERT_EQUAL(result, 2); + + result = iso_dir_get_children(dir, &iter); + CU_ASSERT_EQUAL(result, 1); + result = iso_dir_iter_next(iter, &node); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(node, node2); + + result = iso_dir_iter_next(iter, &node); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(node, node1); + + /* take last child */ + result = iso_dir_iter_remove(iter); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_EQUAL(dir->nchildren, 1); + CU_ASSERT_PTR_EQUAL(dir->children, node2); + + result = iso_dir_iter_has_next(iter); + CU_ASSERT_EQUAL(result, 0); + + result = iso_dir_iter_next(iter, &node); + CU_ASSERT_EQUAL(result, 0); + CU_ASSERT_PTR_NULL(node); + iso_dir_iter_free(iter); + + /* Ok, now another situation. Modification of dir during iteration */ + node1->refcount++; + result = iso_dir_add_node(dir, node1, 0); + CU_ASSERT_EQUAL(result, 2); + + result = iso_dir_get_children(dir, &iter); + CU_ASSERT_EQUAL(result, 1); + result = iso_dir_iter_next(iter, &node); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(node, node2); + + /* returned dir is node2, it should be the node taken next, but + * let's insert a node after node2 and before node1 */ + node3 = calloc(1, sizeof(IsoNode)); + node3->name = "A node to be added second"; + node3->refcount = 2; + result = iso_dir_add_node(dir, node3, 0); + CU_ASSERT_EQUAL(dir->nchildren, 3); + + /* is the node 2 the removed one? */ + result = iso_dir_iter_remove(iter); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_EQUAL(dir->nchildren, 2); + CU_ASSERT_PTR_EQUAL(dir->children, node3); + CU_ASSERT_PTR_EQUAL(node3->next, node1); + + iso_dir_iter_free(iter); + + /* assert correct refcount */ + CU_ASSERT_EQUAL(node1->refcount, 2); /* node1 is not removed */ + free(node1); + CU_ASSERT_EQUAL(node2->refcount, 1); + free(node2); + CU_ASSERT_EQUAL(node3->refcount, 2); /* node3 is not removed */ + free(node3); + free(dir); +} + +static void test_iso_node_take() { int result; @@ -690,6 +867,7 @@ void test_iso_node_take() /* 1st node to be added */ node1 = calloc(1, sizeof(IsoNode)); node1->name = "Node1"; + node1->refcount = 1; /* addition of node to an empty dir */ result = iso_dir_add_node(dir, node1, 0); @@ -710,6 +888,7 @@ void test_iso_node_take() /* addition of a 2nd node, to be inserted before */ node2 = calloc(1, sizeof(IsoNode)); node2->name = "A node to be added first"; + node2->refcount = 1; result = iso_dir_add_node(dir, node2, 0); CU_ASSERT_EQUAL(result, 2); @@ -744,6 +923,7 @@ void test_iso_node_take() /* ...and a 3rd child, to be inserted last */ node3 = calloc(1, sizeof(IsoNode)); node3->name = "This node will be inserted last"; + node3->refcount = 1; result = iso_dir_add_node(dir, node3, 0); CU_ASSERT_EQUAL(result, 3); @@ -758,9 +938,13 @@ void test_iso_node_take() CU_ASSERT_PTR_EQUAL(node3->parent, dir); CU_ASSERT_PTR_NULL(node1->next); CU_ASSERT_PTR_NULL(node1->parent); - + + /* assert correct refcount */ + CU_ASSERT_EQUAL(node1->refcount, 1); free(node1); + CU_ASSERT_EQUAL(node2->refcount, 1); free(node2); + CU_ASSERT_EQUAL(node3->refcount, 1); free(node3); free(dir); } @@ -835,6 +1019,7 @@ void add_node_suite() CU_add_test(pSuite, "iso_dir_get_node()", test_iso_dir_get_node); CU_add_test(pSuite, "iso_dir_get_children()", test_iso_dir_get_children); CU_add_test(pSuite, "iso_dir_iter_take()", test_iso_dir_iter_take); + CU_add_test(pSuite, "iso_dir_iter_remove()", test_iso_dir_iter_remove); CU_add_test(pSuite, "iso_node_take()", test_iso_node_take); CU_add_test(pSuite, "iso_node_set_name()", test_iso_node_set_name); } From d894d3719b4d2b60d6895354fd1cb98d1fe4160c Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Sun, 2 Mar 2008 18:21:58 +0100 Subject: [PATCH 08/29] Some little unit test assert. --- test/test_node.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test_node.c b/test/test_node.c index 7c05d8f..1211028 100644 --- a/test/test_node.c +++ b/test/test_node.c @@ -612,6 +612,10 @@ void test_iso_dir_iter_take() CU_ASSERT_EQUAL(result, 1); CU_ASSERT_EQUAL(dir->nchildren, 1); CU_ASSERT_PTR_EQUAL(dir->children, node1); + + /* we can't take two times without next()!! */ + result = iso_dir_iter_take(iter); + CU_ASSERT_TRUE(result < 0); /* should fail */ /* next should still work */ result = iso_dir_iter_next(iter, &node); From c75f1a430ebc4b4f5742353fb5cd7dd7f7510a84 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Mon, 3 Mar 2008 20:42:06 +0100 Subject: [PATCH 09/29] Added function to get the lba of an old image file. --- libisofs/libisofs.h | 29 +++++++++++++++++++++++++ libisofs/node.c | 52 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index ac8f70d..ee80fd5 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -2230,6 +2230,35 @@ off_t iso_file_get_size(IsoFile *file); */ IsoStream *iso_file_get_stream(IsoFile *file); +/** + * Get the block lba of a file node, if it was imported from an old image. + * + * @param file + * The file + * @param lba + * Will be filled with the kba + * @param flag + * Reserved for future usage, submit 0 + * @return + * 1 if lba is valid (file comes from old image), 0 if file was newly + * added, i.e. it does not come from an old image, < 0 error + * + * @since 0.6.4 + */ +int iso_file_get_old_image_lba(IsoFile *file, uint32_t *lba, int flag); + +/* + * Like iso_file_get_old_image_lba(), but take an IsoNode. + * + * @return + * 1 if lba is valid (file comes from old image), 0 if file was newly + * added, i.e. it does not come from an old image, 2 node type has no + * LBA (no regular file), < 0 error + * + * @since 0.6.4 + */ +int iso_node_get_old_image_lba(IsoNode *node, uint32_t *lba, int flag); + /** * Add a new directory to the iso tree. Permissions, owner and hidden atts * are taken from parent, you can modify them later. diff --git a/libisofs/node.c b/libisofs/node.c index 9ba1c66..4f6f77a 100644 --- a/libisofs/node.c +++ b/libisofs/node.c @@ -686,6 +686,58 @@ IsoStream *iso_file_get_stream(IsoFile *file) return file->stream; } +/** + * Get the block lba of a file node, if it was imported from an old image. + * + * @param file + * The file + * @param lba + * Will be filled with the kba + * @param flag + * Reserved for future usage, submit 0 + * @return + * 1 if lba is valid (file comes from old image), 0 if file was newly + * added, i.e. it does not come from an old image, < 0 error + * + * @since 0.6.4 + */ +int iso_file_get_old_image_lba(IsoFile *file, uint32_t *lba, int flag) +{ + if (file == NULL || lba == NULL) { + return ISO_NULL_POINTER; + } + if (flag != 0) { + return ISO_WRONG_ARG_VALUE; + } + if (file->msblock != 0) { + *lba = file->msblock; + return 1; + } + return 0; +} + +/* + * Like iso_file_get_old_image_lba(), but take an IsoNode. + * + * @return + * 1 if lba is valid (file comes from old image), 0 if file was newly + * added, i.e. it does not come from an old image, 2 node type has no + * LBA (no regular file), < 0 error + * + * @since 0.6.4 + */ +int iso_node_get_old_image_lba(IsoNode *node, uint32_t *lba, int flag) +{ + if (node == NULL) { + return ISO_NULL_POINTER; + } + if (ISO_NODE_IS_FILE(node)) { + return iso_file_get_old_image_lba((IsoFile*)node, lba, flag); + } else { + return 2; + } +} + /** * Check if a given name is valid for an iso node. * From dd02d1d97685c020115a7a8885ef0121e0ed4098 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Mon, 3 Mar 2008 21:18:54 +0100 Subject: [PATCH 10/29] Convert IsoDirIter in an interface. --- libisofs/node.c | 192 +++++++++++++++++++++++++++++++++++------------- libisofs/node.h | 26 +++++-- 2 files changed, 158 insertions(+), 60 deletions(-) diff --git a/libisofs/node.c b/libisofs/node.c index 4f6f77a..9276ef8 100644 --- a/libisofs/node.c +++ b/libisofs/node.c @@ -15,6 +15,17 @@ #include #include +struct dir_iter_data +{ + /* points to the last visited child, to NULL before start */ + IsoNode *pos; + + /* Some control flags. + * bit 0 -> 1 if next called, 0 reseted at start or on deletion + */ + int flag; +}; + /** * Increments the reference counting of the given node. */ @@ -354,69 +365,53 @@ int iso_dir_get_children_count(IsoDir *dir) return dir->nchildren; } -int iso_dir_get_children(const IsoDir *dir, IsoDirIter **iter) -{ - IsoDirIter *it; - - if (dir == NULL || iter == NULL) { - return ISO_NULL_POINTER; - } - it = malloc(sizeof(IsoDirIter)); - if (it == NULL) { - return ISO_OUT_OF_MEM; - } - - it->dir = (IsoDir*)dir; - it->pos = NULL; - it->flag = 0x00; - - *iter = it; - return ISO_SUCCESS; -} - -int iso_dir_iter_next(IsoDirIter *iter, IsoNode **node) +static +int iter_next(IsoDirIter *iter, IsoNode **node) { + struct dir_iter_data *data; if (iter == NULL || node == NULL) { return ISO_NULL_POINTER; } - /* clear next flag */ - iter->flag &= ~0x01; + data = iter->data; - if (iter->pos == NULL) { + /* clear next flag */ + data->flag &= ~0x01; + + if (data->pos == NULL) { /* we are at the beginning */ - iter->pos = iter->dir->children; - if (iter->pos == NULL) { + data->pos = iter->dir->children; + if (data->pos == NULL) { /* empty dir */ *node = NULL; return 0; } } else { - if (iter->pos->parent != iter->dir) { + if (data->pos->parent != iter->dir) { /* this can happen if the node has been moved to another dir */ /* TODO specific error */ return ISO_ERROR; } - if (iter->pos->next == NULL) { + if (data->pos->next == NULL) { /* no more children */ *node = NULL; return 0; } else { /* free reference to current position */ - iso_node_unref(iter->pos); /* it is never last ref!! */ + iso_node_unref(data->pos); /* it is never last ref!! */ /* advance a position */ - iter->pos = iter->pos->next; + data->pos = data->pos->next; } } /* ok, take a ref to the current position, to prevent internal errors * if deleted somewhere */ - iso_node_ref(iter->pos); - iter->flag |= 0x01; /* set next flag */ + iso_node_ref(data->pos); + data->flag |= 0x01; /* set next flag */ /* return pointed node */ - *node = iter->pos; + *node = data->pos; return ISO_SUCCESS; } @@ -428,24 +423,30 @@ int iso_dir_iter_next(IsoDirIter *iter, IsoNode **node) * Possible errors: * ISO_NULL_POINTER, if iter is NULL */ -int iso_dir_iter_has_next(IsoDirIter *iter) +static +int iter_has_next(IsoDirIter *iter) { + struct dir_iter_data *data; if (iter == NULL) { return ISO_NULL_POINTER; } - if (iter->pos == NULL) { + data = iter->data; + if (data->pos == NULL) { return iter->dir->children == NULL ? 0 : 1; } else { - return iter->pos->next == NULL ? 0 : 1; + return data->pos->next == NULL ? 0 : 1; } } -void iso_dir_iter_free(IsoDirIter *iter) +static +void iter_free(IsoDirIter *iter) { - if (iter->pos != NULL) { - iso_node_unref(iter->pos); + struct dir_iter_data *data; + data = iter->data; + if (data->pos != NULL) { + iso_node_unref(data->pos); } - free(iter); + free(data); } static IsoNode** iso_dir_find_node(IsoDir *dir, IsoNode *node) @@ -526,27 +527,31 @@ IsoDir *iso_node_get_parent(IsoNode *node) } /* TODO #00005 optimize iso_dir_iter_take */ -int iso_dir_iter_take(IsoDirIter *iter) +static +int iter_take(IsoDirIter *iter) { + struct dir_iter_data *data; IsoNode *pos, *pre; if (iter == NULL) { return ISO_NULL_POINTER; } - if (!(iter->flag & 0x01)) { + data = iter->data; + + if (!(data->flag & 0x01)) { return ISO_ERROR; /* next not called or end of dir */ } - if (iter->pos == NULL) { + if (data->pos == NULL) { return ISO_ASSERT_FAILURE; } /* clear next flag */ - iter->flag &= ~0x01; + data->flag &= ~0x01; pos = iter->dir->children; pre = NULL; - while (pos != NULL && pos != iter->pos) { + while (pos != NULL && pos != data->pos) { pre = pos; pos = pos->next; } @@ -554,20 +559,20 @@ int iso_dir_iter_take(IsoDirIter *iter) return ISO_ERROR; /* node not in dir */ } - if (pos != iter->pos) { + if (pos != data->pos) { return ISO_ASSERT_FAILURE; } /* dispose iterator reference */ - iso_node_unref(iter->pos); + iso_node_unref(data->pos); if (pre == NULL) { /* node is a first position */ iter->dir->children = pos->next; - iter->pos = NULL; + data->pos = NULL; } else { pre->next = pos->next; - iter->pos = pre; + data->pos = pre; iso_node_ref(pre); /* take iter ref */ } @@ -578,27 +583,108 @@ int iso_dir_iter_take(IsoDirIter *iter) return ISO_SUCCESS; } -int iso_dir_iter_remove(IsoDirIter *iter) +static +int iter_remove(IsoDirIter *iter) { int ret; IsoNode *pos; + struct dir_iter_data *data; if (iter == NULL) { return ISO_NULL_POINTER; } - pos = iter->pos; + data = iter->data; + pos = data->pos; - ret = iso_dir_iter_take(iter); + ret = iter_take(iter); if (ret == ISO_SUCCESS) { /* remove node */ iso_node_unref(pos); } - if (iter->pos == pos) { + if (data->pos == pos) { return ISO_ERROR; } return ret; } +static +struct iso_dir_iter_iface iter_class = { + iter_next, + iter_has_next, + iter_free, + iter_take, + iter_remove +}; + + +int iso_dir_get_children(const IsoDir *dir, IsoDirIter **iter) +{ + IsoDirIter *it; + struct dir_iter_data *data; + + if (dir == NULL || iter == NULL) { + return ISO_NULL_POINTER; + } + it = malloc(sizeof(IsoDirIter)); + if (it == NULL) { + return ISO_OUT_OF_MEM; + } + data = malloc(sizeof(struct dir_iter_data)); + if (data == NULL) { + free(it); + return ISO_OUT_OF_MEM; + } + + it->class = &iter_class; + it->dir = (IsoDir*)dir; + data->pos = NULL; + data->flag = 0x00; + it->data = data; + + *iter = it; + return ISO_SUCCESS; +} + +int iso_dir_iter_next(IsoDirIter *iter, IsoNode **node) +{ + if (iter == NULL || node == NULL) { + return ISO_NULL_POINTER; + } + return iter->class->next(iter, node); +} + +int iso_dir_iter_has_next(IsoDirIter *iter) +{ + if (iter == NULL) { + return ISO_NULL_POINTER; + } + return iter->class->has_next(iter); +} + +void iso_dir_iter_free(IsoDirIter *iter) +{ + if (iter != NULL) { + iter->class->free(iter); + free(iter); + } +} + +int iso_dir_iter_take(IsoDirIter *iter) +{ + if (iter == NULL) { + return ISO_NULL_POINTER; + } + return iter->class->take(iter); +} + +int iso_dir_iter_remove(IsoDirIter *iter) +{ + if (iter == NULL) { + return ISO_NULL_POINTER; + } + return iter->class->remove(iter); +} + /** * Get the destination of a node. * The returned string belongs to the node and should not be modified nor diff --git a/libisofs/node.h b/libisofs/node.h index 0a77169..a1fc96d 100644 --- a/libisofs/node.h +++ b/libisofs/node.h @@ -148,20 +148,32 @@ struct Iso_Special dev_t dev; }; +struct iso_dir_iter_iface +{ + + int (*next)(IsoDirIter *iter, IsoNode **node); + + int (*has_next)(IsoDirIter *iter); + + void (*free)(IsoDirIter *iter); + + int (*take)(IsoDirIter *iter); + + int (*remove)(IsoDirIter *iter); + +}; + /** * An iterator for directory children. */ struct Iso_Dir_Iter { + struct iso_dir_iter_iface *class; + + /* the directory this iterator iterates over */ IsoDir *dir; - /* points to the last visited child, to NULL before start */ - IsoNode *pos; - - /* Some control flags. - * bit 0 -> 1 if next called, 0 reseted at start or on deletion - */ - int flag; + void *data; }; int iso_node_new_root(IsoDir **root); From cb47296913738b7189fb37bff20789618599b224 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Mon, 3 Mar 2008 22:02:10 +0100 Subject: [PATCH 11/29] Preliminary support for find nodes. --- .bzrignore | 1 + Makefile.am | 6 ++ demo/find.c | 59 ++++++++++++++ libisofs/find.c | 182 ++++++++++++++++++++++++++++++++++++++++++++ libisofs/libisofs.h | 37 +++++++++ libisofs/node.c | 1 - 6 files changed, 285 insertions(+), 1 deletion(-) create mode 100644 demo/find.c create mode 100644 libisofs/find.c diff --git a/.bzrignore b/.bzrignore index 900e90d..4adeb9a 100644 --- a/.bzrignore +++ b/.bzrignore @@ -38,3 +38,4 @@ demo/isogrow doc/html doc/doxygen.conf libisofs-1.pc +demo/find diff --git a/Makefile.am b/Makefile.am index b4f7137..f992d25 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,6 +16,7 @@ libisofs_libisofs_la_SOURCES = \ libisofs/node.c \ libisofs/tree.h \ libisofs/tree.c \ + libisofs/find.c \ libisofs/image.h \ libisofs/image.c \ libisofs/fsource.h \ @@ -65,6 +66,7 @@ noinst_PROGRAMS = \ demo/cat \ demo/catbuffer \ demo/tree \ + demo/find \ demo/ecma119tree \ demo/iso \ demo/isoread \ @@ -89,6 +91,10 @@ demo_tree_CPPFLAGS = -Ilibisofs demo_tree_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) demo_tree_SOURCES = demo/tree.c +demo_find_CPPFLAGS = -Ilibisofs +demo_find_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) +demo_find_SOURCES = demo/find.c + demo_ecma119tree_CPPFLAGS = -Ilibisofs demo_ecma119tree_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) demo_ecma119tree_SOURCES = demo/ecma119_tree.c diff --git a/demo/find.c b/demo/find.c new file mode 100644 index 0000000..abae63d --- /dev/null +++ b/demo/find.c @@ -0,0 +1,59 @@ +/* + * Little program that import a directory, find matching nodes and prints the + * resulting iso tree. + */ + +#include "libisofs.h" +#include +#include +#include +#include +#include +#include + +static void +print_dir(IsoDir *dir) +{ + IsoDirIter *iter; + IsoNode *node; + IsoFindCondition *cond; + + cond = iso_new_find_conditions_name("*a*"); + iso_dir_find_children(dir, cond, &iter); + while (iso_dir_iter_next(iter, &node) == 1) { + 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; + } + + iso_init(); + iso_set_msgs_severities("NEVER", "ALL", ""); + + result = iso_image_new("volume_id", &image); + if (result < 0) { + printf ("Error creating image\n"); + return 1; + } + + 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; + } + + print_dir(iso_image_get_root(image)); + + iso_image_unref(image); + iso_finish(); + return 0; +} diff --git a/libisofs/find.c b/libisofs/find.c new file mode 100644 index 0000000..57fbb4c --- /dev/null +++ b/libisofs/find.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2008 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. + */ + +#include "libisofs.h" +#include "node.h" + +#include +#include + +struct iso_find_condition +{ + /* + * Check whether the given node matches this condition. + * + * @param cond + * The condition to check + * @param node + * The node that should be checked + * @return + * 1 if the node matches the condition, 0 if not + */ + int (*matches)(IsoFindCondition *cond, IsoNode *node); + + /** + * Free condition specific data + */ + void (*free)(IsoFindCondition*); + + /** condition specific data */ + void *data; +}; + +struct find_iter_data +{ + IsoDirIter *iter; + IsoFindCondition *cond; +}; + +static +int find_iter_next(IsoDirIter *iter, IsoNode **node) +{ + int ret; + IsoNode *n; + struct find_iter_data *data = iter->data; + + while ((ret = iso_dir_iter_next(data->iter, &n)) == 1) { + if (data->cond->matches(data->cond, n)) { + *node = n; + break; + } + } + return ret; +} + +static +int find_iter_has_next(IsoDirIter *iter) +{ + struct find_iter_data *data = iter->data; + + /* + * FIXME wrong implementation!!!! the underlying iter may have more nodes, + * but they may not match find conditions + */ + return iso_dir_iter_has_next(data->iter); +} + +static +void find_iter_free(IsoDirIter *iter) +{ + struct find_iter_data *data = iter->data; + data->cond->free(data->cond); + free(data->cond); + iso_dir_iter_free(data->iter); + free(iter->data); +} + +static +int find_iter_take(IsoDirIter *iter) +{ + struct find_iter_data *data = iter->data; + return iso_dir_iter_take(data->iter); +} + +static +int find_iter_remove(IsoDirIter *iter) +{ + struct find_iter_data *data = iter->data; + return iso_dir_iter_remove(data->iter); +} + +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 +}; + +int iso_dir_find_children(IsoDir* dir, IsoFindCondition *cond, + IsoDirIter **iter) +{ + int ret; + IsoDirIter *children; + IsoDirIter *it; + struct find_iter_data *data; + + if (dir == NULL || cond == NULL || iter == NULL) { + return ISO_NULL_POINTER; + } + it = malloc(sizeof(IsoDirIter)); + if (it == NULL) { + return ISO_OUT_OF_MEM; + } + data = malloc(sizeof(struct find_iter_data)); + if (data == NULL) { + free(it); + return ISO_OUT_OF_MEM; + } + ret = iso_dir_get_children(dir, &children); + if (ret < 0) { + free(it); + free(data); + return ret; + } + + it->class = &find_iter_class; + it->dir = (IsoDir*)dir; + data->iter = children; + data->cond = cond; + it->data = data; + + *iter = it; + return ISO_SUCCESS; +} + +/*************** find by name wildcard condition *****************/ + +static +int cond_name_matches(IsoFindCondition *cond, IsoNode *node) +{ + char *pattern = (char*) cond->data; + int ret = fnmatch(pattern, node->name, 0); + return ret == 0 ? 1 : 0; +} + +static +void cond_name_free(IsoFindCondition *cond) +{ + free(cond->data); +} + +/** + * Create a new condition that checks if a the node name matches the given + * wildcard. + * + * @param wildcard + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_name(const char *wildcard) +{ + IsoFindCondition *cond; + if (wildcard == NULL) { + return NULL; + } + cond = malloc(sizeof(IsoFindCondition)); + if (cond == NULL) { + return NULL; + } + cond->data = strdup(wildcard); + cond->free = cond_name_free; + cond->matches = cond_name_matches; + return cond; +} diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index ee80fd5..7ffd308 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -2164,6 +2164,43 @@ int iso_dir_iter_take(IsoDirIter *iter); */ int iso_dir_iter_remove(IsoDirIter *iter); + +/** + * @since 0.6.4 + */ +typedef struct iso_find_condition IsoFindCondition; + +/** + * Create a new condition that checks if a the node name matches the given + * wildcard. + * + * @param wildcard + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_name(const char *wildcard); + +/** + * Find all directory children that match the given condition. + * + * @param dir + * Directory where we will search children. + * @param cond + * Condition that the children must match in order to be returned. + * It will be free together with the iterator. Remember to delete it + * if this function return error. + * @param iter + * Iterator that returns only the children that match condition. + * @return + * 1 on success, < 0 on error + * + * @since 0.6.4 + */ +int iso_dir_find_children(IsoDir* dir, IsoFindCondition *cond, + IsoDirIter **iter); + /** * Get the destination of a node. * The returned string belongs to the node and should not be modified nor diff --git a/libisofs/node.c b/libisofs/node.c index 9276ef8..22f46d7 100644 --- a/libisofs/node.c +++ b/libisofs/node.c @@ -616,7 +616,6 @@ struct iso_dir_iter_iface iter_class = { iter_remove }; - int iso_dir_get_children(const IsoDir *dir, IsoDirIter **iter) { IsoDirIter *it; From 6b583aa31f20e6773da9b280e8198c4a93882ce7 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Tue, 4 Mar 2008 00:34:17 +0100 Subject: [PATCH 12/29] Add find conditions to check for mode, gid and uid attributes. --- libisofs/find.c | 145 +++++++++++++++++++++++++++++++++++++++++++- libisofs/libisofs.h | 45 +++++++++++++- 2 files changed, 188 insertions(+), 2 deletions(-) diff --git a/libisofs/find.c b/libisofs/find.c index 57fbb4c..0517b3d 100644 --- a/libisofs/find.c +++ b/libisofs/find.c @@ -156,7 +156,7 @@ void cond_name_free(IsoFindCondition *cond) } /** - * Create a new condition that checks if a the node name matches the given + * Create a new condition that checks if the node name matches the given * wildcard. * * @param wildcard @@ -180,3 +180,146 @@ IsoFindCondition *iso_new_find_conditions_name(const char *wildcard) cond->matches = cond_name_matches; return cond; } + +/*************** find by mode condition *****************/ + +static +int cond_mode_matches(IsoFindCondition *cond, IsoNode *node) +{ + mode_t *mask = (mode_t*) cond->data; + return node->mode & *mask ? 1 : 0; +} + +static +void cond_mode_free(IsoFindCondition *cond) +{ + free(cond->data); +} + +/** + * Create a new condition that checks the node mode against a mode mask. It + * can be used to check both file type and permissions. + * + * For example: + * + * iso_new_find_conditions_mode(S_IFREG) : search for regular files + * iso_new_find_conditions_mode(S_IFCHR | S_IWUSR) : search for character + * devices where owner has write permissions. + * + * @param mask + * Mode mask to AND against node mode. + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_mode(mode_t mask) +{ + IsoFindCondition *cond; + mode_t *data; + cond = malloc(sizeof(IsoFindCondition)); + if (cond == NULL) { + return NULL; + } + data = malloc(sizeof(mode_t)); + if (data == NULL) { + free(cond); + return NULL; + } + *data = mask; + cond->data = data; + cond->free = cond_mode_free; + cond->matches = cond_mode_matches; + return cond; +} + +/*************** find by gid condition *****************/ + +static +int cond_gid_matches(IsoFindCondition *cond, IsoNode *node) +{ + gid_t *gid = (gid_t*) cond->data; + return node->gid == *gid ? 1 : 0; +} + +static +void cond_gid_free(IsoFindCondition *cond) +{ + free(cond->data); +} + +/** + * Create a new condition that checks the node gid. + * + * @param gid + * Desired Group Id. + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_gid(gid_t gid) +{ + IsoFindCondition *cond; + gid_t *data; + cond = malloc(sizeof(IsoFindCondition)); + if (cond == NULL) { + return NULL; + } + data = malloc(sizeof(gid_t)); + if (data == NULL) { + free(cond); + return NULL; + } + *data = gid; + cond->data = data; + cond->free = cond_gid_free; + cond->matches = cond_gid_matches; + return cond; +} + +/*************** find by uid condition *****************/ + +static +int cond_uid_matches(IsoFindCondition *cond, IsoNode *node) +{ + uid_t *uid = (uid_t*) cond->data; + return node->uid == *uid ? 1 : 0; +} + +static +void cond_uid_free(IsoFindCondition *cond) +{ + free(cond->data); +} + +/** + * Create a new condition that checks the node uid. + * + * @param uid + * Desired User Id. + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_uid(uid_t uid) +{ + IsoFindCondition *cond; + uid_t *data; + cond = malloc(sizeof(IsoFindCondition)); + if (cond == NULL) { + return NULL; + } + data = malloc(sizeof(uid_t)); + if (data == NULL) { + free(cond); + return NULL; + } + *data = uid; + cond->data = data; + cond->free = cond_uid_free; + cond->matches = cond_uid_matches; + return cond; +} + diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 7ffd308..a7fb840 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -2171,7 +2171,7 @@ int iso_dir_iter_remove(IsoDirIter *iter); typedef struct iso_find_condition IsoFindCondition; /** - * Create a new condition that checks if a the node name matches the given + * Create a new condition that checks if the node name matches the given * wildcard. * * @param wildcard @@ -2182,6 +2182,49 @@ typedef struct iso_find_condition IsoFindCondition; */ IsoFindCondition *iso_new_find_conditions_name(const char *wildcard); +/** + * Create a new condition that checks the node mode against a mode mask. It + * can be used to check both file type and permissions. + * + * For example: + * + * iso_new_find_conditions_mode(S_IFREG) : search for regular files + * iso_new_find_conditions_mode(S_IFCHR | S_IWUSR) : search for character + * devices where owner has write permissions. + * + * @param mask + * Mode mask to AND against node mode. + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_mode(mode_t mask); + +/** + * Create a new condition that checks the node gid. + * + * @param gid + * Desired Group Id. + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_gid(gid_t gid); + +/** + * Create a new condition that checks the node uid. + * + * @param uid + * Desired User Id. + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_uid(uid_t uid); + /** * Find all directory children that match the given condition. * From d2a92bd0f6135be0f444a3694257e5d60ff09935 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Tue, 4 Mar 2008 00:53:25 +0100 Subject: [PATCH 13/29] Add find contitions to check for timestamps. --- libisofs/find.c | 154 ++++++++++++++++++++++++++++++++++++++++++++ libisofs/libisofs.h | 64 ++++++++++++++++++ 2 files changed, 218 insertions(+) diff --git a/libisofs/find.c b/libisofs/find.c index 0517b3d..fd0e9f6 100644 --- a/libisofs/find.c +++ b/libisofs/find.c @@ -323,3 +323,157 @@ IsoFindCondition *iso_new_find_conditions_uid(uid_t uid) return cond; } +/*************** find by timestamps condition *****************/ + +struct cond_times +{ + time_t time; + int what_time; /* 0 atime, 1 mtime, 2 ctime */ + enum iso_find_comparisons comparison; +}; + +static +int cond_time_matches(IsoFindCondition *cond, IsoNode *node) +{ + time_t node_time; + struct cond_times *data = cond->data; + + switch (data->what_time) { + case 0: node_time = node->atime; break; + case 1: node_time = node->mtime; break; + default: node_time = node->ctime; break; + } + + switch (data->comparison) { + case ISO_FIND_COND_GREATER: + return node_time > data->time ? 1 : 0; + case ISO_FIND_COND_GREATER_OR_EQUAL: + return node_time >= data->time ? 1 : 0; + case ISO_FIND_COND_EQUAL: + return node_time == data->time ? 1 : 0; + case ISO_FIND_COND_LESS: + return node_time < data->time ? 1 : 0; + case ISO_FIND_COND_LESS_OR_EQUAL: + return node_time <= data->time ? 1 : 0; + } + /* should never happen */ + return 0; +} + +static +void cond_time_free(IsoFindCondition *cond) +{ + free(cond->data); +} + +/** + * Create a new condition that checks the time of last access. + * + * @param time + * Time to compare against IsoNode atime. + * @param comparison + * Comparison to be done between IsoNode atime and submitted time. + * Note that ISO_FIND_COND_GREATER, for example, is true if the node + * time is greater than the submitted time. + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_atime(time_t time, + enum iso_find_comparisons comparison) +{ + IsoFindCondition *cond; + struct cond_times *data; + cond = malloc(sizeof(IsoFindCondition)); + if (cond == NULL) { + return NULL; + } + data = malloc(sizeof(struct cond_times)); + if (data == NULL) { + free(cond); + return NULL; + } + data->time = time; + data->comparison = comparison; + data->what_time = 0; /* atime */ + cond->data = data; + cond->free = cond_time_free; + cond->matches = cond_time_matches; + return cond; +} + +/** + * Create a new condition that checks the time of last modification. + * + * @param time + * Time to compare against IsoNode mtime. + * @param comparison + * Comparison to be done between IsoNode mtime and submitted time. + * Note that ISO_FIND_COND_GREATER, for example, is true if the node + * time is greater than the submitted time. + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_mtime(time_t time, + enum iso_find_comparisons comparison) +{ + IsoFindCondition *cond; + struct cond_times *data; + cond = malloc(sizeof(IsoFindCondition)); + if (cond == NULL) { + return NULL; + } + data = malloc(sizeof(struct cond_times)); + if (data == NULL) { + free(cond); + return NULL; + } + data->time = time; + data->comparison = comparison; + data->what_time = 1; /* mtime */ + cond->data = data; + cond->free = cond_time_free; + cond->matches = cond_time_matches; + return cond; +} + +/** + * Create a new condition that checks the time of last status change. + * + * @param time + * Time to compare against IsoNode ctime. + * @param comparison + * Comparison to be done between IsoNode ctime and submitted time. + * Note that ISO_FIND_COND_GREATER, for example, is true if the node + * time is greater than the submitted time. + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_ctime(time_t time, + enum iso_find_comparisons comparison) +{ + IsoFindCondition *cond; + struct cond_times *data; + cond = malloc(sizeof(IsoFindCondition)); + if (cond == NULL) { + return NULL; + } + data = malloc(sizeof(struct cond_times)); + if (data == NULL) { + free(cond); + return NULL; + } + data->time = time; + data->comparison = comparison; + data->what_time = 2; /* ctime */ + cond->data = data; + cond->free = cond_time_free; + cond->matches = cond_time_matches; + return cond; +} + diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index a7fb840..6eb29fa 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -2225,6 +2225,70 @@ IsoFindCondition *iso_new_find_conditions_gid(gid_t gid); */ IsoFindCondition *iso_new_find_conditions_uid(uid_t uid); +/** + * Possible comparison between IsoNode and given conditions. + * + * @since 0.6.4 + */ +enum iso_find_comparisons { + ISO_FIND_COND_GREATER, + ISO_FIND_COND_GREATER_OR_EQUAL, + ISO_FIND_COND_EQUAL, + ISO_FIND_COND_LESS, + ISO_FIND_COND_LESS_OR_EQUAL +}; + +/** + * Create a new condition that checks the time of last access. + * + * @param time + * Time to compare against IsoNode atime. + * @param comparison + * Comparison to be done between IsoNode atime and submitted time. + * Note that ISO_FIND_COND_GREATER, for example, is true if the node + * time is greater than the submitted time. + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_atime(time_t time, + enum iso_find_comparisons comparison); + +/** + * Create a new condition that checks the time of last modification. + * + * @param time + * Time to compare against IsoNode mtime. + * @param comparison + * Comparison to be done between IsoNode mtime and submitted time. + * Note that ISO_FIND_COND_GREATER, for example, is true if the node + * time is greater than the submitted time. + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_mtime(time_t time, + enum iso_find_comparisons comparison); + +/** + * Create a new condition that checks the time of last status change. + * + * @param time + * Time to compare against IsoNode ctime. + * @param comparison + * Comparison to be done between IsoNode ctime and submitted time. + * Note that ISO_FIND_COND_GREATER, for example, is true if the node + * time is greater than the submitted time. + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_ctime(time_t time, + enum iso_find_comparisons comparison); + /** * Find all directory children that match the given condition. * From 085f6b64a32ff2447eedc60781d4a121ad716cdc Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Tue, 4 Mar 2008 01:10:56 +0100 Subject: [PATCH 14/29] Add find condition to logically combine two find conditions. --- demo/find.c | 6 +- libisofs/find.c | 138 ++++++++++++++++++++++++++++++++++++++++++++ libisofs/libisofs.h | 41 +++++++++++++ 3 files changed, 183 insertions(+), 2 deletions(-) diff --git a/demo/find.c b/demo/find.c index abae63d..00cccbc 100644 --- a/demo/find.c +++ b/demo/find.c @@ -16,9 +16,11 @@ print_dir(IsoDir *dir) { IsoDirIter *iter; IsoNode *node; - IsoFindCondition *cond; + IsoFindCondition *cond, *c1, *c2; - cond = iso_new_find_conditions_name("*a*"); + c1 = iso_new_find_conditions_name("*a*"); + c2 = iso_new_find_conditions_mode(S_IFREG); + cond = iso_new_find_conditions_and(c1, c2); iso_dir_find_children(dir, cond, &iter); while (iso_dir_iter_next(iter, &node) == 1) { printf(" %s\n", iso_node_get_name(node)); diff --git a/libisofs/find.c b/libisofs/find.c index fd0e9f6..0288113 100644 --- a/libisofs/find.c +++ b/libisofs/find.c @@ -477,3 +477,141 @@ IsoFindCondition *iso_new_find_conditions_ctime(time_t time, return cond; } +/*************** logical operations on conditions *****************/ + +struct logical_binary_conditions { + IsoFindCondition *a; + IsoFindCondition *b; +}; + +static +void cond_logical_binary_free(IsoFindCondition *cond) +{ + struct logical_binary_conditions *data; + data = cond->data; + data->a->free(data->a); + free(data->a); + data->b->free(data->b); + free(data->b); + free(cond->data); +} + +static +int cond_logical_and_matches(IsoFindCondition *cond, IsoNode *node) +{ + struct logical_binary_conditions *data = cond->data; + return data->a->matches(data->a, node) && data->b->matches(data->b, node); +} + +/** + * Create a new condition that check if the two given conditions are + * valid. + * + * @param a + * @param b + * IsoFindCondition to compare + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_and(IsoFindCondition *a, + IsoFindCondition *b) +{ + IsoFindCondition *cond; + struct logical_binary_conditions *data; + cond = malloc(sizeof(IsoFindCondition)); + if (cond == NULL) { + return NULL; + } + data = malloc(sizeof(struct logical_binary_conditions)); + if (data == NULL) { + free(cond); + return NULL; + } + data->a = a; + data->b = b; + cond->data = data; + cond->free = cond_logical_binary_free; + cond->matches = cond_logical_and_matches; + return cond; +} + +static +int cond_logical_or_matches(IsoFindCondition *cond, IsoNode *node) +{ + struct logical_binary_conditions *data = cond->data; + return data->a->matches(data->a, node) || data->b->matches(data->b, node); +} + +/** + * Create a new condition that check if at least one the two given conditions + * is valid. + * + * @param a + * @param b + * IsoFindCondition to compare + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_or(IsoFindCondition *a, + IsoFindCondition *b) +{ + IsoFindCondition *cond; + struct logical_binary_conditions *data; + cond = malloc(sizeof(IsoFindCondition)); + if (cond == NULL) { + return NULL; + } + data = malloc(sizeof(struct logical_binary_conditions)); + if (data == NULL) { + free(cond); + return NULL; + } + data->a = a; + data->b = b; + cond->data = data; + cond->free = cond_logical_binary_free; + cond->matches = cond_logical_or_matches; + return cond; +} + +static +void cond_not_free(IsoFindCondition *cond) +{ + IsoFindCondition *negate = cond->data; + negate->free(negate); + free(negate); +} + +static +int cond_not_matches(IsoFindCondition *cond, IsoNode *node) +{ + IsoFindCondition *negate = cond->data; + return !(negate->matches(negate, node)); +} + +/** + * Create a new condition that check if the given conditions is false. + * + * @param negate + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_not(IsoFindCondition *negate) +{ + IsoFindCondition *cond; + cond = malloc(sizeof(IsoFindCondition)); + if (cond == NULL) { + return NULL; + } + cond->data = negate; + cond->free = cond_not_free; + cond->matches = cond_not_matches; + return cond; +} + diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 6eb29fa..a48666d 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -2289,6 +2289,47 @@ IsoFindCondition *iso_new_find_conditions_mtime(time_t time, IsoFindCondition *iso_new_find_conditions_ctime(time_t time, enum iso_find_comparisons comparison); +/** + * Create a new condition that check if the two given conditions are + * valid. + * + * @param a + * @param b + * IsoFindCondition to compare + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_and(IsoFindCondition *a, + IsoFindCondition *b); + +/** + * Create a new condition that check if at least one the two given conditions + * is valid. + * + * @param a + * @param b + * IsoFindCondition to compare + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_or(IsoFindCondition *a, + IsoFindCondition *b); + +/** + * Create a new condition that check if the given conditions is false. + * + * @param negate + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_not(IsoFindCondition *negate); + /** * Find all directory children that match the given condition. * From d534a96c83a0b70c512bc5dc236572043d42e565 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Thu, 6 Mar 2008 16:13:15 +0100 Subject: [PATCH 15/29] Apply patch by "eostapets" fixing a linking bug. --- Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile.am b/Makefile.am index f992d25..6101ec9 100644 --- a/Makefile.am +++ b/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 From edc5ccf90a9968792f73f4e0bb9d6686efbd09c3 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Thu, 6 Mar 2008 23:59:32 +0100 Subject: [PATCH 16/29] Added iterator global registry. --- libisofs/find.c | 5 +++++ libisofs/node.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++ libisofs/node.h | 14 ++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/libisofs/find.c b/libisofs/find.c index 0288113..85acfca 100644 --- a/libisofs/find.c +++ b/libisofs/find.c @@ -134,6 +134,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/node.c b/libisofs/node.c index 22f46d7..5def3a8 100644 --- a/libisofs/node.c +++ b/libisofs/node.c @@ -639,6 +639,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 +668,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 +976,51 @@ 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; + } +} + int iso_node_new_root(IsoDir **root) { IsoDir *dir; diff --git a/libisofs/node.h b/libisofs/node.h index a1fc96d..821a120 100644 --- a/libisofs/node.h +++ b/libisofs/node.h @@ -322,4 +322,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); + + + #endif /*LIBISO_NODE_H_*/ From 620c7a08e187ad211f46800f325e161b754ccaaa Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Fri, 7 Mar 2008 00:21:18 +0100 Subject: [PATCH 17/29] Add an Unit test to asyncronous removing of children during iteration. --- test/test_node.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/test/test_node.c b/test/test_node.c index 1211028..1df22b3 100644 --- a/test/test_node.c +++ b/test/test_node.c @@ -856,6 +856,107 @@ void test_iso_dir_iter_remove() free(dir); } +static +void test_iso_dir_iter_when_external_take() +{ + int result; + IsoDirIter *iter; + IsoDir *dir; + IsoNode *node, *node1, *node2; + + /* 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"; + node1->refcount = 1; + result = iso_dir_add_node(dir, node1, 0); + CU_ASSERT_EQUAL(dir->nchildren, 1); + + /* test iteration again */ + result = iso_dir_get_children(dir, &iter); + CU_ASSERT_EQUAL(result, 1); + + /* take node */ + result = iso_node_take(node1); + CU_ASSERT_EQUAL(result, 1); + + /* iter should reflect changes */ + result = iso_dir_iter_has_next(iter); + CU_ASSERT_EQUAL(result, 0); + + result = iso_dir_iter_next(iter, &node); + CU_ASSERT_EQUAL(result, 0); + + iso_dir_iter_free(iter); + + /* add two nodes */ + result = iso_dir_add_node(dir, node1, 0); + CU_ASSERT_EQUAL(dir->nchildren, 1); + + node2 = calloc(1, sizeof(IsoNode)); + node2->name = "A node to be added first"; + node2->refcount = 1; + result = iso_dir_add_node(dir, node2, 0); + CU_ASSERT_EQUAL(result, 2); + + result = iso_dir_get_children(dir, &iter); + CU_ASSERT_EQUAL(result, 1); + + /* iter should have two items... */ + result = iso_dir_iter_next(iter, &node); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(node, node2); + + /* remove node 1 asynchronously */ + result = iso_node_take(node1); + CU_ASSERT_EQUAL(result, 1); + + /* iter should reflect changes */ + result = iso_dir_iter_has_next(iter); + CU_ASSERT_EQUAL(result, 0); + + result = iso_dir_iter_next(iter, &node); + CU_ASSERT_EQUAL(result, 0); + + iso_dir_iter_free(iter); + + /* now remove iter has itered */ + result = iso_dir_add_node(dir, node1, 0); + CU_ASSERT_EQUAL(dir->nchildren, 2); + + result = iso_dir_get_children(dir, &iter); + CU_ASSERT_EQUAL(result, 1); + + result = iso_dir_iter_next(iter, &node); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(node, node2); + + /* remove node 2 asynchronously */ + result = iso_node_take(node2); + CU_ASSERT_EQUAL(result, 1); + + /* iter should reflect changes */ + result = iso_dir_iter_has_next(iter); + CU_ASSERT_EQUAL(result, 1); + + result = iso_dir_iter_next(iter, &node); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(node, node1); + + iso_dir_iter_free(iter); + + /* assert correct refcount */ + CU_ASSERT_EQUAL(node1->refcount, 1); + free(node1); + CU_ASSERT_EQUAL(node2->refcount, 1); + free(node2); + free(dir); +} + static void test_iso_node_take() { @@ -1025,5 +1126,6 @@ void add_node_suite() CU_add_test(pSuite, "iso_dir_iter_take()", test_iso_dir_iter_take); CU_add_test(pSuite, "iso_dir_iter_remove()", test_iso_dir_iter_remove); CU_add_test(pSuite, "iso_node_take()", test_iso_node_take); + CU_add_test(pSuite, "iso_node_take() during iteration", test_iso_dir_iter_when_external_take); CU_add_test(pSuite, "iso_node_set_name()", test_iso_node_set_name); } From ae43626f0bc5b3aa6a4b4117a128b2a2d66e248e Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Sat, 8 Mar 2008 00:45:19 +0100 Subject: [PATCH 18/29] Definitelly fix ticket #127. Iterators now support asynchronous remove. --- libisofs/find.c | 9 ++++- libisofs/node.c | 88 ++++++++++++++++++++++++++++--------------------- libisofs/node.h | 7 +++- 3 files changed, 65 insertions(+), 39 deletions(-) diff --git a/libisofs/find.c b/libisofs/find.c index 85acfca..797ef88 100644 --- a/libisofs/find.c +++ b/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, diff --git a/libisofs/node.c b/libisofs/node.c index 5def3a8..95a0095 100644 --- a/libisofs/node.c +++ b/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) @@ -1021,6 +1023,18 @@ void iso_dir_iter_unregister(IsoDirIter *iter) } } +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/node.h b/libisofs/node.h index 821a120..dd13469 100644 --- a/libisofs/node.h +++ b/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); }; /** @@ -334,6 +339,6 @@ int iso_dir_iter_register(IsoDirIter *iter); */ void iso_dir_iter_unregister(IsoDirIter *iter); - +void iso_notify_dir_iters(IsoNode *node, int flag); #endif /*LIBISO_NODE_H_*/ From 0c69463c5a10861b3bef3354c2d3550375cd46ad Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Sat, 8 Mar 2008 01:06:46 +0100 Subject: [PATCH 19/29] Add support for adding a node with a given name. --- libisofs/libisofs.h | 29 +++++++++++++++++++++++++ libisofs/tree.c | 53 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index a48666d..a5bd199 100644 --- a/libisofs/libisofs.h +++ b/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/tree.c b/libisofs/tree.c index 5dc360e..420b611 100644 --- a/libisofs/tree.c +++ b/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) { From 69fe1d6074dbb1d413bc8d675903a70cf8ae94fd Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Sat, 8 Mar 2008 17:28:40 +0100 Subject: [PATCH 20/29] Implement iso_tree_add_new_file() to add new files from scratch. --- TODO | 1 - libisofs/libisofs.h | 40 +++++++++++++++++++----- libisofs/tree.c | 75 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 8 deletions(-) diff --git a/TODO b/TODO index bad313f..e94a680 100644 --- a/TODO +++ b/TODO @@ -9,7 +9,6 @@ TODO #00004 (libisofs.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 #00008 (data_dource.c) -> guard against partial reads #00009 (ecma119_tree.c/h) -> add true support for harlinks and inode numbers #00010 (buffer.c) -> optimize ring buffer diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index a5bd199..72e20c7 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -2131,8 +2131,8 @@ void iso_dir_iter_free(IsoDirIter *iter); * It's like iso_node_take(), but to be used during a directory iteration. * The node removed will be the last returned by the iteration. * - * The behavior on two call to this function without calling iso_dir_iter_next - * between then is undefined, and should never occur. (TODO protect against this?) + * If you call this function twice without calling iso_dir_iter_next between + * them is not allowed and you will get an ISO_ERROR in second call. * * @return * 1 on succes, < 0 error @@ -2150,8 +2150,8 @@ int iso_dir_iter_take(IsoDirIter *iter); * It's like iso_node_remove(), but to be used during a directory iteration. * The node removed will be the last returned by the iteration. * - * The behavior on two call to this function without calling iso_tree_iter_next - * between then is undefined, and should never occur. (TODO protect against this?) + * If you call this function twice without calling iso_dir_iter_next between + * them is not allowed and you will get an ISO_ERROR in second call. * * @return * 1 on succes, < 0 error @@ -2469,10 +2469,36 @@ int iso_node_get_old_image_lba(IsoNode *node, uint32_t *lba, int flag); */ int iso_tree_add_new_dir(IsoDir *parent, const char *name, IsoDir **dir); -/* - TODO #00007 expose Stream and this function: - int iso_tree_add_new_file(IsoDir *parent, const char *name, stream, file) +/** + * Add a new regular file to the iso tree. Permissions are set to 0444, + * owner and hidden atts are taken from parent. You can modify any of them + * later. + * + * @param parent + * the dir where the new file will be created + * @param name + * name for the new file. If a node with same name already exists on + * parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE. + * @param stream + * IsoStream for the contents of the file. The reference will be taken + * by the newly created file, you will need to take an extra ref to it + * if you need it. + * @param file + * place where to store a pointer to the newly created 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 parent, name or dest 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_file(IsoDir *parent, const char *name, IsoStream *stream, + IsoFile **file); /** * Add a new symlink to the directory tree. Permissions are set to 0777, diff --git a/libisofs/tree.c b/libisofs/tree.c index 420b611..a53e62d 100644 --- a/libisofs/tree.c +++ b/libisofs/tree.c @@ -256,6 +256,81 @@ int iso_tree_add_new_special(IsoDir *parent, const char *name, mode_t mode, return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER); } +/** + * Add a new regular file to the iso tree. Permissions are set to 0444, + * owner and hidden atts are taken from parent. You can modify any of them + * later. + * + * @param parent + * the dir where the new file will be created + * @param name + * name for the new file. If a node with same name already exists on + * parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE. + * @param stream + * IsoStream for the contents of the file + * @param file + * place where to store a pointer to the newly created 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 parent, name or dest 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_file(IsoDir *parent, const char *name, IsoStream *stream, + IsoFile **file) +{ + int ret; + char *n; + IsoFile *node; + IsoNode **pos; + time_t now; + + if (parent == NULL || name == NULL || stream == NULL) { + return ISO_NULL_POINTER; + } + if (file) { + *file = NULL; + } + + /* find place where to insert */ + if (iso_dir_exists(parent, name, &pos)) { + /* a node with same name already exists */ + return ISO_NODE_NAME_NOT_UNIQUE; + } + + n = strdup(name); + ret = iso_node_new_file(n, stream, &node); + if (ret < 0) { + free(n); + return ret; + } + + /* permissions from parent */ + iso_node_set_permissions((IsoNode*)node, 0444); + iso_node_set_uid((IsoNode*)node, parent->node.uid); + iso_node_set_gid((IsoNode*)node, parent->node.gid); + iso_node_set_hidden((IsoNode*)node, parent->node.hidden); + + /* current time */ + now = time(NULL); + iso_node_set_atime((IsoNode*)node, now); + iso_node_set_ctime((IsoNode*)node, now); + iso_node_set_mtime((IsoNode*)node, now); + + if (file) { + *file = node; + } + + /* add to dir */ + return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER); +} + /** * Set whether to follow or not symbolic links when added a file from a source * to IsoImage. From bad03a9a2b91917b470fe6625409e517d2025cea Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Sat, 8 Mar 2008 18:34:41 +0100 Subject: [PATCH 21/29] Add lseek() function to IsoFileSource. --- libisofs/fs_image.c | 55 +++++++++++++++++++++++++++++++++++++++++++++ libisofs/fs_local.c | 47 ++++++++++++++++++++++++++++++++++++++ libisofs/fsource.c | 6 +++++ libisofs/libisofs.h | 38 +++++++++++++++++++++++++++++++ 4 files changed, 146 insertions(+) diff --git a/libisofs/fs_image.c b/libisofs/fs_image.c index 8394cfd..54bb456 100644 --- a/libisofs/fs_image.c +++ b/libisofs/fs_image.c @@ -632,6 +632,60 @@ int ifs_read(IsoFileSource *src, void *buf, size_t count) return read; } +static +off_t ifs_lseek(IsoFileSource *src, off_t offset, int flag) +{ + ImageFileSourceData *data; + + if (src == NULL) { + return (off_t)ISO_NULL_POINTER; + } + if (offset < (off_t)0) { + return (off_t)ISO_WRONG_ARG_VALUE; + } + + data = src->data; + + if (!data->opened) { + return (off_t)ISO_FILE_NOT_OPENED; + } else if (data->opened != 1) { + return (off_t)ISO_FILE_IS_DIR; + } + + switch (flag) { + case 0: /* SEEK_SET */ + data->data.offset = offset; + break; + case 1: /* SEEK_CUR */ + data->data.offset += offset; + break; + case 2: /* SEEK_END */ + /* do this make sense? */ + data->data.offset = data->info.st_size + offset; + break; + default: + return (off_t)ISO_WRONG_ARG_VALUE; + } + + if (data->data.offset % BLOCK_SIZE != 0) { + /* we need to buffer the block */ + uint32_t block; + _ImageFsData *fsdata; + + if (data->data.offset < data->info.st_size) { + int ret; + fsdata = data->fs->data; + block = data->block + (data->data.offset / BLOCK_SIZE); + ret = fsdata->src->read_block(fsdata->src, block, + data->data.content); + if (ret < 0) { + return (off_t)ret; + } + } + } + return data->data.offset; +} + static int ifs_readdir(IsoFileSource *src, IsoFileSource **child) { @@ -771,6 +825,7 @@ IsoFileSourceIface ifs_class = { ifs_open, ifs_close, ifs_read, + ifs_lseek, ifs_readdir, ifs_readlink, ifs_get_filesystem, diff --git a/libisofs/fs_local.c b/libisofs/fs_local.c index bf37337..e9c61a1 100644 --- a/libisofs/fs_local.c +++ b/libisofs/fs_local.c @@ -304,6 +304,52 @@ int lfs_read(IsoFileSource *src, void *buf, size_t count) } } +static +off_t lfs_lseek(IsoFileSource *src, off_t offset, int flag) +{ + _LocalFsFileSource *data; + int whence; + + if (src == NULL) { + return (off_t)ISO_NULL_POINTER; + } + switch (flag) { + case 0: + whence = SEEK_SET; break; + case 1: + whence = SEEK_CUR; break; + case 2: + whence = SEEK_END; break; + default: + return (off_t)ISO_WRONG_ARG_VALUE; + } + + data = src->data; + switch (data->openned) { + case 1: /* not dir */ + { + off_t ret; + ret = lseek(data->info.fd, offset, whence); + if (ret < 0) { + /* error on read */ + switch (errno) { + case ESPIPE: + ret = (off_t)ISO_FILE_ERROR; + break; + default: + ret = (off_t)ISO_ERROR; + break; + } + } + return ret; + } + case 2: /* directory */ + return (off_t)ISO_FILE_IS_DIR; + default: + return (off_t)ISO_FILE_NOT_OPENED; + } +} + static int lfs_readdir(IsoFileSource *src, IsoFileSource **child) { @@ -430,6 +476,7 @@ IsoFileSourceIface lfs_class = { lfs_open, lfs_close, lfs_read, + lfs_lseek, lfs_readdir, lfs_readlink, lfs_get_filesystem, diff --git a/libisofs/fsource.c b/libisofs/fsource.c index b6e5c5f..4b74350 100644 --- a/libisofs/fsource.c +++ b/libisofs/fsource.c @@ -92,6 +92,12 @@ int iso_file_source_read(IsoFileSource *src, void *buf, size_t count) return src->class->read(src, buf, count); } +inline +off_t iso_file_source_lseek(IsoFileSource *src, off_t offset, int flag) +{ + return src->class->lseek(src, offset, flag); +} + inline int iso_file_source_readdir(IsoFileSource *src, IsoFileSource **child) { diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 72e20c7..848bf70 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -559,6 +559,25 @@ struct IsoFileSource_Iface * ISO_INTERRUPTED */ int (*read)(IsoFileSource *src, void *buf, size_t count); + + /** + * Repositions the offset of the IsoFileSource (must be opened) to the + * given offset according to the value of flag. + * + * @param offset + * in bytes + * @param flag + * 0 The offset is set to offset bytes (SEEK_SET) + * 1 The offset is set to its current location plus offset bytes + * (SEEK_CUR) + * 2 The offset is set to the size of the file plus offset bytes + * (SEEK_END). + * @return + * Absolute offset posistion on the file, or < 0 on error. Cast the + * returning value to int to get a valid libisofs error. + * @since 0.6.4 + */ + off_t (*lseek)(IsoFileSource *src, off_t offset, int flag); /** * Read a directory. @@ -3216,6 +3235,25 @@ int iso_file_source_close(IsoFileSource *src); */ int iso_file_source_read(IsoFileSource *src, void *buf, size_t count); +/** + * Repositions the offset of the given IsoFileSource (must be opened) to the + * given offset according to the value of flag. + * + * @param offset + * in bytes + * @param flag + * 0 The offset is set to offset bytes (SEEK_SET) + * 1 The offset is set to its current location plus offset bytes + * (SEEK_CUR) + * 2 The offset is set to the size of the file plus offset bytes + * (SEEK_END). + * @return + * Absolute offset posistion on the file, or < 0 on error. Cast the + * returning value to int to get a valid libisofs error. + * @since 0.6.4 + */ +off_t iso_file_source_lseek(IsoFileSource *src, off_t offset, int flag); + /** * Read a directory. * From d455f9b5403f8d4646b86bf9210638570b1e5648 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Sat, 8 Mar 2008 21:45:19 +0100 Subject: [PATCH 22/29] Add support for cut-out files. --- libisofs/builder.c | 5 +- libisofs/builder.h | 3 +- libisofs/libisofs.h | 46 ++++++++++- libisofs/stream.c | 190 +++++++++++++++++++++++++++++++++++++++++++- libisofs/stream.h | 10 +++ libisofs/tree.c | 86 +++++++++++++++++++- 6 files changed, 331 insertions(+), 9 deletions(-) diff --git a/libisofs/builder.c b/libisofs/builder.c index 9dbea87..1b00dfd 100644 --- a/libisofs/builder.c +++ b/libisofs/builder.c @@ -52,12 +52,13 @@ int default_create_file(IsoNodeBuilder *builder, IsoImage *image, if (ret < 0) { return ret; } + + /* take a ref to the src, as stream has taken our ref */ + iso_file_source_ref(src); name = iso_file_source_get_name(src); ret = iso_node_new_file(name, stream, &node); if (ret < 0) { - /* the stream has taken our ref to src, so we need to add one */ - iso_file_source_ref(src); iso_stream_unref(stream); free(name); return ret; diff --git a/libisofs/builder.h b/libisofs/builder.h index e0d3ff1..34bc6e5 100644 --- a/libisofs/builder.h +++ b/libisofs/builder.h @@ -34,8 +34,7 @@ struct Iso_Node_Builder * In that case, if the implementation can't do the conversion, it * should fail propertly. * - * On sucess, the ref. to src will be owned by file, 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 diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 848bf70..e2decce 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -2805,6 +2805,44 @@ int iso_tree_add_node(IsoImage *image, IsoDir *parent, const char *path, int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name, 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. The node will be cut-out to the + * submitted size, and its contents will be read from the given offset. This + * function is thus suitable for adding only a piece of a file to the image. + * + * @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. For now only regular + * files and symlinks to regular files are supported. + * @param offset + * Offset on the given file from where to start reading data. + * @param size + * Max size of the file. + * @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_cut_out_node(IsoImage *image, IsoDir *parent, + const char *name, const char *path, + off_t offset, off_t size, + IsoNode **node); + /** * Add the contents of a dir to a given directory of the iso tree. * @@ -3639,10 +3677,16 @@ void iso_stream_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id, /** * File path break specification constraints and will be ignored - * (HINT,MEDIUM, -141) + * (HINT,MEDIUM, -144) */ #define ISO_FILE_IMGPATH_WRONG 0xC020FF70 +/** + * Offset greater than file size (FAILURE,HIGH, -145) + * @since 0.6.4 + */ +#define ISO_FILE_OFFSET_TOO_BIG 0xE830FF6A + /** Charset conversion error (FAILURE,HIGH, -256) */ #define ISO_CHARSET_CONV_ERROR 0xE830FF00 diff --git a/libisofs/stream.c b/libisofs/stream.c index 6058e89..dd747cf 100644 --- a/libisofs/stream.c +++ b/libisofs/stream.c @@ -17,6 +17,7 @@ ino_t serial_id = (ino_t)1; ino_t mem_serial_id = (ino_t)1; +ino_t cut_out_serial_id = (ino_t)1; typedef struct { @@ -175,7 +176,7 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream) return ISO_OUT_OF_MEM; } data = malloc(sizeof(FSrcStreamData)); - if (str == NULL) { + if (data == NULL) { free(str); return ISO_OUT_OF_MEM; } @@ -212,6 +213,193 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream) return ISO_SUCCESS; } +struct cut_out_stream +{ + IsoFileSource *src; + + /* key for file identification inside filesystem */ + dev_t dev_id; + ino_t ino_id; + off_t offset; /**< offset where read begins */ + off_t size; /**< size of this file */ + off_t pos; /* position on the file for read */ +}; + +static +int cut_out_open(IsoStream *stream) +{ + int ret; + struct stat info; + IsoFileSource *src; + struct cut_out_stream *data; + + if (stream == NULL) { + return ISO_NULL_POINTER; + } + + data = stream->data; + src = data->src; + ret = iso_file_source_stat(data->src, &info); + if (ret < 0) { + return ret; + } + ret = iso_file_source_open(src); + if (ret < 0) { + return ret; + } + + { + off_t ret; + if (data->offset > info.st_size) { + /* file is smaller than expected */ + ret = iso_file_source_lseek(src, info.st_size, 0); + } else { + ret = iso_file_source_lseek(src, data->offset, 0); + } + if (ret < 0) { + return (int) ret; + } + } + data->pos = 0; + if (data->offset + data->size > info.st_size) { + return 3; /* file smaller than expected */ + } else { + return ISO_SUCCESS; + } +} + +static +int cut_out_close(IsoStream *stream) +{ + IsoFileSource *src; + if (stream == NULL) { + return ISO_NULL_POINTER; + } + src = ((struct cut_out_stream*)stream->data)->src; + return iso_file_source_close(src); +} + +static +off_t cut_out_get_size(IsoStream *stream) +{ + struct cut_out_stream *data = stream->data; + return data->size; +} + +static +int cut_out_read(IsoStream *stream, void *buf, size_t count) +{ + struct cut_out_stream *data = stream->data; + count = (size_t)MIN(data->size - data->pos, count); + if (count == 0) { + return 0; + } + return iso_file_source_read(data->src, buf, count); +} + +static +int cut_out_is_repeatable(IsoStream *stream) +{ + /* reg files are always repeatable */ + return 1; +} + +static +void cut_out_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id, + ino_t *ino_id) +{ + FSrcStreamData *data; + IsoFilesystem *fs; + + data = (FSrcStreamData*)stream->data; + fs = iso_file_source_get_filesystem(data->src); + + *fs_id = fs->get_id(fs); + *dev_id = data->dev_id; + *ino_id = data->ino_id; +} + +static +void cut_out_free(IsoStream *stream) +{ + struct cut_out_stream *data = stream->data; + iso_file_source_unref(data->src); + free(data); +} + +IsoStreamIface cut_out_stream_class = { + 0, + "cout", + cut_out_open, + cut_out_close, + cut_out_get_size, + cut_out_read, + cut_out_is_repeatable, + cut_out_get_id, + cut_out_free +}; + +int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size, + IsoStream **stream) +{ + int r; + struct stat info; + IsoStream *str; + struct cut_out_stream *data; + + if (src == NULL || stream == NULL) { + return ISO_NULL_POINTER; + } + if (size == 0) { + return ISO_WRONG_ARG_VALUE; + } + + r = iso_file_source_stat(src, &info); + if (r < 0) { + return r; + } + if (!S_ISREG(info.st_mode)) { + return ISO_WRONG_ARG_VALUE; + } + if (offset > info.st_size) { + return ISO_FILE_OFFSET_TOO_BIG; + } + + /* check for read access to contents */ + r = iso_file_source_access(src); + if (r < 0) { + return r; + } + + str = malloc(sizeof(IsoStream)); + if (str == NULL) { + return ISO_OUT_OF_MEM; + } + data = malloc(sizeof(struct cut_out_stream)); + if (data == NULL) { + free(str); + return ISO_OUT_OF_MEM; + } + + /* take a new ref to IsoFileSource */ + data->src = src; + iso_file_source_ref(src); + + data->offset = offset; + data->size = MIN(info.st_size - offset, size); + + /* get the id numbers */ + data->dev_id = (dev_t) 0; + data->ino_id = cut_out_serial_id++; + + str->refcount = 1; + str->data = data; + str->class = &cut_out_stream_class; + + *stream = str; + return ISO_SUCCESS; +} + typedef struct diff --git a/libisofs/stream.h b/libisofs/stream.h index 804faf1..3893785 100644 --- a/libisofs/stream.h +++ b/libisofs/stream.h @@ -33,6 +33,16 @@ void iso_stream_get_file_name(IsoStream *stream, char *name); */ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream); +/** + * Create a new stream to read a chunk of an IsoFileSource.. + * The stream will add a ref. to the IsoFileSource. + * + * @return + * 1 sucess, < 0 error + */ +int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size, + IsoStream **stream); + /** * Create a stream for reading from a arbitrary memory buffer. * When the Stream refcount reach 0, the buffer is free(3). diff --git a/libisofs/tree.c b/libisofs/tree.c index a53e62d..624539a 100644 --- a/libisofs/tree.c +++ b/libisofs/tree.c @@ -582,13 +582,14 @@ int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name, } result = image->builder->create_node(image->builder, image, file, &new); - if (result < 0) { - return result; - } /* free the file */ iso_file_source_unref(file); + if (result < 0) { + return result; + } + result = iso_node_set_name(new, name); if (result < 0) { iso_node_unref(new); @@ -603,6 +604,85 @@ int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name, return iso_dir_insert(parent, new, pos, ISO_REPLACE_NEVER); } +int iso_tree_add_new_cut_out_node(IsoImage *image, IsoDir *parent, + const char *name, const char *path, + off_t offset, off_t size, + IsoNode **node) +{ + int result; + struct stat info; + IsoFilesystem *fs; + IsoFileSource *src; + IsoFile *new; + IsoNode **pos; + IsoStream *stream; + + if (image == NULL || parent == NULL || name == NULL || path == NULL) { + return ISO_NULL_POINTER; + } + + if (node) { + *node = NULL; + } + + /* find place where to insert */ + result = iso_dir_exists(parent, name, &pos); + if (result) { + /* a node with same name already exists */ + return ISO_NODE_NAME_NOT_UNIQUE; + } + + fs = image->fs; + result = fs->get_by_path(fs, path, &src); + if (result < 0) { + return result; + } + + result = iso_file_source_stat(src, &info); + if (result < 0) { + iso_file_source_unref(src); + return result; + } + if (!S_ISREG(info.st_mode)) { + return ISO_WRONG_ARG_VALUE; + } + if (offset >= info.st_size) { + return ISO_WRONG_ARG_VALUE; + } + + /* force regular file */ + result = image->builder->create_file(image->builder, image, src, &new); + + /* free the file */ + iso_file_source_unref(src); + + if (result < 0) { + return result; + } + + /* replace file iso stream with a cut-out-stream */ + result = iso_cut_out_stream_new(src, offset, size, &stream); + if (result < 0) { + iso_node_unref((IsoNode*)new); + return result; + } + iso_stream_unref(new->stream); + new->stream = stream; + + result = iso_node_set_name((IsoNode*)new, name); + if (result < 0) { + iso_node_unref((IsoNode*)new); + return result; + } + + if (node) { + *node = (IsoNode*)new; + } + + /* finally, add node to parent */ + return iso_dir_insert(parent, (IsoNode*)new, pos, ISO_REPLACE_NEVER); +} + static int check_excludes(IsoImage *image, const char *path) { From 648941cb15351f22b56e2eeb428b61388929468d Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Sat, 8 Mar 2008 21:48:03 +0100 Subject: [PATCH 23/29] lseek() needs to be added to the end to ensure ABI compatibility. --- libisofs/fs_image.c | 4 ++-- libisofs/fs_local.c | 4 ++-- libisofs/libisofs.h | 39 ++++++++++++++++++++------------------- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/libisofs/fs_image.c b/libisofs/fs_image.c index 54bb456..cbe991f 100644 --- a/libisofs/fs_image.c +++ b/libisofs/fs_image.c @@ -825,11 +825,11 @@ IsoFileSourceIface ifs_class = { ifs_open, ifs_close, ifs_read, - ifs_lseek, ifs_readdir, ifs_readlink, ifs_get_filesystem, - ifs_free + ifs_free, + ifs_lseek }; /** diff --git a/libisofs/fs_local.c b/libisofs/fs_local.c index e9c61a1..43a2a93 100644 --- a/libisofs/fs_local.c +++ b/libisofs/fs_local.c @@ -476,11 +476,11 @@ IsoFileSourceIface lfs_class = { lfs_open, lfs_close, lfs_read, - lfs_lseek, lfs_readdir, lfs_readlink, lfs_get_filesystem, - lfs_free + lfs_free, + lfs_lseek }; /** diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index e2decce..30338f1 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -559,25 +559,6 @@ struct IsoFileSource_Iface * ISO_INTERRUPTED */ int (*read)(IsoFileSource *src, void *buf, size_t count); - - /** - * Repositions the offset of the IsoFileSource (must be opened) to the - * given offset according to the value of flag. - * - * @param offset - * in bytes - * @param flag - * 0 The offset is set to offset bytes (SEEK_SET) - * 1 The offset is set to its current location plus offset bytes - * (SEEK_CUR) - * 2 The offset is set to the size of the file plus offset bytes - * (SEEK_END). - * @return - * Absolute offset posistion on the file, or < 0 on error. Cast the - * returning value to int to get a valid libisofs error. - * @since 0.6.4 - */ - off_t (*lseek)(IsoFileSource *src, off_t offset, int flag); /** * Read a directory. @@ -641,6 +622,26 @@ struct IsoFileSource_Iface * Use iso_file_source_unref() instead. */ void (*free)(IsoFileSource *src); + + /** + * Repositions the offset of the IsoFileSource (must be opened) to the + * given offset according to the value of flag. + * + * @param offset + * in bytes + * @param flag + * 0 The offset is set to offset bytes (SEEK_SET) + * 1 The offset is set to its current location plus offset bytes + * (SEEK_CUR) + * 2 The offset is set to the size of the file plus offset bytes + * (SEEK_END). + * @return + * Absolute offset posistion on the file, or < 0 on error. Cast the + * returning value to int to get a valid libisofs error. + * + * @since 0.6.4 + */ + off_t (*lseek)(IsoFileSource *src, off_t offset, int flag); /* * TODO #00004 Add a get_mime_type() function. From 166f1d83bda1621aed86962e82fc979aa70b7df8 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Sat, 15 Mar 2008 17:34:58 +0100 Subject: [PATCH 24/29] Expose node extended info. Add unit test for it. --- libisofs/libisofs.h | 72 ++++++++++++++++++ libisofs/node.c | 137 +++++++++++++++++++++++++++++++-- libisofs/node.h | 9 +-- test/test_node.c | 180 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 384 insertions(+), 14 deletions(-) diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 30338f1..eb7e0af 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -1820,6 +1820,78 @@ void iso_node_unref(IsoNode *node); */ enum IsoNodeType iso_node_get_type(IsoNode *node); +/** + * Function to handle particular extended information. The function + * pointer acts as an identifier for the type of the information. Structs + * with same information type must use the same function. + * + * @param data + * Attached data + * @param flag + * What to do with the data. At this time the following values are + * defined: + * -> 1 the data must be freed + * @return + * 1 in any case. + * + * @since 0.6.4 + */ +typedef int (*iso_node_xinfo_func)(void *data, int flag); + +/** + * Add extended information to the given node. Extended info allows + * applications (and libisofs itself) to add more information to an IsoNode. + * You can use this facilities to associate new information with a given + * node. + * + * Each node keeps a list of added extended info, meaning you can add several + * extended info data to each node. Each extended info you add is identified + * by the proc parameter, a pointer to a function that knows how to manage + * the external info data. Thus, in order to add several types of extended + * info, you need to define a "proc" function for each type. + * + * @param node + * The node where to add the extended info + * @param proc + * A function pointer used to identify the type of the data, and that + * knows how to manage it + * @param data + * Extended info to add. + * @return + * 1 if success, 0 if the given node already has extended info of the + * type defined by the "proc" function, < 0 on error + * + * @since 0.6.4 + */ +int iso_node_add_xinfo(IsoNode *node, iso_node_xinfo_func proc, void *data); + +/** + * Remove the given extended info (defined by the proc function) from the + * given node. + * + * @return + * 1 on success, 0 if node does not have extended info of the requested + * type, < 0 on error + * + * @since 0.6.4 + */ +int iso_node_remove_xinfo(IsoNode *node, iso_node_xinfo_func proc); + +/** + * Get the given extended info (defined by the proc function) from the + * given node. + * + * @param data + * Will be filled with the extended info corresponding to the given proc + * function + * @return + * 1 on success, 0 if node does not have extended info of the requested + * type, < 0 on error + * + * @since 0.6.4 + */ +int iso_node_get_xinfo(IsoNode *node, iso_node_xinfo_func proc, void **data); + /** * Set the name of a node. Note that if the node is already added to a dir * this can fail if dir already contains a node with the new name. diff --git a/libisofs/node.c b/libisofs/node.c index 95a0095..6442473 100644 --- a/libisofs/node.c +++ b/libisofs/node.c @@ -69,19 +69,144 @@ void iso_node_unref(IsoNode *node) /* other kind of nodes does not need to delete anything here */ break; } - -#ifdef LIBISO_EXTENDED_INFORMATION + if (node->xinfo) { - /* free extended info */ - node->xinfo->process(node->xinfo->data, 1); - free(node->xinfo); + IsoExtendedInfo *info = node->xinfo; + while (info != NULL) { + IsoExtendedInfo *tmp = info->next; + + /* free extended info */ + info->process(info->data, 1); + free(info); + info = tmp; + } } -#endif free(node->name); free(node); } } +/** + * Add extended information to the given node. Extended info allows + * applications (and libisofs itself) to add more information to an IsoNode. + * You can use this facilities to associate new information with a given + * node. + * + * Each node keeps a list of added extended info, meaning you can add several + * extended info data to each node. Each extended info you add is identified + * by the proc parameter, a pointer to a function that knows how to manage + * the external info data. Thus, in order to add several types of extended + * info, you need to define a "proc" function for each type. + * + * @param node + * The node where to add the extended info + * @param proc + * A function pointer used to identify the type of the data, and that + * knows how to manage it + * @param data + * Extended info to add. + * @return + * 1 if success, 0 if the given node already has extended info of the + * type defined by the "proc" function, < 0 on error + */ +int iso_node_add_xinfo(IsoNode *node, iso_node_xinfo_func proc, void *data) +{ + IsoExtendedInfo *info; + IsoExtendedInfo *pos; + + if (node == NULL || proc == NULL) { + return ISO_NULL_POINTER; + } + + pos = node->xinfo; + while (pos != NULL) { + if (pos->process == proc) { + return 0; /* extended info already added */ + } + pos = pos->next; + } + + info = malloc(sizeof(IsoExtendedInfo)); + if (info == NULL) { + return ISO_OUT_OF_MEM; + } + info->next = node->xinfo; + info->data = data; + info->process = proc; + node->xinfo = info; + return ISO_SUCCESS; +} + +/** + * Remove the given extended info (defined by the proc function) from the + * given node. + * + * @return + * 1 on success, 0 if node does not have extended info of the requested + * type, < 0 on error + */ +int iso_node_remove_xinfo(IsoNode *node, iso_node_xinfo_func proc) +{ + IsoExtendedInfo *pos, *prev; + + if (node == NULL || proc == NULL) { + return ISO_NULL_POINTER; + } + + prev = NULL; + pos = node->xinfo; + while (pos != NULL) { + if (pos->process == proc) { + /* this is the extended info we want to remove */ + pos->process(pos->data, 1); + + if (prev != NULL) { + prev->next = pos->next; + } else { + node->xinfo = pos->next; + } + free(pos); + return ISO_SUCCESS; + } + prev = pos; + pos = pos->next; + } + /* requested xinfo not found */ + return 0; +} + +/** + * Get the given extended info (defined by the proc function) from the + * given node. + * + * @param data + * Will be filled with the extended info corresponding to the given proc + * function + * @return + * 1 on success, 0 if node does not have extended info of the requested + * type, < 0 on error + */ +int iso_node_get_xinfo(IsoNode *node, iso_node_xinfo_func proc, void **data) +{ + IsoExtendedInfo *pos; + + if (node == NULL || proc == NULL || data == NULL) { + return ISO_NULL_POINTER; + } + + pos = node->xinfo; + while (pos != NULL) { + if (pos->process == proc) { + /* this is the extended info we want */ + *data = pos->data; + return ISO_SUCCESS; + } + pos = pos->next; + } + /* requested xinfo not found */ + return 0; +} + /** * Get the type of an IsoNode. */ diff --git a/libisofs/node.h b/libisofs/node.h index dd13469..993051c 100644 --- a/libisofs/node.h +++ b/libisofs/node.h @@ -20,9 +20,6 @@ #include #include -/* #define LIBISO_EXTENDED_INFORMATION */ -#ifdef LIBISO_EXTENDED_INFORMATION - /** * The extended information is a way to attach additional information to each * IsoNode. External applications may want to use this extension system to @@ -55,7 +52,7 @@ struct iso_extended_info { * @return * 1 */ - int (*process)(void *data, int flag); + iso_node_xinfo_func process; /** * Pointer to information specific data. @@ -63,8 +60,6 @@ struct iso_extended_info { void *data; }; -#endif - /** * */ @@ -102,12 +97,10 @@ struct Iso_Node */ IsoNode *next; -#ifdef LIBISO_EXTENDED_INFORMATION /** * Extended information for the node. */ IsoExtendedInfo *xinfo; -#endif }; struct Iso_Dir diff --git a/test/test_node.c b/test/test_node.c index 1df22b3..2fdcf0c 100644 --- a/test/test_node.c +++ b/test/test_node.c @@ -1106,6 +1106,183 @@ void test_iso_node_set_name() free(dir); } +static +int xinfo_a(void *data, int flag) { + return 1; +} + +static +int xinfo_b(void *data, int flag) { + return 1; +} + +static +void test_iso_node_add_xinfo() +{ + int result; + IsoNode *node; + + /* cretae a node */ + node = calloc(1, sizeof(IsoNode)); + + /* add xinfo data */ + result = iso_node_add_xinfo(node, xinfo_a, NULL); + CU_ASSERT_EQUAL(result, 1); + + /* we can't add again the same xinfo type */ + result = iso_node_add_xinfo(node, xinfo_a, &result); + CU_ASSERT_EQUAL(result, 0); + + result = iso_node_add_xinfo(node, xinfo_b, NULL); + CU_ASSERT_EQUAL(result, 1); + + free(node->xinfo->next); + free(node->xinfo); + free(node); +} + +static +void test_iso_node_get_xinfo() +{ + int result; + IsoNode *node; + char *one_data = "my data"; + char *another_data = "my data 2"; + void *data; + + /* cretae a node */ + node = calloc(1, sizeof(IsoNode)); + + /* at the beginning we have no data */ + result = iso_node_get_xinfo(node, xinfo_b, &data); + CU_ASSERT_EQUAL(result, 0); + result = iso_node_get_xinfo(node, xinfo_a, &data); + CU_ASSERT_EQUAL(result, 0); + + /* add xinfo data */ + result = iso_node_add_xinfo(node, xinfo_a, one_data); + CU_ASSERT_EQUAL(result, 1); + + /* we get the correct data */ + result = iso_node_get_xinfo(node, xinfo_a, &data); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(data, one_data); + + /* we can't add again the same xinfo type */ + result = iso_node_add_xinfo(node, xinfo_a, &result); + CU_ASSERT_EQUAL(result, 0); + + /* we get the correct data again */ + result = iso_node_get_xinfo(node, xinfo_a, &data); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(data, one_data); + + /* xinfo_b has no data */ + result = iso_node_get_xinfo(node, xinfo_b, &data); + CU_ASSERT_EQUAL(result, 0); + + /* add another xinfo */ + result = iso_node_add_xinfo(node, xinfo_b, another_data); + CU_ASSERT_EQUAL(result, 1); + + /* test both data is returned propertly */ + result = iso_node_get_xinfo(node, xinfo_a, &data); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(data, one_data); + + result = iso_node_get_xinfo(node, xinfo_b, &data); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(data, another_data); + + free(node->xinfo->next); + free(node->xinfo); + free(node); +} + +static +void test_iso_node_remove_xinfo() +{ + int result; + IsoNode *node; + char *one_data = "my data"; + char *another_data = "my data 2"; + void *data; + + /* cretae a node */ + node = calloc(1, sizeof(IsoNode)); + + /* try to remove inexistent data */ + result = iso_node_remove_xinfo(node, xinfo_b); + CU_ASSERT_EQUAL(result, 0); + result = iso_node_remove_xinfo(node, xinfo_a); + CU_ASSERT_EQUAL(result, 0); + + /* add xinfo data */ + result = iso_node_add_xinfo(node, xinfo_a, one_data); + CU_ASSERT_EQUAL(result, 1); + result = iso_node_get_xinfo(node, xinfo_a, &data); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(data, one_data); + + /* remove it */ + result = iso_node_remove_xinfo(node, xinfo_b); + CU_ASSERT_EQUAL(result, 0); + result = iso_node_remove_xinfo(node, xinfo_a); + CU_ASSERT_EQUAL(result, 1); + + result = iso_node_get_xinfo(node, xinfo_a, &data); + CU_ASSERT_EQUAL(result, 0); + + /* add again the same xinfo type */ + result = iso_node_add_xinfo(node, xinfo_a, one_data); + CU_ASSERT_EQUAL(result, 1); + + /* we get the correct data again */ + result = iso_node_get_xinfo(node, xinfo_a, &data); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(data, one_data); + + /* add another xinfo */ + result = iso_node_add_xinfo(node, xinfo_b, another_data); + CU_ASSERT_EQUAL(result, 1); + + /* test both data is returned propertly */ + result = iso_node_get_xinfo(node, xinfo_a, &data); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(data, one_data); + + result = iso_node_get_xinfo(node, xinfo_b, &data); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(data, another_data); + + /* remove b */ + result = iso_node_remove_xinfo(node, xinfo_b); + CU_ASSERT_EQUAL(result, 1); + + /* only a can be get */ + result = iso_node_get_xinfo(node, xinfo_a, &data); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(data, one_data); + + result = iso_node_get_xinfo(node, xinfo_b, &data); + CU_ASSERT_EQUAL(result, 0); + + /* try to remove b again */ + result = iso_node_remove_xinfo(node, xinfo_b); + CU_ASSERT_EQUAL(result, 0); + + /* remove a */ + result = iso_node_remove_xinfo(node, xinfo_a); + CU_ASSERT_EQUAL(result, 1); + + result = iso_node_get_xinfo(node, xinfo_a, &data); + CU_ASSERT_EQUAL(result, 0); + result = iso_node_get_xinfo(node, xinfo_b, &data); + CU_ASSERT_EQUAL(result, 0); + + free(node); +} + void add_node_suite() { CU_pSuite pSuite = CU_add_suite("Node Test Suite", NULL, NULL); @@ -1128,4 +1305,7 @@ void add_node_suite() CU_add_test(pSuite, "iso_node_take()", test_iso_node_take); CU_add_test(pSuite, "iso_node_take() during iteration", test_iso_dir_iter_when_external_take); CU_add_test(pSuite, "iso_node_set_name()", test_iso_node_set_name); + CU_add_test(pSuite, "iso_node_add_xinfo()", test_iso_node_add_xinfo); + CU_add_test(pSuite, "iso_node_get_xinfo()", test_iso_node_get_xinfo); + CU_add_test(pSuite, "iso_node_remove_xinfo()", test_iso_node_remove_xinfo); } From 987fa4b32368cc13af72caf94e396566f413ae47 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Mon, 17 Mar 2008 15:50:38 +0100 Subject: [PATCH 25/29] Improve find iterator, to make has_next() actually work. --- libisofs/find.c | 94 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 75 insertions(+), 19 deletions(-) diff --git a/libisofs/find.c b/libisofs/find.c index 797ef88..787c36d 100644 --- a/libisofs/find.c +++ b/libisofs/find.c @@ -39,22 +39,49 @@ struct find_iter_data { IsoDirIter *iter; IsoFindCondition *cond; + int err; /**< error? */ + IsoNode *current; /**< node to be returned next */ + IsoNode *prev; /**< last returned node, needed for removal */ + int free_cond; /**< whether to free cond on iter_free */ }; +static +void update_next(struct find_iter_data *iter) +{ + int ret; + IsoNode *n; + + if (iter->prev) { + iso_node_unref(iter->prev); + } + iter->prev = iter->current; + while ((ret = iso_dir_iter_next(iter->iter, &n)) == 1) { + if (iter->cond->matches(iter->cond, n)) { + iter->current = n; + iso_node_ref(n); + iter->err = 0; + return; + } + } + iter->current = NULL; + iter->err = ret; +} + static int find_iter_next(IsoDirIter *iter, IsoNode **node) { - int ret; - IsoNode *n; struct find_iter_data *data = iter->data; - while ((ret = iso_dir_iter_next(data->iter, &n)) == 1) { - if (data->cond->matches(data->cond, n)) { - *node = n; - break; - } + if (iter == NULL || node == NULL) { + return ISO_NULL_POINTER; } - return ret; + + if (data->err < 0) { + return data->err; + } + *node = data->current; + update_next(data); + return (*node == NULL) ? 0 : ISO_SUCCESS; } static @@ -62,19 +89,27 @@ int find_iter_has_next(IsoDirIter *iter) { struct find_iter_data *data = iter->data; - /* - * FIXME wrong implementation!!!! the underlying iter may have more nodes, - * but they may not match find conditions - */ - return iso_dir_iter_has_next(data->iter); + return (data->current != NULL); } static void find_iter_free(IsoDirIter *iter) { struct find_iter_data *data = iter->data; - data->cond->free(data->cond); - free(data->cond); + if (data->free_cond) { + data->cond->free(data->cond); + free(data->cond); + } + + /* free refs to nodes */ + if (data->prev) { + iso_node_unref(data->prev); + } + if (data->current) { + iso_node_unref(data->current); + } + + /* free underlying iter */ iso_dir_iter_free(data->iter); free(iter->data); } @@ -83,20 +118,37 @@ static int find_iter_take(IsoDirIter *iter) { struct find_iter_data *data = iter->data; - return iso_dir_iter_take(data->iter); + + if (data->prev == NULL) { + return ISO_ERROR; /* next not called or end of dir */ + } + return iso_node_take(data->prev); } static int find_iter_remove(IsoDirIter *iter) { struct find_iter_data *data = iter->data; - return iso_dir_iter_remove(data->iter); + + if (data->prev == NULL) { + return ISO_ERROR; /* next not called or end of dir */ + } + return iso_node_remove(data->prev); } void find_notify_child_taken(IsoDirIter *iter, IsoNode *node) { - /* nothing to do */ - return; + struct find_iter_data *data = iter->data; + + if (data->prev == node) { + /* free our ref */ + iso_node_unref(node); + data->prev = NULL; + } else if (data->current == node) { + iso_node_unref(node); + data->current = NULL; + update_next(data); + } } static @@ -140,6 +192,9 @@ int iso_dir_find_children(IsoDir* dir, IsoFindCondition *cond, it->dir = (IsoDir*)dir; data->iter = children; data->cond = cond; + data->free_cond = 1; + data->err = 0; + data->prev = data->current = NULL; it->data = data; if (iso_dir_iter_register(it) < 0) { @@ -147,6 +202,7 @@ int iso_dir_find_children(IsoDir* dir, IsoFindCondition *cond, return ISO_OUT_OF_MEM; } + update_next(data); *iter = it; return ISO_SUCCESS; } From 8b10d3107a7f346378042b438e7dcacd9a8a760b Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Mon, 17 Mar 2008 16:02:50 +0100 Subject: [PATCH 26/29] Make IsoDirIters take also a ref on the dir they iterate. --- libisofs/find.c | 1 + libisofs/node.c | 2 ++ test/test_node.c | 8 ++++++++ 3 files changed, 11 insertions(+) diff --git a/libisofs/find.c b/libisofs/find.c index 787c36d..6a63307 100644 --- a/libisofs/find.c +++ b/libisofs/find.c @@ -203,6 +203,7 @@ int iso_dir_find_children(IsoDir* dir, IsoFindCondition *cond, } update_next(data); + iso_node_ref((IsoNode*)dir); *iter = it; return ISO_SUCCESS; } diff --git a/libisofs/node.c b/libisofs/node.c index 6442473..9c8dee9 100644 --- a/libisofs/node.c +++ b/libisofs/node.c @@ -772,6 +772,7 @@ int iso_dir_get_children(const IsoDir *dir, IsoDirIter **iter) return ISO_OUT_OF_MEM; } + iso_node_ref((IsoNode*)dir); /* tak a ref to the dir */ *iter = it; return ISO_SUCCESS; } @@ -797,6 +798,7 @@ void iso_dir_iter_free(IsoDirIter *iter) if (iter != NULL) { iso_dir_iter_unregister(iter); iter->class->free(iter); + iso_node_unref((IsoNode*)iter->dir); free(iter); } } diff --git a/test/test_node.c b/test/test_node.c index 2fdcf0c..803d2eb 100644 --- a/test/test_node.c +++ b/test/test_node.c @@ -420,11 +420,13 @@ void test_iso_dir_get_children() /* init dir with default values, not all field need to be initialized */ dir = malloc(sizeof(IsoDir)); + dir->node.refcount = 1; dir->children = NULL; dir->nchildren = 0; result = iso_dir_get_children(dir, &iter); CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_EQUAL(dir->node.refcount, 2); /* item should have no items */ result = iso_dir_iter_has_next(iter); @@ -524,6 +526,7 @@ void test_iso_dir_get_children() CU_ASSERT_EQUAL(result, 0); CU_ASSERT_PTR_NULL(node); iso_dir_iter_free(iter); + CU_ASSERT_EQUAL(dir->node.refcount, 1); /* assert correct refcount */ CU_ASSERT_EQUAL(node1->refcount, 1); @@ -545,11 +548,13 @@ void test_iso_dir_iter_take() /* init dir with default values, not all field need to be initialized */ dir = malloc(sizeof(IsoDir)); + dir->node.refcount = 1; dir->children = NULL; dir->nchildren = 0; result = iso_dir_get_children(dir, &iter); CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_EQUAL(dir->node.refcount, 2); /* remove on empty dir! */ result = iso_dir_iter_take(iter); @@ -685,6 +690,7 @@ void test_iso_dir_iter_take() CU_ASSERT_PTR_EQUAL(node3->next, node1); iso_dir_iter_free(iter); + CU_ASSERT_EQUAL(dir->node.refcount, 1); /* assert correct refcount */ CU_ASSERT_EQUAL(node1->refcount, 1); @@ -706,6 +712,7 @@ void test_iso_dir_iter_remove() /* init dir with default values, not all field need to be initialized */ dir = malloc(sizeof(IsoDir)); + dir->node.refcount = 1; dir->children = NULL; dir->nchildren = 0; @@ -866,6 +873,7 @@ void test_iso_dir_iter_when_external_take() /* init dir with default values, not all field need to be initialized */ dir = malloc(sizeof(IsoDir)); + dir->node.refcount = 1; dir->children = NULL; dir->nchildren = 0; From 2374976b6df4099ad2250f8f48978292939a6bd8 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Mon, 17 Mar 2008 17:24:42 +0100 Subject: [PATCH 27/29] Make iso_dir_find_children() work recursivelly. --- libisofs/find.c | 103 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 89 insertions(+), 14 deletions(-) diff --git a/libisofs/find.c b/libisofs/find.c index 6a63307..2d81190 100644 --- a/libisofs/find.c +++ b/libisofs/find.c @@ -37,7 +37,9 @@ struct iso_find_condition struct find_iter_data { + IsoDir *dir; /**< original dir of the iterator */ IsoDirIter *iter; + IsoDirIter *itersec; /**< iterator to deal with child dirs */ IsoFindCondition *cond; int err; /**< error? */ IsoNode *current; /**< node to be returned next */ @@ -45,26 +47,90 @@ struct find_iter_data int free_cond; /**< whether to free cond on iter_free */ }; +static +int get_next(struct find_iter_data *iter, IsoNode **n) +{ + int ret; + + if (iter->itersec != NULL) { + ret = iso_dir_iter_next(iter->itersec, n); + if (ret <= 0) { + /* secondary item no more needed */ + iso_dir_iter_free(iter->itersec); + iter->itersec = NULL; + } + if (ret != 0) { + /* succes or error */ + return ret; + } + } + + /* + * we reach here if: + * - no secondary item is present + * - secondary item has no more items + */ + + while ((ret = iso_dir_iter_next(iter->iter, n)) == 1) { + if (iter->cond->matches(iter->cond, *n)) { + return ISO_SUCCESS; + } else if (ISO_NODE_IS_DIR(*n)) { + /* recurse on child dir */ + struct find_iter_data *data; + ret = iso_dir_find_children((IsoDir*)*n, iter->cond, + &iter->itersec); + if (ret < 0) { + return ret; + } + data = iter->itersec->data; + data->free_cond = 0; /* we don't need sec iter to free cond */ + return get_next(iter, n); + } + } + return ret; +} + static -void update_next(struct find_iter_data *iter) +void update_next(IsoDirIter *iter) { int ret; IsoNode *n; + struct find_iter_data *data = iter->data; - if (iter->prev) { - iso_node_unref(iter->prev); + if (data->prev) { + iso_node_unref(data->prev); } - iter->prev = iter->current; - while ((ret = iso_dir_iter_next(iter->iter, &n)) == 1) { - if (iter->cond->matches(iter->cond, n)) { - iter->current = n; - iso_node_ref(n); - iter->err = 0; + data->prev = data->current; + + if (data->itersec == NULL && data->current != NULL + && ISO_NODE_IS_DIR(data->current)) { + + /* we need to recurse on child dir */ + struct find_iter_data *data2; + ret = iso_dir_find_children((IsoDir*)data->current, data->cond, + &data->itersec); + if (ret < 0) { + data->current = NULL; + data->err = ret; return; } + data2 = data->itersec->data; + data2->free_cond = 0; /* we don't need sec iter to free cond */ } - iter->current = NULL; - iter->err = ret; + + ret = get_next(data, &n); + iso_node_unref((IsoNode*)iter->dir); + if (ret == 1) { + data->current = n; + iso_node_ref(n); + data->err = 0; + iter->dir = n->parent; + } else { + data->current = NULL; + data->err = ret; + iter->dir = data->dir; + } + iso_node_ref((IsoNode*)iter->dir); } static @@ -80,7 +146,7 @@ int find_iter_next(IsoDirIter *iter, IsoNode **node) return data->err; } *node = data->current; - update_next(data); + update_next(iter); return (*node == NULL) ? 0 : ISO_SUCCESS; } @@ -100,6 +166,8 @@ void find_iter_free(IsoDirIter *iter) data->cond->free(data->cond); free(data->cond); } + + iso_node_unref((IsoNode*)data->dir); /* free refs to nodes */ if (data->prev) { @@ -147,7 +215,7 @@ void find_notify_child_taken(IsoDirIter *iter, IsoNode *node) } else if (data->current == node) { iso_node_unref(node); data->current = NULL; - update_next(data); + update_next(iter); } } @@ -191,6 +259,7 @@ int iso_dir_find_children(IsoDir* dir, IsoFindCondition *cond, it->class = &find_iter_class; it->dir = (IsoDir*)dir; data->iter = children; + data->itersec = NULL; data->cond = cond; data->free_cond = 1; data->err = 0; @@ -202,8 +271,14 @@ int iso_dir_find_children(IsoDir* dir, IsoFindCondition *cond, return ISO_OUT_OF_MEM; } - update_next(data); iso_node_ref((IsoNode*)dir); + + /* take another ref to the original dir */ + data->dir = (IsoDir*)dir; + iso_node_ref((IsoNode*)dir); + + update_next(it); + *iter = it; return ISO_SUCCESS; } From 7b0da1ecd6bb422fe8d676c1125ebd3594fa1230 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Mon, 17 Mar 2008 21:42:44 +0100 Subject: [PATCH 28/29] Add a function to get the path of a node in the IsoImage. --- demo/find.c | 4 +++- libisofs/libisofs.h | 10 ++++++++++ libisofs/tree.c | 24 ++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/demo/find.c b/demo/find.c index 00cccbc..7adc6d0 100644 --- a/demo/find.c +++ b/demo/find.c @@ -23,7 +23,9 @@ print_dir(IsoDir *dir) cond = iso_new_find_conditions_and(c1, c2); iso_dir_find_children(dir, cond, &iter); while (iso_dir_iter_next(iter, &node) == 1) { - printf(" %s\n", iso_node_get_name(node)); + char *path = iso_tree_get_node_path(node); + printf(" %s\n", path); + free(path); } iso_dir_iter_free(iter); } diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index eb7e0af..6c827c0 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -2955,6 +2955,16 @@ int iso_tree_add_dir_rec(IsoImage *image, IsoDir *parent, const char *dir); */ int iso_tree_path_to_node(IsoImage *image, const char *path, IsoNode **node); +/** + * Get the path on image of the given node. + * + * @return + * The path on the image, that must be freed when no more needed. If the + * given node is not added to any image, this returns NULL. + * @since 0.6.4 + */ +char *iso_tree_get_node_path(IsoNode *node); + /** * Increments the reference counting of the given IsoDataSource. * diff --git a/libisofs/tree.c b/libisofs/tree.c index 624539a..8daf7f6 100644 --- a/libisofs/tree.c +++ b/libisofs/tree.c @@ -957,3 +957,27 @@ int iso_tree_path_to_node(IsoImage *image, const char *path, IsoNode **node) } return result; } + +char *iso_tree_get_node_path(IsoNode *node) +{ + if (node == NULL || node->parent == NULL) { + return NULL; + } + + if ((IsoNode*)node->parent == node) { + return strdup("/"); + } else { + char path[PATH_MAX]; + char *parent_path = iso_tree_get_node_path((IsoNode*)node->parent); + if (parent_path == NULL) { + return NULL; + } + if (strlen(parent_path) == 1) { + snprintf(path, PATH_MAX, "/%s", node->name); + } else { + snprintf(path, PATH_MAX, "%s/%s", parent_path, node->name); + } + free(parent_path); + return strdup(path); + } +} From ccc7b0b58fc30eb8926299a3964bf08853fc4e34 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Sat, 5 Apr 2008 17:08:17 +0200 Subject: [PATCH 29/29] Fix allocation problem. --- libisofs/fs_image.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libisofs/fs_image.c b/libisofs/fs_image.c index cbe991f..3387c65 100644 --- a/libisofs/fs_image.c +++ b/libisofs/fs_image.c @@ -2136,7 +2136,7 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image, free(name); return ret; } - link = malloc(sizeof(IsoSymlink)); + link = calloc(1, sizeof(IsoSymlink)); if (link == NULL) { free(name); return ISO_OUT_OF_MEM; @@ -2154,7 +2154,7 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image, { /* source is an special file */ IsoSpecial *special; - special = malloc(sizeof(IsoSpecial)); + special = calloc(1, sizeof(IsoSpecial)); if (special == NULL) { free(name); return ISO_OUT_OF_MEM;