From 0a6c5d7fa2f276b8e155d69bea17650bad46f089 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Wed, 18 Dec 2019 19:57:22 +0100 Subject: Split the libfstree add_by_path tree traversal function out Signed-off-by: David Oberhollenzer --- include/fstree.h | 14 +++++++++ lib/fstree/Makemodule.am | 2 +- lib/fstree/add_by_path.c | 56 ++++------------------------------- lib/fstree/get_by_path.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+), 52 deletions(-) create mode 100644 lib/fstree/get_by_path.c diff --git a/include/fstree.h b/include/fstree.h index 9d0d045..aff3952 100644 --- a/include/fstree.h +++ b/include/fstree.h @@ -172,6 +172,20 @@ void fstree_post_process(fstree_t *fs); */ char *fstree_get_path(tree_node_t *node); +/* + Resolve a path to a tree node. Returns NULL on failure and sets errno. + + If "create_implicitly" is set to true, the function acts essentially like + mkdir_p if part of the path doesn't exist yet. + + If "stop_at_parent" is true, the function stops at the last component and + returns the parent or would-be-parent of the last path component, but doesn't + check if the last path component exists or not. + */ +tree_node_t *fstree_get_node_by_path(fstree_t *fs, tree_node_t *root, + const char *path, bool create_implicitly, + bool stop_at_parent); + /* Convert back to forward slashed, remove all preceeding and trailing slashes, collapse all sequences of slashes, remove all path components that are '.' diff --git a/lib/fstree/Makemodule.am b/lib/fstree/Makemodule.am index 31bcb31..751d7dc 100644 --- a/lib/fstree/Makemodule.am +++ b/lib/fstree/Makemodule.am @@ -2,7 +2,7 @@ libfstree_a_SOURCES = lib/fstree/fstree.c lib/fstree/fstree_from_file.c libfstree_a_SOURCES += lib/fstree/fstree_sort.c libfstree_a_SOURCES += lib/fstree/post_process.c lib/fstree/get_path.c libfstree_a_SOURCES += lib/fstree/mknode.c -libfstree_a_SOURCES += lib/fstree/add_by_path.c +libfstree_a_SOURCES += lib/fstree/add_by_path.c lib/fstree/get_by_path.c libfstree_a_SOURCES += include/fstree.h lib/fstree/internal.h libfstree_a_SOURCES += lib/fstree/source_date_epoch.c libfstree_a_SOURCES += lib/fstree/canonicalize_name.c diff --git a/lib/fstree/add_by_path.c b/lib/fstree/add_by_path.c index bd47a76..7c9063e 100644 --- a/lib/fstree/add_by_path.c +++ b/lib/fstree/add_by_path.c @@ -11,69 +11,23 @@ #include #include -static tree_node_t *child_by_name(tree_node_t *root, const char *name, - size_t len) -{ - tree_node_t *n = root->data.dir.children; - - while (n != NULL) { - if (strncmp(n->name, name, len) == 0 && n->name[len] == '\0') - break; - - n = n->next; - } - - return n; -} - -static tree_node_t *get_parent_node(fstree_t *fs, tree_node_t *root, - const char *path) -{ - const char *end; - tree_node_t *n; - - for (;;) { - if (!S_ISDIR(root->mode)) { - errno = ENOTDIR; - return NULL; - } - - end = strchr(path, '/'); - if (end == NULL) - break; - - n = child_by_name(root, path, end - path); - - if (n == NULL) { - n = fstree_mknode(root, path, end - path, NULL, - &fs->defaults); - if (n == NULL) - return NULL; - - n->data.dir.created_implicitly = true; - } - - root = n; - path = end + 1; - } - - return root; -} - tree_node_t *fstree_add_generic(fstree_t *fs, const char *path, const struct stat *sb, const char *extra) { tree_node_t *child, *parent; const char *name; - parent = get_parent_node(fs, fs->root, path); + parent = fstree_get_node_by_path(fs, fs->root, path, true, true); if (parent == NULL) return NULL; name = strrchr(path, '/'); name = (name == NULL ? path : (name + 1)); - child = child_by_name(parent, name, strlen(name)); + child = parent->data.dir.children; + while (child != NULL && strcmp(child->name, name) != 0) + child = child->next; + if (child != NULL) { if (!S_ISDIR(child->mode) || !S_ISDIR(sb->st_mode) || !child->data.dir.created_implicitly) { diff --git a/lib/fstree/get_by_path.c b/lib/fstree/get_by_path.c new file mode 100644 index 0000000..8742892 --- /dev/null +++ b/lib/fstree/get_by_path.c @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * get_by_path.c + * + * Copyright (C) 2019 David Oberhollenzer + */ +#include "config.h" + +#include "fstree.h" + +#include +#include + +static tree_node_t *child_by_name(tree_node_t *root, const char *name, + size_t len) +{ + tree_node_t *n = root->data.dir.children; + + while (n != NULL) { + if (strncmp(n->name, name, len) == 0 && n->name[len] == '\0') + break; + + n = n->next; + } + + return n; +} + +tree_node_t *fstree_get_node_by_path(fstree_t *fs, tree_node_t *root, + const char *path, bool create_implicitly, + bool stop_at_parent) +{ + const char *end; + tree_node_t *n; + size_t len; + + while (*path != '\0') { + while (*path == '/') + ++path; + + if (!S_ISDIR(root->mode)) { + errno = ENOTDIR; + return NULL; + } + + end = strchr(path, '/'); + if (end == NULL) { + if (stop_at_parent) + break; + + len = strlen(path); + } else { + len = end - path; + } + + n = child_by_name(root, path, len); + + if (n == NULL) { + if (!create_implicitly) { + errno = ENOENT; + return NULL; + } + + n = fstree_mknode(root, path, len, NULL, &fs->defaults); + if (n == NULL) + return NULL; + + n->data.dir.created_implicitly = true; + } + + root = n; + path = path + len; + } + + return root; +} -- cgit v1.2.3