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,
1295 if (
auto ExternalWorkingDirectory =
1296 ExternalFS->getCurrentWorkingDirectory()) {
1297 WorkingDirectory = *ExternalWorkingDirectory;
1308 std::error_code incrementImpl(
bool IsFirstTime) {
1309 assert((IsFirstTime || Current != End) &&
"cannot iterate past end");
1312 if (Current != End) {
1316 switch ((*Current)->getKind()) {
1337 : Dir(Path.str()), Current(Begin), End(End) {
1338 EC = incrementImpl(
true);
1342 return incrementImpl(
false);
1356 RedirectingFSDirRemapIterImpl(std::string DirPath,
1358 : Dir(
std::
move(DirPath)), DirStyle(getExistingStyle(Dir)),
1359 ExternalIter(ExtIter) {
1364 void setCurrentEntry() {
1375 std::error_code increment()
override {
1378 if (!EC && ExternalIter != llvm::vfs::directory_iterator())
1381 CurrentEntry = directory_entry();
1387llvm::ErrorOr<std::string>
1389 return WorkingDirectory;
1399 Path.toVector(AbsolutePath);
1400 if (std::error_code EC = makeAbsolute(AbsolutePath))
1402 WorkingDirectory = std::string(AbsolutePath);
1411 if (makeAbsolute(Path))
1414 return ExternalFS->isLocal(Path, Result);
1429 return WorkingDir.getError();
1431 return makeAbsolute(WorkingDir.get(), Path);
1435RedirectingFileSystem::makeAbsolute(
StringRef WorkingDir,
1441 if (!WorkingDir.
empty() &&
1445 return std::error_code();
1457 std::string
Result = std::string(WorkingDir);
1458 StringRef Dir(Result);
1474 std::error_code &EC) {
1478 EC = makeAbsolute(Path);
1485 isFileNotFound(Result.getError()))
1486 return ExternalFS->dir_begin(Path, EC);
1488 EC = Result.getError();
1496 isFileNotFound(S.
getError(), Result->E))
1497 return ExternalFS->dir_begin(Dir, EC);
1503 if (!S->isDirectory()) {
1511 std::error_code RedirectEC;
1512 if (
auto ExtRedirect = Result->getExternalRedirect()) {
1514 RedirectIter = ExternalFS->dir_begin(*ExtRedirect, RedirectEC);
1516 if (!RE->useExternalName(UseExternalNames)) {
1520 std::string(Path), RedirectIter));
1526 Path, DE->contents_begin(), DE->contents_end(), RedirectEC));
1539 return RedirectIter;
1542 std::error_code ExternalEC;
1553 switch (Redirection) {
1567 std::make_shared<CombiningDirIterImpl>(Iters, EC)};
1574 OverlayFileDir = Dir.
str();
1578 return OverlayFileDir;
1595 std::vector<StringRef> R;
1596 R.reserve(Roots.size());
1597 for (
const auto &Root : Roots)
1598 R.push_back(Root->getName());
1603 unsigned IndentLevel)
const {
1605 OS <<
"RedirectingFileSystem (UseExternalNames: "
1606 << (UseExternalNames ?
"true" :
"false") <<
")\n";
1610 for (
const auto &Root : Roots)
1614 OS <<
"ExternalFS:\n";
1621 unsigned IndentLevel)
const {
1623 OS <<
"'" << E->getName() <<
"'";
1625 switch (E->getKind()) {
1630 for (std::unique_ptr<Entry> &SubEntry :
1632 printEntry(OS, SubEntry.get(), IndentLevel + 1);
1638 OS <<
" -> '" << RE->getExternalContentsPath() <<
"'";
1639 switch (RE->getUseName()) {
1643 OS <<
" (UseExternalName: true)";
1646 OS <<
" (UseExternalName: false)";
1657 Callback(*ExternalFS);
1658 ExternalFS->visitChildFileSystems(Callback);
1674 error(
N,
"expected string");
1677 Result = S->getValue(Storage);
1682 bool parseScalarBool(
yaml::Node *
N,
bool &Result) {
1685 if (!parseScalarString(
N,
Value, Storage))
1688 if (
Value.equals_insensitive(
"true") ||
Value.equals_insensitive(
"on") ||
1689 Value.equals_insensitive(
"yes") ||
Value ==
"1") {
1692 }
else if (
Value.equals_insensitive(
"false") ||
1693 Value.equals_insensitive(
"off") ||
1694 Value.equals_insensitive(
"no") ||
Value ==
"0") {
1699 error(
N,
"expected boolean value");
1703 std::optional<RedirectingFileSystem::RedirectKind>
1707 if (!parseScalarString(
N,
Value, Storage))
1708 return std::nullopt;
1710 if (
Value.equals_insensitive(
"fallthrough")) {
1712 }
else if (
Value.equals_insensitive(
"fallback")) {
1714 }
else if (
Value.equals_insensitive(
"redirect-only")) {
1717 return std::nullopt;
1720 std::optional<RedirectingFileSystem::RootRelativeKind>
1724 if (!parseScalarString(
N,
Value, Storage))
1725 return std::nullopt;
1726 if (
Value.equals_insensitive(
"cwd")) {
1728 }
else if (
Value.equals_insensitive(
"overlay-dir")) {
1731 return std::nullopt;
1741 using KeyStatusPair = std::pair<StringRef, KeyStatus>;
1747 if (It == Keys.
end()) {
1748 error(KeyNode,
"unknown key");
1751 KeyStatus &S = It->second;
1762 for (
const auto &
I : Keys) {
1763 if (
I.second.Required && !
I.second.Seen) {
1764 error(Obj,
Twine(
"missing key '") +
I.first +
"'");
1776 for (
const auto &Root : FS->Roots) {
1777 if (Name == Root->getName()) {
1778 ParentEntry = Root.get();
1784 for (std::unique_ptr<RedirectingFileSystem::Entry> &Content :
1788 if (DirContent && Name == Content->getName())
1794 std::unique_ptr<RedirectingFileSystem::Entry> E =
1795 std::make_unique<RedirectingFileSystem::DirectoryEntry>(
1797 std::chrono::system_clock::now(), 0, 0, 0,
1801 FS->Roots.push_back(std::move(E));
1802 ParentEntry = FS->Roots.back().get();
1807 DE->addContent(std::move(E));
1808 return DE->getLastContent();
1823 NewParentE = lookupOrCreateEntry(FS, Name, NewParentE);
1824 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
1826 uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
1830 assert(NewParentE &&
"Parent entry must exist");
1834 std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
1835 Name, DR->getExternalContentsPath(), DR->getUseName()));
1839 assert(NewParentE &&
"Parent entry must exist");
1842 DE->addContent(std::make_unique<RedirectingFileSystem::FileEntry>(
1843 Name, FE->getExternalContentsPath(), FE->getUseName()));
1849 std::unique_ptr<RedirectingFileSystem::Entry>
1850 parseEntry(yaml::Node *
N, RedirectingFileSystem *FS,
bool IsRootEntry) {
1853 error(
N,
"expected mapping node for file or directory entry");
1857 KeyStatusPair Fields[] = {
1858 KeyStatusPair(
"name",
true),
1859 KeyStatusPair(
"type",
true),
1860 KeyStatusPair(
"contents",
false),
1861 KeyStatusPair(
"external-contents",
false),
1862 KeyStatusPair(
"use-external-name",
false),
1865 DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
1867 enum { CF_NotSet, CF_List, CF_External } ContentsField = CF_NotSet;
1868 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>>
1870 SmallString<256> ExternalContentsPath;
1871 SmallString<256>
Name;
1872 yaml::Node *NameValueNode =
nullptr;
1876 for (
auto &
I : *M) {
1880 SmallString<256> Buffer;
1881 if (!parseScalarString(
I.getKey(),
Key, Buffer))
1884 if (!checkDuplicateOrUnknownKey(
I.getKey(),
Key, Keys))
1888 if (
Key ==
"name") {
1889 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1892 NameValueNode =
I.getValue();
1896 }
else if (
Key ==
"type") {
1897 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1899 if (
Value ==
"file")
1901 else if (
Value ==
"directory")
1903 else if (
Value ==
"directory-remap")
1906 error(
I.getValue(),
"unknown value for 'type'");
1909 }
else if (
Key ==
"contents") {
1910 if (ContentsField != CF_NotSet) {
1912 "entry already has 'contents' or 'external-contents'");
1915 ContentsField = CF_List;
1919 error(
I.getValue(),
"expected array");
1923 for (
auto &
I : *Contents) {
1924 if (std::unique_ptr<RedirectingFileSystem::Entry>
E =
1925 parseEntry(&
I, FS,
false))
1926 EntryArrayContents.push_back(std::move(
E));
1930 }
else if (
Key ==
"external-contents") {
1931 if (ContentsField != CF_NotSet) {
1933 "entry already has 'contents' or 'external-contents'");
1936 ContentsField = CF_External;
1937 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1940 SmallString<256> FullPath;
1941 if (
FS->IsRelativeOverlay) {
1942 FullPath =
FS->getOverlayFileDir();
1944 "External contents prefix directory must exist");
1945 SmallString<256> AbsFullPath =
Value;
1946 if (
FS->makeAbsolute(FullPath, AbsFullPath)) {
1947 error(
N,
"failed to make 'external-contents' absolute");
1950 FullPath = AbsFullPath;
1957 FullPath = canonicalize(FullPath);
1958 ExternalContentsPath = FullPath.
str();
1959 }
else if (
Key ==
"use-external-name") {
1961 if (!parseScalarBool(
I.getValue(), Val))
1974 if (ContentsField == CF_NotSet) {
1975 error(
N,
"missing key 'contents' or 'external-contents'");
1978 if (!checkMissingKeys(
N, Keys))
1984 error(
N,
"'use-external-name' is not supported for 'directory' entries");
1989 ContentsField == CF_List) {
1990 error(
N,
"'contents' is not supported for 'directory-remap' entries");
1999 path_style = sys::path::Style::posix;
2001 sys::path::Style::windows_backslash)) {
2002 path_style = sys::path::Style::windows_backslash;
2008 if (
FS->RootRelative ==
2009 RedirectingFileSystem::RootRelativeKind::OverlayDir) {
2010 StringRef FullPath =
FS->getOverlayFileDir();
2011 assert(!FullPath.
empty() &&
"Overlay file directory must exist");
2012 EC =
FS->makeAbsolute(FullPath, Name);
2013 Name = canonicalize(Name);
2015 EC =
FS->makeAbsolute(Name);
2018 assert(NameValueNode &&
"Name presence should be checked earlier");
2021 "entry with relative path at the root level is not discoverable");
2025 ? sys::path::Style::posix
2026 : sys::path::Style::windows_backslash;
2031 if (path_style == sys::path::Style::windows_backslash &&
2032 getExistingStyle(Name) != sys::path::Style::windows_backslash)
2033 path_style = sys::path::Style::windows_slash;
2037 StringRef Trimmed =
Name;
2039 while (Trimmed.
size() > RootPathLen &&
2041 Trimmed = Trimmed.
slice(0, Trimmed.
size() - 1);
2046 std::unique_ptr<RedirectingFileSystem::Entry>
Result;
2049 Result = std::make_unique<RedirectingFileSystem::FileEntry>(
2050 LastComponent, std::move(ExternalContentsPath), UseExternalName);
2053 Result = std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
2054 LastComponent, std::move(ExternalContentsPath), UseExternalName);
2057 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
2058 LastComponent, std::move(EntryArrayContents),
2072 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> Entries;
2073 Entries.push_back(std::move(Result));
2074 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
2075 *
I, std::move(Entries),
2089 error(Root,
"expected mapping node");
2093 KeyStatusPair Fields[] = {
2094 KeyStatusPair(
"version",
true),
2095 KeyStatusPair(
"case-sensitive",
false),
2096 KeyStatusPair(
"use-external-names",
false),
2097 KeyStatusPair(
"root-relative",
false),
2098 KeyStatusPair(
"overlay-relative",
false),
2099 KeyStatusPair(
"fallthrough",
false),
2100 KeyStatusPair(
"redirecting-with",
false),
2101 KeyStatusPair(
"roots",
true),
2105 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> RootEntries;
2108 for (
auto &
I : *Top) {
2111 if (!parseScalarString(
I.getKey(),
Key, KeyBuffer))
2114 if (!checkDuplicateOrUnknownKey(
I.getKey(),
Key, Keys))
2117 if (
Key ==
"roots") {
2120 error(
I.getValue(),
"expected array");
2124 for (
auto &
I : *Roots) {
2125 if (std::unique_ptr<RedirectingFileSystem::Entry> E =
2126 parseEntry(&
I, FS,
true))
2127 RootEntries.push_back(std::move(E));
2131 }
else if (
Key ==
"version") {
2134 if (!parseScalarString(
I.getValue(), VersionString, Storage))
2138 error(
I.getValue(),
"expected integer");
2142 error(
I.getValue(),
"invalid version number");
2146 error(
I.getValue(),
"version mismatch, expected 0");
2149 }
else if (
Key ==
"case-sensitive") {
2150 if (!parseScalarBool(
I.getValue(), FS->CaseSensitive))
2152 }
else if (
Key ==
"overlay-relative") {
2153 if (!parseScalarBool(
I.getValue(), FS->IsRelativeOverlay))
2155 }
else if (
Key ==
"use-external-names") {
2156 if (!parseScalarBool(
I.getValue(), FS->UseExternalNames))
2158 }
else if (
Key ==
"fallthrough") {
2159 if (Keys[
"redirecting-with"].Seen) {
2161 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2165 bool ShouldFallthrough =
false;
2166 if (!parseScalarBool(
I.getValue(), ShouldFallthrough))
2169 if (ShouldFallthrough) {
2174 }
else if (
Key ==
"redirecting-with") {
2175 if (Keys[
"fallthrough"].Seen) {
2177 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2181 if (
auto Kind = parseRedirectKind(
I.getValue())) {
2182 FS->Redirection = *Kind;
2184 error(
I.getValue(),
"expected valid redirect kind");
2187 }
else if (
Key ==
"root-relative") {
2188 if (
auto Kind = parseRootRelativeKind(
I.getValue())) {
2189 FS->RootRelative = *Kind;
2191 error(
I.getValue(),
"expected valid root-relative kind");
2199 if (Stream.failed())
2202 if (!checkMissingKeys(Top, Keys))
2208 for (
auto &E : RootEntries)
2209 uniqueOverlayTree(FS, E.get());
2215std::unique_ptr<RedirectingFileSystem>
2218 StringRef YAMLFilePath,
void *DiagContext,
2226 if (DI == Stream.
end() || !Root) {
2233 std::unique_ptr<RedirectingFileSystem> FS(
2234 new RedirectingFileSystem(ExternalFS));
2236 if (!YAMLFilePath.
empty()) {
2246 std::error_code EC = FS->makeAbsolute(OverlayAbsDir);
2247 assert(!EC &&
"Overlay dir final path must be absolute");
2249 FS->setOverlayFileDir(OverlayAbsDir);
2252 if (!
P.parse(Root, FS.get()))
2259 ArrayRef<std::pair<std::string, std::string>> RemappedFiles,
2261 std::unique_ptr<RedirectingFileSystem> FS(
2262 new RedirectingFileSystem(ExternalFS));
2263 FS->UseExternalNames = UseExternalNames;
2271 auto EC = ExternalFS->makeAbsolute(From);
2273 assert(!EC &&
"Could not make absolute path");
2291 assert(Parent &&
"File without a directory?");
2293 auto EC = ExternalFS->makeAbsolute(To);
2295 assert(!EC &&
"Could not make absolute path");
2299 auto NewFile = std::make_unique<RedirectingFileSystem::FileEntry>(
2303 ToEntry = NewFile.get();
2305 std::move(NewFile));
2321 getExistingStyle(DRE->getExternalContentsPath()));
2322 ExternalRedirect = std::string(Redirect);
2334std::error_code RedirectingFileSystem::makeCanonicalForLookup(
2336 if (std::error_code EC = makeAbsolute(Path))
2340 canonicalize(
StringRef(Path.data(), Path.size()));
2341 if (CanonicalPath.
empty())
2344 Path.assign(CanonicalPath.
begin(), CanonicalPath.
end());
2351 if (std::error_code EC = makeCanonicalForLookup(CanonicalPath))
2361 for (
const auto &Root : Roots) {
2363 lookupPathImpl(Start, End, Root.get(), Entries);
2367 Result->Parents = std::move(Entries);
2375RedirectingFileSystem::lookupPathImpl(
2381 "Paths should not contain traversal components");
2386 if (!FromName.
empty()) {
2387 if (!pathComponentMatches(*Start, FromName))
2394 return LookupResult(From, Start, End);
2402 return LookupResult(From, Start, End);
2405 for (
const std::unique_ptr<RedirectingFileSystem::Entry> &DirEntry :
2409 lookupPathImpl(Start, End, DirEntry.get(), Entries);
2419 bool UseExternalNames,
2424 return ExternalStatus;
2426 Status S = ExternalStatus;
2427 if (!UseExternalNames)
2434ErrorOr<Status> RedirectingFileSystem::status(
2435 const Twine &LookupPath,
const Twine &OriginalPath,
2436 const RedirectingFileSystem::LookupResult &Result) {
2437 if (std::optional<StringRef> ExtRedirect =
Result.getExternalRedirect()) {
2438 SmallString<256> RemappedPath((*ExtRedirect).str());
2439 if (std::error_code EC = makeAbsolute(RemappedPath))
2442 ErrorOr<Status> S = ExternalFS->status(RemappedPath);
2448 RE->useExternalName(UseExternalNames), *S);
2456RedirectingFileSystem::getExternalStatus(
const Twine &LookupPath,
2457 const Twine &OriginalPath)
const {
2458 auto Result = ExternalFS->status(LookupPath);
2462 if (!Result ||
Result->ExposesExternalVFSPath)
2471 if (std::error_code EC = makeAbsolute(Path))
2487 isFileNotFound(Result.getError()))
2488 return getExternalStatus(Path, OriginalPath);
2489 return Result.getError();
2494 isFileNotFound(S.
getError(), Result->E)) {
2498 return getExternalStatus(Path, OriginalPath);
2508 if (makeAbsolute(Path))
2514 if (ExternalFS->exists(Path))
2523 isFileNotFound(Result.getError()))
2524 return ExternalFS->exists(Path);
2528 std::optional<StringRef> ExtRedirect = Result->getExternalRedirect();
2535 if (makeAbsolute(RemappedPath))
2538 if (ExternalFS->exists(RemappedPath))
2545 return ExternalFS->exists(Path);
2554class FileWithFixedStatus :
public File {
2555 std::unique_ptr<File> InnerFile;
2559 FileWithFixedStatus(std::unique_ptr<File> InnerFile,
Status S)
2565 getBuffer(
const Twine &Name, int64_t FileSize,
bool RequiresNullTerminator,
2566 bool IsVolatile)
override {
2567 return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
2571 std::error_code close()
override {
return InnerFile->close(); }
2573 void setPath(
const Twine &Path)
override { S = S.
copyWithNewName(S, Path); }
2578ErrorOr<std::unique_ptr<File>>
2582 if (!Result || (*Result)->status()->ExposesExternalVFSPath)
2586 auto Name =
F->get()->getName();
2587 if (Name && Name.get() !=
P.str())
2588 F->get()->setPath(
P);
2597 if (std::error_code EC = makeAbsolute(Path))
2613 isFileNotFound(Result.getError()))
2615 return Result.getError();
2618 if (!Result->getExternalRedirect())
2621 StringRef ExtRedirect = *Result->getExternalRedirect();
2623 if (std::error_code EC = makeAbsolute(RemappedPath))
2630 if (!ExternalFile) {
2632 isFileNotFound(ExternalFile.getError(), Result->E)) {
2638 return ExternalFile;
2641 auto ExternalStatus = (*ExternalFile)->status();
2642 if (!ExternalStatus)
2643 return ExternalStatus.getError();
2648 OriginalPath, RE->useExternalName(UseExternalNames), *ExternalStatus);
2649 return std::unique_ptr<File>(
2650 std::make_unique<FileWithFixedStatus>(std::move(*ExternalFile), S));
2659 if (std::error_code EC = makeAbsolute(Path))
2665 std::error_code EC = ExternalFS->getRealPath(Path, Output);
2675 isFileNotFound(Result.getError()))
2676 return ExternalFS->getRealPath(Path, Output);
2677 return Result.getError();
2682 if (
auto ExtRedirect = Result->getExternalRedirect()) {
2683 auto P = ExternalFS->getRealPath(*ExtRedirect, Output);
2685 isFileNotFound(
P, Result->E)) {
2689 return ExternalFS->getRealPath(Path, Output);
2697 Result->getPath(Output);
2703std::unique_ptr<FileSystem>
2706 StringRef YAMLFilePath,
void *DiagContext,
2709 YAMLFilePath, DiagContext,
2710 std::move(ExternalFS));
2719 assert(DE &&
"Must be a directory");
2720 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
2722 Path.push_back(SubEntry->getName());
2731 assert(DR &&
"Must be a directory remap");
2733 for (
auto &Comp : Path)
2742 assert(FE &&
"Must be a file");
2744 for (
auto &Comp : Path)
2760 static std::atomic<unsigned> UID;
2761 unsigned ID = ++UID;
2764 return UniqueID(std::numeric_limits<uint64_t>::max(),
ID);
2772 Mappings.emplace_back(VirtualPath, RealPath, IsDirectory);
2776 addEntry(VirtualPath, RealPath,
false);
2781 addEntry(VirtualPath, RealPath,
true);
2790 unsigned getDirIndent() {
return 4 * DirStack.
size(); }
2791 unsigned getFileIndent() {
return 4 * (DirStack.
size() + 1); }
2795 void endDirectory();
2802 std::optional<bool> UseExternalNames,
2803 std::optional<bool> IsCaseSensitive,
2804 std::optional<bool> IsOverlayRelative, StringRef OverlayDir);
2809bool JSONWriter::containedIn(StringRef Parent, StringRef Path) {
2810 using namespace llvm::sys;
2815 IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
2816 if (*IParent != *IChild)
2820 return IParent == EParent;
2823StringRef JSONWriter::containedPart(StringRef Parent, StringRef Path) {
2825 assert(containedIn(Parent, Path));
2826 return Path.substr(Parent.
size() + 1);
2829void JSONWriter::startDirectory(StringRef Path) {
2831 DirStack.
empty() ?
Path : containedPart(DirStack.
back(), Path);
2833 unsigned Indent = getDirIndent();
2834 OS.
indent(Indent) <<
"{\n";
2835 OS.
indent(Indent + 2) <<
"'type': 'directory',\n";
2837 OS.
indent(Indent + 2) <<
"'contents': [\n";
2840void JSONWriter::endDirectory() {
2841 unsigned Indent = getDirIndent();
2842 OS.
indent(Indent + 2) <<
"]\n";
2843 OS.
indent(Indent) <<
"}";
2848void JSONWriter::writeEntry(StringRef VPath, StringRef RPath) {
2849 unsigned Indent = getFileIndent();
2850 OS.
indent(Indent) <<
"{\n";
2851 OS.
indent(Indent + 2) <<
"'type': 'file',\n";
2853 OS.
indent(Indent + 2) <<
"'external-contents': \""
2855 OS.
indent(Indent) <<
"}";
2859 std::optional<bool> UseExternalNames,
2860 std::optional<bool> IsCaseSensitive,
2861 std::optional<bool> IsOverlayRelative,
2863 using namespace llvm::sys;
2867 if (IsCaseSensitive)
2868 OS <<
" 'case-sensitive': '" << (*IsCaseSensitive ?
"true" :
"false")
2870 if (UseExternalNames)
2871 OS <<
" 'use-external-names': '" << (*UseExternalNames ?
"true" :
"false")
2873 bool UseOverlayRelative =
false;
2874 if (IsOverlayRelative) {
2875 UseOverlayRelative = *IsOverlayRelative;
2876 OS <<
" 'overlay-relative': '" << (UseOverlayRelative ?
"true" :
"false")
2879 OS <<
" 'roots': [\n";
2881 if (!Entries.
empty()) {
2889 if (UseOverlayRelative) {
2891 "Overlay dir must be contained in RPath");
2895 bool IsCurrentDirEmpty =
true;
2896 if (!
Entry.IsDirectory) {
2898 IsCurrentDirEmpty =
false;
2904 if (Dir == DirStack.
back()) {
2905 if (!IsCurrentDirEmpty) {
2909 bool IsDirPoppedFromStack =
false;
2910 while (!DirStack.
empty() && !containedIn(DirStack.
back(), Dir)) {
2913 IsDirPoppedFromStack =
true;
2915 if (IsDirPoppedFromStack || !IsCurrentDirEmpty) {
2918 startDirectory(Dir);
2919 IsCurrentDirEmpty =
true;
2922 if (UseOverlayRelative) {
2924 "Overlay dir must be contained in RPath");
2927 if (!
Entry.IsDirectory) {
2929 IsCurrentDirEmpty =
false;
2933 while (!DirStack.
empty()) {
2946 return LHS.VPath < RHS.VPath;
2949 JSONWriter(OS).
write(Mappings, UseExternalNames, IsCaseSensitive,
2950 IsOverlayRelative, OverlayDir);
2958 State = std::make_shared<detail::RecDirIterState>();
2959 State->Stack.push_back(
I);
2965 assert(FS && State && !State->Stack.empty() &&
"incrementing past end");
2966 assert(!State->Stack.back()->path().empty() &&
"non-canonical end iterator");
2969 if (State->HasNoPushRequest)
2970 State->HasNoPushRequest =
false;
2974 FS->dir_begin(State->Stack.back()->path(), EC);
2976 State->Stack.push_back(
I);
2982 while (!State->Stack.empty() && State->Stack.back().increment(EC) == End)
2983 State->Stack.pop_back();
2985 if (State->Stack.empty())
2992 unsigned IndentLevel)
const {
2993 printIndent(OS, IndentLevel);
2994 OS <<
"TracingFileSystem\n";
2995 if (
Type == PrintType::Summary)
2998 printIndent(OS, IndentLevel);
3000 printIndent(OS, IndentLevel);
3002 printIndent(OS, IndentLevel);
3004 printIndent(OS, IndentLevel);
3006 printIndent(OS, IndentLevel);
3008 printIndent(OS, IndentLevel);
3011 if (
Type == PrintType::Contents)
3012 Type = PrintType::Summary;
3013 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 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.
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.
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)
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.
LLVM_ABI Error write(MCStreamer &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue, Dwarf64StrOffsetsPromotion StrOffsetsOptValue)
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