diff options
author | Bernd Schubert <bernd.schubert@fastmail.fm> | 2010-05-31 21:27:52 +0200 |
---|---|---|
committer | Bernd Schubert <bernd.schubert@fastmail.fm> | 2010-05-31 21:27:52 +0200 |
commit | 1d9f17c0536cb2891987feee7f4e08a5dabf2579 (patch) | |
tree | d2a420dcca28b9d186b0dbd75ab1a6ee3f38606c /src | |
parent | 5857e2ae19211ae94a3c026413fe94c292a1f0ed (diff) | |
download | unionfs-fuse-1d9f17c0536cb2891987feee7f4e08a5dabf2579.tar.gz |
Fix ubuntu bug 587917, Properly check on rmdir() if sub-branches are empty
Diffstat (limited to 'src')
-rw-r--r-- | src/readdir.c | 80 | ||||
-rw-r--r-- | src/readdir.h | 1 | ||||
-rw-r--r-- | src/rmdir.c | 3 |
3 files changed, 84 insertions, 0 deletions
diff --git a/src/readdir.c b/src/readdir.c index b5eb19c..d5c3d01 100644 --- a/src/readdir.c +++ b/src/readdir.c @@ -182,3 +182,83 @@ out: return rc; } + +/** + * check if a directory on all paths is empty + * return 0 if empty, 1 if not and negative value on error + * + * TODO: This shares lots of code with unionfs_readdir(), can we merge + * both functions? + */ +int dir_not_empty(const char *path) { + + DBG_IN(); + + int i = 0; + int rc = 0; + int not_empty = 0; + + struct hashtable *whiteouts = NULL; + + if (uopt.cow_enabled) whiteouts = create_hashtable(16, string_hash, string_equal); + + bool subdir_hidden = false; + + for (i = 0; i < uopt.nbranches; i++) { + if (subdir_hidden) break; + + char p[PATHLEN_MAX]; + if (BUILD_PATH(p, uopt.branches[i].path, path)) { + rc = -ENAMETOOLONG; + goto out; + } + + // check if branches below this branch are hidden + int res = path_hidden(path, i); + if (res < 0) { + rc = res; // error + goto out; + } + + if (res > 0) subdir_hidden = true; + + DIR *dp = opendir(p); + if (dp == NULL) { + if (uopt.cow_enabled) read_whiteouts(path, whiteouts, i); + continue; + } + + struct dirent *de; + while ((de = readdir(dp)) != NULL) { + + // Ignore . and .. + if ((strcmp(de->d_name, ".") == 0) || (strcmp(de->d_name, "..") == 0)) + continue; + + // check if we need file hiding + if (uopt.cow_enabled) { + // file should be hidden from the user + if (hashtable_search(whiteouts, de->d_name) != NULL) continue; + } + + if (hide_meta_dir(i, p, de) == true) continue; + + // When we arrive here, a valid entry was found + not_empty = 1; + closedir(dp); + goto out; + } + + closedir(dp); + if (uopt.cow_enabled) read_whiteouts(path, whiteouts, i); + } + +out: + if (uopt.cow_enabled) hashtable_destroy(whiteouts, 1); + + if (rc) return rc; + + return not_empty; +} + + diff --git a/src/readdir.h b/src/readdir.h index e52a622..cfbf227 100644 --- a/src/readdir.h +++ b/src/readdir.h @@ -4,5 +4,6 @@ #include <fuse.h> int unionfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi); +int dir_not_empty(const char *path); #endif diff --git a/src/rmdir.c b/src/rmdir.c index ccaf7e0..e5212c9 100644 --- a/src/rmdir.c +++ b/src/rmdir.c @@ -31,6 +31,7 @@ #include "general.h" #include "findbranch.h" #include "string.h" +#include "readdir.h" /** * If the branch that has the directory to be removed is in read-write mode, @@ -84,6 +85,8 @@ static int rmdir_ro(const char *path, int branch_ro) { int unionfs_rmdir(const char *path) { DBG_IN(); + if (dir_not_empty(path)) return -ENOTEMPTY; + int i = find_rorw_branch(path); if (i == -1) return -errno; |