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) {
124 return (*F)->getBuffer(
Name, FileSize, RequiresNullTerminator, IsVolatile);
133 return WorkingDir.getError();
153#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
159 return Component.equals(
"..") || Component.equals(
".");
179class RealFile :
public File {
180 friend class RealFileSystem;
184 std::string RealName;
187 : FD(RawFD), S(NewName, {}, {}, {}, {}, {},
189 RealName(NewRealPathName.str()) {
190 assert(FD != kInvalidFile &&
"Invalid or inactive file descriptor");
194 ~RealFile()
override;
200 bool RequiresNullTerminator,
201 bool IsVolatile)
override;
202 std::error_code close()
override;
203 void setPath(
const Twine &Path)
override;
208RealFile::~RealFile() { close(); }
211 assert(FD != kInvalidFile &&
"cannot stat closed file");
212 if (!S.isStatusKnown()) {
222 return RealName.empty() ? S.getName().str() : RealName;
226RealFile::getBuffer(
const Twine &
Name, int64_t FileSize,
227 bool RequiresNullTerminator,
bool IsVolatile) {
228 assert(FD != kInvalidFile &&
"cannot get buffer for closed file");
233std::error_code RealFile::close() {
239void RealFile::setPath(
const Twine &Path) {
240 RealName =
Path.str();
257 explicit RealFileSystem(
bool LinkCWDToProcess) {
258 if (!LinkCWDToProcess) {
274 std::error_code setCurrentWorkingDirectory(
const Twine &Path)
override;
275 std::error_code isLocal(
const Twine &Path,
bool &Result)
override;
276 std::error_code getRealPath(
const Twine &Path,
281 unsigned IndentLevel)
const override;
289 Path.toVector(Storage);
294 struct WorkingDirectory {
300 std::optional<WorkingDirectory> WD;
308 if (std::error_code EC =
315RealFileSystem::openFileForRead(
const Twine &
Name) {
321 return std::unique_ptr<File>(
322 new RealFile(*FDOrErr,
Name.str(), RealName.
str()));
327 return std::string(WD->Specified.str());
332 return std::string(Dir.
str());
335std::error_code RealFileSystem::setCurrentWorkingDirectory(
const Twine &Path) {
340 adjustPath(Path, Storage).toVector(Absolute);
345 return std::make_error_code(std::errc::not_a_directory);
349 return std::error_code();
352std::error_code RealFileSystem::isLocal(
const Twine &Path,
bool &Result) {
358RealFileSystem::getRealPath(
const Twine &Path,
365 unsigned IndentLevel)
const {
366 printIndent(
OS, IndentLevel);
367 OS <<
"RealFileSystem using ";
381 return std::make_unique<RealFileSystem>(
false);
390 RealFSDirIter(
const Twine &Path, std::error_code &EC) : Iter(Path, EC) {
395 std::error_code increment()
override {
408 std::error_code &EC) {
411 std::make_shared<RealFSDirIter>(adjustPath(Dir, Storage), EC));
443 auto Result = (*I)->openFileForRead(Path);
453 return FSList.
front()->getCurrentWorkingDirectory();
458 for (
auto &FS : FSList)
459 if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))
465 for (
auto &FS : FSList)
466 if (FS->exists(Path))
467 return FS->isLocal(Path, Result);
474 for (
const auto &FS : FSList)
475 if (FS->exists(Path))
476 return FS->getRealPath(Path, Output);
481 unsigned IndentLevel)
const {
483 OS <<
"OverlayFileSystem\n";
490 FS->print(
OS,
Type, IndentLevel + 1);
510 std::error_code incrementIter(
bool IsFirstTime) {
511 while (!IterList.
empty()) {
512 CurrentDirIter = IterList.
back();
519 return errc::no_such_file_or_directory;
523 std::error_code incrementDirIter(
bool IsFirstTime) {
525 "incrementing past end");
530 EC = incrementIter(IsFirstTime);
534 std::error_code incrementImpl(
bool IsFirstTime) {
536 std::error_code
EC = incrementDirIter(IsFirstTime);
541 CurrentEntry = *CurrentDirIter;
551 std::error_code &EC) {
552 for (
auto FS : FileSystems) {
555 if (FEC && FEC != errc::no_such_file_or_directory) {
562 EC = incrementImpl(
true);
567 : IterList(DirIters.
begin(), DirIters.
end()) {
568 EC = incrementImpl(
true);
571 std::error_code increment()
override {
return incrementImpl(
false); }
577 std::error_code &EC) {
579 std::make_shared<CombiningDirIterImpl>(FSList, Dir.
str(), EC));
585void ProxyFileSystem::anchor() {}
603 std::string FileName;
607 : Kind(Kind), FileName(
std::
string(
llvm::sys::path::filename(FileName))) {
619 virtual std::string
toString(
unsigned Indent)
const = 0;
624 std::unique_ptr<llvm::MemoryBuffer> Buffer;
632 return Status::copyWithNewName(Stat, RequestedName);
636 std::string
toString(
unsigned Indent)
const override {
637 return (std::string(Indent,
' ') + Stat.
getName() +
"\n").str();
647class InMemoryHardLink :
public InMemoryNode {
648 const InMemoryFile &ResolvedFile;
651 InMemoryHardLink(
StringRef Path,
const InMemoryFile &ResolvedFile)
652 : InMemoryNode(Path, IME_HardLink), ResolvedFile(ResolvedFile) {}
653 const InMemoryFile &getResolvedFile()
const {
return ResolvedFile; }
655 Status getStatus(
const Twine &RequestedName)
const override {
656 return ResolvedFile.getStatus(RequestedName);
659 std::string
toString(
unsigned Indent)
const override {
660 return std::string(Indent,
' ') +
"HardLink to -> " +
661 ResolvedFile.toString(0);
664 static bool classof(
const InMemoryNode *
N) {
669class InMemorySymbolicLink :
public InMemoryNode {
670 std::string TargetPath;
678 std::string
toString(
unsigned Indent)
const override {
679 return std::string(Indent,
' ') +
"SymbolicLink to -> " + TargetPath;
682 Status getStatus(
const Twine &RequestedName)
const override {
683 return Status::copyWithNewName(Stat, RequestedName);
686 StringRef getTargetPath()
const {
return TargetPath; }
688 static bool classof(
const InMemoryNode *
N) {
696class InMemoryFileAdaptor :
public File {
697 const InMemoryFile &
Node;
699 std::string RequestedName;
702 explicit InMemoryFileAdaptor(
const InMemoryFile &
Node,
703 std::string RequestedName)
707 return Node.getStatus(RequestedName);
711 getBuffer(
const Twine &
Name, int64_t FileSize,
bool RequiresNullTerminator,
712 bool IsVolatile)
override {
718 std::error_code close()
override {
return {}; }
720 void setPath(
const Twine &Path)
override { RequestedName =
Path.str(); }
736 return Status::copyWithNewName(Stat, RequestedName);
742 auto I = Entries.find(
Name);
743 if (
I != Entries.end())
744 return I->second.get();
749 return Entries.insert(make_pair(
Name, std::move(Child)))
750 .first->second.get();
758 std::string
toString(
unsigned Indent)
const override {
760 (std::string(Indent,
' ') + Stat.
getName() +
"\n").str();
761 for (
const auto &Entry : Entries)
762 Result += Entry.second->toString(Indent + 2);
792 (
Type == sys::fs::file_type::directory_file)
794 :
getFileID(DirUID,
Name, Buffer ? Buffer->getBuffer() :
"");
797 Group, Buffer ? Buffer->getBufferSize() : 0,
Type, Perms);
801 : Root(new detail::InMemoryDirectory(
804 llvm::sys::fs::file_type::directory_file,
805 llvm::sys::fs::perms::all_all))),
806 UseNormalizedPaths(UseNormalizedPaths) {}
811 return Root->toString(0);
814bool InMemoryFileSystem::addFile(
const Twine &
P, time_t ModificationTime,
815 std::unique_ptr<llvm::MemoryBuffer> Buffer,
816 std::optional<uint32_t>
User,
817 std::optional<uint32_t> Group,
818 std::optional<llvm::sys::fs::file_type>
Type,
819 std::optional<llvm::sys::fs::perms> Perms,
820 MakeNodeFn MakeNode) {
837 const auto ResolvedUser =
User.value_or(0);
838 const auto ResolvedGroup = Group.value_or(0);
853 std::move(Buffer), ResolvedUser, ResolvedGroup,
854 ResolvedType, ResolvedPerms}));
860 StringRef(Path.str().begin(),
Name.end() - Path.str().begin()),
864 Dir = cast<detail::InMemoryDirectory>(Dir->
addChild(
865 Name, std::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
869 if (
auto *NewDir = dyn_cast<detail::InMemoryDirectory>(
Node)) {
873 isa<detail::InMemoryHardLink>(
Node)) &&
874 "Must be either file, hardlink or directory!");
881 if (
auto Link = dyn_cast<detail::InMemoryHardLink>(
Node)) {
882 return Link->getResolvedFile().getBuffer()->getBuffer() ==
885 return cast<detail::InMemoryFile>(
Node)->getBuffer()->getBuffer() ==
891bool InMemoryFileSystem::addFile(
const Twine &
P, time_t ModificationTime,
892 std::unique_ptr<llvm::MemoryBuffer> Buffer,
893 std::optional<uint32_t>
User,
894 std::optional<uint32_t> Group,
895 std::optional<llvm::sys::fs::file_type>
Type,
896 std::optional<llvm::sys::fs::perms> Perms) {
897 return addFile(
P, ModificationTime, std::move(Buffer),
User, Group,
Type,
900 -> std::unique_ptr<detail::InMemoryNode> {
903 return std::make_unique<detail::InMemoryDirectory>(Stat);
904 return std::make_unique<detail::InMemoryFile>(
905 Stat, std::move(NNI.
Buffer));
910 const Twine &
P, time_t ModificationTime,
912 std::optional<uint32_t> Group, std::optional<llvm::sys::fs::file_type>
Type,
913 std::optional<llvm::sys::fs::perms> Perms) {
915 std::move(
User), std::move(Group), std::move(
Type),
918 -> std::unique_ptr<detail::InMemoryNode> {
921 return std::make_unique<detail::InMemoryDirectory>(Stat);
922 return std::make_unique<detail::InMemoryFile>(
923 Stat, std::move(NNI.
Buffer));
928InMemoryFileSystem::lookupNode(
const Twine &
P,
bool FollowFinalSymlink,
929 size_t SymlinkDepth)
const {
952 if (
auto Symlink = dyn_cast<detail::InMemorySymbolicLink>(Node)) {
955 if (
I ==
E && !FollowFinalSymlink)
970 lookupNode(TargetPath,
true, SymlinkDepth + 1);
974 if (!isa<detail::InMemoryDirectory>(*
Target))
978 Dir = cast<detail::InMemoryDirectory>(*
Target);
983 if (
auto File = dyn_cast<detail::InMemoryFile>(Node)) {
990 if (
auto File = dyn_cast<detail::InMemoryHardLink>(
Node)) {
996 Dir = cast<detail::InMemoryDirectory>(
Node);
1004 auto NewLinkNode = lookupNode(NewLink,
false);
1008 auto TargetNode = lookupNode(
Target,
true);
1011 if (!TargetNode || NewLinkNode || !isa<detail::InMemoryFile>(*TargetNode))
1013 return addFile(NewLink, 0,
nullptr, std::nullopt, std::nullopt, std::nullopt,
1015 return std::make_unique<detail::InMemoryHardLink>(
1017 *cast<detail::InMemoryFile>(*TargetNode));
1023 std::optional<uint32_t>
User, std::optional<uint32_t> Group,
1024 std::optional<llvm::sys::fs::perms> Perms) {
1025 auto NewLinkNode = lookupNode(NewLink,
false);
1031 Target.toVector(TargetStr);
1033 return addFile(NewLinkStr, ModificationTime,
nullptr,
User, Group,
1036 return std::make_unique<detail::InMemorySymbolicLink>(
1042 auto Node = lookupNode(Path,
true);
1044 return (*Node)->getStatus(Path);
1045 return Node.getError();
1050 auto Node = lookupNode(Path,
true);
1052 return Node.getError();
1056 if (
auto *
F = dyn_cast<detail::InMemoryFile>(*Node))
1057 return std::unique_ptr<File>(
1058 new detail::InMemoryFileAdaptor(*
F, Path.str()));
1069 std::string RequestedDirName;
1071 void setCurrentEntry() {
1076 switch (
I->second->getKind()) {
1085 if (
auto SymlinkTarget =
1086 FS->lookupNode(Path,
true)) {
1087 Path = SymlinkTarget.getName();
1088 Type = (*SymlinkTarget)->getStatus(Path).getType();
1105 std::string RequestedDirName)
1106 : FS(FS),
I(Dir.begin()), E(Dir.end()),
1107 RequestedDirName(
std::
move(RequestedDirName)) {
1119 std::error_code &EC) {
1120 auto Node = lookupNode(Dir,
true);
1122 EC = Node.getError();
1126 if (
auto *DirNode = dyn_cast<detail::InMemoryDirectory>(*Node))
1128 std::make_shared<DirIterator>(
this, *DirNode, Dir.
str()));
1147 WorkingDirectory = std::string(Path.str());
1155 if (!CWD || CWD->empty())
1157 Path.toVector(Output);
1170 unsigned IndentLevel)
const {
1172 OS <<
"InMemoryFileSystem\n";
1187 const size_t n = Path.find_first_of(
"/\\");
1189 if (n !=
static_cast<size_t>(-1))
1209static bool isFileNotFound(std::error_code EC,
1211 if (
E && !isa<RedirectingFileSystem::DirectoryRemapEntry>(
E))
1222 if (
auto ExternalWorkingDirectory =
1223 ExternalFS->getCurrentWorkingDirectory()) {
1224 WorkingDirectory = *ExternalWorkingDirectory;
1235 std::error_code incrementImpl(
bool IsFirstTime) {
1236 assert((IsFirstTime || Current != End) &&
"cannot iterate past end");
1239 if (Current != End) {
1243 switch ((*Current)->getKind()) {
1264 : Dir(Path.str()), Current(Begin), End(End) {
1265 EC = incrementImpl(
true);
1269 return incrementImpl(
false);
1283 RedirectingFSDirRemapIterImpl(std::string DirPath,
1285 : Dir(
std::
move(DirPath)), DirStyle(getExistingStyle(Dir)),
1286 ExternalIter(ExtIter) {
1291 void setCurrentEntry() {
1302 std::error_code increment()
override {
1316 return WorkingDirectory;
1326 Path.toVector(AbsolutePath);
1327 if (std::error_code EC = makeAbsolute(AbsolutePath))
1329 WorkingDirectory = std::string(AbsolutePath.
str());
1338 if (std::error_code EC = makeCanonical(Path))
1341 return ExternalFS->isLocal(Path, Result);
1356 return WorkingDir.getError();
1358 return makeAbsolute(WorkingDir.get(), Path);
1362RedirectingFileSystem::makeAbsolute(
StringRef WorkingDir,
1368 if (!WorkingDir.
empty() &&
1372 return std::error_code();
1384 std::string
Result = std::string(WorkingDir);
1401 std::error_code &EC) {
1405 EC = makeCanonical(Path);
1412 isFileNotFound(Result.getError()))
1413 return ExternalFS->dir_begin(Path, EC);
1415 EC = Result.getError();
1423 isFileNotFound(S.
getError(), Result->E))
1424 return ExternalFS->dir_begin(Dir, EC);
1430 if (!S->isDirectory()) {
1438 std::error_code RedirectEC;
1439 if (
auto ExtRedirect = Result->getExternalRedirect()) {
1440 auto RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
1441 RedirectIter = ExternalFS->dir_begin(*ExtRedirect, RedirectEC);
1443 if (!RE->useExternalName(UseExternalNames)) {
1447 std::string(Path), RedirectIter));
1450 auto DE = cast<DirectoryEntry>(Result->E);
1453 Path, DE->contents_begin(), DE->contents_end(), RedirectEC));
1466 return RedirectIter;
1469 std::error_code ExternalEC;
1480 switch (Redirection) {
1494 std::make_shared<CombiningDirIterImpl>(Iters, EC)};
1501 OverlayFileDir = Dir.
str();
1505 return OverlayFileDir;
1522 std::vector<StringRef> R;
1523 R.reserve(Roots.size());
1524 for (
const auto &Root : Roots)
1525 R.push_back(Root->getName());
1530 unsigned IndentLevel)
const {
1532 OS <<
"RedirectingFileSystem (UseExternalNames: "
1533 << (UseExternalNames ?
"true" :
"false") <<
")\n";
1537 for (
const auto &Root : Roots)
1541 OS <<
"ExternalFS:\n";
1548 unsigned IndentLevel)
const {
1550 OS <<
"'" <<
E->getName() <<
"'";
1552 switch (
E->getKind()) {
1554 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(
E);
1557 for (std::unique_ptr<Entry> &SubEntry :
1564 auto *RE = cast<RedirectingFileSystem::RemapEntry>(
E);
1565 OS <<
" -> '" << RE->getExternalContentsPath() <<
"'";
1566 switch (RE->getUseName()) {
1570 OS <<
" (UseExternalName: true)";
1573 OS <<
" (UseExternalName: false)";
1591 const auto *S = dyn_cast<yaml::ScalarNode>(
N);
1594 error(
N,
"expected string");
1597 Result = S->getValue(Storage);
1602 bool parseScalarBool(
yaml::Node *
N,
bool &Result) {
1605 if (!parseScalarString(
N,
Value, Storage))
1608 if (
Value.equals_insensitive(
"true") ||
Value.equals_insensitive(
"on") ||
1609 Value.equals_insensitive(
"yes") ||
Value ==
"1") {
1612 }
else if (
Value.equals_insensitive(
"false") ||
1613 Value.equals_insensitive(
"off") ||
1614 Value.equals_insensitive(
"no") ||
Value ==
"0") {
1619 error(
N,
"expected boolean value");
1623 std::optional<RedirectingFileSystem::RedirectKind>
1627 if (!parseScalarString(
N,
Value, Storage))
1628 return std::nullopt;
1630 if (
Value.equals_insensitive(
"fallthrough")) {
1632 }
else if (
Value.equals_insensitive(
"fallback")) {
1634 }
else if (
Value.equals_insensitive(
"redirect-only")) {
1637 return std::nullopt;
1640 std::optional<RedirectingFileSystem::RootRelativeKind>
1644 if (!parseScalarString(
N,
Value, Storage))
1645 return std::nullopt;
1646 if (
Value.equals_insensitive(
"cwd")) {
1648 }
else if (
Value.equals_insensitive(
"overlay-dir")) {
1651 return std::nullopt;
1658 KeyStatus(
bool Required =
false) : Required(Required) {}
1661 using KeyStatusPair = std::pair<StringRef, KeyStatus>;
1666 if (!
Keys.count(Key)) {
1667 error(KeyNode,
"unknown key");
1670 KeyStatus &S =
Keys[Key];
1672 error(KeyNode,
Twine(
"duplicate key '") + Key +
"'");
1681 for (
const auto &
I :
Keys) {
1682 if (
I.second.Required && !
I.second.Seen) {
1683 error(Obj,
Twine(
"missing key '") +
I.first +
"'");
1695 for (
const auto &Root : FS->Roots) {
1696 if (
Name.equals(Root->getName())) {
1697 ParentEntry = Root.get();
1702 auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
1703 for (std::unique_ptr<RedirectingFileSystem::Entry> &
Content :
1706 dyn_cast<RedirectingFileSystem::DirectoryEntry>(
Content.get());
1707 if (DirContent &&
Name.equals(
Content->getName()))
1713 std::unique_ptr<RedirectingFileSystem::Entry>
E =
1714 std::make_unique<RedirectingFileSystem::DirectoryEntry>(
1716 std::chrono::system_clock::now(), 0, 0, 0,
1720 FS->Roots.push_back(std::move(
E));
1721 ParentEntry = FS->Roots.back().get();
1725 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
1726 DE->addContent(std::move(
E));
1727 return DE->getLastContent();
1737 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
1743 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
1745 uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
1749 assert(NewParentE &&
"Parent entry must exist");
1750 auto *DR = cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
1751 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
1753 std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
1754 Name, DR->getExternalContentsPath(), DR->getUseName()));
1758 assert(NewParentE &&
"Parent entry must exist");
1759 auto *FE = cast<RedirectingFileSystem::FileEntry>(SrcE);
1760 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
1761 DE->addContent(std::make_unique<RedirectingFileSystem::FileEntry>(
1762 Name, FE->getExternalContentsPath(), FE->getUseName()));
1768 std::unique_ptr<RedirectingFileSystem::Entry>
1770 auto *
M = dyn_cast<yaml::MappingNode>(
N);
1772 error(
N,
"expected mapping node for file or directory entry");
1776 KeyStatusPair Fields[] = {
1777 KeyStatusPair(
"name",
true),
1778 KeyStatusPair(
"type",
true),
1779 KeyStatusPair(
"contents",
false),
1780 KeyStatusPair(
"external-contents",
false),
1781 KeyStatusPair(
"use-external-name",
false),
1786 enum { CF_NotSet, CF_List, CF_External } ContentsField = CF_NotSet;
1787 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>>
1795 for (
auto &
I : *M) {
1800 if (!parseScalarString(
I.getKey(), Key, Buffer))
1803 if (!checkDuplicateOrUnknownKey(
I.getKey(), Key,
Keys))
1807 if (Key ==
"name") {
1808 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1811 NameValueNode =
I.getValue();
1815 }
else if (Key ==
"type") {
1816 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1818 if (
Value ==
"file")
1820 else if (
Value ==
"directory")
1822 else if (
Value ==
"directory-remap")
1825 error(
I.getValue(),
"unknown value for 'type'");
1828 }
else if (Key ==
"contents") {
1829 if (ContentsField != CF_NotSet) {
1831 "entry already has 'contents' or 'external-contents'");
1834 ContentsField = CF_List;
1835 auto *Contents = dyn_cast<yaml::SequenceNode>(
I.getValue());
1838 error(
I.getValue(),
"expected array");
1842 for (
auto &
I : *Contents) {
1843 if (std::unique_ptr<RedirectingFileSystem::Entry>
E =
1844 parseEntry(&
I, FS,
false))
1845 EntryArrayContents.push_back(std::move(
E));
1849 }
else if (Key ==
"external-contents") {
1850 if (ContentsField != CF_NotSet) {
1852 "entry already has 'contents' or 'external-contents'");
1855 ContentsField = CF_External;
1856 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1860 if (
FS->IsRelativeOverlay) {
1861 FullPath =
FS->getOverlayFileDir();
1863 "External contents prefix directory must exist");
1871 FullPath = canonicalize(FullPath);
1872 ExternalContentsPath = FullPath.
str();
1873 }
else if (Key ==
"use-external-name") {
1875 if (!parseScalarBool(
I.getValue(), Val))
1888 if (ContentsField == CF_NotSet) {
1889 error(
N,
"missing key 'contents' or 'external-contents'");
1892 if (!checkMissingKeys(
N,
Keys))
1898 error(
N,
"'use-external-name' is not supported for 'directory' entries");
1903 ContentsField == CF_List) {
1904 error(
N,
"'contents' is not supported for 'directory-remap' entries");
1922 if (
FS->RootRelative ==
1925 assert(!FullPath.
empty() &&
"Overlay file directory must exist");
1926 EC =
FS->makeAbsolute(FullPath,
Name);
1932 assert(NameValueNode &&
"Name presence should be checked earlier");
1935 "entry with relative path at the root level is not discoverable");
1953 while (Trimmed.
size() > RootPathLen &&
1955 Trimmed = Trimmed.
slice(0, Trimmed.
size() - 1);
1960 std::unique_ptr<RedirectingFileSystem::Entry>
Result;
1963 Result = std::make_unique<RedirectingFileSystem::FileEntry>(
1964 LastComponent, std::move(ExternalContentsPath), UseExternalName);
1967 Result = std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
1968 LastComponent, std::move(ExternalContentsPath), UseExternalName);
1971 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
1972 LastComponent, std::move(EntryArrayContents),
1986 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> Entries;
1987 Entries.push_back(std::move(Result));
1988 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
1989 *
I, std::move(Entries),
2001 auto *Top = dyn_cast<yaml::MappingNode>(Root);
2003 error(Root,
"expected mapping node");
2007 KeyStatusPair Fields[] = {
2008 KeyStatusPair(
"version",
true),
2009 KeyStatusPair(
"case-sensitive",
false),
2010 KeyStatusPair(
"use-external-names",
false),
2011 KeyStatusPair(
"root-relative",
false),
2012 KeyStatusPair(
"overlay-relative",
false),
2013 KeyStatusPair(
"fallthrough",
false),
2014 KeyStatusPair(
"redirecting-with",
false),
2015 KeyStatusPair(
"roots",
true),
2019 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> RootEntries;
2022 for (
auto &
I : *Top) {
2025 if (!parseScalarString(
I.getKey(), Key, KeyBuffer))
2028 if (!checkDuplicateOrUnknownKey(
I.getKey(), Key,
Keys))
2031 if (Key ==
"roots") {
2032 auto *Roots = dyn_cast<yaml::SequenceNode>(
I.getValue());
2034 error(
I.getValue(),
"expected array");
2038 for (
auto &
I : *Roots) {
2039 if (std::unique_ptr<RedirectingFileSystem::Entry>
E =
2040 parseEntry(&
I, FS,
true))
2041 RootEntries.push_back(std::move(
E));
2045 }
else if (Key ==
"version") {
2048 if (!parseScalarString(
I.getValue(), VersionString, Storage))
2052 error(
I.getValue(),
"expected integer");
2056 error(
I.getValue(),
"invalid version number");
2060 error(
I.getValue(),
"version mismatch, expected 0");
2063 }
else if (Key ==
"case-sensitive") {
2064 if (!parseScalarBool(
I.getValue(), FS->CaseSensitive))
2066 }
else if (Key ==
"overlay-relative") {
2067 if (!parseScalarBool(
I.getValue(), FS->IsRelativeOverlay))
2069 }
else if (Key ==
"use-external-names") {
2070 if (!parseScalarBool(
I.getValue(), FS->UseExternalNames))
2072 }
else if (Key ==
"fallthrough") {
2073 if (
Keys[
"redirecting-with"].Seen) {
2075 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2079 bool ShouldFallthrough =
false;
2080 if (!parseScalarBool(
I.getValue(), ShouldFallthrough))
2083 if (ShouldFallthrough) {
2088 }
else if (Key ==
"redirecting-with") {
2089 if (
Keys[
"fallthrough"].Seen) {
2091 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2095 if (
auto Kind = parseRedirectKind(
I.getValue())) {
2096 FS->Redirection = *Kind;
2098 error(
I.getValue(),
"expected valid redirect kind");
2101 }
else if (Key ==
"root-relative") {
2102 if (
auto Kind = parseRootRelativeKind(
I.getValue())) {
2103 FS->RootRelative = *Kind;
2105 error(
I.getValue(),
"expected valid root-relative kind");
2116 if (!checkMissingKeys(Top,
Keys))
2122 for (
auto &
E : RootEntries)
2123 uniqueOverlayTree(FS,
E.get());
2129std::unique_ptr<RedirectingFileSystem>
2132 StringRef YAMLFilePath,
void *DiagContext,
2140 if (DI == Stream.
end() || !Root) {
2147 std::unique_ptr<RedirectingFileSystem> FS(
2150 if (!YAMLFilePath.
empty()) {
2161 assert(!EC &&
"Overlay dir final path must be absolute");
2163 FS->setOverlayFileDir(OverlayAbsDir);
2166 if (!
P.parse(Root, FS.get()))
2173 ArrayRef<std::pair<std::string, std::string>> RemappedFiles,
2174 bool UseExternalNames,
FileSystem &ExternalFS) {
2175 std::unique_ptr<RedirectingFileSystem> FS(
2177 FS->UseExternalNames = UseExternalNames;
2187 assert(!EC &&
"Could not make absolute path");
2205 assert(Parent &&
"File without a directory?");
2209 assert(!EC &&
"Could not make absolute path");
2213 auto NewFile = std::make_unique<RedirectingFileSystem::FileEntry>(
2217 ToEntry = NewFile.get();
2218 cast<RedirectingFileSystem::DirectoryEntry>(Parent)->addContent(
2219 std::move(NewFile));
2232 if (
auto *DRE = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(
E)) {
2235 getExistingStyle(DRE->getExternalContentsPath()));
2236 ExternalRedirect = std::string(Redirect);
2242 if (std::error_code EC = makeAbsolute(Path))
2246 canonicalize(
StringRef(Path.data(), Path.size()));
2247 if (CanonicalPath.
empty())
2250 Path.assign(CanonicalPath.
begin(), CanonicalPath.
end());
2258 for (
const auto &Root : Roots) {
2260 lookupPathImpl(Start, End, Root.get());
2268RedirectingFileSystem::lookupPathImpl(
2273 "Paths should not contain traversal components");
2278 if (!FromName.
empty()) {
2279 if (!pathComponentMatches(*Start, FromName))
2286 return LookupResult(
From, Start, End);
2290 if (isa<RedirectingFileSystem::FileEntry>(
From))
2293 if (isa<RedirectingFileSystem::DirectoryRemapEntry>(
From))
2294 return LookupResult(
From, Start, End);
2296 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(
From);
2297 for (
const std::unique_ptr<RedirectingFileSystem::Entry> &DirEntry :
2300 lookupPathImpl(Start, End, DirEntry.get());
2309 bool UseExternalNames,
2314 return ExternalStatus;
2316 Status S = ExternalStatus;
2317 if (!UseExternalNames)
2326 const Twine &CanonicalPath,
const Twine &OriginalPath,
2328 if (std::optional<StringRef> ExtRedirect =
Result.getExternalRedirect()) {
2330 if (std::error_code EC = makeCanonical(CanonicalRemappedPath))
2337 auto *RE = cast<RedirectingFileSystem::RemapEntry>(
Result.E);
2339 RE->useExternalName(UseExternalNames), *S);
2342 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(
Result.E);
2347RedirectingFileSystem::getExternalStatus(
const Twine &CanonicalPath,
2348 const Twine &OriginalPath)
const {
2349 auto Result = ExternalFS->status(CanonicalPath);
2353 if (!Result ||
Result->ExposesExternalVFSPath)
2360 OriginalPath.
toVector(CanonicalPath);
2362 if (std::error_code EC = makeCanonical(CanonicalPath))
2379 isFileNotFound(Result.getError()))
2380 return getExternalStatus(CanonicalPath, OriginalPath);
2381 return Result.getError();
2386 isFileNotFound(S.
getError(), Result->E)) {
2390 return getExternalStatus(CanonicalPath, OriginalPath);
2399class FileWithFixedStatus :
public File {
2400 std::unique_ptr<File> InnerFile;
2404 FileWithFixedStatus(std::unique_ptr<File> InnerFile,
Status S)
2410 getBuffer(
const Twine &
Name, int64_t FileSize,
bool RequiresNullTerminator,
2411 bool IsVolatile)
override {
2412 return InnerFile->getBuffer(
Name, FileSize, RequiresNullTerminator,
2416 std::error_code close()
override {
return InnerFile->close(); }
2427 if (!Result || (*Result)->status()->ExposesExternalVFSPath)
2431 auto Name =
F->get()->getName();
2433 F->get()->setPath(
P);
2440 OriginalPath.
toVector(CanonicalPath);
2442 if (std::error_code EC = makeCanonical(CanonicalPath))
2460 isFileNotFound(Result.getError()))
2463 return Result.getError();
2466 if (!Result->getExternalRedirect())
2469 StringRef ExtRedirect = *Result->getExternalRedirect();
2471 if (std::error_code EC = makeCanonical(CanonicalRemappedPath))
2474 auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
2477 ExternalFS->openFileForRead(CanonicalRemappedPath), ExtRedirect);
2478 if (!ExternalFile) {
2480 isFileNotFound(ExternalFile.getError(), Result->E)) {
2487 return ExternalFile;
2490 auto ExternalStatus = (*ExternalFile)->status();
2491 if (!ExternalStatus)
2492 return ExternalStatus.getError();
2497 OriginalPath, RE->useExternalName(UseExternalNames), *ExternalStatus);
2498 return std::unique_ptr<File>(
2499 std::make_unique<FileWithFixedStatus>(std::move(*ExternalFile), S));
2506 OriginalPath.
toVector(CanonicalPath);
2508 if (std::error_code EC = makeCanonical(CanonicalPath))
2514 std::error_code EC = ExternalFS->getRealPath(CanonicalPath, Output);
2525 isFileNotFound(Result.getError()))
2526 return ExternalFS->getRealPath(CanonicalPath, Output);
2527 return Result.getError();
2532 if (
auto ExtRedirect = Result->getExternalRedirect()) {
2533 auto P = ExternalFS->getRealPath(*ExtRedirect, Output);
2535 isFileNotFound(
P, Result->E)) {
2539 return ExternalFS->getRealPath(CanonicalPath, Output);
2547 return ExternalFS->getRealPath(CanonicalPath, Output);
2551std::unique_ptr<FileSystem>
2554 StringRef YAMLFilePath,
void *DiagContext,
2557 YAMLFilePath, DiagContext,
2558 std::move(ExternalFS));
2566 auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
2567 assert(DE &&
"Must be a directory");
2568 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
2570 Path.push_back(SubEntry->getName());
2578 auto *DR = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
2579 assert(DR &&
"Must be a directory remap");
2581 for (
auto &Comp : Path)
2589 auto *FE = dyn_cast<RedirectingFileSystem::FileEntry>(SrcE);
2590 assert(FE &&
"Must be a file");
2592 for (
auto &Comp : Path)
2604 std::move(Buffer),
DiagHandler, YAMLFilePath, DiagContext,
2605 std::move(ExternalFS));
2609 VFS->lookupPath(
"/");
2618 static std::atomic<unsigned> UID;
2619 unsigned ID = ++UID;
2622 return UniqueID(std::numeric_limits<uint64_t>::max(),
ID);
2630 Mappings.emplace_back(VirtualPath, RealPath, IsDirectory);
2634 addEntry(VirtualPath, RealPath,
false);
2639 addEntry(VirtualPath, RealPath,
true);
2648 unsigned getDirIndent() {
return 4 * DirStack.
size(); }
2649 unsigned getFileIndent() {
return 4 * (DirStack.
size() + 1); }
2653 void endDirectory();
2660 std::optional<bool> UseExternalNames,
2661 std::optional<bool> IsCaseSensitive,
2662 std::optional<bool> IsOverlayRelative,
StringRef OverlayDir);
2673 IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
2674 if (*IParent != *IChild)
2678 return IParent == EParent;
2683 assert(containedIn(Parent, Path));
2687void JSONWriter::startDirectory(
StringRef Path) {
2689 DirStack.
empty() ?
Path : containedPart(DirStack.
back(), Path);
2691 unsigned Indent = getDirIndent();
2693 OS.
indent(Indent + 2) <<
"'type': 'directory',\n";
2695 OS.
indent(Indent + 2) <<
"'contents': [\n";
2698void JSONWriter::endDirectory() {
2699 unsigned Indent = getDirIndent();
2707 unsigned Indent = getFileIndent();
2709 OS.
indent(Indent + 2) <<
"'type': 'file',\n";
2711 OS.
indent(Indent + 2) <<
"'external-contents': \""
2717 std::optional<bool> UseExternalNames,
2718 std::optional<bool> IsCaseSensitive,
2719 std::optional<bool> IsOverlayRelative,
2725 if (IsCaseSensitive)
2726 OS <<
" 'case-sensitive': '" << (*IsCaseSensitive ?
"true" :
"false")
2728 if (UseExternalNames)
2729 OS <<
" 'use-external-names': '" << (*UseExternalNames ?
"true" :
"false")
2731 bool UseOverlayRelative =
false;
2732 if (IsOverlayRelative) {
2733 UseOverlayRelative = *IsOverlayRelative;
2734 OS <<
" 'overlay-relative': '" << (UseOverlayRelative ?
"true" :
"false")
2737 OS <<
" 'roots': [\n";
2739 if (!Entries.empty()) {
2747 if (UseOverlayRelative) {
2750 "Overlay dir must be contained in RPath");
2754 bool IsCurrentDirEmpty =
true;
2755 if (!Entry.IsDirectory) {
2757 IsCurrentDirEmpty =
false;
2760 for (
const auto &Entry : Entries.slice(1)) {
2763 if (Dir == DirStack.
back()) {
2764 if (!IsCurrentDirEmpty) {
2768 bool IsDirPoppedFromStack =
false;
2769 while (!DirStack.
empty() && !containedIn(DirStack.
back(), Dir)) {
2772 IsDirPoppedFromStack =
true;
2774 if (IsDirPoppedFromStack || !IsCurrentDirEmpty) {
2777 startDirectory(Dir);
2778 IsCurrentDirEmpty =
true;
2781 if (UseOverlayRelative) {
2784 "Overlay dir must be contained in RPath");
2787 if (!Entry.IsDirectory) {
2789 IsCurrentDirEmpty =
false;
2793 while (!DirStack.
empty()) {
2806 return LHS.VPath <
RHS.VPath;
2809 JSONWriter(
OS).write(
Mappings, UseExternalNames, IsCaseSensitive,
2818 State = std::make_shared<detail::RecDirIterState>();
2819 State->Stack.push(
I);
2825 assert(FS && State && !State->Stack.empty() &&
"incrementing past end");
2826 assert(!State->Stack.top()->path().empty() &&
"non-canonical end iterator");
2829 if (State->HasNoPushRequest)
2830 State->HasNoPushRequest =
false;
2835 State->Stack.push(
I);
2841 while (!State->Stack.empty() && State->Stack.top().increment(EC) == End)
2844 if (State->Stack.empty())
BlockVerifier::State From
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file defines the DenseMap class.
Provides ErrorOr<T> smart pointer.
This file defines the RefCountedBase, ThreadSafeRefCountedBase, and IntrusiveRefCntPtr classes.
static StringRef getName(Value *V)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallString class.
This file defines the SmallVector class.
StringSet - A set-like wrapper for the StringMap.
std::array< StringRef, 64 > Keys
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),...
Represents either an error or a value T.
std::error_code getError() const
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
A smart pointer to a reference-counted object that inherits from RefCountedBase or ThreadSafeRefCount...
This interface provides simple read-only access to a block of memory, and provides simple methods for...
static ErrorOr< std::unique_ptr< MemoryBuffer > > getOpenFile(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Given an already-open file descriptor, read the file and return a MemoryBuffer.
static std::unique_ptr< MemoryBuffer > getMemBuffer(StringRef InputData, StringRef BufferName="", bool RequiresNullTerminator=true)
Open the specified memory range as a MemoryBuffer.
virtual StringRef getBufferIdentifier() const
Return an identifier for this buffer, typically the filename it was read from.
StringRef getBuffer() const
Represents a location in source code.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
StringRef str() const
Explicit conversion to StringRef.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
This owns the files read by a parser, handles include stacks, and handles diagnostic wrangling.
void PrintMessage(raw_ostream &OS, SMLoc Loc, DiagKind Kind, const Twine &Msg, ArrayRef< SMRange > Ranges={}, ArrayRef< SMFixIt > FixIts={}, bool ShowColors=true) const
Emit a message about the specified location with the specified string.
void(*)(const SMDiagnostic &, void *Context) DiagHandlerTy
Clients that want to handle their own diagnostics in a custom way can register a function pointer+con...
void setDiagHandler(DiagHandlerTy DH, void *Ctx=nullptr)
Specify a diagnostic handler to be invoked every time PrintMessage is called.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
StringRef - Represent a constant reference to a string, i.e.
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
std::string str() const
str - Get the contents as an std::string.
constexpr bool empty() const
empty - Check if the string is empty.
char back() const
back - Get the last character in the string.
StringRef slice(size_t Start, size_t End) const
Return a reference to the substring from [Start, End).
constexpr size_t size() const
size - Get the string size.
static constexpr size_t npos
StringSet - A wrapper for StringMap that provides set-like functionality.
std::pair< typename Base::iterator, bool > insert(StringRef key)
Target - Wrapper for Target specific information.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
std::string str() const
Return the twine contents as a std::string.
void toVector(SmallVectorImpl< char > &Out) const
Append the concatenated string into the given SmallString or SmallVector.
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM Value Representation.
An 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.
bool exists(const Twine &Path)
Check whether a file exists. Provided for convenience.
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getBufferForFile(const Twine &Name, int64_t FileSize=-1, bool RequiresNullTerminator=true, bool IsVolatile=false)
This is a convenience method that opens a file, gets its content and then closes the file.
virtual std::error_code makeAbsolute(SmallVectorImpl< char > &Path) const
Make Path an absolute path.
virtual llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path)=0
Get a File object for the file at Path, if one exists.
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
virtual std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) const
Gets real path of Path e.g.
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
Is the file mounted on a local filesystem?
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override
Get a directory_iterator for Dir.
~InMemoryFileSystem() override
std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) const override
Canonicalizes Path by combining with the current working directory and normalizing the path (e....
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
Get the working directory of this file system.
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
Set the working directory.
llvm::ErrorOr< Status > status(const Twine &Path) override
Get the status of the entry at Path, if one exists.
llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override
Get a File object for the file at Path, if one exists.
std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) const override
Gets real path of Path e.g.
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override
Get a directory_iterator for Dir.
llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override
Get a File object for the file at Path, if one exists.
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
Set the working directory.
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
Get the working directory of this file system.
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
Is the file mounted on a local filesystem?
llvm::ErrorOr< Status > status(const Twine &Path) override
Get the status of the entry at Path, if one exists.
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.
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.
ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override
Get a File object for the file at Path, if one exists.
void setOverlayFileDir(StringRef PrefixDir)
llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override
Get the working directory of this file system.
void setRedirection(RedirectingFileSystem::RedirectKind Kind)
std::error_code isLocal(const Twine &Path, bool &Result) override
Is the file mounted on a local filesystem?
static std::unique_ptr< RedirectingFileSystem > create(std::unique_ptr< MemoryBuffer > Buffer, SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, void *DiagContext, IntrusiveRefCntPtr< FileSystem > ExternalFS)
Parses Buffer, which is expected to be in YAML format and returns a virtual file system representing ...
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
Set the working directory.
std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) const override
Gets real path of Path e.g.
StringRef getOverlayFileDir() const
void printEntry(raw_ostream &OS, Entry *E, unsigned IndentLevel=0) const
The result of a status operation.
llvm::sys::fs::UniqueID getUniqueID() const
bool equivalent(const Status &Other) const
static Status copyWithNewName(const Status &In, const Twine &NewName)
Get a copy of a Status with a different name.
bool isStatusKnown() const
bool ExposesExternalVFSPath
Whether this entity has an external path different from the virtual path, and the external path is ex...
static Status copyWithNewSize(const Status &In, uint64_t NewSize)
Get a copy of a Status with a different size.
llvm::sys::fs::file_type getType() const
bool isRegularFile() const
StringRef getName() const
Returns the name that should be used for this file or directory.
void addFileMapping(StringRef VirtualPath, StringRef RealPath)
void write(llvm::raw_ostream &OS)
void addDirectoryMapping(StringRef VirtualPath, StringRef RealPath)
InMemoryDirectory(Status Stat)
InMemoryNode * addChild(StringRef Name, std::unique_ptr< InMemoryNode > Child)
Status getStatus(const Twine &RequestedName) const override
Return the Status for this node.
const_iterator end() const
static bool classof(const InMemoryNode *N)
InMemoryNode * getChild(StringRef Name) const
const_iterator begin() const
UniqueID getUniqueID() const
decltype(Entries)::const_iterator const_iterator
std::string toString(unsigned Indent) const override
Status getStatus(const Twine &RequestedName) const override
Return the Status for this node.
std::string toString(unsigned Indent) const override
InMemoryFile(Status Stat, std::unique_ptr< llvm::MemoryBuffer > Buffer)
static bool classof(const InMemoryNode *N)
llvm::MemoryBuffer * getBuffer() const
The in memory file system is a tree of Nodes.
StringRef getFileName() const
Get the filename of this node (the name without the directory part).
InMemoryNodeKind getKind() const
virtual ~InMemoryNode()=default
InMemoryNode(llvm::StringRef FileName, InMemoryNodeKind Kind)
virtual std::string toString(unsigned Indent) const =0
virtual Status getStatus(const Twine &RequestedName) const =0
Return the Status for this node.
A member of a directory, yielded by a directory_iterator.
llvm::StringRef path() const
llvm::sys::fs::file_type type() const
An input iterator over the entries in a virtual path, similar to llvm::sys::fs::directory_iterator.
directory_iterator & increment(std::error_code &EC)
Equivalent to operator++, with an error code.
An input iterator over the recursive contents of a virtual path, similar to llvm::sys::fs::recursive_...
recursive_directory_iterator()=default
Construct an 'end' iterator.
recursive_directory_iterator & increment(std::error_code &EC)
Equivalent to operator++, with an error code.
Abstract base class for all Nodes.
This class represents a YAML stream potentially containing multiple documents.
document_iterator begin()
void printError(Node *N, const Twine &Msg, SourceMgr::DiagKind Kind=SourceMgr::DK_Error)
Iterator abstraction for Documents over a Stream.
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
std::optional< const char * > toString(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract a string value from it.
@ Resolved
Queried, materialization begun.
void make_absolute(const Twine ¤t_directory, SmallVectorImpl< char > &path)
Make path an absolute path.
const file_t kInvalidFile
std::error_code real_path(const Twine &path, SmallVectorImpl< char > &output, bool expand_tilde=false)
Collapse all .
std::error_code closeFile(file_t &F)
Close the file object.
std::error_code openFileForRead(const Twine &Name, int &ResultFD, OpenFlags Flags=OF_None, SmallVectorImpl< char > *RealPath=nullptr)
Opens the file with the given name in a read-only mode, returning its open file descriptor.
std::error_code status(const Twine &path, file_status &result, bool follow=true)
Get file status as if by POSIX stat().
file_type
An enumeration for the file system's view of the type.
std::error_code set_current_path(const Twine &path)
Set the current path.
std::error_code is_local(const Twine &path, bool &result)
Is the file mounted on a local filesystem?
Expected< file_t > openNativeFileForRead(const Twine &Name, OpenFlags Flags=OF_None, SmallVectorImpl< char > *RealPath=nullptr)
Opens the file with the given name in a read-only mode, returning its open file descriptor.
std::error_code current_path(SmallVectorImpl< char > &result)
Get the current path.
bool is_directory(const basic_file_status &status)
Does status represent a directory?
StringRef get_separator(Style style=Style::native)
Return the preferred separator for this platform.
const_iterator begin(StringRef path, Style style=Style::native)
Get begin iterator over path.
reverse_iterator rend(StringRef path)
Get reverse end iterator over path.
const_iterator end(StringRef path)
Get end iterator over path.
bool remove_dots(SmallVectorImpl< char > &path, bool remove_dot_dot=false, Style style=Style::native)
In-place remove any '.
StringRef filename(StringRef path, Style style=Style::native)
Get filename.
reverse_iterator rbegin(StringRef path, Style style=Style::native)
Get reverse begin iterator over path.
StringRef parent_path(StringRef path, Style style=Style::native)
Get parent path.
bool is_absolute(const Twine &path, Style style=Style::native)
Is path absolute?
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
StringRef root_path(StringRef path, Style style=Style::native)
Get root path.
bool is_separator(char value, Style style=Style::native)
Check whether the given char is a path separator on the host OS.
StringRef remove_leading_dotslash(StringRef path, Style style=Style::native)
Remove redundant leading "./" pieces and consecutive separators.
std::chrono::time_point< std::chrono::system_clock, D > TimePoint
A time point on the system clock.
TimePoint< std::chrono::seconds > toTimePoint(std::time_t T)
Convert a std::time_t to a TimePoint.
void collectVFSFromYAML(std::unique_ptr< llvm::MemoryBuffer > Buffer, llvm::SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, SmallVectorImpl< YAMLVFSEntry > &CollectedEntries, void *DiagContext=nullptr, IntrusiveRefCntPtr< FileSystem > ExternalFS=getRealFileSystem())
Collect all pairs of <virtual path, real path> entries from the YAMLFilePath.
std::unique_ptr< FileSystem > getVFSFromYAML(std::unique_ptr< llvm::MemoryBuffer > Buffer, llvm::SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, void *DiagContext=nullptr, IntrusiveRefCntPtr< FileSystem > ExternalFS=getRealFileSystem())
Gets a FileSystem for a virtual file system described in YAML format.
std::unique_ptr< FileSystem > createPhysicalFileSystem()
Create an vfs::FileSystem for the 'real' file system, as seen by the operating system.
static sys::fs::UniqueID getFileID(sys::fs::UniqueID Parent, llvm::StringRef Name, llvm::StringRef Contents)
llvm::sys::fs::UniqueID getNextVirtualUniqueID()
Get a globally unique ID for a virtual file or directory.
static sys::fs::UniqueID getUniqueID(hash_code Hash)
IntrusiveRefCntPtr< FileSystem > getRealFileSystem()
Gets an vfs::FileSystem for the 'real' file system, as seen by the operating system.
static sys::fs::UniqueID getDirectoryID(sys::fs::UniqueID Parent, llvm::StringRef Name)
std::string escape(StringRef Input, bool EscapePrintable=true)
Escape Input for a double quoted scalar; if EscapePrintable is true, all UTF8 sequences will be escap...
This is an optimization pass for GlobalISel generic memory operations.
Error write(MCStreamer &Out, ArrayRef< std::string > Inputs)
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)
void sort(IteratorTy Start, IteratorTy End)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
std::error_code errorToErrorCode(Error Err)
Helper for converting an ECError to a std::error_code.
Represents the result of a path lookup into the RedirectingFileSystem.
Entry * E
The entry the looked-up path corresponds to.
LookupResult(Entry *E, sys::path::const_iterator Start, sys::path::const_iterator End)
An interface for virtual file systems to provide an iterator over the (non-recursive) contents of a d...
directory_entry CurrentEntry
Status makeStatus() const
std::unique_ptr< llvm::MemoryBuffer > Buffer