24#include "llvm/Config/llvm-config.h"
50#include <system_error>
76 return Status(In.getName(), In.getUniqueID(), In.getLastModificationTime(),
77 In.getUser(), In.getGroup(), NewSize, In.getType(),
82 return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
83 In.getUser(), In.getGroup(), In.getSize(), In.getType(),
88 return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
89 In.getUser(), In.getGroup(), In.getSize(), In.type(),
120 bool RequiresNullTerminator,
bool IsVolatile) {
125 return (*F)->getBuffer(
Name, FileSize, RequiresNullTerminator, IsVolatile);
134 return WorkingDir.getError();
154#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
160 return Component.equals(
"..") || Component.equals(
".");
180class RealFile :
public File {
181 friend class RealFileSystem;
185 std::string RealName;
188 : FD(RawFD), S(NewName, {}, {}, {}, {}, {},
190 RealName(NewRealPathName.str()) {
191 assert(FD != kInvalidFile &&
"Invalid or inactive file descriptor");
195 ~RealFile()
override;
201 bool RequiresNullTerminator,
202 bool IsVolatile)
override;
203 std::error_code close()
override;
204 void setPath(
const Twine &Path)
override;
209RealFile::~RealFile() { close(); }
212 assert(FD != kInvalidFile &&
"cannot stat closed file");
213 if (!S.isStatusKnown()) {
223 return RealName.empty() ? S.getName().str() : RealName;
227RealFile::getBuffer(
const Twine &
Name, int64_t FileSize,
228 bool RequiresNullTerminator,
bool IsVolatile) {
229 assert(FD != kInvalidFile &&
"cannot get buffer for closed file");
234std::error_code RealFile::close() {
240void RealFile::setPath(
const Twine &Path) {
241 RealName =
Path.str();
258 explicit RealFileSystem(
bool LinkCWDToProcess) {
259 if (!LinkCWDToProcess) {
264 WD = WorkingDirectory{PWD, PWD};
266 WD = WorkingDirectory{PWD, RealPWD};
275 std::error_code setCurrentWorkingDirectory(
const Twine &Path)
override;
276 std::error_code isLocal(
const Twine &Path,
bool &Result)
override;
277 std::error_code getRealPath(
const Twine &Path,
282 unsigned IndentLevel)
const override;
290 Path.toVector(Storage);
295 struct WorkingDirectory {
301 std::optional<llvm::ErrorOr<WorkingDirectory>> WD;
309 if (std::error_code EC =
316RealFileSystem::openFileForRead(
const Twine &
Name) {
322 return std::unique_ptr<File>(
323 new RealFile(*FDOrErr,
Name.str(), RealName.
str()));
328 return std::string(WD->get().Specified);
330 return WD->getError();
335 return std::string(Dir);
338std::error_code RealFileSystem::setCurrentWorkingDirectory(
const Twine &Path) {
343 adjustPath(Path, Storage).toVector(Absolute);
348 return std::make_error_code(std::errc::not_a_directory);
352 return std::error_code();
355std::error_code RealFileSystem::isLocal(
const Twine &Path,
bool &Result) {
360std::error_code RealFileSystem::getRealPath(
const Twine &Path,
367 unsigned IndentLevel)
const {
368 printIndent(
OS, IndentLevel);
369 OS <<
"RealFileSystem using ";
383 return std::make_unique<RealFileSystem>(
false);
392 RealFSDirIter(
const Twine &Path, std::error_code &EC) : Iter(Path, EC) {
397 std::error_code increment()
override {
410 std::error_code &EC) {
413 std::make_shared<RealFSDirIter>(adjustPath(Dir, Storage), EC));
444 if ((*I)->exists(Path))
454 auto Result = (*I)->openFileForRead(Path);
464 return FSList.
front()->getCurrentWorkingDirectory();
469 for (
auto &FS : FSList)
470 if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))
476 for (
auto &FS : FSList)
477 if (FS->exists(Path))
478 return FS->isLocal(Path, Result);
484 for (
const auto &FS : FSList)
485 if (FS->exists(Path))
486 return FS->getRealPath(Path, Output);
493 FS->visitChildFileSystems(Callback);
498 unsigned IndentLevel)
const {
499 printIndent(
OS, IndentLevel);
500 OS <<
"OverlayFileSystem\n";
501 if (
Type == PrintType::Summary)
504 if (
Type == PrintType::Contents)
505 Type = PrintType::Summary;
507 FS->print(
OS,
Type, IndentLevel + 1);
527 std::error_code incrementIter(
bool IsFirstTime) {
528 while (!IterList.
empty()) {
529 CurrentDirIter = IterList.
back();
536 return errc::no_such_file_or_directory;
540 std::error_code incrementDirIter(
bool IsFirstTime) {
542 "incrementing past end");
547 EC = incrementIter(IsFirstTime);
551 std::error_code incrementImpl(
bool IsFirstTime) {
553 std::error_code
EC = incrementDirIter(IsFirstTime);
558 CurrentEntry = *CurrentDirIter;
568 std::error_code &EC) {
569 for (
const auto &FS : FileSystems) {
572 if (FEC && FEC != errc::no_such_file_or_directory) {
579 EC = incrementImpl(
true);
584 : IterList(DirIters.
begin(), DirIters.
end()) {
585 EC = incrementImpl(
true);
588 std::error_code increment()
override {
return incrementImpl(
false); }
594 std::error_code &EC) {
596 std::make_shared<CombiningDirIterImpl>(FSList, Dir.
str(), EC));
602void ProxyFileSystem::anchor() {}
620 std::string FileName;
624 : Kind(Kind), FileName(
std::
string(
llvm::sys::path::filename(FileName))) {
636 virtual std::string
toString(
unsigned Indent)
const = 0;
641 std::unique_ptr<llvm::MemoryBuffer> Buffer;
649 return Status::copyWithNewName(Stat, RequestedName);
653 std::string
toString(
unsigned Indent)
const override {
654 return (std::string(Indent,
' ') + Stat.
getName() +
"\n").str();
664class InMemoryHardLink :
public InMemoryNode {
665 const InMemoryFile &ResolvedFile;
668 InMemoryHardLink(
StringRef Path,
const InMemoryFile &ResolvedFile)
669 : InMemoryNode(Path, IME_HardLink), ResolvedFile(ResolvedFile) {}
670 const InMemoryFile &getResolvedFile()
const {
return ResolvedFile; }
672 Status getStatus(
const Twine &RequestedName)
const override {
673 return ResolvedFile.getStatus(RequestedName);
676 std::string
toString(
unsigned Indent)
const override {
677 return std::string(Indent,
' ') +
"HardLink to -> " +
678 ResolvedFile.toString(0);
681 static bool classof(
const InMemoryNode *
N) {
686class InMemorySymbolicLink :
public InMemoryNode {
687 std::string TargetPath;
695 std::string
toString(
unsigned Indent)
const override {
696 return std::string(Indent,
' ') +
"SymbolicLink to -> " + TargetPath;
699 Status getStatus(
const Twine &RequestedName)
const override {
700 return Status::copyWithNewName(Stat, RequestedName);
703 StringRef getTargetPath()
const {
return TargetPath; }
705 static bool classof(
const InMemoryNode *
N) {
713class InMemoryFileAdaptor :
public File {
714 const InMemoryFile &
Node;
716 std::string RequestedName;
719 explicit InMemoryFileAdaptor(
const InMemoryFile &
Node,
720 std::string RequestedName)
724 return Node.getStatus(RequestedName);
728 getBuffer(
const Twine &
Name, int64_t FileSize,
bool RequiresNullTerminator,
729 bool IsVolatile)
override {
735 std::error_code close()
override {
return {}; }
737 void setPath(
const Twine &Path)
override { RequestedName =
Path.str(); }
743 std::map<std::string, std::unique_ptr<InMemoryNode>> Entries;
753 return Status::copyWithNewName(Stat, RequestedName);
759 auto I = Entries.find(
Name.str());
760 if (
I != Entries.end())
761 return I->second.get();
766 return Entries.emplace(
Name, std::move(Child)).first->second.get();
774 std::string
toString(
unsigned Indent)
const override {
776 (std::string(Indent,
' ') + Stat.
getName() +
"\n").str();
777 for (
const auto &Entry : Entries)
778 Result += Entry.second->toString(Indent + 2);
808 (
Type == sys::fs::file_type::directory_file)
810 :
getFileID(DirUID,
Name, Buffer ? Buffer->getBuffer() :
"");
813 Group, Buffer ? Buffer->getBufferSize() : 0,
Type, Perms);
817 : Root(new
detail::InMemoryDirectory(
820 llvm::sys::fs::file_type::directory_file,
821 llvm::sys::fs::perms::all_all))),
822 UseNormalizedPaths(UseNormalizedPaths) {}
827 return Root->toString(0);
830bool InMemoryFileSystem::addFile(
const Twine &
P, time_t ModificationTime,
831 std::unique_ptr<llvm::MemoryBuffer> Buffer,
832 std::optional<uint32_t>
User,
833 std::optional<uint32_t> Group,
834 std::optional<llvm::sys::fs::file_type>
Type,
835 std::optional<llvm::sys::fs::perms> Perms,
836 MakeNodeFn MakeNode) {
853 const auto ResolvedUser =
User.value_or(0);
854 const auto ResolvedGroup = Group.value_or(0);
869 std::move(Buffer), ResolvedUser, ResolvedGroup,
870 ResolvedType, ResolvedPerms}));
876 StringRef(Path.str().begin(),
Name.end() - Path.str().begin()),
880 Dir = cast<detail::InMemoryDirectory>(Dir->
addChild(
881 Name, std::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
885 if (
auto *NewDir = dyn_cast<detail::InMemoryDirectory>(
Node)) {
889 isa<detail::InMemoryHardLink>(
Node)) &&
890 "Must be either file, hardlink or directory!");
897 if (
auto Link = dyn_cast<detail::InMemoryHardLink>(
Node)) {
898 return Link->getResolvedFile().getBuffer()->getBuffer() ==
901 return cast<detail::InMemoryFile>(
Node)->getBuffer()->getBuffer() ==
907bool InMemoryFileSystem::addFile(
const Twine &
P, time_t ModificationTime,
908 std::unique_ptr<llvm::MemoryBuffer> Buffer,
909 std::optional<uint32_t>
User,
910 std::optional<uint32_t> Group,
911 std::optional<llvm::sys::fs::file_type>
Type,
912 std::optional<llvm::sys::fs::perms> Perms) {
913 return addFile(
P, ModificationTime, std::move(Buffer),
User, Group,
Type,
916 -> std::unique_ptr<detail::InMemoryNode> {
919 return std::make_unique<detail::InMemoryDirectory>(Stat);
920 return std::make_unique<detail::InMemoryFile>(
921 Stat, std::move(NNI.
Buffer));
926 const Twine &
P, time_t ModificationTime,
928 std::optional<uint32_t> Group, std::optional<llvm::sys::fs::file_type>
Type,
929 std::optional<llvm::sys::fs::perms> Perms) {
931 std::move(
User), std::move(Group), std::move(
Type),
934 -> std::unique_ptr<detail::InMemoryNode> {
937 return std::make_unique<detail::InMemoryDirectory>(Stat);
938 return std::make_unique<detail::InMemoryFile>(
939 Stat, std::move(NNI.
Buffer));
944InMemoryFileSystem::lookupNode(
const Twine &
P,
bool FollowFinalSymlink,
945 size_t SymlinkDepth)
const {
968 if (
auto Symlink = dyn_cast<detail::InMemorySymbolicLink>(Node)) {
971 if (
I == E && !FollowFinalSymlink)
986 lookupNode(TargetPath,
true, SymlinkDepth + 1);
990 if (!isa<detail::InMemoryDirectory>(*
Target))
994 Dir = cast<detail::InMemoryDirectory>(*
Target);
999 if (
auto File = dyn_cast<detail::InMemoryFile>(Node)) {
1006 if (
auto File = dyn_cast<detail::InMemoryHardLink>(
Node)) {
1012 Dir = cast<detail::InMemoryDirectory>(
Node);
1020 auto NewLinkNode = lookupNode(NewLink,
false);
1024 auto TargetNode = lookupNode(
Target,
true);
1027 if (!TargetNode || NewLinkNode || !isa<detail::InMemoryFile>(*TargetNode))
1029 return addFile(NewLink, 0,
nullptr, std::nullopt, std::nullopt, std::nullopt,
1031 return std::make_unique<detail::InMemoryHardLink>(
1033 *cast<detail::InMemoryFile>(*TargetNode));
1039 std::optional<uint32_t>
User, std::optional<uint32_t> Group,
1040 std::optional<llvm::sys::fs::perms> Perms) {
1041 auto NewLinkNode = lookupNode(NewLink,
false);
1047 Target.toVector(TargetStr);
1049 return addFile(NewLinkStr, ModificationTime,
nullptr,
User, Group,
1052 return std::make_unique<detail::InMemorySymbolicLink>(
1058 auto Node = lookupNode(Path,
true);
1060 return (*Node)->getStatus(Path);
1061 return Node.getError();
1066 auto Node = lookupNode(Path,
true);
1068 return Node.getError();
1072 if (
auto *
F = dyn_cast<detail::InMemoryFile>(*Node))
1073 return std::unique_ptr<File>(
1074 new detail::InMemoryFileAdaptor(*
F, Path.str()));
1085 std::string RequestedDirName;
1087 void setCurrentEntry() {
1092 switch (
I->second->getKind()) {
1101 if (
auto SymlinkTarget =
1102 FS->lookupNode(Path,
true)) {
1103 Path = SymlinkTarget.getName();
1104 Type = (*SymlinkTarget)->getStatus(Path).getType();
1121 std::string RequestedDirName)
1122 : FS(FS),
I(Dir.begin()), E(Dir.end()),
1123 RequestedDirName(
std::
move(RequestedDirName)) {
1135 std::error_code &EC) {
1136 auto Node = lookupNode(Dir,
true);
1138 EC = Node.getError();
1142 if (
auto *DirNode = dyn_cast<detail::InMemoryDirectory>(*Node))
1144 std::make_shared<DirIterator>(
this, *DirNode, Dir.
str()));
1163 WorkingDirectory = std::string(Path);
1170 if (!CWD || CWD->empty())
1172 Path.toVector(Output);
1185 unsigned IndentLevel)
const {
1186 printIndent(
OS, IndentLevel);
1187 OS <<
"InMemoryFileSystem\n";
1202 const size_t n = Path.find_first_of(
"/\\");
1204 if (n !=
static_cast<size_t>(-1))
1224static bool isFileNotFound(std::error_code EC,
1226 if (E && !isa<RedirectingFileSystem::DirectoryRemapEntry>(E))
1237 if (
auto ExternalWorkingDirectory =
1238 ExternalFS->getCurrentWorkingDirectory()) {
1239 WorkingDirectory = *ExternalWorkingDirectory;
1250 std::error_code incrementImpl(
bool IsFirstTime) {
1251 assert((IsFirstTime || Current !=
End) &&
"cannot iterate past end");
1254 if (Current !=
End) {
1258 switch ((*Current)->getKind()) {
1279 : Dir(Path.str()), Current(Begin),
End(
End) {
1280 EC = incrementImpl(
true);
1284 return incrementImpl(
false);
1298 RedirectingFSDirRemapIterImpl(std::string DirPath,
1300 : Dir(
std::
move(DirPath)), DirStyle(getExistingStyle(Dir)),
1301 ExternalIter(ExtIter) {
1306 void setCurrentEntry() {
1317 std::error_code increment()
override {
1331 return WorkingDirectory;
1341 Path.toVector(AbsolutePath);
1342 if (std::error_code EC = makeAbsolute(AbsolutePath))
1344 WorkingDirectory = std::string(AbsolutePath);
1353 if (makeAbsolute(Path))
1356 return ExternalFS->isLocal(Path, Result);
1371 return WorkingDir.getError();
1373 return makeAbsolute(WorkingDir.get(), Path);
1377RedirectingFileSystem::makeAbsolute(
StringRef WorkingDir,
1383 if (!WorkingDir.
empty() &&
1387 return std::error_code();
1399 std::string
Result = std::string(WorkingDir);
1416 std::error_code &EC) {
1420 EC = makeAbsolute(Path);
1427 isFileNotFound(Result.getError()))
1428 return ExternalFS->dir_begin(Path, EC);
1430 EC = Result.getError();
1438 isFileNotFound(S.
getError(), Result->E))
1439 return ExternalFS->dir_begin(Dir, EC);
1445 if (!S->isDirectory()) {
1453 std::error_code RedirectEC;
1454 if (
auto ExtRedirect = Result->getExternalRedirect()) {
1455 auto RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
1456 RedirectIter = ExternalFS->dir_begin(*ExtRedirect, RedirectEC);
1458 if (!RE->useExternalName(UseExternalNames)) {
1462 std::string(Path), RedirectIter));
1465 auto DE = cast<DirectoryEntry>(Result->E);
1468 Path, DE->contents_begin(), DE->contents_end(), RedirectEC));
1481 return RedirectIter;
1484 std::error_code ExternalEC;
1495 switch (Redirection) {
1509 std::make_shared<CombiningDirIterImpl>(Iters, EC)};
1516 OverlayFileDir = Dir.
str();
1520 return OverlayFileDir;
1537 std::vector<StringRef> R;
1538 R.reserve(Roots.size());
1539 for (
const auto &Root : Roots)
1540 R.push_back(Root->getName());
1545 unsigned IndentLevel)
const {
1547 OS <<
"RedirectingFileSystem (UseExternalNames: "
1548 << (UseExternalNames ?
"true" :
"false") <<
")\n";
1552 for (
const auto &Root : Roots)
1556 OS <<
"ExternalFS:\n";
1563 unsigned IndentLevel)
const {
1569 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(E);
1572 for (std::unique_ptr<Entry> &SubEntry :
1579 auto *RE = cast<RedirectingFileSystem::RemapEntry>(E);
1580 OS <<
" -> '" << RE->getExternalContentsPath() <<
"'";
1581 switch (RE->getUseName()) {
1585 OS <<
" (UseExternalName: true)";
1588 OS <<
" (UseExternalName: false)";
1599 Callback(*ExternalFS);
1600 ExternalFS->visitChildFileSystems(Callback);
1613 const auto *S = dyn_cast<yaml::ScalarNode>(
N);
1616 error(
N,
"expected string");
1619 Result = S->getValue(Storage);
1624 bool parseScalarBool(
yaml::Node *
N,
bool &Result) {
1627 if (!parseScalarString(
N,
Value, Storage))
1630 if (
Value.equals_insensitive(
"true") ||
Value.equals_insensitive(
"on") ||
1631 Value.equals_insensitive(
"yes") ||
Value ==
"1") {
1634 }
else if (
Value.equals_insensitive(
"false") ||
1635 Value.equals_insensitive(
"off") ||
1636 Value.equals_insensitive(
"no") ||
Value ==
"0") {
1641 error(
N,
"expected boolean value");
1645 std::optional<RedirectingFileSystem::RedirectKind>
1649 if (!parseScalarString(
N,
Value, Storage))
1650 return std::nullopt;
1652 if (
Value.equals_insensitive(
"fallthrough")) {
1654 }
else if (
Value.equals_insensitive(
"fallback")) {
1656 }
else if (
Value.equals_insensitive(
"redirect-only")) {
1659 return std::nullopt;
1662 std::optional<RedirectingFileSystem::RootRelativeKind>
1666 if (!parseScalarString(
N,
Value, Storage))
1667 return std::nullopt;
1668 if (
Value.equals_insensitive(
"cwd")) {
1670 }
else if (
Value.equals_insensitive(
"overlay-dir")) {
1673 return std::nullopt;
1680 KeyStatus(
bool Required =
false) : Required(Required) {}
1683 using KeyStatusPair = std::pair<StringRef, KeyStatus>;
1688 if (!Keys.
count(Key)) {
1689 error(KeyNode,
"unknown key");
1692 KeyStatus &S = Keys[Key];
1694 error(KeyNode,
Twine(
"duplicate key '") + Key +
"'");
1703 for (
const auto &
I : Keys) {
1704 if (
I.second.Required && !
I.second.Seen) {
1705 error(Obj,
Twine(
"missing key '") +
I.first +
"'");
1717 for (
const auto &Root : FS->Roots) {
1718 if (
Name.equals(Root->getName())) {
1719 ParentEntry = Root.get();
1724 auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
1725 for (std::unique_ptr<RedirectingFileSystem::Entry> &
Content :
1728 dyn_cast<RedirectingFileSystem::DirectoryEntry>(
Content.get());
1729 if (DirContent &&
Name.equals(
Content->getName()))
1735 std::unique_ptr<RedirectingFileSystem::Entry> E =
1736 std::make_unique<RedirectingFileSystem::DirectoryEntry>(
1738 std::chrono::system_clock::now(), 0, 0, 0,
1742 FS->Roots.push_back(std::move(E));
1743 ParentEntry = FS->Roots.back().get();
1747 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
1748 DE->addContent(std::move(E));
1749 return DE->getLastContent();
1759 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
1765 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
1767 uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
1771 assert(NewParentE &&
"Parent entry must exist");
1772 auto *DR = cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
1773 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
1775 std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
1776 Name, DR->getExternalContentsPath(), DR->getUseName()));
1780 assert(NewParentE &&
"Parent entry must exist");
1781 auto *FE = cast<RedirectingFileSystem::FileEntry>(SrcE);
1782 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
1783 DE->addContent(std::make_unique<RedirectingFileSystem::FileEntry>(
1784 Name, FE->getExternalContentsPath(), FE->getUseName()));
1790 std::unique_ptr<RedirectingFileSystem::Entry>
1792 auto *
M = dyn_cast<yaml::MappingNode>(
N);
1794 error(
N,
"expected mapping node for file or directory entry");
1798 KeyStatusPair Fields[] = {
1799 KeyStatusPair(
"name",
true),
1800 KeyStatusPair(
"type",
true),
1801 KeyStatusPair(
"contents",
false),
1802 KeyStatusPair(
"external-contents",
false),
1803 KeyStatusPair(
"use-external-name",
false),
1808 enum { CF_NotSet, CF_List, CF_External } ContentsField = CF_NotSet;
1809 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>>
1817 for (
auto &
I : *M) {
1822 if (!parseScalarString(
I.getKey(), Key, Buffer))
1825 if (!checkDuplicateOrUnknownKey(
I.getKey(), Key, Keys))
1829 if (Key ==
"name") {
1830 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1833 NameValueNode =
I.getValue();
1837 }
else if (Key ==
"type") {
1838 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1840 if (
Value ==
"file")
1842 else if (
Value ==
"directory")
1844 else if (
Value ==
"directory-remap")
1847 error(
I.getValue(),
"unknown value for 'type'");
1850 }
else if (Key ==
"contents") {
1851 if (ContentsField != CF_NotSet) {
1853 "entry already has 'contents' or 'external-contents'");
1856 ContentsField = CF_List;
1857 auto *Contents = dyn_cast<yaml::SequenceNode>(
I.getValue());
1860 error(
I.getValue(),
"expected array");
1864 for (
auto &
I : *Contents) {
1865 if (std::unique_ptr<RedirectingFileSystem::Entry> E =
1866 parseEntry(&
I, FS,
false))
1867 EntryArrayContents.push_back(std::move(E));
1871 }
else if (Key ==
"external-contents") {
1872 if (ContentsField != CF_NotSet) {
1874 "entry already has 'contents' or 'external-contents'");
1877 ContentsField = CF_External;
1878 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1882 if (
FS->IsRelativeOverlay) {
1883 FullPath =
FS->getOverlayFileDir();
1885 "External contents prefix directory must exist");
1893 FullPath = canonicalize(FullPath);
1894 ExternalContentsPath = FullPath.
str();
1895 }
else if (Key ==
"use-external-name") {
1897 if (!parseScalarBool(
I.getValue(), Val))
1910 if (ContentsField == CF_NotSet) {
1911 error(
N,
"missing key 'contents' or 'external-contents'");
1914 if (!checkMissingKeys(
N, Keys))
1920 error(
N,
"'use-external-name' is not supported for 'directory' entries");
1925 ContentsField == CF_List) {
1926 error(
N,
"'contents' is not supported for 'directory-remap' entries");
1944 if (
FS->RootRelative ==
1947 assert(!FullPath.
empty() &&
"Overlay file directory must exist");
1948 EC =
FS->makeAbsolute(FullPath,
Name);
1954 assert(NameValueNode &&
"Name presence should be checked earlier");
1957 "entry with relative path at the root level is not discoverable");
1975 while (Trimmed.
size() > RootPathLen &&
1977 Trimmed = Trimmed.
slice(0, Trimmed.
size() - 1);
1982 std::unique_ptr<RedirectingFileSystem::Entry>
Result;
1985 Result = std::make_unique<RedirectingFileSystem::FileEntry>(
1986 LastComponent, std::move(ExternalContentsPath), UseExternalName);
1989 Result = std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
1990 LastComponent, std::move(ExternalContentsPath), UseExternalName);
1993 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
1994 LastComponent, std::move(EntryArrayContents),
2008 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> Entries;
2009 Entries.push_back(std::move(Result));
2010 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
2011 *
I, std::move(Entries),
2023 auto *Top = dyn_cast<yaml::MappingNode>(Root);
2025 error(Root,
"expected mapping node");
2029 KeyStatusPair Fields[] = {
2030 KeyStatusPair(
"version",
true),
2031 KeyStatusPair(
"case-sensitive",
false),
2032 KeyStatusPair(
"use-external-names",
false),
2033 KeyStatusPair(
"root-relative",
false),
2034 KeyStatusPair(
"overlay-relative",
false),
2035 KeyStatusPair(
"fallthrough",
false),
2036 KeyStatusPair(
"redirecting-with",
false),
2037 KeyStatusPair(
"roots",
true),
2041 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> RootEntries;
2044 for (
auto &
I : *Top) {
2047 if (!parseScalarString(
I.getKey(), Key, KeyBuffer))
2050 if (!checkDuplicateOrUnknownKey(
I.getKey(), Key, Keys))
2053 if (Key ==
"roots") {
2054 auto *Roots = dyn_cast<yaml::SequenceNode>(
I.getValue());
2056 error(
I.getValue(),
"expected array");
2060 for (
auto &
I : *Roots) {
2061 if (std::unique_ptr<RedirectingFileSystem::Entry> E =
2062 parseEntry(&
I, FS,
true))
2063 RootEntries.push_back(std::move(E));
2067 }
else if (Key ==
"version") {
2070 if (!parseScalarString(
I.getValue(), VersionString, Storage))
2074 error(
I.getValue(),
"expected integer");
2078 error(
I.getValue(),
"invalid version number");
2082 error(
I.getValue(),
"version mismatch, expected 0");
2085 }
else if (Key ==
"case-sensitive") {
2086 if (!parseScalarBool(
I.getValue(), FS->CaseSensitive))
2088 }
else if (Key ==
"overlay-relative") {
2089 if (!parseScalarBool(
I.getValue(), FS->IsRelativeOverlay))
2091 }
else if (Key ==
"use-external-names") {
2092 if (!parseScalarBool(
I.getValue(), FS->UseExternalNames))
2094 }
else if (Key ==
"fallthrough") {
2095 if (Keys[
"redirecting-with"].Seen) {
2097 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2101 bool ShouldFallthrough =
false;
2102 if (!parseScalarBool(
I.getValue(), ShouldFallthrough))
2105 if (ShouldFallthrough) {
2110 }
else if (Key ==
"redirecting-with") {
2111 if (Keys[
"fallthrough"].Seen) {
2113 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2117 if (
auto Kind = parseRedirectKind(
I.getValue())) {
2118 FS->Redirection = *Kind;
2120 error(
I.getValue(),
"expected valid redirect kind");
2123 }
else if (Key ==
"root-relative") {
2124 if (
auto Kind = parseRootRelativeKind(
I.getValue())) {
2125 FS->RootRelative = *Kind;
2127 error(
I.getValue(),
"expected valid root-relative kind");
2138 if (!checkMissingKeys(Top, Keys))
2144 for (
auto &E : RootEntries)
2145 uniqueOverlayTree(FS, E.get());
2151std::unique_ptr<RedirectingFileSystem>
2154 StringRef YAMLFilePath,
void *DiagContext,
2162 if (DI == Stream.
end() || !Root) {
2169 std::unique_ptr<RedirectingFileSystem> FS(
2172 if (!YAMLFilePath.
empty()) {
2183 assert(!EC &&
"Overlay dir final path must be absolute");
2185 FS->setOverlayFileDir(OverlayAbsDir);
2188 if (!
P.parse(Root, FS.get()))
2195 ArrayRef<std::pair<std::string, std::string>> RemappedFiles,
2196 bool UseExternalNames,
FileSystem &ExternalFS) {
2197 std::unique_ptr<RedirectingFileSystem> FS(
2199 FS->UseExternalNames = UseExternalNames;
2209 assert(!EC &&
"Could not make absolute path");
2227 assert(Parent &&
"File without a directory?");
2231 assert(!EC &&
"Could not make absolute path");
2235 auto NewFile = std::make_unique<RedirectingFileSystem::FileEntry>(
2239 ToEntry = NewFile.get();
2240 cast<RedirectingFileSystem::DirectoryEntry>(Parent)->addContent(
2241 std::move(NewFile));
2254 if (
auto *DRE = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(
E)) {
2257 getExistingStyle(DRE->getExternalContentsPath()));
2258 ExternalRedirect = std::string(Redirect);
2265 for (
Entry *Parent : Parents)
2270std::error_code RedirectingFileSystem::makeCanonicalForLookup(
2272 if (std::error_code EC = makeAbsolute(Path))
2276 canonicalize(
StringRef(Path.data(), Path.size()));
2277 if (CanonicalPath.
empty())
2280 Path.assign(CanonicalPath.
begin(), CanonicalPath.
end());
2287 if (std::error_code EC = makeCanonicalForLookup(CanonicalPath))
2297 for (
const auto &Root : Roots) {
2299 lookupPathImpl(Start,
End, Root.get(), Entries);
2300 if (UsageTrackingActive && Result && isa<RemapEntry>(Result->E))
2303 Result->Parents = std::move(Entries);
2311RedirectingFileSystem::lookupPathImpl(
2317 "Paths should not contain traversal components");
2322 if (!FromName.
empty()) {
2323 if (!pathComponentMatches(*Start, FromName))
2330 return LookupResult(
From, Start,
End);
2334 if (isa<RedirectingFileSystem::FileEntry>(
From))
2337 if (isa<RedirectingFileSystem::DirectoryRemapEntry>(
From))
2338 return LookupResult(
From, Start,
End);
2340 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(
From);
2341 for (
const std::unique_ptr<RedirectingFileSystem::Entry> &DirEntry :
2343 Entries.push_back(
From);
2345 lookupPathImpl(Start,
End, DirEntry.get(), Entries);
2355 bool UseExternalNames,
2360 return ExternalStatus;
2362 Status S = ExternalStatus;
2363 if (!UseExternalNames)
2371 const Twine &LookupPath,
const Twine &OriginalPath,
2373 if (std::optional<StringRef> ExtRedirect =
Result.getExternalRedirect()) {
2375 if (std::error_code EC = makeAbsolute(RemappedPath))
2382 auto *RE = cast<RedirectingFileSystem::RemapEntry>(
Result.E);
2384 RE->useExternalName(UseExternalNames), *S);
2387 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(
Result.E);
2392RedirectingFileSystem::getExternalStatus(
const Twine &LookupPath,
2393 const Twine &OriginalPath)
const {
2394 auto Result = ExternalFS->status(LookupPath);
2398 if (!Result ||
Result->ExposesExternalVFSPath)
2407 if (std::error_code EC = makeAbsolute(Path))
2423 isFileNotFound(Result.getError()))
2424 return getExternalStatus(Path, OriginalPath);
2425 return Result.getError();
2430 isFileNotFound(S.
getError(), Result->E)) {
2434 return getExternalStatus(Path, OriginalPath);
2444 if (makeAbsolute(Path))
2450 if (ExternalFS->exists(Path))
2459 isFileNotFound(Result.getError()))
2460 return ExternalFS->exists(Path);
2464 std::optional<StringRef> ExtRedirect = Result->getExternalRedirect();
2466 assert(isa<RedirectingFileSystem::DirectoryEntry>(Result->E));
2471 if (makeAbsolute(RemappedPath))
2474 if (ExternalFS->exists(RemappedPath))
2481 return ExternalFS->exists(Path);
2490class FileWithFixedStatus :
public File {
2491 std::unique_ptr<File> InnerFile;
2495 FileWithFixedStatus(std::unique_ptr<File> InnerFile,
Status S)
2501 getBuffer(
const Twine &
Name, int64_t FileSize,
bool RequiresNullTerminator,
2502 bool IsVolatile)
override {
2503 return InnerFile->getBuffer(
Name, FileSize, RequiresNullTerminator,
2507 std::error_code close()
override {
return InnerFile->close(); }
2518 if (!Result || (*Result)->status()->ExposesExternalVFSPath)
2522 auto Name =
F->get()->getName();
2524 F->get()->setPath(
P);
2533 if (std::error_code EC = makeAbsolute(Path))
2549 isFileNotFound(Result.getError()))
2551 return Result.getError();
2554 if (!Result->getExternalRedirect())
2557 StringRef ExtRedirect = *Result->getExternalRedirect();
2559 if (std::error_code EC = makeAbsolute(RemappedPath))
2562 auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
2566 if (!ExternalFile) {
2568 isFileNotFound(ExternalFile.getError(), Result->E)) {
2574 return ExternalFile;
2577 auto ExternalStatus = (*ExternalFile)->status();
2578 if (!ExternalStatus)
2579 return ExternalStatus.getError();
2584 OriginalPath, RE->useExternalName(UseExternalNames), *ExternalStatus);
2585 return std::unique_ptr<File>(
2586 std::make_unique<FileWithFixedStatus>(std::move(*ExternalFile), S));
2595 if (std::error_code EC = makeAbsolute(Path))
2601 std::error_code EC = ExternalFS->getRealPath(Path, Output);
2611 isFileNotFound(Result.getError()))
2612 return ExternalFS->getRealPath(Path, Output);
2613 return Result.getError();
2618 if (
auto ExtRedirect = Result->getExternalRedirect()) {
2619 auto P = ExternalFS->getRealPath(*ExtRedirect, Output);
2621 isFileNotFound(
P, Result->E)) {
2625 return ExternalFS->getRealPath(Path, Output);
2633 Result->getPath(Output);
2639std::unique_ptr<FileSystem>
2642 StringRef YAMLFilePath,
void *DiagContext,
2645 YAMLFilePath, DiagContext,
2646 std::move(ExternalFS));
2654 auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
2655 assert(DE &&
"Must be a directory");
2656 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
2658 Path.push_back(SubEntry->getName());
2666 auto *DR = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
2667 assert(DR &&
"Must be a directory remap");
2669 for (
auto &Comp : Path)
2677 auto *FE = dyn_cast<RedirectingFileSystem::FileEntry>(SrcE);
2678 assert(FE &&
"Must be a file");
2680 for (
auto &Comp : Path)
2692 std::move(Buffer),
DiagHandler, YAMLFilePath, DiagContext,
2693 std::move(ExternalFS));
2697 VFS->lookupPath(
"/");
2706 static std::atomic<unsigned> UID;
2707 unsigned ID = ++UID;
2710 return UniqueID(std::numeric_limits<uint64_t>::max(),
ID);
2718 Mappings.emplace_back(VirtualPath, RealPath, IsDirectory);
2722 addEntry(VirtualPath, RealPath,
false);
2727 addEntry(VirtualPath, RealPath,
true);
2736 unsigned getDirIndent() {
return 4 * DirStack.
size(); }
2737 unsigned getFileIndent() {
return 4 * (DirStack.
size() + 1); }
2741 void endDirectory();
2748 std::optional<bool> UseExternalNames,
2749 std::optional<bool> IsCaseSensitive,
2750 std::optional<bool> IsOverlayRelative,
StringRef OverlayDir);
2761 IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
2762 if (*IParent != *IChild)
2766 return IParent == EParent;
2771 assert(containedIn(Parent, Path));
2775void JSONWriter::startDirectory(
StringRef Path) {
2777 DirStack.
empty() ?
Path : containedPart(DirStack.
back(), Path);
2779 unsigned Indent = getDirIndent();
2781 OS.
indent(Indent + 2) <<
"'type': 'directory',\n";
2783 OS.
indent(Indent + 2) <<
"'contents': [\n";
2786void JSONWriter::endDirectory() {
2787 unsigned Indent = getDirIndent();
2795 unsigned Indent = getFileIndent();
2797 OS.
indent(Indent + 2) <<
"'type': 'file',\n";
2799 OS.
indent(Indent + 2) <<
"'external-contents': \""
2805 std::optional<bool> UseExternalNames,
2806 std::optional<bool> IsCaseSensitive,
2807 std::optional<bool> IsOverlayRelative,
2813 if (IsCaseSensitive)
2814 OS <<
" 'case-sensitive': '" << (*IsCaseSensitive ?
"true" :
"false")
2816 if (UseExternalNames)
2817 OS <<
" 'use-external-names': '" << (*UseExternalNames ?
"true" :
"false")
2819 bool UseOverlayRelative =
false;
2820 if (IsOverlayRelative) {
2821 UseOverlayRelative = *IsOverlayRelative;
2822 OS <<
" 'overlay-relative': '" << (UseOverlayRelative ?
"true" :
"false")
2825 OS <<
" 'roots': [\n";
2827 if (!Entries.empty()) {
2835 if (UseOverlayRelative) {
2837 "Overlay dir must be contained in RPath");
2841 bool IsCurrentDirEmpty =
true;
2842 if (!Entry.IsDirectory) {
2844 IsCurrentDirEmpty =
false;
2847 for (
const auto &Entry : Entries.slice(1)) {
2850 if (Dir == DirStack.
back()) {
2851 if (!IsCurrentDirEmpty) {
2855 bool IsDirPoppedFromStack =
false;
2856 while (!DirStack.
empty() && !containedIn(DirStack.
back(), Dir)) {
2859 IsDirPoppedFromStack =
true;
2861 if (IsDirPoppedFromStack || !IsCurrentDirEmpty) {
2864 startDirectory(Dir);
2865 IsCurrentDirEmpty =
true;
2868 if (UseOverlayRelative) {
2870 "Overlay dir must be contained in RPath");
2873 if (!Entry.IsDirectory) {
2875 IsCurrentDirEmpty =
false;
2879 while (!DirStack.
empty()) {
2892 return LHS.VPath <
RHS.VPath;
2895 JSONWriter(
OS).write(Mappings, UseExternalNames, IsCaseSensitive,
2904 State = std::make_shared<detail::RecDirIterState>();
2905 State->Stack.push(
I);
2911 assert(FS && State && !State->Stack.empty() &&
"incrementing past end");
2912 assert(!State->Stack.top()->path().empty() &&
"non-canonical end iterator");
2915 if (State->HasNoPushRequest)
2916 State->HasNoPushRequest =
false;
2921 State->Stack.push(
I);
2927 while (!State->Stack.empty() && State->Stack.top().increment(EC) ==
End)
2930 if (State->Stack.empty())
BlockVerifier::State From
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 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),...
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
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.
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.
static constexpr size_t npos
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.
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.
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getBufferForFile(const Twine &Name, int64_t FileSize=-1, bool RequiresNullTerminator=true, bool IsVolatile=false)
This is a convenience method that opens a file, gets its content and then closes the file.
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 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
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 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.
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.
std::optional< const char * > toString(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract a string value from it.
@ 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().
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.
const_iterator begin(StringRef path, Style style=Style::native)
Get begin iterator over path.
reverse_iterator rend(StringRef path)
Get reverse end iterator over path.
const_iterator end(StringRef path)
Get end iterator over path.
bool remove_dots(SmallVectorImpl< char > &path, bool remove_dot_dot=false, Style style=Style::native)
In-place remove any '.
StringRef filename(StringRef path, Style style=Style::native)
Get filename.
reverse_iterator rbegin(StringRef path, Style style=Style::native)
Get reverse begin iterator over path.
StringRef parent_path(StringRef path, Style style=Style::native)
Get parent path.
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.
StringRef root_path(StringRef path, Style style=Style::native)
Get root path.
bool is_separator(char value, Style style=Style::native)
Check whether the given char is a path separator on the host OS.
StringRef remove_leading_dotslash(StringRef path, Style style=Style::native)
Remove redundant leading "./" pieces and consecutive separators.
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.
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