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;
298 getDirectoryContentRealSources(
const Twine &Dir,
299 SmallVectorImpl<std::string> &Out)
override {
302 std::error_code getRealPath(
const Twine &Path,
303 SmallVectorImpl<char> &Output)
override;
307 unsigned IndentLevel)
const override;
312 Twine adjustPath(
const Twine &Path, SmallVectorImpl<char> &Storage)
const {
315 Path.toVector(Storage);
320 ErrorOr<std::unique_ptr<File>>
322 SmallString<256> RealName, Storage;
324 adjustPath(Name, Storage), Flags, &RealName);
327 return std::unique_ptr<File>(
328 new RealFile(*FDOrErr,
Name.str(), RealName.
str()));
331 struct WorkingDirectory {
333 SmallString<128> Specified;
337 std::optional<llvm::ErrorOr<WorkingDirectory>> WD;
342ErrorOr<Status> RealFileSystem::status(
const Twine &Path) {
345 SmallString<256> Storage;
346 sys::fs::file_status RealStatus;
347 if (std::error_code EC =
353ErrorOr<std::unique_ptr<File>>
354RealFileSystem::openFileForRead(
const Twine &Name) {
360ErrorOr<std::unique_ptr<File>>
361RealFileSystem::openFileForReadBinary(
const Twine &Name) {
367llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory()
const {
371 return std::string(WD->get().Specified);
373 return WD->getError();
375 SmallString<128> Dir;
378 return std::string(Dir);
381std::error_code RealFileSystem::setCurrentWorkingDirectory(
const Twine &Path) {
388 adjustPath(Path, Storage).toVector(Absolute);
393 return std::make_error_code(std::errc::not_a_directory);
397 return std::error_code();
400std::error_code RealFileSystem::isLocal(
const Twine &Path,
bool &Result) {
403 SmallString<256> Storage;
407std::error_code RealFileSystem::getRealPath(
const Twine &Path,
408 SmallVectorImpl<char> &Output) {
411 SmallString<256> Storage;
415void RealFileSystem::printImpl(raw_ostream &OS, PrintType
Type,
416 unsigned IndentLevel)
const {
417 printIndent(OS, IndentLevel);
418 OS <<
"RealFileSystem using ";
437 return std::make_unique<RealFileSystem>(
false);
446 RealFSDirIter(
const Twine &Path, std::error_code &EC) {
454 std::error_code increment()
override {
469 std::error_code &EC) {
472 SmallString<128> Storage;
474 std::make_shared<RealFSDirIter>(adjustPath(Dir, Storage), EC));
482 FSList.push_back(std::move(BaseFS));
486 FSList.push_back(FS);
505 if ((*I)->exists(Path))
515 auto Result = (*I)->openFileForRead(Path);
525 return FSList.front()->getCurrentWorkingDirectory();
530 for (
auto &FS : FSList)
531 if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))
537 for (
auto &FS : FSList)
538 if (FS->exists(Path))
539 return FS->isLocal(Path, Result);
545 for (
const auto &FS : FSList)
546 if (FS->exists(Path))
547 return FS->getRealPath(Path, Output);
555 (*I)->getDirectoryContentRealSources(Dir, Out);
561 FS->visitChildFileSystems(Callback);
566 unsigned IndentLevel)
const {
567 printIndent(OS, IndentLevel);
568 OS <<
"OverlayFileSystem\n";
569 if (
Type == PrintType::Summary)
572 if (
Type == PrintType::Contents)
573 Type = PrintType::Summary;
575 FS->print(OS,
Type, IndentLevel + 1);
595 std::error_code incrementIter(
bool IsFirstTime) {
596 while (!IterList.
empty()) {
597 CurrentDirIter = IterList.
back();
608 std::error_code incrementDirIter(
bool IsFirstTime) {
609 assert((IsFirstTime || CurrentDirIter != directory_iterator()) &&
610 "incrementing past end");
614 if (!EC && CurrentDirIter == directory_iterator())
615 EC = incrementIter(IsFirstTime);
619 std::error_code incrementImpl(
bool IsFirstTime) {
621 std::error_code
EC = incrementDirIter(IsFirstTime);
622 if (EC || CurrentDirIter == directory_iterator()) {
623 CurrentEntry = directory_entry();
626 CurrentEntry = *CurrentDirIter;
628 if (SeenNames.
insert(Name).second)
636 std::error_code &EC) {
637 for (
const auto &FS : FileSystems) {
639 directory_iterator Iter =
FS->dir_begin(Dir, FEC);
640 if (FEC && FEC != errc::no_such_file_or_directory) {
647 EC = incrementImpl(
true);
652 : IterList(DirIters) {
653 EC = incrementImpl(
true);
656 std::error_code increment()
override {
return incrementImpl(
false); }
662 std::error_code &EC) {
664 std::make_shared<CombiningDirIterImpl>(FSList, Dir.
str(), EC));
670void ProxyFileSystem::anchor() {}
688 std::string FileName;
692 : Kind(Kind), FileName(
std::string(
llvm::
sys::
path::filename(FileName))) {
704 virtual std::string
toString(
unsigned Indent)
const = 0;
709 std::unique_ptr<llvm::MemoryBuffer> Buffer;
721 std::string
toString(
unsigned Indent)
const override {
722 return (std::string(Indent,
' ') + Stat.getName() +
"\n").str();
732class InMemoryHardLink :
public InMemoryNode {
733 const InMemoryFile &ResolvedFile;
736 InMemoryHardLink(
StringRef Path,
const InMemoryFile &ResolvedFile)
737 : InMemoryNode(Path,
IME_HardLink), ResolvedFile(ResolvedFile) {}
738 const InMemoryFile &getResolvedFile()
const {
return ResolvedFile; }
740 Status getStatus(
const Twine &RequestedName)
const override {
741 return ResolvedFile.getStatus(RequestedName);
744 std::string
toString(
unsigned Indent)
const override {
745 return std::string(Indent,
' ') +
"HardLink to -> " +
746 ResolvedFile.toString(0);
749 static bool classof(
const InMemoryNode *
N) {
755 std::string TargetPath;
759 InMemorySymbolicLink(StringRef Path, StringRef TargetPath, Status Stat)
763 std::string
toString(
unsigned Indent)
const override {
764 return std::string(Indent,
' ') +
"SymbolicLink to -> " + TargetPath;
767 Status getStatus(
const Twine &RequestedName)
const override {
771 StringRef getTargetPath()
const {
return TargetPath; }
773 static bool classof(
const InMemoryNode *
N) {
781class InMemoryFileAdaptor :
public File {
782 const InMemoryFile &Node;
784 std::string RequestedName;
787 explicit InMemoryFileAdaptor(
const InMemoryFile &Node,
788 std::string RequestedName)
789 : Node(Node), RequestedName(std::
move(RequestedName)) {}
791 llvm::ErrorOr<Status>
status()
override {
792 return Node.getStatus(RequestedName);
795 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
796 getBuffer(
const Twine &Name, int64_t FileSize,
bool RequiresNullTerminator,
797 bool IsVolatile)
override {
798 llvm::MemoryBuffer *Buf = Node.getBuffer();
803 std::error_code close()
override {
return {}; }
805 void setPath(
const Twine &Path)
override { RequestedName =
Path.str(); }
811 std::map<std::string, std::unique_ptr<InMemoryNode>, std::less<>> Entries;
827 auto I = Entries.find(Name);
828 if (
I != Entries.end())
829 return I->second.get();
834 return Entries.emplace(Name, std::move(Child)).first->second.get();
842 std::string
toString(
unsigned Indent)
const override {
844 (std::string(Indent,
' ') + Stat.getName() +
"\n").str();
845 for (
const auto &Entry : Entries)
846 Result += Entry.second->toString(Indent + 2);
885 : Root(new
detail::InMemoryDirectory(
890 UseNormalizedPaths(UseNormalizedPaths) {}
895 return Root->toString(0);
898bool InMemoryFileSystem::addFile(
const Twine &
P, time_t ModificationTime,
899 std::unique_ptr<llvm::MemoryBuffer> Buffer,
900 std::optional<uint32_t>
User,
901 std::optional<uint32_t> Group,
902 std::optional<llvm::sys::fs::file_type>
Type,
903 std::optional<llvm::sys::fs::perms> Perms,
904 MakeNodeFn MakeNode) {
921 const auto ResolvedUser =
User.value_or(0);
922 const auto ResolvedGroup = Group.value_or(0);
939 StringRef(Path.str().begin(), Name.end() - Path.str().begin()),
944 Name, std::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
955 MakeNode({Dir->
getUniqueID(), Path, Name, ModificationTime,
956 std::move(Buffer), ResolvedUser, ResolvedGroup,
957 ResolvedType, ResolvedPerms}));
965 "Must be either file, hardlink or directory!");
969 return Link->getResolvedFile().getBuffer()->getBuffer() ==
976bool InMemoryFileSystem::addFile(
const Twine &
P, time_t ModificationTime,
977 std::unique_ptr<llvm::MemoryBuffer> Buffer,
978 std::optional<uint32_t>
User,
979 std::optional<uint32_t> Group,
980 std::optional<llvm::sys::fs::file_type>
Type,
981 std::optional<llvm::sys::fs::perms> Perms) {
982 return addFile(
P, ModificationTime, std::move(Buffer),
User, Group,
Type,
985 -> std::unique_ptr<detail::InMemoryNode> {
988 return std::make_unique<detail::InMemoryDirectory>(Stat);
989 return std::make_unique<detail::InMemoryFile>(
990 Stat, std::move(NNI.
Buffer));
995 const Twine &
P, time_t ModificationTime,
997 std::optional<uint32_t> Group, std::optional<llvm::sys::fs::file_type>
Type,
998 std::optional<llvm::sys::fs::perms> Perms) {
1000 std::move(
User), std::move(Group), std::move(
Type),
1003 -> std::unique_ptr<detail::InMemoryNode> {
1006 return std::make_unique<detail::InMemoryDirectory>(Stat);
1007 return std::make_unique<detail::InMemoryFile>(
1008 Stat, std::move(NNI.
Buffer));
1013InMemoryFileSystem::lookupNode(
const Twine &
P,
bool FollowFinalSymlink,
1014 size_t SymlinkDepth)
const {
1040 if (
I == E && !FollowFinalSymlink)
1055 lookupNode(TargetPath,
true, SymlinkDepth + 1);
1083 return detail::NamedNodeOrError(Path, Dir);
1089 auto NewLinkNode = lookupNode(NewLink,
false);
1093 auto TargetNode = lookupNode(
Target,
true);
1098 return addFile(NewLink, 0,
nullptr, std::nullopt, std::nullopt, std::nullopt,
1100 return std::make_unique<detail::InMemoryHardLink>(
1108 std::optional<uint32_t>
User, std::optional<uint32_t> Group,
1109 std::optional<llvm::sys::fs::perms> Perms) {
1110 auto NewLinkNode = lookupNode(NewLink,
false);
1116 Target.toVector(TargetStr);
1118 return addFile(NewLinkStr, ModificationTime,
nullptr,
User, Group,
1121 return std::make_unique<detail::InMemorySymbolicLink>(
1127 auto Node = lookupNode(Path,
true);
1129 return (*Node)->getStatus(Path);
1130 return Node.getError();
1135 auto Node = lookupNode(Path,
true);
1137 return Node.getError();
1142 return std::unique_ptr<File>(
1143 new detail::InMemoryFileAdaptor(*
F, Path.str()));
1154 std::string RequestedDirName;
1156 void setCurrentEntry() {
1161 switch (I->second->getKind()) {
1170 if (
auto SymlinkTarget =
1171 FS->lookupNode(Path,
true)) {
1172 Path = SymlinkTarget.getName();
1173 Type = (*SymlinkTarget)->getStatus(Path).getType();
1190 std::string RequestedDirName)
1191 : FS(FS), I(Dir.begin()), E(Dir.end()),
1192 RequestedDirName(
std::
move(RequestedDirName)) {
1204 std::error_code &EC) {
1205 auto Node = lookupNode(Dir,
true);
1207 EC =
Node.getError();
1213 std::make_shared<DirIterator>(
this, *DirNode, Dir.
str()));
1232 WorkingDirectory = std::string(Path);
1239 if (!CWD || CWD->empty())
1241 Path.toVector(Output);
1254 unsigned IndentLevel)
const {
1255 printIndent(OS, IndentLevel);
1256 OS <<
"InMemoryFileSystem\n";
1271 const size_t n = Path.find_first_of(
"/\\");
1273 if (n !=
static_cast<size_t>(-1))
1293static bool isFileNotFound(std::error_code EC,
1305 assert(ExternalFS &&
"RedirectingFileSystem requires an external FS");
1306 if (
auto ExternalWorkingDirectory = ExternalFS->getCurrentWorkingDirectory())
1307 WorkingDirectory = *ExternalWorkingDirectory;
1317 std::error_code incrementImpl(
bool IsFirstTime) {
1318 assert((IsFirstTime || Current != End) &&
"cannot iterate past end");
1321 if (Current != End) {
1325 switch ((*Current)->getKind()) {
1346 : Dir(Path.str()), Current(Begin), End(End) {
1347 EC = incrementImpl(
true);
1351 return incrementImpl(
false);
1365 RedirectingFSDirRemapIterImpl(std::string DirPath,
1367 : Dir(
std::
move(DirPath)), DirStyle(getExistingStyle(Dir)),
1368 ExternalIter(ExtIter) {
1373 void setCurrentEntry() {
1384 std::error_code increment()
override {
1387 if (!EC && ExternalIter != llvm::vfs::directory_iterator())
1390 CurrentEntry = directory_entry();
1396llvm::ErrorOr<std::string>
1398 return WorkingDirectory;
1408 Path.toVector(AbsolutePath);
1409 if (std::error_code EC = makeAbsolute(AbsolutePath))
1411 WorkingDirectory = std::string(AbsolutePath);
1420 if (makeAbsolute(Path))
1423 return ExternalFS->isLocal(Path, Result);
1438 return WorkingDir.getError();
1440 return makeAbsolute(WorkingDir.get(), Path);
1444RedirectingFileSystem::makeAbsolute(
StringRef WorkingDir,
1450 if (!WorkingDir.
empty() &&
1454 return std::error_code();
1466 std::string
Result = std::string(WorkingDir);
1467 StringRef Dir(Result);
1483 std::error_code &EC) {
1487 EC = makeAbsolute(Path);
1494 isFileNotFound(Result.getError()))
1495 return ExternalFS->dir_begin(Path, EC);
1497 EC = Result.getError();
1505 isFileNotFound(S.
getError(), Result->E))
1506 return ExternalFS->dir_begin(Dir, EC);
1512 if (!S->isDirectory()) {
1520 std::error_code RedirectEC;
1521 if (
auto ExtRedirect = Result->getExternalRedirect()) {
1523 RedirectIter = ExternalFS->dir_begin(*ExtRedirect, RedirectEC);
1525 if (!RE->useExternalName(UseExternalNames)) {
1529 std::string(Path), RedirectIter));
1535 Path, DE->contents_begin(), DE->contents_end(), RedirectEC));
1548 return RedirectIter;
1551 std::error_code ExternalEC;
1562 switch (Redirection) {
1576 std::make_shared<CombiningDirIterImpl>(Iters, EC)};
1583 OverlayFileDir = Dir.
str();
1587 return OverlayFileDir;
1604 std::vector<StringRef> R;
1605 R.reserve(Roots.size());
1606 for (
const auto &Root : Roots)
1607 R.push_back(Root->getName());
1612 unsigned IndentLevel)
const {
1614 OS <<
"RedirectingFileSystem (UseExternalNames: "
1615 << (UseExternalNames ?
"true" :
"false") <<
")\n";
1619 for (
const auto &Root : Roots)
1623 OS <<
"ExternalFS:\n";
1630 unsigned IndentLevel)
const {
1632 OS <<
"'" << E->getName() <<
"'";
1634 switch (E->getKind()) {
1639 for (std::unique_ptr<Entry> &SubEntry :
1641 printEntry(OS, SubEntry.get(), IndentLevel + 1);
1647 OS <<
" -> '" << RE->getExternalContentsPath() <<
"'";
1648 switch (RE->getUseName()) {
1652 OS <<
" (UseExternalName: true)";
1655 OS <<
" (UseExternalName: false)";
1666 Callback(*ExternalFS);
1667 ExternalFS->visitChildFileSystems(Callback);
1683 error(
N,
"expected string");
1686 Result = S->getValue(Storage);
1691 bool parseScalarBool(
yaml::Node *
N,
bool &Result) {
1694 if (!parseScalarString(
N,
Value, Storage))
1697 if (
Value.equals_insensitive(
"true") ||
Value.equals_insensitive(
"on") ||
1698 Value.equals_insensitive(
"yes") ||
Value ==
"1") {
1701 }
else if (
Value.equals_insensitive(
"false") ||
1702 Value.equals_insensitive(
"off") ||
1703 Value.equals_insensitive(
"no") ||
Value ==
"0") {
1708 error(
N,
"expected boolean value");
1712 std::optional<RedirectingFileSystem::RedirectKind>
1716 if (!parseScalarString(
N,
Value, Storage))
1717 return std::nullopt;
1719 if (
Value.equals_insensitive(
"fallthrough")) {
1721 }
else if (
Value.equals_insensitive(
"fallback")) {
1723 }
else if (
Value.equals_insensitive(
"redirect-only")) {
1726 return std::nullopt;
1729 std::optional<RedirectingFileSystem::RootRelativeKind>
1733 if (!parseScalarString(
N,
Value, Storage))
1734 return std::nullopt;
1735 if (
Value.equals_insensitive(
"cwd")) {
1737 }
else if (
Value.equals_insensitive(
"overlay-dir")) {
1740 return std::nullopt;
1747 KeyStatus(
bool Required =
false) : Required(Required) {}
1750 using KeyStatusPair = std::pair<StringRef, KeyStatus>;
1756 if (It == Keys.
end()) {
1757 error(KeyNode,
"unknown key");
1760 KeyStatus &S = It->second;
1771 for (
const auto &
I : Keys) {
1772 if (
I.second.Required && !
I.second.Seen) {
1773 error(Obj,
Twine(
"missing key '") +
I.first +
"'");
1785 for (
const auto &Root : FS->Roots) {
1786 if (Name == Root->getName()) {
1787 ParentEntry = Root.get();
1793 for (std::unique_ptr<RedirectingFileSystem::Entry> &Content :
1797 if (DirContent && Name == Content->getName())
1803 std::unique_ptr<RedirectingFileSystem::Entry> E =
1804 std::make_unique<RedirectingFileSystem::DirectoryEntry>(
1806 std::chrono::system_clock::now(), 0, 0, 0,
1810 FS->Roots.push_back(std::move(E));
1811 ParentEntry = FS->Roots.back().get();
1816 DE->addContent(std::move(E));
1817 return DE->getLastContent();
1832 NewParentE = lookupOrCreateEntry(FS, Name, NewParentE);
1833 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
1835 uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
1839 assert(NewParentE &&
"Parent entry must exist");
1843 std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
1844 Name, DR->getExternalContentsPath(), DR->getUseName()));
1848 assert(NewParentE &&
"Parent entry must exist");
1851 DE->addContent(std::make_unique<RedirectingFileSystem::FileEntry>(
1852 Name, FE->getExternalContentsPath(), FE->getUseName()));
1858 std::unique_ptr<RedirectingFileSystem::Entry>
1859 parseEntry(yaml::Node *
N, RedirectingFileSystem *FS,
bool IsRootEntry) {
1862 error(
N,
"expected mapping node for file or directory entry");
1866 KeyStatusPair Fields[] = {
1867 KeyStatusPair(
"name",
true),
1868 KeyStatusPair(
"type",
true),
1869 KeyStatusPair(
"contents",
false),
1870 KeyStatusPair(
"external-contents",
false),
1871 KeyStatusPair(
"use-external-name",
false),
1874 DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
1876 enum { CF_NotSet, CF_List, CF_External } ContentsField = CF_NotSet;
1877 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>>
1879 SmallString<256> ExternalContentsPath;
1880 SmallString<256>
Name;
1881 yaml::Node *NameValueNode =
nullptr;
1885 for (
auto &
I : *M) {
1889 SmallString<256> Buffer;
1890 if (!parseScalarString(
I.getKey(),
Key, Buffer))
1893 if (!checkDuplicateOrUnknownKey(
I.getKey(),
Key, Keys))
1897 if (
Key ==
"name") {
1898 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1901 NameValueNode =
I.getValue();
1905 }
else if (
Key ==
"type") {
1906 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1908 if (
Value ==
"file")
1910 else if (
Value ==
"directory")
1912 else if (
Value ==
"directory-remap")
1915 error(
I.getValue(),
"unknown value for 'type'");
1918 }
else if (
Key ==
"contents") {
1919 if (ContentsField != CF_NotSet) {
1921 "entry already has 'contents' or 'external-contents'");
1924 ContentsField = CF_List;
1928 error(
I.getValue(),
"expected array");
1932 for (
auto &
I : *Contents) {
1933 if (std::unique_ptr<RedirectingFileSystem::Entry>
E =
1934 parseEntry(&
I, FS,
false))
1935 EntryArrayContents.push_back(std::move(
E));
1939 }
else if (
Key ==
"external-contents") {
1940 if (ContentsField != CF_NotSet) {
1942 "entry already has 'contents' or 'external-contents'");
1945 ContentsField = CF_External;
1946 if (!parseScalarString(
I.getValue(),
Value, Buffer))
1949 SmallString<256> FullPath;
1950 if (
FS->IsRelativeOverlay) {
1951 FullPath =
FS->getOverlayFileDir();
1953 "External contents prefix directory must exist");
1954 SmallString<256> AbsFullPath =
Value;
1955 if (
FS->makeAbsolute(FullPath, AbsFullPath)) {
1956 error(
N,
"failed to make 'external-contents' absolute");
1959 FullPath = AbsFullPath;
1966 FullPath = canonicalize(FullPath);
1967 ExternalContentsPath = FullPath.
str();
1968 }
else if (
Key ==
"use-external-name") {
1970 if (!parseScalarBool(
I.getValue(), Val))
1983 if (ContentsField == CF_NotSet) {
1984 error(
N,
"missing key 'contents' or 'external-contents'");
1987 if (!checkMissingKeys(
N, Keys))
1993 error(
N,
"'use-external-name' is not supported for 'directory' entries");
1998 ContentsField == CF_List) {
1999 error(
N,
"'contents' is not supported for 'directory-remap' entries");
2008 path_style = sys::path::Style::posix;
2010 sys::path::Style::windows_backslash)) {
2011 path_style = sys::path::Style::windows_backslash;
2017 if (
FS->RootRelative ==
2018 RedirectingFileSystem::RootRelativeKind::OverlayDir) {
2019 StringRef FullPath =
FS->getOverlayFileDir();
2020 assert(!FullPath.
empty() &&
"Overlay file directory must exist");
2021 EC =
FS->makeAbsolute(FullPath, Name);
2022 Name = canonicalize(Name);
2024 EC =
FS->makeAbsolute(Name);
2027 assert(NameValueNode &&
"Name presence should be checked earlier");
2030 "entry with relative path at the root level is not discoverable");
2034 ? sys::path::Style::posix
2035 : sys::path::Style::windows_backslash;
2040 if (path_style == sys::path::Style::windows_backslash &&
2041 getExistingStyle(Name) != sys::path::Style::windows_backslash)
2042 path_style = sys::path::Style::windows_slash;
2046 StringRef Trimmed =
Name;
2048 while (Trimmed.
size() > RootPathLen &&
2050 Trimmed = Trimmed.
slice(0, Trimmed.
size() - 1);
2055 std::unique_ptr<RedirectingFileSystem::Entry>
Result;
2058 Result = std::make_unique<RedirectingFileSystem::FileEntry>(
2059 LastComponent, std::move(ExternalContentsPath), UseExternalName);
2062 Result = std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
2063 LastComponent, std::move(ExternalContentsPath), UseExternalName);
2066 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
2067 LastComponent, std::move(EntryArrayContents),
2081 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> Entries;
2082 Entries.push_back(std::move(Result));
2083 Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
2084 *
I, std::move(Entries),
2098 error(Root,
"expected mapping node");
2102 KeyStatusPair Fields[] = {
2103 KeyStatusPair(
"version",
true),
2104 KeyStatusPair(
"case-sensitive",
false),
2105 KeyStatusPair(
"use-external-names",
false),
2106 KeyStatusPair(
"root-relative",
false),
2107 KeyStatusPair(
"overlay-relative",
false),
2108 KeyStatusPair(
"fallthrough",
false),
2109 KeyStatusPair(
"redirecting-with",
false),
2110 KeyStatusPair(
"roots",
true),
2114 std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> RootEntries;
2117 for (
auto &
I : *Top) {
2120 if (!parseScalarString(
I.getKey(),
Key, KeyBuffer))
2123 if (!checkDuplicateOrUnknownKey(
I.getKey(),
Key, Keys))
2126 if (
Key ==
"roots") {
2129 error(
I.getValue(),
"expected array");
2133 for (
auto &
I : *Roots) {
2134 if (std::unique_ptr<RedirectingFileSystem::Entry> E =
2135 parseEntry(&
I, FS,
true))
2136 RootEntries.push_back(std::move(E));
2140 }
else if (
Key ==
"version") {
2143 if (!parseScalarString(
I.getValue(), VersionString, Storage))
2147 error(
I.getValue(),
"expected integer");
2151 error(
I.getValue(),
"invalid version number");
2155 error(
I.getValue(),
"version mismatch, expected 0");
2158 }
else if (
Key ==
"case-sensitive") {
2159 if (!parseScalarBool(
I.getValue(), FS->CaseSensitive))
2161 }
else if (
Key ==
"overlay-relative") {
2162 if (!parseScalarBool(
I.getValue(), FS->IsRelativeOverlay))
2164 }
else if (
Key ==
"use-external-names") {
2165 if (!parseScalarBool(
I.getValue(), FS->UseExternalNames))
2167 }
else if (
Key ==
"fallthrough") {
2168 if (Keys[
"redirecting-with"].Seen) {
2170 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2174 bool ShouldFallthrough =
false;
2175 if (!parseScalarBool(
I.getValue(), ShouldFallthrough))
2178 if (ShouldFallthrough) {
2183 }
else if (
Key ==
"redirecting-with") {
2184 if (Keys[
"fallthrough"].Seen) {
2186 "'fallthrough' and 'redirecting-with' are mutually exclusive");
2190 if (
auto Kind = parseRedirectKind(
I.getValue())) {
2191 FS->Redirection = *Kind;
2193 error(
I.getValue(),
"expected valid redirect kind");
2196 }
else if (
Key ==
"root-relative") {
2197 if (
auto Kind = parseRootRelativeKind(
I.getValue())) {
2198 FS->RootRelative = *Kind;
2200 error(
I.getValue(),
"expected valid root-relative kind");
2208 if (Stream.failed())
2211 if (!checkMissingKeys(Top, Keys))
2217 for (
auto &E : RootEntries)
2218 uniqueOverlayTree(FS, E.get());
2224std::unique_ptr<RedirectingFileSystem>
2227 StringRef YAMLFilePath,
void *DiagContext,
2235 if (DI == Stream.
end() || !Root) {
2242 std::unique_ptr<RedirectingFileSystem> FS(
2243 new RedirectingFileSystem(ExternalFS));
2245 if (!YAMLFilePath.
empty()) {
2255 std::error_code EC = FS->makeAbsolute(OverlayAbsDir);
2256 assert(!EC &&
"Overlay dir final path must be absolute");
2258 FS->setOverlayFileDir(OverlayAbsDir);
2261 if (!
P.parse(Root, FS.get()))
2268 ArrayRef<std::pair<std::string, std::string>> RemappedFiles,
2270 std::unique_ptr<RedirectingFileSystem> FS(
2271 new RedirectingFileSystem(ExternalFS));
2272 FS->UseExternalNames = UseExternalNames;
2280 auto EC = ExternalFS->makeAbsolute(From);
2282 assert(!EC &&
"Could not make absolute path");
2300 assert(Parent &&
"File without a directory?");
2302 auto EC = ExternalFS->makeAbsolute(To);
2304 assert(!EC &&
"Could not make absolute path");
2308 auto NewFile = std::make_unique<RedirectingFileSystem::FileEntry>(
2312 ToEntry = NewFile.get();
2314 std::move(NewFile));
2330 getExistingStyle(DRE->getExternalContentsPath()));
2331 ExternalRedirect = std::string(Redirect);
2343std::error_code RedirectingFileSystem::makeCanonicalForLookup(
2345 if (std::error_code EC = makeAbsolute(Path))
2349 canonicalize(
StringRef(Path.data(), Path.size()));
2350 if (CanonicalPath.
empty())
2353 Path.assign(CanonicalPath.
begin(), CanonicalPath.
end());
2360 if (std::error_code EC = makeCanonicalForLookup(CanonicalPath))
2370 for (
const auto &Root : Roots) {
2372 lookupPathImpl(Start, End, Root.get(), Entries);
2376 Result->Parents = std::move(Entries);
2387RedirectingFileSystem::lookupPathImpl(
2393 "Paths should not contain traversal components");
2398 if (!FromName.
empty()) {
2399 if (!pathComponentMatches(*Start, FromName))
2406 return LookupResult(From, Start, End);
2414 return LookupResult(From, Start, End);
2417 for (
const std::unique_ptr<RedirectingFileSystem::Entry> &DirEntry :
2421 lookupPathImpl(Start, End, DirEntry.get(), Entries);
2431 bool UseExternalNames,
2436 return ExternalStatus;
2438 Status S = ExternalStatus;
2439 if (!UseExternalNames)
2446ErrorOr<Status> RedirectingFileSystem::status(
2447 const Twine &LookupPath,
const Twine &OriginalPath,
2448 const RedirectingFileSystem::LookupResult &Result) {
2449 if (std::optional<StringRef> ExtRedirect =
Result.getExternalRedirect()) {
2450 SmallString<256> RemappedPath((*ExtRedirect).str());
2451 if (std::error_code EC = makeAbsolute(RemappedPath))
2454 ErrorOr<Status> S = ExternalFS->status(RemappedPath);
2460 RE->useExternalName(UseExternalNames), *S);
2468RedirectingFileSystem::getExternalStatus(
const Twine &LookupPath,
2469 const Twine &OriginalPath)
const {
2470 auto Result = ExternalFS->status(LookupPath);
2474 if (!Result ||
Result->ExposesExternalVFSPath)
2483 if (std::error_code EC = makeAbsolute(Path))
2499 isFileNotFound(Result.getError()))
2500 return getExternalStatus(Path, OriginalPath);
2501 return Result.getError();
2506 isFileNotFound(S.
getError(), Result->E)) {
2510 return getExternalStatus(Path, OriginalPath);
2520 if (makeAbsolute(Path))
2526 if (ExternalFS->exists(Path))
2535 isFileNotFound(Result.getError()))
2536 return ExternalFS->exists(Path);
2540 std::optional<StringRef> ExtRedirect = Result->getExternalRedirect();
2547 if (makeAbsolute(RemappedPath))
2550 if (ExternalFS->exists(RemappedPath))
2557 return ExternalFS->exists(Path);
2566class FileWithFixedStatus :
public File {
2567 std::unique_ptr<File> InnerFile;
2571 FileWithFixedStatus(std::unique_ptr<File> InnerFile,
Status S)
2577 getBuffer(
const Twine &Name, int64_t FileSize,
bool RequiresNullTerminator,
2578 bool IsVolatile)
override {
2579 return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
2583 std::error_code close()
override {
return InnerFile->close(); }
2585 void setPath(
const Twine &Path)
override { S = S.
copyWithNewName(S, Path); }
2590ErrorOr<std::unique_ptr<File>>
2594 if (!Result || (*Result)->status()->ExposesExternalVFSPath)
2598 auto Name =
F->get()->getName();
2599 if (Name && Name.get() !=
P.str())
2600 F->get()->setPath(
P);
2609 if (std::error_code EC = makeAbsolute(Path))
2625 isFileNotFound(Result.getError()))
2627 return Result.getError();
2630 if (!Result->getExternalRedirect())
2633 StringRef ExtRedirect = *Result->getExternalRedirect();
2635 if (std::error_code EC = makeAbsolute(RemappedPath))
2642 if (!ExternalFile) {
2644 isFileNotFound(ExternalFile.getError(), Result->E)) {
2650 return ExternalFile;
2653 auto ExternalStatus = (*ExternalFile)->status();
2654 if (!ExternalStatus)
2655 return ExternalStatus.getError();
2660 OriginalPath, RE->useExternalName(UseExternalNames), *ExternalStatus);
2661 return std::unique_ptr<File>(
2662 std::make_unique<FileWithFixedStatus>(std::move(*ExternalFile), S));
2671 if (std::error_code EC = makeAbsolute(Path))
2677 std::error_code EC = ExternalFS->getRealPath(Path, Output);
2687 isFileNotFound(Result.getError()))
2688 return ExternalFS->getRealPath(Path, Output);
2689 return Result.getError();
2694 if (
auto ExtRedirect = Result->getExternalRedirect()) {
2695 auto P = ExternalFS->getRealPath(*ExtRedirect, Output);
2697 isFileNotFound(
P, Result->E)) {
2701 return ExternalFS->getRealPath(Path, Output);
2709 Result->getPath(Output);
2720 if (makeAbsolute(Path))
2729 if (ConsultsExternalFS)
2730 ExternalFS->getDirectoryContentRealSources(Path, Out);
2734 switch (Result->E->getKind()) {
2744 if (!makeAbsolute(RemappedPath))
2745 ExternalFS->getDirectoryContentRealSources(RemappedPath, Out);
2751 if (ConsultsExternalFS)
2752 ExternalFS->getDirectoryContentRealSources(Path, Out);
2755std::unique_ptr<FileSystem>
2758 StringRef YAMLFilePath,
void *DiagContext,
2761 YAMLFilePath, DiagContext,
2762 std::move(ExternalFS));
2771 assert(DE &&
"Must be a directory");
2772 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
2774 Path.push_back(SubEntry->getName());
2783 assert(DR &&
"Must be a directory remap");
2785 for (
auto &Comp : Path)
2794 assert(FE &&
"Must be a file");
2796 for (
auto &Comp : Path)
2812 static std::atomic<unsigned> UID;
2813 unsigned ID = ++UID;
2816 return UniqueID(std::numeric_limits<uint64_t>::max(), ID);
2824 Mappings.emplace_back(VirtualPath, RealPath, IsDirectory);
2828 addEntry(VirtualPath, RealPath,
false);
2833 addEntry(VirtualPath, RealPath,
true);
2842 unsigned getDirIndent() {
return 4 * DirStack.
size(); }
2843 unsigned getFileIndent() {
return 4 * (DirStack.
size() + 1); }
2847 void endDirectory();
2854 std::optional<bool> UseExternalNames,
2855 std::optional<bool> IsCaseSensitive,
2856 std::optional<bool> IsOverlayRelative, StringRef OverlayDir);
2861bool JSONWriter::containedIn(StringRef Parent, StringRef Path) {
2862 using namespace llvm::sys;
2867 IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
2868 if (*IParent != *IChild)
2872 return IParent == EParent;
2875StringRef JSONWriter::containedPart(StringRef Parent, StringRef Path) {
2877 assert(containedIn(Parent, Path));
2878 return Path.substr(Parent.
size() + 1);
2881void JSONWriter::startDirectory(StringRef Path) {
2883 DirStack.
empty() ?
Path : containedPart(DirStack.
back(), Path);
2885 unsigned Indent = getDirIndent();
2886 OS.
indent(Indent) <<
"{\n";
2887 OS.
indent(Indent + 2) <<
"'type': 'directory',\n";
2889 OS.
indent(Indent + 2) <<
"'contents': [\n";
2892void JSONWriter::endDirectory() {
2893 unsigned Indent = getDirIndent();
2894 OS.
indent(Indent + 2) <<
"]\n";
2895 OS.
indent(Indent) <<
"}";
2900void JSONWriter::writeEntry(StringRef VPath, StringRef RPath) {
2901 unsigned Indent = getFileIndent();
2902 OS.
indent(Indent) <<
"{\n";
2903 OS.
indent(Indent + 2) <<
"'type': 'file',\n";
2905 OS.
indent(Indent + 2) <<
"'external-contents': \""
2907 OS.
indent(Indent) <<
"}";
2911 std::optional<bool> UseExternalNames,
2912 std::optional<bool> IsCaseSensitive,
2913 std::optional<bool> IsOverlayRelative,
2915 using namespace llvm::sys;
2919 if (IsCaseSensitive)
2920 OS <<
" 'case-sensitive': '" << (*IsCaseSensitive ?
"true" :
"false")
2922 if (UseExternalNames)
2923 OS <<
" 'use-external-names': '" << (*UseExternalNames ?
"true" :
"false")
2925 bool UseOverlayRelative =
false;
2926 if (IsOverlayRelative) {
2927 UseOverlayRelative = *IsOverlayRelative;
2928 OS <<
" 'overlay-relative': '" << (UseOverlayRelative ?
"true" :
"false")
2931 OS <<
" 'roots': [\n";
2933 if (!Entries.
empty()) {
2941 if (UseOverlayRelative) {
2943 "Overlay dir must be contained in RPath");
2947 bool IsCurrentDirEmpty =
true;
2948 if (!
Entry.IsDirectory) {
2950 IsCurrentDirEmpty =
false;
2956 if (Dir == DirStack.
back()) {
2957 if (!IsCurrentDirEmpty) {
2961 bool IsDirPoppedFromStack =
false;
2962 while (!DirStack.
empty() && !containedIn(DirStack.
back(), Dir)) {
2965 IsDirPoppedFromStack =
true;
2967 if (IsDirPoppedFromStack || !IsCurrentDirEmpty) {
2970 startDirectory(Dir);
2971 IsCurrentDirEmpty =
true;
2974 if (UseOverlayRelative) {
2976 "Overlay dir must be contained in RPath");
2979 if (!
Entry.IsDirectory) {
2981 IsCurrentDirEmpty =
false;
2985 while (!DirStack.
empty()) {
2998 return LHS.VPath < RHS.VPath;
3001 JSONWriter(OS).
write(Mappings, UseExternalNames, IsCaseSensitive,
3002 IsOverlayRelative, OverlayDir);
3010 State = std::make_shared<detail::RecDirIterState>();
3011 State->Stack.push_back(
I);
3017 assert(FS && State && !State->Stack.empty() &&
"incrementing past end");
3018 assert(!State->Stack.back()->path().empty() &&
"non-canonical end iterator");
3021 if (State->HasNoPushRequest)
3022 State->HasNoPushRequest =
false;
3026 FS->dir_begin(State->Stack.back()->path(), EC);
3028 State->Stack.push_back(
I);
3034 while (!State->Stack.empty() && State->Stack.back().increment(EC) == End)
3035 State->Stack.pop_back();
3037 if (State->Stack.empty())
3049unsigned ::llvm::IntrusiveRefCntPtrInfo<FileSystem>::useCount(
3051 return FS->UseCount();
3054void ::llvm::IntrusiveRefCntPtrInfo<FileSystem>::retain(
FileSystem *FS) {
3058void ::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
void getDirectoryContentRealSources(const Twine &Dir, SmallVectorImpl< std::string > &Out) 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
void getDirectoryContentRealSources(const Twine &Dir, SmallVectorImpl< std::string > &Out) override
Collect the paths in the real file system that contribute to a potentially virtual directory when ite...
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