1*e171cef6Sandvar /* $NetBSD: t_vnops.c,v 1.63 2023/05/08 19:23:45 andvar Exp $ */
22a5fd96fSpooka
32a5fd96fSpooka /*-
42a5fd96fSpooka * Copyright (c) 2010 The NetBSD Foundation, Inc.
52a5fd96fSpooka * All rights reserved.
62a5fd96fSpooka *
72a5fd96fSpooka * Redistribution and use in source and binary forms, with or without
82a5fd96fSpooka * modification, are permitted provided that the following conditions
92a5fd96fSpooka * are met:
102a5fd96fSpooka * 1. Redistributions of source code must retain the above copyright
112a5fd96fSpooka * notice, this list of conditions and the following disclaimer.
122a5fd96fSpooka * 2. Redistributions in binary form must reproduce the above copyright
132a5fd96fSpooka * notice, this list of conditions and the following disclaimer in the
142a5fd96fSpooka * documentation and/or other materials provided with the distribution.
152a5fd96fSpooka *
162a5fd96fSpooka * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
172a5fd96fSpooka * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
182a5fd96fSpooka * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
192a5fd96fSpooka * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
202a5fd96fSpooka * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
212a5fd96fSpooka * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
222a5fd96fSpooka * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
232a5fd96fSpooka * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
242a5fd96fSpooka * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
252a5fd96fSpooka * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
262a5fd96fSpooka * POSSIBILITY OF SUCH DAMAGE.
272a5fd96fSpooka */
282a5fd96fSpooka
292a5fd96fSpooka #include <sys/stat.h>
302a5fd96fSpooka #include <sys/statvfs.h>
317760e6f9Skre #include <sys/time.h>
322a5fd96fSpooka
33e8bcfa54Spooka #include <assert.h>
342a5fd96fSpooka #include <atf-c.h>
3579350377Sgson #include <ctype.h>
362a5fd96fSpooka #include <fcntl.h>
372a5fd96fSpooka #include <libgen.h>
38dccf0d48Snjoly #include <stdlib.h>
39e8bcfa54Spooka #include <string.h>
402a5fd96fSpooka #include <unistd.h>
412a5fd96fSpooka
422a5fd96fSpooka #include <rump/rump_syscalls.h>
432a5fd96fSpooka #include <rump/rump.h>
442a5fd96fSpooka
452a5fd96fSpooka #include "../common/h_fsmacros.h"
46c54cb811Schristos #include "h_macros.h"
472a5fd96fSpooka
4845bfa2deSpooka #define TESTFILE "afile"
4945bfa2deSpooka
502a5fd96fSpooka #define USES_DIRS \
517557af29Snjoly if (FSTYPE_SYSVBFS(tc)) \
527557af29Snjoly atf_tc_skip("directories not supported by file system")
532a5fd96fSpooka
54b28267edSpooka #define USES_SYMLINKS \
55b28267edSpooka if (FSTYPE_SYSVBFS(tc) || FSTYPE_MSDOS(tc)) \
567601b30dSnjoly atf_tc_skip("symlinks not supported by file system")
57b28267edSpooka
58ae0b9cceSpooka static char *
md(char * buf,size_t buflen,const char * base,const char * tail)590ca6f6b2Schristos md(char *buf, size_t buflen, const char *base, const char *tail)
60ae0b9cceSpooka {
61ae0b9cceSpooka
620ca6f6b2Schristos snprintf(buf, buflen, "%s/%s", base, tail);
63ae0b9cceSpooka return buf;
64ae0b9cceSpooka }
65ae0b9cceSpooka
662a5fd96fSpooka static void
lookup_simple(const atf_tc_t * tc,const char * mountpath)672a5fd96fSpooka lookup_simple(const atf_tc_t *tc, const char *mountpath)
682a5fd96fSpooka {
692a5fd96fSpooka char pb[MAXPATHLEN], final[MAXPATHLEN];
702a5fd96fSpooka struct stat sb1, sb2;
712a5fd96fSpooka
722a5fd96fSpooka strcpy(final, mountpath);
730ca6f6b2Schristos snprintf(pb, sizeof(pb), "%s/../%s", mountpath, basename(final));
742a5fd96fSpooka if (rump_sys_stat(pb, &sb1) == -1)
752a5fd96fSpooka atf_tc_fail_errno("stat 1");
762a5fd96fSpooka
770ca6f6b2Schristos snprintf(pb, sizeof(pb), "%s/./../%s", mountpath, basename(final));
782a5fd96fSpooka if (rump_sys_stat(pb, &sb2) == -1)
792a5fd96fSpooka atf_tc_fail_errno("stat 2");
802a5fd96fSpooka
812a5fd96fSpooka ATF_REQUIRE(memcmp(&sb1, &sb2, sizeof(sb1)) == 0);
822a5fd96fSpooka }
832a5fd96fSpooka
842a5fd96fSpooka static void
lookup_complex(const atf_tc_t * tc,const char * mountpath)852a5fd96fSpooka lookup_complex(const atf_tc_t *tc, const char *mountpath)
862a5fd96fSpooka {
872a5fd96fSpooka char pb[MAXPATHLEN];
882a5fd96fSpooka struct stat sb1, sb2;
897760e6f9Skre struct timespec atplus1, onesec;
902a5fd96fSpooka
912a5fd96fSpooka USES_DIRS;
922a5fd96fSpooka
930ca6f6b2Schristos snprintf(pb, sizeof(pb), "%s/dir", mountpath);
942a5fd96fSpooka if (rump_sys_mkdir(pb, 0777) == -1)
952a5fd96fSpooka atf_tc_fail_errno("mkdir");
962a5fd96fSpooka if (rump_sys_stat(pb, &sb1) == -1)
972a5fd96fSpooka atf_tc_fail_errno("stat 1");
982a5fd96fSpooka
990ca6f6b2Schristos snprintf(pb, sizeof(pb), "%s/./dir/../././dir/.", mountpath);
1002a5fd96fSpooka if (rump_sys_stat(pb, &sb2) == -1)
1012a5fd96fSpooka atf_tc_fail_errno("stat 2");
1022a5fd96fSpooka
1037760e6f9Skre /*
1047760e6f9Skre * The lookup is permitted to modify the access time of
1057760e6f9Skre * any directories searched - such a directory is the
1067760e6f9Skre * subject of this test. Any difference should cause
107*e171cef6Sandvar * the 2nd lookup atime to be >= the first, if it is ==, all is
1087760e6f9Skre * OK (atime is not required to be modified by the search, or
109*e171cef6Sandvar * both references may happen within the same clock tick), if the
1107760e6f9Skre * 2nd lookup atime is > the first, but not "too much" greater,
1117760e6f9Skre * just set it back, so the memcmp just below succeeds
1127760e6f9Skre * (assuming all else is OK).
1137760e6f9Skre */
1147760e6f9Skre onesec.tv_sec = 1;
1157760e6f9Skre onesec.tv_nsec = 0;
1167760e6f9Skre timespecadd(&sb1.st_atimespec, &onesec, &atplus1);
1177760e6f9Skre if (timespeccmp(&sb2.st_atimespec, &sb1.st_atimespec, >) &&
1187760e6f9Skre timespeccmp(&sb2.st_atimespec, &atplus1, <))
1197760e6f9Skre sb2.st_atimespec = sb1.st_atimespec;
1207760e6f9Skre
121dbd2e87eSmartin if (memcmp(&sb1, &sb2, sizeof(sb1)) != 0) {
122dbd2e87eSmartin printf("what\tsb1\t\tsb2\n");
123dbd2e87eSmartin
124dbd2e87eSmartin #define FIELD(FN) \
125dbd2e87eSmartin printf(#FN "\t%lld\t%lld\n", \
126dbd2e87eSmartin (long long)sb1.FN, (long long)sb2.FN)
127dbd2e87eSmartin #define TIME(FN) \
128dbd2e87eSmartin printf(#FN "\t%lld.%ld\t%lld.%ld\n", \
129dbd2e87eSmartin (long long)sb1.FN.tv_sec, sb1.FN.tv_nsec, \
130dbd2e87eSmartin (long long)sb2.FN.tv_sec, sb2.FN.tv_nsec)
131dbd2e87eSmartin
132dbd2e87eSmartin FIELD(st_dev);
133dbd2e87eSmartin FIELD(st_mode);
134dbd2e87eSmartin FIELD(st_ino);
135dbd2e87eSmartin FIELD(st_nlink);
136dbd2e87eSmartin FIELD(st_uid);
137dbd2e87eSmartin FIELD(st_gid);
138dbd2e87eSmartin FIELD(st_rdev);
1398c0065dbSriastradh TIME(st_atimespec);
1408c0065dbSriastradh TIME(st_mtimespec);
1418c0065dbSriastradh TIME(st_ctimespec);
1428c0065dbSriastradh TIME(st_birthtimespec);
143dbd2e87eSmartin FIELD(st_size);
144dbd2e87eSmartin FIELD(st_blocks);
145dbd2e87eSmartin FIELD(st_flags);
146dbd2e87eSmartin FIELD(st_gen);
147dbd2e87eSmartin
148dbd2e87eSmartin #undef FIELD
149dbd2e87eSmartin #undef TIME
150dbd2e87eSmartin
15160f3bf6aSandvar atf_tc_fail("stat results differ, see output for more details");
152dbd2e87eSmartin }
1532a5fd96fSpooka }
1542a5fd96fSpooka
1552a5fd96fSpooka static void
dir_simple(const atf_tc_t * tc,const char * mountpath)1562a5fd96fSpooka dir_simple(const atf_tc_t *tc, const char *mountpath)
1572a5fd96fSpooka {
1582a5fd96fSpooka char pb[MAXPATHLEN];
1592a5fd96fSpooka struct stat sb;
1602a5fd96fSpooka
1612a5fd96fSpooka USES_DIRS;
1622a5fd96fSpooka
1632a5fd96fSpooka /* check we can create directories */
1640ca6f6b2Schristos snprintf(pb, sizeof(pb), "%s/dir", mountpath);
1652a5fd96fSpooka if (rump_sys_mkdir(pb, 0777) == -1)
1662a5fd96fSpooka atf_tc_fail_errno("mkdir");
1672a5fd96fSpooka if (rump_sys_stat(pb, &sb) == -1)
1682a5fd96fSpooka atf_tc_fail_errno("stat new directory");
1692a5fd96fSpooka
170*e171cef6Sandvar /* check we can remove them and that it makes them unreachable */
1712a5fd96fSpooka if (rump_sys_rmdir(pb) == -1)
1722a5fd96fSpooka atf_tc_fail_errno("rmdir");
1732a5fd96fSpooka if (rump_sys_stat(pb, &sb) != -1 || errno != ENOENT)
1742a5fd96fSpooka atf_tc_fail("ENOENT expected from stat");
1752a5fd96fSpooka }
1762a5fd96fSpooka
1772a5fd96fSpooka static void
do_dir_slash(const atf_tc_t * tc,const char * mountpath,const char * addend)1780df09db4Smartin do_dir_slash(const atf_tc_t *tc, const char *mountpath, const char *addend)
1790df09db4Smartin {
1800df09db4Smartin char plain[MAXPATHLEN], with_slash[MAXPATHLEN];
1810df09db4Smartin struct stat sb;
1820df09db4Smartin
1830df09db4Smartin USES_DIRS;
1840df09db4Smartin
1850df09db4Smartin /* check we can create directories with one or more / appended */
1860df09db4Smartin snprintf(plain, sizeof(plain), "%s/dir%s", mountpath, addend);
1870df09db4Smartin snprintf(with_slash, sizeof(with_slash), "%s/dir/", mountpath);
1880df09db4Smartin if (rump_sys_mkdir(with_slash, 0777) == -1)
1890df09db4Smartin atf_tc_fail_errno("mkdir");
1900df09db4Smartin if (rump_sys_stat(plain, &sb) == -1)
1910df09db4Smartin atf_tc_fail_errno("stat new directory");
1920df09db4Smartin if (rump_sys_rmdir(plain) == -1)
1930df09db4Smartin atf_tc_fail_errno("rmdir");
1940df09db4Smartin if (rump_sys_stat(with_slash, &sb) != -1 || errno != ENOENT)
1950df09db4Smartin atf_tc_fail("ENOENT expected from stat");
1960df09db4Smartin }
1970df09db4Smartin
1980df09db4Smartin static void
dir_slash(const atf_tc_t * tc,const char * mountpath)1990df09db4Smartin dir_slash(const atf_tc_t *tc, const char *mountpath)
2000df09db4Smartin {
2010df09db4Smartin do_dir_slash(tc, mountpath, "/");
2020df09db4Smartin }
2030df09db4Smartin
2040df09db4Smartin static void
dir_2slash(const atf_tc_t * tc,const char * mountpath)2050df09db4Smartin dir_2slash(const atf_tc_t *tc, const char *mountpath)
2060df09db4Smartin {
2070df09db4Smartin do_dir_slash(tc, mountpath, "//");
2080df09db4Smartin }
2090df09db4Smartin
2100df09db4Smartin static void
dir_3slash(const atf_tc_t * tc,const char * mountpath)2110df09db4Smartin dir_3slash(const atf_tc_t *tc, const char *mountpath)
2120df09db4Smartin {
2130df09db4Smartin do_dir_slash(tc, mountpath, "///");
2140df09db4Smartin }
2150df09db4Smartin
2160df09db4Smartin static void
dir_notempty(const atf_tc_t * tc,const char * mountpath)2172a5fd96fSpooka dir_notempty(const atf_tc_t *tc, const char *mountpath)
2182a5fd96fSpooka {
2192a5fd96fSpooka char pb[MAXPATHLEN], pb2[MAXPATHLEN];
2202a5fd96fSpooka int fd, rv;
2212a5fd96fSpooka
2222a5fd96fSpooka USES_DIRS;
2232a5fd96fSpooka
2242a5fd96fSpooka /* check we can create directories */
2250ca6f6b2Schristos snprintf(pb, sizeof(pb), "%s/dir", mountpath);
2262a5fd96fSpooka if (rump_sys_mkdir(pb, 0777) == -1)
2272a5fd96fSpooka atf_tc_fail_errno("mkdir");
2282a5fd96fSpooka
2290ca6f6b2Schristos snprintf(pb2, sizeof(pb2), "%s/dir/file", mountpath);
2302a5fd96fSpooka fd = rump_sys_open(pb2, O_RDWR | O_CREAT, 0777);
2312a5fd96fSpooka if (fd == -1)
2322a5fd96fSpooka atf_tc_fail_errno("create file");
2332a5fd96fSpooka rump_sys_close(fd);
2342a5fd96fSpooka
2352a5fd96fSpooka rv = rump_sys_rmdir(pb);
2362a5fd96fSpooka if (rv != -1 || errno != ENOTEMPTY)
23772e44f84Sandvar atf_tc_fail("non-empty directory removed successfully");
2382a5fd96fSpooka
2392a5fd96fSpooka if (rump_sys_unlink(pb2) == -1)
2402a5fd96fSpooka atf_tc_fail_errno("cannot remove dir/file");
2412a5fd96fSpooka
2422a5fd96fSpooka if (rump_sys_rmdir(pb) == -1)
2432a5fd96fSpooka atf_tc_fail_errno("remove directory");
2442a5fd96fSpooka }
2452a5fd96fSpooka
246ae0b9cceSpooka static void
dir_rmdirdotdot(const atf_tc_t * tc,const char * mp)247878d41e6Spooka dir_rmdirdotdot(const atf_tc_t *tc, const char *mp)
248878d41e6Spooka {
249878d41e6Spooka char pb[MAXPATHLEN];
250878d41e6Spooka int xerrno;
251878d41e6Spooka
252878d41e6Spooka USES_DIRS;
253878d41e6Spooka
254878d41e6Spooka FSTEST_ENTER();
255878d41e6Spooka RL(rump_sys_mkdir("test", 0777));
256878d41e6Spooka RL(rump_sys_chdir("test"));
257878d41e6Spooka
258878d41e6Spooka RL(rump_sys_mkdir("subtest", 0777));
259878d41e6Spooka RL(rump_sys_chdir("subtest"));
260878d41e6Spooka
2610ca6f6b2Schristos md(pb, sizeof(pb), mp, "test/subtest");
262878d41e6Spooka RL(rump_sys_rmdir(pb));
2630ca6f6b2Schristos md(pb, sizeof(pb), mp, "test");
264878d41e6Spooka RL(rump_sys_rmdir(pb));
265878d41e6Spooka
266878d41e6Spooka if (FSTYPE_NFS(tc))
267878d41e6Spooka xerrno = ESTALE;
268878d41e6Spooka else
269878d41e6Spooka xerrno = ENOENT;
270878d41e6Spooka ATF_REQUIRE_ERRNO(xerrno, rump_sys_chdir("..") == -1);
271878d41e6Spooka FSTEST_EXIT();
272878d41e6Spooka }
273878d41e6Spooka
274878d41e6Spooka static void
checkfile(const char * path,struct stat * refp)275ae0b9cceSpooka checkfile(const char *path, struct stat *refp)
276ae0b9cceSpooka {
277ae0b9cceSpooka char buf[MAXPATHLEN];
278ae0b9cceSpooka struct stat sb;
279ae0b9cceSpooka static int n = 1;
280ae0b9cceSpooka
2810ca6f6b2Schristos md(buf, sizeof(buf), path, "file");
282ae0b9cceSpooka if (rump_sys_stat(buf, &sb) == -1)
283ae0b9cceSpooka atf_tc_fail_errno("cannot stat file %d (%s)", n, buf);
284ae0b9cceSpooka if (memcmp(&sb, refp, sizeof(sb)) != 0)
285ae0b9cceSpooka atf_tc_fail("stat mismatch %d", n);
286ae0b9cceSpooka n++;
287ae0b9cceSpooka }
288ae0b9cceSpooka
289ae0b9cceSpooka static void
rename_dir(const atf_tc_t * tc,const char * mp)290ae0b9cceSpooka rename_dir(const atf_tc_t *tc, const char *mp)
291ae0b9cceSpooka {
292ae0b9cceSpooka char pb1[MAXPATHLEN], pb2[MAXPATHLEN], pb3[MAXPATHLEN];
2931157445bSpooka struct stat ref, sb;
294ae0b9cceSpooka
29588b6bdf1Spooka if (FSTYPE_RUMPFS(tc))
2967557af29Snjoly atf_tc_skip("rename not supported by file system");
29788b6bdf1Spooka
298ae0b9cceSpooka USES_DIRS;
299ae0b9cceSpooka
3000ca6f6b2Schristos md(pb1, sizeof(pb1), mp, "dir1");
301ae0b9cceSpooka if (rump_sys_mkdir(pb1, 0777) == -1)
302ae0b9cceSpooka atf_tc_fail_errno("mkdir 1");
303ae0b9cceSpooka
3040ca6f6b2Schristos md(pb2, sizeof(pb2), mp, "dir2");
305ae0b9cceSpooka if (rump_sys_mkdir(pb2, 0777) == -1)
306ae0b9cceSpooka atf_tc_fail_errno("mkdir 2");
3070ca6f6b2Schristos md(pb2, sizeof(pb2), mp, "dir2/subdir");
308ae0b9cceSpooka if (rump_sys_mkdir(pb2, 0777) == -1)
309ae0b9cceSpooka atf_tc_fail_errno("mkdir 3");
310ae0b9cceSpooka
3110ca6f6b2Schristos md(pb3, sizeof(pb3), mp, "dir1/file");
312ae0b9cceSpooka if (rump_sys_mknod(pb3, S_IFREG | 0777, -1) == -1)
313ae0b9cceSpooka atf_tc_fail_errno("create file");
314ae0b9cceSpooka if (rump_sys_stat(pb3, &ref) == -1)
315ae0b9cceSpooka atf_tc_fail_errno("stat of file");
316ae0b9cceSpooka
317ae0b9cceSpooka /*
318ae0b9cceSpooka * First try ops which should succeed.
319ae0b9cceSpooka */
320ae0b9cceSpooka
321ae0b9cceSpooka /* rename within directory */
3220ca6f6b2Schristos md(pb3, sizeof(pb3), mp, "dir3");
323ae0b9cceSpooka if (rump_sys_rename(pb1, pb3) == -1)
324ae0b9cceSpooka atf_tc_fail_errno("rename 1");
325ae0b9cceSpooka checkfile(pb3, &ref);
326ae0b9cceSpooka
327ae0b9cceSpooka /* rename directory onto itself (two ways, should fail) */
3280ca6f6b2Schristos md(pb1, sizeof(pb1), mp, "dir3/.");
329ae0b9cceSpooka if (rump_sys_rename(pb1, pb3) != -1 || errno != EINVAL)
330ae0b9cceSpooka atf_tc_fail_errno("rename 2");
331ae0b9cceSpooka if (rump_sys_rename(pb3, pb1) != -1 || errno != EISDIR)
332ae0b9cceSpooka atf_tc_fail_errno("rename 3");
333ae0b9cceSpooka
334ae0b9cceSpooka checkfile(pb3, &ref);
335ae0b9cceSpooka
336ae0b9cceSpooka /* rename father of directory into directory */
3370ca6f6b2Schristos md(pb1, sizeof(pb1), mp, "dir2/dir");
3380ca6f6b2Schristos md(pb2, sizeof(pb2), mp, "dir2");
339ae0b9cceSpooka if (rump_sys_rename(pb2, pb1) != -1 || errno != EINVAL)
340ae0b9cceSpooka atf_tc_fail_errno("rename 4");
341ae0b9cceSpooka
342ae0b9cceSpooka /* same for grandfather */
3430ca6f6b2Schristos md(pb1, sizeof(pb1), mp, "dir2/subdir/dir2");
344ae0b9cceSpooka if (rump_sys_rename(pb2, pb1) != -1 || errno != EINVAL)
345ae0b9cceSpooka atf_tc_fail("rename 5");
346ae0b9cceSpooka
347ae0b9cceSpooka checkfile(pb3, &ref);
348ae0b9cceSpooka
349ae0b9cceSpooka /* rename directory over a non-empty directory */
350ae0b9cceSpooka if (rump_sys_rename(pb2, pb3) != -1 || errno != ENOTEMPTY)
351ae0b9cceSpooka atf_tc_fail("rename 6");
352ae0b9cceSpooka
353ae0b9cceSpooka /* cross-directory rename */
3540ca6f6b2Schristos md(pb1, sizeof(pb1), mp, "dir3");
3550ca6f6b2Schristos md(pb2, sizeof(pb2), mp, "dir2/somedir");
356ae0b9cceSpooka if (rump_sys_rename(pb1, pb2) == -1)
357ae0b9cceSpooka atf_tc_fail_errno("rename 7");
358ae0b9cceSpooka checkfile(pb2, &ref);
359ae0b9cceSpooka
360ae0b9cceSpooka /* move to parent directory */
3610ca6f6b2Schristos md(pb1, sizeof(pb1), mp, "dir2/somedir/../../dir3");
362ae0b9cceSpooka if (rump_sys_rename(pb2, pb1) == -1)
363ae0b9cceSpooka atf_tc_fail_errno("rename 8");
3640ca6f6b2Schristos md(pb1, sizeof(pb1), mp, "dir2/../dir3");
365ae0b9cceSpooka checkfile(pb1, &ref);
366ae0b9cceSpooka
3671157445bSpooka /* atomic cross-directory rename */
3680ca6f6b2Schristos md(pb3, sizeof(pb3), mp, "dir2/subdir");
369ae0b9cceSpooka if (rump_sys_rename(pb1, pb3) == -1)
370ae0b9cceSpooka atf_tc_fail_errno("rename 9");
371ae0b9cceSpooka checkfile(pb3, &ref);
3721157445bSpooka
3731157445bSpooka /* rename directory over an empty directory */
3740ca6f6b2Schristos md(pb1, sizeof(pb1), mp, "parent");
3750ca6f6b2Schristos md(pb2, sizeof(pb2), mp, "parent/dir1");
3760ca6f6b2Schristos md(pb3, sizeof(pb3), mp, "parent/dir2");
3771157445bSpooka RL(rump_sys_mkdir(pb1, 0777));
3781157445bSpooka RL(rump_sys_mkdir(pb2, 0777));
3791157445bSpooka RL(rump_sys_mkdir(pb3, 0777));
3801157445bSpooka RL(rump_sys_rename(pb2, pb3));
3811157445bSpooka
3821157445bSpooka RL(rump_sys_stat(pb1, &sb));
383d8c44cecShannken if (! FSTYPE_MSDOS(tc))
3841157445bSpooka ATF_CHECK_EQ(sb.st_nlink, 3);
3851157445bSpooka RL(rump_sys_rmdir(pb3));
3861157445bSpooka RL(rump_sys_rmdir(pb1));
387ae0b9cceSpooka }
388ae0b9cceSpooka
389ae0b9cceSpooka static void
rename_dotdot(const atf_tc_t * tc,const char * mp)390ae0b9cceSpooka rename_dotdot(const atf_tc_t *tc, const char *mp)
391ae0b9cceSpooka {
392ae0b9cceSpooka
39388b6bdf1Spooka if (FSTYPE_RUMPFS(tc))
3947557af29Snjoly atf_tc_skip("rename not supported by file system");
39588b6bdf1Spooka
396ae0b9cceSpooka USES_DIRS;
397ae0b9cceSpooka
398ae0b9cceSpooka if (rump_sys_chdir(mp) == -1)
399ae0b9cceSpooka atf_tc_fail_errno("chdir mountpoint");
400ae0b9cceSpooka
401ae0b9cceSpooka if (rump_sys_mkdir("dir1", 0777) == -1)
402ae0b9cceSpooka atf_tc_fail_errno("mkdir 1");
403ae0b9cceSpooka if (rump_sys_mkdir("dir2", 0777) == -1)
404ae0b9cceSpooka atf_tc_fail_errno("mkdir 2");
405ae0b9cceSpooka
406ae0b9cceSpooka if (rump_sys_rename("dir1", "dir1/..") != -1 || errno != EINVAL)
407ae0b9cceSpooka atf_tc_fail_errno("self-dotdot to");
408ae0b9cceSpooka
409ae0b9cceSpooka if (rump_sys_rename("dir1/..", "sometarget") != -1 || errno != EINVAL)
410ae0b9cceSpooka atf_tc_fail_errno("self-dotdot from");
411ae0b9cceSpooka
412ae0b9cceSpooka if (rump_sys_rename("dir1", "dir2/..") != -1 || errno != EINVAL)
413ae0b9cceSpooka atf_tc_fail("other-dotdot");
414ae0b9cceSpooka
415ae0b9cceSpooka rump_sys_chdir("/");
416ae0b9cceSpooka }
417ae0b9cceSpooka
418ae0b9cceSpooka static void
rename_reg_nodir(const atf_tc_t * tc,const char * mp)419ae0b9cceSpooka rename_reg_nodir(const atf_tc_t *tc, const char *mp)
420ae0b9cceSpooka {
421ae0b9cceSpooka bool haslinks;
422ae0b9cceSpooka struct stat sb;
423d56fcfc9Schristos ino_t f1ino;
424ae0b9cceSpooka
42588b6bdf1Spooka if (FSTYPE_RUMPFS(tc))
4267557af29Snjoly atf_tc_skip("rename not supported by file system");
42788b6bdf1Spooka
428ae0b9cceSpooka if (rump_sys_chdir(mp) == -1)
429ae0b9cceSpooka atf_tc_fail_errno("chdir mountpoint");
430ae0b9cceSpooka
431ae0b9cceSpooka if (FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))
432ae0b9cceSpooka haslinks = false;
433ae0b9cceSpooka else
434ae0b9cceSpooka haslinks = true;
435ae0b9cceSpooka
436ae0b9cceSpooka if (rump_sys_mknod("file1", S_IFREG | 0777, -1) == -1)
437ae0b9cceSpooka atf_tc_fail_errno("create file");
438ae0b9cceSpooka if (rump_sys_mknod("file2", S_IFREG | 0777, -1) == -1)
439ae0b9cceSpooka atf_tc_fail_errno("create file");
440ae0b9cceSpooka
441ae0b9cceSpooka if (rump_sys_stat("file1", &sb) == -1)
442ae0b9cceSpooka atf_tc_fail_errno("stat");
443ae0b9cceSpooka f1ino = sb.st_ino;
444ae0b9cceSpooka
445ae0b9cceSpooka if (haslinks) {
446ae0b9cceSpooka if (rump_sys_link("file1", "file_link") == -1)
447ae0b9cceSpooka atf_tc_fail_errno("link");
448ae0b9cceSpooka if (rump_sys_stat("file_link", &sb) == -1)
449ae0b9cceSpooka atf_tc_fail_errno("stat");
450ae0b9cceSpooka ATF_REQUIRE_EQ(sb.st_ino, f1ino);
451ae0b9cceSpooka ATF_REQUIRE_EQ(sb.st_nlink, 2);
452ae0b9cceSpooka }
453ae0b9cceSpooka
454ae0b9cceSpooka if (rump_sys_stat("file2", &sb) == -1)
455ae0b9cceSpooka atf_tc_fail_errno("stat");
456ae0b9cceSpooka
457ae0b9cceSpooka if (rump_sys_rename("file1", "file3") == -1)
458ae0b9cceSpooka atf_tc_fail_errno("rename 1");
459ae0b9cceSpooka if (rump_sys_stat("file3", &sb) == -1)
460ae0b9cceSpooka atf_tc_fail_errno("stat 1");
461ae0b9cceSpooka if (haslinks) {
462ae0b9cceSpooka ATF_REQUIRE_EQ(sb.st_ino, f1ino);
463ae0b9cceSpooka }
464ae0b9cceSpooka if (rump_sys_stat("file1", &sb) != -1 || errno != ENOENT)
465ae0b9cceSpooka atf_tc_fail_errno("source 1");
466ae0b9cceSpooka
467ae0b9cceSpooka if (rump_sys_rename("file3", "file2") == -1)
468ae0b9cceSpooka atf_tc_fail_errno("rename 2");
469ae0b9cceSpooka if (rump_sys_stat("file2", &sb) == -1)
470ae0b9cceSpooka atf_tc_fail_errno("stat 2");
471ae0b9cceSpooka if (haslinks) {
472ae0b9cceSpooka ATF_REQUIRE_EQ(sb.st_ino, f1ino);
473ae0b9cceSpooka }
474ae0b9cceSpooka
475ae0b9cceSpooka if (rump_sys_stat("file3", &sb) != -1 || errno != ENOENT)
476ae0b9cceSpooka atf_tc_fail_errno("source 2");
477ae0b9cceSpooka
478ae0b9cceSpooka if (haslinks) {
479ae0b9cceSpooka if (rump_sys_rename("file2", "file_link") == -1)
480ae0b9cceSpooka atf_tc_fail_errno("rename hardlink");
481ae0b9cceSpooka if (rump_sys_stat("file2", &sb) != -1 || errno != ENOENT)
482ae0b9cceSpooka atf_tc_fail_errno("source 3");
483ae0b9cceSpooka if (rump_sys_stat("file_link", &sb) == -1)
484ae0b9cceSpooka atf_tc_fail_errno("stat 2");
485ae0b9cceSpooka ATF_REQUIRE_EQ(sb.st_ino, f1ino);
486ae0b9cceSpooka ATF_REQUIRE_EQ(sb.st_nlink, 1);
487ae0b9cceSpooka }
488ae0b9cceSpooka
4891fe37e8eSnjoly ATF_CHECK_ERRNO(EFAULT, rump_sys_rename("file2", NULL) == -1);
4901fe37e8eSnjoly ATF_CHECK_ERRNO(EFAULT, rump_sys_rename(NULL, "file2") == -1);
4911fe37e8eSnjoly
492ae0b9cceSpooka rump_sys_chdir("/");
493ae0b9cceSpooka }
494ae0b9cceSpooka
4958b742e7aSpooka /* PR kern/50607 */
496dccf0d48Snjoly static void
create_many(const atf_tc_t * tc,const char * mp)497596d7c22Spooka create_many(const atf_tc_t *tc, const char *mp)
498596d7c22Spooka {
499596d7c22Spooka char buf[64];
500596d7c22Spooka int nfiles = 2324; /* #Nancy */
501596d7c22Spooka int i;
502596d7c22Spooka
503596d7c22Spooka /* takes forever with many files */
504596d7c22Spooka if (FSTYPE_MSDOS(tc))
505596d7c22Spooka nfiles /= 4;
506596d7c22Spooka
507596d7c22Spooka RL(rump_sys_chdir(mp));
508596d7c22Spooka
509419929efSpooka if (FSTYPE_SYSVBFS(tc)) {
510419929efSpooka /* fs doesn't support many files or subdirectories */
511419929efSpooka nfiles = 5;
512419929efSpooka } else {
513596d7c22Spooka /* msdosfs doesn't like many entries in the root directory */
514596d7c22Spooka RL(rump_sys_mkdir("subdir", 0777));
515596d7c22Spooka RL(rump_sys_chdir("subdir"));
516419929efSpooka }
517596d7c22Spooka
518596d7c22Spooka /* create them */
51910c4a4e0Spooka #define TESTFN "testfile"
520596d7c22Spooka for (i = 0; i < nfiles; i++) {
521596d7c22Spooka int fd;
522596d7c22Spooka
5230ca6f6b2Schristos snprintf(buf, sizeof(buf), TESTFN "%d", i);
524596d7c22Spooka RL(fd = rump_sys_open(buf, O_RDWR|O_CREAT|O_EXCL, 0666));
525596d7c22Spooka RL(rump_sys_close(fd));
526596d7c22Spooka }
527596d7c22Spooka
528596d7c22Spooka /* wipe them out */
529596d7c22Spooka for (i = 0; i < nfiles; i++) {
5300ca6f6b2Schristos snprintf(buf, sizeof(buf), TESTFN "%d", i);
5310ca6f6b2Schristos RLF(rump_sys_unlink(buf), "%s", buf);
532596d7c22Spooka }
533596d7c22Spooka #undef TESTFN
534596d7c22Spooka
535596d7c22Spooka rump_sys_chdir("/");
536596d7c22Spooka }
537596d7c22Spooka
53879350377Sgson /*
53979350377Sgson * Test creating files with one-character names using all possible
54079350377Sgson * character values. Failures to create the file are ignored as the
54179350377Sgson * characters allowed in file names vary by file system, but at least
54279350377Sgson * we can check that the fs does not crash, and if the file is
54379350377Sgson * successfully created, unlinking it should also succeed.
54479350377Sgson */
54579350377Sgson static void
create_nonalphanum(const atf_tc_t * tc,const char * mp)54679350377Sgson create_nonalphanum(const atf_tc_t *tc, const char *mp)
54779350377Sgson {
54879350377Sgson char buf[64];
54979350377Sgson int i;
55079350377Sgson
55179350377Sgson RL(rump_sys_chdir(mp));
55279350377Sgson
55379350377Sgson for (i = 0; i < 256; i++) {
55479350377Sgson int fd;
5550ca6f6b2Schristos snprintf(buf, sizeof(buf), "%c", i);
55679350377Sgson fd = rump_sys_open(buf, O_RDWR|O_CREAT|O_EXCL, 0666);
55779350377Sgson if (fd == -1)
55879350377Sgson continue;
5590ca6f6b2Schristos RLF(rump_sys_close(fd), "%d", fd);
5600ca6f6b2Schristos RLF(rump_sys_unlink(buf), "%s", buf);
56179350377Sgson }
56279350377Sgson printf("\n");
56379350377Sgson
56479350377Sgson rump_sys_chdir("/");
56579350377Sgson }
56679350377Sgson
567596d7c22Spooka static void
create_nametoolong(const atf_tc_t * tc,const char * mp)568dccf0d48Snjoly create_nametoolong(const atf_tc_t *tc, const char *mp)
569dccf0d48Snjoly {
570dccf0d48Snjoly char *name;
571dccf0d48Snjoly int fd;
572dccf0d48Snjoly long val;
573dccf0d48Snjoly size_t len;
574dccf0d48Snjoly
575dccf0d48Snjoly if (rump_sys_chdir(mp) == -1)
576dccf0d48Snjoly atf_tc_fail_errno("chdir mountpoint");
577dccf0d48Snjoly
578dccf0d48Snjoly val = rump_sys_pathconf(".", _PC_NAME_MAX);
579dccf0d48Snjoly if (val == -1)
580dccf0d48Snjoly atf_tc_fail_errno("pathconf");
581dccf0d48Snjoly
582dccf0d48Snjoly len = val + 1;
583dccf0d48Snjoly name = malloc(len+1);
584dccf0d48Snjoly if (name == NULL)
585dccf0d48Snjoly atf_tc_fail_errno("malloc");
586dccf0d48Snjoly
587dccf0d48Snjoly memset(name, 'a', len);
588dccf0d48Snjoly *(name+len) = '\0';
589dccf0d48Snjoly
590dccf0d48Snjoly val = rump_sys_pathconf(".", _PC_NO_TRUNC);
591dccf0d48Snjoly if (val == -1)
592dccf0d48Snjoly atf_tc_fail_errno("pathconf");
593dccf0d48Snjoly
594dccf0d48Snjoly fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666);
595dccf0d48Snjoly if (val != 0 && (fd != -1 || errno != ENAMETOOLONG))
596dccf0d48Snjoly atf_tc_fail_errno("open");
597dccf0d48Snjoly
598dccf0d48Snjoly if (val == 0 && rump_sys_close(fd) == -1)
599dccf0d48Snjoly atf_tc_fail_errno("close");
600dccf0d48Snjoly if (val == 0 && rump_sys_unlink(name) == -1)
601dccf0d48Snjoly atf_tc_fail_errno("unlink");
602dccf0d48Snjoly
603dccf0d48Snjoly free(name);
604dccf0d48Snjoly
605dccf0d48Snjoly rump_sys_chdir("/");
606dccf0d48Snjoly }
607dccf0d48Snjoly
608dccf0d48Snjoly static void
create_exist(const atf_tc_t * tc,const char * mp)6090aabb924Syamt create_exist(const atf_tc_t *tc, const char *mp)
6100aabb924Syamt {
6110aabb924Syamt const char *name = "hoge";
6120aabb924Syamt int fd;
6130aabb924Syamt
6140aabb924Syamt RL(rump_sys_chdir(mp));
6150aabb924Syamt RL(fd = rump_sys_open(name, O_RDWR|O_CREAT|O_EXCL, 0666));
6160aabb924Syamt RL(rump_sys_close(fd));
6170aabb924Syamt RL(rump_sys_unlink(name));
6180aabb924Syamt RL(fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666));
6190aabb924Syamt RL(rump_sys_close(fd));
6200aabb924Syamt RL(fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666));
6210aabb924Syamt RL(rump_sys_close(fd));
6220aabb924Syamt ATF_REQUIRE_ERRNO(EEXIST,
6230aabb924Syamt (fd = rump_sys_open(name, O_RDWR|O_CREAT|O_EXCL, 0666)));
6240aabb924Syamt RL(rump_sys_unlink(name));
6250aabb924Syamt RL(rump_sys_chdir("/"));
6260aabb924Syamt }
6270aabb924Syamt
6280aabb924Syamt static void
rename_nametoolong(const atf_tc_t * tc,const char * mp)629dccf0d48Snjoly rename_nametoolong(const atf_tc_t *tc, const char *mp)
630dccf0d48Snjoly {
631dccf0d48Snjoly char *name;
632dccf0d48Snjoly int res, fd;
633dccf0d48Snjoly long val;
634dccf0d48Snjoly size_t len;
635dccf0d48Snjoly
63688b6bdf1Spooka if (FSTYPE_RUMPFS(tc))
6377557af29Snjoly atf_tc_skip("rename not supported by file system");
63888b6bdf1Spooka
639dccf0d48Snjoly if (rump_sys_chdir(mp) == -1)
640dccf0d48Snjoly atf_tc_fail_errno("chdir mountpoint");
641dccf0d48Snjoly
642dccf0d48Snjoly val = rump_sys_pathconf(".", _PC_NAME_MAX);
643dccf0d48Snjoly if (val == -1)
644dccf0d48Snjoly atf_tc_fail_errno("pathconf");
645dccf0d48Snjoly
646dccf0d48Snjoly len = val + 1;
647dccf0d48Snjoly name = malloc(len+1);
648dccf0d48Snjoly if (name == NULL)
649dccf0d48Snjoly atf_tc_fail_errno("malloc");
650dccf0d48Snjoly
651dccf0d48Snjoly memset(name, 'a', len);
652dccf0d48Snjoly *(name+len) = '\0';
653dccf0d48Snjoly
654dccf0d48Snjoly fd = rump_sys_open("dummy", O_RDWR|O_CREAT, 0666);
655dccf0d48Snjoly if (fd == -1)
656dccf0d48Snjoly atf_tc_fail_errno("open");
657dccf0d48Snjoly if (rump_sys_close(fd) == -1)
658dccf0d48Snjoly atf_tc_fail_errno("close");
659dccf0d48Snjoly
660dccf0d48Snjoly val = rump_sys_pathconf(".", _PC_NO_TRUNC);
661dccf0d48Snjoly if (val == -1)
662dccf0d48Snjoly atf_tc_fail_errno("pathconf");
663dccf0d48Snjoly
664dccf0d48Snjoly res = rump_sys_rename("dummy", name);
665dccf0d48Snjoly if (val != 0 && (res != -1 || errno != ENAMETOOLONG))
666dccf0d48Snjoly atf_tc_fail_errno("rename");
667dccf0d48Snjoly
668dccf0d48Snjoly if (val == 0 && rump_sys_unlink(name) == -1)
669dccf0d48Snjoly atf_tc_fail_errno("unlink");
670dccf0d48Snjoly
671dccf0d48Snjoly free(name);
672dccf0d48Snjoly
673dccf0d48Snjoly rump_sys_chdir("/");
674dccf0d48Snjoly }
675dccf0d48Snjoly
676dec58decSgson /*
677dec58decSgson * Test creating a symlink whose length is "len" bytes, not including
678dec58decSgson * the terminating NUL.
679dec58decSgson */
680b28267edSpooka static void
symlink_len(const atf_tc_t * tc,const char * mp,size_t len)681dec58decSgson symlink_len(const atf_tc_t *tc, const char *mp, size_t len)
682b28267edSpooka {
683dec58decSgson char *buf;
684dec58decSgson int r;
685b28267edSpooka
686b28267edSpooka USES_SYMLINKS;
687b28267edSpooka
68803f6cc70Schristos RLF(rump_sys_chdir(mp), "%s", mp);
689192b53ecSpooka
690dec58decSgson buf = malloc(len + 1);
691dec58decSgson ATF_REQUIRE(buf);
692dec58decSgson memset(buf, 'a', len);
693dec58decSgson buf[len] = '\0';
694dec58decSgson r = rump_sys_symlink(buf, "afile");
695dec58decSgson if (r == -1) {
696dec58decSgson ATF_REQUIRE_ERRNO(ENAMETOOLONG, r);
697dec58decSgson } else {
698dec58decSgson RL(rump_sys_unlink("afile"));
699dec58decSgson }
700dec58decSgson free(buf);
701dec58decSgson
702b28267edSpooka RL(rump_sys_chdir("/"));
703b28267edSpooka }
704b28267edSpooka
70545bfa2deSpooka static void
symlink_zerolen(const atf_tc_t * tc,const char * mp)706dec58decSgson symlink_zerolen(const atf_tc_t *tc, const char *mp)
707dec58decSgson {
708dec58decSgson symlink_len(tc, mp, 0);
709dec58decSgson }
710dec58decSgson
711dec58decSgson static void
symlink_long(const atf_tc_t * tc,const char * mp)712dec58decSgson symlink_long(const atf_tc_t *tc, const char *mp)
713dec58decSgson {
714dec58decSgson /*
715dec58decSgson * Test lengths close to powers of two, as those are likely
716dec58decSgson * to be edge cases.
717dec58decSgson */
718dec58decSgson size_t len;
719dec58decSgson int fuzz;
720dec58decSgson for (len = 2; len <= 65536; len *= 2) {
721dec58decSgson for (fuzz = -1; fuzz <= 1; fuzz++) {
722dec58decSgson symlink_len(tc, mp, len + fuzz);
723dec58decSgson }
724dec58decSgson }
725dec58decSgson }
726dec58decSgson
727dec58decSgson static void
symlink_root(const atf_tc_t * tc,const char * mp)7280ed1cdc7Sriastradh symlink_root(const atf_tc_t *tc, const char *mp)
7290ed1cdc7Sriastradh {
7300ed1cdc7Sriastradh
7310ed1cdc7Sriastradh USES_SYMLINKS;
7320ed1cdc7Sriastradh
7330ed1cdc7Sriastradh RL(rump_sys_chdir(mp));
7340ed1cdc7Sriastradh RL(rump_sys_symlink("/", "foo"));
7350ed1cdc7Sriastradh RL(rump_sys_chdir("foo"));
7360ed1cdc7Sriastradh }
7370ed1cdc7Sriastradh
7380ed1cdc7Sriastradh static void
attrs(const atf_tc_t * tc,const char * mp)73945bfa2deSpooka attrs(const atf_tc_t *tc, const char *mp)
74045bfa2deSpooka {
74145bfa2deSpooka struct stat sb, sb2;
74245bfa2deSpooka struct timeval tv[2];
74345bfa2deSpooka int fd;
74445bfa2deSpooka
74545bfa2deSpooka FSTEST_ENTER();
74645bfa2deSpooka RL(fd = rump_sys_open(TESTFILE, O_RDWR | O_CREAT, 0755));
74745bfa2deSpooka RL(rump_sys_close(fd));
74845bfa2deSpooka RL(rump_sys_stat(TESTFILE, &sb));
74945bfa2deSpooka if (!(FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))) {
75045bfa2deSpooka RL(rump_sys_chown(TESTFILE, 1, 2));
75145bfa2deSpooka sb.st_uid = 1;
75245bfa2deSpooka sb.st_gid = 2;
75345bfa2deSpooka RL(rump_sys_chmod(TESTFILE, 0123));
75445bfa2deSpooka sb.st_mode = (sb.st_mode & ~ACCESSPERMS) | 0123;
75545bfa2deSpooka }
75645bfa2deSpooka
75745bfa2deSpooka tv[0].tv_sec = 1000000000; /* need something >1980 for msdosfs */
75845bfa2deSpooka tv[0].tv_usec = 1;
75945bfa2deSpooka tv[1].tv_sec = 1000000002; /* need even seconds for msdosfs */
76045bfa2deSpooka tv[1].tv_usec = 3;
76145bfa2deSpooka RL(rump_sys_utimes(TESTFILE, tv));
76245bfa2deSpooka RL(rump_sys_utimes(TESTFILE, tv)); /* XXX: utimes & birthtime */
76345bfa2deSpooka sb.st_atimespec.tv_sec = 1000000000;
76445bfa2deSpooka sb.st_atimespec.tv_nsec = 1000;
76545bfa2deSpooka sb.st_mtimespec.tv_sec = 1000000002;
76645bfa2deSpooka sb.st_mtimespec.tv_nsec = 3000;
76745bfa2deSpooka
76845bfa2deSpooka RL(rump_sys_stat(TESTFILE, &sb2));
76945bfa2deSpooka #define CHECK(a) ATF_REQUIRE_EQ(sb.a, sb2.a)
77045bfa2deSpooka if (!(FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))) {
77145bfa2deSpooka CHECK(st_uid);
77245bfa2deSpooka CHECK(st_gid);
77345bfa2deSpooka CHECK(st_mode);
77445bfa2deSpooka }
77545bfa2deSpooka if (!FSTYPE_MSDOS(tc)) {
77645bfa2deSpooka /* msdosfs has only access date, not time */
77745bfa2deSpooka CHECK(st_atimespec.tv_sec);
77845bfa2deSpooka }
77945bfa2deSpooka CHECK(st_mtimespec.tv_sec);
780154297fdSuch if (!(FSTYPE_EXT2FS(tc) || FSTYPE_MSDOS(tc) ||
781154297fdSuch FSTYPE_SYSVBFS(tc) || FSTYPE_V7FS(tc))) {
78245bfa2deSpooka CHECK(st_atimespec.tv_nsec);
78345bfa2deSpooka CHECK(st_mtimespec.tv_nsec);
78445bfa2deSpooka }
78545bfa2deSpooka #undef CHECK
78645bfa2deSpooka
78745bfa2deSpooka FSTEST_EXIT();
78845bfa2deSpooka }
78945bfa2deSpooka
790eea5c398Skefren static void
fcntl_lock(const atf_tc_t * tc,const char * mp)791eea5c398Skefren fcntl_lock(const atf_tc_t *tc, const char *mp)
792eea5c398Skefren {
793eea5c398Skefren int fd, fd2;
794eea5c398Skefren struct flock l;
795eea5c398Skefren struct lwp *lwp1, *lwp2;
796eea5c398Skefren
797eea5c398Skefren FSTEST_ENTER();
798eea5c398Skefren l.l_pid = 0;
799eea5c398Skefren l.l_start = l.l_len = 1024;
800eea5c398Skefren l.l_type = F_RDLCK | F_WRLCK;
801eea5c398Skefren l.l_whence = SEEK_END;
802eea5c398Skefren
803eea5c398Skefren lwp1 = rump_pub_lwproc_curlwp();
804eea5c398Skefren RL(fd = rump_sys_open(TESTFILE, O_RDWR | O_CREAT, 0755));
805eea5c398Skefren RL(rump_sys_ftruncate(fd, 8192));
806eea5c398Skefren
807eea5c398Skefren RL(rump_sys_fcntl(fd, F_SETLK, &l));
808eea5c398Skefren
809eea5c398Skefren /* Next, we fork and try to lock the same area */
810eea5c398Skefren RZ(rump_pub_lwproc_rfork(RUMP_RFCFDG));
811eea5c398Skefren lwp2 = rump_pub_lwproc_curlwp();
812eea5c398Skefren RL(fd2 = rump_sys_open(TESTFILE, O_RDWR, 0));
813eea5c398Skefren ATF_REQUIRE_ERRNO(EAGAIN, rump_sys_fcntl(fd2, F_SETLK, &l));
814eea5c398Skefren
815eea5c398Skefren /* Switch back and unlock... */
816eea5c398Skefren rump_pub_lwproc_switch(lwp1);
817eea5c398Skefren l.l_type = F_UNLCK;
818eea5c398Skefren RL(rump_sys_fcntl(fd, F_SETLK, &l));
819eea5c398Skefren
820eea5c398Skefren /* ... and try to lock again */
821eea5c398Skefren rump_pub_lwproc_switch(lwp2);
822eea5c398Skefren l.l_type = F_RDLCK | F_WRLCK;
823eea5c398Skefren RL(rump_sys_fcntl(fd2, F_SETLK, &l));
824eea5c398Skefren
825eea5c398Skefren RL(rump_sys_close(fd2));
826eea5c398Skefren rump_pub_lwproc_releaselwp();
827eea5c398Skefren
828eea5c398Skefren RL(rump_sys_close(fd));
829eea5c398Skefren
830eea5c398Skefren FSTEST_EXIT();
831eea5c398Skefren }
832eea5c398Skefren
833e8bcfa54Spooka static int
flock_compare(const void * p,const void * q)834e8bcfa54Spooka flock_compare(const void *p, const void *q)
835e8bcfa54Spooka {
836e8bcfa54Spooka int a = ((const struct flock *)p)->l_start;
837e8bcfa54Spooka int b = ((const struct flock *)q)->l_start;
838e8bcfa54Spooka return a < b ? -1 : (a > b ? 1 : 0);
839e8bcfa54Spooka }
840e8bcfa54Spooka
841f60611afSalnsn /*
842f60611afSalnsn * Find all locks set by fcntl_getlock_pids test
843f60611afSalnsn * using GETLK for a range [start, start+end], and,
844f60611afSalnsn * if there is a blocking lock, recursively find
845f60611afSalnsn * all locks to the left (toward the beginning of
846f60611afSalnsn * a file) and to the right of the lock.
847f60611afSalnsn * The function also understands "until end of file"
848f60611afSalnsn * convention when len==0.
849f60611afSalnsn */
850f60611afSalnsn static unsigned int
fcntl_getlocks(int fildes,off_t start,off_t len,struct flock * lock,struct flock * end)851f60611afSalnsn fcntl_getlocks(int fildes, off_t start, off_t len,
852f60611afSalnsn struct flock *lock, struct flock *end)
853f60611afSalnsn {
854f60611afSalnsn unsigned int rv = 0;
855f60611afSalnsn const struct flock l = { start, len, 0, F_RDLCK, SEEK_SET };
856f60611afSalnsn
857f60611afSalnsn if (lock == end)
858f60611afSalnsn return rv;
859f60611afSalnsn
860f60611afSalnsn RL(rump_sys_fcntl(fildes, F_GETLK, &l));
861f60611afSalnsn
862f60611afSalnsn if (l.l_type == F_UNLCK)
863f60611afSalnsn return rv;
864f60611afSalnsn
865f60611afSalnsn *lock++ = l;
866f60611afSalnsn rv += 1;
867f60611afSalnsn
868f60611afSalnsn ATF_REQUIRE(l.l_whence == SEEK_SET);
869f60611afSalnsn
870f60611afSalnsn if (l.l_start > start) {
871f60611afSalnsn unsigned int n =
872f60611afSalnsn fcntl_getlocks(fildes, start, l.l_start - start, lock, end);
873f60611afSalnsn rv += n;
874f60611afSalnsn lock += n;
875f60611afSalnsn if (lock == end)
876f60611afSalnsn return rv;
877f60611afSalnsn }
878f60611afSalnsn
879f60611afSalnsn if (l.l_len == 0) /* does l spans until the end? */
880f60611afSalnsn return rv;
881f60611afSalnsn
882f60611afSalnsn if (len == 0) /* are we looking for locks until the end? */ {
883f60611afSalnsn rv += fcntl_getlocks(fildes, l.l_start + l.l_len, len, lock, end);
884f60611afSalnsn } else if (l.l_start + l.l_len < start + len) {
885f60611afSalnsn len -= l.l_start + l.l_len - start;
886f60611afSalnsn rv += fcntl_getlocks(fildes, l.l_start + l.l_len, len, lock, end);
887f60611afSalnsn }
888f60611afSalnsn
889f60611afSalnsn return rv;
890f60611afSalnsn }
891f60611afSalnsn
892e8bcfa54Spooka static void
fcntl_getlock_pids(const atf_tc_t * tc,const char * mp)893e8bcfa54Spooka fcntl_getlock_pids(const atf_tc_t *tc, const char *mp)
894e8bcfa54Spooka {
895e8bcfa54Spooka /* test non-overlaping ranges */
896e8bcfa54Spooka struct flock expect[4];
897e8bcfa54Spooka const struct flock lock[4] = {
898e8bcfa54Spooka { 0, 2, 0, F_WRLCK, SEEK_SET },
899e8bcfa54Spooka { 2, 1, 0, F_WRLCK, SEEK_SET },
900e8bcfa54Spooka { 7, 5, 0, F_WRLCK, SEEK_SET },
901e8bcfa54Spooka { 4, 3, 0, F_WRLCK, SEEK_SET },
902e8bcfa54Spooka };
903e8bcfa54Spooka
904f60611afSalnsn /* Add extra element to make sure recursion does't stop at array end */
905f60611afSalnsn struct flock result[5];
906f60611afSalnsn
907f60611afSalnsn /* Add 5th process */
908f60611afSalnsn int fd[5];
909f60611afSalnsn pid_t pid[5];
910f60611afSalnsn struct lwp *lwp[5];
911e8bcfa54Spooka
912e8bcfa54Spooka unsigned int i, j;
913e8bcfa54Spooka const off_t sz = 8192;
914e8bcfa54Spooka int omode = 0755;
915e8bcfa54Spooka int oflags = O_RDWR | O_CREAT;
916e8bcfa54Spooka
917e8bcfa54Spooka memcpy(expect, lock, sizeof(lock));
918e8bcfa54Spooka
919e8bcfa54Spooka FSTEST_ENTER();
920e8bcfa54Spooka
921e8bcfa54Spooka /*
922e8bcfa54Spooka * First, we create 4 processes and let each lock a range of the
923e8bcfa54Spooka * file. Note that the third and fourth processes lock in
924e8bcfa54Spooka * "reverse" order, i.e. the greater pid locks a range before
925e8bcfa54Spooka * the lesser pid.
926f60611afSalnsn * Then, we create 5th process which doesn't lock anything.
927e8bcfa54Spooka */
928e8bcfa54Spooka for (i = 0; i < __arraycount(lwp); i++) {
929e8bcfa54Spooka RZ(rump_pub_lwproc_rfork(RUMP_RFCFDG));
930e8bcfa54Spooka
931e8bcfa54Spooka lwp[i] = rump_pub_lwproc_curlwp();
932f60611afSalnsn pid[i] = rump_sys_getpid();
933e8bcfa54Spooka
934e8bcfa54Spooka RL(fd[i] = rump_sys_open(TESTFILE, oflags, omode));
935e8bcfa54Spooka oflags = O_RDWR;
936e8bcfa54Spooka omode = 0;
937e8bcfa54Spooka
938e8bcfa54Spooka RL(rump_sys_ftruncate(fd[i], sz));
939f60611afSalnsn
940f60611afSalnsn if (i < __arraycount(lock)) {
941e8bcfa54Spooka RL(rump_sys_fcntl(fd[i], F_SETLK, &lock[i]));
942f60611afSalnsn expect[i].l_pid = pid[i];
943f60611afSalnsn }
944e8bcfa54Spooka }
945e8bcfa54Spooka
946f60611afSalnsn qsort(expect, __arraycount(expect), sizeof(expect[0]), &flock_compare);
947f60611afSalnsn
948e8bcfa54Spooka /*
949f60611afSalnsn * In the context of each process, recursively find all locks
950f60611afSalnsn * that would block the current process. Processes 1-4 don't
951f60611afSalnsn * see their own lock, we insert it to simplify checks.
952f60611afSalnsn * Process 5 sees all 4 locks.
953e8bcfa54Spooka */
954e8bcfa54Spooka for (i = 0; i < __arraycount(lwp); i++) {
955f60611afSalnsn unsigned int nlocks;
956f60611afSalnsn
957e8bcfa54Spooka rump_pub_lwproc_switch(lwp[i]);
958e8bcfa54Spooka
959f60611afSalnsn memset(result, 0, sizeof(result));
960f60611afSalnsn nlocks = fcntl_getlocks(fd[i], 0, sz,
961f60611afSalnsn result, result + __arraycount(result));
962e8bcfa54Spooka
963f60611afSalnsn if (i < __arraycount(lock)) {
964f60611afSalnsn ATF_REQUIRE(nlocks < __arraycount(result));
965f60611afSalnsn result[nlocks] = lock[i];
966f60611afSalnsn result[nlocks].l_pid = pid[i];
967f60611afSalnsn nlocks++;
968e8bcfa54Spooka }
969f60611afSalnsn
970f60611afSalnsn ATF_CHECK_EQ(nlocks, __arraycount(expect));
971f60611afSalnsn
972f60611afSalnsn qsort(result, nlocks, sizeof(result[0]), &flock_compare);
973f60611afSalnsn
974f60611afSalnsn for (j = 0; j < nlocks; j++) {
975f60611afSalnsn ATF_CHECK_EQ(result[j].l_start, expect[j].l_start );
976f60611afSalnsn ATF_CHECK_EQ(result[j].l_len, expect[j].l_len );
977f60611afSalnsn ATF_CHECK_EQ(result[j].l_pid, expect[j].l_pid );
978f60611afSalnsn ATF_CHECK_EQ(result[j].l_type, expect[j].l_type );
979f60611afSalnsn ATF_CHECK_EQ(result[j].l_whence, expect[j].l_whence);
980e8bcfa54Spooka }
981e8bcfa54Spooka }
982e8bcfa54Spooka
983e8bcfa54Spooka /*
984e8bcfa54Spooka * Release processes. This also releases the fds and locks
985e8bcfa54Spooka * making fs unmount possible
986e8bcfa54Spooka */
987e8bcfa54Spooka for (i = 0; i < __arraycount(lwp); i++) {
988e8bcfa54Spooka rump_pub_lwproc_switch(lwp[i]);
989e8bcfa54Spooka rump_pub_lwproc_releaselwp();
990e8bcfa54Spooka }
991e8bcfa54Spooka
992e8bcfa54Spooka FSTEST_EXIT();
993e8bcfa54Spooka }
994e8bcfa54Spooka
9956ae16092Spooka static void
access_simple(const atf_tc_t * tc,const char * mp)9966ae16092Spooka access_simple(const atf_tc_t *tc, const char *mp)
9976ae16092Spooka {
9986ae16092Spooka int fd;
9996ae16092Spooka int tmode;
10006ae16092Spooka
10016ae16092Spooka FSTEST_ENTER();
10026ae16092Spooka RL(fd = rump_sys_open("tfile", O_CREAT | O_RDWR, 0777));
10036ae16092Spooka RL(rump_sys_close(fd));
10046ae16092Spooka
10056ae16092Spooka #define ALLACC (F_OK | X_OK | W_OK | R_OK)
10066ae16092Spooka if (FSTYPE_SYSVBFS(tc) || FSTYPE_MSDOS(tc))
10076ae16092Spooka tmode = F_OK;
10086ae16092Spooka else
10096ae16092Spooka tmode = ALLACC;
10106ae16092Spooka
10116ae16092Spooka RL(rump_sys_access("tfile", tmode));
10126ae16092Spooka
10136ae16092Spooka /* PR kern/44648 */
10146ae16092Spooka ATF_REQUIRE_ERRNO(EINVAL, rump_sys_access("tfile", ALLACC+1) == -1);
10156ae16092Spooka #undef ALLACC
10166ae16092Spooka FSTEST_EXIT();
10176ae16092Spooka }
10186ae16092Spooka
1019973e4855Snjoly static void
read_directory(const atf_tc_t * tc,const char * mp)1020973e4855Snjoly read_directory(const atf_tc_t *tc, const char *mp)
1021973e4855Snjoly {
1022973e4855Snjoly char buf[1024];
1023973e4855Snjoly int fd, res;
1024973e4855Snjoly ssize_t size;
1025973e4855Snjoly
1026973e4855Snjoly FSTEST_ENTER();
1027973e4855Snjoly fd = rump_sys_open(".", O_DIRECTORY | O_RDONLY, 0777);
1028973e4855Snjoly ATF_REQUIRE(fd != -1);
1029973e4855Snjoly
1030973e4855Snjoly size = rump_sys_pread(fd, buf, sizeof(buf), 0);
1031973e4855Snjoly ATF_CHECK(size != -1 || errno == EISDIR);
1032973e4855Snjoly size = rump_sys_read(fd, buf, sizeof(buf));
1033973e4855Snjoly ATF_CHECK(size != -1 || errno == EISDIR);
1034973e4855Snjoly
1035973e4855Snjoly res = rump_sys_close(fd);
1036973e4855Snjoly ATF_REQUIRE(res != -1);
1037973e4855Snjoly FSTEST_EXIT();
1038973e4855Snjoly }
1039973e4855Snjoly
1040954ca525Snjoly static void
lstat_symlink(const atf_tc_t * tc,const char * mp)1041954ca525Snjoly lstat_symlink(const atf_tc_t *tc, const char *mp)
1042954ca525Snjoly {
1043954ca525Snjoly const char *src, *dst;
1044954ca525Snjoly int res;
1045954ca525Snjoly struct stat st;
1046954ca525Snjoly
1047954ca525Snjoly USES_SYMLINKS;
104876c3358aSgson
1049954ca525Snjoly FSTEST_ENTER();
1050954ca525Snjoly
1051954ca525Snjoly src = "source";
1052954ca525Snjoly dst = "destination";
1053954ca525Snjoly
1054954ca525Snjoly res = rump_sys_symlink(src, dst);
1055954ca525Snjoly ATF_REQUIRE(res != -1);
1056954ca525Snjoly res = rump_sys_lstat(dst, &st);
1057954ca525Snjoly ATF_REQUIRE(res != -1);
1058954ca525Snjoly
1059954ca525Snjoly ATF_CHECK(S_ISLNK(st.st_mode) != 0);
1060954ca525Snjoly ATF_CHECK(st.st_size == (off_t)strlen(src));
1061954ca525Snjoly
1062954ca525Snjoly FSTEST_EXIT();
1063954ca525Snjoly }
1064954ca525Snjoly
10652a5fd96fSpooka ATF_TC_FSAPPLY(lookup_simple, "simple lookup (./.. on root)");
10662a5fd96fSpooka ATF_TC_FSAPPLY(lookup_complex, "lookup of non-dot entries");
10672a5fd96fSpooka ATF_TC_FSAPPLY(dir_simple, "mkdir/rmdir");
10680df09db4Smartin ATF_TC_FSAPPLY(dir_slash, "mkdir with appended slash");
10690df09db4Smartin ATF_TC_FSAPPLY(dir_2slash, "mkdir with two slashes appended");
10700df09db4Smartin ATF_TC_FSAPPLY(dir_3slash, "mkdir with three slashes appended");
10712a5fd96fSpooka ATF_TC_FSAPPLY(dir_notempty, "non-empty directories cannot be removed");
107259c51f5cSchristos ATF_TC_FSAPPLY(dir_rmdirdotdot, "remove .. and try to cd out (PR kern/44657)");
107359c51f5cSchristos ATF_TC_FSAPPLY(rename_dir, "exercise various directory renaming ops "
107459c51f5cSchristos "(PR kern/44288)");
107559c51f5cSchristos ATF_TC_FSAPPLY(rename_dotdot, "rename dir .. (PR kern/43617)");
1076ae0b9cceSpooka ATF_TC_FSAPPLY(rename_reg_nodir, "rename regular files, no subdirectories");
1077dccf0d48Snjoly ATF_TC_FSAPPLY(create_nametoolong, "create file with name too long");
10780aabb924Syamt ATF_TC_FSAPPLY(create_exist, "create with O_EXCL");
1079dccf0d48Snjoly ATF_TC_FSAPPLY(rename_nametoolong, "rename to file with name too long");
1080dec58decSgson ATF_TC_FSAPPLY(symlink_zerolen, "symlink with target of length 0");
1081dec58decSgson ATF_TC_FSAPPLY(symlink_long, "symlink with target of length > 0");
10820ed1cdc7Sriastradh ATF_TC_FSAPPLY(symlink_root, "symlink to root directory");
108345bfa2deSpooka ATF_TC_FSAPPLY(attrs, "check setting attributes works");
1084eea5c398Skefren ATF_TC_FSAPPLY(fcntl_lock, "check fcntl F_SETLK");
1085e8bcfa54Spooka ATF_TC_FSAPPLY(fcntl_getlock_pids,"fcntl F_GETLK w/ many procs, PR kern/44494");
10866ae16092Spooka ATF_TC_FSAPPLY(access_simple, "access(2)");
1087973e4855Snjoly ATF_TC_FSAPPLY(read_directory, "read(2) on directories");
1088954ca525Snjoly ATF_TC_FSAPPLY(lstat_symlink, "lstat(2) values for symbolic links");
10892a5fd96fSpooka
1090596d7c22Spooka #undef FSTEST_IMGSIZE
1091596d7c22Spooka #define FSTEST_IMGSIZE (1024*1024*64)
1092596d7c22Spooka ATF_TC_FSAPPLY(create_many, "create many directory entries");
109379350377Sgson ATF_TC_FSAPPLY(create_nonalphanum, "non-alphanumeric filenames");
1094596d7c22Spooka
ATF_TP_ADD_TCS(tp)10952a5fd96fSpooka ATF_TP_ADD_TCS(tp)
10962a5fd96fSpooka {
10972a5fd96fSpooka
10982a5fd96fSpooka ATF_TP_FSAPPLY(lookup_simple);
10992a5fd96fSpooka ATF_TP_FSAPPLY(lookup_complex);
11002a5fd96fSpooka ATF_TP_FSAPPLY(dir_simple);
11012a5fd96fSpooka ATF_TP_FSAPPLY(dir_notempty);
1102878d41e6Spooka ATF_TP_FSAPPLY(dir_rmdirdotdot);
11030df09db4Smartin ATF_TP_FSAPPLY(dir_slash);
11040df09db4Smartin ATF_TP_FSAPPLY(dir_2slash);
11050df09db4Smartin ATF_TP_FSAPPLY(dir_3slash);
1106ae0b9cceSpooka ATF_TP_FSAPPLY(rename_dir);
1107ae0b9cceSpooka ATF_TP_FSAPPLY(rename_dotdot);
1108ae0b9cceSpooka ATF_TP_FSAPPLY(rename_reg_nodir);
1109596d7c22Spooka ATF_TP_FSAPPLY(create_many);
111079350377Sgson ATF_TP_FSAPPLY(create_nonalphanum);
1111dccf0d48Snjoly ATF_TP_FSAPPLY(create_nametoolong);
11120aabb924Syamt ATF_TP_FSAPPLY(create_exist);
1113dccf0d48Snjoly ATF_TP_FSAPPLY(rename_nametoolong);
1114b28267edSpooka ATF_TP_FSAPPLY(symlink_zerolen);
1115dec58decSgson ATF_TP_FSAPPLY(symlink_long);
11160ed1cdc7Sriastradh ATF_TP_FSAPPLY(symlink_root);
111745bfa2deSpooka ATF_TP_FSAPPLY(attrs);
1118eea5c398Skefren ATF_TP_FSAPPLY(fcntl_lock);
1119e8bcfa54Spooka ATF_TP_FSAPPLY(fcntl_getlock_pids);
11206ae16092Spooka ATF_TP_FSAPPLY(access_simple);
1121973e4855Snjoly ATF_TP_FSAPPLY(read_directory);
1122954ca525Snjoly ATF_TP_FSAPPLY(lstat_symlink);
11232a5fd96fSpooka
11242a5fd96fSpooka return atf_no_error();
11252a5fd96fSpooka }
1126