virtual std::error_code close() = 0;
};
+/// A member of a directory, yielded by a directory_iterator.
+/// Only information available on most platforms is included.
+class directory_entry {
+ std::string Path;
+ llvm::sys::fs::file_type Type;
+
+public:
+ directory_entry() = default;
+ directory_entry(std::string Path, llvm::sys::fs::file_type Type)
+ : Path(std::move(Path)), Type(Type) {}
+
+ llvm::StringRef path() const { return Path; }
+ llvm::sys::fs::file_type type() const { return Type; }
+};
+
namespace detail {
/// An interface for virtual file systems to provide an iterator over the
virtual ~DirIterImpl();
/// Sets \c CurrentEntry to the next entry in the directory on success,
- /// or returns a system-defined \c error_code.
+ /// to directory_entry() at end, or returns a system-defined \c error_code.
virtual std::error_code increment() = 0;
- Status CurrentEntry;
+ directory_entry CurrentEntry;
};
} // namespace detail
directory_iterator(std::shared_ptr<detail::DirIterImpl> I)
: Impl(std::move(I)) {
assert(Impl.get() != nullptr && "requires non-null implementation");
- if (!Impl->CurrentEntry.isStatusKnown())
+ if (Impl->CurrentEntry.path().empty())
Impl.reset(); // Normalize the end iterator to Impl == nullptr.
}
directory_iterator &increment(std::error_code &EC) {
assert(Impl && "attempting to increment past end");
EC = Impl->increment();
- if (!Impl->CurrentEntry.isStatusKnown())
+ if (Impl->CurrentEntry.path().empty())
Impl.reset(); // Normalize the end iterator to Impl == nullptr.
return *this;
}
- const Status &operator*() const { return Impl->CurrentEntry; }
- const Status *operator->() const { return &Impl->CurrentEntry; }
+ const directory_entry &operator*() const { return Impl->CurrentEntry; }
+ const directory_entry *operator->() const { return &Impl->CurrentEntry; }
bool operator==(const directory_iterator &RHS) const {
if (Impl && RHS.Impl)
- return Impl->CurrentEntry.equivalent(RHS.Impl->CurrentEntry);
+ return Impl->CurrentEntry.path() == RHS.Impl->CurrentEntry.path();
return !Impl && !RHS.Impl;
}
bool operator!=(const directory_iterator &RHS) const {
/// Equivalent to operator++, with an error code.
recursive_directory_iterator &increment(std::error_code &EC);
- const Status &operator*() const { return *State->top(); }
- const Status *operator->() const { return &*State->top(); }
+ const directory_entry &operator*() const { return *State->top(); }
+ const directory_entry *operator->() const { return &*State->top(); }
bool operator==(const recursive_directory_iterator &Other) const {
return State == Other.State; // identity
public:
RealFSDirIter(const Twine &Path, std::error_code &EC) : Iter(Path, EC) {
- if (Iter != llvm::sys::fs::directory_iterator()) {
- llvm::sys::fs::file_status S;
- std::error_code ErrorCode = llvm::sys::fs::status(Iter->path(), S, true);
- CurrentEntry = Status::copyWithNewName(S, Iter->path());
- if (!EC)
- EC = ErrorCode;
- }
+ if (Iter != llvm::sys::fs::directory_iterator())
+ CurrentEntry = directory_entry(Iter->path(), Iter->type());
}
std::error_code increment() override {
std::error_code EC;
Iter.increment(EC);
- if (Iter == llvm::sys::fs::directory_iterator()) {
- CurrentEntry = Status();
- } else {
- llvm::sys::fs::file_status S;
- std::error_code ErrorCode = llvm::sys::fs::status(Iter->path(), S, true);
- CurrentEntry = Status::copyWithNewName(S, Iter->path());
- if (!EC)
- EC = ErrorCode;
- }
+ CurrentEntry = (Iter == llvm::sys::fs::directory_iterator())
+ ? directory_entry()
+ : directory_entry(Iter->path(), Iter->type());
return EC;
}
};
while (true) {
std::error_code EC = incrementDirIter(IsFirstTime);
if (EC || CurrentDirIter == directory_iterator()) {
- CurrentEntry = Status();
+ CurrentEntry = directory_entry();
return EC;
}
CurrentEntry = *CurrentDirIter;
- StringRef Name = llvm::sys::path::filename(CurrentEntry.getName());
+ StringRef Name = llvm::sys::path::filename(CurrentEntry.path());
if (SeenNames.insert(Name).second)
return EC; // name not seen before
}
if (I != E) {
SmallString<256> Path(RequestedDirName);
llvm::sys::path::append(Path, I->second->getFileName());
- CurrentEntry = detail::getNodeStatus(I->second.get(), Path);
+ sys::fs::file_type Type;
+ switch (I->second->getKind()) {
+ case detail::IME_File:
+ case detail::IME_HardLink:
+ Type = sys::fs::file_type::regular_file;
+ break;
+ case detail::IME_Directory:
+ Type = sys::fs::file_type::directory_file;
+ break;
+ }
+ CurrentEntry = directory_entry(Path.str(), Type);
} else {
// When we're at the end, make CurrentEntry invalid and DirIterImpl will
// do the rest.
- CurrentEntry = Status();
+ CurrentEntry = directory_entry();
}
}
static bool classof(const Entry *E) { return E->getKind() == EK_File; }
};
-class RedirectingFileSystem;
-
class VFSFromYamlDirIterImpl : public clang::vfs::detail::DirIterImpl {
std::string Dir;
- RedirectingFileSystem &FS;
RedirectingDirectoryEntry::iterator Current, End;
std::error_code incrementImpl();
public:
- VFSFromYamlDirIterImpl(const Twine &Path, RedirectingFileSystem &FS,
+ VFSFromYamlDirIterImpl(const Twine &Path,
RedirectingDirectoryEntry::iterator Begin,
RedirectingDirectoryEntry::iterator End,
std::error_code &EC);
}
auto *D = cast<RedirectingDirectoryEntry>(*E);
- return directory_iterator(std::make_shared<VFSFromYamlDirIterImpl>(Dir,
- *this, D->contents_begin(), D->contents_end(), EC));
+ return directory_iterator(std::make_shared<VFSFromYamlDirIterImpl>(
+ Dir, D->contents_begin(), D->contents_end(), EC));
}
void setExternalContentsPrefixDir(StringRef PrefixDir) {
}
VFSFromYamlDirIterImpl::VFSFromYamlDirIterImpl(
- const Twine &_Path, RedirectingFileSystem &FS,
- RedirectingDirectoryEntry::iterator Begin,
+ const Twine &_Path, RedirectingDirectoryEntry::iterator Begin,
RedirectingDirectoryEntry::iterator End, std::error_code &EC)
- : Dir(_Path.str()), FS(FS), Current(Begin), End(End) {
+ : Dir(_Path.str()), Current(Begin), End(End) {
EC = incrementImpl();
}
while (Current != End) {
SmallString<128> PathStr(Dir);
llvm::sys::path::append(PathStr, (*Current)->getName());
- llvm::ErrorOr<vfs::Status> S = FS.status(PathStr);
- if (!S) {
- // Skip entries which do not map to a reliable external content.
- if (FS.ignoreNonExistentContents() &&
- S.getError() == llvm::errc::no_such_file_or_directory) {
- ++Current;
- continue;
- } else {
- return S.getError();
- }
+ sys::fs::file_type Type;
+ switch ((*Current)->getKind()) {
+ case EK_Directory:
+ Type = sys::fs::file_type::directory_file;
+ break;
+ case EK_File:
+ Type = sys::fs::file_type::regular_file;
+ break;
}
- CurrentEntry = *S;
+ CurrentEntry = directory_entry(PathStr.str(), Type);
break;
}
if (Current == End)
- CurrentEntry = Status();
+ CurrentEntry = directory_entry();
return {};
}
vfs::recursive_directory_iterator &
recursive_directory_iterator::increment(std::error_code &EC) {
assert(FS && State && !State->empty() && "incrementing past end");
- assert(State->top()->isStatusKnown() && "non-canonical end iterator");
+ assert(!State->top()->path().empty() && "non-canonical end iterator");
vfs::directory_iterator End;
- if (State->top()->isDirectory()) {
- vfs::directory_iterator I = FS->dir_begin(State->top()->getName(), EC);
+ if (State->top()->type() == sys::fs::file_type::directory_file) {
+ vfs::directory_iterator I = FS->dir_begin(State->top()->path(), EC);
if (I != End) {
State->push(I);
return *this;
for (vfs::directory_iterator LI =
getDriver().getVFS().dir_begin(Dir.str(), EC), LE;
!EC && LI != LE; LI = LI.increment(EC)) {
- StringRef VersionText = llvm::sys::path::filename(LI->getName());
+ StringRef VersionText = llvm::sys::path::filename(LI->path());
auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);
if (CandidateVersion.Major == -1)
continue;
std::error_code EC;
for (vfs::directory_iterator LI = D.getVFS().dir_begin(PrefixDir, EC), LE;
!EC && LI != LE; LI = LI.increment(EC)) {
- StringRef VersionText = llvm::sys::path::filename(LI->getName());
+ StringRef VersionText = llvm::sys::path::filename(LI->path());
GCCVersion CandidateVersion = GCCVersion::Parse(VersionText);
// Filter out obviously bad entries.
LI = D.getVFS().dir_begin(LibDir + "/" + LibSuffix, EC),
LE;
!EC && LI != LE; LI = LI.increment(EC)) {
- StringRef VersionText = llvm::sys::path::filename(LI->getName());
+ StringRef VersionText = llvm::sys::path::filename(LI->path());
GCCVersion CandidateVersion = GCCVersion::Parse(VersionText);
if (CandidateVersion.Major != -1) // Filter obviously bad entries.
- if (!CandidateGCCInstallPaths.insert(LI->getName()).second)
+ if (!CandidateGCCInstallPaths.insert(LI->path()).second)
continue; // Saw this path before; no need to look at it again.
if (CandidateVersion.isOlderThan(4, 1, 1))
continue;
if (CandidateVersion <= Version)
continue;
- if (!ScanGCCForMultilibs(TargetTriple, Args, LI->getName(),
+ if (!ScanGCCForMultilibs(TargetTriple, Args, LI->path(),
NeedsBiarchSuffix))
continue;
// used here since we're not interested in validating the PCH at this time,
// but only to check whether this is a file containing an AST.
if (!ASTReader::readASTFileControlBlock(
- Dir->getName(), FileMgr, CI.getPCHContainerReader(),
+ Dir->path(), FileMgr, CI.getPCHContainerReader(),
/*FindModuleFileExtensions=*/false, Validator,
/*ValidateDiagnosticOptions=*/false))
- MDC->addFile(Dir->getName());
+ MDC->addFile(Dir->path());
}
}
Dir != End && !EC; Dir.increment(EC)) {
// Check whether this entry has an extension typically associated with
// headers.
- if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->getName()))
- .Cases(".h", ".H", ".hh", ".hpp", true)
- .Default(false))
+ if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->path()))
+ .Cases(".h", ".H", ".hh", ".hpp", true)
+ .Default(false))
continue;
- const FileEntry *Header = FileMgr.getFile(Dir->getName());
+ const FileEntry *Header = FileMgr.getFile(Dir->path());
// FIXME: This shouldn't happen unless there is a file system race. Is
// that worth diagnosing?
if (!Header)
// Compute the relative path from the directory to this file.
SmallVector<StringRef, 16> Components;
- auto PathIt = llvm::sys::path::rbegin(Dir->getName());
+ auto PathIt = llvm::sys::path::rbegin(Dir->path());
for (int I = 0; I != Dir.level() + 1; ++I, ++PathIt)
Components.push_back(*PathIt);
SmallString<128> RelativeHeader(UmbrellaDir.NameAsWritten);
Dir != DirEnd && !EC; Dir.increment(EC)) {
// Check whether this is an acceptable AST file.
if (ASTReader::isAcceptableASTFile(
- Dir->getName(), FileMgr, CI.getPCHContainerReader(),
+ Dir->path(), FileMgr, CI.getPCHContainerReader(),
CI.getLangOpts(), CI.getTargetOpts(), CI.getPreprocessorOpts(),
SpecificModuleCachePath)) {
- PPOpts.ImplicitPCHInclude = Dir->getName();
+ PPOpts.ImplicitPCHInclude = Dir->path();
Found = true;
break;
}
vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
for (vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC), DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
- if (llvm::sys::path::extension(Dir->getName()) != ".framework")
+ if (llvm::sys::path::extension(Dir->path()) != ".framework")
continue;
const DirectoryEntry *FrameworkDir =
- FileMgr.getDirectory(Dir->getName());
+ FileMgr.getDirectory(Dir->path());
if (!FrameworkDir)
continue;
// Load this framework module.
- loadFrameworkModule(llvm::sys::path::stem(Dir->getName()),
- FrameworkDir, IsSystem);
+ loadFrameworkModule(llvm::sys::path::stem(Dir->path()), FrameworkDir,
+ IsSystem);
}
continue;
}
vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
for (vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC), DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
- bool IsFramework =
- llvm::sys::path::extension(Dir->getName()) == ".framework";
+ bool IsFramework = llvm::sys::path::extension(Dir->path()) == ".framework";
if (IsFramework == SearchDir.isFramework())
- loadModuleMapFile(Dir->getName(), SearchDir.isSystemHeaderDirectory(),
+ loadModuleMapFile(Dir->path(), SearchDir.isSystemHeaderDirectory(),
SearchDir.isFramework());
}
for (vfs::directory_iterator Dir = FS.dir_begin(SubframeworksDirName, EC),
DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
- if (!StringRef(Dir->getName()).endswith(".framework"))
+ if (!StringRef(Dir->path()).endswith(".framework"))
continue;
if (const DirectoryEntry *SubframeworkDir =
- FileMgr.getDirectory(Dir->getName())) {
+ FileMgr.getDirectory(Dir->path())) {
// Note: as an egregious but useful hack, we use the real path here and
// check whether it is actually a subdirectory of the parent directory.
// This will not be the case if the 'subframework' is actually a symlink
vfs::FileSystem &FS = *SourceMgr.getFileManager().getVirtualFileSystem();
for (vfs::recursive_directory_iterator I(FS, Dir->getName(), EC), E;
I != E && !EC; I.increment(EC)) {
- if (const FileEntry *FE =
- SourceMgr.getFileManager().getFile(I->getName())) {
+ if (const FileEntry *FE = SourceMgr.getFileManager().getFile(I->path())) {
- Module::Header Header = {I->getName(), FE};
+ Module::Header Header = {I->path(), FE};
Headers.push_back(std::move(Header));
}
}
// Check whether this entry has an extension typically associated with
// headers.
- if (!StringSwitch<bool>(llvm::sys::path::extension(Entry->getName()))
+ if (!StringSwitch<bool>(llvm::sys::path::extension(Entry->path()))
.Cases(".h", ".H", ".hh", ".hpp", true)
.Default(false))
continue;
- if (const FileEntry *Header = getFileManager().getFile(Entry->getName()))
+ if (const FileEntry *Header = getFileManager().getFile(Entry->path()))
if (!getSourceManager().hasFileInfo(Header)) {
if (!ModMap.isHeaderInUnavailableModule(Header)) {
// Find the relative path that would access this header.
Path(_Path.str()) {
for ( ; I != FilesAndDirs.end(); ++I) {
if (isInPath(I->first)) {
- CurrentEntry = I->second;
+ CurrentEntry =
+ vfs::directory_entry(I->second.getName(), I->second.getType());
break;
}
}
++I;
for ( ; I != FilesAndDirs.end(); ++I) {
if (isInPath(I->first)) {
- CurrentEntry = I->second;
+ CurrentEntry =
+ vfs::directory_entry(I->second.getName(), I->second.getType());
break;
}
}
if (I == FilesAndDirs.end())
- CurrentEntry = vfs::Status();
+ CurrentEntry = vfs::directory_entry();
return std::error_code();
}
};
ASSERT_FALSE(EC);
ASSERT_NE(vfs::directory_iterator(), I);
// Check either a or c, since we can't rely on the iteration order.
- EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c"));
+ EXPECT_TRUE(I->path().endswith("a") || I->path().endswith("c"));
I.increment(EC);
ASSERT_FALSE(EC);
ASSERT_NE(vfs::directory_iterator(), I);
- EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c"));
+ EXPECT_TRUE(I->path().endswith("a") || I->path().endswith("c"));
I.increment(EC);
EXPECT_EQ(vfs::directory_iterator(), I);
}
<< "EC message: " << EC2.message() << "\n";
}
ASSERT_FALSE(EC);
- EXPECT_TRUE(I->getName() == _b);
+ EXPECT_TRUE(I->path() == _b);
}
}
#endif
std::vector<std::string> Contents;
for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
I.increment(EC)) {
- Contents.push_back(I->getName());
+ Contents.push_back(I->path());
}
// Check contents, which may be in any order
I != E; I.increment(EC)) {
auto EC2 = std::make_error_code(std::errc::no_such_file_or_directory);
if (EC == EC2) {
- VisitedBrokenSymlinks.push_back(I->getName());
+ VisitedBrokenSymlinks.push_back(I->path());
continue;
}
// For bot debugging.
<< "EC message: " << EC2.message() << "\n";
}
ASSERT_FALSE(EC);
- VisitedNonBrokenSymlinks.push_back(I->getName());
+ VisitedNonBrokenSymlinks.push_back(I->path());
}
// Check visited file names.
// Do not rely on iteration order to check for contents, sort both
// content vectors before comparison.
for (DirIter E; !EC && I != E; I.increment(EC))
- InputToCheck.push_back(I->getName());
+ InputToCheck.push_back(I->path());
llvm::sort(InputToCheck.begin(), InputToCheck.end());
llvm::sort(Expected.begin(), Expected.end());
O->pushOverlay(Upper);
std::error_code EC;
- Lower->addRegularFile("/onlyInLow", sys::fs::owner_read);
- Lower->addRegularFile("/hiddenByMid", sys::fs::owner_read);
- Lower->addRegularFile("/hiddenByUp", sys::fs::owner_read);
- Middle->addRegularFile("/onlyInMid", sys::fs::owner_write);
- Middle->addRegularFile("/hiddenByMid", sys::fs::owner_write);
- Middle->addRegularFile("/hiddenByUp", sys::fs::owner_write);
- Upper->addRegularFile("/onlyInUp", sys::fs::owner_all);
- Upper->addRegularFile("/hiddenByUp", sys::fs::owner_all);
+ Lower->addRegularFile("/onlyInLow");
+ Lower->addDirectory("/hiddenByMid");
+ Lower->addDirectory("/hiddenByUp");
+ Middle->addRegularFile("/onlyInMid");
+ Middle->addRegularFile("/hiddenByMid");
+ Middle->addDirectory("/hiddenByUp");
+ Upper->addRegularFile("/onlyInUp");
+ Upper->addRegularFile("/hiddenByUp");
checkContents(
O->dir_begin("/", EC),
{"/hiddenByUp", "/onlyInUp", "/hiddenByMid", "/onlyInMid", "/onlyInLow"});
std::error_code EC;
vfs::directory_iterator I = O->dir_begin("/", EC), E;
for ( ; !EC && I != E; I.increment(EC))
- if (I->getName() == "/hiddenByUp")
+ if (I->path() == "/hiddenByUp")
break;
ASSERT_NE(E, I);
- EXPECT_EQ(sys::fs::owner_all, I->getPermissions());
+ EXPECT_EQ(sys::fs::file_type::regular_file, I->type());
}
{
std::error_code EC;
vfs::directory_iterator I = O->dir_begin("/", EC), E;
for ( ; !EC && I != E; I.increment(EC))
- if (I->getName() == "/hiddenByMid")
+ if (I->path() == "/hiddenByMid")
break;
ASSERT_NE(E, I);
- EXPECT_EQ(sys::fs::owner_write, I->getPermissions());
+ EXPECT_EQ(sys::fs::file_type::regular_file, I->type());
}
}
std::error_code EC;
vfs::directory_iterator I = FS.dir_begin("/", EC);
ASSERT_FALSE(EC);
- ASSERT_EQ("/a", I->getName());
+ ASSERT_EQ("/a", I->path());
I.increment(EC);
ASSERT_FALSE(EC);
- ASSERT_EQ("/b", I->getName());
+ ASSERT_EQ("/b", I->path());
I.increment(EC);
ASSERT_FALSE(EC);
ASSERT_EQ(vfs::directory_iterator(), I);
ASSERT_FALSE(EC);
// When on Windows, we end up with "/b\\c" as the name. Convert to Posix
// path for the sake of the comparison.
- ASSERT_EQ("/b/c", getPosixPath(I->getName()));
+ ASSERT_EQ("/b/c", getPosixPath(I->path()));
I.increment(EC);
ASSERT_FALSE(EC);
ASSERT_EQ(vfs::directory_iterator(), I);
clang::vfs::directory_iterator It = NormalizedFS.dir_begin("../b", EC);
// When on Windows, we end up with "../b\\c" as the name. Convert to Posix
// path for the sake of the comparison.
- ASSERT_EQ("../b/c", getPosixPath(It->getName()));
+ ASSERT_EQ("../b/c", getPosixPath(It->path()));
}
TEST_F(InMemoryFileSystemTest, AddHardLinkToFile) {
std::vector<std::string> Nodes;
for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
I.increment(EC)) {
- Nodes.push_back(getPosixPath(I->getName()));
+ Nodes.push_back(getPosixPath(I->path()));
}
EXPECT_THAT(Nodes, testing::UnorderedElementsAre("/a", "/a/b", "/c", "/c/d"));
}