aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorGravatar Bill Zissimooulos <billziss@navimatics.com>2018-05-12 18:51:44 -0700
committerGravatar Nikolaus Rath <Nikolaus@rath.org>2018-05-18 12:52:10 +0100
commitd105fafabbd01d39dd98d4e7d24e41da5cb2680e (patch)
treedfd561c3891d3a90856d6a7ec360ea922fe545f1 /test
parent88da32d665eb3372f590675a5642c52f11c3ca03 (diff)
rename: perform user mode dir loop check when not done in kernel
Linux performs the dir loop check (rename(a, a/b/c) or rename(a/b/c, a), etc.) in kernel. Unfortunately other systems do not perform this check (e.g. FreeBSD). This results in a deadlock in get_path2, because libfuse did not expect to handle such cases. We add a check_dir_loop function that performs the dir loop check in user mode and enable it on systems that need it.
Diffstat (limited to 'test')
-rw-r--r--test/test_syscalls.c216
1 files changed, 216 insertions, 0 deletions
diff --git a/test/test_syscalls.c b/test/test_syscalls.c
index 392a210..38a37a1 100644
--- a/test/test_syscalls.c
+++ b/test/test_syscalls.c
@@ -1282,6 +1282,221 @@ static int test_rename_dir(void)
return 0;
}
+static int test_rename_dir_loop(void)
+{
+#define PATH(p) (snprintf(path, sizeof path, "%s/%s", testdir, p), path)
+#define PATH2(p) (snprintf(path2, sizeof path2, "%s/%s", testdir, p), path2)
+
+ char path[1024], path2[1024];
+ int err = 0;
+ int res;
+
+ start_test("rename dir loop");
+
+ res = create_dir(testdir, testdir_files);
+ if (res == -1)
+ return -1;
+
+ res = mkdir(PATH("a"), 0755);
+ if (res == -1) {
+ PERROR("mkdir");
+ goto fail;
+ }
+
+ res = rename(PATH("a"), PATH2("a"));
+ if (res == -1) {
+ PERROR("rename");
+ goto fail;
+ }
+
+ errno = 0;
+ res = rename(PATH("a"), PATH2("a/b"));
+ if (res == 0 || errno != EINVAL) {
+ PERROR("rename");
+ goto fail;
+ }
+
+ res = mkdir(PATH("a/b"), 0755);
+ if (res == -1) {
+ PERROR("mkdir");
+ goto fail;
+ }
+
+ res = mkdir(PATH("a/b/c"), 0755);
+ if (res == -1) {
+ PERROR("mkdir");
+ goto fail;
+ }
+
+ errno = 0;
+ res = rename(PATH("a"), PATH2("a/b/c"));
+ if (res == 0 || errno != EINVAL) {
+ PERROR("rename");
+ goto fail;
+ }
+
+ errno = 0;
+ res = rename(PATH("a"), PATH2("a/b/c/a"));
+ if (res == 0 || errno != EINVAL) {
+ PERROR("rename");
+ goto fail;
+ }
+
+ errno = 0;
+ res = rename(PATH("a/b/c"), PATH2("a"));
+ if (res == 0 || errno != ENOTEMPTY) {
+ PERROR("rename");
+ goto fail;
+ }
+
+ res = open(PATH("a/foo"), O_CREAT, 0644);
+ if (res == -1) {
+ PERROR("open");
+ goto fail;
+ }
+ close(res);
+
+ res = rename(PATH("a/foo"), PATH2("a/bar"));
+ if (res == -1) {
+ PERROR("rename");
+ goto fail;
+ }
+
+ res = rename(PATH("a/bar"), PATH2("a/foo"));
+ if (res == -1) {
+ PERROR("rename");
+ goto fail;
+ }
+
+ res = rename(PATH("a/foo"), PATH2("a/b/bar"));
+ if (res == -1) {
+ PERROR("rename");
+ goto fail;
+ }
+
+ res = rename(PATH("a/b/bar"), PATH2("a/foo"));
+ if (res == -1) {
+ PERROR("rename");
+ goto fail;
+ }
+
+ res = rename(PATH("a/foo"), PATH2("a/b/c/bar"));
+ if (res == -1) {
+ PERROR("rename");
+ goto fail;
+ }
+
+ res = rename(PATH("a/b/c/bar"), PATH2("a/foo"));
+ if (res == -1) {
+ PERROR("rename");
+ goto fail;
+ }
+
+ res = open(PATH("a/bar"), O_CREAT, 0644);
+ if (res == -1) {
+ PERROR("open");
+ goto fail;
+ }
+ close(res);
+
+ res = rename(PATH("a/foo"), PATH2("a/bar"));
+ if (res == -1) {
+ PERROR("rename");
+ goto fail;
+ }
+
+ unlink(PATH("a/bar"));
+
+ res = rename(PATH("a/b"), PATH2("a/d"));
+ if (res == -1) {
+ PERROR("rename");
+ goto fail;
+ }
+
+ res = rename(PATH("a/d"), PATH2("a/b"));
+ if (res == -1) {
+ PERROR("rename");
+ goto fail;
+ }
+
+ res = mkdir(PATH("a/d"), 0755);
+ if (res == -1) {
+ PERROR("mkdir");
+ goto fail;
+ }
+
+ res = rename(PATH("a/b"), PATH2("a/d"));
+ if (res == -1) {
+ PERROR("rename");
+ goto fail;
+ }
+
+ res = rename(PATH("a/d"), PATH2("a/b"));
+ if (res == -1) {
+ PERROR("rename");
+ goto fail;
+ }
+
+ res = mkdir(PATH("a/d"), 0755);
+ if (res == -1) {
+ PERROR("mkdir");
+ goto fail;
+ }
+
+ res = mkdir(PATH("a/d/e"), 0755);
+ if (res == -1) {
+ PERROR("mkdir");
+ goto fail;
+ }
+
+ errno = 0;
+ res = rename(PATH("a/b"), PATH2("a/d"));
+ if (res == 0 || errno != ENOTEMPTY) {
+ PERROR("rename");
+ goto fail;
+ }
+
+ rmdir(PATH("a/d/e"));
+ rmdir(PATH("a/d"));
+
+ rmdir(PATH("a/b/c"));
+ rmdir(PATH("a/b"));
+ rmdir(PATH("a"));
+
+ err += cleanup_dir(testdir, testdir_files, 0);
+ res = rmdir(testdir);
+ if (res == -1) {
+ PERROR("rmdir");
+ goto fail;
+ }
+ res = check_nonexist(testdir);
+ if (res == -1)
+ return -1;
+ if (err)
+ return -1;
+
+ success();
+ return 0;
+
+fail:
+ unlink(PATH("a/bar"));
+
+ rmdir(PATH("a/d/e"));
+ rmdir(PATH("a/d"));
+
+ rmdir(PATH("a/b/c"));
+ rmdir(PATH("a/b"));
+ rmdir(PATH("a"));
+
+ cleanup_dir(testdir, testdir_files, 1);
+ rmdir(testdir);
+
+ return -1;
+
+#undef PATH2
+#undef PATH
+}
+
#ifndef __FreeBSD__
static int test_mkfifo(void)
{
@@ -1461,6 +1676,7 @@ int main(int argc, char *argv[])
err += test_mkdir();
err += test_rename_file();
err += test_rename_dir();
+ err += test_rename_dir_loop();
err += test_utime();
err += test_truncate(0);
err += test_truncate(testdatalen / 2);