1 // Copyright 2010 The Kyua Authors. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // * Neither the name of Google Inc. nor the names of its contributors 14 // may be used to endorse or promote products derived from this software 15 // without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 #include "utils/fs/operations.hpp" 30 31 extern "C" { 32 #include <sys/types.h> 33 #include <sys/stat.h> 34 #include <sys/wait.h> 35 36 #include <dirent.h> 37 #include <signal.h> 38 #include <unistd.h> 39 } 40 41 #include <cerrno> 42 #include <cstdlib> 43 #include <cstring> 44 #include <iostream> 45 #include <stdexcept> 46 #include <string> 47 #include <vector> 48 49 #include <atf-c++.hpp> 50 51 #include "utils/env.hpp" 52 #include "utils/format/containers.ipp" 53 #include "utils/format/macros.hpp" 54 #include "utils/fs/directory.hpp" 55 #include "utils/fs/exceptions.hpp" 56 #include "utils/fs/path.hpp" 57 #include "utils/optional.ipp" 58 #include "utils/passwd.hpp" 59 #include "utils/stream.hpp" 60 #include "utils/units.hpp" 61 62 namespace fs = utils::fs; 63 namespace passwd = utils::passwd; 64 namespace units = utils::units; 65 66 using utils::optional; 67 68 69 namespace { 70 71 72 /// Checks if a directory entry exists and matches a specific type. 73 /// 74 /// \param dir The directory in which to look for the entry. 75 /// \param name The name of the entry to look up. 76 /// \param expected_type The expected type of the file as given by dir(5). 77 /// 78 /// \return True if the entry exists and matches the given type; false 79 /// otherwise. 80 static bool 81 lookup(const char* dir, const char* name, const unsigned int expected_type) 82 { 83 DIR* dirp = ::opendir(dir); 84 ATF_REQUIRE(dirp != NULL); 85 86 bool found = false; 87 struct dirent* dp; 88 while (!found && (dp = readdir(dirp)) != NULL) { 89 if (std::strcmp(dp->d_name, name) == 0) { 90 struct ::stat s; 91 const fs::path lookup_path = fs::path(dir) / name; 92 ATF_REQUIRE(::stat(lookup_path.c_str(), &s) != -1); 93 if ((s.st_mode & S_IFMT) == expected_type) { 94 found = true; 95 } 96 } 97 } 98 ::closedir(dirp); 99 return found; 100 } 101 102 103 } // anonymous namespace 104 105 106 ATF_TEST_CASE_WITHOUT_HEAD(copy__ok); 107 ATF_TEST_CASE_BODY(copy__ok) 108 { 109 const fs::path source("f1.txt"); 110 const fs::path target("f2.txt"); 111 112 atf::utils::create_file(source.str(), "This is the input"); 113 fs::copy(source, target); 114 ATF_REQUIRE(atf::utils::compare_file(target.str(), "This is the input")); 115 } 116 117 118 ATF_TEST_CASE_WITHOUT_HEAD(copy__fail_open); 119 ATF_TEST_CASE_BODY(copy__fail_open) 120 { 121 const fs::path source("f1.txt"); 122 const fs::path target("f2.txt"); 123 124 ATF_REQUIRE_THROW_RE(fs::error, "Cannot open copy source f1.txt", 125 fs::copy(source, target)); 126 } 127 128 129 ATF_TEST_CASE(copy__fail_create); 130 ATF_TEST_CASE_HEAD(copy__fail_create) 131 { 132 set_md_var("require.user", "unprivileged"); 133 } 134 ATF_TEST_CASE_BODY(copy__fail_create) 135 { 136 const fs::path source("f1.txt"); 137 const fs::path target("f2.txt"); 138 139 atf::utils::create_file(target.str(), "Do not override"); 140 ATF_REQUIRE(::chmod(target.c_str(), 0444) != -1); 141 142 atf::utils::create_file(source.str(), "This is the input"); 143 ATF_REQUIRE_THROW_RE(fs::error, "Cannot create copy target f2.txt", 144 fs::copy(source, target)); 145 } 146 147 148 ATF_TEST_CASE_WITHOUT_HEAD(current_path__ok); 149 ATF_TEST_CASE_BODY(current_path__ok) 150 { 151 const fs::path previous = fs::current_path(); 152 fs::mkdir(fs::path("root"), 0755); 153 ATF_REQUIRE(::chdir("root") != -1); 154 const fs::path cwd = fs::current_path(); 155 ATF_REQUIRE_EQ(cwd.str().length() - 5, cwd.str().find("/root")); 156 ATF_REQUIRE_EQ(previous / "root", cwd); 157 } 158 159 160 ATF_TEST_CASE_WITHOUT_HEAD(current_path__enoent); 161 ATF_TEST_CASE_BODY(current_path__enoent) 162 { 163 const fs::path previous = fs::current_path(); 164 fs::mkdir(fs::path("root"), 0755); 165 ATF_REQUIRE(::chdir("root") != -1); 166 ATF_REQUIRE(::rmdir("../root") != -1); 167 try { 168 (void)fs::current_path(); 169 fail("system_errpr not raised"); 170 } catch (const fs::system_error& e) { 171 ATF_REQUIRE_EQ(ENOENT, e.original_errno()); 172 } 173 } 174 175 176 ATF_TEST_CASE_WITHOUT_HEAD(exists); 177 ATF_TEST_CASE_BODY(exists) 178 { 179 const fs::path dir("dir"); 180 ATF_REQUIRE(!fs::exists(dir)); 181 fs::mkdir(dir, 0755); 182 ATF_REQUIRE(fs::exists(dir)); 183 } 184 185 186 ATF_TEST_CASE_WITHOUT_HEAD(find_in_path__no_path); 187 ATF_TEST_CASE_BODY(find_in_path__no_path) 188 { 189 utils::unsetenv("PATH"); 190 ATF_REQUIRE(!fs::find_in_path("ls")); 191 atf::utils::create_file("ls", ""); 192 ATF_REQUIRE(!fs::find_in_path("ls")); 193 } 194 195 196 ATF_TEST_CASE_WITHOUT_HEAD(find_in_path__empty_path); 197 ATF_TEST_CASE_BODY(find_in_path__empty_path) 198 { 199 utils::setenv("PATH", ""); 200 ATF_REQUIRE(!fs::find_in_path("ls")); 201 atf::utils::create_file("ls", ""); 202 ATF_REQUIRE(!fs::find_in_path("ls")); 203 } 204 205 206 ATF_TEST_CASE_WITHOUT_HEAD(find_in_path__one_component); 207 ATF_TEST_CASE_BODY(find_in_path__one_component) 208 { 209 const fs::path dir = fs::current_path() / "bin"; 210 fs::mkdir(dir, 0755); 211 utils::setenv("PATH", dir.str()); 212 213 ATF_REQUIRE(!fs::find_in_path("ls")); 214 atf::utils::create_file((dir / "ls").str(), ""); 215 ATF_REQUIRE_EQ(dir / "ls", fs::find_in_path("ls").get()); 216 } 217 218 219 ATF_TEST_CASE_WITHOUT_HEAD(find_in_path__many_components); 220 ATF_TEST_CASE_BODY(find_in_path__many_components) 221 { 222 const fs::path dir1 = fs::current_path() / "dir1"; 223 const fs::path dir2 = fs::current_path() / "dir2"; 224 fs::mkdir(dir1, 0755); 225 fs::mkdir(dir2, 0755); 226 utils::setenv("PATH", dir1.str() + ":" + dir2.str()); 227 228 ATF_REQUIRE(!fs::find_in_path("ls")); 229 atf::utils::create_file((dir2 / "ls").str(), ""); 230 ATF_REQUIRE_EQ(dir2 / "ls", fs::find_in_path("ls").get()); 231 atf::utils::create_file((dir1 / "ls").str(), ""); 232 ATF_REQUIRE_EQ(dir1 / "ls", fs::find_in_path("ls").get()); 233 } 234 235 236 ATF_TEST_CASE_WITHOUT_HEAD(find_in_path__current_directory); 237 ATF_TEST_CASE_BODY(find_in_path__current_directory) 238 { 239 utils::setenv("PATH", "bin:"); 240 241 ATF_REQUIRE(!fs::find_in_path("foo-bar")); 242 atf::utils::create_file("foo-bar", ""); 243 ATF_REQUIRE_EQ(fs::path("foo-bar").to_absolute(), 244 fs::find_in_path("foo-bar").get()); 245 } 246 247 248 ATF_TEST_CASE_WITHOUT_HEAD(find_in_path__always_absolute); 249 ATF_TEST_CASE_BODY(find_in_path__always_absolute) 250 { 251 fs::mkdir(fs::path("my-bin"), 0755); 252 utils::setenv("PATH", "my-bin"); 253 254 ATF_REQUIRE(!fs::find_in_path("abcd")); 255 atf::utils::create_file("my-bin/abcd", ""); 256 ATF_REQUIRE_EQ(fs::path("my-bin/abcd").to_absolute(), 257 fs::find_in_path("abcd").get()); 258 } 259 260 261 ATF_TEST_CASE_WITHOUT_HEAD(free_disk_space__ok__smoke); 262 ATF_TEST_CASE_BODY(free_disk_space__ok__smoke) 263 { 264 const units::bytes space = fs::free_disk_space(fs::path(".")); 265 ATF_REQUIRE(space > units::MB); // Simple test that should always pass. 266 } 267 268 269 /// Unmounts a directory without raising errors. 270 /// 271 /// \param cookie Name of a file that exists while the mount point is still 272 /// mounted. Used to prevent a double-unmount, which would print a 273 /// misleading error message. 274 /// \param mount_point Path to the mount point to unmount. 275 static void 276 cleanup_mount_point(const fs::path& cookie, const fs::path& mount_point) 277 { 278 try { 279 if (fs::exists(cookie)) { 280 fs::unmount(mount_point); 281 } 282 } catch (const std::runtime_error& e) { 283 std::cerr << "Failed trying to unmount " + mount_point.str() + 284 " during cleanup: " << e.what() << '\n'; 285 } 286 } 287 288 289 ATF_TEST_CASE_WITH_CLEANUP(free_disk_space__ok__real); 290 ATF_TEST_CASE_HEAD(free_disk_space__ok__real) 291 { 292 set_md_var("require.user", "root"); 293 } 294 ATF_TEST_CASE_BODY(free_disk_space__ok__real) 295 { 296 try { 297 const fs::path mount_point("mount_point"); 298 fs::mkdir(mount_point, 0755); 299 fs::mount_tmpfs(mount_point, units::bytes(32 * units::MB)); 300 atf::utils::create_file("mounted", ""); 301 const units::bytes space = fs::free_disk_space(fs::path(mount_point)); 302 fs::unmount(mount_point); 303 fs::unlink(fs::path("mounted")); 304 ATF_REQUIRE(space < 35 * units::MB); 305 ATF_REQUIRE(space > 28 * units::MB); 306 } catch (const fs::unsupported_operation_error& e) { 307 ATF_SKIP(e.what()); 308 } 309 } 310 ATF_TEST_CASE_CLEANUP(free_disk_space__ok__real) 311 { 312 cleanup_mount_point(fs::path("mounted"), fs::path("mount_point")); 313 } 314 315 316 ATF_TEST_CASE_WITHOUT_HEAD(free_disk_space__fail); 317 ATF_TEST_CASE_BODY(free_disk_space__fail) 318 { 319 ATF_REQUIRE_THROW_RE(fs::error, "Failed to stat file system for missing", 320 fs::free_disk_space(fs::path("missing"))); 321 } 322 323 324 ATF_TEST_CASE_WITHOUT_HEAD(is_directory__ok); 325 ATF_TEST_CASE_BODY(is_directory__ok) 326 { 327 const fs::path file("file"); 328 atf::utils::create_file(file.str(), ""); 329 ATF_REQUIRE(!fs::is_directory(file)); 330 331 const fs::path dir("dir"); 332 fs::mkdir(dir, 0755); 333 ATF_REQUIRE(fs::is_directory(dir)); 334 } 335 336 337 ATF_TEST_CASE_WITH_CLEANUP(is_directory__fail); 338 ATF_TEST_CASE_HEAD(is_directory__fail) 339 { 340 set_md_var("require.user", "unprivileged"); 341 } 342 ATF_TEST_CASE_BODY(is_directory__fail) 343 { 344 fs::mkdir(fs::path("dir"), 0000); 345 ATF_REQUIRE_THROW(fs::error, fs::is_directory(fs::path("dir/foo"))); 346 } 347 ATF_TEST_CASE_CLEANUP(is_directory__fail) 348 { 349 if (::chmod("dir", 0755) == -1) { 350 // If we cannot restore the original permissions, we cannot do much 351 // more. However, leaving an unwritable directory behind will cause the 352 // runtime engine to report us as broken. 353 } 354 } 355 356 357 ATF_TEST_CASE_WITHOUT_HEAD(mkdir__ok); 358 ATF_TEST_CASE_BODY(mkdir__ok) 359 { 360 fs::mkdir(fs::path("dir"), 0755); 361 ATF_REQUIRE(lookup(".", "dir", S_IFDIR)); 362 } 363 364 365 ATF_TEST_CASE_WITHOUT_HEAD(mkdir__enoent); 366 ATF_TEST_CASE_BODY(mkdir__enoent) 367 { 368 try { 369 fs::mkdir(fs::path("dir1/dir2"), 0755); 370 fail("system_error not raised"); 371 } catch (const fs::system_error& e) { 372 ATF_REQUIRE_EQ(ENOENT, e.original_errno()); 373 } 374 ATF_REQUIRE(!lookup(".", "dir1", S_IFDIR)); 375 ATF_REQUIRE(!lookup(".", "dir2", S_IFDIR)); 376 } 377 378 379 ATF_TEST_CASE_WITHOUT_HEAD(mkdir_p__one_component); 380 ATF_TEST_CASE_BODY(mkdir_p__one_component) 381 { 382 ATF_REQUIRE(!lookup(".", "new-dir", S_IFDIR)); 383 fs::mkdir_p(fs::path("new-dir"), 0755); 384 ATF_REQUIRE(lookup(".", "new-dir", S_IFDIR)); 385 } 386 387 388 ATF_TEST_CASE_WITHOUT_HEAD(mkdir_p__many_components); 389 ATF_TEST_CASE_BODY(mkdir_p__many_components) 390 { 391 ATF_REQUIRE(!lookup(".", "a", S_IFDIR)); 392 fs::mkdir_p(fs::path("a/b/c"), 0755); 393 ATF_REQUIRE(lookup(".", "a", S_IFDIR)); 394 ATF_REQUIRE(lookup("a", "b", S_IFDIR)); 395 ATF_REQUIRE(lookup("a/b", "c", S_IFDIR)); 396 } 397 398 399 ATF_TEST_CASE_WITHOUT_HEAD(mkdir_p__already_exists); 400 ATF_TEST_CASE_BODY(mkdir_p__already_exists) 401 { 402 fs::mkdir(fs::path("a"), 0755); 403 fs::mkdir(fs::path("a/b"), 0755); 404 fs::mkdir_p(fs::path("a/b"), 0755); 405 } 406 407 408 ATF_TEST_CASE(mkdir_p__eacces) 409 ATF_TEST_CASE_HEAD(mkdir_p__eacces) 410 { 411 set_md_var("require.user", "unprivileged"); 412 } 413 ATF_TEST_CASE_BODY(mkdir_p__eacces) 414 { 415 fs::mkdir(fs::path("a"), 0755); 416 fs::mkdir(fs::path("a/b"), 0755); 417 ATF_REQUIRE(::chmod("a/b", 0555) != -1); 418 try { 419 fs::mkdir_p(fs::path("a/b/c/d"), 0755); 420 fail("system_error not raised"); 421 } catch (const fs::system_error& e) { 422 ATF_REQUIRE_EQ(EACCES, e.original_errno()); 423 } 424 ATF_REQUIRE(lookup(".", "a", S_IFDIR)); 425 ATF_REQUIRE(lookup("a", "b", S_IFDIR)); 426 ATF_REQUIRE(!lookup(".", "c", S_IFDIR)); 427 ATF_REQUIRE(!lookup("a", "c", S_IFDIR)); 428 ATF_REQUIRE(!lookup("a/b", "c", S_IFDIR)); 429 } 430 431 432 ATF_TEST_CASE_WITHOUT_HEAD(mkdtemp_public) 433 ATF_TEST_CASE_BODY(mkdtemp_public) 434 { 435 const fs::path tmpdir = fs::current_path() / "tmp"; 436 utils::setenv("TMPDIR", tmpdir.str()); 437 fs::mkdir(tmpdir, 0755); 438 439 const std::string dir_template("tempdir.XXXXXX"); 440 const fs::path tempdir = fs::mkdtemp_public(dir_template); 441 ATF_REQUIRE(!lookup("tmp", dir_template.c_str(), S_IFDIR)); 442 ATF_REQUIRE(lookup("tmp", tempdir.leaf_name().c_str(), S_IFDIR)); 443 } 444 445 446 ATF_TEST_CASE(mkdtemp_public__getcwd_as_non_root) 447 ATF_TEST_CASE_HEAD(mkdtemp_public__getcwd_as_non_root) 448 { 449 set_md_var("require.config", "unprivileged-user"); 450 set_md_var("require.user", "root"); 451 } 452 ATF_TEST_CASE_BODY(mkdtemp_public__getcwd_as_non_root) 453 { 454 const std::string dir_template("dir.XXXXXX"); 455 const fs::path dir = fs::mkdtemp_public(dir_template); 456 const fs::path subdir = dir / "subdir"; 457 fs::mkdir(subdir, 0755); 458 459 const uid_t old_euid = ::geteuid(); 460 const gid_t old_egid = ::getegid(); 461 462 const passwd::user unprivileged_user = passwd::find_user_by_name( 463 get_config_var("unprivileged-user")); 464 ATF_REQUIRE(::setegid(unprivileged_user.gid) != -1); 465 ATF_REQUIRE(::seteuid(unprivileged_user.uid) != -1); 466 467 // The next code block runs as non-root. We cannot use any ATF macros nor 468 // functions in it because a failure would cause the test to attempt to 469 // write to the ATF result file which may not be writable as non-root. 470 bool failed = false; 471 { 472 try { 473 if (::chdir(subdir.c_str()) == -1) { 474 std::cerr << "Cannot enter directory\n"; 475 failed |= true; 476 } else { 477 fs::current_path(); 478 } 479 } catch (const fs::error& e) { 480 failed |= true; 481 std::cerr << "Failed to query current path in: " << subdir << '\n'; 482 } 483 484 if (::seteuid(old_euid) == -1) { 485 std::cerr << "Failed to restore euid; cannot continue\n"; 486 std::abort(); 487 } 488 if (::setegid(old_egid) == -1) { 489 std::cerr << "Failed to restore egid; cannot continue\n"; 490 std::abort(); 491 } 492 } 493 494 if (failed) 495 fail("Test failed; see stdout for details"); 496 } 497 498 499 ATF_TEST_CASE(mkdtemp_public__search_permissions_as_non_root) 500 ATF_TEST_CASE_HEAD(mkdtemp_public__search_permissions_as_non_root) 501 { 502 set_md_var("require.config", "unprivileged-user"); 503 set_md_var("require.user", "root"); 504 } 505 ATF_TEST_CASE_BODY(mkdtemp_public__search_permissions_as_non_root) 506 { 507 const std::string dir_template("dir.XXXXXX"); 508 const fs::path dir = fs::mkdtemp_public(dir_template); 509 const fs::path cookie = dir / "not-secret"; 510 atf::utils::create_file(cookie.str(), "this is readable"); 511 512 // We are running as root so there is no reason to assume that our current 513 // work directory is accessible by non-root. Weaken the permissions so that 514 // our code below works. 515 ATF_REQUIRE(::chmod(".", 0755) != -1); 516 517 const uid_t old_euid = ::geteuid(); 518 const gid_t old_egid = ::getegid(); 519 520 const passwd::user unprivileged_user = passwd::find_user_by_name( 521 get_config_var("unprivileged-user")); 522 ATF_REQUIRE(::setegid(unprivileged_user.gid) != -1); 523 ATF_REQUIRE(::seteuid(unprivileged_user.uid) != -1); 524 525 // The next code block runs as non-root. We cannot use any ATF macros nor 526 // functions in it because a failure would cause the test to attempt to 527 // write to the ATF result file which may not be writable as non-root. 528 bool failed = false; 529 { 530 try { 531 const std::string contents = utils::read_file(cookie); 532 std::cerr << "Read contents: " << contents << '\n'; 533 failed |= (contents != "this is readable"); 534 } catch (const std::runtime_error& e) { 535 failed |= true; 536 std::cerr << "Failed to read " << cookie << '\n'; 537 } 538 539 if (::seteuid(old_euid) == -1) { 540 std::cerr << "Failed to restore euid; cannot continue\n"; 541 std::abort(); 542 } 543 if (::setegid(old_egid) == -1) { 544 std::cerr << "Failed to restore egid; cannot continue\n"; 545 std::abort(); 546 } 547 } 548 549 if (failed) 550 fail("Test failed; see stdout for details"); 551 } 552 553 554 ATF_TEST_CASE_WITHOUT_HEAD(mkstemp) 555 ATF_TEST_CASE_BODY(mkstemp) 556 { 557 const fs::path tmpdir = fs::current_path() / "tmp"; 558 utils::setenv("TMPDIR", tmpdir.str()); 559 fs::mkdir(tmpdir, 0755); 560 561 const std::string file_template("tempfile.XXXXXX"); 562 const fs::path tempfile = fs::mkstemp(file_template); 563 ATF_REQUIRE(!lookup("tmp", file_template.c_str(), S_IFREG)); 564 ATF_REQUIRE(lookup("tmp", tempfile.leaf_name().c_str(), S_IFREG)); 565 } 566 567 568 static void 569 test_mount_tmpfs_ok(const units::bytes& size) 570 { 571 const fs::path mount_point("mount_point"); 572 fs::mkdir(mount_point, 0755); 573 574 try { 575 atf::utils::create_file("outside", ""); 576 fs::mount_tmpfs(mount_point, size); 577 atf::utils::create_file("mounted", ""); 578 atf::utils::create_file((mount_point / "inside").str(), ""); 579 580 struct ::stat outside, inside; 581 ATF_REQUIRE(::stat("outside", &outside) != -1); 582 ATF_REQUIRE(::stat((mount_point / "inside").c_str(), &inside) != -1); 583 ATF_REQUIRE(outside.st_dev != inside.st_dev); 584 fs::unmount(mount_point); 585 } catch (const fs::unsupported_operation_error& e) { 586 ATF_SKIP(e.what()); 587 } 588 } 589 590 591 ATF_TEST_CASE_WITH_CLEANUP(mount_tmpfs__ok__default_size) 592 ATF_TEST_CASE_HEAD(mount_tmpfs__ok__default_size) 593 { 594 set_md_var("require.user", "root"); 595 } 596 ATF_TEST_CASE_BODY(mount_tmpfs__ok__default_size) 597 { 598 test_mount_tmpfs_ok(units::bytes()); 599 } 600 ATF_TEST_CASE_CLEANUP(mount_tmpfs__ok__default_size) 601 { 602 cleanup_mount_point(fs::path("mounted"), fs::path("mount_point")); 603 } 604 605 606 ATF_TEST_CASE_WITH_CLEANUP(mount_tmpfs__ok__explicit_size) 607 ATF_TEST_CASE_HEAD(mount_tmpfs__ok__explicit_size) 608 { 609 set_md_var("require.user", "root"); 610 } 611 ATF_TEST_CASE_BODY(mount_tmpfs__ok__explicit_size) 612 { 613 test_mount_tmpfs_ok(units::bytes(10 * units::MB)); 614 } 615 ATF_TEST_CASE_CLEANUP(mount_tmpfs__ok__explicit_size) 616 { 617 cleanup_mount_point(fs::path("mounted"), fs::path("mount_point")); 618 } 619 620 621 ATF_TEST_CASE(mount_tmpfs__fail) 622 ATF_TEST_CASE_HEAD(mount_tmpfs__fail) 623 { 624 set_md_var("require.user", "root"); 625 } 626 ATF_TEST_CASE_BODY(mount_tmpfs__fail) 627 { 628 try { 629 fs::mount_tmpfs(fs::path("non-existent")); 630 } catch (const fs::unsupported_operation_error& e) { 631 ATF_SKIP(e.what()); 632 } catch (const fs::error& e) { 633 // Expected. 634 } 635 } 636 637 638 ATF_TEST_CASE_WITHOUT_HEAD(rm_r__empty); 639 ATF_TEST_CASE_BODY(rm_r__empty) 640 { 641 fs::mkdir(fs::path("root"), 0755); 642 ATF_REQUIRE(lookup(".", "root", S_IFDIR)); 643 fs::rm_r(fs::path("root")); 644 ATF_REQUIRE(!lookup(".", "root", S_IFDIR)); 645 } 646 647 648 ATF_TEST_CASE_WITHOUT_HEAD(rm_r__files_and_directories); 649 ATF_TEST_CASE_BODY(rm_r__files_and_directories) 650 { 651 fs::mkdir(fs::path("root"), 0755); 652 atf::utils::create_file("root/.hidden_file", ""); 653 fs::mkdir(fs::path("root/.hidden_dir"), 0755); 654 atf::utils::create_file("root/.hidden_dir/a", ""); 655 atf::utils::create_file("root/file", ""); 656 atf::utils::create_file("root/with spaces", ""); 657 fs::mkdir(fs::path("root/dir1"), 0755); 658 fs::mkdir(fs::path("root/dir1/dir2"), 0755); 659 atf::utils::create_file("root/dir1/dir2/file", ""); 660 fs::mkdir(fs::path("root/dir1/dir3"), 0755); 661 ATF_REQUIRE(lookup(".", "root", S_IFDIR)); 662 fs::rm_r(fs::path("root")); 663 ATF_REQUIRE(!lookup(".", "root", S_IFDIR)); 664 } 665 666 667 ATF_TEST_CASE_WITHOUT_HEAD(rmdir__ok) 668 ATF_TEST_CASE_BODY(rmdir__ok) 669 { 670 ATF_REQUIRE(::mkdir("foo", 0755) != -1); 671 ATF_REQUIRE(::access("foo", X_OK) == 0); 672 fs::rmdir(fs::path("foo")); 673 ATF_REQUIRE(::access("foo", X_OK) == -1); 674 } 675 676 677 ATF_TEST_CASE_WITHOUT_HEAD(rmdir__fail) 678 ATF_TEST_CASE_BODY(rmdir__fail) 679 { 680 ATF_REQUIRE_THROW_RE(fs::system_error, "Removal of foo failed", 681 fs::rmdir(fs::path("foo"))); 682 } 683 684 685 ATF_TEST_CASE_WITHOUT_HEAD(scan_directory__ok) 686 ATF_TEST_CASE_BODY(scan_directory__ok) 687 { 688 fs::mkdir(fs::path("dir"), 0755); 689 atf::utils::create_file("dir/foo", ""); 690 atf::utils::create_file("dir/.hidden", ""); 691 692 const std::set< fs::directory_entry > contents = fs::scan_directory( 693 fs::path("dir")); 694 695 std::set< fs::directory_entry > exp_contents; 696 exp_contents.insert(fs::directory_entry(".")); 697 exp_contents.insert(fs::directory_entry("..")); 698 exp_contents.insert(fs::directory_entry(".hidden")); 699 exp_contents.insert(fs::directory_entry("foo")); 700 701 ATF_REQUIRE_EQ(exp_contents, contents); 702 } 703 704 705 ATF_TEST_CASE_WITHOUT_HEAD(scan_directory__fail) 706 ATF_TEST_CASE_BODY(scan_directory__fail) 707 { 708 ATF_REQUIRE_THROW_RE(fs::system_error, "opendir(.*missing.*) failed", 709 fs::scan_directory(fs::path("missing"))); 710 } 711 712 713 ATF_TEST_CASE_WITHOUT_HEAD(unlink__ok) 714 ATF_TEST_CASE_BODY(unlink__ok) 715 { 716 atf::utils::create_file("foo", ""); 717 ATF_REQUIRE(::access("foo", R_OK) == 0); 718 fs::unlink(fs::path("foo")); 719 ATF_REQUIRE(::access("foo", R_OK) == -1); 720 } 721 722 723 ATF_TEST_CASE_WITHOUT_HEAD(unlink__fail) 724 ATF_TEST_CASE_BODY(unlink__fail) 725 { 726 ATF_REQUIRE_THROW_RE(fs::system_error, "Removal of foo failed", 727 fs::unlink(fs::path("foo"))); 728 } 729 730 731 ATF_TEST_CASE(unmount__ok) 732 ATF_TEST_CASE_HEAD(unmount__ok) 733 { 734 set_md_var("require.user", "root"); 735 } 736 ATF_TEST_CASE_BODY(unmount__ok) 737 { 738 const fs::path mount_point("mount_point"); 739 fs::mkdir(mount_point, 0755); 740 741 atf::utils::create_file((mount_point / "test1").str(), ""); 742 try { 743 fs::mount_tmpfs(mount_point); 744 } catch (const fs::unsupported_operation_error& e) { 745 ATF_SKIP(e.what()); 746 } 747 748 atf::utils::create_file((mount_point / "test2").str(), ""); 749 750 ATF_REQUIRE(!fs::exists(mount_point / "test1")); 751 ATF_REQUIRE( fs::exists(mount_point / "test2")); 752 fs::unmount(mount_point); 753 ATF_REQUIRE( fs::exists(mount_point / "test1")); 754 ATF_REQUIRE(!fs::exists(mount_point / "test2")); 755 } 756 757 758 ATF_TEST_CASE(unmount__fail) 759 ATF_TEST_CASE_HEAD(unmount__fail) 760 { 761 set_md_var("require.user", "root"); 762 } 763 ATF_TEST_CASE_BODY(unmount__fail) 764 { 765 ATF_REQUIRE_THROW(fs::error, fs::unmount(fs::path("non-existent"))); 766 } 767 768 769 ATF_INIT_TEST_CASES(tcs) 770 { 771 ATF_ADD_TEST_CASE(tcs, copy__ok); 772 ATF_ADD_TEST_CASE(tcs, copy__fail_open); 773 ATF_ADD_TEST_CASE(tcs, copy__fail_create); 774 775 ATF_ADD_TEST_CASE(tcs, current_path__ok); 776 ATF_ADD_TEST_CASE(tcs, current_path__enoent); 777 778 ATF_ADD_TEST_CASE(tcs, exists); 779 780 ATF_ADD_TEST_CASE(tcs, find_in_path__no_path); 781 ATF_ADD_TEST_CASE(tcs, find_in_path__empty_path); 782 ATF_ADD_TEST_CASE(tcs, find_in_path__one_component); 783 ATF_ADD_TEST_CASE(tcs, find_in_path__many_components); 784 ATF_ADD_TEST_CASE(tcs, find_in_path__current_directory); 785 ATF_ADD_TEST_CASE(tcs, find_in_path__always_absolute); 786 787 ATF_ADD_TEST_CASE(tcs, free_disk_space__ok__smoke); 788 ATF_ADD_TEST_CASE(tcs, free_disk_space__ok__real); 789 ATF_ADD_TEST_CASE(tcs, free_disk_space__fail); 790 791 ATF_ADD_TEST_CASE(tcs, is_directory__ok); 792 ATF_ADD_TEST_CASE(tcs, is_directory__fail); 793 794 ATF_ADD_TEST_CASE(tcs, mkdir__ok); 795 ATF_ADD_TEST_CASE(tcs, mkdir__enoent); 796 797 ATF_ADD_TEST_CASE(tcs, mkdir_p__one_component); 798 ATF_ADD_TEST_CASE(tcs, mkdir_p__many_components); 799 ATF_ADD_TEST_CASE(tcs, mkdir_p__already_exists); 800 ATF_ADD_TEST_CASE(tcs, mkdir_p__eacces); 801 802 ATF_ADD_TEST_CASE(tcs, mkdtemp_public); 803 ATF_ADD_TEST_CASE(tcs, mkdtemp_public__getcwd_as_non_root); 804 ATF_ADD_TEST_CASE(tcs, mkdtemp_public__search_permissions_as_non_root); 805 806 ATF_ADD_TEST_CASE(tcs, mkstemp); 807 808 ATF_ADD_TEST_CASE(tcs, mount_tmpfs__ok__default_size); 809 ATF_ADD_TEST_CASE(tcs, mount_tmpfs__ok__explicit_size); 810 ATF_ADD_TEST_CASE(tcs, mount_tmpfs__fail); 811 812 ATF_ADD_TEST_CASE(tcs, rm_r__empty); 813 ATF_ADD_TEST_CASE(tcs, rm_r__files_and_directories); 814 815 ATF_ADD_TEST_CASE(tcs, rmdir__ok); 816 ATF_ADD_TEST_CASE(tcs, rmdir__fail); 817 818 ATF_ADD_TEST_CASE(tcs, scan_directory__ok); 819 ATF_ADD_TEST_CASE(tcs, scan_directory__fail); 820 821 ATF_ADD_TEST_CASE(tcs, unlink__ok); 822 ATF_ADD_TEST_CASE(tcs, unlink__fail); 823 824 ATF_ADD_TEST_CASE(tcs, unmount__ok); 825 ATF_ADD_TEST_CASE(tcs, unmount__fail); 826 } 827