Home | History | Annotate | Line # | Download | only in vfs
      1 /*	$NetBSD: t_vnops.c,v 1.63 2023/05/08 19:23:45 andvar Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2010 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/stat.h>
     30 #include <sys/statvfs.h>
     31 #include <sys/time.h>
     32 
     33 #include <assert.h>
     34 #include <atf-c.h>
     35 #include <ctype.h>
     36 #include <fcntl.h>
     37 #include <libgen.h>
     38 #include <stdlib.h>
     39 #include <string.h>
     40 #include <unistd.h>
     41 
     42 #include <rump/rump_syscalls.h>
     43 #include <rump/rump.h>
     44 
     45 #include "../common/h_fsmacros.h"
     46 #include "h_macros.h"
     47 
     48 #define TESTFILE "afile"
     49 
     50 #define USES_DIRS					\
     51     if (FSTYPE_SYSVBFS(tc))				\
     52 	atf_tc_skip("directories not supported by file system")
     53 
     54 #define USES_SYMLINKS					\
     55     if (FSTYPE_SYSVBFS(tc) || FSTYPE_MSDOS(tc))		\
     56 	atf_tc_skip("symlinks not supported by file system")
     57 
     58 static char *
     59 md(char *buf, size_t buflen, const char *base, const char *tail)
     60 {
     61 
     62 	snprintf(buf, buflen, "%s/%s", base, tail);
     63 	return buf;
     64 }
     65 
     66 static void
     67 lookup_simple(const atf_tc_t *tc, const char *mountpath)
     68 {
     69 	char pb[MAXPATHLEN], final[MAXPATHLEN];
     70 	struct stat sb1, sb2;
     71 
     72 	strcpy(final, mountpath);
     73 	snprintf(pb, sizeof(pb), "%s/../%s", mountpath, basename(final));
     74 	if (rump_sys_stat(pb, &sb1) == -1)
     75 		atf_tc_fail_errno("stat 1");
     76 
     77 	snprintf(pb, sizeof(pb), "%s/./../%s", mountpath, basename(final));
     78 	if (rump_sys_stat(pb, &sb2) == -1)
     79 		atf_tc_fail_errno("stat 2");
     80 
     81 	ATF_REQUIRE(memcmp(&sb1, &sb2, sizeof(sb1)) == 0);
     82 }
     83 
     84 static void
     85 lookup_complex(const atf_tc_t *tc, const char *mountpath)
     86 {
     87 	char pb[MAXPATHLEN];
     88 	struct stat sb1, sb2;
     89 	struct timespec atplus1, onesec;
     90 
     91 	USES_DIRS;
     92 
     93 	snprintf(pb, sizeof(pb), "%s/dir", mountpath);
     94 	if (rump_sys_mkdir(pb, 0777) == -1)
     95 		atf_tc_fail_errno("mkdir");
     96 	if (rump_sys_stat(pb, &sb1) == -1)
     97 		atf_tc_fail_errno("stat 1");
     98 
     99 	snprintf(pb, sizeof(pb), "%s/./dir/../././dir/.", mountpath);
    100 	if (rump_sys_stat(pb, &sb2) == -1)
    101 		atf_tc_fail_errno("stat 2");
    102 
    103 	/*
    104 	 * The lookup is permitted to modify the access time of
    105 	 * any directories searched - such a directory is the
    106 	 * subject of this test.   Any difference should cause
    107 	 * the 2nd lookup atime to be >= the first, if it is ==, all is
    108 	 * OK (atime is not required to be modified by the search, or
    109 	 * both references may happen within the same clock tick), if the
    110 	 * 2nd lookup atime is > the first, but not "too much" greater,
    111 	 * just set it back, so the memcmp just below succeeds
    112 	 * (assuming all else is OK).
    113 	 */
    114 	onesec.tv_sec = 1;
    115 	onesec.tv_nsec = 0;
    116 	timespecadd(&sb1.st_atimespec, &onesec, &atplus1);
    117 	if (timespeccmp(&sb2.st_atimespec, &sb1.st_atimespec, >) &&
    118 	    timespeccmp(&sb2.st_atimespec, &atplus1, <))
    119 		sb2.st_atimespec = sb1.st_atimespec;
    120 
    121 	if (memcmp(&sb1, &sb2, sizeof(sb1)) != 0) {
    122 		printf("what\tsb1\t\tsb2\n");
    123 
    124 #define FIELD(FN)	\
    125 		printf(#FN "\t%lld\t%lld\n", \
    126 		(long long)sb1.FN, (long long)sb2.FN)
    127 #define TIME(FN)	\
    128 		printf(#FN "\t%lld.%ld\t%lld.%ld\n", \
    129 		(long long)sb1.FN.tv_sec, sb1.FN.tv_nsec, \
    130 		(long long)sb2.FN.tv_sec, sb2.FN.tv_nsec)
    131 
    132 		FIELD(st_dev);
    133 		FIELD(st_mode);
    134 		FIELD(st_ino);
    135 		FIELD(st_nlink);
    136 		FIELD(st_uid);
    137 		FIELD(st_gid);
    138 		FIELD(st_rdev);
    139 		TIME(st_atimespec);
    140 		TIME(st_mtimespec);
    141 		TIME(st_ctimespec);
    142 		TIME(st_birthtimespec);
    143 		FIELD(st_size);
    144 		FIELD(st_blocks);
    145 		FIELD(st_flags);
    146 		FIELD(st_gen);
    147 
    148 #undef FIELD
    149 #undef TIME
    150 
    151 		atf_tc_fail("stat results differ, see output for more details");
    152 	}
    153 }
    154 
    155 static void
    156 dir_simple(const atf_tc_t *tc, const char *mountpath)
    157 {
    158 	char pb[MAXPATHLEN];
    159 	struct stat sb;
    160 
    161 	USES_DIRS;
    162 
    163 	/* check we can create directories */
    164 	snprintf(pb, sizeof(pb), "%s/dir", mountpath);
    165 	if (rump_sys_mkdir(pb, 0777) == -1)
    166 		atf_tc_fail_errno("mkdir");
    167 	if (rump_sys_stat(pb, &sb) == -1)
    168 		atf_tc_fail_errno("stat new directory");
    169 
    170 	/* check we can remove them and that it makes them unreachable */
    171 	if (rump_sys_rmdir(pb) == -1)
    172 		atf_tc_fail_errno("rmdir");
    173 	if (rump_sys_stat(pb, &sb) != -1 || errno != ENOENT)
    174 		atf_tc_fail("ENOENT expected from stat");
    175 }
    176 
    177 static void
    178 do_dir_slash(const atf_tc_t *tc, const char *mountpath, const char *addend)
    179 {
    180 	char plain[MAXPATHLEN], with_slash[MAXPATHLEN];
    181 	struct stat sb;
    182 
    183 	USES_DIRS;
    184 
    185 	/* check we can create directories with one or more / appended */
    186 	snprintf(plain, sizeof(plain), "%s/dir%s", mountpath, addend);
    187 	snprintf(with_slash, sizeof(with_slash), "%s/dir/", mountpath);
    188 	if (rump_sys_mkdir(with_slash, 0777) == -1)
    189 		atf_tc_fail_errno("mkdir");
    190 	if (rump_sys_stat(plain, &sb) == -1)
    191 		atf_tc_fail_errno("stat new directory");
    192 	if (rump_sys_rmdir(plain) == -1)
    193 		atf_tc_fail_errno("rmdir");
    194 	if (rump_sys_stat(with_slash, &sb) != -1 || errno != ENOENT)
    195 		atf_tc_fail("ENOENT expected from stat");
    196 }
    197 
    198 static void
    199 dir_slash(const atf_tc_t *tc, const char *mountpath)
    200 {
    201 	do_dir_slash(tc, mountpath, "/");
    202 }
    203 
    204 static void
    205 dir_2slash(const atf_tc_t *tc, const char *mountpath)
    206 {
    207 	do_dir_slash(tc, mountpath, "//");
    208 }
    209 
    210 static void
    211 dir_3slash(const atf_tc_t *tc, const char *mountpath)
    212 {
    213 	do_dir_slash(tc, mountpath, "///");
    214 }
    215 
    216 static void
    217 dir_notempty(const atf_tc_t *tc, const char *mountpath)
    218 {
    219 	char pb[MAXPATHLEN], pb2[MAXPATHLEN];
    220 	int fd, rv;
    221 
    222 	USES_DIRS;
    223 
    224 	/* check we can create directories */
    225 	snprintf(pb, sizeof(pb), "%s/dir", mountpath);
    226 	if (rump_sys_mkdir(pb, 0777) == -1)
    227 		atf_tc_fail_errno("mkdir");
    228 
    229 	snprintf(pb2, sizeof(pb2), "%s/dir/file", mountpath);
    230 	fd = rump_sys_open(pb2, O_RDWR | O_CREAT, 0777);
    231 	if (fd == -1)
    232 		atf_tc_fail_errno("create file");
    233 	rump_sys_close(fd);
    234 
    235 	rv = rump_sys_rmdir(pb);
    236 	if (rv != -1 || errno != ENOTEMPTY)
    237 		atf_tc_fail("non-empty directory removed successfully");
    238 
    239 	if (rump_sys_unlink(pb2) == -1)
    240 		atf_tc_fail_errno("cannot remove dir/file");
    241 
    242 	if (rump_sys_rmdir(pb) == -1)
    243 		atf_tc_fail_errno("remove directory");
    244 }
    245 
    246 static void
    247 dir_rmdirdotdot(const atf_tc_t *tc, const char *mp)
    248 {
    249 	char pb[MAXPATHLEN];
    250 	int xerrno;
    251 
    252 	USES_DIRS;
    253 
    254 	FSTEST_ENTER();
    255 	RL(rump_sys_mkdir("test", 0777));
    256 	RL(rump_sys_chdir("test"));
    257 
    258 	RL(rump_sys_mkdir("subtest", 0777));
    259 	RL(rump_sys_chdir("subtest"));
    260 
    261 	md(pb, sizeof(pb), mp, "test/subtest");
    262 	RL(rump_sys_rmdir(pb));
    263 	md(pb, sizeof(pb), mp, "test");
    264 	RL(rump_sys_rmdir(pb));
    265 
    266 	if (FSTYPE_NFS(tc))
    267 		xerrno = ESTALE;
    268 	else
    269 		xerrno = ENOENT;
    270 	ATF_REQUIRE_ERRNO(xerrno, rump_sys_chdir("..") == -1);
    271 	FSTEST_EXIT();
    272 }
    273 
    274 static void
    275 checkfile(const char *path, struct stat *refp)
    276 {
    277 	char buf[MAXPATHLEN];
    278 	struct stat sb;
    279 	static int n = 1;
    280 
    281 	md(buf, sizeof(buf), path, "file");
    282 	if (rump_sys_stat(buf, &sb) == -1)
    283 		atf_tc_fail_errno("cannot stat file %d (%s)", n, buf);
    284 	if (memcmp(&sb, refp, sizeof(sb)) != 0)
    285 		atf_tc_fail("stat mismatch %d", n);
    286 	n++;
    287 }
    288 
    289 static void
    290 rename_dir(const atf_tc_t *tc, const char *mp)
    291 {
    292 	char pb1[MAXPATHLEN], pb2[MAXPATHLEN], pb3[MAXPATHLEN];
    293 	struct stat ref, sb;
    294 
    295 	if (FSTYPE_RUMPFS(tc))
    296 		atf_tc_skip("rename not supported by file system");
    297 
    298 	USES_DIRS;
    299 
    300 	md(pb1, sizeof(pb1), mp, "dir1");
    301 	if (rump_sys_mkdir(pb1, 0777) == -1)
    302 		atf_tc_fail_errno("mkdir 1");
    303 
    304 	md(pb2, sizeof(pb2), mp, "dir2");
    305 	if (rump_sys_mkdir(pb2, 0777) == -1)
    306 		atf_tc_fail_errno("mkdir 2");
    307 	md(pb2, sizeof(pb2), mp, "dir2/subdir");
    308 	if (rump_sys_mkdir(pb2, 0777) == -1)
    309 		atf_tc_fail_errno("mkdir 3");
    310 
    311 	md(pb3, sizeof(pb3), mp, "dir1/file");
    312 	if (rump_sys_mknod(pb3, S_IFREG | 0777, -1) == -1)
    313 		atf_tc_fail_errno("create file");
    314 	if (rump_sys_stat(pb3, &ref) == -1)
    315 		atf_tc_fail_errno("stat of file");
    316 
    317 	/*
    318 	 * First try ops which should succeed.
    319 	 */
    320 
    321 	/* rename within directory */
    322 	md(pb3, sizeof(pb3), mp, "dir3");
    323 	if (rump_sys_rename(pb1, pb3) == -1)
    324 		atf_tc_fail_errno("rename 1");
    325 	checkfile(pb3, &ref);
    326 
    327 	/* rename directory onto itself (two ways, should fail) */
    328 	md(pb1, sizeof(pb1), mp, "dir3/.");
    329 	if (rump_sys_rename(pb1, pb3) != -1 || errno != EINVAL)
    330 		atf_tc_fail_errno("rename 2");
    331 	if (rump_sys_rename(pb3, pb1) != -1 || errno != EISDIR)
    332 		atf_tc_fail_errno("rename 3");
    333 
    334 	checkfile(pb3, &ref);
    335 
    336 	/* rename father of directory into directory */
    337 	md(pb1, sizeof(pb1), mp, "dir2/dir");
    338 	md(pb2, sizeof(pb2), mp, "dir2");
    339 	if (rump_sys_rename(pb2, pb1) != -1 || errno != EINVAL)
    340 		atf_tc_fail_errno("rename 4");
    341 
    342 	/* same for grandfather */
    343 	md(pb1, sizeof(pb1), mp, "dir2/subdir/dir2");
    344 	if (rump_sys_rename(pb2, pb1) != -1 || errno != EINVAL)
    345 		atf_tc_fail("rename 5");
    346 
    347 	checkfile(pb3, &ref);
    348 
    349 	/* rename directory over a non-empty directory */
    350 	if (rump_sys_rename(pb2, pb3) != -1 || errno != ENOTEMPTY)
    351 		atf_tc_fail("rename 6");
    352 
    353 	/* cross-directory rename */
    354 	md(pb1, sizeof(pb1), mp, "dir3");
    355 	md(pb2, sizeof(pb2), mp, "dir2/somedir");
    356 	if (rump_sys_rename(pb1, pb2) == -1)
    357 		atf_tc_fail_errno("rename 7");
    358 	checkfile(pb2, &ref);
    359 
    360 	/* move to parent directory */
    361 	md(pb1, sizeof(pb1), mp, "dir2/somedir/../../dir3");
    362 	if (rump_sys_rename(pb2, pb1) == -1)
    363 		atf_tc_fail_errno("rename 8");
    364 	md(pb1, sizeof(pb1), mp, "dir2/../dir3");
    365 	checkfile(pb1, &ref);
    366 
    367 	/* atomic cross-directory rename */
    368 	md(pb3, sizeof(pb3), mp, "dir2/subdir");
    369 	if (rump_sys_rename(pb1, pb3) == -1)
    370 		atf_tc_fail_errno("rename 9");
    371 	checkfile(pb3, &ref);
    372 
    373 	/* rename directory over an empty directory */
    374 	md(pb1, sizeof(pb1), mp, "parent");
    375 	md(pb2, sizeof(pb2), mp, "parent/dir1");
    376 	md(pb3, sizeof(pb3), mp, "parent/dir2");
    377 	RL(rump_sys_mkdir(pb1, 0777));
    378 	RL(rump_sys_mkdir(pb2, 0777));
    379 	RL(rump_sys_mkdir(pb3, 0777));
    380 	RL(rump_sys_rename(pb2, pb3));
    381 
    382 	RL(rump_sys_stat(pb1, &sb));
    383 	if (! FSTYPE_MSDOS(tc))
    384 		ATF_CHECK_EQ(sb.st_nlink, 3);
    385 	RL(rump_sys_rmdir(pb3));
    386 	RL(rump_sys_rmdir(pb1));
    387 }
    388 
    389 static void
    390 rename_dotdot(const atf_tc_t *tc, const char *mp)
    391 {
    392 
    393 	if (FSTYPE_RUMPFS(tc))
    394 		atf_tc_skip("rename not supported by file system");
    395 
    396 	USES_DIRS;
    397 
    398 	if (rump_sys_chdir(mp) == -1)
    399 		atf_tc_fail_errno("chdir mountpoint");
    400 
    401 	if (rump_sys_mkdir("dir1", 0777) == -1)
    402 		atf_tc_fail_errno("mkdir 1");
    403 	if (rump_sys_mkdir("dir2", 0777) == -1)
    404 		atf_tc_fail_errno("mkdir 2");
    405 
    406 	if (rump_sys_rename("dir1", "dir1/..") != -1 || errno != EINVAL)
    407 		atf_tc_fail_errno("self-dotdot to");
    408 
    409 	if (rump_sys_rename("dir1/..", "sometarget") != -1 || errno != EINVAL)
    410 		atf_tc_fail_errno("self-dotdot from");
    411 
    412 	if (rump_sys_rename("dir1", "dir2/..") != -1 || errno != EINVAL)
    413 		atf_tc_fail("other-dotdot");
    414 
    415 	rump_sys_chdir("/");
    416 }
    417 
    418 static void
    419 rename_reg_nodir(const atf_tc_t *tc, const char *mp)
    420 {
    421 	bool haslinks;
    422 	struct stat sb;
    423 	ino_t f1ino;
    424 
    425 	if (FSTYPE_RUMPFS(tc))
    426 		atf_tc_skip("rename not supported by file system");
    427 
    428 	if (rump_sys_chdir(mp) == -1)
    429 		atf_tc_fail_errno("chdir mountpoint");
    430 
    431 	if (FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))
    432 		haslinks = false;
    433 	else
    434 		haslinks = true;
    435 
    436 	if (rump_sys_mknod("file1", S_IFREG | 0777, -1) == -1)
    437 		atf_tc_fail_errno("create file");
    438 	if (rump_sys_mknod("file2", S_IFREG | 0777, -1) == -1)
    439 		atf_tc_fail_errno("create file");
    440 
    441 	if (rump_sys_stat("file1", &sb) == -1)
    442 		atf_tc_fail_errno("stat");
    443 	f1ino = sb.st_ino;
    444 
    445 	if (haslinks) {
    446 		if (rump_sys_link("file1", "file_link") == -1)
    447 			atf_tc_fail_errno("link");
    448 		if (rump_sys_stat("file_link", &sb) == -1)
    449 			atf_tc_fail_errno("stat");
    450 		ATF_REQUIRE_EQ(sb.st_ino, f1ino);
    451 		ATF_REQUIRE_EQ(sb.st_nlink, 2);
    452 	}
    453 
    454 	if (rump_sys_stat("file2", &sb) == -1)
    455 		atf_tc_fail_errno("stat");
    456 
    457 	if (rump_sys_rename("file1", "file3") == -1)
    458 		atf_tc_fail_errno("rename 1");
    459 	if (rump_sys_stat("file3", &sb) == -1)
    460 		atf_tc_fail_errno("stat 1");
    461 	if (haslinks) {
    462 		ATF_REQUIRE_EQ(sb.st_ino, f1ino);
    463 	}
    464 	if (rump_sys_stat("file1", &sb) != -1 || errno != ENOENT)
    465 		atf_tc_fail_errno("source 1");
    466 
    467 	if (rump_sys_rename("file3", "file2") == -1)
    468 		atf_tc_fail_errno("rename 2");
    469 	if (rump_sys_stat("file2", &sb) == -1)
    470 		atf_tc_fail_errno("stat 2");
    471 	if (haslinks) {
    472 		ATF_REQUIRE_EQ(sb.st_ino, f1ino);
    473 	}
    474 
    475 	if (rump_sys_stat("file3", &sb) != -1 || errno != ENOENT)
    476 		atf_tc_fail_errno("source 2");
    477 
    478 	if (haslinks) {
    479 		if (rump_sys_rename("file2", "file_link") == -1)
    480 			atf_tc_fail_errno("rename hardlink");
    481 		if (rump_sys_stat("file2", &sb) != -1 || errno != ENOENT)
    482 			atf_tc_fail_errno("source 3");
    483 		if (rump_sys_stat("file_link", &sb) == -1)
    484 			atf_tc_fail_errno("stat 2");
    485 		ATF_REQUIRE_EQ(sb.st_ino, f1ino);
    486 		ATF_REQUIRE_EQ(sb.st_nlink, 1);
    487 	}
    488 
    489 	ATF_CHECK_ERRNO(EFAULT, rump_sys_rename("file2", NULL) == -1);
    490 	ATF_CHECK_ERRNO(EFAULT, rump_sys_rename(NULL, "file2") == -1);
    491 
    492 	rump_sys_chdir("/");
    493 }
    494 
    495 /* PR kern/50607 */
    496 static void
    497 create_many(const atf_tc_t *tc, const char *mp)
    498 {
    499 	char buf[64];
    500 	int nfiles = 2324; /* #Nancy */
    501 	int i;
    502 
    503 	/* takes forever with many files */
    504 	if (FSTYPE_MSDOS(tc))
    505 		nfiles /= 4;
    506 
    507 	RL(rump_sys_chdir(mp));
    508 
    509 	if (FSTYPE_SYSVBFS(tc)) {
    510 		/* fs doesn't support many files or subdirectories */
    511 		nfiles = 5;
    512 	} else {
    513 		/* msdosfs doesn't like many entries in the root directory */
    514 		RL(rump_sys_mkdir("subdir", 0777));
    515 		RL(rump_sys_chdir("subdir"));
    516 	}
    517 
    518 	/* create them */
    519 #define TESTFN "testfile"
    520 	for (i = 0; i < nfiles; i++) {
    521 		int fd;
    522 
    523 		snprintf(buf, sizeof(buf), TESTFN "%d", i);
    524 		RL(fd = rump_sys_open(buf, O_RDWR|O_CREAT|O_EXCL, 0666));
    525 		RL(rump_sys_close(fd));
    526 	}
    527 
    528 	/* wipe them out */
    529 	for (i = 0; i < nfiles; i++) {
    530 		snprintf(buf, sizeof(buf), TESTFN "%d", i);
    531 		RLF(rump_sys_unlink(buf), "%s", buf);
    532 	}
    533 #undef TESTFN
    534 
    535 	rump_sys_chdir("/");
    536 }
    537 
    538 /*
    539  * Test creating files with one-character names using all possible
    540  * character values.  Failures to create the file are ignored as the
    541  * characters allowed in file names vary by file system, but at least
    542  * we can check that the fs does not crash, and if the file is
    543  * successfully created, unlinking it should also succeed.
    544  */
    545 static void
    546 create_nonalphanum(const atf_tc_t *tc, const char *mp)
    547 {
    548 	char buf[64];
    549 	int i;
    550 
    551 	RL(rump_sys_chdir(mp));
    552 
    553 	for (i = 0; i < 256; i++) {
    554 		int fd;
    555 		snprintf(buf, sizeof(buf), "%c", i);
    556 		fd = rump_sys_open(buf, O_RDWR|O_CREAT|O_EXCL, 0666);
    557 		if (fd == -1)
    558 			continue;
    559 		RLF(rump_sys_close(fd), "%d", fd);
    560 		RLF(rump_sys_unlink(buf), "%s", buf);
    561 	}
    562 	printf("\n");
    563 
    564 	rump_sys_chdir("/");
    565 }
    566 
    567 static void
    568 create_nametoolong(const atf_tc_t *tc, const char *mp)
    569 {
    570 	char *name;
    571 	int fd;
    572 	long val;
    573 	size_t len;
    574 
    575 	if (rump_sys_chdir(mp) == -1)
    576 		atf_tc_fail_errno("chdir mountpoint");
    577 
    578 	val = rump_sys_pathconf(".", _PC_NAME_MAX);
    579 	if (val == -1)
    580 		atf_tc_fail_errno("pathconf");
    581 
    582 	len = val + 1;
    583 	name = malloc(len+1);
    584 	if (name == NULL)
    585 		atf_tc_fail_errno("malloc");
    586 
    587 	memset(name, 'a', len);
    588 	*(name+len) = '\0';
    589 
    590 	val = rump_sys_pathconf(".", _PC_NO_TRUNC);
    591 	if (val == -1)
    592 		atf_tc_fail_errno("pathconf");
    593 
    594 	fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666);
    595 	if (val != 0 && (fd != -1 || errno != ENAMETOOLONG))
    596 		atf_tc_fail_errno("open");
    597 
    598 	if (val == 0 && rump_sys_close(fd) == -1)
    599 		atf_tc_fail_errno("close");
    600 	if (val == 0 && rump_sys_unlink(name) == -1)
    601 		atf_tc_fail_errno("unlink");
    602 
    603 	free(name);
    604 
    605 	rump_sys_chdir("/");
    606 }
    607 
    608 static void
    609 create_exist(const atf_tc_t *tc, const char *mp)
    610 {
    611 	const char *name = "hoge";
    612 	int fd;
    613 
    614 	RL(rump_sys_chdir(mp));
    615 	RL(fd = rump_sys_open(name, O_RDWR|O_CREAT|O_EXCL, 0666));
    616 	RL(rump_sys_close(fd));
    617 	RL(rump_sys_unlink(name));
    618 	RL(fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666));
    619 	RL(rump_sys_close(fd));
    620 	RL(fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666));
    621 	RL(rump_sys_close(fd));
    622 	ATF_REQUIRE_ERRNO(EEXIST,
    623 	    (fd = rump_sys_open(name, O_RDWR|O_CREAT|O_EXCL, 0666)));
    624 	RL(rump_sys_unlink(name));
    625 	RL(rump_sys_chdir("/"));
    626 }
    627 
    628 static void
    629 rename_nametoolong(const atf_tc_t *tc, const char *mp)
    630 {
    631 	char *name;
    632 	int res, fd;
    633 	long val;
    634 	size_t len;
    635 
    636 	if (FSTYPE_RUMPFS(tc))
    637 		atf_tc_skip("rename not supported by file system");
    638 
    639 	if (rump_sys_chdir(mp) == -1)
    640 		atf_tc_fail_errno("chdir mountpoint");
    641 
    642 	val = rump_sys_pathconf(".", _PC_NAME_MAX);
    643 	if (val == -1)
    644 		atf_tc_fail_errno("pathconf");
    645 
    646 	len = val + 1;
    647 	name = malloc(len+1);
    648 	if (name == NULL)
    649 		atf_tc_fail_errno("malloc");
    650 
    651 	memset(name, 'a', len);
    652 	*(name+len) = '\0';
    653 
    654 	fd = rump_sys_open("dummy", O_RDWR|O_CREAT, 0666);
    655 	if (fd == -1)
    656 		atf_tc_fail_errno("open");
    657 	if (rump_sys_close(fd) == -1)
    658 		atf_tc_fail_errno("close");
    659 
    660 	val = rump_sys_pathconf(".", _PC_NO_TRUNC);
    661 	if (val == -1)
    662 		atf_tc_fail_errno("pathconf");
    663 
    664 	res = rump_sys_rename("dummy", name);
    665 	if (val != 0 && (res != -1 || errno != ENAMETOOLONG))
    666 		atf_tc_fail_errno("rename");
    667 
    668 	if (val == 0 && rump_sys_unlink(name) == -1)
    669 		atf_tc_fail_errno("unlink");
    670 
    671 	free(name);
    672 
    673 	rump_sys_chdir("/");
    674 }
    675 
    676 /*
    677  * Test creating a symlink whose length is "len" bytes, not including
    678  * the terminating NUL.
    679  */
    680 static void
    681 symlink_len(const atf_tc_t *tc, const char *mp, size_t len)
    682 {
    683 	char *buf;
    684 	int r;
    685 
    686 	USES_SYMLINKS;
    687 
    688 	RLF(rump_sys_chdir(mp), "%s", mp);
    689 
    690 	buf = malloc(len + 1);
    691 	ATF_REQUIRE(buf);
    692 	memset(buf, 'a', len);
    693 	buf[len] = '\0';
    694 	r = rump_sys_symlink(buf, "afile");
    695 	if (r == -1) {
    696 		ATF_REQUIRE_ERRNO(ENAMETOOLONG, r);
    697 	} else {
    698 		RL(rump_sys_unlink("afile"));
    699 	}
    700 	free(buf);
    701 
    702 	RL(rump_sys_chdir("/"));
    703 }
    704 
    705 static void
    706 symlink_zerolen(const atf_tc_t *tc, const char *mp)
    707 {
    708 	symlink_len(tc, mp, 0);
    709 }
    710 
    711 static void
    712 symlink_long(const atf_tc_t *tc, const char *mp)
    713 {
    714 	/*
    715 	 * Test lengths close to powers of two, as those are likely
    716 	 * to be edge cases.
    717 	 */
    718 	size_t len;
    719 	int fuzz;
    720 	for (len = 2; len <= 65536; len *= 2) {
    721 		for (fuzz = -1; fuzz <= 1; fuzz++) {
    722 			symlink_len(tc, mp, len + fuzz);
    723 		}
    724 	}
    725 }
    726 
    727 static void
    728 symlink_root(const atf_tc_t *tc, const char *mp)
    729 {
    730 
    731 	USES_SYMLINKS;
    732 
    733 	RL(rump_sys_chdir(mp));
    734 	RL(rump_sys_symlink("/", "foo"));
    735 	RL(rump_sys_chdir("foo"));
    736 }
    737 
    738 static void
    739 attrs(const atf_tc_t *tc, const char *mp)
    740 {
    741 	struct stat sb, sb2;
    742 	struct timeval tv[2];
    743 	int fd;
    744 
    745 	FSTEST_ENTER();
    746 	RL(fd = rump_sys_open(TESTFILE, O_RDWR | O_CREAT, 0755));
    747 	RL(rump_sys_close(fd));
    748 	RL(rump_sys_stat(TESTFILE, &sb));
    749 	if (!(FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))) {
    750 		RL(rump_sys_chown(TESTFILE, 1, 2));
    751 		sb.st_uid = 1;
    752 		sb.st_gid = 2;
    753 		RL(rump_sys_chmod(TESTFILE, 0123));
    754 		sb.st_mode = (sb.st_mode & ~ACCESSPERMS) | 0123;
    755 	}
    756 
    757 	tv[0].tv_sec = 1000000000; /* need something >1980 for msdosfs */
    758 	tv[0].tv_usec = 1;
    759 	tv[1].tv_sec = 1000000002; /* need even seconds for msdosfs */
    760 	tv[1].tv_usec = 3;
    761 	RL(rump_sys_utimes(TESTFILE, tv));
    762 	RL(rump_sys_utimes(TESTFILE, tv)); /* XXX: utimes & birthtime */
    763 	sb.st_atimespec.tv_sec = 1000000000;
    764 	sb.st_atimespec.tv_nsec = 1000;
    765 	sb.st_mtimespec.tv_sec = 1000000002;
    766 	sb.st_mtimespec.tv_nsec = 3000;
    767 
    768 	RL(rump_sys_stat(TESTFILE, &sb2));
    769 #define CHECK(a) ATF_REQUIRE_EQ(sb.a, sb2.a)
    770 	if (!(FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))) {
    771 		CHECK(st_uid);
    772 		CHECK(st_gid);
    773 		CHECK(st_mode);
    774 	}
    775 	if (!FSTYPE_MSDOS(tc)) {
    776 		/* msdosfs has only access date, not time */
    777 		CHECK(st_atimespec.tv_sec);
    778 	}
    779 	CHECK(st_mtimespec.tv_sec);
    780 	if (!(FSTYPE_EXT2FS(tc) || FSTYPE_MSDOS(tc) ||
    781 	      FSTYPE_SYSVBFS(tc) || FSTYPE_V7FS(tc))) {
    782 		CHECK(st_atimespec.tv_nsec);
    783 		CHECK(st_mtimespec.tv_nsec);
    784 	}
    785 #undef  CHECK
    786 
    787 	FSTEST_EXIT();
    788 }
    789 
    790 static void
    791 fcntl_lock(const atf_tc_t *tc, const char *mp)
    792 {
    793 	int fd, fd2;
    794 	struct flock l;
    795 	struct lwp *lwp1, *lwp2;
    796 
    797 	FSTEST_ENTER();
    798 	l.l_pid = 0;
    799 	l.l_start = l.l_len = 1024;
    800 	l.l_type = F_RDLCK | F_WRLCK;
    801 	l.l_whence = SEEK_END;
    802 
    803 	lwp1 = rump_pub_lwproc_curlwp();
    804 	RL(fd = rump_sys_open(TESTFILE, O_RDWR | O_CREAT, 0755));
    805 	RL(rump_sys_ftruncate(fd, 8192));
    806 
    807 	RL(rump_sys_fcntl(fd, F_SETLK, &l));
    808 
    809 	/* Next, we fork and try to lock the same area */
    810 	RZ(rump_pub_lwproc_rfork(RUMP_RFCFDG));
    811 	lwp2 = rump_pub_lwproc_curlwp();
    812 	RL(fd2 = rump_sys_open(TESTFILE, O_RDWR, 0));
    813 	ATF_REQUIRE_ERRNO(EAGAIN, rump_sys_fcntl(fd2, F_SETLK, &l));
    814 
    815 	/* Switch back and unlock... */
    816 	rump_pub_lwproc_switch(lwp1);
    817 	l.l_type = F_UNLCK;
    818 	RL(rump_sys_fcntl(fd, F_SETLK, &l));
    819 
    820 	/* ... and try to lock again */
    821 	rump_pub_lwproc_switch(lwp2);
    822 	l.l_type = F_RDLCK | F_WRLCK;
    823 	RL(rump_sys_fcntl(fd2, F_SETLK, &l));
    824 
    825 	RL(rump_sys_close(fd2));
    826 	rump_pub_lwproc_releaselwp();
    827 
    828 	RL(rump_sys_close(fd));
    829 
    830 	FSTEST_EXIT();
    831 }
    832 
    833 static int
    834 flock_compare(const void *p, const void *q)
    835 {
    836 	int a = ((const struct flock *)p)->l_start;
    837 	int b = ((const struct flock *)q)->l_start;
    838 	return a < b ? -1 : (a > b ? 1 : 0);
    839 }
    840 
    841 /*
    842  * Find all locks set by fcntl_getlock_pids test
    843  * using GETLK for a range [start, start+end], and,
    844  * if there is a blocking lock, recursively find
    845  * all locks to the left (toward the beginning of
    846  * a file) and to the right of the lock.
    847  * The function also understands "until end of file"
    848  * convention when len==0.
    849  */
    850 static unsigned int
    851 fcntl_getlocks(int fildes, off_t start, off_t len,
    852     struct flock *lock, struct flock *end)
    853 {
    854 	unsigned int rv = 0;
    855 	const struct flock l = { start, len, 0, F_RDLCK, SEEK_SET };
    856 
    857 	if (lock == end)
    858 		return rv;
    859 
    860 	RL(rump_sys_fcntl(fildes, F_GETLK, &l));
    861 
    862 	if (l.l_type == F_UNLCK)
    863 		return rv;
    864 
    865 	*lock++ = l;
    866 	rv += 1;
    867 
    868 	ATF_REQUIRE(l.l_whence == SEEK_SET);
    869 
    870 	if (l.l_start > start) {
    871 		unsigned int n =
    872 		    fcntl_getlocks(fildes, start, l.l_start - start, lock, end);
    873 		rv += n;
    874 		lock += n;
    875 		if (lock == end)
    876 			return rv;
    877 	}
    878 
    879 	if (l.l_len == 0) /* does l spans until the end? */
    880 		return rv;
    881 
    882 	if (len == 0) /* are we looking for locks until the end? */ {
    883 		rv += fcntl_getlocks(fildes, l.l_start + l.l_len, len, lock, end);
    884 	} else if (l.l_start + l.l_len < start + len) {
    885 		len -= l.l_start + l.l_len - start;
    886 		rv += fcntl_getlocks(fildes, l.l_start + l.l_len, len, lock, end);
    887 	}
    888 
    889 	return rv;
    890 }
    891 
    892 static void
    893 fcntl_getlock_pids(const atf_tc_t *tc, const char *mp)
    894 {
    895 	/* test non-overlaping ranges */
    896 	struct flock expect[4];
    897 	const struct flock lock[4] = {
    898 		{ 0, 2, 0, F_WRLCK, SEEK_SET },
    899 		{ 2, 1, 0, F_WRLCK, SEEK_SET },
    900 		{ 7, 5, 0, F_WRLCK, SEEK_SET },
    901 		{ 4, 3, 0, F_WRLCK, SEEK_SET },
    902 	};
    903 
    904     /* Add extra element to make sure recursion does't stop at array end */
    905 	struct flock result[5];
    906 
    907 	/* Add 5th process */
    908 	int fd[5];
    909 	pid_t pid[5];
    910 	struct lwp *lwp[5];
    911 
    912 	unsigned int i, j;
    913 	const off_t sz = 8192;
    914 	int omode  = 0755;
    915 	int oflags = O_RDWR | O_CREAT;
    916 
    917 	memcpy(expect, lock, sizeof(lock));
    918 
    919 	FSTEST_ENTER();
    920 
    921 	/*
    922 	 * First, we create 4 processes and let each lock a range of the
    923 	 * file.  Note that the third and fourth processes lock in
    924 	 * "reverse" order, i.e. the greater pid locks a range before
    925 	 * the lesser pid.
    926 	 * Then, we create 5th process which doesn't lock anything.
    927 	 */
    928 	for (i = 0; i < __arraycount(lwp); i++) {
    929 		RZ(rump_pub_lwproc_rfork(RUMP_RFCFDG));
    930 
    931 		lwp[i] = rump_pub_lwproc_curlwp();
    932 		pid[i] = rump_sys_getpid();
    933 
    934 		RL(fd[i] = rump_sys_open(TESTFILE, oflags, omode));
    935 		oflags = O_RDWR;
    936 		omode  = 0;
    937 
    938 		RL(rump_sys_ftruncate(fd[i], sz));
    939 
    940 		if (i < __arraycount(lock)) {
    941 			RL(rump_sys_fcntl(fd[i], F_SETLK, &lock[i]));
    942 			expect[i].l_pid = pid[i];
    943 		}
    944 	}
    945 
    946 	qsort(expect, __arraycount(expect), sizeof(expect[0]), &flock_compare);
    947 
    948 	/*
    949 	 * In the context of each process, recursively find all locks
    950 	 * that would block the current process. Processes 1-4 don't
    951 	 * see their own lock, we insert it to simplify checks.
    952 	 * Process 5 sees all 4 locks.
    953 	 */
    954 	for (i = 0; i < __arraycount(lwp); i++) {
    955 		unsigned int nlocks;
    956 
    957 		rump_pub_lwproc_switch(lwp[i]);
    958 
    959 		memset(result, 0, sizeof(result));
    960 		nlocks = fcntl_getlocks(fd[i], 0, sz,
    961 		    result, result + __arraycount(result));
    962 
    963 		if (i < __arraycount(lock)) {
    964 			ATF_REQUIRE(nlocks < __arraycount(result));
    965 			result[nlocks] = lock[i];
    966 			result[nlocks].l_pid = pid[i];
    967 			nlocks++;
    968 		}
    969 
    970 		ATF_CHECK_EQ(nlocks, __arraycount(expect));
    971 
    972 		qsort(result, nlocks, sizeof(result[0]), &flock_compare);
    973 
    974 		for (j = 0; j < nlocks; j++) {
    975 			ATF_CHECK_EQ(result[j].l_start,  expect[j].l_start );
    976 			ATF_CHECK_EQ(result[j].l_len,    expect[j].l_len   );
    977 			ATF_CHECK_EQ(result[j].l_pid,    expect[j].l_pid   );
    978 			ATF_CHECK_EQ(result[j].l_type,   expect[j].l_type  );
    979 			ATF_CHECK_EQ(result[j].l_whence, expect[j].l_whence);
    980 		}
    981 	}
    982 
    983 	/*
    984 	 * Release processes.  This also releases the fds and locks
    985 	 * making fs unmount possible
    986 	 */
    987 	for (i = 0; i < __arraycount(lwp); i++) {
    988 		rump_pub_lwproc_switch(lwp[i]);
    989 		rump_pub_lwproc_releaselwp();
    990 	}
    991 
    992 	FSTEST_EXIT();
    993 }
    994 
    995 static void
    996 access_simple(const atf_tc_t *tc, const char *mp)
    997 {
    998 	int fd;
    999 	int tmode;
   1000 
   1001 	FSTEST_ENTER();
   1002 	RL(fd = rump_sys_open("tfile", O_CREAT | O_RDWR, 0777));
   1003 	RL(rump_sys_close(fd));
   1004 
   1005 #define ALLACC (F_OK | X_OK | W_OK | R_OK)
   1006 	if (FSTYPE_SYSVBFS(tc) || FSTYPE_MSDOS(tc))
   1007 		tmode = F_OK;
   1008 	else
   1009 		tmode = ALLACC;
   1010 
   1011 	RL(rump_sys_access("tfile", tmode));
   1012 
   1013 	/* PR kern/44648 */
   1014 	ATF_REQUIRE_ERRNO(EINVAL, rump_sys_access("tfile", ALLACC+1) == -1);
   1015 #undef ALLACC
   1016 	FSTEST_EXIT();
   1017 }
   1018 
   1019 static void
   1020 read_directory(const atf_tc_t *tc, const char *mp)
   1021 {
   1022 	char buf[1024];
   1023 	int fd, res;
   1024 	ssize_t size;
   1025 
   1026 	FSTEST_ENTER();
   1027 	fd = rump_sys_open(".", O_DIRECTORY | O_RDONLY, 0777);
   1028 	ATF_REQUIRE(fd != -1);
   1029 
   1030 	size = rump_sys_pread(fd, buf, sizeof(buf), 0);
   1031 	ATF_CHECK(size != -1 || errno == EISDIR);
   1032 	size = rump_sys_read(fd, buf, sizeof(buf));
   1033 	ATF_CHECK(size != -1 || errno == EISDIR);
   1034 
   1035 	res = rump_sys_close(fd);
   1036 	ATF_REQUIRE(res != -1);
   1037 	FSTEST_EXIT();
   1038 }
   1039 
   1040 static void
   1041 lstat_symlink(const atf_tc_t *tc, const char *mp)
   1042 {
   1043 	const char *src, *dst;
   1044 	int res;
   1045 	struct stat st;
   1046 
   1047 	USES_SYMLINKS;
   1048 
   1049 	FSTEST_ENTER();
   1050 
   1051 	src = "source";
   1052 	dst = "destination";
   1053 
   1054 	res = rump_sys_symlink(src, dst);
   1055 	ATF_REQUIRE(res != -1);
   1056 	res = rump_sys_lstat(dst, &st);
   1057 	ATF_REQUIRE(res != -1);
   1058 
   1059 	ATF_CHECK(S_ISLNK(st.st_mode) != 0);
   1060 	ATF_CHECK(st.st_size == (off_t)strlen(src));
   1061 
   1062 	FSTEST_EXIT();
   1063 }
   1064 
   1065 ATF_TC_FSAPPLY(lookup_simple, "simple lookup (./.. on root)");
   1066 ATF_TC_FSAPPLY(lookup_complex, "lookup of non-dot entries");
   1067 ATF_TC_FSAPPLY(dir_simple, "mkdir/rmdir");
   1068 ATF_TC_FSAPPLY(dir_slash, "mkdir with appended slash");
   1069 ATF_TC_FSAPPLY(dir_2slash, "mkdir with two slashes appended");
   1070 ATF_TC_FSAPPLY(dir_3slash, "mkdir with three slashes appended");
   1071 ATF_TC_FSAPPLY(dir_notempty, "non-empty directories cannot be removed");
   1072 ATF_TC_FSAPPLY(dir_rmdirdotdot, "remove .. and try to cd out (PR kern/44657)");
   1073 ATF_TC_FSAPPLY(rename_dir, "exercise various directory renaming ops "
   1074 "(PR kern/44288)");
   1075 ATF_TC_FSAPPLY(rename_dotdot, "rename dir .. (PR kern/43617)");
   1076 ATF_TC_FSAPPLY(rename_reg_nodir, "rename regular files, no subdirectories");
   1077 ATF_TC_FSAPPLY(create_nametoolong, "create file with name too long");
   1078 ATF_TC_FSAPPLY(create_exist, "create with O_EXCL");
   1079 ATF_TC_FSAPPLY(rename_nametoolong, "rename to file with name too long");
   1080 ATF_TC_FSAPPLY(symlink_zerolen, "symlink with target of length 0");
   1081 ATF_TC_FSAPPLY(symlink_long, "symlink with target of length > 0");
   1082 ATF_TC_FSAPPLY(symlink_root, "symlink to root directory");
   1083 ATF_TC_FSAPPLY(attrs, "check setting attributes works");
   1084 ATF_TC_FSAPPLY(fcntl_lock, "check fcntl F_SETLK");
   1085 ATF_TC_FSAPPLY(fcntl_getlock_pids,"fcntl F_GETLK w/ many procs, PR kern/44494");
   1086 ATF_TC_FSAPPLY(access_simple, "access(2)");
   1087 ATF_TC_FSAPPLY(read_directory, "read(2) on directories");
   1088 ATF_TC_FSAPPLY(lstat_symlink, "lstat(2) values for symbolic links");
   1089 
   1090 #undef FSTEST_IMGSIZE
   1091 #define FSTEST_IMGSIZE (1024*1024*64)
   1092 ATF_TC_FSAPPLY(create_many, "create many directory entries");
   1093 ATF_TC_FSAPPLY(create_nonalphanum, "non-alphanumeric filenames");
   1094 
   1095 ATF_TP_ADD_TCS(tp)
   1096 {
   1097 
   1098 	ATF_TP_FSAPPLY(lookup_simple);
   1099 	ATF_TP_FSAPPLY(lookup_complex);
   1100 	ATF_TP_FSAPPLY(dir_simple);
   1101 	ATF_TP_FSAPPLY(dir_notempty);
   1102 	ATF_TP_FSAPPLY(dir_rmdirdotdot);
   1103 	ATF_TP_FSAPPLY(dir_slash);
   1104 	ATF_TP_FSAPPLY(dir_2slash);
   1105 	ATF_TP_FSAPPLY(dir_3slash);
   1106 	ATF_TP_FSAPPLY(rename_dir);
   1107 	ATF_TP_FSAPPLY(rename_dotdot);
   1108 	ATF_TP_FSAPPLY(rename_reg_nodir);
   1109 	ATF_TP_FSAPPLY(create_many);
   1110 	ATF_TP_FSAPPLY(create_nonalphanum);
   1111 	ATF_TP_FSAPPLY(create_nametoolong);
   1112 	ATF_TP_FSAPPLY(create_exist);
   1113 	ATF_TP_FSAPPLY(rename_nametoolong);
   1114 	ATF_TP_FSAPPLY(symlink_zerolen);
   1115 	ATF_TP_FSAPPLY(symlink_long);
   1116 	ATF_TP_FSAPPLY(symlink_root);
   1117 	ATF_TP_FSAPPLY(attrs);
   1118 	ATF_TP_FSAPPLY(fcntl_lock);
   1119 	ATF_TP_FSAPPLY(fcntl_getlock_pids);
   1120 	ATF_TP_FSAPPLY(access_simple);
   1121 	ATF_TP_FSAPPLY(read_directory);
   1122 	ATF_TP_FSAPPLY(lstat_symlink);
   1123 
   1124 	return atf_no_error();
   1125 }
   1126