24#include "llvm/Config/llvm-config.h"
49#include <system_error>
75 return Status(In.getName(), In.getUniqueID(), In.getLastModificationTime(),
76 In.getUser(), In.getGroup(), NewSize, In.getType(),
81 return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
82 In.getUser(), In.getGroup(), In.getSize(), In.getType(),
87 return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
88 In.getUser(), In.getGroup(), In.getSize(), In.type(),
119 bool RequiresNullTerminator,
bool IsVolatile,
125 return (*F)->getBuffer(
Name, FileSize, RequiresNullTerminator, IsVolatile);
134 return WorkingDir.getError();
157 return StatusA.getError();
160 return StatusB.getError();
161 return StatusA->equivalent(*StatusB);
164#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
170 return Component ==
".." || Component ==
".";
190class RealFile :
public File {
191 friend class RealFileSystem;
195 std::string RealName;
198 : FD(RawFD), S(NewName, {}, {}, {}, {}, {},
200 RealName(NewRealPathName.str()) {
201 assert(FD != kInvalidFile &&
"Invalid or inactive file descriptor");
205 ~RealFile()
override;
211 bool RequiresNullTerminator,
212 bool IsVolatile)
override;
213 std::error_code close()
override;
214 void setPath(
const Twine &Path)
override;
219RealFile::~RealFile() { close(); }
222 assert(FD != kInvalidFile &&
"cannot stat closed file");
223 if (!S.isStatusKnown()) {
233 return RealName.empty() ? S.getName().str() : RealName;
237RealFile::getBuffer(
const Twine &
Name, int64_t FileSize,
238 bool RequiresNullTerminator,
bool IsVolatile) {
239 assert(FD != kInvalidFile &&
"cannot get buffer for closed file");
244std::error_code RealFile::close() {
250void RealFile::setPath(
const Twine &Path) {
251 RealName =
Path.str();
268 explicit RealFileSystem(
bool LinkCWDToProcess) {
269 if (!LinkCWDToProcess) {
274 WD = WorkingDirectory{PWD, PWD};
276 WD = WorkingDirectory{PWD, RealPWD};
283 openFileForReadBinary(
const Twine &Path)
override;
287 std::error_code setCurrentWorkingDirectory(
const Twine &Path)
override;
288 std::error_code isLocal(
const Twine &Path,
bool &Result)
override;
289 std::error_code getRealPath(
const Twine &Path,
294 unsigned IndentLevel)
const override;
302 Path.toVector(Storage);
311 adjustPath(
Name, Storage), Flags, &RealName);
314 return std::unique_ptr<File>(
315 new RealFile(*FDOrErr,
Name.str(), RealName.
str()));
318 struct WorkingDirectory {
324 std::optional<llvm::ErrorOr<WorkingDirectory>> WD;
332 if (std::error_code EC =
339RealFileSystem::openFileForRead(
const Twine &
Name) {
344RealFileSystem::openFileForReadBinary(
const Twine &
Name) {
350 return std::string(WD->get().Specified);
352 return WD->getError();
357 return std::string(Dir);
360std::error_code RealFileSystem::setCurrentWorkingDirectory(
const Twine &Path) {
365 adjustPath(Path, Storage).toVector(Absolute);
370 return std::make_error_code(std::errc::not_a_directory);
374 return std::error_code();
377std::error_code RealFileSystem::isLocal(
const Twine &Path,
bool &Result) {
382std::error_code RealFileSystem::getRealPath(
const Twine &Path,
389 unsigned IndentLevel)
const {
390 printIndent(
OS, IndentLevel);
391 OS <<
"RealFileSystem using ";
405 return std::make_unique<RealFileSystem>(
false);
414 RealFSDirIter(
const Twine &Path, std::error_code &EC) : Iter(Path, EC) {
419 std::error_code increment()
override {
432 std::error_code &EC) {
435 std::make_shared<RealFSDirIter>(adjustPath(Dir, Storage), EC));
466 if ((*I)->exists(Path))
476 auto Result = (*I)->openFileForRead(Path);
486 return FSList.
front()->getCurrentWorkingDirectory();
491 for (
auto &FS : FSList)
492 if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))
498 for (
auto &FS : FSList)
499 if (FS->exists(Path))
500 return FS->isLocal(Path, Result);
506 for (
const auto &FS : FSList)
507 if (FS->exists(Path))
508 return FS->getRealPath(Path, Output);
515 FS->visitChildFileSystems(Callback);
520 unsigned IndentLevel)
const {
521 printIndent(
OS, IndentLevel);
522 OS <<
"OverlayFileSystem\n";
523 if (
Type == PrintType::Summary)
526 if (
Type == PrintType::Contents)
527 Type = PrintType::Summary;
529 FS->print(
OS,
Type, IndentLevel + 1);
549 std::error_code incrementIter(
bool IsFirstTime) {
550 while (!IterList.
empty()) {
551 CurrentDirIter = IterList.
back();
558 return errc::no_such_file_or_directory;
562 std::error_code incrementDirIter(
bool IsFirstTime) {
564 "incrementing past end");
569 EC = incrementIter(IsFirstTime);
573 std::error_code incrementImpl(
bool IsFirstTime) {
575 std::error_code
EC = incrementDirIter(IsFirstTime);
580 CurrentEntry = *CurrentDirIter;
590 std::error_code &EC) {
591 for (
const auto &FS : FileSystems) {
594 if (FEC && FEC != errc::no_such_file_or_directory) {
601 EC = incrementImpl(
true);
606 : IterList(DirIters) {
607 EC = incrementImpl(
true);
610 std::error_code increment()
override {
return incrementImpl(
false); }
616 std::error_code &EC) {
618 std::make_shared<CombiningDirIterImpl>(FSList, Dir.
str(), EC));
624void ProxyFileSystem::anchor() {}
642 std::string FileName;
646 : Kind(Kind), FileName(
std::
string(
llvm::sys::path::filename(FileName))) {
658 virtual std::string
toString(
unsigned Indent)
const = 0;
663 std::unique_ptr<llvm::MemoryBuffer> Buffer;
671 return Status::copyWithNewName(Stat, RequestedName);
675 std::string
toString(
unsigned Indent)
const override {
676 return (std::string(Indent,
' ') + Stat.
getName() +
"\n").str();
686class InMemoryHardLink :
public InMemoryNode {
687 const InMemoryFile &ResolvedFile;
690 InMemoryHardLink(
StringRef Path,
const InMemoryFile &ResolvedFile)
691 : InMemoryNode(Path, IME_HardLink), ResolvedFile(ResolvedFile) {}
692 const InMemoryFile &getResolvedFile()
const {
return ResolvedFile; }
694 Status getStatus(
const Twine &RequestedName)
const override {
695 return ResolvedFile.getStatus(RequestedName);
698 std::string
toString(
unsigned Indent)
const override {
699 return std::string(Indent,
' ') +
"HardLink to -> " +
700 ResolvedFile.toString(0);
703 static bool classof(
const InMemoryNode *
N) {
708class InMemorySymbolicLink :
public InMemoryNode {
709 std::string TargetPath;
717 std::string
toString(
unsigned Indent)
const override {
718 return std::string(Indent,
' ') +
"SymbolicLink to -> " + TargetPath;
721 Status getStatus(
const Twine &RequestedName)
const override {
722 return Status::copyWithNewName(Stat, RequestedName);
725 StringRef getTargetPath()
const {
return TargetPath; }
727 static bool classof(
const InMemoryNode *
N) {
735class InMemoryFileAdaptor :
public File {
736 const InMemoryFile &
Node;
738 std::string RequestedName;
741 explicit InMemoryFileAdaptor(
const InMemoryFile &
Node,
742 std::string RequestedName)
746 return Node.getStatus(RequestedName);
750 getBuffer(
const Twine &
Name, int64_t FileSize,
bool RequiresNullTerminator,
751 bool IsVolatile)
override {
757 std::error_code close()
override {
return {}; }
759 void setPath(
const Twine &Path)
override { RequestedName =
Path.str(); }
765 std::map<std::string, std::unique_ptr<InMemoryNode>, std::less<>> Entries;
775 return Status::copyWithNewName(Stat, RequestedName);
781 auto I = Entries.find(
Name);
782 if (
I != Entries.end())
783 return I->second.get();
788 return Entries.emplace(
Name, std::move(Child)).first->second.get();
796 std::string
toString(
unsigned Indent)
const override {
798 (std::string(Indent,
' ') + Stat.
getName() +
"\n").str();
799 for (
const auto &Entry : Entries)
800 Result += Entry.second->toString(Indent + 2);
830 (
Type == sys::fs::file_type::directory_file)
832 :
getFileID(DirUID,
Name, Buffer ? Buffer->getBuffer() :
"");
835 Group, Buffer ? Buffer->getBufferSize() : 0,
Type, Perms);
839 : Root(new
detail::InMemoryDirectory(
842 llvm::sys::fs::file_type::directory_file,
843 llvm::sys::fs::perms::all_all))),
844 UseNormalizedPaths(UseNormalizedPaths) {}
849 return Root->toString(0);
852bool InMemoryFileSystem::addFile(
const Twine &
P, time_t ModificationTime,
853 std::unique_ptr<llvm::MemoryBuffer> Buffer,
854 std::optional<uint32_t>
User,
855 std::optional<uint32_t> Group,
856 std::optional<llvm::sys::fs::file_type>
Type,
857 std::optional<llvm::sys::fs::perms> Perms,
858 MakeNodeFn MakeNode) {
875 const auto ResolvedUser =
User.value_or(0);
876 const auto ResolvedGroup = Group.value_or(0);
893 StringRef(Path.str().begin(),
Name.end() - Path.str().begin()),
897 Dir = cast<detail::InMemoryDirectory>(Dir->
addChild(
898 Name, std::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
902 if (!isa<detail::InMemoryDirectory>(Node))
904 Dir = cast<detail::InMemoryDirectory>(Node);
910 std::move(Buffer), ResolvedUser, ResolvedGroup,
911 ResolvedType, ResolvedPerms}));
914 if (isa<detail::InMemoryDirectory>(
Node))
918 isa<detail::InMemoryHardLink>(
Node)) &&
919 "Must be either file, hardlink or directory!");
922 if (
auto *Link = dyn_cast<detail::InMemoryHardLink>(
Node)) {
923 return Link->getResolvedFile().getBuffer()->getBuffer() ==
926 return cast<detail::InMemoryFile>(
Node)->getBuffer()->getBuffer() ==
930bool InMemoryFileSystem::addFile(
const Twine &
P, time_t ModificationTime,
931 std::unique_ptr<llvm::MemoryBuffer> Buffer,
932 std::optional<uint32_t>
User,
933 std::optional<uint32_t> Group,
934 std::optional<llvm::sys::fs::file_type>
Type,
935 std::optional<llvm::sys::fs::perms> Perms) {
936 return addFile(
P, ModificationTime, std::move(Buffer),
User, Group,
Type,
939 -> std::unique_ptr<detail::InMemoryNode> {
942 return std::make_unique<detail::InMemoryDirectory>(Stat);
943 return std::make_unique<detail::InMemoryFile>(
944 Stat, std::move(NNI.
Buffer));
949 const Twine &
P, time_t ModificationTime,
951 std::optional<uint32_t> Group, std::optional<llvm::sys::fs::file_type>
Type,
952 std::optional<llvm::sys::fs::perms> Perms) {
954 std::move(
User), std::move(Group), std::move(
Type),
957 -> std::unique_ptr<detail::InMemoryNode> {
960 return std::make_unique<detail::InMemoryDirectory>(Stat);
961 return std::make_unique<detail::InMemoryFile>(
962 Stat, std::move(NNI.
Buffer));
967InMemoryFileSystem::lookupNode(
const Twine &
P,
bool FollowFinalSymlink,
968 size_t SymlinkDepth)
const {
991 if (
auto Symlink = dyn_cast<detail::InMemorySymbolicLink>(Node)) {
994 if (
I == E && !FollowFinalSymlink)
1009 lookupNode(TargetPath,
true, SymlinkDepth + 1);
1013 if (!isa<detail::InMemoryDirectory>(*
Target))
1017 Dir = cast<detail::InMemoryDirectory>(*
Target);
1022 if (
auto File = dyn_cast<detail::InMemoryFile>(Node)) {
1029 if (
auto File = dyn_cast<detail::InMemoryHardLink>(
Node)) {
1035 Dir = cast<detail::InMemoryDirectory>(
Node);
1043 auto NewLinkNode = lookupNode(NewLink,
false);
1047 auto TargetNode = lookupNode(
Target,
true);
1050 if (!TargetNode || NewLinkNode || !isa<detail::InMemoryFile>(*TargetNode))
1052 return addFile(NewLink, 0,
nullptr, std::nullopt, std::nullopt, std::nullopt,
1054 return std::make_unique<detail::InMemoryHardLink>(
1056 *cast<detail::InMemoryFile>(*TargetNode));
1062 std::optional<uint32_t>
User, std::optional<uint32_t> Group,
1063 std::optional<llvm::sys::fs::perms> Perms) {
1064 auto NewLinkNode = lookupNode(NewLink,
false);
1070 Target.toVector(TargetStr);
1072 return addFile(NewLinkStr, ModificationTime,
nullptr,
User, Group,
1075 return std::make_unique<detail::InMemorySymbolicLink>(
1081 auto Node = lookupNode(Path,
true);
1083 return (*Node)->getStatus(Path);
1084 return Node.getError();
1089 auto Node = lookupNode(Path,
true);
1091 return Node.getError();
1095 if (
auto *
F = dyn_cast<detail::InMemoryFile>(*Node))
1096 return std::unique_ptr<File>(
1097 new detail::InMemoryFileAdaptor(*
F, Path.str()));
1108 std::string RequestedDirName;
1110 void setCurrentEntry() {
1115 switch (
I->second->getKind()) {
1124 if (
auto SymlinkTarget =
1125 FS->lookupNode(Path,
true)) {
1126 Path = SymlinkTarget.getName();
1127 Type = (*SymlinkTarget)->getStatus(Path).getType();
1144 std::string RequestedDirName)
1145 : FS(FS),
I(Dir.begin()), E(Dir.end()),
1146 RequestedDirName(
std::
move(RequestedDirName)) {
1158 std::error_code &EC) {
1159 auto Node = lookupNode(Dir,
true);
1161 EC = Node.getError();
1165 if (
auto *DirNode = dyn_cast<detail::InMemoryDirectory>(*Node))
1167 std::make_shared<DirIterator>(
this, *DirNode, Dir.
str()));
1186 WorkingDirectory = std::string(Path);
1193 if (!CWD || CWD->empty())
1195 Path.toVector(Output);
1208 unsigned IndentLevel)
const {
1209 printIndent(
OS, IndentLevel);
1210 OS <<
"InMemoryFileSystem\n";
1225 const size_t n = Path.find_first_of(
"/\\");
1227 if (n !=
static_cast<size_t>(-1))
1247static bool isFileNotFound(std::error_code EC,
1249 if (E && !isa<RedirectingFileSystem::DirectoryRemapEntry>(E))
1260 if (
auto ExternalWorkingDirectory =
1261 ExternalFS->getCurrentWorkingDirectory()) {
1262 WorkingDirectory = *ExternalWorkingDirectory;
1273 std::error_code incrementImpl(
bool IsFirstTime) {
1274 assert((IsFirstTime || Current !=
End) &&
"cannot iterate past end");
1277 if (Current !=
End) {
1281 switch ((*Current)->getKind()) {
1302 : Dir(Path.str()), Current(Begin),
End(
End) {
1303 EC = incrementImpl(
true);
1307 return incrementImpl(
false);
1321 RedirectingFSDirRemapIterImpl(std::string DirPath,
1323 : Dir(
std::
move(DirPath)), DirStyle(getExistingStyle(Dir)),
1324 ExternalIter(ExtIter) {
1329 void setCurrentEntry() {
1340 std::error_code increment()
override {
1354 return WorkingDirectory;
1364 Path.toVector(AbsolutePath);
1365 if (std::error_code EC = makeAbsolute(AbsolutePath))
1367 WorkingDirectory = std::string(AbsolutePath);
1376 if (makeAbsolute(Path))
1379 return ExternalFS->isLocal(Path, Result);
1394 return WorkingDir.getError();
1396 return makeAbsolute(WorkingDir.get(), Path);
1400RedirectingFileSystem::makeAbsolute(
StringRef WorkingDir,
1406 if (!WorkingDir.
empty() &&
1410 return std::error_code();
1422 std::string
Result = std::string(WorkingDir);
1439 std::error_code &EC) {
1443 EC = makeAbsolute(Path);
1450 isFileNotFound(Result.getError()))
1451 return ExternalFS->dir_begin(Path, EC);
1453 EC = Result.getError();
1461 isFileNotFound(S.
getError(), Result->E))
1462 return ExternalFS->dir_begin(Dir, EC);
1468 if (!S->isDirectory()) {
1476 std::error_code RedirectEC;
1477 if (
auto ExtRedirect = Result->getExternalRedirect()) {
1478 auto RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
1479 RedirectIter = ExternalFS->dir_begin(*ExtRedirect, RedirectEC);
1481 if (!RE->useExternalName(UseExternalNames)) {
1485 std::string(Path), RedirectIter));
1488 auto DE = cast<DirectoryEntry>(Result->E);
1491 Path, DE->contents_begin(), DE->contents_end(), RedirectEC));
1504 return RedirectIter;
1507 std::error_code ExternalEC;
1518 switch (Redirection) {
1532 std::make_shared<CombiningDirIterImpl>(Iters, EC)};
1539 OverlayFileDir = Dir.
str();
1543 return OverlayFileDir;
1560 std::vector<StringRef> R;
1561 R.reserve(Roots.size());
1562 for (
const auto &Root : Roots)
1563 R.push_back(Root->getName());
1568 unsigned IndentLevel)
const {
1570 OS <<
"RedirectingFileSystem (UseExternalNames: "
1571 << (UseExternalNames ?
"true" :
"false") <<
")\n";
1575 for (
const auto &Root : Roots)
1579 OS <<
"ExternalFS:\n";
1586 unsigned IndentLevel)
const {
1592 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(E);
1595 for (std::unique_ptr<Entry> &SubEntry :
1602 auto *RE = cast<RedirectingFileSystem::RemapEntry>(E);
1603 OS <<
" -> '" << RE->getExternalContentsPath() <<
"'";
1604 switch (RE->getUseName()) {
1608 OS <<
" (UseExternalName: true)";
1611 OS <<
" (UseExternalName: false)";
1622 Callback(*ExternalFS);
1623 ExternalFS->visitChildFileSystems(Callback);
1636 const auto *S = dyn_cast<yaml::ScalarNode>(
N);
1639 error(
N,
"expected string");
1642 Result = S->getValue(Storage);
1647 bool parseScalarBool(
yaml::Node *
N,
bool &Result) {
1650 if (!parseScalarString(
N,
Value, Storage))
1653 if (
Value.equals_insensitive(
"true") ||
Value.equals_insensitive(
"on") ||
1654 Value.equals_insensitive(
"yes") ||
Value ==
"1") {
1657 }
else if (
Value.equals_insensitive(
"false") ||
1658 Value.equals_insensitive(
"off") ||
1659 Value.equals_insensitive(
"no") ||
Value ==
"0") {
1664 error(
N,
"expected boolean value");
1668 std::optional<RedirectingFileSystem::RedirectKind>
1672 if (!parseScalarString(
N,
Value, Storage))
1673 return std::nullopt;
1675 if (
Value.equals_insensitive(
"fallthrough")) {
1677 }
else if (
Value.equals_insensitive(
"fallback")) {
1679 }
else if (
Value.equals_insensitive(
"redirect-only")) {
1682 return std::nullopt;
1685 std::optional<RedirectingFileSystem::RootRelativeKind>
1689 if (!parseScalarString(
N,
Value, Storage))
1690 return std::nullopt;
1691 if (
Value.equals_insensitive(
"cwd")) {
1693 }
else if (
Value.equals_insensitive(
"overlay-dir")) {
1696 return std::nullopt;
1703 KeyStatus(
bool Required =
false) : Required(Required) {}
1706 using KeyStatusPair = std::pair<StringRef, KeyStatus>;
1711 if (!Keys.
count(Key)) {
1712 error(KeyNode,
"unknown key");
1715 KeyStatus &S = Keys[Key];
1717 error(KeyNode,
Twine(
"duplicate key '") + Key +
"'");
1726 for (
const auto &
I : Keys) {
1727 if (
I.second.Required && !
I.second.Seen) {
1728 error(Obj,
Twine(
"missing key '") +
I.first +
"'");
1740 for (
const auto &Root : FS->Roots) {
1741 if (
Name == Root->getName()) {
1742 ParentEntry = Root.get();
1747 auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
1748 for (std::unique_ptr<RedirectingFileSystem::Entry> &
Content :
1751 dyn_cast<RedirectingFileSystem::DirectoryEntry>(
Content.get());
1758 std::unique_ptr<RedirectingFileSystem::Entry> E =
1759 std::make_unique<RedirectingFileSystem::DirectoryEntry>(
1761 std::chrono::system_clock::now(), 0, 0, 0,
1765 FS->Roots.push_back(std::move(E));
1766 ParentEntry = FS->Roots.back().get();
1770 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
1771 DE->addContent(std::move(E));
1772 return DE->getLastContent();
1782 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
1788 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
1790 uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
1794 assert(NewParentE &&
"Parent entry must exist");
1795 auto *DR = cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
1796 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
1798 std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
1799 Name, DR->getExternalContentsPath(), DR->getUseName()));
1803 assert(NewParentE &&
"Parent entry must exist");
1804 auto *FE = cast<RedirectingFileSystem::FileEntry>(SrcE);
1805 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
1806 DE->addContent(std::make_unique<RedirectingFileSystem::FileEntry>(
1807 Name, FE->getExternalContentsPath(), FE->getUseName()));
1813 std::unique_ptr<RedirectingFileSystem::Entry>
1815 auto *
M = dyn_cast<yaml::MappingNode>(
N);
1817 error(
N,
"expected mapping node for file or directory entry");
1821 KeyStatusPair Fields[] = {
1822 KeyStatusPair(
"name",
true),
1823 KeyStatusPair(
"type",
true),
1824 KeyStatusPair(
"contents",
false),
1825 KeyStatusPair(
"external-contents",
false),
1826 KeyStatusPair(
"use-external-name",
false),
1831 enum { CF_NotSet, CF_List, CF_External } ContentsField = CF_NotSet;
1832 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>>
1840 for (
auto &
I : *M) {
1845 if (!parseScalarString(
I.getKey(), Key, Buffer))
1848 if (!checkDuplicateOrUnknownKey(
I.getKey(), Key, Keys))
1852 if (Key ==
"name") {
1853 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1856 NameValueNode =
I.getValue();
1860 }
else if (Key ==
"type") {
1861 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1863 if (
Value ==
"file")
1865 else if (
Value ==
"directory")
1867 else if (
Value ==
"directory-remap")
1870 error(
I.getValue(),
"unknown value for 'type'");
1873 }
else if (Key ==
"contents") {
1874 if (ContentsField != CF_NotSet) {
1876 "entry already has 'contents' or 'external-contents'");
1879 ContentsField = CF_List;
1880 auto *Contents = dyn_cast<yaml::SequenceNode>(
I.getValue());
1883 error(
I.getValue(),
"expected array");
1887 for (
auto &
I : *Contents) {
1888 if (std::unique_ptr<RedirectingFileSystem::Entry> E =
1889 parseEntry(&
I, FS,
false))
1890 EntryArrayContents.push_back(std::move(E));
1894 }
else if (Key ==
"external-contents") {
1895 if (ContentsField != CF_NotSet) {
1897 "entry already has 'contents' or 'external-contents'");
1900 ContentsField = CF_External;
1901 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1905 if (
FS->IsRelativeOverlay) {
1906 FullPath =
FS->getOverlayFileDir();
1908 "External contents prefix directory must exist");
1916 FullPath = canonicalize(FullPath);
1917 ExternalContentsPath = FullPath.
str();
1918 }
else if (Key ==
"use-external-name") {
1920 if (!parseScalarBool(
I.getValue(), Val))
1933 if (ContentsField == CF_NotSet) {
1934 error(
N,
"missing key 'contents' or 'external-contents'");
1937 if (!checkMissingKeys(
N, Keys))
1943 error(
N,
"'use-external-name' is not supported for 'directory' entries");
1948 ContentsField == CF_List) {
1949 error(
N,
"'contents' is not supported for 'directory-remap' entries");
1967 if (
FS->RootRelative ==
1970 assert(!FullPath.
empty() &&
"Overlay file directory must exist");
1971 EC =
FS->makeAbsolute(FullPath,
Name);
1977 assert(NameValueNode &&
"Name presence should be checked earlier");
1980 "entry with relative path at the root level is not discoverable");
1998 while (Trimmed.
size() > RootPathLen &&
2000 Trimmed = Trimmed.
slice(0, Trimmed.
size() - 1);
2005 std::unique_ptr<RedirectingFileSystem::Entry>
Result;
2008 Result = std::make_unique<RedirectingFileSystem::FileEntry>(
2009 LastComponent, std::move(ExternalContentsPath), UseExternalName);
2012 Result = std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
2013 LastComponent, std::move(ExternalContentsPath), UseExternalName);
2016 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
2017 LastComponent, std::move(EntryArrayContents),
2031 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> Entries;
2032 Entries.push_back(std::move(Result));
2033 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
2034 *
I, std::move(Entries),
2046 auto *Top = dyn_cast<yaml::MappingNode>(Root);
2048 error(Root,
"expected mapping node");
2052 KeyStatusPair Fields[] = {
2053 KeyStatusPair(
"version",
true),
2054 KeyStatusPair(
"case-sensitive",
false),
2055 KeyStatusPair(
"use-external-names",
false),
2056 KeyStatusPair(
"root-relative",
false),
2057 KeyStatusPair(
"overlay-relative",
false),
2058 KeyStatusPair(
"fallthrough",
false),
2059 KeyStatusPair(
"redirecting-with",
false),
2060 KeyStatusPair(
"roots",
true),
2064 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> RootEntries;
2067 for (
auto &
I : *Top) {
2070 if (!parseScalarString(
I.getKey(), Key, KeyBuffer))
2073 if (!checkDuplicateOrUnknownKey(
I.getKey(), Key, Keys))
2076 if (Key ==
"roots") {
2077 auto *Roots = dyn_cast<yaml::SequenceNode>(
I.getValue());
2079 error(
I.getValue(),
"expected array");
2083 for (
auto &
I : *Roots) {
2084 if (std::unique_ptr<RedirectingFileSystem::Entry> E =
2085 parseEntry(&
I, FS,
true))
2086 RootEntries.push_back(std::move(E));
2090 }
else if (Key ==
"version") {
2093 if (!parseScalarString(
I.getValue(), VersionString, Storage))
2097 error(
I.getValue(),
"expected integer");
2101 error(
I.getValue(),
"invalid version number");
2105 error(
I.getValue(),
"version mismatch, expected 0");
2108 }
else if (Key ==
"case-sensitive") {
2109 if (!parseScalarBool(
I.getValue(), FS->CaseSensitive))
2111 }
else if (Key ==
"overlay-relative") {
2112 if (!parseScalarBool(
I.getValue(), FS->IsRelativeOverlay))
2114 }
else if (Key ==
"use-external-names") {
2115 if (!parseScalarBool(
I.getValue(), FS->UseExternalNames))
2117 }
else if (Key ==
"fallthrough") {
2118 if (Keys[
"redirecting-with"].Seen) {
2120 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2124 bool ShouldFallthrough =
false;
2125 if (!parseScalarBool(
I.getValue(), ShouldFallthrough))
2128 if (ShouldFallthrough) {
2133 }
else if (Key ==
"redirecting-with") {
2134 if (Keys[
"fallthrough"].Seen) {
2136 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2140 if (
auto Kind = parseRedirectKind(
I.getValue())) {
2141 FS->Redirection = *Kind;
2143 error(
I.getValue(),
"expected valid redirect kind");
2146 }
else if (Key ==
"root-relative") {
2147 if (
auto Kind = parseRootRelativeKind(
I.getValue())) {
2148 FS->RootRelative = *Kind;
2150 error(
I.getValue(),
"expected valid root-relative kind");
2161 if (!checkMissingKeys(Top, Keys))
2167 for (
auto &E : RootEntries)
2168 uniqueOverlayTree(FS, E.get());
2174std::unique_ptr<RedirectingFileSystem>
2177 StringRef YAMLFilePath,
void *DiagContext,
2185 if (DI == Stream.
end() || !Root) {
2192 std::unique_ptr<RedirectingFileSystem> FS(
2195 if (!YAMLFilePath.
empty()) {
2206 assert(!EC &&
"Overlay dir final path must be absolute");
2208 FS->setOverlayFileDir(OverlayAbsDir);
2211 if (!
P.parse(Root, FS.get()))
2218 ArrayRef<std::pair<std::string, std::string>> RemappedFiles,
2219 bool UseExternalNames,
FileSystem &ExternalFS) {
2220 std::unique_ptr<RedirectingFileSystem> FS(
2222 FS->UseExternalNames = UseExternalNames;
2232 assert(!EC &&
"Could not make absolute path");
2250 assert(Parent &&
"File without a directory?");
2254 assert(!EC &&
"Could not make absolute path");
2258 auto NewFile = std::make_unique<RedirectingFileSystem::FileEntry>(
2262 ToEntry = NewFile.get();
2263 cast<RedirectingFileSystem::DirectoryEntry>(Parent)->addContent(
2264 std::move(NewFile));
2277 if (
auto *DRE = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(
E)) {
2280 getExistingStyle(DRE->getExternalContentsPath()));
2281 ExternalRedirect = std::string(Redirect);
2288 for (
Entry *Parent : Parents)
2293std::error_code RedirectingFileSystem::makeCanonicalForLookup(
2295 if (std::error_code EC = makeAbsolute(Path))
2299 canonicalize(
StringRef(Path.data(), Path.size()));
2300 if (CanonicalPath.
empty())
2303 Path.assign(CanonicalPath.
begin(), CanonicalPath.
end());
2310 if (std::error_code EC = makeCanonicalForLookup(CanonicalPath))
2320 for (
const auto &Root : Roots) {
2322 lookupPathImpl(Start,
End, Root.get(), Entries);
2323 if (UsageTrackingActive && Result && isa<RemapEntry>(Result->E))
2326 Result->Parents = std::move(Entries);
2334RedirectingFileSystem::lookupPathImpl(
2340 "Paths should not contain traversal components");
2345 if (!FromName.
empty()) {
2346 if (!pathComponentMatches(*Start, FromName))
2353 return LookupResult(
From, Start,
End);
2357 if (isa<RedirectingFileSystem::FileEntry>(
From))
2360 if (isa<RedirectingFileSystem::DirectoryRemapEntry>(
From))
2361 return LookupResult(
From, Start,
End);
2363 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(
From);
2364 for (
const std::unique_ptr<RedirectingFileSystem::Entry> &DirEntry :
2366 Entries.push_back(
From);
2368 lookupPathImpl(Start,
End, DirEntry.get(), Entries);
2378 bool UseExternalNames,
2383 return ExternalStatus;
2385 Status S = ExternalStatus;
2386 if (!UseExternalNames)
2394 const Twine &LookupPath,
const Twine &OriginalPath,
2396 if (std::optional<StringRef> ExtRedirect =
Result.getExternalRedirect()) {
2398 if (std::error_code EC = makeAbsolute(RemappedPath))
2405 auto *RE = cast<RedirectingFileSystem::RemapEntry>(
Result.E);
2407 RE->useExternalName(UseExternalNames), *S);
2410 auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(
Result.E);
2415RedirectingFileSystem::getExternalStatus(
const Twine &LookupPath,
2416 const Twine &OriginalPath)
const {
2417 auto Result = ExternalFS->status(LookupPath);
2421 if (!Result ||
Result->ExposesExternalVFSPath)
2430 if (std::error_code EC = makeAbsolute(Path))
2446 isFileNotFound(Result.getError()))
2447 return getExternalStatus(Path, OriginalPath);
2448 return Result.getError();
2453 isFileNotFound(S.
getError(), Result->E)) {
2457 return getExternalStatus(Path, OriginalPath);
2467 if (makeAbsolute(Path))
2473 if (ExternalFS->exists(Path))
2482 isFileNotFound(Result.getError()))
2483 return ExternalFS->exists(Path);
2487 std::optional<StringRef> ExtRedirect = Result->getExternalRedirect();
2489 assert(isa<RedirectingFileSystem::DirectoryEntry>(Result->E));
2494 if (makeAbsolute(RemappedPath))
2497 if (ExternalFS->exists(RemappedPath))
2504 return ExternalFS->exists(Path);
2513class FileWithFixedStatus :
public File {
2514 std::unique_ptr<File> InnerFile;
2518 FileWithFixedStatus(std::unique_ptr<File> InnerFile,
Status S)
2524 getBuffer(
const Twine &
Name, int64_t FileSize,
bool RequiresNullTerminator,
2525 bool IsVolatile)
override {
2526 return InnerFile->getBuffer(
Name, FileSize, RequiresNullTerminator,
2530 std::error_code close()
override {
return InnerFile->close(); }
2541 if (!Result || (*Result)->status()->ExposesExternalVFSPath)
2545 auto Name =
F->get()->getName();
2547 F->get()->setPath(
P);
2556 if (std::error_code EC = makeAbsolute(Path))
2572 isFileNotFound(Result.getError()))
2574 return Result.getError();
2577 if (!Result->getExternalRedirect())
2580 StringRef ExtRedirect = *Result->getExternalRedirect();
2582 if (std::error_code EC = makeAbsolute(RemappedPath))
2585 auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
2589 if (!ExternalFile) {
2591 isFileNotFound(ExternalFile.getError(), Result->E)) {
2597 return ExternalFile;
2600 auto ExternalStatus = (*ExternalFile)->status();
2601 if (!ExternalStatus)
2602 return ExternalStatus.getError();
2607 OriginalPath, RE->useExternalName(UseExternalNames), *ExternalStatus);
2608 return std::unique_ptr<File>(
2609 std::make_unique<FileWithFixedStatus>(std::move(*ExternalFile), S));
2618 if (std::error_code EC = makeAbsolute(Path))
2624 std::error_code EC = ExternalFS->getRealPath(Path, Output);
2634 isFileNotFound(Result.getError()))
2635 return ExternalFS->getRealPath(Path, Output);
2636 return Result.getError();
2641 if (
auto ExtRedirect = Result->getExternalRedirect()) {
2642 auto P = ExternalFS->getRealPath(*ExtRedirect, Output);
2644 isFileNotFound(
P, Result->E)) {
2648 return ExternalFS->getRealPath(Path, Output);
2656 Result->getPath(Output);
2662std::unique_ptr<FileSystem>
2665 StringRef YAMLFilePath,
void *DiagContext,
2668 YAMLFilePath, DiagContext,
2669 std::move(ExternalFS));
2677 auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
2678 assert(DE &&
"Must be a directory");
2679 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
2681 Path.push_back(SubEntry->getName());
2689 auto *DR = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
2690 assert(DR &&
"Must be a directory remap");
2692 for (
auto &Comp : Path)
2700 auto *FE = dyn_cast<RedirectingFileSystem::FileEntry>(SrcE);
2701 assert(FE &&
"Must be a file");
2703 for (
auto &Comp : Path)
2715 std::move(Buffer),
DiagHandler, YAMLFilePath, DiagContext,
2716 std::move(ExternalFS));
2720 VFS->lookupPath(
"/");
2729 static std::atomic<unsigned> UID;
2730 unsigned ID = ++UID;
2733 return UniqueID(std::numeric_limits<uint64_t>::max(),
ID);
2741 Mappings.emplace_back(VirtualPath, RealPath, IsDirectory);
2745 addEntry(VirtualPath, RealPath,
false);
2750 addEntry(VirtualPath, RealPath,
true);
2759 unsigned getDirIndent() {
return 4 * DirStack.
size(); }
2760 unsigned getFileIndent() {
return 4 * (DirStack.
size() + 1); }
2764 void endDirectory();
2771 std::optional<bool> UseExternalNames,
2772 std::optional<bool> IsCaseSensitive,
2773 std::optional<bool> IsOverlayRelative,
StringRef OverlayDir);
2784 IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
2785 if (*IParent != *IChild)
2789 return IParent == EParent;
2794 assert(containedIn(Parent, Path));
2795 return Path.substr(Parent.
size() + 1);
2798void JSONWriter::startDirectory(
StringRef Path) {
2800 DirStack.
empty() ?
Path : containedPart(DirStack.
back(), Path);
2802 unsigned Indent = getDirIndent();
2804 OS.
indent(Indent + 2) <<
"'type': 'directory',\n";
2806 OS.
indent(Indent + 2) <<
"'contents': [\n";
2809void JSONWriter::endDirectory() {
2810 unsigned Indent = getDirIndent();
2818 unsigned Indent = getFileIndent();
2820 OS.
indent(Indent + 2) <<
"'type': 'file',\n";
2822 OS.
indent(Indent + 2) <<
"'external-contents': \""
2828 std::optional<bool> UseExternalNames,
2829 std::optional<bool> IsCaseSensitive,
2830 std::optional<bool> IsOverlayRelative,
2836 if (IsCaseSensitive)
2837 OS <<
" 'case-sensitive': '" << (*IsCaseSensitive ?
"true" :
"false")
2839 if (UseExternalNames)
2840 OS <<
" 'use-external-names': '" << (*UseExternalNames ?
"true" :
"false")
2842 bool UseOverlayRelative =
false;
2843 if (IsOverlayRelative) {
2844 UseOverlayRelative = *IsOverlayRelative;
2845 OS <<
" 'overlay-relative': '" << (UseOverlayRelative ?
"true" :
"false")
2848 OS <<
" 'roots': [\n";
2850 if (!Entries.empty()) {
2858 if (UseOverlayRelative) {
2860 "Overlay dir must be contained in RPath");
2864 bool IsCurrentDirEmpty =
true;
2865 if (!
Entry.IsDirectory) {
2867 IsCurrentDirEmpty =
false;
2870 for (
const auto &Entry : Entries.slice(1)) {
2873 if (Dir == DirStack.
back()) {
2874 if (!IsCurrentDirEmpty) {
2878 bool IsDirPoppedFromStack =
false;
2879 while (!DirStack.
empty() && !containedIn(DirStack.
back(), Dir)) {
2882 IsDirPoppedFromStack =
true;
2884 if (IsDirPoppedFromStack || !IsCurrentDirEmpty) {
2887 startDirectory(Dir);
2888 IsCurrentDirEmpty =
true;
2891 if (UseOverlayRelative) {
2893 "Overlay dir must be contained in RPath");
2896 if (!
Entry.IsDirectory) {
2898 IsCurrentDirEmpty =
false;
2902 while (!DirStack.
empty()) {
2915 return LHS.VPath <
RHS.VPath;
2918 JSONWriter(
OS).write(Mappings, UseExternalNames, IsCaseSensitive,
2927 State = std::make_shared<detail::RecDirIterState>();
2928 State->Stack.push_back(
I);
2934 assert(FS && State && !State->Stack.empty() &&
"incrementing past end");
2935 assert(!State->Stack.back()->path().empty() &&
"non-canonical end iterator");
2938 if (State->HasNoPushRequest)
2939 State->HasNoPushRequest =
false;
2943 FS->dir_begin(State->Stack.back()->path(), EC);
2945 State->Stack.push_back(
I);
2951 while (!State->Stack.empty() && State->Stack.back().increment(EC) ==
End)
2952 State->Stack.pop_back();
2954 if (State->Stack.empty())
2961 unsigned IndentLevel)
const {
2962 printIndent(
OS, IndentLevel);
2963 OS <<
"TracingFileSystem\n";
2964 if (
Type == PrintType::Summary)
2967 printIndent(
OS, IndentLevel);
2969 printIndent(
OS, IndentLevel);
2971 printIndent(
OS, IndentLevel);
2973 printIndent(
OS, IndentLevel);
2975 printIndent(
OS, IndentLevel);
2977 printIndent(
OS, IndentLevel);
2980 if (
Type == PrintType::Contents)
2981 Type = PrintType::Summary;
2982 getUnderlyingFS().
print(
OS,
Type, IndentLevel + 1);
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.
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
constexpr bool empty() const
empty - Check if the string is empty.
char back() const
back - Get the last character in the string.
StringRef slice(size_t Start, size_t End) const
Return a reference to the substring from [Start, End).
constexpr size_t size() const
size - Get the string size.
StringSet - A wrapper for StringMap that provides set-like functionality.
std::pair< typename Base::iterator, bool > insert(StringRef key)
Target - Wrapper for Target specific information.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
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.
void print(raw_ostream &O, bool IsForDebug=false, bool NoDetails=false) const
Print the current type.
LLVM Value Representation.
An efficient, type-erasing, non-owning reference to a callable.
An opaque object representing a hash code.
This class implements an extremely fast bulk output stream that can only output to a stream.
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
const std::string & path() const
directory_iterator - Iterates through the entries in path.
directory_iterator & increment(std::error_code &ec)
Represents the result of a call to sys::fs::status().
The virtual file system interface.
virtual llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const =0
Get the working directory of this file system.
virtual bool exists(const Twine &Path)
Check whether Path exists.
virtual llvm::ErrorOr< std::unique_ptr< File > > openFileForReadBinary(const Twine &Path)
Get a File object for the binary file at Path, if one exists.
virtual std::error_code makeAbsolute(SmallVectorImpl< char > &Path) const
Make Path an absolute path.
virtual llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path)=0
Get a File object for the text file at Path, if one exists.
virtual std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output)
Gets real path of Path e.g.
void printIndent(raw_ostream &OS, unsigned IndentLevel) const
LLVM_DUMP_METHOD void dump() const
void print(raw_ostream &OS, PrintType Type=PrintType::Contents, unsigned IndentLevel=0) const
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getBufferForFile(const Twine &Name, int64_t FileSize=-1, bool RequiresNullTerminator=true, bool IsVolatile=false, bool IsText=true)
This is a convenience method that opens a file, gets its content and then closes the file.
llvm::ErrorOr< bool > equivalent(const Twine &A, const Twine &B)
virtual std::error_code isLocal(const Twine &Path, bool &Result)
Is the file mounted on a local filesystem?
virtual llvm::ErrorOr< Status > status(const Twine &Path)=0
Get the status of the entry at Path, if one exists.
static ErrorOr< std::unique_ptr< File > > getWithPath(ErrorOr< std::unique_ptr< File > > Result, const Twine &P)
virtual ~File()
Destroy the file after closing it (if open).
Adaptor from InMemoryDir::iterator to directory_iterator.
DirIterator(const InMemoryFileSystem *FS, const detail::InMemoryDirectory &Dir, std::string RequestedDirName)
std::error_code increment() override
Sets CurrentEntry to the next entry in the directory on success, to directory_entry() at end,...
An in-memory file system.
std::error_code isLocal(const Twine &Path, bool &Result) override
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override
std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) override
Canonicalizes Path by combining with the current working directory and normalizing the path (e....
~InMemoryFileSystem() override
static constexpr size_t MaxSymlinkDepth
Arbitrary max depth to search through symlinks.
InMemoryFileSystem(bool UseNormalizedPaths=true)
bool useNormalizedPaths() const
Return true if this file system normalizes . and .. in paths.
void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override
llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override
bool addHardLink(const Twine &NewLink, const Twine &Target)
Add a hard link to a file.
std::string toString() const
bool addFileNoOwn(const Twine &Path, time_t ModificationTime, const llvm::MemoryBufferRef &Buffer, std::optional< uint32_t > User=std::nullopt, std::optional< uint32_t > Group=std::nullopt, std::optional< llvm::sys::fs::file_type > Type=std::nullopt, std::optional< llvm::sys::fs::perms > Perms=std::nullopt)
Add a buffer to the VFS with a path.
bool addSymbolicLink(const Twine &NewLink, const Twine &Target, time_t ModificationTime, std::optional< uint32_t > User=std::nullopt, std::optional< uint32_t > Group=std::nullopt, std::optional< llvm::sys::fs::perms > Perms=std::nullopt)
Add a symbolic link.
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
llvm::ErrorOr< Status > status(const Twine &Path) override
llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override
void visitChildFileSystems(VisitCallbackTy Callback) override
llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override
std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) override
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
void pushOverlay(IntrusiveRefCntPtr< FileSystem > FS)
Pushes a file system on top of the stack.
OverlayFileSystem(IntrusiveRefCntPtr< FileSystem > Base)
llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override
iterator overlays_end()
Get an iterator pointing one-past the least recently added file system.
std::error_code isLocal(const Twine &Path, bool &Result) override
bool exists(const Twine &Path) override
llvm::ErrorOr< Status > status(const Twine &Path) override
iterator overlays_begin()
Get an iterator pointing to the most recently added file system.
FileSystemList::reverse_iterator iterator
void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override
Directory iterator implementation for RedirectingFileSystem's directory entries.
std::error_code increment() override
Sets CurrentEntry to the next entry in the directory on success, to directory_entry() at end,...
RedirectingFSDirIterImpl(const Twine &Path, RedirectingFileSystem::DirectoryEntry::iterator Begin, RedirectingFileSystem::DirectoryEntry::iterator End, std::error_code &EC)
A helper class to hold the common YAML parsing state.
RedirectingFileSystemParser(yaml::Stream &S)
static RedirectingFileSystem::Entry * lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name, RedirectingFileSystem::Entry *ParentEntry=nullptr)
bool parse(yaml::Node *Root, RedirectingFileSystem *FS)
decltype(Contents)::iterator iterator
A single file or directory in the VFS.
StringRef getName() const
EntryKind getKind() const
A virtual file system parsed from a YAML file.
@ OverlayDir
The roots are relative to the directory where the Overlay YAML file.
@ CWD
The roots are relative to the current working directory.
bool exists(const Twine &Path) override
Check whether Path exists.
void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override
std::vector< llvm::StringRef > getRoots() const
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override
Get a directory_iterator for Dir.
ErrorOr< LookupResult > lookupPath(StringRef Path) const
Looks up Path in Roots and returns a LookupResult giving the matched entry and, if the entry was a Fi...
RedirectKind
The type of redirection to perform.
@ Fallthrough
Lookup the redirected path first (ie.
@ Fallback
Lookup the provided path first and if that fails, "fallback" to a lookup of the redirected path.
@ RedirectOnly
Only lookup the redirected path, do not lookup the originally provided path.
void setFallthrough(bool Fallthrough)
Sets the redirection kind to Fallthrough if true or RedirectOnly otherwise.
void visitChildFileSystems(VisitCallbackTy Callback) override
std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) override
Gets real path of Path e.g.
ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override
Get a File object for the text file at Path, if one exists.
void setOverlayFileDir(StringRef PrefixDir)
llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override
Get the working directory of this file system.
void setRedirection(RedirectingFileSystem::RedirectKind Kind)
std::error_code isLocal(const Twine &Path, bool &Result) override
Is the file mounted on a local filesystem?
static std::unique_ptr< RedirectingFileSystem > create(std::unique_ptr< MemoryBuffer > Buffer, SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, void *DiagContext, IntrusiveRefCntPtr< FileSystem > ExternalFS)
Parses Buffer, which is expected to be in YAML format and returns a virtual file system representing ...
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
Set the working directory.
StringRef getOverlayFileDir() const
void printEntry(raw_ostream &OS, Entry *E, unsigned IndentLevel=0) const
The result of a status operation.
llvm::sys::fs::UniqueID getUniqueID() const
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.
std::size_t NumOpenFileForReadCalls
std::size_t NumIsLocalCalls
std::size_t NumExistsCalls
void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override
std::size_t NumDirBeginCalls
std::size_t NumGetRealPathCalls
std::size_t NumStatusCalls
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.
@ 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().
@ OF_Text
The file should be opened in text mode on platforms like z/OS that make this distinction.
file_type
An enumeration for the file system's view of the type.
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.
const char * toString(DWARFSectionKind Kind)
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