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 31extern "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 62namespace fs = utils::fs; 63namespace passwd = utils::passwd; 64namespace units = utils::units; 65 66using utils::optional; 67 68 69namespace { 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. 80static bool 81lookup(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 106ATF_TEST_CASE_WITHOUT_HEAD(copy__ok); 107ATF_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 118ATF_TEST_CASE_WITHOUT_HEAD(copy__fail_open); 119ATF_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 129ATF_TEST_CASE(copy__fail_create); 130ATF_TEST_CASE_HEAD(copy__fail_create) 131{ 132 set_md_var("require.user", "unprivileged"); 133} 134ATF_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 148ATF_TEST_CASE_WITHOUT_HEAD(current_path__ok); 149ATF_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 160ATF_TEST_CASE_WITHOUT_HEAD(current_path__enoent); 161ATF_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 176ATF_TEST_CASE_WITHOUT_HEAD(exists); 177ATF_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 186ATF_TEST_CASE_WITHOUT_HEAD(find_in_path__no_path); 187ATF_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 196ATF_TEST_CASE_WITHOUT_HEAD(find_in_path__empty_path); 197ATF_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 206ATF_TEST_CASE_WITHOUT_HEAD(find_in_path__one_component); 207ATF_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 219ATF_TEST_CASE_WITHOUT_HEAD(find_in_path__many_components); 220ATF_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 236ATF_TEST_CASE_WITHOUT_HEAD(find_in_path__current_directory); 237ATF_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 248ATF_TEST_CASE_WITHOUT_HEAD(find_in_path__always_absolute); 249ATF_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 261ATF_TEST_CASE_WITHOUT_HEAD(free_disk_space__ok__smoke); 262ATF_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. 275static void 276cleanup_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 289ATF_TEST_CASE_WITH_CLEANUP(free_disk_space__ok__real); 290ATF_TEST_CASE_HEAD(free_disk_space__ok__real) 291{ 292 set_md_var("require.user", "root"); 293} 294ATF_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} 310ATF_TEST_CASE_CLEANUP(free_disk_space__ok__real) 311{ 312 cleanup_mount_point(fs::path("mounted"), fs::path("mount_point")); 313} 314 315 316ATF_TEST_CASE_WITHOUT_HEAD(free_disk_space__fail); 317ATF_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 324ATF_TEST_CASE_WITHOUT_HEAD(is_directory__ok); 325ATF_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 337ATF_TEST_CASE_WITH_CLEANUP(is_directory__fail); 338ATF_TEST_CASE_HEAD(is_directory__fail) 339{ 340 set_md_var("require.user", "unprivileged"); 341} 342ATF_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} 347ATF_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 357ATF_TEST_CASE_WITHOUT_HEAD(mkdir__ok); 358ATF_TEST_CASE_BODY(mkdir__ok) 359{ 360 fs::mkdir(fs::path("dir"), 0755); 361 ATF_REQUIRE(lookup(".", "dir", S_IFDIR)); 362} 363 364 365ATF_TEST_CASE_WITHOUT_HEAD(mkdir__enoent); 366ATF_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 379ATF_TEST_CASE_WITHOUT_HEAD(mkdir_p__one_component); 380ATF_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 388ATF_TEST_CASE_WITHOUT_HEAD(mkdir_p__many_components); 389ATF_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 399ATF_TEST_CASE_WITHOUT_HEAD(mkdir_p__already_exists); 400ATF_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 408ATF_TEST_CASE(mkdir_p__eacces) 409ATF_TEST_CASE_HEAD(mkdir_p__eacces) 410{ 411 set_md_var("require.user", "unprivileged"); 412} 413ATF_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 432ATF_TEST_CASE_WITHOUT_HEAD(mkdtemp_public) 433ATF_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 446ATF_TEST_CASE(mkdtemp_public__getcwd_as_non_root) 447ATF_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} 452ATF_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 499ATF_TEST_CASE(mkdtemp_public__search_permissions_as_non_root) 500ATF_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} 505ATF_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 554ATF_TEST_CASE_WITHOUT_HEAD(mkstemp) 555ATF_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 568static void 569test_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 591ATF_TEST_CASE_WITH_CLEANUP(mount_tmpfs__ok__default_size) 592ATF_TEST_CASE_HEAD(mount_tmpfs__ok__default_size) 593{ 594 set_md_var("require.user", "root"); 595} 596ATF_TEST_CASE_BODY(mount_tmpfs__ok__default_size) 597{ 598 test_mount_tmpfs_ok(units::bytes()); 599} 600ATF_TEST_CASE_CLEANUP(mount_tmpfs__ok__default_size) 601{ 602 cleanup_mount_point(fs::path("mounted"), fs::path("mount_point")); 603} 604 605 606ATF_TEST_CASE_WITH_CLEANUP(mount_tmpfs__ok__explicit_size) 607ATF_TEST_CASE_HEAD(mount_tmpfs__ok__explicit_size) 608{ 609 set_md_var("require.user", "root"); 610} 611ATF_TEST_CASE_BODY(mount_tmpfs__ok__explicit_size) 612{ 613 test_mount_tmpfs_ok(units::bytes(10 * units::MB)); 614} 615ATF_TEST_CASE_CLEANUP(mount_tmpfs__ok__explicit_size) 616{ 617 cleanup_mount_point(fs::path("mounted"), fs::path("mount_point")); 618} 619 620 621ATF_TEST_CASE(mount_tmpfs__fail) 622ATF_TEST_CASE_HEAD(mount_tmpfs__fail) 623{ 624 set_md_var("require.user", "root"); 625} 626ATF_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 638ATF_TEST_CASE_WITHOUT_HEAD(rm_r__empty); 639ATF_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 648ATF_TEST_CASE_WITHOUT_HEAD(rm_r__files_and_directories); 649ATF_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 667ATF_TEST_CASE_WITHOUT_HEAD(rmdir__ok) 668ATF_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 677ATF_TEST_CASE_WITHOUT_HEAD(rmdir__fail) 678ATF_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 685ATF_TEST_CASE_WITHOUT_HEAD(scan_directory__ok) 686ATF_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 705ATF_TEST_CASE_WITHOUT_HEAD(scan_directory__fail) 706ATF_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 713ATF_TEST_CASE_WITHOUT_HEAD(unlink__ok) 714ATF_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 723ATF_TEST_CASE_WITHOUT_HEAD(unlink__fail) 724ATF_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 731ATF_TEST_CASE(unmount__ok) 732ATF_TEST_CASE_HEAD(unmount__ok) 733{ 734 set_md_var("require.user", "root"); 735} 736ATF_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 758ATF_TEST_CASE(unmount__fail) 759ATF_TEST_CASE_HEAD(unmount__fail) 760{ 761 set_md_var("require.user", "root"); 762} 763ATF_TEST_CASE_BODY(unmount__fail) 764{ 765 ATF_REQUIRE_THROW(fs::error, fs::unmount(fs::path("non-existent"))); 766} 767 768 769ATF_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