aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bindfs.138
-rw-r--r--src/bindfs.c59
2 files changed, 74 insertions, 23 deletions
diff --git a/src/bindfs.1 b/src/bindfs.1
index 55fc349..01887ac 100644
--- a/src/bindfs.1
+++ b/src/bindfs.1
@@ -221,6 +221,35 @@ following (1024-based) suffixes: \fBk\fP, \fBM\fP, \fBG\fP, \fBT\fP.
.B \-\-write\-rate=\fIN\fP, \-o write\-rate=\fIN\fP
Same as above, but for writes.
+.SH LINK HANDLING
+
+.TP
+.B \-\-hide\-hard\-links, \-o hide\-hard\-links
+Shows the hard link count of all files as 1.
+
+.TP
+.B \-\-resolve\-symlinks, \-o resolve-symlinks
+Transparently resolves symbolic links. Disables creation of new symbolic
+links.
+
+With the following exceptions, operations will operate directly on the target
+file instead of the symlink. Renaming/moving a resolved symlink (inside the same
+mount point) will move the symlink instead of the underlying file. Deleting a
+resolved symlink will delete the underlying symlink but not the destination
+file. This can be configured with \fB\-\-resolved-symlink-deletion\fP.
+
+Note that when some programs, such as \fBvim\fP, save files, they actually move
+the old file out of the way, create a new file in its place, and finally delete
+the old file. Doing these operations on a resolved symlink will replace it with
+a regular file.
+
+Symlinks pointing outside the source directory are supported with the following
+exception: accessing the mountpoint recursively through a resolved symlink is
+not supported and will return an error. This is because a FUSE filesystem cannot
+reliably call itself recursively without deadlocking, especially in
+single-threaded mode.
+
+
.SH MISCELLANEOUS OPTIONS
.TP
@@ -259,15 +288,6 @@ will be reflected in a mirrored file's ctime.
The underlying file's ctime will still be updated normally.
.TP
-.B \-\-hide-hard-links, \-o hide-hard-links
-Shows the hard link count of all files as 1.
-
-.TP
-.B \-\-resolve\-symlinks, \-o resolve-symlinks
-Transparently resolves symbolic links. Disables creation of new symbolic
-links.
-
-.TP
.B \-\-multithreaded, \-o multithreaded
Run bindfs in multithreaded mode. While bindfs is designed to be
otherwise thread-safe, there is currently a race condition that may pose
diff --git a/src/bindfs.c b/src/bindfs.c
index eb8b874..6d08a11 100644
--- a/src/bindfs.c
+++ b/src/bindfs.c
@@ -93,18 +93,19 @@ static struct Settings {
gid_t new_gid; /* user-specified gid */
uid_t create_for_uid;
gid_t create_for_gid;
- const char *mntsrc;
- const char *mntdest;
+ char *mntsrc;
+ char *mntdest;
+ int mntdest_len; /* caches strlen(mntdest) */
int mntsrc_fd;
- char* original_working_dir;
+ char *original_working_dir;
mode_t original_umask;
- UserMap* usermap; /* From the --map option. */
- UserMap* usermap_reverse;
+ UserMap *usermap; /* From the --map option. */
+ UserMap *usermap_reverse;
- RateLimiter* read_limiter;
- RateLimiter* write_limiter;
+ RateLimiter *read_limiter;
+ RateLimiter *write_limiter;
enum CreatePolicy {
CREATE_AS_USER,
@@ -142,7 +143,7 @@ static struct Settings {
} xattr_policy;
int mirrored_users_only;
- uid_t* mirrored_users;
+ uid_t *mirrored_users;
int num_mirrored_users;
gid_t *mirrored_members;
int num_mirrored_members;
@@ -260,10 +261,26 @@ static char *process_path(const char *path, bool resolve_symlinks)
if (*path == '\0')
path = ".";
- if (resolve_symlinks && settings.resolve_symlinks)
- return realpath(path, NULL);
- else
+ if (resolve_symlinks && settings.resolve_symlinks) {
+ char* result = realpath(path, NULL);
+ if (result == NULL) {
+ if (errno == ENOENT) {
+ /* Broken symlink (or missing file). Don't return null because
+ we want to be able to operate on broken symlinks. */
+ return strdup(path);
+ }
+ } else if (strncmp(result, settings.mntdest, settings.mntdest_len) == 0) {
+ /* Recursive call. We cannot handle this without deadlocking,
+ especially in single-threaded mode. */
+ DPRINTF("Denying recursive access to mountpoint `%s'", result);
+ free(result);
+ errno = EPERM;
+ return NULL;
+ }
+ return result;
+ } else {
return strdup(path);
+ }
}
static int getattr_common(const char *procpath, struct stat *stbuf)
@@ -1395,10 +1412,21 @@ static int process_option(void *data, const char *arg, int key,
case OPTKEY_NONOPTION:
if (!settings.mntsrc) {
- settings.mntsrc = arg;
+ settings.mntsrc = realpath(arg, NULL);
+ if (settings.mntsrc == NULL) {
+ fprintf(stderr, "Failed to resolve source directory `%s': ", arg);
+ perror(NULL);
+ return -1;
+ }
return 0;
} else if (!settings.mntdest) {
- settings.mntdest = arg;
+ settings.mntdest = realpath(arg, NULL);
+ if (settings.mntdest == NULL) {
+ fprintf(stderr, "Failed to resolve mount point `%s': ", arg);
+ perror(NULL);
+ return -1;
+ }
+ settings.mntdest_len = strlen(settings.mntdest);
return 1; /* leave this argument for fuse_main */
} else {
fprintf(stderr, "Too many arguments given\n");
@@ -1417,7 +1445,7 @@ static int parse_mirrored_users(char* mirror)
char *p, *tmpstr;
settings.num_mirrored_users = count_chars(mirror, ',') +
- count_chars(mirror, ':') + 1;
+ count_chars(mirror, ':') + 1;
settings.num_mirrored_members = ((*mirror == '@') ? 1 : 0) +
count_substrs(mirror, ",@") +
count_substrs(mirror, ":@");
@@ -1599,6 +1627,8 @@ static void signal_handler(int sig)
static void atexit_func()
{
+ free(settings.mntsrc);
+ free(settings.mntdest);
free(settings.original_working_dir);
settings.original_working_dir = NULL;
if (settings.read_limiter) {
@@ -1729,6 +1759,7 @@ int main(int argc, char *argv[])
settings.create_for_gid = -1;
settings.mntsrc = NULL;
settings.mntdest = NULL;
+ settings.mntdest_len = 0;
settings.original_working_dir = get_working_dir();
settings.create_policy = (getuid() == 0) ? CREATE_AS_USER : CREATE_AS_MOUNTER;
settings.create_permchain = permchain_create();