aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--ChangeLog10
-rw-r--r--configure.ac4
-rw-r--r--src/bindfs.c14
-rw-r--r--tests/Makefile.am3
-rwxr-xr-xtests/test_bindfs.rb15
-rw-r--r--tests/utimens_nofollow.c32
7 files changed, 69 insertions, 10 deletions
diff --git a/.gitignore b/.gitignore
index 3d7daaa..d579346 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,6 +34,7 @@ Makefile
src/bindfs
tests/readdir_inode
+tests/utimens_nofollow
tests/*.log
tests/internals/test_internals
tests/internals/*.log
diff --git a/ChangeLog b/ChangeLog
index 3abbacf..27e6d82 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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;
+}