Hello community, here is the log from the commit of package bindfs for openSUSE:Factory checked in at 2019-08-23 11:09:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/bindfs (Old) and /work/SRC/openSUSE:Factory/.bindfs.new.7948 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "bindfs" Fri Aug 23 11:09:48 2019 rev:18 rq:725417 version:1.14.1 Changes: -------- --- /work/SRC/openSUSE:Factory/bindfs/bindfs.changes 2018-02-09 15:46:52.708829510 +0100 +++ /work/SRC/openSUSE:Factory/.bindfs.new.7948/bindfs.changes 2019-08-23 11:09:53.206457323 +0200 @@ -1,0 +2,11 @@ +Thu Aug 22 20:03:57 UTC 2019 - Jan Engelhardt <[email protected]> + +- Update to new upstream release 1.14.1 + * Do not call realpath() on source dirs starting with "/proc/". + * Fixes to --gid-offset when used with a setgid bit or with + --create-as-mounter. + * Added --forward-odirect. Bindfs now clears O_DIRECT by default. + * Resolve symlinks in readdir() so correct attributes are + returned. + +------------------------------------------------------------------- Old: ---- bindfs-1.13.9.tar.gz New: ---- bindfs-1.14.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ bindfs.spec ++++++ --- /var/tmp/diff_new_pack.mv825j/_old 2019-08-23 11:09:53.738457257 +0200 +++ /var/tmp/diff_new_pack.mv825j/_new 2019-08-23 11:09:53.738457257 +0200 @@ -1,7 +1,7 @@ # # spec file for package bindfs # -# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -12,20 +12,21 @@ # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# Please submit bugfixes or comments via https://bugs.opensuse.org/ # Name: bindfs -Version: 1.13.9 +Version: 1.14.1 Release: 0 -Summary: Mount Directories to other Locations and alter Permission Bits -License: GPL-2.0+ +Summary: Filesystem for mapping directories with alternate permissions +License: GPL-2.0-or-later Group: System/Filesystems -Url: http://bindfs.org/ +URL: https://bindfs.org/ + #Git-Clone: git://github.com/mpartel/bindfs -Source: http://bindfs.org/downloads/%name-%version.tar.gz -BuildRequires: pkgconfig +Source: https://bindfs.org/downloads/%name-%version.tar.gz +BuildRequires: pkg-config BuildRequires: pkgconfig(fuse) >= 2.6.0 %description @@ -34,7 +35,7 @@ mountpoint can be altered using various rules. %prep -%setup -q +%autosetup -p1 %build %configure @@ -44,7 +45,8 @@ %make_install %files -%doc ChangeLog COPYING +%doc ChangeLog +%license COPYING %_bindir/%name %_mandir/man1/%name.1%ext_man ++++++ bindfs-1.13.9.tar.gz -> bindfs-1.14.1.tar.gz ++++++ ++++ 3829 lines of diff (skipped) ++++ retrying with extended exclude list diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/bindfs-1.13.9/.gitignore new/bindfs-1.14.1/.gitignore --- old/bindfs-1.13.9/.gitignore 2017-11-30 11:30:07.000000000 +0100 +++ new/bindfs-1.14.1/.gitignore 2019-06-26 10:47:09.000000000 +0200 @@ -35,6 +35,8 @@ src/bindfs tests/fcntl_locker +tests/odirect_read +tests/odirect_write tests/readdir_inode tests/test_dir_rewind tests/utimens_nofollow diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/bindfs-1.13.9/.travis.yml new/bindfs-1.14.1/.travis.yml --- old/bindfs-1.13.9/.travis.yml 2017-11-30 11:30:07.000000000 +0100 +++ new/bindfs-1.14.1/.travis.yml 2019-06-26 10:47:09.000000000 +0200 @@ -1,6 +1,6 @@ language: c sudo: required -dist: trusty +dist: xenial compiler: - clang - gcc diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/bindfs-1.13.9/ChangeLog new/bindfs-1.14.1/ChangeLog --- old/bindfs-1.13.9/ChangeLog 2017-11-30 11:30:07.000000000 +0100 +++ new/bindfs-1.14.1/ChangeLog 2019-06-26 10:47:09.000000000 +0200 @@ -1,3 +1,23 @@ +2019-06-26 Martin Pärtel <martin dot partel at gmail dot com> + + * Resolve symlinks in readdir() so correct attributes are returned (issue #76). + * Released 1.14.1 + +2019-04-29 Martin Pärtel <martin dot partel at gmail dot com> + + * Added --forward-odirect. Bindfs now clears O_DIRECT by default (PR #74, thanks barp@!). + * Released 1.14.0 + +2019-03-31 Martin Pärtel <martin dot partel at gmail dot com> + + * Fixes to --gid-offset when used with a setgid bit or with --create-as-mounter (PR #73, thanks ehmm@!). + * Released 1.13.11 + +2018-10-09 Martin Pärtel <martin dot partel at gmail dot com> + + * Don't call realpath() on source dirs starting with "/proc/". See #66. + * Released 1.13.10 + 2017-11-30 Martin Pärtel <martin dot partel at gmail dot com> * Added options --delete-deny and --rename-deny as suggested by @roojs. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/bindfs-1.13.9/configure.ac new/bindfs-1.14.1/configure.ac --- old/bindfs-1.13.9/configure.ac 2017-11-30 11:30:07.000000000 +0100 +++ new/bindfs-1.14.1/configure.ac 2019-06-26 10:47:09.000000000 +0200 @@ -1,4 +1,4 @@ -AC_INIT([bindfs],[1.13.9],[[email protected]]) +AC_INIT([bindfs],[1.14.1],[[email protected]]) AM_INIT_AUTOMAKE([foreign serial-tests]) AC_CONFIG_HEADERS([config.h]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/bindfs-1.13.9/src/bindfs.1 new/bindfs-1.14.1/src/bindfs.1 --- old/bindfs-1.13.9/src/bindfs.1 2017-11-30 11:30:07.000000000 +0100 +++ new/bindfs-1.14.1/src/bindfs.1 2019-06-26 10:47:09.000000000 +0200 @@ -366,6 +366,14 @@ otherwise thread-safe, there is currently a race condition that may pose a security risk for some use cases. See \fB\%BUGS\fP below. +.TP +.B \-\-forward\-odirect=\fIalignment\fP, \-o forward\-odirect=\fIalignment\fP +Enable experimental \fBO_DIRECT\fP forwarding, with all read/write requests rounded +to the given alignment (in bytes). By default, the \fBO_DIRECT\fP flag is +not forwarded to the underlying FS. +See \fBopen\fP(2) for details about \fBO_DIRECT\fP. + +Only works on Linux. Ignored on other platforms. .SH FUSE OPTIONS .TP diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/bindfs-1.13.9/src/bindfs.c new/bindfs-1.14.1/src/bindfs.c --- old/bindfs-1.13.9/src/bindfs.c 2017-11-30 11:30:07.000000000 +0100 +++ new/bindfs-1.14.1/src/bindfs.c 2019-06-26 10:47:09.000000000 +0200 @@ -1,5 +1,5 @@ /* - Copyright 2006,2007,2008,2009,2010,2012 Martin Pärtel <[email protected]> + Copyright 2006,2007,2008,2009,2010,2012,2019 Martin Pärtel <[email protected]> This file is part of bindfs. @@ -31,7 +31,7 @@ #include <config.h> -/* For >= 500 for pread/pwrite and readdir_r; >= 700 for utimensat */ +/* For >= 500 for pread/pwrite; >= 700 for utimensat */ #define _XOPEN_SOURCE 700 /* For flock() on FreeBSD. It otherwise gets hidden by _XOPEN_SOURCE */ @@ -72,8 +72,14 @@ #include <sys/xattr.h> #endif -#ifdef __LINUX__ +#ifdef __linux__ +#include <sys/mman.h> +#include <fcntl.h> #include <linux/fs.h> // For BLKGETSIZE64 + +#ifndef O_DIRECT +#define O_DIRECT 00040000 /* direct disk access hint */ +#endif #endif #include <fuse.h> @@ -187,7 +193,12 @@ int enable_lock_forwarding; int enable_ioctl; - + +#ifdef __linux__ + int forward_odirect; + size_t odirect_alignment; +#endif + uid_t uid_offset; gid_t gid_offset; @@ -220,6 +231,10 @@ static int unapply_uid_offset(uid_t *uid); static int unapply_gid_offset(gid_t *gid); +#ifdef __linux__ +static size_t round_up_buffer_size_for_direct_io(size_t size); +#endif + /* FUSE callbacks */ static void *bindfs_init(); static void bindfs_destroy(void *private_data); @@ -381,15 +396,15 @@ /* Block files as regular files. */ if (settings.block_devices_as_files && S_ISBLK(stbuf->st_mode)) { stbuf->st_mode ^= S_IFBLK | S_IFREG; // Flip both bits -#ifdef __LINUX__ + int fd = open(procpath, O_RDONLY); +#ifdef __linux__ uint64_t size; - ioctl(file, BLKGETSIZE64, &size); + ioctl(fd, BLKGETSIZE64, &size); stbuf->st_size = (off_t)size; if (stbuf->st_size < 0) { // Underflow return -EOVERFLOW; } #else - int fd = open(procpath, O_RDONLY); if (fd == -1) { return -errno; } @@ -450,11 +465,16 @@ file_owner = usermap_get_uid_or_default(settings.usermap_reverse, fc->uid, file_owner); file_group = usermap_get_gid_or_default(settings.usermap_reverse, fc->gid, file_group); - if (!unapply_uid_offset(&file_owner)) { - return -UID_GID_OVERFLOW_ERRNO; + if (file_owner != (uid_t)-1) { + if (!unapply_uid_offset(&file_owner)) { + return -UID_GID_OVERFLOW_ERRNO; + } } - if (!unapply_gid_offset(&file_group)) { - return -UID_GID_OVERFLOW_ERRNO; + + if (file_group != (gid_t)-1) { + if (!unapply_gid_offset(&file_group)) { + return -UID_GID_OVERFLOW_ERRNO; + } } if (settings.create_for_uid != -1) @@ -580,6 +600,20 @@ return 1; } +#ifdef __linux__ +static size_t round_up_buffer_size_for_direct_io(size_t size) +{ + // `man 2 open` says this should be block-size aligned and that there's no + // general way to determine this. Empirically the page size should be good enough. + // See also: Pull Request #74 + size_t alignment = settings.odirect_alignment; + size_t rem = size % alignment; + if (rem == 0) { + return size; + } + return size - rem + alignment; +} +#endif static void *bindfs_init() { @@ -680,7 +714,6 @@ } long pc_ret = pathconf(real_path, _PC_NAME_MAX); - free(real_path); if (pc_ret < 0) { DPRINTF("pathconf failed: %s (%d)", strerror(errno), errno); pc_ret = NAME_MAX; @@ -690,17 +723,25 @@ pc_ret = NAME_MAX; } - struct dirent *de_buf = - malloc(offsetof(struct dirent, d_name) + pc_ret + 1); + // Path buffer for resolving symlinks + struct memory_block resolve_buf = MEMORY_BLOCK_INITIALIZER; + if (settings.resolve_symlinks) { + int len = strlen(real_path); + append_to_memory_block(&resolve_buf, real_path, len + 1); + resolve_buf.ptr[len] = '/'; + } + + free(real_path); + real_path = NULL; + int result = 0; while (1) { - struct dirent *de; - result = readdir_r(dp, de_buf, &de); - if (result != 0) { - result = -result; - break; - } + errno = 0; + struct dirent *de = readdir(dp); if (de == NULL) { + if (errno != 0) { + result = -errno; + } break; } @@ -709,6 +750,21 @@ st.st_ino = de->d_ino; st.st_mode = de->d_type << 12; + if (settings.resolve_symlinks && (st.st_mode & S_IFLNK) == S_IFLNK) { + int file_len = strlen(de->d_name) + 1; // (include null terminator) + append_to_memory_block(&resolve_buf, de->d_name, file_len); + char *resolved = realpath(resolve_buf.ptr, NULL); + resolve_buf.size -= file_len; + + if (resolved) { + if (lstat(resolved, &st) == -1) { + result = -errno; + break; + } + free(resolved); + } + } + // See issue #28 for why we pass a 0 offset to `filler` and ignore // `offset`. // @@ -716,14 +772,16 @@ // consider it an error if it does. It is undocumented whether it sets // errno in that case, so we zero it first and set it ourself if it // doesn't. - errno = 0; if (filler(buf, de->d_name, &st, 0) != 0) { result = errno != 0 ? -errno : -EIO; break; } } - free(de_buf); + if (settings.resolve_symlinks) { + free_memory_block(&resolve_buf); + } + closedir(dp); return result; } @@ -1055,7 +1113,14 @@ mode |= S_IFREG; /* tell permchain_apply this is a regular file */ mode = permchain_apply(settings.create_permchain, mode); - fd = open(real_path, fi->flags, mode & 0777); + int flags = fi->flags; +#ifdef __linux__ + if (!settings.forward_odirect) { + flags &= ~O_DIRECT; + } +#endif + + fd = open(real_path, flags, mode & 0777); if (fd == -1) { free(real_path); return -errno; @@ -1078,7 +1143,14 @@ if (real_path == NULL) return -errno; - fd = open(real_path, fi->flags); + int flags = fi->flags; +#ifdef __linux__ + if (!settings.forward_odirect) { + flags &= ~O_DIRECT; + } +#endif + + fd = open(real_path, flags); free(real_path); if (fd == -1) return -errno; @@ -1093,14 +1165,34 @@ int res; (void) path; + char *target_buf = buf; + if (settings.read_limiter) { rate_limiter_wait(settings.read_limiter, size); } - res = pread(fi->fh, buf, size, offset); +#ifdef __linux__ + size_t mmap_size = 0; + if ((fi->flags & O_DIRECT) && settings.forward_odirect) { + mmap_size = round_up_buffer_size_for_direct_io(size); + target_buf = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); + if (target_buf == MAP_FAILED) { + return -ENOMEM; + } + } +#endif + + res = pread(fi->fh, target_buf, size, offset); if (res == -1) res = -errno; +#ifdef __linux__ + if (target_buf != buf) { + memcpy(buf, target_buf, size); + munmap(target_buf, mmap_size); + } +#endif + return res; } @@ -1109,15 +1201,34 @@ { int res; (void) path; + char *source_buf = (char*)buf; if (settings.write_limiter) { rate_limiter_wait(settings.write_limiter, size); } - res = pwrite(fi->fh, buf, size, offset); +#ifdef __linux__ + size_t mmap_size = 0; + if ((fi->flags & O_DIRECT) && settings.forward_odirect) { + mmap_size = round_up_buffer_size_for_direct_io(size); + source_buf = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); + if (source_buf == MAP_FAILED) { + return -ENOMEM; + } + memcpy(source_buf, buf, size); + } +#endif + + res = pwrite(fi->fh, source_buf, size, offset); if (res == -1) res = -errno; +#ifdef __linux__ + if (source_buf != buf) { + munmap(source_buf, mmap_size); + } +#endif + return res; } @@ -1488,6 +1599,7 @@ " --block-devices-as-files Show block devices as regular files.\n" " --multithreaded Enable multithreaded mode. See man page\n" " for security issue with current implementation.\n" + " --forward-odirect=... Forward O_DIRECT (it's cleared by default).\n" "\n" "FUSE options:\n" " -o opt[,opt,...] Mount options.\n" @@ -1636,7 +1748,15 @@ case OPTKEY_NONOPTION: if (!settings.mntsrc) { - settings.mntsrc = realpath(arg, NULL); + if (strncmp(arg, "/proc/", strlen("/proc/")) == 0) { + // /proc/<PID>/root is a strange magical symlink that points to '/' when inspected, + // but leads to a container's root directory when traversed. + // This only works if we don't call realpath() on it. + // See also: #66 + settings.mntsrc = strdup(arg); + } else { + settings.mntsrc = realpath(arg, NULL); + } if (settings.mntsrc == NULL) { fprintf(stderr, "Failed to resolve source directory `%s': ", arg); perror(NULL); @@ -1904,6 +2024,7 @@ char *resolved_symlink_deletion; int no_allow_other; int multithreaded; + char *forward_odirect; char *uid_offset; char *gid_offset; } od; @@ -1975,12 +2096,10 @@ OPT2("--disable-lock-forwarding", "disable-lock-forwarding", OPTKEY_DISABLE_LOCK_FORWARDING), OPT2("--enable-ioctl", "enable-ioctl", OPTKEY_ENABLE_IOCTL), OPT_OFFSET2("--multithreaded", "multithreaded", multithreaded, -1), + OPT_OFFSET2("--forward-odirect=%s", "forward-odirect=%s", forward_odirect, -1), OPT_OFFSET2("--uid-offset=%s", "uid-offset=%s", uid_offset, 0), OPT_OFFSET2("--gid-offset=%s", "gid-offset=%s", gid_offset, 0), - - - - + FUSE_OPT_END }; @@ -2028,6 +2147,10 @@ settings.enable_ioctl = 0; settings.uid_offset = 0; settings.gid_offset = 0; +#ifdef __linux__ + settings.forward_odirect = 0; + settings.odirect_alignment = 0; +#endif atexit(&atexit_func); @@ -2117,7 +2240,7 @@ char* endptr = od.uid_offset; settings.uid_offset = strtoul(od.uid_offset, &endptr, 10); if (*endptr != '\0') { - fprintf(stderr, "Error: Value of --uid-offset must be a positive integer.\n"); + fprintf(stderr, "Error: Value of --uid-offset must be an integer.\n"); return 1; } } @@ -2134,11 +2257,29 @@ char* endptr = od.gid_offset; settings.gid_offset = strtoul(od.gid_offset, &endptr, 10); if (*endptr != '\0') { - fprintf(stderr, "Error: Value of --gid-offset must be a positive integer.\n"); + fprintf(stderr, "Error: Value of --gid-offset must be an integer.\n"); return 1; } } + if (od.forward_odirect) { +#ifdef __linux__ + settings.forward_odirect = 1; + char* endptr = od.forward_odirect; + settings.odirect_alignment = strtoul(od.forward_odirect, &endptr, 10); + if (*endptr != '\0') { + fprintf(stderr, "Error: Value of --forward-odirect must be an integer.\n"); + return 1; + } + if (settings.odirect_alignment == 0) { + fprintf(stderr, "Error: Value of --forward-odirect must be positive.\n"); + return 1; + } +#else + fprintf(stderr, "Warning: --forward-odirect is not supported on this platform.\n"); +#endif + } + /* Parse user and group for new creates */ if (od.create_for_user) { if (getuid() != 0) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/bindfs-1.13.9/src/misc.c new/bindfs-1.14.1/src/misc.c --- old/bindfs-1.13.9/src/misc.c 2017-11-30 11:30:07.000000000 +0100 +++ new/bindfs-1.14.1/src/misc.c 2019-06-26 10:47:09.000000000 +0200 @@ -170,7 +170,7 @@ return 1; } -void init_arena(struct arena *a, int initial_capacity) +void init_memory_block(struct memory_block *a, int initial_capacity) { a->size = 0; a->capacity = initial_capacity; @@ -181,33 +181,39 @@ } } -void grow_arena(struct arena *a, int amount) +void grow_memory_block(struct memory_block *a, int amount) { int new_cap; a->size += amount; if (a->size >= a->capacity) { new_cap = a->capacity; - if (new_cap == 0) { - new_cap = 8; - } else { - new_cap *= 2; + while (new_cap < a->size) { + if (new_cap == 0) { + new_cap = 8; + } else { + new_cap *= 2; + } + if (new_cap < 0) { // Overflow + fprintf(stderr, "Memory block too large."); + abort(); + } } a->ptr = (char *)realloc(a->ptr, new_cap); a->capacity = new_cap; } } -int append_to_arena(struct arena *a, void *src, int src_size) +int append_to_memory_block(struct memory_block *a, void *src, int src_size) { int dest = a->size; - grow_arena(a, src_size); + grow_memory_block(a, src_size); memcpy(&a->ptr[dest], src, src_size); return dest; } -void free_arena(struct arena *a) +void free_memory_block(struct memory_block *a) { free(a->ptr); - init_arena(a, 0); + init_memory_block(a, 0); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/bindfs-1.13.9/src/misc.h new/bindfs-1.14.1/src/misc.h --- old/bindfs-1.13.9/src/misc.h 2017-11-30 11:30:07.000000000 +0100 +++ new/bindfs-1.14.1/src/misc.h 2019-06-26 10:47:09.000000000 +0200 @@ -58,21 +58,21 @@ /* Returns 1 on success, 0 on syntax error. */ int parse_byte_count(const char *str, double *result); -/* Simple arena allocation for when it's convenient to - grow multiple times and deallocate all at once. */ -struct arena { +/* An allocation of contiguous memory with convenient functions for + growing it and appending to it. */ +struct memory_block { char *ptr; int size; int capacity; }; -#define ARENA_INITIALIZER { NULL, 0, 0 } +#define MEMORY_BLOCK_INITIALIZER { NULL, 0, 0 } -void init_arena(struct arena *a, int initial_capacity); -void grow_arena(struct arena *a, int amount); -int append_to_arena(struct arena *a, void *src, int src_size); -void free_arena(struct arena *a); +void init_memory_block(struct memory_block *a, int initial_capacity); +void grow_memory_block(struct memory_block *a, int amount); +int append_to_memory_block(struct memory_block *a, void *src, int src_size); +void free_memory_block(struct memory_block *a); -#define ARENA_GET(a, offset) (&(a).ptr[(offset)]) +#define MEMORY_BLOCK_GET(a, offset) (&(a).ptr[(offset)]) #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/bindfs-1.13.9/src/userinfo.c new/bindfs-1.14.1/src/userinfo.c --- old/bindfs-1.13.9/src/userinfo.c 2017-11-30 11:30:07.000000000 +0100 +++ new/bindfs-1.14.1/src/userinfo.c 2019-06-26 10:47:09.000000000 +0200 @@ -28,13 +28,13 @@ struct uid_cache_entry { uid_t uid; gid_t main_gid; - int username_offset; /* arena-allocated */ + int username_offset; /* allocated in cache_memory_block */ }; struct gid_cache_entry { gid_t gid; int uid_count; - int uids_offset; /* arena-allocated */ + int uids_offset; /* allocated in cache_memory_block */ }; static pthread_rwlock_t cache_lock = PTHREAD_RWLOCK_INITIALIZER; @@ -47,7 +47,7 @@ static int gid_cache_size = 0; static int gid_cache_capacity = 0; -static struct arena cache_arena = ARENA_INITIALIZER; +static struct memory_block cache_memory_block = MEMORY_BLOCK_INITIALIZER; static volatile int cache_rebuild_requested = 1; @@ -67,8 +67,8 @@ static void rebuild_cache() { - free_arena(&cache_arena); - init_arena(&cache_arena, 1024); + free_memory_block(&cache_memory_block); + init_memory_block(&cache_memory_block, 1024); rebuild_uid_cache(); rebuild_gid_cache(); qsort(uid_cache, uid_cache_size, sizeof(struct uid_cache_entry), uid_cache_uid_sortcmp); @@ -126,7 +126,7 @@ ent->main_gid = pw->pw_gid; username_len = strlen(pw->pw_name) + 1; - ent->username_offset = append_to_arena(&cache_arena, pw->pw_name, username_len); + ent->username_offset = append_to_memory_block(&cache_memory_block, pw->pw_name, username_len); } endpwent(); @@ -168,7 +168,7 @@ ent = &gid_cache[gid_cache_size++]; ent->gid = gr->gr_gid; ent->uid_count = 0; - ent->uids_offset = cache_arena.size; + ent->uids_offset = cache_memory_block.size; for (i = 0; gr->gr_mem[i] != NULL; ++i) { uid_ent = (struct uid_cache_entry *)bsearch( @@ -179,8 +179,8 @@ uid_cache_name_searchcmp ); if (uid_ent != NULL) { - grow_arena(&cache_arena, sizeof(uid_t)); - ((uid_t *)ARENA_GET(cache_arena, ent->uids_offset))[ent->uid_count++] = uid_ent->uid; + grow_memory_block(&cache_memory_block, sizeof(uid_t)); + ((uid_t *)MEMORY_BLOCK_GET(cache_memory_block, ent->uids_offset))[ent->uid_count++] = uid_ent->uid; } } } @@ -208,15 +208,15 @@ { int name_a_off = ((struct uid_cache_entry *)a)->username_offset; int name_b_off = ((struct uid_cache_entry *)b)->username_offset; - const char *name_a = (const char *)ARENA_GET(cache_arena, name_a_off); - const char *name_b = (const char *)ARENA_GET(cache_arena, name_b_off); + const char *name_a = (const char *)MEMORY_BLOCK_GET(cache_memory_block, name_a_off); + const char *name_b = (const char *)MEMORY_BLOCK_GET(cache_memory_block, name_b_off); return strcmp(name_a, name_b); } static int uid_cache_name_searchcmp(const void *key, const void *entry) { int name_off = ((struct uid_cache_entry *)entry)->username_offset; - const char *name = (const char *)ARENA_GET(cache_arena, name_off); + const char *name = (const char *)MEMORY_BLOCK_GET(cache_memory_block, name_off); return strcmp((const char *)key, name); } @@ -368,7 +368,7 @@ struct gid_cache_entry *gent = gid_cache_lookup(gid); if (gent) { - uids = (uid_t*)ARENA_GET(cache_arena, gent->uids_offset); + uids = (uid_t*)MEMORY_BLOCK_GET(cache_memory_block, gent->uids_offset); for (i = 0; i < gent->uid_count; ++i) { if (uids[i] == uid) { ret = 1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/bindfs-1.13.9/tests/Makefile.am new/bindfs-1.14.1/tests/Makefile.am --- old/bindfs-1.13.9/tests/Makefile.am 2017-11-30 11:30:07.000000000 +0100 +++ new/bindfs-1.14.1/tests/Makefile.am 2019-06-26 10:47:09.000000000 +0200 @@ -4,10 +4,12 @@ AM_CPPFLAGS = ${my_CPPFLAGS} AM_CFLAGS = ${my_CFLAGS} -noinst_PROGRAMS = readdir_inode utimens_nofollow fcntl_locker test_dir_rewind +noinst_PROGRAMS = readdir_inode utimens_nofollow fcntl_locker odirect_read odirect_write test_dir_rewind readdir_inode_SOURCES = readdir_inode.c utimens_nofollow_SOURCES = utimens_nofollow.c fcntl_locker_SOURCES = fcntl_locker.c +odirect_read_SOURCES = odirect_read.c +odirect_write_SOURCES = odirect_write.c test_dir_rewind_SOURCES = test_dir_rewind.c TESTS = test_bindfs.rb diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/bindfs-1.13.9/tests/internals/test_internals_valgrind.sh new/bindfs-1.14.1/tests/internals/test_internals_valgrind.sh --- old/bindfs-1.13.9/tests/internals/test_internals_valgrind.sh 2017-11-30 11:30:07.000000000 +0100 +++ new/bindfs-1.14.1/tests/internals/test_internals_valgrind.sh 2019-06-26 10:47:09.000000000 +0200 @@ -1,5 +1,11 @@ -#!/bin/sh +#!/bin/sh -eu if [ ! -x ./test_internals ]; then cd `dirname "$0"` fi -valgrind --error-exitcode=100 ./test_internals + +if [ -n "`which valgrind`" ]; then + valgrind --error-exitcode=100 ./test_internals +else + echo "Warning: valgrind not found. Running without." + ./test_internals +fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/bindfs-1.13.9/tests/internals/test_rate_limiter_valgrind.sh new/bindfs-1.14.1/tests/internals/test_rate_limiter_valgrind.sh --- old/bindfs-1.13.9/tests/internals/test_rate_limiter_valgrind.sh 2017-11-30 11:30:07.000000000 +0100 +++ new/bindfs-1.14.1/tests/internals/test_rate_limiter_valgrind.sh 2019-06-26 10:47:09.000000000 +0200 @@ -1,5 +1,11 @@ -#!/bin/sh +#!/bin/sh -eu if [ ! -x ./test_rate_limiter ]; then cd `dirname "$0"` fi -valgrind --error-exitcode=100 ./test_rate_limiter + +if [ -n "`which valgrind`" ]; then + valgrind --error-exitcode=100 ./test_rate_limiter +else + echo "Warning: valgrind not found. Running without." + ./test_rate_limiter +fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/bindfs-1.13.9/tests/odirect_read.c new/bindfs-1.14.1/tests/odirect_read.c --- old/bindfs-1.13.9/tests/odirect_read.c 1970-01-01 01:00:00.000000000 +0100 +++ new/bindfs-1.14.1/tests/odirect_read.c 2019-06-26 10:47:09.000000000 +0200 @@ -0,0 +1,59 @@ +#ifdef __linux__ + +#include <stdio.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <unistd.h> + +#ifndef O_DIRECT +#define O_DIRECT 00040000 /* direct disk access hint */ +#endif + +int main(int argc, char** argv) { + if (argc != 2) { + fprintf(stderr, "Expected 1 argument: the file to read.\n"); + return 1; + } + + int fd = open(argv[1], O_RDONLY | O_DIRECT); + if (fd == -1) { + perror("failed to open file"); + return 1; + } + + const size_t buf_size = 4096; + unsigned char* buf = mmap(NULL, buf_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); + if (buf == MAP_FAILED) { + perror("mmap failed"); + return 1; + } + + while (1) { + ssize_t amt_read = read(fd, buf, buf_size); + if (amt_read == 0) { + break; + } + if (amt_read == -1) { + perror("failed to read file"); + return 1; + } + fwrite(buf, 1, amt_read, stdout); + fflush(stdout); + } + + return 0; +} + +#else // __linux__ + +#include <stdio.h> + +int main() { + fprintf(stderr, "Not supported on this platform.\n"); + return 1; +} + +#endif // __linux__ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/bindfs-1.13.9/tests/odirect_write.c new/bindfs-1.14.1/tests/odirect_write.c --- old/bindfs-1.13.9/tests/odirect_write.c 1970-01-01 01:00:00.000000000 +0100 +++ new/bindfs-1.14.1/tests/odirect_write.c 2019-06-26 10:47:09.000000000 +0200 @@ -0,0 +1,78 @@ +#ifdef __linux__ + +#include <stdio.h> +#include <string.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <unistd.h> + +#ifndef O_DIRECT +#define O_DIRECT 00040000 /* direct disk access hint */ +#endif + +int main(int argc, char** argv) { + if (argc != 2) { + fprintf(stderr, "Expected 1 argument: the file to read.\n"); + return 1; + } + + int fd = open(argv[1], O_WRONLY | O_CREAT | O_DIRECT, 0644); + if (fd == -1) { + perror("failed to open file"); + return 1; + } + + const size_t buf_size = 4096; + unsigned char* buf = mmap(NULL, buf_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); + if (buf == MAP_FAILED) { + perror("mmap failed"); + return 1; + } + + size_t total_size = 0; + while (1) { + if (feof(stdin)) { + break; + } + + memset(buf, 0, buf_size); + size_t amt_read = fread(buf, 1, buf_size, stdin); + if (ferror(stdin)) { + perror("failed to read stdin"); + return 1; + } + if (amt_read == 0) { + continue; + } + + total_size += amt_read; + + ssize_t res = write(fd, buf, buf_size); + if (res == -1) { + perror("failed to write"); + return 1; + } + if (res != buf_size) { + // Too lazy to write a loop here unless it turns out to be necessary. + fprintf(stderr, "Failed to write exactly %ld bytes", amt_read); + } + } + + munmap(buf, buf_size); + + return 0; +} + +#else // __linux__ + +#include <stdio.h> + +int main() { + fprintf(stderr, "Not supported on this platform.\n"); + return 1; +} + +#endif // __linux__ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/bindfs-1.13.9/tests/test_bindfs.rb new/bindfs-1.14.1/tests/test_bindfs.rb --- old/bindfs-1.13.9/tests/test_bindfs.rb 2017-11-30 11:30:07.000000000 +0100 +++ new/bindfs-1.14.1/tests/test_bindfs.rb 2019-06-26 10:47:09.000000000 +0200 @@ -452,6 +452,7 @@ symlink('file', 'link') end + sleep 1 # Not sure why this is needed, but something seems to overwrite the atime right after we set it, at least on Bionic. system("#{$tests_dir}/utimens_nofollow mnt/link 12 34 56 78") raise "Failed to run utimens_nofollow: #{$?.inspect}" unless $?.success? @@ -634,6 +635,22 @@ end end +testenv("--resolve-symlinks", :title => "resolving broken symlinks") do + Dir.chdir 'src' do + symlink('dir', 'dirlink') + symlink('dir/file', 'filelink') + end + + assert { File.lstat('mnt/dirlink').symlink? } + assert { File.lstat('mnt/filelink').symlink? } + + File.unlink('mnt/filelink') + assert { !File.exist?('mnt/filelink') } + + File.unlink('mnt/dirlink') + assert { !File.exist?('mnt/dirlink') } +end + # Issue #28 reproduction attempt. testenv("", :title => "many files in a directory") do mkdir('src/dir') @@ -761,6 +778,57 @@ assert { File.exist?("a\nb/f") } end +# Pull Request #73 +if `uname`.strip == 'Linux' && + `uname -r`.strip =~ /^[456789]/ && # 3.x kernels used by CentOS 7 and older don't support all `unshare` options despite the userspace binary supporting them + `which unshare` != '' && + `unshare --help`.include?("--map-root-user") && + `unshare --help`.include?("--user") + root_testenv("--gid-offset=10000", :title => "setgid and gid-offset") do + system("chmod g+s src") + system("unshare --map-root-user --user mkdir mnt/dir") + assert { File.stat("src/dir").gid == 0 } + assert { File.stat("mnt/dir").gid == 10000 } + end +end + +# Pull Request #74 +if `uname`.strip == 'Linux' + def odirect_data + ('abc' * 10000)[0...8192] + end + + testenv("", :title => "O_DIRECT reads with O_DIRECT ignored") do + File.write("src/f", odirect_data) + read_data = `#{$tests_dir}/odirect_read mnt/f` + assert { $?.success? } + assert { read_data == odirect_data } + end + + testenv("", :title => "O_DIRECT writes with O_DIRECT ignored") do + IO.popen("#{$tests_dir}/odirect_write mnt/f", "w") do |pipe| + pipe.write(odirect_data) + end + assert { $?.success? } + assert { File.read("src/f") == odirect_data } + end + + testenv("--forward-odirect=512", :title => "O_DIRECT reads with O_DIRECT forwarded") do + File.write("src/f", odirect_data) + read_data = `#{$tests_dir}/odirect_read mnt/f` + assert { $?.success? } + assert { read_data == odirect_data } + end + + testenv("--forward-odirect=512", :title => "O_DIRECT writes with O_DIRECT forwarded") do + IO.popen("#{$tests_dir}/odirect_write mnt/f", "w") do |pipe| + pipe.write(odirect_data) + end + assert { $?.success? } + assert { File.read("src/f") == odirect_data } + end +end + if `uname`.strip != 'FreeBSD' # -o dev is not supported on FreeBSD root_testenv("-odev") do system("mknod mnt/zero c 1 5") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/bindfs-1.13.9/vagrant/bionic64/Vagrantfile new/bindfs-1.14.1/vagrant/bionic64/Vagrantfile --- old/bindfs-1.13.9/vagrant/bionic64/Vagrantfile 1970-01-01 01:00:00.000000000 +0100 +++ new/bindfs-1.14.1/vagrant/bionic64/Vagrantfile 2019-06-26 10:47:09.000000000 +0200 @@ -0,0 +1,25 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +Vagrant.configure("2") do |config| + config.vm.box = "ubuntu/bionic64" + + config.vm.synced_folder ".", "/vagrant", disabled: true + config.vm.synced_folder "../../", "/bindfs", + type: "rsync", + rsync__auto: false, + rsync__exclude: ["vagrant"], + rsync__args: ["-av", "--delete-after"] + + config.vm.provider "virtualbox" do |v| + v.name = "bindfs-bionic64" + end + + config.vm.provision "shell", inline: <<-SHELL + apt-get update + apt-get install -y fuse libfuse-dev build-essential pkg-config ruby valgrind + apt-get clean + adduser vagrant fuse + echo user_allow_other > /etc/fuse.conf + SHELL +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/bindfs-1.13.9/vagrant/centos6/Vagrantfile new/bindfs-1.14.1/vagrant/centos6/Vagrantfile --- old/bindfs-1.13.9/vagrant/centos6/Vagrantfile 2017-11-30 11:30:07.000000000 +0100 +++ new/bindfs-1.14.1/vagrant/centos6/Vagrantfile 2019-06-26 10:47:09.000000000 +0200 @@ -15,8 +15,9 @@ v.name = "bindfs-centos6" end + # Don't install valgrind here since it appears to be broken (2019-04-28) config.vm.provision "shell", inline: <<-SHELL - yum install -y fuse fuse-devel gcc make pkg-config ruby valgrind + yum install -y fuse fuse-devel gcc make pkg-config ruby usermod -G fuse -a vagrant echo user_allow_other > /etc/fuse.conf SHELL diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/bindfs-1.13.9/vagrant/precise64/Vagrantfile new/bindfs-1.14.1/vagrant/precise64/Vagrantfile --- old/bindfs-1.13.9/vagrant/precise64/Vagrantfile 2017-11-30 11:30:07.000000000 +0100 +++ new/bindfs-1.14.1/vagrant/precise64/Vagrantfile 1970-01-01 01:00:00.000000000 +0100 @@ -1,25 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -Vagrant.configure("2") do |config| - config.vm.box = "ubuntu/precise64" - - config.vm.synced_folder ".", "/vagrant", disabled: true - config.vm.synced_folder "../../", "/bindfs", - type: "rsync", - rsync__auto: false, - rsync__exclude: ["vagrant"], - rsync__args: ["-av", "--delete-after"] - - config.vm.provider "virtualbox" do |v| - v.name = "bindfs-precise64" - end - - config.vm.provision "shell", inline: <<-SHELL - apt-get update - apt-get install -y fuse libfuse-dev build-essential pkg-config ruby1.9.3 valgrind - apt-get clean - adduser vagrant fuse - echo user_allow_other > /etc/fuse.conf - SHELL -end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/bindfs-1.13.9/vagrant/test.rb new/bindfs-1.14.1/vagrant/test.rb --- old/bindfs-1.13.9/vagrant/test.rb 2017-11-30 11:30:07.000000000 +0100 +++ new/bindfs-1.14.1/vagrant/test.rb 2019-06-26 10:47:09.000000000 +0200 @@ -82,7 +82,7 @@ unless run_and_log.call "vagrant rsync" raise "vagrant rsync failed" end - unless run_and_log.call "vagrant ssh -c 'cd /bindfs && sudo rm -Rf tests/tmp_test_bindfs && ./configure && make clean && make && make check && sudo make check'" + unless run_and_log.call "vagrant ssh -c 'cd /bindfs && sudo rm -Rf tests/tmp_test_bindfs && ./configure && make distclean && ./configure && make && make check && sudo make check'" mutex.synchronize do errors << "VM #{dir} tests failed." end
