From 94269ff3c0166474c018c4973c481b2fcff00080 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Fri, 19 Feb 2021 00:55:11 +0100 Subject: libfstree: Add a filter callback to the directory scanning function Signed-off-by: David Oberhollenzer --- bin/gensquashfs/mkfs.c | 4 ++-- include/fstree.h | 14 +++++++++-- lib/fstree/fstree_from_dir.c | 55 +++++++++++++++++++++++++++++++++++++------- tests/fstree_from_file.c | 2 +- 4 files changed, 62 insertions(+), 13 deletions(-) diff --git a/bin/gensquashfs/mkfs.c b/bin/gensquashfs/mkfs.c index 2885d84..b25d325 100644 --- a/bin/gensquashfs/mkfs.c +++ b/bin/gensquashfs/mkfs.c @@ -160,8 +160,8 @@ int main(int argc, char **argv) } if (opt.infile == NULL) { - if (fstree_from_dir(&sqfs.fs, sqfs.fs.root, - opt.packdir, opt.dirscan_flags)) { + if (fstree_from_dir(&sqfs.fs, sqfs.fs.root, opt.packdir, + NULL, NULL, opt.dirscan_flags)) { goto out; } } else { diff --git a/include/fstree.h b/include/fstree.h index e5fc966..35d6778 100644 --- a/include/fstree.h +++ b/include/fstree.h @@ -41,6 +41,15 @@ typedef struct file_info_t file_info_t; typedef struct dir_info_t dir_info_t; typedef struct fstree_t fstree_t; +/* + Optionally used by fstree_from_dir and fstree_from_subdir to + execute custom actions for each discovered node. + + If it returns a value > 0, the new node is discarded, if < 0, scanning is + aborted and returns a failure status. + */ +typedef int (*scan_node_callback)(void *user, fstree_t *fs, tree_node_t *node); + /* Additional meta data stored in a tree_node_t for regular files. */ struct file_info_t { /* Linked list pointer for files in fstree_t */ @@ -252,7 +261,8 @@ int fstree_resolve_hard_link(fstree_t *fs, tree_node_t *node); Returns 0 on success, prints to stderr on failure. */ int fstree_from_dir(fstree_t *fs, tree_node_t *root, - const char *path, unsigned int flags); + const char *path, scan_node_callback cb, void *user, + unsigned int flags); /* Same as fstree_from_dir, but scans a sub-directory inside the specified path. @@ -261,6 +271,6 @@ int fstree_from_dir(fstree_t *fs, tree_node_t *root, */ int fstree_from_subdir(fstree_t *fs, tree_node_t *root, const char *path, const char *subdir, - unsigned int flags); + scan_node_callback cb, void *user, unsigned int flags); #endif /* FSTREE_H */ diff --git a/lib/fstree/fstree_from_dir.c b/lib/fstree/fstree_from_dir.c index d3e188d..cb066b1 100644 --- a/lib/fstree/fstree_from_dir.c +++ b/lib/fstree/fstree_from_dir.c @@ -12,30 +12,53 @@ #include #include +static void discard_node(tree_node_t *root, tree_node_t *n) +{ + tree_node_t *it; + + if (n == root->data.dir.children) { + root->data.dir.children = n->next; + } else { + it = root->data.dir.children; + + while (it != NULL && it->next != n) + it = it->next; + + if (it != NULL) + it->next = n->next; + } + + free(n); +} + #ifdef _WIN32 int fstree_from_subdir(fstree_t *fs, tree_node_t *root, const char *path, const char *subdir, + scan_node_callback cb, void *user, unsigned int flags) { (void)fs; (void)root; (void)path; (void)subdir; (void)flags; + (void)cb; (void)user; fputs("Packing a directory is not supported on Windows.\n", stderr); return -1; } int fstree_from_dir(fstree_t *fs, tree_node_t *root, - const char *path, unsigned int flags) + const char *path, scan_node_callback cb, + void *user, unsigned int flags) { - return fstree_from_subdir(fs, root, path, NULL, flags); + return fstree_from_subdir(fs, root, path, NULL, cb, user, flags); } #else static int populate_dir(int dir_fd, fstree_t *fs, tree_node_t *root, - dev_t devstart, unsigned int flags) + dev_t devstart, scan_node_callback cb, + void *user, unsigned int flags) { char *extra = NULL; struct dirent *ent; + int ret, childfd; struct stat sb; tree_node_t *n; - int childfd; DIR *dir; dir = fdopendir(dir_fd); @@ -122,6 +145,8 @@ static int populate_dir(int dir_fd, fstree_t *fs, tree_node_t *root, false, false); if (n == NULL) continue; + + ret = 0; } else { n = fstree_mknode(root, ent->d_name, strlen(ent->d_name), extra, &sb); @@ -129,11 +154,21 @@ static int populate_dir(int dir_fd, fstree_t *fs, tree_node_t *root, perror("creating tree node"); goto fail; } + + ret = (cb == NULL) ? 0 : cb(user, fs, n); } free(extra); extra = NULL; + if (ret < 0) + goto fail; + + if (ret > 0) { + discard_node(root, n); + continue; + } + if (S_ISDIR(n->mode) && !(flags & DIR_SCAN_NO_RECURSION)) { childfd = openat(dir_fd, n->name, O_DIRECTORY | O_RDONLY | O_CLOEXEC); @@ -142,8 +177,10 @@ static int populate_dir(int dir_fd, fstree_t *fs, tree_node_t *root, goto fail; } - if (populate_dir(childfd, fs, n, devstart, flags)) + if (populate_dir(childfd, fs, n, devstart, + cb, user, flags)) { goto fail; + } } } @@ -159,6 +196,7 @@ fail: int fstree_from_subdir(fstree_t *fs, tree_node_t *root, const char *path, const char *subdir, + scan_node_callback cb, void *user, unsigned int flags) { struct stat sb; @@ -199,12 +237,13 @@ int fstree_from_subdir(fstree_t *fs, tree_node_t *root, return -1; } - return populate_dir(fd, fs, root, sb.st_dev, flags); + return populate_dir(fd, fs, root, sb.st_dev, cb, user, flags); } int fstree_from_dir(fstree_t *fs, tree_node_t *root, - const char *path, unsigned int flags) + const char *path, scan_node_callback cb, + void *user, unsigned int flags) { - return fstree_from_subdir(fs, root, path, NULL, flags); + return fstree_from_subdir(fs, root, path, NULL, cb, user, flags); } #endif diff --git a/tests/fstree_from_file.c b/tests/fstree_from_file.c index f8f0892..140ffd7 100644 --- a/tests/fstree_from_file.c +++ b/tests/fstree_from_file.c @@ -15,7 +15,7 @@ int main(void) fstree_t fs; TEST_ASSERT(fstree_init(&fs, NULL) == 0); - TEST_ASSERT(fstree_from_file(&fs, TEST_PATH) == 0); + TEST_ASSERT(fstree_from_file(&fs, TEST_PATH, NULL) == 0); fstree_post_process(&fs); n = fs.root->data.dir.children; -- cgit v1.2.3