diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bindfs.1 | 38 | ||||
-rw-r--r-- | src/bindfs.c | 59 |
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(); |