From f978743907a2dd9dfa3d10cec2b19977f180adcc Mon Sep 17 00:00:00 2001 From: Juergen Ributzka Date: Tue, 14 Mar 2017 00:14:40 +0000 Subject: Reapply [VFS] Ignore broken symlinks in the directory iterator. Modified the tests to accept any iteration order, to run only on Unix, and added additional error reporting to investigate SystemZ bot issue. The VFS directory iterator and recursive directory iterator behave differently from the LLVM counterparts. Once the VFS iterators hit a broken symlink they immediately abort. The LLVM counterparts don't stat entries unless they have to descend into the next directory, which allows to recover from this issue by clearing the error code and skipping to the next entry. This change adds similar behavior to the VFS iterators. There should be no change in current behavior in the current CLANG source base, because all clients have loop exit conditions that also check the error code. This fixes rdar://problem/30934619. Differential Revision: https://reviews.llvm.org/D30768 llvm-svn: 297693 --- clang/unittests/Basic/VirtualFileSystemTest.cpp | 90 +++++++++++++++++++++++++ 1 file changed, 90 insertions(+) (limited to 'clang/unittests/Basic/VirtualFileSystemTest.cpp') diff --git a/clang/unittests/Basic/VirtualFileSystemTest.cpp b/clang/unittests/Basic/VirtualFileSystemTest.cpp index 580343d93ea..92e3663f926 100644 --- a/clang/unittests/Basic/VirtualFileSystemTest.cpp +++ b/clang/unittests/Basic/VirtualFileSystemTest.cpp @@ -305,6 +305,22 @@ struct ScopedDir { } operator StringRef() { return Path.str(); } }; + +struct ScopedLink { + SmallString<128> Path; + ScopedLink(const Twine &To, const Twine &From) { + Path = From.str(); + std::error_code EC = sys::fs::create_link(To, From); + if (EC) + Path = ""; + EXPECT_FALSE(EC); + } + ~ScopedLink() { + if (Path != "") + EXPECT_FALSE(llvm::sys::fs::remove(Path.str())); + } + operator StringRef() { return Path.str(); } +}; } // end anonymous namespace TEST(VirtualFileSystemTest, BasicRealFSIteration) { @@ -334,6 +350,36 @@ TEST(VirtualFileSystemTest, BasicRealFSIteration) { EXPECT_EQ(vfs::directory_iterator(), I); } +#ifdef LLVM_ON_UNIX +TEST(VirtualFileSystemTest, BrokenSymlinkRealFSIteration) { + ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true); + IntrusiveRefCntPtr FS = vfs::getRealFileSystem(); + + ScopedLink _a("no_such_file", TestDirectory + "/a"); + ScopedDir _b(TestDirectory + "/b"); + ScopedLink _c("no_such_file", TestDirectory + "/c"); + + std::error_code EC; + for (vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC), E; + I != E; I.increment(EC)) { + // Skip broken symlinks. + if (EC == std::errc::no_such_file_or_directory) { + EC = std::error_code(); + continue; + } + // For bot debugging. + if (EC) { + outs() << "std::errc::no_such_file_or_directory: " + << (int)std::errc::no_such_file_or_directory << "\n"; + outs() << "EC: " << EC.value() << "\n"; + outs() << "EC message: " << EC.message() << "\n"; + } + ASSERT_FALSE(EC); + EXPECT_TRUE(I->getName() == _b); + } +} +#endif + TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) { ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true); IntrusiveRefCntPtr FS = vfs::getRealFileSystem(); @@ -373,6 +419,50 @@ TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) { EXPECT_EQ(1, Counts[3]); // d } +#ifdef LLVM_ON_UNIX +TEST(VirtualFileSystemTest, BrokenSymlinkRealFSRecursiveIteration) { + ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true); + IntrusiveRefCntPtr FS = vfs::getRealFileSystem(); + + ScopedLink _a("no_such_file", TestDirectory + "/a"); + ScopedDir _b(TestDirectory + "/b"); + ScopedLink _ba("no_such_file", TestDirectory + "/b/a"); + ScopedDir _bb(TestDirectory + "/b/b"); + ScopedLink _bc("no_such_file", TestDirectory + "/b/c"); + ScopedLink _c("no_such_file", TestDirectory + "/c"); + ScopedDir _d(TestDirectory + "/d"); + ScopedDir _dd(TestDirectory + "/d/d"); + ScopedDir _ddd(TestDirectory + "/d/d/d"); + ScopedLink _e("no_such_file", TestDirectory + "/e"); + std::vector Expected = {_b, _bb, _d, _dd, _ddd}; + + std::vector Contents; + std::error_code EC; + for (vfs::recursive_directory_iterator I(*FS, Twine(TestDirectory), EC), E; + I != E; I.increment(EC)) { + // Skip broken symlinks. + if (EC == std::errc::no_such_file_or_directory) { + EC = std::error_code(); + continue; + } + // For bot debugging. + if (EC) { + outs() << "std::errc::no_such_file_or_directory: " + << (int)std::errc::no_such_file_or_directory << "\n"; + outs() << "EC: " << EC.value() << "\n"; + outs() << "EC message: " << EC.message() << "\n"; + } + ASSERT_FALSE(EC); + Contents.push_back(I->getName()); + } + + // Check sorted contents. + std::sort(Contents.begin(), Contents.end()); + EXPECT_EQ(Expected.size(), Contents.size()); + EXPECT_TRUE(std::equal(Contents.begin(), Contents.end(), Expected.begin())); +} +#endif + template static void checkContents(DirIter I, ArrayRef ExpectedOut) { std::error_code EC; -- cgit v1.2.3