diff options
author | Martin Pärtel <martin.partel@gmail.com> | 2013-09-23 23:57:51 +0300 |
---|---|---|
committer | Martin Pärtel <martin.partel@gmail.com> | 2013-09-23 23:57:51 +0300 |
commit | 189a8d53fa68f0a630ce671fa2ddcccc15588441 (patch) | |
tree | f6ce7d0ee23a14d08df8d3a8f18030b69f00bebd | |
parent | e17adbb805c7363b8e6a18fe49d4269a94d4c8b8 (diff) | |
download | bindfs-189a8d53fa68f0a630ce671fa2ddcccc15588441.tar.gz |
Implement fuse_utimens instead of fuse_utime.
Fixes utime'ing symlinks.
Seems to also fix an attribute caching problem.
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | src/bindfs.c | 14 | ||||
-rw-r--r-- | tests/Makefile.am | 3 | ||||
-rwxr-xr-x | tests/test_bindfs.rb | 15 | ||||
-rw-r--r-- | tests/utimens_nofollow.c | 32 |
7 files changed, 69 insertions, 10 deletions
@@ -34,6 +34,7 @@ Makefile src/bindfs tests/readdir_inode +tests/utimens_nofollow tests/*.log tests/internals/test_internals tests/internals/*.log @@ -1,3 +1,13 @@ +2013-09-23 Martin Pärtel <martin dot partel at gmail dot com> + + * Use `utimensat` to support settings mtime/atime on symlinks, + and with nanosecond precision. + * Any "utime" errors when untarring with a modern version of `tar` + should now be fixed. + * Time modifications seem to no longer get caught in FUSE's + attribute cache. + * Now using FUSE API version 26. + 2013-07-22 Martin Pärtel <martin dot partel at gmail dot com> * Added --chmod-filter, contributed by Anton Ageev. Thanks! diff --git a/configure.ac b/configure.ac index 95164ed..9de90b2 100644 --- a/configure.ac +++ b/configure.ac @@ -31,7 +31,7 @@ if test x"$with_core_foundation" == "xyes" ; then LDFLAGS="${LDFLAGS} -framework CoreFoundation" fi -my_CPPFLAGS="-D_REENTRANT -D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=25" +my_CPPFLAGS="-D_REENTRANT -D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=26" my_CFLAGS="$my_CFLAGS -Wall" my_LDFLAGS="-pthread" AC_SUBST([my_CPPFLAGS]) @@ -43,7 +43,7 @@ AC_CHECK_FUNCS([setxattr getxattr listxattr removexattr]) AC_CHECK_FUNCS([lsetxattr lgetxattr llistxattr lremovexattr]) # Check for fuse -PKG_CHECK_MODULES([fuse], [fuse >= 2.5.3]) +PKG_CHECK_MODULES([fuse], [fuse >= 2.6.0]) AC_CONFIG_FILES([Makefile \ src/Makefile \ diff --git a/src/bindfs.c b/src/bindfs.c index cfd67a0..9348b2c 100644 --- a/src/bindfs.c +++ b/src/bindfs.c @@ -31,8 +31,8 @@ #include <config.h> -/* For pread/pwrite and readdir_r */ -#define _XOPEN_SOURCE 500 +/* For >= 500 for pread/pwrite and readdir_r; >= 700 for utimensat */ +#define _XOPEN_SOURCE 700 #include <stdlib.h> #include <stddef.h> @@ -177,7 +177,7 @@ static int bindfs_chown(const char *path, uid_t uid, gid_t gid); static int bindfs_truncate(const char *path, off_t size); static int bindfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi); -static int bindfs_utime(const char *path, struct utimbuf *buf); +static int bindfs_utimens(const char *path, const struct timespec tv[2]); static int bindfs_create(const char *path, mode_t mode, struct fuse_file_info *fi); static int bindfs_open(const char *path, struct fuse_file_info *fi); static int bindfs_read(const char *path, char *buf, size_t size, off_t offset, @@ -690,13 +690,13 @@ static int bindfs_ftruncate(const char *path, off_t size, return 0; } -static int bindfs_utime(const char *path, struct utimbuf *buf) +static int bindfs_utimens(const char *path, const struct timespec tv[2]) { int res; path = process_path(path); - res = utime(path, buf); + res = utimensat(settings.mntsrc_fd, path, tv, AT_SYMLINK_NOFOLLOW); if (res == -1) return -errno; @@ -906,7 +906,7 @@ static struct fuse_operations bindfs_oper = { .chown = bindfs_chown, .truncate = bindfs_truncate, .ftruncate = bindfs_ftruncate, - .utime = bindfs_utime, + .utimens = bindfs_utimens, .create = bindfs_create, .open = bindfs_open, .read = bindfs_read, @@ -1597,7 +1597,7 @@ int main(int argc, char *argv[]) /* fuse_main will daemonize by fork()'ing. The signal handler will persist. */ setup_signal_handling(); - fuse_main_return = fuse_main(args.argc, args.argv, &bindfs_oper); + fuse_main_return = fuse_main(args.argc, args.argv, &bindfs_oper, NULL); fuse_opt_free_args(&args); close(settings.mntsrc_fd); diff --git a/tests/Makefile.am b/tests/Makefile.am index 2e053dd..8fc80ea 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,6 +1,7 @@ -noinst_PROGRAMS = readdir_inode +noinst_PROGRAMS = readdir_inode utimens_nofollow readdir_inode_SOURCES = readdir_inode.c +utimens_nofollow_SOURCES = utimens_nofollow.c TESTS = test_bindfs.rb SUBDIRS = internals diff --git a/tests/test_bindfs.rb b/tests/test_bindfs.rb index f8a9d89..6e95020 100755 --- a/tests/test_bindfs.rb +++ b/tests/test_bindfs.rb @@ -371,6 +371,21 @@ root_testenv("", :title => "setgid directories") do assert { File.stat('mnt/dir/file').gid == $nogroup_gid } end +root_testenv("", :title => "utimens on symlinks") do + touch('mnt/file') + Dir.chdir "mnt" do + system('ln -sf file link') + end + + system("#{$tests_dir}/utimens_nofollow mnt/link 12 34 56 78") + raise "Failed to run utimens_nofollow: #{$?.inspect}" unless $?.success? + + assert { File.lstat('mnt/link').atime.to_i < 100 } + assert { File.lstat('mnt/link').mtime.to_i < 100 } + assert { File.lstat('mnt/file').atime.to_i > 100 } + assert { File.lstat('mnt/file').mtime.to_i > 100 } +end + # FIXME: this stuff around testenv is a hax, and testenv may also exit(), which defeats the 'ensure' below. # the test setup ought to be refactored. It might well use MiniTest or something. if Process.uid == 0 diff --git a/tests/utimens_nofollow.c b/tests/utimens_nofollow.c new file mode 100644 index 0000000..ced9b5f --- /dev/null +++ b/tests/utimens_nofollow.c @@ -0,0 +1,32 @@ + +#define _BSD_SOURCE /* For atoll */ + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +int main(int argc, char* argv[]) +{ + struct timespec times[2]; + + if (argc != 6) { + fprintf(stderr, "Usage: utimens_nofollow path atime atime_nsec mtime mtime_nsec\n"); + return 1; + } + + times[0].tv_sec = (time_t)atoll(argv[2]); + times[0].tv_nsec = atoll(argv[3]); + times[1].tv_sec = (time_t)atoll(argv[4]); + times[1].tv_nsec = atoll(argv[5]); + + if (utimensat(AT_FDCWD, argv[1], times, AT_SYMLINK_NOFOLLOW) == -1) { + perror("failed to utimensat the given path"); + return 2; + } + + return 0; +} |