24#include "llvm/Config/llvm-config.h"
50#include <system_error>
76 return Status(In.getName(), In.getUniqueID(), In.getLastModificationTime(),
77 In.getUser(), In.getGroup(), NewSize, In.getType(),
82 return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
83 In.getUser(), In.getGroup(), In.getSize(), In.getType(),
88 return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
89 In.getUser(), In.getGroup(), In.getSize(), In.type(),
120 bool RequiresNullTerminator,
bool IsVolatile) {
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};
285 std::error_code setCurrentWorkingDirectory(
const Twine &Path)
override;
286 std::error_code isLocal(
const Twine &Path,
bool &Result)
override;
287 std::error_code getRealPath(
const Twine &Path,
292 unsigned IndentLevel)
const override;
300 Path.toVector(Storage);
305 struct WorkingDirectory {
311 std::optional<llvm::ErrorOr<WorkingDirectory>> WD;
319 if (std::error_code EC =
326RealFileSystem::openFileForRead(
const Twine &
Name) {
332 return std::unique_ptr<File>(
333 new RealFile(*FDOrErr,
Name.str(), RealName.
str()));
338 return std::string(WD->get().Specified);
340 return WD->getError();
345 return std::string(Dir);
348std::error_code RealFileSystem::setCurrentWorkingDirectory(
const Twine &Path) {
353 adjustPath(Path, Storage).toVector(Absolute);
358 return std::make_error_code(std::errc::not_a_directory);
362 return std::error_code();
365std::error_code RealFileSystem::isLocal(
const Twine &Path,
bool &Result) {
370std::error_code RealFileSystem::getRealPath(
const Twine &Path,
377 unsigned IndentLevel)
const {
378 printIndent(
OS, IndentLevel);
379 OS <<
"RealFileSystem using ";
393 return std::make_unique<RealFileSystem>(
false);
402 RealFSDirIter(
const Twine &Path, std::error_code &EC) : Iter(Path, EC) {
407 std::error_code increment()
override {
420 std::error_code &EC) {
423 std::make_shared<RealFSDirIter>(adjustPath(Dir, Storage), EC));
454 if ((*I)->exists(Path))
464 auto Result = (*I)->openFileForRead(Path);
474 return FSList.
front()->getCurrentWorkingDirectory();
479 for (
auto &FS : FSList)
480 if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))
486 for (
auto &FS : FSList)
487 if (FS->exists(Path))
488 return FS->isLocal(Path, Result);
494 for (
const auto &FS : FSList)
495 if (FS->exists(Path))
496 return FS->getRealPath(Path, Output);
503 FS->visitChildFileSystems(Callback);
508 unsigned IndentLevel)
const {
509 printIndent(
OS, IndentLevel);
510 OS <<
"OverlayFileSystem\n";
511 if (
Type == PrintType::Summary)
514 if (
Type == PrintType::Contents)
515 Type = PrintType::Summary;
517 FS->print(
OS,
Type, IndentLevel + 1);
537 std::error_code incrementIter(
bool IsFirstTime) {
538 while (!IterList.
empty()) {
539 CurrentDirIter = IterList.
back();
546 return errc::no_such_file_or_directory;
550 std::error_code incrementDirIter(
bool IsFirstTime) {
552 "incrementing past end");
557 EC = incrementIter(IsFirstTime);
561 std::error_code incrementImpl(
bool IsFirstTime) {
563 std::error_code
EC = incrementDirIter(IsFirstTime);
568 CurrentEntry = *CurrentDirIter;
578 std::error_code &EC) {
579 for (
const auto &FS : FileSystems) {
582 if (FEC && FEC != errc::no_such_file_or_directory) {
589 EC = incrementImpl(
true);
594 : IterList(DirIters.
begin(), DirIters.
end()) {
595 EC = incrementImpl(
true);
598 std::error_code increment()
override {
return incrementImpl(
false); }
604 std::error_code &EC) {
606 std::make_shared<CombiningDirIterImpl>(FSList, Dir.
str(), EC));
612void ProxyFileSystem::anchor() {}
630 std::string FileName;
634 : Kind(Kind), FileName(
std::
string(
llvm::sys::path::filename(FileName))) {
646 virtual std::string
toString(
unsigned Indent)
const = 0;
651 std::unique_ptr<llvm::MemoryBuffer> Buffer;
659 return Status::copyWithNewName(Stat, RequestedName);
663 std::string
toString(
unsigned Indent)
const override {
664 return (std::string(Indent,
' ') + Stat.
getName() +
"\n").str();
674class InMemoryHardLink :
public InMemoryNode {
675 const InMemoryFile &ResolvedFile;
678 InMemoryHardLink(
StringRef Path,
const InMemoryFile &ResolvedFile)
679 : InMemoryNode(Path, IME_HardLink), ResolvedFile(ResolvedFile) {}
680 const InMemoryFile &getResolvedFile()
const {
return ResolvedFile; }
682 Status getStatus(
const Twine &RequestedName)
const override {
683 return ResolvedFile.getStatus(RequestedName);
686 std::string
toString(
unsigned Indent)
const override {
687 return std::string(Indent,
' ') +
"HardLink to -> " +
688 ResolvedFile.toString(0);
691 static bool classof(
const InMemoryNode *
N) {
696class InMemorySymbolicLink :
public InMemoryNode {
697 std::string TargetPath;
705 std::string
toString(
unsigned Indent)
const override {
706 return std::string(Indent,
' ') +
"SymbolicLink to -> " + TargetPath;
709 Status getStatus(
const Twine &RequestedName)
const override {
710 return Status::copyWithNewName(Stat, RequestedName);
713 StringRef getTargetPath()
const {
return TargetPath; }
715 static bool classof(
const InMemoryNode *
N) {
723class InMemoryFileAdaptor :
public File {
724 const InMemoryFile &
Node;
726 std::string RequestedName;
729 explicit InMemoryFileAdaptor(
const InMemoryFile &
Node,
730 std::string RequestedName)
734 return Node.getStatus(RequestedName);
738 getBuffer(
const Twine &
Name, int64_t FileSize,
bool RequiresNullTerminator,
739 bool IsVolatile)
override {
745 std::error_code close()
override {
return {}; }
747 void setPath(
const Twine &Path)
override { RequestedName =
Path.str(); }
753 std::map<std::string, std::unique_ptr<InMemoryNode>> Entries;
763 return Status::copyWithNewName(Stat, RequestedName);
769 auto I = Entries.find(
Name.str());
770 if (
I != Entries.end())
771 return I->second.get();
776 return Entries.emplace(
Name, std::move(Child)).first->second.get();
784 std::string
toString(
unsigned Indent)
const override {
786 (std::string(Indent,
' ') + Stat.
getName() +
"\n").str();
787 for (
const auto &Entry : Entries)
788 Result += Entry.second->toString(Indent + 2);
818 (
Type == sys::fs::file_type::directory_file)
820 :
getFileID(DirUID,
Name, Buffer ? Buffer->getBuffer() :
"");
823 Group, Buffer ? Buffer->getBufferSize() : 0,
Type, Perms);
827 : Root(new
detail::InMemoryDirectory(
830 llvm::sys::fs::file_type::directory_file,
831 llvm::sys::fs::perms::all_all))),
832 UseNormalizedPaths(UseNormalizedPaths) {}
837 return Root->toString(0);
840bool InMemoryFileSystem::addFile(
const Twine &
P, time_t ModificationTime,
841 std::unique_ptr<llvm::MemoryBuffer> Buffer,
842 std::optional<uint32_t>
User,
843 std::optional<uint32_t> Group,
844 std::optional<llvm::sys::fs::file_type>
Type,
845 std::optional<llvm::sys::fs::perms> Perms,
846 MakeNodeFn MakeNode) {
863 const auto ResolvedUser =
User.value_or(0);
864 const auto ResolvedGroup = Group.value_or(0);
879 std::move(Buffer), ResolvedUser, ResolvedGroup,
880 ResolvedType, ResolvedPerms}));
886 StringRef(Path.str().begin(),
Name.end() - Path.str().begin()),
890 Dir = cast<detail::InMemoryDirectory>(Dir->
addChild(
891 Name, std::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
895 if (
auto *NewDir = dyn_cast<detail::InMemoryDirectory>(
Node)) {
899 isa<detail::InMemoryHardLink>(
Node)) &&
900 "Must be either file, hardlink or directory!");
907 if (
auto Link = dyn_cast<detail::InMemoryHardLink>(
Node)) {
908 return Link->getResolvedFile().getBuffer()->getBuffer() ==
911 return cast<detail::InMemoryFile>(
Node)->getBuffer()->getBuffer() ==
917bool InMemoryFileSystem::addFile(
const Twine &
P, time_t ModificationTime,
918 std::unique_ptr<llvm::MemoryBuffer> Buffer,
919 std::optional<uint32_t>
User,
920 std::optional<uint32_t> Group,
921 std::optional<llvm::sys::fs::file_type>
Type,
922 std::optional<llvm::sys::fs::perms> Perms) {
923 return addFile(
P, ModificationTime, std::move(Buffer),
User, Group,
Type,
926 -> std::unique_ptr<detail::InMemoryNode> {
929 return std::make_unique<detail::InMemoryDirectory>(Stat);
930 return std::make_unique<detail::InMemoryFile>(
931 Stat, std::move(NNI.
Buffer));
936 const Twine &
P, time_t ModificationTime,
938 std::optional<uint32_t> Group, std::optional<llvm::sys::fs::file_type>
Type,
939 std::optional<llvm::sys::fs::perms> Perms) {
941 std::move(
User), std::move(Group), std::move(
Type),
944 -> std::unique_ptr<detail::InMemoryNode> {
947 return std::make_unique<detail::InMemoryDirectory>(Stat);
948 return std::make_unique<detail::InMemoryFile>(
949 Stat, std::move(NNI.
Buffer));
954InMemoryFileSystem::lookupNode(
const Twine &
P,
bool FollowFinalSymlink,
955 size_t SymlinkDepth)
const {
978 if (
auto Symlink = dyn_cast<detail::InMemorySymbolicLink>(Node)) {
981 if (
I == E && !FollowFinalSymlink)
996 lookupNode(TargetPath,
true, SymlinkDepth + 1);
1000 if (!isa<detail::InMemoryDirectory>(*
Target))
1004 Dir = cast<detail::InMemoryDirectory>(*
Target);
1009 if (
auto File = dyn_cast<detail::InMemoryFile>(Node)) {
1016 if (
auto File = dyn_cast<detail::InMemoryHardLink>(
Node)) {
1022 Dir = cast<detail::InMemoryDirectory>(
Node);
1030 auto NewLinkNode = lookupNode(NewLink,
false);
1034 auto TargetNode = lookupNode(
Target,
true);
1037 if (!TargetNode || NewLinkNode || !isa<detail::InMemoryFile>(*TargetNode))
1039 return addFile(NewLink, 0,
nullptr, std::nullopt, std::nullopt, std::nullopt,
1041 return std::make_unique<detail::InMemoryHardLink>(
1043 *cast<detail::InMemoryFile>(*TargetNode));
1049 std::optional<uint32_t>
User, std::optional<uint32_t> Group,
1050 std::optional<llvm::sys::fs::perms> Perms) {
1051 auto NewLinkNode = lookupNode(NewLink,
false);
1057 Target.toVector(TargetStr);
1059 return addFile(NewLinkStr, ModificationTime,
nullptr,
User, Group,
1062 return std::make_unique<detail::InMemorySymbolicLink>(
1068 auto Node = lookupNode(Path,
true);
1070 return (*Node)->getStatus(Path);
1071 return Node.getError();
1076 auto Node = lookupNode(Path,
true);
1078 return Node.getError();
1082 if (
auto *
F = dyn_cast<detail::InMemoryFile>(*Node))
1083 return std::unique_ptr<File>(
1084 new detail::InMemoryFileAdaptor(*
F, Path.str()));
1095 std::string RequestedDirName;
1097 void setCurrentEntry() {
1102 switch (
I->second->getKind()) {
1111 if (
auto SymlinkTarget =
1112 FS->lookupNode(Path,
true)) {
1113 Path = SymlinkTarget.getName();
1114 Type = (*SymlinkTarget)->getStatus(Path).getType();
1131 std::string RequestedDirName)
1132 : FS(FS),
I(Dir.begin()), E(Dir.end()),
1133 RequestedDirName(
std::
move(RequestedDirName)) {
1145 std::error_code &EC) {
1146 auto Node = lookupNode(Dir,
true);
1148 EC = Node.getError();
1152 if (
auto *DirNode = dyn_cast<detail::InMemoryDirectory>(*Node))
1154 std::make_shared<DirIterator>(
this, *DirNode, Dir.
str()));
1173 WorkingDirectory = std::string(Path);
1180 if (!CWD || CWD->empty())
1182 Path.toVector(Output);
1195 unsigned IndentLevel)
const {
1196 printIndent(
OS, IndentLevel);
1197 OS <<
"InMemoryFileSystem\n";
1212 const size_t n = Path.find_first_of(
"/\\");
1214 if (n !=
static_cast<size_t>(-1))
1234static bool isFileNotFound(std::error_code EC,
1236 if (E && !isa<RedirectingFileSystem::DirectoryRemapEntry>(E))
1247 if (
auto ExternalWorkingDirectory =
1248 ExternalFS->getCurrentWorkingDirectory()) {
1249 WorkingDirectory = *ExternalWorkingDirectory;
1260 std::error_code incrementImpl(
bool IsFirstTime) {
1261 assert((IsFirstTime || Current !=
End) &&
"cannot iterate past end");
1264 if (Current !=
End) {
1268 switch ((*Current)->getKind()) {
1289 : Dir(Path.str()), Current(Begin),
End(
End) {
1290 EC = incrementImpl(
true);
1294 return incrementImpl(
false);
1308 RedirectingFSDirRemapIterImpl(std::string DirPath,
1310 : Dir(
std::
move(DirPath)), DirStyle(getExistingStyle(Dir)),
1311 ExternalIter(ExtIter) {
1316 void setCurrentEntry() {
1327 std::error_code increment()
override {
1341 return WorkingDirectory;
1351 Path.toVector(AbsolutePath);
1352 if (std::error_code EC = makeAbsolute(AbsolutePath))
1354 WorkingDirectory = std::string(AbsolutePath);
1363 if (makeAbsolute(Path))
1366 return ExternalFS->isLocal(Path, Result);
1381 return WorkingDir.getError();
1383 return makeAbsolute(WorkingDir.get(), Path);
1387RedirectingFileSystem::makeAbsolute(
StringRef WorkingDir,
1393 if (!WorkingDir.
empty() &&
1397 return std::error_code();
1409 std::string
Result = std::string(WorkingDir);
1426 std::error_code &EC) {
1430 EC = makeAbsolute(Path);
1437 isFileNotFound(Result.getError()))
1438 return ExternalFS->dir_begin(Path, EC);
1440 EC = Result.getError();
1448 isFileNotFound(S.
getError(), Result->E))
1449 return ExternalFS->dir_begin(Dir, EC);
1455 if (!S->isDirectory()) {
1463 std::error_code RedirectEC;
1464 if (
auto ExtRedirect = Result->getExternalRedirect()) {
1465 auto RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
1466 RedirectIter = ExternalFS->dir_begin(*ExtRedirect, RedirectEC);
1468 if (!RE->useExternalName(UseExternalNames)) {
1472 std::string(Path), RedirectIter));
1475 auto DE = cast<DirectoryEntry>(Result->E);
1478 Path, DE->contents_begin(), DE->contents_end(), RedirectEC));
1491 return RedirectIter;
1494 std::error_code ExternalEC;
1505 switch (Redirection) {
1519 std::make_shared<CombiningDirIterImpl>(Iters, EC)};
1526 OverlayFileDir = Dir.
str();
1530 return OverlayFileDir;
1547 std::vector<StringRef> R;
1548 R.reserve(Roots.size());
1549 for (
const auto &Root : Roots)
1550 R.push_back(Root->getName());
1555 unsigned IndentLevel)
const {
1557 OS <<
"RedirectingFileSystem (UseExternalNames: "
1558 << (UseExternalNames ?
"true" :
"false") <<
")\n";
1562 for (
const auto &Root : Roots)
1566 OS <<
"ExternalFS:\n";
1573 unsigned IndentLevel)
const {
1579 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(E);
1582 for (std::unique_ptr<Entry> &SubEntry :
1589 auto *RE = cast<RedirectingFileSystem::RemapEntry>(E);
1590 OS <<
" -> '" << RE->getExternalContentsPath() <<
"'";
1591 switch (RE->getUseName()) {
1595 OS <<
" (UseExternalName: true)";
1598 OS <<
" (UseExternalName: false)";
1609 Callback(*ExternalFS);
1610 ExternalFS->visitChildFileSystems(Callback);
1623 const auto *S = dyn_cast<yaml::ScalarNode>(
N);
1626 error(
N,
"expected string");
1629 Result = S->getValue(Storage);
1634 bool parseScalarBool(
yaml::Node *
N,
bool &Result) {
1637 if (!parseScalarString(
N,
Value, Storage))
1640 if (
Value.equals_insensitive(
"true") ||
Value.equals_insensitive(
"on") ||
1641 Value.equals_insensitive(
"yes") ||
Value ==
"1") {
1644 }
else if (
Value.equals_insensitive(
"false") ||
1645 Value.equals_insensitive(
"off") ||
1646 Value.equals_insensitive(
"no") ||
Value ==
"0") {
1651 error(
N,
"expected boolean value");
1655 std::optional<RedirectingFileSystem::RedirectKind>
1659 if (!parseScalarString(
N,
Value, Storage))
1660 return std::nullopt;
1662 if (
Value.equals_insensitive(
"fallthrough")) {
1664 }
else if (
Value.equals_insensitive(
"fallback")) {
1666 }
else if (
Value.equals_insensitive(
"redirect-only")) {
1669 return std::nullopt;
1672 std::optional<RedirectingFileSystem::RootRelativeKind>
1676 if (!parseScalarString(
N,
Value, Storage))
1677 return std::nullopt;
1678 if (
Value.equals_insensitive(
"cwd")) {
1680 }
else if (
Value.equals_insensitive(
"overlay-dir")) {
1683 return std::nullopt;
1690 KeyStatus(
bool Required =
false) : Required(Required) {}
1693 using KeyStatusPair = std::pair<StringRef, KeyStatus>;
1698 if (!Keys.
count(Key)) {
1699 error(KeyNode,
"unknown key");
1702 KeyStatus &S = Keys[Key];
1704 error(KeyNode,
Twine(
"duplicate key '") + Key +
"'");
1713 for (
const auto &
I : Keys) {
1714 if (
I.second.Required && !
I.second.Seen) {
1715 error(Obj,
Twine(
"missing key '") +
I.first +
"'");
1727 for (
const auto &Root : FS->Roots) {
1728 if (
Name == Root->getName()) {
1729 ParentEntry = Root.get();
1734 auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
1735 for (std::unique_ptr<RedirectingFileSystem::Entry> &
Content :
1738 dyn_cast<RedirectingFileSystem::DirectoryEntry>(
Content.get());
1745 std::unique_ptr<RedirectingFileSystem::Entry> E =
1746 std::make_unique<RedirectingFileSystem::DirectoryEntry>(
1748 std::chrono::system_clock::now(), 0, 0, 0,
1752 FS->Roots.push_back(std::move(E));
1753 ParentEntry = FS->Roots.back().get();
1757 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
1758 DE->addContent(std::move(E));
1759 return DE->getLastContent();
1769 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
1775 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
1777 uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
1781 assert(NewParentE &&
"Parent entry must exist");
1782 auto *DR = cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
1783 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
1785 std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
1786 Name, DR->getExternalContentsPath(), DR->getUseName()));
1790 assert(NewParentE &&
"Parent entry must exist");
1791 auto *FE = cast<RedirectingFileSystem::FileEntry>(SrcE);
1792 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
1793 DE->addContent(std::make_unique<RedirectingFileSystem::FileEntry>(
1794 Name, FE->getExternalContentsPath(), FE->getUseName()));
1800 std::unique_ptr<RedirectingFileSystem::Entry>
1802 auto *
M = dyn_cast<yaml::MappingNode>(
N);
1804 error(
N,
"expected mapping node for file or directory entry");
1808 KeyStatusPair Fields[] = {
1809 KeyStatusPair(
"name",
true),
1810 KeyStatusPair(
"type",
true),
1811 KeyStatusPair(
"contents",
false),
1812 KeyStatusPair(
"external-contents",
false),
1813 KeyStatusPair(
"use-external-name",
false),
1818 enum { CF_NotSet, CF_List, CF_External } ContentsField = CF_NotSet;
1819 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>>
1827 for (
auto &
I : *M) {
1832 if (!parseScalarString(
I.getKey(), Key, Buffer))
1835 if (!checkDuplicateOrUnknownKey(
I.getKey(), Key, Keys))
1839 if (Key ==
"name") {
1840 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1843 NameValueNode =
I.getValue();
1847 }
else if (Key ==
"type") {
1848 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1850 if (
Value ==
"file")
1852 else if (
Value ==
"directory")
1854 else if (
Value ==
"directory-remap")
1857 error(
I.getValue(),
"unknown value for 'type'");
1860 }
else if (Key ==
"contents") {
1861 if (ContentsField != CF_NotSet) {
1863 "entry already has 'contents' or 'external-contents'");
1866 ContentsField = CF_List;
1867 auto *Contents = dyn_cast<yaml::SequenceNode>(
I.getValue());
1870 error(
I.getValue(),
"expected array");
1874 for (
auto &
I : *Contents) {
1875 if (std::unique_ptr<RedirectingFileSystem::Entry> E =
1876 parseEntry(&
I, FS,
false))
1877 EntryArrayContents.push_back(std::move(E));
1881 }
else if (Key ==
"external-contents") {
1882 if (ContentsField != CF_NotSet) {
1884 "entry already has 'contents' or 'external-contents'");
1887 ContentsField = CF_External;
1888 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1892 if (
FS->IsRelativeOverlay) {
1893 FullPath =
FS->getOverlayFileDir();
1895 "External contents prefix directory must exist");
1903 FullPath = canonicalize(FullPath);
1904 ExternalContentsPath = FullPath.
str();
1905 }
else if (Key ==
"use-external-name") {
1907 if (!parseScalarBool(
I.getValue(), Val))
1920 if (ContentsField == CF_NotSet) {
1921 error(
N,
"missing key 'contents' or 'external-contents'");
1924 if (!checkMissingKeys(
N, Keys))
1930 error(
N,
"'use-external-name' is not supported for 'directory' entries");
1935 ContentsField == CF_List) {
1936 error(
N,
"'contents' is not supported for 'directory-remap' entries");
1954 if (
FS->RootRelative ==
1957 assert(!FullPath.
empty() &&
"Overlay file directory must exist");
1958 EC =
FS->makeAbsolute(FullPath,
Name);
1964 assert(NameValueNode &&
"Name presence should be checked earlier");
1967 "entry with relative path at the root level is not discoverable");
1985 while (Trimmed.
size() > RootPathLen &&
1987 Trimmed = Trimmed.
slice(0, Trimmed.
size() - 1);
1992 std::unique_ptr<RedirectingFileSystem::Entry>
Result;
1995 Result = std::make_unique<RedirectingFileSystem::FileEntry>(
1996 LastComponent, std::move(ExternalContentsPath), UseExternalName);
1999 Result = std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
2000 LastComponent, std::move(ExternalContentsPath), UseExternalName);
2003 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
2004 LastComponent, std::move(EntryArrayContents),
2018 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> Entries;
2019 Entries.push_back(std::move(Result));
2020 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
2021 *
I, std::move(Entries),
2033 auto *Top = dyn_cast<yaml::MappingNode>(Root);
2035 error(Root,
"expected mapping node");
2039 KeyStatusPair Fields[] = {
2040 KeyStatusPair(
"version",
true),
2041 KeyStatusPair(
"case-sensitive",
false),
2042 KeyStatusPair(
"use-external-names",
false),
2043 KeyStatusPair(
"root-relative",
false),
2044 KeyStatusPair(
"overlay-relative",
false),
2045 KeyStatusPair(
"fallthrough",
false),
2046 KeyStatusPair(
"redirecting-with",
false),
2047 KeyStatusPair(
"roots",
true),
2051 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> RootEntries;
2054 for (
auto &
I : *Top) {
2057 if (!parseScalarString(
I.getKey(), Key, KeyBuffer))
2060 if (!checkDuplicateOrUnknownKey(
I.getKey(), Key, Keys))
2063 if (Key ==
"roots") {
2064 auto *Roots = dyn_cast<yaml::SequenceNode>(
I.getValue());
2066 error(
I.getValue(),
"expected array");
2070 for (
auto &
I : *Roots) {
2071 if (std::unique_ptr<RedirectingFileSystem::Entry> E =
2072 parseEntry(&
I, FS,
true))
2073 RootEntries.push_back(std::move(E));
2077 }
else if (Key ==
"version") {
2080 if (!parseScalarString(
I.getValue(), VersionString, Storage))
2084 error(
I.getValue(),
"expected integer");
2088 error(
I.getValue(),
"invalid version number");
2092 error(
I.getValue(),
"version mismatch, expected 0");
2095 }
else if (Key ==
"case-sensitive") {
2096 if (!parseScalarBool(
I.getValue(), FS->CaseSensitive))
2098 }
else if (Key ==
"overlay-relative") {
2099 if (!parseScalarBool(
I.getValue(), FS->IsRelativeOverlay))
2101 }
else if (Key ==
"use-external-names") {
2102 if (!parseScalarBool(
I.getValue(), FS->UseExternalNames))
2104 }
else if (Key ==
"fallthrough") {
2105 if (Keys[
"redirecting-with"].Seen) {
2107 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2111 bool ShouldFallthrough =
false;
2112 if (!parseScalarBool(
I.getValue(), ShouldFallthrough))
2115 if (ShouldFallthrough) {
2120 }
else if (Key ==
"redirecting-with") {
2121 if (Keys[
"fallthrough"].Seen) {
2123 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2127 if (
auto Kind = parseRedirectKind(
I.getValue())) {
2128 FS->Redirection = *Kind;
2130 error(
I.getValue(),
"expected valid redirect kind");
2133 }
else if (Key ==
"root-relative") {
2134 if (
auto Kind = parseRootRelativeKind(
I.getValue())) {
2135 FS->RootRelative = *Kind;
2137 error(
I.getValue(),
"expected valid root-relative kind");
2148 if (!checkMissingKeys(Top, Keys))
2154 for (
auto &E : RootEntries)
2155 uniqueOverlayTree(FS, E.get());
2161std::unique_ptr<RedirectingFileSystem>
2164 StringRef YAMLFilePath,
void *DiagContext,
2172 if (DI == Stream.
end() || !Root) {
2179 std::unique_ptr<RedirectingFileSystem> FS(
2182 if (!YAMLFilePath.
empty()) {
2193 assert(!EC &&
"Overlay dir final path must be absolute");
2195 FS->setOverlayFileDir(OverlayAbsDir);
2198 if (!
P.parse(Root, FS.get()))
2205 ArrayRef<std::pair<std::string, std::string>> RemappedFiles,
2206 bool UseExternalNames,
FileSystem &ExternalFS) {
2207 std::unique_ptr<RedirectingFileSystem> FS(
2209 FS->UseExternalNames = UseExternalNames;
2219 assert(!EC &&
"Could not make absolute path");
2237 assert(Parent &&
"File without a directory?");
2241 assert(!EC &&
"Could not make absolute path");
2245 auto NewFile = std::make_unique<RedirectingFileSystem::FileEntry>(
2249 ToEntry = NewFile.get();
2250 cast<RedirectingFileSystem::DirectoryEntry>(Parent)->addContent(
2251 std::move(NewFile));
2264 if (
auto *DRE = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(
E)) {
2267 getExistingStyle(DRE->getExternalContentsPath()));
2268 ExternalRedirect = std::string(Redirect);
2275 for (
Entry *Parent : Parents)
2280std::error_code RedirectingFileSystem::makeCanonicalForLookup(
2282 if (std::error_code EC = makeAbsolute(Path))
2286 canonicalize(
StringRef(Path.data(), Path.size()));
2287 if (CanonicalPath.
empty())
2290 Path.assign(CanonicalPath.
begin(), CanonicalPath.
end());
2297 if (std::error_code EC = makeCanonicalForLookup(CanonicalPath))
2307 for (
const auto &Root : Roots) {
2309 lookupPathImpl(Start,
End, Root.get(), Entries);
2310 if (UsageTrackingActive && Result && isa<RemapEntry>(Result->E))
2313 Result->Parents = std::move(Entries);
2321RedirectingFileSystem::lookupPathImpl(
2327 "Paths should not contain traversal components");
2332 if (!FromName.
empty()) {
2333 if (!pathComponentMatches(*Start, FromName))
2340 return LookupResult(
From, Start,
End);
2344 if (isa<RedirectingFileSystem::FileEntry>(
From))
2347 if (isa<RedirectingFileSystem::DirectoryRemapEntry>(
From))
2348 return LookupResult(
From, Start,
End);
2350 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(
From);
2351 for (
const std::unique_ptr<RedirectingFileSystem::Entry> &DirEntry :
2353 Entries.push_back(
From);
2355 lookupPathImpl(Start,
End, DirEntry.get(), Entries);
2365 bool UseExternalNames,
2370 return ExternalStatus;
2372 Status S = ExternalStatus;
2373 if (!UseExternalNames)
2381 const Twine &LookupPath,
const Twine &OriginalPath,
2383 if (std::optional<StringRef> ExtRedirect =
Result.getExternalRedirect()) {
2385 if (std::error_code EC = makeAbsolute(RemappedPath))
2392 auto *RE = cast<RedirectingFileSystem::RemapEntry>(
Result.E);
2394 RE->useExternalName(UseExternalNames), *S);
2397 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(
Result.E);
2402RedirectingFileSystem::getExternalStatus(
const Twine &LookupPath,
2403 const Twine &OriginalPath)
const {
2404 auto Result = ExternalFS->status(LookupPath);
2408 if (!Result ||
Result->ExposesExternalVFSPath)
2417 if (std::error_code EC = makeAbsolute(Path))
2433 isFileNotFound(Result.getError()))
2434 return getExternalStatus(Path, OriginalPath);
2435 return Result.getError();
2440 isFileNotFound(S.
getError(), Result->E)) {
2444 return getExternalStatus(Path, OriginalPath);
2454 if (makeAbsolute(Path))
2460 if (ExternalFS->exists(Path))
2469 isFileNotFound(Result.getError()))
2470 return ExternalFS->exists(Path);
2474 std::optional<StringRef> ExtRedirect = Result->getExternalRedirect();
2476 assert(isa<RedirectingFileSystem::DirectoryEntry>(Result->E));
2481 if (makeAbsolute(RemappedPath))
2484 if (ExternalFS->exists(RemappedPath))
2491 return ExternalFS->exists(Path);
2500class FileWithFixedStatus :
public File {
2501 std::unique_ptr<File> InnerFile;
2505 FileWithFixedStatus(std::unique_ptr<File> InnerFile,
Status S)
2511 getBuffer(
const Twine &
Name, int64_t FileSize,
bool RequiresNullTerminator,
2512 bool IsVolatile)
override {
2513 return InnerFile->getBuffer(
Name, FileSize, RequiresNullTerminator,
2517 std::error_code close()
override {
return InnerFile->close(); }
2528 if (!Result || (*Result)->status()->ExposesExternalVFSPath)
2532 auto Name =
F->get()->getName();
2534 F->get()->setPath(
P);
2543 if (std::error_code EC = makeAbsolute(Path))
2559 isFileNotFound(Result.getError()))
2561 return Result.getError();
2564 if (!Result->getExternalRedirect())
2567 StringRef ExtRedirect = *Result->getExternalRedirect();
2569 if (std::error_code EC = makeAbsolute(RemappedPath))
2572 auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
2576 if (!ExternalFile) {
2578 isFileNotFound(ExternalFile.getError(), Result->E)) {
2584 return ExternalFile;
2587 auto ExternalStatus = (*ExternalFile)->status();
2588 if (!ExternalStatus)
2589 return ExternalStatus.getError();
2594 OriginalPath, RE->useExternalName(UseExternalNames), *ExternalStatus);
2595 return std::unique_ptr<File>(
2596 std::make_unique<FileWithFixedStatus>(std::move(*ExternalFile), S));
2605 if (std::error_code EC = makeAbsolute(Path))
2611 std::error_code EC = ExternalFS->getRealPath(Path, Output);
2621 isFileNotFound(Result.getError()))
2622 return ExternalFS->getRealPath(Path, Output);
2623 return Result.getError();
2628 if (
auto ExtRedirect = Result->getExternalRedirect()) {
2629 auto P = ExternalFS->getRealPath(*ExtRedirect, Output);
2631 isFileNotFound(
P, Result->E)) {
2635 return ExternalFS->getRealPath(Path, Output);
2643 Result->getPath(Output);
2649std::unique_ptr<FileSystem>
2652 StringRef YAMLFilePath,
void *DiagContext,
2655 YAMLFilePath, DiagContext,
2656 std::move(ExternalFS));
2664 auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
2665 assert(DE &&
"Must be a directory");
2666 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
2668 Path.push_back(SubEntry->getName());
2676 auto *DR = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
2677 assert(DR &&
"Must be a directory remap");
2679 for (
auto &Comp : Path)
2687 auto *FE = dyn_cast<RedirectingFileSystem::FileEntry>(SrcE);
2688 assert(FE &&
"Must be a file");
2690 for (
auto &Comp : Path)
2702 std::move(Buffer),
DiagHandler, YAMLFilePath, DiagContext,
2703 std::move(ExternalFS));
2707 VFS->lookupPath(
"/");
2716 static std::atomic<unsigned> UID;
2717 unsigned ID = ++UID;
2720 return UniqueID(std::numeric_limits<uint64_t>::max(),
ID);
2728 Mappings.emplace_back(VirtualPath, RealPath, IsDirectory);
2732 addEntry(VirtualPath, RealPath,
false);
2737 addEntry(VirtualPath, RealPath,
true);
2746 unsigned getDirIndent() {
return 4 * DirStack.
size(); }
2747 unsigned getFileIndent() {
return 4 * (DirStack.
size() + 1); }
2751 void endDirectory();
2758 std::optional<bool> UseExternalNames,
2759 std::optional<bool> IsCaseSensitive,
2760 std::optional<bool> IsOverlayRelative,
StringRef OverlayDir);
2771 IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
2772 if (*IParent != *IChild)
2776 return IParent == EParent;
2781 assert(containedIn(Parent, Path));
2785void JSONWriter::startDirectory(
StringRef Path) {
2787 DirStack.
empty() ?
Path : containedPart(DirStack.
back(), Path);
2789 unsigned Indent = getDirIndent();
2791 OS.
indent(Indent + 2) <<
"'type': 'directory',\n";
2793 OS.
indent(Indent + 2) <<
"'contents': [\n";
2796void JSONWriter::endDirectory() {
2797 unsigned Indent = getDirIndent();
2805 unsigned Indent = getFileIndent();
2807 OS.
indent(Indent + 2) <<
"'type': 'file',\n";
2809 OS.
indent(Indent + 2) <<
"'external-contents': \""
2815 std::optional<bool> UseExternalNames,
2816 std::optional<bool> IsCaseSensitive,
2817 std::optional<bool> IsOverlayRelative,
2823 if (IsCaseSensitive)
2824 OS <<
" 'case-sensitive': '" << (*IsCaseSensitive ?
"true" :
"false")
2826 if (UseExternalNames)
2827 OS <<
" 'use-external-names': '" << (*UseExternalNames ?
"true" :
"false")
2829 bool UseOverlayRelative =
false;
2830 if (IsOverlayRelative) {
2831 UseOverlayRelative = *IsOverlayRelative;
2832 OS <<
" 'overlay-relative': '" << (UseOverlayRelative ?
"true" :
"false")
2835 OS <<
" 'roots': [\n";
2837 if (!Entries.empty()) {
2845 if (UseOverlayRelative) {
2847 "Overlay dir must be contained in RPath");
2851 bool IsCurrentDirEmpty =
true;
2852 if (!Entry.IsDirectory) {
2854 IsCurrentDirEmpty =
false;
2857 for (
const auto &Entry : Entries.slice(1)) {
2860 if (Dir == DirStack.
back()) {
2861 if (!IsCurrentDirEmpty) {
2865 bool IsDirPoppedFromStack =
false;
2866 while (!DirStack.
empty() && !containedIn(DirStack.
back(), Dir)) {
2869 IsDirPoppedFromStack =
true;
2871 if (IsDirPoppedFromStack || !IsCurrentDirEmpty) {
2874 startDirectory(Dir);
2875 IsCurrentDirEmpty =
true;
2878 if (UseOverlayRelative) {
2880 "Overlay dir must be contained in RPath");
2883 if (!Entry.IsDirectory) {
2885 IsCurrentDirEmpty =
false;
2889 while (!DirStack.
empty()) {
2902 return LHS.VPath <
RHS.VPath;
2905 JSONWriter(
OS).write(Mappings, UseExternalNames, IsCaseSensitive,
2914 State = std::make_shared<detail::RecDirIterState>();
2915 State->Stack.push(
I);
2921 assert(FS && State && !State->Stack.empty() &&
"incrementing past end");
2922 assert(!State->Stack.top()->path().empty() &&
"non-canonical end iterator");
2925 if (State->HasNoPushRequest)
2926 State->HasNoPushRequest =
false;
2931 State->Stack.push(
I);
2937 while (!State->Stack.empty() && State->Stack.top().increment(EC) ==
End)
2940 if (State->Stack.empty())
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 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.
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),...
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
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.
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.
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 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.
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.
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< 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 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
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.
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)
Error write(MCStreamer &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue)
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.
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.
LookupResult(Entry *E, sys::path::const_iterator Start, sys::path::const_iterator End)
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
Status makeStatus() const
std::unique_ptr< llvm::MemoryBuffer > Buffer