Hacks to the vfs tests to test various cases of rename more thoroughly. This isn't fit to commit because it GCC take hundreds of megabytes to compile t_vnops, and it triggers quadratic-time behaviour in atf-run because it is so huge. Index: tests/fs/common/h_fsmacros.h =================================================================== RCS file: /cvsroot/src/tests/fs/common/h_fsmacros.h,v retrieving revision 1.35 diff -p -u -r1.35 h_fsmacros.h --- tests/fs/common/h_fsmacros.h 11 Aug 2011 10:52:12 -0000 1.35 +++ tests/fs/common/h_fsmacros.h 7 Apr 2012 21:19:57 -0000 @@ -42,12 +42,25 @@ #include "../../h_macros.h" +struct fsprotos { + int (*newfs)(const atf_tc_t *, void **, const char *, off_t, void *); + int (*delfs)(const atf_tc_t *, void *); + int (*mount)(const atf_tc_t *, void *, const char *, int); + int (*unmount)(const atf_tc_t *, const char *, int); +}; + #define FSPROTOS(_fs_) \ int _fs_##_fstest_newfs(const atf_tc_t *, void **, const char *, \ - off_t, void *); \ + off_t, void *); \ int _fs_##_fstest_delfs(const atf_tc_t *, void *); \ int _fs_##_fstest_mount(const atf_tc_t *, void *, const char *, int); \ -int _fs_##_fstest_unmount(const atf_tc_t *, const char *, int); +int _fs_##_fstest_unmount(const atf_tc_t *, const char *, int); \ +static const struct fsprotos _fs_##_fstest_protos = { \ + .newfs = &_fs_##_fstest_newfs, \ + .delfs = &_fs_##_fstest_delfs, \ + .mount = &_fs_##_fstest_mount, \ + .unmount = &_fs_##_fstest_unmount, \ +} FSPROTOS(ext2fs); FSPROTOS(ffs); @@ -73,33 +86,78 @@ FSPROTOS(v7fs); #define FSTEST_MNTNAME "/mnt" #endif +static __unused bool +atf_check_fstype(const atf_tc_t *tc, const char *fs) +{ + const char *fstype; + + if (!atf_tc_has_config_var(tc, "fstype")) + return true; + + fstype = atf_tc_get_config_var(tc, "fstype"); + if (strcmp(fstype, fs) == 0) + return true; + return false; +} + +static __unused void +fstest_constructor(const atf_tc_t *tc, const char *fstype, + const struct fsprotos *fs, void **args) +{ + if (!atf_check_fstype(tc, fstype)) + atf_tc_skip("filesystem not selected"); + if (fs->newfs(tc, args, FSTEST_IMGNAME, FSTEST_IMGSIZE, NULL) != 0) + atf_tc_fail_errno("newfs failed"); + if (fs->mount(tc, *args, FSTEST_MNTNAME, 0) != 0) + atf_tc_fail_errno("mount failed"); +} + +static __unused void +fstest_constructor_fspriv(const atf_tc_t *tc, const char *fstype, + const struct fsprotos *fs, void **args, void *privargs) +{ + if (!atf_check_fstype(tc, fstype)) + atf_tc_skip("filesystem not selected"); + if (fs->newfs(tc, args, FSTEST_IMGNAME, FSTEST_IMGSIZE, privargs) != 0) + atf_tc_fail_errno("newfs failed"); + if (fs->mount(tc, *args, FSTEST_MNTNAME, 0) != 0) + atf_tc_fail_errno("mount failed"); +} + +static __unused void +fstest_remount_ro(const atf_tc_t *tc, const struct fsprotos *fs, void *args) +{ + if (fs->unmount(tc, FSTEST_MNTNAME, 0) != 0) + atf_tc_fail_errno("unmount r/w failed"); + if (fs->mount(tc, args, FSTEST_MNTNAME, MNT_RDONLY) != 0) + atf_tc_fail_errno("mount ro failed"); +} + +static __unused void +fstest_destructor(const atf_tc_t *tc, const struct fsprotos *fs, void *args) +{ + if (fs->unmount(tc, FSTEST_MNTNAME, 0) != 0) { + int error = errno; + rump_pub_vfs_mount_print(FSTEST_MNTNAME, 1); + errno = error; + atf_tc_fail_errno("unmount failed"); + } + if (fs->delfs(tc, args) != 0) + atf_tc_fail_errno("delfs failed"); +} + #define FSTEST_CONSTRUCTOR(_tc_, _fs_, _args_) \ -do { \ - if (_fs_##_fstest_newfs(_tc_, &_args_, \ - FSTEST_IMGNAME, FSTEST_IMGSIZE, NULL) != 0) \ - atf_tc_fail_errno("newfs failed"); \ - if (_fs_##_fstest_mount(_tc_, _args_, FSTEST_MNTNAME, 0) != 0) \ - atf_tc_fail_errno("mount failed"); \ -} while (/*CONSTCOND*/0); + fstest_constructor(tc, #_fs_, &_fs_##_fstest_protos, &_args_) #define FSTEST_CONSTRUCTOR_FSPRIV(_tc_, _fs_, _args_, _privargs_) \ -do { \ - if (_fs_##_fstest_newfs(_tc_, &_args_, \ - FSTEST_IMGNAME, FSTEST_IMGSIZE, _privargs_) != 0) \ - atf_tc_fail_errno("newfs failed"); \ - if (_fs_##_fstest_mount(_tc_, _args_, FSTEST_MNTNAME, 0) != 0) \ - atf_tc_fail_errno("mount failed"); \ -} while (/*CONSTCOND*/0); + fstest_constructor_fspriv(tc, #_fs_, &_fs_##_fstest_protos, \ + &_args_, _privargs_) + +#define FSTEST_REMOUNT_RO(_tc_, _fs_, _args_) \ + fstest_remount_ro(tc, &_fs_##_fstest_protos, _args_) #define FSTEST_DESTRUCTOR(_tc_, _fs_, _args_) \ -do { \ - if (_fs_##_fstest_unmount(_tc_, FSTEST_MNTNAME, 0) != 0) { \ - rump_pub_vfs_mount_print(FSTEST_MNTNAME, 1); \ - atf_tc_fail_errno("unmount failed"); \ - } \ - if (_fs_##_fstest_delfs(_tc_, _args_) != 0) \ - atf_tc_fail_errno("delfs failed"); \ -} while (/*CONSTCOND*/0); + fstest_destructor(_tc_, &_fs_##_fstest_protos, _args_) #define ATF_TC_FSADD(fs,type,func,desc) \ ATF_TC(fs##_##func); \ @@ -113,14 +171,9 @@ do { \ \ ATF_TC_BODY(fs##_##func,tc) \ { \ - if (!atf_check_fstype(tc, #fs)) \ - atf_tc_skip("filesystem not selected"); \ FSTEST_CONSTRUCTOR(tc,fs,fs##func##tmp); \ func(tc,FSTEST_MNTNAME); \ - if (fs##_fstest_unmount(tc, FSTEST_MNTNAME, 0) != 0) { \ - rump_pub_vfs_mount_print(FSTEST_MNTNAME, 1); \ - atf_tc_fail_errno("unmount failed"); \ - } \ + FSTEST_DESTRUCTOR(tc,fs,fs##func##tmp); \ } #define ATF_TC_FSADD_RO(_fs_,_type_,_func_,_desc_,_gen_) \ @@ -135,20 +188,11 @@ do { \ \ ATF_TC_BODY(_fs_##_##_func_,tc) \ { \ - if (!atf_check_fstype(tc, #_fs_)) \ - atf_tc_skip("filesystem not selected"); \ FSTEST_CONSTRUCTOR(tc,_fs_,_fs_##_func_##tmp); \ _gen_(tc,FSTEST_MNTNAME); \ - if (_fs_##_fstest_unmount(tc, FSTEST_MNTNAME, 0) != 0) \ - atf_tc_fail_errno("unmount r/w failed"); \ - if (_fs_##_fstest_mount(tc, _fs_##_func_##tmp, \ - FSTEST_MNTNAME, MNT_RDONLY) != 0) \ - atf_tc_fail_errno("mount ro failed"); \ + FSTEST_REMOUNT_RO(tc,_fs_,_fs_##_func_##tmp); \ _func_(tc,FSTEST_MNTNAME); \ - if (_fs_##_fstest_unmount(tc, FSTEST_MNTNAME, 0) != 0) {\ - rump_pub_vfs_mount_print(FSTEST_MNTNAME, 1); \ - atf_tc_fail_errno("unmount failed"); \ - } \ + FSTEST_DESTRUCTOR(tc,_fs_,_fs_##_func_##tmp); \ } #define ATF_TP_FSADD(fs,func) \ @@ -221,20 +265,6 @@ do { \ return atf_no_error(); \ } -static __inline bool -atf_check_fstype(const atf_tc_t *tc, const char *fs) -{ - const char *fstype; - - if (!atf_tc_has_config_var(tc, "fstype")) - return true; - - fstype = atf_tc_get_config_var(tc, "fstype"); - if (strcmp(fstype, fs) == 0) - return true; - return false; -} - #define FSTYPE_EXT2FS(tc)\ (strcmp(atf_tc_get_md_var(tc, "X-fs.type"), "ext2fs") == 0) #define FSTYPE_FFS(tc)\ Index: tests/fs/vfs/Makefile =================================================================== RCS file: /cvsroot/src/tests/fs/vfs/Makefile,v retrieving revision 1.16 diff -p -u -r1.16 Makefile --- tests/fs/vfs/Makefile 11 Aug 2011 10:52:12 -0000 1.16 +++ tests/fs/vfs/Makefile 8 Apr 2012 19:38:49 -0000 @@ -6,6 +6,9 @@ TESTSDIR= ${TESTSBASE}/fs/vfs WARNS= 4 +# GCC blows up on this without -fno-var-tracking. +COPTS.t_vnops.c+= ${${ACTIVE_CC} == "gcc" :? -fno-var-tracking :} + TESTS_C+= t_full TESTS_C+= t_io TESTS_C+= t_renamerace Index: tests/fs/vfs/t_vnops.c =================================================================== RCS file: /cvsroot/src/tests/fs/vfs/t_vnops.c,v retrieving revision 1.33 diff -p -u -r1.33 t_vnops.c --- tests/fs/vfs/t_vnops.c 20 Mar 2012 18:20:49 -0000 1.33 +++ tests/fs/vfs/t_vnops.c 8 Apr 2012 19:38:49 -0000 @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -180,6 +181,483 @@ dir_rmdirdotdot(const atf_tc_t *tc, cons FSTEST_EXIT(); } +/* + * Rename directory setup: + * + * grandparent/ + * parent/ + * brother + * clone (hard link to brother) + * sister + * dir/ (empty directory) + * sub/ + * dir/ (empty directory) + * file (regular file) + * file (regular file) + * good (symbolic link to `file') + * bad (symbolic link to `oblivion') + * uncle + * clone (hard link to uncle) + * other-uncle + * aunt/ + * brother + * cousin + * clone (hard link to brother) + * dir/ + * dir/ (empty directory) + * file (regular file) + * good (symbolic link to `file') + * bad (symbolic link to `oblivion') + * immutable0 (immutable regular file) + * immutable1 (immutable regular file) + * append0 (append-only regular file) + * append1 (append-only regular file) + * immdir0/ (immutable directory) + * x (regular file) + * immdir1/ (immutable directory) + * appdir0/ (append-only directory) + * x (regular file) + * appdir1/ (append-only directory) + */ + +#define USES_fifo do {} while (0) /* ? */ +#define USES_chrdev do {} while (0) /* ? */ +#define USES_directory USES_DIRS +#define USES_blkdev do {} while (0) /* ? */ +#define USES_regular do {} while (0) +#define USES_symlink USES_SYMLINKS +#define USES_socket do {} while (0) /* ? */ + +static int __unused +touch_fifo(const char *pathname) +{ + + return rump_sys_mkfifo(pathname, 0777); +} + +static int __unused +touch_chrdev(const char *pathname) +{ + + return rump_sys_mknod(pathname, S_IFCHR, 1); +} + +static int +touch_directory(const char *pathname) +{ + + return rump_sys_mkdir(pathname, 0777); +} + +static int __unused +touch_blkdev(const char *pathname) +{ + + return rump_sys_mknod(pathname, S_IFBLK, 1); +} + +static int +touch_regular(const char *pathname) +{ + int fd; + + fd = rump_sys_open(pathname, O_WRONLY | O_CREAT | O_EXCL, 0); + if (fd == -1) + return -1; + (void)rump_sys_close(fd); + return 0; +} + +static int +touch_symlink(const char *pathname) +{ + + return rump_sys_symlink("Hello, world!", pathname); +} + +static int __unused +touch_socket(const char *pathname) +{ + union { struct sockaddr sa; struct sockaddr_un un; } addr; + int s; + + (void)strlcpy(addr.un.sun_path, pathname, sizeof addr.un.sun_path); + + s = rump_sys_socket(PF_LOCAL, SOCK_STREAM, 0); + if (s == -1) + return -1; + + if (rump_sys_bind(s, &addr.sa, sizeof addr.un) == -1) + return -1; + + (void)rump_sys_close(s); + return 0; +} + +static int +regflag(const char *pathname, unsigned long flags) +{ + + if (touch_regular(pathname) == -1) + return -1; + if (rump_sys_chflags(pathname, flags) == -1) + return -1; + return 0; +} + +static int +dirflag(const char *pathname, unsigned long flags) +{ + + if (rump_sys_mkdir(pathname, 0777) == -1) + return -1; + if (rump_sys_chflags(pathname, flags) == -1) + return -1; + return 0; +} + +enum rename_test_options { + DIRS = (1 << 0), + FLAGS = (1 << 1), + LINKS = (1 << 2), + SYMLINKS = (1 << 3), + SKIPDIR = (1 << 4), +}; + +/* + * v7fs is an approximation: it supports APPEND but not IMMUTABLE. + * Someone else should fix this. + */ + +#define USES_FLAGS \ + if (FSTYPE_MSDOS(tc) || FSTYPE_NFS(tc) || FSTYPE_PUFFS(tc) || \ + FSTYPE_RUMPFS(tc) || FSTYPE_SYSVBFS(tc) || FSTYPE_V7FS(tc)) \ + atf_tc_skip("flags not supported by file system") + +#define USES_LINKS USES_SYMLINKS /* kludge */ + +static void +setup_rename_test(const atf_tc_t *tc, const char *mp, const char *type, + int (*touch)(const char *), + int options) +{ + char buf[MAXPATHLEN], buf0[MAXPATHLEN]; + + if (options & DIRS) USES_DIRS; + if (options & FLAGS) USES_FLAGS; + if (options & LINKS) USES_LINKS; + if (options & SYMLINKS) USES_SYMLINKS; + + if ((options & LINKS) && (0 == strcmp(type, "directory"))) + atf_tc_skip("can't hard link directories"); + + if ((options & LINKS) && (0 == strcmp(type, "symlink"))) + atf_tc_skip("can't hard link symlinks"); + + if ((options & SKIPDIR) && (0 == strcmp(type, "directory"))) + atf_tc_skip("doesn't work for directories"); + + md(buf, mp, "uncle"); RL((*touch)(buf)); + md(buf, mp, "other-uncle"); RL((*touch)(buf)); + md(buf, mp, "file"); RL(touch_regular(buf)); + + if (options & DIRS) { + md(buf, mp, "parent"); RL(rump_sys_mkdir(buf, 0777)); + md(buf, mp, "parent/brother"); RL((*touch)(buf)); + md(buf, mp, "parent/sister"); RL((*touch)(buf)); + md(buf, mp, "parent/dir"); RL(rump_sys_mkdir(buf, 0777)); + md(buf, mp, "parent/sub"); RL(rump_sys_mkdir(buf, 0777)); + md(buf, mp, "parent/sub/dir"); RL(rump_sys_mkdir(buf, 0777)); + md(buf, mp, "parent/sub/file"); RL(touch_regular(buf)); + md(buf, mp, "parent/file"); RL(touch_regular(buf)); + md(buf, mp, "aunt"); RL(rump_sys_mkdir(buf, 0777)); + md(buf, mp, "aunt/brother"); RL((*touch)(buf)); + md(buf, mp, "aunt/cousin"); RL((*touch)(buf)); + md(buf, mp, "aunt/dir"); RL(rump_sys_mkdir(buf, 0777)); + md(buf, mp, "dir"); RL(rump_sys_mkdir(buf, 0777)); + } + + if (options & FLAGS) { + md(buf, mp, "immutable0"); RL(regflag(buf, UF_IMMUTABLE)); + md(buf, mp, "immutable1"); RL(regflag(buf, UF_IMMUTABLE)); + md(buf, mp, "append0"); RL(regflag(buf, UF_APPEND)); + md(buf, mp, "append1"); RL(regflag(buf, UF_APPEND)); + } + + if (options & LINKS) { + md(buf, mp, "uncle"); + md(buf0, mp, "clone"); RL(rump_sys_link(buf, buf0)); + } + + if (options & SYMLINKS) { + md(buf, mp, "good"); RL(rump_sys_symlink("file", buf)); + md(buf, mp, "bad"); RL(rump_sys_symlink("oblivion", buf)); + } + + if ((options & DIRS) && (options & FLAGS)) { + md(buf, mp, "immdir0"); RL(rump_sys_mkdir(buf, 0777)); + md(buf0, mp, "immdir0/x"); RL(touch_regular(buf0)); + RL(rump_sys_chflags(buf, UF_IMMUTABLE)); + md(buf, mp, "immdir1"); RL(dirflag(buf, UF_IMMUTABLE)); + md(buf, mp, "appdir0"); RL(rump_sys_mkdir(buf, 0777)); + md(buf0, mp, "appdir0/x"); RL(touch_regular(buf0)); + RL(rump_sys_chflags(buf, UF_APPEND)); + md(buf, mp, "appdir1"); RL(dirflag(buf, UF_APPEND)); + } + + if ((options & DIRS) && (options & LINKS)) { + md(buf, mp, "parent/brother"); + md(buf0, mp, "parent/clone"); RL(rump_sys_link(buf, buf0)); + md(buf0, mp, "aunt/clone"); RL(rump_sys_link(buf, buf0)); + } + + if ((options & DIRS) && (options & SYMLINKS)) { + md(buf, mp, "parent/good"); + RL(rump_sys_symlink("file", buf)); + md(buf, mp, "parent/bad"); + RL(rump_sys_symlink("oblivion", buf)); + } +} + +/* XXX Should check link counts on everything. */ + +static void __unused +test_rename(const atf_tc_t *tc, const char *mp, const char *type, + int (*touch)(const char *), + const char *from, const char *to, int options) +{ + char path_from[MAXPATHLEN], path_to[MAXPATHLEN]; + struct stat sb0, sb1; + int error; + + if (FSTYPE_RUMPFS(tc)) + atf_tc_skip("rename not supported by file system"); + + md(path_from, mp, from); + md(path_to, mp, to); + setup_rename_test(tc, mp, type, touch, options); + RL(rump_sys_lstat(path_from, &sb0)); + error = rump_sys_lstat(path_to, &sb1); + RL(rump_sys_rename(path_from, path_to)); + if (0 != strcmp(from, to)) { + ATF_REQUIRE_ERRNO(ENOENT, + rump_sys_lstat(path_from, &sb0) == -1); + } else { + /* Special case for rename("a", "a"). */ + RL(rump_sys_lstat(path_from, &sb1)); + if (0 != memcmp(&sb0, &sb1, sizeof(struct stat))) + atf_tc_fail("stat changed"); + } + if ((error == 0) + && (sb0.st_dev == sb1.st_dev) + && (sb0.st_ino == sb1.st_ino) + && (0 != strcmp(from, to))) { + /* Special case for link("a", "b"); rename("a", "b"). */ + RL(rump_sys_lstat(path_to, &sb1)); + ATF_REQUIRE_EQ(sb1.st_nlink, (sb0.st_nlink - 1)); + sb1.st_nlink = sb0.st_nlink; + } else { + RL(rump_sys_lstat(path_to, &sb1)); + } + + ATF_REQUIRE_EQ(sb0.st_dev, sb1.st_dev); + ATF_REQUIRE_EQ(sb0.st_mode, sb1.st_mode); + /* msdosfs inode numbers for regular files are hosed. */ + if (!(FSTYPE_MSDOS(tc) && (0 == strcmp(type, "regular")))) + ATF_REQUIRE_EQ(sb0.st_ino, sb1.st_ino); + ATF_REQUIRE_EQ(sb0.st_nlink, sb1.st_nlink); + ATF_REQUIRE_EQ(sb0.st_uid, sb1.st_uid); + ATF_REQUIRE_EQ(sb0.st_gid, sb1.st_gid); + ATF_REQUIRE_EQ(sb0.st_rdev, sb1.st_rdev); + ATF_REQUIRE_EQ(sb0.st_atimespec.tv_sec, sb1.st_atimespec.tv_sec); + ATF_REQUIRE_EQ(sb0.st_atimespec.tv_nsec, sb1.st_atimespec.tv_nsec); + ATF_REQUIRE_EQ(sb0.st_mtimespec.tv_sec, sb1.st_mtimespec.tv_sec); + ATF_REQUIRE_EQ(sb0.st_mtimespec.tv_nsec, sb1.st_mtimespec.tv_nsec); + /* + * rename may update the ctime by provisionally changing the + * link count, so ignore any changes to it. + */ +#if 0 + ATF_REQUIRE_EQ(sb0.st_ctimespec.tv_sec, sb1.st_ctimespec.tv_sec); + ATF_REQUIRE_EQ(sb0.st_ctimespec.tv_nsec, sb1.st_ctimespec.tv_nsec); +#endif + ATF_REQUIRE_EQ(sb0.st_birthtimespec.tv_sec, + sb1.st_birthtimespec.tv_sec); + ATF_REQUIRE_EQ(sb0.st_birthtimespec.tv_nsec, + sb1.st_birthtimespec.tv_nsec); + ATF_REQUIRE_EQ(sb0.st_size, sb1.st_size); + ATF_REQUIRE_EQ(sb0.st_blocks, sb1.st_blocks); + ATF_REQUIRE_EQ(sb0.st_blksize, sb1.st_blksize); + ATF_REQUIRE_EQ(sb0.st_flags, sb1.st_flags); + ATF_REQUIRE_EQ(sb0.st_gen, sb1.st_gen); +} + +static void __unused +test_rename_fail(const atf_tc_t *tc, const char *mp, const char *type, + int (*touch)(const char *), + const char *from, const char *to, int options, int error) +{ + char path_from[MAXPATHLEN], path_to[MAXPATHLEN]; + + if (FSTYPE_RUMPFS(tc)) + atf_tc_skip("rename not supported by file system"); + + md(path_from, mp, from); + md(path_to, mp, to); + setup_rename_test(tc, mp, type, touch, options); + ATF_REQUIRE_ERRNO(error, rump_sys_rename(path_from, path_to) == -1); +} + +#define ATF_TC_RENAME(NAME, FROM, TO, OPTIONS) \ +static void \ +rename_##NAME(const atf_tc_t *tc, const char *mp, const char *type, \ + int (*touch)(const char *)) \ +{ \ + test_rename(tc, mp, type, touch, FROM, TO, OPTIONS); \ +} \ +ATF_TC_RENAME_TYPES(rename_##NAME, "rename(" #FROM ", " #TO ")") + +#define ATF_TC_RENAME_FAIL(NAME, FROM, TO, OPTIONS, ERROR) \ +static void \ +rename_fail_##NAME(const atf_tc_t *tc, const char *mp, const char *type,\ + int (*touch)(const char *)) \ +{ \ + test_rename_fail(tc, mp, type, touch, FROM, TO, OPTIONS, ERROR);\ +} \ +ATF_TC_RENAME_TYPES(rename_fail_##NAME, \ + "rename(" #FROM ", " #TO ") should fail") + +#define ATF_TC_RENAME_TYPES(NAME, DESC) \ +/* ATF_TC_RENAME_TYPE(NAME, fifo, DESC) */ \ +/* ATF_TC_RENAME_TYPE(NAME, chrdev, DESC) */ \ +ATF_TC_RENAME_TYPE(NAME, directory, DESC) \ +/* ATF_TC_RENAME_TYPE(NAME, blkdev, DESC) */ \ +ATF_TC_RENAME_TYPE(NAME, regular, DESC) \ +ATF_TC_RENAME_TYPE(NAME, symlink, DESC) \ +/* ATF_TC_RENAME_TYPE(NAME, socket, DESC) */ + +#define ATF_TC_RENAME_TYPE(NAME, TYPE, DESCRIPTION) \ +static void \ +NAME##_##TYPE(const atf_tc_t *tc, const char *mp) \ +{ \ + USES_##TYPE; \ + NAME(tc, mp, #TYPE, touch_##TYPE); \ +} \ +ATF_TC_FSAPPLY(NAME##_##TYPE, DESCRIPTION) + +#define ATF_TP_RENAME(NAME) do { \ + ATF_TP_RENAME_TYPES(rename_##NAME); \ +} while (0) + +#define ATF_TP_RENAME_FAIL(NAME) do { \ + ATF_TP_RENAME_TYPES(rename_fail_##NAME); \ +} while (0) + +#define ATF_TP_RENAME_TYPES(NAME) do \ +{ \ + /* ATF_TP_RENAME_TYPE(NAME, fifo); */ \ + /* ATF_TP_RENAME_TYPE(NAME, chrdev); */ \ + ATF_TP_RENAME_TYPE(NAME, directory); \ + /* ATF_TP_RENAME_TYPE(NAME, blkdev); */ \ + ATF_TP_RENAME_TYPE(NAME, regular); \ + ATF_TP_RENAME_TYPE(NAME, symlink); \ + /* ATF_TP_RENAME_TYPE(NAME, socket); */ \ +} while (0) + +#define ATF_TP_RENAME_TYPE(NAME, TYPE) do \ +{ \ + ATF_TP_FSAPPLY(NAME##_##TYPE); \ +} while (0) + +ATF_TC_RENAME(0, "parent/brother", "parent/brother", DIRS) +ATF_TC_RENAME(1, "parent/brother", "parent/brother0", DIRS) +ATF_TC_RENAME(2, "parent/brother", "parent/clone", DIRS | LINKS) +ATF_TC_RENAME(3, "parent/brother", "parent/sister", DIRS) +ATF_TC_RENAME(4, "parent/brother", "parent/dir/brother", DIRS) +ATF_TC_RENAME(5, "parent/brother", "parent/dir/brother0", DIRS) +ATF_TC_RENAME(6, "parent/brother", "parent/file", DIRS | SKIPDIR) +ATF_TC_RENAME(7, "parent/brother", "parent/good", DIRS | SKIPDIR | SYMLINKS) +ATF_TC_RENAME(8, "parent/brother", "parent/bad", DIRS | SKIPDIR | SYMLINKS) +ATF_TC_RENAME(9, "parent/brother", "uncle", DIRS) +ATF_TC_RENAME(10, "parent/brother", "uncle0", DIRS) +ATF_TC_RENAME(11, "parent/brother", "aunt/brother", DIRS) +ATF_TC_RENAME(12, "parent/brother", "aunt/cousin", DIRS) +ATF_TC_RENAME(13, "parent/brother", "aunt/cousin0", DIRS) +ATF_TC_RENAME(14, "parent/brother", "aunt/clone", DIRS | LINKS) +ATF_TC_RENAME(15, "parent/brother", "dir/brother", DIRS) +ATF_TC_RENAME(16, "parent/brother", "dir/brother0", DIRS) +ATF_TC_RENAME(17, "parent/dir", "dir", DIRS) +ATF_TC_RENAME(18, "parent/dir", "parent/dir", DIRS) +ATF_TC_RENAME(19, "parent/dir", "aunt/dir", DIRS) +ATF_TC_RENAME(20, "uncle", "uncle", 0) +ATF_TC_RENAME(21, "uncle", "uncle0", 0) +ATF_TC_RENAME(22, "uncle", "clone", LINKS) +ATF_TC_RENAME(23, "uncle", "other-uncle", 0) +ATF_TC_RENAME(24, "uncle", "good", SKIPDIR | SYMLINKS) +ATF_TC_RENAME(25, "uncle", "bad", SKIPDIR | SYMLINKS) +ATF_TC_RENAME(26, "uncle", "parent/brother", DIRS) +ATF_TC_RENAME(27, "uncle", "parent/clone", DIRS | LINKS) +ATF_TC_RENAME(28, "uncle", "parent/sister", DIRS) +ATF_TC_RENAME(29, "uncle", "aunt/cousin", DIRS) +ATF_TC_RENAME(30, "uncle", "aunt/clone", DIRS | LINKS) +ATF_TC_RENAME(31, "aunt", "parent/dir", DIRS) +ATF_TC_RENAME(32, "aunt", "dir", DIRS) +ATF_TC_RENAME(33, "file", "appdir0/file", DIRS | FLAGS) + +ATF_TC_RENAME_FAIL(0, "parent", "aunt", DIRS, ENOTEMPTY) +ATF_TC_RENAME_FAIL(1, "parent", "aunt/.", DIRS, EISDIR) /* XXX EINVAL? */ +ATF_TC_RENAME_FAIL(2, "parent/.", "aunt", DIRS, EINVAL) +ATF_TC_RENAME_FAIL(3, "parent", "parent/.", DIRS, EISDIR) /* XXX EINVAL? */ +ATF_TC_RENAME_FAIL(4, "parent/.", "parent", DIRS, EINVAL) +ATF_TC_RENAME_FAIL(5, "parent", "parent/..", DIRS, EINVAL) +ATF_TC_RENAME_FAIL(6, "parent/..", "parent", DIRS, EINVAL) +ATF_TC_RENAME_FAIL(7, "parent", "aunt/..", DIRS, EINVAL) +ATF_TC_RENAME_FAIL(8, "parent/..", "aunt", DIRS, EINVAL) +ATF_TC_RENAME_FAIL(9, "parent", "parent/dir", DIRS, EINVAL) +ATF_TC_RENAME_FAIL(10, "parent", "parent/sub", DIRS, EINVAL) +ATF_TC_RENAME_FAIL(11, "parent", "parent/sub/dir", DIRS, EINVAL) +ATF_TC_RENAME_FAIL(12, "parent/dir", "parent", DIRS, ENOTEMPTY) +ATF_TC_RENAME_FAIL(13, "parent/sub", "parent", DIRS, ENOTEMPTY) +ATF_TC_RENAME_FAIL(14, "parent/sub/dir", "parent", DIRS, ENOTEMPTY) +ATF_TC_RENAME_FAIL(15, "parent", "parent/dir/loser", DIRS, EINVAL) +ATF_TC_RENAME_FAIL(16, "parent", "parent/sub/dir/loser", DIRS, EINVAL) +ATF_TC_RENAME_FAIL(17, "file", "dir", DIRS, EISDIR) +ATF_TC_RENAME_FAIL(18, "parent/file", "dir", DIRS, EISDIR) +ATF_TC_RENAME_FAIL(19, "parent/sub/file", "dir", DIRS, EISDIR) +ATF_TC_RENAME_FAIL(20, "file", "parent/dir", DIRS, EISDIR) +ATF_TC_RENAME_FAIL(21, "dir", "file", DIRS, ENOTDIR) +ATF_TC_RENAME_FAIL(22, "dir", "parent/file", DIRS, ENOTDIR) +ATF_TC_RENAME_FAIL(23, "parent/dir", "file", DIRS, ENOTDIR) +ATF_TC_RENAME_FAIL(24, "parent/sub", "file", DIRS, ENOTDIR) +ATF_TC_RENAME_FAIL(25, "parent/sub/dir", "file", DIRS, ENOTDIR) +ATF_TC_RENAME_FAIL(26, "immutable0", "immutable1", FLAGS, EPERM) +ATF_TC_RENAME_FAIL(27, "immutable0", "file", FLAGS, EPERM) +ATF_TC_RENAME_FAIL(28, "file", "immutable1", FLAGS, EPERM) +ATF_TC_RENAME_FAIL(29, "append0", "append1", FLAGS, EPERM) +ATF_TC_RENAME_FAIL(30, "append0", "file", FLAGS, EPERM) +ATF_TC_RENAME_FAIL(31, "file", "append1", FLAGS, EPERM) +ATF_TC_RENAME_FAIL(32, "immdir0", "immdir1", DIRS | FLAGS, EPERM) +ATF_TC_RENAME_FAIL(33, "immdir0", "dir", DIRS | FLAGS, EPERM) +ATF_TC_RENAME_FAIL(34, "dir", "immdir1", DIRS | FLAGS, EPERM) +ATF_TC_RENAME_FAIL(35, "file", "immdir1/file", DIRS | FLAGS, EPERM) +ATF_TC_RENAME_FAIL(36, "immdir0/x", "file", DIRS | FLAGS, EPERM) +ATF_TC_RENAME_FAIL(37, "file", "immdir1/x", DIRS | FLAGS, EPERM) +ATF_TC_RENAME_FAIL(38, "appdir0", "appdir1", DIRS | FLAGS, EPERM) +ATF_TC_RENAME_FAIL(39, "appdir0/x", "file", DIRS | FLAGS, EPERM) +ATF_TC_RENAME_FAIL(40, "appdir0/x", "appdir0/file", DIRS | FLAGS, EPERM) +ATF_TC_RENAME_FAIL(41, "nonexistent", "nonexistent", 0, ENOENT) +ATF_TC_RENAME_FAIL(42, "nonexistent", "file", 0, ENOENT) +ATF_TC_RENAME_FAIL(43, "nonexistent", "parent/nonexistent", DIRS, ENOENT) +ATF_TC_RENAME_FAIL(44, "nonexistent", "parent/file", DIRS, ENOENT) +ATF_TC_RENAME_FAIL(45, "nonexistent", "parent/dir/loser", DIRS, ENOENT) +ATF_TC_RENAME_FAIL(46, "nonexistent", "parent/sub/dir/loser", DIRS, ENOENT) +ATF_TC_RENAME_FAIL(47, "parent/nonexistent", "nonexistent", 0, ENOENT) +ATF_TC_RENAME_FAIL(48, "parent/nonexistent", "file", 0, ENOENT) +ATF_TC_RENAME_FAIL(49, "parent/nonexistent", "parent/nonexistent", DIRS, ENOENT) +ATF_TC_RENAME_FAIL(50, "parent/nonexistent", "parent/file", DIRS, ENOENT) +ATF_TC_RENAME_FAIL(51, "parent/nonexistent", "parent/dir/loser", DIRS, ENOENT) +ATF_TC_RENAME_FAIL(52, "parent/nonexistent", "parent/sub/dir/loser", DIRS, ENOENT) + static void checkfile(const char *path, struct stat *refp) { @@ -862,6 +1340,93 @@ ATF_TP_ADD_TCS(tp) ATF_TP_FSAPPLY(dir_simple); ATF_TP_FSAPPLY(dir_notempty); ATF_TP_FSAPPLY(dir_rmdirdotdot); + ATF_TP_RENAME(0); + ATF_TP_RENAME(1); + ATF_TP_RENAME(2); + ATF_TP_RENAME(3); + ATF_TP_RENAME(4); + ATF_TP_RENAME(5); + ATF_TP_RENAME(6); + ATF_TP_RENAME(7); + ATF_TP_RENAME(8); + ATF_TP_RENAME(9); + ATF_TP_RENAME(10); + ATF_TP_RENAME(11); + ATF_TP_RENAME(12); + ATF_TP_RENAME(13); + ATF_TP_RENAME(14); + ATF_TP_RENAME(15); + ATF_TP_RENAME(16); + ATF_TP_RENAME(17); + ATF_TP_RENAME(18); + ATF_TP_RENAME(19); + ATF_TP_RENAME(20); + ATF_TP_RENAME(21); + ATF_TP_RENAME(22); + ATF_TP_RENAME(23); + ATF_TP_RENAME(24); + ATF_TP_RENAME(25); + ATF_TP_RENAME(26); + ATF_TP_RENAME(27); + ATF_TP_RENAME(28); + ATF_TP_RENAME(29); + ATF_TP_RENAME(30); + ATF_TP_RENAME(31); + ATF_TP_RENAME(32); + ATF_TP_RENAME(33); + ATF_TP_RENAME_FAIL(0); + ATF_TP_RENAME_FAIL(1); + ATF_TP_RENAME_FAIL(2); + ATF_TP_RENAME_FAIL(3); + ATF_TP_RENAME_FAIL(4); + ATF_TP_RENAME_FAIL(5); + ATF_TP_RENAME_FAIL(6); + ATF_TP_RENAME_FAIL(7); + ATF_TP_RENAME_FAIL(8); + ATF_TP_RENAME_FAIL(9); + ATF_TP_RENAME_FAIL(10); + ATF_TP_RENAME_FAIL(11); + ATF_TP_RENAME_FAIL(12); + ATF_TP_RENAME_FAIL(13); + ATF_TP_RENAME_FAIL(14); + ATF_TP_RENAME_FAIL(15); + ATF_TP_RENAME_FAIL(16); + ATF_TP_RENAME_FAIL(17); + ATF_TP_RENAME_FAIL(18); + ATF_TP_RENAME_FAIL(19); + ATF_TP_RENAME_FAIL(20); + ATF_TP_RENAME_FAIL(21); + ATF_TP_RENAME_FAIL(22); + ATF_TP_RENAME_FAIL(23); + ATF_TP_RENAME_FAIL(24); + ATF_TP_RENAME_FAIL(25); + ATF_TP_RENAME_FAIL(26); + ATF_TP_RENAME_FAIL(27); + ATF_TP_RENAME_FAIL(28); + ATF_TP_RENAME_FAIL(29); + ATF_TP_RENAME_FAIL(30); + ATF_TP_RENAME_FAIL(31); + ATF_TP_RENAME_FAIL(32); + ATF_TP_RENAME_FAIL(33); + ATF_TP_RENAME_FAIL(34); + ATF_TP_RENAME_FAIL(35); + ATF_TP_RENAME_FAIL(36); + ATF_TP_RENAME_FAIL(37); + ATF_TP_RENAME_FAIL(38); + ATF_TP_RENAME_FAIL(39); + ATF_TP_RENAME_FAIL(40); + ATF_TP_RENAME_FAIL(41); + ATF_TP_RENAME_FAIL(42); + ATF_TP_RENAME_FAIL(43); + ATF_TP_RENAME_FAIL(44); + ATF_TP_RENAME_FAIL(45); + ATF_TP_RENAME_FAIL(46); + ATF_TP_RENAME_FAIL(47); + ATF_TP_RENAME_FAIL(48); + ATF_TP_RENAME_FAIL(49); + ATF_TP_RENAME_FAIL(50); + ATF_TP_RENAME_FAIL(51); + ATF_TP_RENAME_FAIL(52); ATF_TP_FSAPPLY(rename_dir); ATF_TP_FSAPPLY(rename_dotdot); ATF_TP_FSAPPLY(rename_reg_nodir);