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