aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile.am3
-rw-r--r--tests/fcntl_locker.c67
-rwxr-xr-xtests/test_bindfs.rb41
3 files changed, 110 insertions, 1 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am
index eca8563..66713e2 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,9 +1,10 @@
UNAME_S := $(shell uname -s)
-noinst_PROGRAMS = readdir_inode utimens_nofollow
+noinst_PROGRAMS = readdir_inode utimens_nofollow fcntl_locker
readdir_inode_SOURCES = readdir_inode.c
utimens_nofollow_SOURCES = utimens_nofollow.c
+fcntl_locker_SOURCES = fcntl_locker.c
TESTS = test_bindfs.rb
SUBDIRS = internals
diff --git a/tests/fcntl_locker.c b/tests/fcntl_locker.c
new file mode 100644
index 0000000..fa2e9dc
--- /dev/null
+++ b/tests/fcntl_locker.c
@@ -0,0 +1,67 @@
+// Takes two files and exits with 0 if fcntl-locking one fcntl-locks the other.
+// If the files don't fcntl-lock each other, returns 1.
+// If any other error occurs, returns 2.
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+int main(int argc, const char* argv[]) {
+ if (argc != 3) {
+ fprintf(stderr, "expecting exactly two arguments\n");
+ return 2;
+ }
+
+ int fd1 = -1;
+ int fd2 = -1;
+ int result = 2;
+
+ fd1 = open(argv[1], O_RDWR);
+ if (fd1 == -1) {
+ perror("failed to open the first file");
+ goto exit;
+ }
+ fd2 = open(argv[2], O_RDWR);
+ if (fd2 == -1) {
+ perror("failed to open the second file");
+ goto exit;
+ }
+
+ struct flock lock;
+ memset(&lock, 0, sizeof(lock));
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ if (fcntl(fd1, F_SETLK, &lock) == -1) {
+ perror("fcntl F_SETLK on the first file failed");
+ goto exit;
+ }
+
+ memset(&lock, 0, sizeof(lock));
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ if (fcntl(fd2, F_SETLK, &lock) == -1) {
+ if (errno == EACCES || errno == EAGAIN) {
+ result = 0;
+ goto exit;
+ } else {
+ perror("fcntl F_SETLK on the second file failed");
+ goto exit;
+ }
+ } else {
+ result = 1;
+ goto exit;
+ }
+
+exit:
+ close(fd1);
+ close(fd2);
+ return result;
+}
diff --git a/tests/test_bindfs.rb b/tests/test_bindfs.rb
index 04c853d..c0ae5dd 100755
--- a/tests/test_bindfs.rb
+++ b/tests/test_bindfs.rb
@@ -616,6 +616,47 @@ testenv("", :title => "many files in a directory") do
assert { Dir.entries('mnt/dir').sort == expected_entries.sort }
end
+testenv("--enable-lock-forwarding --multithreaded", :title => "lock forwarding") do
+ File.write('src/file', 'some contents for fcntl lockng')
+ # (this test passes with an empty file as well, but this way is clearer)
+
+ # flock
+ File.open('mnt/file') do |f1|
+ File.open('src/file') do |f2|
+ assert { f1.flock(File::LOCK_EX | File::LOCK_NB) }
+ assert { !f2.flock(File::LOCK_EX | File::LOCK_NB) }
+ assert { f1.flock(File::LOCK_UN) }
+
+ assert { f2.flock(File::LOCK_EX | File::LOCK_NB) }
+ assert { !f1.flock(File::LOCK_EX | File::LOCK_NB) }
+ end
+ assert { f1.flock(File::LOCK_EX | File::LOCK_NB) }
+ end
+
+ # fcntl locking
+ system("#{$tests_dir}/fcntl_locker src/file mnt/file")
+ raise "fcntl lock sharing test failed" unless $?.success?
+end
+
+testenv("--disable-lock-forwarding", :title => "no lock forwarding") do
+ File.write('src/file', 'some contents for fcntl lockng')
+
+ # flock
+ File.open('mnt/file') do |f1|
+ File.open('src/file') do |f2|
+ assert { f1.flock(File::LOCK_EX | File::LOCK_NB) }
+ assert { f2.flock(File::LOCK_EX | File::LOCK_NB) }
+ end
+ File.open('mnt/file') do |f2|
+ assert { !f2.flock(File::LOCK_EX | File::LOCK_NB) }
+ end
+ end
+
+ # fcntl locking
+ system("#{$tests_dir}/fcntl_locker src/file mnt/file")
+ raise "fcntl lock sharing test failed" unless $?.exitstatus == 1
+end
+
# Issue #37
root_testenv("--enable-ioctl", :title => "append-only ioctl") do
touch('mnt/file')