aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;
+}