Module Name: src Committed By: pooka Date: Wed Jul 14 20:45:49 UTC 2010
Modified Files: src/tests/fs/vfs: t_vnops.c Log Message: Add an assortment of rename tests. Not complete, but at least tests something. This contains the tests for PR kern/43616 and PR kern/43617. To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 src/tests/fs/vfs/t_vnops.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/tests/fs/vfs/t_vnops.c diff -u src/tests/fs/vfs/t_vnops.c:1.1 src/tests/fs/vfs/t_vnops.c:1.2 --- src/tests/fs/vfs/t_vnops.c:1.1 Tue Jul 13 18:13:10 2010 +++ src/tests/fs/vfs/t_vnops.c Wed Jul 14 20:45:48 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: t_vnops.c,v 1.1 2010/07/13 18:13:10 pooka Exp $ */ +/* $NetBSD: t_vnops.c,v 1.2 2010/07/14 20:45:48 pooka Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -48,6 +48,14 @@ #define USES_DIRS \ if (FSTYPE_SYSVBFS(tc)) atf_tc_skip("dirs not supported by file system") +static char * +md(char *buf, const char *base, const char *tail) +{ + + sprintf(buf, "%s/%s", base, tail); + return buf; +} + static void lookup_simple(const atf_tc_t *tc, const char *mountpath) { @@ -139,10 +147,216 @@ atf_tc_fail_errno("remove directory"); } +static void +checkfile(const char *path, struct stat *refp) +{ + char buf[MAXPATHLEN]; + struct stat sb; + static int n = 1; + + md(buf, path, "file"); + if (rump_sys_stat(buf, &sb) == -1) + atf_tc_fail_errno("cannot stat file %d (%s)", n, buf); + if (memcmp(&sb, refp, sizeof(sb)) != 0) + atf_tc_fail("stat mismatch %d", n); + n++; +} + +static void +rename_dir(const atf_tc_t *tc, const char *mp) +{ + char pb1[MAXPATHLEN], pb2[MAXPATHLEN], pb3[MAXPATHLEN]; + struct stat ref; + + USES_DIRS; + + md(pb1, mp, "dir1"); + if (rump_sys_mkdir(pb1, 0777) == -1) + atf_tc_fail_errno("mkdir 1"); + + md(pb2, mp, "dir2"); + if (rump_sys_mkdir(pb2, 0777) == -1) + atf_tc_fail_errno("mkdir 2"); + md(pb2, mp, "dir2/subdir"); + if (rump_sys_mkdir(pb2, 0777) == -1) + atf_tc_fail_errno("mkdir 3"); + + md(pb3, mp, "dir1/file"); + if (rump_sys_mknod(pb3, S_IFREG | 0777, -1) == -1) + atf_tc_fail_errno("create file"); + if (rump_sys_stat(pb3, &ref) == -1) + atf_tc_fail_errno("stat of file"); + + /* + * First try ops which should succeed. + */ + + /* rename within directory */ + md(pb3, mp, "dir3"); + if (rump_sys_rename(pb1, pb3) == -1) + atf_tc_fail_errno("rename 1"); + checkfile(pb3, &ref); + + /* rename directory onto itself (two ways, should fail) */ + md(pb1, mp, "dir3/."); + if (rump_sys_rename(pb1, pb3) != -1 || errno != EINVAL) + atf_tc_fail_errno("rename 2"); + if (rump_sys_rename(pb3, pb1) != -1 || errno != EISDIR) + atf_tc_fail_errno("rename 3"); + + checkfile(pb3, &ref); + + /* rename father of directory into directory */ + md(pb1, mp, "dir2/dir"); + md(pb2, mp, "dir2"); + if (rump_sys_rename(pb2, pb1) != -1 || errno != EINVAL) + atf_tc_fail_errno("rename 4"); + + /* same for grandfather */ + md(pb1, mp, "dir2/subdir/dir2"); + if (rump_sys_rename(pb2, pb1) != -1 || errno != EINVAL) + atf_tc_fail("rename 5"); + + checkfile(pb3, &ref); + + /* rename directory over a non-empty directory */ + if (rump_sys_rename(pb2, pb3) != -1 || errno != ENOTEMPTY) + atf_tc_fail("rename 6"); + + /* cross-directory rename */ + md(pb1, mp, "dir3"); + md(pb2, mp, "dir2/somedir"); + if (rump_sys_rename(pb1, pb2) == -1) + atf_tc_fail_errno("rename 7"); + checkfile(pb2, &ref); + + /* move to parent directory */ + md(pb1, mp, "dir2/somedir/../../dir3"); + if (rump_sys_rename(pb2, pb1) == -1) + atf_tc_fail_errno("rename 8"); + md(pb1, mp, "dir2/../dir3"); + checkfile(pb1, &ref); + + /* finally, atomic cross-directory rename */ + md(pb3, mp, "dir2/subdir"); + if (rump_sys_rename(pb1, pb3) == -1) + atf_tc_fail_errno("rename 9"); + checkfile(pb3, &ref); +} + +static void +rename_dotdot(const atf_tc_t *tc, const char *mp) +{ + + USES_DIRS; + + if (rump_sys_chdir(mp) == -1) + atf_tc_fail_errno("chdir mountpoint"); + + if (rump_sys_mkdir("dir1", 0777) == -1) + atf_tc_fail_errno("mkdir 1"); + if (rump_sys_mkdir("dir2", 0777) == -1) + atf_tc_fail_errno("mkdir 2"); + + /* msdosfs fails both at least currently */ + if (FSTYPE_MSDOS(tc)) { + atf_tc_expect_fail("PR kern/43616"); + } + if (rump_sys_rename("dir1", "dir1/..") != -1 || errno != EINVAL) + atf_tc_fail_errno("self-dotdot to"); + + if (rump_sys_rename("dir1/..", "sometarget") != -1 || errno != EINVAL) + atf_tc_fail_errno("self-dotdot from"); + atf_tc_expect_pass(); + + if (FSTYPE_TMPFS(tc)) { + atf_tc_expect_fail("PR kern/43617"); + } + if (rump_sys_rename("dir1", "dir2/..") != -1 || errno != EINVAL) + atf_tc_fail("other-dotdot"); + + rump_sys_chdir("/"); +} + +static void +rename_reg_nodir(const atf_tc_t *tc, const char *mp) +{ + bool haslinks; + struct stat sb; + ino_t f1ino, f2ino; + + if (rump_sys_chdir(mp) == -1) + atf_tc_fail_errno("chdir mountpoint"); + + if (FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc)) + haslinks = false; + else + haslinks = true; + + if (rump_sys_mknod("file1", S_IFREG | 0777, -1) == -1) + atf_tc_fail_errno("create file"); + if (rump_sys_mknod("file2", S_IFREG | 0777, -1) == -1) + atf_tc_fail_errno("create file"); + + if (rump_sys_stat("file1", &sb) == -1) + atf_tc_fail_errno("stat"); + f1ino = sb.st_ino; + + if (haslinks) { + if (rump_sys_link("file1", "file_link") == -1) + atf_tc_fail_errno("link"); + if (rump_sys_stat("file_link", &sb) == -1) + atf_tc_fail_errno("stat"); + ATF_REQUIRE_EQ(sb.st_ino, f1ino); + ATF_REQUIRE_EQ(sb.st_nlink, 2); + } + + if (rump_sys_stat("file2", &sb) == -1) + atf_tc_fail_errno("stat"); + f2ino = sb.st_ino; + + if (rump_sys_rename("file1", "file3") == -1) + atf_tc_fail_errno("rename 1"); + if (rump_sys_stat("file3", &sb) == -1) + atf_tc_fail_errno("stat 1"); + if (haslinks) { + ATF_REQUIRE_EQ(sb.st_ino, f1ino); + } + if (rump_sys_stat("file1", &sb) != -1 || errno != ENOENT) + atf_tc_fail_errno("source 1"); + + if (rump_sys_rename("file3", "file2") == -1) + atf_tc_fail_errno("rename 2"); + if (rump_sys_stat("file2", &sb) == -1) + atf_tc_fail_errno("stat 2"); + if (haslinks) { + ATF_REQUIRE_EQ(sb.st_ino, f1ino); + } + + if (rump_sys_stat("file3", &sb) != -1 || errno != ENOENT) + atf_tc_fail_errno("source 2"); + + if (haslinks) { + if (rump_sys_rename("file2", "file_link") == -1) + atf_tc_fail_errno("rename hardlink"); + if (rump_sys_stat("file2", &sb) != -1 || errno != ENOENT) + atf_tc_fail_errno("source 3"); + if (rump_sys_stat("file_link", &sb) == -1) + atf_tc_fail_errno("stat 2"); + ATF_REQUIRE_EQ(sb.st_ino, f1ino); + ATF_REQUIRE_EQ(sb.st_nlink, 1); + } + + rump_sys_chdir("/"); +} + ATF_TC_FSAPPLY(lookup_simple, "simple lookup (./.. on root)"); ATF_TC_FSAPPLY(lookup_complex, "lookup of non-dot entries"); ATF_TC_FSAPPLY(dir_simple, "mkdir/rmdir"); ATF_TC_FSAPPLY(dir_notempty, "non-empty directories cannot be removed"); +ATF_TC_FSAPPLY(rename_dir, "exercise various directory renaming ops"); +ATF_TC_FSAPPLY(rename_dotdot, "rename dir .."); +ATF_TC_FSAPPLY(rename_reg_nodir, "rename regular files, no subdirectories"); ATF_TP_ADD_TCS(tp) { @@ -151,6 +365,9 @@ ATF_TP_FSAPPLY(lookup_complex); ATF_TP_FSAPPLY(dir_simple); ATF_TP_FSAPPLY(dir_notempty); + ATF_TP_FSAPPLY(rename_dir); + ATF_TP_FSAPPLY(rename_dotdot); + ATF_TP_FSAPPLY(rename_reg_nodir); return atf_no_error(); }