X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;ds=inline;f=tests%2Ftest-rename.h;h=2bc610fc8e183d74cb99cd5bae5a6640be698360;hb=a6ae1bb228f3bcfac76095600d05969d214ed65f;hp=63ec8ca97470763f2e6d4f9b7355054eb4735e5c;hpb=b7be78fd0c455acefbdf32618c2f6488915c1a33;p=gnulib.git diff --git a/tests/test-rename.h b/tests/test-rename.h index 63ec8ca97..2bc610fc8 100644 --- a/tests/test-rename.h +++ b/tests/test-rename.h @@ -1,9 +1,9 @@ /* Test of rename() function. - Copyright (C) 2009 Free Software Foundation, Inc. + Copyright (C) 2009-2014 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -20,6 +20,54 @@ appropriate headers are already included. If PRINT, warn before skipping symlink tests with status 77. */ +/* Tests whether a file, given by a file name without slashes, exists in + the current directory, by scanning the directory entries. */ +static bool +dentry_exists (const char *filename) +{ + bool exists = false; + DIR *dir = opendir ("."); + + ASSERT (dir != NULL); + for (;;) + { + struct dirent *d = readdir (dir); + if (d == NULL) + break; + if (strcmp (d->d_name, filename) == 0) + { + exists = true; + break; + } + } + ASSERT (closedir (dir) == 0); + return exists; +} + +/* Asserts that a specific file, given by a file name without slashes, does + not exist in the current directory. */ +static void +assert_nonexistent (const char *filename) +{ + struct stat st; + + /* The usual way to test the presence of a file is via stat() or lstat(). */ + errno = 0; + if (stat (filename, &st) == -1) + ASSERT (errno == ENOENT); + else + { + /* But after renaming a directory over an empty directory on an NFS- + mounted file system, on Linux 2.6.18, for a period of 30 seconds the + old directory name is "present" according to stat() but "nonexistent" + according to dentry_exists(). */ + ASSERT (!dentry_exists (filename)); + /* Remove the old directory name, so that subsequent mkdir calls + succeed. */ + (void) rmdir (filename); + } +} + static int test_rename (int (*func) (char const *, char const *), bool print) { @@ -31,168 +79,400 @@ test_rename (int (*func) (char const *, char const *), bool print) ASSERT (close (fd) == 0); ASSERT (mkdir (BASE "dir", 0700) == 0); + /* Files present here: + {BASE}file + {BASE}dir/ + */ + /* Obvious errors. */ - errno = 0; /* Missing source. */ - ASSERT (func (BASE "missing", BASE "missing") == -1); - ASSERT (errno == ENOENT); - errno = 0; - ASSERT (func (BASE "missing/", BASE "missing") == -1); - ASSERT (errno == ENOENT); - errno = 0; - ASSERT (func (BASE "missing", BASE "missing/") == -1); - ASSERT (errno == ENOENT); - errno = 0; /* Empty operand. */ - ASSERT (func ("", BASE "missing") == -1); - ASSERT (errno == ENOENT); - errno = 0; - ASSERT (func (BASE "file", "") == -1); - ASSERT (errno == ENOENT); - errno = 0; - ASSERT (func (BASE "", "") == -1); - ASSERT (errno == ENOENT); + { /* Missing source. */ + { + errno = 0; + ASSERT (func (BASE "missing", BASE "missing") == -1); + ASSERT (errno == ENOENT); + } + { + errno = 0; + ASSERT (func (BASE "missing/", BASE "missing") == -1); + ASSERT (errno == ENOENT); + } + { + errno = 0; + ASSERT (func (BASE "missing", BASE "missing/") == -1); + ASSERT (errno == ENOENT); + } + } + { /* Empty operand. */ + { + errno = 0; + ASSERT (func ("", BASE "missing") == -1); + ASSERT (errno == ENOENT); + } + { + errno = 0; + ASSERT (func (BASE "file", "") == -1); + ASSERT (errno == ENOENT); + } + { + errno = 0; + ASSERT (func (BASE "", "") == -1); + ASSERT (errno == ENOENT); + } + } /* Files. */ - errno = 0; /* Trailing slash. */ - ASSERT (func (BASE "file", BASE "file2/") == -1); - ASSERT (errno == ENOENT || errno == ENOTDIR); - errno = 0; - ASSERT (func (BASE "file/", BASE "file2") == -1); - ASSERT (errno == ENOTDIR); - errno = 0; - ASSERT (stat (BASE "file2", &st) == -1); - ASSERT (errno == ENOENT); - ASSERT (func (BASE "file", BASE "file2") == 0); /* Simple rename. */ - errno = 0; - ASSERT (stat (BASE "file", &st) == -1); - ASSERT (errno == ENOENT); - memset (&st, 0, sizeof st); - ASSERT (stat (BASE "file2", &st) == 0); - ASSERT (st.st_size == 2); - ASSERT (close (creat (BASE "file", 0600)) == 0); /* Overwrite. */ - errno = 0; - ASSERT (func (BASE "file2", BASE "file/") == -1); - ASSERT (errno == ENOTDIR); - ASSERT (func (BASE "file2", BASE "file") == 0); - memset (&st, 0, sizeof st); - ASSERT (stat (BASE "file", &st) == 0); - ASSERT (st.st_size == 2); - errno = 0; - ASSERT (stat (BASE "file2", &st) == -1); - ASSERT (errno == ENOENT); + + { /* Trailing slash. */ + { + errno = 0; + ASSERT (func (BASE "file", BASE "file2/") == -1); + ASSERT (errno == ENOENT || errno == ENOTDIR); + } + { + errno = 0; + ASSERT (func (BASE "file/", BASE "file2") == -1); + ASSERT (errno == ENOTDIR); + } + { + errno = 0; + ASSERT (stat (BASE "file2", &st) == -1); + ASSERT (errno == ENOENT); + } + } + { /* Simple rename. */ + ASSERT (func (BASE "file", BASE "file2") == 0); + errno = 0; + ASSERT (stat (BASE "file", &st) == -1); + ASSERT (errno == ENOENT); + memset (&st, 0, sizeof st); + ASSERT (stat (BASE "file2", &st) == 0); + ASSERT (st.st_size == 2); + } + /* Files present here: + {BASE}file2 + {BASE}dir/ + */ + { /* Overwrite. */ + ASSERT (close (creat (BASE "file", 0600)) == 0); + errno = 0; + ASSERT (func (BASE "file2", BASE "file/") == -1); + ASSERT (errno == ENOTDIR); + ASSERT (func (BASE "file2", BASE "file") == 0); + memset (&st, 0, sizeof st); + ASSERT (stat (BASE "file", &st) == 0); + ASSERT (st.st_size == 2); + errno = 0; + ASSERT (stat (BASE "file2", &st) == -1); + ASSERT (errno == ENOENT); + } + /* Files present here: + {BASE}file + {BASE}dir/ + */ /* Directories. */ - ASSERT (func (BASE "dir", BASE "dir2/") == 0); /* Simple rename. */ - errno = 0; - ASSERT (stat (BASE "dir", &st) == -1); - ASSERT (errno == ENOENT); - ASSERT (stat (BASE "dir2", &st) == 0); - ASSERT (func (BASE "dir2/", BASE "dir") == 0); - ASSERT (stat (BASE "dir", &st) == 0); - errno = 0; - ASSERT (stat (BASE "dir2", &st) == -1); - ASSERT (errno == ENOENT); - ASSERT (func (BASE "dir", BASE "dir2") == 0); - errno = 0; - ASSERT (stat (BASE "dir", &st) == -1); - ASSERT (errno == ENOENT); - ASSERT (stat (BASE "dir2", &st) == 0); - ASSERT (mkdir (BASE "dir", 0700) == 0); /* Empty onto empty. */ - ASSERT (func (BASE "dir2", BASE "dir") == 0); - ASSERT (mkdir (BASE "dir2", 0700) == 0); - ASSERT (func (BASE "dir2", BASE "dir/") == 0); - ASSERT (mkdir (BASE "dir2", 0700) == 0); - ASSERT (func (BASE "dir2/", BASE "dir") == 0); - ASSERT (mkdir (BASE "dir2", 0700) == 0); - ASSERT (close (creat (BASE "dir/file", 0600)) == 0); /* Empty onto full. */ - errno = 0; - ASSERT (func (BASE "dir2", BASE "dir") == -1); - ASSERT (errno == EEXIST || errno == ENOTEMPTY); - errno = 0; - ASSERT (func (BASE "dir2/", BASE "dir") == -1); - ASSERT (errno == EEXIST || errno == ENOTEMPTY); - errno = 0; - ASSERT (func (BASE "dir2", BASE "dir/") == -1); - ASSERT (errno == EEXIST || errno == ENOTEMPTY); - ASSERT (func (BASE "dir", BASE "dir2") == 0); /* Full onto empty. */ - errno = 0; - ASSERT (stat (BASE "dir", &st) == -1); - ASSERT (errno == ENOENT); - ASSERT (stat (BASE "dir2/file", &st) == 0); - ASSERT (mkdir (BASE "dir", 0700) == 0); - ASSERT (func (BASE "dir2/", BASE "dir") == 0); - ASSERT (stat (BASE "dir/file", &st) == 0); - errno = 0; - ASSERT (stat (BASE "dir2", &st) == -1); - ASSERT (errno == ENOENT); - ASSERT (mkdir (BASE "dir2", 0700) == 0); - ASSERT (func (BASE "dir", BASE "dir2/") == 0); - errno = 0; - ASSERT (stat (BASE "dir", &st) == -1); - ASSERT (errno == ENOENT); - ASSERT (stat (BASE "dir2/file", &st) == 0); - ASSERT (unlink (BASE "dir2/file") == 0); - errno = 0; /* Reject trailing dot. */ - ASSERT (func (BASE "dir2", BASE "dir/.") == -1); - ASSERT (errno == EINVAL || errno == ENOENT); - ASSERT (mkdir (BASE "dir", 0700) == 0); - errno = 0; - ASSERT (func (BASE "dir2", BASE "dir/.") == -1); - ASSERT (errno == EINVAL || errno == EBUSY || errno == EISDIR - || errno == ENOTEMPTY); - errno = 0; - ASSERT (func (BASE "dir2/.", BASE "dir") == -1); - ASSERT (errno == EINVAL || errno == EBUSY); - ASSERT (rmdir (BASE "dir") == 0); - errno = 0; - ASSERT (func (BASE "dir2", BASE "dir/.//") == -1); - ASSERT (errno == EINVAL || errno == ENOENT); - ASSERT (mkdir (BASE "dir", 0700) == 0); - errno = 0; - ASSERT (func (BASE "dir2", BASE "dir/.//") == -1); - ASSERT (errno == EINVAL || errno == EBUSY || errno == EISDIR - || errno == ENOTEMPTY); - errno = 0; - ASSERT (func (BASE "dir2/.//", BASE "dir") == -1); - ASSERT (errno == EINVAL || errno == EBUSY); - ASSERT (rmdir (BASE "dir2") == 0); - errno = 0; /* Move into subdir. */ - ASSERT (func (BASE "dir", BASE "dir/sub") == -1); - ASSERT (errno == EINVAL || errno == EACCES); - errno = 0; - ASSERT (stat (BASE "dir/sub", &st) == -1); - ASSERT (errno == ENOENT); - ASSERT (mkdir (BASE "dir/sub", 0700) == 0); - errno = 0; - ASSERT (func (BASE "dir", BASE "dir/sub") == -1); - ASSERT (errno == EINVAL); - ASSERT (stat (BASE "dir/sub", &st) == 0); - ASSERT (rmdir (BASE "dir/sub") == 0); + + { /* Simple rename. */ + { + ASSERT (func (BASE "dir", BASE "dir2/") == 0); + errno = 0; + ASSERT (stat (BASE "dir", &st) == -1); + ASSERT (errno == ENOENT); + ASSERT (stat (BASE "dir2", &st) == 0); + } + /* Files present here: + {BASE}file + {BASE}dir2/ + */ + { + ASSERT (func (BASE "dir2/", BASE "dir") == 0); + ASSERT (stat (BASE "dir", &st) == 0); + errno = 0; + ASSERT (stat (BASE "dir2", &st) == -1); + ASSERT (errno == ENOENT); + } + /* Files present here: + {BASE}file + {BASE}dir/ + */ + { + ASSERT (func (BASE "dir", BASE "dir2") == 0); + errno = 0; + ASSERT (stat (BASE "dir", &st) == -1); + ASSERT (errno == ENOENT); + ASSERT (stat (BASE "dir2", &st) == 0); + } + /* Files present here: + {BASE}file + {BASE}dir2/ + */ + { /* Empty onto empty. */ + ASSERT (mkdir (BASE "dir", 0700) == 0); + /* Files present here: + {BASE}file + {BASE}dir/ + {BASE}dir2/ + */ + ASSERT (func (BASE "dir2", BASE "dir") == 0); + /* Files present here: + {BASE}file + {BASE}dir/ + */ + ASSERT (mkdir (BASE "dir2", 0700) == 0); + /* Files present here: + {BASE}file + {BASE}dir/ + {BASE}dir2/ + */ + ASSERT (func (BASE "dir2", BASE "dir/") == 0); + /* Files present here: + {BASE}file + {BASE}dir/ + */ + ASSERT (mkdir (BASE "dir2", 0700) == 0); + /* Files present here: + {BASE}file + {BASE}dir/ + {BASE}dir2/ + */ + ASSERT (func (BASE "dir2/", BASE "dir") == 0); + /* Files present here: + {BASE}file + {BASE}dir/ + */ + ASSERT (mkdir (BASE "dir2", 0700) == 0); + } + /* Files present here: + {BASE}file + {BASE}dir/ + {BASE}dir2/ + */ + { /* Empty onto full. */ + ASSERT (close (creat (BASE "dir/file", 0600)) == 0); + /* Files present here: + {BASE}file + {BASE}dir/ + {BASE}dir/file + {BASE}dir2/ + */ + { + errno = 0; + ASSERT (func (BASE "dir2", BASE "dir") == -1); + ASSERT (errno == EEXIST || errno == ENOTEMPTY); + } + { + errno = 0; + ASSERT (func (BASE "dir2/", BASE "dir") == -1); + ASSERT (errno == EEXIST || errno == ENOTEMPTY); + } + { + errno = 0; + ASSERT (func (BASE "dir2", BASE "dir/") == -1); + ASSERT (errno == EEXIST || errno == ENOTEMPTY); + } + } + { /* Full onto empty. */ + ASSERT (func (BASE "dir", BASE "dir2") == 0); + assert_nonexistent (BASE "dir"); + ASSERT (stat (BASE "dir2/file", &st) == 0); + /* Files present here: + {BASE}file + {BASE}dir2/ + {BASE}dir2/file + */ + ASSERT (mkdir (BASE "dir", 0700) == 0); + /* Files present here: + {BASE}file + {BASE}dir/ + {BASE}dir2/ + {BASE}dir2/file + */ + { + ASSERT (func (BASE "dir2/", BASE "dir") == 0); + ASSERT (stat (BASE "dir/file", &st) == 0); + errno = 0; + ASSERT (stat (BASE "dir2", &st) == -1); + ASSERT (errno == ENOENT); + } + /* Files present here: + {BASE}file + {BASE}dir/ + {BASE}dir/file + */ + ASSERT (mkdir (BASE "dir2", 0700) == 0); + /* Files present here: + {BASE}file + {BASE}dir/ + {BASE}dir/file + {BASE}dir2/ + */ + { + ASSERT (func (BASE "dir", BASE "dir2/") == 0); + assert_nonexistent (BASE "dir"); + ASSERT (stat (BASE "dir2/file", &st) == 0); + } + /* Files present here: + {BASE}file + {BASE}dir2/ + {BASE}dir2/file + */ + ASSERT (unlink (BASE "dir2/file") == 0); + } + /* Files present here: + {BASE}file + {BASE}dir2/ + */ + { /* Reject trailing dot. */ + { + errno = 0; + ASSERT (func (BASE "dir2", BASE "dir/.") == -1); + ASSERT (errno == EINVAL || errno == ENOENT); + } + ASSERT (mkdir (BASE "dir", 0700) == 0); + /* Files present here: + {BASE}file + {BASE}dir/ + {BASE}dir2/ + */ + { + errno = 0; + ASSERT (func (BASE "dir2", BASE "dir/.") == -1); + ASSERT (errno == EINVAL || errno == EBUSY || errno == EISDIR + || errno == ENOTEMPTY || errno == EEXIST); + } + { + errno = 0; + ASSERT (func (BASE "dir2/.", BASE "dir") == -1); + ASSERT (errno == EINVAL || errno == EBUSY || errno == EEXIST); + } + ASSERT (rmdir (BASE "dir") == 0); + /* Files present here: + {BASE}file + {BASE}dir2/ + */ + { + errno = 0; + ASSERT (func (BASE "dir2", BASE "dir/.//") == -1); + ASSERT (errno == EINVAL || errno == ENOENT); + } + ASSERT (mkdir (BASE "dir", 0700) == 0); + /* Files present here: + {BASE}file + {BASE}dir/ + {BASE}dir2/ + */ + { + errno = 0; + ASSERT (func (BASE "dir2", BASE "dir/.//") == -1); + ASSERT (errno == EINVAL || errno == EBUSY || errno == EISDIR + || errno == ENOTEMPTY || errno == EEXIST); + } + { + errno = 0; + ASSERT (func (BASE "dir2/.//", BASE "dir") == -1); + ASSERT (errno == EINVAL || errno == EBUSY || errno == EEXIST); + } + ASSERT (rmdir (BASE "dir2") == 0); + /* Files present here: + {BASE}file + {BASE}dir/ + */ + } + { /* Move into subdir. */ + { + errno = 0; + ASSERT (func (BASE "dir", BASE "dir/sub") == -1); + ASSERT (errno == EINVAL || errno == EACCES); + } + { + errno = 0; + ASSERT (stat (BASE "dir/sub", &st) == -1); + ASSERT (errno == ENOENT); + } + ASSERT (mkdir (BASE "dir/sub", 0700) == 0); + /* Files present here: + {BASE}file + {BASE}dir/ + {BASE}dir/sub/ + */ + { + errno = 0; + ASSERT (func (BASE "dir", BASE "dir/sub") == -1); + ASSERT (errno == EINVAL); + ASSERT (stat (BASE "dir/sub", &st) == 0); + } + ASSERT (rmdir (BASE "dir/sub") == 0); + } + } + /* Files present here: + {BASE}file + {BASE}dir/ + */ /* Mixing file and directory. */ - errno = 0; /* File onto dir. */ - ASSERT (func (BASE "file", BASE "dir") == -1); - ASSERT (errno == EISDIR || errno == ENOTDIR); - errno = 0; - ASSERT (func (BASE "file", BASE "dir/") == -1); - ASSERT (errno == EISDIR || errno == ENOTDIR); - errno = 0; /* Dir onto file. */ - ASSERT (func (BASE "dir", BASE "file") == -1); - ASSERT (errno == ENOTDIR); - errno = 0; - ASSERT (func (BASE "dir/", BASE "file") == -1); - ASSERT (errno == ENOTDIR); + + { + { /* File onto dir. */ + { + errno = 0; + ASSERT (func (BASE "file", BASE "dir") == -1); + ASSERT (errno == EISDIR || errno == ENOTDIR); + } + { + errno = 0; + ASSERT (func (BASE "file", BASE "dir/") == -1); + ASSERT (errno == EISDIR || errno == ENOTDIR); + } + } + { /* Dir onto file. */ + { + errno = 0; + ASSERT (func (BASE "dir", BASE "file") == -1); + ASSERT (errno == ENOTDIR); + } + { + errno = 0; + ASSERT (func (BASE "dir/", BASE "file") == -1); + ASSERT (errno == ENOTDIR); + } + } + } /* Hard links. */ - ASSERT (func (BASE "file", BASE "file") == 0); /* File onto self. */ - memset (&st, 0, sizeof st); - ASSERT (stat (BASE "file", &st) == 0); - ASSERT (st.st_size == 2); - ASSERT (func (BASE "dir", BASE "dir") == 0); /* Empty dir onto self. */ - ASSERT (stat (BASE "dir", &st) == 0); + + { /* File onto self. */ + ASSERT (func (BASE "file", BASE "file") == 0); + memset (&st, 0, sizeof st); + ASSERT (stat (BASE "file", &st) == 0); + ASSERT (st.st_size == 2); + } + /* Files present here: + {BASE}file + {BASE}dir/ + */ + { /* Empty dir onto self. */ + ASSERT (func (BASE "dir", BASE "dir") == 0); + ASSERT (stat (BASE "dir", &st) == 0); + } + /* Files present here: + {BASE}file + {BASE}dir/ + */ ASSERT (close (creat (BASE "dir/file", 0600)) == 0); - ASSERT (func (BASE "dir", BASE "dir") == 0); /* Full dir onto self. */ + /* Files present here: + {BASE}file + {BASE}dir/ + {BASE}dir/file + */ + { /* Full dir onto self. */ + ASSERT (func (BASE "dir", BASE "dir") == 0); + } ASSERT (unlink (BASE "dir/file") == 0); + /* Files present here: + {BASE}file + {BASE}dir/ + */ { /* Not all file systems support link. Mingw doesn't have reliable st_nlink on hard links, but our implementation does @@ -234,16 +514,33 @@ test_rename (int (*func) (char const *, char const *), bool print) } ASSERT (ret == 0); } - ASSERT (func (BASE "file", BASE "file2") == 0); /* File onto hard link. */ - memset (&st, 0, sizeof st); - ASSERT (stat (BASE "file", &st) == 0); - ASSERT (st.st_size == 2); - memset (&st, 0, sizeof st); - ASSERT (stat (BASE "file2", &st) == 0); - ASSERT (st.st_size == 2); + /* Files present here: + {BASE}file + {BASE}file2 (hard link to file) + {BASE}dir/ + */ + { /* File onto hard link. */ + ASSERT (func (BASE "file", BASE "file2") == 0); + memset (&st, 0, sizeof st); + ASSERT (stat (BASE "file", &st) == 0); + ASSERT (st.st_size == 2); + memset (&st, 0, sizeof st); + ASSERT (stat (BASE "file2", &st) == 0); + ASSERT (st.st_size == 2); + } + /* Files present here: + {BASE}file + {BASE}file2 + {BASE}dir/ + */ ASSERT (unlink (BASE "file2") == 0); + /* Files present here: + {BASE}file + {BASE}dir/ + */ /* Symlinks. */ + if (symlink (BASE "file", BASE "link1")) { if (print) @@ -253,118 +550,298 @@ test_rename (int (*func) (char const *, char const *), bool print) ASSERT (rmdir (BASE "dir") == 0); return 77; } - ASSERT (func (BASE "link1", BASE "link2") == 0); /* Simple rename. */ - ASSERT (stat (BASE "file", &st) == 0); - errno = 0; - ASSERT (lstat (BASE "link1", &st) == -1); - ASSERT (errno == ENOENT); - memset (&st, 0, sizeof st); - ASSERT (lstat (BASE "link2", &st) == 0); - ASSERT (S_ISLNK (st.st_mode)); - ASSERT (symlink (BASE "nowhere", BASE "link1") == 0); /* Overwrite. */ - ASSERT (func (BASE "link2", BASE "link1") == 0); - memset (&st, 0, sizeof st); - ASSERT (stat (BASE "link1", &st) == 0); - ASSERT (st.st_size == 2); - errno = 0; - ASSERT (lstat (BASE "link2", &st) == -1); - ASSERT (errno == ENOENT); - ASSERT (symlink (BASE "link2", BASE "link2") == 0); /* Symlink loop. */ - ASSERT (func (BASE "link2", BASE "link2") == 0); - errno = 0; - ASSERT (func (BASE "link2/", BASE "link2") == -1); - ASSERT (errno == ELOOP || errno == ENOTDIR); - ASSERT (func (BASE "link2", BASE "link3") == 0); - ASSERT (unlink (BASE "link3") == 0); - ASSERT (symlink (BASE "nowhere", BASE "link2") == 0); /* Dangling link. */ - ASSERT (func (BASE "link2", BASE "link3") == 0); - errno = 0; - ASSERT (lstat (BASE "link2", &st) == -1); - ASSERT (errno == ENOENT); - memset (&st, 0, sizeof st); - ASSERT (lstat (BASE "link3", &st) == 0); - errno = 0; /* Trailing slash on dangling. */ - ASSERT (func (BASE "link3/", BASE "link2") == -1); - ASSERT (errno == ENOENT || errno == ENOTDIR); - errno = 0; - ASSERT (func (BASE "link3", BASE "link2/") == -1); - ASSERT (errno == ENOENT || errno == ENOTDIR); - errno = 0; - ASSERT (lstat (BASE "link2", &st) == -1); - ASSERT (errno == ENOENT); - memset (&st, 0, sizeof st); - ASSERT (lstat (BASE "link3", &st) == 0); - errno = 0; /* Trailing slash on link to file. */ - ASSERT (func (BASE "link1/", BASE "link2") == -1); - ASSERT (errno == ENOTDIR); - errno = 0; - ASSERT (func (BASE "link1", BASE "link3/") == -1); - ASSERT (errno == ENOENT || errno == ENOTDIR); + /* Files present here: + {BASE}file + {BASE}link1 -> {BASE}file + {BASE}dir/ + */ + { /* Simple rename. */ + ASSERT (func (BASE "link1", BASE "link2") == 0); + ASSERT (stat (BASE "file", &st) == 0); + errno = 0; + ASSERT (lstat (BASE "link1", &st) == -1); + ASSERT (errno == ENOENT); + memset (&st, 0, sizeof st); + ASSERT (lstat (BASE "link2", &st) == 0); + ASSERT (S_ISLNK (st.st_mode)); + } + /* Files present here: + {BASE}file + {BASE}link2 -> {BASE}file + {BASE}dir/ + */ + { /* Overwrite. */ + ASSERT (symlink (BASE "nowhere", BASE "link1") == 0); + /* Files present here: + {BASE}file + {BASE}link1 -> {BASE}nowhere + {BASE}link2 -> {BASE}file + {BASE}dir/ + */ + { + ASSERT (func (BASE "link2", BASE "link1") == 0); + memset (&st, 0, sizeof st); + ASSERT (stat (BASE "link1", &st) == 0); + ASSERT (st.st_size == 2); + errno = 0; + ASSERT (lstat (BASE "link2", &st) == -1); + ASSERT (errno == ENOENT); + } + } + /* Files present here: + {BASE}file + {BASE}link1 -> {BASE}file + {BASE}dir/ + */ + { /* Symlink loop. */ + ASSERT (symlink (BASE "link2", BASE "link2") == 0); + /* Files present here: + {BASE}file + {BASE}link1 -> {BASE}file + {BASE}link2 -> {BASE}link2 + {BASE}dir/ + */ + { + ASSERT (func (BASE "link2", BASE "link2") == 0); + } + { + errno = 0; + ASSERT (func (BASE "link2/", BASE "link2") == -1); + ASSERT (errno == ELOOP || errno == ENOTDIR); + } + ASSERT (func (BASE "link2", BASE "link3") == 0); + /* Files present here: + {BASE}file + {BASE}link1 -> {BASE}file + {BASE}link3 -> {BASE}link2 + {BASE}dir/ + */ + ASSERT (unlink (BASE "link3") == 0); + } + /* Files present here: + {BASE}file + {BASE}link1 -> {BASE}file + {BASE}dir/ + */ + { /* Dangling link. */ + ASSERT (symlink (BASE "nowhere", BASE "link2") == 0); + /* Files present here: + {BASE}file + {BASE}link1 -> {BASE}file + {BASE}link2 -> {BASE}nowhere + {BASE}dir/ + */ + { + ASSERT (func (BASE "link2", BASE "link3") == 0); + errno = 0; + ASSERT (lstat (BASE "link2", &st) == -1); + ASSERT (errno == ENOENT); + memset (&st, 0, sizeof st); + ASSERT (lstat (BASE "link3", &st) == 0); + } + } + /* Files present here: + {BASE}file + {BASE}link1 -> {BASE}file + {BASE}link3 -> {BASE}nowhere + {BASE}dir/ + */ + { /* Trailing slash on dangling. */ + { + errno = 0; + ASSERT (func (BASE "link3/", BASE "link2") == -1); + ASSERT (errno == ENOENT || errno == ENOTDIR); + } + { + errno = 0; + ASSERT (func (BASE "link3", BASE "link2/") == -1); + ASSERT (errno == ENOENT || errno == ENOTDIR); + } + { + errno = 0; + ASSERT (lstat (BASE "link2", &st) == -1); + ASSERT (errno == ENOENT); + } + memset (&st, 0, sizeof st); + ASSERT (lstat (BASE "link3", &st) == 0); + } + /* Files present here: + {BASE}file + {BASE}link1 -> {BASE}file + {BASE}link3 -> {BASE}nowhere + {BASE}dir/ + */ + { /* Trailing slash on link to file. */ + { + errno = 0; + ASSERT (func (BASE "link1/", BASE "link2") == -1); + ASSERT (errno == ENOTDIR); + } + { + errno = 0; + ASSERT (func (BASE "link1", BASE "link3/") == -1); + ASSERT (errno == ENOENT || errno == ENOTDIR); + } + } + /* Files present here: + {BASE}file + {BASE}link1 -> {BASE}file + {BASE}link3 -> {BASE}nowhere + {BASE}dir/ + */ /* Mixing symlink and file. */ - ASSERT (close (creat (BASE "file2", 0600)) == 0); /* File onto link. */ - ASSERT (func (BASE "file2", BASE "link3") == 0); - errno = 0; - ASSERT (stat (BASE "file2", &st) == -1); - ASSERT (errno == ENOENT); - memset (&st, 0, sizeof st); - ASSERT (lstat (BASE "link3", &st) == 0); - ASSERT (S_ISREG (st.st_mode)); - ASSERT (unlink (BASE "link3") == 0); - ASSERT (symlink (BASE "nowhere", BASE "link2") == 0); /* Link onto file. */ - ASSERT (close (creat (BASE "file2", 0600)) == 0); - ASSERT (func (BASE "link2", BASE "file2") == 0); - errno = 0; - ASSERT (lstat (BASE "link2", &st) == -1); - ASSERT (errno == ENOENT); - memset (&st, 0, sizeof st); - ASSERT (lstat (BASE "file2", &st) == 0); - ASSERT (S_ISLNK (st.st_mode)); - ASSERT (unlink (BASE "file2") == 0); - errno = 0; /* Trailing slash. */ - ASSERT (func (BASE "file/", BASE "link1") == -1); - ASSERT (errno == ENOTDIR); - errno = 0; - ASSERT (func (BASE "file", BASE "link1/") == -1); - ASSERT (errno == ENOTDIR || errno == ENOENT); - errno = 0; - ASSERT (func (BASE "link1/", BASE "file") == -1); - ASSERT (errno == ENOTDIR); - errno = 0; - ASSERT (func (BASE "link1", BASE "file/") == -1); - ASSERT (errno == ENOTDIR || errno == ENOENT); - memset (&st, 0, sizeof st); - ASSERT (lstat (BASE "file", &st) == 0); - ASSERT (S_ISREG (st.st_mode)); - memset (&st, 0, sizeof st); - ASSERT (lstat (BASE "link1", &st) == 0); - ASSERT (S_ISLNK (st.st_mode)); + + { /* File onto link. */ + ASSERT (close (creat (BASE "file2", 0600)) == 0); + /* Files present here: + {BASE}file + {BASE}file2 + {BASE}link1 -> {BASE}file + {BASE}link3 -> {BASE}nowhere + {BASE}dir/ + */ + { + ASSERT (func (BASE "file2", BASE "link3") == 0); + errno = 0; + ASSERT (stat (BASE "file2", &st) == -1); + ASSERT (errno == ENOENT); + memset (&st, 0, sizeof st); + ASSERT (lstat (BASE "link3", &st) == 0); + ASSERT (S_ISREG (st.st_mode)); + } + /* Files present here: + {BASE}file + {BASE}link1 -> {BASE}file + {BASE}link3 + {BASE}dir/ + */ + ASSERT (unlink (BASE "link3") == 0); + } + /* Files present here: + {BASE}file + {BASE}link1 -> {BASE}file + {BASE}dir/ + */ + { /* Link onto file. */ + ASSERT (symlink (BASE "nowhere", BASE "link2") == 0); + /* Files present here: + {BASE}file + {BASE}link1 -> {BASE}file + {BASE}link2 -> {BASE}nowhere + {BASE}dir/ + */ + ASSERT (close (creat (BASE "file2", 0600)) == 0); + /* Files present here: + {BASE}file + {BASE}file2 + {BASE}link1 -> {BASE}file + {BASE}link2 -> {BASE}nowhere + {BASE}dir/ + */ + { + ASSERT (func (BASE "link2", BASE "file2") == 0); + errno = 0; + ASSERT (lstat (BASE "link2", &st) == -1); + ASSERT (errno == ENOENT); + memset (&st, 0, sizeof st); + ASSERT (lstat (BASE "file2", &st) == 0); + ASSERT (S_ISLNK (st.st_mode)); + } + /* Files present here: + {BASE}file + {BASE}file2 -> {BASE}nowhere + {BASE}link1 -> {BASE}file + {BASE}dir/ + */ + ASSERT (unlink (BASE "file2") == 0); + } + /* Files present here: + {BASE}file + {BASE}link1 -> {BASE}file + {BASE}dir/ + */ + { /* Trailing slash. */ + { + errno = 0; + ASSERT (func (BASE "file/", BASE "link1") == -1); + ASSERT (errno == ENOTDIR); + } + { + errno = 0; + ASSERT (func (BASE "file", BASE "link1/") == -1); + ASSERT (errno == ENOTDIR || errno == ENOENT); + } + { + errno = 0; + ASSERT (func (BASE "link1/", BASE "file") == -1); + ASSERT (errno == ENOTDIR); + } + { + errno = 0; + ASSERT (func (BASE "link1", BASE "file/") == -1); + ASSERT (errno == ENOTDIR || errno == ENOENT); + memset (&st, 0, sizeof st); + ASSERT (lstat (BASE "file", &st) == 0); + ASSERT (S_ISREG (st.st_mode)); + memset (&st, 0, sizeof st); + ASSERT (lstat (BASE "link1", &st) == 0); + ASSERT (S_ISLNK (st.st_mode)); + } + } + /* Files present here: + {BASE}file + {BASE}link1 -> {BASE}file + {BASE}dir/ + */ /* Mixing symlink and directory. */ - errno = 0; /* Directory onto link. */ - ASSERT (func (BASE "dir", BASE "link1") == -1); - ASSERT (errno == ENOTDIR); - errno = 0; - ASSERT (func (BASE "dir/", BASE "link1") == -1); - ASSERT (errno == ENOTDIR); - errno = 0; - ASSERT (func (BASE "dir", BASE "link1/") == -1); - ASSERT (errno == ENOTDIR); - errno = 0; /* Link onto directory. */ - ASSERT (func (BASE "link1", BASE "dir") == -1); - ASSERT (errno == EISDIR || errno == ENOTDIR); - errno = 0; - ASSERT (func (BASE "link1", BASE "dir/") == -1); - ASSERT (errno == EISDIR || errno == ENOTDIR); - errno = 0; - ASSERT (func (BASE "link1/", BASE "dir") == -1); - ASSERT (errno == ENOTDIR); - memset (&st, 0, sizeof st); - ASSERT (lstat (BASE "link1", &st) == 0); - ASSERT (S_ISLNK (st.st_mode)); - memset (&st, 0, sizeof st); - ASSERT (lstat (BASE "dir", &st) == 0); - ASSERT (S_ISDIR (st.st_mode)); + + { /* Directory onto link. */ + { + errno = 0; + ASSERT (func (BASE "dir", BASE "link1") == -1); + ASSERT (errno == ENOTDIR); + } + { + errno = 0; + ASSERT (func (BASE "dir/", BASE "link1") == -1); + ASSERT (errno == ENOTDIR); + } + { + errno = 0; + ASSERT (func (BASE "dir", BASE "link1/") == -1); + ASSERT (errno == ENOTDIR); + } + } + { /* Link onto directory. */ + { + errno = 0; + ASSERT (func (BASE "link1", BASE "dir") == -1); + ASSERT (errno == EISDIR || errno == ENOTDIR); + } + { + errno = 0; + ASSERT (func (BASE "link1", BASE "dir/") == -1); + ASSERT (errno == EISDIR || errno == ENOTDIR); + } + { + errno = 0; + ASSERT (func (BASE "link1/", BASE "dir") == -1); + ASSERT (errno == ENOTDIR); + memset (&st, 0, sizeof st); + ASSERT (lstat (BASE "link1", &st) == 0); + ASSERT (S_ISLNK (st.st_mode)); + memset (&st, 0, sizeof st); + ASSERT (lstat (BASE "dir", &st) == 0); + ASSERT (S_ISDIR (st.st_mode)); + } + } + /* Files present here: + {BASE}file + {BASE}link1 -> {BASE}file + {BASE}dir/ + */ /* POSIX requires rename("link-to-dir/","other") to rename "dir" and leave "link-to-dir" dangling, but GNU rejects this. POSIX @@ -376,6 +853,12 @@ test_rename (int (*func) (char const *, char const *), bool print) { int result; ASSERT (symlink (BASE "dir2", BASE "link2") == 0); + /* Files present here: + {BASE}file + {BASE}link1 -> {BASE}file + {BASE}link2 -> {BASE}dir2 + {BASE}dir/ + */ errno = 0; result = func (BASE "dir", BASE "link2/"); if (result == 0) @@ -390,16 +873,24 @@ test_rename (int (*func) (char const *, char const *), bool print) memset (&st, 0, sizeof st); ASSERT (lstat (BASE "link2", &st) == 0); ASSERT (S_ISLNK (st.st_mode)); - ASSERT (func (BASE "link2/", BASE "dir") == 0); - memset (&st, 0, sizeof st); - ASSERT (lstat (BASE "dir", &st) == 0); - ASSERT (S_ISDIR (st.st_mode)); - errno = 0; - ASSERT (lstat (BASE "dir2", &st) == -1); - ASSERT (errno == ENOENT); - memset (&st, 0, sizeof st); - ASSERT (lstat (BASE "link2", &st) == 0); - ASSERT (S_ISLNK (st.st_mode)); + /* Files present here: + {BASE}file + {BASE}link1 -> {BASE}file + {BASE}link2 -> {BASE}dir2 + {BASE}dir2/ + */ + { + ASSERT (func (BASE "link2/", BASE "dir") == 0); + memset (&st, 0, sizeof st); + ASSERT (lstat (BASE "dir", &st) == 0); + ASSERT (S_ISDIR (st.st_mode)); + errno = 0; + ASSERT (lstat (BASE "dir2", &st) == -1); + ASSERT (errno == ENOENT); + memset (&st, 0, sizeof st); + ASSERT (lstat (BASE "link2", &st) == 0); + ASSERT (S_ISLNK (st.st_mode)); + } } else { @@ -417,12 +908,18 @@ test_rename (int (*func) (char const *, char const *), bool print) ASSERT (S_ISLNK (st.st_mode)); ASSERT (unlink (BASE "link2") == 0); ASSERT (symlink (BASE "dir", BASE "link2") == 0); + /* Files present here: + {BASE}file + {BASE}link1 -> {BASE}file + {BASE}link2 -> {BASE}dir + {BASE}dir/ + */ errno = 0; /* OpenBSD notices that link2/ and dir are the same. */ result = func (BASE "link2/", BASE "dir"); if (result) /* GNU/Linux rejects attempts to use link2/. */ { ASSERT (result == -1); - ASSERT (errno == ENOTDIR); + ASSERT (errno == ENOTDIR || errno == EISDIR); } memset (&st, 0, sizeof st); ASSERT (lstat (BASE "dir", &st) == 0); @@ -435,6 +932,12 @@ test_rename (int (*func) (char const *, char const *), bool print) ASSERT (S_ISLNK (st.st_mode)); } } + /* Files present here: + {BASE}file + {BASE}link1 -> {BASE}file + {BASE}link2 -> {BASE}dir or {BASE}dir2 + {BASE}dir/ + */ /* Clean up. */ ASSERT (unlink (BASE "file") == 0);