LLVM  16.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 <optional>
50 #include <string>
51 #include <system_error>
52 #include <utility>
53 #include <vector>
54 
55 using namespace llvm;
56 using namespace llvm::vfs;
57 
64 
66  : UID(Status.getUniqueID()), MTime(Status.getLastModificationTime()),
67  User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()),
68  Type(Status.type()), Perms(Status.permissions()) {}
69 
70 Status::Status(const Twine &Name, UniqueID UID, sys::TimePoint<> MTime,
72  perms Perms)
73  : Name(Name.str()), UID(UID), MTime(MTime), User(User), Group(Group),
74  Size(Size), Type(Type), Perms(Perms) {}
75 
77  return Status(In.getName(), In.getUniqueID(), In.getLastModificationTime(),
78  In.getUser(), In.getGroup(), NewSize, In.getType(),
79  In.getPermissions());
80 }
81 
82 Status Status::copyWithNewName(const Status &In, const Twine &NewName) {
83  return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
84  In.getUser(), In.getGroup(), In.getSize(), In.getType(),
85  In.getPermissions());
86 }
87 
89  return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
90  In.getUser(), In.getGroup(), In.getSize(), In.type(),
91  In.permissions());
92 }
93 
94 bool Status::equivalent(const Status &Other) const {
95  assert(isStatusKnown() && Other.isStatusKnown());
96  return getUniqueID() == Other.getUniqueID();
97 }
98 
99 bool Status::isDirectory() const { return Type == file_type::directory_file; }
100 
101 bool Status::isRegularFile() const { return Type == file_type::regular_file; }
102 
103 bool Status::isOther() const {
104  return exists() && !isRegularFile() && !isDirectory() && !isSymlink();
105 }
106 
107 bool Status::isSymlink() const { return Type == file_type::symlink_file; }
108 
109 bool Status::isStatusKnown() const { return Type != file_type::status_error; }
110 
111 bool Status::exists() const {
112  return isStatusKnown() && Type != file_type::file_not_found;
113 }
114 
115 File::~File() = default;
116 
117 FileSystem::~FileSystem() = default;
118 
120 FileSystem::getBufferForFile(const llvm::Twine &Name, int64_t FileSize,
121  bool RequiresNullTerminator, bool IsVolatile) {
122  auto F = openFileForRead(Name);
123  if (!F)
124  return F.getError();
125 
126  return (*F)->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile);
127 }
128 
129 std::error_code FileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const {
131  return {};
132 
133  auto WorkingDir = getCurrentWorkingDirectory();
134  if (!WorkingDir)
135  return WorkingDir.getError();
136 
137  llvm::sys::fs::make_absolute(WorkingDir.get(), Path);
138  return {};
139 }
140 
141 std::error_code FileSystem::getRealPath(const Twine &Path,
142  SmallVectorImpl<char> &Output) const {
144 }
145 
146 std::error_code FileSystem::isLocal(const Twine &Path, bool &Result) {
148 }
149 
150 bool FileSystem::exists(const Twine &Path) {
151  auto Status = status(Path);
152  return Status && Status->exists();
153 }
154 
155 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
157 #endif
158 
159 #ifndef NDEBUG
161  return Component.equals("..") || Component.equals(".");
162 }
163 
164 static bool pathHasTraversal(StringRef Path) {
165  using namespace llvm::sys;
166 
167  for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path)))
168  if (isTraversalComponent(Comp))
169  return true;
170  return false;
171 }
172 #endif
173 
174 //===-----------------------------------------------------------------------===/
175 // RealFileSystem implementation
176 //===-----------------------------------------------------------------------===/
177 
178 namespace {
179 
180 /// Wrapper around a raw file descriptor.
181 class RealFile : public File {
182  friend class RealFileSystem;
183 
184  file_t FD;
185  Status S;
186  std::string RealName;
187 
188  RealFile(file_t RawFD, StringRef NewName, StringRef NewRealPathName)
189  : FD(RawFD), S(NewName, {}, {}, {}, {}, {},
191  RealName(NewRealPathName.str()) {
192  assert(FD != kInvalidFile && "Invalid or inactive file descriptor");
193  }
194 
195 public:
196  ~RealFile() override;
197 
198  ErrorOr<Status> status() override;
199  ErrorOr<std::string> getName() override;
201  int64_t FileSize,
202  bool RequiresNullTerminator,
203  bool IsVolatile) override;
204  std::error_code close() override;
205  void setPath(const Twine &Path) override;
206 };
207 
208 } // namespace
209 
210 RealFile::~RealFile() { close(); }
211 
213  assert(FD != kInvalidFile && "cannot stat closed file");
214  if (!S.isStatusKnown()) {
215  file_status RealStatus;
216  if (std::error_code EC = sys::fs::status(FD, RealStatus))
217  return EC;
218  S = Status::copyWithNewName(RealStatus, S.getName());
219  }
220  return S;
221 }
222 
224  return RealName.empty() ? S.getName().str() : RealName;
225 }
226 
228 RealFile::getBuffer(const Twine &Name, int64_t FileSize,
229  bool RequiresNullTerminator, bool IsVolatile) {
230  assert(FD != kInvalidFile && "cannot get buffer for closed file");
231  return MemoryBuffer::getOpenFile(FD, Name, FileSize, RequiresNullTerminator,
232  IsVolatile);
233 }
234 
235 std::error_code RealFile::close() {
236  std::error_code EC = sys::fs::closeFile(FD);
237  FD = kInvalidFile;
238  return EC;
239 }
240 
241 void RealFile::setPath(const Twine &Path) {
242  RealName = Path.str();
243  if (auto Status = status())
244  S = Status.get().copyWithNewName(Status.get(), Path);
245 }
246 
247 namespace {
248 
249 /// A file system according to your operating system.
250 /// This may be linked to the process's working directory, or maintain its own.
251 ///
252 /// Currently, its own working directory is emulated by storing the path and
253 /// sending absolute paths to llvm::sys::fs:: functions.
254 /// A more principled approach would be to push this down a level, modelling
255 /// the working dir as an llvm::sys::fs::WorkingDir or similar.
256 /// This would enable the use of openat()-style functions on some platforms.
257 class RealFileSystem : public FileSystem {
258 public:
259  explicit RealFileSystem(bool LinkCWDToProcess) {
260  if (!LinkCWDToProcess) {
261  SmallString<128> PWD, RealPWD;
263  return; // Awful, but nothing to do here.
264  if (llvm::sys::fs::real_path(PWD, RealPWD))
265  WD = {PWD, PWD};
266  else
267  WD = {PWD, RealPWD};
268  }
269  }
270 
271  ErrorOr<Status> status(const Twine &Path) override;
272  ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
273  directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
274 
275  llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override;
276  std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
277  std::error_code isLocal(const Twine &Path, bool &Result) override;
278  std::error_code getRealPath(const Twine &Path,
279  SmallVectorImpl<char> &Output) const override;
280 
281 protected:
282  void printImpl(raw_ostream &OS, PrintType Type,
283  unsigned IndentLevel) const override;
284 
285 private:
286  // If this FS has its own working dir, use it to make Path absolute.
287  // The returned twine is safe to use as long as both Storage and Path live.
288  Twine adjustPath(const Twine &Path, SmallVectorImpl<char> &Storage) const {
289  if (!WD)
290  return Path;
291  Path.toVector(Storage);
292  sys::fs::make_absolute(WD->Resolved, Storage);
293  return Storage;
294  }
295 
296  struct WorkingDirectory {
297  // The current working directory, without symlinks resolved. (echo $PWD).
298  SmallString<128> Specified;
299  // The current working directory, with links resolved. (readlink .).
301  };
302  std::optional<WorkingDirectory> WD;
303 };
304 
305 } // namespace
306 
308  SmallString<256> Storage;
309  sys::fs::file_status RealStatus;
310  if (std::error_code EC =
311  sys::fs::status(adjustPath(Path, Storage), RealStatus))
312  return EC;
313  return Status::copyWithNewName(RealStatus, Path);
314 }
315 
318  SmallString<256> RealName, Storage;
320  adjustPath(Name, Storage), sys::fs::OF_None, &RealName);
321  if (!FDOrErr)
322  return errorToErrorCode(FDOrErr.takeError());
323  return std::unique_ptr<File>(
324  new RealFile(*FDOrErr, Name.str(), RealName.str()));
325 }
326 
327 llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory() const {
328  if (WD)
329  return std::string(WD->Specified.str());
330 
331  SmallString<128> Dir;
332  if (std::error_code EC = llvm::sys::fs::current_path(Dir))
333  return EC;
334  return std::string(Dir.str());
335 }
336 
337 std::error_code RealFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
338  if (!WD)
339  return llvm::sys::fs::set_current_path(Path);
340 
342  adjustPath(Path, Storage).toVector(Absolute);
343  bool IsDir;
344  if (auto Err = llvm::sys::fs::is_directory(Absolute, IsDir))
345  return Err;
346  if (!IsDir)
347  return std::make_error_code(std::errc::not_a_directory);
348  if (auto Err = llvm::sys::fs::real_path(Absolute, Resolved))
349  return Err;
350  WD = {Absolute, Resolved};
351  return std::error_code();
352 }
353 
354 std::error_code RealFileSystem::isLocal(const Twine &Path, bool &Result) {
355  SmallString<256> Storage;
356  return llvm::sys::fs::is_local(adjustPath(Path, Storage), Result);
357 }
358 
359 std::error_code
360 RealFileSystem::getRealPath(const Twine &Path,
361  SmallVectorImpl<char> &Output) const {
362  SmallString<256> Storage;
363  return llvm::sys::fs::real_path(adjustPath(Path, Storage), Output);
364 }
365 
366 void RealFileSystem::printImpl(raw_ostream &OS, PrintType Type,
367  unsigned IndentLevel) const {
368  printIndent(OS, IndentLevel);
369  OS << "RealFileSystem using ";
370  if (WD)
371  OS << "own";
372  else
373  OS << "process";
374  OS << " CWD\n";
375 }
376 
378  static IntrusiveRefCntPtr<FileSystem> FS(new RealFileSystem(true));
379  return FS;
380 }
381 
382 std::unique_ptr<FileSystem> vfs::createPhysicalFileSystem() {
383  return std::make_unique<RealFileSystem>(false);
384 }
385 
386 namespace {
387 
388 class RealFSDirIter : public llvm::vfs::detail::DirIterImpl {
390 
391 public:
392  RealFSDirIter(const Twine &Path, std::error_code &EC) : Iter(Path, EC) {
393  if (Iter != llvm::sys::fs::directory_iterator())
394  CurrentEntry = directory_entry(Iter->path(), Iter->type());
395  }
396 
397  std::error_code increment() override {
398  std::error_code EC;
399  Iter.increment(EC);
400  CurrentEntry = (Iter == llvm::sys::fs::directory_iterator())
401  ? directory_entry()
402  : directory_entry(Iter->path(), Iter->type());
403  return EC;
404  }
405 };
406 
407 } // namespace
408 
409 directory_iterator RealFileSystem::dir_begin(const Twine &Dir,
410  std::error_code &EC) {
411  SmallString<128> Storage;
412  return directory_iterator(
413  std::make_shared<RealFSDirIter>(adjustPath(Dir, Storage), EC));
414 }
415 
416 //===-----------------------------------------------------------------------===/
417 // OverlayFileSystem implementation
418 //===-----------------------------------------------------------------------===/
419 
421  FSList.push_back(std::move(BaseFS));
422 }
423 
425  FSList.push_back(FS);
426  // Synchronize added file systems by duplicating the working directory from
427  // the first one in the list.
428  FS->setCurrentWorkingDirectory(getCurrentWorkingDirectory().get());
429 }
430 
432  // FIXME: handle symlinks that cross file systems
433  for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
434  ErrorOr<Status> Status = (*I)->status(Path);
436  return Status;
437  }
439 }
440 
443  // FIXME: handle symlinks that cross file systems
444  for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
445  auto Result = (*I)->openFileForRead(Path);
446  if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
447  return Result;
448  }
450 }
451 
454  // All file systems are synchronized, just take the first working directory.
455  return FSList.front()->getCurrentWorkingDirectory();
456 }
457 
458 std::error_code
460  for (auto &FS : FSList)
461  if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))
462  return EC;
463  return {};
464 }
465 
466 std::error_code OverlayFileSystem::isLocal(const Twine &Path, bool &Result) {
467  for (auto &FS : FSList)
468  if (FS->exists(Path))
469  return FS->isLocal(Path, Result);
471 }
472 
473 std::error_code
475  SmallVectorImpl<char> &Output) const {
476  for (const auto &FS : FSList)
477  if (FS->exists(Path))
478  return FS->getRealPath(Path, Output);
480 }
481 
483  unsigned IndentLevel) const {
484  printIndent(OS, IndentLevel);
485  OS << "OverlayFileSystem\n";
486  if (Type == PrintType::Summary)
487  return;
488 
489  if (Type == PrintType::Contents)
491  for (auto FS : overlays_range())
492  FS->print(OS, Type, IndentLevel + 1);
493 }
494 
496 
497 namespace {
498 
499 /// Combines and deduplicates directory entries across multiple file systems.
500 class CombiningDirIterImpl : public llvm::vfs::detail::DirIterImpl {
502 
503  /// Iterators to combine, processed in reverse order.
505  /// The iterator currently being traversed.
506  directory_iterator CurrentDirIter;
507  /// The set of names already returned as entries.
508  llvm::StringSet<> SeenNames;
509 
510  /// Sets \c CurrentDirIter to the next iterator in the list, or leaves it as
511  /// is (at its end position) if we've already gone through them all.
512  std::error_code incrementIter(bool IsFirstTime) {
513  while (!IterList.empty()) {
514  CurrentDirIter = IterList.back();
515  IterList.pop_back();
516  if (CurrentDirIter != directory_iterator())
517  break; // found
518  }
519 
520  if (IsFirstTime && CurrentDirIter == directory_iterator())
522  return {};
523  }
524 
525  std::error_code incrementDirIter(bool IsFirstTime) {
526  assert((IsFirstTime || CurrentDirIter != directory_iterator()) &&
527  "incrementing past end");
528  std::error_code EC;
529  if (!IsFirstTime)
530  CurrentDirIter.increment(EC);
531  if (!EC && CurrentDirIter == directory_iterator())
532  EC = incrementIter(IsFirstTime);
533  return EC;
534  }
535 
536  std::error_code incrementImpl(bool IsFirstTime) {
537  while (true) {
538  std::error_code EC = incrementDirIter(IsFirstTime);
539  if (EC || CurrentDirIter == directory_iterator()) {
540  CurrentEntry = directory_entry();
541  return EC;
542  }
543  CurrentEntry = *CurrentDirIter;
544  StringRef Name = llvm::sys::path::filename(CurrentEntry.path());
545  if (SeenNames.insert(Name).second)
546  return EC; // name not seen before
547  }
548  llvm_unreachable("returned above");
549  }
550 
551 public:
552  CombiningDirIterImpl(ArrayRef<FileSystemPtr> FileSystems, std::string Dir,
553  std::error_code &EC) {
554  for (auto FS : FileSystems) {
555  std::error_code FEC;
556  directory_iterator Iter = FS->dir_begin(Dir, FEC);
557  if (FEC && FEC != errc::no_such_file_or_directory) {
558  EC = FEC;
559  return;
560  }
561  if (!FEC)
562  IterList.push_back(Iter);
563  }
564  EC = incrementImpl(true);
565  }
566 
567  CombiningDirIterImpl(ArrayRef<directory_iterator> DirIters,
568  std::error_code &EC)
569  : IterList(DirIters.begin(), DirIters.end()) {
570  EC = incrementImpl(true);
571  }
572 
573  std::error_code increment() override { return incrementImpl(false); }
574 };
575 
576 } // namespace
577 
579  std::error_code &EC) {
581  std::make_shared<CombiningDirIterImpl>(FSList, Dir.str(), EC));
582  if (EC)
583  return {};
584  return Combined;
585 }
586 
587 void ProxyFileSystem::anchor() {}
588 
589 namespace llvm {
590 namespace vfs {
591 
592 namespace detail {
593 
599 };
600 
601 /// The in memory file system is a tree of Nodes. Every node can either be a
602 /// file, symlink, hardlink or a directory.
604  InMemoryNodeKind Kind;
605  std::string FileName;
606 
607 public:
609  : Kind(Kind), FileName(std::string(llvm::sys::path::filename(FileName))) {
610  }
611  virtual ~InMemoryNode() = default;
612 
613  /// Return the \p Status for this node. \p RequestedName should be the name
614  /// through which the caller referred to this node. It will override
615  /// \p Status::Name in the return value, to mimic the behavior of \p RealFile.
616  virtual Status getStatus(const Twine &RequestedName) const = 0;
617 
618  /// Get the filename of this node (the name without the directory part).
619  StringRef getFileName() const { return FileName; }
620  InMemoryNodeKind getKind() const { return Kind; }
621  virtual std::string toString(unsigned Indent) const = 0;
622 };
623 
624 class InMemoryFile : public InMemoryNode {
625  Status Stat;
626  std::unique_ptr<llvm::MemoryBuffer> Buffer;
627 
628 public:
629  InMemoryFile(Status Stat, std::unique_ptr<llvm::MemoryBuffer> Buffer)
630  : InMemoryNode(Stat.getName(), IME_File), Stat(std::move(Stat)),
631  Buffer(std::move(Buffer)) {}
632 
633  Status getStatus(const Twine &RequestedName) const override {
634  return Status::copyWithNewName(Stat, RequestedName);
635  }
636  llvm::MemoryBuffer *getBuffer() const { return Buffer.get(); }
637 
638  std::string toString(unsigned Indent) const override {
639  return (std::string(Indent, ' ') + Stat.getName() + "\n").str();
640  }
641 
642  static bool classof(const InMemoryNode *N) {
643  return N->getKind() == IME_File;
644  }
645 };
646 
647 namespace {
648 
649 class InMemoryHardLink : public InMemoryNode {
650  const InMemoryFile &ResolvedFile;
651 
652 public:
653  InMemoryHardLink(StringRef Path, const InMemoryFile &ResolvedFile)
654  : InMemoryNode(Path, IME_HardLink), ResolvedFile(ResolvedFile) {}
655  const InMemoryFile &getResolvedFile() const { return ResolvedFile; }
656 
657  Status getStatus(const Twine &RequestedName) const override {
658  return ResolvedFile.getStatus(RequestedName);
659  }
660 
661  std::string toString(unsigned Indent) const override {
662  return std::string(Indent, ' ') + "HardLink to -> " +
663  ResolvedFile.toString(0);
664  }
665 
666  static bool classof(const InMemoryNode *N) {
667  return N->getKind() == IME_HardLink;
668  }
669 };
670 
671 class InMemorySymbolicLink : public InMemoryNode {
672  std::string TargetPath;
673  Status Stat;
674 
675 public:
676  InMemorySymbolicLink(StringRef Path, StringRef TargetPath, Status Stat)
677  : InMemoryNode(Path, IME_SymbolicLink), TargetPath(std::move(TargetPath)),
678  Stat(Stat) {}
679 
680  std::string toString(unsigned Indent) const override {
681  return std::string(Indent, ' ') + "SymbolicLink to -> " + TargetPath;
682  }
683 
684  Status getStatus(const Twine &RequestedName) const override {
685  return Status::copyWithNewName(Stat, RequestedName);
686  }
687 
688  StringRef getTargetPath() const { return TargetPath; }
689 
690  static bool classof(const InMemoryNode *N) {
691  return N->getKind() == IME_SymbolicLink;
692  }
693 };
694 
695 /// Adapt a InMemoryFile for VFS' File interface. The goal is to make
696 /// \p InMemoryFileAdaptor mimic as much as possible the behavior of
697 /// \p RealFile.
698 class InMemoryFileAdaptor : public File {
699  const InMemoryFile &Node;
700  /// The name to use when returning a Status for this file.
701  std::string RequestedName;
702 
703 public:
704  explicit InMemoryFileAdaptor(const InMemoryFile &Node,
705  std::string RequestedName)
706  : Node(Node), RequestedName(std::move(RequestedName)) {}
707 
708  llvm::ErrorOr<Status> status() override {
709  return Node.getStatus(RequestedName);
710  }
711 
713  getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
714  bool IsVolatile) override {
715  llvm::MemoryBuffer *Buf = Node.getBuffer();
717  Buf->getBuffer(), Buf->getBufferIdentifier(), RequiresNullTerminator);
718  }
719 
720  std::error_code close() override { return {}; }
721 
722  void setPath(const Twine &Path) override { RequestedName = Path.str(); }
723 };
724 } // namespace
725 
727  Status Stat;
729 
730 public:
732  : InMemoryNode(Stat.getName(), IME_Directory), Stat(std::move(Stat)) {}
733 
734  /// Return the \p Status for this node. \p RequestedName should be the name
735  /// through which the caller referred to this node. It will override
736  /// \p Status::Name in the return value, to mimic the behavior of \p RealFile.
737  Status getStatus(const Twine &RequestedName) const override {
738  return Status::copyWithNewName(Stat, RequestedName);
739  }
740 
741  UniqueID getUniqueID() const { return Stat.getUniqueID(); }
742 
744  auto I = Entries.find(Name);
745  if (I != Entries.end())
746  return I->second.get();
747  return nullptr;
748  }
749 
750  InMemoryNode *addChild(StringRef Name, std::unique_ptr<InMemoryNode> Child) {
751  return Entries.insert(make_pair(Name, std::move(Child)))
752  .first->second.get();
753  }
754 
755  using const_iterator = decltype(Entries)::const_iterator;
756 
757  const_iterator begin() const { return Entries.begin(); }
758  const_iterator end() const { return Entries.end(); }
759 
760  std::string toString(unsigned Indent) const override {
761  std::string Result =
762  (std::string(Indent, ' ') + Stat.getName() + "\n").str();
763  for (const auto &Entry : Entries)
764  Result += Entry.second->toString(Indent + 2);
765  return Result;
766  }
767 
768  static bool classof(const InMemoryNode *N) {
769  return N->getKind() == IME_Directory;
770  }
771 };
772 
773 } // namespace detail
774 
775 // The UniqueID of in-memory files is derived from path and content.
776 // This avoids difficulties in creating exactly equivalent in-memory FSes,
777 // as often needed in multithreaded programs.
780  uint64_t(size_t(Hash)));
781 }
783  llvm::StringRef Name,
784  llvm::StringRef Contents) {
785  return getUniqueID(llvm::hash_combine(Parent.getFile(), Name, Contents));
786 }
788  llvm::StringRef Name) {
789  return getUniqueID(llvm::hash_combine(Parent.getFile(), Name));
790 }
791 
793  UniqueID UID =
795  ? getDirectoryID(DirUID, Name)
796  : getFileID(DirUID, Name, Buffer ? Buffer->getBuffer() : "");
797 
798  return Status(Path, UID, llvm::sys::toTimePoint(ModificationTime), User,
799  Group, Buffer ? Buffer->getBufferSize() : 0, Type, Perms);
800 }
801 
803  : Root(new detail::InMemoryDirectory(
804  Status("", getDirectoryID(llvm::sys::fs::UniqueID(), ""),
805  llvm::sys::TimePoint<>(), 0, 0, 0,
806  llvm::sys::fs::file_type::directory_file,
807  llvm::sys::fs::perms::all_all))),
808  UseNormalizedPaths(UseNormalizedPaths) {}
809 
811 
812 std::string InMemoryFileSystem::toString() const {
813  return Root->toString(/*Indent=*/0);
814 }
815 
816 bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
817  std::unique_ptr<llvm::MemoryBuffer> Buffer,
819  Optional<uint32_t> Group,
822  MakeNodeFn MakeNode) {
823  SmallString<128> Path;
824  P.toVector(Path);
825 
826  // Fix up relative paths. This just prepends the current working directory.
827  std::error_code EC = makeAbsolute(Path);
828  assert(!EC);
829  (void)EC;
830 
831  if (useNormalizedPaths())
832  llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
833 
834  if (Path.empty())
835  return false;
836 
837  detail::InMemoryDirectory *Dir = Root.get();
838  auto I = llvm::sys::path::begin(Path), E = sys::path::end(Path);
839  const auto ResolvedUser = User.value_or(0);
840  const auto ResolvedGroup = Group.value_or(0);
841  const auto ResolvedType = Type.value_or(sys::fs::file_type::regular_file);
842  const auto ResolvedPerms = Perms.value_or(sys::fs::all_all);
843  // Any intermediate directories we create should be accessible by
844  // the owner, even if Perms says otherwise for the final path.
845  const auto NewDirectoryPerms = ResolvedPerms | sys::fs::owner_all;
846  while (true) {
847  StringRef Name = *I;
848  detail::InMemoryNode *Node = Dir->getChild(Name);
849  ++I;
850  if (!Node) {
851  if (I == E) {
852  // End of the path.
853  Dir->addChild(
854  Name, MakeNode({Dir->getUniqueID(), Path, Name, ModificationTime,
855  std::move(Buffer), ResolvedUser, ResolvedGroup,
856  ResolvedType, ResolvedPerms}));
857  return true;
858  }
859 
860  // Create a new directory. Use the path up to here.
861  Status Stat(
862  StringRef(Path.str().begin(), Name.end() - Path.str().begin()),
863  getDirectoryID(Dir->getUniqueID(), Name),
864  llvm::sys::toTimePoint(ModificationTime), ResolvedUser, ResolvedGroup,
865  0, sys::fs::file_type::directory_file, NewDirectoryPerms);
866  Dir = cast<detail::InMemoryDirectory>(Dir->addChild(
867  Name, std::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
868  continue;
869  }
870 
871  if (auto *NewDir = dyn_cast<detail::InMemoryDirectory>(Node)) {
872  Dir = NewDir;
873  } else {
874  assert((isa<detail::InMemoryFile>(Node) ||
875  isa<detail::InMemoryHardLink>(Node)) &&
876  "Must be either file, hardlink or directory!");
877 
878  // Trying to insert a directory in place of a file.
879  if (I != E)
880  return false;
881 
882  // Return false only if the new file is different from the existing one.
883  if (auto Link = dyn_cast<detail::InMemoryHardLink>(Node)) {
884  return Link->getResolvedFile().getBuffer()->getBuffer() ==
885  Buffer->getBuffer();
886  }
887  return cast<detail::InMemoryFile>(Node)->getBuffer()->getBuffer() ==
888  Buffer->getBuffer();
889  }
890  }
891 }
892 
893 bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
894  std::unique_ptr<llvm::MemoryBuffer> Buffer,
896  Optional<uint32_t> Group,
899  return addFile(P, ModificationTime, std::move(Buffer), User, Group, Type,
900  Perms,
902  -> std::unique_ptr<detail::InMemoryNode> {
903  Status Stat = NNI.makeStatus();
905  return std::make_unique<detail::InMemoryDirectory>(Stat);
906  return std::make_unique<detail::InMemoryFile>(
907  Stat, std::move(NNI.Buffer));
908  });
909 }
910 
911 bool InMemoryFileSystem::addFileNoOwn(const Twine &P, time_t ModificationTime,
912  const llvm::MemoryBufferRef &Buffer,
914  Optional<uint32_t> Group,
917  return addFile(P, ModificationTime, llvm::MemoryBuffer::getMemBuffer(Buffer),
919  std::move(Perms),
921  -> std::unique_ptr<detail::InMemoryNode> {
922  Status Stat = NNI.makeStatus();
924  return std::make_unique<detail::InMemoryDirectory>(Stat);
925  return std::make_unique<detail::InMemoryFile>(
926  Stat, std::move(NNI.Buffer));
927  });
928 }
929 
931 InMemoryFileSystem::lookupNode(const Twine &P, bool FollowFinalSymlink,
932  size_t SymlinkDepth) const {
933  SmallString<128> Path;
934  P.toVector(Path);
935 
936  // Fix up relative paths. This just prepends the current working directory.
937  std::error_code EC = makeAbsolute(Path);
938  assert(!EC);
939  (void)EC;
940 
941  if (useNormalizedPaths())
942  llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
943 
944  const detail::InMemoryDirectory *Dir = Root.get();
945  if (Path.empty())
946  return detail::NamedNodeOrError(Path, Dir);
947 
948  auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path);
949  while (true) {
950  detail::InMemoryNode *Node = Dir->getChild(*I);
951  ++I;
952  if (!Node)
954 
955  if (auto Symlink = dyn_cast<detail::InMemorySymbolicLink>(Node)) {
956  // If we're at the end of the path, and we're not following through
957  // terminal symlinks, then we're done.
958  if (I == E && !FollowFinalSymlink)
959  return detail::NamedNodeOrError(Path, Symlink);
960 
961  if (SymlinkDepth > InMemoryFileSystem::MaxSymlinkDepth)
963 
964  SmallString<128> TargetPath = Symlink->getTargetPath();
965  if (std::error_code EC = makeAbsolute(TargetPath))
966  return EC;
967 
968  // Keep going with the target. We always want to follow symlinks here
969  // because we're either at the end of a path that we want to follow, or
970  // not at the end of a path, in which case we need to follow the symlink
971  // regardless.
972  auto Target =
973  lookupNode(TargetPath, /*FollowFinalSymlink=*/true, SymlinkDepth + 1);
974  if (!Target || I == E)
975  return Target;
976 
977  if (!isa<detail::InMemoryDirectory>(*Target))
979 
980  // Otherwise, continue on the search in the symlinked directory.
981  Dir = cast<detail::InMemoryDirectory>(*Target);
982  continue;
983  }
984 
985  // Return the file if it's at the end of the path.
986  if (auto File = dyn_cast<detail::InMemoryFile>(Node)) {
987  if (I == E)
988  return detail::NamedNodeOrError(Path, File);
990  }
991 
992  // If Node is HardLink then return the resolved file.
993  if (auto File = dyn_cast<detail::InMemoryHardLink>(Node)) {
994  if (I == E)
995  return detail::NamedNodeOrError(Path, &File->getResolvedFile());
997  }
998  // Traverse directories.
999  Dir = cast<detail::InMemoryDirectory>(Node);
1000  if (I == E)
1001  return detail::NamedNodeOrError(Path, Dir);
1002  }
1003 }
1004 
1006  const Twine &Target) {
1007  auto NewLinkNode = lookupNode(NewLink, /*FollowFinalSymlink=*/false);
1008  // Whether symlinks in the hardlink target are followed is
1009  // implementation-defined in POSIX.
1010  // We're following symlinks here to be consistent with macOS.
1011  auto TargetNode = lookupNode(Target, /*FollowFinalSymlink=*/true);
1012  // FromPath must not have been added before. ToPath must have been added
1013  // before. Resolved ToPath must be a File.
1014  if (!TargetNode || NewLinkNode || !isa<detail::InMemoryFile>(*TargetNode))
1015  return false;
1016  return addFile(NewLink, 0, nullptr, None, None, None, None,
1017  [&](detail::NewInMemoryNodeInfo NNI) {
1018  return std::make_unique<detail::InMemoryHardLink>(
1019  NNI.Path.str(),
1020  *cast<detail::InMemoryFile>(*TargetNode));
1021  });
1022 }
1023 
1025  const Twine &Target,
1026  time_t ModificationTime,
1028  Optional<uint32_t> Group,
1030  auto NewLinkNode = lookupNode(NewLink, /*FollowFinalSymlink=*/false);
1031  if (NewLinkNode)
1032  return false;
1033 
1034  SmallString<128> NewLinkStr, TargetStr;
1035  NewLink.toVector(NewLinkStr);
1036  Target.toVector(TargetStr);
1037 
1038  return addFile(NewLinkStr, ModificationTime, nullptr, User, Group,
1040  [&](detail::NewInMemoryNodeInfo NNI) {
1041  return std::make_unique<detail::InMemorySymbolicLink>(
1042  NewLinkStr, TargetStr, NNI.makeStatus());
1043  });
1044 }
1045 
1047  auto Node = lookupNode(Path, /*FollowFinalSymlink=*/true);
1048  if (Node)
1049  return (*Node)->getStatus(Path);
1050  return Node.getError();
1051 }
1052 
1055  auto Node = lookupNode(Path,/*FollowFinalSymlink=*/true);
1056  if (!Node)
1057  return Node.getError();
1058 
1059  // When we have a file provide a heap-allocated wrapper for the memory buffer
1060  // to match the ownership semantics for File.
1061  if (auto *F = dyn_cast<detail::InMemoryFile>(*Node))
1062  return std::unique_ptr<File>(
1063  new detail::InMemoryFileAdaptor(*F, Path.str()));
1064 
1065  // FIXME: errc::not_a_file?
1067 }
1068 
1069 /// Adaptor from InMemoryDir::iterator to directory_iterator.
1071  const InMemoryFileSystem *FS;
1074  std::string RequestedDirName;
1075 
1076  void setCurrentEntry() {
1077  if (I != E) {
1078  SmallString<256> Path(RequestedDirName);
1079  llvm::sys::path::append(Path, I->second->getFileName());
1081  switch (I->second->getKind()) {
1082  case detail::IME_File:
1083  case detail::IME_HardLink:
1085  break;
1086  case detail::IME_Directory:
1088  break;
1090  if (auto SymlinkTarget =
1091  FS->lookupNode(Path, /*FollowFinalSymlink=*/true)) {
1092  Path = SymlinkTarget.getName();
1093  Type = (*SymlinkTarget)->getStatus(Path).getType();
1094  }
1095  break;
1096  }
1097  CurrentEntry = directory_entry(std::string(Path.str()), Type);
1098  } else {
1099  // When we're at the end, make CurrentEntry invalid and DirIterImpl will
1100  // do the rest.
1102  }
1103  }
1104 
1105 public:
1106  DirIterator() = default;
1107 
1109  const detail::InMemoryDirectory &Dir,
1110  std::string RequestedDirName)
1111  : FS(FS), I(Dir.begin()), E(Dir.end()),
1112  RequestedDirName(std::move(RequestedDirName)) {
1113  setCurrentEntry();
1114  }
1115 
1116  std::error_code increment() override {
1117  ++I;
1118  setCurrentEntry();
1119  return {};
1120  }
1121 };
1122 
1124  std::error_code &EC) {
1125  auto Node = lookupNode(Dir, /*FollowFinalSymlink=*/true);
1126  if (!Node) {
1127  EC = Node.getError();
1128  return directory_iterator(std::make_shared<DirIterator>());
1129  }
1130 
1131  if (auto *DirNode = dyn_cast<detail::InMemoryDirectory>(*Node))
1132  return directory_iterator(
1133  std::make_shared<DirIterator>(this, *DirNode, Dir.str()));
1134 
1136  return directory_iterator(std::make_shared<DirIterator>());
1137 }
1138 
1140  SmallString<128> Path;
1141  P.toVector(Path);
1142 
1143  // Fix up relative paths. This just prepends the current working directory.
1144  std::error_code EC = makeAbsolute(Path);
1145  assert(!EC);
1146  (void)EC;
1147 
1148  if (useNormalizedPaths())
1149  llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
1150 
1151  if (!Path.empty())
1152  WorkingDirectory = std::string(Path.str());
1153  return {};
1154 }
1155 
1156 std::error_code
1158  SmallVectorImpl<char> &Output) const {
1159  auto CWD = getCurrentWorkingDirectory();
1160  if (!CWD || CWD->empty())
1162  Path.toVector(Output);
1163  if (auto EC = makeAbsolute(Output))
1164  return EC;
1165  llvm::sys::path::remove_dots(Output, /*remove_dot_dot=*/true);
1166  return {};
1167 }
1168 
1169 std::error_code InMemoryFileSystem::isLocal(const Twine &Path, bool &Result) {
1170  Result = false;
1171  return {};
1172 }
1173 
1175  unsigned IndentLevel) const {
1176  printIndent(OS, IndentLevel);
1177  OS << "InMemoryFileSystem\n";
1178 }
1179 
1180 } // namespace vfs
1181 } // namespace llvm
1182 
1183 //===-----------------------------------------------------------------------===/
1184 // RedirectingFileSystem implementation
1185 //===-----------------------------------------------------------------------===/
1186 
1187 namespace {
1188 
1189 static llvm::sys::path::Style getExistingStyle(llvm::StringRef Path) {
1190  // Detect the path style in use by checking the first separator.
1192  const size_t n = Path.find_first_of("/\\");
1193  // Can't distinguish between posix and windows_slash here.
1194  if (n != static_cast<size_t>(-1))
1195  style = (Path[n] == '/') ? llvm::sys::path::Style::posix
1197  return style;
1198 }
1199 
1200 /// Removes leading "./" as well as path components like ".." and ".".
1201 static llvm::SmallString<256> canonicalize(llvm::StringRef Path) {
1202  // First detect the path style in use by checking the first separator.
1203  llvm::sys::path::Style style = getExistingStyle(Path);
1204 
1205  // Now remove the dots. Explicitly specifying the path style prevents the
1206  // direction of the slashes from changing.
1209  llvm::sys::path::remove_dots(result, /*remove_dot_dot=*/true, style);
1210  return result;
1211 }
1212 
1213 /// Whether the error and entry specify a file/directory that was not found.
1214 static bool isFileNotFound(std::error_code EC,
1215  RedirectingFileSystem::Entry *E = nullptr) {
1216  if (E && !isa<RedirectingFileSystem::DirectoryRemapEntry>(E))
1217  return false;
1219 }
1220 
1221 } // anonymous namespace
1222 
1223 
1224 RedirectingFileSystem::RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> FS)
1225  : ExternalFS(std::move(FS)) {
1226  if (ExternalFS)
1227  if (auto ExternalWorkingDirectory =
1228  ExternalFS->getCurrentWorkingDirectory()) {
1229  WorkingDirectory = *ExternalWorkingDirectory;
1230  }
1231 }
1232 
1233 /// Directory iterator implementation for \c RedirectingFileSystem's
1234 /// directory entries.
1237  std::string Dir;
1239 
1240  std::error_code incrementImpl(bool IsFirstTime) {
1241  assert((IsFirstTime || Current != End) && "cannot iterate past end");
1242  if (!IsFirstTime)
1243  ++Current;
1244  if (Current != End) {
1245  SmallString<128> PathStr(Dir);
1246  llvm::sys::path::append(PathStr, (*Current)->getName());
1248  switch ((*Current)->getKind()) {
1250  [[fallthrough]];
1253  break;
1256  break;
1257  }
1258  CurrentEntry = directory_entry(std::string(PathStr.str()), Type);
1259  } else {
1261  }
1262  return {};
1263  };
1264 
1265 public:
1268  RedirectingFileSystem::DirectoryEntry::iterator End, std::error_code &EC)
1269  : Dir(Path.str()), Current(Begin), End(End) {
1270  EC = incrementImpl(/*IsFirstTime=*/true);
1271  }
1272 
1273  std::error_code increment() override {
1274  return incrementImpl(/*IsFirstTime=*/false);
1275  }
1276 };
1277 
1278 namespace {
1279 /// Directory iterator implementation for \c RedirectingFileSystem's
1280 /// directory remap entries that maps the paths reported by the external
1281 /// file system's directory iterator back to the virtual directory's path.
1282 class RedirectingFSDirRemapIterImpl : public llvm::vfs::detail::DirIterImpl {
1283  std::string Dir;
1284  llvm::sys::path::Style DirStyle;
1285  llvm::vfs::directory_iterator ExternalIter;
1286 
1287 public:
1288  RedirectingFSDirRemapIterImpl(std::string DirPath,
1290  : Dir(std::move(DirPath)), DirStyle(getExistingStyle(Dir)),
1291  ExternalIter(ExtIter) {
1292  if (ExternalIter != llvm::vfs::directory_iterator())
1293  setCurrentEntry();
1294  }
1295 
1296  void setCurrentEntry() {
1297  StringRef ExternalPath = ExternalIter->path();
1298  llvm::sys::path::Style ExternalStyle = getExistingStyle(ExternalPath);
1299  StringRef File = llvm::sys::path::filename(ExternalPath, ExternalStyle);
1300 
1301  SmallString<128> NewPath(Dir);
1302  llvm::sys::path::append(NewPath, DirStyle, File);
1303 
1304  CurrentEntry = directory_entry(std::string(NewPath), ExternalIter->type());
1305  }
1306 
1307  std::error_code increment() override {
1308  std::error_code EC;
1309  ExternalIter.increment(EC);
1310  if (!EC && ExternalIter != llvm::vfs::directory_iterator())
1311  setCurrentEntry();
1312  else
1313  CurrentEntry = directory_entry();
1314  return EC;
1315  }
1316 };
1317 } // namespace
1318 
1321  return WorkingDirectory;
1322 }
1323 
1324 std::error_code
1326  // Don't change the working directory if the path doesn't exist.
1327  if (!exists(Path))
1329 
1330  SmallString<128> AbsolutePath;
1331  Path.toVector(AbsolutePath);
1332  if (std::error_code EC = makeAbsolute(AbsolutePath))
1333  return EC;
1334  WorkingDirectory = std::string(AbsolutePath.str());
1335  return {};
1336 }
1337 
1338 std::error_code RedirectingFileSystem::isLocal(const Twine &Path_,
1339  bool &Result) {
1340  SmallString<256> Path;
1341  Path_.toVector(Path);
1342 
1343  if (std::error_code EC = makeCanonical(Path))
1344  return {};
1345 
1346  return ExternalFS->isLocal(Path, Result);
1347 }
1348 
1350  // is_absolute(..., Style::windows_*) accepts paths with both slash types.
1354  return {};
1355 
1356  auto WorkingDir = getCurrentWorkingDirectory();
1357  if (!WorkingDir)
1358  return WorkingDir.getError();
1359 
1360  // We can't use sys::fs::make_absolute because that assumes the path style
1361  // is native and there is no way to override that. Since we know WorkingDir
1362  // is absolute, we can use it to determine which style we actually have and
1363  // append Path ourselves.
1365  if (sys::path::is_absolute(WorkingDir.get(), sys::path::Style::posix)) {
1366  style = sys::path::Style::posix;
1367  } else {
1368  // Distinguish between windows_backslash and windows_slash; getExistingStyle
1369  // returns posix for a path with windows_slash.
1370  if (getExistingStyle(WorkingDir.get()) !=
1373  }
1374 
1375  std::string Result = WorkingDir.get();
1376  StringRef Dir(Result);
1377  if (!Dir.endswith(sys::path::get_separator(style))) {
1378  Result += sys::path::get_separator(style);
1379  }
1380  Result.append(Path.data(), Path.size());
1381  Path.assign(Result.begin(), Result.end());
1382 
1383  return {};
1384 }
1385 
1387  std::error_code &EC) {
1388  SmallString<256> Path;
1389  Dir.toVector(Path);
1390 
1391  EC = makeCanonical(Path);
1392  if (EC)
1393  return {};
1394 
1396  if (!Result) {
1397  if (Redirection != RedirectKind::RedirectOnly &&
1398  isFileNotFound(Result.getError()))
1399  return ExternalFS->dir_begin(Path, EC);
1400 
1401  EC = Result.getError();
1402  return {};
1403  }
1404 
1405  // Use status to make sure the path exists and refers to a directory.
1406  ErrorOr<Status> S = status(Path, Dir, *Result);
1407  if (!S) {
1408  if (Redirection != RedirectKind::RedirectOnly &&
1409  isFileNotFound(S.getError(), Result->E))
1410  return ExternalFS->dir_begin(Dir, EC);
1411 
1412  EC = S.getError();
1413  return {};
1414  }
1415 
1416  if (!S->isDirectory()) {
1417  EC = errc::not_a_directory;
1418  return {};
1419  }
1420 
1421  // Create the appropriate directory iterator based on whether we found a
1422  // DirectoryRemapEntry or DirectoryEntry.
1423  directory_iterator RedirectIter;
1424  std::error_code RedirectEC;
1425  if (auto ExtRedirect = Result->getExternalRedirect()) {
1426  auto RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
1427  RedirectIter = ExternalFS->dir_begin(*ExtRedirect, RedirectEC);
1428 
1429  if (!RE->useExternalName(UseExternalNames)) {
1430  // Update the paths in the results to use the virtual directory's path.
1431  RedirectIter =
1432  directory_iterator(std::make_shared<RedirectingFSDirRemapIterImpl>(
1433  std::string(Path), RedirectIter));
1434  }
1435  } else {
1436  auto DE = cast<DirectoryEntry>(Result->E);
1437  RedirectIter =
1438  directory_iterator(std::make_shared<RedirectingFSDirIterImpl>(
1439  Path, DE->contents_begin(), DE->contents_end(), RedirectEC));
1440  }
1441 
1442  if (RedirectEC) {
1443  if (RedirectEC != errc::no_such_file_or_directory) {
1444  EC = RedirectEC;
1445  return {};
1446  }
1447  RedirectIter = {};
1448  }
1449 
1450  if (Redirection == RedirectKind::RedirectOnly) {
1451  EC = RedirectEC;
1452  return RedirectIter;
1453  }
1454 
1455  std::error_code ExternalEC;
1456  directory_iterator ExternalIter = ExternalFS->dir_begin(Path, ExternalEC);
1457  if (ExternalEC) {
1458  if (ExternalEC != errc::no_such_file_or_directory) {
1459  EC = ExternalEC;
1460  return {};
1461  }
1462  ExternalIter = {};
1463  }
1464 
1466  switch (Redirection) {
1468  Iters.push_back(ExternalIter);
1469  Iters.push_back(RedirectIter);
1470  break;
1472  Iters.push_back(RedirectIter);
1473  Iters.push_back(ExternalIter);
1474  break;
1475  default:
1476  llvm_unreachable("unhandled RedirectKind");
1477  }
1478 
1479  directory_iterator Combined{
1480  std::make_shared<CombiningDirIterImpl>(Iters, EC)};
1481  if (EC)
1482  return {};
1483  return Combined;
1484 }
1485 
1487  ExternalContentsPrefixDir = PrefixDir.str();
1488 }
1489 
1491  return ExternalContentsPrefixDir;
1492 }
1493 
1495  if (Fallthrough) {
1497  } else {
1499  }
1500 }
1501 
1504  Redirection = Kind;
1505 }
1506 
1507 std::vector<StringRef> RedirectingFileSystem::getRoots() const {
1508  std::vector<StringRef> R;
1509  for (const auto &Root : Roots)
1510  R.push_back(Root->getName());
1511  return R;
1512 }
1513 
1515  unsigned IndentLevel) const {
1516  printIndent(OS, IndentLevel);
1517  OS << "RedirectingFileSystem (UseExternalNames: "
1518  << (UseExternalNames ? "true" : "false") << ")\n";
1519  if (Type == PrintType::Summary)
1520  return;
1521 
1522  for (const auto &Root : Roots)
1523  printEntry(OS, Root.get(), IndentLevel);
1524 
1525  printIndent(OS, IndentLevel);
1526  OS << "ExternalFS:\n";
1527  ExternalFS->print(OS, Type == PrintType::Contents ? PrintType::Summary : Type,
1528  IndentLevel + 1);
1529 }
1530 
1533  unsigned IndentLevel) const {
1534  printIndent(OS, IndentLevel);
1535  OS << "'" << E->getName() << "'";
1536 
1537  switch (E->getKind()) {
1538  case EK_Directory: {
1539  auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(E);
1540 
1541  OS << "\n";
1542  for (std::unique_ptr<Entry> &SubEntry :
1543  llvm::make_range(DE->contents_begin(), DE->contents_end()))
1544  printEntry(OS, SubEntry.get(), IndentLevel + 1);
1545  break;
1546  }
1547  case EK_DirectoryRemap:
1548  case EK_File: {
1549  auto *RE = cast<RedirectingFileSystem::RemapEntry>(E);
1550  OS << " -> '" << RE->getExternalContentsPath() << "'";
1551  switch (RE->getUseName()) {
1552  case NK_NotSet:
1553  break;
1554  case NK_External:
1555  OS << " (UseExternalName: true)";
1556  break;
1557  case NK_Virtual:
1558  OS << " (UseExternalName: false)";
1559  break;
1560  }
1561  OS << "\n";
1562  break;
1563  }
1564  }
1565 }
1566 
1567 /// A helper class to hold the common YAML parsing state.
1569  yaml::Stream &Stream;
1570 
1571  void error(yaml::Node *N, const Twine &Msg) { Stream.printError(N, Msg); }
1572 
1573  // false on error
1574  bool parseScalarString(yaml::Node *N, StringRef &Result,
1575  SmallVectorImpl<char> &Storage) {
1576  const auto *S = dyn_cast<yaml::ScalarNode>(N);
1577 
1578  if (!S) {
1579  error(N, "expected string");
1580  return false;
1581  }
1582  Result = S->getValue(Storage);
1583  return true;
1584  }
1585 
1586  // false on error
1587  bool parseScalarBool(yaml::Node *N, bool &Result) {
1588  SmallString<5> Storage;
1589  StringRef Value;
1590  if (!parseScalarString(N, Value, Storage))
1591  return false;
1592 
1593  if (Value.equals_insensitive("true") || Value.equals_insensitive("on") ||
1594  Value.equals_insensitive("yes") || Value == "1") {
1595  Result = true;
1596  return true;
1597  } else if (Value.equals_insensitive("false") ||
1598  Value.equals_insensitive("off") ||
1599  Value.equals_insensitive("no") || Value == "0") {
1600  Result = false;
1601  return true;
1602  }
1603 
1604  error(N, "expected boolean value");
1605  return false;
1606  }
1607 
1608  std::optional<RedirectingFileSystem::RedirectKind>
1609  parseRedirectKind(yaml::Node *N) {
1610  SmallString<12> Storage;
1611  StringRef Value;
1612  if (!parseScalarString(N, Value, Storage))
1613  return None;
1614 
1615  if (Value.equals_insensitive("fallthrough")) {
1617  } else if (Value.equals_insensitive("fallback")) {
1619  } else if (Value.equals_insensitive("redirect-only")) {
1621  }
1622  return None;
1623  }
1624 
1625  struct KeyStatus {
1626  bool Required;
1627  bool Seen = false;
1628 
1629  KeyStatus(bool Required = false) : Required(Required) {}
1630  };
1631 
1632  using KeyStatusPair = std::pair<StringRef, KeyStatus>;
1633 
1634  // false on error
1635  bool checkDuplicateOrUnknownKey(yaml::Node *KeyNode, StringRef Key,
1637  if (!Keys.count(Key)) {
1638  error(KeyNode, "unknown key");
1639  return false;
1640  }
1641  KeyStatus &S = Keys[Key];
1642  if (S.Seen) {
1643  error(KeyNode, Twine("duplicate key '") + Key + "'");
1644  return false;
1645  }
1646  S.Seen = true;
1647  return true;
1648  }
1649 
1650  // false on error
1651  bool checkMissingKeys(yaml::Node *Obj, DenseMap<StringRef, KeyStatus> &Keys) {
1652  for (const auto &I : Keys) {
1653  if (I.second.Required && !I.second.Seen) {
1654  error(Obj, Twine("missing key '") + I.first + "'");
1655  return false;
1656  }
1657  }
1658  return true;
1659  }
1660 
1661 public:
1664  RedirectingFileSystem::Entry *ParentEntry = nullptr) {
1665  if (!ParentEntry) { // Look for a existent root
1666  for (const auto &Root : FS->Roots) {
1667  if (Name.equals(Root->getName())) {
1668  ParentEntry = Root.get();
1669  return ParentEntry;
1670  }
1671  }
1672  } else { // Advance to the next component
1673  auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
1674  for (std::unique_ptr<RedirectingFileSystem::Entry> &Content :
1675  llvm::make_range(DE->contents_begin(), DE->contents_end())) {
1676  auto *DirContent =
1677  dyn_cast<RedirectingFileSystem::DirectoryEntry>(Content.get());
1678  if (DirContent && Name.equals(Content->getName()))
1679  return DirContent;
1680  }
1681  }
1682 
1683  // ... or create a new one
1684  std::unique_ptr<RedirectingFileSystem::Entry> E =
1685  std::make_unique<RedirectingFileSystem::DirectoryEntry>(
1686  Name, Status("", getNextVirtualUniqueID(),
1687  std::chrono::system_clock::now(), 0, 0, 0,
1688  file_type::directory_file, sys::fs::all_all));
1689 
1690  if (!ParentEntry) { // Add a new root to the overlay
1691  FS->Roots.push_back(std::move(E));
1692  ParentEntry = FS->Roots.back().get();
1693  return ParentEntry;
1694  }
1695 
1696  auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
1697  DE->addContent(std::move(E));
1698  return DE->getLastContent();
1699  }
1700 
1701 private:
1702  void uniqueOverlayTree(RedirectingFileSystem *FS,
1704  RedirectingFileSystem::Entry *NewParentE = nullptr) {
1705  StringRef Name = SrcE->getName();
1706  switch (SrcE->getKind()) {
1708  auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
1709  // Empty directories could be present in the YAML as a way to
1710  // describe a file for a current directory after some of its subdir
1711  // is parsed. This only leads to redundant walks, ignore it.
1712  if (!Name.empty())
1713  NewParentE = lookupOrCreateEntry(FS, Name, NewParentE);
1714  for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
1715  llvm::make_range(DE->contents_begin(), DE->contents_end()))
1716  uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
1717  break;
1718  }
1720  assert(NewParentE && "Parent entry must exist");
1721  auto *DR = cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
1722  auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
1723  DE->addContent(
1724  std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
1725  Name, DR->getExternalContentsPath(), DR->getUseName()));
1726  break;
1727  }
1729  assert(NewParentE && "Parent entry must exist");
1730  auto *FE = cast<RedirectingFileSystem::FileEntry>(SrcE);
1731  auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
1732  DE->addContent(std::make_unique<RedirectingFileSystem::FileEntry>(
1733  Name, FE->getExternalContentsPath(), FE->getUseName()));
1734  break;
1735  }
1736  }
1737  }
1738 
1739  std::unique_ptr<RedirectingFileSystem::Entry>
1740  parseEntry(yaml::Node *N, RedirectingFileSystem *FS, bool IsRootEntry) {
1741  auto *M = dyn_cast<yaml::MappingNode>(N);
1742  if (!M) {
1743  error(N, "expected mapping node for file or directory entry");
1744  return nullptr;
1745  }
1746 
1747  KeyStatusPair Fields[] = {
1748  KeyStatusPair("name", true),
1749  KeyStatusPair("type", true),
1750  KeyStatusPair("contents", false),
1751  KeyStatusPair("external-contents", false),
1752  KeyStatusPair("use-external-name", false),
1753  };
1754 
1755  DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
1756 
1757  enum { CF_NotSet, CF_List, CF_External } ContentsField = CF_NotSet;
1758  std::vector<std::unique_ptr<RedirectingFileSystem::Entry>>
1759  EntryArrayContents;
1760  SmallString<256> ExternalContentsPath;
1762  yaml::Node *NameValueNode = nullptr;
1763  auto UseExternalName = RedirectingFileSystem::NK_NotSet;
1765 
1766  for (auto &I : *M) {
1767  StringRef Key;
1768  // Reuse the buffer for key and value, since we don't look at key after
1769  // parsing value.
1770  SmallString<256> Buffer;
1771  if (!parseScalarString(I.getKey(), Key, Buffer))
1772  return nullptr;
1773 
1774  if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys))
1775  return nullptr;
1776 
1777  StringRef Value;
1778  if (Key == "name") {
1779  if (!parseScalarString(I.getValue(), Value, Buffer))
1780  return nullptr;
1781 
1782  NameValueNode = I.getValue();
1783  // Guarantee that old YAML files containing paths with ".." and "."
1784  // are properly canonicalized before read into the VFS.
1785  Name = canonicalize(Value).str();
1786  } else if (Key == "type") {
1787  if (!parseScalarString(I.getValue(), Value, Buffer))
1788  return nullptr;
1789  if (Value == "file")
1791  else if (Value == "directory")
1793  else if (Value == "directory-remap")
1795  else {
1796  error(I.getValue(), "unknown value for 'type'");
1797  return nullptr;
1798  }
1799  } else if (Key == "contents") {
1800  if (ContentsField != CF_NotSet) {
1801  error(I.getKey(),
1802  "entry already has 'contents' or 'external-contents'");
1803  return nullptr;
1804  }
1805  ContentsField = CF_List;
1806  auto *Contents = dyn_cast<yaml::SequenceNode>(I.getValue());
1807  if (!Contents) {
1808  // FIXME: this is only for directories, what about files?
1809  error(I.getValue(), "expected array");
1810  return nullptr;
1811  }
1812 
1813  for (auto &I : *Contents) {
1814  if (std::unique_ptr<RedirectingFileSystem::Entry> E =
1815  parseEntry(&I, FS, /*IsRootEntry*/ false))
1816  EntryArrayContents.push_back(std::move(E));
1817  else
1818  return nullptr;
1819  }
1820  } else if (Key == "external-contents") {
1821  if (ContentsField != CF_NotSet) {
1822  error(I.getKey(),
1823  "entry already has 'contents' or 'external-contents'");
1824  return nullptr;
1825  }
1826  ContentsField = CF_External;
1827  if (!parseScalarString(I.getValue(), Value, Buffer))
1828  return nullptr;
1829 
1830  SmallString<256> FullPath;
1831  if (FS->IsRelativeOverlay) {
1832  FullPath = FS->getExternalContentsPrefixDir();
1833  assert(!FullPath.empty() &&
1834  "External contents prefix directory must exist");
1835  llvm::sys::path::append(FullPath, Value);
1836  } else {
1837  FullPath = Value;
1838  }
1839 
1840  // Guarantee that old YAML files containing paths with ".." and "."
1841  // are properly canonicalized before read into the VFS.
1842  FullPath = canonicalize(FullPath);
1843  ExternalContentsPath = FullPath.str();
1844  } else if (Key == "use-external-name") {
1845  bool Val;
1846  if (!parseScalarBool(I.getValue(), Val))
1847  return nullptr;
1848  UseExternalName = Val ? RedirectingFileSystem::NK_External
1850  } else {
1851  llvm_unreachable("key missing from Keys");
1852  }
1853  }
1854 
1855  if (Stream.failed())
1856  return nullptr;
1857 
1858  // check for missing keys
1859  if (ContentsField == CF_NotSet) {
1860  error(N, "missing key 'contents' or 'external-contents'");
1861  return nullptr;
1862  }
1863  if (!checkMissingKeys(N, Keys))
1864  return nullptr;
1865 
1866  // check invalid configuration
1868  UseExternalName != RedirectingFileSystem::NK_NotSet) {
1869  error(N, "'use-external-name' is not supported for 'directory' entries");
1870  return nullptr;
1871  }
1872 
1874  ContentsField == CF_List) {
1875  error(N, "'contents' is not supported for 'directory-remap' entries");
1876  return nullptr;
1877  }
1878 
1880  if (IsRootEntry) {
1881  // VFS root entries may be in either Posix or Windows style. Figure out
1882  // which style we have, and use it consistently.
1884  path_style = sys::path::Style::posix;
1885  } else if (sys::path::is_absolute(Name,
1888  } else {
1889  // Relative VFS root entries are made absolute to the current working
1890  // directory, then we can determine the path style from that.
1891  auto EC = sys::fs::make_absolute(Name);
1892  if (EC) {
1893  assert(NameValueNode && "Name presence should be checked earlier");
1894  error(
1895  NameValueNode,
1896  "entry with relative path at the root level is not discoverable");
1897  return nullptr;
1898  }
1902  }
1903  }
1904 
1905  // Remove trailing slash(es), being careful not to remove the root path
1906  StringRef Trimmed = Name;
1907  size_t RootPathLen = sys::path::root_path(Trimmed, path_style).size();
1908  while (Trimmed.size() > RootPathLen &&
1909  sys::path::is_separator(Trimmed.back(), path_style))
1910  Trimmed = Trimmed.slice(0, Trimmed.size() - 1);
1911 
1912  // Get the last component
1913  StringRef LastComponent = sys::path::filename(Trimmed, path_style);
1914 
1915  std::unique_ptr<RedirectingFileSystem::Entry> Result;
1916  switch (Kind) {
1918  Result = std::make_unique<RedirectingFileSystem::FileEntry>(
1919  LastComponent, std::move(ExternalContentsPath), UseExternalName);
1920  break;
1922  Result = std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
1923  LastComponent, std::move(ExternalContentsPath), UseExternalName);
1924  break;
1926  Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
1927  LastComponent, std::move(EntryArrayContents),
1929  0, 0, 0, file_type::directory_file, sys::fs::all_all));
1930  break;
1931  }
1932 
1933  StringRef Parent = sys::path::parent_path(Trimmed, path_style);
1934  if (Parent.empty())
1935  return Result;
1936 
1937  // if 'name' contains multiple components, create implicit directory entries
1938  for (sys::path::reverse_iterator I = sys::path::rbegin(Parent, path_style),
1939  E = sys::path::rend(Parent);
1940  I != E; ++I) {
1941  std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> Entries;
1942  Entries.push_back(std::move(Result));
1943  Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
1944  *I, std::move(Entries),
1946  0, 0, 0, file_type::directory_file, sys::fs::all_all));
1947  }
1948  return Result;
1949  }
1950 
1951 public:
1953 
1954  // false on error
1956  auto *Top = dyn_cast<yaml::MappingNode>(Root);
1957  if (!Top) {
1958  error(Root, "expected mapping node");
1959  return false;
1960  }
1961 
1962  KeyStatusPair Fields[] = {
1963  KeyStatusPair("version", true),
1964  KeyStatusPair("case-sensitive", false),
1965  KeyStatusPair("use-external-names", false),
1966  KeyStatusPair("overlay-relative", false),
1967  KeyStatusPair("fallthrough", false),
1968  KeyStatusPair("redirecting-with", false),
1969  KeyStatusPair("roots", true),
1970  };
1971 
1972  DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
1973  std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> RootEntries;
1974 
1975  // Parse configuration and 'roots'
1976  for (auto &I : *Top) {
1977  SmallString<10> KeyBuffer;
1978  StringRef Key;
1979  if (!parseScalarString(I.getKey(), Key, KeyBuffer))
1980  return false;
1981 
1982  if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys))
1983  return false;
1984 
1985  if (Key == "roots") {
1986  auto *Roots = dyn_cast<yaml::SequenceNode>(I.getValue());
1987  if (!Roots) {
1988  error(I.getValue(), "expected array");
1989  return false;
1990  }
1991 
1992  for (auto &I : *Roots) {
1993  if (std::unique_ptr<RedirectingFileSystem::Entry> E =
1994  parseEntry(&I, FS, /*IsRootEntry*/ true))
1995  RootEntries.push_back(std::move(E));
1996  else
1997  return false;
1998  }
1999  } else if (Key == "version") {
2000  StringRef VersionString;
2001  SmallString<4> Storage;
2002  if (!parseScalarString(I.getValue(), VersionString, Storage))
2003  return false;
2004  int Version;
2005  if (VersionString.getAsInteger<int>(10, Version)) {
2006  error(I.getValue(), "expected integer");
2007  return false;
2008  }
2009  if (Version < 0) {
2010  error(I.getValue(), "invalid version number");
2011  return false;
2012  }
2013  if (Version != 0) {
2014  error(I.getValue(), "version mismatch, expected 0");
2015  return false;
2016  }
2017  } else if (Key == "case-sensitive") {
2018  if (!parseScalarBool(I.getValue(), FS->CaseSensitive))
2019  return false;
2020  } else if (Key == "overlay-relative") {
2021  if (!parseScalarBool(I.getValue(), FS->IsRelativeOverlay))
2022  return false;
2023  } else if (Key == "use-external-names") {
2024  if (!parseScalarBool(I.getValue(), FS->UseExternalNames))
2025  return false;
2026  } else if (Key == "fallthrough") {
2027  if (Keys["redirecting-with"].Seen) {
2028  error(I.getValue(),
2029  "'fallthrough' and 'redirecting-with' are mutually exclusive");
2030  return false;
2031  }
2032 
2033  bool ShouldFallthrough = false;
2034  if (!parseScalarBool(I.getValue(), ShouldFallthrough))
2035  return false;
2036 
2037  if (ShouldFallthrough) {
2039  } else {
2041  }
2042  } else if (Key == "redirecting-with") {
2043  if (Keys["fallthrough"].Seen) {
2044  error(I.getValue(),
2045  "'fallthrough' and 'redirecting-with' are mutually exclusive");
2046  return false;
2047  }
2048 
2049  if (auto Kind = parseRedirectKind(I.getValue())) {
2050  FS->Redirection = *Kind;
2051  } else {
2052  error(I.getValue(), "expected valid redirect kind");
2053  return false;
2054  }
2055  } else {
2056  llvm_unreachable("key missing from Keys");
2057  }
2058  }
2059 
2060  if (Stream.failed())
2061  return false;
2062 
2063  if (!checkMissingKeys(Top, Keys))
2064  return false;
2065 
2066  // Now that we sucessefully parsed the YAML file, canonicalize the internal
2067  // representation to a proper directory tree so that we can search faster
2068  // inside the VFS.
2069  for (auto &E : RootEntries)
2070  uniqueOverlayTree(FS, E.get());
2071 
2072  return true;
2073  }
2074 };
2075 
2076 std::unique_ptr<RedirectingFileSystem>
2077 RedirectingFileSystem::create(std::unique_ptr<MemoryBuffer> Buffer,
2079  StringRef YAMLFilePath, void *DiagContext,
2080  IntrusiveRefCntPtr<FileSystem> ExternalFS) {
2081  SourceMgr SM;
2082  yaml::Stream Stream(Buffer->getMemBufferRef(), SM);
2083 
2084  SM.setDiagHandler(DiagHandler, DiagContext);
2085  yaml::document_iterator DI = Stream.begin();
2086  yaml::Node *Root = DI->getRoot();
2087  if (DI == Stream.end() || !Root) {
2088  SM.PrintMessage(SMLoc(), SourceMgr::DK_Error, "expected root node");
2089  return nullptr;
2090  }
2091 
2093 
2094  std::unique_ptr<RedirectingFileSystem> FS(
2095  new RedirectingFileSystem(ExternalFS));
2096 
2097  if (!YAMLFilePath.empty()) {
2098  // Use the YAML path from -ivfsoverlay to compute the dir to be prefixed
2099  // to each 'external-contents' path.
2100  //
2101  // Example:
2102  // -ivfsoverlay dummy.cache/vfs/vfs.yaml
2103  // yields:
2104  // FS->ExternalContentsPrefixDir => /<absolute_path_to>/dummy.cache/vfs
2105  //
2106  SmallString<256> OverlayAbsDir = sys::path::parent_path(YAMLFilePath);
2107  std::error_code EC = llvm::sys::fs::make_absolute(OverlayAbsDir);
2108  assert(!EC && "Overlay dir final path must be absolute");
2109  (void)EC;
2110  FS->setExternalContentsPrefixDir(OverlayAbsDir);
2111  }
2112 
2113  if (!P.parse(Root, FS.get()))
2114  return nullptr;
2115 
2116  return FS;
2117 }
2118 
2119 std::unique_ptr<RedirectingFileSystem> RedirectingFileSystem::create(
2120  ArrayRef<std::pair<std::string, std::string>> RemappedFiles,
2121  bool UseExternalNames, FileSystem &ExternalFS) {
2122  std::unique_ptr<RedirectingFileSystem> FS(
2123  new RedirectingFileSystem(&ExternalFS));
2124  FS->UseExternalNames = UseExternalNames;
2125 
2127 
2128  for (auto &Mapping : llvm::reverse(RemappedFiles)) {
2129  SmallString<128> From = StringRef(Mapping.first);
2130  SmallString<128> To = StringRef(Mapping.second);
2131  {
2132  auto EC = ExternalFS.makeAbsolute(From);
2133  (void)EC;
2134  assert(!EC && "Could not make absolute path");
2135  }
2136 
2137  // Check if we've already mapped this file. The first one we see (in the
2138  // reverse iteration) wins.
2139  RedirectingFileSystem::Entry *&ToEntry = Entries[From];
2140  if (ToEntry)
2141  continue;
2142 
2143  // Add parent directories.
2144  RedirectingFileSystem::Entry *Parent = nullptr;
2145  StringRef FromDirectory = llvm::sys::path::parent_path(From);
2146  for (auto I = llvm::sys::path::begin(FromDirectory),
2147  E = llvm::sys::path::end(FromDirectory);
2148  I != E; ++I) {
2150  Parent);
2151  }
2152  assert(Parent && "File without a directory?");
2153  {
2154  auto EC = ExternalFS.makeAbsolute(To);
2155  (void)EC;
2156  assert(!EC && "Could not make absolute path");
2157  }
2158 
2159  // Add the file.
2160  auto NewFile = std::make_unique<RedirectingFileSystem::FileEntry>(
2162  UseExternalNames ? RedirectingFileSystem::NK_External
2164  ToEntry = NewFile.get();
2165  cast<RedirectingFileSystem::DirectoryEntry>(Parent)->addContent(
2166  std::move(NewFile));
2167  }
2168 
2169  return FS;
2170 }
2171 
2174  : E(E) {
2175  assert(E != nullptr);
2176  // If the matched entry is a DirectoryRemapEntry, set ExternalRedirect to the
2177  // path of the directory it maps to in the external file system plus any
2178  // remaining path components in the provided iterator.
2179  if (auto *DRE = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(E)) {
2180  SmallString<256> Redirect(DRE->getExternalContentsPath());
2181  sys::path::append(Redirect, Start, End,
2182  getExistingStyle(DRE->getExternalContentsPath()));
2183  ExternalRedirect = std::string(Redirect);
2184  }
2185 }
2186 
2187 std::error_code
2188 RedirectingFileSystem::makeCanonical(SmallVectorImpl<char> &Path) const {
2189  if (std::error_code EC = makeAbsolute(Path))
2190  return EC;
2191 
2192  llvm::SmallString<256> CanonicalPath =
2193  canonicalize(StringRef(Path.data(), Path.size()));
2194  if (CanonicalPath.empty())
2196 
2197  Path.assign(CanonicalPath.begin(), CanonicalPath.end());
2198  return {};
2199 }
2200 
2205  for (const auto &Root : Roots) {
2207  lookupPathImpl(Start, End, Root.get());
2208  if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
2209  return Result;
2210  }
2212 }
2213 
2215 RedirectingFileSystem::lookupPathImpl(
2218  assert(!isTraversalComponent(*Start) &&
2219  !isTraversalComponent(From->getName()) &&
2220  "Paths should not contain traversal components");
2221 
2222  StringRef FromName = From->getName();
2223 
2224  // Forward the search to the next component in case this is an empty one.
2225  if (!FromName.empty()) {
2226  if (!pathComponentMatches(*Start, FromName))
2228 
2229  ++Start;
2230 
2231  if (Start == End) {
2232  // Match!
2233  return LookupResult(From, Start, End);
2234  }
2235  }
2236 
2237  if (isa<RedirectingFileSystem::FileEntry>(From))
2239 
2240  if (isa<RedirectingFileSystem::DirectoryRemapEntry>(From))
2241  return LookupResult(From, Start, End);
2242 
2243  auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(From);
2244  for (const std::unique_ptr<RedirectingFileSystem::Entry> &DirEntry :
2245  llvm::make_range(DE->contents_begin(), DE->contents_end())) {
2247  lookupPathImpl(Start, End, DirEntry.get());
2248  if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
2249  return Result;
2250  }
2251 
2253 }
2254 
2255 static Status getRedirectedFileStatus(const Twine &OriginalPath,
2256  bool UseExternalNames,
2257  Status ExternalStatus) {
2258  // The path has been mapped by some nested VFS and exposes an external path,
2259  // don't override it with the original path.
2260  if (ExternalStatus.ExposesExternalVFSPath)
2261  return ExternalStatus;
2262 
2263  Status S = ExternalStatus;
2264  if (!UseExternalNames)
2265  S = Status::copyWithNewName(S, OriginalPath);
2266  else
2267  S.ExposesExternalVFSPath = true;
2268  S.IsVFSMapped = true;
2269  return S;
2270 }
2271 
2272 ErrorOr<Status> RedirectingFileSystem::status(
2273  const Twine &CanonicalPath, const Twine &OriginalPath,
2274  const RedirectingFileSystem::LookupResult &Result) {
2275  if (Optional<StringRef> ExtRedirect = Result.getExternalRedirect()) {
2276  SmallString<256> CanonicalRemappedPath((*ExtRedirect).str());
2277  if (std::error_code EC = makeCanonical(CanonicalRemappedPath))
2278  return EC;
2279 
2280  ErrorOr<Status> S = ExternalFS->status(CanonicalRemappedPath);
2281  if (!S)
2282  return S;
2283  S = Status::copyWithNewName(*S, *ExtRedirect);
2284  auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result.E);
2285  return getRedirectedFileStatus(OriginalPath,
2286  RE->useExternalName(UseExternalNames), *S);
2287  }
2288 
2289  auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(Result.E);
2290  return Status::copyWithNewName(DE->getStatus(), CanonicalPath);
2291 }
2292 
2294 RedirectingFileSystem::getExternalStatus(const Twine &CanonicalPath,
2295  const Twine &OriginalPath) const {
2296  auto Result = ExternalFS->status(CanonicalPath);
2297 
2298  // The path has been mapped by some nested VFS, don't override it with the
2299  // original path.
2300  if (!Result || Result->ExposesExternalVFSPath)
2301  return Result;
2302  return Status::copyWithNewName(Result.get(), OriginalPath);
2303 }
2304 
2305 ErrorOr<Status> RedirectingFileSystem::status(const Twine &OriginalPath) {
2306  SmallString<256> CanonicalPath;
2307  OriginalPath.toVector(CanonicalPath);
2308 
2309  if (std::error_code EC = makeCanonical(CanonicalPath))
2310  return EC;
2311 
2312  if (Redirection == RedirectKind::Fallback) {
2313  // Attempt to find the original file first, only falling back to the
2314  // mapped file if that fails.
2315  ErrorOr<Status> S = getExternalStatus(CanonicalPath, OriginalPath);
2316  if (S)
2317  return S;
2318  }
2319 
2321  lookupPath(CanonicalPath);
2322  if (!Result) {
2323  // Was not able to map file, fallthrough to using the original path if
2324  // that was the specified redirection type.
2325  if (Redirection == RedirectKind::Fallthrough &&
2326  isFileNotFound(Result.getError()))
2327  return getExternalStatus(CanonicalPath, OriginalPath);
2328  return Result.getError();
2329  }
2330 
2331  ErrorOr<Status> S = status(CanonicalPath, OriginalPath, *Result);
2332  if (!S && Redirection == RedirectKind::Fallthrough &&
2333  isFileNotFound(S.getError(), Result->E)) {
2334  // Mapped the file but it wasn't found in the underlying filesystem,
2335  // fallthrough to using the original path if that was the specified
2336  // redirection type.
2337  return getExternalStatus(CanonicalPath, OriginalPath);
2338  }
2339 
2340  return S;
2341 }
2342 
2343 namespace {
2344 
2345 /// Provide a file wrapper with an overriden status.
2346 class FileWithFixedStatus : public File {
2347  std::unique_ptr<File> InnerFile;
2348  Status S;
2349 
2350 public:
2351  FileWithFixedStatus(std::unique_ptr<File> InnerFile, Status S)
2352  : InnerFile(std::move(InnerFile)), S(std::move(S)) {}
2353 
2354  ErrorOr<Status> status() override { return S; }
2356 
2357  getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
2358  bool IsVolatile) override {
2359  return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
2360  IsVolatile);
2361  }
2362 
2363  std::error_code close() override { return InnerFile->close(); }
2364 
2365  void setPath(const Twine &Path) override { S = S.copyWithNewName(S, Path); }
2366 };
2367 
2368 } // namespace
2369 
2371 File::getWithPath(ErrorOr<std::unique_ptr<File>> Result, const Twine &P) {
2372  // See \c getRedirectedFileStatus - don't update path if it's exposing an
2373  // external path.
2374  if (!Result || (*Result)->status()->ExposesExternalVFSPath)
2375  return Result;
2376 
2378  auto Name = F->get()->getName();
2379  if (Name && Name.get() != P.str())
2380  F->get()->setPath(P);
2381  return F;
2382 }
2383 
2386  SmallString<256> CanonicalPath;
2387  OriginalPath.toVector(CanonicalPath);
2388 
2389  if (std::error_code EC = makeCanonical(CanonicalPath))
2390  return EC;
2391 
2392  if (Redirection == RedirectKind::Fallback) {
2393  // Attempt to find the original file first, only falling back to the
2394  // mapped file if that fails.
2395  auto F = File::getWithPath(ExternalFS->openFileForRead(CanonicalPath),
2396  OriginalPath);
2397  if (F)
2398  return F;
2399  }
2400 
2402  lookupPath(CanonicalPath);
2403  if (!Result) {
2404  // Was not able to map file, fallthrough to using the original path if
2405  // that was the specified redirection type.
2406  if (Redirection == RedirectKind::Fallthrough &&
2407  isFileNotFound(Result.getError()))
2408  return File::getWithPath(ExternalFS->openFileForRead(CanonicalPath),
2409  OriginalPath);
2410  return Result.getError();
2411  }
2412 
2413  if (!Result->getExternalRedirect()) // FIXME: errc::not_a_file?
2415 
2416  StringRef ExtRedirect = *Result->getExternalRedirect();
2417  SmallString<256> CanonicalRemappedPath(ExtRedirect.str());
2418  if (std::error_code EC = makeCanonical(CanonicalRemappedPath))
2419  return EC;
2420 
2421  auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
2422 
2423  auto ExternalFile = File::getWithPath(
2424  ExternalFS->openFileForRead(CanonicalRemappedPath), ExtRedirect);
2425  if (!ExternalFile) {
2426  if (Redirection == RedirectKind::Fallthrough &&
2427  isFileNotFound(ExternalFile.getError(), Result->E)) {
2428  // Mapped the file but it wasn't found in the underlying filesystem,
2429  // fallthrough to using the original path if that was the specified
2430  // redirection type.
2431  return File::getWithPath(ExternalFS->openFileForRead(CanonicalPath),
2432  OriginalPath);
2433  }
2434  return ExternalFile;
2435  }
2436 
2437  auto ExternalStatus = (*ExternalFile)->status();
2438  if (!ExternalStatus)
2439  return ExternalStatus.getError();
2440 
2441  // Otherwise, the file was successfully remapped. Mark it as such. Also
2442  // replace the underlying path if the external name is being used.
2444  OriginalPath, RE->useExternalName(UseExternalNames), *ExternalStatus);
2445  return std::unique_ptr<File>(
2446  std::make_unique<FileWithFixedStatus>(std::move(*ExternalFile), S));
2447 }
2448 
2449 std::error_code
2451  SmallVectorImpl<char> &Output) const {
2452  SmallString<256> CanonicalPath;
2453  OriginalPath.toVector(CanonicalPath);
2454 
2455  if (std::error_code EC = makeCanonical(CanonicalPath))
2456  return EC;
2457 
2458  if (Redirection == RedirectKind::Fallback) {
2459  // Attempt to find the original file first, only falling back to the
2460  // mapped file if that fails.
2461  std::error_code EC = ExternalFS->getRealPath(CanonicalPath, Output);
2462  if (!EC)
2463  return EC;
2464  }
2465 
2467  lookupPath(CanonicalPath);
2468  if (!Result) {
2469  // Was not able to map file, fallthrough to using the original path if
2470  // that was the specified redirection type.
2471  if (Redirection == RedirectKind::Fallthrough &&
2472  isFileNotFound(Result.getError()))
2473  return ExternalFS->getRealPath(CanonicalPath, Output);
2474  return Result.getError();
2475  }
2476 
2477  // If we found FileEntry or DirectoryRemapEntry, look up the mapped
2478  // path in the external file system.
2479  if (auto ExtRedirect = Result->getExternalRedirect()) {
2480  auto P = ExternalFS->getRealPath(*ExtRedirect, Output);
2481  if (P && Redirection == RedirectKind::Fallthrough &&
2482  isFileNotFound(P, Result->E)) {
2483  // Mapped the file but it wasn't found in the underlying filesystem,
2484  // fallthrough to using the original path if that was the specified
2485  // redirection type.
2486  return ExternalFS->getRealPath(CanonicalPath, Output);
2487  }
2488  return P;
2489  }
2490 
2491  // If we found a DirectoryEntry, still fallthrough to the original path if
2492  // allowed, because directories don't have a single external contents path.
2493  if (Redirection == RedirectKind::Fallthrough)
2494  return ExternalFS->getRealPath(CanonicalPath, Output);
2496 }
2497 
2498 std::unique_ptr<FileSystem>
2499 vfs::getVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,
2501  StringRef YAMLFilePath, void *DiagContext,
2502  IntrusiveRefCntPtr<FileSystem> ExternalFS) {
2504  YAMLFilePath, DiagContext,
2505  std::move(ExternalFS));
2506 }
2507 
2510  SmallVectorImpl<YAMLVFSEntry> &Entries) {
2511  auto Kind = SrcE->getKind();
2513  auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
2514  assert(DE && "Must be a directory");
2515  for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
2516  llvm::make_range(DE->contents_begin(), DE->contents_end())) {
2517  Path.push_back(SubEntry->getName());
2518  getVFSEntries(SubEntry.get(), Path, Entries);
2519  Path.pop_back();
2520  }
2521  return;
2522  }
2523 
2525  auto *DR = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
2526  assert(DR && "Must be a directory remap");
2527  SmallString<128> VPath;
2528  for (auto &Comp : Path)
2529  llvm::sys::path::append(VPath, Comp);
2530  Entries.push_back(
2531  YAMLVFSEntry(VPath.c_str(), DR->getExternalContentsPath()));
2532  return;
2533  }
2534 
2535  assert(Kind == RedirectingFileSystem::EK_File && "Must be a EK_File");
2536  auto *FE = dyn_cast<RedirectingFileSystem::FileEntry>(SrcE);
2537  assert(FE && "Must be a file");
2538  SmallString<128> VPath;
2539  for (auto &Comp : Path)
2540  llvm::sys::path::append(VPath, Comp);
2541  Entries.push_back(YAMLVFSEntry(VPath.c_str(), FE->getExternalContentsPath()));
2542 }
2543 
2544 void vfs::collectVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,
2546  StringRef YAMLFilePath,
2547  SmallVectorImpl<YAMLVFSEntry> &CollectedEntries,
2548  void *DiagContext,
2549  IntrusiveRefCntPtr<FileSystem> ExternalFS) {
2550  std::unique_ptr<RedirectingFileSystem> VFS = RedirectingFileSystem::create(
2551  std::move(Buffer), DiagHandler, YAMLFilePath, DiagContext,
2552  std::move(ExternalFS));
2553  if (!VFS)
2554  return;
2556  VFS->lookupPath("/");
2557  if (!RootResult)
2558  return;
2559  SmallVector<StringRef, 8> Components;
2560  Components.push_back("/");
2561  getVFSEntries(RootResult->E, Components, CollectedEntries);
2562 }
2563 
2565  static std::atomic<unsigned> UID;
2566  unsigned ID = ++UID;
2567  // The following assumes that uint64_t max will never collide with a real
2568  // dev_t value from the OS.
2570 }
2571 
2572 void YAMLVFSWriter::addEntry(StringRef VirtualPath, StringRef RealPath,
2573  bool IsDirectory) {
2574  assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute");
2575  assert(sys::path::is_absolute(RealPath) && "real path not absolute");
2576  assert(!pathHasTraversal(VirtualPath) && "path traversal is not supported");
2577  Mappings.emplace_back(VirtualPath, RealPath, IsDirectory);
2578 }
2579 
2581  addEntry(VirtualPath, RealPath, /*IsDirectory=*/false);
2582 }
2583 
2585  StringRef RealPath) {
2586  addEntry(VirtualPath, RealPath, /*IsDirectory=*/true);
2587 }
2588 
2589 namespace {
2590 
2591 class JSONWriter {
2592  llvm::raw_ostream &OS;
2593  SmallVector<StringRef, 16> DirStack;
2594 
2595  unsigned getDirIndent() { return 4 * DirStack.size(); }
2596  unsigned getFileIndent() { return 4 * (DirStack.size() + 1); }
2597  bool containedIn(StringRef Parent, StringRef Path);
2598  StringRef containedPart(StringRef Parent, StringRef Path);
2599  void startDirectory(StringRef Path);
2600  void endDirectory();
2601  void writeEntry(StringRef VPath, StringRef RPath);
2602 
2603 public:
2604  JSONWriter(llvm::raw_ostream &OS) : OS(OS) {}
2605 
2606  void write(ArrayRef<YAMLVFSEntry> Entries, Optional<bool> UseExternalNames,
2607  Optional<bool> IsCaseSensitive, Optional<bool> IsOverlayRelative,
2608  StringRef OverlayDir);
2609 };
2610 
2611 } // namespace
2612 
2613 bool JSONWriter::containedIn(StringRef Parent, StringRef Path) {
2614  using namespace llvm::sys;
2615 
2616  // Compare each path component.
2617  auto IParent = path::begin(Parent), EParent = path::end(Parent);
2618  for (auto IChild = path::begin(Path), EChild = path::end(Path);
2619  IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
2620  if (*IParent != *IChild)
2621  return false;
2622  }
2623  // Have we exhausted the parent path?
2624  return IParent == EParent;
2625 }
2626 
2627 StringRef JSONWriter::containedPart(StringRef Parent, StringRef Path) {
2628  assert(!Parent.empty());
2629  assert(containedIn(Parent, Path));
2630  return Path.slice(Parent.size() + 1, StringRef::npos);
2631 }
2632 
2633 void JSONWriter::startDirectory(StringRef Path) {
2634  StringRef Name =
2635  DirStack.empty() ? Path : containedPart(DirStack.back(), Path);
2636  DirStack.push_back(Path);
2637  unsigned Indent = getDirIndent();
2638  OS.indent(Indent) << "{\n";
2639  OS.indent(Indent + 2) << "'type': 'directory',\n";
2640  OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(Name) << "\",\n";
2641  OS.indent(Indent + 2) << "'contents': [\n";
2642 }
2643 
2644 void JSONWriter::endDirectory() {
2645  unsigned Indent = getDirIndent();
2646  OS.indent(Indent + 2) << "]\n";
2647  OS.indent(Indent) << "}";
2648 
2649  DirStack.pop_back();
2650 }
2651 
2652 void JSONWriter::writeEntry(StringRef VPath, StringRef RPath) {
2653  unsigned Indent = getFileIndent();
2654  OS.indent(Indent) << "{\n";
2655  OS.indent(Indent + 2) << "'type': 'file',\n";
2656  OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(VPath) << "\",\n";
2657  OS.indent(Indent + 2) << "'external-contents': \""
2658  << llvm::yaml::escape(RPath) << "\"\n";
2659  OS.indent(Indent) << "}";
2660 }
2661 
2663  Optional<bool> UseExternalNames,
2664  Optional<bool> IsCaseSensitive,
2665  Optional<bool> IsOverlayRelative,
2666  StringRef OverlayDir) {
2667  using namespace llvm::sys;
2668 
2669  OS << "{\n"
2670  " 'version': 0,\n";
2671  if (IsCaseSensitive)
2672  OS << " 'case-sensitive': '"
2673  << (IsCaseSensitive.value() ? "true" : "false") << "',\n";
2674  if (UseExternalNames)
2675  OS << " 'use-external-names': '"
2676  << (UseExternalNames.value() ? "true" : "false") << "',\n";
2677  bool UseOverlayRelative = false;
2678  if (IsOverlayRelative) {
2679  UseOverlayRelative = IsOverlayRelative.value();
2680  OS << " 'overlay-relative': '" << (UseOverlayRelative ? "true" : "false")
2681  << "',\n";
2682  }
2683  OS << " 'roots': [\n";
2684 
2685  if (!Entries.empty()) {
2686  const YAMLVFSEntry &Entry = Entries.front();
2687 
2688  startDirectory(
2689  Entry.IsDirectory ? Entry.VPath : path::parent_path(Entry.VPath)
2690  );
2691 
2692  StringRef RPath = Entry.RPath;
2693  if (UseOverlayRelative) {
2694  unsigned OverlayDirLen = OverlayDir.size();
2695  assert(RPath.substr(0, OverlayDirLen) == OverlayDir &&
2696  "Overlay dir must be contained in RPath");
2697  RPath = RPath.slice(OverlayDirLen, RPath.size());
2698  }
2699 
2700  bool IsCurrentDirEmpty = true;
2701  if (!Entry.IsDirectory) {
2702  writeEntry(path::filename(Entry.VPath), RPath);
2703  IsCurrentDirEmpty = false;
2704  }
2705 
2706  for (const auto &Entry : Entries.slice(1)) {
2707  StringRef Dir =
2708  Entry.IsDirectory ? Entry.VPath : path::parent_path(Entry.VPath);
2709  if (Dir == DirStack.back()) {
2710  if (!IsCurrentDirEmpty) {
2711  OS << ",\n";
2712  }
2713  } else {
2714  bool IsDirPoppedFromStack = false;
2715  while (!DirStack.empty() && !containedIn(DirStack.back(), Dir)) {
2716  OS << "\n";
2717  endDirectory();
2718  IsDirPoppedFromStack = true;
2719  }
2720  if (IsDirPoppedFromStack || !IsCurrentDirEmpty) {
2721  OS << ",\n";
2722  }
2723  startDirectory(Dir);
2724  IsCurrentDirEmpty = true;
2725  }
2726  StringRef RPath = Entry.RPath;
2727  if (UseOverlayRelative) {
2728  unsigned OverlayDirLen = OverlayDir.size();
2729  assert(RPath.substr(0, OverlayDirLen) == OverlayDir &&
2730  "Overlay dir must be contained in RPath");
2731  RPath = RPath.slice(OverlayDirLen, RPath.size());
2732  }
2733  if (!Entry.IsDirectory) {
2734  writeEntry(path::filename(Entry.VPath), RPath);
2735  IsCurrentDirEmpty = false;
2736  }
2737  }
2738 
2739  while (!DirStack.empty()) {
2740  OS << "\n";
2741  endDirectory();
2742  }
2743  OS << "\n";
2744  }
2745 
2746  OS << " ]\n"
2747  << "}\n";
2748 }
2749 
2751  llvm::sort(Mappings, [](const YAMLVFSEntry &LHS, const YAMLVFSEntry &RHS) {
2752  return LHS.VPath < RHS.VPath;
2753  });
2754 
2755  JSONWriter(OS).write(Mappings, UseExternalNames, IsCaseSensitive,
2756  IsOverlayRelative, OverlayDir);
2757 }
2758 
2760  FileSystem &FS_, const Twine &Path, std::error_code &EC)
2761  : FS(&FS_) {
2762  directory_iterator I = FS->dir_begin(Path, EC);
2763  if (I != directory_iterator()) {
2764  State = std::make_shared<detail::RecDirIterState>();
2765  State->Stack.push(I);
2766  }
2767 }
2768 
2771  assert(FS && State && !State->Stack.empty() && "incrementing past end");
2772  assert(!State->Stack.top()->path().empty() && "non-canonical end iterator");
2774 
2775  if (State->HasNoPushRequest)
2776  State->HasNoPushRequest = false;
2777  else {
2778  if (State->Stack.top()->type() == sys::fs::file_type::directory_file) {
2779  vfs::directory_iterator I = FS->dir_begin(State->Stack.top()->path(), EC);
2780  if (I != End) {
2781  State->Stack.push(I);
2782  return *this;
2783  }
2784  }
2785  }
2786 
2787  while (!State->Stack.empty() && State->Stack.top().increment(EC) == End)
2788  State->Stack.pop();
2789 
2790  if (State->Stack.empty())
2791  State.reset(); // end iterator
2792 
2793  return *this;
2794 }
llvm::vfs::RedirectingFileSystem::EK_File
@ EK_File
Definition: VirtualFileSystem.h:731
MemoryBuffer.h
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:1235
llvm::vfs::RedirectingFileSystemParser::lookupOrCreateEntry
static RedirectingFileSystem::Entry * lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name, RedirectingFileSystem::Entry *ParentEntry=nullptr)
Definition: VirtualFileSystem.cpp:1663
getRedirectedFileStatus
static Status getRedirectedFileStatus(const Twine &OriginalPath, bool UseExternalNames, Status ExternalStatus)
Definition: VirtualFileSystem.cpp:2255
llvm::vfs::InMemoryFileSystem::setCurrentWorkingDirectory
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
Set the working directory.
Definition: VirtualFileSystem.cpp:1139
getName
static StringRef getName(Value *V)
Definition: ProvenanceAnalysisEvaluator.cpp:20
llvm::vfs::Status::isRegularFile
bool isRegularFile() const
Definition: VirtualFileSystem.cpp:101
llvm::vfs::RedirectingFileSystem::setCurrentWorkingDirectory
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
Set the working directory.
Definition: VirtualFileSystem.cpp:1325
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
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:1320
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:778
getVFSEntries
static void getVFSEntries(RedirectingFileSystem::Entry *SrcE, SmallVectorImpl< StringRef > &Path, SmallVectorImpl< YAMLVFSEntry > &Entries)
Definition: VirtualFileSystem.cpp:2508
Optional.h
llvm::sys::fs::directory_entry::type
file_type type() const
Definition: FileSystem.h:1385
llvm::vfs::FileSystem::PrintType::RecursiveContents
@ RecursiveContents
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
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:382
llvm::sys::path::Style::posix
@ posix
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:1123
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:1494
llvm::vfs::RedirectingFileSystemParser::parse
bool parse(yaml::Node *Root, RedirectingFileSystem *FS)
Definition: VirtualFileSystem.cpp:1955
llvm::write
Error write(MCStreamer &Out, ArrayRef< std::string > Inputs)
Definition: DWP.cpp:549
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:2077
llvm::Target
Target - Wrapper for Target specific information.
Definition: TargetRegistry.h:149
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:52
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1199
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:802
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:1108
Content
T Content
Definition: ELFObjHandler.cpp:89
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:755
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:1157
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::vfs::detail::InMemoryNode::getKind
InMemoryNodeKind getKind() const
Definition: VirtualFileSystem.cpp:620
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:453
llvm::X86AS::FS
@ FS
Definition: X86.h:200
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::AMDGPU::VOPD::Component
Component
Definition: AMDGPUBaseInfo.h:514
llvm::Optional< uint32_t >
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:145
llvm::StringRef::substr
StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition: StringRef.h:564
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:151
STLExtras.h
RHS
Value * RHS
Definition: X86PartialReduction.cpp:76
llvm::vfs::detail::IME_Directory
@ IME_Directory
Definition: VirtualFileSystem.cpp:596
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:619
llvm::vfs::detail::IME_SymbolicLink
@ IME_SymbolicLink
Definition: VirtualFileSystem.cpp:598
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:2385
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:51
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:474
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:1338
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:146
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:482
Mappings
Inject TLI Mappings
Definition: InjectTLIMappings.cpp:171
llvm::vfs::detail::InMemoryDirectory::addChild
InMemoryNode * addChild(StringRef Name, std::unique_ptr< InMemoryNode > Child)
Definition: VirtualFileSystem.cpp:750
llvm::vfs::detail::InMemoryDirectory::getStatus
Status getStatus(const Twine &RequestedName) const override
Return the Status for this node.
Definition: VirtualFileSystem.cpp:737
LHS
Value * LHS
Definition: X86PartialReduction.cpp:75
llvm::vfs::FileSystem::dump
LLVM_DUMP_METHOD void dump() const
Definition: VirtualFileSystem.cpp:156
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:431
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:2450
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:82
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:117
llvm::vfs::detail::InMemoryDirectory::begin
const_iterator begin() const
Definition: VirtualFileSystem.cpp:757
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:743
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:120
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:118
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:47
llvm::StringRef::getAsInteger
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition: StringRef.h:474
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::yaml::Stream::end
document_iterator end()
Definition: YAMLParser.cpp:1930
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:1273
SMLoc.h
llvm::vfs::directory_entry::path
llvm::StringRef path() const
Definition: VirtualFileSystem.h:160
llvm::yaml::Stream::printError
void printError(Node *N, const Twine &Msg, SourceMgr::DiagKind Kind=SourceMgr::DK_Error)
Definition: YAMLParser.cpp:1910
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:53
llvm::vfs::FileSystem::exists
bool exists(const Twine &Path)
Check whether a file exists. Provided for convenience.
Definition: VirtualFileSystem.cpp:150
llvm::IndexedInstrProf::Version
const uint64_t Version
Definition: InstrProf.h:1056
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:70
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::orc::tpctypes::LookupResult
std::vector< ExecutorAddr > LookupResult
Definition: TargetProcessControlTypes.h:90
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:603
llvm::vfs::getDirectoryID
static sys::fs::UniqueID getDirectoryID(sys::fs::UniqueID Parent, llvm::StringRef Name)
Definition: VirtualFileSystem.cpp:787
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::StringRef::slice
StringRef slice(size_t Start, size_t End) const
Return a reference to the substring from [Start, End).
Definition: StringRef.h:676
llvm::vfs::detail::InMemoryDirectory::getUniqueID
UniqueID getUniqueID() const
Definition: VirtualFileSystem.cpp:741
llvm::MemoryBuffer::getBufferIdentifier
virtual StringRef getBufferIdentifier() const
Return an identifier for this buffer, typically the filename it was read from.
Definition: MemoryBuffer.h:76
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:1490
pathHasTraversal
static bool pathHasTraversal(StringRef Path)
Definition: VirtualFileSystem.cpp:164
llvm::vfs::Status::isOther
bool isOther() const
Definition: VirtualFileSystem.cpp:103
llvm::sort
void sort(IteratorTy Start, IteratorTy End)
Definition: STLExtras.h:1657
llvm::StringRef::empty
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:134
llvm::vfs::detail::IME_HardLink
@ IME_HardLink
Definition: VirtualFileSystem.cpp:597
llvm::tgtok::In
@ In
Definition: TGLexer.h:51
llvm::vfs::detail::InMemoryDirectory::InMemoryDirectory
InMemoryDirectory(Status Stat)
Definition: VirtualFileSystem.cpp:731
llvm::SmallString::c_str
const char * c_str()
Definition: SmallString.h:263
isTraversalComponent
static bool isTraversalComponent(StringRef Component)
Definition: VirtualFileSystem.cpp:160
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:377
llvm::vfs::FileSystem::getCurrentWorkingDirectory
virtual llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const =0
Get the working directory of this file system.
type
AMD64 Optimization Manual has some nice information about optimizing integer multiplication by a constant How much of it applies to Intel s X86 implementation There are definite trade offs to xmm0 cvttss2siq rdx jb L3 subss xmm0 rax cvttss2siq rdx xorq rdx rax ret instead of xmm1 cvttss2siq rcx movaps xmm2 subss xmm2 cvttss2siq rax rdx xorq rax ucomiss xmm0 cmovb rax ret Seems like the jb branch has high likelihood of being taken It would have saved a few instructions It s not possible to reference and DH registers in an instruction requiring REX prefix divb and mulb both produce results in AH If isel emits a CopyFromReg which gets turned into a movb and that can be allocated a r8b r15b To get around isel emits a CopyFromReg from AX and then right shift it down by and truncate it It s not pretty but it works We need some register allocation magic to make the hack go which would often require a callee saved register Callees usually need to keep this value live for most of their body so it doesn t add a significant burden on them We currently implement this in however this is suboptimal because it means that it would be quite awkward to implement the optimization for callers A better implementation would be to relax the LLVM IR rules for sret arguments to allow a function with an sret argument to have a non void return type
Definition: README-X86-64.txt:70
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:2770
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:76
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:624
llvm::vfs::File::getWithPath
static ErrorOr< std::unique_ptr< File > > getWithPath(ErrorOr< std::unique_ptr< File >> Result, const Twine &P)
Definition: VirtualFileSystem.cpp:2371
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:99
llvm::DenseMap
Definition: DenseMap.h:714
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:1116
llvm::vfs::InMemoryFileSystem::toString
std::string toString() const
Definition: VirtualFileSystem.cpp:812
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:636
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:1386
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:1486
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:1836
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:1568
llvm::vfs::InMemoryFileSystem::addHardLink
bool addHardLink(const Twine &NewLink, const Twine &Target)
Add a hard link to a file.
Definition: VirtualFileSystem.cpp:1005
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:1046
llvm::sys::fs::kInvalidFile
const file_t kInvalidFile
llvm::yaml::Stream::failed
bool failed()
Definition: YAMLParser.cpp:1908
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:2564
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:1507
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
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:726
llvm::vfs::detail::InMemoryDirectory::end
const_iterator end() const
Definition: VirtualFileSystem.cpp:758
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:1174
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:2750
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:274
llvm::AMDGPU::SendMsg::Msg
const CustomOperand< const MCSubtargetInfo & > Msg[]
Definition: AMDGPUAsmUtils.cpp:39
llvm::vfs::Status::isSymlink
bool isSymlink() const
Definition: VirtualFileSystem.cpp:107
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:911
llvm::StringRef::size
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:137
StringSet.h
llvm::yaml::Stream::begin
document_iterator begin()
Definition: YAMLParser.cpp:1919
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:81
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::None
constexpr std::nullopt_t None
Definition: None.h:27
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:1070
llvm::vfs::RedirectingFileSystem::LookupResult::LookupResult
LookupResult(Entry *E, sys::path::const_iterator Start, sys::path::const_iterator End)
Definition: VirtualFileSystem.cpp:2172
llvm::vfs::RedirectingFileSystem::printImpl
void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override
Definition: VirtualFileSystem.cpp:1514
llvm::vfs::detail::InMemoryNode::InMemoryNode
InMemoryNode(llvm::StringRef FileName, InMemoryNodeKind Kind)
Definition: VirtualFileSystem.cpp:608
llvm::StringRef::endswith
bool endswith(StringRef Suffix) const
Definition: StringRef.h:276
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:2202
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:578
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:1024
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::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:2580
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:1502
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, Optional< Align > Alignment=None)
Given an already-open file descriptor, read the file and return a MemoryBuffer.
Definition: MemoryBuffer.cpp:513
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:1266
llvm::vfs::OverlayFileSystem::setCurrentWorkingDirectory
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
Set the working directory.
Definition: VirtualFileSystem.cpp:459
llvm::vfs::Status::exists
bool exists() const
Definition: VirtualFileSystem.cpp:111
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:1169
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:424
llvm::Expected::takeError
Error takeError()
Take ownership of the stored error.
Definition: Error.h:596
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:442
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:629
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:1952
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:494
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:1531
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:642
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:768
llvm::vfs::detail::IME_File
@ IME_File
Definition: VirtualFileSystem.cpp:595
llvm::vfs::YAMLVFSWriter::addDirectoryMapping
void addDirectoryMapping(StringRef VirtualPath, StringRef RealPath)
Definition: VirtualFileSystem.cpp:2584
llvm::vfs::Status::getType
llvm::sys::fs::file_type getType() const
Definition: VirtualFileSystem.h:92
llvm::StringRef::back
char back() const
back - Get the last character in the string.
Definition: StringRef.h:146
llvm::Optional::value
constexpr const T & value() const &
Definition: Optional.h:281
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:633
llvm::SmallVectorImpl< char >
llvm::sys::path::rend
reverse_iterator rend(StringRef path)
Get reverse end iterator over path.
Definition: Path.cpp:306
llvm::reverse
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:485
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:141
llvm::StringRef::str
std::string str() const
str - Get the contents as an std::string.
Definition: StringRef.h:221
llvm::vfs::detail::InMemoryNodeKind
InMemoryNodeKind
Definition: VirtualFileSystem.cpp:594
llvm::vfs::FileSystem::makeAbsolute
virtual std::error_code makeAbsolute(SmallVectorImpl< char > &Path) const
Make Path an absolute path.
Definition: VirtualFileSystem.cpp:129
llvm::vfs::getFileID
static sys::fs::UniqueID getFileID(sys::fs::UniqueID Parent, llvm::StringRef Name, llvm::StringRef Contents)
Definition: VirtualFileSystem.cpp:782
llvm::vfs::detail::InMemoryFile::toString
std::string toString(unsigned Indent) const override
Definition: VirtualFileSystem.cpp:638
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:1349
llvm::vfs::Status::equivalent
bool equivalent(const Status &Other) const
Definition: VirtualFileSystem.cpp:94
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:466
llvm::vfs::detail::InMemoryDirectory::toString
std::string toString(unsigned Indent) const override
Definition: VirtualFileSystem.cpp:760
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:1054
llvm::Optional::value_or
constexpr T value_or(U &&alt) const &
Definition: Optional.h:291
llvm::Value
LLVM Value Representation.
Definition: Value.h:74
llvm::vfs::detail::NewInMemoryNodeInfo::makeStatus
Status makeStatus() const
Definition: VirtualFileSystem.cpp:792
llvm::vfs::Status::isStatusKnown
bool isStatusKnown() const
Definition: VirtualFileSystem.cpp:109
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:1251
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:420