brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.5 KiB · 1f22939 Raw
517 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// REQUIRES: can-create-symlinks10// UNSUPPORTED: c++03, c++11, c++1411// UNSUPPORTED: no-filesystem12 13// On Android L, ~scoped_test_env() is unable to delete the temp dir using14// chmod+rm because chmod is too broken.15// XFAIL: LIBCXX-ANDROID-FIXME && android-device-api={{21|22}}16 17// <filesystem>18 19// class recursive_directory_iterator20 21// recursive_directory_iterator& operator++();22// recursive_directory_iterator& increment(error_code& ec) noexcept;23 24#include <filesystem>25#include <type_traits>26#include <set>27#include <cassert>28 29#include "assert_macros.h"30#include "test_macros.h"31#include "filesystem_test_helper.h"32namespace fs = std::filesystem;33using namespace fs;34 35static void test_increment_signatures()36{37    recursive_directory_iterator d; ((void)d);38    std::error_code ec; ((void)ec);39 40    ASSERT_SAME_TYPE(decltype(++d), recursive_directory_iterator&);41    ASSERT_NOT_NOEXCEPT(++d);42 43    ASSERT_SAME_TYPE(decltype(d.increment(ec)), recursive_directory_iterator&);44    ASSERT_NOT_NOEXCEPT(d.increment(ec));45}46 47static void test_prefix_increment()48{49    static_test_env static_env;50    const path testDir = static_env.Dir;51    const std::set<path> dir_contents(static_env.RecDirIterationList.begin(),52                                      static_env.RecDirIterationList.end());53    const recursive_directory_iterator endIt{};54 55    std::error_code ec;56    recursive_directory_iterator it(testDir, ec);57    assert(!ec);58 59    std::set<path> unseen_entries = dir_contents;60    while (!unseen_entries.empty()) {61        assert(it != endIt);62        const path entry = *it;63        assert(unseen_entries.erase(entry) == 1);64        recursive_directory_iterator& it_ref = ++it;65        assert(&it_ref == &it);66    }67 68    assert(it == endIt);69}70 71static void test_postfix_increment()72{73    static_test_env static_env;74    const path testDir = static_env.Dir;75    const std::set<path> dir_contents(static_env.RecDirIterationList.begin(),76                                      static_env.RecDirIterationList.end());77    const recursive_directory_iterator endIt{};78 79    std::error_code ec;80    recursive_directory_iterator it(testDir, ec);81    assert(!ec);82 83    std::set<path> unseen_entries = dir_contents;84    while (!unseen_entries.empty()) {85        assert(it != endIt);86        const path entry = *it;87        assert(unseen_entries.erase(entry) == 1);88        const path entry2 = *it++;89        assert(entry2 == entry);90    }91    assert(it == endIt);92}93 94 95static void test_increment_method()96{97    static_test_env static_env;98    const path testDir = static_env.Dir;99    const std::set<path> dir_contents(static_env.RecDirIterationList.begin(),100                                      static_env.RecDirIterationList.end());101    const recursive_directory_iterator endIt{};102 103    std::error_code ec;104    recursive_directory_iterator it(testDir, ec);105    assert(!ec);106 107    std::set<path> unseen_entries = dir_contents;108    while (!unseen_entries.empty()) {109        assert(it != endIt);110        const path entry = *it;111        assert(unseen_entries.erase(entry) == 1);112        recursive_directory_iterator& it_ref = it.increment(ec);113        assert(!ec);114        assert(&it_ref == &it);115    }116 117    assert(it == endIt);118}119 120static void test_follow_symlinks()121{122    static_test_env static_env;123    const path testDir = static_env.Dir;124    auto const& IterList = static_env.RecDirFollowSymlinksIterationList;125 126    const std::set<path> dir_contents(IterList.begin(), IterList.end());127    const recursive_directory_iterator endIt{};128 129    std::error_code ec;130    recursive_directory_iterator it(testDir,131                              directory_options::follow_directory_symlink, ec);132    assert(!ec);133 134    std::set<path> unseen_entries = dir_contents;135    while (!unseen_entries.empty()) {136        assert(it != endIt);137        const path entry = *it;138 139        assert(unseen_entries.erase(entry) == 1);140        recursive_directory_iterator& it_ref = it.increment(ec);141        assert(!ec);142        assert(&it_ref == &it);143    }144    assert(it == endIt);145}146 147// Windows doesn't support setting perms::none to trigger failures148// reading directories.149#ifndef TEST_WIN_NO_FILESYSTEM_PERMS_NONE150static void access_denied_on_recursion_test_case()151{152    using namespace fs;153    scoped_test_env env;154    const path testFiles[] = {155        env.create_dir("dir1"),156        env.create_dir("dir1/dir2"),157        env.create_file("dir1/dir2/file1"),158        env.create_file("dir1/file2")159    };160    const path startDir = testFiles[0];161    const path permDeniedDir = testFiles[1];162    const path otherFile = testFiles[3];163    auto SkipEPerm = directory_options::skip_permission_denied;164 165    // Change the permissions so we can no longer iterate166    permissions(permDeniedDir, perms::none);167 168    const recursive_directory_iterator endIt;169 170    // Test that recursion resulting in a "EACCESS" error is not ignored171    // by default.172    {173        std::error_code ec = GetTestEC();174        recursive_directory_iterator it(startDir, ec);175        assert(ec != GetTestEC());176        assert(!ec);177        while (it != endIt && it->path() != permDeniedDir)178            ++it;179        assert(it != endIt);180        assert(*it == permDeniedDir);181 182        it.increment(ec);183        assert(ec);184        assert(it == endIt);185    }186    // Same as above but test operator++().187    {188        std::error_code ec = GetTestEC();189        recursive_directory_iterator it(startDir, ec);190        assert(!ec);191        while (it != endIt && it->path() != permDeniedDir)192            ++it;193        assert(it != endIt);194        assert(*it == permDeniedDir);195 196        TEST_THROWS_TYPE(filesystem_error, ++it);197    }198    // Test that recursion resulting in a "EACCESS" error is ignored when the199    // correct options are given to the constructor.200    {201        std::error_code ec = GetTestEC();202        recursive_directory_iterator it(startDir, SkipEPerm, ec);203        assert(!ec);204        assert(it != endIt);205 206        bool seenOtherFile = false;207        if (*it == otherFile) {208            ++it;209            seenOtherFile = true;210            assert (it != endIt);211        }212        assert(*it == permDeniedDir);213 214        ec = GetTestEC();215        it.increment(ec);216        assert(!ec);217 218        if (seenOtherFile) {219            assert(it == endIt);220        } else {221            assert(it != endIt);222            assert(*it == otherFile);223        }224    }225    // Test that construction resulting in a "EACCESS" error is not ignored226    // by default.227    {228        std::error_code ec;229        recursive_directory_iterator it(permDeniedDir, ec);230        assert(ec);231        assert(it == endIt);232    }233    // Same as above but testing the throwing constructors234    {235        TEST_THROWS_TYPE(filesystem_error,236                           recursive_directory_iterator(permDeniedDir));237    }238    // Test that construction resulting in a "EACCESS" error constructs the239    // end iterator when the correct options are given.240    {241        std::error_code ec = GetTestEC();242        recursive_directory_iterator it(permDeniedDir, SkipEPerm, ec);243        assert(!ec);244        assert(it == endIt);245    }246}247 248// See llvm.org/PR35078249static void test_PR35078()250{251  using namespace fs;252    scoped_test_env env;253    const path testFiles[] = {254        env.create_dir("dir1"),255        env.create_dir("dir1/dir2"),256        env.create_dir("dir1/dir2/dir3"),257        env.create_file("dir1/file1"),258        env.create_file("dir1/dir2/dir3/file2")259    };260    const path startDir = testFiles[0];261    const path permDeniedDir = testFiles[1];262    const path nestedDir = testFiles[2];263    const path nestedFile = testFiles[3];264 265    // Change the permissions so we can no longer iterate266    permissions(permDeniedDir,267                perms::group_exec|perms::owner_exec|perms::others_exec,268                perm_options::remove);269 270    const std::errc eacess = std::errc::permission_denied;271    std::error_code ec = GetTestEC();272 273    const recursive_directory_iterator endIt;274 275    auto SetupState = [&](bool AllowEAccess, bool& SeenFile3) {276      SeenFile3 = false;277      auto Opts = AllowEAccess ? directory_options::skip_permission_denied278          : directory_options::none;279      recursive_directory_iterator it(startDir, Opts, ec);280      while (!ec && it != endIt && *it != nestedDir) {281        if (*it == nestedFile)282          SeenFile3 = true;283        it.increment(ec);284      }285      return it;286    };287 288    {289      bool SeenNestedFile = false;290      recursive_directory_iterator it = SetupState(false, SeenNestedFile);291      assert(it != endIt);292      assert(*it == nestedDir);293      ec = GetTestEC();294      it.increment(ec);295      assert(ec);296      assert(ErrorIs(ec, eacess));297      assert(it == endIt);298    }299    {300      bool SeenNestedFile = false;301      recursive_directory_iterator it = SetupState(true, SeenNestedFile);302      assert(it != endIt);303      assert(*it == nestedDir);304      ec = GetTestEC();305      it.increment(ec);306      assert(!ec);307      if (SeenNestedFile) {308        assert(it == endIt);309      } else {310        assert(it != endIt);311        assert(*it == nestedFile);312      }313    }314    {315      bool SeenNestedFile = false;316      recursive_directory_iterator it = SetupState(false, SeenNestedFile);317      assert(it != endIt);318      assert(*it == nestedDir);319 320      ExceptionChecker Checker(std::errc::permission_denied,321                               "recursive_directory_iterator::operator++()",322                               format_string("attempting recursion into \"%s\"",323                                             nestedDir.string().c_str()));324      TEST_VALIDATE_EXCEPTION(filesystem_error, Checker, ++it);325    }326}327 328 329// See llvm.org/PR35078330static void test_PR35078_with_symlink()331{332  using namespace fs;333    scoped_test_env env;334    const path testFiles[] = {335        env.create_dir("dir1"),336        env.create_file("dir1/file1"),337        env.create_dir("sym_dir"),338        env.create_dir("sym_dir/nested_sym_dir"),339        env.create_directory_symlink("sym_dir/nested_sym_dir", "dir1/dir2"),340        env.create_dir("sym_dir/dir1"),341        env.create_dir("sym_dir/dir1/dir2"),342 343    };344   // const unsigned TestFilesSize = sizeof(testFiles) / sizeof(testFiles[0]);345    const path startDir = testFiles[0];346    const path nestedFile = testFiles[1];347    const path permDeniedDir = testFiles[2];348    const path symDir = testFiles[4];349 350    // Change the permissions so we can no longer iterate351    permissions(permDeniedDir,352                perms::group_exec|perms::owner_exec|perms::others_exec,353                perm_options::remove);354 355    const std::errc eacess = std::errc::permission_denied;356    std::error_code ec = GetTestEC();357 358    const recursive_directory_iterator endIt;359 360    auto SetupState = [&](bool AllowEAccess, bool FollowSym, bool& SeenFile3) {361      SeenFile3 = false;362      auto Opts = AllowEAccess ? directory_options::skip_permission_denied363          : directory_options::none;364      if (FollowSym)365        Opts |= directory_options::follow_directory_symlink;366      recursive_directory_iterator it(startDir, Opts, ec);367      while (!ec && it != endIt && *it != symDir) {368        if (*it == nestedFile)369          SeenFile3 = true;370        it.increment(ec);371      }372      return it;373    };374 375    struct {376      bool SkipPermDenied;377      bool FollowSymlinks;378      bool ExpectSuccess;379    } TestCases[]  = {380        // Passing cases381        {false, false, true}, {true, true, true}, {true, false, true},382        // Failing cases383        {false, true, false}384    };385    for (auto TC : TestCases) {386      bool SeenNestedFile = false;387      recursive_directory_iterator it = SetupState(TC.SkipPermDenied,388                                                   TC.FollowSymlinks,389                                                   SeenNestedFile);390      assert(!ec);391      assert(it != endIt);392      assert(*it == symDir);393      ec = GetTestEC();394      it.increment(ec);395      if (TC.ExpectSuccess) {396        assert(!ec);397        if (SeenNestedFile) {398          assert(it == endIt);399        } else {400          assert(it != endIt);401          assert(*it == nestedFile);402        }403      } else {404        assert(ec);405        assert(ErrorIs(ec, eacess));406        assert(it == endIt);407      }408    }409}410 411 412// See llvm.org/PR35078413static void test_PR35078_with_symlink_file()414{415  using namespace fs;416    scoped_test_env env;417    const path testFiles[] = {418        env.create_dir("dir1"),419        env.create_dir("dir1/dir2"),420        env.create_file("dir1/file2"),421        env.create_dir("sym_dir"),422        env.create_dir("sym_dir/sdir1"),423        env.create_file("sym_dir/sdir1/sfile1"),424        env.create_symlink("sym_dir/sdir1/sfile1", "dir1/dir2/file1")425    };426    const unsigned TestFilesSize = sizeof(testFiles) / sizeof(testFiles[0]);427    const path startDir = testFiles[0];428    const path nestedDir = testFiles[1];429    const path nestedFile = testFiles[2];430    const path permDeniedDir = testFiles[3];431    const path symFile = testFiles[TestFilesSize - 1];432 433    // Change the permissions so we can no longer iterate434    permissions(permDeniedDir,435                perms::group_exec|perms::owner_exec|perms::others_exec,436                perm_options::remove);437 438    const std::errc eacess = std::errc::permission_denied;439    std::error_code ec = GetTestEC();440 441    const recursive_directory_iterator EndIt;442 443    auto SetupState = [&](bool AllowEAccess, bool FollowSym, bool& SeenNestedFile) {444      SeenNestedFile = false;445      auto Opts = AllowEAccess ? directory_options::skip_permission_denied446          : directory_options::none;447      if (FollowSym)448        Opts |= directory_options::follow_directory_symlink;449      recursive_directory_iterator it(startDir, Opts, ec);450      while (!ec && it != EndIt && *it != nestedDir) {451        if (*it == nestedFile)452          SeenNestedFile = true;453        it.increment(ec);454      }455      return it;456    };457 458    struct {459      bool SkipPermDenied;460      bool FollowSymlinks;461      bool ExpectSuccess;462    } TestCases[]  = {463        // Passing cases464        {false, false, true}, {true, true, true}, {true, false, true},465        // Failing cases466        {false, true, false}467    };468    for (auto TC : TestCases){469      bool SeenNestedFile = false;470      recursive_directory_iterator it = SetupState(TC.SkipPermDenied,471                                                   TC.FollowSymlinks,472                                                   SeenNestedFile);473      assert(!ec);474      assert(it != EndIt);475      assert(*it == nestedDir);476      ec = GetTestEC();477      it.increment(ec);478      assert(it != EndIt);479      assert(!ec);480      assert(*it == symFile);481      ec = GetTestEC();482      it.increment(ec);483      if (TC.ExpectSuccess) {484        if (!SeenNestedFile) {485          assert(!ec);486          assert(it != EndIt);487          assert(*it == nestedFile);488          ec = GetTestEC();489          it.increment(ec);490        }491        assert(!ec);492        assert(it == EndIt);493      } else {494        assert(ec);495        assert(ErrorIs(ec, eacess));496        assert(it == EndIt);497      }498    }499}500#endif // TEST_WIN_NO_FILESYSTEM_PERMS_NONE501 502int main(int, char**) {503    test_increment_signatures();504    test_prefix_increment();505    test_postfix_increment();506    test_increment_method();507    test_follow_symlinks();508#ifndef TEST_WIN_NO_FILESYSTEM_PERMS_NONE509    access_denied_on_recursion_test_case();510    test_PR35078();511    test_PR35078_with_symlink();512    test_PR35078_with_symlink_file();513#endif514 515    return 0;516}517