24#include "llvm/Config/llvm-config.h"
50#include <system_error>
72 : Name(Name.str()), UID(UID), MTime(MTime), User(User), Group(Group),
73 Size(Size), Type(Type), Perms(Perms) {}
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,
126 return (*F)->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile);
135 return WorkingDir.getError();
158 return StatusA.getError();
161 return StatusB.getError();
162 return StatusA->equivalent(*StatusB);
165#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
171 return Component ==
".." || Component ==
".";
191class RealFile :
public File {
192 friend class RealFileSystem;
196 std::string RealName;
198 RealFile(
file_t RawFD, StringRef NewName, StringRef NewRealPathName)
199 : FD(RawFD), S(NewName, {}, {}, {}, {}, {},
201 RealName(NewRealPathName.str()) {
206 ~RealFile()
override;
208 ErrorOr<Status>
status()
override;
209 ErrorOr<std::string>
getName()
override;
210 ErrorOr<std::unique_ptr<MemoryBuffer>> getBuffer(
const Twine &Name,
212 bool RequiresNullTerminator,
213 bool IsVolatile)
override;
214 std::error_code close()
override;
215 void setPath(
const Twine &Path)
override;
220RealFile::~RealFile() { close(); }
222ErrorOr<Status> RealFile::status() {
226 if (!S.isStatusKnown()) {
227 file_status RealStatus;
235ErrorOr<std::string> RealFile::getName() {
236 return RealName.empty() ? S.getName().str() : RealName;
239ErrorOr<std::unique_ptr<MemoryBuffer>>
240RealFile::getBuffer(
const Twine &Name, int64_t FileSize,
241 bool RequiresNullTerminator,
bool IsVolatile) {
249std::error_code RealFile::close() {
257void RealFile::setPath(
const Twine &Path) {
260 RealName =
Path.str();
275class RealFileSystem :
public FileSystem {
277 explicit RealFileSystem(
bool LinkCWDToProcess) {
278 if (!LinkCWDToProcess) {
279 SmallString<128> PWD, RealPWD;
283 WD = WorkingDirectory{PWD, PWD};
285 WD = WorkingDirectory{PWD, RealPWD};
289 ErrorOr<Status>
status(
const Twine &Path)
override;
290 ErrorOr<std::unique_ptr<File>>
openFileForRead(
const Twine &Path)
override;
291 ErrorOr<std::unique_ptr<File>>
292 openFileForReadBinary(
const Twine &Path)
override;
293 directory_iterator dir_begin(
const Twine &Dir, std::error_code &EC)
override;
295 llvm::ErrorOr<std::string> getCurrentWorkingDirectory()
const override;
296 std::error_code setCurrentWorkingDirectory(
const Twine &Path)
override;
297 std::error_code isLocal(
const Twine &Path,
bool &Result)
override;
298 std::error_code getRealPath(
const Twine &Path,
299 SmallVectorImpl<char> &Output)
override;
303 unsigned IndentLevel)
const override;
308 Twine adjustPath(
const Twine &Path, SmallVectorImpl<char> &Storage)
const {
311 Path.toVector(Storage);
316 ErrorOr<std::unique_ptr<File>>
318 SmallString<256> RealName, Storage;
320 adjustPath(Name, Storage), Flags, &RealName);
323 return std::unique_ptr<File>(
324 new RealFile(*FDOrErr,
Name.str(), RealName.
str()));
327 struct WorkingDirectory {
329 SmallString<128> Specified;
333 std::optional<llvm::ErrorOr<WorkingDirectory>> WD;
338ErrorOr<Status> RealFileSystem::status(
const Twine &Path) {
341 SmallString<256> Storage;
342 sys::fs::file_status RealStatus;
343 if (std::error_code EC =
349ErrorOr<std::unique_ptr<File>>
350RealFileSystem::openFileForRead(
const Twine &Name) {
356ErrorOr<std::unique_ptr<File>>
357RealFileSystem::openFileForReadBinary(
const Twine &Name) {
363llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory()
const {
367 return std::string(WD->get().Specified);
369 return WD->getError();
371 SmallString<128> Dir;
374 return std::string(Dir);
377std::error_code RealFileSystem::setCurrentWorkingDirectory(
const Twine &Path) {
384 adjustPath(Path, Storage).toVector(Absolute);
389 return std::make_error_code(std::errc::not_a_directory);
393 return std::error_code();
396std::error_code RealFileSystem::isLocal(
const Twine &Path,
bool &Result) {
399 SmallString<256> Storage;
403std::error_code RealFileSystem::getRealPath(
const Twine &Path,
404 SmallVectorImpl<char> &Output) {
407 SmallString<256> Storage;
411void RealFileSystem::printImpl(raw_ostream &OS, PrintType
Type,
412 unsigned IndentLevel)
const {
413 printIndent(OS, IndentLevel);
414 OS <<
"RealFileSystem using ";
433 return std::make_unique<RealFileSystem>(
false);
442 RealFSDirIter(
const Twine &Path, std::error_code &EC) {
450 std::error_code increment()
override {
465 std::error_code &EC) {
468 SmallString<128> Storage;
470 std::make_shared<RealFSDirIter>(adjustPath(Dir, Storage), EC));
478 FSList.push_back(std::move(BaseFS));
482 FSList.push_back(FS);
501 if ((*I)->exists(Path))
511 auto Result = (*I)->openFileForRead(Path);
521 return FSList.front()->getCurrentWorkingDirectory();
526 for (
auto &FS : FSList)
527 if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))
533 for (
auto &FS : FSList)
534 if (FS->exists(Path))
535 return FS->isLocal(Path, Result);
541 for (
const auto &FS : FSList)
542 if (FS->exists(Path))
543 return FS->getRealPath(Path, Output);
550 FS->visitChildFileSystems(Callback);
555 unsigned IndentLevel)
const {
556 printIndent(OS, IndentLevel);
557 OS <<
"OverlayFileSystem\n";
558 if (
Type == PrintType::Summary)
561 if (
Type == PrintType::Contents)
562 Type = PrintType::Summary;
564 FS->print(OS,
Type, IndentLevel + 1);
584 std::error_code incrementIter(
bool IsFirstTime) {
585 while (!IterList.
empty()) {
586 CurrentDirIter = IterList.
back();
597 std::error_code incrementDirIter(
bool IsFirstTime) {
598 assert((IsFirstTime || CurrentDirIter != directory_iterator()) &&
599 "incrementing past end");
603 if (!EC && CurrentDirIter == directory_iterator())
604 EC = incrementIter(IsFirstTime);
608 std::error_code incrementImpl(
bool IsFirstTime) {
610 std::error_code
EC = incrementDirIter(IsFirstTime);
611 if (EC || CurrentDirIter == directory_iterator()) {
612 CurrentEntry = directory_entry();
615 CurrentEntry = *CurrentDirIter;
617 if (SeenNames.
insert(Name).second)
625 std::error_code &EC) {
626 for (
const auto &FS : FileSystems) {
628 directory_iterator Iter =
FS->dir_begin(Dir, FEC);
629 if (FEC && FEC != errc::no_such_file_or_directory) {
636 EC = incrementImpl(
true);
641 : IterList(DirIters) {
642 EC = incrementImpl(
true);
645 std::error_code increment()
override {
return incrementImpl(
false); }
651 std::error_code &EC) {
653 std::make_shared<CombiningDirIterImpl>(FSList, Dir.
str(), EC));
659void ProxyFileSystem::anchor() {}
677 std::string FileName;
681 : Kind(Kind), FileName(
std::string(
llvm::
sys::
path::filename(FileName))) {
693 virtual std::string
toString(
unsigned Indent)
const = 0;
698 std::unique_ptr<llvm::MemoryBuffer> Buffer;
710 std::string
toString(
unsigned Indent)
const override {
711 return (std::string(Indent,
' ') + Stat.getName() +
"\n").str();
721class InMemoryHardLink :
public InMemoryNode {
722 const InMemoryFile &ResolvedFile;
725 InMemoryHardLink(
StringRef Path,
const InMemoryFile &ResolvedFile)
726 : InMemoryNode(Path,
IME_HardLink), ResolvedFile(ResolvedFile) {}
727 const InMemoryFile &getResolvedFile()
const {
return ResolvedFile; }
729 Status getStatus(
const Twine &RequestedName)
const override {
730 return ResolvedFile.getStatus(RequestedName);
733 std::string
toString(
unsigned Indent)
const override {
734 return std::string(Indent,
' ') +
"HardLink to -> " +
735 ResolvedFile.toString(0);
738 static bool classof(
const InMemoryNode *
N) {
744 std::string TargetPath;
748 InMemorySymbolicLink(StringRef Path, StringRef TargetPath, Status Stat)
752 std::string
toString(
unsigned Indent)
const override {
753 return std::string(Indent,
' ') +
"SymbolicLink to -> " + TargetPath;
756 Status getStatus(
const Twine &RequestedName)
const override {
760 StringRef getTargetPath()
const {
return TargetPath; }
762 static bool classof(
const InMemoryNode *
N) {
770class InMemoryFileAdaptor :
public File {
771 const InMemoryFile &Node;
773 std::string RequestedName;
776 explicit InMemoryFileAdaptor(
const InMemoryFile &Node,
777 std::string RequestedName)
778 : Node(Node), RequestedName(std::
move(RequestedName)) {}
780 llvm::ErrorOr<Status>
status()
override {
781 return Node.getStatus(RequestedName);
784 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
785 getBuffer(
const Twine &Name, int64_t FileSize,
bool RequiresNullTerminator,
786 bool IsVolatile)
override {
787 llvm::MemoryBuffer *Buf = Node.getBuffer();
792 std::error_code close()
override {
return {}; }
794 void setPath(
const Twine &Path)
override { RequestedName =
Path.str(); }
800 std::map<std::string, std::unique_ptr<InMemoryNode>, std::less<>> Entries;
816 auto I = Entries.find(Name);
817 if (
I != Entries.end())
818 return I->second.get();
823 return Entries.emplace(Name, std::move(Child)).first->second.get();
831 std::string
toString(
unsigned Indent)
const override {
833 (std::string(Indent,
' ') + Stat.getName() +
"\n").str();
834 for (
const auto &Entry : Entries)
835 Result += Entry.second->toString(Indent + 2);
874 : Root(new
detail::InMemoryDirectory(
879 UseNormalizedPaths(UseNormalizedPaths) {}
884 return Root->toString(0);
887bool InMemoryFileSystem::addFile(
const Twine &
P, time_t ModificationTime,
888 std::unique_ptr<llvm::MemoryBuffer> Buffer,
889 std::optional<uint32_t>
User,
890 std::optional<uint32_t> Group,
891 std::optional<llvm::sys::fs::file_type>
Type,
892 std::optional<llvm::sys::fs::perms> Perms,
893 MakeNodeFn MakeNode) {
910 const auto ResolvedUser =
User.value_or(0);
911 const auto ResolvedGroup = Group.value_or(0);
928 StringRef(Path.str().begin(), Name.end() - Path.str().begin()),
933 Name, std::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
944 MakeNode({Dir->
getUniqueID(), Path, Name, ModificationTime,
945 std::move(Buffer), ResolvedUser, ResolvedGroup,
946 ResolvedType, ResolvedPerms}));
954 "Must be either file, hardlink or directory!");
958 return Link->getResolvedFile().getBuffer()->getBuffer() ==
965bool InMemoryFileSystem::addFile(
const Twine &
P, time_t ModificationTime,
966 std::unique_ptr<llvm::MemoryBuffer> Buffer,
967 std::optional<uint32_t>
User,
968 std::optional<uint32_t> Group,
969 std::optional<llvm::sys::fs::file_type>
Type,
970 std::optional<llvm::sys::fs::perms> Perms) {
971 return addFile(
P, ModificationTime, std::move(Buffer),
User, Group,
Type,
974 -> std::unique_ptr<detail::InMemoryNode> {
977 return std::make_unique<detail::InMemoryDirectory>(Stat);
978 return std::make_unique<detail::InMemoryFile>(
979 Stat, std::move(NNI.
Buffer));
984 const Twine &
P, time_t ModificationTime,
986 std::optional<uint32_t> Group, std::optional<llvm::sys::fs::file_type>
Type,
987 std::optional<llvm::sys::fs::perms> Perms) {
989 std::move(
User), std::move(Group), std::move(
Type),
992 -> std::unique_ptr<detail::InMemoryNode> {
995 return std::make_unique<detail::InMemoryDirectory>(Stat);
996 return std::make_unique<detail::InMemoryFile>(
997 Stat, std::move(NNI.
Buffer));
1002InMemoryFileSystem::lookupNode(
const Twine &
P,
bool FollowFinalSymlink,
1003 size_t SymlinkDepth)
const {
1029 if (
I == E && !FollowFinalSymlink)
1044 lookupNode(TargetPath,
true, SymlinkDepth + 1);
1072 return detail::NamedNodeOrError(Path, Dir);
1078 auto NewLinkNode = lookupNode(NewLink,
false);
1082 auto TargetNode = lookupNode(
Target,
true);
1087 return addFile(NewLink, 0,
nullptr, std::nullopt, std::nullopt, std::nullopt,
1089 return std::make_unique<detail::InMemoryHardLink>(
1097 std::optional<uint32_t>
User, std::optional<uint32_t> Group,
1098 std::optional<llvm::sys::fs::perms> Perms) {
1099 auto NewLinkNode = lookupNode(NewLink,
false);
1105 Target.toVector(TargetStr);
1107 return addFile(NewLinkStr, ModificationTime,
nullptr,
User, Group,
1110 return std::make_unique<detail::InMemorySymbolicLink>(
1116 auto Node = lookupNode(Path,
true);
1118 return (*Node)->getStatus(Path);
1119 return Node.getError();
1124 auto Node = lookupNode(Path,
true);
1126 return Node.getError();
1131 return std::unique_ptr<File>(
1132 new detail::InMemoryFileAdaptor(*
F, Path.str()));
1143 std::string RequestedDirName;
1145 void setCurrentEntry() {
1150 switch (I->second->getKind()) {
1159 if (
auto SymlinkTarget =
1160 FS->lookupNode(Path,
true)) {
1161 Path = SymlinkTarget.getName();
1162 Type = (*SymlinkTarget)->getStatus(Path).getType();
1179 std::string RequestedDirName)
1180 : FS(FS), I(Dir.begin()), E(Dir.end()),
1181 RequestedDirName(
std::
move(RequestedDirName)) {
1193 std::error_code &EC) {
1194 auto Node = lookupNode(Dir,
true);
1196 EC =
Node.getError();
1202 std::make_shared<DirIterator>(
this, *DirNode, Dir.
str()));
1221 WorkingDirectory = std::string(Path);
1228 if (!CWD || CWD->empty())
1230 Path.toVector(Output);
1243 unsigned IndentLevel)
const {
1244 printIndent(OS, IndentLevel);
1245 OS <<
"InMemoryFileSystem\n";
1260 const size_t n = Path.find_first_of(
"/\\");
1262 if (n !=
static_cast<size_t>(-1))
1282static bool isFileNotFound(std::error_code EC,
1294 assert(ExternalFS &&
"RedirectingFileSystem requires an external FS");
1295 if (
auto ExternalWorkingDirectory = ExternalFS->getCurrentWorkingDirectory())
1296 WorkingDirectory = *ExternalWorkingDirectory;
1306 std::error_code incrementImpl(
bool IsFirstTime) {
1307 assert((IsFirstTime || Current != End) &&
"cannot iterate past end");
1310 if (Current != End) {
1314 switch ((*Current)->getKind()) {
1335 : Dir(Path.str()), Current(Begin), End(End) {
1336 EC = incrementImpl(
true);
1340 return incrementImpl(
false);
1354 RedirectingFSDirRemapIterImpl(std::string DirPath,
1356 : Dir(
std::
move(DirPath)), DirStyle(getExistingStyle(Dir)),
1357 ExternalIter(ExtIter) {
1362 void setCurrentEntry() {
1373 std::error_code increment()
override {
1376 if (!EC && ExternalIter != llvm::vfs::directory_iterator())
1379 CurrentEntry = directory_entry();
1385llvm::ErrorOr<std::string>
1387 return WorkingDirectory;
1397 Path.toVector(AbsolutePath);
1398 if (std::error_code EC = makeAbsolute(AbsolutePath))
1400 WorkingDirectory = std::string(AbsolutePath);
1409 if (makeAbsolute(Path))
1412 return ExternalFS->isLocal(Path, Result);
1427 return WorkingDir.getError();
1429 return makeAbsolute(WorkingDir.get(), Path);
1433RedirectingFileSystem::makeAbsolute(
StringRef WorkingDir,
1439 if (!WorkingDir.
empty() &&
1443 return std::error_code();
1455 std::string
Result = std::string(WorkingDir);
1456 StringRef Dir(Result);
1472 std::error_code &EC) {
1476 EC = makeAbsolute(Path);
1483 isFileNotFound(Result.getError()))
1484 return ExternalFS->dir_begin(Path, EC);
1486 EC = Result.getError();
1494 isFileNotFound(S.
getError(), Result->E))
1495 return ExternalFS->dir_begin(Dir, EC);
1501 if (!S->isDirectory()) {
1509 std::error_code RedirectEC;
1510 if (
auto ExtRedirect = Result->getExternalRedirect()) {
1512 RedirectIter = ExternalFS->dir_begin(*ExtRedirect, RedirectEC);
1514 if (!RE->useExternalName(UseExternalNames)) {
1518 std::string(Path), RedirectIter));
1524 Path, DE->contents_begin(), DE->contents_end(), RedirectEC));
1537 return RedirectIter;
1540 std::error_code ExternalEC;
1551 switch (Redirection) {
1565 std::make_shared<CombiningDirIterImpl>(Iters, EC)};
1572 OverlayFileDir = Dir.
str();
1576 return OverlayFileDir;
1593 std::vector<StringRef> R;
1594 R.reserve(Roots.size());
1595 for (
const auto &Root : Roots)
1596 R.push_back(Root->getName());
1601 unsigned IndentLevel)
const {
1603 OS <<
"RedirectingFileSystem (UseExternalNames: "
1604 << (UseExternalNames ?
"true" :
"false") <<
")\n";
1608 for (
const auto &Root : Roots)
1612 OS <<
"ExternalFS:\n";
1619 unsigned IndentLevel)
const {
1621 OS <<
"'" << E->getName() <<
"'";
1623 switch (E->getKind()) {
1628 for (std::unique_ptr<Entry> &SubEntry :
1630 printEntry(OS, SubEntry.get(), IndentLevel + 1);
1636 OS <<
" -> '" << RE->getExternalContentsPath() <<
"'";
1637 switch (RE->getUseName()) {
1641 OS <<
" (UseExternalName: true)";
1644 OS <<
" (UseExternalName: false)";
1655 Callback(*ExternalFS);
1656 ExternalFS->visitChildFileSystems(Callback);
1672 error(
N,
"expected string");
1675 Result = S->getValue(Storage);
1680 bool parseScalarBool(
yaml::Node *
N,
bool &Result) {
1683 if (!parseScalarString(
N,
Value, Storage))
1686 if (
Value.equals_insensitive(
"true") ||
Value.equals_insensitive(
"on") ||
1687 Value.equals_insensitive(
"yes") ||
Value ==
"1") {
1690 }
else if (
Value.equals_insensitive(
"false") ||
1691 Value.equals_insensitive(
"off") ||
1692 Value.equals_insensitive(
"no") ||
Value ==
"0") {
1697 error(
N,
"expected boolean value");
1701 std::optional<RedirectingFileSystem::RedirectKind>
1705 if (!parseScalarString(
N,
Value, Storage))
1706 return std::nullopt;
1708 if (
Value.equals_insensitive(
"fallthrough")) {
1710 }
else if (
Value.equals_insensitive(
"fallback")) {
1712 }
else if (
Value.equals_insensitive(
"redirect-only")) {
1715 return std::nullopt;
1718 std::optional<RedirectingFileSystem::RootRelativeKind>
1722 if (!parseScalarString(
N,
Value, Storage))
1723 return std::nullopt;
1724 if (
Value.equals_insensitive(
"cwd")) {
1726 }
else if (
Value.equals_insensitive(
"overlay-dir")) {
1729 return std::nullopt;
1736 KeyStatus(
bool Required =
false) : Required(Required) {}
1739 using KeyStatusPair = std::pair<StringRef, KeyStatus>;
1745 if (It == Keys.
end()) {
1746 error(KeyNode,
"unknown key");
1749 KeyStatus &S = It->second;
1760 for (
const auto &
I : Keys) {
1761 if (
I.second.Required && !
I.second.Seen) {
1762 error(Obj,
Twine(
"missing key '") +
I.first +
"'");
1774 for (
const auto &Root : FS->Roots) {
1775 if (Name == Root->getName()) {
1776 ParentEntry = Root.get();
1782 for (std::unique_ptr<RedirectingFileSystem::Entry> &Content :
1786 if (DirContent && Name == Content->getName())
1792 std::unique_ptr<RedirectingFileSystem::Entry> E =
1793 std::make_unique<RedirectingFileSystem::DirectoryEntry>(
1795 std::chrono::system_clock::now(), 0, 0, 0,
1799 FS->Roots.push_back(std::move(E));
1800 ParentEntry = FS->Roots.back().get();
1805 DE->addContent(std::move(E));
1806 return DE->getLastContent();
1821 NewParentE = lookupOrCreateEntry(FS, Name, NewParentE);
1822 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
1824 uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
1828 assert(NewParentE &&
"Parent entry must exist");
1832 std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
1833 Name, DR->getExternalContentsPath(), DR->getUseName()));
1837 assert(NewParentE &&
"Parent entry must exist");
1840 DE->addContent(std::make_unique<RedirectingFileSystem::FileEntry>(
1841 Name, FE->getExternalContentsPath(), FE->getUseName()));
1847 std::unique_ptr<RedirectingFileSystem::Entry>
1848 parseEntry(yaml::Node *
N, RedirectingFileSystem *FS,
bool IsRootEntry) {
1851 error(
N,
"expected mapping node for file or directory entry");
1855 KeyStatusPair Fields[] = {
1856 KeyStatusPair(
"name",
true),
1857 KeyStatusPair(
"type",
true),
1858 KeyStatusPair(
"contents",
false),
1859 KeyStatusPair(
"external-contents",
false),
1860 KeyStatusPair(
"use-external-name",
false),
1863 DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
1865 enum { CF_NotSet, CF_List, CF_External } ContentsField = CF_NotSet;
1866 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>>
1868 SmallString<256> ExternalContentsPath;
1869 SmallString<256>
Name;
1870 yaml::Node *NameValueNode =
nullptr;
1874 for (
auto &
I : *M) {
1878 SmallString<256> Buffer;
1879 if (!parseScalarString(
I.getKey(),
Key, Buffer))
1882 if (!checkDuplicateOrUnknownKey(
I.getKey(),
Key, Keys))
1886 if (
Key ==
"name") {
1887 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1890 NameValueNode =
I.getValue();
1894 }
else if (
Key ==
"type") {
1895 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1897 if (
Value ==
"file")
1899 else if (
Value ==
"directory")
1901 else if (
Value ==
"directory-remap")
1904 error(
I.getValue(),
"unknown value for 'type'");
1907 }
else if (
Key ==
"contents") {
1908 if (ContentsField != CF_NotSet) {
1910 "entry already has 'contents' or 'external-contents'");
1913 ContentsField = CF_List;
1917 error(
I.getValue(),
"expected array");
1921 for (
auto &
I : *Contents) {
1922 if (std::unique_ptr<RedirectingFileSystem::Entry>
E =
1923 parseEntry(&
I, FS,
false))
1924 EntryArrayContents.push_back(std::move(
E));
1928 }
else if (
Key ==
"external-contents") {
1929 if (ContentsField != CF_NotSet) {
1931 "entry already has 'contents' or 'external-contents'");
1934 ContentsField = CF_External;
1935 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1938 SmallString<256> FullPath;
1939 if (
FS->IsRelativeOverlay) {
1940 FullPath =
FS->getOverlayFileDir();
1942 "External contents prefix directory must exist");
1943 SmallString<256> AbsFullPath =
Value;
1944 if (
FS->makeAbsolute(FullPath, AbsFullPath)) {
1945 error(
N,
"failed to make 'external-contents' absolute");
1948 FullPath = AbsFullPath;
1955 FullPath = canonicalize(FullPath);
1956 ExternalContentsPath = FullPath.
str();
1957 }
else if (
Key ==
"use-external-name") {
1959 if (!parseScalarBool(
I.getValue(), Val))
1972 if (ContentsField == CF_NotSet) {
1973 error(
N,
"missing key 'contents' or 'external-contents'");
1976 if (!checkMissingKeys(
N, Keys))
1982 error(
N,
"'use-external-name' is not supported for 'directory' entries");
1987 ContentsField == CF_List) {
1988 error(
N,
"'contents' is not supported for 'directory-remap' entries");
1997 path_style = sys::path::Style::posix;
1999 sys::path::Style::windows_backslash)) {
2000 path_style = sys::path::Style::windows_backslash;
2006 if (
FS->RootRelative ==
2007 RedirectingFileSystem::RootRelativeKind::OverlayDir) {
2008 StringRef FullPath =
FS->getOverlayFileDir();
2009 assert(!FullPath.
empty() &&
"Overlay file directory must exist");
2010 EC =
FS->makeAbsolute(FullPath, Name);
2011 Name = canonicalize(Name);
2013 EC =
FS->makeAbsolute(Name);
2016 assert(NameValueNode &&
"Name presence should be checked earlier");
2019 "entry with relative path at the root level is not discoverable");
2023 ? sys::path::Style::posix
2024 : sys::path::Style::windows_backslash;
2029 if (path_style == sys::path::Style::windows_backslash &&
2030 getExistingStyle(Name) != sys::path::Style::windows_backslash)
2031 path_style = sys::path::Style::windows_slash;
2035 StringRef Trimmed =
Name;
2037 while (Trimmed.
size() > RootPathLen &&
2039 Trimmed = Trimmed.
slice(0, Trimmed.
size() - 1);
2044 std::unique_ptr<RedirectingFileSystem::Entry>
Result;
2047 Result = std::make_unique<RedirectingFileSystem::FileEntry>(
2048 LastComponent, std::move(ExternalContentsPath), UseExternalName);
2051 Result = std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
2052 LastComponent, std::move(ExternalContentsPath), UseExternalName);
2055 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
2056 LastComponent, std::move(EntryArrayContents),
2070 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> Entries;
2071 Entries.push_back(std::move(Result));
2072 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
2073 *
I, std::move(Entries),
2087 error(Root,
"expected mapping node");
2091 KeyStatusPair Fields[] = {
2092 KeyStatusPair(
"version",
true),
2093 KeyStatusPair(
"case-sensitive",
false),
2094 KeyStatusPair(
"use-external-names",
false),
2095 KeyStatusPair(
"root-relative",
false),
2096 KeyStatusPair(
"overlay-relative",
false),
2097 KeyStatusPair(
"fallthrough",
false),
2098 KeyStatusPair(
"redirecting-with",
false),
2099 KeyStatusPair(
"roots",
true),
2103 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> RootEntries;
2106 for (
auto &
I : *Top) {
2109 if (!parseScalarString(
I.getKey(),
Key, KeyBuffer))
2112 if (!checkDuplicateOrUnknownKey(
I.getKey(),
Key, Keys))
2115 if (
Key ==
"roots") {
2118 error(
I.getValue(),
"expected array");
2122 for (
auto &
I : *Roots) {
2123 if (std::unique_ptr<RedirectingFileSystem::Entry> E =
2124 parseEntry(&
I, FS,
true))
2125 RootEntries.push_back(std::move(E));
2129 }
else if (
Key ==
"version") {
2132 if (!parseScalarString(
I.getValue(), VersionString, Storage))
2136 error(
I.getValue(),
"expected integer");
2140 error(
I.getValue(),
"invalid version number");
2144 error(
I.getValue(),
"version mismatch, expected 0");
2147 }
else if (
Key ==
"case-sensitive") {
2148 if (!parseScalarBool(
I.getValue(), FS->CaseSensitive))
2150 }
else if (
Key ==
"overlay-relative") {
2151 if (!parseScalarBool(
I.getValue(), FS->IsRelativeOverlay))
2153 }
else if (
Key ==
"use-external-names") {
2154 if (!parseScalarBool(
I.getValue(), FS->UseExternalNames))
2156 }
else if (
Key ==
"fallthrough") {
2157 if (Keys[
"redirecting-with"].Seen) {
2159 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2163 bool ShouldFallthrough =
false;
2164 if (!parseScalarBool(
I.getValue(), ShouldFallthrough))
2167 if (ShouldFallthrough) {
2172 }
else if (
Key ==
"redirecting-with") {
2173 if (Keys[
"fallthrough"].Seen) {
2175 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2179 if (
auto Kind = parseRedirectKind(
I.getValue())) {
2180 FS->Redirection = *Kind;
2182 error(
I.getValue(),
"expected valid redirect kind");
2185 }
else if (
Key ==
"root-relative") {
2186 if (
auto Kind = parseRootRelativeKind(
I.getValue())) {
2187 FS->RootRelative = *Kind;
2189 error(
I.getValue(),
"expected valid root-relative kind");
2197 if (Stream.failed())
2200 if (!checkMissingKeys(Top, Keys))
2206 for (
auto &E : RootEntries)
2207 uniqueOverlayTree(FS, E.get());
2213std::unique_ptr<RedirectingFileSystem>
2216 StringRef YAMLFilePath,
void *DiagContext,
2224 if (DI == Stream.
end() || !Root) {
2231 std::unique_ptr<RedirectingFileSystem> FS(
2232 new RedirectingFileSystem(ExternalFS));
2234 if (!YAMLFilePath.
empty()) {
2244 std::error_code EC = FS->makeAbsolute(OverlayAbsDir);
2245 assert(!EC &&
"Overlay dir final path must be absolute");
2247 FS->setOverlayFileDir(OverlayAbsDir);
2250 if (!
P.parse(Root, FS.get()))
2257 ArrayRef<std::pair<std::string, std::string>> RemappedFiles,
2259 std::unique_ptr<RedirectingFileSystem> FS(
2260 new RedirectingFileSystem(ExternalFS));
2261 FS->UseExternalNames = UseExternalNames;
2269 auto EC = ExternalFS->makeAbsolute(From);
2271 assert(!EC &&
"Could not make absolute path");
2289 assert(Parent &&
"File without a directory?");
2291 auto EC = ExternalFS->makeAbsolute(To);
2293 assert(!EC &&
"Could not make absolute path");
2297 auto NewFile = std::make_unique<RedirectingFileSystem::FileEntry>(
2301 ToEntry = NewFile.get();
2303 std::move(NewFile));
2319 getExistingStyle(DRE->getExternalContentsPath()));
2320 ExternalRedirect = std::string(Redirect);
2332std::error_code RedirectingFileSystem::makeCanonicalForLookup(
2334 if (std::error_code EC = makeAbsolute(Path))
2338 canonicalize(
StringRef(Path.data(), Path.size()));
2339 if (CanonicalPath.
empty())
2342 Path.assign(CanonicalPath.
begin(), CanonicalPath.
end());
2349 if (std::error_code EC = makeCanonicalForLookup(CanonicalPath))
2359 for (
const auto &Root : Roots) {
2361 lookupPathImpl(Start, End, Root.get(), Entries);
2365 Result->Parents = std::move(Entries);
2376RedirectingFileSystem::lookupPathImpl(
2382 "Paths should not contain traversal components");
2387 if (!FromName.
empty()) {
2388 if (!pathComponentMatches(*Start, FromName))
2395 return LookupResult(From, Start, End);
2403 return LookupResult(From, Start, End);
2406 for (
const std::unique_ptr<RedirectingFileSystem::Entry> &DirEntry :
2410 lookupPathImpl(Start, End, DirEntry.get(), Entries);
2420 bool UseExternalNames,
2425 return ExternalStatus;
2427 Status S = ExternalStatus;
2428 if (!UseExternalNames)
2435ErrorOr<Status> RedirectingFileSystem::status(
2436 const Twine &LookupPath,
const Twine &OriginalPath,
2437 const RedirectingFileSystem::LookupResult &Result) {
2438 if (std::optional<StringRef> ExtRedirect =
Result.getExternalRedirect()) {
2439 SmallString<256> RemappedPath((*ExtRedirect).str());
2440 if (std::error_code EC = makeAbsolute(RemappedPath))
2443 ErrorOr<Status> S = ExternalFS->status(RemappedPath);
2449 RE->useExternalName(UseExternalNames), *S);
2457RedirectingFileSystem::getExternalStatus(
const Twine &LookupPath,
2458 const Twine &OriginalPath)
const {
2459 auto Result = ExternalFS->status(LookupPath);
2463 if (!Result ||
Result->ExposesExternalVFSPath)
2472 if (std::error_code EC = makeAbsolute(Path))
2488 isFileNotFound(Result.getError()))
2489 return getExternalStatus(Path, OriginalPath);
2490 return Result.getError();
2495 isFileNotFound(S.
getError(), Result->E)) {
2499 return getExternalStatus(Path, OriginalPath);
2509 if (makeAbsolute(Path))
2515 if (ExternalFS->exists(Path))
2524 isFileNotFound(Result.getError()))
2525 return ExternalFS->exists(Path);
2529 std::optional<StringRef> ExtRedirect = Result->getExternalRedirect();
2536 if (makeAbsolute(RemappedPath))
2539 if (ExternalFS->exists(RemappedPath))
2546 return ExternalFS->exists(Path);
2555class FileWithFixedStatus :
public File {
2556 std::unique_ptr<File> InnerFile;
2560 FileWithFixedStatus(std::unique_ptr<File> InnerFile,
Status S)
2566 getBuffer(
const Twine &Name, int64_t FileSize,
bool RequiresNullTerminator,
2567 bool IsVolatile)
override {
2568 return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
2572 std::error_code close()
override {
return InnerFile->close(); }
2574 void setPath(
const Twine &Path)
override { S = S.
copyWithNewName(S, Path); }
2579ErrorOr<std::unique_ptr<File>>
2583 if (!Result || (*Result)->status()->ExposesExternalVFSPath)
2587 auto Name =
F->get()->getName();
2588 if (Name && Name.get() !=
P.str())
2589 F->get()->setPath(
P);
2598 if (std::error_code EC = makeAbsolute(Path))
2614 isFileNotFound(Result.getError()))
2616 return Result.getError();
2619 if (!Result->getExternalRedirect())
2622 StringRef ExtRedirect = *Result->getExternalRedirect();
2624 if (std::error_code EC = makeAbsolute(RemappedPath))
2631 if (!ExternalFile) {
2633 isFileNotFound(ExternalFile.getError(), Result->E)) {
2639 return ExternalFile;
2642 auto ExternalStatus = (*ExternalFile)->status();
2643 if (!ExternalStatus)
2644 return ExternalStatus.getError();
2649 OriginalPath, RE->useExternalName(UseExternalNames), *ExternalStatus);
2650 return std::unique_ptr<File>(
2651 std::make_unique<FileWithFixedStatus>(std::move(*ExternalFile), S));
2660 if (std::error_code EC = makeAbsolute(Path))
2666 std::error_code EC = ExternalFS->getRealPath(Path, Output);
2676 isFileNotFound(Result.getError()))
2677 return ExternalFS->getRealPath(Path, Output);
2678 return Result.getError();
2683 if (
auto ExtRedirect = Result->getExternalRedirect()) {
2684 auto P = ExternalFS->getRealPath(*ExtRedirect, Output);
2686 isFileNotFound(
P, Result->E)) {
2690 return ExternalFS->getRealPath(Path, Output);
2698 Result->getPath(Output);
2704std::unique_ptr<FileSystem>
2707 StringRef YAMLFilePath,
void *DiagContext,
2710 YAMLFilePath, DiagContext,
2711 std::move(ExternalFS));
2720 assert(DE &&
"Must be a directory");
2721 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
2723 Path.push_back(SubEntry->getName());
2732 assert(DR &&
"Must be a directory remap");
2734 for (
auto &Comp : Path)
2743 assert(FE &&
"Must be a file");
2745 for (
auto &Comp : Path)
2761 static std::atomic<unsigned> UID;
2762 unsigned ID = ++UID;
2765 return UniqueID(std::numeric_limits<uint64_t>::max(), ID);
2773 Mappings.emplace_back(VirtualPath, RealPath, IsDirectory);
2777 addEntry(VirtualPath, RealPath,
false);
2782 addEntry(VirtualPath, RealPath,
true);
2791 unsigned getDirIndent() {
return 4 * DirStack.
size(); }
2792 unsigned getFileIndent() {
return 4 * (DirStack.
size() + 1); }
2796 void endDirectory();
2803 std::optional<bool> UseExternalNames,
2804 std::optional<bool> IsCaseSensitive,
2805 std::optional<bool> IsOverlayRelative, StringRef OverlayDir);
2810bool JSONWriter::containedIn(StringRef Parent, StringRef Path) {
2811 using namespace llvm::sys;
2816 IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
2817 if (*IParent != *IChild)
2821 return IParent == EParent;
2824StringRef JSONWriter::containedPart(StringRef Parent, StringRef Path) {
2826 assert(containedIn(Parent, Path));
2827 return Path.substr(Parent.
size() + 1);
2830void JSONWriter::startDirectory(StringRef Path) {
2832 DirStack.
empty() ?
Path : containedPart(DirStack.
back(), Path);
2834 unsigned Indent = getDirIndent();
2835 OS.
indent(Indent) <<
"{\n";
2836 OS.
indent(Indent + 2) <<
"'type': 'directory',\n";
2838 OS.
indent(Indent + 2) <<
"'contents': [\n";
2841void JSONWriter::endDirectory() {
2842 unsigned Indent = getDirIndent();
2843 OS.
indent(Indent + 2) <<
"]\n";
2844 OS.
indent(Indent) <<
"}";
2849void JSONWriter::writeEntry(StringRef VPath, StringRef RPath) {
2850 unsigned Indent = getFileIndent();
2851 OS.
indent(Indent) <<
"{\n";
2852 OS.
indent(Indent + 2) <<
"'type': 'file',\n";
2854 OS.
indent(Indent + 2) <<
"'external-contents': \""
2856 OS.
indent(Indent) <<
"}";
2860 std::optional<bool> UseExternalNames,
2861 std::optional<bool> IsCaseSensitive,
2862 std::optional<bool> IsOverlayRelative,
2864 using namespace llvm::sys;
2868 if (IsCaseSensitive)
2869 OS <<
" 'case-sensitive': '" << (*IsCaseSensitive ?
"true" :
"false")
2871 if (UseExternalNames)
2872 OS <<
" 'use-external-names': '" << (*UseExternalNames ?
"true" :
"false")
2874 bool UseOverlayRelative =
false;
2875 if (IsOverlayRelative) {
2876 UseOverlayRelative = *IsOverlayRelative;
2877 OS <<
" 'overlay-relative': '" << (UseOverlayRelative ?
"true" :
"false")
2880 OS <<
" 'roots': [\n";
2882 if (!Entries.
empty()) {
2890 if (UseOverlayRelative) {
2892 "Overlay dir must be contained in RPath");
2896 bool IsCurrentDirEmpty =
true;
2897 if (!
Entry.IsDirectory) {
2899 IsCurrentDirEmpty =
false;
2905 if (Dir == DirStack.
back()) {
2906 if (!IsCurrentDirEmpty) {
2910 bool IsDirPoppedFromStack =
false;
2911 while (!DirStack.
empty() && !containedIn(DirStack.
back(), Dir)) {
2914 IsDirPoppedFromStack =
true;
2916 if (IsDirPoppedFromStack || !IsCurrentDirEmpty) {
2919 startDirectory(Dir);
2920 IsCurrentDirEmpty =
true;
2923 if (UseOverlayRelative) {
2925 "Overlay dir must be contained in RPath");
2928 if (!
Entry.IsDirectory) {
2930 IsCurrentDirEmpty =
false;
2934 while (!DirStack.
empty()) {
2947 return LHS.VPath < RHS.VPath;
2950 JSONWriter(OS).
write(Mappings, UseExternalNames, IsCaseSensitive,
2951 IsOverlayRelative, OverlayDir);
2959 State = std::make_shared<detail::RecDirIterState>();
2960 State->Stack.push_back(
I);
2966 assert(FS && State && !State->Stack.empty() &&
"incrementing past end");
2967 assert(!State->Stack.back()->path().empty() &&
"non-canonical end iterator");
2970 if (State->HasNoPushRequest)
2971 State->HasNoPushRequest =
false;
2975 FS->dir_begin(State->Stack.back()->path(), EC);
2977 State->Stack.push_back(
I);
2983 while (!State->Stack.empty() && State->Stack.back().increment(EC) == End)
2984 State->Stack.pop_back();
2986 if (State->Stack.empty())
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.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
const T & front() const
Get the first element.
bool empty() const
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",...
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
Get the contents as an std::string.
constexpr bool empty() const
Check if the string is empty.
char back() const
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
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 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
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.
@ 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)
Remove '.
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.
void violationIfEnabled()
ScopedSetting scopedDisable()
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)
LLVM_ABI 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.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
auto dyn_cast_if_present(const Y &Val)
dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a null (or none in the case ...
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.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
@ no_such_file_or_directory
@ operation_not_permitted
auto reverse(ContainerTy &&C)
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
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.
LLVM_ABI Error write(DWPWriter &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue, Dwarf64StrOffsetsPromotion StrOffsetsOptValue, raw_pwrite_stream *OS=nullptr)
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