aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenry Stern <stern@fsi.io>2015-09-11 13:11:12 -0300
committerHenry Stern <stern@fsi.io>2015-09-11 13:11:12 -0300
commitdb20a1bfae369f619f9ee2afcafffb27b9897fa4 (patch)
tree1cbcea879be2a7d6e53d41d92855cd7ca63294c1
parent5922a236d0ce7fcf911fce6ff7a52b11ddcf2142 (diff)
downloadbindfs-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.
-rw-r--r--src/bindfs.c71
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;