summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Kendall <brian@briankendall.net>2022-03-31 16:05:31 -0400
committerRadek Podgorny <radek@podgorny.cz>2022-07-02 18:36:54 +0200
commitfead5105e3bbbe57d18a8a0d1bb8e2c1b8637824 (patch)
tree2cf92dbe6b72c7616c95ad6d4ed8640d9b9e5b44
parent222d01ef8612f33a55cbd6e7326517d0ba8e8652 (diff)
downloadunionfs-fuse-git-fead5105e3bbbe57d18a8a0d1bb8e2c1b8637824.tar.gz
Change rename behavior so that a file stays in the same branch if possible
-rw-r--r--src/findbranch.c40
-rw-r--r--src/findbranch.h1
-rw-r--r--src/fuse_ops.c5
3 files changed, 46 insertions, 0 deletions
diff --git a/src/findbranch.c b/src/findbranch.c
index 843c44f..af526ea 100644
--- a/src/findbranch.c
+++ b/src/findbranch.c
@@ -51,6 +51,46 @@
#include "debug.h"
#include "usyslog.h"
+static bool branch_contains_path(int branch, const char *path, bool *is_dir) {
+ if (branch < 0 || branch >= uopt.nbranches)
+ RETURN(false);
+
+ char p[PATHLEN_MAX];
+ if (BUILD_PATH(p, uopt.branches[branch].path, path)) {
+ errno = ENAMETOOLONG;
+ RETURN(false);
+ }
+
+ printf("***** p: %s\n", p);
+ struct stat stbuf;
+ int res = lstat(p, &stbuf);
+
+ if (res == 0) {
+ (*is_dir) = S_ISDIR(stbuf.st_mode);
+ RETURN(true);
+ } else
+ RETURN(false);
+}
+
+bool branch_contains_file_or_parent_dir(int branch, const char *path) {
+ bool is_dir = false;
+ bool found = branch_contains_path(branch, path, &is_dir);
+
+ if (found)
+ RETURN(true);
+
+ char *dname = u_dirname(path);
+ if (dname == NULL) {
+ errno = ENOMEM;
+ RETURN(false);
+ }
+
+ found = branch_contains_path(branch, dname, &is_dir);
+
+ free(dname);
+ RETURN(found && is_dir);
+}
+
/**
* Find a branch that has "path". Return the branch number.
*/
diff --git a/src/findbranch.h b/src/findbranch.h
index 0636285..8393602 100644
--- a/src/findbranch.h
+++ b/src/findbranch.h
@@ -12,6 +12,7 @@ typedef enum searchflag {
RWONLY
} searchflag_t;
+bool branch_contains_file_or_parent_dir(int branch, const char *path);
int find_rorw_branch(const char *path);
int find_lowest_rw_branch(int branch_ro);
int find_rw_branch_cutlast(const char *path);
diff --git a/src/fuse_ops.c b/src/fuse_ops.c
index 915ceaa..a5a5851 100644
--- a/src/fuse_ops.c
+++ b/src/fuse_ops.c
@@ -490,6 +490,11 @@ static int unionfs_rename(const char *from, const char *to, unsigned int flags)
int i = find_rorw_branch(from);
if (i == -1) RETURN(-errno);
+ if (uopt.branches[i].rw && branch_contains_file_or_parent_dir(i, to)) {
+ DBG("file can stay in same branch\n");
+ j = i;
+ }
+
if (!uopt.branches[i].rw) {
i = find_rw_branch_cow_common(from, true);
if (i == -1) RETURN(-errno);