diff --git a/include/vcpkg/base/files.h b/include/vcpkg/base/files.h index ad7eb6a770..61d0081fcf 100644 --- a/include/vcpkg/base/files.h +++ b/include/vcpkg/base/files.h @@ -237,6 +237,10 @@ namespace vcpkg virtual std::vector get_regular_files_recursive(const Path& dir, std::error_code& ec) const = 0; std::vector get_regular_files_recursive(const Path& dir, LineInfo li) const; + virtual std::vector get_regular_files_recursive_lexically_proximate(const Path& dir, + std::error_code& ec) const = 0; + std::vector get_regular_files_recursive_lexically_proximate(const Path& dir, LineInfo li) const; + virtual std::vector get_regular_files_non_recursive(const Path& dir, std::error_code& ec) const = 0; std::vector get_regular_files_non_recursive(const Path& dir, LineInfo li) const; diff --git a/src/vcpkg-test/files.cpp b/src/vcpkg-test/files.cpp index 05ce1b403e..4457026145 100644 --- a/src/vcpkg-test/files.cpp +++ b/src/vcpkg-test/files.cpp @@ -167,6 +167,7 @@ namespace template void do_filesystem_enumeration_test(Enumerator&& enumerator, ExpectedGenerator&& generate_expected) { + // Note: not seeded with random data, so this will always produce the same sequence of names urbg_t urbg; auto& fs = setup(); @@ -186,6 +187,8 @@ namespace const auto target_inside_directory = target_directory / "some-inner-directory"; const auto target_inside_directory_symlink = target_directory / "symlink-to-some-inner-directory"; + fs.remove_all(temp_dir, VCPKG_LINE_INFO); + fs.create_directory(temp_dir, VCPKG_LINE_INFO); fs.create_directory(target_root, VCPKG_LINE_INFO); fs.create_directory(target_directory, VCPKG_LINE_INFO); @@ -198,6 +201,7 @@ namespace fs.create_symlink(target_file, target_symlink, ec); if (ec) { + INFO(ec.message()); REQUIRE(is_valid_symlink_failure(ec)); } else @@ -741,6 +745,23 @@ TEST_CASE ("get_files_recursive_symlinks", "[files]") }); } +TEST_CASE ("get_regular_files_recursive_proximate_symlinks", "[files]") +{ + do_filesystem_enumeration_test( + [](Filesystem& fs, const Path& root) { + return fs.get_regular_files_recursive_lexically_proximate(root, VCPKG_LINE_INFO); + }, + [](const Path&) { + Path somedir{"some-directory"}; + return std::vector{ + "file.txt", + somedir / "file2.txt", + somedir / "symlink-to-file2.txt", + "symlink-to-file.txt", + }; + }); +} + TEST_CASE ("get_files_non_recursive_symlinks", "[files]") { do_filesystem_enumeration_test( diff --git a/src/vcpkg/base/files.cpp b/src/vcpkg/base/files.cpp index bdbc57c96a..17761fa7b6 100644 --- a/src/vcpkg/base/files.cpp +++ b/src/vcpkg/base/files.cpp @@ -826,7 +826,7 @@ namespace { // if it isn't still a directory something is racy ec = std::make_error_code(std::errc::device_or_resource_busy); - mark_recursive_error(base, ec, failure_point); + failure_point = base; return; } @@ -1420,6 +1420,18 @@ namespace vcpkg return maybe_directories; } + std::vector Filesystem::get_regular_files_recursive_lexically_proximate(const Path& dir, LineInfo li) const + { + std::error_code ec; + auto maybe_directories = this->get_regular_files_recursive_lexically_proximate(dir, ec); + if (ec) + { + exit_filesystem_call_error(li, ec, __func__, {dir}); + } + + return maybe_directories; + } + std::vector Filesystem::get_regular_files_non_recursive(const Path& dir, LineInfo li) const { std::error_code ec; @@ -2066,6 +2078,21 @@ namespace vcpkg { return get_regular_files_impl(dir, ec); } + + virtual std::vector get_regular_files_recursive_lexically_proximate(const Path& dir, + std::error_code& ec) const override + { + auto ret = this->get_regular_files_recursive(dir, ec); + if (!ec) + { + const auto base = to_stdfs_path(dir); + for (auto& p : ret) + { + p = from_stdfs_path(to_stdfs_path(p).lexically_proximate(base)); + } + } + return ret; + } #else // ^^^ _WIN32 // !_WIN32 vvv static void insert_if_stat_matches(std::vector& result, const Path& full, @@ -2101,6 +2128,7 @@ namespace vcpkg static void get_files_recursive_impl(std::vector& result, const Path& base, + const Path& out_base, std::error_code& ec, bool want_directories, bool want_regular_files, @@ -2135,6 +2163,7 @@ namespace vcpkg } const auto full = base / entry->d_name; + const auto out_full = out_base / entry->d_name; const auto entry_dtype = get_d_type(entry); struct stat s; struct stat ls; @@ -2144,11 +2173,11 @@ namespace vcpkg if (want_directories) { // push results before recursion to get outer entries first - result.push_back(full); + result.push_back(out_full); } get_files_recursive_impl( - result, full, ec, want_directories, want_regular_files, want_other); + result, full, out_full, ec, want_directories, want_regular_files, want_other); if (ec) { return; @@ -2158,7 +2187,7 @@ namespace vcpkg case PosixDType::Regular: if (want_regular_files) { - result.push_back(full); + result.push_back(out_full); } break; @@ -2169,7 +2198,7 @@ namespace vcpkg case PosixDType::BlockDevice: if (want_other) { - result.push_back(full); + result.push_back(out_full); } break; @@ -2196,7 +2225,7 @@ namespace vcpkg if (want_directories && want_regular_files && want_other) { // skip extra stat syscall since we want everything - result.push_back(full); + result.push_back(out_full); } else { @@ -2216,21 +2245,21 @@ namespace vcpkg } insert_if_stat_matches( - result, full, &s, want_directories, want_regular_files, want_other); + result, out_full, &s, want_directories, want_regular_files, want_other); } } else { // push results before recursion to get outer entries first insert_if_stat_matches( - result, full, &ls, want_directories, want_regular_files, want_other); + result, out_full, &ls, want_directories, want_regular_files, want_other); } // recursion check doesn't follow symlinks: if (S_ISDIR(ls.st_mode)) { get_files_recursive_impl( - result, full, ec, want_directories, want_regular_files, want_other); + result, full, out_full, ec, want_directories, want_regular_files, want_other); } break; } @@ -2286,7 +2315,8 @@ namespace vcpkg virtual std::vector get_files_recursive(const Path& dir, std::error_code& ec) const override { std::vector result; - get_files_recursive_impl(result, dir, ec, true, true, true); + Path out_base = dir; + get_files_recursive_impl(result, dir, out_base, ec, true, true, true); return result; } @@ -2300,7 +2330,8 @@ namespace vcpkg virtual std::vector get_directories_recursive(const Path& dir, std::error_code& ec) const override { std::vector result; - get_files_recursive_impl(result, dir, ec, true, false, false); + Path out_base = dir; + get_files_recursive_impl(result, dir, out_base, ec, true, false, false); return result; } @@ -2329,7 +2360,17 @@ namespace vcpkg virtual std::vector get_regular_files_recursive(const Path& dir, std::error_code& ec) const override { std::vector result; - get_files_recursive_impl(result, dir, ec, false, true, false); + Path out_base = dir; + get_files_recursive_impl(result, dir, out_base, ec, false, true, false); + return result; + } + + virtual std::vector get_regular_files_recursive_lexically_proximate(const Path& dir, + std::error_code& ec) const override + { + std::vector result; + Path out_base; + get_files_recursive_impl(result, dir, out_base, ec, false, true, false); return result; }