diff --git a/core/relinker/cli/src/NativeModules.cpp b/core/relinker/cli/src/NativeModules.cpp index d10056fa28..6163063c69 100644 --- a/core/relinker/cli/src/NativeModules.cpp +++ b/core/relinker/cli/src/NativeModules.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace Cli { @@ -155,16 +156,26 @@ void ReportUnconvertedNeeded(const NativeModules& modules, const std::vector found; - for (auto entry = std::filesystem::recursive_directory_iterator(modules.Root, std::filesystem::directory_options::skip_permission_denied); entry != std::filesystem::recursive_directory_iterator(); ++entry) { - if (entry->is_directory()) { - if (std::any_of(modules.Directories.begin(), modules.Directories.end(), [&](const auto& directory) { return SameDirectory(directory, entry->path()); })) entry.disable_recursion_pending(); + std::error_code error; + for (auto entry = std::filesystem::recursive_directory_iterator(modules.Root, std::filesystem::directory_options::skip_permission_denied, error); !error && entry != std::filesystem::recursive_directory_iterator(); entry.increment(error)) { + const bool directory = entry->is_directory(error); + if (error) { + error.clear(); + continue; + } + if (directory) { + if (std::any_of(modules.Directories.begin(), modules.Directories.end(), [&](const auto& scanned) { return std::filesystem::equivalent(scanned, entry->path(), error) && !error; })) entry.disable_recursion_pending(); + error.clear(); continue; } - if (!entry->is_regular_file()) continue; const auto filename = FoldedName(Io::Utf8Path(entry->path().filename()), foldCase); if (Domain::ModuleSuffix(filename).empty()) continue; const auto stem = stems.find(std::string(ModuleStem(filename))); if (stem == stems.end()) continue; + if (!entry->is_regular_file(error) || error) { + error.clear(); + continue; + } const auto header = TryReadCandidateHeader(entry->path()); if (!header || (!header->Self && !(header->Elf && header->Type == 0xfe18))) continue; for (const auto& name : stem->second) found.push_back({entry->path().lexically_relative(modules.Root), name, header->Self}); diff --git a/core/relinker/relinker/tests/test_guest_needed_modules.py b/core/relinker/relinker/tests/test_guest_needed_modules.py index c6b04179dc..4cd66ab6f5 100644 --- a/core/relinker/relinker/tests/test_guest_needed_modules.py +++ b/core/relinker/relinker/tests/test_guest_needed_modules.py @@ -162,6 +162,27 @@ def check_needed_outside(relinker, work): finally: (case / "needed.prx").chmod(0o644) + if os.name != "nt": + case = work / "outside-loops" + (case / "sce_module").mkdir(parents=True) + (case / "Media").mkdir() + (case / "Media" / "needed.prx").write_bytes(sce_module) + os.symlink("loop", case / "loop") + os.symlink("needed.prx", case / "needed.prx") + os.symlink("missing.prx", case / "Media" / "needed.sprx") + (case / "Media" / "Nested").mkdir() + os.symlink("..", case / "Media" / "Nested" / "needed.suprx") + expected = [message + "needed.prx at Media/needed.prx; add --module-dir Media"] + assert convert(case) == expected + if os.geteuid() != 0: + (case / "locked").mkdir() + (case / "locked" / "needed.prx").write_bytes(sce_module) + (case / "locked").chmod(0) + try: + assert convert(case) == expected + finally: + (case / "locked").chmod(0o755) + def main(): relinker = Path(sys.argv[1]).resolve()