24#include "llvm/Config/llvm-config.h"
49#include <system_error>
71 : Name(Name.str()), UID(UID), MTime(MTime), User(User), Group(Group),
72 Size(Size), Type(Type), Perms(Perms) {}
75 return Status(In.getName(), In.getUniqueID(), In.getLastModificationTime(),
76 In.getUser(), In.getGroup(), NewSize, In.getType(),
81 return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
82 In.getUser(), In.getGroup(), In.getSize(), In.getType(),
87 return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
88 In.getUser(), In.getGroup(), In.getSize(), In.type(),
119 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;
197 RealFile(
file_t RawFD, StringRef NewName, StringRef NewRealPathName)
198 : FD(RawFD), S(NewName, {}, {}, {}, {}, {},
200 RealName(NewRealPathName.str()) {
205 ~RealFile()
override;
207 ErrorOr<Status>
status()
override;
208 ErrorOr<std::string>
getName()
override;
209 ErrorOr<std::unique_ptr<MemoryBuffer>> getBuffer(
const Twine &Name,
211 bool RequiresNullTerminator,
212 bool IsVolatile)
override;
213 std::error_code close()
override;
214 void setPath(
const Twine &Path)
override;
219RealFile::~RealFile() { close(); }
221ErrorOr<Status> RealFile::status() {
223 if (!S.isStatusKnown()) {
224 file_status RealStatus;
232ErrorOr<std::string> RealFile::getName() {
233 return RealName.empty() ? S.getName().str() : RealName;
236ErrorOr<std::unique_ptr<MemoryBuffer>>
237RealFile::getBuffer(
const Twine &Name, int64_t FileSize,
238 bool RequiresNullTerminator,
bool IsVolatile) {
244std::error_code RealFile::close() {
250void RealFile::setPath(
const Twine &Path) {
251 RealName =
Path.str();
266class RealFileSystem :
public FileSystem {
268 explicit RealFileSystem(
bool LinkCWDToProcess) {
269 if (!LinkCWDToProcess) {
270 SmallString<128> PWD, RealPWD;
274 WD = WorkingDirectory{PWD, PWD};
276 WD = WorkingDirectory{PWD, RealPWD};
280 ErrorOr<Status>
status(
const Twine &Path)
override;
281 ErrorOr<std::unique_ptr<File>>
openFileForRead(
const Twine &Path)
override;
282 ErrorOr<std::unique_ptr<File>>
283 openFileForReadBinary(
const Twine &Path)
override;
284 directory_iterator dir_begin(
const Twine &Dir, std::error_code &EC)
override;
286 llvm::ErrorOr<std::string> getCurrentWorkingDirectory()
const override;
287 std::error_code setCurrentWorkingDirectory(
const Twine &Path)
override;
288 std::error_code isLocal(
const Twine &Path,
bool &Result)
override;
289 std::error_code getRealPath(
const Twine &Path,
290 SmallVectorImpl<char> &Output)
override;
294 unsigned IndentLevel)
const override;
299 Twine adjustPath(
const Twine &Path, SmallVectorImpl<char> &Storage)
const {
302 Path.toVector(Storage);
307 ErrorOr<std::unique_ptr<File>>
309 SmallString<256> RealName, Storage;
311 adjustPath(Name, Storage), Flags, &RealName);
314 return std::unique_ptr<File>(
315 new RealFile(*FDOrErr,
Name.str(), RealName.
str()));
318 struct WorkingDirectory {
320 SmallString<128> Specified;
324 std::optional<llvm::ErrorOr<WorkingDirectory>> WD;
329ErrorOr<Status> RealFileSystem::status(
const Twine &Path) {
330 SmallString<256> Storage;
331 sys::fs::file_status RealStatus;
332 if (std::error_code EC =
338ErrorOr<std::unique_ptr<File>>
339RealFileSystem::openFileForRead(
const Twine &Name) {
343ErrorOr<std::unique_ptr<File>>
344RealFileSystem::openFileForReadBinary(
const Twine &Name) {
348llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory()
const {
350 return std::string(WD->get().Specified);
352 return WD->getError();
354 SmallString<128> Dir;
357 return std::string(Dir);
360std::error_code RealFileSystem::setCurrentWorkingDirectory(
const Twine &Path) {
365 adjustPath(Path, Storage).toVector(Absolute);
370 return std::make_error_code(std::errc::not_a_directory);
374 return std::error_code();
377std::error_code RealFileSystem::isLocal(
const Twine &Path,
bool &Result) {
378 SmallString<256> Storage;
382std::error_code RealFileSystem::getRealPath(
const Twine &Path,
383 SmallVectorImpl<char> &Output) {
384 SmallString<256> Storage;
388void RealFileSystem::printImpl(raw_ostream &OS, PrintType
Type,
389 unsigned IndentLevel)
const {
390 printIndent(OS, IndentLevel);
391 OS <<
"RealFileSystem using ";
406 return std::make_unique<RealFileSystem>(
false);
415 RealFSDirIter(
const Twine &Path, std::error_code &EC) : Iter(Path, EC) {
420 std::error_code increment()
override {
433 std::error_code &EC) {
434 SmallString<128> Storage;
436 std::make_shared<RealFSDirIter>(adjustPath(Dir, Storage), EC));
444 FSList.push_back(std::move(BaseFS));
448 FSList.push_back(FS);
467 if ((*I)->exists(Path))
477 auto Result = (*I)->openFileForRead(Path);
487 return FSList.front()->getCurrentWorkingDirectory();
492 for (
auto &FS : FSList)
493 if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))
499 for (
auto &FS : FSList)
500 if (FS->exists(Path))
501 return FS->isLocal(Path, Result);
507 for (
const auto &FS : FSList)
508 if (FS->exists(Path))
509 return FS->getRealPath(Path, Output);
516 FS->visitChildFileSystems(Callback);
521 unsigned IndentLevel)
const {
522 printIndent(OS, IndentLevel);
523 OS <<
"OverlayFileSystem\n";
524 if (
Type == PrintType::Summary)
527 if (
Type == PrintType::Contents)
528 Type = PrintType::Summary;
530 FS->print(OS,
Type, IndentLevel + 1);
550 std::error_code incrementIter(
bool IsFirstTime) {
551 while (!IterList.
empty()) {
552 CurrentDirIter = IterList.
back();
563 std::error_code incrementDirIter(
bool IsFirstTime) {
564 assert((IsFirstTime || CurrentDirIter != directory_iterator()) &&
565 "incrementing past end");
569 if (!EC && CurrentDirIter == directory_iterator())
570 EC = incrementIter(IsFirstTime);
574 std::error_code incrementImpl(
bool IsFirstTime) {
576 std::error_code
EC = incrementDirIter(IsFirstTime);
577 if (EC || CurrentDirIter == directory_iterator()) {
578 CurrentEntry = directory_entry();
581 CurrentEntry = *CurrentDirIter;
583 if (SeenNames.
insert(Name).second)
591 std::error_code &EC) {
592 for (
const auto &FS : FileSystems) {
594 directory_iterator Iter =
FS->dir_begin(Dir, FEC);
595 if (FEC && FEC != errc::no_such_file_or_directory) {
602 EC = incrementImpl(
true);
607 : IterList(DirIters) {
608 EC = incrementImpl(
true);
611 std::error_code increment()
override {
return incrementImpl(
false); }
617 std::error_code &EC) {
619 std::make_shared<CombiningDirIterImpl>(FSList, Dir.
str(), EC));
625void ProxyFileSystem::anchor() {}
643 std::string FileName;
647 : Kind(Kind), FileName(
std::string(
llvm::
sys::
path::filename(FileName))) {
659 virtual std::string
toString(
unsigned Indent)
const = 0;
664 std::unique_ptr<llvm::MemoryBuffer> Buffer;
676 std::string
toString(
unsigned Indent)
const override {
677 return (std::string(Indent,
' ') + Stat.getName() +
"\n").str();
687class InMemoryHardLink :
public InMemoryNode {
688 const InMemoryFile &ResolvedFile;
691 InMemoryHardLink(
StringRef Path,
const InMemoryFile &ResolvedFile)
692 : InMemoryNode(Path,
IME_HardLink), ResolvedFile(ResolvedFile) {}
693 const InMemoryFile &getResolvedFile()
const {
return ResolvedFile; }
695 Status getStatus(
const Twine &RequestedName)
const override {
696 return ResolvedFile.getStatus(RequestedName);
699 std::string
toString(
unsigned Indent)
const override {
700 return std::string(Indent,
' ') +
"HardLink to -> " +
701 ResolvedFile.toString(0);
704 static bool classof(
const InMemoryNode *
N) {
710 std::string TargetPath;
714 InMemorySymbolicLink(StringRef Path, StringRef TargetPath, Status Stat)
718 std::string
toString(
unsigned Indent)
const override {
719 return std::string(Indent,
' ') +
"SymbolicLink to -> " + TargetPath;
722 Status getStatus(
const Twine &RequestedName)
const override {
726 StringRef getTargetPath()
const {
return TargetPath; }
728 static bool classof(
const InMemoryNode *
N) {
736class InMemoryFileAdaptor :
public File {
737 const InMemoryFile &Node;
739 std::string RequestedName;
742 explicit InMemoryFileAdaptor(
const InMemoryFile &Node,
743 std::string RequestedName)
744 : Node(Node), RequestedName(std::
move(RequestedName)) {}
746 llvm::ErrorOr<Status>
status()
override {
747 return Node.getStatus(RequestedName);
750 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
751 getBuffer(
const Twine &Name, int64_t FileSize,
bool RequiresNullTerminator,
752 bool IsVolatile)
override {
753 llvm::MemoryBuffer *Buf = Node.getBuffer();
758 std::error_code close()
override {
return {}; }
760 void setPath(
const Twine &Path)
override { RequestedName =
Path.str(); }
766 std::map<std::string, std::unique_ptr<InMemoryNode>, std::less<>> Entries;
782 auto I = Entries.find(Name);
783 if (
I != Entries.end())
784 return I->second.get();
789 return Entries.emplace(Name, std::move(Child)).first->second.get();
797 std::string
toString(
unsigned Indent)
const override {
799 (std::string(Indent,
' ') + Stat.getName() +
"\n").str();
800 for (
const auto &Entry : Entries)
801 Result += Entry.second->toString(Indent + 2);
840 : Root(new
detail::InMemoryDirectory(
845 UseNormalizedPaths(UseNormalizedPaths) {}
850 return Root->toString(0);
853bool InMemoryFileSystem::addFile(
const Twine &
P, time_t ModificationTime,
854 std::unique_ptr<llvm::MemoryBuffer> Buffer,
855 std::optional<uint32_t>
User,
856 std::optional<uint32_t> Group,
857 std::optional<llvm::sys::fs::file_type>
Type,
858 std::optional<llvm::sys::fs::perms> Perms,
859 MakeNodeFn MakeNode) {
876 const auto ResolvedUser =
User.value_or(0);
877 const auto ResolvedGroup = Group.value_or(0);
894 StringRef(Path.str().begin(), Name.end() - Path.str().begin()),
899 Name, std::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
910 MakeNode({Dir->
getUniqueID(), Path, Name, ModificationTime,
911 std::move(Buffer), ResolvedUser, ResolvedGroup,
912 ResolvedType, ResolvedPerms}));
920 "Must be either file, hardlink or directory!");
924 return Link->getResolvedFile().getBuffer()->getBuffer() ==
931bool InMemoryFileSystem::addFile(
const Twine &
P, time_t ModificationTime,
932 std::unique_ptr<llvm::MemoryBuffer> Buffer,
933 std::optional<uint32_t>
User,
934 std::optional<uint32_t> Group,
935 std::optional<llvm::sys::fs::file_type>
Type,
936 std::optional<llvm::sys::fs::perms> Perms) {
937 return addFile(
P, ModificationTime, std::move(Buffer),
User, Group,
Type,
940 -> std::unique_ptr<detail::InMemoryNode> {
943 return std::make_unique<detail::InMemoryDirectory>(Stat);
944 return std::make_unique<detail::InMemoryFile>(
945 Stat, std::move(NNI.
Buffer));
950 const Twine &
P, time_t ModificationTime,
952 std::optional<uint32_t> Group, std::optional<llvm::sys::fs::file_type>
Type,
953 std::optional<llvm::sys::fs::perms> Perms) {
955 std::move(
User), std::move(Group), std::move(
Type),
958 -> std::unique_ptr<detail::InMemoryNode> {
961 return std::make_unique<detail::InMemoryDirectory>(Stat);
962 return std::make_unique<detail::InMemoryFile>(
963 Stat, std::move(NNI.
Buffer));
968InMemoryFileSystem::lookupNode(
const Twine &
P,
bool FollowFinalSymlink,
969 size_t SymlinkDepth)
const {
995 if (
I == E && !FollowFinalSymlink)
1010 lookupNode(TargetPath,
true, SymlinkDepth + 1);
1038 return detail::NamedNodeOrError(Path, Dir);
1044 auto NewLinkNode = lookupNode(NewLink,
false);
1048 auto TargetNode = lookupNode(
Target,
true);
1053 return addFile(NewLink, 0,
nullptr, std::nullopt, std::nullopt, std::nullopt,
1055 return std::make_unique<detail::InMemoryHardLink>(
1063 std::optional<uint32_t>
User, std::optional<uint32_t> Group,
1064 std::optional<llvm::sys::fs::perms> Perms) {
1065 auto NewLinkNode = lookupNode(NewLink,
false);
1071 Target.toVector(TargetStr);
1073 return addFile(NewLinkStr, ModificationTime,
nullptr,
User, Group,
1076 return std::make_unique<detail::InMemorySymbolicLink>(
1082 auto Node = lookupNode(Path,
true);
1084 return (*Node)->getStatus(Path);
1085 return Node.getError();
1090 auto Node = lookupNode(Path,
true);
1092 return Node.getError();
1097 return std::unique_ptr<File>(
1098 new detail::InMemoryFileAdaptor(*
F, Path.str()));
1109 std::string RequestedDirName;
1111 void setCurrentEntry() {
1116 switch (I->second->getKind()) {
1125 if (
auto SymlinkTarget =
1126 FS->lookupNode(Path,
true)) {
1127 Path = SymlinkTarget.getName();
1128 Type = (*SymlinkTarget)->getStatus(Path).getType();
1145 std::string RequestedDirName)
1146 : FS(FS), I(Dir.begin()), E(Dir.end()),
1147 RequestedDirName(
std::
move(RequestedDirName)) {
1159 std::error_code &EC) {
1160 auto Node = lookupNode(Dir,
true);
1162 EC =
Node.getError();
1168 std::make_shared<DirIterator>(
this, *DirNode, Dir.
str()));
1187 WorkingDirectory = std::string(Path);
1194 if (!CWD || CWD->empty())
1196 Path.toVector(Output);
1209 unsigned IndentLevel)
const {
1210 printIndent(OS, IndentLevel);
1211 OS <<
"InMemoryFileSystem\n";
1226 const size_t n = Path.find_first_of(
"/\\");
1228 if (n !=
static_cast<size_t>(-1))
1248static bool isFileNotFound(std::error_code EC,
1261 if (
auto ExternalWorkingDirectory =
1262 ExternalFS->getCurrentWorkingDirectory()) {
1263 WorkingDirectory = *ExternalWorkingDirectory;
1274 std::error_code incrementImpl(
bool IsFirstTime) {
1275 assert((IsFirstTime || Current != End) &&
"cannot iterate past end");
1278 if (Current != End) {
1282 switch ((*Current)->getKind()) {
1303 : Dir(Path.str()), Current(Begin), End(End) {
1304 EC = incrementImpl(
true);
1308 return incrementImpl(
false);
1322 RedirectingFSDirRemapIterImpl(std::string DirPath,
1324 : Dir(
std::
move(DirPath)), DirStyle(getExistingStyle(Dir)),
1325 ExternalIter(ExtIter) {
1330 void setCurrentEntry() {
1341 std::error_code increment()
override {
1344 if (!EC && ExternalIter != llvm::vfs::directory_iterator())
1347 CurrentEntry = directory_entry();
1353llvm::ErrorOr<std::string>
1355 return WorkingDirectory;
1365 Path.toVector(AbsolutePath);
1366 if (std::error_code EC = makeAbsolute(AbsolutePath))
1368 WorkingDirectory = std::string(AbsolutePath);
1377 if (makeAbsolute(Path))
1380 return ExternalFS->isLocal(Path, Result);
1395 return WorkingDir.getError();
1397 return makeAbsolute(WorkingDir.get(), Path);
1401RedirectingFileSystem::makeAbsolute(
StringRef WorkingDir,
1407 if (!WorkingDir.
empty() &&
1411 return std::error_code();
1423 std::string
Result = std::string(WorkingDir);
1424 StringRef Dir(Result);
1440 std::error_code &EC) {
1444 EC = makeAbsolute(Path);
1451 isFileNotFound(Result.getError()))
1452 return ExternalFS->dir_begin(Path, EC);
1454 EC = Result.getError();
1462 isFileNotFound(S.
getError(), Result->E))
1463 return ExternalFS->dir_begin(Dir, EC);
1469 if (!S->isDirectory()) {
1477 std::error_code RedirectEC;
1478 if (
auto ExtRedirect = Result->getExternalRedirect()) {
1480 RedirectIter = ExternalFS->dir_begin(*ExtRedirect, RedirectEC);
1482 if (!RE->useExternalName(UseExternalNames)) {
1486 std::string(Path), RedirectIter));
1492 Path, DE->contents_begin(), DE->contents_end(), RedirectEC));
1505 return RedirectIter;
1508 std::error_code ExternalEC;
1519 switch (Redirection) {
1533 std::make_shared<CombiningDirIterImpl>(Iters, EC)};
1540 OverlayFileDir = Dir.
str();
1544 return OverlayFileDir;
1561 std::vector<StringRef> R;
1562 R.reserve(Roots.size());
1563 for (
const auto &Root : Roots)
1564 R.push_back(Root->getName());
1569 unsigned IndentLevel)
const {
1571 OS <<
"RedirectingFileSystem (UseExternalNames: "
1572 << (UseExternalNames ?
"true" :
"false") <<
")\n";
1576 for (
const auto &Root : Roots)
1580 OS <<
"ExternalFS:\n";
1587 unsigned IndentLevel)
const {
1589 OS <<
"'" << E->getName() <<
"'";
1591 switch (E->getKind()) {
1596 for (std::unique_ptr<Entry> &SubEntry :
1598 printEntry(OS, SubEntry.get(), IndentLevel + 1);
1604 OS <<
" -> '" << RE->getExternalContentsPath() <<
"'";
1605 switch (RE->getUseName()) {
1609 OS <<
" (UseExternalName: true)";
1612 OS <<
" (UseExternalName: false)";
1623 Callback(*ExternalFS);
1624 ExternalFS->visitChildFileSystems(Callback);
1640 error(
N,
"expected string");
1643 Result = S->getValue(Storage);
1648 bool parseScalarBool(
yaml::Node *
N,
bool &Result) {
1651 if (!parseScalarString(
N,
Value, Storage))
1654 if (
Value.equals_insensitive(
"true") ||
Value.equals_insensitive(
"on") ||
1655 Value.equals_insensitive(
"yes") ||
Value ==
"1") {
1658 }
else if (
Value.equals_insensitive(
"false") ||
1659 Value.equals_insensitive(
"off") ||
1660 Value.equals_insensitive(
"no") ||
Value ==
"0") {
1665 error(
N,
"expected boolean value");
1669 std::optional<RedirectingFileSystem::RedirectKind>
1673 if (!parseScalarString(
N,
Value, Storage))
1674 return std::nullopt;
1676 if (
Value.equals_insensitive(
"fallthrough")) {
1678 }
else if (
Value.equals_insensitive(
"fallback")) {
1680 }
else if (
Value.equals_insensitive(
"redirect-only")) {
1683 return std::nullopt;
1686 std::optional<RedirectingFileSystem::RootRelativeKind>
1690 if (!parseScalarString(
N,
Value, Storage))
1691 return std::nullopt;
1692 if (
Value.equals_insensitive(
"cwd")) {
1694 }
else if (
Value.equals_insensitive(
"overlay-dir")) {
1697 return std::nullopt;
1707 using KeyStatusPair = std::pair<StringRef, KeyStatus>;
1713 if (It == Keys.
end()) {
1714 error(KeyNode,
"unknown key");
1717 KeyStatus &S = It->second;
1728 for (
const auto &
I : Keys) {
1729 if (
I.second.Required && !
I.second.Seen) {
1730 error(Obj,
Twine(
"missing key '") +
I.first +
"'");
1742 for (
const auto &Root : FS->Roots) {
1743 if (Name == Root->getName()) {
1744 ParentEntry = Root.get();
1750 for (std::unique_ptr<RedirectingFileSystem::Entry> &Content :
1754 if (DirContent && Name == Content->getName())
1760 std::unique_ptr<RedirectingFileSystem::Entry> E =
1761 std::make_unique<RedirectingFileSystem::DirectoryEntry>(
1763 std::chrono::system_clock::now(), 0, 0, 0,
1767 FS->Roots.push_back(std::move(E));
1768 ParentEntry = FS->Roots.back().get();
1773 DE->addContent(std::move(E));
1774 return DE->getLastContent();
1789 NewParentE = lookupOrCreateEntry(FS, Name, NewParentE);
1790 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
1792 uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
1796 assert(NewParentE &&
"Parent entry must exist");
1800 std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
1801 Name, DR->getExternalContentsPath(), DR->getUseName()));
1805 assert(NewParentE &&
"Parent entry must exist");
1808 DE->addContent(std::make_unique<RedirectingFileSystem::FileEntry>(
1809 Name, FE->getExternalContentsPath(), FE->getUseName()));
1815 std::unique_ptr<RedirectingFileSystem::Entry>
1816 parseEntry(yaml::Node *
N, RedirectingFileSystem *FS,
bool IsRootEntry) {
1819 error(
N,
"expected mapping node for file or directory entry");
1823 KeyStatusPair Fields[] = {
1824 KeyStatusPair(
"name",
true),
1825 KeyStatusPair(
"type",
true),
1826 KeyStatusPair(
"contents",
false),
1827 KeyStatusPair(
"external-contents",
false),
1828 KeyStatusPair(
"use-external-name",
false),
1831 DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
1833 enum { CF_NotSet, CF_List, CF_External } ContentsField = CF_NotSet;
1834 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>>
1836 SmallString<256> ExternalContentsPath;
1837 SmallString<256>
Name;
1838 yaml::Node *NameValueNode =
nullptr;
1842 for (
auto &
I : *M) {
1846 SmallString<256> Buffer;
1847 if (!parseScalarString(
I.getKey(),
Key, Buffer))
1850 if (!checkDuplicateOrUnknownKey(
I.getKey(),
Key, Keys))
1854 if (
Key ==
"name") {
1855 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1858 NameValueNode =
I.getValue();
1862 }
else if (
Key ==
"type") {
1863 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1865 if (
Value ==
"file")
1867 else if (
Value ==
"directory")
1869 else if (
Value ==
"directory-remap")
1872 error(
I.getValue(),
"unknown value for 'type'");
1875 }
else if (
Key ==
"contents") {
1876 if (ContentsField != CF_NotSet) {
1878 "entry already has 'contents' or 'external-contents'");
1881 ContentsField = CF_List;
1885 error(
I.getValue(),
"expected array");
1889 for (
auto &
I : *Contents) {
1890 if (std::unique_ptr<RedirectingFileSystem::Entry>
E =
1891 parseEntry(&
I, FS,
false))
1892 EntryArrayContents.push_back(std::move(
E));
1896 }
else if (
Key ==
"external-contents") {
1897 if (ContentsField != CF_NotSet) {
1899 "entry already has 'contents' or 'external-contents'");
1902 ContentsField = CF_External;
1903 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1906 SmallString<256> FullPath;
1907 if (
FS->IsRelativeOverlay) {
1908 FullPath =
FS->getOverlayFileDir();
1910 "External contents prefix directory must exist");
1911 SmallString<256> AbsFullPath =
Value;
1912 if (
FS->makeAbsolute(FullPath, AbsFullPath)) {
1913 error(
N,
"failed to make 'external-contents' absolute");
1916 FullPath = AbsFullPath;
1923 FullPath = canonicalize(FullPath);
1924 ExternalContentsPath = FullPath.
str();
1925 }
else if (
Key ==
"use-external-name") {
1927 if (!parseScalarBool(
I.getValue(), Val))
1940 if (ContentsField == CF_NotSet) {
1941 error(
N,
"missing key 'contents' or 'external-contents'");
1944 if (!checkMissingKeys(
N, Keys))
1950 error(
N,
"'use-external-name' is not supported for 'directory' entries");
1955 ContentsField == CF_List) {
1956 error(
N,
"'contents' is not supported for 'directory-remap' entries");
1965 path_style = sys::path::Style::posix;
1967 sys::path::Style::windows_backslash)) {
1968 path_style = sys::path::Style::windows_backslash;
1974 if (
FS->RootRelative ==
1975 RedirectingFileSystem::RootRelativeKind::OverlayDir) {
1976 StringRef FullPath =
FS->getOverlayFileDir();
1977 assert(!FullPath.
empty() &&
"Overlay file directory must exist");
1978 EC =
FS->makeAbsolute(FullPath, Name);
1979 Name = canonicalize(Name);
1981 EC =
FS->makeAbsolute(Name);
1984 assert(NameValueNode &&
"Name presence should be checked earlier");
1987 "entry with relative path at the root level is not discoverable");
1991 ? sys::path::Style::posix
1992 : sys::path::Style::windows_backslash;
1997 if (path_style == sys::path::Style::windows_backslash &&
1998 getExistingStyle(Name) != sys::path::Style::windows_backslash)
1999 path_style = sys::path::Style::windows_slash;
2003 StringRef Trimmed =
Name;
2005 while (Trimmed.
size() > RootPathLen &&
2007 Trimmed = Trimmed.
slice(0, Trimmed.
size() - 1);
2012 std::unique_ptr<RedirectingFileSystem::Entry>
Result;
2015 Result = std::make_unique<RedirectingFileSystem::FileEntry>(
2016 LastComponent, std::move(ExternalContentsPath), UseExternalName);
2019 Result = std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
2020 LastComponent, std::move(ExternalContentsPath), UseExternalName);
2023 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
2024 LastComponent, std::move(EntryArrayContents),
2038 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> Entries;
2039 Entries.push_back(std::move(Result));
2040 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
2041 *
I, std::move(Entries),
2055 error(Root,
"expected mapping node");
2059 KeyStatusPair Fields[] = {
2060 KeyStatusPair(
"version",
true),
2061 KeyStatusPair(
"case-sensitive",
false),
2062 KeyStatusPair(
"use-external-names",
false),
2063 KeyStatusPair(
"root-relative",
false),
2064 KeyStatusPair(
"overlay-relative",
false),
2065 KeyStatusPair(
"fallthrough",
false),
2066 KeyStatusPair(
"redirecting-with",
false),
2067 KeyStatusPair(
"roots",
true),
2071 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> RootEntries;
2074 for (
auto &
I : *Top) {
2077 if (!parseScalarString(
I.getKey(),
Key, KeyBuffer))
2080 if (!checkDuplicateOrUnknownKey(
I.getKey(),
Key, Keys))
2083 if (
Key ==
"roots") {
2086 error(
I.getValue(),
"expected array");
2090 for (
auto &
I : *Roots) {
2091 if (std::unique_ptr<RedirectingFileSystem::Entry> E =
2092 parseEntry(&
I, FS,
true))
2093 RootEntries.push_back(std::move(E));
2097 }
else if (
Key ==
"version") {
2100 if (!parseScalarString(
I.getValue(), VersionString, Storage))
2104 error(
I.getValue(),
"expected integer");
2108 error(
I.getValue(),
"invalid version number");
2112 error(
I.getValue(),
"version mismatch, expected 0");
2115 }
else if (
Key ==
"case-sensitive") {
2116 if (!parseScalarBool(
I.getValue(), FS->CaseSensitive))
2118 }
else if (
Key ==
"overlay-relative") {
2119 if (!parseScalarBool(
I.getValue(), FS->IsRelativeOverlay))
2121 }
else if (
Key ==
"use-external-names") {
2122 if (!parseScalarBool(
I.getValue(), FS->UseExternalNames))
2124 }
else if (
Key ==
"fallthrough") {
2125 if (Keys[
"redirecting-with"].Seen) {
2127 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2131 bool ShouldFallthrough =
false;
2132 if (!parseScalarBool(
I.getValue(), ShouldFallthrough))
2135 if (ShouldFallthrough) {
2140 }
else if (
Key ==
"redirecting-with") {
2141 if (Keys[
"fallthrough"].Seen) {
2143 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2147 if (
auto Kind = parseRedirectKind(
I.getValue())) {
2148 FS->Redirection = *Kind;
2150 error(
I.getValue(),
"expected valid redirect kind");
2153 }
else if (
Key ==
"root-relative") {
2154 if (
auto Kind = parseRootRelativeKind(
I.getValue())) {
2155 FS->RootRelative = *Kind;
2157 error(
I.getValue(),
"expected valid root-relative kind");
2165 if (Stream.failed())
2168 if (!checkMissingKeys(Top, Keys))
2174 for (
auto &E : RootEntries)
2175 uniqueOverlayTree(FS, E.get());
2181std::unique_ptr<RedirectingFileSystem>
2184 StringRef YAMLFilePath,
void *DiagContext,
2192 if (DI == Stream.
end() || !Root) {
2199 std::unique_ptr<RedirectingFileSystem> FS(
2200 new RedirectingFileSystem(ExternalFS));
2202 if (!YAMLFilePath.
empty()) {
2212 std::error_code EC = FS->makeAbsolute(OverlayAbsDir);
2213 assert(!EC &&
"Overlay dir final path must be absolute");
2215 FS->setOverlayFileDir(OverlayAbsDir);
2218 if (!
P.parse(Root, FS.get()))
2225 ArrayRef<std::pair<std::string, std::string>> RemappedFiles,
2227 std::unique_ptr<RedirectingFileSystem> FS(
2228 new RedirectingFileSystem(ExternalFS));
2229 FS->UseExternalNames = UseExternalNames;
2237 auto EC = ExternalFS->makeAbsolute(From);
2239 assert(!EC &&
"Could not make absolute path");
2257 assert(Parent &&
"File without a directory?");
2259 auto EC = ExternalFS->makeAbsolute(To);
2261 assert(!EC &&
"Could not make absolute path");
2265 auto NewFile = std::make_unique<RedirectingFileSystem::FileEntry>(
2269 ToEntry = NewFile.get();
2271 std::move(NewFile));
2287 getExistingStyle(DRE->getExternalContentsPath()));
2288 ExternalRedirect = std::string(Redirect);
2300std::error_code RedirectingFileSystem::makeCanonicalForLookup(
2302 if (std::error_code EC = makeAbsolute(Path))
2306 canonicalize(
StringRef(Path.data(), Path.size()));
2307 if (CanonicalPath.
empty())
2310 Path.assign(CanonicalPath.
begin(), CanonicalPath.
end());
2317 if (std::error_code EC = makeCanonicalForLookup(CanonicalPath))
2327 for (
const auto &Root : Roots) {
2329 lookupPathImpl(Start, End, Root.get(), Entries);
2333 Result->Parents = std::move(Entries);
2341RedirectingFileSystem::lookupPathImpl(
2347 "Paths should not contain traversal components");
2352 if (!FromName.
empty()) {
2353 if (!pathComponentMatches(*Start, FromName))
2360 return LookupResult(From, Start, End);
2368 return LookupResult(From, Start, End);
2371 for (
const std::unique_ptr<RedirectingFileSystem::Entry> &DirEntry :
2375 lookupPathImpl(Start, End, DirEntry.get(), Entries);
2385 bool UseExternalNames,
2390 return ExternalStatus;
2392 Status S = ExternalStatus;
2393 if (!UseExternalNames)
2400ErrorOr<Status> RedirectingFileSystem::status(
2401 const Twine &LookupPath,
const Twine &OriginalPath,
2402 const RedirectingFileSystem::LookupResult &Result) {
2403 if (std::optional<StringRef> ExtRedirect =
Result.getExternalRedirect()) {
2404 SmallString<256> RemappedPath((*ExtRedirect).str());
2405 if (std::error_code EC = makeAbsolute(RemappedPath))
2408 ErrorOr<Status> S = ExternalFS->status(RemappedPath);
2414 RE->useExternalName(UseExternalNames), *S);
2422RedirectingFileSystem::getExternalStatus(
const Twine &LookupPath,
2423 const Twine &OriginalPath)
const {
2424 auto Result = ExternalFS->status(LookupPath);
2428 if (!Result ||
Result->ExposesExternalVFSPath)
2437 if (std::error_code EC = makeAbsolute(Path))
2453 isFileNotFound(Result.getError()))
2454 return getExternalStatus(Path, OriginalPath);
2455 return Result.getError();
2460 isFileNotFound(S.
getError(), Result->E)) {
2464 return getExternalStatus(Path, OriginalPath);
2474 if (makeAbsolute(Path))
2480 if (ExternalFS->exists(Path))
2489 isFileNotFound(Result.getError()))
2490 return ExternalFS->exists(Path);
2494 std::optional<StringRef> ExtRedirect = Result->getExternalRedirect();
2501 if (makeAbsolute(RemappedPath))
2504 if (ExternalFS->exists(RemappedPath))
2511 return ExternalFS->exists(Path);
2520class FileWithFixedStatus :
public File {
2521 std::unique_ptr<File> InnerFile;
2525 FileWithFixedStatus(std::unique_ptr<File> InnerFile,
Status S)
2531 getBuffer(
const Twine &Name, int64_t FileSize,
bool RequiresNullTerminator,
2532 bool IsVolatile)
override {
2533 return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
2537 std::error_code close()
override {
return InnerFile->close(); }
2539 void setPath(
const Twine &Path)
override { S = S.
copyWithNewName(S, Path); }
2544ErrorOr<std::unique_ptr<File>>
2548 if (!Result || (*Result)->status()->ExposesExternalVFSPath)
2552 auto Name =
F->get()->getName();
2553 if (Name && Name.get() !=
P.str())
2554 F->get()->setPath(
P);
2563 if (std::error_code EC = makeAbsolute(Path))
2579 isFileNotFound(Result.getError()))
2581 return Result.getError();
2584 if (!Result->getExternalRedirect())
2587 StringRef ExtRedirect = *Result->getExternalRedirect();
2589 if (std::error_code EC = makeAbsolute(RemappedPath))
2596 if (!ExternalFile) {
2598 isFileNotFound(ExternalFile.getError(), Result->E)) {
2604 return ExternalFile;
2607 auto ExternalStatus = (*ExternalFile)->status();
2608 if (!ExternalStatus)
2609 return ExternalStatus.getError();
2614 OriginalPath, RE->useExternalName(UseExternalNames), *ExternalStatus);
2615 return std::unique_ptr<File>(
2616 std::make_unique<FileWithFixedStatus>(std::move(*ExternalFile), S));
2625 if (std::error_code EC = makeAbsolute(Path))
2631 std::error_code EC = ExternalFS->getRealPath(Path, Output);
2641 isFileNotFound(Result.getError()))
2642 return ExternalFS->getRealPath(Path, Output);
2643 return Result.getError();
2648 if (
auto ExtRedirect = Result->getExternalRedirect()) {
2649 auto P = ExternalFS->getRealPath(*ExtRedirect, Output);
2651 isFileNotFound(
P, Result->E)) {
2655 return ExternalFS->getRealPath(Path, Output);
2663 Result->getPath(Output);
2669std::unique_ptr<FileSystem>
2672 StringRef YAMLFilePath,
void *DiagContext,
2675 YAMLFilePath, DiagContext,
2676 std::move(ExternalFS));
2685 assert(DE &&
"Must be a directory");
2686 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
2688 Path.push_back(SubEntry->getName());
2697 assert(DR &&
"Must be a directory remap");
2699 for (
auto &Comp : Path)
2708 assert(FE &&
"Must be a file");
2710 for (
auto &Comp : Path)
2726 static std::atomic<unsigned> UID;
2727 unsigned ID = ++UID;
2730 return UniqueID(std::numeric_limits<uint64_t>::max(),
ID);
2738 Mappings.emplace_back(VirtualPath, RealPath, IsDirectory);
2742 addEntry(VirtualPath, RealPath,
false);
2747 addEntry(VirtualPath, RealPath,
true);
2756 unsigned getDirIndent() {
return 4 * DirStack.
size(); }
2757 unsigned getFileIndent() {
return 4 * (DirStack.
size() + 1); }
2761 void endDirectory();
2768 std::optional<bool> UseExternalNames,
2769 std::optional<bool> IsCaseSensitive,
2770 std::optional<bool> IsOverlayRelative, StringRef OverlayDir);
2775bool JSONWriter::containedIn(StringRef Parent, StringRef Path) {
2776 using namespace llvm::sys;
2781 IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
2782 if (*IParent != *IChild)
2786 return IParent == EParent;
2789StringRef JSONWriter::containedPart(StringRef Parent, StringRef Path) {
2791 assert(containedIn(Parent, Path));
2792 return Path.substr(Parent.
size() + 1);
2795void JSONWriter::startDirectory(StringRef Path) {
2797 DirStack.
empty() ?
Path : containedPart(DirStack.
back(), Path);
2799 unsigned Indent = getDirIndent();
2800 OS.
indent(Indent) <<
"{\n";
2801 OS.
indent(Indent + 2) <<
"'type': 'directory',\n";
2803 OS.
indent(Indent + 2) <<
"'contents': [\n";
2806void JSONWriter::endDirectory() {
2807 unsigned Indent = getDirIndent();
2808 OS.
indent(Indent + 2) <<
"]\n";
2809 OS.
indent(Indent) <<
"}";
2814void JSONWriter::writeEntry(StringRef VPath, StringRef RPath) {
2815 unsigned Indent = getFileIndent();
2816 OS.
indent(Indent) <<
"{\n";
2817 OS.
indent(Indent + 2) <<
"'type': 'file',\n";
2819 OS.
indent(Indent + 2) <<
"'external-contents': \""
2821 OS.
indent(Indent) <<
"}";
2825 std::optional<bool> UseExternalNames,
2826 std::optional<bool> IsCaseSensitive,
2827 std::optional<bool> IsOverlayRelative,
2829 using namespace llvm::sys;
2833 if (IsCaseSensitive)
2834 OS <<
" 'case-sensitive': '" << (*IsCaseSensitive ?
"true" :
"false")
2836 if (UseExternalNames)
2837 OS <<
" 'use-external-names': '" << (*UseExternalNames ?
"true" :
"false")
2839 bool UseOverlayRelative =
false;
2840 if (IsOverlayRelative) {
2841 UseOverlayRelative = *IsOverlayRelative;
2842 OS <<
" 'overlay-relative': '" << (UseOverlayRelative ?
"true" :
"false")
2845 OS <<
" 'roots': [\n";
2847 if (!Entries.
empty()) {
2854 StringRef RPath =
Entry.RPath;
2855 if (UseOverlayRelative) {
2857 "Overlay dir must be contained in RPath");
2861 bool IsCurrentDirEmpty =
true;
2862 if (!
Entry.IsDirectory) {
2864 IsCurrentDirEmpty =
false;
2870 if (Dir == DirStack.
back()) {
2871 if (!IsCurrentDirEmpty) {
2875 bool IsDirPoppedFromStack =
false;
2876 while (!DirStack.
empty() && !containedIn(DirStack.
back(), Dir)) {
2879 IsDirPoppedFromStack =
true;
2881 if (IsDirPoppedFromStack || !IsCurrentDirEmpty) {
2884 startDirectory(Dir);
2885 IsCurrentDirEmpty =
true;
2887 StringRef RPath =
Entry.RPath;
2888 if (UseOverlayRelative) {
2890 "Overlay dir must be contained in RPath");
2893 if (!
Entry.IsDirectory) {
2895 IsCurrentDirEmpty =
false;
2899 while (!DirStack.
empty()) {
2912 return LHS.VPath < RHS.VPath;
2915 JSONWriter(OS).
write(Mappings, UseExternalNames, IsCaseSensitive,
2916 IsOverlayRelative, OverlayDir);
2924 State = std::make_shared<detail::RecDirIterState>();
2925 State->Stack.push_back(
I);
2931 assert(FS && State && !State->Stack.empty() &&
"incrementing past end");
2932 assert(!State->Stack.back()->path().empty() &&
"non-canonical end iterator");
2935 if (State->HasNoPushRequest)
2936 State->HasNoPushRequest =
false;
2940 FS->dir_begin(State->Stack.back()->path(), EC);
2942 State->Stack.push_back(
I);
2948 while (!State->Stack.empty() && State->Stack.back().increment(EC) == End)
2949 State->Stack.pop_back();
2951 if (State->Stack.empty())
2958 unsigned IndentLevel)
const {
2959 printIndent(OS, IndentLevel);
2960 OS <<
"TracingFileSystem\n";
2961 if (
Type == PrintType::Summary)
2964 printIndent(OS, IndentLevel);
2966 printIndent(OS, IndentLevel);
2968 printIndent(OS, IndentLevel);
2970 printIndent(OS, IndentLevel);
2972 printIndent(OS, IndentLevel);
2974 printIndent(OS, IndentLevel);
2977 if (
Type == PrintType::Contents)
2978 Type = PrintType::Summary;
2979 getUnderlyingFS().
print(OS,
Type, IndentLevel + 1);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file defines the DenseMap class.
Provides ErrorOr<T> smart pointer.
static void makeAbsolute(vfs::FileSystem &VFS, SmallVectorImpl< char > &Path)
Make Path absolute.
This file defines the RefCountedBase, ThreadSafeRefCountedBase, and IntrusiveRefCntPtr classes.
static void printImpl(const MCAsmInfo &MAI, raw_ostream &OS, const MCSpecifierExpr &Expr)
static StringRef getName(Value *V)
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)
LLVM_ABI const file_t kInvalidFile
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.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
const T & front() const
front - Get the first element.
bool empty() const
empty - Check if the array is empty.
ArrayRef< T > slice(size_t N, size_t M) const
slice(n, m) - Chop off the first N elements of the array, and keep M elements in the array.
iterator find(const_arg_type_t< KeyT > Val)
Represents either an error or a value T.
std::error_code getError() const
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.
LLVM_ABI void PrintMessage(raw_ostream &OS, SMLoc Loc, DiagKind Kind, const Twine &Msg, ArrayRef< SMRange > Ranges={}, ArrayRef< SMFixIt > FixIts={}, bool ShowColors=true) const
Emit a message about the specified location with the specified string.
void(*)(const SMDiagnostic &, void *Context) DiagHandlerTy
Clients that want to handle their own diagnostics in a custom way can register a function pointer+con...
void setDiagHandler(DiagHandlerTy DH, void *Ctx=nullptr)
Specify a diagnostic handler to be invoked every time PrintMessage is called.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
StringRef - Represent a constant reference to a string, i.e.
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
std::string str() const
str - Get the contents as an std::string.
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
constexpr bool empty() const
empty - Check if the string is empty.
char back() const
back - Get the last character in the string.
StringRef slice(size_t Start, size_t End) const
Return a reference to the substring from [Start, End).
constexpr size_t size() const
size - Get the string size.
StringSet - A wrapper for StringMap that provides set-like functionality.
std::pair< typename Base::iterator, bool > insert(StringRef key)
Target - Wrapper for Target specific information.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
LLVM_ABI std::string str() const
Return the twine contents as a std::string.
LLVM_ABI 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_ABI void print(raw_ostream &O, bool IsForDebug=false, bool NoDetails=false) const
Print the current type.
LLVM Value Representation.
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 & write(unsigned char C)
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.
llvm::function_ref< void(FileSystem &)> VisitCallbackTy
virtual llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const =0
Get the working directory of this file system.
virtual bool exists(const Twine &Path)
Check whether Path exists.
virtual llvm::ErrorOr< std::unique_ptr< File > > openFileForReadBinary(const Twine &Path)
Get a File object for the binary file at Path, if one exists.
virtual std::error_code makeAbsolute(SmallVectorImpl< char > &Path) const
Make Path an absolute path.
virtual llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path)=0
Get a File object for the text file at Path, if one exists.
virtual std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output)
Gets real path of Path e.g.
void printIndent(raw_ostream &OS, unsigned IndentLevel) const
LLVM_DUMP_METHOD void dump() const
void print(raw_ostream &OS, PrintType Type=PrintType::Contents, unsigned IndentLevel=0) const
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getBufferForFile(const Twine &Name, int64_t FileSize=-1, bool RequiresNullTerminator=true, bool IsVolatile=false, bool IsText=true)
This is a convenience method that opens a file, gets its content and then closes the file.
llvm::ErrorOr< bool > equivalent(const Twine &A, const Twine &B)
virtual std::error_code isLocal(const Twine &Path, bool &Result)
Is the file mounted on a local filesystem?
virtual llvm::ErrorOr< Status > status(const Twine &Path)=0
Get the status of the entry at Path, if one exists.
static ErrorOr< std::unique_ptr< File > > getWithPath(ErrorOr< std::unique_ptr< File > > Result, const Twine &P)
virtual ~File()
Destroy the file after closing it (if open).
Adaptor from InMemoryDir::iterator to directory_iterator.
DirIterator(const InMemoryFileSystem *FS, const detail::InMemoryDirectory &Dir, std::string RequestedDirName)
std::error_code increment() override
Sets CurrentEntry to the next entry in the directory on success, to directory_entry() at end,...
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
friend class RedirectingFileSystemParser
std::vector< llvm::StringRef > getRoots() const
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override
Get a directory_iterator for Dir.
ErrorOr< LookupResult > lookupPath(StringRef Path) const
Looks up Path in Roots and returns a LookupResult giving the matched entry and, if the entry was a Fi...
RedirectKind
The type of redirection to perform.
@ Fallthrough
Lookup the redirected path first (ie.
@ Fallback
Lookup the provided path first and if that fails, "fallback" to a lookup of the redirected path.
@ RedirectOnly
Only lookup the redirected path, do not lookup the originally provided path.
void setFallthrough(bool Fallthrough)
Sets the redirection kind to Fallthrough if true or RedirectOnly otherwise.
void visitChildFileSystems(VisitCallbackTy Callback) override
std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) override
Gets real path of Path e.g.
ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override
Get a File object for the text file at Path, if one exists.
void setOverlayFileDir(StringRef PrefixDir)
llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override
Get the working directory of this file system.
void setRedirection(RedirectingFileSystem::RedirectKind Kind)
std::error_code isLocal(const Twine &Path, bool &Result) override
Is the file mounted on a local filesystem?
static std::unique_ptr< RedirectingFileSystem > create(std::unique_ptr< MemoryBuffer > Buffer, SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, void *DiagContext, IntrusiveRefCntPtr< FileSystem > ExternalFS)
Parses Buffer, which is expected to be in YAML format and returns a virtual file system representing ...
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
Set the working directory.
StringRef getOverlayFileDir() const
void printEntry(raw_ostream &OS, Entry *E, unsigned IndentLevel=0) const
The result of a status operation.
llvm::sys::fs::UniqueID getUniqueID() const
LLVM_ABI bool equivalent(const Status &Other) const
static LLVM_ABI Status copyWithNewName(const Status &In, const Twine &NewName)
Get a copy of a Status with a different name.
LLVM_ABI bool isStatusKnown() const
LLVM_ABI bool exists() const
bool ExposesExternalVFSPath
Whether this entity has an external path different from the virtual path, and the external path is ex...
uint32_t getGroup() const
static LLVM_ABI Status copyWithNewSize(const Status &In, uint64_t NewSize)
Get a copy of a Status with a different size.
LLVM_ABI bool isOther() const
LLVM_ABI bool isSymlink() const
llvm::sys::TimePoint getLastModificationTime() const
llvm::sys::fs::file_type getType() const
LLVM_ABI bool isRegularFile() const
LLVM_ABI bool isDirectory() const
std::size_t NumOpenFileForReadCalls
std::size_t NumIsLocalCalls
std::size_t NumExistsCalls
void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override
std::size_t NumDirBeginCalls
std::size_t NumGetRealPathCalls
std::size_t NumStatusCalls
LLVM_ABI void addFileMapping(StringRef VirtualPath, StringRef RealPath)
LLVM_ABI void write(llvm::raw_ostream &OS)
LLVM_ABI 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.
LLVM_ABI 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.
LLVM_ABI document_iterator end()
LLVM_ABI document_iterator begin()
LLVM_ABI 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.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ Resolved
Queried, materialization begun.
LLVM_ABI std::error_code closeFile(file_t &F)
Close the file object.
LLVM_ABI const file_t kInvalidFile
@ OF_Text
The file should be opened in text mode on platforms like z/OS that make this distinction.
file_type
An enumeration for the file system's view of the type.
LLVM_ABI std::error_code set_current_path(const Twine &path)
Set the current path.
LLVM_ABI std::error_code real_path(const Twine &path, SmallVectorImpl< char > &output, bool expand_tilde=false)
Collapse all .
LLVM_ABI 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.
LLVM_ABI std::error_code current_path(SmallVectorImpl< char > &result)
Get the current path.
LLVM_ABI std::error_code status(const Twine &path, file_status &result, bool follow=true)
Get file status as if by POSIX stat().
LLVM_ABI std::error_code is_local(const Twine &path, bool &result)
Is the file mounted on a local filesystem?
LLVM_ABI 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.
LLVM_ABI bool is_directory(const basic_file_status &status)
Does status represent a directory?
LLVM_ABI StringRef get_separator(Style style=Style::native)
Return the preferred separator for this platform.
LLVM_ABI StringRef root_path(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get root path.
LLVM_ABI const_iterator begin(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get begin iterator over path.
LLVM_ABI bool remove_dots(SmallVectorImpl< char > &path, bool remove_dot_dot=false, Style style=Style::native)
In-place remove any '.
LLVM_ABI StringRef parent_path(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get parent path.
LLVM_ABI void make_absolute(const Twine ¤t_directory, SmallVectorImpl< char > &path)
Make path an absolute path.
LLVM_ABI StringRef filename(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get filename.
LLVM_ABI StringRef remove_leading_dotslash(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Remove redundant leading "./" pieces and consecutive separators.
LLVM_ABI bool is_absolute(const Twine &path, Style style=Style::native)
Is path absolute?
LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
LLVM_ABI reverse_iterator rend(StringRef path LLVM_LIFETIME_BOUND)
Get reverse end iterator over path.
LLVM_ABI reverse_iterator rbegin(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get reverse begin iterator over path.
LLVM_ABI const_iterator end(StringRef path LLVM_LIFETIME_BOUND)
Get end iterator over path.
LLVM_ABI bool is_separator(char value, Style style=Style::native)
Check whether the given char is a path separator on the host OS.
std::chrono::time_point< std::chrono::system_clock, D > TimePoint
A time point on the system clock.
TimePoint< std::chrono::seconds > toTimePoint(std::time_t T)
Convert a std::time_t to a TimePoint.
std::error_code make_error_code(OutputErrorCode EV)
void collectVFSEntries(RedirectingFileSystem &VFS, SmallVectorImpl< YAMLVFSEntry > &CollectedEntries)
Collect all pairs of <virtual path, real path> entries from the VFS.
LLVM_ABI 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_ABI llvm::sys::fs::UniqueID getNextVirtualUniqueID()
Get a globally unique ID for a virtual file or directory.
static sys::fs::UniqueID getUniqueID(hash_code Hash)
LLVM_ABI IntrusiveRefCntPtr< FileSystem > getRealFileSystem()
Gets an vfs::FileSystem for the 'real' file system, as seen by the operating system.
LLVM_ABI 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.
static sys::fs::UniqueID getDirectoryID(sys::fs::UniqueID Parent, llvm::StringRef Name)
LLVM_ABI 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.
FunctionAddr VTableAddr Value
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
IntrusiveRefCntPtr< T > makeIntrusiveRefCnt(Args &&...A)
Factory function for creating intrusive ref counted pointers.
@ no_such_file_or_directory
@ operation_not_permitted
FunctionAddr VTableAddr uintptr_t uintptr_t Version
auto reverse(ContainerTy &&C)
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
LLVM_ABI Error write(MCStreamer &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue)
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
ArrayRef(const T &OneElt) -> ArrayRef< T >
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
LLVM_ABI 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.
Entry * E
The entry the looked-up path corresponds to.
LLVM_ABI LookupResult(Entry *E, sys::path::const_iterator Start, sys::path::const_iterator End)
LLVM_ABI void getPath(llvm::SmallVectorImpl< char > &Path) const
Get the (canonical) path of the found entry.
llvm::SmallVector< Entry *, 32 > Parents
Chain of parent directory entries for E.
An interface for virtual file systems to provide an iterator over the (non-recursive) contents of a d...
directory_entry CurrentEntry
LLVM_ABI Status makeStatus() const
llvm::sys::fs::file_type Type
std::unique_ptr< llvm::MemoryBuffer > Buffer
llvm::sys::fs::perms Perms
llvm::sys::fs::UniqueID DirUID