diff options
-rw-r--r-- | include/fstree.h | 4 | ||||
-rw-r--r-- | lib/fstree/src/hardlink.c | 99 | ||||
-rw-r--r-- | lib/fstree/src/post_process.c | 47 |
3 files changed, 78 insertions, 72 deletions
diff --git a/include/fstree.h b/include/fstree.h index 7abf6f5..430574d 100644 --- a/include/fstree.h +++ b/include/fstree.h @@ -208,11 +208,11 @@ tree_node_t *fstree_add_hard_link(fstree_t *fs, const char *path, const char *target); /* - Resolve a hard link node and replace it with a direct pointer to the target. + Try to resolve all hard links in the tree. Returns 0 on success. On failure, errno is set. */ -int fstree_resolve_hard_link(fstree_t *fs, tree_node_t *node); +int fstree_resolve_hard_links(fstree_t *fs); void fstree_insert_sorted(tree_node_t *root, tree_node_t *n); 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); +} diff --git a/lib/fstree/src/post_process.c b/lib/fstree/src/post_process.c index 088916b..940f93d 100644 --- a/lib/fstree/src/post_process.c +++ b/lib/fstree/src/post_process.c @@ -56,51 +56,6 @@ fail_ov: return -1; } -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 (fstree_resolve_hard_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; -} - static file_info_t *file_list_dfs(tree_node_t *n) { if (S_ISREG(n->mode)) { @@ -187,7 +142,7 @@ int fstree_post_process(fstree_t *fs) { size_t inum; - if (resolve_hard_links_dfs(fs, fs->root)) + if (fstree_resolve_hard_links(fs)) return -1; fs->unique_inode_count = 0; |