Home | History | Annotate | Line # | Download | only in vfs
t_vnops.c revision 1.59
      1 /*	$NetBSD: t_vnops.c,v 1.59 2017/01/13 21:30:40 christos 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 tp 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 came 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 ouput 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 then 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 dir_notempty(const atf_tc_t *tc, const char *mountpath)
    179 {
    180 	char pb[MAXPATHLEN], pb2[MAXPATHLEN];
    181 	int fd, rv;
    182 
    183 	USES_DIRS;
    184 
    185 	/* check we can create directories */
    186 	snprintf(pb, sizeof(pb), "%s/dir", mountpath);
    187 	if (rump_sys_mkdir(pb, 0777) == -1)
    188 		atf_tc_fail_errno("mkdir");
    189 
    190 	snprintf(pb2, sizeof(pb2), "%s/dir/file", mountpath);
    191 	fd = rump_sys_open(pb2, O_RDWR | O_CREAT, 0777);
    192 	if (fd == -1)
    193 		atf_tc_fail_errno("create file");
    194 	rump_sys_close(fd);
    195 
    196 	rv = rump_sys_rmdir(pb);
    197 	if (rv != -1 || errno != ENOTEMPTY)
    198 		atf_tc_fail("non-empty directory removed succesfully");
    199 
    200 	if (rump_sys_unlink(pb2) == -1)
    201 		atf_tc_fail_errno("cannot remove dir/file");
    202 
    203 	if (rump_sys_rmdir(pb) == -1)
    204 		atf_tc_fail_errno("remove directory");
    205 }
    206 
    207 static void
    208 dir_rmdirdotdot(const atf_tc_t *tc, const char *mp)
    209 {
    210 	char pb[MAXPATHLEN];
    211 	int xerrno;
    212 
    213 	USES_DIRS;
    214 
    215 	FSTEST_ENTER();
    216 	RL(rump_sys_mkdir("test", 0777));
    217 	RL(rump_sys_chdir("test"));
    218 
    219 	RL(rump_sys_mkdir("subtest", 0777));
    220 	RL(rump_sys_chdir("subtest"));
    221 
    222 	md(pb, sizeof(pb), mp, "test/subtest");
    223 	RL(rump_sys_rmdir(pb));
    224 	md(pb, sizeof(pb), mp, "test");
    225 	RL(rump_sys_rmdir(pb));
    226 
    227 	if (FSTYPE_NFS(tc))
    228 		xerrno = ESTALE;
    229 	else
    230 		xerrno = ENOENT;
    231 	ATF_REQUIRE_ERRNO(xerrno, rump_sys_chdir("..") == -1);
    232 	FSTEST_EXIT();
    233 }
    234 
    235 static void
    236 checkfile(const char *path, struct stat *refp)
    237 {
    238 	char buf[MAXPATHLEN];
    239 	struct stat sb;
    240 	static int n = 1;
    241 
    242 	md(buf, sizeof(buf), path, "file");
    243 	if (rump_sys_stat(buf, &sb) == -1)
    244 		atf_tc_fail_errno("cannot stat file %d (%s)", n, buf);
    245 	if (memcmp(&sb, refp, sizeof(sb)) != 0)
    246 		atf_tc_fail("stat mismatch %d", n);
    247 	n++;
    248 }
    249 
    250 static void
    251 rename_dir(const atf_tc_t *tc, const char *mp)
    252 {
    253 	char pb1[MAXPATHLEN], pb2[MAXPATHLEN], pb3[MAXPATHLEN];
    254 	struct stat ref, sb;
    255 
    256 	if (FSTYPE_RUMPFS(tc))
    257 		atf_tc_skip("rename not supported by file system");
    258 
    259 	USES_DIRS;
    260 
    261 	md(pb1, sizeof(pb1), mp, "dir1");
    262 	if (rump_sys_mkdir(pb1, 0777) == -1)
    263 		atf_tc_fail_errno("mkdir 1");
    264 
    265 	md(pb2, sizeof(pb2), mp, "dir2");
    266 	if (rump_sys_mkdir(pb2, 0777) == -1)
    267 		atf_tc_fail_errno("mkdir 2");
    268 	md(pb2, sizeof(pb2), mp, "dir2/subdir");
    269 	if (rump_sys_mkdir(pb2, 0777) == -1)
    270 		atf_tc_fail_errno("mkdir 3");
    271 
    272 	md(pb3, sizeof(pb3), mp, "dir1/file");
    273 	if (rump_sys_mknod(pb3, S_IFREG | 0777, -1) == -1)
    274 		atf_tc_fail_errno("create file");
    275 	if (rump_sys_stat(pb3, &ref) == -1)
    276 		atf_tc_fail_errno("stat of file");
    277 
    278 	/*
    279 	 * First try ops which should succeed.
    280 	 */
    281 
    282 	/* rename within directory */
    283 	md(pb3, sizeof(pb3), mp, "dir3");
    284 	if (rump_sys_rename(pb1, pb3) == -1)
    285 		atf_tc_fail_errno("rename 1");
    286 	checkfile(pb3, &ref);
    287 
    288 	/* rename directory onto itself (two ways, should fail) */
    289 	md(pb1, sizeof(pb1), mp, "dir3/.");
    290 	if (rump_sys_rename(pb1, pb3) != -1 || errno != EINVAL)
    291 		atf_tc_fail_errno("rename 2");
    292 	if (rump_sys_rename(pb3, pb1) != -1 || errno != EISDIR)
    293 		atf_tc_fail_errno("rename 3");
    294 
    295 	checkfile(pb3, &ref);
    296 
    297 	/* rename father of directory into directory */
    298 	md(pb1, sizeof(pb1), mp, "dir2/dir");
    299 	md(pb2, sizeof(pb2), mp, "dir2");
    300 	if (rump_sys_rename(pb2, pb1) != -1 || errno != EINVAL)
    301 		atf_tc_fail_errno("rename 4");
    302 
    303 	/* same for grandfather */
    304 	md(pb1, sizeof(pb1), mp, "dir2/subdir/dir2");
    305 	if (rump_sys_rename(pb2, pb1) != -1 || errno != EINVAL)
    306 		atf_tc_fail("rename 5");
    307 
    308 	checkfile(pb3, &ref);
    309 
    310 	/* rename directory over a non-empty directory */
    311 	if (rump_sys_rename(pb2, pb3) != -1 || errno != ENOTEMPTY)
    312 		atf_tc_fail("rename 6");
    313 
    314 	/* cross-directory rename */
    315 	md(pb1, sizeof(pb1), mp, "dir3");
    316 	md(pb2, sizeof(pb2), mp, "dir2/somedir");
    317 	if (rump_sys_rename(pb1, pb2) == -1)
    318 		atf_tc_fail_errno("rename 7");
    319 	checkfile(pb2, &ref);
    320 
    321 	/* move to parent directory */
    322 	md(pb1, sizeof(pb1), mp, "dir2/somedir/../../dir3");
    323 	if (rump_sys_rename(pb2, pb1) == -1)
    324 		atf_tc_fail_errno("rename 8");
    325 	md(pb1, sizeof(pb1), mp, "dir2/../dir3");
    326 	checkfile(pb1, &ref);
    327 
    328 	/* atomic cross-directory rename */
    329 	md(pb3, sizeof(pb3), mp, "dir2/subdir");
    330 	if (rump_sys_rename(pb1, pb3) == -1)
    331 		atf_tc_fail_errno("rename 9");
    332 	checkfile(pb3, &ref);
    333 
    334 	/* rename directory over an empty directory */
    335 	md(pb1, sizeof(pb1), mp, "parent");
    336 	md(pb2, sizeof(pb2), mp, "parent/dir1");
    337 	md(pb3, sizeof(pb3), mp, "parent/dir2");
    338 	RL(rump_sys_mkdir(pb1, 0777));
    339 	RL(rump_sys_mkdir(pb2, 0777));
    340 	RL(rump_sys_mkdir(pb3, 0777));
    341 	RL(rump_sys_rename(pb2, pb3));
    342 
    343 	RL(rump_sys_stat(pb1, &sb));
    344 	if (! FSTYPE_MSDOS(tc))
    345 		ATF_CHECK_EQ(sb.st_nlink, 3);
    346 	RL(rump_sys_rmdir(pb3));
    347 	RL(rump_sys_rmdir(pb1));
    348 }
    349 
    350 static void
    351 rename_dotdot(const atf_tc_t *tc, const char *mp)
    352 {
    353 
    354 	if (FSTYPE_RUMPFS(tc))
    355 		atf_tc_skip("rename not supported by file system");
    356 
    357 	USES_DIRS;
    358 
    359 	if (rump_sys_chdir(mp) == -1)
    360 		atf_tc_fail_errno("chdir mountpoint");
    361 
    362 	if (rump_sys_mkdir("dir1", 0777) == -1)
    363 		atf_tc_fail_errno("mkdir 1");
    364 	if (rump_sys_mkdir("dir2", 0777) == -1)
    365 		atf_tc_fail_errno("mkdir 2");
    366 
    367 	if (rump_sys_rename("dir1", "dir1/..") != -1 || errno != EINVAL)
    368 		atf_tc_fail_errno("self-dotdot to");
    369 
    370 	if (rump_sys_rename("dir1/..", "sometarget") != -1 || errno != EINVAL)
    371 		atf_tc_fail_errno("self-dotdot from");
    372 
    373 	if (rump_sys_rename("dir1", "dir2/..") != -1 || errno != EINVAL)
    374 		atf_tc_fail("other-dotdot");
    375 
    376 	rump_sys_chdir("/");
    377 }
    378 
    379 static void
    380 rename_reg_nodir(const atf_tc_t *tc, const char *mp)
    381 {
    382 	bool haslinks;
    383 	struct stat sb;
    384 	ino_t f1ino;
    385 
    386 	if (FSTYPE_RUMPFS(tc))
    387 		atf_tc_skip("rename not supported by file system");
    388 
    389 	if (rump_sys_chdir(mp) == -1)
    390 		atf_tc_fail_errno("chdir mountpoint");
    391 
    392 	if (FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))
    393 		haslinks = false;
    394 	else
    395 		haslinks = true;
    396 
    397 	if (rump_sys_mknod("file1", S_IFREG | 0777, -1) == -1)
    398 		atf_tc_fail_errno("create file");
    399 	if (rump_sys_mknod("file2", S_IFREG | 0777, -1) == -1)
    400 		atf_tc_fail_errno("create file");
    401 
    402 	if (rump_sys_stat("file1", &sb) == -1)
    403 		atf_tc_fail_errno("stat");
    404 	f1ino = sb.st_ino;
    405 
    406 	if (haslinks) {
    407 		if (rump_sys_link("file1", "file_link") == -1)
    408 			atf_tc_fail_errno("link");
    409 		if (rump_sys_stat("file_link", &sb) == -1)
    410 			atf_tc_fail_errno("stat");
    411 		ATF_REQUIRE_EQ(sb.st_ino, f1ino);
    412 		ATF_REQUIRE_EQ(sb.st_nlink, 2);
    413 	}
    414 
    415 	if (rump_sys_stat("file2", &sb) == -1)
    416 		atf_tc_fail_errno("stat");
    417 
    418 	if (rump_sys_rename("file1", "file3") == -1)
    419 		atf_tc_fail_errno("rename 1");
    420 	if (rump_sys_stat("file3", &sb) == -1)
    421 		atf_tc_fail_errno("stat 1");
    422 	if (haslinks) {
    423 		ATF_REQUIRE_EQ(sb.st_ino, f1ino);
    424 	}
    425 	if (rump_sys_stat("file1", &sb) != -1 || errno != ENOENT)
    426 		atf_tc_fail_errno("source 1");
    427 
    428 	if (rump_sys_rename("file3", "file2") == -1)
    429 		atf_tc_fail_errno("rename 2");
    430 	if (rump_sys_stat("file2", &sb) == -1)
    431 		atf_tc_fail_errno("stat 2");
    432 	if (haslinks) {
    433 		ATF_REQUIRE_EQ(sb.st_ino, f1ino);
    434 	}
    435 
    436 	if (rump_sys_stat("file3", &sb) != -1 || errno != ENOENT)
    437 		atf_tc_fail_errno("source 2");
    438 
    439 	if (haslinks) {
    440 		if (rump_sys_rename("file2", "file_link") == -1)
    441 			atf_tc_fail_errno("rename hardlink");
    442 		if (rump_sys_stat("file2", &sb) != -1 || errno != ENOENT)
    443 			atf_tc_fail_errno("source 3");
    444 		if (rump_sys_stat("file_link", &sb) == -1)
    445 			atf_tc_fail_errno("stat 2");
    446 		ATF_REQUIRE_EQ(sb.st_ino, f1ino);
    447 		ATF_REQUIRE_EQ(sb.st_nlink, 1);
    448 	}
    449 
    450 	ATF_CHECK_ERRNO(EFAULT, rump_sys_rename("file2", NULL) == -1);
    451 	ATF_CHECK_ERRNO(EFAULT, rump_sys_rename(NULL, "file2") == -1);
    452 
    453 	rump_sys_chdir("/");
    454 }
    455 
    456 /* PR kern/50607 */
    457 static void
    458 create_many(const atf_tc_t *tc, const char *mp)
    459 {
    460 	char buf[64];
    461 	int nfiles = 2324; /* #Nancy */
    462 	int i;
    463 
    464 	/* takes forever with many files */
    465 	if (FSTYPE_MSDOS(tc))
    466 		nfiles /= 4;
    467 
    468 	RL(rump_sys_chdir(mp));
    469 
    470 	if (FSTYPE_SYSVBFS(tc)) {
    471 		/* fs doesn't support many files or subdirectories */
    472 		nfiles = 5;
    473 	} else {
    474 		/* msdosfs doesn't like many entries in the root directory */
    475 		RL(rump_sys_mkdir("subdir", 0777));
    476 		RL(rump_sys_chdir("subdir"));
    477 	}
    478 
    479 	/* create them */
    480 #define TESTFN "testfile"
    481 	for (i = 0; i < nfiles; i++) {
    482 		int fd;
    483 
    484 		snprintf(buf, sizeof(buf), TESTFN "%d", i);
    485 		RL(fd = rump_sys_open(buf, O_RDWR|O_CREAT|O_EXCL, 0666));
    486 		RL(rump_sys_close(fd));
    487 	}
    488 
    489 	/* wipe them out */
    490 	for (i = 0; i < nfiles; i++) {
    491 		snprintf(buf, sizeof(buf), TESTFN "%d", i);
    492 		RLF(rump_sys_unlink(buf), "%s", buf);
    493 	}
    494 #undef TESTFN
    495 
    496 	rump_sys_chdir("/");
    497 }
    498 
    499 /*
    500  * Test creating files with one-character names using all possible
    501  * character values.  Failures to create the file are ignored as the
    502  * characters allowed in file names vary by file system, but at least
    503  * we can check that the fs does not crash, and if the file is
    504  * successfully created, unlinking it should also succeed.
    505  */
    506 static void
    507 create_nonalphanum(const atf_tc_t *tc, const char *mp)
    508 {
    509 	char buf[64];
    510 	int i;
    511 
    512 	RL(rump_sys_chdir(mp));
    513 
    514 	for (i = 0; i < 256; i++) {
    515 		int fd;
    516 		snprintf(buf, sizeof(buf), "%c", i);
    517 		fd = rump_sys_open(buf, O_RDWR|O_CREAT|O_EXCL, 0666);
    518 		if (fd == -1)
    519 			continue;
    520 		RLF(rump_sys_close(fd), "%d", fd);
    521 		RLF(rump_sys_unlink(buf), "%s", buf);
    522 	}
    523 	printf("\n");
    524 
    525 	rump_sys_chdir("/");
    526 }
    527 
    528 static void
    529 create_nametoolong(const atf_tc_t *tc, const char *mp)
    530 {
    531 	char *name;
    532 	int fd;
    533 	long val;
    534 	size_t len;
    535 
    536 	if (rump_sys_chdir(mp) == -1)
    537 		atf_tc_fail_errno("chdir mountpoint");
    538 
    539 	val = rump_sys_pathconf(".", _PC_NAME_MAX);
    540 	if (val == -1)
    541 		atf_tc_fail_errno("pathconf");
    542 
    543 	len = val + 1;
    544 	name = malloc(len+1);
    545 	if (name == NULL)
    546 		atf_tc_fail_errno("malloc");
    547 
    548 	memset(name, 'a', len);
    549 	*(name+len) = '\0';
    550 
    551 	val = rump_sys_pathconf(".", _PC_NO_TRUNC);
    552 	if (val == -1)
    553 		atf_tc_fail_errno("pathconf");
    554 
    555 	fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666);
    556 	if (val != 0 && (fd != -1 || errno != ENAMETOOLONG))
    557 		atf_tc_fail_errno("open");
    558 
    559 	if (val == 0 && rump_sys_close(fd) == -1)
    560 		atf_tc_fail_errno("close");
    561 	if (val == 0 && rump_sys_unlink(name) == -1)
    562 		atf_tc_fail_errno("unlink");
    563 
    564 	free(name);
    565 
    566 	rump_sys_chdir("/");
    567 }
    568 
    569 static void
    570 create_exist(const atf_tc_t *tc, const char *mp)
    571 {
    572 	const char *name = "hoge";
    573 	int fd;
    574 
    575 	RL(rump_sys_chdir(mp));
    576 	RL(fd = rump_sys_open(name, O_RDWR|O_CREAT|O_EXCL, 0666));
    577 	RL(rump_sys_close(fd));
    578 	RL(rump_sys_unlink(name));
    579 	RL(fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666));
    580 	RL(rump_sys_close(fd));
    581 	RL(fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666));
    582 	RL(rump_sys_close(fd));
    583 	ATF_REQUIRE_ERRNO(EEXIST,
    584 	    (fd = rump_sys_open(name, O_RDWR|O_CREAT|O_EXCL, 0666)));
    585 	RL(rump_sys_unlink(name));
    586 	RL(rump_sys_chdir("/"));
    587 }
    588 
    589 static void
    590 rename_nametoolong(const atf_tc_t *tc, const char *mp)
    591 {
    592 	char *name;
    593 	int res, fd;
    594 	long val;
    595 	size_t len;
    596 
    597 	if (FSTYPE_RUMPFS(tc))
    598 		atf_tc_skip("rename not supported by file system");
    599 
    600 	if (rump_sys_chdir(mp) == -1)
    601 		atf_tc_fail_errno("chdir mountpoint");
    602 
    603 	val = rump_sys_pathconf(".", _PC_NAME_MAX);
    604 	if (val == -1)
    605 		atf_tc_fail_errno("pathconf");
    606 
    607 	len = val + 1;
    608 	name = malloc(len+1);
    609 	if (name == NULL)
    610 		atf_tc_fail_errno("malloc");
    611 
    612 	memset(name, 'a', len);
    613 	*(name+len) = '\0';
    614 
    615 	fd = rump_sys_open("dummy", O_RDWR|O_CREAT, 0666);
    616 	if (fd == -1)
    617 		atf_tc_fail_errno("open");
    618 	if (rump_sys_close(fd) == -1)
    619 		atf_tc_fail_errno("close");
    620 
    621 	val = rump_sys_pathconf(".", _PC_NO_TRUNC);
    622 	if (val == -1)
    623 		atf_tc_fail_errno("pathconf");
    624 
    625 	res = rump_sys_rename("dummy", name);
    626 	if (val != 0 && (res != -1 || errno != ENAMETOOLONG))
    627 		atf_tc_fail_errno("rename");
    628 
    629 	if (val == 0 && rump_sys_unlink(name) == -1)
    630 		atf_tc_fail_errno("unlink");
    631 
    632 	free(name);
    633 
    634 	rump_sys_chdir("/");
    635 }
    636 
    637 /*
    638  * Test creating a symlink whose length is "len" bytes, not including
    639  * the terminating NUL.
    640  */
    641 static void
    642 symlink_len(const atf_tc_t *tc, const char *mp, size_t len)
    643 {
    644 	char *buf;
    645 	int r;
    646 
    647 	USES_SYMLINKS;
    648 
    649 	RLF(rump_sys_chdir(mp), "%s", mp);
    650 
    651 	buf = malloc(len + 1);
    652 	ATF_REQUIRE(buf);
    653 	memset(buf, 'a', len);
    654 	buf[len] = '\0';
    655 	r = rump_sys_symlink(buf, "afile");
    656 	if (r == -1) {
    657 		ATF_REQUIRE_ERRNO(ENAMETOOLONG, r);
    658 	} else {
    659 		RL(rump_sys_unlink("afile"));
    660 	}
    661 	free(buf);
    662 
    663 	RL(rump_sys_chdir("/"));
    664 }
    665 
    666 static void
    667 symlink_zerolen(const atf_tc_t *tc, const char *mp)
    668 {
    669 	symlink_len(tc, mp, 0);
    670 }
    671 
    672 static void
    673 symlink_long(const atf_tc_t *tc, const char *mp)
    674 {
    675 	/*
    676 	 * Test lengths close to powers of two, as those are likely
    677 	 * to be edge cases.
    678 	 */
    679 	size_t len;
    680 	int fuzz;
    681 	for (len = 2; len <= 65536; len *= 2) {
    682 		for (fuzz = -1; fuzz <= 1; fuzz++) {
    683 			symlink_len(tc, mp, len + fuzz);
    684 		}
    685 	}
    686 }
    687 
    688 static void
    689 symlink_root(const atf_tc_t *tc, const char *mp)
    690 {
    691 
    692 	USES_SYMLINKS;
    693 
    694 	RL(rump_sys_chdir(mp));
    695 	RL(rump_sys_symlink("/", "foo"));
    696 	RL(rump_sys_chdir("foo"));
    697 }
    698 
    699 static void
    700 attrs(const atf_tc_t *tc, const char *mp)
    701 {
    702 	struct stat sb, sb2;
    703 	struct timeval tv[2];
    704 	int fd;
    705 
    706 	FSTEST_ENTER();
    707 	RL(fd = rump_sys_open(TESTFILE, O_RDWR | O_CREAT, 0755));
    708 	RL(rump_sys_close(fd));
    709 	RL(rump_sys_stat(TESTFILE, &sb));
    710 	if (!(FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))) {
    711 		RL(rump_sys_chown(TESTFILE, 1, 2));
    712 		sb.st_uid = 1;
    713 		sb.st_gid = 2;
    714 		RL(rump_sys_chmod(TESTFILE, 0123));
    715 		sb.st_mode = (sb.st_mode & ~ACCESSPERMS) | 0123;
    716 	}
    717 
    718 	tv[0].tv_sec = 1000000000; /* need something >1980 for msdosfs */
    719 	tv[0].tv_usec = 1;
    720 	tv[1].tv_sec = 1000000002; /* need even seconds for msdosfs */
    721 	tv[1].tv_usec = 3;
    722 	RL(rump_sys_utimes(TESTFILE, tv));
    723 	RL(rump_sys_utimes(TESTFILE, tv)); /* XXX: utimes & birthtime */
    724 	sb.st_atimespec.tv_sec = 1000000000;
    725 	sb.st_atimespec.tv_nsec = 1000;
    726 	sb.st_mtimespec.tv_sec = 1000000002;
    727 	sb.st_mtimespec.tv_nsec = 3000;
    728 
    729 	RL(rump_sys_stat(TESTFILE, &sb2));
    730 #define CHECK(a) ATF_REQUIRE_EQ(sb.a, sb2.a)
    731 	if (!(FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))) {
    732 		CHECK(st_uid);
    733 		CHECK(st_gid);
    734 		CHECK(st_mode);
    735 	}
    736 	if (!FSTYPE_MSDOS(tc)) {
    737 		/* msdosfs has only access date, not time */
    738 		CHECK(st_atimespec.tv_sec);
    739 	}
    740 	CHECK(st_mtimespec.tv_sec);
    741 	if (!(FSTYPE_EXT2FS(tc) || FSTYPE_MSDOS(tc) ||
    742 	      FSTYPE_SYSVBFS(tc) || FSTYPE_V7FS(tc))) {
    743 		CHECK(st_atimespec.tv_nsec);
    744 		CHECK(st_mtimespec.tv_nsec);
    745 	}
    746 #undef  CHECK
    747 
    748 	FSTEST_EXIT();
    749 }
    750 
    751 static void
    752 fcntl_lock(const atf_tc_t *tc, const char *mp)
    753 {
    754 	int fd, fd2;
    755 	struct flock l;
    756 	struct lwp *lwp1, *lwp2;
    757 
    758 	FSTEST_ENTER();
    759 	l.l_pid = 0;
    760 	l.l_start = l.l_len = 1024;
    761 	l.l_type = F_RDLCK | F_WRLCK;
    762 	l.l_whence = SEEK_END;
    763 
    764 	lwp1 = rump_pub_lwproc_curlwp();
    765 	RL(fd = rump_sys_open(TESTFILE, O_RDWR | O_CREAT, 0755));
    766 	RL(rump_sys_ftruncate(fd, 8192));
    767 
    768 	RL(rump_sys_fcntl(fd, F_SETLK, &l));
    769 
    770 	/* Next, we fork and try to lock the same area */
    771 	RZ(rump_pub_lwproc_rfork(RUMP_RFCFDG));
    772 	lwp2 = rump_pub_lwproc_curlwp();
    773 	RL(fd2 = rump_sys_open(TESTFILE, O_RDWR, 0));
    774 	ATF_REQUIRE_ERRNO(EAGAIN, rump_sys_fcntl(fd2, F_SETLK, &l));
    775 
    776 	/* Switch back and unlock... */
    777 	rump_pub_lwproc_switch(lwp1);
    778 	l.l_type = F_UNLCK;
    779 	RL(rump_sys_fcntl(fd, F_SETLK, &l));
    780 
    781 	/* ... and try to lock again */
    782 	rump_pub_lwproc_switch(lwp2);
    783 	l.l_type = F_RDLCK | F_WRLCK;
    784 	RL(rump_sys_fcntl(fd2, F_SETLK, &l));
    785 
    786 	RL(rump_sys_close(fd2));
    787 	rump_pub_lwproc_releaselwp();
    788 
    789 	RL(rump_sys_close(fd));
    790 
    791 	FSTEST_EXIT();
    792 }
    793 
    794 static int
    795 flock_compare(const void *p, const void *q)
    796 {
    797 	int a = ((const struct flock *)p)->l_start;
    798 	int b = ((const struct flock *)q)->l_start;
    799 	return a < b ? -1 : (a > b ? 1 : 0);
    800 }
    801 
    802 /*
    803  * Find all locks set by fcntl_getlock_pids test
    804  * using GETLK for a range [start, start+end], and,
    805  * if there is a blocking lock, recursively find
    806  * all locks to the left (toward the beginning of
    807  * a file) and to the right of the lock.
    808  * The function also understands "until end of file"
    809  * convention when len==0.
    810  */
    811 static unsigned int
    812 fcntl_getlocks(int fildes, off_t start, off_t len,
    813     struct flock *lock, struct flock *end)
    814 {
    815 	unsigned int rv = 0;
    816 	const struct flock l = { start, len, 0, F_RDLCK, SEEK_SET };
    817 
    818 	if (lock == end)
    819 		return rv;
    820 
    821 	RL(rump_sys_fcntl(fildes, F_GETLK, &l));
    822 
    823 	if (l.l_type == F_UNLCK)
    824 		return rv;
    825 
    826 	*lock++ = l;
    827 	rv += 1;
    828 
    829 	ATF_REQUIRE(l.l_whence == SEEK_SET);
    830 
    831 	if (l.l_start > start) {
    832 		unsigned int n =
    833 		    fcntl_getlocks(fildes, start, l.l_start - start, lock, end);
    834 		rv += n;
    835 		lock += n;
    836 		if (lock == end)
    837 			return rv;
    838 	}
    839 
    840 	if (l.l_len == 0) /* does l spans until the end? */
    841 		return rv;
    842 
    843 	if (len == 0) /* are we looking for locks until the end? */ {
    844 		rv += fcntl_getlocks(fildes, l.l_start + l.l_len, len, lock, end);
    845 	} else if (l.l_start + l.l_len < start + len) {
    846 		len -= l.l_start + l.l_len - start;
    847 		rv += fcntl_getlocks(fildes, l.l_start + l.l_len, len, lock, end);
    848 	}
    849 
    850 	return rv;
    851 }
    852 
    853 static void
    854 fcntl_getlock_pids(const atf_tc_t *tc, const char *mp)
    855 {
    856 	/* test non-overlaping ranges */
    857 	struct flock expect[4];
    858 	const struct flock lock[4] = {
    859 		{ 0, 2, 0, F_WRLCK, SEEK_SET },
    860 		{ 2, 1, 0, F_WRLCK, SEEK_SET },
    861 		{ 7, 5, 0, F_WRLCK, SEEK_SET },
    862 		{ 4, 3, 0, F_WRLCK, SEEK_SET },
    863 	};
    864 
    865     /* Add extra element to make sure recursion does't stop at array end */
    866 	struct flock result[5];
    867 
    868 	/* Add 5th process */
    869 	int fd[5];
    870 	pid_t pid[5];
    871 	struct lwp *lwp[5];
    872 
    873 	unsigned int i, j;
    874 	const off_t sz = 8192;
    875 	int omode  = 0755;
    876 	int oflags = O_RDWR | O_CREAT;
    877 
    878 	memcpy(expect, lock, sizeof(lock));
    879 
    880 	FSTEST_ENTER();
    881 
    882 	/*
    883 	 * First, we create 4 processes and let each lock a range of the
    884 	 * file.  Note that the third and fourth processes lock in
    885 	 * "reverse" order, i.e. the greater pid locks a range before
    886 	 * the lesser pid.
    887 	 * Then, we create 5th process which doesn't lock anything.
    888 	 */
    889 	for (i = 0; i < __arraycount(lwp); i++) {
    890 		RZ(rump_pub_lwproc_rfork(RUMP_RFCFDG));
    891 
    892 		lwp[i] = rump_pub_lwproc_curlwp();
    893 		pid[i] = rump_sys_getpid();
    894 
    895 		RL(fd[i] = rump_sys_open(TESTFILE, oflags, omode));
    896 		oflags = O_RDWR;
    897 		omode  = 0;
    898 
    899 		RL(rump_sys_ftruncate(fd[i], sz));
    900 
    901 		if (i < __arraycount(lock)) {
    902 			RL(rump_sys_fcntl(fd[i], F_SETLK, &lock[i]));
    903 			expect[i].l_pid = pid[i];
    904 		}
    905 	}
    906 
    907 	qsort(expect, __arraycount(expect), sizeof(expect[0]), &flock_compare);
    908 
    909 	/*
    910 	 * In the context of each process, recursively find all locks
    911 	 * that would block the current process. Processes 1-4 don't
    912 	 * see their own lock, we insert it to simplify checks.
    913 	 * Process 5 sees all 4 locks.
    914 	 */
    915 	for (i = 0; i < __arraycount(lwp); i++) {
    916 		unsigned int nlocks;
    917 
    918 		rump_pub_lwproc_switch(lwp[i]);
    919 
    920 		memset(result, 0, sizeof(result));
    921 		nlocks = fcntl_getlocks(fd[i], 0, sz,
    922 		    result, result + __arraycount(result));
    923 
    924 		if (i < __arraycount(lock)) {
    925 			ATF_REQUIRE(nlocks < __arraycount(result));
    926 			result[nlocks] = lock[i];
    927 			result[nlocks].l_pid = pid[i];
    928 			nlocks++;
    929 		}
    930 
    931 		ATF_CHECK_EQ(nlocks, __arraycount(expect));
    932 
    933 		qsort(result, nlocks, sizeof(result[0]), &flock_compare);
    934 
    935 		for (j = 0; j < nlocks; j++) {
    936 			ATF_CHECK_EQ(result[j].l_start,  expect[j].l_start );
    937 			ATF_CHECK_EQ(result[j].l_len,    expect[j].l_len   );
    938 			ATF_CHECK_EQ(result[j].l_pid,    expect[j].l_pid   );
    939 			ATF_CHECK_EQ(result[j].l_type,   expect[j].l_type  );
    940 			ATF_CHECK_EQ(result[j].l_whence, expect[j].l_whence);
    941 		}
    942 	}
    943 
    944 	/*
    945 	 * Release processes.  This also releases the fds and locks
    946 	 * making fs unmount possible
    947 	 */
    948 	for (i = 0; i < __arraycount(lwp); i++) {
    949 		rump_pub_lwproc_switch(lwp[i]);
    950 		rump_pub_lwproc_releaselwp();
    951 	}
    952 
    953 	FSTEST_EXIT();
    954 }
    955 
    956 static void
    957 access_simple(const atf_tc_t *tc, const char *mp)
    958 {
    959 	int fd;
    960 	int tmode;
    961 
    962 	FSTEST_ENTER();
    963 	RL(fd = rump_sys_open("tfile", O_CREAT | O_RDWR, 0777));
    964 	RL(rump_sys_close(fd));
    965 
    966 #define ALLACC (F_OK | X_OK | W_OK | R_OK)
    967 	if (FSTYPE_SYSVBFS(tc) || FSTYPE_MSDOS(tc))
    968 		tmode = F_OK;
    969 	else
    970 		tmode = ALLACC;
    971 
    972 	RL(rump_sys_access("tfile", tmode));
    973 
    974 	/* PR kern/44648 */
    975 	ATF_REQUIRE_ERRNO(EINVAL, rump_sys_access("tfile", ALLACC+1) == -1);
    976 #undef ALLACC
    977 	FSTEST_EXIT();
    978 }
    979 
    980 static void
    981 read_directory(const atf_tc_t *tc, const char *mp)
    982 {
    983 	char buf[1024];
    984 	int fd, res;
    985 	ssize_t size;
    986 
    987 	FSTEST_ENTER();
    988 	fd = rump_sys_open(".", O_DIRECTORY | O_RDONLY, 0777);
    989 	ATF_REQUIRE(fd != -1);
    990 
    991 	size = rump_sys_pread(fd, buf, sizeof(buf), 0);
    992 	ATF_CHECK(size != -1 || errno == EISDIR);
    993 	size = rump_sys_read(fd, buf, sizeof(buf));
    994 	ATF_CHECK(size != -1 || errno == EISDIR);
    995 
    996 	res = rump_sys_close(fd);
    997 	ATF_REQUIRE(res != -1);
    998 	FSTEST_EXIT();
    999 }
   1000 
   1001 static void
   1002 lstat_symlink(const atf_tc_t *tc, const char *mp)
   1003 {
   1004 	const char *src, *dst;
   1005 	int res;
   1006 	struct stat st;
   1007 
   1008 	USES_SYMLINKS;
   1009 
   1010 	FSTEST_ENTER();
   1011 
   1012 	src = "source";
   1013 	dst = "destination";
   1014 
   1015 	res = rump_sys_symlink(src, dst);
   1016 	ATF_REQUIRE(res != -1);
   1017 	res = rump_sys_lstat(dst, &st);
   1018 	ATF_REQUIRE(res != -1);
   1019 
   1020 	ATF_CHECK(S_ISLNK(st.st_mode) != 0);
   1021 	ATF_CHECK(st.st_size == (off_t)strlen(src));
   1022 
   1023 	FSTEST_EXIT();
   1024 }
   1025 
   1026 ATF_TC_FSAPPLY(lookup_simple, "simple lookup (./.. on root)");
   1027 ATF_TC_FSAPPLY(lookup_complex, "lookup of non-dot entries");
   1028 ATF_TC_FSAPPLY(dir_simple, "mkdir/rmdir");
   1029 ATF_TC_FSAPPLY(dir_notempty, "non-empty directories cannot be removed");
   1030 ATF_TC_FSAPPLY(dir_rmdirdotdot, "remove .. and try to cd out (PR kern/44657)");
   1031 ATF_TC_FSAPPLY(rename_dir, "exercise various directory renaming ops "
   1032 "(PR kern/44288)");
   1033 ATF_TC_FSAPPLY(rename_dotdot, "rename dir .. (PR kern/43617)");
   1034 ATF_TC_FSAPPLY(rename_reg_nodir, "rename regular files, no subdirectories");
   1035 ATF_TC_FSAPPLY(create_nametoolong, "create file with name too long");
   1036 ATF_TC_FSAPPLY(create_exist, "create with O_EXCL");
   1037 ATF_TC_FSAPPLY(rename_nametoolong, "rename to file with name too long");
   1038 ATF_TC_FSAPPLY(symlink_zerolen, "symlink with target of length 0");
   1039 ATF_TC_FSAPPLY(symlink_long, "symlink with target of length > 0");
   1040 ATF_TC_FSAPPLY(symlink_root, "symlink to root directory");
   1041 ATF_TC_FSAPPLY(attrs, "check setting attributes works");
   1042 ATF_TC_FSAPPLY(fcntl_lock, "check fcntl F_SETLK");
   1043 ATF_TC_FSAPPLY(fcntl_getlock_pids,"fcntl F_GETLK w/ many procs, PR kern/44494");
   1044 ATF_TC_FSAPPLY(access_simple, "access(2)");
   1045 ATF_TC_FSAPPLY(read_directory, "read(2) on directories");
   1046 ATF_TC_FSAPPLY(lstat_symlink, "lstat(2) values for symbolic links");
   1047 
   1048 #undef FSTEST_IMGSIZE
   1049 #define FSTEST_IMGSIZE (1024*1024*64)
   1050 ATF_TC_FSAPPLY(create_many, "create many directory entries");
   1051 ATF_TC_FSAPPLY(create_nonalphanum, "non-alphanumeric filenames");
   1052 
   1053 ATF_TP_ADD_TCS(tp)
   1054 {
   1055 
   1056 	ATF_TP_FSAPPLY(lookup_simple);
   1057 	ATF_TP_FSAPPLY(lookup_complex);
   1058 	ATF_TP_FSAPPLY(dir_simple);
   1059 	ATF_TP_FSAPPLY(dir_notempty);
   1060 	ATF_TP_FSAPPLY(dir_rmdirdotdot);
   1061 	ATF_TP_FSAPPLY(rename_dir);
   1062 	ATF_TP_FSAPPLY(rename_dotdot);
   1063 	ATF_TP_FSAPPLY(rename_reg_nodir);
   1064 	ATF_TP_FSAPPLY(create_many);
   1065 	ATF_TP_FSAPPLY(create_nonalphanum);
   1066 	ATF_TP_FSAPPLY(create_nametoolong);
   1067 	ATF_TP_FSAPPLY(create_exist);
   1068 	ATF_TP_FSAPPLY(rename_nametoolong);
   1069 	ATF_TP_FSAPPLY(symlink_zerolen);
   1070 	ATF_TP_FSAPPLY(symlink_long);
   1071 	ATF_TP_FSAPPLY(symlink_root);
   1072 	ATF_TP_FSAPPLY(attrs);
   1073 	ATF_TP_FSAPPLY(fcntl_lock);
   1074 	ATF_TP_FSAPPLY(fcntl_getlock_pids);
   1075 	ATF_TP_FSAPPLY(access_simple);
   1076 	ATF_TP_FSAPPLY(read_directory);
   1077 	ATF_TP_FSAPPLY(lstat_symlink);
   1078 
   1079 	return atf_no_error();
   1080 }
   1081