diff options
author | Henry Stern <stern@fsi.io> | 2015-09-11 13:11:12 -0300 |
---|---|---|
committer | Henry Stern <stern@fsi.io> | 2015-09-11 13:11:12 -0300 |
commit | db20a1bfae369f619f9ee2afcafffb27b9897fa4 (patch) | |
tree | 1cbcea879be2a7d6e53d41d92855cd7ca63294c1 /src/bindfs.c | |
parent | 5922a236d0ce7fcf911fce6ff7a52b11ddcf2142 (diff) | |
download | bindfs-db20a1bfae369f619f9ee2afcafffb27b9897fa4.tar.gz |
Better handle symlinks with destructive system calls.
The unlink, rmdir, and rename system calls behave unexpectedly
if you resolve the symbolic link and perform the operation on that
instead. It would leave a dangling symlink and delete the original
instead which is probably not the intention.
This commit adds another parameter to process_path to enable or disable
the symlink resolution. The bindfs_unlink, bindfs_rmdir and
bindfs_rename functions use this parameter to produce the expected
result. rm -rf will still behave differently, deleting the contents of
the symlinked directory before removing the symlink and not the
linked directory.
Diffstat (limited to 'src/bindfs.c')
-rw-r--r-- | src/bindfs.c | 71 |
1 files changed, 42 insertions, 29 deletions
diff --git a/src/bindfs.c b/src/bindfs.c index 3ee8ac5..48a8693 100644 --- a/src/bindfs.c +++ b/src/bindfs.c @@ -40,6 +40,7 @@ #include <stdlib.h> #include <stddef.h> #include <stdio.h> +#include <stdbool.h> #include <string.h> #include <ctype.h> #ifdef HAVE_SYS_TYPES_H @@ -164,7 +165,7 @@ static int is_mirroring_enabled(); static int is_mirrored_user(uid_t uid); /* Processes the virtual path to a real path. Always free() the result. */ -static char *process_path(const char *path); +static char *process_path(const char *path, bool resolve_symlinks); /* The common parts of getattr and fgetattr. */ static int getattr_common(const char *path, struct stat *stbuf); @@ -246,7 +247,7 @@ static int is_mirrored_user(uid_t uid) } -static char * process_path(const char *path) +static char * process_path(const char *path, bool resolve_symlinks) { char * res; @@ -261,7 +262,7 @@ static char * process_path(const char *path) if (*path == '\0') path = "."; - if (settings.resolve_symlinks) { + if (resolve_symlinks && settings.resolve_symlinks) { res = realpath(path, NULL); if (res) return res; @@ -398,7 +399,7 @@ static int bindfs_getattr(const char *path, struct stat *stbuf) int res; char *real_path; - real_path = process_path(path); + real_path = process_path(path, true); if (real_path == NULL) return -errno; @@ -418,7 +419,7 @@ static int bindfs_fgetattr(const char *path, struct stat *stbuf, int res; char *real_path; - real_path = process_path(path); + real_path = process_path(path, true); if (real_path == NULL) return -errno; @@ -436,7 +437,7 @@ static int bindfs_readlink(const char *path, char *buf, size_t size) int res; char *real_path; - real_path = process_path(path); + real_path = process_path(path, true); if (real_path == NULL) return -errno; @@ -458,7 +459,7 @@ static int bindfs_opendir(const char *path, struct fuse_file_info *fi) DIR *dp; char *real_path; - real_path = process_path(path); + real_path = process_path(path, true); if (real_path == NULL) return -errno; @@ -487,7 +488,7 @@ static int bindfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, long pc_ret; char *real_path; - real_path = process_path(path); + real_path = process_path(path, true); if (real_path == NULL) return -errno; @@ -535,7 +536,7 @@ static int bindfs_mknod(const char *path, mode_t mode, dev_t rdev) struct fuse_context *fc; char *real_path; - real_path = process_path(path); + real_path = process_path(path, true); if (real_path == NULL) return -errno; @@ -563,7 +564,7 @@ static int bindfs_mkdir(const char *path, mode_t mode) struct fuse_context *fc; char *real_path; - real_path = process_path(path); + real_path = process_path(path, true); if (real_path == NULL) return -errno; @@ -588,7 +589,7 @@ static int bindfs_unlink(const char *path) int res; char *real_path; - real_path = process_path(path); + real_path = process_path(path, false); if (real_path == NULL) return -errno; @@ -604,11 +605,23 @@ static int bindfs_rmdir(const char *path) { int res; char *real_path; + struct stat st; - real_path = process_path(path); + real_path = process_path(path, false); if (real_path == NULL) return -errno; + if (lstat(real_path, &st) == -1) + return -errno; + + if (S_ISLNK(st.st_mode)) { + res = unlink(real_path); + free(real_path); + if (res == -1) + return -errno; + return 0; + } + res = rmdir(real_path); free(real_path); if (res == -1) @@ -626,11 +639,11 @@ static int bindfs_symlink(const char *from, const char *to) if (settings.resolve_symlinks) return -EPERM; - real_from = process_path(from); + real_from = process_path(from, false); if (real_from == NULL) return -errno; - real_to = process_path(to); + real_to = process_path(to, false); if (real_to == NULL) { free(real_from); return -errno; @@ -656,11 +669,11 @@ static int bindfs_rename(const char *from, const char *to) int res; char *real_from, *real_to; - real_from = process_path(from); + real_from = process_path(from, false); if (real_from == NULL) return -errno; - real_to = process_path(to); + real_to = process_path(to, true); if (real_to == NULL) { free(real_from); return -errno; @@ -680,11 +693,11 @@ static int bindfs_link(const char *from, const char *to) int res; char *real_from, *real_to; - real_from = process_path(from); + real_from = process_path(from, true); if (real_from == NULL) return -errno; - real_to = process_path(to); + real_to = process_path(to, true); if (real_to == NULL) { free(real_from); return -errno; @@ -706,7 +719,7 @@ static int bindfs_chmod(const char *path, mode_t mode) mode_t diff = 0; char *real_path; - real_path = process_path(path); + real_path = process_path(path, true); if (real_path == NULL) return -errno; @@ -794,7 +807,7 @@ static int bindfs_chown(const char *path, uid_t uid, gid_t gid) } if (uid != -1 || gid != -1) { - real_path = process_path(path); + real_path = process_path(path, true); if (real_path == NULL) return -errno; @@ -812,7 +825,7 @@ static int bindfs_truncate(const char *path, off_t size) int res; char *real_path; - real_path = process_path(path); + real_path = process_path(path, true); if (real_path == NULL) return -errno; @@ -842,7 +855,7 @@ static int bindfs_utimens(const char *path, const struct timespec ts[2]) int res; char *real_path; - real_path = process_path(path); + real_path = process_path(path, true); if (real_path == NULL ) return -errno; @@ -872,7 +885,7 @@ static int bindfs_create(const char *path, mode_t mode, struct fuse_file_info *f struct fuse_context *fc; char *real_path; - real_path = process_path(path); + real_path = process_path(path, true); if (real_path == NULL) return -errno; @@ -898,7 +911,7 @@ static int bindfs_open(const char *path, struct fuse_file_info *fi) int fd; char *real_path; - real_path = process_path(path); + real_path = process_path(path, true); if (real_path == NULL) return -errno; @@ -950,7 +963,7 @@ static int bindfs_statfs(const char *path, struct statvfs *stbuf) int res; char *real_path; - real_path = process_path(path); + real_path = process_path(path, true); if (real_path == NULL) return -errno; @@ -1012,7 +1025,7 @@ static int bindfs_setxattr(const char *path, const char *name, const char *value if (settings.xattr_policy == XATTR_READ_ONLY) return -EACCES; - real_path = process_path(path); + real_path = process_path(path, true); if (real_path == NULL) return -errno; @@ -1054,7 +1067,7 @@ static int bindfs_getxattr(const char *path, const char *name, char *value, DPRINTF("getxattr %s %s", path, name); - real_path = process_path(path); + real_path = process_path(path, true); if (real_path == NULL) return -errno; @@ -1084,7 +1097,7 @@ static int bindfs_listxattr(const char *path, char* list, size_t size) DPRINTF("listxattr %s", path); - real_path = process_path(path); + real_path = process_path(path, true); if (real_path == NULL) return -errno; @@ -1137,7 +1150,7 @@ static int bindfs_removexattr(const char *path, const char *name) if (settings.xattr_policy == XATTR_READ_ONLY) return -EACCES; - real_path = process_path(path); + real_path = process_path(path, true); if (real_path == NULL) return -errno; |