summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuergen Ributzka <juergen@apple.com>2017-03-10 22:49:04 +0000
committerJuergen Ributzka <juergen@apple.com>2017-03-10 22:49:04 +0000
commit46541f1b0bc2126d2bb5b8c673ddec212c18c64e (patch)
treee91b3bece50c9c30f024ea7fa20db002f4242238
parent83c37c4dac6cc0d8af01902e81cf6f6f4995c8f6 (diff)
downloadbcm5719-llvm-46541f1b0bc2126d2bb5b8c673ddec212c18c64e.tar.gz
bcm5719-llvm-46541f1b0bc2126d2bb5b8c673ddec212c18c64e.zip
Reapply [VFS] Ignore broken symlinks in the directory iterator.
Modified the tests to accept any iteration order. 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 allow to recover from this issue by clearing the error code and skipping to the next entry. This change adds the same functionality 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: 297528
-rw-r--r--clang/include/clang/Basic/VirtualFileSystem.h2
-rw-r--r--clang/lib/Basic/VirtualFileSystem.cpp7
-rw-r--r--clang/unittests/Basic/VirtualFileSystemTest.cpp74
3 files changed, 77 insertions, 6 deletions
diff --git a/clang/include/clang/Basic/VirtualFileSystem.h b/clang/include/clang/Basic/VirtualFileSystem.h
index 39dab6cbf04..e52b345e286 100644
--- a/clang/include/clang/Basic/VirtualFileSystem.h
+++ b/clang/include/clang/Basic/VirtualFileSystem.h
@@ -161,7 +161,7 @@ public:
directory_iterator &increment(std::error_code &EC) {
assert(Impl && "attempting to increment past end");
EC = Impl->increment();
- if (EC || !Impl->CurrentEntry.isStatusKnown())
+ if (!Impl->CurrentEntry.isStatusKnown())
Impl.reset(); // Normalize the end iterator to Impl == nullptr.
return *this;
}
diff --git a/clang/lib/Basic/VirtualFileSystem.cpp b/clang/lib/Basic/VirtualFileSystem.cpp
index 43cd9f17ceb..f5db717866a 100644
--- a/clang/lib/Basic/VirtualFileSystem.cpp
+++ b/clang/lib/Basic/VirtualFileSystem.cpp
@@ -244,8 +244,7 @@ public:
if (!EC && Iter != llvm::sys::fs::directory_iterator()) {
llvm::sys::fs::file_status S;
EC = Iter->status(S);
- if (!EC)
- CurrentEntry = Status::copyWithNewName(S, Iter->path());
+ CurrentEntry = Status::copyWithNewName(S, Iter->path());
}
}
@@ -1856,7 +1855,7 @@ vfs::recursive_directory_iterator::recursive_directory_iterator(FileSystem &FS_,
std::error_code &EC)
: FS(&FS_) {
directory_iterator I = FS->dir_begin(Path, EC);
- if (!EC && I != directory_iterator()) {
+ if (I != directory_iterator()) {
State = std::make_shared<IterState>();
State->push(I);
}
@@ -1869,8 +1868,6 @@ recursive_directory_iterator::increment(std::error_code &EC) {
vfs::directory_iterator End;
if (State->top()->isDirectory()) {
vfs::directory_iterator I = FS->dir_begin(State->top()->getName(), EC);
- if (EC)
- return *this;
if (I != End) {
State->push(I);
return *this;
diff --git a/clang/unittests/Basic/VirtualFileSystemTest.cpp b/clang/unittests/Basic/VirtualFileSystemTest.cpp
index 580343d93ea..79b4d87044b 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,28 @@ TEST(VirtualFileSystemTest, BasicRealFSIteration) {
EXPECT_EQ(vfs::directory_iterator(), I);
}
+TEST(VirtualFileSystemTest, BrokenSymlinkRealFSIteration) {
+ ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
+ IntrusiveRefCntPtr<vfs::FileSystem> 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;
+ } else if (EC) {
+ break;
+ }
+ EXPECT_TRUE(I->getName() == _b);
+ }
+}
+
TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) {
ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true);
IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
@@ -373,6 +411,42 @@ TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) {
EXPECT_EQ(1, Counts[3]); // d
}
+TEST(VirtualFileSystemTest, BrokenSymlinkRealFSRecursiveIteration) {
+ ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
+ IntrusiveRefCntPtr<vfs::FileSystem> 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<StringRef> Expected = {_b, _bb, _d, _dd, _ddd};
+
+ std::vector<std::string> 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;
+ } else if (EC) {
+ break;
+ }
+ 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()));
+}
+
template <typename DirIter>
static void checkContents(DirIter I, ArrayRef<StringRef> ExpectedOut) {
std::error_code EC;
OpenPOWER on IntegriCloud