aboutsummaryrefslogtreecommitdiff
path: root/lib/fstree/src/hardlink.c
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-04-06 14:53:49 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-04-06 18:07:59 +0200
commitc42e4fbbc6b175f843c4d0eeaaa9ead2d0e746b6 (patch)
treeadf2e61d9acdf5e18321d6ba0277dd3428de8fe3 /lib/fstree/src/hardlink.c
parent23fab1d2b8164a99c5536581bb80769a620c65c0 (diff)
Cleanup: libfstree: move all the hardlink related code to hardlink.c
For some reason, the recursive hardlink resolution ended up in post process, calling into the non recrusive one in hardlink.c that wasn't used elsewhere. Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/fstree/src/hardlink.c')
-rw-r--r--lib/fstree/src/hardlink.c99
1 files changed, 75 insertions, 24 deletions
diff --git a/lib/fstree/src/hardlink.c b/lib/fstree/src/hardlink.c
index 2165b5f..9686219 100644
--- a/lib/fstree/src/hardlink.c
+++ b/lib/fstree/src/hardlink.c
@@ -11,32 +11,10 @@
#include <string.h>
#include <stdlib.h>
+#include <assert.h>
#include <errno.h>
-tree_node_t *fstree_add_hard_link(fstree_t *fs, const char *path,
- const char *target)
-{
- struct stat sb;
- tree_node_t *n;
-
- memset(&sb, 0, sizeof(sb));
- sb.st_mode = S_IFLNK | 0777;
-
- n = fstree_add_generic(fs, path, &sb, target);
- if (n != NULL) {
- if (canonicalize_name(n->data.target)) {
- free(n);
- errno = EINVAL;
- return NULL;
- }
-
- n->mode = FSTREE_MODE_HARD_LINK;
- }
-
- return n;
-}
-
-int fstree_resolve_hard_link(fstree_t *fs, tree_node_t *node)
+static int resolve_link(fstree_t *fs, tree_node_t *node)
{
tree_node_t *start = node;
@@ -74,3 +52,76 @@ int fstree_resolve_hard_link(fstree_t *fs, tree_node_t *node)
node->link_count++;
return 0;
}
+
+static int resolve_hard_links_dfs(fstree_t *fs, tree_node_t *n)
+{
+ tree_node_t *it;
+
+ if (n->mode == FSTREE_MODE_HARD_LINK) {
+ if (resolve_link(fs, n))
+ goto fail_link;
+
+ assert(n->mode == FSTREE_MODE_HARD_LINK_RESOLVED);
+ it = n->data.target_node;
+
+ if (S_ISDIR(it->mode) && it->data.dir.visited)
+ goto fail_link_loop;
+ } else if (S_ISDIR(n->mode)) {
+ n->data.dir.visited = true;
+
+ for (it = n->data.dir.children; it != NULL; it = it->next) {
+ if (resolve_hard_links_dfs(fs, it))
+ return -1;
+ }
+
+ n->data.dir.visited = false;
+ }
+
+ return 0;
+fail_link: {
+ char *path = fstree_get_path(n);
+ fprintf(stderr, "Resolving hard link '%s' -> '%s': %s\n",
+ path == NULL ? n->name : path, n->data.target,
+ strerror(errno));
+ free(path);
+}
+ return -1;
+fail_link_loop: {
+ char *npath = fstree_get_path(n);
+ char *tpath = fstree_get_path(it);
+ fprintf(stderr, "Hard link loop detected in '%s' -> '%s'\n",
+ npath == NULL ? n->name : npath,
+ tpath == NULL ? it->name : tpath);
+ free(npath);
+ free(tpath);
+}
+ return -1;
+}
+
+tree_node_t *fstree_add_hard_link(fstree_t *fs, const char *path,
+ const char *target)
+{
+ struct stat sb;
+ tree_node_t *n;
+
+ memset(&sb, 0, sizeof(sb));
+ sb.st_mode = S_IFLNK | 0777;
+
+ n = fstree_add_generic(fs, path, &sb, target);
+ if (n != NULL) {
+ if (canonicalize_name(n->data.target)) {
+ free(n);
+ errno = EINVAL;
+ return NULL;
+ }
+
+ n->mode = FSTREE_MODE_HARD_LINK;
+ }
+
+ return n;
+}
+
+int fstree_resolve_hard_links(fstree_t *fs)
+{
+ return resolve_hard_links_dfs(fs, fs->root);
+}