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();
157 return StatusA.getError();
160 return StatusB.getError();
161 return StatusA->equivalent(*StatusB);
164#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
170 return Component ==
".." || Component ==
".";
190class RealFile :
public File {
191 friend class RealFileSystem;
195 std::string RealName;
198 : FD(RawFD), S(NewName, {}, {}, {}, {}, {},
200 RealName(NewRealPathName.str()) {
201 assert(FD != kInvalidFile &&
"Invalid or inactive file descriptor");
205 ~RealFile()
override;
211 bool RequiresNullTerminator,
212 bool IsVolatile)
override;
213 std::error_code close()
override;
214 void setPath(
const Twine &Path)
override;
219RealFile::~RealFile() { close(); }
222 assert(FD != kInvalidFile &&
"cannot stat closed file");
223 if (!S.isStatusKnown()) {
233 return RealName.empty() ? S.getName().str() : RealName;
237RealFile::getBuffer(
const Twine &
Name, int64_t FileSize,
238 bool RequiresNullTerminator,
bool IsVolatile) {
239 assert(FD != kInvalidFile &&
"cannot get buffer for closed file");
244std::error_code RealFile::close() {
250void RealFile::setPath(
const Twine &Path) {
251 RealName =
Path.str();
268 explicit RealFileSystem(
bool LinkCWDToProcess) {
269 if (!LinkCWDToProcess) {
274 WD = WorkingDirectory{PWD, PWD};
276 WD = WorkingDirectory{PWD, RealPWD};
285 std::error_code setCurrentWorkingDirectory(
const Twine &Path)
override;
286 std::error_code isLocal(
const Twine &Path,
bool &Result)
override;
287 std::error_code getRealPath(
const Twine &Path,
292 unsigned IndentLevel)
const override;
300 Path.toVector(Storage);
305 struct WorkingDirectory {
311 std::optional<llvm::ErrorOr<WorkingDirectory>> WD;
319 if (std::error_code EC =
326RealFileSystem::openFileForRead(
const Twine &
Name) {
332 return std::unique_ptr<File>(
333 new RealFile(*FDOrErr,
Name.str(), RealName.
str()));
338 return std::string(WD->get().Specified);
340 return WD->getError();
345 return std::string(Dir);
348std::error_code RealFileSystem::setCurrentWorkingDirectory(
const Twine &Path) {
353 adjustPath(Path, Storage).toVector(Absolute);
358 return std::make_error_code(std::errc::not_a_directory);
362 return std::error_code();
365std::error_code RealFileSystem::isLocal(
const Twine &Path,
bool &Result) {
370std::error_code RealFileSystem::getRealPath(
const Twine &Path,
377 unsigned IndentLevel)
const {
378 printIndent(
OS, IndentLevel);
379 OS <<
"RealFileSystem using ";
393 return std::make_unique<RealFileSystem>(
false);
402 RealFSDirIter(
const Twine &Path, std::error_code &EC) : Iter(Path, EC) {
407 std::error_code increment()
override {
420 std::error_code &EC) {
423 std::make_shared<RealFSDirIter>(adjustPath(Dir, Storage), EC));
454 if ((*I)->exists(Path))
464 auto Result = (*I)->openFileForRead(Path);
474 return FSList.
front()->getCurrentWorkingDirectory();
479 for (
auto &FS : FSList)
480 if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))
486 for (
auto &FS : FSList)
487 if (FS->exists(Path))
488 return FS->isLocal(Path, Result);
494 for (
const auto &FS : FSList)
495 if (FS->exists(Path))
496 return FS->getRealPath(Path, Output);
503 FS->visitChildFileSystems(Callback);
508 unsigned IndentLevel)
const {
509 printIndent(
OS, IndentLevel);
510 OS <<
"OverlayFileSystem\n";
511 if (
Type == PrintType::Summary)
514 if (
Type == PrintType::Contents)
515 Type = PrintType::Summary;
517 FS->print(
OS,
Type, IndentLevel + 1);
537 std::error_code incrementIter(
bool IsFirstTime) {
538 while (!IterList.
empty()) {
539 CurrentDirIter = IterList.
back();
546 return errc::no_such_file_or_directory;
550 std::error_code incrementDirIter(
bool IsFirstTime) {
552 "incrementing past end");
557 EC = incrementIter(IsFirstTime);
561 std::error_code incrementImpl(
bool IsFirstTime) {
563 std::error_code
EC = incrementDirIter(IsFirstTime);
568 CurrentEntry = *CurrentDirIter;
578 std::error_code &EC) {
579 for (
const auto &FS : FileSystems) {
582 if (FEC && FEC != errc::no_such_file_or_directory) {
589 EC = incrementImpl(
true);
594 : IterList(DirIters) {
595 EC = incrementImpl(
true);
598 std::error_code increment()
override {
return incrementImpl(
false); }
604 std::error_code &EC) {
606 std::make_shared<CombiningDirIterImpl>(FSList, Dir.
str(), EC));
612void ProxyFileSystem::anchor() {}
630 std::string FileName;
634 : Kind(Kind), FileName(
std::
string(
llvm::sys::path::filename(FileName))) {
646 virtual std::string
toString(
unsigned Indent)
const = 0;
651 std::unique_ptr<llvm::MemoryBuffer> Buffer;
659 return Status::copyWithNewName(Stat, RequestedName);
663 std::string
toString(
unsigned Indent)
const override {
664 return (std::string(Indent,
' ') + Stat.
getName() +
"\n").str();
674class InMemoryHardLink :
public InMemoryNode {
675 const InMemoryFile &ResolvedFile;
678 InMemoryHardLink(
StringRef Path,
const InMemoryFile &ResolvedFile)
679 : InMemoryNode(Path, IME_HardLink), ResolvedFile(ResolvedFile) {}
680 const InMemoryFile &getResolvedFile()
const {
return ResolvedFile; }
682 Status getStatus(
const Twine &RequestedName)
const override {
683 return ResolvedFile.getStatus(RequestedName);
686 std::string
toString(
unsigned Indent)
const override {
687 return std::string(Indent,
' ') +
"HardLink to -> " +
688 ResolvedFile.toString(0);
691 static bool classof(
const InMemoryNode *
N) {
696class InMemorySymbolicLink :
public InMemoryNode {
697 std::string TargetPath;
705 std::string
toString(
unsigned Indent)
const override {
706 return std::string(Indent,
' ') +
"SymbolicLink to -> " + TargetPath;
709 Status getStatus(
const Twine &RequestedName)
const override {
710 return Status::copyWithNewName(Stat, RequestedName);
713 StringRef getTargetPath()
const {
return TargetPath; }
715 static bool classof(
const InMemoryNode *
N) {
723class InMemoryFileAdaptor :
public File {
724 const InMemoryFile &
Node;
726 std::string RequestedName;
729 explicit InMemoryFileAdaptor(
const InMemoryFile &
Node,
730 std::string RequestedName)
734 return Node.getStatus(RequestedName);
738 getBuffer(
const Twine &
Name, int64_t FileSize,
bool RequiresNullTerminator,
739 bool IsVolatile)
override {
745 std::error_code close()
override {
return {}; }
747 void setPath(
const Twine &Path)
override { RequestedName =
Path.str(); }
753 std::map<std::string, std::unique_ptr<InMemoryNode>> Entries;
763 return Status::copyWithNewName(Stat, RequestedName);
769 auto I = Entries.find(
Name.str());
770 if (
I != Entries.end())
771 return I->second.get();
776 return Entries.emplace(
Name, std::move(Child)).first->second.get();
784 std::string
toString(
unsigned Indent)
const override {
786 (std::string(Indent,
' ') + Stat.
getName() +
"\n").str();
787 for (
const auto &Entry : Entries)
788 Result += Entry.second->toString(Indent + 2);
818 (
Type == sys::fs::file_type::directory_file)
820 :
getFileID(DirUID,
Name, Buffer ? Buffer->getBuffer() :
"");
823 Group, Buffer ? Buffer->getBufferSize() : 0,
Type, Perms);
827 : Root(new
detail::InMemoryDirectory(
830 llvm::sys::fs::file_type::directory_file,
831 llvm::sys::fs::perms::all_all))),
832 UseNormalizedPaths(UseNormalizedPaths) {}
837 return Root->toString(0);
840bool InMemoryFileSystem::addFile(
const Twine &
P, time_t ModificationTime,
841 std::unique_ptr<llvm::MemoryBuffer> Buffer,
842 std::optional<uint32_t>
User,
843 std::optional<uint32_t> Group,
844 std::optional<llvm::sys::fs::file_type>
Type,
845 std::optional<llvm::sys::fs::perms> Perms,
846 MakeNodeFn MakeNode) {
863 const auto ResolvedUser =
User.value_or(0);
864 const auto ResolvedGroup = Group.value_or(0);
881 StringRef(Path.str().begin(),
Name.end() - Path.str().begin()),
885 Dir = cast<detail::InMemoryDirectory>(Dir->
addChild(
886 Name, std::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
890 if (!isa<detail::InMemoryDirectory>(Node))
892 Dir = cast<detail::InMemoryDirectory>(Node);
898 std::move(Buffer), ResolvedUser, ResolvedGroup,
899 ResolvedType, ResolvedPerms}));
902 if (isa<detail::InMemoryDirectory>(
Node))
906 isa<detail::InMemoryHardLink>(
Node)) &&
907 "Must be either file, hardlink or directory!");
910 if (
auto *Link = dyn_cast<detail::InMemoryHardLink>(
Node)) {
911 return Link->getResolvedFile().getBuffer()->getBuffer() ==
914 return cast<detail::InMemoryFile>(
Node)->getBuffer()->getBuffer() ==
918bool InMemoryFileSystem::addFile(
const Twine &
P, time_t ModificationTime,
919 std::unique_ptr<llvm::MemoryBuffer> Buffer,
920 std::optional<uint32_t>
User,
921 std::optional<uint32_t> Group,
922 std::optional<llvm::sys::fs::file_type>
Type,
923 std::optional<llvm::sys::fs::perms> Perms) {
924 return addFile(
P, ModificationTime, std::move(Buffer),
User, Group,
Type,
927 -> std::unique_ptr<detail::InMemoryNode> {
930 return std::make_unique<detail::InMemoryDirectory>(Stat);
931 return std::make_unique<detail::InMemoryFile>(
932 Stat, std::move(NNI.
Buffer));
937 const Twine &
P, time_t ModificationTime,
939 std::optional<uint32_t> Group, std::optional<llvm::sys::fs::file_type>
Type,
940 std::optional<llvm::sys::fs::perms> Perms) {
942 std::move(
User), std::move(Group), std::move(
Type),
945 -> std::unique_ptr<detail::InMemoryNode> {
948 return std::make_unique<detail::InMemoryDirectory>(Stat);
949 return std::make_unique<detail::InMemoryFile>(
950 Stat, std::move(NNI.
Buffer));
955InMemoryFileSystem::lookupNode(
const Twine &
P,
bool FollowFinalSymlink,
956 size_t SymlinkDepth)
const {
979 if (
auto Symlink = dyn_cast<detail::InMemorySymbolicLink>(Node)) {
982 if (
I == E && !FollowFinalSymlink)
997 lookupNode(TargetPath,
true, SymlinkDepth + 1);
1001 if (!isa<detail::InMemoryDirectory>(*
Target))
1005 Dir = cast<detail::InMemoryDirectory>(*
Target);
1010 if (
auto File = dyn_cast<detail::InMemoryFile>(Node)) {
1017 if (
auto File = dyn_cast<detail::InMemoryHardLink>(
Node)) {
1023 Dir = cast<detail::InMemoryDirectory>(
Node);
1031 auto NewLinkNode = lookupNode(NewLink,
false);
1035 auto TargetNode = lookupNode(
Target,
true);
1038 if (!TargetNode || NewLinkNode || !isa<detail::InMemoryFile>(*TargetNode))
1040 return addFile(NewLink, 0,
nullptr, std::nullopt, std::nullopt, std::nullopt,
1042 return std::make_unique<detail::InMemoryHardLink>(
1044 *cast<detail::InMemoryFile>(*TargetNode));
1050 std::optional<uint32_t>
User, std::optional<uint32_t> Group,
1051 std::optional<llvm::sys::fs::perms> Perms) {
1052 auto NewLinkNode = lookupNode(NewLink,
false);
1058 Target.toVector(TargetStr);
1060 return addFile(NewLinkStr, ModificationTime,
nullptr,
User, Group,
1063 return std::make_unique<detail::InMemorySymbolicLink>(
1069 auto Node = lookupNode(Path,
true);
1071 return (*Node)->getStatus(Path);
1072 return Node.getError();
1077 auto Node = lookupNode(Path,
true);
1079 return Node.getError();
1083 if (
auto *
F = dyn_cast<detail::InMemoryFile>(*Node))
1084 return std::unique_ptr<File>(
1085 new detail::InMemoryFileAdaptor(*
F, Path.str()));
1096 std::string RequestedDirName;
1098 void setCurrentEntry() {
1103 switch (
I->second->getKind()) {
1112 if (
auto SymlinkTarget =
1113 FS->lookupNode(Path,
true)) {
1114 Path = SymlinkTarget.getName();
1115 Type = (*SymlinkTarget)->getStatus(Path).getType();
1132 std::string RequestedDirName)
1133 : FS(FS),
I(Dir.begin()), E(Dir.end()),
1134 RequestedDirName(
std::
move(RequestedDirName)) {
1146 std::error_code &EC) {
1147 auto Node = lookupNode(Dir,
true);
1149 EC = Node.getError();
1153 if (
auto *DirNode = dyn_cast<detail::InMemoryDirectory>(*Node))
1155 std::make_shared<DirIterator>(
this, *DirNode, Dir.
str()));
1174 WorkingDirectory = std::string(Path);
1181 if (!CWD || CWD->empty())
1183 Path.toVector(Output);
1196 unsigned IndentLevel)
const {
1197 printIndent(
OS, IndentLevel);
1198 OS <<
"InMemoryFileSystem\n";
1213 const size_t n = Path.find_first_of(
"/\\");
1215 if (n !=
static_cast<size_t>(-1))
1235static bool isFileNotFound(std::error_code EC,
1237 if (E && !isa<RedirectingFileSystem::DirectoryRemapEntry>(E))
1248 if (
auto ExternalWorkingDirectory =
1249 ExternalFS->getCurrentWorkingDirectory()) {
1250 WorkingDirectory = *ExternalWorkingDirectory;
1261 std::error_code incrementImpl(
bool IsFirstTime) {
1262 assert((IsFirstTime || Current !=
End) &&
"cannot iterate past end");
1265 if (Current !=
End) {
1269 switch ((*Current)->getKind()) {
1290 : Dir(Path.str()), Current(Begin),
End(
End) {
1291 EC = incrementImpl(
true);
1295 return incrementImpl(
false);
1309 RedirectingFSDirRemapIterImpl(std::string DirPath,
1311 : Dir(
std::
move(DirPath)), DirStyle(getExistingStyle(Dir)),
1312 ExternalIter(ExtIter) {
1317 void setCurrentEntry() {
1328 std::error_code increment()
override {
1342 return WorkingDirectory;
1352 Path.toVector(AbsolutePath);
1353 if (std::error_code EC = makeAbsolute(AbsolutePath))
1355 WorkingDirectory = std::string(AbsolutePath);
1364 if (makeAbsolute(Path))
1367 return ExternalFS->isLocal(Path, Result);
1382 return WorkingDir.getError();
1384 return makeAbsolute(WorkingDir.get(), Path);
1388RedirectingFileSystem::makeAbsolute(
StringRef WorkingDir,
1394 if (!WorkingDir.
empty() &&
1398 return std::error_code();
1410 std::string
Result = std::string(WorkingDir);
1427 std::error_code &EC) {
1431 EC = makeAbsolute(Path);
1438 isFileNotFound(Result.getError()))
1439 return ExternalFS->dir_begin(Path, EC);
1441 EC = Result.getError();
1449 isFileNotFound(S.
getError(), Result->E))
1450 return ExternalFS->dir_begin(Dir, EC);
1456 if (!S->isDirectory()) {
1464 std::error_code RedirectEC;
1465 if (
auto ExtRedirect = Result->getExternalRedirect()) {
1466 auto RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
1467 RedirectIter = ExternalFS->dir_begin(*ExtRedirect, RedirectEC);
1469 if (!RE->useExternalName(UseExternalNames)) {
1473 std::string(Path), RedirectIter));
1476 auto DE = cast<DirectoryEntry>(Result->E);
1479 Path, DE->contents_begin(), DE->contents_end(), RedirectEC));
1492 return RedirectIter;
1495 std::error_code ExternalEC;
1506 switch (Redirection) {
1520 std::make_shared<CombiningDirIterImpl>(Iters, EC)};
1527 OverlayFileDir = Dir.
str();
1531 return OverlayFileDir;
1548 std::vector<StringRef> R;
1549 R.reserve(Roots.size());
1550 for (
const auto &Root : Roots)
1551 R.push_back(Root->getName());
1556 unsigned IndentLevel)
const {
1558 OS <<
"RedirectingFileSystem (UseExternalNames: "
1559 << (UseExternalNames ?
"true" :
"false") <<
")\n";
1563 for (
const auto &Root : Roots)
1567 OS <<
"ExternalFS:\n";
1574 unsigned IndentLevel)
const {
1580 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(E);
1583 for (std::unique_ptr<Entry> &SubEntry :
1590 auto *RE = cast<RedirectingFileSystem::RemapEntry>(E);
1591 OS <<
" -> '" << RE->getExternalContentsPath() <<
"'";
1592 switch (RE->getUseName()) {
1596 OS <<
" (UseExternalName: true)";
1599 OS <<
" (UseExternalName: false)";
1610 Callback(*ExternalFS);
1611 ExternalFS->visitChildFileSystems(Callback);
1624 const auto *S = dyn_cast<yaml::ScalarNode>(
N);
1627 error(
N,
"expected string");
1630 Result = S->getValue(Storage);
1635 bool parseScalarBool(
yaml::Node *
N,
bool &Result) {
1638 if (!parseScalarString(
N,
Value, Storage))
1641 if (
Value.equals_insensitive(
"true") ||
Value.equals_insensitive(
"on") ||
1642 Value.equals_insensitive(
"yes") ||
Value ==
"1") {
1645 }
else if (
Value.equals_insensitive(
"false") ||
1646 Value.equals_insensitive(
"off") ||
1647 Value.equals_insensitive(
"no") ||
Value ==
"0") {
1652 error(
N,
"expected boolean value");
1656 std::optional<RedirectingFileSystem::RedirectKind>
1660 if (!parseScalarString(
N,
Value, Storage))
1661 return std::nullopt;
1663 if (
Value.equals_insensitive(
"fallthrough")) {
1665 }
else if (
Value.equals_insensitive(
"fallback")) {
1667 }
else if (
Value.equals_insensitive(
"redirect-only")) {
1670 return std::nullopt;
1673 std::optional<RedirectingFileSystem::RootRelativeKind>
1677 if (!parseScalarString(
N,
Value, Storage))
1678 return std::nullopt;
1679 if (
Value.equals_insensitive(
"cwd")) {
1681 }
else if (
Value.equals_insensitive(
"overlay-dir")) {
1684 return std::nullopt;
1691 KeyStatus(
bool Required =
false) : Required(Required) {}
1694 using KeyStatusPair = std::pair<StringRef, KeyStatus>;
1699 if (!Keys.
count(Key)) {
1700 error(KeyNode,
"unknown key");
1703 KeyStatus &S = Keys[Key];
1705 error(KeyNode,
Twine(
"duplicate key '") + Key +
"'");
1714 for (
const auto &
I : Keys) {
1715 if (
I.second.Required && !
I.second.Seen) {
1716 error(Obj,
Twine(
"missing key '") +
I.first +
"'");
1728 for (
const auto &Root : FS->Roots) {
1729 if (
Name == Root->getName()) {
1730 ParentEntry = Root.get();
1735 auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
1736 for (std::unique_ptr<RedirectingFileSystem::Entry> &
Content :
1739 dyn_cast<RedirectingFileSystem::DirectoryEntry>(
Content.get());
1746 std::unique_ptr<RedirectingFileSystem::Entry> E =
1747 std::make_unique<RedirectingFileSystem::DirectoryEntry>(
1749 std::chrono::system_clock::now(), 0, 0, 0,
1753 FS->Roots.push_back(std::move(E));
1754 ParentEntry = FS->Roots.back().get();
1758 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
1759 DE->addContent(std::move(E));
1760 return DE->getLastContent();
1770 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
1776 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
1778 uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
1782 assert(NewParentE &&
"Parent entry must exist");
1783 auto *DR = cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
1784 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
1786 std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
1787 Name, DR->getExternalContentsPath(), DR->getUseName()));
1791 assert(NewParentE &&
"Parent entry must exist");
1792 auto *FE = cast<RedirectingFileSystem::FileEntry>(SrcE);
1793 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
1794 DE->addContent(std::make_unique<RedirectingFileSystem::FileEntry>(
1795 Name, FE->getExternalContentsPath(), FE->getUseName()));
1801 std::unique_ptr<RedirectingFileSystem::Entry>
1803 auto *
M = dyn_cast<yaml::MappingNode>(
N);
1805 error(
N,
"expected mapping node for file or directory entry");
1809 KeyStatusPair Fields[] = {
1810 KeyStatusPair(
"name",
true),
1811 KeyStatusPair(
"type",
true),
1812 KeyStatusPair(
"contents",
false),
1813 KeyStatusPair(
"external-contents",
false),
1814 KeyStatusPair(
"use-external-name",
false),
1819 enum { CF_NotSet, CF_List, CF_External } ContentsField = CF_NotSet;
1820 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>>
1828 for (
auto &
I : *M) {
1833 if (!parseScalarString(
I.getKey(), Key, Buffer))
1836 if (!checkDuplicateOrUnknownKey(
I.getKey(), Key, Keys))
1840 if (Key ==
"name") {
1841 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1844 NameValueNode =
I.getValue();
1848 }
else if (Key ==
"type") {
1849 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1851 if (
Value ==
"file")
1853 else if (
Value ==
"directory")
1855 else if (
Value ==
"directory-remap")
1858 error(
I.getValue(),
"unknown value for 'type'");
1861 }
else if (Key ==
"contents") {
1862 if (ContentsField != CF_NotSet) {
1864 "entry already has 'contents' or 'external-contents'");
1867 ContentsField = CF_List;
1868 auto *Contents = dyn_cast<yaml::SequenceNode>(
I.getValue());
1871 error(
I.getValue(),
"expected array");
1875 for (
auto &
I : *Contents) {
1876 if (std::unique_ptr<RedirectingFileSystem::Entry> E =
1877 parseEntry(&
I, FS,
false))
1878 EntryArrayContents.push_back(std::move(E));
1882 }
else if (Key ==
"external-contents") {
1883 if (ContentsField != CF_NotSet) {
1885 "entry already has 'contents' or 'external-contents'");
1888 ContentsField = CF_External;
1889 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1893 if (
FS->IsRelativeOverlay) {
1894 FullPath =
FS->getOverlayFileDir();
1896 "External contents prefix directory must exist");
1904 FullPath = canonicalize(FullPath);
1905 ExternalContentsPath = FullPath.
str();
1906 }
else if (Key ==
"use-external-name") {
1908 if (!parseScalarBool(
I.getValue(), Val))
1921 if (ContentsField == CF_NotSet) {
1922 error(
N,
"missing key 'contents' or 'external-contents'");
1925 if (!checkMissingKeys(
N, Keys))
1931 error(
N,
"'use-external-name' is not supported for 'directory' entries");
1936 ContentsField == CF_List) {
1937 error(
N,
"'contents' is not supported for 'directory-remap' entries");
1955 if (
FS->RootRelative ==
1958 assert(!FullPath.
empty() &&
"Overlay file directory must exist");
1959 EC =
FS->makeAbsolute(FullPath,
Name);
1965 assert(NameValueNode &&
"Name presence should be checked earlier");
1968 "entry with relative path at the root level is not discoverable");
1986 while (Trimmed.
size() > RootPathLen &&
1988 Trimmed = Trimmed.
slice(0, Trimmed.
size() - 1);
1993 std::unique_ptr<RedirectingFileSystem::Entry>
Result;
1996 Result = std::make_unique<RedirectingFileSystem::FileEntry>(
1997 LastComponent, std::move(ExternalContentsPath), UseExternalName);
2000 Result = std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
2001 LastComponent, std::move(ExternalContentsPath), UseExternalName);
2004 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
2005 LastComponent, std::move(EntryArrayContents),
2019 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> Entries;
2020 Entries.push_back(std::move(Result));
2021 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
2022 *
I, std::move(Entries),
2034 auto *Top = dyn_cast<yaml::MappingNode>(Root);
2036 error(Root,
"expected mapping node");
2040 KeyStatusPair Fields[] = {
2041 KeyStatusPair(
"version",
true),
2042 KeyStatusPair(
"case-sensitive",
false),
2043 KeyStatusPair(
"use-external-names",
false),
2044 KeyStatusPair(
"root-relative",
false),
2045 KeyStatusPair(
"overlay-relative",
false),
2046 KeyStatusPair(
"fallthrough",
false),
2047 KeyStatusPair(
"redirecting-with",
false),
2048 KeyStatusPair(
"roots",
true),
2052 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> RootEntries;
2055 for (
auto &
I : *Top) {
2058 if (!parseScalarString(
I.getKey(), Key, KeyBuffer))
2061 if (!checkDuplicateOrUnknownKey(
I.getKey(), Key, Keys))
2064 if (Key ==
"roots") {
2065 auto *Roots = dyn_cast<yaml::SequenceNode>(
I.getValue());
2067 error(
I.getValue(),
"expected array");
2071 for (
auto &
I : *Roots) {
2072 if (std::unique_ptr<RedirectingFileSystem::Entry> E =
2073 parseEntry(&
I, FS,
true))
2074 RootEntries.push_back(std::move(E));
2078 }
else if (Key ==
"version") {
2081 if (!parseScalarString(
I.getValue(), VersionString, Storage))
2085 error(
I.getValue(),
"expected integer");
2089 error(
I.getValue(),
"invalid version number");
2093 error(
I.getValue(),
"version mismatch, expected 0");
2096 }
else if (Key ==
"case-sensitive") {
2097 if (!parseScalarBool(
I.getValue(), FS->CaseSensitive))
2099 }
else if (Key ==
"overlay-relative") {
2100 if (!parseScalarBool(
I.getValue(), FS->IsRelativeOverlay))
2102 }
else if (Key ==
"use-external-names") {
2103 if (!parseScalarBool(
I.getValue(), FS->UseExternalNames))
2105 }
else if (Key ==
"fallthrough") {
2106 if (Keys[
"redirecting-with"].Seen) {
2108 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2112 bool ShouldFallthrough =
false;
2113 if (!parseScalarBool(
I.getValue(), ShouldFallthrough))
2116 if (ShouldFallthrough) {
2121 }
else if (Key ==
"redirecting-with") {
2122 if (Keys[
"fallthrough"].Seen) {
2124 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2128 if (
auto Kind = parseRedirectKind(
I.getValue())) {
2129 FS->Redirection = *Kind;
2131 error(
I.getValue(),
"expected valid redirect kind");
2134 }
else if (Key ==
"root-relative") {
2135 if (
auto Kind = parseRootRelativeKind(
I.getValue())) {
2136 FS->RootRelative = *Kind;
2138 error(
I.getValue(),
"expected valid root-relative kind");
2149 if (!checkMissingKeys(Top, Keys))
2155 for (
auto &E : RootEntries)
2156 uniqueOverlayTree(FS, E.get());
2162std::unique_ptr<RedirectingFileSystem>
2165 StringRef YAMLFilePath,
void *DiagContext,
2173 if (DI == Stream.
end() || !Root) {
2180 std::unique_ptr<RedirectingFileSystem> FS(
2183 if (!YAMLFilePath.
empty()) {
2194 assert(!EC &&
"Overlay dir final path must be absolute");
2196 FS->setOverlayFileDir(OverlayAbsDir);
2199 if (!
P.parse(Root, FS.get()))
2206 ArrayRef<std::pair<std::string, std::string>> RemappedFiles,
2207 bool UseExternalNames,
FileSystem &ExternalFS) {
2208 std::unique_ptr<RedirectingFileSystem> FS(
2210 FS->UseExternalNames = UseExternalNames;
2220 assert(!EC &&
"Could not make absolute path");
2238 assert(Parent &&
"File without a directory?");
2242 assert(!EC &&
"Could not make absolute path");
2246 auto NewFile = std::make_unique<RedirectingFileSystem::FileEntry>(
2250 ToEntry = NewFile.get();
2251 cast<RedirectingFileSystem::DirectoryEntry>(Parent)->addContent(
2252 std::move(NewFile));
2265 if (
auto *DRE = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(
E)) {
2268 getExistingStyle(DRE->getExternalContentsPath()));
2269 ExternalRedirect = std::string(Redirect);
2276 for (
Entry *Parent : Parents)
2281std::error_code RedirectingFileSystem::makeCanonicalForLookup(
2283 if (std::error_code EC = makeAbsolute(Path))
2287 canonicalize(
StringRef(Path.data(), Path.size()));
2288 if (CanonicalPath.
empty())
2291 Path.assign(CanonicalPath.
begin(), CanonicalPath.
end());
2298 if (std::error_code EC = makeCanonicalForLookup(CanonicalPath))
2308 for (
const auto &Root : Roots) {
2310 lookupPathImpl(Start,
End, Root.get(), Entries);
2311 if (UsageTrackingActive && Result && isa<RemapEntry>(Result->E))
2314 Result->Parents = std::move(Entries);
2322RedirectingFileSystem::lookupPathImpl(
2328 "Paths should not contain traversal components");
2333 if (!FromName.
empty()) {
2334 if (!pathComponentMatches(*Start, FromName))
2341 return LookupResult(
From, Start,
End);
2345 if (isa<RedirectingFileSystem::FileEntry>(
From))
2348 if (isa<RedirectingFileSystem::DirectoryRemapEntry>(
From))
2349 return LookupResult(
From, Start,
End);
2351 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(
From);
2352 for (
const std::unique_ptr<RedirectingFileSystem::Entry> &DirEntry :
2354 Entries.push_back(
From);
2356 lookupPathImpl(Start,
End, DirEntry.get(), Entries);
2366 bool UseExternalNames,
2371 return ExternalStatus;
2373 Status S = ExternalStatus;
2374 if (!UseExternalNames)
2382 const Twine &LookupPath,
const Twine &OriginalPath,
2384 if (std::optional<StringRef> ExtRedirect =
Result.getExternalRedirect()) {
2386 if (std::error_code EC = makeAbsolute(RemappedPath))
2393 auto *RE = cast<RedirectingFileSystem::RemapEntry>(
Result.E);
2395 RE->useExternalName(UseExternalNames), *S);
2398 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(
Result.E);
2403RedirectingFileSystem::getExternalStatus(
const Twine &LookupPath,
2404 const Twine &OriginalPath)
const {
2405 auto Result = ExternalFS->status(LookupPath);
2409 if (!Result ||
Result->ExposesExternalVFSPath)
2418 if (std::error_code EC = makeAbsolute(Path))
2434 isFileNotFound(Result.getError()))
2435 return getExternalStatus(Path, OriginalPath);
2436 return Result.getError();
2441 isFileNotFound(S.
getError(), Result->E)) {
2445 return getExternalStatus(Path, OriginalPath);
2455 if (makeAbsolute(Path))
2461 if (ExternalFS->exists(Path))
2470 isFileNotFound(Result.getError()))
2471 return ExternalFS->exists(Path);
2475 std::optional<StringRef> ExtRedirect = Result->getExternalRedirect();
2477 assert(isa<RedirectingFileSystem::DirectoryEntry>(Result->E));
2482 if (makeAbsolute(RemappedPath))
2485 if (ExternalFS->exists(RemappedPath))
2492 return ExternalFS->exists(Path);
2501class FileWithFixedStatus :
public File {
2502 std::unique_ptr<File> InnerFile;
2506 FileWithFixedStatus(std::unique_ptr<File> InnerFile,
Status S)
2512 getBuffer(
const Twine &
Name, int64_t FileSize,
bool RequiresNullTerminator,
2513 bool IsVolatile)
override {
2514 return InnerFile->getBuffer(
Name, FileSize, RequiresNullTerminator,
2518 std::error_code close()
override {
return InnerFile->close(); }
2529 if (!Result || (*Result)->status()->ExposesExternalVFSPath)
2533 auto Name =
F->get()->getName();
2535 F->get()->setPath(
P);
2544 if (std::error_code EC = makeAbsolute(Path))
2560 isFileNotFound(Result.getError()))
2562 return Result.getError();
2565 if (!Result->getExternalRedirect())
2568 StringRef ExtRedirect = *Result->getExternalRedirect();
2570 if (std::error_code EC = makeAbsolute(RemappedPath))
2573 auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
2577 if (!ExternalFile) {
2579 isFileNotFound(ExternalFile.getError(), Result->E)) {
2585 return ExternalFile;
2588 auto ExternalStatus = (*ExternalFile)->status();
2589 if (!ExternalStatus)
2590 return ExternalStatus.getError();
2595 OriginalPath, RE->useExternalName(UseExternalNames), *ExternalStatus);
2596 return std::unique_ptr<File>(
2597 std::make_unique<FileWithFixedStatus>(std::move(*ExternalFile), S));
2606 if (std::error_code EC = makeAbsolute(Path))
2612 std::error_code EC = ExternalFS->getRealPath(Path, Output);
2622 isFileNotFound(Result.getError()))
2623 return ExternalFS->getRealPath(Path, Output);
2624 return Result.getError();
2629 if (
auto ExtRedirect = Result->getExternalRedirect()) {
2630 auto P = ExternalFS->getRealPath(*ExtRedirect, Output);
2632 isFileNotFound(
P, Result->E)) {
2636 return ExternalFS->getRealPath(Path, Output);
2644 Result->getPath(Output);
2650std::unique_ptr<FileSystem>
2653 StringRef YAMLFilePath,
void *DiagContext,
2656 YAMLFilePath, DiagContext,
2657 std::move(ExternalFS));
2665 auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
2666 assert(DE &&
"Must be a directory");
2667 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
2669 Path.push_back(SubEntry->getName());
2677 auto *DR = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
2678 assert(DR &&
"Must be a directory remap");
2680 for (
auto &Comp : Path)
2688 auto *FE = dyn_cast<RedirectingFileSystem::FileEntry>(SrcE);
2689 assert(FE &&
"Must be a file");
2691 for (
auto &Comp : Path)
2703 std::move(Buffer),
DiagHandler, YAMLFilePath, DiagContext,
2704 std::move(ExternalFS));
2708 VFS->lookupPath(
"/");
2717 static std::atomic<unsigned> UID;
2718 unsigned ID = ++UID;
2721 return UniqueID(std::numeric_limits<uint64_t>::max(),
ID);
2729 Mappings.emplace_back(VirtualPath, RealPath, IsDirectory);
2733 addEntry(VirtualPath, RealPath,
false);
2738 addEntry(VirtualPath, RealPath,
true);
2747 unsigned getDirIndent() {
return 4 * DirStack.
size(); }
2748 unsigned getFileIndent() {
return 4 * (DirStack.
size() + 1); }
2752 void endDirectory();
2759 std::optional<bool> UseExternalNames,
2760 std::optional<bool> IsCaseSensitive,
2761 std::optional<bool> IsOverlayRelative,
StringRef OverlayDir);
2772 IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
2773 if (*IParent != *IChild)
2777 return IParent == EParent;
2782 assert(containedIn(Parent, Path));
2786void JSONWriter::startDirectory(
StringRef Path) {
2788 DirStack.
empty() ?
Path : containedPart(DirStack.
back(), Path);
2790 unsigned Indent = getDirIndent();
2792 OS.
indent(Indent + 2) <<
"'type': 'directory',\n";
2794 OS.
indent(Indent + 2) <<
"'contents': [\n";
2797void JSONWriter::endDirectory() {
2798 unsigned Indent = getDirIndent();
2806 unsigned Indent = getFileIndent();
2808 OS.
indent(Indent + 2) <<
"'type': 'file',\n";
2810 OS.
indent(Indent + 2) <<
"'external-contents': \""
2816 std::optional<bool> UseExternalNames,
2817 std::optional<bool> IsCaseSensitive,
2818 std::optional<bool> IsOverlayRelative,
2824 if (IsCaseSensitive)
2825 OS <<
" 'case-sensitive': '" << (*IsCaseSensitive ?
"true" :
"false")
2827 if (UseExternalNames)
2828 OS <<
" 'use-external-names': '" << (*UseExternalNames ?
"true" :
"false")
2830 bool UseOverlayRelative =
false;
2831 if (IsOverlayRelative) {
2832 UseOverlayRelative = *IsOverlayRelative;
2833 OS <<
" 'overlay-relative': '" << (UseOverlayRelative ?
"true" :
"false")
2836 OS <<
" 'roots': [\n";
2838 if (!Entries.empty()) {
2846 if (UseOverlayRelative) {
2848 "Overlay dir must be contained in RPath");
2852 bool IsCurrentDirEmpty =
true;
2853 if (!
Entry.IsDirectory) {
2855 IsCurrentDirEmpty =
false;
2858 for (
const auto &Entry : Entries.slice(1)) {
2861 if (Dir == DirStack.
back()) {
2862 if (!IsCurrentDirEmpty) {
2866 bool IsDirPoppedFromStack =
false;
2867 while (!DirStack.
empty() && !containedIn(DirStack.
back(), Dir)) {
2870 IsDirPoppedFromStack =
true;
2872 if (IsDirPoppedFromStack || !IsCurrentDirEmpty) {
2875 startDirectory(Dir);
2876 IsCurrentDirEmpty =
true;
2879 if (UseOverlayRelative) {
2881 "Overlay dir must be contained in RPath");
2884 if (!
Entry.IsDirectory) {
2886 IsCurrentDirEmpty =
false;
2890 while (!DirStack.
empty()) {
2903 return LHS.VPath <
RHS.VPath;
2906 JSONWriter(
OS).write(Mappings, UseExternalNames, IsCaseSensitive,
2915 State = std::make_shared<detail::RecDirIterState>();
2916 State->Stack.push_back(
I);
2922 assert(FS && State && !State->Stack.empty() &&
"incrementing past end");
2923 assert(!State->Stack.back()->path().empty() &&
"non-canonical end iterator");
2926 if (State->HasNoPushRequest)
2927 State->HasNoPushRequest =
false;
2931 FS->dir_begin(State->Stack.back()->path(), EC);
2933 State->Stack.push_back(
I);
2939 while (!State->Stack.empty() && State->Stack.back().increment(EC) ==
End)
2940 State->Stack.pop_back();
2942 if (State->Stack.empty())
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 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
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 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