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