summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-12-18 19:57:22 +0100
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-12-19 16:34:10 +0100
commit0a6c5d7fa2f276b8e155d69bea17650bad46f089 (patch)
treece9129012b5c8461dbdeaf797aa53b92e33778f5
parentcaa34ed48ba55a50a4187cd1ae307c09c6b75311 (diff)
Split the libfstree add_by_path tree traversal function out
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
-rw-r--r--include/fstree.h14
-rw-r--r--lib/fstree/Makemodule.am2
-rw-r--r--lib/fstree/add_by_path.c56
-rw-r--r--lib/fstree/get_by_path.c76
4 files changed, 96 insertions, 52 deletions
diff --git a/include/fstree.h b/include/fstree.h
index 9d0d045..aff3952 100644
--- a/include/fstree.h
+++ b/include/fstree.h
@@ -173,6 +173,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 '.'
and returns failure state if one of the path components is '..'.
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 <string.h>
#include <errno.h>
-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 <goliath@infraroot.at>
+ */
+#include "config.h"
+
+#include "fstree.h"
+
+#include <string.h>
+#include <errno.h>
+
+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;
+}