1//===- VirtualFileSystem.cpp - Virtual File System Layer ------------------===// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7//===----------------------------------------------------------------------===// 9// This file implements the VirtualFileSystem interface. 11//===----------------------------------------------------------------------===// 24#include "llvm/Config/llvm-config.h" 49#include <system_error> 75returnStatus(In.getName(), In.getUniqueID(), In.getLastModificationTime(),
76 In.getUser(), In.getGroup(), NewSize, In.getType(),
81returnStatus(NewName, In.getUniqueID(), In.getLastModificationTime(),
82 In.getUser(), In.getGroup(), In.getSize(), In.getType(),
87returnStatus(NewName, In.getUniqueID(), In.getLastModificationTime(),
88 In.getUser(), In.getGroup(), In.getSize(), In.type(),
119bool RequiresNullTerminator,
bool IsVolatile,
125return (*F)->getBuffer(
Name, FileSize, RequiresNullTerminator, IsVolatile);
134return WorkingDir.getError();
157return StatusA.getError();
160return StatusB.getError();
161return StatusA->equivalent(*StatusB);
164#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 170return Component ==
".." || Component ==
".";
183//===-----------------------------------------------------------------------===/ 184// RealFileSystem implementation 185//===-----------------------------------------------------------------------===/ 189/// Wrapper around a raw file descriptor. 190classRealFile :
publicFile {
191friendclassRealFileSystem;
195 std::string RealName;
198 : FD(RawFD), S(NewName, {}, {}, {}, {}, {},
200 RealName(NewRealPathName.str()) {
201assert(FD != kInvalidFile &&
"Invalid or inactive file descriptor");
211bool RequiresNullTerminator,
212bool IsVolatile)
override;
213 std::error_code close()
override;
214void setPath(
constTwine &Path)
override;
219RealFile::~RealFile() { close(); }
222assert(FD != kInvalidFile &&
"cannot stat closed file");
223if (!S.isStatusKnown()) {
233return RealName.empty() ? S.getName().str() : RealName;
237RealFile::getBuffer(
constTwine &
Name, int64_t FileSize,
238bool RequiresNullTerminator,
bool IsVolatile) {
239assert(FD != kInvalidFile &&
"cannot get buffer for closed file");
244std::error_code RealFile::close() {
250void RealFile::setPath(
constTwine &Path) {
251 RealName =
Path.str();
258/// A file system according to your operating system. 259/// This may be linked to the process's working directory, or maintain its own. 261/// Currently, its own working directory is emulated by storing the path and 262/// sending absolute paths to llvm::sys::fs:: functions. 263/// A more principled approach would be to push this down a level, modelling 264/// the working dir as an llvm::sys::fs::WorkingDir or similar. 265/// This would enable the use of openat()-style functions on some platforms. 268explicit RealFileSystem(
bool LinkCWDToProcess) {
269if (!LinkCWDToProcess) {
274 WD = WorkingDirectory{PWD, PWD};
276 WD = WorkingDirectory{PWD, RealPWD};
283 openFileForReadBinary(
constTwine &Path)
override;
287 std::error_code setCurrentWorkingDirectory(
constTwine &Path)
override;
288 std::error_code isLocal(
constTwine &Path,
bool &Result)
override;
289 std::error_code getRealPath(
constTwine &Path,
294unsigned IndentLevel)
const override;
297// If this FS has its own working dir, use it to make Path absolute. 298// The returned twine is safe to use as long as both Storage and Path live. 302Path.toVector(Storage);
311 adjustPath(
Name, Storage), Flags, &RealName);
314return std::unique_ptr<File>(
315new RealFile(*FDOrErr,
Name.str(), RealName.
str()));
318structWorkingDirectory {
319// The current working directory, without symlinks resolved. (echo $PWD). 321// The current working directory, with links resolved. (readlink .). 324 std::optional<llvm::ErrorOr<WorkingDirectory>> WD;
332if (std::error_code EC =
339RealFileSystem::openFileForRead(
constTwine &
Name) {
344RealFileSystem::openFileForReadBinary(
constTwine &
Name) {
350return std::string(WD->get().Specified);
352return WD->getError();
357return std::string(Dir);
360std::error_code RealFileSystem::setCurrentWorkingDirectory(
constTwine &Path) {
365 adjustPath(Path, Storage).toVector(Absolute);
370return std::make_error_code(std::errc::not_a_directory);
374return std::error_code();
377std::error_code RealFileSystem::isLocal(
constTwine &Path,
bool &Result) {
382std::error_code RealFileSystem::getRealPath(
constTwine &Path,
389unsigned IndentLevel)
const{
390 printIndent(
OS, IndentLevel);
391OS <<
"RealFileSystem using ";
405return std::make_unique<RealFileSystem>(
false);
414 RealFSDirIter(
constTwine &Path, std::error_code &EC) : Iter(Path, EC) {
419 std::error_code increment()
override{
432 std::error_code &EC) {
435 std::make_shared<RealFSDirIter>(adjustPath(Dir, Storage), EC));
438//===-----------------------------------------------------------------------===/ 439// OverlayFileSystem implementation 440//===-----------------------------------------------------------------------===/ 448// Synchronize added file systems by duplicating the working directory from 449// the first one in the list. 454// FIXME: handle symlinks that cross file systems 464// FIXME: handle symlinks that cross file systems 466if ((*I)->exists(Path))
474// FIXME: handle symlinks that cross file systems 476auto Result = (*I)->openFileForRead(Path);
485// All file systems are synchronized, just take the first working directory. 486return FSList.
front()->getCurrentWorkingDirectory();
491for (
auto &FS : FSList)
492if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))
498for (
auto &FS : FSList)
500return FS->isLocal(Path, Result);
506for (
constauto &FS : FSList)
508return FS->getRealPath(Path, Output);
515 FS->visitChildFileSystems(Callback);
520unsigned IndentLevel)
const{
521 printIndent(
OS, IndentLevel);
522OS <<
"OverlayFileSystem\n";
523if (
Type == PrintType::Summary)
526if (
Type == PrintType::Contents)
527Type = PrintType::Summary;
529 FS->print(
OS,
Type, IndentLevel + 1);
536/// Combines and deduplicates directory entries across multiple file systems. 540 /// Iterators to combine, processed in reverse order. 542 /// The iterator currently being traversed. 544 /// The set of names already returned as entries. 547 /// Sets \c CurrentDirIter to the next iterator in the list, or leaves it as 548 /// is (at its end position) if we've already gone through them all. 549 std::error_code incrementIter(
bool IsFirstTime) {
550while (!IterList.
empty()) {
551 CurrentDirIter = IterList.
back();
558return errc::no_such_file_or_directory;
562 std::error_code incrementDirIter(
bool IsFirstTime) {
564"incrementing past end");
569EC = incrementIter(IsFirstTime);
573 std::error_code incrementImpl(
bool IsFirstTime) {
575 std::error_code
EC = incrementDirIter(IsFirstTime);
580 CurrentEntry = *CurrentDirIter;
583returnEC;
// name not seen before 590 std::error_code &EC) {
591for (
constauto &FS : FileSystems) {
594if (FEC && FEC != errc::no_such_file_or_directory) {
601EC = incrementImpl(
true);
606 : IterList(DirIters) {
607EC = incrementImpl(
true);
610 std::error_code increment()
override{
return incrementImpl(
false); }
616 std::error_code &EC) {
618 std::make_shared<CombiningDirIterImpl>(FSList, Dir.
str(), EC));
624void ProxyFileSystem::anchor() {}
638/// The in memory file system is a tree of Nodes. Every node can either be a 639/// file, symlink, hardlink or a directory. 642 std::string FileName;
646 : Kind(Kind), FileName(
std::
string(
llvm::sys::path::filename(FileName))) {
650 /// Return the \p Status for this node. \p RequestedName should be the name 651 /// through which the caller referred to this node. It will override 652 /// \p Status::Name in the return value, to mimic the behavior of \p RealFile. 655 /// Get the filename of this node (the name without the directory part). 658virtual std::string
toString(
unsigned Indent)
const = 0;
663 std::unique_ptr<llvm::MemoryBuffer> Buffer;
671return Status::copyWithNewName(Stat, RequestedName);
675 std::string
toString(
unsigned Indent)
const override{
676return (std::string(Indent,
' ') + Stat.
getName() +
"\n").str();
686classInMemoryHardLink :
public InMemoryNode {
687const InMemoryFile &ResolvedFile;
690 InMemoryHardLink(
StringRef Path,
const InMemoryFile &ResolvedFile)
691 : InMemoryNode(Path, IME_HardLink), ResolvedFile(ResolvedFile) {}
692const InMemoryFile &getResolvedFile()
const{
return ResolvedFile; }
694Status getStatus(
constTwine &RequestedName)
const override{
695return ResolvedFile.getStatus(RequestedName);
698 std::string
toString(
unsigned Indent)
const override{
699return std::string(Indent,
' ') +
"HardLink to -> " +
700 ResolvedFile.toString(0);
703staticbool classof(
const InMemoryNode *
N) {
708classInMemorySymbolicLink :
public InMemoryNode {
709 std::string TargetPath;
717 std::string
toString(
unsigned Indent)
const override{
718return std::string(Indent,
' ') +
"SymbolicLink to -> " + TargetPath;
721Status getStatus(
constTwine &RequestedName)
const override{
722return Status::copyWithNewName(Stat, RequestedName);
725StringRef getTargetPath()
const{
return TargetPath; }
727staticbool classof(
const InMemoryNode *
N) {
732/// Adapt a InMemoryFile for VFS' File interface. The goal is to make 733/// \p InMemoryFileAdaptor mimic as much as possible the behavior of 735classInMemoryFileAdaptor :
publicFile {
736const InMemoryFile &
Node;
737 /// The name to use when returning a Status for this file. 738 std::string RequestedName;
741explicit InMemoryFileAdaptor(
const InMemoryFile &
Node,
742 std::string RequestedName)
746returnNode.getStatus(RequestedName);
750 getBuffer(
constTwine &
Name, int64_t FileSize,
bool RequiresNullTerminator,
751bool IsVolatile)
override{
757 std::error_code close()
override{
return {}; }
759void setPath(
constTwine &Path)
override{ RequestedName =
Path.str(); }
765 std::map<std::string, std::unique_ptr<InMemoryNode>, std::less<>> Entries;
771 /// Return the \p Status for this node. \p RequestedName should be the name 772 /// through which the caller referred to this node. It will override 773 /// \p Status::Name in the return value, to mimic the behavior of \p RealFile. 775return Status::copyWithNewName(Stat, RequestedName);
781autoI = Entries.find(
Name);
782if (
I != Entries.end())
783returnI->second.get();
788return Entries.emplace(
Name, std::move(Child)).first->second.get();
796 std::string
toString(
unsigned Indent)
const override{
798 (std::string(Indent,
' ') + Stat.
getName() +
"\n").str();
799for (
constauto &Entry : Entries)
800 Result += Entry.second->toString(Indent + 2);
811// The UniqueID of in-memory files is derived from path and content. 812// This avoids difficulties in creating exactly equivalent in-memory FSes, 813// as often needed in multithreaded programs. 830 (
Type == sys::fs::file_type::directory_file)
835 Group, Buffer ? Buffer->getBufferSize() : 0,
Type, Perms);
839 : Root(new
detail::InMemoryDirectory(
842llvm::sys::fs::file_type::directory_file,
843llvm::sys::fs::perms::all_all))),
844 UseNormalizedPaths(UseNormalizedPaths) {}
849return Root->toString(
/*Indent=*/0);
852bool InMemoryFileSystem::addFile(
constTwine &
P, time_t ModificationTime,
853 std::unique_ptr<llvm::MemoryBuffer> Buffer,
854 std::optional<uint32_t>
User,
855 std::optional<uint32_t> Group,
856 std::optional<llvm::sys::fs::file_type>
Type,
857 std::optional<llvm::sys::fs::perms> Perms,
858 MakeNodeFn MakeNode) {
862// Fix up relative paths. This just prepends the current working directory. 875constauto ResolvedUser =
User.value_or(0);
876constauto ResolvedGroup = Group.value_or(0);
879// Any intermediate directories we create should be accessible by 880// the owner, even if Perms says otherwise for the final path. 891// This isn't the last element, so we create a new directory. 893StringRef(Path.str().begin(),
Name.end() - Path.str().begin()),
897 Dir = cast<detail::InMemoryDirectory>(Dir->
addChild(
898Name, std::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
901// Creating file under another file. 902if (!isa<detail::InMemoryDirectory>(Node))
904 Dir = cast<detail::InMemoryDirectory>(Node);
910 std::move(Buffer), ResolvedUser, ResolvedGroup,
911 ResolvedType, ResolvedPerms}));
914if (isa<detail::InMemoryDirectory>(
Node))
918 isa<detail::InMemoryHardLink>(
Node)) &&
919"Must be either file, hardlink or directory!");
921// Return false only if the new file is different from the existing one. 922if (
auto *Link = dyn_cast<detail::InMemoryHardLink>(
Node)) {
923returnLink->getResolvedFile().getBuffer()->getBuffer() ==
926return cast<detail::InMemoryFile>(
Node)->getBuffer()->getBuffer() ==
930bool InMemoryFileSystem::addFile(
constTwine &
P, time_t ModificationTime,
931 std::unique_ptr<llvm::MemoryBuffer> Buffer,
932 std::optional<uint32_t>
User,
933 std::optional<uint32_t> Group,
934 std::optional<llvm::sys::fs::file_type>
Type,
935 std::optional<llvm::sys::fs::perms> Perms) {
936return addFile(
P, ModificationTime, std::move(Buffer),
User, Group,
Type,
939 -> std::unique_ptr<detail::InMemoryNode> {
942return std::make_unique<detail::InMemoryDirectory>(Stat);
943return std::make_unique<detail::InMemoryFile>(
944 Stat, std::move(NNI.
Buffer));
949constTwine &
P, time_t ModificationTime,
951 std::optional<uint32_t> Group, std::optional<llvm::sys::fs::file_type>
Type,
952 std::optional<llvm::sys::fs::perms> Perms) {
954 std::move(
User), std::move(Group), std::move(
Type),
957 -> std::unique_ptr<detail::InMemoryNode> {
960return std::make_unique<detail::InMemoryDirectory>(Stat);
961return std::make_unique<detail::InMemoryFile>(
962 Stat, std::move(NNI.
Buffer));
967InMemoryFileSystem::lookupNode(
constTwine &
P,
bool FollowFinalSymlink,
968size_t SymlinkDepth)
const{
972// Fix up relative paths. This just prepends the current working directory. 991if (
auto Symlink = dyn_cast<detail::InMemorySymbolicLink>(Node)) {
992// If we're at the end of the path, and we're not following through 993// terminal symlinks, then we're done. 994if (
I == E && !FollowFinalSymlink)
1004// Keep going with the target. We always want to follow symlinks here 1005// because we're either at the end of a path that we want to follow, or 1006// not at the end of a path, in which case we need to follow the symlink 1009 lookupNode(TargetPath,
/*FollowFinalSymlink=*/true, SymlinkDepth + 1);
1013if (!isa<detail::InMemoryDirectory>(*
Target))
1016// Otherwise, continue on the search in the symlinked directory. 1017 Dir = cast<detail::InMemoryDirectory>(*
Target);
1021// Return the file if it's at the end of the path. 1022if (
autoFile = dyn_cast<detail::InMemoryFile>(Node)) {
1028// If Node is HardLink then return the resolved file. 1029if (
autoFile = dyn_cast<detail::InMemoryHardLink>(
Node)) {
1034// Traverse directories. 1035 Dir = cast<detail::InMemoryDirectory>(
Node);
1043auto NewLinkNode = lookupNode(NewLink,
/*FollowFinalSymlink=*/false);
1044// Whether symlinks in the hardlink target are followed is 1045// implementation-defined in POSIX. 1046// We're following symlinks here to be consistent with macOS. 1047auto TargetNode = lookupNode(
Target,
/*FollowFinalSymlink=*/true);
1048// FromPath must not have been added before. ToPath must have been added 1049// before. Resolved ToPath must be a File. 1050if (!TargetNode || NewLinkNode || !isa<detail::InMemoryFile>(*TargetNode))
1052return addFile(NewLink, 0,
nullptr, std::nullopt, std::nullopt, std::nullopt,
1054return std::make_unique<detail::InMemoryHardLink>(
1056 *cast<detail::InMemoryFile>(*TargetNode));
1062 std::optional<uint32_t>
User, std::optional<uint32_t> Group,
1063 std::optional<llvm::sys::fs::perms> Perms) {
1064auto NewLinkNode = lookupNode(NewLink,
/*FollowFinalSymlink=*/false);
1070Target.toVector(TargetStr);
1072return addFile(NewLinkStr, ModificationTime,
nullptr,
User, Group,
1075return std::make_unique<detail::InMemorySymbolicLink>(
1081auto Node = lookupNode(Path,
/*FollowFinalSymlink=*/true);
1083return (*Node)->getStatus(Path);
1084return Node.getError();
1089auto Node = lookupNode(Path,
/*FollowFinalSymlink=*/true);
1091return Node.getError();
1093// When we have a file provide a heap-allocated wrapper for the memory buffer 1094// to match the ownership semantics for File. 1095if (
auto *
F = dyn_cast<detail::InMemoryFile>(*Node))
1096return std::unique_ptr<File>(
1097new detail::InMemoryFileAdaptor(*
F, Path.str()));
1099// FIXME: errc::not_a_file? 1103/// Adaptor from InMemoryDir::iterator to directory_iterator. 1108 std::string RequestedDirName;
1110void setCurrentEntry() {
1115switch (
I->second->getKind()) {
1124if (
auto SymlinkTarget =
1125 FS->lookupNode(Path,
/*FollowFinalSymlink=*/true)) {
1126 Path = SymlinkTarget.getName();
1127Type = (*SymlinkTarget)->getStatus(Path).getType();
1133// When we're at the end, make CurrentEntry invalid and DirIterImpl will 1144 std::string RequestedDirName)
1145 : FS(FS),
I(Dir.begin()), E(Dir.end()),
1146 RequestedDirName(
std::
move(RequestedDirName)) {
1158 std::error_code &EC) {
1159auto Node = lookupNode(Dir,
/*FollowFinalSymlink=*/true);
1161 EC = Node.getError();
1165if (
auto *DirNode = dyn_cast<detail::InMemoryDirectory>(*Node))
1167 std::make_shared<DirIterator>(
this, *DirNode, Dir.
str()));
1177// Fix up relative paths. This just prepends the current working directory. 1186 WorkingDirectory = std::string(Path);
1193if (!CWD || CWD->empty())
1195 Path.toVector(Output);
1208unsigned IndentLevel)
const{
1209 printIndent(
OS, IndentLevel);
1210OS <<
"InMemoryFileSystem\n";
1216//===-----------------------------------------------------------------------===/ 1217// RedirectingFileSystem implementation 1218//===-----------------------------------------------------------------------===/ 1223// Detect the path style in use by checking the first separator. 1225constsize_t n = Path.find_first_of(
"/\\");
1226// Can't distinguish between posix and windows_slash here. 1227if (n !=
static_cast<size_t>(-1))
1233/// Removes leading "./" as well as path components like ".." and ".". 1235// First detect the path style in use by checking the first separator. 1238// Now remove the dots. Explicitly specifying the path style prevents the 1239// direction of the slashes from changing. 1246/// Whether the error and entry specify a file/directory that was not found. 1247staticbool isFileNotFound(std::error_code EC,
1249if (E && !isa<RedirectingFileSystem::DirectoryRemapEntry>(E))
1254}
// anonymous namespace 1260if (
auto ExternalWorkingDirectory =
1261 ExternalFS->getCurrentWorkingDirectory()) {
1262 WorkingDirectory = *ExternalWorkingDirectory;
1266/// Directory iterator implementation for \c RedirectingFileSystem's 1267/// directory entries. 1273 std::error_code incrementImpl(
bool IsFirstTime) {
1274assert((IsFirstTime || Current !=
End) &&
"cannot iterate past end");
1281switch ((*Current)->getKind()) {
1302 : Dir(Path.str()), Current(Begin),
End(
End) {
1303 EC = incrementImpl(
/*IsFirstTime=*/true);
1307return incrementImpl(
/*IsFirstTime=*/false);
1312/// Directory iterator implementation for \c RedirectingFileSystem's 1313/// directory remap entries that maps the paths reported by the external 1314/// file system's directory iterator back to the virtual directory's path. 1321 RedirectingFSDirRemapIterImpl(std::string DirPath,
1323 : Dir(
std::
move(DirPath)), DirStyle(getExistingStyle(Dir)),
1324 ExternalIter(ExtIter) {
1329void setCurrentEntry() {
1340 std::error_code increment()
override{
1354return WorkingDirectory;
1359// Don't change the working directory if the path doesn't exist. 1364 Path.toVector(AbsolutePath);
1365if (std::error_code EC = makeAbsolute(AbsolutePath))
1367 WorkingDirectory = std::string(AbsolutePath);
1376if (makeAbsolute(Path))
1379return ExternalFS->isLocal(Path, Result);
1383// is_absolute(..., Style::windows_*) accepts paths with both slash types. 1387// This covers windows absolute path with forward slash as well, as the 1388// forward slashes are treated as path separation in llvm::path 1389// regardless of what path::Style is used. 1394return WorkingDir.getError();
1396return makeAbsolute(WorkingDir.get(), Path);
1400RedirectingFileSystem::makeAbsolute(
StringRef WorkingDir,
1402// We can't use sys::fs::make_absolute because that assumes the path style 1403// is native and there is no way to override that. Since we know WorkingDir 1404// is absolute, we can use it to determine which style we actually have and 1405// append Path ourselves. 1406if (!WorkingDir.
empty() &&
1410return std::error_code();
1416// Distinguish between windows_backslash and windows_slash; getExistingStyle 1417// returns posix for a path with windows_slash. 1422 std::string
Result = std::string(WorkingDir);
1427// backslashes '\' are legit path charactors under POSIX. Windows APIs 1428// like CreateFile accepts forward slashes '/' as path 1429// separator (even when mixed with backslashes). Therefore, 1430// `Path` should be directly appended to `WorkingDir` without converting 1439 std::error_code &EC) {
1443 EC = makeAbsolute(Path);
1450 isFileNotFound(Result.getError()))
1451return ExternalFS->dir_begin(Path, EC);
1453 EC = Result.getError();
1457// Use status to make sure the path exists and refers to a directory. 1461 isFileNotFound(S.
getError(), Result->E))
1462return ExternalFS->dir_begin(Dir, EC);
1468if (!S->isDirectory()) {
1473// Create the appropriate directory iterator based on whether we found a 1474// DirectoryRemapEntry or DirectoryEntry. 1476 std::error_code RedirectEC;
1477if (
auto ExtRedirect = Result->getExternalRedirect()) {
1478auto RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
1479 RedirectIter = ExternalFS->dir_begin(*ExtRedirect, RedirectEC);
1481if (!RE->useExternalName(UseExternalNames)) {
1482// Update the paths in the results to use the virtual directory's path. 1485 std::string(Path), RedirectIter));
1488auto DE = cast<DirectoryEntry>(Result->E);
1491 Path, DE->contents_begin(), DE->contents_end(), RedirectEC));
1507 std::error_code ExternalEC;
1518switch (Redirection) {
1532 std::make_shared<CombiningDirIterImpl>(Iters, EC)};
1539 OverlayFileDir = Dir.
str();
1543return OverlayFileDir;
1560 std::vector<StringRef> R;
1561 R.reserve(Roots.size());
1562for (
constauto &Root : Roots)
1563 R.push_back(Root->getName());
1568unsigned IndentLevel)
const{
1570OS <<
"RedirectingFileSystem (UseExternalNames: " 1571 << (UseExternalNames ?
"true" :
"false") <<
")\n";
1575for (
constauto &Root : Roots)
1579OS <<
"ExternalFS:\n";
1586unsigned IndentLevel)
const{
1592auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(E);
1595for (std::unique_ptr<Entry> &SubEntry :
1602auto *RE = cast<RedirectingFileSystem::RemapEntry>(E);
1603OS <<
" -> '" << RE->getExternalContentsPath() <<
"'";
1604switch (RE->getUseName()) {
1608OS <<
" (UseExternalName: true)";
1611OS <<
" (UseExternalName: false)";
1622 Callback(*ExternalFS);
1623 ExternalFS->visitChildFileSystems(Callback);
1627/// A helper class to hold the common YAML parsing state. 1636constauto *S = dyn_cast<yaml::ScalarNode>(
N);
1639error(
N,
"expected string");
1642 Result = S->getValue(Storage);
1650if (!parseScalarString(
N,
Value, Storage))
1653if (
Value.equals_insensitive(
"true") ||
Value.equals_insensitive(
"on") ||
1654Value.equals_insensitive(
"yes") ||
Value ==
"1") {
1657 }
elseif (
Value.equals_insensitive(
"false") ||
1658Value.equals_insensitive(
"off") ||
1659Value.equals_insensitive(
"no") ||
Value ==
"0") {
1664error(
N,
"expected boolean value");
1668 std::optional<RedirectingFileSystem::RedirectKind>
1672if (!parseScalarString(
N,
Value, Storage))
1675if (
Value.equals_insensitive(
"fallthrough")) {
1677 }
elseif (
Value.equals_insensitive(
"fallback")) {
1679 }
elseif (
Value.equals_insensitive(
"redirect-only")) {
1685 std::optional<RedirectingFileSystem::RootRelativeKind>
1689if (!parseScalarString(
N,
Value, Storage))
1691if (
Value.equals_insensitive(
"cwd")) {
1693 }
elseif (
Value.equals_insensitive(
"overlay-dir")) {
1703 KeyStatus(
bool Required =
false) : Required(Required) {}
1706usingKeyStatusPair = std::pair<StringRef, KeyStatus>;
1711auto It = Keys.
find(Key);
1712if (It == Keys.
end()) {
1713error(KeyNode,
"unknown key");
1716 KeyStatus &S = It->second;
1718error(KeyNode,
Twine(
"duplicate key '") + Key +
"'");
1727for (
constauto &
I : Keys) {
1728if (
I.second.Required && !
I.second.Seen) {
1740if (!ParentEntry) {
// Look for a existent root 1741for (
constauto &Root : FS->Roots) {
1742if (
Name == Root->getName()) {
1743 ParentEntry = Root.get();
1747 }
else {
// Advance to the next component 1748auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
1749for (std::unique_ptr<RedirectingFileSystem::Entry> &
Content :
1752 dyn_cast<RedirectingFileSystem::DirectoryEntry>(
Content.get());
1758// ... or create a new one 1759 std::unique_ptr<RedirectingFileSystem::Entry> E =
1760 std::make_unique<RedirectingFileSystem::DirectoryEntry>(
1762 std::chrono::system_clock::now(), 0, 0, 0,
1765if (!ParentEntry) {
// Add a new root to the overlay 1766 FS->Roots.push_back(std::move(E));
1767 ParentEntry = FS->Roots.back().get();
1771auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
1772 DE->addContent(std::move(E));
1773return DE->getLastContent();
1783auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
1784// Empty directories could be present in the YAML as a way to 1785// describe a file for a current directory after some of its subdir 1786// is parsed. This only leads to redundant walks, ignore it. 1789for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
1791 uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
1795assert(NewParentE &&
"Parent entry must exist");
1796auto *DR = cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
1797auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
1799 std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
1800Name, DR->getExternalContentsPath(), DR->getUseName()));
1804assert(NewParentE &&
"Parent entry must exist");
1805auto *FE = cast<RedirectingFileSystem::FileEntry>(SrcE);
1806auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
1807 DE->addContent(std::make_unique<RedirectingFileSystem::FileEntry>(
1808Name, FE->getExternalContentsPath(), FE->getUseName()));
1814 std::unique_ptr<RedirectingFileSystem::Entry>
1816auto *
M = dyn_cast<yaml::MappingNode>(
N);
1818error(
N,
"expected mapping node for file or directory entry");
1822 KeyStatusPair Fields[] = {
1823 KeyStatusPair(
"name",
true),
1824 KeyStatusPair(
"type",
true),
1825 KeyStatusPair(
"contents",
false),
1826 KeyStatusPair(
"external-contents",
false),
1827 KeyStatusPair(
"use-external-name",
false),
1832enum { CF_NotSet, CF_List, CF_External } ContentsField = CF_NotSet;
1833 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>>
1843// Reuse the buffer for key and value, since we don't look at key after 1846if (!parseScalarString(
I.getKey(), Key, Buffer))
1849if (!checkDuplicateOrUnknownKey(
I.getKey(), Key, Keys))
1854if (!parseScalarString(
I.getValue(),
Value, Buffer))
1857 NameValueNode =
I.getValue();
1858// Guarantee that old YAML files containing paths with ".." and "." 1859// are properly canonicalized before read into the VFS. 1861 }
elseif (Key ==
"type") {
1862if (!parseScalarString(
I.getValue(),
Value, Buffer))
1866elseif (
Value ==
"directory")
1868elseif (
Value ==
"directory-remap")
1871error(
I.getValue(),
"unknown value for 'type'");
1874 }
elseif (Key ==
"contents") {
1875if (ContentsField != CF_NotSet) {
1877"entry already has 'contents' or 'external-contents'");
1880 ContentsField = CF_List;
1881auto *Contents = dyn_cast<yaml::SequenceNode>(
I.getValue());
1883// FIXME: this is only for directories, what about files? 1884error(
I.getValue(),
"expected array");
1888for (
auto &
I : *Contents) {
1889if (std::unique_ptr<RedirectingFileSystem::Entry> E =
1890 parseEntry(&
I, FS,
/*IsRootEntry*/false))
1891 EntryArrayContents.push_back(std::move(E));
1895 }
elseif (Key ==
"external-contents") {
1896if (ContentsField != CF_NotSet) {
1898"entry already has 'contents' or 'external-contents'");
1901 ContentsField = CF_External;
1902if (!parseScalarString(
I.getValue(),
Value, Buffer))
1906if (
FS->IsRelativeOverlay) {
1907 FullPath =
FS->getOverlayFileDir();
1909"External contents prefix directory must exist");
1915// Guarantee that old YAML files containing paths with ".." and "." 1916// are properly canonicalized before read into the VFS. 1917 FullPath = canonicalize(FullPath);
1918 ExternalContentsPath = FullPath.
str();
1919 }
elseif (Key ==
"use-external-name") {
1921if (!parseScalarBool(
I.getValue(), Val))
1933// check for missing keys 1934if (ContentsField == CF_NotSet) {
1935error(
N,
"missing key 'contents' or 'external-contents'");
1938if (!checkMissingKeys(
N, Keys))
1941// check invalid configuration 1944error(
N,
"'use-external-name' is not supported for 'directory' entries");
1949 ContentsField == CF_List) {
1950error(
N,
"'contents' is not supported for 'directory-remap' entries");
1956// VFS root entries may be in either Posix or Windows style. Figure out 1957// which style we have, and use it consistently. 1964// Relative VFS root entries are made absolute to either the overlay 1965// directory, or the current working directory, then we can determine 1966// the path style from that. 1968if (
FS->RootRelative ==
1971assert(!FullPath.
empty() &&
"Overlay file directory must exist");
1972EC =
FS->makeAbsolute(FullPath,
Name);
1978assert(NameValueNode &&
"Name presence should be checked earlier");
1981"entry with relative path at the root level is not discoverable");
1988// is::path::is_absolute(Name, sys::path::Style::windows_backslash) will 1989// return true even if `Name` is using forward slashes. Distinguish 1990// between windows_backslash and windows_slash. 1996// Remove trailing slash(es), being careful not to remove the root path 1999while (Trimmed.
size() > RootPathLen &&
2001 Trimmed = Trimmed.
slice(0, Trimmed.
size() - 1);
2003// Get the last component 2006 std::unique_ptr<RedirectingFileSystem::Entry>
Result;
2009Result = std::make_unique<RedirectingFileSystem::FileEntry>(
2010 LastComponent, std::move(ExternalContentsPath), UseExternalName);
2013Result = std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
2014 LastComponent, std::move(ExternalContentsPath), UseExternalName);
2017Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
2018 LastComponent, std::move(EntryArrayContents),
2028// if 'name' contains multiple components, create implicit directory entries 2032 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> Entries;
2033 Entries.push_back(std::move(Result));
2034Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
2035 *
I, std::move(Entries),
2047auto *Top = dyn_cast<yaml::MappingNode>(Root);
2049error(Root,
"expected mapping node");
2053 KeyStatusPair Fields[] = {
2054 KeyStatusPair(
"version",
true),
2055 KeyStatusPair(
"case-sensitive",
false),
2056 KeyStatusPair(
"use-external-names",
false),
2057 KeyStatusPair(
"root-relative",
false),
2058 KeyStatusPair(
"overlay-relative",
false),
2059 KeyStatusPair(
"fallthrough",
false),
2060 KeyStatusPair(
"redirecting-with",
false),
2061 KeyStatusPair(
"roots",
true),
2065 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> RootEntries;
2067// Parse configuration and 'roots' 2068for (
auto &
I : *Top) {
2071if (!parseScalarString(
I.getKey(), Key, KeyBuffer))
2074if (!checkDuplicateOrUnknownKey(
I.getKey(), Key, Keys))
2078auto *Roots = dyn_cast<yaml::SequenceNode>(
I.getValue());
2080error(
I.getValue(),
"expected array");
2084for (
auto &
I : *Roots) {
2085if (std::unique_ptr<RedirectingFileSystem::Entry> E =
2086 parseEntry(&
I, FS,
/*IsRootEntry*/true))
2087 RootEntries.push_back(std::move(E));
2091 }
elseif (Key ==
"version") {
2094if (!parseScalarString(
I.getValue(), VersionString, Storage))
2098error(
I.getValue(),
"expected integer");
2102error(
I.getValue(),
"invalid version number");
2106error(
I.getValue(),
"version mismatch, expected 0");
2109 }
elseif (Key ==
"case-sensitive") {
2110if (!parseScalarBool(
I.getValue(), FS->CaseSensitive))
2112 }
elseif (Key ==
"overlay-relative") {
2113if (!parseScalarBool(
I.getValue(), FS->IsRelativeOverlay))
2115 }
elseif (Key ==
"use-external-names") {
2116if (!parseScalarBool(
I.getValue(), FS->UseExternalNames))
2118 }
elseif (Key ==
"fallthrough") {
2119if (Keys[
"redirecting-with"].Seen) {
2121"'fallthrough' and 'redirecting-with' are mutually exclusive");
2125bool ShouldFallthrough =
false;
2126if (!parseScalarBool(
I.getValue(), ShouldFallthrough))
2129if (ShouldFallthrough) {
2134 }
elseif (Key ==
"redirecting-with") {
2135if (Keys[
"fallthrough"].Seen) {
2137"'fallthrough' and 'redirecting-with' are mutually exclusive");
2141if (
auto Kind = parseRedirectKind(
I.getValue())) {
2142 FS->Redirection = *Kind;
2144error(
I.getValue(),
"expected valid redirect kind");
2147 }
elseif (Key ==
"root-relative") {
2148if (
auto Kind = parseRootRelativeKind(
I.getValue())) {
2149 FS->RootRelative = *Kind;
2151error(
I.getValue(),
"expected valid root-relative kind");
2162if (!checkMissingKeys(Top, Keys))
2165// Now that we sucessefully parsed the YAML file, canonicalize the internal 2166// representation to a proper directory tree so that we can search faster 2168for (
auto &E : RootEntries)
2169 uniqueOverlayTree(FS, E.get());
2175std::unique_ptr<RedirectingFileSystem>
2178StringRef YAMLFilePath,
void *DiagContext,
2186if (DI == Stream.
end() || !Root) {
2193 std::unique_ptr<RedirectingFileSystem> FS(
2196if (!YAMLFilePath.
empty()) {
2197// Use the YAML path from -ivfsoverlay to compute the dir to be prefixed 2198// to each 'external-contents' path. 2201// -ivfsoverlay dummy.cache/vfs/vfs.yaml 2203// FS->OverlayFileDir => /<absolute_path_to>/dummy.cache/vfs 2207assert(!EC &&
"Overlay dir final path must be absolute");
2209 FS->setOverlayFileDir(OverlayAbsDir);
2212if (!
P.parse(Root, FS.get()))
2219ArrayRef<std::pair<std::string, std::string>> RemappedFiles,
2220bool UseExternalNames,
FileSystem &ExternalFS) {
2221 std::unique_ptr<RedirectingFileSystem> FS(
2223 FS->UseExternalNames = UseExternalNames;
2233assert(!EC &&
"Could not make absolute path");
2236// Check if we've already mapped this file. The first one we see (in the 2237// reverse iteration) wins. 2242// Add parent directories. 2251assert(Parent &&
"File without a directory?");
2255assert(!EC &&
"Could not make absolute path");
2259auto NewFile = std::make_unique<RedirectingFileSystem::FileEntry>(
2263 ToEntry = NewFile.get();
2264 cast<RedirectingFileSystem::DirectoryEntry>(Parent)->addContent(
2265 std::move(NewFile));
2275// If the matched entry is a DirectoryRemapEntry, set ExternalRedirect to the 2276// path of the directory it maps to in the external file system plus any 2277// remaining path components in the provided iterator. 2278if (
auto *DRE = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(
E)) {
2281 getExistingStyle(DRE->getExternalContentsPath()));
2282 ExternalRedirect = std::string(Redirect);
2289for (
Entry *Parent : Parents)
2294std::error_code RedirectingFileSystem::makeCanonicalForLookup(
2296if (std::error_code EC = makeAbsolute(Path))
2300 canonicalize(
StringRef(Path.data(), Path.size()));
2301if (CanonicalPath.
empty())
2304 Path.assign(CanonicalPath.
begin(), CanonicalPath.
end());
2311if (std::error_code EC = makeCanonicalForLookup(CanonicalPath))
2314// RedirectOnly means the VFS is always used. 2321for (
constauto &Root : Roots) {
2323 lookupPathImpl(Start,
End, Root.get(), Entries);
2324if (UsageTrackingActive && Result && isa<RemapEntry>(Result->E))
2327 Result->Parents = std::move(Entries);
2335RedirectingFileSystem::lookupPathImpl(
2341"Paths should not contain traversal components");
2345// Forward the search to the next component in case this is an empty one. 2346if (!FromName.
empty()) {
2347if (!pathComponentMatches(*Start, FromName))
2354return LookupResult(
From, Start,
End);
2358if (isa<RedirectingFileSystem::FileEntry>(
From))
2361if (isa<RedirectingFileSystem::DirectoryRemapEntry>(
From))
2362return LookupResult(
From, Start,
End);
2364auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(
From);
2365for (
const std::unique_ptr<RedirectingFileSystem::Entry> &DirEntry :
2367 Entries.push_back(
From);
2369 lookupPathImpl(Start,
End, DirEntry.get(), Entries);
2379bool UseExternalNames,
2381// The path has been mapped by some nested VFS and exposes an external path, 2382// don't override it with the original path. 2384return ExternalStatus;
2386Status S = ExternalStatus;
2387if (!UseExternalNames)
2395constTwine &LookupPath,
constTwine &OriginalPath,
2397if (std::optional<StringRef> ExtRedirect =
Result.getExternalRedirect()) {
2399if (std::error_code EC = makeAbsolute(RemappedPath))
2406auto *RE = cast<RedirectingFileSystem::RemapEntry>(
Result.E);
2408 RE->useExternalName(UseExternalNames), *S);
2411auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(
Result.E);
2416RedirectingFileSystem::getExternalStatus(
constTwine &LookupPath,
2417constTwine &OriginalPath)
const{
2418autoResult = ExternalFS->status(LookupPath);
2420// The path has been mapped by some nested VFS, don't override it with the 2422if (!Result ||
Result->ExposesExternalVFSPath)
2431if (std::error_code EC = makeAbsolute(Path))
2435// Attempt to find the original file first, only falling back to the 2436// mapped file if that fails. 2444// Was not able to map file, fallthrough to using the original path if 2445// that was the specified redirection type. 2447 isFileNotFound(Result.getError()))
2448return getExternalStatus(Path, OriginalPath);
2449return Result.getError();
2454 isFileNotFound(S.
getError(), Result->E)) {
2455// Mapped the file but it wasn't found in the underlying filesystem, 2456// fallthrough to using the original path if that was the specified 2458return getExternalStatus(Path, OriginalPath);
2468if (makeAbsolute(Path))
2472// Attempt to find the original file first, only falling back to the 2473// mapped file if that fails. 2474if (ExternalFS->exists(Path))
2480// Was not able to map file, fallthrough to using the original path if 2481// that was the specified redirection type. 2483 isFileNotFound(Result.getError()))
2484return ExternalFS->exists(Path);
2488 std::optional<StringRef> ExtRedirect = Result->getExternalRedirect();
2490assert(isa<RedirectingFileSystem::DirectoryEntry>(Result->E));
2495if (makeAbsolute(RemappedPath))
2498if (ExternalFS->exists(RemappedPath))
2502// Mapped the file but it wasn't found in the underlying filesystem, 2503// fallthrough to using the original path if that was the specified 2505return ExternalFS->exists(Path);
2513/// Provide a file wrapper with an overriden status. 2514classFileWithFixedStatus :
publicFile {
2515 std::unique_ptr<File> InnerFile;
2519 FileWithFixedStatus(std::unique_ptr<File> InnerFile,
Status S)
2525 getBuffer(
constTwine &
Name, int64_t FileSize,
bool RequiresNullTerminator,
2526bool IsVolatile)
override{
2527return InnerFile->getBuffer(
Name, FileSize, RequiresNullTerminator,
2531 std::error_code close()
override{
return InnerFile->close(); }
2540// See \c getRedirectedFileStatus - don't update path if it's exposing an 2542if (!Result || (*Result)->status()->ExposesExternalVFSPath)
2546autoName =
F->get()->getName();
2548F->get()->setPath(
P);
2557if (std::error_code EC = makeAbsolute(Path))
2561// Attempt to find the original file first, only falling back to the 2562// mapped file if that fails. 2570// Was not able to map file, fallthrough to using the original path if 2571// that was the specified redirection type. 2573 isFileNotFound(Result.getError()))
2575return Result.getError();
2578if (!Result->getExternalRedirect())
// FIXME: errc::not_a_file? 2581StringRef ExtRedirect = *Result->getExternalRedirect();
2583if (std::error_code EC = makeAbsolute(RemappedPath))
2586auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
2592 isFileNotFound(ExternalFile.getError(), Result->E)) {
2593// Mapped the file but it wasn't found in the underlying filesystem, 2594// fallthrough to using the original path if that was the specified 2601auto ExternalStatus = (*ExternalFile)->status();
2603return ExternalStatus.getError();
2605// Otherwise, the file was successfully remapped. Mark it as such. Also 2606// replace the underlying path if the external name is being used. 2608 OriginalPath, RE->useExternalName(UseExternalNames), *ExternalStatus);
2609return std::unique_ptr<File>(
2610 std::make_unique<FileWithFixedStatus>(std::move(*ExternalFile), S));
2619if (std::error_code EC = makeAbsolute(Path))
2623// Attempt to find the original file first, only falling back to the 2624// mapped file if that fails. 2625 std::error_code EC = ExternalFS->getRealPath(Path, Output);
2632// Was not able to map file, fallthrough to using the original path if 2633// that was the specified redirection type. 2635 isFileNotFound(Result.getError()))
2636return ExternalFS->getRealPath(Path, Output);
2637return Result.getError();
2640// If we found FileEntry or DirectoryRemapEntry, look up the mapped 2641// path in the external file system. 2642if (
auto ExtRedirect = Result->getExternalRedirect()) {
2643autoP = ExternalFS->getRealPath(*ExtRedirect, Output);
2645 isFileNotFound(
P, Result->E)) {
2646// Mapped the file but it wasn't found in the underlying filesystem, 2647// fallthrough to using the original path if that was the specified 2649return ExternalFS->getRealPath(Path, Output);
2654// We found a DirectoryEntry, which does not have a single external contents 2655// path. Use the canonical virtual path. 2657 Result->getPath(Output);
2663std::unique_ptr<FileSystem>
2666StringRef YAMLFilePath,
void *DiagContext,
2669 YAMLFilePath, DiagContext,
2670 std::move(ExternalFS));
2678auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
2679assert(DE &&
"Must be a directory");
2680for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
2682 Path.push_back(SubEntry->getName());
2690auto *DR = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
2691assert(DR &&
"Must be a directory remap");
2693for (
auto &Comp : Path)
2701auto *FE = dyn_cast<RedirectingFileSystem::FileEntry>(SrcE);
2702assert(FE &&
"Must be a file");
2704for (
auto &Comp : Path)
2716 std::move(Buffer),
DiagHandler, YAMLFilePath, DiagContext,
2717 std::move(ExternalFS));
2721 VFS->lookupPath(
"/");
2730static std::atomic<unsigned> UID;
2732// The following assumes that uint64_t max will never collide with a real 2733// dev_t value from the OS. 2734returnUniqueID(std::numeric_limits<uint64_t>::max(),
ID);
2742 Mappings.emplace_back(VirtualPath, RealPath, IsDirectory);
2746 addEntry(VirtualPath, RealPath,
/*IsDirectory=*/false);
2751 addEntry(VirtualPath, RealPath,
/*IsDirectory=*/true);
2760unsigned getDirIndent() {
return 4 * DirStack.
size(); }
2761unsigned getFileIndent() {
return 4 * (DirStack.
size() + 1); }
2772 std::optional<bool> UseExternalNames,
2773 std::optional<bool> IsCaseSensitive,
2774 std::optional<bool> IsOverlayRelative,
StringRef OverlayDir);
2782// Compare each path component. 2785 IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
2786if (*IParent != *IChild)
2789// Have we exhausted the parent path? 2790return IParent == EParent;
2795assert(containedIn(Parent, Path));
2796returnPath.substr(Parent.
size() + 1);
2799void JSONWriter::startDirectory(
StringRef Path) {
2801 DirStack.
empty() ?
Path : containedPart(DirStack.
back(), Path);
2803unsigned Indent = getDirIndent();
2805OS.
indent(Indent + 2) <<
"'type': 'directory',\n";
2807OS.
indent(Indent + 2) <<
"'contents': [\n";
2810void JSONWriter::endDirectory() {
2811unsigned Indent = getDirIndent();
2819unsigned Indent = getFileIndent();
2821OS.
indent(Indent + 2) <<
"'type': 'file',\n";
2823OS.
indent(Indent + 2) <<
"'external-contents': \"" 2829 std::optional<bool> UseExternalNames,
2830 std::optional<bool> IsCaseSensitive,
2831 std::optional<bool> IsOverlayRelative,
2838OS <<
" 'case-sensitive': '" << (*IsCaseSensitive ?
"true" :
"false")
2840if (UseExternalNames)
2841OS <<
" 'use-external-names': '" << (*UseExternalNames ?
"true" :
"false")
2843bool UseOverlayRelative =
false;
2844if (IsOverlayRelative) {
2845 UseOverlayRelative = *IsOverlayRelative;
2846OS <<
" 'overlay-relative': '" << (UseOverlayRelative ?
"true" :
"false")
2849OS <<
" 'roots': [\n";
2851if (!Entries.empty()) {
2859if (UseOverlayRelative) {
2861"Overlay dir must be contained in RPath");
2865bool IsCurrentDirEmpty =
true;
2866if (!
Entry.IsDirectory) {
2868 IsCurrentDirEmpty =
false;
2871for (
constauto &Entry : Entries.slice(1)) {
2874if (Dir == DirStack.
back()) {
2875if (!IsCurrentDirEmpty) {
2879bool IsDirPoppedFromStack =
false;
2880while (!DirStack.
empty() && !containedIn(DirStack.
back(), Dir)) {
2883 IsDirPoppedFromStack =
true;
2885if (IsDirPoppedFromStack || !IsCurrentDirEmpty) {
2888 startDirectory(Dir);
2889 IsCurrentDirEmpty =
true;
2892if (UseOverlayRelative) {
2894"Overlay dir must be contained in RPath");
2897if (!
Entry.IsDirectory) {
2899 IsCurrentDirEmpty =
false;
2903while (!DirStack.
empty()) {
2916returnLHS.VPath <
RHS.VPath;
2919 JSONWriter(
OS).write(Mappings, UseExternalNames, IsCaseSensitive,
2928 State = std::make_shared<detail::RecDirIterState>();
2929 State->Stack.push_back(
I);
2935assert(FS && State && !State->Stack.empty() &&
"incrementing past end");
2936assert(!State->Stack.back()->path().empty() &&
"non-canonical end iterator");
2939if (State->HasNoPushRequest)
2940 State->HasNoPushRequest =
false;
2944 FS->dir_begin(State->Stack.back()->path(), EC);
2946 State->Stack.push_back(
I);
2952while (!State->Stack.empty() && State->Stack.back().increment(EC) ==
End)
2953 State->Stack.pop_back();
2955if (State->Stack.empty())
2956 State.reset();
// end iterator 2962unsigned IndentLevel)
const{
2963 printIndent(
OS, IndentLevel);
2964OS <<
"TracingFileSystem\n";
2965if (
Type == PrintType::Summary)
2968 printIndent(
OS, IndentLevel);
2970 printIndent(
OS, IndentLevel);
2972 printIndent(
OS, IndentLevel);
2974 printIndent(
OS, IndentLevel);
2976 printIndent(
OS, IndentLevel);
2978 printIndent(
OS, IndentLevel);
2981if (
Type == PrintType::Contents)
2982Type = PrintType::Summary;
2983 getUnderlyingFS().
print(
OS,
Type, IndentLevel + 1);
BlockVerifier::State From
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
This file defines the DenseMap class.
Provides ErrorOr<T> smart pointer.
static void makeAbsolute(SmallVectorImpl< char > &Path)
Make Path absolute.
This file defines the RefCountedBase, ThreadSafeRefCountedBase, and IntrusiveRefCntPtr classes.
static StringRef getName(Value *V)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file contains some templates that are useful if you are working with the STL at all.
This file defines the SmallString class.
This file defines the SmallVector class.
StringSet - A set-like wrapper for the StringMap.
static void DiagHandler(const SMDiagnostic &Diag, void *Context)
static void getVFSEntries(RedirectingFileSystem::Entry *SrcE, SmallVectorImpl< StringRef > &Path, SmallVectorImpl< YAMLVFSEntry > &Entries)
static Status getRedirectedFileStatus(const Twine &OriginalPath, bool UseExternalNames, Status ExternalStatus)
static bool pathHasTraversal(StringRef Path)
static bool isTraversalComponent(StringRef Component)
Defines the virtual file system interface vfs::FileSystem.
static unsigned getSize(unsigned Kind)
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
iterator find(const_arg_type_t< KeyT > Val)
Represents either an error or a value T.
std::error_code getError() const
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
A smart pointer to a reference-counted object that inherits from RefCountedBase or ThreadSafeRefCount...
This interface provides simple read-only access to a block of memory, and provides simple methods for...
static ErrorOr< std::unique_ptr< MemoryBuffer > > getOpenFile(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Given an already-open file descriptor, read the file and return a MemoryBuffer.
static std::unique_ptr< MemoryBuffer > getMemBuffer(StringRef InputData, StringRef BufferName="", bool RequiresNullTerminator=true)
Open the specified memory range as a MemoryBuffer.
virtual StringRef getBufferIdentifier() const
Return an identifier for this buffer, typically the filename it was read from.
StringRef getBuffer() const
Represents a location in source code.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
StringRef str() const
Explicit conversion to StringRef.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
This owns the files read by a parser, handles include stacks, and handles diagnostic wrangling.
void PrintMessage(raw_ostream &OS, SMLoc Loc, DiagKind Kind, const Twine &Msg, ArrayRef< SMRange > Ranges={}, ArrayRef< SMFixIt > FixIts={}, bool ShowColors=true) const
Emit a message about the specified location with the specified string.
void(*)(const SMDiagnostic &, void *Context) DiagHandlerTy
Clients that want to handle their own diagnostics in a custom way can register a function pointer+con...
void setDiagHandler(DiagHandlerTy DH, void *Ctx=nullptr)
Specify a diagnostic handler to be invoked every time PrintMessage is called.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
StringRef - Represent a constant reference to a string, i.e.
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
std::string str() const
str - Get the contents as an std::string.
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
constexpr bool empty() const
empty - Check if the string is empty.
char back() const
back - Get the last character in the string.
StringRef slice(size_t Start, size_t End) const
Return a reference to the substring from [Start, End).
constexpr size_t size() const
size - Get the string size.
StringSet - A wrapper for StringMap that provides set-like functionality.
std::pair< typename Base::iterator, bool > insert(StringRef key)
Target - Wrapper for Target specific information.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
std::string str() const
Return the twine contents as a std::string.
void toVector(SmallVectorImpl< char > &Out) const
Append the concatenated string into the given SmallString or SmallVector.
The instances of the Type class are immutable: once they are created, they are never changed.
void print(raw_ostream &O, bool IsForDebug=false, bool NoDetails=false) const
Print the current type.
LLVM Value Representation.
An efficient, type-erasing, non-owning reference to a callable.
An opaque object representing a hash code.
This class implements an extremely fast bulk output stream that can only output to a stream.
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
const std::string & path() const
directory_iterator - Iterates through the entries in path.
directory_iterator & increment(std::error_code &ec)
Represents the result of a call to sys::fs::status().
The virtual file system interface.
virtual llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const =0
Get the working directory of this file system.
virtual bool exists(const Twine &Path)
Check whether Path exists.
virtual llvm::ErrorOr< std::unique_ptr< File > > openFileForReadBinary(const Twine &Path)
Get a File object for the binary file at Path, if one exists.
virtual std::error_code makeAbsolute(SmallVectorImpl< char > &Path) const
Make Path an absolute path.
virtual llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path)=0
Get a File object for the text file at Path, if one exists.
virtual std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output)
Gets real path of Path e.g.
void printIndent(raw_ostream &OS, unsigned IndentLevel) const
LLVM_DUMP_METHOD void dump() const
void print(raw_ostream &OS, PrintType Type=PrintType::Contents, unsigned IndentLevel=0) const
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getBufferForFile(const Twine &Name, int64_t FileSize=-1, bool RequiresNullTerminator=true, bool IsVolatile=false, bool IsText=true)
This is a convenience method that opens a file, gets its content and then closes the file.
llvm::ErrorOr< bool > equivalent(const Twine &A, const Twine &B)
virtual std::error_code isLocal(const Twine &Path, bool &Result)
Is the file mounted on a local filesystem?
virtual llvm::ErrorOr< Status > status(const Twine &Path)=0
Get the status of the entry at Path, if one exists.
static ErrorOr< std::unique_ptr< File > > getWithPath(ErrorOr< std::unique_ptr< File > > Result, const Twine &P)
virtual ~File()
Destroy the file after closing it (if open).
Adaptor from InMemoryDir::iterator to directory_iterator.
DirIterator(const InMemoryFileSystem *FS, const detail::InMemoryDirectory &Dir, std::string RequestedDirName)
std::error_code increment() override
Sets CurrentEntry to the next entry in the directory on success, to directory_entry() at end,...
An in-memory file system.
std::error_code isLocal(const Twine &Path, bool &Result) override
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override
std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) override
Canonicalizes Path by combining with the current working directory and normalizing the path (e....
~InMemoryFileSystem() override
static constexpr size_t MaxSymlinkDepth
Arbitrary max depth to search through symlinks.
InMemoryFileSystem(bool UseNormalizedPaths=true)
bool useNormalizedPaths() const
Return true if this file system normalizes . and .. in paths.
void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override
llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override
bool addHardLink(const Twine &NewLink, const Twine &Target)
Add a hard link to a file.
std::string toString() const
bool addFileNoOwn(const Twine &Path, time_t ModificationTime, const llvm::MemoryBufferRef &Buffer, std::optional< uint32_t > User=std::nullopt, std::optional< uint32_t > Group=std::nullopt, std::optional< llvm::sys::fs::file_type > Type=std::nullopt, std::optional< llvm::sys::fs::perms > Perms=std::nullopt)
Add a buffer to the VFS with a path.
bool addSymbolicLink(const Twine &NewLink, const Twine &Target, time_t ModificationTime, std::optional< uint32_t > User=std::nullopt, std::optional< uint32_t > Group=std::nullopt, std::optional< llvm::sys::fs::perms > Perms=std::nullopt)
Add a symbolic link.
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
llvm::ErrorOr< Status > status(const Twine &Path) override
llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override
void visitChildFileSystems(VisitCallbackTy Callback) override
llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override
std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) override
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
void pushOverlay(IntrusiveRefCntPtr< FileSystem > FS)
Pushes a file system on top of the stack.
OverlayFileSystem(IntrusiveRefCntPtr< FileSystem > Base)
llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override
iterator overlays_end()
Get an iterator pointing one-past the least recently added file system.
std::error_code isLocal(const Twine &Path, bool &Result) override
bool exists(const Twine &Path) override
llvm::ErrorOr< Status > status(const Twine &Path) override
iterator overlays_begin()
Get an iterator pointing to the most recently added file system.
FileSystemList::reverse_iterator iterator
void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override
Directory iterator implementation for RedirectingFileSystem's directory entries.
std::error_code increment() override
Sets CurrentEntry to the next entry in the directory on success, to directory_entry() at end,...
RedirectingFSDirIterImpl(const Twine &Path, RedirectingFileSystem::DirectoryEntry::iterator Begin, RedirectingFileSystem::DirectoryEntry::iterator End, std::error_code &EC)
A helper class to hold the common YAML parsing state.
RedirectingFileSystemParser(yaml::Stream &S)
static RedirectingFileSystem::Entry * lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name, RedirectingFileSystem::Entry *ParentEntry=nullptr)
bool parse(yaml::Node *Root, RedirectingFileSystem *FS)
decltype(Contents)::iterator iterator
A single file or directory in the VFS.
StringRef getName() const
EntryKind getKind() const
A virtual file system parsed from a YAML file.
@ OverlayDir
The roots are relative to the directory where the Overlay YAML file.
@ CWD
The roots are relative to the current working directory.
bool exists(const Twine &Path) override
Check whether Path exists.
void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override
std::vector< llvm::StringRef > getRoots() const
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override
Get a directory_iterator for Dir.
ErrorOr< LookupResult > lookupPath(StringRef Path) const
Looks up Path in Roots and returns a LookupResult giving the matched entry and, if the entry was a Fi...
RedirectKind
The type of redirection to perform.
@ Fallthrough
Lookup the redirected path first (ie.
@ Fallback
Lookup the provided path first and if that fails, "fallback" to a lookup of the redirected path.
@ RedirectOnly
Only lookup the redirected path, do not lookup the originally provided path.
void setFallthrough(bool Fallthrough)
Sets the redirection kind to Fallthrough if true or RedirectOnly otherwise.
void visitChildFileSystems(VisitCallbackTy Callback) override
std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) override
Gets real path of Path e.g.
ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override
Get a File object for the text file at Path, if one exists.
void setOverlayFileDir(StringRef PrefixDir)
llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override
Get the working directory of this file system.
void setRedirection(RedirectingFileSystem::RedirectKind Kind)
std::error_code isLocal(const Twine &Path, bool &Result) override
Is the file mounted on a local filesystem?
static std::unique_ptr< RedirectingFileSystem > create(std::unique_ptr< MemoryBuffer > Buffer, SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, void *DiagContext, IntrusiveRefCntPtr< FileSystem > ExternalFS)
Parses Buffer, which is expected to be in YAML format and returns a virtual file system representing ...
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
Set the working directory.
StringRef getOverlayFileDir() const
void printEntry(raw_ostream &OS, Entry *E, unsigned IndentLevel=0) const
The result of a status operation.
llvm::sys::fs::UniqueID getUniqueID() const
bool equivalent(const Status &Other) const
static Status copyWithNewName(const Status &In, const Twine &NewName)
Get a copy of a Status with a different name.
bool isStatusKnown() const
bool ExposesExternalVFSPath
Whether this entity has an external path different from the virtual path, and the external path is ex...
static Status copyWithNewSize(const Status &In, uint64_t NewSize)
Get a copy of a Status with a different size.
llvm::sys::fs::file_type getType() const
bool isRegularFile() const
StringRef getName() const
Returns the name that should be used for this file or directory.
std::size_t NumOpenFileForReadCalls
std::size_t NumIsLocalCalls
std::size_t NumExistsCalls
void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override
std::size_t NumDirBeginCalls
std::size_t NumGetRealPathCalls
std::size_t NumStatusCalls
void addFileMapping(StringRef VirtualPath, StringRef RealPath)
void write(llvm::raw_ostream &OS)
void addDirectoryMapping(StringRef VirtualPath, StringRef RealPath)
InMemoryDirectory(Status Stat)
InMemoryNode * addChild(StringRef Name, std::unique_ptr< InMemoryNode > Child)
Status getStatus(const Twine &RequestedName) const override
Return the Status for this node.
const_iterator end() const
static bool classof(const InMemoryNode *N)
InMemoryNode * getChild(StringRef Name) const
const_iterator begin() const
UniqueID getUniqueID() const
decltype(Entries)::const_iterator const_iterator
std::string toString(unsigned Indent) const override
Status getStatus(const Twine &RequestedName) const override
Return the Status for this node.
std::string toString(unsigned Indent) const override
InMemoryFile(Status Stat, std::unique_ptr< llvm::MemoryBuffer > Buffer)
static bool classof(const InMemoryNode *N)
llvm::MemoryBuffer * getBuffer() const
The in memory file system is a tree of Nodes.
StringRef getFileName() const
Get the filename of this node (the name without the directory part).
InMemoryNodeKind getKind() const
virtual ~InMemoryNode()=default
InMemoryNode(llvm::StringRef FileName, InMemoryNodeKind Kind)
virtual std::string toString(unsigned Indent) const =0
virtual Status getStatus(const Twine &RequestedName) const =0
Return the Status for this node.
A member of a directory, yielded by a directory_iterator.
llvm::StringRef path() const
llvm::sys::fs::file_type type() const
An input iterator over the entries in a virtual path, similar to llvm::sys::fs::directory_iterator.
directory_iterator & increment(std::error_code &EC)
Equivalent to operator++, with an error code.
An input iterator over the recursive contents of a virtual path, similar to llvm::sys::fs::recursive_...
recursive_directory_iterator()=default
Construct an 'end' iterator.
recursive_directory_iterator & increment(std::error_code &EC)
Equivalent to operator++, with an error code.
Abstract base class for all Nodes.
This class represents a YAML stream potentially containing multiple documents.
document_iterator begin()
void printError(Node *N, const Twine &Msg, SourceMgr::DiagKind Kind=SourceMgr::DK_Error)
Iterator abstraction for Documents over a Stream.
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ Resolved
Queried, materialization begun.
void make_absolute(const Twine ¤t_directory, SmallVectorImpl< char > &path)
Make path an absolute path.
const file_t kInvalidFile
std::error_code real_path(const Twine &path, SmallVectorImpl< char > &output, bool expand_tilde=false)
Collapse all .
std::error_code closeFile(file_t &F)
Close the file object.
std::error_code openFileForRead(const Twine &Name, int &ResultFD, OpenFlags Flags=OF_None, SmallVectorImpl< char > *RealPath=nullptr)
Opens the file with the given name in a read-only mode, returning its open file descriptor.
std::error_code status(const Twine &path, file_status &result, bool follow=true)
Get file status as if by POSIX stat().
@ OF_Text
The file should be opened in text mode on platforms like z/OS that make this distinction.
file_type
An enumeration for the file system's view of the type.
std::error_code set_current_path(const Twine &path)
Set the current path.
std::error_code is_local(const Twine &path, bool &result)
Is the file mounted on a local filesystem?
Expected< file_t > openNativeFileForRead(const Twine &Name, OpenFlags Flags=OF_None, SmallVectorImpl< char > *RealPath=nullptr)
Opens the file with the given name in a read-only mode, returning its open file descriptor.
std::error_code current_path(SmallVectorImpl< char > &result)
Get the current path.
bool is_directory(const basic_file_status &status)
Does status represent a directory?
StringRef get_separator(Style style=Style::native)
Return the preferred separator for this platform.
StringRef root_path(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get root path.
const_iterator begin(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get begin iterator over path.
reverse_iterator rend(StringRef path LLVM_LIFETIME_BOUND)
Get reverse end iterator over path.
bool remove_dots(SmallVectorImpl< char > &path, bool remove_dot_dot=false, Style style=Style::native)
In-place remove any '.
StringRef parent_path(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get parent path.
StringRef remove_leading_dotslash(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Remove redundant leading "./" pieces and consecutive separators.
StringRef filename(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get filename.
bool is_absolute(const Twine &path, Style style=Style::native)
Is path absolute?
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
reverse_iterator rbegin(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get reverse begin iterator over path.
const_iterator end(StringRef path LLVM_LIFETIME_BOUND)
Get end iterator over path.
bool is_separator(char value, Style style=Style::native)
Check whether the given char is a path separator on the host OS.
std::chrono::time_point< std::chrono::system_clock, D > TimePoint
A time point on the system clock.
TimePoint< std::chrono::seconds > toTimePoint(std::time_t T)
Convert a std::time_t to a TimePoint.
void collectVFSFromYAML(std::unique_ptr< llvm::MemoryBuffer > Buffer, llvm::SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, SmallVectorImpl< YAMLVFSEntry > &CollectedEntries, void *DiagContext=nullptr, IntrusiveRefCntPtr< FileSystem > ExternalFS=getRealFileSystem())
Collect all pairs of <virtual path, real path> entries from the YAMLFilePath.
std::unique_ptr< FileSystem > getVFSFromYAML(std::unique_ptr< llvm::MemoryBuffer > Buffer, llvm::SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, void *DiagContext=nullptr, IntrusiveRefCntPtr< FileSystem > ExternalFS=getRealFileSystem())
Gets a FileSystem for a virtual file system described in YAML format.
std::unique_ptr< FileSystem > createPhysicalFileSystem()
Create an vfs::FileSystem for the 'real' file system, as seen by the operating system.
static sys::fs::UniqueID getFileID(sys::fs::UniqueID Parent, llvm::StringRef Name, llvm::StringRef Contents)
llvm::sys::fs::UniqueID getNextVirtualUniqueID()
Get a globally unique ID for a virtual file or directory.
static sys::fs::UniqueID getUniqueID(hash_code Hash)
IntrusiveRefCntPtr< FileSystem > getRealFileSystem()
Gets an vfs::FileSystem for the 'real' file system, as seen by the operating system.
static sys::fs::UniqueID getDirectoryID(sys::fs::UniqueID Parent, llvm::StringRef Name)
std::string escape(StringRef Input, bool EscapePrintable=true)
Escape Input for a double quoted scalar; if EscapePrintable is true, all UTF8 sequences will be escap...
This is an optimization pass for GlobalISel generic memory operations.
std::error_code make_error_code(BitcodeError E)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
@ no_such_file_or_directory
@ operation_not_permitted
auto reverse(ContainerTy &&C)
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
Error write(MCStreamer &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue)
void sort(IteratorTy Start, IteratorTy End)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
const char * toString(DWARFSectionKind Kind)
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
std::error_code errorToErrorCode(Error Err)
Helper for converting an ECError to a std::error_code.
Implement std::hash so that hash_code can be used in STL containers.
Represents the result of a path lookup into the RedirectingFileSystem.
Entry * E
The entry the looked-up path corresponds to.
LookupResult(Entry *E, sys::path::const_iterator Start, sys::path::const_iterator End)
void getPath(llvm::SmallVectorImpl< char > &Path) const
Get the (canonical) path of the found entry.
An interface for virtual file systems to provide an iterator over the (non-recursive) contents of a d...
directory_entry CurrentEntry
Status makeStatus() const
std::unique_ptr< llvm::MemoryBuffer > Buffer