24#include "llvm/Config/llvm-config.h"
49#include <system_error>
75 return Status(In.getName(), In.getUniqueID(), In.getLastModificationTime(),
76 In.getUser(), In.getGroup(), NewSize, In.getType(),
81 return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
82 In.getUser(), In.getGroup(), In.getSize(), In.getType(),
87 return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
88 In.getUser(), In.getGroup(), In.getSize(), In.type(),
119 bool RequiresNullTerminator,
bool IsVolatile,
125 return (*F)->getBuffer(
Name, FileSize, RequiresNullTerminator, IsVolatile);
134 return WorkingDir.getError();
157 return StatusA.getError();
160 return StatusB.getError();
161 return StatusA->equivalent(*StatusB);
164#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
170 return Component ==
".." || Component ==
".";
190class RealFile :
public File {
191 friend class RealFileSystem;
195 std::string RealName;
198 : FD(RawFD), S(NewName, {}, {}, {}, {}, {},
200 RealName(NewRealPathName.str()) {
201 assert(FD != kInvalidFile &&
"Invalid or inactive file descriptor");
205 ~RealFile()
override;
211 bool RequiresNullTerminator,
212 bool IsVolatile)
override;
213 std::error_code close()
override;
214 void setPath(
const Twine &Path)
override;
219RealFile::~RealFile() { close(); }
222 assert(FD != kInvalidFile &&
"cannot stat closed file");
223 if (!S.isStatusKnown()) {
233 return RealName.empty() ? S.getName().str() : RealName;
237RealFile::getBuffer(
const Twine &
Name, int64_t FileSize,
238 bool RequiresNullTerminator,
bool IsVolatile) {
239 assert(FD != kInvalidFile &&
"cannot get buffer for closed file");
244std::error_code RealFile::close() {
250void RealFile::setPath(
const Twine &Path) {
251 RealName =
Path.str();
268 explicit RealFileSystem(
bool LinkCWDToProcess) {
269 if (!LinkCWDToProcess) {
274 WD = WorkingDirectory{PWD, PWD};
276 WD = WorkingDirectory{PWD, RealPWD};
283 openFileForReadBinary(
const Twine &Path)
override;
287 std::error_code setCurrentWorkingDirectory(
const Twine &Path)
override;
288 std::error_code isLocal(
const Twine &Path,
bool &Result)
override;
289 std::error_code getRealPath(
const Twine &Path,
294 unsigned IndentLevel)
const override;
302 Path.toVector(Storage);
311 adjustPath(
Name, Storage), Flags, &RealName);
314 return std::unique_ptr<File>(
315 new RealFile(*FDOrErr,
Name.str(), RealName.
str()));
318 struct WorkingDirectory {
324 std::optional<llvm::ErrorOr<WorkingDirectory>> WD;
332 if (std::error_code EC =
339RealFileSystem::openFileForRead(
const Twine &
Name) {
344RealFileSystem::openFileForReadBinary(
const Twine &
Name) {
350 return std::string(WD->get().Specified);
352 return WD->getError();
357 return std::string(Dir);
360std::error_code RealFileSystem::setCurrentWorkingDirectory(
const Twine &Path) {
365 adjustPath(Path, Storage).toVector(Absolute);
370 return std::make_error_code(std::errc::not_a_directory);
374 return std::error_code();
377std::error_code RealFileSystem::isLocal(
const Twine &Path,
bool &Result) {
382std::error_code RealFileSystem::getRealPath(
const Twine &Path,
389 unsigned IndentLevel)
const {
390 printIndent(
OS, IndentLevel);
391 OS <<
"RealFileSystem using ";
401 makeIntrusiveRefCnt<RealFileSystem>(
true);
406 return std::make_unique<RealFileSystem>(
false);
415 RealFSDirIter(
const Twine &Path, std::error_code &EC) : Iter(Path, EC) {
420 std::error_code increment()
override {
433 std::error_code &EC) {
436 std::make_shared<RealFSDirIter>(adjustPath(Dir, Storage), EC));
467 if ((*I)->exists(Path))
477 auto Result = (*I)->openFileForRead(Path);
487 return FSList.
front()->getCurrentWorkingDirectory();
492 for (
auto &FS : FSList)
493 if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))
499 for (
auto &FS : FSList)
500 if (FS->exists(Path))
501 return FS->isLocal(Path, Result);
507 for (
const auto &FS : FSList)
508 if (FS->exists(Path))
509 return FS->getRealPath(Path, Output);
516 FS->visitChildFileSystems(Callback);
521 unsigned IndentLevel)
const {
522 printIndent(
OS, IndentLevel);
523 OS <<
"OverlayFileSystem\n";
524 if (
Type == PrintType::Summary)
527 if (
Type == PrintType::Contents)
528 Type = PrintType::Summary;
530 FS->print(
OS,
Type, IndentLevel + 1);
550 std::error_code incrementIter(
bool IsFirstTime) {
551 while (!IterList.
empty()) {
552 CurrentDirIter = IterList.
back();
559 return errc::no_such_file_or_directory;
563 std::error_code incrementDirIter(
bool IsFirstTime) {
565 "incrementing past end");
570 EC = incrementIter(IsFirstTime);
574 std::error_code incrementImpl(
bool IsFirstTime) {
576 std::error_code
EC = incrementDirIter(IsFirstTime);
581 CurrentEntry = *CurrentDirIter;
591 std::error_code &EC) {
592 for (
const auto &FS : FileSystems) {
595 if (FEC && FEC != errc::no_such_file_or_directory) {
602 EC = incrementImpl(
true);
607 : IterList(DirIters) {
608 EC = incrementImpl(
true);
611 std::error_code increment()
override {
return incrementImpl(
false); }
617 std::error_code &EC) {
619 std::make_shared<CombiningDirIterImpl>(FSList, Dir.
str(), EC));
625void ProxyFileSystem::anchor() {}
643 std::string FileName;
647 : Kind(Kind), FileName(
std::
string(
llvm::sys::path::filename(FileName))) {
659 virtual std::string
toString(
unsigned Indent)
const = 0;
664 std::unique_ptr<llvm::MemoryBuffer> Buffer;
672 return Status::copyWithNewName(Stat, RequestedName);
676 std::string
toString(
unsigned Indent)
const override {
677 return (std::string(Indent,
' ') + Stat.
getName() +
"\n").str();
687class InMemoryHardLink :
public InMemoryNode {
688 const InMemoryFile &ResolvedFile;
691 InMemoryHardLink(
StringRef Path,
const InMemoryFile &ResolvedFile)
692 : InMemoryNode(Path, IME_HardLink), ResolvedFile(ResolvedFile) {}
693 const InMemoryFile &getResolvedFile()
const {
return ResolvedFile; }
695 Status getStatus(
const Twine &RequestedName)
const override {
696 return ResolvedFile.getStatus(RequestedName);
699 std::string
toString(
unsigned Indent)
const override {
700 return std::string(Indent,
' ') +
"HardLink to -> " +
701 ResolvedFile.toString(0);
704 static bool classof(
const InMemoryNode *
N) {
709class InMemorySymbolicLink :
public InMemoryNode {
710 std::string TargetPath;
718 std::string
toString(
unsigned Indent)
const override {
719 return std::string(Indent,
' ') +
"SymbolicLink to -> " + TargetPath;
722 Status getStatus(
const Twine &RequestedName)
const override {
723 return Status::copyWithNewName(Stat, RequestedName);
726 StringRef getTargetPath()
const {
return TargetPath; }
728 static bool classof(
const InMemoryNode *
N) {
736class InMemoryFileAdaptor :
public File {
737 const InMemoryFile &
Node;
739 std::string RequestedName;
742 explicit InMemoryFileAdaptor(
const InMemoryFile &
Node,
743 std::string RequestedName)
747 return Node.getStatus(RequestedName);
751 getBuffer(
const Twine &
Name, int64_t FileSize,
bool RequiresNullTerminator,
752 bool IsVolatile)
override {
758 std::error_code close()
override {
return {}; }
760 void setPath(
const Twine &Path)
override { RequestedName =
Path.str(); }
766 std::map<std::string, std::unique_ptr<InMemoryNode>, std::less<>> Entries;
776 return Status::copyWithNewName(Stat, RequestedName);
782 auto I = Entries.find(
Name);
783 if (
I != Entries.end())
784 return I->second.get();
789 return Entries.emplace(
Name, std::move(Child)).first->second.get();
797 std::string
toString(
unsigned Indent)
const override {
799 (std::string(Indent,
' ') + Stat.
getName() +
"\n").str();
800 for (
const auto &Entry : Entries)
801 Result += Entry.second->toString(Indent + 2);
831 (
Type == sys::fs::file_type::directory_file)
833 :
getFileID(DirUID,
Name, Buffer ? Buffer->getBuffer() :
"");
836 Group, Buffer ? Buffer->getBufferSize() : 0,
Type, Perms);
840 : Root(new
detail::InMemoryDirectory(
843 llvm::sys::fs::file_type::directory_file,
844 llvm::sys::fs::perms::all_all))),
845 UseNormalizedPaths(UseNormalizedPaths) {}
850 return Root->toString(0);
853bool InMemoryFileSystem::addFile(
const Twine &
P, time_t ModificationTime,
854 std::unique_ptr<llvm::MemoryBuffer> Buffer,
855 std::optional<uint32_t>
User,
856 std::optional<uint32_t> Group,
857 std::optional<llvm::sys::fs::file_type>
Type,
858 std::optional<llvm::sys::fs::perms> Perms,
859 MakeNodeFn MakeNode) {
876 const auto ResolvedUser =
User.value_or(0);
877 const auto ResolvedGroup = Group.value_or(0);
894 StringRef(Path.str().begin(),
Name.end() - Path.str().begin()),
898 Dir = cast<detail::InMemoryDirectory>(Dir->
addChild(
899 Name, std::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
903 if (!isa<detail::InMemoryDirectory>(Node))
905 Dir = cast<detail::InMemoryDirectory>(Node);
911 std::move(Buffer), ResolvedUser, ResolvedGroup,
912 ResolvedType, ResolvedPerms}));
915 if (isa<detail::InMemoryDirectory>(
Node))
919 isa<detail::InMemoryHardLink>(
Node)) &&
920 "Must be either file, hardlink or directory!");
923 if (
auto *Link = dyn_cast<detail::InMemoryHardLink>(
Node)) {
924 return Link->getResolvedFile().getBuffer()->getBuffer() ==
927 return cast<detail::InMemoryFile>(
Node)->getBuffer()->getBuffer() ==
931bool InMemoryFileSystem::addFile(
const Twine &
P, time_t ModificationTime,
932 std::unique_ptr<llvm::MemoryBuffer> Buffer,
933 std::optional<uint32_t>
User,
934 std::optional<uint32_t> Group,
935 std::optional<llvm::sys::fs::file_type>
Type,
936 std::optional<llvm::sys::fs::perms> Perms) {
937 return addFile(
P, ModificationTime, std::move(Buffer),
User, Group,
Type,
940 -> std::unique_ptr<detail::InMemoryNode> {
943 return std::make_unique<detail::InMemoryDirectory>(Stat);
944 return std::make_unique<detail::InMemoryFile>(
945 Stat, std::move(NNI.
Buffer));
950 const Twine &
P, time_t ModificationTime,
952 std::optional<uint32_t> Group, std::optional<llvm::sys::fs::file_type>
Type,
953 std::optional<llvm::sys::fs::perms> Perms) {
955 std::move(
User), std::move(Group), std::move(
Type),
958 -> std::unique_ptr<detail::InMemoryNode> {
961 return std::make_unique<detail::InMemoryDirectory>(Stat);
962 return std::make_unique<detail::InMemoryFile>(
963 Stat, std::move(NNI.
Buffer));
968InMemoryFileSystem::lookupNode(
const Twine &
P,
bool FollowFinalSymlink,
969 size_t SymlinkDepth)
const {
992 if (
auto Symlink = dyn_cast<detail::InMemorySymbolicLink>(Node)) {
995 if (
I == E && !FollowFinalSymlink)
1010 lookupNode(TargetPath,
true, SymlinkDepth + 1);
1014 if (!isa<detail::InMemoryDirectory>(*
Target))
1018 Dir = cast<detail::InMemoryDirectory>(*
Target);
1023 if (
auto File = dyn_cast<detail::InMemoryFile>(Node)) {
1030 if (
auto File = dyn_cast<detail::InMemoryHardLink>(
Node)) {
1036 Dir = cast<detail::InMemoryDirectory>(
Node);
1044 auto NewLinkNode = lookupNode(NewLink,
false);
1048 auto TargetNode = lookupNode(
Target,
true);
1051 if (!TargetNode || NewLinkNode || !isa<detail::InMemoryFile>(*TargetNode))
1053 return addFile(NewLink, 0,
nullptr, std::nullopt, std::nullopt, std::nullopt,
1055 return std::make_unique<detail::InMemoryHardLink>(
1057 *cast<detail::InMemoryFile>(*TargetNode));
1063 std::optional<uint32_t>
User, std::optional<uint32_t> Group,
1064 std::optional<llvm::sys::fs::perms> Perms) {
1065 auto NewLinkNode = lookupNode(NewLink,
false);
1071 Target.toVector(TargetStr);
1073 return addFile(NewLinkStr, ModificationTime,
nullptr,
User, Group,
1076 return std::make_unique<detail::InMemorySymbolicLink>(
1082 auto Node = lookupNode(Path,
true);
1084 return (*Node)->getStatus(Path);
1085 return Node.getError();
1090 auto Node = lookupNode(Path,
true);
1092 return Node.getError();
1096 if (
auto *
F = dyn_cast<detail::InMemoryFile>(*Node))
1097 return std::unique_ptr<File>(
1098 new detail::InMemoryFileAdaptor(*
F, Path.str()));
1109 std::string RequestedDirName;
1111 void setCurrentEntry() {
1116 switch (
I->second->getKind()) {
1125 if (
auto SymlinkTarget =
1126 FS->lookupNode(Path,
true)) {
1127 Path = SymlinkTarget.getName();
1128 Type = (*SymlinkTarget)->getStatus(Path).getType();
1145 std::string RequestedDirName)
1146 : FS(FS),
I(Dir.begin()), E(Dir.end()),
1147 RequestedDirName(
std::
move(RequestedDirName)) {
1159 std::error_code &EC) {
1160 auto Node = lookupNode(Dir,
true);
1162 EC = Node.getError();
1166 if (
auto *DirNode = dyn_cast<detail::InMemoryDirectory>(*Node))
1168 std::make_shared<DirIterator>(
this, *DirNode, Dir.
str()));
1187 WorkingDirectory = std::string(Path);
1194 if (!CWD || CWD->empty())
1196 Path.toVector(Output);
1209 unsigned IndentLevel)
const {
1210 printIndent(
OS, IndentLevel);
1211 OS <<
"InMemoryFileSystem\n";
1226 const size_t n = Path.find_first_of(
"/\\");
1228 if (n !=
static_cast<size_t>(-1))
1248static bool isFileNotFound(std::error_code EC,
1250 if (E && !isa<RedirectingFileSystem::DirectoryRemapEntry>(E))
1261 if (
auto ExternalWorkingDirectory =
1262 ExternalFS->getCurrentWorkingDirectory()) {
1263 WorkingDirectory = *ExternalWorkingDirectory;
1274 std::error_code incrementImpl(
bool IsFirstTime) {
1275 assert((IsFirstTime || Current !=
End) &&
"cannot iterate past end");
1278 if (Current !=
End) {
1282 switch ((*Current)->getKind()) {
1303 : Dir(Path.str()), Current(Begin),
End(
End) {
1304 EC = incrementImpl(
true);
1308 return incrementImpl(
false);
1322 RedirectingFSDirRemapIterImpl(std::string DirPath,
1324 : Dir(
std::
move(DirPath)), DirStyle(getExistingStyle(Dir)),
1325 ExternalIter(ExtIter) {
1330 void setCurrentEntry() {
1341 std::error_code increment()
override {
1355 return WorkingDirectory;
1365 Path.toVector(AbsolutePath);
1366 if (std::error_code EC = makeAbsolute(AbsolutePath))
1368 WorkingDirectory = std::string(AbsolutePath);
1377 if (makeAbsolute(Path))
1380 return ExternalFS->isLocal(Path, Result);
1395 return WorkingDir.getError();
1397 return makeAbsolute(WorkingDir.get(), Path);
1401RedirectingFileSystem::makeAbsolute(
StringRef WorkingDir,
1407 if (!WorkingDir.
empty() &&
1411 return std::error_code();
1423 std::string
Result = std::string(WorkingDir);
1440 std::error_code &EC) {
1444 EC = makeAbsolute(Path);
1451 isFileNotFound(Result.getError()))
1452 return ExternalFS->dir_begin(Path, EC);
1454 EC = Result.getError();
1462 isFileNotFound(S.
getError(), Result->E))
1463 return ExternalFS->dir_begin(Dir, EC);
1469 if (!S->isDirectory()) {
1477 std::error_code RedirectEC;
1478 if (
auto ExtRedirect = Result->getExternalRedirect()) {
1479 auto RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
1480 RedirectIter = ExternalFS->dir_begin(*ExtRedirect, RedirectEC);
1482 if (!RE->useExternalName(UseExternalNames)) {
1486 std::string(Path), RedirectIter));
1489 auto DE = cast<DirectoryEntry>(Result->E);
1492 Path, DE->contents_begin(), DE->contents_end(), RedirectEC));
1505 return RedirectIter;
1508 std::error_code ExternalEC;
1519 switch (Redirection) {
1533 std::make_shared<CombiningDirIterImpl>(Iters, EC)};
1540 OverlayFileDir = Dir.
str();
1544 return OverlayFileDir;
1561 std::vector<StringRef> R;
1562 R.reserve(Roots.size());
1563 for (
const auto &Root : Roots)
1564 R.push_back(Root->getName());
1569 unsigned IndentLevel)
const {
1571 OS <<
"RedirectingFileSystem (UseExternalNames: "
1572 << (UseExternalNames ?
"true" :
"false") <<
")\n";
1576 for (
const auto &Root : Roots)
1580 OS <<
"ExternalFS:\n";
1587 unsigned IndentLevel)
const {
1593 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(E);
1596 for (std::unique_ptr<Entry> &SubEntry :
1603 auto *RE = cast<RedirectingFileSystem::RemapEntry>(E);
1604 OS <<
" -> '" << RE->getExternalContentsPath() <<
"'";
1605 switch (RE->getUseName()) {
1609 OS <<
" (UseExternalName: true)";
1612 OS <<
" (UseExternalName: false)";
1623 Callback(*ExternalFS);
1624 ExternalFS->visitChildFileSystems(Callback);
1637 const auto *S = dyn_cast<yaml::ScalarNode>(
N);
1640 error(
N,
"expected string");
1643 Result = S->getValue(Storage);
1648 bool parseScalarBool(
yaml::Node *
N,
bool &Result) {
1651 if (!parseScalarString(
N,
Value, Storage))
1654 if (
Value.equals_insensitive(
"true") ||
Value.equals_insensitive(
"on") ||
1655 Value.equals_insensitive(
"yes") ||
Value ==
"1") {
1658 }
else if (
Value.equals_insensitive(
"false") ||
1659 Value.equals_insensitive(
"off") ||
1660 Value.equals_insensitive(
"no") ||
Value ==
"0") {
1665 error(
N,
"expected boolean value");
1669 std::optional<RedirectingFileSystem::RedirectKind>
1673 if (!parseScalarString(
N,
Value, Storage))
1674 return std::nullopt;
1676 if (
Value.equals_insensitive(
"fallthrough")) {
1678 }
else if (
Value.equals_insensitive(
"fallback")) {
1680 }
else if (
Value.equals_insensitive(
"redirect-only")) {
1683 return std::nullopt;
1686 std::optional<RedirectingFileSystem::RootRelativeKind>
1690 if (!parseScalarString(
N,
Value, Storage))
1691 return std::nullopt;
1692 if (
Value.equals_insensitive(
"cwd")) {
1694 }
else if (
Value.equals_insensitive(
"overlay-dir")) {
1697 return std::nullopt;
1704 KeyStatus(
bool Required =
false) : Required(Required) {}
1707 using KeyStatusPair = std::pair<StringRef, KeyStatus>;
1712 auto It = Keys.
find(Key);
1713 if (It == Keys.
end()) {
1714 error(KeyNode,
"unknown key");
1717 KeyStatus &S = It->second;
1719 error(KeyNode,
Twine(
"duplicate key '") + Key +
"'");
1728 for (
const auto &
I : Keys) {
1729 if (
I.second.Required && !
I.second.Seen) {
1730 error(Obj,
Twine(
"missing key '") +
I.first +
"'");
1742 for (
const auto &Root : FS->Roots) {
1743 if (
Name == Root->getName()) {
1744 ParentEntry = Root.get();
1749 auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
1750 for (std::unique_ptr<RedirectingFileSystem::Entry> &
Content :
1753 dyn_cast<RedirectingFileSystem::DirectoryEntry>(
Content.get());
1760 std::unique_ptr<RedirectingFileSystem::Entry> E =
1761 std::make_unique<RedirectingFileSystem::DirectoryEntry>(
1763 std::chrono::system_clock::now(), 0, 0, 0,
1767 FS->Roots.push_back(std::move(E));
1768 ParentEntry = FS->Roots.back().get();
1772 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
1773 DE->addContent(std::move(E));
1774 return DE->getLastContent();
1784 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
1790 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
1792 uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
1796 assert(NewParentE &&
"Parent entry must exist");
1797 auto *DR = cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
1798 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
1800 std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
1801 Name, DR->getExternalContentsPath(), DR->getUseName()));
1805 assert(NewParentE &&
"Parent entry must exist");
1806 auto *FE = cast<RedirectingFileSystem::FileEntry>(SrcE);
1807 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
1808 DE->addContent(std::make_unique<RedirectingFileSystem::FileEntry>(
1809 Name, FE->getExternalContentsPath(), FE->getUseName()));
1815 std::unique_ptr<RedirectingFileSystem::Entry>
1817 auto *
M = dyn_cast<yaml::MappingNode>(
N);
1819 error(
N,
"expected mapping node for file or directory entry");
1823 KeyStatusPair Fields[] = {
1824 KeyStatusPair(
"name",
true),
1825 KeyStatusPair(
"type",
true),
1826 KeyStatusPair(
"contents",
false),
1827 KeyStatusPair(
"external-contents",
false),
1828 KeyStatusPair(
"use-external-name",
false),
1833 enum { CF_NotSet, CF_List, CF_External } ContentsField = CF_NotSet;
1834 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>>
1842 for (
auto &
I : *M) {
1847 if (!parseScalarString(
I.getKey(), Key, Buffer))
1850 if (!checkDuplicateOrUnknownKey(
I.getKey(), Key, Keys))
1854 if (Key ==
"name") {
1855 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1858 NameValueNode =
I.getValue();
1862 }
else if (Key ==
"type") {
1863 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1865 if (
Value ==
"file")
1867 else if (
Value ==
"directory")
1869 else if (
Value ==
"directory-remap")
1872 error(
I.getValue(),
"unknown value for 'type'");
1875 }
else if (Key ==
"contents") {
1876 if (ContentsField != CF_NotSet) {
1878 "entry already has 'contents' or 'external-contents'");
1881 ContentsField = CF_List;
1882 auto *Contents = dyn_cast<yaml::SequenceNode>(
I.getValue());
1885 error(
I.getValue(),
"expected array");
1889 for (
auto &
I : *Contents) {
1890 if (std::unique_ptr<RedirectingFileSystem::Entry> E =
1891 parseEntry(&
I, FS,
false))
1892 EntryArrayContents.push_back(std::move(E));
1896 }
else if (Key ==
"external-contents") {
1897 if (ContentsField != CF_NotSet) {
1899 "entry already has 'contents' or 'external-contents'");
1902 ContentsField = CF_External;
1903 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1907 if (
FS->IsRelativeOverlay) {
1908 FullPath =
FS->getOverlayFileDir();
1910 "External contents prefix directory must exist");
1918 FullPath = canonicalize(FullPath);
1919 ExternalContentsPath = FullPath.
str();
1920 }
else if (Key ==
"use-external-name") {
1922 if (!parseScalarBool(
I.getValue(), Val))
1935 if (ContentsField == CF_NotSet) {
1936 error(
N,
"missing key 'contents' or 'external-contents'");
1939 if (!checkMissingKeys(
N, Keys))
1945 error(
N,
"'use-external-name' is not supported for 'directory' entries");
1950 ContentsField == CF_List) {
1951 error(
N,
"'contents' is not supported for 'directory-remap' entries");
1969 if (
FS->RootRelative ==
1972 assert(!FullPath.
empty() &&
"Overlay file directory must exist");
1973 EC =
FS->makeAbsolute(FullPath,
Name);
1979 assert(NameValueNode &&
"Name presence should be checked earlier");
1982 "entry with relative path at the root level is not discoverable");
2000 while (Trimmed.
size() > RootPathLen &&
2002 Trimmed = Trimmed.
slice(0, Trimmed.
size() - 1);
2007 std::unique_ptr<RedirectingFileSystem::Entry>
Result;
2010 Result = std::make_unique<RedirectingFileSystem::FileEntry>(
2011 LastComponent, std::move(ExternalContentsPath), UseExternalName);
2014 Result = std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
2015 LastComponent, std::move(ExternalContentsPath), UseExternalName);
2018 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
2019 LastComponent, std::move(EntryArrayContents),
2033 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> Entries;
2034 Entries.push_back(std::move(Result));
2035 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
2036 *
I, std::move(Entries),
2048 auto *Top = dyn_cast<yaml::MappingNode>(Root);
2050 error(Root,
"expected mapping node");
2054 KeyStatusPair Fields[] = {
2055 KeyStatusPair(
"version",
true),
2056 KeyStatusPair(
"case-sensitive",
false),
2057 KeyStatusPair(
"use-external-names",
false),
2058 KeyStatusPair(
"root-relative",
false),
2059 KeyStatusPair(
"overlay-relative",
false),
2060 KeyStatusPair(
"fallthrough",
false),
2061 KeyStatusPair(
"redirecting-with",
false),
2062 KeyStatusPair(
"roots",
true),
2066 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> RootEntries;
2069 for (
auto &
I : *Top) {
2072 if (!parseScalarString(
I.getKey(), Key, KeyBuffer))
2075 if (!checkDuplicateOrUnknownKey(
I.getKey(), Key, Keys))
2078 if (Key ==
"roots") {
2079 auto *Roots = dyn_cast<yaml::SequenceNode>(
I.getValue());
2081 error(
I.getValue(),
"expected array");
2085 for (
auto &
I : *Roots) {
2086 if (std::unique_ptr<RedirectingFileSystem::Entry> E =
2087 parseEntry(&
I, FS,
true))
2088 RootEntries.push_back(std::move(E));
2092 }
else if (Key ==
"version") {
2095 if (!parseScalarString(
I.getValue(), VersionString, Storage))
2099 error(
I.getValue(),
"expected integer");
2103 error(
I.getValue(),
"invalid version number");
2107 error(
I.getValue(),
"version mismatch, expected 0");
2110 }
else if (Key ==
"case-sensitive") {
2111 if (!parseScalarBool(
I.getValue(), FS->CaseSensitive))
2113 }
else if (Key ==
"overlay-relative") {
2114 if (!parseScalarBool(
I.getValue(), FS->IsRelativeOverlay))
2116 }
else if (Key ==
"use-external-names") {
2117 if (!parseScalarBool(
I.getValue(), FS->UseExternalNames))
2119 }
else if (Key ==
"fallthrough") {
2120 if (Keys[
"redirecting-with"].Seen) {
2122 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2126 bool ShouldFallthrough =
false;
2127 if (!parseScalarBool(
I.getValue(), ShouldFallthrough))
2130 if (ShouldFallthrough) {
2135 }
else if (Key ==
"redirecting-with") {
2136 if (Keys[
"fallthrough"].Seen) {
2138 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2142 if (
auto Kind = parseRedirectKind(
I.getValue())) {
2143 FS->Redirection = *Kind;
2145 error(
I.getValue(),
"expected valid redirect kind");
2148 }
else if (Key ==
"root-relative") {
2149 if (
auto Kind = parseRootRelativeKind(
I.getValue())) {
2150 FS->RootRelative = *Kind;
2152 error(
I.getValue(),
"expected valid root-relative kind");
2163 if (!checkMissingKeys(Top, Keys))
2169 for (
auto &E : RootEntries)
2170 uniqueOverlayTree(FS, E.get());
2176std::unique_ptr<RedirectingFileSystem>
2179 StringRef YAMLFilePath,
void *DiagContext,
2187 if (DI == Stream.
end() || !Root) {
2194 std::unique_ptr<RedirectingFileSystem> FS(
2197 if (!YAMLFilePath.
empty()) {
2208 assert(!EC &&
"Overlay dir final path must be absolute");
2210 FS->setOverlayFileDir(OverlayAbsDir);
2213 if (!
P.parse(Root, FS.get()))
2220 ArrayRef<std::pair<std::string, std::string>> RemappedFiles,
2222 std::unique_ptr<RedirectingFileSystem> FS(
2224 FS->UseExternalNames = UseExternalNames;
2232 auto EC = ExternalFS->makeAbsolute(
From);
2234 assert(!EC &&
"Could not make absolute path");
2252 assert(Parent &&
"File without a directory?");
2254 auto EC = ExternalFS->makeAbsolute(To);
2256 assert(!EC &&
"Could not make absolute path");
2260 auto NewFile = std::make_unique<RedirectingFileSystem::FileEntry>(
2264 ToEntry = NewFile.get();
2265 cast<RedirectingFileSystem::DirectoryEntry>(Parent)->addContent(
2266 std::move(NewFile));
2279 if (
auto *DRE = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(
E)) {
2282 getExistingStyle(DRE->getExternalContentsPath()));
2283 ExternalRedirect = std::string(Redirect);
2290 for (
Entry *Parent : Parents)
2295std::error_code RedirectingFileSystem::makeCanonicalForLookup(
2297 if (std::error_code EC = makeAbsolute(Path))
2301 canonicalize(
StringRef(Path.data(), Path.size()));
2302 if (CanonicalPath.
empty())
2305 Path.assign(CanonicalPath.
begin(), CanonicalPath.
end());
2312 if (std::error_code EC = makeCanonicalForLookup(CanonicalPath))
2322 for (
const auto &Root : Roots) {
2324 lookupPathImpl(Start,
End, Root.get(), Entries);
2325 if (UsageTrackingActive && Result && isa<RemapEntry>(Result->E))
2328 Result->Parents = std::move(Entries);
2336RedirectingFileSystem::lookupPathImpl(
2342 "Paths should not contain traversal components");
2347 if (!FromName.
empty()) {
2348 if (!pathComponentMatches(*Start, FromName))
2355 return LookupResult(
From, Start,
End);
2359 if (isa<RedirectingFileSystem::FileEntry>(
From))
2362 if (isa<RedirectingFileSystem::DirectoryRemapEntry>(
From))
2363 return LookupResult(
From, Start,
End);
2365 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(
From);
2366 for (
const std::unique_ptr<RedirectingFileSystem::Entry> &DirEntry :
2368 Entries.push_back(
From);
2370 lookupPathImpl(Start,
End, DirEntry.get(), Entries);
2380 bool UseExternalNames,
2385 return ExternalStatus;
2387 Status S = ExternalStatus;
2388 if (!UseExternalNames)
2396 const Twine &LookupPath,
const Twine &OriginalPath,
2398 if (std::optional<StringRef> ExtRedirect =
Result.getExternalRedirect()) {
2400 if (std::error_code EC = makeAbsolute(RemappedPath))
2407 auto *RE = cast<RedirectingFileSystem::RemapEntry>(
Result.E);
2409 RE->useExternalName(UseExternalNames), *S);
2412 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(
Result.E);
2417RedirectingFileSystem::getExternalStatus(
const Twine &LookupPath,
2418 const Twine &OriginalPath)
const {
2419 auto Result = ExternalFS->status(LookupPath);
2423 if (!Result ||
Result->ExposesExternalVFSPath)
2432 if (std::error_code EC = makeAbsolute(Path))
2448 isFileNotFound(Result.getError()))
2449 return getExternalStatus(Path, OriginalPath);
2450 return Result.getError();
2455 isFileNotFound(S.
getError(), Result->E)) {
2459 return getExternalStatus(Path, OriginalPath);
2469 if (makeAbsolute(Path))
2475 if (ExternalFS->exists(Path))
2484 isFileNotFound(Result.getError()))
2485 return ExternalFS->exists(Path);
2489 std::optional<StringRef> ExtRedirect = Result->getExternalRedirect();
2491 assert(isa<RedirectingFileSystem::DirectoryEntry>(Result->E));
2496 if (makeAbsolute(RemappedPath))
2499 if (ExternalFS->exists(RemappedPath))
2506 return ExternalFS->exists(Path);
2515class FileWithFixedStatus :
public File {
2516 std::unique_ptr<File> InnerFile;
2520 FileWithFixedStatus(std::unique_ptr<File> InnerFile,
Status S)
2526 getBuffer(
const Twine &
Name, int64_t FileSize,
bool RequiresNullTerminator,
2527 bool IsVolatile)
override {
2528 return InnerFile->getBuffer(
Name, FileSize, RequiresNullTerminator,
2532 std::error_code close()
override {
return InnerFile->close(); }
2543 if (!Result || (*Result)->status()->ExposesExternalVFSPath)
2547 auto Name =
F->get()->getName();
2549 F->get()->setPath(
P);
2558 if (std::error_code EC = makeAbsolute(Path))
2574 isFileNotFound(Result.getError()))
2576 return Result.getError();
2579 if (!Result->getExternalRedirect())
2582 StringRef ExtRedirect = *Result->getExternalRedirect();
2584 if (std::error_code EC = makeAbsolute(RemappedPath))
2587 auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
2591 if (!ExternalFile) {
2593 isFileNotFound(ExternalFile.getError(), Result->E)) {
2599 return ExternalFile;
2602 auto ExternalStatus = (*ExternalFile)->status();
2603 if (!ExternalStatus)
2604 return ExternalStatus.getError();
2609 OriginalPath, RE->useExternalName(UseExternalNames), *ExternalStatus);
2610 return std::unique_ptr<File>(
2611 std::make_unique<FileWithFixedStatus>(std::move(*ExternalFile), S));
2620 if (std::error_code EC = makeAbsolute(Path))
2626 std::error_code EC = ExternalFS->getRealPath(Path, Output);
2636 isFileNotFound(Result.getError()))
2637 return ExternalFS->getRealPath(Path, Output);
2638 return Result.getError();
2643 if (
auto ExtRedirect = Result->getExternalRedirect()) {
2644 auto P = ExternalFS->getRealPath(*ExtRedirect, Output);
2646 isFileNotFound(
P, Result->E)) {
2650 return ExternalFS->getRealPath(Path, Output);
2658 Result->getPath(Output);
2664std::unique_ptr<FileSystem>
2667 StringRef YAMLFilePath,
void *DiagContext,
2670 YAMLFilePath, DiagContext,
2671 std::move(ExternalFS));
2679 auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
2680 assert(DE &&
"Must be a directory");
2681 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
2683 Path.push_back(SubEntry->getName());
2691 auto *DR = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
2692 assert(DR &&
"Must be a directory remap");
2694 for (
auto &Comp : Path)
2702 auto *FE = dyn_cast<RedirectingFileSystem::FileEntry>(SrcE);
2703 assert(FE &&
"Must be a file");
2705 for (
auto &Comp : Path)
2717 std::move(Buffer),
DiagHandler, YAMLFilePath, DiagContext,
2718 std::move(ExternalFS));
2722 VFS->lookupPath(
"/");
2731 static std::atomic<unsigned> UID;
2732 unsigned ID = ++UID;
2735 return UniqueID(std::numeric_limits<uint64_t>::max(),
ID);
2743 Mappings.emplace_back(VirtualPath, RealPath, IsDirectory);
2747 addEntry(VirtualPath, RealPath,
false);
2752 addEntry(VirtualPath, RealPath,
true);
2761 unsigned getDirIndent() {
return 4 * DirStack.
size(); }
2762 unsigned getFileIndent() {
return 4 * (DirStack.
size() + 1); }
2766 void endDirectory();
2773 std::optional<bool> UseExternalNames,
2774 std::optional<bool> IsCaseSensitive,
2775 std::optional<bool> IsOverlayRelative,
StringRef OverlayDir);
2786 IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
2787 if (*IParent != *IChild)
2791 return IParent == EParent;
2796 assert(containedIn(Parent, Path));
2797 return Path.substr(Parent.
size() + 1);
2800void JSONWriter::startDirectory(
StringRef Path) {
2802 DirStack.
empty() ?
Path : containedPart(DirStack.
back(), Path);
2804 unsigned Indent = getDirIndent();
2806 OS.
indent(Indent + 2) <<
"'type': 'directory',\n";
2808 OS.
indent(Indent + 2) <<
"'contents': [\n";
2811void JSONWriter::endDirectory() {
2812 unsigned Indent = getDirIndent();
2820 unsigned Indent = getFileIndent();
2822 OS.
indent(Indent + 2) <<
"'type': 'file',\n";
2824 OS.
indent(Indent + 2) <<
"'external-contents': \""
2830 std::optional<bool> UseExternalNames,
2831 std::optional<bool> IsCaseSensitive,
2832 std::optional<bool> IsOverlayRelative,
2838 if (IsCaseSensitive)
2839 OS <<
" 'case-sensitive': '" << (*IsCaseSensitive ?
"true" :
"false")
2841 if (UseExternalNames)
2842 OS <<
" 'use-external-names': '" << (*UseExternalNames ?
"true" :
"false")
2844 bool UseOverlayRelative =
false;
2845 if (IsOverlayRelative) {
2846 UseOverlayRelative = *IsOverlayRelative;
2847 OS <<
" 'overlay-relative': '" << (UseOverlayRelative ?
"true" :
"false")
2850 OS <<
" 'roots': [\n";
2852 if (!Entries.empty()) {
2860 if (UseOverlayRelative) {
2862 "Overlay dir must be contained in RPath");
2866 bool IsCurrentDirEmpty =
true;
2867 if (!
Entry.IsDirectory) {
2869 IsCurrentDirEmpty =
false;
2872 for (
const auto &Entry : Entries.slice(1)) {
2875 if (Dir == DirStack.
back()) {
2876 if (!IsCurrentDirEmpty) {
2880 bool IsDirPoppedFromStack =
false;
2881 while (!DirStack.
empty() && !containedIn(DirStack.
back(), Dir)) {
2884 IsDirPoppedFromStack =
true;
2886 if (IsDirPoppedFromStack || !IsCurrentDirEmpty) {
2889 startDirectory(Dir);
2890 IsCurrentDirEmpty =
true;
2893 if (UseOverlayRelative) {
2895 "Overlay dir must be contained in RPath");
2898 if (!
Entry.IsDirectory) {
2900 IsCurrentDirEmpty =
false;
2904 while (!DirStack.
empty()) {
2917 return LHS.VPath <
RHS.VPath;
2920 JSONWriter(
OS).write(Mappings, UseExternalNames, IsCaseSensitive,
2929 State = std::make_shared<detail::RecDirIterState>();
2930 State->Stack.push_back(
I);
2936 assert(FS && State && !State->Stack.empty() &&
"incrementing past end");
2937 assert(!State->Stack.back()->path().empty() &&
"non-canonical end iterator");
2940 if (State->HasNoPushRequest)
2941 State->HasNoPushRequest =
false;
2945 FS->dir_begin(State->Stack.back()->path(), EC);
2947 State->Stack.push_back(
I);
2953 while (!State->Stack.empty() && State->Stack.back().increment(EC) ==
End)
2954 State->Stack.pop_back();
2956 if (State->Stack.empty())
2963 unsigned IndentLevel)
const {
2964 printIndent(
OS, IndentLevel);
2965 OS <<
"TracingFileSystem\n";
2966 if (
Type == PrintType::Summary)
2969 printIndent(
OS, IndentLevel);
2971 printIndent(
OS, IndentLevel);
2973 printIndent(
OS, IndentLevel);
2975 printIndent(
OS, IndentLevel);
2977 printIndent(
OS, IndentLevel);
2979 printIndent(
OS, IndentLevel);
2982 if (
Type == PrintType::Contents)
2983 Type = PrintType::Summary;
2984 getUnderlyingFS().
print(
OS,
Type, IndentLevel + 1);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
BlockVerifier::State From
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
This file defines the DenseMap class.
Provides ErrorOr<T> smart pointer.
static void makeAbsolute(SmallVectorImpl< char > &Path)
Make Path absolute.
This file defines the RefCountedBase, ThreadSafeRefCountedBase, and IntrusiveRefCntPtr classes.
static 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)
static void getVFSEntries(RedirectingFileSystem::Entry *SrcE, SmallVectorImpl< StringRef > &Path, SmallVectorImpl< YAMLVFSEntry > &Entries)
static Status getRedirectedFileStatus(const Twine &OriginalPath, bool UseExternalNames, Status ExternalStatus)
static bool pathHasTraversal(StringRef Path)
static bool isTraversalComponent(StringRef Component)
Defines the virtual file system interface vfs::FileSystem.
static unsigned getSize(unsigned Kind)
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
iterator find(const_arg_type_t< KeyT > Val)
Represents either an error or a value T.
std::error_code getError() const
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
A smart pointer to a reference-counted object that inherits from RefCountedBase or ThreadSafeRefCount...
This interface provides simple read-only access to a block of memory, and provides simple methods for...
static ErrorOr< std::unique_ptr< MemoryBuffer > > getOpenFile(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Given an already-open file descriptor, read the file and return a MemoryBuffer.
static std::unique_ptr< MemoryBuffer > getMemBuffer(StringRef InputData, StringRef BufferName="", bool RequiresNullTerminator=true)
Open the specified memory range as a MemoryBuffer.
virtual StringRef getBufferIdentifier() const
Return an identifier for this buffer, typically the filename it was read from.
StringRef getBuffer() const
Represents a location in source code.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
StringRef str() const
Explicit conversion to StringRef.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
This owns the files read by a parser, handles include stacks, and handles diagnostic wrangling.
LLVM_ABI void PrintMessage(raw_ostream &OS, SMLoc Loc, DiagKind Kind, const Twine &Msg, ArrayRef< SMRange > Ranges={}, ArrayRef< SMFixIt > FixIts={}, bool ShowColors=true) const
Emit a message about the specified location with the specified string.
void(*)(const SMDiagnostic &, void *Context) DiagHandlerTy
Clients that want to handle their own diagnostics in a custom way can register a function pointer+con...
void setDiagHandler(DiagHandlerTy DH, void *Ctx=nullptr)
Specify a diagnostic handler to be invoked every time PrintMessage is called.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
StringRef - Represent a constant reference to a string, i.e.
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
std::string str() const
str - Get the contents as an std::string.
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
constexpr bool empty() const
empty - Check if the string is empty.
char back() const
back - Get the last character in the string.
StringRef slice(size_t Start, size_t End) const
Return a reference to the substring from [Start, End).
constexpr size_t size() const
size - Get the string size.
StringSet - A wrapper for StringMap that provides set-like functionality.
std::pair< typename Base::iterator, bool > insert(StringRef key)
Target - Wrapper for Target specific information.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
LLVM_ABI std::string str() const
Return the twine contents as a std::string.
LLVM_ABI void toVector(SmallVectorImpl< char > &Out) const
Append the concatenated string into the given SmallString or SmallVector.
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM_ABI void print(raw_ostream &O, bool IsForDebug=false, bool NoDetails=false) const
Print the current type.
LLVM Value Representation.
An efficient, type-erasing, non-owning reference to a callable.
An opaque object representing a hash code.
This class implements an extremely fast bulk output stream that can only output to a stream.
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
const std::string & path() const
directory_iterator - Iterates through the entries in path.
directory_iterator & increment(std::error_code &ec)
Represents the result of a call to sys::fs::status().
The virtual file system interface.
virtual llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const =0
Get the working directory of this file system.
virtual bool exists(const Twine &Path)
Check whether Path exists.
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,...
An in-memory file system.
std::error_code isLocal(const Twine &Path, bool &Result) override
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override
std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) override
Canonicalizes Path by combining with the current working directory and normalizing the path (e....
~InMemoryFileSystem() override
static constexpr size_t MaxSymlinkDepth
Arbitrary max depth to search through symlinks.
InMemoryFileSystem(bool UseNormalizedPaths=true)
bool useNormalizedPaths() const
Return true if this file system normalizes . and .. in paths.
void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override
llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override
bool addHardLink(const Twine &NewLink, const Twine &Target)
Add a hard link to a file.
std::string toString() const
bool addFileNoOwn(const Twine &Path, time_t ModificationTime, const llvm::MemoryBufferRef &Buffer, std::optional< uint32_t > User=std::nullopt, std::optional< uint32_t > Group=std::nullopt, std::optional< llvm::sys::fs::file_type > Type=std::nullopt, std::optional< llvm::sys::fs::perms > Perms=std::nullopt)
Add a buffer to the VFS with a path.
bool addSymbolicLink(const Twine &NewLink, const Twine &Target, time_t ModificationTime, std::optional< uint32_t > User=std::nullopt, std::optional< uint32_t > Group=std::nullopt, std::optional< llvm::sys::fs::perms > Perms=std::nullopt)
Add a symbolic link.
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
llvm::ErrorOr< Status > status(const Twine &Path) override
llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override
void visitChildFileSystems(VisitCallbackTy Callback) override
llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override
std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) override
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
void pushOverlay(IntrusiveRefCntPtr< FileSystem > FS)
Pushes a file system on top of the stack.
OverlayFileSystem(IntrusiveRefCntPtr< FileSystem > Base)
llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override
iterator overlays_end()
Get an iterator pointing one-past the least recently added file system.
std::error_code isLocal(const Twine &Path, bool &Result) override
bool exists(const Twine &Path) override
llvm::ErrorOr< Status > status(const Twine &Path) override
iterator overlays_begin()
Get an iterator pointing to the most recently added file system.
FileSystemList::reverse_iterator iterator
void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override
Directory iterator implementation for RedirectingFileSystem's directory entries.
std::error_code increment() override
Sets CurrentEntry to the next entry in the directory on success, to directory_entry() at end,...
RedirectingFSDirIterImpl(const Twine &Path, RedirectingFileSystem::DirectoryEntry::iterator Begin, RedirectingFileSystem::DirectoryEntry::iterator End, std::error_code &EC)
A helper class to hold the common YAML parsing state.
RedirectingFileSystemParser(yaml::Stream &S)
static RedirectingFileSystem::Entry * lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name, RedirectingFileSystem::Entry *ParentEntry=nullptr)
bool parse(yaml::Node *Root, RedirectingFileSystem *FS)
decltype(Contents)::iterator iterator
A single file or directory in the VFS.
StringRef getName() const
EntryKind getKind() const
A virtual file system parsed from a YAML file.
@ OverlayDir
The roots are relative to the directory where the Overlay YAML file.
@ CWD
The roots are relative to the current working directory.
bool exists(const Twine &Path) override
Check whether Path exists.
void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override
std::vector< llvm::StringRef > getRoots() const
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override
Get a directory_iterator for Dir.
ErrorOr< LookupResult > lookupPath(StringRef Path) const
Looks up Path in Roots and returns a LookupResult giving the matched entry and, if the entry was a Fi...
RedirectKind
The type of redirection to perform.
@ Fallthrough
Lookup the redirected path first (ie.
@ Fallback
Lookup the provided path first and if that fails, "fallback" to a lookup of the redirected path.
@ RedirectOnly
Only lookup the redirected path, do not lookup the originally provided path.
void setFallthrough(bool Fallthrough)
Sets the redirection kind to Fallthrough if true or RedirectOnly otherwise.
void visitChildFileSystems(VisitCallbackTy Callback) override
std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) override
Gets real path of Path e.g.
ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override
Get a File object for the 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...
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::fs::file_type getType() const
LLVM_ABI bool isRegularFile() const
LLVM_ABI bool isDirectory() const
StringRef getName() const
Returns the name that should be used for this file or directory.
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.
@ Resolved
Queried, materialization begun.
LLVM_ABI void make_absolute(const Twine ¤t_directory, SmallVectorImpl< char > &path)
Make path an absolute path.
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 StringRef filename(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get filename.
LLVM_ABI StringRef remove_leading_dotslash(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Remove redundant leading "./" pieces and consecutive separators.
LLVM_ABI bool is_absolute(const Twine &path, Style style=Style::native)
Is path absolute?
LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
LLVM_ABI reverse_iterator rend(StringRef path LLVM_LIFETIME_BOUND)
Get reverse end iterator over path.
LLVM_ABI reverse_iterator rbegin(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get reverse begin iterator over path.
LLVM_ABI const_iterator end(StringRef path LLVM_LIFETIME_BOUND)
Get end iterator over path.
LLVM_ABI bool is_separator(char value, Style style=Style::native)
Check whether the given char is a path separator on the host OS.
std::chrono::time_point< std::chrono::system_clock, D > TimePoint
A time point on the system clock.
TimePoint< std::chrono::seconds > toTimePoint(std::time_t T)
Convert a std::time_t to a TimePoint.
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 void collectVFSFromYAML(std::unique_ptr< llvm::MemoryBuffer > Buffer, llvm::SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, SmallVectorImpl< YAMLVFSEntry > &CollectedEntries, void *DiagContext=nullptr, IntrusiveRefCntPtr< FileSystem > ExternalFS=getRealFileSystem())
Collect all pairs of <virtual path, real path> entries from the YAMLFilePath.
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.
std::error_code make_error_code(BitcodeError E)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
@ no_such_file_or_directory
@ operation_not_permitted
auto reverse(ContainerTy &&C)
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
LLVM_ABI Error write(MCStreamer &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue)
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
const char * toString(DWARFSectionKind Kind)
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.
Represents the result of a path lookup into the RedirectingFileSystem.
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.
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
std::unique_ptr< llvm::MemoryBuffer > Buffer