summaryrefslogtreecommitdiff
path: root/lib/fstree/hardlink.c
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-12-19 16:10:39 +0100
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-12-22 22:07:44 +0100
commit1466f1f8571aca423156ee7ef4094a0c082f88d7 (patch)
tree76863754fe3a0546ec8279da97cbeae7700b0abc /lib/fstree/hardlink.c
parent0a6c5d7fa2f276b8e155d69bea17650bad46f089 (diff)
Add basic support for handling and serializing hard links
In libfstree, add a function to add a hard link to the fstree. The hard links stores the target in the data.target field, canonicalizes the target and sets a sentinel mode. A second function is used to resolve link, i.e. replacing it with a direct pointer, setting another sentinel mode and increasing the targets link count. The post process function tries to resolve unresolved hard links and only allocates inode numbers for nodes that aren't hard links. If the target node of a hard link does not have an inode number yet, the two need to be swapped, since this is also the order in which they are serialized. The serialization function in libcommon simply has to skip hard link nodes and when writing directory entries, use the inode num/ref of the target node. Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/fstree/hardlink.c')
-rw-r--r--lib/fstree/hardlink.c65
1 files changed, 65 insertions, 0 deletions
diff --git a/lib/fstree/hardlink.c b/lib/fstree/hardlink.c
new file mode 100644
index 0000000..8a79d46
--- /dev/null
+++ b/lib/fstree/hardlink.c
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+/*
+ * hardlink.c
+ *
+ * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
+ */
+#include "config.h"
+
+#include "fstree.h"
+
+#include <string.h>
+#include <stdlib.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)
+{
+ tree_node_t *start = node;
+
+ while (node->mode == FSTREE_MODE_HARD_LINK ||
+ node->mode == FSTREE_MODE_HARD_LINK_RESOLVED) {
+ if (node->mode == FSTREE_MODE_HARD_LINK_RESOLVED) {
+ node = node->data.target_node;
+ } else {
+ node = fstree_get_node_by_path(fs, fs->root,
+ node->data.target,
+ false, false);
+ if (node == NULL)
+ return -1;
+ }
+
+ if (node == start) {
+ errno = EMLINK;
+ return -1;
+ }
+ }
+
+ start->mode = FSTREE_MODE_HARD_LINK_RESOLVED;
+ start->data.target_node = node;
+
+ node->link_count += 1;
+ return 0;
+}