24#include "llvm/Config/llvm-config.h"
50#include <system_error>
71 : Name(Name.str()), UID(UID), MTime(MTime), User(User), Group(Group),
72 Size(Size), Type(Type), Perms(Perms) {}
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;
197 RealFile(file_t RawFD, StringRef NewName, StringRef NewRealPathName)
198 : FD(RawFD), S(NewName, {}, {}, {}, {}, {},
200 RealName(NewRealPathName.str()) {
201 assert(FD.
isValid() &&
"Invalid or inactive file descriptor");
205 ~RealFile()
override;
207 ErrorOr<Status>
status()
override;
208 ErrorOr<std::string>
getName()
override;
209 ErrorOr<std::unique_ptr<MemoryBuffer>> getBuffer(
const Twine &Name,
211 bool RequiresNullTerminator,
212 bool IsVolatile)
override;
213 std::error_code close()
override;
214 void setPath(
const Twine &Path)
override;
219RealFile::~RealFile() { close(); }
221ErrorOr<Status> RealFile::status() {
224 assert(FD.isValid() &&
"cannot stat closed file");
225 if (!S.isStatusKnown()) {
226 file_status RealStatus;
234ErrorOr<std::string> RealFile::getName() {
235 return RealName.empty() ? S.getName().str() : RealName;
238ErrorOr<std::unique_ptr<MemoryBuffer>>
239RealFile::getBuffer(
const Twine &Name, int64_t FileSize,
240 bool RequiresNullTerminator,
bool IsVolatile) {
243 assert(FD.isValid() &&
"cannot get buffer for closed file");
248std::error_code RealFile::close() {
256void RealFile::setPath(
const Twine &Path) {
259 RealName =
Path.str();
274class RealFileSystem :
public FileSystem {
276 explicit RealFileSystem(
bool LinkCWDToProcess) {
277 if (!LinkCWDToProcess) {
278 SmallString<128> PWD, RealPWD;
282 WD = WorkingDirectory{PWD, PWD};
284 WD = WorkingDirectory{PWD, RealPWD};
288 ErrorOr<Status>
status(
const Twine &Path)
override;
289 ErrorOr<std::unique_ptr<File>>
openFileForRead(
const Twine &Path)
override;
290 ErrorOr<std::unique_ptr<File>>
291 openFileForReadBinary(
const Twine &Path)
override;
292 directory_iterator dir_begin(
const Twine &Dir, std::error_code &EC)
override;
294 llvm::ErrorOr<std::string> getCurrentWorkingDirectory()
const override;
295 std::error_code setCurrentWorkingDirectory(
const Twine &Path)
override;
296 std::error_code isLocal(
const Twine &Path,
bool &Result)
override;
297 std::error_code getRealPath(
const Twine &Path,
298 SmallVectorImpl<char> &Output)
override;
302 unsigned IndentLevel)
const override;
307 Twine adjustPath(
const Twine &Path, SmallVectorImpl<char> &Storage)
const {
310 Path.toVector(Storage);
315 ErrorOr<std::unique_ptr<File>>
317 SmallString<256> RealName, Storage;
319 adjustPath(Name, Storage), Flags, &RealName);
322 return std::unique_ptr<File>(
323 new RealFile(*FDOrErr,
Name.str(), RealName.
str()));
326 struct WorkingDirectory {
328 SmallString<128> Specified;
332 std::optional<llvm::ErrorOr<WorkingDirectory>> WD;
337ErrorOr<Status> RealFileSystem::status(
const Twine &Path) {
340 SmallString<256> Storage;
341 sys::fs::file_status RealStatus;
342 if (std::error_code EC =
348ErrorOr<std::unique_ptr<File>>
349RealFileSystem::openFileForRead(
const Twine &Name) {
355ErrorOr<std::unique_ptr<File>>
356RealFileSystem::openFileForReadBinary(
const Twine &Name) {
362llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory()
const {
366 return std::string(WD->get().Specified);
368 return WD->getError();
370 SmallString<128> Dir;
373 return std::string(Dir);
376std::error_code RealFileSystem::setCurrentWorkingDirectory(
const Twine &Path) {
383 adjustPath(Path, Storage).toVector(Absolute);
388 return std::make_error_code(std::errc::not_a_directory);
392 return std::error_code();
395std::error_code RealFileSystem::isLocal(
const Twine &Path,
bool &Result) {
398 SmallString<256> Storage;
402std::error_code RealFileSystem::getRealPath(
const Twine &Path,
403 SmallVectorImpl<char> &Output) {
406 SmallString<256> Storage;
410void RealFileSystem::printImpl(raw_ostream &OS, PrintType
Type,
411 unsigned IndentLevel)
const {
412 printIndent(OS, IndentLevel);
413 OS <<
"RealFileSystem using ";
432 return std::make_unique<RealFileSystem>(
false);
441 RealFSDirIter(
const Twine &Path, std::error_code &EC) {
449 std::error_code increment()
override {
464 std::error_code &EC) {
467 SmallString<128> Storage;
469 std::make_shared<RealFSDirIter>(adjustPath(Dir, Storage), EC));
477 FSList.push_back(std::move(BaseFS));
481 FSList.push_back(FS);
500 if ((*I)->exists(Path))
510 auto Result = (*I)->openFileForRead(Path);
520 return FSList.front()->getCurrentWorkingDirectory();
525 for (
auto &FS : FSList)
526 if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))
532 for (
auto &FS : FSList)
533 if (FS->exists(Path))
534 return FS->isLocal(Path, Result);
540 for (
const auto &FS : FSList)
541 if (FS->exists(Path))
542 return FS->getRealPath(Path, Output);
549 FS->visitChildFileSystems(Callback);
554 unsigned IndentLevel)
const {
555 printIndent(OS, IndentLevel);
556 OS <<
"OverlayFileSystem\n";
557 if (
Type == PrintType::Summary)
560 if (
Type == PrintType::Contents)
561 Type = PrintType::Summary;
563 FS->print(OS,
Type, IndentLevel + 1);
583 std::error_code incrementIter(
bool IsFirstTime) {
584 while (!IterList.
empty()) {
585 CurrentDirIter = IterList.
back();
596 std::error_code incrementDirIter(
bool IsFirstTime) {
597 assert((IsFirstTime || CurrentDirIter != directory_iterator()) &&
598 "incrementing past end");
602 if (!EC && CurrentDirIter == directory_iterator())
603 EC = incrementIter(IsFirstTime);
607 std::error_code incrementImpl(
bool IsFirstTime) {
609 std::error_code
EC = incrementDirIter(IsFirstTime);
610 if (EC || CurrentDirIter == directory_iterator()) {
611 CurrentEntry = directory_entry();
614 CurrentEntry = *CurrentDirIter;
616 if (SeenNames.
insert(Name).second)
624 std::error_code &EC) {
625 for (
const auto &FS : FileSystems) {
627 directory_iterator Iter =
FS->dir_begin(Dir, FEC);
628 if (FEC && FEC != errc::no_such_file_or_directory) {
635 EC = incrementImpl(
true);
640 : IterList(DirIters) {
641 EC = incrementImpl(
true);
644 std::error_code increment()
override {
return incrementImpl(
false); }
650 std::error_code &EC) {
652 std::make_shared<CombiningDirIterImpl>(FSList, Dir.
str(), EC));
658void ProxyFileSystem::anchor() {}
676 std::string FileName;
680 : Kind(Kind), FileName(
std::string(
llvm::
sys::
path::filename(FileName))) {
692 virtual std::string
toString(
unsigned Indent)
const = 0;
697 std::unique_ptr<llvm::MemoryBuffer> Buffer;
709 std::string
toString(
unsigned Indent)
const override {
710 return (std::string(Indent,
' ') + Stat.getName() +
"\n").str();
720class InMemoryHardLink :
public InMemoryNode {
721 const InMemoryFile &ResolvedFile;
724 InMemoryHardLink(
StringRef Path,
const InMemoryFile &ResolvedFile)
725 : InMemoryNode(Path,
IME_HardLink), ResolvedFile(ResolvedFile) {}
726 const InMemoryFile &getResolvedFile()
const {
return ResolvedFile; }
728 Status getStatus(
const Twine &RequestedName)
const override {
729 return ResolvedFile.getStatus(RequestedName);
732 std::string
toString(
unsigned Indent)
const override {
733 return std::string(Indent,
' ') +
"HardLink to -> " +
734 ResolvedFile.toString(0);
737 static bool classof(
const InMemoryNode *
N) {
743 std::string TargetPath;
747 InMemorySymbolicLink(StringRef Path, StringRef TargetPath, Status Stat)
751 std::string
toString(
unsigned Indent)
const override {
752 return std::string(Indent,
' ') +
"SymbolicLink to -> " + TargetPath;
755 Status getStatus(
const Twine &RequestedName)
const override {
759 StringRef getTargetPath()
const {
return TargetPath; }
761 static bool classof(
const InMemoryNode *
N) {
769class InMemoryFileAdaptor :
public File {
770 const InMemoryFile &Node;
772 std::string RequestedName;
775 explicit InMemoryFileAdaptor(
const InMemoryFile &Node,
776 std::string RequestedName)
777 : Node(Node), RequestedName(std::
move(RequestedName)) {}
779 llvm::ErrorOr<Status>
status()
override {
780 return Node.getStatus(RequestedName);
783 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
784 getBuffer(
const Twine &Name, int64_t FileSize,
bool RequiresNullTerminator,
785 bool IsVolatile)
override {
786 llvm::MemoryBuffer *Buf = Node.getBuffer();
791 std::error_code close()
override {
return {}; }
793 void setPath(
const Twine &Path)
override { RequestedName =
Path.str(); }
799 std::map<std::string, std::unique_ptr<InMemoryNode>, std::less<>> Entries;
815 auto I = Entries.find(Name);
816 if (
I != Entries.end())
817 return I->second.get();
822 return Entries.emplace(Name, std::move(Child)).first->second.get();
830 std::string
toString(
unsigned Indent)
const override {
832 (std::string(Indent,
' ') + Stat.getName() +
"\n").str();
833 for (
const auto &Entry : Entries)
834 Result += Entry.second->toString(Indent + 2);
873 : Root(new
detail::InMemoryDirectory(
878 UseNormalizedPaths(UseNormalizedPaths) {}
883 return Root->toString(0);
886bool InMemoryFileSystem::addFile(
const Twine &
P, time_t ModificationTime,
887 std::unique_ptr<llvm::MemoryBuffer> Buffer,
888 std::optional<uint32_t>
User,
889 std::optional<uint32_t> Group,
890 std::optional<llvm::sys::fs::file_type>
Type,
891 std::optional<llvm::sys::fs::perms> Perms,
892 MakeNodeFn MakeNode) {
909 const auto ResolvedUser =
User.value_or(0);
910 const auto ResolvedGroup = Group.value_or(0);
927 StringRef(Path.str().begin(), Name.end() - Path.str().begin()),
932 Name, std::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
943 MakeNode({Dir->
getUniqueID(), Path, Name, ModificationTime,
944 std::move(Buffer), ResolvedUser, ResolvedGroup,
945 ResolvedType, ResolvedPerms}));
953 "Must be either file, hardlink or directory!");
957 return Link->getResolvedFile().getBuffer()->getBuffer() ==
964bool InMemoryFileSystem::addFile(
const Twine &
P, time_t ModificationTime,
965 std::unique_ptr<llvm::MemoryBuffer> Buffer,
966 std::optional<uint32_t>
User,
967 std::optional<uint32_t> Group,
968 std::optional<llvm::sys::fs::file_type>
Type,
969 std::optional<llvm::sys::fs::perms> Perms) {
970 return addFile(
P, ModificationTime, std::move(Buffer),
User, Group,
Type,
973 -> std::unique_ptr<detail::InMemoryNode> {
976 return std::make_unique<detail::InMemoryDirectory>(Stat);
977 return std::make_unique<detail::InMemoryFile>(
978 Stat, std::move(NNI.
Buffer));
983 const Twine &
P, time_t ModificationTime,
985 std::optional<uint32_t> Group, std::optional<llvm::sys::fs::file_type>
Type,
986 std::optional<llvm::sys::fs::perms> Perms) {
988 std::move(
User), std::move(Group), std::move(
Type),
991 -> std::unique_ptr<detail::InMemoryNode> {
994 return std::make_unique<detail::InMemoryDirectory>(Stat);
995 return std::make_unique<detail::InMemoryFile>(
996 Stat, std::move(NNI.
Buffer));
1001InMemoryFileSystem::lookupNode(
const Twine &
P,
bool FollowFinalSymlink,
1002 size_t SymlinkDepth)
const {
1028 if (
I == E && !FollowFinalSymlink)
1043 lookupNode(TargetPath,
true, SymlinkDepth + 1);
1071 return detail::NamedNodeOrError(Path, Dir);
1077 auto NewLinkNode = lookupNode(NewLink,
false);
1081 auto TargetNode = lookupNode(
Target,
true);
1086 return addFile(NewLink, 0,
nullptr, std::nullopt, std::nullopt, std::nullopt,
1088 return std::make_unique<detail::InMemoryHardLink>(
1096 std::optional<uint32_t>
User, std::optional<uint32_t> Group,
1097 std::optional<llvm::sys::fs::perms> Perms) {
1098 auto NewLinkNode = lookupNode(NewLink,
false);
1104 Target.toVector(TargetStr);
1106 return addFile(NewLinkStr, ModificationTime,
nullptr,
User, Group,
1109 return std::make_unique<detail::InMemorySymbolicLink>(
1115 auto Node = lookupNode(Path,
true);
1117 return (*Node)->getStatus(Path);
1118 return Node.getError();
1123 auto Node = lookupNode(Path,
true);
1125 return Node.getError();
1130 return std::unique_ptr<File>(
1131 new detail::InMemoryFileAdaptor(*
F, Path.str()));
1142 std::string RequestedDirName;
1144 void setCurrentEntry() {
1149 switch (I->second->getKind()) {
1158 if (
auto SymlinkTarget =
1159 FS->lookupNode(Path,
true)) {
1160 Path = SymlinkTarget.getName();
1161 Type = (*SymlinkTarget)->getStatus(Path).getType();
1178 std::string RequestedDirName)
1179 : FS(FS), I(Dir.begin()), E(Dir.end()),
1180 RequestedDirName(
std::
move(RequestedDirName)) {
1192 std::error_code &EC) {
1193 auto Node = lookupNode(Dir,
true);
1195 EC =
Node.getError();
1201 std::make_shared<DirIterator>(
this, *DirNode, Dir.
str()));
1220 WorkingDirectory = std::string(Path);
1227 if (!CWD || CWD->empty())
1229 Path.toVector(Output);
1242 unsigned IndentLevel)
const {
1243 printIndent(OS, IndentLevel);
1244 OS <<
"InMemoryFileSystem\n";
1259 const size_t n = Path.find_first_of(
"/\\");
1261 if (n !=
static_cast<size_t>(-1))
1281static bool isFileNotFound(std::error_code EC,
1293 assert(ExternalFS &&
"RedirectingFileSystem requires an external FS");
1294 if (
auto ExternalWorkingDirectory = ExternalFS->getCurrentWorkingDirectory())
1295 WorkingDirectory = *ExternalWorkingDirectory;
1305 std::error_code incrementImpl(
bool IsFirstTime) {
1306 assert((IsFirstTime || Current != End) &&
"cannot iterate past end");
1309 if (Current != End) {
1313 switch ((*Current)->getKind()) {
1334 : Dir(Path.str()), Current(Begin), End(End) {
1335 EC = incrementImpl(
true);
1339 return incrementImpl(
false);
1353 RedirectingFSDirRemapIterImpl(std::string DirPath,
1355 : Dir(
std::
move(DirPath)), DirStyle(getExistingStyle(Dir)),
1356 ExternalIter(ExtIter) {
1361 void setCurrentEntry() {
1372 std::error_code increment()
override {
1375 if (!EC && ExternalIter != llvm::vfs::directory_iterator())
1378 CurrentEntry = directory_entry();
1384llvm::ErrorOr<std::string>
1386 return WorkingDirectory;
1396 Path.toVector(AbsolutePath);
1397 if (std::error_code EC = makeAbsolute(AbsolutePath))
1399 WorkingDirectory = std::string(AbsolutePath);
1408 if (makeAbsolute(Path))
1411 return ExternalFS->isLocal(Path, Result);
1426 return WorkingDir.getError();
1428 return makeAbsolute(WorkingDir.get(), Path);
1432RedirectingFileSystem::makeAbsolute(
StringRef WorkingDir,
1438 if (!WorkingDir.
empty() &&
1442 return std::error_code();
1454 std::string
Result = std::string(WorkingDir);
1455 StringRef Dir(Result);
1471 std::error_code &EC) {
1475 EC = makeAbsolute(Path);
1482 isFileNotFound(Result.getError()))
1483 return ExternalFS->dir_begin(Path, EC);
1485 EC = Result.getError();
1493 isFileNotFound(S.
getError(), Result->E))
1494 return ExternalFS->dir_begin(Dir, EC);
1500 if (!S->isDirectory()) {
1508 std::error_code RedirectEC;
1509 if (
auto ExtRedirect = Result->getExternalRedirect()) {
1511 RedirectIter = ExternalFS->dir_begin(*ExtRedirect, RedirectEC);
1513 if (!RE->useExternalName(UseExternalNames)) {
1517 std::string(Path), RedirectIter));
1523 Path, DE->contents_begin(), DE->contents_end(), RedirectEC));
1536 return RedirectIter;
1539 std::error_code ExternalEC;
1550 switch (Redirection) {
1564 std::make_shared<CombiningDirIterImpl>(Iters, EC)};
1571 OverlayFileDir = Dir.
str();
1575 return OverlayFileDir;
1592 std::vector<StringRef> R;
1593 R.reserve(Roots.size());
1594 for (
const auto &Root : Roots)
1595 R.push_back(Root->getName());
1600 unsigned IndentLevel)
const {
1602 OS <<
"RedirectingFileSystem (UseExternalNames: "
1603 << (UseExternalNames ?
"true" :
"false") <<
")\n";
1607 for (
const auto &Root : Roots)
1611 OS <<
"ExternalFS:\n";
1618 unsigned IndentLevel)
const {
1620 OS <<
"'" << E->getName() <<
"'";
1622 switch (E->getKind()) {
1627 for (std::unique_ptr<Entry> &SubEntry :
1629 printEntry(OS, SubEntry.get(), IndentLevel + 1);
1635 OS <<
" -> '" << RE->getExternalContentsPath() <<
"'";
1636 switch (RE->getUseName()) {
1640 OS <<
" (UseExternalName: true)";
1643 OS <<
" (UseExternalName: false)";
1654 Callback(*ExternalFS);
1655 ExternalFS->visitChildFileSystems(Callback);
1671 error(
N,
"expected string");
1674 Result = S->getValue(Storage);
1679 bool parseScalarBool(
yaml::Node *
N,
bool &Result) {
1682 if (!parseScalarString(
N,
Value, Storage))
1685 if (
Value.equals_insensitive(
"true") ||
Value.equals_insensitive(
"on") ||
1686 Value.equals_insensitive(
"yes") ||
Value ==
"1") {
1689 }
else if (
Value.equals_insensitive(
"false") ||
1690 Value.equals_insensitive(
"off") ||
1691 Value.equals_insensitive(
"no") ||
Value ==
"0") {
1696 error(
N,
"expected boolean value");
1700 std::optional<RedirectingFileSystem::RedirectKind>
1704 if (!parseScalarString(
N,
Value, Storage))
1705 return std::nullopt;
1707 if (
Value.equals_insensitive(
"fallthrough")) {
1709 }
else if (
Value.equals_insensitive(
"fallback")) {
1711 }
else if (
Value.equals_insensitive(
"redirect-only")) {
1714 return std::nullopt;
1717 std::optional<RedirectingFileSystem::RootRelativeKind>
1721 if (!parseScalarString(
N,
Value, Storage))
1722 return std::nullopt;
1723 if (
Value.equals_insensitive(
"cwd")) {
1725 }
else if (
Value.equals_insensitive(
"overlay-dir")) {
1728 return std::nullopt;
1735 KeyStatus(
bool Required =
false) : Required(Required) {}
1738 using KeyStatusPair = std::pair<StringRef, KeyStatus>;
1744 if (It == Keys.
end()) {
1745 error(KeyNode,
"unknown key");
1748 KeyStatus &S = It->second;
1759 for (
const auto &
I : Keys) {
1760 if (
I.second.Required && !
I.second.Seen) {
1761 error(Obj,
Twine(
"missing key '") +
I.first +
"'");
1773 for (
const auto &Root : FS->Roots) {
1774 if (Name == Root->getName()) {
1775 ParentEntry = Root.get();
1781 for (std::unique_ptr<RedirectingFileSystem::Entry> &Content :
1785 if (DirContent && Name == Content->getName())
1791 std::unique_ptr<RedirectingFileSystem::Entry> E =
1792 std::make_unique<RedirectingFileSystem::DirectoryEntry>(
1794 std::chrono::system_clock::now(), 0, 0, 0,
1798 FS->Roots.push_back(std::move(E));
1799 ParentEntry = FS->Roots.back().get();
1804 DE->addContent(std::move(E));
1805 return DE->getLastContent();
1820 NewParentE = lookupOrCreateEntry(FS, Name, NewParentE);
1821 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
1823 uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
1827 assert(NewParentE &&
"Parent entry must exist");
1831 std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
1832 Name, DR->getExternalContentsPath(), DR->getUseName()));
1836 assert(NewParentE &&
"Parent entry must exist");
1839 DE->addContent(std::make_unique<RedirectingFileSystem::FileEntry>(
1840 Name, FE->getExternalContentsPath(), FE->getUseName()));
1846 std::unique_ptr<RedirectingFileSystem::Entry>
1847 parseEntry(yaml::Node *
N, RedirectingFileSystem *FS,
bool IsRootEntry) {
1850 error(
N,
"expected mapping node for file or directory entry");
1854 KeyStatusPair Fields[] = {
1855 KeyStatusPair(
"name",
true),
1856 KeyStatusPair(
"type",
true),
1857 KeyStatusPair(
"contents",
false),
1858 KeyStatusPair(
"external-contents",
false),
1859 KeyStatusPair(
"use-external-name",
false),
1862 DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
1864 enum { CF_NotSet, CF_List, CF_External } ContentsField = CF_NotSet;
1865 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>>
1867 SmallString<256> ExternalContentsPath;
1868 SmallString<256>
Name;
1869 yaml::Node *NameValueNode =
nullptr;
1873 for (
auto &
I : *M) {
1877 SmallString<256> Buffer;
1878 if (!parseScalarString(
I.getKey(),
Key, Buffer))
1881 if (!checkDuplicateOrUnknownKey(
I.getKey(),
Key, Keys))
1885 if (
Key ==
"name") {
1886 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1889 NameValueNode =
I.getValue();
1893 }
else if (
Key ==
"type") {
1894 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1896 if (
Value ==
"file")
1898 else if (
Value ==
"directory")
1900 else if (
Value ==
"directory-remap")
1903 error(
I.getValue(),
"unknown value for 'type'");
1906 }
else if (
Key ==
"contents") {
1907 if (ContentsField != CF_NotSet) {
1909 "entry already has 'contents' or 'external-contents'");
1912 ContentsField = CF_List;
1916 error(
I.getValue(),
"expected array");
1920 for (
auto &
I : *Contents) {
1921 if (std::unique_ptr<RedirectingFileSystem::Entry>
E =
1922 parseEntry(&
I, FS,
false))
1923 EntryArrayContents.push_back(std::move(
E));
1927 }
else if (
Key ==
"external-contents") {
1928 if (ContentsField != CF_NotSet) {
1930 "entry already has 'contents' or 'external-contents'");
1933 ContentsField = CF_External;
1934 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1937 SmallString<256> FullPath;
1938 if (
FS->IsRelativeOverlay) {
1939 FullPath =
FS->getOverlayFileDir();
1941 "External contents prefix directory must exist");
1942 SmallString<256> AbsFullPath =
Value;
1943 if (
FS->makeAbsolute(FullPath, AbsFullPath)) {
1944 error(
N,
"failed to make 'external-contents' absolute");
1947 FullPath = AbsFullPath;
1954 FullPath = canonicalize(FullPath);
1955 ExternalContentsPath = FullPath.
str();
1956 }
else if (
Key ==
"use-external-name") {
1958 if (!parseScalarBool(
I.getValue(), Val))
1971 if (ContentsField == CF_NotSet) {
1972 error(
N,
"missing key 'contents' or 'external-contents'");
1975 if (!checkMissingKeys(
N, Keys))
1981 error(
N,
"'use-external-name' is not supported for 'directory' entries");
1986 ContentsField == CF_List) {
1987 error(
N,
"'contents' is not supported for 'directory-remap' entries");
1996 path_style = sys::path::Style::posix;
1998 sys::path::Style::windows_backslash)) {
1999 path_style = sys::path::Style::windows_backslash;
2005 if (
FS->RootRelative ==
2006 RedirectingFileSystem::RootRelativeKind::OverlayDir) {
2007 StringRef FullPath =
FS->getOverlayFileDir();
2008 assert(!FullPath.
empty() &&
"Overlay file directory must exist");
2009 EC =
FS->makeAbsolute(FullPath, Name);
2010 Name = canonicalize(Name);
2012 EC =
FS->makeAbsolute(Name);
2015 assert(NameValueNode &&
"Name presence should be checked earlier");
2018 "entry with relative path at the root level is not discoverable");
2022 ? sys::path::Style::posix
2023 : sys::path::Style::windows_backslash;
2028 if (path_style == sys::path::Style::windows_backslash &&
2029 getExistingStyle(Name) != sys::path::Style::windows_backslash)
2030 path_style = sys::path::Style::windows_slash;
2034 StringRef Trimmed =
Name;
2036 while (Trimmed.
size() > RootPathLen &&
2038 Trimmed = Trimmed.
slice(0, Trimmed.
size() - 1);
2043 std::unique_ptr<RedirectingFileSystem::Entry>
Result;
2046 Result = std::make_unique<RedirectingFileSystem::FileEntry>(
2047 LastComponent, std::move(ExternalContentsPath), UseExternalName);
2050 Result = std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
2051 LastComponent, std::move(ExternalContentsPath), UseExternalName);
2054 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
2055 LastComponent, std::move(EntryArrayContents),
2069 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> Entries;
2070 Entries.push_back(std::move(Result));
2071 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
2072 *
I, std::move(Entries),
2086 error(Root,
"expected mapping node");
2090 KeyStatusPair Fields[] = {
2091 KeyStatusPair(
"version",
true),
2092 KeyStatusPair(
"case-sensitive",
false),
2093 KeyStatusPair(
"use-external-names",
false),
2094 KeyStatusPair(
"root-relative",
false),
2095 KeyStatusPair(
"overlay-relative",
false),
2096 KeyStatusPair(
"fallthrough",
false),
2097 KeyStatusPair(
"redirecting-with",
false),
2098 KeyStatusPair(
"roots",
true),
2102 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> RootEntries;
2105 for (
auto &
I : *Top) {
2108 if (!parseScalarString(
I.getKey(),
Key, KeyBuffer))
2111 if (!checkDuplicateOrUnknownKey(
I.getKey(),
Key, Keys))
2114 if (
Key ==
"roots") {
2117 error(
I.getValue(),
"expected array");
2121 for (
auto &
I : *Roots) {
2122 if (std::unique_ptr<RedirectingFileSystem::Entry> E =
2123 parseEntry(&
I, FS,
true))
2124 RootEntries.push_back(std::move(E));
2128 }
else if (
Key ==
"version") {
2131 if (!parseScalarString(
I.getValue(), VersionString, Storage))
2135 error(
I.getValue(),
"expected integer");
2139 error(
I.getValue(),
"invalid version number");
2143 error(
I.getValue(),
"version mismatch, expected 0");
2146 }
else if (
Key ==
"case-sensitive") {
2147 if (!parseScalarBool(
I.getValue(), FS->CaseSensitive))
2149 }
else if (
Key ==
"overlay-relative") {
2150 if (!parseScalarBool(
I.getValue(), FS->IsRelativeOverlay))
2152 }
else if (
Key ==
"use-external-names") {
2153 if (!parseScalarBool(
I.getValue(), FS->UseExternalNames))
2155 }
else if (
Key ==
"fallthrough") {
2156 if (Keys[
"redirecting-with"].Seen) {
2158 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2162 bool ShouldFallthrough =
false;
2163 if (!parseScalarBool(
I.getValue(), ShouldFallthrough))
2166 if (ShouldFallthrough) {
2171 }
else if (
Key ==
"redirecting-with") {
2172 if (Keys[
"fallthrough"].Seen) {
2174 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2178 if (
auto Kind = parseRedirectKind(
I.getValue())) {
2179 FS->Redirection = *Kind;
2181 error(
I.getValue(),
"expected valid redirect kind");
2184 }
else if (
Key ==
"root-relative") {
2185 if (
auto Kind = parseRootRelativeKind(
I.getValue())) {
2186 FS->RootRelative = *Kind;
2188 error(
I.getValue(),
"expected valid root-relative kind");
2196 if (Stream.failed())
2199 if (!checkMissingKeys(Top, Keys))
2205 for (
auto &E : RootEntries)
2206 uniqueOverlayTree(FS, E.get());
2212std::unique_ptr<RedirectingFileSystem>
2215 StringRef YAMLFilePath,
void *DiagContext,
2223 if (DI == Stream.
end() || !Root) {
2230 std::unique_ptr<RedirectingFileSystem> FS(
2231 new RedirectingFileSystem(ExternalFS));
2233 if (!YAMLFilePath.
empty()) {
2243 std::error_code EC = FS->makeAbsolute(OverlayAbsDir);
2244 assert(!EC &&
"Overlay dir final path must be absolute");
2246 FS->setOverlayFileDir(OverlayAbsDir);
2249 if (!
P.parse(Root, FS.get()))
2256 ArrayRef<std::pair<std::string, std::string>> RemappedFiles,
2258 std::unique_ptr<RedirectingFileSystem> FS(
2259 new RedirectingFileSystem(ExternalFS));
2260 FS->UseExternalNames = UseExternalNames;
2268 auto EC = ExternalFS->makeAbsolute(From);
2270 assert(!EC &&
"Could not make absolute path");
2288 assert(Parent &&
"File without a directory?");
2290 auto EC = ExternalFS->makeAbsolute(To);
2292 assert(!EC &&
"Could not make absolute path");
2296 auto NewFile = std::make_unique<RedirectingFileSystem::FileEntry>(
2300 ToEntry = NewFile.get();
2302 std::move(NewFile));
2318 getExistingStyle(DRE->getExternalContentsPath()));
2319 ExternalRedirect = std::string(Redirect);
2331std::error_code RedirectingFileSystem::makeCanonicalForLookup(
2333 if (std::error_code EC = makeAbsolute(Path))
2337 canonicalize(
StringRef(Path.data(), Path.size()));
2338 if (CanonicalPath.
empty())
2341 Path.assign(CanonicalPath.
begin(), CanonicalPath.
end());
2348 if (std::error_code EC = makeCanonicalForLookup(CanonicalPath))
2358 for (
const auto &Root : Roots) {
2360 lookupPathImpl(Start, End, Root.get(), Entries);
2364 Result->Parents = std::move(Entries);
2375RedirectingFileSystem::lookupPathImpl(
2381 "Paths should not contain traversal components");
2386 if (!FromName.
empty()) {
2387 if (!pathComponentMatches(*Start, FromName))
2394 return LookupResult(From, Start, End);
2402 return LookupResult(From, Start, End);
2405 for (
const std::unique_ptr<RedirectingFileSystem::Entry> &DirEntry :
2409 lookupPathImpl(Start, End, DirEntry.get(), Entries);
2419 bool UseExternalNames,
2424 return ExternalStatus;
2426 Status S = ExternalStatus;
2427 if (!UseExternalNames)
2434ErrorOr<Status> RedirectingFileSystem::status(
2435 const Twine &LookupPath,
const Twine &OriginalPath,
2436 const RedirectingFileSystem::LookupResult &Result) {
2437 if (std::optional<StringRef> ExtRedirect =
Result.getExternalRedirect()) {
2438 SmallString<256> RemappedPath((*ExtRedirect).str());
2439 if (std::error_code EC = makeAbsolute(RemappedPath))
2442 ErrorOr<Status> S = ExternalFS->status(RemappedPath);
2448 RE->useExternalName(UseExternalNames), *S);
2456RedirectingFileSystem::getExternalStatus(
const Twine &LookupPath,
2457 const Twine &OriginalPath)
const {
2458 auto Result = ExternalFS->status(LookupPath);
2462 if (!Result ||
Result->ExposesExternalVFSPath)
2471 if (std::error_code EC = makeAbsolute(Path))
2487 isFileNotFound(Result.getError()))
2488 return getExternalStatus(Path, OriginalPath);
2489 return Result.getError();
2494 isFileNotFound(S.
getError(), Result->E)) {
2498 return getExternalStatus(Path, OriginalPath);
2508 if (makeAbsolute(Path))
2514 if (ExternalFS->exists(Path))
2523 isFileNotFound(Result.getError()))
2524 return ExternalFS->exists(Path);
2528 std::optional<StringRef> ExtRedirect = Result->getExternalRedirect();
2535 if (makeAbsolute(RemappedPath))
2538 if (ExternalFS->exists(RemappedPath))
2545 return ExternalFS->exists(Path);
2554class FileWithFixedStatus :
public File {
2555 std::unique_ptr<File> InnerFile;
2559 FileWithFixedStatus(std::unique_ptr<File> InnerFile,
Status S)
2565 getBuffer(
const Twine &Name, int64_t FileSize,
bool RequiresNullTerminator,
2566 bool IsVolatile)
override {
2567 return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
2571 std::error_code close()
override {
return InnerFile->close(); }
2573 void setPath(
const Twine &Path)
override { S = S.
copyWithNewName(S, Path); }
2578ErrorOr<std::unique_ptr<File>>
2582 if (!Result || (*Result)->status()->ExposesExternalVFSPath)
2586 auto Name =
F->get()->getName();
2587 if (Name && Name.get() !=
P.str())
2588 F->get()->setPath(
P);
2597 if (std::error_code EC = makeAbsolute(Path))
2613 isFileNotFound(Result.getError()))
2615 return Result.getError();
2618 if (!Result->getExternalRedirect())
2621 StringRef ExtRedirect = *Result->getExternalRedirect();
2623 if (std::error_code EC = makeAbsolute(RemappedPath))
2630 if (!ExternalFile) {
2632 isFileNotFound(ExternalFile.getError(), Result->E)) {
2638 return ExternalFile;
2641 auto ExternalStatus = (*ExternalFile)->status();
2642 if (!ExternalStatus)
2643 return ExternalStatus.getError();
2648 OriginalPath, RE->useExternalName(UseExternalNames), *ExternalStatus);
2649 return std::unique_ptr<File>(
2650 std::make_unique<FileWithFixedStatus>(std::move(*ExternalFile), S));
2659 if (std::error_code EC = makeAbsolute(Path))
2665 std::error_code EC = ExternalFS->getRealPath(Path, Output);
2675 isFileNotFound(Result.getError()))
2676 return ExternalFS->getRealPath(Path, Output);
2677 return Result.getError();
2682 if (
auto ExtRedirect = Result->getExternalRedirect()) {
2683 auto P = ExternalFS->getRealPath(*ExtRedirect, Output);
2685 isFileNotFound(
P, Result->E)) {
2689 return ExternalFS->getRealPath(Path, Output);
2697 Result->getPath(Output);
2703std::unique_ptr<FileSystem>
2706 StringRef YAMLFilePath,
void *DiagContext,
2709 YAMLFilePath, DiagContext,
2710 std::move(ExternalFS));
2719 assert(DE &&
"Must be a directory");
2720 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
2722 Path.push_back(SubEntry->getName());
2731 assert(DR &&
"Must be a directory remap");
2733 for (
auto &Comp : Path)
2742 assert(FE &&
"Must be a file");
2744 for (
auto &Comp : Path)
2760 static std::atomic<unsigned> UID;
2761 unsigned ID = ++UID;
2764 return UniqueID(std::numeric_limits<uint64_t>::max(), ID);
2772 Mappings.emplace_back(VirtualPath, RealPath, IsDirectory);
2776 addEntry(VirtualPath, RealPath,
false);
2781 addEntry(VirtualPath, RealPath,
true);
2790 unsigned getDirIndent() {
return 4 * DirStack.
size(); }
2791 unsigned getFileIndent() {
return 4 * (DirStack.
size() + 1); }
2795 void endDirectory();
2802 std::optional<bool> UseExternalNames,
2803 std::optional<bool> IsCaseSensitive,
2804 std::optional<bool> IsOverlayRelative, StringRef OverlayDir);
2809bool JSONWriter::containedIn(StringRef Parent, StringRef Path) {
2810 using namespace llvm::sys;
2815 IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
2816 if (*IParent != *IChild)
2820 return IParent == EParent;
2823StringRef JSONWriter::containedPart(StringRef Parent, StringRef Path) {
2825 assert(containedIn(Parent, Path));
2826 return Path.substr(Parent.
size() + 1);
2829void JSONWriter::startDirectory(StringRef Path) {
2831 DirStack.
empty() ?
Path : containedPart(DirStack.
back(), Path);
2833 unsigned Indent = getDirIndent();
2834 OS.
indent(Indent) <<
"{\n";
2835 OS.
indent(Indent + 2) <<
"'type': 'directory',\n";
2837 OS.
indent(Indent + 2) <<
"'contents': [\n";
2840void JSONWriter::endDirectory() {
2841 unsigned Indent = getDirIndent();
2842 OS.
indent(Indent + 2) <<
"]\n";
2843 OS.
indent(Indent) <<
"}";
2848void JSONWriter::writeEntry(StringRef VPath, StringRef RPath) {
2849 unsigned Indent = getFileIndent();
2850 OS.
indent(Indent) <<
"{\n";
2851 OS.
indent(Indent + 2) <<
"'type': 'file',\n";
2853 OS.
indent(Indent + 2) <<
"'external-contents': \""
2855 OS.
indent(Indent) <<
"}";
2859 std::optional<bool> UseExternalNames,
2860 std::optional<bool> IsCaseSensitive,
2861 std::optional<bool> IsOverlayRelative,
2863 using namespace llvm::sys;
2867 if (IsCaseSensitive)
2868 OS <<
" 'case-sensitive': '" << (*IsCaseSensitive ?
"true" :
"false")
2870 if (UseExternalNames)
2871 OS <<
" 'use-external-names': '" << (*UseExternalNames ?
"true" :
"false")
2873 bool UseOverlayRelative =
false;
2874 if (IsOverlayRelative) {
2875 UseOverlayRelative = *IsOverlayRelative;
2876 OS <<
" 'overlay-relative': '" << (UseOverlayRelative ?
"true" :
"false")
2879 OS <<
" 'roots': [\n";
2881 if (!Entries.
empty()) {
2889 if (UseOverlayRelative) {
2891 "Overlay dir must be contained in RPath");
2895 bool IsCurrentDirEmpty =
true;
2896 if (!
Entry.IsDirectory) {
2898 IsCurrentDirEmpty =
false;
2904 if (Dir == DirStack.
back()) {
2905 if (!IsCurrentDirEmpty) {
2909 bool IsDirPoppedFromStack =
false;
2910 while (!DirStack.
empty() && !containedIn(DirStack.
back(), Dir)) {
2913 IsDirPoppedFromStack =
true;
2915 if (IsDirPoppedFromStack || !IsCurrentDirEmpty) {
2918 startDirectory(Dir);
2919 IsCurrentDirEmpty =
true;
2922 if (UseOverlayRelative) {
2924 "Overlay dir must be contained in RPath");
2927 if (!
Entry.IsDirectory) {
2929 IsCurrentDirEmpty =
false;
2933 while (!DirStack.
empty()) {
2946 return LHS.VPath < RHS.VPath;
2949 JSONWriter(OS).
write(Mappings, UseExternalNames, IsCaseSensitive,
2950 IsOverlayRelative, OverlayDir);
2958 State = std::make_shared<detail::RecDirIterState>();
2959 State->Stack.push_back(
I);
2965 assert(FS && State && !State->Stack.empty() &&
"incrementing past end");
2966 assert(!State->Stack.back()->path().empty() &&
"non-canonical end iterator");
2969 if (State->HasNoPushRequest)
2970 State->HasNoPushRequest =
false;
2974 FS->dir_begin(State->Stack.back()->path(), EC);
2976 State->Stack.push_back(
I);
2982 while (!State->Stack.empty() && State->Stack.back().increment(EC) == End)
2983 State->Stack.pop_back();
2985 if (State->Stack.empty())
2997unsigned ::llvm::IntrusiveRefCntPtrInfo<FileSystem>::useCount(
2999 return FS->UseCount();
3002void ::llvm::IntrusiveRefCntPtrInfo<FileSystem>::retain(
FileSystem *FS) {
3006void ::llvm::IntrusiveRefCntPtrInfo<FileSystem>::release(
FileSystem *FS) {
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file defines the DenseMap class.
Provides ErrorOr<T> smart pointer.
static void makeAbsolute(vfs::FileSystem &VFS, SmallVectorImpl< char > &Path)
Make Path absolute.
This file defines the RefCountedBase, ThreadSafeRefCountedBase, and IntrusiveRefCntPtr classes.
static void printImpl(const MCAsmInfo &MAI, raw_ostream &OS, const MCSpecifierExpr &Expr)
static StringRef getName(Value *V)
This file defines the SmallString class.
This file defines the SmallVector class.
StringSet - A set-like wrapper for the StringMap.
static void DiagHandler(const SMDiagnostic &Diag, void *Context)
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.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
const T & front() const
Get the first element.
bool empty() const
Check if the array is empty.
ArrayRef< T > slice(size_t N, size_t M) const
slice(n, m) - Chop off the first N elements of the array, and keep M elements in the array.
iterator find(const_arg_type_t< KeyT > Val)
Represents either an error or a value T.
std::error_code getError() const
Error takeError()
Take ownership of the stored error.
A smart pointer to a reference-counted object that inherits from RefCountedBase or ThreadSafeRefCount...
This interface provides simple read-only access to a block of memory, and provides simple methods for...
static ErrorOr< std::unique_ptr< MemoryBuffer > > getOpenFile(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Given an already-open file descriptor, read the file and return a MemoryBuffer.
static std::unique_ptr< MemoryBuffer > getMemBuffer(StringRef InputData, StringRef BufferName="", bool RequiresNullTerminator=true)
Open the specified memory range as a MemoryBuffer.
virtual StringRef getBufferIdentifier() const
Return an identifier for this buffer, typically the filename it was read from.
StringRef getBuffer() const
Represents a location in source code.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
StringRef str() const
Explicit conversion to StringRef.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
This owns the files read by a parser, handles include stacks, and handles diagnostic wrangling.
LLVM_ABI void PrintMessage(raw_ostream &OS, SMLoc Loc, DiagKind Kind, const Twine &Msg, ArrayRef< SMRange > Ranges={}, ArrayRef< SMFixIt > FixIts={}, bool ShowColors=true) const
Emit a message about the specified location with the specified string.
void(*)(const SMDiagnostic &, void *Context) DiagHandlerTy
Clients that want to handle their own diagnostics in a custom way can register a function pointer+con...
void setDiagHandler(DiagHandlerTy DH, void *Ctx=nullptr)
Specify a diagnostic handler to be invoked every time PrintMessage is called.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
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
Get the contents as an std::string.
constexpr bool empty() const
Check if the string is empty.
char back() const
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
Get the string size.
StringSet - A wrapper for StringMap that provides set-like functionality.
std::pair< typename Base::iterator, bool > insert(StringRef key)
Target - Wrapper for Target specific information.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
LLVM_ABI std::string str() const
Return the twine contents as a std::string.
LLVM_ABI void toVector(SmallVectorImpl< char > &Out) const
Append the concatenated string into the given SmallString or SmallVector.
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM Value Representation.
An opaque object representing a hash code.
This class implements an extremely fast bulk output stream that can only output to a stream.
raw_ostream & write(unsigned char C)
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
const std::string & path() const
directory_iterator - Iterates through the entries in path.
directory_iterator & increment(std::error_code &ec)
Represents the result of a call to sys::fs::status().
The virtual file system interface.
llvm::function_ref< void(FileSystem &)> VisitCallbackTy
virtual llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const =0
Get the working directory of this file system.
virtual bool exists(const Twine &Path)
Check whether Path exists.
virtual llvm::ErrorOr< std::unique_ptr< File > > openFileForReadBinary(const Twine &Path)
Get a File object for the binary file at Path, if one exists.
virtual std::error_code makeAbsolute(SmallVectorImpl< char > &Path) const
Make Path an absolute path.
virtual llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path)=0
Get a File object for the text file at Path, if one exists.
virtual std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output)
Gets real path of Path e.g.
void printIndent(raw_ostream &OS, unsigned IndentLevel) const
LLVM_DUMP_METHOD void dump() const
void print(raw_ostream &OS, PrintType Type=PrintType::Contents, unsigned IndentLevel=0) const
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getBufferForFile(const Twine &Name, int64_t FileSize=-1, bool RequiresNullTerminator=true, bool IsVolatile=false, bool IsText=true)
This is a convenience method that opens a file, gets its content and then closes the file.
llvm::ErrorOr< bool > equivalent(const Twine &A, const Twine &B)
virtual std::error_code isLocal(const Twine &Path, bool &Result)
Is the file mounted on a local filesystem?
virtual llvm::ErrorOr< Status > status(const Twine &Path)=0
Get the status of the entry at Path, if one exists.
static ErrorOr< std::unique_ptr< File > > getWithPath(ErrorOr< std::unique_ptr< File > > Result, const Twine &P)
virtual ~File()
Destroy the file after closing it (if open).
Adaptor from InMemoryDir::iterator to directory_iterator.
DirIterator(const InMemoryFileSystem *FS, const detail::InMemoryDirectory &Dir, std::string RequestedDirName)
std::error_code increment() override
Sets CurrentEntry to the next entry in the directory on success, to directory_entry() at end,...
std::error_code isLocal(const Twine &Path, bool &Result) override
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override
std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) override
Canonicalizes Path by combining with the current working directory and normalizing the path (e....
~InMemoryFileSystem() override
static constexpr size_t MaxSymlinkDepth
Arbitrary max depth to search through symlinks.
InMemoryFileSystem(bool UseNormalizedPaths=true)
bool useNormalizedPaths() const
Return true if this file system normalizes . and .. in paths.
void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override
llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override
bool addHardLink(const Twine &NewLink, const Twine &Target)
Add a hard link to a file.
std::string toString() const
bool addFileNoOwn(const Twine &Path, time_t ModificationTime, const llvm::MemoryBufferRef &Buffer, std::optional< uint32_t > User=std::nullopt, std::optional< uint32_t > Group=std::nullopt, std::optional< llvm::sys::fs::file_type > Type=std::nullopt, std::optional< llvm::sys::fs::perms > Perms=std::nullopt)
Add a buffer to the VFS with a path.
bool addSymbolicLink(const Twine &NewLink, const Twine &Target, time_t ModificationTime, std::optional< uint32_t > User=std::nullopt, std::optional< uint32_t > Group=std::nullopt, std::optional< llvm::sys::fs::perms > Perms=std::nullopt)
Add a symbolic link.
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
llvm::ErrorOr< Status > status(const Twine &Path) override
llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override
void visitChildFileSystems(VisitCallbackTy Callback) override
llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override
std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) override
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
void pushOverlay(IntrusiveRefCntPtr< FileSystem > FS)
Pushes a file system on top of the stack.
OverlayFileSystem(IntrusiveRefCntPtr< FileSystem > Base)
llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override
iterator overlays_end()
Get an iterator pointing one-past the least recently added file system.
std::error_code isLocal(const Twine &Path, bool &Result) override
bool exists(const Twine &Path) override
llvm::ErrorOr< Status > status(const Twine &Path) override
iterator overlays_begin()
Get an iterator pointing to the most recently added file system.
FileSystemList::reverse_iterator iterator
void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override
Directory iterator implementation for RedirectingFileSystem's directory entries.
std::error_code increment() override
Sets CurrentEntry to the next entry in the directory on success, to directory_entry() at end,...
RedirectingFSDirIterImpl(const Twine &Path, RedirectingFileSystem::DirectoryEntry::iterator Begin, RedirectingFileSystem::DirectoryEntry::iterator End, std::error_code &EC)
A helper class to hold the common YAML parsing state.
RedirectingFileSystemParser(yaml::Stream &S)
static RedirectingFileSystem::Entry * lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name, RedirectingFileSystem::Entry *ParentEntry=nullptr)
bool parse(yaml::Node *Root, RedirectingFileSystem *FS)
decltype(Contents)::iterator iterator
A single file or directory in the VFS.
StringRef getName() const
EntryKind getKind() const
A virtual file system parsed from a YAML file.
@ OverlayDir
The roots are relative to the directory where the Overlay YAML file.
@ CWD
The roots are relative to the current working directory.
bool exists(const Twine &Path) override
Check whether Path exists.
void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override
friend class RedirectingFileSystemParser
std::vector< llvm::StringRef > getRoots() const
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override
Get a directory_iterator for Dir.
ErrorOr< LookupResult > lookupPath(StringRef Path) const
Looks up Path in Roots and returns a LookupResult giving the matched entry and, if the entry was a Fi...
RedirectKind
The type of redirection to perform.
@ Fallthrough
Lookup the redirected path first (ie.
@ Fallback
Lookup the provided path first and if that fails, "fallback" to a lookup of the redirected path.
@ RedirectOnly
Only lookup the redirected path, do not lookup the originally provided path.
void setFallthrough(bool Fallthrough)
Sets the redirection kind to Fallthrough if true or RedirectOnly otherwise.
void visitChildFileSystems(VisitCallbackTy Callback) override
std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) override
Gets real path of Path e.g.
ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override
Get a File object for the text file at Path, if one exists.
void setOverlayFileDir(StringRef PrefixDir)
llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override
Get the working directory of this file system.
void setRedirection(RedirectingFileSystem::RedirectKind Kind)
std::error_code isLocal(const Twine &Path, bool &Result) override
Is the file mounted on a local filesystem?
static std::unique_ptr< RedirectingFileSystem > create(std::unique_ptr< MemoryBuffer > Buffer, SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, void *DiagContext, IntrusiveRefCntPtr< FileSystem > ExternalFS)
Parses Buffer, which is expected to be in YAML format and returns a virtual file system representing ...
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
Set the working directory.
StringRef getOverlayFileDir() const
void printEntry(raw_ostream &OS, Entry *E, unsigned IndentLevel=0) const
The result of a status operation.
llvm::sys::fs::UniqueID getUniqueID() const
LLVM_ABI bool equivalent(const Status &Other) const
static LLVM_ABI Status copyWithNewName(const Status &In, const Twine &NewName)
Get a copy of a Status with a different name.
LLVM_ABI bool isStatusKnown() const
LLVM_ABI bool exists() const
bool ExposesExternalVFSPath
Whether this entity has an external path different from the virtual path, and the external path is ex...
uint32_t getGroup() const
static LLVM_ABI Status copyWithNewSize(const Status &In, uint64_t NewSize)
Get a copy of a Status with a different size.
LLVM_ABI bool isOther() const
LLVM_ABI bool isSymlink() const
llvm::sys::TimePoint getLastModificationTime() const
llvm::sys::fs::file_type getType() const
LLVM_ABI bool isRegularFile() const
LLVM_ABI bool isDirectory() const
LLVM_ABI void addFileMapping(StringRef VirtualPath, StringRef RealPath)
LLVM_ABI void write(llvm::raw_ostream &OS)
LLVM_ABI void addDirectoryMapping(StringRef VirtualPath, StringRef RealPath)
InMemoryDirectory(Status Stat)
InMemoryNode * addChild(StringRef Name, std::unique_ptr< InMemoryNode > Child)
Status getStatus(const Twine &RequestedName) const override
Return the Status for this node.
const_iterator end() const
static bool classof(const InMemoryNode *N)
InMemoryNode * getChild(StringRef Name) const
const_iterator begin() const
UniqueID getUniqueID() const
decltype(Entries)::const_iterator const_iterator
std::string toString(unsigned Indent) const override
Status getStatus(const Twine &RequestedName) const override
Return the Status for this node.
std::string toString(unsigned Indent) const override
InMemoryFile(Status Stat, std::unique_ptr< llvm::MemoryBuffer > Buffer)
static bool classof(const InMemoryNode *N)
llvm::MemoryBuffer * getBuffer() const
The in memory file system is a tree of Nodes.
StringRef getFileName() const
Get the filename of this node (the name without the directory part).
InMemoryNodeKind getKind() const
virtual ~InMemoryNode()=default
InMemoryNode(llvm::StringRef FileName, InMemoryNodeKind Kind)
virtual std::string toString(unsigned Indent) const =0
virtual Status getStatus(const Twine &RequestedName) const =0
Return the Status for this node.
A member of a directory, yielded by a directory_iterator.
llvm::StringRef path() const
llvm::sys::fs::file_type type() const
An input iterator over the entries in a virtual path, similar to llvm::sys::fs::directory_iterator.
directory_iterator & increment(std::error_code &EC)
Equivalent to operator++, with an error code.
An input iterator over the recursive contents of a virtual path, similar to llvm::sys::fs::recursive_...
recursive_directory_iterator()=default
Construct an 'end' iterator.
LLVM_ABI recursive_directory_iterator & increment(std::error_code &EC)
Equivalent to operator++, with an error code.
Abstract base class for all Nodes.
This class represents a YAML stream potentially containing multiple documents.
LLVM_ABI document_iterator end()
LLVM_ABI document_iterator begin()
LLVM_ABI void printError(Node *N, const Twine &Msg, SourceMgr::DiagKind Kind=SourceMgr::DK_Error)
Iterator abstraction for Documents over a Stream.
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ Resolved
Queried, materialization begun.
LLVM_ABI std::error_code closeFile(file_t &F)
Close the file object.
@ OF_Text
The file should be opened in text mode on platforms like z/OS that make this distinction.
file_type
An enumeration for the file system's view of the type.
LLVM_ABI std::error_code set_current_path(const Twine &path)
Set the current path.
LLVM_ABI std::error_code real_path(const Twine &path, SmallVectorImpl< char > &output, bool expand_tilde=false)
Collapse all .
LLVM_ABI Expected< file_t > openNativeFileForRead(const Twine &Name, OpenFlags Flags=OF_None, SmallVectorImpl< char > *RealPath=nullptr)
Opens the file with the given name in a read-only mode, returning its open file descriptor.
LLVM_ABI std::error_code current_path(SmallVectorImpl< char > &result)
Get the current path.
LLVM_ABI std::error_code status(const Twine &path, file_status &result, bool follow=true)
Get file status as if by POSIX stat().
LLVM_ABI std::error_code is_local(const Twine &path, bool &result)
Is the file mounted on a local filesystem?
LLVM_ABI std::error_code openFileForRead(const Twine &Name, int &ResultFD, OpenFlags Flags=OF_None, SmallVectorImpl< char > *RealPath=nullptr)
Opens the file with the given name in a read-only mode, returning its open file descriptor.
LLVM_ABI bool is_directory(const basic_file_status &status)
Does status represent a directory?
LLVM_ABI StringRef get_separator(Style style=Style::native)
Return the preferred separator for this platform.
LLVM_ABI StringRef root_path(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get root path.
LLVM_ABI const_iterator begin(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get begin iterator over path.
LLVM_ABI bool remove_dots(SmallVectorImpl< char > &path, bool remove_dot_dot=false, Style style=Style::native)
Remove '.
LLVM_ABI StringRef parent_path(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get parent path.
LLVM_ABI void make_absolute(const Twine ¤t_directory, SmallVectorImpl< char > &path)
Make path an absolute path.
LLVM_ABI StringRef filename(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get filename.
LLVM_ABI StringRef remove_leading_dotslash(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Remove redundant leading "./" pieces and consecutive separators.
LLVM_ABI bool is_absolute(const Twine &path, Style style=Style::native)
Is path absolute?
LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
LLVM_ABI reverse_iterator rend(StringRef path LLVM_LIFETIME_BOUND)
Get reverse end iterator over path.
LLVM_ABI reverse_iterator rbegin(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get reverse begin iterator over path.
LLVM_ABI const_iterator end(StringRef path LLVM_LIFETIME_BOUND)
Get end iterator over path.
LLVM_ABI bool is_separator(char value, Style style=Style::native)
Check whether the given char is a path separator on the host OS.
void violationIfEnabled()
ScopedSetting scopedDisable()
std::chrono::time_point< std::chrono::system_clock, D > TimePoint
A time point on the system clock.
TimePoint< std::chrono::seconds > toTimePoint(std::time_t T)
Convert a std::time_t to a TimePoint.
std::error_code make_error_code(OutputErrorCode EV)
LLVM_ABI void collectVFSEntries(RedirectingFileSystem &VFS, SmallVectorImpl< YAMLVFSEntry > &CollectedEntries)
Collect all pairs of <virtual path, real path> entries from the VFS.
LLVM_ABI std::unique_ptr< FileSystem > createPhysicalFileSystem()
Create an vfs::FileSystem for the 'real' file system, as seen by the operating system.
static sys::fs::UniqueID getFileID(sys::fs::UniqueID Parent, llvm::StringRef Name, llvm::StringRef Contents)
LLVM_ABI llvm::sys::fs::UniqueID getNextVirtualUniqueID()
Get a globally unique ID for a virtual file or directory.
static sys::fs::UniqueID getUniqueID(hash_code Hash)
LLVM_ABI IntrusiveRefCntPtr< FileSystem > getRealFileSystem()
Gets an vfs::FileSystem for the 'real' file system, as seen by the operating system.
LLVM_ABI std::unique_ptr< FileSystem > getVFSFromYAML(std::unique_ptr< llvm::MemoryBuffer > Buffer, llvm::SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, void *DiagContext=nullptr, IntrusiveRefCntPtr< FileSystem > ExternalFS=getRealFileSystem())
Gets a FileSystem for a virtual file system described in YAML format.
static sys::fs::UniqueID getDirectoryID(sys::fs::UniqueID Parent, llvm::StringRef Name)
LLVM_ABI std::string escape(StringRef Input, bool EscapePrintable=true)
Escape Input for a double quoted scalar; if EscapePrintable is true, all UTF8 sequences will be escap...
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
auto dyn_cast_if_present(const Y &Val)
dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a null (or none in the case ...
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
IntrusiveRefCntPtr< T > makeIntrusiveRefCnt(Args &&...A)
Factory function for creating intrusive ref counted pointers.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
@ no_such_file_or_directory
@ operation_not_permitted
auto reverse(ContainerTy &&C)
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
ArrayRef(const T &OneElt) -> ArrayRef< T >
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
LLVM_ABI std::error_code errorToErrorCode(Error Err)
Helper for converting an ECError to a std::error_code.
LLVM_ABI Error write(DWPWriter &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue, Dwarf64StrOffsetsPromotion StrOffsetsOptValue, raw_pwrite_stream *OS=nullptr)
Implement std::hash so that hash_code can be used in STL containers.
static constexpr value_type Invalid
Value for an invalid file descriptor.
This class wraps the platform specific file handle/descriptor type to provide an unified representati...
bool isValid() const
Is a valid file.
Entry * E
The entry the looked-up path corresponds to.
LLVM_ABI LookupResult(Entry *E, sys::path::const_iterator Start, sys::path::const_iterator End)
LLVM_ABI void getPath(llvm::SmallVectorImpl< char > &Path) const
Get the (canonical) path of the found entry.
llvm::SmallVector< Entry *, 32 > Parents
Chain of parent directory entries for E.
An interface for virtual file systems to provide an iterator over the (non-recursive) contents of a d...
directory_entry CurrentEntry
LLVM_ABI Status makeStatus() const
llvm::sys::fs::file_type Type
std::unique_ptr< llvm::MemoryBuffer > Buffer
llvm::sys::fs::perms Perms
llvm::sys::fs::UniqueID DirUID