LLVM  15.0.0git
VirtualFileSystem.cpp
Go to the documentation of this file.
1 //===- VirtualFileSystem.cpp - Virtual File System Layer ------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the VirtualFileSystem interface.
10 //
11 //===----------------------------------------------------------------------===//
12 
14 #include "llvm/ADT/ArrayRef.h"
15 #include "llvm/ADT/DenseMap.h"
17 #include "llvm/ADT/None.h"
18 #include "llvm/ADT/Optional.h"
19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/ADT/SmallString.h"
21 #include "llvm/ADT/SmallVector.h"
22 #include "llvm/ADT/StringRef.h"
23 #include "llvm/ADT/StringSet.h"
24 #include "llvm/ADT/Twine.h"
26 #include "llvm/Config/llvm-config.h"
27 #include "llvm/Support/Casting.h"
28 #include "llvm/Support/Chrono.h"
29 #include "llvm/Support/Compiler.h"
30 #include "llvm/Support/Debug.h"
31 #include "llvm/Support/Errc.h"
33 #include "llvm/Support/ErrorOr.h"
37 #include "llvm/Support/Path.h"
38 #include "llvm/Support/SMLoc.h"
39 #include "llvm/Support/SourceMgr.h"
42 #include <algorithm>
43 #include <atomic>
44 #include <cassert>
45 #include <cstdint>
46 #include <iterator>
47 #include <limits>
48 #include <memory>
49 #include <string>
50 #include <system_error>
51 #include <utility>
52 #include <vector>
53 
54 using namespace llvm;
55 using namespace llvm::vfs;
56 
63 
65  : UID(Status.getUniqueID()), MTime(Status.getLastModificationTime()),
66  User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()),
67  Type(Status.type()), Perms(Status.permissions()) {}
68 
71  perms Perms)
72  : Name(Name.str()), UID(UID), MTime(MTime), User(User), Group(Group),
73  Size(Size), Type(Type), Perms(Perms) {}
74 
76  return Status(In.getName(), In.getUniqueID(), In.getLastModificationTime(),
77  In.getUser(), In.getGroup(), NewSize, In.getType(),
78  In.getPermissions());
79 }
80 
81 Status Status::copyWithNewName(const Status &In, const Twine &NewName) {
82  return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
83  In.getUser(), In.getGroup(), In.getSize(), In.getType(),
84  In.getPermissions());
85 }
86 
88  return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
89  In.getUser(), In.getGroup(), In.getSize(), In.type(),
90  In.permissions());
91 }
92 
93 bool Status::equivalent(const Status &Other) const {
94  assert(isStatusKnown() && Other.isStatusKnown());
95  return getUniqueID() == Other.getUniqueID();
96 }
97 
98 bool Status::isDirectory() const { return Type == file_type::directory_file; }
99 
100 bool Status::isRegularFile() const { return Type == file_type::regular_file; }
101 
102 bool Status::isOther() const {
103  return exists() && !isRegularFile() && !isDirectory() && !isSymlink();
104 }
105 
106 bool Status::isSymlink() const { return Type == file_type::symlink_file; }
107 
108 bool Status::isStatusKnown() const { return Type != file_type::status_error; }
109 
110 bool Status::exists() const {
111  return isStatusKnown() && Type != file_type::file_not_found;
112 }
113 
114 File::~File() = default;
115 
116 FileSystem::~FileSystem() = default;
117 
120  bool RequiresNullTerminator, bool IsVolatile) {
121  auto F = openFileForRead(Name);
122  if (!F)
123  return F.getError();
124 
125  return (*F)->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile);
126 }
127 
128 std::error_code FileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const {
130  return {};
131 
132  auto WorkingDir = getCurrentWorkingDirectory();
133  if (!WorkingDir)
134  return WorkingDir.getError();
135 
136  llvm::sys::fs::make_absolute(WorkingDir.get(), Path);
137  return {};
138 }
139 
140 std::error_code FileSystem::getRealPath(const Twine &Path,
141  SmallVectorImpl<char> &Output) const {
143 }
144 
145 std::error_code FileSystem::isLocal(const Twine &Path, bool &Result) {
147 }
148 
149 bool FileSystem::exists(const Twine &Path) {
150  auto Status = status(Path);
151  return Status && Status->exists();
152 }
153 
154 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
156 #endif
157 
158 #ifndef NDEBUG
159 static bool isTraversalComponent(StringRef Component) {
160  return Component.equals("..") || Component.equals(".");
161 }
162 
163 static bool pathHasTraversal(StringRef Path) {
164  using namespace llvm::sys;
165 
166  for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path)))
167  if (isTraversalComponent(Comp))
168  return true;
169  return false;
170 }
171 #endif
172 
173 //===-----------------------------------------------------------------------===/
174 // RealFileSystem implementation
175 //===-----------------------------------------------------------------------===/
176 
177 namespace {
178 
179 /// Wrapper around a raw file descriptor.
180 class RealFile : public File {
181  friend class RealFileSystem;
182 
183  file_t FD;
184  Status S;
185  std::string RealName;
186 
187  RealFile(file_t RawFD, StringRef NewName, StringRef NewRealPathName)
188  : FD(RawFD), S(NewName, {}, {}, {}, {}, {},
190  RealName(NewRealPathName.str()) {
191  assert(FD != kInvalidFile && "Invalid or inactive file descriptor");
192  }
193 
194 public:
195  ~RealFile() override;
196 
197  ErrorOr<Status> status() override;
198  ErrorOr<std::string> getName() override;
200  int64_t FileSize,
201  bool RequiresNullTerminator,
202  bool IsVolatile) override;
203  std::error_code close() override;
204  void setPath(const Twine &Path) override;
205 };
206 
207 } // namespace
208 
209 RealFile::~RealFile() { close(); }
210 
212  assert(FD != kInvalidFile && "cannot stat closed file");
213  if (!S.isStatusKnown()) {
214  file_status RealStatus;
215  if (std::error_code EC = sys::fs::status(FD, RealStatus))
216  return EC;
217  S = Status::copyWithNewName(RealStatus, S.getName());
218  }
219  return S;
220 }
221 
223  return RealName.empty() ? S.getName().str() : RealName;
224 }
225 
227 RealFile::getBuffer(const Twine &Name, int64_t FileSize,
228  bool RequiresNullTerminator, bool IsVolatile) {
229  assert(FD != kInvalidFile && "cannot get buffer for closed file");
230  return MemoryBuffer::getOpenFile(FD, Name, FileSize, RequiresNullTerminator,
231  IsVolatile);
232 }
233 
234 std::error_code RealFile::close() {
235  std::error_code EC = sys::fs::closeFile(FD);
236  FD = kInvalidFile;
237  return EC;
238 }
239 
240 void RealFile::setPath(const Twine &Path) {
241  RealName = Path.str();
242  if (auto Status = status())
243  S = Status.get().copyWithNewName(Status.get(), Path);
244 }
245 
246 namespace {
247 
248 /// A file system according to your operating system.
249 /// This may be linked to the process's working directory, or maintain its own.
250 ///
251 /// Currently, its own working directory is emulated by storing the path and
252 /// sending absolute paths to llvm::sys::fs:: functions.
253 /// A more principled approach would be to push this down a level, modelling
254 /// the working dir as an llvm::sys::fs::WorkingDir or similar.
255 /// This would enable the use of openat()-style functions on some platforms.
256 class RealFileSystem : public FileSystem {
257 public:
258  explicit RealFileSystem(bool LinkCWDToProcess) {
259  if (!LinkCWDToProcess) {
260  SmallString<128> PWD, RealPWD;
262  return; // Awful, but nothing to do here.
263  if (llvm::sys::fs::real_path(PWD, RealPWD))
264  WD = {PWD, PWD};
265  else
266  WD = {PWD, RealPWD};
267  }
268  }
269 
270  ErrorOr<Status> status(const Twine &Path) override;
271  ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
272  directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
273 
274  llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override;
275  std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
276  std::error_code isLocal(const Twine &Path, bool &Result) override;
277  std::error_code getRealPath(const Twine &Path,
278  SmallVectorImpl<char> &Output) const override;
279 
280 protected:
281  void printImpl(raw_ostream &OS, PrintType Type,
282  unsigned IndentLevel) const override;
283 
284 private:
285  // If this FS has its own working dir, use it to make Path absolute.
286  // The returned twine is safe to use as long as both Storage and Path live.
287  Twine adjustPath(const Twine &Path, SmallVectorImpl<char> &Storage) const {
288  if (!WD)
289  return Path;
290  Path.toVector(Storage);
291  sys::fs::make_absolute(WD->Resolved, Storage);
292  return Storage;
293  }
294 
295  struct WorkingDirectory {
296  // The current working directory, without symlinks resolved. (echo $PWD).
297  SmallString<128> Specified;
298  // The current working directory, with links resolved. (readlink .).
300  };
302 };
303 
304 } // namespace
305 
307  SmallString<256> Storage;
308  sys::fs::file_status RealStatus;
309  if (std::error_code EC =
310  sys::fs::status(adjustPath(Path, Storage), RealStatus))
311  return EC;
312  return Status::copyWithNewName(RealStatus, Path);
313 }
314 
317  SmallString<256> RealName, Storage;
319  adjustPath(Name, Storage), sys::fs::OF_None, &RealName);
320  if (!FDOrErr)
321  return errorToErrorCode(FDOrErr.takeError());
322  return std::unique_ptr<File>(
323  new RealFile(*FDOrErr, Name.str(), RealName.str()));
324 }
325 
326 llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory() const {
327  if (WD)
328  return std::string(WD->Specified.str());
329 
330  SmallString<128> Dir;
331  if (std::error_code EC = llvm::sys::fs::current_path(Dir))
332  return EC;
333  return std::string(Dir.str());
334 }
335 
336 std::error_code RealFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
337  if (!WD)
338  return llvm::sys::fs::set_current_path(Path);
339 
341  adjustPath(Path, Storage).toVector(Absolute);
342  bool IsDir;
343  if (auto Err = llvm::sys::fs::is_directory(Absolute, IsDir))
344  return Err;
345  if (!IsDir)
346  return std::make_error_code(std::errc::not_a_directory);
347  if (auto Err = llvm::sys::fs::real_path(Absolute, Resolved))
348  return Err;
349  WD = {Absolute, Resolved};
350  return std::error_code();
351 }
352 
353 std::error_code RealFileSystem::isLocal(const Twine &Path, bool &Result) {
354  SmallString<256> Storage;
355  return llvm::sys::fs::is_local(adjustPath(Path, Storage), Result);
356 }
357 
358 std::error_code
359 RealFileSystem::getRealPath(const Twine &Path,
360  SmallVectorImpl<char> &Output) const {
361  SmallString<256> Storage;
362  return llvm::sys::fs::real_path(adjustPath(Path, Storage), Output);
363 }
364 
365 void RealFileSystem::printImpl(raw_ostream &OS, PrintType Type,
366  unsigned IndentLevel) const {
367  printIndent(OS, IndentLevel);
368  OS << "RealFileSystem using ";
369  if (WD)
370  OS << "own";
371  else
372  OS << "process";
373  OS << " CWD\n";
374 }
375 
377  static IntrusiveRefCntPtr<FileSystem> FS(new RealFileSystem(true));
378  return FS;
379 }
380 
381 std::unique_ptr<FileSystem> vfs::createPhysicalFileSystem() {
382  return std::make_unique<RealFileSystem>(false);
383 }
384 
385 namespace {
386 
387 class RealFSDirIter : public llvm::vfs::detail::DirIterImpl {
389 
390 public:
391  RealFSDirIter(const Twine &Path, std::error_code &EC) : Iter(Path, EC) {
392  if (Iter != llvm::sys::fs::directory_iterator())
393  CurrentEntry = directory_entry(Iter->path(), Iter->type());
394  }
395 
396  std::error_code increment() override {
397  std::error_code EC;
398  Iter.increment(EC);
399  CurrentEntry = (Iter == llvm::sys::fs::directory_iterator())
400  ? directory_entry()
401  : directory_entry(Iter->path(), Iter->type());
402  return EC;
403  }
404 };
405 
406 } // namespace
407 
408 directory_iterator RealFileSystem::dir_begin(const Twine &Dir,
409  std::error_code &EC) {
410  SmallString<128> Storage;
411  return directory_iterator(
412  std::make_shared<RealFSDirIter>(adjustPath(Dir, Storage), EC));
413 }
414 
415 //===-----------------------------------------------------------------------===/
416 // OverlayFileSystem implementation
417 //===-----------------------------------------------------------------------===/
418 
420  FSList.push_back(std::move(BaseFS));
421 }
422 
424  FSList.push_back(FS);
425  // Synchronize added file systems by duplicating the working directory from
426  // the first one in the list.
427  FS->setCurrentWorkingDirectory(getCurrentWorkingDirectory().get());
428 }
429 
431  // FIXME: handle symlinks that cross file systems
432  for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
433  ErrorOr<Status> Status = (*I)->status(Path);
435  return Status;
436  }
438 }
439 
442  // FIXME: handle symlinks that cross file systems
443  for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
444  auto Result = (*I)->openFileForRead(Path);
445  if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
446  return Result;
447  }
449 }
450 
453  // All file systems are synchronized, just take the first working directory.
454  return FSList.front()->getCurrentWorkingDirectory();
455 }
456 
457 std::error_code
459  for (auto &FS : FSList)
460  if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))
461  return EC;
462  return {};
463 }
464 
465 std::error_code OverlayFileSystem::isLocal(const Twine &Path, bool &Result) {
466  for (auto &FS : FSList)
467  if (FS->exists(Path))
468  return FS->isLocal(Path, Result);
470 }
471 
472 std::error_code
474  SmallVectorImpl<char> &Output) const {
475  for (const auto &FS : FSList)
476  if (FS->exists(Path))
477  return FS->getRealPath(Path, Output);
479 }
480 
482  unsigned IndentLevel) const {
483  printIndent(OS, IndentLevel);
484  OS << "OverlayFileSystem\n";
485  if (Type == PrintType::Summary)
486  return;
487 
488  if (Type == PrintType::Contents)
490  for (auto FS : overlays_range())
491  FS->print(OS, Type, IndentLevel + 1);
492 }
493 
495 
496 namespace {
497 
498 /// Combines and deduplicates directory entries across multiple file systems.
499 class CombiningDirIterImpl : public llvm::vfs::detail::DirIterImpl {
501 
502  /// Iterators to combine, processed in reverse order.
504  /// The iterator currently being traversed.
505  directory_iterator CurrentDirIter;
506  /// The set of names already returned as entries.
507  llvm::StringSet<> SeenNames;
508 
509  /// Sets \c CurrentDirIter to the next iterator in the list, or leaves it as
510  /// is (at its end position) if we've already gone through them all.
511  std::error_code incrementIter(bool IsFirstTime) {
512  while (!IterList.empty()) {
513  CurrentDirIter = IterList.back();
514  IterList.pop_back();
515  if (CurrentDirIter != directory_iterator())
516  break; // found
517  }
518 
519  if (IsFirstTime && CurrentDirIter == directory_iterator())
521  return {};
522  }
523 
524  std::error_code incrementDirIter(bool IsFirstTime) {
525  assert((IsFirstTime || CurrentDirIter != directory_iterator()) &&
526  "incrementing past end");
527  std::error_code EC;
528  if (!IsFirstTime)
529  CurrentDirIter.increment(EC);
530  if (!EC && CurrentDirIter == directory_iterator())
531  EC = incrementIter(IsFirstTime);
532  return EC;
533  }
534 
535  std::error_code incrementImpl(bool IsFirstTime) {
536  while (true) {
537  std::error_code EC = incrementDirIter(IsFirstTime);
538  if (EC || CurrentDirIter == directory_iterator()) {
539  CurrentEntry = directory_entry();
540  return EC;
541  }
542  CurrentEntry = *CurrentDirIter;
543  StringRef Name = llvm::sys::path::filename(CurrentEntry.path());
544  if (SeenNames.insert(Name).second)
545  return EC; // name not seen before
546  }
547  llvm_unreachable("returned above");
548  }
549 
550 public:
551  CombiningDirIterImpl(ArrayRef<FileSystemPtr> FileSystems, std::string Dir,
552  std::error_code &EC) {
553  for (auto FS : FileSystems) {
554  std::error_code FEC;
555  directory_iterator Iter = FS->dir_begin(Dir, FEC);
556  if (FEC && FEC != errc::no_such_file_or_directory) {
557  EC = FEC;
558  return;
559  }
560  if (!FEC)
561  IterList.push_back(Iter);
562  }
563  EC = incrementImpl(true);
564  }
565 
566  CombiningDirIterImpl(ArrayRef<directory_iterator> DirIters,
567  std::error_code &EC)
568  : IterList(DirIters.begin(), DirIters.end()) {
569  EC = incrementImpl(true);
570  }
571 
572  std::error_code increment() override { return incrementImpl(false); }
573 };
574 
575 } // namespace
576 
578  std::error_code &EC) {
580  std::make_shared<CombiningDirIterImpl>(FSList, Dir.str(), EC));
581  if (EC)
582  return {};
583  return Combined;
584 }
585 
586 void ProxyFileSystem::anchor() {}
587 
588 namespace llvm {
589 namespace vfs {
590 
591 namespace detail {
592 
598 };
599 
600 /// The in memory file system is a tree of Nodes. Every node can either be a
601 /// file, symlink, hardlink or a directory.
604  std::string FileName;
605 
606 public:
608  : Kind(Kind), FileName(std::string(llvm::sys::path::filename(FileName))) {
609  }
610  virtual ~InMemoryNode() = default;
611 
612  /// Return the \p Status for this node. \p RequestedName should be the name
613  /// through which the caller referred to this node. It will override
614  /// \p Status::Name in the return value, to mimic the behavior of \p RealFile.
615  virtual Status getStatus(const Twine &RequestedName) const = 0;
616 
617  /// Get the filename of this node (the name without the directory part).
618  StringRef getFileName() const { return FileName; }
619  InMemoryNodeKind getKind() const { return Kind; }
620  virtual std::string toString(unsigned Indent) const = 0;
621 };
622 
623 class InMemoryFile : public InMemoryNode {
624  Status Stat;
625  std::unique_ptr<llvm::MemoryBuffer> Buffer;
626 
627 public:
628  InMemoryFile(Status Stat, std::unique_ptr<llvm::MemoryBuffer> Buffer)
629  : InMemoryNode(Stat.getName(), IME_File), Stat(std::move(Stat)),
630  Buffer(std::move(Buffer)) {}
631 
632  Status getStatus(const Twine &RequestedName) const override {
633  return Status::copyWithNewName(Stat, RequestedName);
634  }
635  llvm::MemoryBuffer *getBuffer() const { return Buffer.get(); }
636 
637  std::string toString(unsigned Indent) const override {
638  return (std::string(Indent, ' ') + Stat.getName() + "\n").str();
639  }
640 
641  static bool classof(const InMemoryNode *N) {
642  return N->getKind() == IME_File;
643  }
644 };
645 
646 namespace {
647 
648 class InMemoryHardLink : public InMemoryNode {
649  const InMemoryFile &ResolvedFile;
650 
651 public:
652  InMemoryHardLink(StringRef Path, const InMemoryFile &ResolvedFile)
653  : InMemoryNode(Path, IME_HardLink), ResolvedFile(ResolvedFile) {}
654  const InMemoryFile &getResolvedFile() const { return ResolvedFile; }
655 
656  Status getStatus(const Twine &RequestedName) const override {
657  return ResolvedFile.getStatus(RequestedName);
658  }
659 
660  std::string toString(unsigned Indent) const override {
661  return std::string(Indent, ' ') + "HardLink to -> " +
662  ResolvedFile.toString(0);
663  }
664 
665  static bool classof(const InMemoryNode *N) {
666  return N->getKind() == IME_HardLink;
667  }
668 };
669 
670 class InMemorySymbolicLink : public InMemoryNode {
671  std::string TargetPath;
672  Status Stat;
673 
674 public:
675  InMemorySymbolicLink(StringRef Path, StringRef TargetPath, Status Stat)
676  : InMemoryNode(Path, IME_SymbolicLink), TargetPath(std::move(TargetPath)),
677  Stat(Stat) {}
678 
679  std::string toString(unsigned Indent) const override {
680  return std::string(Indent, ' ') + "SymbolicLink to -> " + TargetPath;
681  }
682 
683  Status getStatus(const Twine &RequestedName) const override {
684  return Status::copyWithNewName(Stat, RequestedName);
685  }
686 
687  StringRef getTargetPath() const { return TargetPath; }
688 
689  static bool classof(const InMemoryNode *N) {
690  return N->getKind() == IME_SymbolicLink;
691  }
692 };
693 
694 /// Adapt a InMemoryFile for VFS' File interface. The goal is to make
695 /// \p InMemoryFileAdaptor mimic as much as possible the behavior of
696 /// \p RealFile.
697 class InMemoryFileAdaptor : public File {
698  const InMemoryFile &Node;
699  /// The name to use when returning a Status for this file.
700  std::string RequestedName;
701 
702 public:
703  explicit InMemoryFileAdaptor(const InMemoryFile &Node,
704  std::string RequestedName)
705  : Node(Node), RequestedName(std::move(RequestedName)) {}
706 
707  llvm::ErrorOr<Status> status() override {
708  return Node.getStatus(RequestedName);
709  }
710 
712  getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
713  bool IsVolatile) override {
714  llvm::MemoryBuffer *Buf = Node.getBuffer();
716  Buf->getBuffer(), Buf->getBufferIdentifier(), RequiresNullTerminator);
717  }
718 
719  std::error_code close() override { return {}; }
720 
721  void setPath(const Twine &Path) override { RequestedName = Path.str(); }
722 };
723 } // namespace
724 
726  Status Stat;
728 
729 public:
731  : InMemoryNode(Stat.getName(), IME_Directory), Stat(std::move(Stat)) {}
732 
733  /// Return the \p Status for this node. \p RequestedName should be the name
734  /// through which the caller referred to this node. It will override
735  /// \p Status::Name in the return value, to mimic the behavior of \p RealFile.
736  Status getStatus(const Twine &RequestedName) const override {
737  return Status::copyWithNewName(Stat, RequestedName);
738  }
739 
740  UniqueID getUniqueID() const { return Stat.getUniqueID(); }
741 
743  auto I = Entries.find(Name);
744  if (I != Entries.end())
745  return I->second.get();
746  return nullptr;
747  }
748 
749  InMemoryNode *addChild(StringRef Name, std::unique_ptr<InMemoryNode> Child) {
750  return Entries.insert(make_pair(Name, std::move(Child)))
751  .first->second.get();
752  }
753 
754  using const_iterator = decltype(Entries)::const_iterator;
755 
756  const_iterator begin() const { return Entries.begin(); }
757  const_iterator end() const { return Entries.end(); }
758 
759  std::string toString(unsigned Indent) const override {
760  std::string Result =
761  (std::string(Indent, ' ') + Stat.getName() + "\n").str();
762  for (const auto &Entry : Entries)
763  Result += Entry.second->toString(Indent + 2);
764  return Result;
765  }
766 
767  static bool classof(const InMemoryNode *N) {
768  return N->getKind() == IME_Directory;
769  }
770 };
771 
772 } // namespace detail
773 
774 // The UniqueID of in-memory files is derived from path and content.
775 // This avoids difficulties in creating exactly equivalent in-memory FSes,
776 // as often needed in multithreaded programs.
779  uint64_t(size_t(Hash)));
780 }
783  llvm::StringRef Contents) {
784  return getUniqueID(llvm::hash_combine(Parent.getFile(), Name, Contents));
785 }
788  return getUniqueID(llvm::hash_combine(Parent.getFile(), Name));
789 }
790 
792  UniqueID UID =
794  ? getDirectoryID(DirUID, Name)
795  : getFileID(DirUID, Name, Buffer ? Buffer->getBuffer() : "");
796 
797  return Status(Path, UID, llvm::sys::toTimePoint(ModificationTime), User,
798  Group, Buffer ? Buffer->getBufferSize() : 0, Type, Perms);
799 }
800 
802  : Root(new detail::InMemoryDirectory(
803  Status("", getDirectoryID(llvm::sys::fs::UniqueID(), ""),
804  llvm::sys::TimePoint<>(), 0, 0, 0,
805  llvm::sys::fs::file_type::directory_file,
806  llvm::sys::fs::perms::all_all))),
807  UseNormalizedPaths(UseNormalizedPaths) {}
808 
810 
811 std::string InMemoryFileSystem::toString() const {
812  return Root->toString(/*Indent=*/0);
813 }
814 
815 bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
816  std::unique_ptr<llvm::MemoryBuffer> Buffer,
818  Optional<uint32_t> Group,
821  MakeNodeFn MakeNode) {
822  SmallString<128> Path;
823  P.toVector(Path);
824 
825  // Fix up relative paths. This just prepends the current working directory.
826  std::error_code EC = makeAbsolute(Path);
827  assert(!EC);
828  (void)EC;
829 
830  if (useNormalizedPaths())
831  llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
832 
833  if (Path.empty())
834  return false;
835 
836  detail::InMemoryDirectory *Dir = Root.get();
837  auto I = llvm::sys::path::begin(Path), E = sys::path::end(Path);
838  const auto ResolvedUser = User.value_or(0);
839  const auto ResolvedGroup = Group.value_or(0);
840  const auto ResolvedType = Type.value_or(sys::fs::file_type::regular_file);
841  const auto ResolvedPerms = Perms.value_or(sys::fs::all_all);
842  // Any intermediate directories we create should be accessible by
843  // the owner, even if Perms says otherwise for the final path.
844  const auto NewDirectoryPerms = ResolvedPerms | sys::fs::owner_all;
845  while (true) {
846  StringRef Name = *I;
847  detail::InMemoryNode *Node = Dir->getChild(Name);
848  ++I;
849  if (!Node) {
850  if (I == E) {
851  // End of the path.
852  Dir->addChild(
853  Name, MakeNode({Dir->getUniqueID(), Path, Name, ModificationTime,
854  std::move(Buffer), ResolvedUser, ResolvedGroup,
855  ResolvedType, ResolvedPerms}));
856  return true;
857  }
858 
859  // Create a new directory. Use the path up to here.
860  Status Stat(
861  StringRef(Path.str().begin(), Name.end() - Path.str().begin()),
863  llvm::sys::toTimePoint(ModificationTime), ResolvedUser, ResolvedGroup,
864  0, sys::fs::file_type::directory_file, NewDirectoryPerms);
865  Dir = cast<detail::InMemoryDirectory>(Dir->addChild(
866  Name, std::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
867  continue;
868  }
869 
870  if (auto *NewDir = dyn_cast<detail::InMemoryDirectory>(Node)) {
871  Dir = NewDir;
872  } else {
873  assert((isa<detail::InMemoryFile>(Node) ||
874  isa<detail::InMemoryHardLink>(Node)) &&
875  "Must be either file, hardlink or directory!");
876 
877  // Trying to insert a directory in place of a file.
878  if (I != E)
879  return false;
880 
881  // Return false only if the new file is different from the existing one.
882  if (auto Link = dyn_cast<detail::InMemoryHardLink>(Node)) {
883  return Link->getResolvedFile().getBuffer()->getBuffer() ==
884  Buffer->getBuffer();
885  }
886  return cast<detail::InMemoryFile>(Node)->getBuffer()->getBuffer() ==
887  Buffer->getBuffer();
888  }
889  }
890 }
891 
892 bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
893  std::unique_ptr<llvm::MemoryBuffer> Buffer,
895  Optional<uint32_t> Group,
898  return addFile(P, ModificationTime, std::move(Buffer), User, Group, Type,
899  Perms,
901  -> std::unique_ptr<detail::InMemoryNode> {
902  Status Stat = NNI.makeStatus();
904  return std::make_unique<detail::InMemoryDirectory>(Stat);
905  return std::make_unique<detail::InMemoryFile>(
906  Stat, std::move(NNI.Buffer));
907  });
908 }
909 
910 bool InMemoryFileSystem::addFileNoOwn(const Twine &P, time_t ModificationTime,
911  const llvm::MemoryBufferRef &Buffer,
913  Optional<uint32_t> Group,
916  return addFile(P, ModificationTime, llvm::MemoryBuffer::getMemBuffer(Buffer),
918  std::move(Perms),
920  -> std::unique_ptr<detail::InMemoryNode> {
921  Status Stat = NNI.makeStatus();
923  return std::make_unique<detail::InMemoryDirectory>(Stat);
924  return std::make_unique<detail::InMemoryFile>(
925  Stat, std::move(NNI.Buffer));
926  });
927 }
928 
930 InMemoryFileSystem::lookupNode(const Twine &P, bool FollowFinalSymlink,
931  size_t SymlinkDepth) const {
932  SmallString<128> Path;
933  P.toVector(Path);
934 
935  // Fix up relative paths. This just prepends the current working directory.
936  std::error_code EC = makeAbsolute(Path);
937  assert(!EC);
938  (void)EC;
939 
940  if (useNormalizedPaths())
941  llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
942 
943  const detail::InMemoryDirectory *Dir = Root.get();
944  if (Path.empty())
945  return detail::NamedNodeOrError(Path, Dir);
946 
947  auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path);
948  while (true) {
949  detail::InMemoryNode *Node = Dir->getChild(*I);
950  ++I;
951  if (!Node)
953 
954  if (auto Symlink = dyn_cast<detail::InMemorySymbolicLink>(Node)) {
955  // If we're at the end of the path, and we're not following through
956  // terminal symlinks, then we're done.
957  if (I == E && !FollowFinalSymlink)
958  return detail::NamedNodeOrError(Path, Symlink);
959 
960  if (SymlinkDepth > InMemoryFileSystem::MaxSymlinkDepth)
962 
963  SmallString<128> TargetPath = Symlink->getTargetPath();
964  if (std::error_code EC = makeAbsolute(TargetPath))
965  return EC;
966 
967  // Keep going with the target. We always want to follow symlinks here
968  // because we're either at the end of a path that we want to follow, or
969  // not at the end of a path, in which case we need to follow the symlink
970  // regardless.
971  auto Target =
972  lookupNode(TargetPath, /*FollowFinalSymlink=*/true, SymlinkDepth + 1);
973  if (!Target || I == E)
974  return Target;
975 
976  if (!isa<detail::InMemoryDirectory>(*Target))
978 
979  // Otherwise, continue on the search in the symlinked directory.
980  Dir = cast<detail::InMemoryDirectory>(*Target);
981  continue;
982  }
983 
984  // Return the file if it's at the end of the path.
985  if (auto File = dyn_cast<detail::InMemoryFile>(Node)) {
986  if (I == E)
987  return detail::NamedNodeOrError(Path, File);
989  }
990 
991  // If Node is HardLink then return the resolved file.
992  if (auto File = dyn_cast<detail::InMemoryHardLink>(Node)) {
993  if (I == E)
994  return detail::NamedNodeOrError(Path, &File->getResolvedFile());
996  }
997  // Traverse directories.
998  Dir = cast<detail::InMemoryDirectory>(Node);
999  if (I == E)
1000  return detail::NamedNodeOrError(Path, Dir);
1001  }
1002 }
1003 
1005  const Twine &Target) {
1006  auto NewLinkNode = lookupNode(NewLink, /*FollowFinalSymlink=*/false);
1007  // Whether symlinks in the hardlink target are followed is
1008  // implementation-defined in POSIX.
1009  // We're following symlinks here to be consistent with macOS.
1010  auto TargetNode = lookupNode(Target, /*FollowFinalSymlink=*/true);
1011  // FromPath must not have been added before. ToPath must have been added
1012  // before. Resolved ToPath must be a File.
1013  if (!TargetNode || NewLinkNode || !isa<detail::InMemoryFile>(*TargetNode))
1014  return false;
1015  return addFile(NewLink, 0, nullptr, None, None, None, None,
1016  [&](detail::NewInMemoryNodeInfo NNI) {
1017  return std::make_unique<detail::InMemoryHardLink>(
1018  NNI.Path.str(),
1019  *cast<detail::InMemoryFile>(*TargetNode));
1020  });
1021 }
1022 
1024  const Twine &Target,
1025  time_t ModificationTime,
1027  Optional<uint32_t> Group,
1029  auto NewLinkNode = lookupNode(NewLink, /*FollowFinalSymlink=*/false);
1030  if (NewLinkNode)
1031  return false;
1032 
1033  SmallString<128> NewLinkStr, TargetStr;
1034  NewLink.toVector(NewLinkStr);
1035  Target.toVector(TargetStr);
1036 
1037  return addFile(NewLinkStr, ModificationTime, nullptr, User, Group,
1039  [&](detail::NewInMemoryNodeInfo NNI) {
1040  return std::make_unique<detail::InMemorySymbolicLink>(
1041  NewLinkStr, TargetStr, NNI.makeStatus());
1042  });
1043 }
1044 
1046  auto Node = lookupNode(Path, /*FollowFinalSymlink=*/true);
1047  if (Node)
1048  return (*Node)->getStatus(Path);
1049  return Node.getError();
1050 }
1051 
1054  auto Node = lookupNode(Path,/*FollowFinalSymlink=*/true);
1055  if (!Node)
1056  return Node.getError();
1057 
1058  // When we have a file provide a heap-allocated wrapper for the memory buffer
1059  // to match the ownership semantics for File.
1060  if (auto *F = dyn_cast<detail::InMemoryFile>(*Node))
1061  return std::unique_ptr<File>(
1062  new detail::InMemoryFileAdaptor(*F, Path.str()));
1063 
1064  // FIXME: errc::not_a_file?
1066 }
1067 
1068 /// Adaptor from InMemoryDir::iterator to directory_iterator.
1070  const InMemoryFileSystem *FS;
1073  std::string RequestedDirName;
1074 
1075  void setCurrentEntry() {
1076  if (I != E) {
1077  SmallString<256> Path(RequestedDirName);
1078  llvm::sys::path::append(Path, I->second->getFileName());
1080  switch (I->second->getKind()) {
1081  case detail::IME_File:
1082  case detail::IME_HardLink:
1084  break;
1085  case detail::IME_Directory:
1087  break;
1089  if (auto SymlinkTarget =
1090  FS->lookupNode(Path, /*FollowFinalSymlink=*/true)) {
1091  Path = SymlinkTarget.getName();
1092  Type = (*SymlinkTarget)->getStatus(Path).getType();
1093  }
1094  break;
1095  }
1096  CurrentEntry = directory_entry(std::string(Path.str()), Type);
1097  } else {
1098  // When we're at the end, make CurrentEntry invalid and DirIterImpl will
1099  // do the rest.
1101  }
1102  }
1103 
1104 public:
1105  DirIterator() = default;
1106 
1108  const detail::InMemoryDirectory &Dir,
1109  std::string RequestedDirName)
1110  : FS(FS), I(Dir.begin()), E(Dir.end()),
1111  RequestedDirName(std::move(RequestedDirName)) {
1112  setCurrentEntry();
1113  }
1114 
1115  std::error_code increment() override {
1116  ++I;
1117  setCurrentEntry();
1118  return {};
1119  }
1120 };
1121 
1123  std::error_code &EC) {
1124  auto Node = lookupNode(Dir, /*FollowFinalSymlink=*/true);
1125  if (!Node) {
1126  EC = Node.getError();
1127  return directory_iterator(std::make_shared<DirIterator>());
1128  }
1129 
1130  if (auto *DirNode = dyn_cast<detail::InMemoryDirectory>(*Node))
1131  return directory_iterator(
1132  std::make_shared<DirIterator>(this, *DirNode, Dir.str()));
1133 
1135  return directory_iterator(std::make_shared<DirIterator>());
1136 }
1137 
1139  SmallString<128> Path;
1140  P.toVector(Path);
1141 
1142  // Fix up relative paths. This just prepends the current working directory.
1143  std::error_code EC = makeAbsolute(Path);
1144  assert(!EC);
1145  (void)EC;
1146 
1147  if (useNormalizedPaths())
1148  llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
1149 
1150  if (!Path.empty())
1151  WorkingDirectory = std::string(Path.str());
1152  return {};
1153 }
1154 
1155 std::error_code
1157  SmallVectorImpl<char> &Output) const {
1158  auto CWD = getCurrentWorkingDirectory();
1159  if (!CWD || CWD->empty())
1161  Path.toVector(Output);
1162  if (auto EC = makeAbsolute(Output))
1163  return EC;
1164  llvm::sys::path::remove_dots(Output, /*remove_dot_dot=*/true);
1165  return {};
1166 }
1167 
1168 std::error_code InMemoryFileSystem::isLocal(const Twine &Path, bool &Result) {
1169  Result = false;
1170  return {};
1171 }
1172 
1174  unsigned IndentLevel) const {
1175  printIndent(OS, IndentLevel);
1176  OS << "InMemoryFileSystem\n";
1177 }
1178 
1179 } // namespace vfs
1180 } // namespace llvm
1181 
1182 //===-----------------------------------------------------------------------===/
1183 // RedirectingFileSystem implementation
1184 //===-----------------------------------------------------------------------===/
1185 
1186 namespace {
1187 
1188 static llvm::sys::path::Style getExistingStyle(llvm::StringRef Path) {
1189  // Detect the path style in use by checking the first separator.
1191  const size_t n = Path.find_first_of("/\\");
1192  // Can't distinguish between posix and windows_slash here.
1193  if (n != static_cast<size_t>(-1))
1194  style = (Path[n] == '/') ? llvm::sys::path::Style::posix
1196  return style;
1197 }
1198 
1199 /// Removes leading "./" as well as path components like ".." and ".".
1200 static llvm::SmallString<256> canonicalize(llvm::StringRef Path) {
1201  // First detect the path style in use by checking the first separator.
1202  llvm::sys::path::Style style = getExistingStyle(Path);
1203 
1204  // Now remove the dots. Explicitly specifying the path style prevents the
1205  // direction of the slashes from changing.
1208  llvm::sys::path::remove_dots(result, /*remove_dot_dot=*/true, style);
1209  return result;
1210 }
1211 
1212 /// Whether the error and entry specify a file/directory that was not found.
1213 static bool isFileNotFound(std::error_code EC,
1214  RedirectingFileSystem::Entry *E = nullptr) {
1215  if (E && !isa<RedirectingFileSystem::DirectoryRemapEntry>(E))
1216  return false;
1218 }
1219 
1220 } // anonymous namespace
1221 
1222 
1223 RedirectingFileSystem::RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> FS)
1224  : ExternalFS(std::move(FS)) {
1225  if (ExternalFS)
1226  if (auto ExternalWorkingDirectory =
1227  ExternalFS->getCurrentWorkingDirectory()) {
1228  WorkingDirectory = *ExternalWorkingDirectory;
1229  }
1230 }
1231 
1232 /// Directory iterator implementation for \c RedirectingFileSystem's
1233 /// directory entries.
1236  std::string Dir;
1238 
1239  std::error_code incrementImpl(bool IsFirstTime) {
1240  assert((IsFirstTime || Current != End) && "cannot iterate past end");
1241  if (!IsFirstTime)
1242  ++Current;
1243  if (Current != End) {
1244  SmallString<128> PathStr(Dir);
1245  llvm::sys::path::append(PathStr, (*Current)->getName());
1247  switch ((*Current)->getKind()) {
1252  break;
1255  break;
1256  }
1257  CurrentEntry = directory_entry(std::string(PathStr.str()), Type);
1258  } else {
1260  }
1261  return {};
1262  };
1263 
1264 public:
1267  RedirectingFileSystem::DirectoryEntry::iterator End, std::error_code &EC)
1268  : Dir(Path.str()), Current(Begin), End(End) {
1269  EC = incrementImpl(/*IsFirstTime=*/true);
1270  }
1271 
1272  std::error_code increment() override {
1273  return incrementImpl(/*IsFirstTime=*/false);
1274  }
1275 };
1276 
1277 namespace {
1278 /// Directory iterator implementation for \c RedirectingFileSystem's
1279 /// directory remap entries that maps the paths reported by the external
1280 /// file system's directory iterator back to the virtual directory's path.
1281 class RedirectingFSDirRemapIterImpl : public llvm::vfs::detail::DirIterImpl {
1282  std::string Dir;
1283  llvm::sys::path::Style DirStyle;
1284  llvm::vfs::directory_iterator ExternalIter;
1285 
1286 public:
1287  RedirectingFSDirRemapIterImpl(std::string DirPath,
1289  : Dir(std::move(DirPath)), DirStyle(getExistingStyle(Dir)),
1290  ExternalIter(ExtIter) {
1291  if (ExternalIter != llvm::vfs::directory_iterator())
1292  setCurrentEntry();
1293  }
1294 
1295  void setCurrentEntry() {
1296  StringRef ExternalPath = ExternalIter->path();
1297  llvm::sys::path::Style ExternalStyle = getExistingStyle(ExternalPath);
1298  StringRef File = llvm::sys::path::filename(ExternalPath, ExternalStyle);
1299 
1300  SmallString<128> NewPath(Dir);
1301  llvm::sys::path::append(NewPath, DirStyle, File);
1302 
1303  CurrentEntry = directory_entry(std::string(NewPath), ExternalIter->type());
1304  }
1305 
1306  std::error_code increment() override {
1307  std::error_code EC;
1308  ExternalIter.increment(EC);
1309  if (!EC && ExternalIter != llvm::vfs::directory_iterator())
1310  setCurrentEntry();
1311  else
1312  CurrentEntry = directory_entry();
1313  return EC;
1314  }
1315 };
1316 } // namespace
1317 
1320  return WorkingDirectory;
1321 }
1322 
1323 std::error_code
1325  // Don't change the working directory if the path doesn't exist.
1326  if (!exists(Path))
1328 
1329  SmallString<128> AbsolutePath;
1330  Path.toVector(AbsolutePath);
1331  if (std::error_code EC = makeAbsolute(AbsolutePath))
1332  return EC;
1333  WorkingDirectory = std::string(AbsolutePath.str());
1334  return {};
1335 }
1336 
1337 std::error_code RedirectingFileSystem::isLocal(const Twine &Path_,
1338  bool &Result) {
1339  SmallString<256> Path;
1340  Path_.toVector(Path);
1341 
1342  if (std::error_code EC = makeCanonical(Path))
1343  return {};
1344 
1345  return ExternalFS->isLocal(Path, Result);
1346 }
1347 
1349  // is_absolute(..., Style::windows_*) accepts paths with both slash types.
1353  return {};
1354 
1355  auto WorkingDir = getCurrentWorkingDirectory();
1356  if (!WorkingDir)
1357  return WorkingDir.getError();
1358 
1359  // We can't use sys::fs::make_absolute because that assumes the path style
1360  // is native and there is no way to override that. Since we know WorkingDir
1361  // is absolute, we can use it to determine which style we actually have and
1362  // append Path ourselves.
1364  if (sys::path::is_absolute(WorkingDir.get(), sys::path::Style::posix)) {
1365  style = sys::path::Style::posix;
1366  } else {
1367  // Distinguish between windows_backslash and windows_slash; getExistingStyle
1368  // returns posix for a path with windows_slash.
1369  if (getExistingStyle(WorkingDir.get()) !=
1372  }
1373 
1374  std::string Result = WorkingDir.get();
1375  StringRef Dir(Result);
1376  if (!Dir.endswith(sys::path::get_separator(style))) {
1377  Result += sys::path::get_separator(style);
1378  }
1379  Result.append(Path.data(), Path.size());
1380  Path.assign(Result.begin(), Result.end());
1381 
1382  return {};
1383 }
1384 
1386  std::error_code &EC) {
1387  SmallString<256> Path;
1388  Dir.toVector(Path);
1389 
1390  EC = makeCanonical(Path);
1391  if (EC)
1392  return {};
1393 
1395  if (!Result) {
1396  if (Redirection != RedirectKind::RedirectOnly &&
1397  isFileNotFound(Result.getError()))
1398  return ExternalFS->dir_begin(Path, EC);
1399 
1400  EC = Result.getError();
1401  return {};
1402  }
1403 
1404  // Use status to make sure the path exists and refers to a directory.
1405  ErrorOr<Status> S = status(Path, Dir, *Result);
1406  if (!S) {
1407  if (Redirection != RedirectKind::RedirectOnly &&
1408  isFileNotFound(S.getError(), Result->E))
1409  return ExternalFS->dir_begin(Dir, EC);
1410 
1411  EC = S.getError();
1412  return {};
1413  }
1414 
1415  if (!S->isDirectory()) {
1416  EC = errc::not_a_directory;
1417  return {};
1418  }
1419 
1420  // Create the appropriate directory iterator based on whether we found a
1421  // DirectoryRemapEntry or DirectoryEntry.
1422  directory_iterator RedirectIter;
1423  std::error_code RedirectEC;
1424  if (auto ExtRedirect = Result->getExternalRedirect()) {
1425  auto RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
1426  RedirectIter = ExternalFS->dir_begin(*ExtRedirect, RedirectEC);
1427 
1428  if (!RE->useExternalName(UseExternalNames)) {
1429  // Update the paths in the results to use the virtual directory's path.
1430  RedirectIter =
1431  directory_iterator(std::make_shared<RedirectingFSDirRemapIterImpl>(
1432  std::string(Path), RedirectIter));
1433  }
1434  } else {
1435  auto DE = cast<DirectoryEntry>(Result->E);
1436  RedirectIter =
1437  directory_iterator(std::make_shared<RedirectingFSDirIterImpl>(
1438  Path, DE->contents_begin(), DE->contents_end(), RedirectEC));
1439  }
1440 
1441  if (RedirectEC) {
1442  if (RedirectEC != errc::no_such_file_or_directory) {
1443  EC = RedirectEC;
1444  return {};
1445  }
1446  RedirectIter = {};
1447  }
1448 
1449  if (Redirection == RedirectKind::RedirectOnly) {
1450  EC = RedirectEC;
1451  return RedirectIter;
1452  }
1453 
1454  std::error_code ExternalEC;
1455  directory_iterator ExternalIter = ExternalFS->dir_begin(Path, ExternalEC);
1456  if (ExternalEC) {
1457  if (ExternalEC != errc::no_such_file_or_directory) {
1458  EC = ExternalEC;
1459  return {};
1460  }
1461  ExternalIter = {};
1462  }
1463 
1465  switch (Redirection) {
1467  Iters.push_back(ExternalIter);
1468  Iters.push_back(RedirectIter);
1469  break;
1471  Iters.push_back(RedirectIter);
1472  Iters.push_back(ExternalIter);
1473  break;
1474  default:
1475  llvm_unreachable("unhandled RedirectKind");
1476  }
1477 
1478  directory_iterator Combined{
1479  std::make_shared<CombiningDirIterImpl>(Iters, EC)};
1480  if (EC)
1481  return {};
1482  return Combined;
1483 }
1484 
1486  ExternalContentsPrefixDir = PrefixDir.str();
1487 }
1488 
1490  return ExternalContentsPrefixDir;
1491 }
1492 
1494  if (Fallthrough) {
1496  } else {
1498  }
1499 }
1500 
1503  Redirection = Kind;
1504 }
1505 
1506 std::vector<StringRef> RedirectingFileSystem::getRoots() const {
1507  std::vector<StringRef> R;
1508  for (const auto &Root : Roots)
1509  R.push_back(Root->getName());
1510  return R;
1511 }
1512 
1514  unsigned IndentLevel) const {
1515  printIndent(OS, IndentLevel);
1516  OS << "RedirectingFileSystem (UseExternalNames: "
1517  << (UseExternalNames ? "true" : "false") << ")\n";
1518  if (Type == PrintType::Summary)
1519  return;
1520 
1521  for (const auto &Root : Roots)
1522  printEntry(OS, Root.get(), IndentLevel);
1523 
1524  printIndent(OS, IndentLevel);
1525  OS << "ExternalFS:\n";
1526  ExternalFS->print(OS, Type == PrintType::Contents ? PrintType::Summary : Type,
1527  IndentLevel + 1);
1528 }
1529 
1532  unsigned IndentLevel) const {
1533  printIndent(OS, IndentLevel);
1534  OS << "'" << E->getName() << "'";
1535 
1536  switch (E->getKind()) {
1537  case EK_Directory: {
1538  auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(E);
1539 
1540  OS << "\n";
1541  for (std::unique_ptr<Entry> &SubEntry :
1542  llvm::make_range(DE->contents_begin(), DE->contents_end()))
1543  printEntry(OS, SubEntry.get(), IndentLevel + 1);
1544  break;
1545  }
1546  case EK_DirectoryRemap:
1547  case EK_File: {
1548  auto *RE = cast<RedirectingFileSystem::RemapEntry>(E);
1549  OS << " -> '" << RE->getExternalContentsPath() << "'";
1550  switch (RE->getUseName()) {
1551  case NK_NotSet:
1552  break;
1553  case NK_External:
1554  OS << " (UseExternalName: true)";
1555  break;
1556  case NK_Virtual:
1557  OS << " (UseExternalName: false)";
1558  break;
1559  }
1560  OS << "\n";
1561  break;
1562  }
1563  }
1564 }
1565 
1566 /// A helper class to hold the common YAML parsing state.
1568  yaml::Stream &Stream;
1569 
1570  void error(yaml::Node *N, const Twine &Msg) { Stream.printError(N, Msg); }
1571 
1572  // false on error
1573  bool parseScalarString(yaml::Node *N, StringRef &Result,
1574  SmallVectorImpl<char> &Storage) {
1575  const auto *S = dyn_cast<yaml::ScalarNode>(N);
1576 
1577  if (!S) {
1578  error(N, "expected string");
1579  return false;
1580  }
1581  Result = S->getValue(Storage);
1582  return true;
1583  }
1584 
1585  // false on error
1586  bool parseScalarBool(yaml::Node *N, bool &Result) {
1587  SmallString<5> Storage;
1588  StringRef Value;
1589  if (!parseScalarString(N, Value, Storage))
1590  return false;
1591 
1592  if (Value.equals_insensitive("true") || Value.equals_insensitive("on") ||
1593  Value.equals_insensitive("yes") || Value == "1") {
1594  Result = true;
1595  return true;
1596  } else if (Value.equals_insensitive("false") ||
1597  Value.equals_insensitive("off") ||
1598  Value.equals_insensitive("no") || Value == "0") {
1599  Result = false;
1600  return true;
1601  }
1602 
1603  error(N, "expected boolean value");
1604  return false;
1605  }
1606 
1608  parseRedirectKind(yaml::Node *N) {
1609  SmallString<12> Storage;
1610  StringRef Value;
1611  if (!parseScalarString(N, Value, Storage))
1612  return None;
1613 
1614  if (Value.equals_insensitive("fallthrough")) {
1616  } else if (Value.equals_insensitive("fallback")) {
1618  } else if (Value.equals_insensitive("redirect-only")) {
1620  }
1621  return None;
1622  }
1623 
1624  struct KeyStatus {
1625  bool Required;
1626  bool Seen = false;
1627 
1628  KeyStatus(bool Required = false) : Required(Required) {}
1629  };
1630 
1631  using KeyStatusPair = std::pair<StringRef, KeyStatus>;
1632 
1633  // false on error
1634  bool checkDuplicateOrUnknownKey(yaml::Node *KeyNode, StringRef Key,
1636  if (!Keys.count(Key)) {
1637  error(KeyNode, "unknown key");
1638  return false;
1639  }
1640  KeyStatus &S = Keys[Key];
1641  if (S.Seen) {
1642  error(KeyNode, Twine("duplicate key '") + Key + "'");
1643  return false;
1644  }
1645  S.Seen = true;
1646  return true;
1647  }
1648 
1649  // false on error
1650  bool checkMissingKeys(yaml::Node *Obj, DenseMap<StringRef, KeyStatus> &Keys) {
1651  for (const auto &I : Keys) {
1652  if (I.second.Required && !I.second.Seen) {
1653  error(Obj, Twine("missing key '") + I.first + "'");
1654  return false;
1655  }
1656  }
1657  return true;
1658  }
1659 
1660 public:
1663  RedirectingFileSystem::Entry *ParentEntry = nullptr) {
1664  if (!ParentEntry) { // Look for a existent root
1665  for (const auto &Root : FS->Roots) {
1666  if (Name.equals(Root->getName())) {
1667  ParentEntry = Root.get();
1668  return ParentEntry;
1669  }
1670  }
1671  } else { // Advance to the next component
1672  auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
1673  for (std::unique_ptr<RedirectingFileSystem::Entry> &Content :
1674  llvm::make_range(DE->contents_begin(), DE->contents_end())) {
1675  auto *DirContent =
1676  dyn_cast<RedirectingFileSystem::DirectoryEntry>(Content.get());
1677  if (DirContent && Name.equals(Content->getName()))
1678  return DirContent;
1679  }
1680  }
1681 
1682  // ... or create a new one
1683  std::unique_ptr<RedirectingFileSystem::Entry> E =
1684  std::make_unique<RedirectingFileSystem::DirectoryEntry>(
1686  std::chrono::system_clock::now(), 0, 0, 0,
1687  file_type::directory_file, sys::fs::all_all));
1688 
1689  if (!ParentEntry) { // Add a new root to the overlay
1690  FS->Roots.push_back(std::move(E));
1691  ParentEntry = FS->Roots.back().get();
1692  return ParentEntry;
1693  }
1694 
1695  auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
1696  DE->addContent(std::move(E));
1697  return DE->getLastContent();
1698  }
1699 
1700 private:
1701  void uniqueOverlayTree(RedirectingFileSystem *FS,
1703  RedirectingFileSystem::Entry *NewParentE = nullptr) {
1704  StringRef Name = SrcE->getName();
1705  switch (SrcE->getKind()) {
1707  auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
1708  // Empty directories could be present in the YAML as a way to
1709  // describe a file for a current directory after some of its subdir
1710  // is parsed. This only leads to redundant walks, ignore it.
1711  if (!Name.empty())
1712  NewParentE = lookupOrCreateEntry(FS, Name, NewParentE);
1713  for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
1714  llvm::make_range(DE->contents_begin(), DE->contents_end()))
1715  uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
1716  break;
1717  }
1719  assert(NewParentE && "Parent entry must exist");
1720  auto *DR = cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
1721  auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
1722  DE->addContent(
1723  std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
1724  Name, DR->getExternalContentsPath(), DR->getUseName()));
1725  break;
1726  }
1728  assert(NewParentE && "Parent entry must exist");
1729  auto *FE = cast<RedirectingFileSystem::FileEntry>(SrcE);
1730  auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
1731  DE->addContent(std::make_unique<RedirectingFileSystem::FileEntry>(
1732  Name, FE->getExternalContentsPath(), FE->getUseName()));
1733  break;
1734  }
1735  }
1736  }
1737 
1738  std::unique_ptr<RedirectingFileSystem::Entry>
1739  parseEntry(yaml::Node *N, RedirectingFileSystem *FS, bool IsRootEntry) {
1740  auto *M = dyn_cast<yaml::MappingNode>(N);
1741  if (!M) {
1742  error(N, "expected mapping node for file or directory entry");
1743  return nullptr;
1744  }
1745 
1746  KeyStatusPair Fields[] = {
1747  KeyStatusPair("name", true),
1748  KeyStatusPair("type", true),
1749  KeyStatusPair("contents", false),
1750  KeyStatusPair("external-contents", false),
1751  KeyStatusPair("use-external-name", false),
1752  };
1753 
1754  DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
1755 
1756  enum { CF_NotSet, CF_List, CF_External } ContentsField = CF_NotSet;
1757  std::vector<std::unique_ptr<RedirectingFileSystem::Entry>>
1758  EntryArrayContents;
1759  SmallString<256> ExternalContentsPath;
1761  yaml::Node *NameValueNode = nullptr;
1762  auto UseExternalName = RedirectingFileSystem::NK_NotSet;
1764 
1765  for (auto &I : *M) {
1766  StringRef Key;
1767  // Reuse the buffer for key and value, since we don't look at key after
1768  // parsing value.
1769  SmallString<256> Buffer;
1770  if (!parseScalarString(I.getKey(), Key, Buffer))
1771  return nullptr;
1772 
1773  if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys))
1774  return nullptr;
1775 
1776  StringRef Value;
1777  if (Key == "name") {
1778  if (!parseScalarString(I.getValue(), Value, Buffer))
1779  return nullptr;
1780 
1781  NameValueNode = I.getValue();
1782  // Guarantee that old YAML files containing paths with ".." and "."
1783  // are properly canonicalized before read into the VFS.
1784  Name = canonicalize(Value).str();
1785  } else if (Key == "type") {
1786  if (!parseScalarString(I.getValue(), Value, Buffer))
1787  return nullptr;
1788  if (Value == "file")
1790  else if (Value == "directory")
1792  else if (Value == "directory-remap")
1794  else {
1795  error(I.getValue(), "unknown value for 'type'");
1796  return nullptr;
1797  }
1798  } else if (Key == "contents") {
1799  if (ContentsField != CF_NotSet) {
1800  error(I.getKey(),
1801  "entry already has 'contents' or 'external-contents'");
1802  return nullptr;
1803  }
1804  ContentsField = CF_List;
1805  auto *Contents = dyn_cast<yaml::SequenceNode>(I.getValue());
1806  if (!Contents) {
1807  // FIXME: this is only for directories, what about files?
1808  error(I.getValue(), "expected array");
1809  return nullptr;
1810  }
1811 
1812  for (auto &I : *Contents) {
1813  if (std::unique_ptr<RedirectingFileSystem::Entry> E =
1814  parseEntry(&I, FS, /*IsRootEntry*/ false))
1815  EntryArrayContents.push_back(std::move(E));
1816  else
1817  return nullptr;
1818  }
1819  } else if (Key == "external-contents") {
1820  if (ContentsField != CF_NotSet) {
1821  error(I.getKey(),
1822  "entry already has 'contents' or 'external-contents'");
1823  return nullptr;
1824  }
1825  ContentsField = CF_External;
1826  if (!parseScalarString(I.getValue(), Value, Buffer))
1827  return nullptr;
1828 
1829  SmallString<256> FullPath;
1830  if (FS->IsRelativeOverlay) {
1831  FullPath = FS->getExternalContentsPrefixDir();
1832  assert(!FullPath.empty() &&
1833  "External contents prefix directory must exist");
1834  llvm::sys::path::append(FullPath, Value);
1835  } else {
1836  FullPath = Value;
1837  }
1838 
1839  // Guarantee that old YAML files containing paths with ".." and "."
1840  // are properly canonicalized before read into the VFS.
1841  FullPath = canonicalize(FullPath);
1842  ExternalContentsPath = FullPath.str();
1843  } else if (Key == "use-external-name") {
1844  bool Val;
1845  if (!parseScalarBool(I.getValue(), Val))
1846  return nullptr;
1847  UseExternalName = Val ? RedirectingFileSystem::NK_External
1849  } else {
1850  llvm_unreachable("key missing from Keys");
1851  }
1852  }
1853 
1854  if (Stream.failed())
1855  return nullptr;
1856 
1857  // check for missing keys
1858  if (ContentsField == CF_NotSet) {
1859  error(N, "missing key 'contents' or 'external-contents'");
1860  return nullptr;
1861  }
1862  if (!checkMissingKeys(N, Keys))
1863  return nullptr;
1864 
1865  // check invalid configuration
1867  UseExternalName != RedirectingFileSystem::NK_NotSet) {
1868  error(N, "'use-external-name' is not supported for 'directory' entries");
1869  return nullptr;
1870  }
1871 
1873  ContentsField == CF_List) {
1874  error(N, "'contents' is not supported for 'directory-remap' entries");
1875  return nullptr;
1876  }
1877 
1879  if (IsRootEntry) {
1880  // VFS root entries may be in either Posix or Windows style. Figure out
1881  // which style we have, and use it consistently.
1883  path_style = sys::path::Style::posix;
1884  } else if (sys::path::is_absolute(Name,
1887  } else {
1888  // Relative VFS root entries are made absolute to the current working
1889  // directory, then we can determine the path style from that.
1890  auto EC = sys::fs::make_absolute(Name);
1891  if (EC) {
1892  assert(NameValueNode && "Name presence should be checked earlier");
1893  error(
1894  NameValueNode,
1895  "entry with relative path at the root level is not discoverable");
1896  return nullptr;
1897  }
1901  }
1902  }
1903 
1904  // Remove trailing slash(es), being careful not to remove the root path
1905  StringRef Trimmed = Name;
1906  size_t RootPathLen = sys::path::root_path(Trimmed, path_style).size();
1907  while (Trimmed.size() > RootPathLen &&
1908  sys::path::is_separator(Trimmed.back(), path_style))
1909  Trimmed = Trimmed.slice(0, Trimmed.size() - 1);
1910 
1911  // Get the last component
1912  StringRef LastComponent = sys::path::filename(Trimmed, path_style);
1913 
1914  std::unique_ptr<RedirectingFileSystem::Entry> Result;
1915  switch (Kind) {
1917  Result = std::make_unique<RedirectingFileSystem::FileEntry>(
1918  LastComponent, std::move(ExternalContentsPath), UseExternalName);
1919  break;
1921  Result = std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
1922  LastComponent, std::move(ExternalContentsPath), UseExternalName);
1923  break;
1925  Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
1926  LastComponent, std::move(EntryArrayContents),
1928  0, 0, 0, file_type::directory_file, sys::fs::all_all));
1929  break;
1930  }
1931 
1932  StringRef Parent = sys::path::parent_path(Trimmed, path_style);
1933  if (Parent.empty())
1934  return Result;
1935 
1936  // if 'name' contains multiple components, create implicit directory entries
1937  for (sys::path::reverse_iterator I = sys::path::rbegin(Parent, path_style),
1938  E = sys::path::rend(Parent);
1939  I != E; ++I) {
1940  std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> Entries;
1941  Entries.push_back(std::move(Result));
1942  Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
1943  *I, std::move(Entries),
1945  0, 0, 0, file_type::directory_file, sys::fs::all_all));
1946  }
1947  return Result;
1948  }
1949 
1950 public:
1952 
1953  // false on error
1955  auto *Top = dyn_cast<yaml::MappingNode>(Root);
1956  if (!Top) {
1957  error(Root, "expected mapping node");
1958  return false;
1959  }
1960 
1961  KeyStatusPair Fields[] = {
1962  KeyStatusPair("version", true),
1963  KeyStatusPair("case-sensitive", false),
1964  KeyStatusPair("use-external-names", false),
1965  KeyStatusPair("overlay-relative", false),
1966  KeyStatusPair("fallthrough", false),
1967  KeyStatusPair("redirecting-with", false),
1968  KeyStatusPair("roots", true),
1969  };
1970 
1971  DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
1972  std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> RootEntries;
1973 
1974  // Parse configuration and 'roots'
1975  for (auto &I : *Top) {
1976  SmallString<10> KeyBuffer;
1977  StringRef Key;
1978  if (!parseScalarString(I.getKey(), Key, KeyBuffer))
1979  return false;
1980 
1981  if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys))
1982  return false;
1983 
1984  if (Key == "roots") {
1985  auto *Roots = dyn_cast<yaml::SequenceNode>(I.getValue());
1986  if (!Roots) {
1987  error(I.getValue(), "expected array");
1988  return false;
1989  }
1990 
1991  for (auto &I : *Roots) {
1992  if (std::unique_ptr<RedirectingFileSystem::Entry> E =
1993  parseEntry(&I, FS, /*IsRootEntry*/ true))
1994  RootEntries.push_back(std::move(E));
1995  else
1996  return false;
1997  }
1998  } else if (Key == "version") {
1999  StringRef VersionString;
2000  SmallString<4> Storage;
2001  if (!parseScalarString(I.getValue(), VersionString, Storage))
2002  return false;
2003  int Version;
2004  if (VersionString.getAsInteger<int>(10, Version)) {
2005  error(I.getValue(), "expected integer");
2006  return false;
2007  }
2008  if (Version < 0) {
2009  error(I.getValue(), "invalid version number");
2010  return false;
2011  }
2012  if (Version != 0) {
2013  error(I.getValue(), "version mismatch, expected 0");
2014  return false;
2015  }
2016  } else if (Key == "case-sensitive") {
2017  if (!parseScalarBool(I.getValue(), FS->CaseSensitive))
2018  return false;
2019  } else if (Key == "overlay-relative") {
2020  if (!parseScalarBool(I.getValue(), FS->IsRelativeOverlay))
2021  return false;
2022  } else if (Key == "use-external-names") {
2023  if (!parseScalarBool(I.getValue(), FS->UseExternalNames))
2024  return false;
2025  } else if (Key == "fallthrough") {
2026  if (Keys["redirecting-with"].Seen) {
2027  error(I.getValue(),
2028  "'fallthrough' and 'redirecting-with' are mutually exclusive");
2029  return false;
2030  }
2031 
2032  bool ShouldFallthrough = false;
2033  if (!parseScalarBool(I.getValue(), ShouldFallthrough))
2034  return false;
2035 
2036  if (ShouldFallthrough) {
2038  } else {
2040  }
2041  } else if (Key == "redirecting-with") {
2042  if (Keys["fallthrough"].Seen) {
2043  error(I.getValue(),
2044  "'fallthrough' and 'redirecting-with' are mutually exclusive");
2045  return false;
2046  }
2047 
2048  if (auto Kind = parseRedirectKind(I.getValue())) {
2049  FS->Redirection = *Kind;
2050  } else {
2051  error(I.getValue(), "expected valid redirect kind");
2052  return false;
2053  }
2054  } else {
2055  llvm_unreachable("key missing from Keys");
2056  }
2057  }
2058 
2059  if (Stream.failed())
2060  return false;
2061 
2062  if (!checkMissingKeys(Top, Keys))
2063  return false;
2064 
2065  // Now that we sucessefully parsed the YAML file, canonicalize the internal
2066  // representation to a proper directory tree so that we can search faster
2067  // inside the VFS.
2068  for (auto &E : RootEntries)
2069  uniqueOverlayTree(FS, E.get());
2070 
2071  return true;
2072  }
2073 };
2074 
2075 std::unique_ptr<RedirectingFileSystem>
2076 RedirectingFileSystem::create(std::unique_ptr<MemoryBuffer> Buffer,
2078  StringRef YAMLFilePath, void *DiagContext,
2079  IntrusiveRefCntPtr<FileSystem> ExternalFS) {
2080  SourceMgr SM;
2081  yaml::Stream Stream(Buffer->getMemBufferRef(), SM);
2082 
2083  SM.setDiagHandler(DiagHandler, DiagContext);
2084  yaml::document_iterator DI = Stream.begin();
2085  yaml::Node *Root = DI->getRoot();
2086  if (DI == Stream.end() || !Root) {
2087  SM.PrintMessage(SMLoc(), SourceMgr::DK_Error, "expected root node");
2088  return nullptr;
2089  }
2090 
2092 
2093  std::unique_ptr<RedirectingFileSystem> FS(
2094  new RedirectingFileSystem(ExternalFS));
2095 
2096  if (!YAMLFilePath.empty()) {
2097  // Use the YAML path from -ivfsoverlay to compute the dir to be prefixed
2098  // to each 'external-contents' path.
2099  //
2100  // Example:
2101  // -ivfsoverlay dummy.cache/vfs/vfs.yaml
2102  // yields:
2103  // FS->ExternalContentsPrefixDir => /<absolute_path_to>/dummy.cache/vfs
2104  //
2105  SmallString<256> OverlayAbsDir = sys::path::parent_path(YAMLFilePath);
2106  std::error_code EC = llvm::sys::fs::make_absolute(OverlayAbsDir);
2107  assert(!EC && "Overlay dir final path must be absolute");
2108  (void)EC;
2109  FS->setExternalContentsPrefixDir(OverlayAbsDir);
2110  }
2111 
2112  if (!P.parse(Root, FS.get()))
2113  return nullptr;
2114 
2115  return FS;
2116 }
2117 
2118 std::unique_ptr<RedirectingFileSystem> RedirectingFileSystem::create(
2119  ArrayRef<std::pair<std::string, std::string>> RemappedFiles,
2120  bool UseExternalNames, FileSystem &ExternalFS) {
2121  std::unique_ptr<RedirectingFileSystem> FS(
2122  new RedirectingFileSystem(&ExternalFS));
2123  FS->UseExternalNames = UseExternalNames;
2124 
2126 
2127  for (auto &Mapping : llvm::reverse(RemappedFiles)) {
2128  SmallString<128> From = StringRef(Mapping.first);
2129  SmallString<128> To = StringRef(Mapping.second);
2130  {
2131  auto EC = ExternalFS.makeAbsolute(From);
2132  (void)EC;
2133  assert(!EC && "Could not make absolute path");
2134  }
2135 
2136  // Check if we've already mapped this file. The first one we see (in the
2137  // reverse iteration) wins.
2138  RedirectingFileSystem::Entry *&ToEntry = Entries[From];
2139  if (ToEntry)
2140  continue;
2141 
2142  // Add parent directories.
2143  RedirectingFileSystem::Entry *Parent = nullptr;
2144  StringRef FromDirectory = llvm::sys::path::parent_path(From);
2145  for (auto I = llvm::sys::path::begin(FromDirectory),
2146  E = llvm::sys::path::end(FromDirectory);
2147  I != E; ++I) {
2149  Parent);
2150  }
2151  assert(Parent && "File without a directory?");
2152  {
2153  auto EC = ExternalFS.makeAbsolute(To);
2154  (void)EC;
2155  assert(!EC && "Could not make absolute path");
2156  }
2157 
2158  // Add the file.
2159  auto NewFile = std::make_unique<RedirectingFileSystem::FileEntry>(
2161  UseExternalNames ? RedirectingFileSystem::NK_External
2163  ToEntry = NewFile.get();
2164  cast<RedirectingFileSystem::DirectoryEntry>(Parent)->addContent(
2165  std::move(NewFile));
2166  }
2167 
2168  return FS;
2169 }
2170 
2173  : E(E) {
2174  assert(E != nullptr);
2175  // If the matched entry is a DirectoryRemapEntry, set ExternalRedirect to the
2176  // path of the directory it maps to in the external file system plus any
2177  // remaining path components in the provided iterator.
2178  if (auto *DRE = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(E)) {
2179  SmallString<256> Redirect(DRE->getExternalContentsPath());
2180  sys::path::append(Redirect, Start, End,
2181  getExistingStyle(DRE->getExternalContentsPath()));
2182  ExternalRedirect = std::string(Redirect);
2183  }
2184 }
2185 
2186 std::error_code
2187 RedirectingFileSystem::makeCanonical(SmallVectorImpl<char> &Path) const {
2188  if (std::error_code EC = makeAbsolute(Path))
2189  return EC;
2190 
2191  llvm::SmallString<256> CanonicalPath =
2192  canonicalize(StringRef(Path.data(), Path.size()));
2193  if (CanonicalPath.empty())
2195 
2196  Path.assign(CanonicalPath.begin(), CanonicalPath.end());
2197  return {};
2198 }
2199 
2204  for (const auto &Root : Roots) {
2206  lookupPathImpl(Start, End, Root.get());
2207  if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
2208  return Result;
2209  }
2211 }
2212 
2214 RedirectingFileSystem::lookupPathImpl(
2217  assert(!isTraversalComponent(*Start) &&
2218  !isTraversalComponent(From->getName()) &&
2219  "Paths should not contain traversal components");
2220 
2221  StringRef FromName = From->getName();
2222 
2223  // Forward the search to the next component in case this is an empty one.
2224  if (!FromName.empty()) {
2225  if (!pathComponentMatches(*Start, FromName))
2227 
2228  ++Start;
2229 
2230  if (Start == End) {
2231  // Match!
2232  return LookupResult(From, Start, End);
2233  }
2234  }
2235 
2236  if (isa<RedirectingFileSystem::FileEntry>(From))
2238 
2239  if (isa<RedirectingFileSystem::DirectoryRemapEntry>(From))
2240  return LookupResult(From, Start, End);
2241 
2242  auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(From);
2243  for (const std::unique_ptr<RedirectingFileSystem::Entry> &DirEntry :
2244  llvm::make_range(DE->contents_begin(), DE->contents_end())) {
2246  lookupPathImpl(Start, End, DirEntry.get());
2247  if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
2248  return Result;
2249  }
2250 
2252 }
2253 
2254 static Status getRedirectedFileStatus(const Twine &OriginalPath,
2255  bool UseExternalNames,
2256  Status ExternalStatus) {
2257  // The path has been mapped by some nested VFS and exposes an external path,
2258  // don't override it with the original path.
2259  if (ExternalStatus.ExposesExternalVFSPath)
2260  return ExternalStatus;
2261 
2262  Status S = ExternalStatus;
2263  if (!UseExternalNames)
2264  S = Status::copyWithNewName(S, OriginalPath);
2265  else
2266  S.ExposesExternalVFSPath = true;
2267  S.IsVFSMapped = true;
2268  return S;
2269 }
2270 
2271 ErrorOr<Status> RedirectingFileSystem::status(
2272  const Twine &CanonicalPath, const Twine &OriginalPath,
2273  const RedirectingFileSystem::LookupResult &Result) {
2274  if (Optional<StringRef> ExtRedirect = Result.getExternalRedirect()) {
2275  SmallString<256> CanonicalRemappedPath((*ExtRedirect).str());
2276  if (std::error_code EC = makeCanonical(CanonicalRemappedPath))
2277  return EC;
2278 
2279  ErrorOr<Status> S = ExternalFS->status(CanonicalRemappedPath);
2280  if (!S)
2281  return S;
2282  S = Status::copyWithNewName(*S, *ExtRedirect);
2283  auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result.E);
2284  return getRedirectedFileStatus(OriginalPath,
2285  RE->useExternalName(UseExternalNames), *S);
2286  }
2287 
2288  auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(Result.E);
2289  return Status::copyWithNewName(DE->getStatus(), CanonicalPath);
2290 }
2291 
2293 RedirectingFileSystem::getExternalStatus(const Twine &CanonicalPath,
2294  const Twine &OriginalPath) const {
2295  auto Result = ExternalFS->status(CanonicalPath);
2296 
2297  // The path has been mapped by some nested VFS, don't override it with the
2298  // original path.
2299  if (!Result || Result->ExposesExternalVFSPath)
2300  return Result;
2301  return Status::copyWithNewName(Result.get(), OriginalPath);
2302 }
2303 
2304 ErrorOr<Status> RedirectingFileSystem::status(const Twine &OriginalPath) {
2305  SmallString<256> CanonicalPath;
2306  OriginalPath.toVector(CanonicalPath);
2307 
2308  if (std::error_code EC = makeCanonical(CanonicalPath))
2309  return EC;
2310 
2311  if (Redirection == RedirectKind::Fallback) {
2312  // Attempt to find the original file first, only falling back to the
2313  // mapped file if that fails.
2314  ErrorOr<Status> S = getExternalStatus(CanonicalPath, OriginalPath);
2315  if (S)
2316  return S;
2317  }
2318 
2320  lookupPath(CanonicalPath);
2321  if (!Result) {
2322  // Was not able to map file, fallthrough to using the original path if
2323  // that was the specified redirection type.
2324  if (Redirection == RedirectKind::Fallthrough &&
2325  isFileNotFound(Result.getError()))
2326  return getExternalStatus(CanonicalPath, OriginalPath);
2327  return Result.getError();
2328  }
2329 
2330  ErrorOr<Status> S = status(CanonicalPath, OriginalPath, *Result);
2331  if (!S && Redirection == RedirectKind::Fallthrough &&
2332  isFileNotFound(S.getError(), Result->E)) {
2333  // Mapped the file but it wasn't found in the underlying filesystem,
2334  // fallthrough to using the original path if that was the specified
2335  // redirection type.
2336  return getExternalStatus(CanonicalPath, OriginalPath);
2337  }
2338 
2339  return S;
2340 }
2341 
2342 namespace {
2343 
2344 /// Provide a file wrapper with an overriden status.
2345 class FileWithFixedStatus : public File {
2346  std::unique_ptr<File> InnerFile;
2347  Status S;
2348 
2349 public:
2350  FileWithFixedStatus(std::unique_ptr<File> InnerFile, Status S)
2351  : InnerFile(std::move(InnerFile)), S(std::move(S)) {}
2352 
2353  ErrorOr<Status> status() override { return S; }
2355 
2356  getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
2357  bool IsVolatile) override {
2358  return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
2359  IsVolatile);
2360  }
2361 
2362  std::error_code close() override { return InnerFile->close(); }
2363 
2364  void setPath(const Twine &Path) override { S = S.copyWithNewName(S, Path); }
2365 };
2366 
2367 } // namespace
2368 
2370 File::getWithPath(ErrorOr<std::unique_ptr<File>> Result, const Twine &P) {
2371  // See \c getRedirectedFileStatus - don't update path if it's exposing an
2372  // external path.
2373  if (!Result || (*Result)->status()->ExposesExternalVFSPath)
2374  return Result;
2375 
2377  auto Name = F->get()->getName();
2378  if (Name && Name.get() != P.str())
2379  F->get()->setPath(P);
2380  return F;
2381 }
2382 
2385  SmallString<256> CanonicalPath;
2386  OriginalPath.toVector(CanonicalPath);
2387 
2388  if (std::error_code EC = makeCanonical(CanonicalPath))
2389  return EC;
2390 
2391  if (Redirection == RedirectKind::Fallback) {
2392  // Attempt to find the original file first, only falling back to the
2393  // mapped file if that fails.
2394  auto F = File::getWithPath(ExternalFS->openFileForRead(CanonicalPath),
2395  OriginalPath);
2396  if (F)
2397  return F;
2398  }
2399 
2401  lookupPath(CanonicalPath);
2402  if (!Result) {
2403  // Was not able to map file, fallthrough to using the original path if
2404  // that was the specified redirection type.
2405  if (Redirection == RedirectKind::Fallthrough &&
2406  isFileNotFound(Result.getError()))
2407  return File::getWithPath(ExternalFS->openFileForRead(CanonicalPath),
2408  OriginalPath);
2409  return Result.getError();
2410  }
2411 
2412  if (!Result->getExternalRedirect()) // FIXME: errc::not_a_file?
2414 
2415  StringRef ExtRedirect = *Result->getExternalRedirect();
2416  SmallString<256> CanonicalRemappedPath(ExtRedirect.str());
2417  if (std::error_code EC = makeCanonical(CanonicalRemappedPath))
2418  return EC;
2419 
2420  auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
2421 
2422  auto ExternalFile = File::getWithPath(
2423  ExternalFS->openFileForRead(CanonicalRemappedPath), ExtRedirect);
2424  if (!ExternalFile) {
2425  if (Redirection == RedirectKind::Fallthrough &&
2426  isFileNotFound(ExternalFile.getError(), Result->E)) {
2427  // Mapped the file but it wasn't found in the underlying filesystem,
2428  // fallthrough to using the original path if that was the specified
2429  // redirection type.
2430  return File::getWithPath(ExternalFS->openFileForRead(CanonicalPath),
2431  OriginalPath);
2432  }
2433  return ExternalFile;
2434  }
2435 
2436  auto ExternalStatus = (*ExternalFile)->status();
2437  if (!ExternalStatus)
2438  return ExternalStatus.getError();
2439 
2440  // Otherwise, the file was successfully remapped. Mark it as such. Also
2441  // replace the underlying path if the external name is being used.
2443  OriginalPath, RE->useExternalName(UseExternalNames), *ExternalStatus);
2444  return std::unique_ptr<File>(
2445  std::make_unique<FileWithFixedStatus>(std::move(*ExternalFile), S));
2446 }
2447 
2448 std::error_code
2450  SmallVectorImpl<char> &Output) const {
2451  SmallString<256> CanonicalPath;
2452  OriginalPath.toVector(CanonicalPath);
2453 
2454  if (std::error_code EC = makeCanonical(CanonicalPath))
2455  return EC;
2456 
2457  if (Redirection == RedirectKind::Fallback) {
2458  // Attempt to find the original file first, only falling back to the
2459  // mapped file if that fails.
2460  std::error_code EC = ExternalFS->getRealPath(CanonicalPath, Output);
2461  if (!EC)
2462  return EC;
2463  }
2464 
2466  lookupPath(CanonicalPath);
2467  if (!Result) {
2468  // Was not able to map file, fallthrough to using the original path if
2469  // that was the specified redirection type.
2470  if (Redirection == RedirectKind::Fallthrough &&
2471  isFileNotFound(Result.getError()))
2472  return ExternalFS->getRealPath(CanonicalPath, Output);
2473  return Result.getError();
2474  }
2475 
2476  // If we found FileEntry or DirectoryRemapEntry, look up the mapped
2477  // path in the external file system.
2478  if (auto ExtRedirect = Result->getExternalRedirect()) {
2479  auto P = ExternalFS->getRealPath(*ExtRedirect, Output);
2480  if (P && Redirection == RedirectKind::Fallthrough &&
2481  isFileNotFound(P, Result->E)) {
2482  // Mapped the file but it wasn't found in the underlying filesystem,
2483  // fallthrough to using the original path if that was the specified
2484  // redirection type.
2485  return ExternalFS->getRealPath(CanonicalPath, Output);
2486  }
2487  return P;
2488  }
2489 
2490  // If we found a DirectoryEntry, still fallthrough to the original path if
2491  // allowed, because directories don't have a single external contents path.
2492  if (Redirection == RedirectKind::Fallthrough)
2493  return ExternalFS->getRealPath(CanonicalPath, Output);
2495 }
2496 
2497 std::unique_ptr<FileSystem>
2498 vfs::getVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,
2500  StringRef YAMLFilePath, void *DiagContext,
2501  IntrusiveRefCntPtr<FileSystem> ExternalFS) {
2503  YAMLFilePath, DiagContext,
2504  std::move(ExternalFS));
2505 }
2506 
2509  SmallVectorImpl<YAMLVFSEntry> &Entries) {
2510  auto Kind = SrcE->getKind();
2512  auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
2513  assert(DE && "Must be a directory");
2514  for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
2515  llvm::make_range(DE->contents_begin(), DE->contents_end())) {
2516  Path.push_back(SubEntry->getName());
2517  getVFSEntries(SubEntry.get(), Path, Entries);
2518  Path.pop_back();
2519  }
2520  return;
2521  }
2522 
2524  auto *DR = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
2525  assert(DR && "Must be a directory remap");
2526  SmallString<128> VPath;
2527  for (auto &Comp : Path)
2528  llvm::sys::path::append(VPath, Comp);
2529  Entries.push_back(
2530  YAMLVFSEntry(VPath.c_str(), DR->getExternalContentsPath()));
2531  return;
2532  }
2533 
2534  assert(Kind == RedirectingFileSystem::EK_File && "Must be a EK_File");
2535  auto *FE = dyn_cast<RedirectingFileSystem::FileEntry>(SrcE);
2536  assert(FE && "Must be a file");
2537  SmallString<128> VPath;
2538  for (auto &Comp : Path)
2539  llvm::sys::path::append(VPath, Comp);
2540  Entries.push_back(YAMLVFSEntry(VPath.c_str(), FE->getExternalContentsPath()));
2541 }
2542 
2543 void vfs::collectVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,
2545  StringRef YAMLFilePath,
2546  SmallVectorImpl<YAMLVFSEntry> &CollectedEntries,
2547  void *DiagContext,
2548  IntrusiveRefCntPtr<FileSystem> ExternalFS) {
2549  std::unique_ptr<RedirectingFileSystem> VFS = RedirectingFileSystem::create(
2550  std::move(Buffer), DiagHandler, YAMLFilePath, DiagContext,
2551  std::move(ExternalFS));
2552  if (!VFS)
2553  return;
2555  VFS->lookupPath("/");
2556  if (!RootResult)
2557  return;
2558  SmallVector<StringRef, 8> Components;
2559  Components.push_back("/");
2560  getVFSEntries(RootResult->E, Components, CollectedEntries);
2561 }
2562 
2564  static std::atomic<unsigned> UID;
2565  unsigned ID = ++UID;
2566  // The following assumes that uint64_t max will never collide with a real
2567  // dev_t value from the OS.
2569 }
2570 
2571 void YAMLVFSWriter::addEntry(StringRef VirtualPath, StringRef RealPath,
2572  bool IsDirectory) {
2573  assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute");
2574  assert(sys::path::is_absolute(RealPath) && "real path not absolute");
2575  assert(!pathHasTraversal(VirtualPath) && "path traversal is not supported");
2576  Mappings.emplace_back(VirtualPath, RealPath, IsDirectory);
2577 }
2578 
2580  addEntry(VirtualPath, RealPath, /*IsDirectory=*/false);
2581 }
2582 
2584  StringRef RealPath) {
2585  addEntry(VirtualPath, RealPath, /*IsDirectory=*/true);
2586 }
2587 
2588 namespace {
2589 
2590 class JSONWriter {
2591  llvm::raw_ostream &OS;
2592  SmallVector<StringRef, 16> DirStack;
2593 
2594  unsigned getDirIndent() { return 4 * DirStack.size(); }
2595  unsigned getFileIndent() { return 4 * (DirStack.size() + 1); }
2596  bool containedIn(StringRef Parent, StringRef Path);
2597  StringRef containedPart(StringRef Parent, StringRef Path);
2598  void startDirectory(StringRef Path);
2599  void endDirectory();
2600  void writeEntry(StringRef VPath, StringRef RPath);
2601 
2602 public:
2603  JSONWriter(llvm::raw_ostream &OS) : OS(OS) {}
2604 
2605  void write(ArrayRef<YAMLVFSEntry> Entries, Optional<bool> UseExternalNames,
2606  Optional<bool> IsCaseSensitive, Optional<bool> IsOverlayRelative,
2607  StringRef OverlayDir);
2608 };
2609 
2610 } // namespace
2611 
2612 bool JSONWriter::containedIn(StringRef Parent, StringRef Path) {
2613  using namespace llvm::sys;
2614 
2615  // Compare each path component.
2616  auto IParent = path::begin(Parent), EParent = path::end(Parent);
2617  for (auto IChild = path::begin(Path), EChild = path::end(Path);
2618  IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
2619  if (*IParent != *IChild)
2620  return false;
2621  }
2622  // Have we exhausted the parent path?
2623  return IParent == EParent;
2624 }
2625 
2626 StringRef JSONWriter::containedPart(StringRef Parent, StringRef Path) {
2627  assert(!Parent.empty());
2628  assert(containedIn(Parent, Path));
2629  return Path.slice(Parent.size() + 1, StringRef::npos);
2630 }
2631 
2632 void JSONWriter::startDirectory(StringRef Path) {
2633  StringRef Name =
2634  DirStack.empty() ? Path : containedPart(DirStack.back(), Path);
2635  DirStack.push_back(Path);
2636  unsigned Indent = getDirIndent();
2637  OS.indent(Indent) << "{\n";
2638  OS.indent(Indent + 2) << "'type': 'directory',\n";
2639  OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(Name) << "\",\n";
2640  OS.indent(Indent + 2) << "'contents': [\n";
2641 }
2642 
2643 void JSONWriter::endDirectory() {
2644  unsigned Indent = getDirIndent();
2645  OS.indent(Indent + 2) << "]\n";
2646  OS.indent(Indent) << "}";
2647 
2648  DirStack.pop_back();
2649 }
2650 
2651 void JSONWriter::writeEntry(StringRef VPath, StringRef RPath) {
2652  unsigned Indent = getFileIndent();
2653  OS.indent(Indent) << "{\n";
2654  OS.indent(Indent + 2) << "'type': 'file',\n";
2655  OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(VPath) << "\",\n";
2656  OS.indent(Indent + 2) << "'external-contents': \""
2657  << llvm::yaml::escape(RPath) << "\"\n";
2658  OS.indent(Indent) << "}";
2659 }
2660 
2662  Optional<bool> UseExternalNames,
2663  Optional<bool> IsCaseSensitive,
2664  Optional<bool> IsOverlayRelative,
2665  StringRef OverlayDir) {
2666  using namespace llvm::sys;
2667 
2668  OS << "{\n"
2669  " 'version': 0,\n";
2670  if (IsCaseSensitive)
2671  OS << " 'case-sensitive': '"
2672  << (IsCaseSensitive.value() ? "true" : "false") << "',\n";
2673  if (UseExternalNames)
2674  OS << " 'use-external-names': '"
2675  << (UseExternalNames.value() ? "true" : "false") << "',\n";
2676  bool UseOverlayRelative = false;
2677  if (IsOverlayRelative) {
2678  UseOverlayRelative = IsOverlayRelative.value();
2679  OS << " 'overlay-relative': '" << (UseOverlayRelative ? "true" : "false")
2680  << "',\n";
2681  }
2682  OS << " 'roots': [\n";
2683 
2684  if (!Entries.empty()) {
2685  const YAMLVFSEntry &Entry = Entries.front();
2686 
2687  startDirectory(
2688  Entry.IsDirectory ? Entry.VPath : path::parent_path(Entry.VPath)
2689  );
2690 
2691  StringRef RPath = Entry.RPath;
2692  if (UseOverlayRelative) {
2693  unsigned OverlayDirLen = OverlayDir.size();
2694  assert(RPath.substr(0, OverlayDirLen) == OverlayDir &&
2695  "Overlay dir must be contained in RPath");
2696  RPath = RPath.slice(OverlayDirLen, RPath.size());
2697  }
2698 
2699  bool IsCurrentDirEmpty = true;
2700  if (!Entry.IsDirectory) {
2701  writeEntry(path::filename(Entry.VPath), RPath);
2702  IsCurrentDirEmpty = false;
2703  }
2704 
2705  for (const auto &Entry : Entries.slice(1)) {
2706  StringRef Dir =
2707  Entry.IsDirectory ? Entry.VPath : path::parent_path(Entry.VPath);
2708  if (Dir == DirStack.back()) {
2709  if (!IsCurrentDirEmpty) {
2710  OS << ",\n";
2711  }
2712  } else {
2713  bool IsDirPoppedFromStack = false;
2714  while (!DirStack.empty() && !containedIn(DirStack.back(), Dir)) {
2715  OS << "\n";
2716  endDirectory();
2717  IsDirPoppedFromStack = true;
2718  }
2719  if (IsDirPoppedFromStack || !IsCurrentDirEmpty) {
2720  OS << ",\n";
2721  }
2722  startDirectory(Dir);
2723  IsCurrentDirEmpty = true;
2724  }
2725  StringRef RPath = Entry.RPath;
2726  if (UseOverlayRelative) {
2727  unsigned OverlayDirLen = OverlayDir.size();
2728  assert(RPath.substr(0, OverlayDirLen) == OverlayDir &&
2729  "Overlay dir must be contained in RPath");
2730  RPath = RPath.slice(OverlayDirLen, RPath.size());
2731  }
2732  if (!Entry.IsDirectory) {
2733  writeEntry(path::filename(Entry.VPath), RPath);
2734  IsCurrentDirEmpty = false;
2735  }
2736  }
2737 
2738  while (!DirStack.empty()) {
2739  OS << "\n";
2740  endDirectory();
2741  }
2742  OS << "\n";
2743  }
2744 
2745  OS << " ]\n"
2746  << "}\n";
2747 }
2748 
2750  llvm::sort(Mappings, [](const YAMLVFSEntry &LHS, const YAMLVFSEntry &RHS) {
2751  return LHS.VPath < RHS.VPath;
2752  });
2753 
2754  JSONWriter(OS).write(Mappings, UseExternalNames, IsCaseSensitive,
2755  IsOverlayRelative, OverlayDir);
2756 }
2757 
2759  FileSystem &FS_, const Twine &Path, std::error_code &EC)
2760  : FS(&FS_) {
2761  directory_iterator I = FS->dir_begin(Path, EC);
2762  if (I != directory_iterator()) {
2763  State = std::make_shared<detail::RecDirIterState>();
2764  State->Stack.push(I);
2765  }
2766 }
2767 
2770  assert(FS && State && !State->Stack.empty() && "incrementing past end");
2771  assert(!State->Stack.top()->path().empty() && "non-canonical end iterator");
2773 
2774  if (State->HasNoPushRequest)
2775  State->HasNoPushRequest = false;
2776  else {
2777  if (State->Stack.top()->type() == sys::fs::file_type::directory_file) {
2778  vfs::directory_iterator I = FS->dir_begin(State->Stack.top()->path(), EC);
2779  if (I != End) {
2780  State->Stack.push(I);
2781  return *this;
2782  }
2783  }
2784  }
2785 
2786  while (!State->Stack.empty() && State->Stack.top().increment(EC) == End)
2787  State->Stack.pop();
2788 
2789  if (State->Stack.empty())
2790  State.reset(); // end iterator
2791 
2792  return *this;
2793 }
llvm::vfs::RedirectingFileSystem::EK_File
@ EK_File
Definition: VirtualFileSystem.h:731
MemoryBuffer.h
llvm::StringRef::back
LLVM_NODISCARD char back() const
back - Get the last character in the string.
Definition: StringRef.h:168
llvm::sys::fs::file_t
int file_t
Definition: FileSystem.h:60
llvm::errc::invalid_argument
@ invalid_argument
llvm::vfs::RedirectingFSDirIterImpl
Directory iterator implementation for RedirectingFileSystem's directory entries.
Definition: VirtualFileSystem.cpp:1234
llvm::vfs::RedirectingFileSystemParser::lookupOrCreateEntry
static RedirectingFileSystem::Entry * lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name, RedirectingFileSystem::Entry *ParentEntry=nullptr)
Definition: VirtualFileSystem.cpp:1662
getRedirectedFileStatus
static Status getRedirectedFileStatus(const Twine &OriginalPath, bool UseExternalNames, Status ExternalStatus)
Definition: VirtualFileSystem.cpp:2254
llvm::vfs::InMemoryFileSystem::setCurrentWorkingDirectory
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
Set the working directory.
Definition: VirtualFileSystem.cpp:1138
getName
static StringRef getName(Value *V)
Definition: ProvenanceAnalysisEvaluator.cpp:42
llvm::vfs::Status::isRegularFile
bool isRegularFile() const
Definition: VirtualFileSystem.cpp:100
llvm::vfs::RedirectingFileSystem::setCurrentWorkingDirectory
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
Set the working directory.
Definition: VirtualFileSystem.cpp:1324
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
M
We currently emits eax Perhaps this is what we really should generate is Is imull three or four cycles eax eax The current instruction priority is based on pattern complexity The former is more complex because it folds a load so the latter will not be emitted Perhaps we should use AddedComplexity to give LEA32r a higher priority We should always try to match LEA first since the LEA matching code does some estimate to determine whether the match is profitable if we care more about code then imull is better It s two bytes shorter than movl leal On a Pentium M
Definition: README.txt:252
llvm::vfs::RedirectingFileSystem::getCurrentWorkingDirectory
llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override
Get the working directory of this file system.
Definition: VirtualFileSystem.cpp:1319
llvm::make_range
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
Definition: iterator_range.h:53
llvm::sys::fs::current_path
std::error_code current_path(SmallVectorImpl< char > &result)
Get the current path.
llvm::vfs::getUniqueID
static sys::fs::UniqueID getUniqueID(hash_code Hash)
Definition: VirtualFileSystem.cpp:777
getVFSEntries
static void getVFSEntries(RedirectingFileSystem::Entry *SrcE, SmallVectorImpl< StringRef > &Path, SmallVectorImpl< YAMLVFSEntry > &Entries)
Definition: VirtualFileSystem.cpp:2507
Optional.h
llvm::sys::fs::directory_entry::type
file_type type() const
Definition: FileSystem.h:1385
llvm::vfs::FileSystem::PrintType::RecursiveContents
@ RecursiveContents
llvm::MemoryBuffer::getOpenFile
static ErrorOr< std::unique_ptr< MemoryBuffer > > getOpenFile(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize, bool RequiresNullTerminator=true, bool IsVolatile=false)
Given an already-open file descriptor, read the file and return a MemoryBuffer.
Definition: MemoryBuffer.cpp:498
llvm::vfs::detail::DirIterImpl::CurrentEntry
directory_entry CurrentEntry
Definition: VirtualFileSystem.h:175
FileSystem.h
llvm::sys::fs::OF_None
@ OF_None
Definition: FileSystem.h:757
type
llvm::sys::path::rbegin
reverse_iterator rbegin(StringRef path, Style style=Style::native)
Get reverse begin iterator over path.
Definition: Path.cpp:297
llvm::vfs::createPhysicalFileSystem
std::unique_ptr< FileSystem > createPhysicalFileSystem()
Create an vfs::FileSystem for the 'real' file system, as seen by the operating system.
Definition: VirtualFileSystem.cpp:381
llvm::sys::path::Style::posix
@ posix
llvm::StringRef::endswith
LLVM_NODISCARD bool endswith(StringRef Suffix) const
Check if this string ends with the given Suffix.
Definition: StringRef.h:301
llvm::vfs::InMemoryFileSystem::getCurrentWorkingDirectory
llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override
Get the working directory of this file system.
Definition: VirtualFileSystem.h:592
llvm::vfs::RedirectingFileSystem::LookupResult::E
Entry * E
The entry the looked-up path corresponds to.
Definition: VirtualFileSystem.h:854
llvm::yaml::escape
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...
Definition: YAMLParser.cpp:697
llvm::vfs::InMemoryFileSystem::dir_begin
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override
Get a directory_iterator for Dir.
Definition: VirtualFileSystem.cpp:1122
StringRef.h
P
This currently compiles esp xmm0 movsd esp eax eax esp ret We should use not the dag combiner This is because dagcombine2 needs to be able to see through the X86ISD::Wrapper which DAGCombine can t really do The code for turning x load into a single vector load is target independent and should be moved to the dag combiner The code for turning x load into a vector load can only handle a direct load from a global or a direct load from the stack It should be generalized to handle any load from P
Definition: README-SSE.txt:411
llvm::vfs::recursive_directory_iterator::recursive_directory_iterator
recursive_directory_iterator()=default
Construct an 'end' iterator.
llvm::vfs::RedirectingFileSystem::setFallthrough
void setFallthrough(bool Fallthrough)
Sets the redirection kind to Fallthrough if true or RedirectOnly otherwise.
Definition: VirtualFileSystem.cpp:1493
llvm::vfs::RedirectingFileSystemParser::parse
bool parse(yaml::Node *Root, RedirectingFileSystem *FS)
Definition: VirtualFileSystem.cpp:1954
llvm::write
Error write(MCStreamer &Out, ArrayRef< std::string > Inputs)
Definition: DWP.cpp:541
llvm::yaml::Node
Abstract base class for all Nodes.
Definition: YAMLParser.h:118
YAMLParser.h
llvm::vfs::RedirectingFileSystem::create
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 ...
Definition: VirtualFileSystem.cpp:2076
llvm::Target
Target - Wrapper for Target specific information.
Definition: TargetRegistry.h:145
llvm::sys::path::remove_leading_dotslash
StringRef remove_leading_dotslash(StringRef path, Style style=Style::native)
Remove redundant leading "./" pieces and consecutive separators.
Definition: Path.cpp:703
llvm::StringRef::npos
static constexpr size_t npos
Definition: StringRef.h:60
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1185
Path.h
llvm::vfs::InMemoryFileSystem::useNormalizedPaths
bool useNormalizedPaths() const
Return true if this file system normalizes . and .. in paths.
Definition: VirtualFileSystem.h:585
llvm::vfs::RedirectingFileSystem::NK_External
@ NK_External
Definition: VirtualFileSystem.h:732
llvm::vfs::InMemoryFileSystem::InMemoryFileSystem
InMemoryFileSystem(bool UseNormalizedPaths=true)
Definition: VirtualFileSystem.cpp:801
llvm::sys::path::is_absolute
bool is_absolute(const Twine &path, Style style=Style::native)
Is path absolute?
Definition: Path.cpp:671
ErrorHandling.h
llvm::sys::path::reverse_iterator
Reverse path iterator.
Definition: Path.h:99
llvm::vfs::InMemoryFileSystem::DirIterator::DirIterator
DirIterator(const InMemoryFileSystem *FS, const detail::InMemoryDirectory &Dir, std::string RequestedDirName)
Definition: VirtualFileSystem.cpp:1107
Content
T Content
Definition: ELFObjHandler.cpp:88
llvm::vfs::detail::DirIterImpl
An interface for virtual file systems to provide an iterator over the (non-recursive) contents of a d...
Definition: VirtualFileSystem.h:168
llvm::vfs::detail::InMemoryDirectory::const_iterator
decltype(Entries)::const_iterator const_iterator
Definition: VirtualFileSystem.cpp:754
llvm::vfs::detail::DirIterImpl::~DirIterImpl
virtual ~DirIterImpl()
llvm::errc::not_a_directory
@ not_a_directory
llvm::vfs::InMemoryFileSystem::getRealPath
std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) const override
Canonicalizes Path by combining with the current working directory and normalizing the path (e....
Definition: VirtualFileSystem.cpp:1156
llvm::vfs::detail::NewInMemoryNodeInfo
Definition: VirtualFileSystem.h:467
Errc.h
llvm::vfs::RedirectingFileSystem::Entry::getName
StringRef getName() const
Definition: VirtualFileSystem.h:757
llvm::vfs::FileSystem::status
virtual llvm::ErrorOr< Status > status(const Twine &Path)=0
Get the status of the entry at Path, if one exists.
llvm::Type
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
DenseMap.h
llvm::vfs::directory_iterator
An input iterator over the entries in a virtual path, similar to llvm::sys::fs::directory_iterator.
Definition: VirtualFileSystem.h:182
llvm::reverse
auto reverse(ContainerTy &&C, std::enable_if_t< has_rbegin< ContainerTy >::value > *=nullptr)
Definition: STLExtras.h:380
llvm::vfs::detail::InMemoryNode::getKind
InMemoryNodeKind getKind() const
Definition: VirtualFileSystem.cpp:619
llvm::sys::fs::file_type::regular_file
@ regular_file
llvm::sys::path::end
const_iterator end(StringRef path)
Get end iterator over path.
Definition: Path.cpp:235
llvm::vfs::OverlayFileSystem::getCurrentWorkingDirectory
llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override
Get the working directory of this file system.
Definition: VirtualFileSystem.cpp:452
llvm::sys::fs::all_all
@ all_all
Definition: FileSystem.h:103
llvm::sys::path::begin
const_iterator begin(StringRef path, Style style=Style::native)
Get begin iterator over path.
Definition: Path.cpp:226
llvm::Optional
Definition: APInt.h:33
llvm::DenseMapBase< DenseMap< KeyT, ValueT, DenseMapInfo< KeyT >, llvm::detail::DenseMapPair< KeyT, ValueT > >, KeyT, ValueT, DenseMapInfo< KeyT >, llvm::detail::DenseMapPair< KeyT, ValueT > >::count
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
Definition: DenseMap.h:147
llvm::sys::path::Style::windows_backslash
@ windows_backslash
llvm::errc::no_such_file_or_directory
@ no_such_file_or_directory
llvm::vfs::RedirectingFileSystem::EK_Directory
@ EK_Directory
Definition: VirtualFileSystem.h:731
llvm::vfs::FileSystem::PrintType::Contents
@ Contents
llvm::max
Expected< ExpressionValue > max(const ExpressionValue &Lhs, const ExpressionValue &Rhs)
Definition: FileCheck.cpp:337
llvm::StringSet::insert
std::pair< typename Base::iterator, bool > insert(StringRef key)
Definition: StringSet.h:34
llvm::HexagonII::Absolute
@ Absolute
Definition: HexagonBaseInfo.h:32
llvm::Expected
Tagged union holding either a T or a Error.
Definition: APFloat.h:41
llvm::codeview::Link
@ Link
Definition: CodeView.h:154
STLExtras.h
RHS
Value * RHS
Definition: X86PartialReduction.cpp:76
llvm::vfs::detail::IME_Directory
@ IME_Directory
Definition: VirtualFileSystem.cpp:595
llvm::StringRef::slice
LLVM_NODISCARD StringRef slice(size_t Start, size_t End) const
Return a reference to the substring from [Start, End).
Definition: StringRef.h:736
llvm::sys
Definition: Atomic.h:28
llvm::vfs::Status
The result of a status operation.
Definition: VirtualFileSystem.h:48
IntrusiveRefCntPtr.h
llvm::vfs::detail::InMemoryNode::getFileName
StringRef getFileName() const
Get the filename of this node (the name without the directory part).
Definition: VirtualFileSystem.cpp:618
llvm::vfs::detail::IME_SymbolicLink
@ IME_SymbolicLink
Definition: VirtualFileSystem.cpp:597
llvm::vfs::RedirectingFileSystem::openFileForRead
ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override
Get a File object for the file at Path, if one exists.
Definition: VirtualFileSystem.cpp:2384
llvm::sys::fs::set_current_path
std::error_code set_current_path(const Twine &path)
Set the current path.
llvm::MemoryBufferRef
Definition: MemoryBufferRef.h:22
llvm::MemoryBuffer
This interface provides simple read-only access to a block of memory, and provides simple methods for...
Definition: MemoryBuffer.h:50
llvm::vfs::OverlayFileSystem::getRealPath
std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) const override
Gets real path of Path e.g.
Definition: VirtualFileSystem.cpp:473
llvm::vfs::RedirectingFileSystem
A virtual file system parsed from a YAML file.
Definition: VirtualFileSystem.h:729
new
Common register allocation spilling lr str ldr sxth r3 ldr mla r4 can lr mov lr str ldr sxth r3 mla r4 and then merge mul and lr str ldr sxth r3 mla r4 It also increase the likelihood the store may become dead bb27 Successors according to LLVM ID Predecessors according to mbb< bb27, 0x8b0a7c0 > Note ADDri is not a two address instruction its result reg1037 is an operand of the PHI node in bb76 and its operand reg1039 is the result of the PHI node We should treat it as a two address code and make sure the ADDri is scheduled after any node that reads reg1039 Use info(i.e. register scavenger) to assign it a free register to allow reuse the collector could move the objects and invalidate the derived pointer This is bad enough in the first but safe points can crop up unpredictably **array_addr i32 n y store obj * new
Definition: README.txt:125
F
#define F(x, y, z)
Definition: MD5.cpp:55
llvm::vfs::RedirectingFileSystem::isLocal
std::error_code isLocal(const Twine &Path, bool &Result) override
Is the file mounted on a local filesystem?
Definition: VirtualFileSystem.cpp:1337
llvm::vfs::FileSystem::isLocal
virtual std::error_code isLocal(const Twine &Path, bool &Result)
Is the file mounted on a local filesystem?
Definition: VirtualFileSystem.cpp:145
llvm::sys::TimePoint
std::chrono::time_point< std::chrono::system_clock, D > TimePoint
A time point on the system clock.
Definition: Chrono.h:34
llvm::vfs::OverlayFileSystem::overlays_end
iterator overlays_end()
Get an iterator pointing one-past the least recently added file system.
Definition: VirtualFileSystem.h:402
Chrono.h
result
It looks like we only need to define PPCfmarto for these because according to these instructions perform RTO on fma s result
Definition: README_P9.txt:256
llvm::vfs::OverlayFileSystem::iterator
FileSystemList::reverse_iterator iterator
Definition: VirtualFileSystem.h:390
llvm::sys::path::append
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition: Path.cpp:456
llvm::dbgs
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
llvm::vfs::OverlayFileSystem::printImpl
void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override
Definition: VirtualFileSystem.cpp:481
Mappings
Inject TLI Mappings
Definition: InjectTLIMappings.cpp:171
llvm::StringRef::substr
LLVM_NODISCARD StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition: StringRef.h:615
llvm::vfs::detail::InMemoryDirectory::addChild
InMemoryNode * addChild(StringRef Name, std::unique_ptr< InMemoryNode > Child)
Definition: VirtualFileSystem.cpp:749
llvm::vfs::detail::InMemoryDirectory::getStatus
Status getStatus(const Twine &RequestedName) const override
Return the Status for this node.
Definition: VirtualFileSystem.cpp:736
LHS
Value * LHS
Definition: X86PartialReduction.cpp:75
llvm::vfs::FileSystem::dump
LLVM_DUMP_METHOD void dump() const
Definition: VirtualFileSystem.cpp:155
llvm::vfs::OverlayFileSystem::status
llvm::ErrorOr< Status > status(const Twine &Path) override
Get the status of the entry at Path, if one exists.
Definition: VirtualFileSystem.cpp:430
llvm::vfs::RedirectingFileSystem::getRealPath
std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) const override
Gets real path of Path e.g.
Definition: VirtualFileSystem.cpp:2449
llvm::orc::tpctypes::LookupResult
std::vector< JITTargetAddress > LookupResult
Definition: TargetProcessControlTypes.h:130
llvm::vfs::Status::copyWithNewName
static Status copyWithNewName(const Status &In, const Twine &NewName)
Get a copy of a Status with a different name.
Definition: VirtualFileSystem.cpp:81
llvm::sys::fs::is_local
std::error_code is_local(const Twine &path, bool &result)
Is the file mounted on a local filesystem?
llvm::MemoryBuffer::getMemBuffer
static std::unique_ptr< MemoryBuffer > getMemBuffer(StringRef InputData, StringRef BufferName="", bool RequiresNullTerminator=true)
Open the specified memory range as a MemoryBuffer.
Definition: MemoryBuffer.cpp:115
llvm::vfs::detail::InMemoryDirectory::begin
const_iterator begin() const
Definition: VirtualFileSystem.cpp:756
llvm::SMLoc
Represents a location in source code.
Definition: SMLoc.h:23
llvm::sys::fs::file_type::symlink_file
@ symlink_file
llvm::vfs::detail::InMemoryDirectory::getChild
InMemoryNode * getChild(StringRef Name) const
Definition: VirtualFileSystem.cpp:742
SmallString.h
llvm::vfs::FileSystem::getBufferForFile
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getBufferForFile(const Twine &Name, int64_t FileSize=-1, bool RequiresNullTerminator=true, bool IsVolatile=false)
This is a convenience method that opens a file, gets its content and then closes the file.
Definition: VirtualFileSystem.cpp:119
E
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
llvm::User
Definition: User.h:44
llvm::vfs::collectVFSFromYAML
void collectVFSFromYAML(std::unique_ptr< llvm::MemoryBuffer > Buffer, llvm::SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, SmallVectorImpl< YAMLVFSEntry > &CollectedEntries, void *DiagContext=nullptr, IntrusiveRefCntPtr< FileSystem > ExternalFS=getRealFileSystem())
Collect all pairs of <virtual path, real path> entries from the YAMLFilePath.
llvm::cl::Required
@ Required
Definition: CommandLine.h:117
llvm::vfs::detail::NewInMemoryNodeInfo::Buffer
std::unique_ptr< llvm::MemoryBuffer > Buffer
Definition: VirtualFileSystem.h:472
Twine.h
llvm::vfs::directory_iterator::increment
directory_iterator & increment(std::error_code &EC)
Equivalent to operator++, with an error code.
Definition: VirtualFileSystem.h:197
llvm::sys::fs::file_type::status_error
@ status_error
llvm::vfs::OverlayFileSystem::overlays_begin
iterator overlays_begin()
Get an iterator pointing to the most recently added file system.
Definition: VirtualFileSystem.h:398
llvm::vfs::FileSystem::openFileForRead
virtual llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path)=0
Get a File object for the file at Path, if one exists.
llvm::sys::path::root_path
StringRef root_path(StringRef path, Style style=Style::native)
Get root path.
Definition: Path.cpp:348
llvm::vfs
Definition: CommandLine.h:46
llvm::ms_demangle::QualifierMangleMode::Result
@ Result
llvm::sys::fs::real_path
std::error_code real_path(const Twine &path, SmallVectorImpl< char > &output, bool expand_tilde=false)
Collapse all .
llvm::AMDGPU::PALMD::Key
Key
PAL metadata keys.
Definition: AMDGPUMetadata.h:486
llvm::sys::fs::owner_all
@ owner_all
Definition: FileSystem.h:91
llvm::vfs::InMemoryFileSystem::~InMemoryFileSystem
~InMemoryFileSystem() override
llvm::vfs::RedirectingFSDirIterImpl::increment
std::error_code increment() override
Sets CurrentEntry to the next entry in the directory on success, to directory_entry() at end,...
Definition: VirtualFileSystem.cpp:1272
SMLoc.h
llvm::vfs::directory_entry::path
llvm::StringRef path() const
Definition: VirtualFileSystem.h:160
llvm::vfs::RedirectingFileSystem::Entry::getKind
EntryKind getKind() const
Definition: VirtualFileSystem.h:758
llvm::raw_ostream
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:54
llvm::vfs::FileSystem::exists
bool exists(const Twine &Path)
Check whether a file exists. Provided for convenience.
Definition: VirtualFileSystem.cpp:149
llvm::IndexedInstrProf::Version
const uint64_t Version
Definition: InstrProf.h:1027
llvm::sys::path::Style
Style
Definition: Path.h:27
llvm::sys::fs::openNativeFileForRead
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::MemoryBuffer::getBuffer
StringRef getBuffer() const
Definition: MemoryBuffer.h:69
llvm::vfs::getVFSFromYAML
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.
llvm::sys::fs::file_type
file_type
An enumeration for the file system's view of the type.
Definition: FileSystem.h:66
llvm::vfs::RedirectingFileSystem::DirectoryEntry::iterator
decltype(Contents)::iterator iterator
Definition: VirtualFileSystem.h:785
llvm::sys::fs::UniqueID::getFile
uint64_t getFile() const
Definition: UniqueID.h:48
llvm::pdb::PDB_ColorItem::Path
@ Path
llvm::SourceMgr::setDiagHandler
void setDiagHandler(DiagHandlerTy DH, void *Ctx=nullptr)
Specify a diagnostic handler to be invoked every time PrintMessage is called.
Definition: SourceMgr.h:112
llvm::vfs::directory_entry
A member of a directory, yielded by a directory_iterator.
Definition: VirtualFileSystem.h:151
llvm::StringRef::str
LLVM_NODISCARD std::string str() const
str - Get the contents as an std::string.
Definition: StringRef.h:249
llvm::StringRef::getAsInteger
std::enable_if_t< std::numeric_limits< T >::is_signed, bool > getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition: StringRef.h:514
llvm::None
const NoneType None
Definition: None.h:24
llvm::lltok::Kind
Kind
Definition: LLToken.h:18
now
static sys::TimePoint< std::chrono::seconds > now(bool Deterministic)
Definition: ArchiveWriter.cpp:327
llvm::CallingConv::ID
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
SourceMgr.h
llvm::vfs::FileSystem::PrintType::Summary
@ Summary
llvm::vfs::detail::InMemoryNode
The in memory file system is a tree of Nodes.
Definition: VirtualFileSystem.cpp:602
llvm::vfs::getDirectoryID
static sys::fs::UniqueID getDirectoryID(sys::fs::UniqueID Parent, llvm::StringRef Name)
Definition: VirtualFileSystem.cpp:786
llvm::StringMap
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition: StringMap.h:110
llvm::vfs::InMemoryFileSystem::MaxSymlinkDepth
static constexpr size_t MaxSymlinkDepth
Arbitrary max depth to search through symlinks.
Definition: VirtualFileSystem.h:559
llvm::SmallString< 128 >
llvm::vfs::detail::InMemoryDirectory::getUniqueID
UniqueID getUniqueID() const
Definition: VirtualFileSystem.cpp:740
llvm::MemoryBuffer::getBufferIdentifier
virtual StringRef getBufferIdentifier() const
Return an identifier for this buffer, typically the filename it was read from.
Definition: MemoryBuffer.h:75
llvm::Twine::str
std::string str() const
Return the twine contents as a std::string.
Definition: Twine.cpp:17
llvm::vfs::RedirectingFileSystem::getExternalContentsPrefixDir
StringRef getExternalContentsPrefixDir() const
Definition: VirtualFileSystem.cpp:1489
pathHasTraversal
static bool pathHasTraversal(StringRef Path)
Definition: VirtualFileSystem.cpp:163
llvm::vfs::Status::isOther
bool isOther() const
Definition: VirtualFileSystem.cpp:102
llvm::vfs::detail::IME_HardLink
@ IME_HardLink
Definition: VirtualFileSystem.cpp:596
llvm::tgtok::In
@ In
Definition: TGLexer.h:51
llvm::vfs::detail::InMemoryDirectory::InMemoryDirectory
InMemoryDirectory(Status Stat)
Definition: VirtualFileSystem.cpp:730
llvm::SmallString::c_str
const char * c_str()
Definition: SmallString.h:263
isTraversalComponent
static bool isTraversalComponent(StringRef Component)
Definition: VirtualFileSystem.cpp:159
llvm::sys::fs::file_type::type_unknown
@ type_unknown
llvm::vfs::RedirectingFileSystem::EntryKind
EntryKind
Definition: VirtualFileSystem.h:731
llvm::sys::fs::UniqueID
Definition: UniqueID.h:26
llvm::sys::fs::file_status
Represents the result of a call to sys::fs::status().
Definition: FileSystem.h:226
UniqueID.h
llvm::vfs::Status::getName
StringRef getName() const
Returns the name that should be used for this file or directory.
Definition: VirtualFileSystem.h:88
llvm::sys::path::remove_dots
bool remove_dots(SmallVectorImpl< char > &path, bool remove_dot_dot=false, Style style=Style::native)
In-place remove any '.
Definition: Path.cpp:715
llvm::vfs::getRealFileSystem
IntrusiveRefCntPtr< FileSystem > getRealFileSystem()
Gets an vfs::FileSystem for the 'real' file system, as seen by the operating system.
Definition: VirtualFileSystem.cpp:376
llvm::vfs::FileSystem::getCurrentWorkingDirectory
virtual llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const =0
Get the working directory of this file system.
llvm::vfs::FileSystem::printIndent
void printIndent(raw_ostream &OS, unsigned IndentLevel) const
Definition: VirtualFileSystem.h:339
llvm::vfs::YAMLVFSEntry
Definition: VirtualFileSystem.h:622
llvm::vfs::recursive_directory_iterator::increment
recursive_directory_iterator & increment(std::error_code &EC)
Equivalent to operator++, with an error code.
Definition: VirtualFileSystem.cpp:2769
llvm::StringRef::empty
constexpr LLVM_NODISCARD bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:153
uint64_t
llvm::sys::path::get_separator
StringRef get_separator(Style style=Style::native)
Return the preferred separator for this platform.
Definition: Path.cpp:609
llvm::vfs::Status::copyWithNewSize
static Status copyWithNewSize(const Status &In, uint64_t NewSize)
Get a copy of a Status with a different size.
Definition: VirtualFileSystem.cpp:75
llvm::SourceMgr::PrintMessage
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.
Definition: SourceMgr.cpp:348
llvm::vfs::detail::InMemoryFile
Definition: VirtualFileSystem.cpp:623
llvm::vfs::File::getWithPath
static ErrorOr< std::unique_ptr< File > > getWithPath(ErrorOr< std::unique_ptr< File >> Result, const Twine &P)
Definition: VirtualFileSystem.cpp:2370
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
llvm::Twine::toVector
void toVector(SmallVectorImpl< char > &Out) const
Append the concatenated string into the given SmallString or SmallVector.
Definition: Twine.cpp:32
llvm::vfs::RedirectingFileSystem::RedirectKind::Fallback
@ Fallback
Lookup the provided path first and if that fails, "fallback" to a lookup of the redirected path.
llvm::vfs::Status::isDirectory
bool isDirectory() const
Definition: VirtualFileSystem.cpp:98
llvm::DenseMap
Definition: DenseMap.h:716
llvm::vfs::InMemoryFileSystem::DirIterator::increment
std::error_code increment() override
Sets CurrentEntry to the next entry in the directory on success, to directory_entry() at end,...
Definition: VirtualFileSystem.cpp:1115
llvm::vfs::InMemoryFileSystem::toString
std::string toString() const
Definition: VirtualFileSystem.cpp:811
ErrorOr.h
llvm::SourceMgr::DiagHandlerTy
void(*)(const SMDiagnostic &, void *Context) DiagHandlerTy
Clients that want to handle their own diagnostics in a custom way can register a function pointer+con...
Definition: SourceMgr.h:43
llvm::vfs::detail::InMemoryFile::getBuffer
llvm::MemoryBuffer * getBuffer() const
Definition: VirtualFileSystem.cpp:635
I
#define I(x, y, z)
Definition: MD5.cpp:58
llvm::vfs::OverlayFileSystem::overlays_range
range overlays_range()
Definition: VirtualFileSystem.h:413
llvm::vfs::InMemoryFileSystem::DirIterator::DirIterator
DirIterator()=default
ArrayRef.h
llvm::vfs::RedirectingFileSystem::dir_begin
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override
Get a directory_iterator for Dir.
Definition: VirtualFileSystem.cpp:1385
llvm::vfs::detail::NamedNodeOrError
Definition: VirtualFileSystem.h:481
llvm::sys::path::Style::native
@ native
llvm::vfs::RedirectingFileSystem::RedirectKind::Fallthrough
@ Fallthrough
Lookup the redirected path first (ie.
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::vfs::RedirectingFileSystem::setExternalContentsPrefixDir
void setExternalContentsPrefixDir(StringRef PrefixDir)
Definition: VirtualFileSystem.cpp:1485
llvm::sys::path::parent_path
StringRef parent_path(StringRef path, Style style=Style::native)
Get parent path.
Definition: Path.cpp:467
llvm::move
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1675
llvm::X86AS::FS
@ FS
Definition: X86.h:196
llvm::SPIRV::Decoration::Stream
@ Stream
llvm::sys::fs::closeFile
std::error_code closeFile(file_t &F)
Close the file object.
llvm::codeview::CompileSym2Flags::EC
@ EC
llvm::sys::fs::directory_iterator::increment
directory_iterator & increment(std::error_code &ec)
Definition: FileSystem.h:1449
iterator_range.h
llvm::sys::fs::make_absolute
void make_absolute(const Twine &current_directory, SmallVectorImpl< char > &path)
Make path an absolute path.
Definition: Path.cpp:906
llvm::vfs::RedirectingFileSystemParser
A helper class to hold the common YAML parsing state.
Definition: VirtualFileSystem.cpp:1567
llvm::vfs::InMemoryFileSystem::addHardLink
bool addHardLink(const Twine &NewLink, const Twine &Target)
Add a hard link to a file.
Definition: VirtualFileSystem.cpp:1004
llvm::vfs::InMemoryFileSystem::status
llvm::ErrorOr< Status > status(const Twine &Path) override
Get the status of the entry at Path, if one exists.
Definition: VirtualFileSystem.cpp:1045
llvm::sys::fs::kInvalidFile
const file_t kInvalidFile
llvm::StringSet
StringSet - A wrapper for StringMap that provides set-like functionality.
Definition: StringSet.h:23
llvm::vfs::getNextVirtualUniqueID
llvm::sys::fs::UniqueID getNextVirtualUniqueID()
Get a globally unique ID for a virtual file or directory.
Definition: VirtualFileSystem.cpp:2563
llvm::ArrayRef
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: APInt.h:32
None.h
DiagHandler
static void DiagHandler(const SMDiagnostic &Diag, void *Context)
Definition: TextStub.cpp:1094
llvm::vfs::RedirectingFileSystem::getRoots
std::vector< llvm::StringRef > getRoots() const
Definition: VirtualFileSystem.cpp:1506
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:58
llvm_unreachable
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:143
llvm::SourceMgr
This owns the files read by a parser, handles include stacks, and handles diagnostic wrangling.
Definition: SourceMgr.h:31
uint32_t
Compiler.h
llvm::vfs::detail::InMemoryDirectory
Definition: VirtualFileSystem.cpp:725
llvm::vfs::detail::InMemoryDirectory::end
const_iterator end() const
Definition: VirtualFileSystem.cpp:757
llvm::yaml::Stream
This class represents a YAML stream potentially containing multiple documents.
Definition: YAMLParser.h:85
S
add sub stmia L5 ldr r0 bl L_printf $stub Instead of a and a wouldn t it be better to do three moves *Return an aggregate type is even return S
Definition: README.txt:210
llvm::vfs::InMemoryFileSystem::printImpl
void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override
Definition: VirtualFileSystem.cpp:1173
llvm::vfs::Status::getUniqueID
llvm::sys::fs::UniqueID getUniqueID() const
Definition: VirtualFileSystem.h:95
llvm::AMDGPU::HSAMD::Kernel::Arg::Key::IsVolatile
constexpr char IsVolatile[]
Key for Kernel::Arg::Metadata::mIsVolatile.
Definition: AMDGPUMetadata.h:199
llvm::vfs::detail::NewInMemoryNodeInfo::Path
StringRef Path
Definition: VirtualFileSystem.h:469
llvm::vfs::YAMLVFSWriter::write
void write(llvm::raw_ostream &OS)
Definition: VirtualFileSystem.cpp:2749
LLVM_FALLTHROUGH
#define LLVM_FALLTHROUGH
LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements.
Definition: Compiler.h:280
llvm::sys::path::const_iterator
Path iterator.
Definition: Path.h:73
llvm::vfs::File
Represents an open file.
Definition: VirtualFileSystem.h:114
llvm::vfs::Status::ExposesExternalVFSPath
bool ExposesExternalVFSPath
Whether this entity has an external path different from the virtual path, and the external path is ex...
Definition: VirtualFileSystem.h:71
VirtualFileSystem.h
llvm::vfs::directory_entry::type
llvm::sys::fs::file_type type() const
Definition: VirtualFileSystem.h:161
llvm::make_error_code
std::error_code make_error_code(BitcodeError E)
Definition: BitcodeReader.h:271
llvm::AMDGPU::SendMsg::Msg
const CustomOperand< const MCSubtargetInfo & > Msg[]
Definition: AMDGPUAsmUtils.cpp:39
llvm::vfs::Status::isSymlink
bool isSymlink() const
Definition: VirtualFileSystem.cpp:106
llvm::vfs::InMemoryFileSystem::addFileNoOwn
bool addFileNoOwn(const Twine &Path, time_t ModificationTime, const llvm::MemoryBufferRef &Buffer, Optional< uint32_t > User=None, Optional< uint32_t > Group=None, Optional< llvm::sys::fs::file_type > Type=None, Optional< llvm::sys::fs::perms > Perms=None)
Add a buffer to the VFS with a path.
Definition: VirtualFileSystem.cpp:910
StringSet.h
llvm::StringRef::size
constexpr LLVM_NODISCARD size_t size() const
size - Get the string size.
Definition: StringRef.h:157
llvm::vfs::recursive_directory_iterator
An input iterator over the recursive contents of a virtual path, similar to llvm::sys::fs::recursive_...
Definition: VirtualFileSystem.h:232
llvm::sys::fs::file_type::directory_file
@ directory_file
llvm::Twine
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:83
llvm::vfs::FileSystem::print
void print(raw_ostream &OS, PrintType Type=PrintType::Contents, unsigned IndentLevel=0) const
Definition: VirtualFileSystem.h:323
llvm::vfs::RedirectingFileSystem::EK_DirectoryRemap
@ EK_DirectoryRemap
Definition: VirtualFileSystem.h:731
llvm::vfs::FileSystem
The virtual file system interface.
Definition: VirtualFileSystem.h:268
llvm::GraphProgram::Name
Name
Definition: GraphWriter.h:50
std
Definition: BitVector.h:851
llvm::vfs::InMemoryFileSystem
An in-memory file system.
Definition: VirtualFileSystem.h:502
get
Should compile to something r4 addze r3 instead we get
Definition: README.txt:24
llvm::toString
const char * toString(DWARFSectionKind Kind)
Definition: DWARFUnitIndex.h:67
llvm::vfs::InMemoryFileSystem::DirIterator
Adaptor from InMemoryDir::iterator to directory_iterator.
Definition: VirtualFileSystem.cpp:1069
llvm::vfs::RedirectingFileSystem::LookupResult::LookupResult
LookupResult(Entry *E, sys::path::const_iterator Start, sys::path::const_iterator End)
Definition: VirtualFileSystem.cpp:2171
llvm::vfs::RedirectingFileSystem::printImpl
void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override
Definition: VirtualFileSystem.cpp:1513
llvm::vfs::detail::InMemoryNode::InMemoryNode
InMemoryNode(llvm::StringRef FileName, InMemoryNodeKind Kind)
Definition: VirtualFileSystem.cpp:607
llvm::vfs::RedirectingFileSystem::lookupPath
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...
Definition: VirtualFileSystem.cpp:2201
llvm::vfs::OverlayFileSystem::dir_begin
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override
Get a directory_iterator for Dir.
Definition: VirtualFileSystem.cpp:577
llvm::vfs::InMemoryFileSystem::addSymbolicLink
bool addSymbolicLink(const Twine &NewLink, const Twine &Target, time_t ModificationTime, Optional< uint32_t > User=None, Optional< uint32_t > Group=None, Optional< llvm::sys::fs::perms > Perms=None)
Add a symbolic link.
Definition: VirtualFileSystem.cpp:1023
Casting.h
llvm::vfs::RedirectingFileSystem::NK_Virtual
@ NK_Virtual
Definition: VirtualFileSystem.h:732
llvm::vfs::RedirectingFileSystem::NK_NotSet
@ NK_NotSet
Definition: VirtualFileSystem.h:732
llvm::sort
void sort(IteratorTy Start, IteratorTy End)
Definition: STLExtras.h:1562
llvm::TargetStackID::Value
Value
Definition: TargetFrameLowering.h:27
llvm::SourceMgr::DK_Error
@ DK_Error
Definition: SourceMgr.h:34
llvm::vfs::YAMLVFSWriter::addFileMapping
void addFileMapping(StringRef VirtualPath, StringRef RealPath)
Definition: VirtualFileSystem.cpp:2579
llvm::sys::fs::is_directory
bool is_directory(const basic_file_status &status)
Does status represent a directory?
Definition: Path.cpp:1092
llvm::vfs::RedirectingFileSystem::setRedirection
void setRedirection(RedirectingFileSystem::RedirectKind Kind)
Definition: VirtualFileSystem.cpp:1501
llvm::SmallString::str
StringRef str() const
Explicit conversion to StringRef.
Definition: SmallString.h:260
llvm::vfs::RedirectingFSDirIterImpl::RedirectingFSDirIterImpl
RedirectingFSDirIterImpl(const Twine &Path, RedirectingFileSystem::DirectoryEntry::iterator Begin, RedirectingFileSystem::DirectoryEntry::iterator End, std::error_code &EC)
Definition: VirtualFileSystem.cpp:1265
llvm::vfs::OverlayFileSystem::setCurrentWorkingDirectory
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
Set the working directory.
Definition: VirtualFileSystem.cpp:458
llvm::vfs::Status::exists
bool exists() const
Definition: VirtualFileSystem.cpp:110
llvm::errorToErrorCode
std::error_code errorToErrorCode(Error Err)
Helper for converting an ECError to a std::error_code.
Definition: Error.cpp:98
llvm::vfs::InMemoryFileSystem::isLocal
std::error_code isLocal(const Twine &Path, bool &Result) override
Is the file mounted on a local filesystem?
Definition: VirtualFileSystem.cpp:1168
llvm::vfs::File::~File
virtual ~File()
Destroy the file after closing it (if open).
llvm::vfs::OverlayFileSystem::pushOverlay
void pushOverlay(IntrusiveRefCntPtr< FileSystem > FS)
Pushes a file system on top of the stack.
Definition: VirtualFileSystem.cpp:423
llvm::Expected::takeError
Error takeError()
Take ownership of the stored error.
Definition: Error.h:597
llvm::sys::path::is_separator
bool is_separator(char value, Style style=Style::native)
Check whether the given char is a path separator on the host OS.
Definition: Path.cpp:601
llvm::sys::fs::directory_iterator
directory_iterator - Iterates through the entries in path.
Definition: FileSystem.h:1423
llvm::vfs::OverlayFileSystem::openFileForRead
llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override
Get a File object for the file at Path, if one exists.
Definition: VirtualFileSystem.cpp:441
llvm::sys::fs::perms
perms
Definition: FileSystem.h:86
llvm::vfs::detail::InMemoryFile::InMemoryFile
InMemoryFile(Status Stat, std::unique_ptr< llvm::MemoryBuffer > Buffer)
Definition: VirtualFileSystem.cpp:628
llvm::sys::path::filename
StringRef filename(StringRef path, Style style=Style::native)
Get filename.
Definition: Path.cpp:577
llvm::vfs::RedirectingFileSystemParser::RedirectingFileSystemParser
RedirectingFileSystemParser(yaml::Stream &S)
Definition: VirtualFileSystem.cpp:1951
SmallVector.h
llvm::hash_combine
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition: Hashing.h:605
llvm::raw_ostream::indent
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
Definition: raw_ostream.cpp:496
llvm::sys::fs::directory_entry::path
const std::string & path() const
Definition: FileSystem.h:1377
llvm::vfs::RedirectingFileSystem::printEntry
void printEntry(raw_ostream &OS, Entry *E, unsigned IndentLevel=0) const
Definition: VirtualFileSystem.cpp:1530
llvm::sys::fs::status
std::error_code status(const Twine &path, file_status &result, bool follow=true)
Get file status as if by POSIX stat().
N
#define N
llvm::sys::toTimePoint
TimePoint< std::chrono::seconds > toTimePoint(std::time_t T)
Convert a std::time_t to a TimePoint.
Definition: Chrono.h:45
llvm::vfs::detail::InMemoryFile::classof
static bool classof(const InMemoryNode *N)
Definition: VirtualFileSystem.cpp:641
llvm::ErrorOr
Represents either an error or a value T.
Definition: ErrorOr.h:56
llvm::vfs::FileSystem::PrintType
PrintType
Definition: VirtualFileSystem.h:322
llvm::vfs::RedirectingFileSystem::LookupResult
Represents the result of a path lookup into the RedirectingFileSystem.
Definition: VirtualFileSystem.h:852
llvm::vfs::detail::InMemoryDirectory::classof
static bool classof(const InMemoryNode *N)
Definition: VirtualFileSystem.cpp:767
llvm::vfs::detail::IME_File
@ IME_File
Definition: VirtualFileSystem.cpp:594
llvm::vfs::YAMLVFSWriter::addDirectoryMapping
void addDirectoryMapping(StringRef VirtualPath, StringRef RealPath)
Definition: VirtualFileSystem.cpp:2583
llvm::vfs::Status::getType
llvm::sys::fs::file_type getType() const
Definition: VirtualFileSystem.h:92
llvm::Optional::value
constexpr const T & value() const &
Definition: Optional.h:305
llvm::sys::path::Style::windows_slash
@ windows_slash
llvm::vfs::detail::InMemoryFile::getStatus
Status getStatus(const Twine &RequestedName) const override
Return the Status for this node.
Definition: VirtualFileSystem.cpp:632
llvm::SmallVectorImpl< char >
llvm::sys::path::rend
reverse_iterator rend(StringRef path)
Get reverse end iterator over path.
Definition: Path.cpp:306
llvm::yaml::document_iterator
Iterator abstraction for Documents over a Stream.
Definition: YAMLParser.h:587
llvm::errc::operation_not_permitted
@ operation_not_permitted
llvm::vfs::FileSystem::getRealPath
virtual std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) const
Gets real path of Path e.g.
Definition: VirtualFileSystem.cpp:140
llvm::vfs::detail::InMemoryNodeKind
InMemoryNodeKind
Definition: VirtualFileSystem.cpp:593
llvm::vfs::FileSystem::makeAbsolute
virtual std::error_code makeAbsolute(SmallVectorImpl< char > &Path) const
Make Path an absolute path.
Definition: VirtualFileSystem.cpp:128
llvm::vfs::getFileID
static sys::fs::UniqueID getFileID(sys::fs::UniqueID Parent, llvm::StringRef Name, llvm::StringRef Contents)
Definition: VirtualFileSystem.cpp:781
llvm::vfs::detail::InMemoryFile::toString
std::string toString(unsigned Indent) const override
Definition: VirtualFileSystem.cpp:637
llvm::orc::SymbolState::Resolved
@ Resolved
Queried, materialization begun.
From
BlockVerifier::State From
Definition: BlockVerifier.cpp:55
llvm::vfs::RedirectingFileSystem::makeAbsolute
std::error_code makeAbsolute(SmallVectorImpl< char > &Path) const override
Make Path an absolute path.
Definition: VirtualFileSystem.cpp:1348
llvm::vfs::Status::equivalent
bool equivalent(const Status &Other) const
Definition: VirtualFileSystem.cpp:93
raw_ostream.h
n
The same transformation can work with an even modulo with the addition of a and shrink the compare RHS by the same amount Unless the target supports that transformation probably isn t worthwhile The transformation can also easily be made to work with non zero equality for n
Definition: README.txt:685
llvm::vfs::OverlayFileSystem::isLocal
std::error_code isLocal(const Twine &Path, bool &Result) override
Is the file mounted on a local filesystem?
Definition: VirtualFileSystem.cpp:465
llvm::vfs::detail::InMemoryDirectory::toString
std::string toString(unsigned Indent) const override
Definition: VirtualFileSystem.cpp:759
llvm::vfs::InMemoryFileSystem::openFileForRead
llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override
Get a File object for the file at Path, if one exists.
Definition: VirtualFileSystem.cpp:1053
llvm::Optional::value_or
constexpr T value_or(U &&alt) const &
Definition: Optional.h:318
llvm::Value
LLVM Value Representation.
Definition: Value.h:74
llvm::vfs::detail::NewInMemoryNodeInfo::makeStatus
Status makeStatus() const
Definition: VirtualFileSystem.cpp:791
llvm::vfs::Status::isStatusKnown
bool isStatusKnown() const
Definition: VirtualFileSystem.cpp:108
Debug.h
llvm::IntrusiveRefCntPtr
A smart pointer to a reference-counted object that inherits from RefCountedBase or ThreadSafeRefCount...
Definition: IntrusiveRefCntPtr.h:168
llvm::vfs::Status::Status
Status()=default
llvm::sys::fs::openFileForRead
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.
SpecialSubKind::string
@ string
Other
Optional< std::vector< StOtherPiece > > Other
Definition: ELFYAML.cpp:1238
llvm::vfs::RedirectingFileSystem::Entry
A single file or directory in the VFS.
Definition: VirtualFileSystem.h:749
llvm::vfs::RedirectingFileSystem::RedirectKind::RedirectOnly
@ RedirectOnly
Only lookup the redirected path, do not lookup the originally provided path.
llvm::vfs::RedirectingFileSystem::RedirectKind
RedirectKind
The type of redirection to perform.
Definition: VirtualFileSystem.h:735
write
static void write(bool isBE, void *P, T V)
Definition: RuntimeDyldELF.cpp:37
llvm::vfs::FileSystem::~FileSystem
virtual ~FileSystem()
llvm::hash_code
An opaque object representing a hash code.
Definition: Hashing.h:73
llvm::vfs::OverlayFileSystem::OverlayFileSystem
OverlayFileSystem(IntrusiveRefCntPtr< FileSystem > Base)
Definition: VirtualFileSystem.cpp:419