Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:44:35

0001 //===- VirtualFileSystem.h - Virtual File System Layer ----------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 /// \file
0010 /// Defines the virtual file system interface vfs::FileSystem.
0011 //
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_SUPPORT_VIRTUALFILESYSTEM_H
0015 #define LLVM_SUPPORT_VIRTUALFILESYSTEM_H
0016 
0017 #include "llvm/ADT/IntrusiveRefCntPtr.h"
0018 #include "llvm/ADT/STLFunctionalExtras.h"
0019 #include "llvm/ADT/SmallVector.h"
0020 #include "llvm/ADT/StringRef.h"
0021 #include "llvm/Support/Chrono.h"
0022 #include "llvm/Support/Errc.h"
0023 #include "llvm/Support/Error.h"
0024 #include "llvm/Support/ErrorOr.h"
0025 #include "llvm/Support/ExtensibleRTTI.h"
0026 #include "llvm/Support/FileSystem.h"
0027 #include "llvm/Support/Path.h"
0028 #include "llvm/Support/SourceMgr.h"
0029 #include <cassert>
0030 #include <cstdint>
0031 #include <ctime>
0032 #include <memory>
0033 #include <optional>
0034 #include <string>
0035 #include <system_error>
0036 #include <utility>
0037 #include <vector>
0038 
0039 namespace llvm {
0040 
0041 class MemoryBuffer;
0042 class MemoryBufferRef;
0043 class Twine;
0044 
0045 namespace vfs {
0046 
0047 /// The result of a \p status operation.
0048 class Status {
0049   std::string Name;
0050   llvm::sys::fs::UniqueID UID;
0051   llvm::sys::TimePoint<> MTime;
0052   uint32_t User;
0053   uint32_t Group;
0054   uint64_t Size;
0055   llvm::sys::fs::file_type Type = llvm::sys::fs::file_type::status_error;
0056   llvm::sys::fs::perms Perms;
0057 
0058 public:
0059   /// Whether this entity has an external path different from the virtual path,
0060   /// and the external path is exposed by leaking it through the abstraction.
0061   /// For example, a RedirectingFileSystem will set this for paths where
0062   /// UseExternalName is true.
0063   ///
0064   /// FIXME: Currently the external path is exposed by replacing the virtual
0065   /// path in this Status object. Instead, we should leave the path in the
0066   /// Status intact (matching the requested virtual path) - see
0067   /// FileManager::getFileRef for how we plan to fix this.
0068   bool ExposesExternalVFSPath = false;
0069 
0070   Status() = default;
0071   Status(const llvm::sys::fs::file_status &Status);
0072   Status(const Twine &Name, llvm::sys::fs::UniqueID UID,
0073          llvm::sys::TimePoint<> MTime, uint32_t User, uint32_t Group,
0074          uint64_t Size, llvm::sys::fs::file_type Type,
0075          llvm::sys::fs::perms Perms);
0076 
0077   /// Get a copy of a Status with a different size.
0078   static Status copyWithNewSize(const Status &In, uint64_t NewSize);
0079   /// Get a copy of a Status with a different name.
0080   static Status copyWithNewName(const Status &In, const Twine &NewName);
0081   static Status copyWithNewName(const llvm::sys::fs::file_status &In,
0082                                 const Twine &NewName);
0083 
0084   /// Returns the name that should be used for this file or directory.
0085   StringRef getName() const { return Name; }
0086 
0087   /// @name Status interface from llvm::sys::fs
0088   /// @{
0089   llvm::sys::fs::file_type getType() const { return Type; }
0090   llvm::sys::fs::perms getPermissions() const { return Perms; }
0091   llvm::sys::TimePoint<> getLastModificationTime() const { return MTime; }
0092   llvm::sys::fs::UniqueID getUniqueID() const { return UID; }
0093   uint32_t getUser() const { return User; }
0094   uint32_t getGroup() const { return Group; }
0095   uint64_t getSize() const { return Size; }
0096   /// @}
0097   /// @name Status queries
0098   /// These are static queries in llvm::sys::fs.
0099   /// @{
0100   bool equivalent(const Status &Other) const;
0101   bool isDirectory() const;
0102   bool isRegularFile() const;
0103   bool isOther() const;
0104   bool isSymlink() const;
0105   bool isStatusKnown() const;
0106   bool exists() const;
0107   /// @}
0108 };
0109 
0110 /// Represents an open file.
0111 class File {
0112 public:
0113   /// Destroy the file after closing it (if open).
0114   /// Sub-classes should generally call close() inside their destructors.  We
0115   /// cannot do that from the base class, since close is virtual.
0116   virtual ~File();
0117 
0118   /// Get the status of the file.
0119   virtual llvm::ErrorOr<Status> status() = 0;
0120 
0121   /// Get the name of the file
0122   virtual llvm::ErrorOr<std::string> getName() {
0123     if (auto Status = status())
0124       return Status->getName().str();
0125     else
0126       return Status.getError();
0127   }
0128 
0129   /// Get the contents of the file as a \p MemoryBuffer.
0130   virtual llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
0131   getBuffer(const Twine &Name, int64_t FileSize = -1,
0132             bool RequiresNullTerminator = true, bool IsVolatile = false) = 0;
0133 
0134   /// Closes the file.
0135   virtual std::error_code close() = 0;
0136 
0137   // Get the same file with a different path.
0138   static ErrorOr<std::unique_ptr<File>>
0139   getWithPath(ErrorOr<std::unique_ptr<File>> Result, const Twine &P);
0140 
0141 protected:
0142   // Set the file's underlying path.
0143   virtual void setPath(const Twine &Path) {}
0144 };
0145 
0146 /// A member of a directory, yielded by a directory_iterator.
0147 /// Only information available on most platforms is included.
0148 class directory_entry {
0149   std::string Path;
0150   llvm::sys::fs::file_type Type = llvm::sys::fs::file_type::type_unknown;
0151 
0152 public:
0153   directory_entry() = default;
0154   directory_entry(std::string Path, llvm::sys::fs::file_type Type)
0155       : Path(std::move(Path)), Type(Type) {}
0156 
0157   llvm::StringRef path() const { return Path; }
0158   llvm::sys::fs::file_type type() const { return Type; }
0159 };
0160 
0161 namespace detail {
0162 
0163 /// An interface for virtual file systems to provide an iterator over the
0164 /// (non-recursive) contents of a directory.
0165 struct DirIterImpl {
0166   virtual ~DirIterImpl();
0167 
0168   /// Sets \c CurrentEntry to the next entry in the directory on success,
0169   /// to directory_entry() at end,  or returns a system-defined \c error_code.
0170   virtual std::error_code increment() = 0;
0171 
0172   directory_entry CurrentEntry;
0173 };
0174 
0175 } // namespace detail
0176 
0177 /// An input iterator over the entries in a virtual path, similar to
0178 /// llvm::sys::fs::directory_iterator.
0179 class directory_iterator {
0180   std::shared_ptr<detail::DirIterImpl> Impl; // Input iterator semantics on copy
0181 
0182 public:
0183   directory_iterator(std::shared_ptr<detail::DirIterImpl> I)
0184       : Impl(std::move(I)) {
0185     assert(Impl.get() != nullptr && "requires non-null implementation");
0186     if (Impl->CurrentEntry.path().empty())
0187       Impl.reset(); // Normalize the end iterator to Impl == nullptr.
0188   }
0189 
0190   /// Construct an 'end' iterator.
0191   directory_iterator() = default;
0192 
0193   /// Equivalent to operator++, with an error code.
0194   directory_iterator &increment(std::error_code &EC) {
0195     assert(Impl && "attempting to increment past end");
0196     EC = Impl->increment();
0197     if (Impl->CurrentEntry.path().empty())
0198       Impl.reset(); // Normalize the end iterator to Impl == nullptr.
0199     return *this;
0200   }
0201 
0202   const directory_entry &operator*() const { return Impl->CurrentEntry; }
0203   const directory_entry *operator->() const { return &Impl->CurrentEntry; }
0204 
0205   bool operator==(const directory_iterator &RHS) const {
0206     if (Impl && RHS.Impl)
0207       return Impl->CurrentEntry.path() == RHS.Impl->CurrentEntry.path();
0208     return !Impl && !RHS.Impl;
0209   }
0210   bool operator!=(const directory_iterator &RHS) const {
0211     return !(*this == RHS);
0212   }
0213 };
0214 
0215 class FileSystem;
0216 
0217 namespace detail {
0218 
0219 /// Keeps state for the recursive_directory_iterator.
0220 struct RecDirIterState {
0221   std::vector<directory_iterator> Stack;
0222   bool HasNoPushRequest = false;
0223 };
0224 
0225 } // end namespace detail
0226 
0227 /// An input iterator over the recursive contents of a virtual path,
0228 /// similar to llvm::sys::fs::recursive_directory_iterator.
0229 class recursive_directory_iterator {
0230   FileSystem *FS;
0231   std::shared_ptr<detail::RecDirIterState>
0232       State; // Input iterator semantics on copy.
0233 
0234 public:
0235   recursive_directory_iterator(FileSystem &FS, const Twine &Path,
0236                                std::error_code &EC);
0237 
0238   /// Construct an 'end' iterator.
0239   recursive_directory_iterator() = default;
0240 
0241   /// Equivalent to operator++, with an error code.
0242   recursive_directory_iterator &increment(std::error_code &EC);
0243 
0244   const directory_entry &operator*() const { return *State->Stack.back(); }
0245   const directory_entry *operator->() const { return &*State->Stack.back(); }
0246 
0247   bool operator==(const recursive_directory_iterator &Other) const {
0248     return State == Other.State; // identity
0249   }
0250   bool operator!=(const recursive_directory_iterator &RHS) const {
0251     return !(*this == RHS);
0252   }
0253 
0254   /// Gets the current level. Starting path is at level 0.
0255   int level() const {
0256     assert(!State->Stack.empty() &&
0257            "Cannot get level without any iteration state");
0258     return State->Stack.size() - 1;
0259   }
0260 
0261   void no_push() { State->HasNoPushRequest = true; }
0262 };
0263 
0264 /// The virtual file system interface.
0265 class FileSystem : public llvm::ThreadSafeRefCountedBase<FileSystem>,
0266                    public RTTIExtends<FileSystem, RTTIRoot> {
0267 public:
0268   static const char ID;
0269   virtual ~FileSystem();
0270 
0271   /// Get the status of the entry at \p Path, if one exists.
0272   virtual llvm::ErrorOr<Status> status(const Twine &Path) = 0;
0273 
0274   /// Get a \p File object for the text file at \p Path, if one exists.
0275   virtual llvm::ErrorOr<std::unique_ptr<File>>
0276   openFileForRead(const Twine &Path) = 0;
0277 
0278   /// Get a \p File object for the binary file at \p Path, if one exists.
0279   /// Some non-ascii based file systems perform encoding conversions
0280   /// when reading as a text file, and this function should be used if
0281   /// a file's bytes should be read as-is. On most filesystems, this
0282   /// is the same behaviour as openFileForRead.
0283   virtual llvm::ErrorOr<std::unique_ptr<File>>
0284   openFileForReadBinary(const Twine &Path) {
0285     return openFileForRead(Path);
0286   }
0287 
0288   /// This is a convenience method that opens a file, gets its content and then
0289   /// closes the file.
0290   /// The IsText parameter is used to distinguish whether the file should be
0291   /// opened as a binary or text file.
0292   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
0293   getBufferForFile(const Twine &Name, int64_t FileSize = -1,
0294                    bool RequiresNullTerminator = true, bool IsVolatile = false,
0295                    bool IsText = true);
0296 
0297   /// Get a directory_iterator for \p Dir.
0298   /// \note The 'end' iterator is directory_iterator().
0299   virtual directory_iterator dir_begin(const Twine &Dir,
0300                                        std::error_code &EC) = 0;
0301 
0302   /// Set the working directory. This will affect all following operations on
0303   /// this file system and may propagate down for nested file systems.
0304   virtual std::error_code setCurrentWorkingDirectory(const Twine &Path) = 0;
0305 
0306   /// Get the working directory of this file system.
0307   virtual llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const = 0;
0308 
0309   /// Gets real path of \p Path e.g. collapse all . and .. patterns, resolve
0310   /// symlinks. For real file system, this uses `llvm::sys::fs::real_path`.
0311   /// This returns errc::operation_not_permitted if not implemented by subclass.
0312   virtual std::error_code getRealPath(const Twine &Path,
0313                                       SmallVectorImpl<char> &Output);
0314 
0315   /// Check whether \p Path exists. By default this uses \c status(), but
0316   /// filesystems may provide a more efficient implementation if available.
0317   virtual bool exists(const Twine &Path);
0318 
0319   /// Is the file mounted on a local filesystem?
0320   virtual std::error_code isLocal(const Twine &Path, bool &Result);
0321 
0322   /// Make \a Path an absolute path.
0323   ///
0324   /// Makes \a Path absolute using the current directory if it is not already.
0325   /// An empty \a Path will result in the current directory.
0326   ///
0327   /// /absolute/path   => /absolute/path
0328   /// relative/../path => <current-directory>/relative/../path
0329   ///
0330   /// \param Path A path that is modified to be an absolute path.
0331   /// \returns success if \a path has been made absolute, otherwise a
0332   ///          platform-specific error_code.
0333   virtual std::error_code makeAbsolute(SmallVectorImpl<char> &Path) const;
0334 
0335   /// \returns true if \p A and \p B represent the same file, or an error or
0336   /// false if they do not.
0337   llvm::ErrorOr<bool> equivalent(const Twine &A, const Twine &B);
0338 
0339   enum class PrintType { Summary, Contents, RecursiveContents };
0340   void print(raw_ostream &OS, PrintType Type = PrintType::Contents,
0341              unsigned IndentLevel = 0) const {
0342     printImpl(OS, Type, IndentLevel);
0343   }
0344 
0345   using VisitCallbackTy = llvm::function_ref<void(FileSystem &)>;
0346   virtual void visitChildFileSystems(VisitCallbackTy Callback) {}
0347   void visit(VisitCallbackTy Callback) {
0348     Callback(*this);
0349     visitChildFileSystems(Callback);
0350   }
0351 
0352 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
0353   LLVM_DUMP_METHOD void dump() const;
0354 #endif
0355 
0356 protected:
0357   virtual void printImpl(raw_ostream &OS, PrintType Type,
0358                          unsigned IndentLevel) const {
0359     printIndent(OS, IndentLevel);
0360     OS << "FileSystem\n";
0361   }
0362 
0363   void printIndent(raw_ostream &OS, unsigned IndentLevel) const {
0364     for (unsigned i = 0; i < IndentLevel; ++i)
0365       OS << "  ";
0366   }
0367 };
0368 
0369 /// Gets an \p vfs::FileSystem for the 'real' file system, as seen by
0370 /// the operating system.
0371 /// The working directory is linked to the process's working directory.
0372 /// (This is usually thread-hostile).
0373 IntrusiveRefCntPtr<FileSystem> getRealFileSystem();
0374 
0375 /// Create an \p vfs::FileSystem for the 'real' file system, as seen by
0376 /// the operating system.
0377 /// It has its own working directory, independent of (but initially equal to)
0378 /// that of the process.
0379 std::unique_ptr<FileSystem> createPhysicalFileSystem();
0380 
0381 /// A file system that allows overlaying one \p AbstractFileSystem on top
0382 /// of another.
0383 ///
0384 /// Consists of a stack of >=1 \p FileSystem objects, which are treated as being
0385 /// one merged file system. When there is a directory that exists in more than
0386 /// one file system, the \p OverlayFileSystem contains a directory containing
0387 /// the union of their contents.  The attributes (permissions, etc.) of the
0388 /// top-most (most recently added) directory are used.  When there is a file
0389 /// that exists in more than one file system, the file in the top-most file
0390 /// system overrides the other(s).
0391 class OverlayFileSystem : public RTTIExtends<OverlayFileSystem, FileSystem> {
0392   using FileSystemList = SmallVector<IntrusiveRefCntPtr<FileSystem>, 1>;
0393 
0394   /// The stack of file systems, implemented as a list in order of
0395   /// their addition.
0396   FileSystemList FSList;
0397 
0398 public:
0399   static const char ID;
0400   OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> Base);
0401 
0402   /// Pushes a file system on top of the stack.
0403   void pushOverlay(IntrusiveRefCntPtr<FileSystem> FS);
0404 
0405   llvm::ErrorOr<Status> status(const Twine &Path) override;
0406   bool exists(const Twine &Path) override;
0407   llvm::ErrorOr<std::unique_ptr<File>>
0408   openFileForRead(const Twine &Path) override;
0409   directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
0410   llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override;
0411   std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
0412   std::error_code isLocal(const Twine &Path, bool &Result) override;
0413   std::error_code getRealPath(const Twine &Path,
0414                               SmallVectorImpl<char> &Output) override;
0415 
0416   using iterator = FileSystemList::reverse_iterator;
0417   using const_iterator = FileSystemList::const_reverse_iterator;
0418   using reverse_iterator = FileSystemList::iterator;
0419   using const_reverse_iterator = FileSystemList::const_iterator;
0420   using range = iterator_range<iterator>;
0421   using const_range = iterator_range<const_iterator>;
0422 
0423   /// Get an iterator pointing to the most recently added file system.
0424   iterator overlays_begin() { return FSList.rbegin(); }
0425   const_iterator overlays_begin() const { return FSList.rbegin(); }
0426 
0427   /// Get an iterator pointing one-past the least recently added file system.
0428   iterator overlays_end() { return FSList.rend(); }
0429   const_iterator overlays_end() const { return FSList.rend(); }
0430 
0431   /// Get an iterator pointing to the least recently added file system.
0432   reverse_iterator overlays_rbegin() { return FSList.begin(); }
0433   const_reverse_iterator overlays_rbegin() const { return FSList.begin(); }
0434 
0435   /// Get an iterator pointing one-past the most recently added file system.
0436   reverse_iterator overlays_rend() { return FSList.end(); }
0437   const_reverse_iterator overlays_rend() const { return FSList.end(); }
0438 
0439   range overlays_range() { return llvm::reverse(FSList); }
0440   const_range overlays_range() const { return llvm::reverse(FSList); }
0441 
0442 protected:
0443   void printImpl(raw_ostream &OS, PrintType Type,
0444                  unsigned IndentLevel) const override;
0445   void visitChildFileSystems(VisitCallbackTy Callback) override;
0446 };
0447 
0448 /// By default, this delegates all calls to the underlying file system. This
0449 /// is useful when derived file systems want to override some calls and still
0450 /// proxy other calls.
0451 class ProxyFileSystem : public RTTIExtends<ProxyFileSystem, FileSystem> {
0452 public:
0453   static const char ID;
0454   explicit ProxyFileSystem(IntrusiveRefCntPtr<FileSystem> FS)
0455       : FS(std::move(FS)) {}
0456 
0457   llvm::ErrorOr<Status> status(const Twine &Path) override {
0458     return FS->status(Path);
0459   }
0460   bool exists(const Twine &Path) override { return FS->exists(Path); }
0461   llvm::ErrorOr<std::unique_ptr<File>>
0462   openFileForRead(const Twine &Path) override {
0463     return FS->openFileForRead(Path);
0464   }
0465   directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override {
0466     return FS->dir_begin(Dir, EC);
0467   }
0468   llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
0469     return FS->getCurrentWorkingDirectory();
0470   }
0471   std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
0472     return FS->setCurrentWorkingDirectory(Path);
0473   }
0474   std::error_code getRealPath(const Twine &Path,
0475                               SmallVectorImpl<char> &Output) override {
0476     return FS->getRealPath(Path, Output);
0477   }
0478   std::error_code isLocal(const Twine &Path, bool &Result) override {
0479     return FS->isLocal(Path, Result);
0480   }
0481 
0482 protected:
0483   FileSystem &getUnderlyingFS() const { return *FS; }
0484   void visitChildFileSystems(VisitCallbackTy Callback) override {
0485     if (FS) {
0486       Callback(*FS);
0487       FS->visitChildFileSystems(Callback);
0488     }
0489   }
0490 
0491 private:
0492   IntrusiveRefCntPtr<FileSystem> FS;
0493 
0494   virtual void anchor() override;
0495 };
0496 
0497 namespace detail {
0498 
0499 class InMemoryDirectory;
0500 class InMemoryNode;
0501 
0502 struct NewInMemoryNodeInfo {
0503   llvm::sys::fs::UniqueID DirUID;
0504   StringRef Path;
0505   StringRef Name;
0506   time_t ModificationTime;
0507   std::unique_ptr<llvm::MemoryBuffer> Buffer;
0508   uint32_t User;
0509   uint32_t Group;
0510   llvm::sys::fs::file_type Type;
0511   llvm::sys::fs::perms Perms;
0512 
0513   Status makeStatus() const;
0514 };
0515 
0516 class NamedNodeOrError {
0517   ErrorOr<std::pair<llvm::SmallString<128>, const detail::InMemoryNode *>>
0518       Value;
0519 
0520 public:
0521   NamedNodeOrError(llvm::SmallString<128> Name,
0522                    const detail::InMemoryNode *Node)
0523       : Value(std::make_pair(Name, Node)) {}
0524   NamedNodeOrError(std::error_code EC) : Value(EC) {}
0525   NamedNodeOrError(llvm::errc EC) : Value(EC) {}
0526 
0527   StringRef getName() const { return (*Value).first; }
0528   explicit operator bool() const { return static_cast<bool>(Value); }
0529   operator std::error_code() const { return Value.getError(); }
0530   std::error_code getError() const { return Value.getError(); }
0531   const detail::InMemoryNode *operator*() const { return (*Value).second; }
0532 };
0533 
0534 } // namespace detail
0535 
0536 /// An in-memory file system.
0537 class InMemoryFileSystem : public RTTIExtends<InMemoryFileSystem, FileSystem> {
0538   std::unique_ptr<detail::InMemoryDirectory> Root;
0539   std::string WorkingDirectory;
0540   bool UseNormalizedPaths = true;
0541 
0542 public:
0543   static const char ID;
0544 
0545 private:
0546   using MakeNodeFn = llvm::function_ref<std::unique_ptr<detail::InMemoryNode>(
0547       detail::NewInMemoryNodeInfo)>;
0548 
0549   /// Create node with \p MakeNode and add it into this filesystem at \p Path.
0550   bool addFile(const Twine &Path, time_t ModificationTime,
0551                std::unique_ptr<llvm::MemoryBuffer> Buffer,
0552                std::optional<uint32_t> User, std::optional<uint32_t> Group,
0553                std::optional<llvm::sys::fs::file_type> Type,
0554                std::optional<llvm::sys::fs::perms> Perms, MakeNodeFn MakeNode);
0555 
0556   /// Looks up the in-memory node for the path \p P.
0557   /// If \p FollowFinalSymlink is true, the returned node is guaranteed to
0558   /// not be a symlink and its path may differ from \p P.
0559   detail::NamedNodeOrError lookupNode(const Twine &P, bool FollowFinalSymlink,
0560                                       size_t SymlinkDepth = 0) const;
0561 
0562   class DirIterator;
0563 
0564 public:
0565   explicit InMemoryFileSystem(bool UseNormalizedPaths = true);
0566   ~InMemoryFileSystem() override;
0567 
0568   /// Add a file containing a buffer or a directory to the VFS with a
0569   /// path. The VFS owns the buffer.  If present, User, Group, Type
0570   /// and Perms apply to the newly-created file or directory.
0571   /// \return true if the file or directory was successfully added,
0572   /// false if the file or directory already exists in the file system with
0573   /// different contents.
0574   bool addFile(const Twine &Path, time_t ModificationTime,
0575                std::unique_ptr<llvm::MemoryBuffer> Buffer,
0576                std::optional<uint32_t> User = std::nullopt,
0577                std::optional<uint32_t> Group = std::nullopt,
0578                std::optional<llvm::sys::fs::file_type> Type = std::nullopt,
0579                std::optional<llvm::sys::fs::perms> Perms = std::nullopt);
0580 
0581   /// Add a hard link to a file.
0582   ///
0583   /// Here hard links are not intended to be fully equivalent to the classical
0584   /// filesystem. Both the hard link and the file share the same buffer and
0585   /// status (and thus have the same UniqueID). Because of this there is no way
0586   /// to distinguish between the link and the file after the link has been
0587   /// added.
0588   ///
0589   /// The \p Target path must be an existing file or a hardlink. The
0590   /// \p NewLink file must not have been added before. The \p Target
0591   /// path must not be a directory. The \p NewLink node is added as a hard
0592   /// link which points to the resolved file of \p Target node.
0593   /// \return true if the above condition is satisfied and hardlink was
0594   /// successfully created, false otherwise.
0595   bool addHardLink(const Twine &NewLink, const Twine &Target);
0596 
0597   /// Arbitrary max depth to search through symlinks. We can get into problems
0598   /// if a link links to a link that links back to the link, for example.
0599   static constexpr size_t MaxSymlinkDepth = 16;
0600 
0601   /// Add a symbolic link. Unlike a HardLink, because \p Target doesn't need
0602   /// to refer to a file (or refer to anything, as it happens). Also, an
0603   /// in-memory directory for \p Target isn't automatically created.
0604   bool
0605   addSymbolicLink(const Twine &NewLink, const Twine &Target,
0606                   time_t ModificationTime,
0607                   std::optional<uint32_t> User = std::nullopt,
0608                   std::optional<uint32_t> Group = std::nullopt,
0609                   std::optional<llvm::sys::fs::perms> Perms = std::nullopt);
0610 
0611   /// Add a buffer to the VFS with a path. The VFS does not own the buffer.
0612   /// If present, User, Group, Type and Perms apply to the newly-created file
0613   /// or directory.
0614   /// \return true if the file or directory was successfully added,
0615   /// false if the file or directory already exists in the file system with
0616   /// different contents.
0617   bool addFileNoOwn(const Twine &Path, time_t ModificationTime,
0618                     const llvm::MemoryBufferRef &Buffer,
0619                     std::optional<uint32_t> User = std::nullopt,
0620                     std::optional<uint32_t> Group = std::nullopt,
0621                     std::optional<llvm::sys::fs::file_type> Type = std::nullopt,
0622                     std::optional<llvm::sys::fs::perms> Perms = std::nullopt);
0623 
0624   std::string toString() const;
0625 
0626   /// Return true if this file system normalizes . and .. in paths.
0627   bool useNormalizedPaths() const { return UseNormalizedPaths; }
0628 
0629   llvm::ErrorOr<Status> status(const Twine &Path) override;
0630   llvm::ErrorOr<std::unique_ptr<File>>
0631   openFileForRead(const Twine &Path) override;
0632   directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
0633 
0634   llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
0635     return WorkingDirectory;
0636   }
0637   /// Canonicalizes \p Path by combining with the current working
0638   /// directory and normalizing the path (e.g. remove dots). If the current
0639   /// working directory is not set, this returns errc::operation_not_permitted.
0640   ///
0641   /// This doesn't resolve symlinks as they are not supported in in-memory file
0642   /// system.
0643   std::error_code getRealPath(const Twine &Path,
0644                               SmallVectorImpl<char> &Output) override;
0645   std::error_code isLocal(const Twine &Path, bool &Result) override;
0646   std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
0647 
0648 protected:
0649   void printImpl(raw_ostream &OS, PrintType Type,
0650                  unsigned IndentLevel) const override;
0651 };
0652 
0653 /// Get a globally unique ID for a virtual file or directory.
0654 llvm::sys::fs::UniqueID getNextVirtualUniqueID();
0655 
0656 /// Gets a \p FileSystem for a virtual file system described in YAML
0657 /// format.
0658 std::unique_ptr<FileSystem>
0659 getVFSFromYAML(std::unique_ptr<llvm::MemoryBuffer> Buffer,
0660                llvm::SourceMgr::DiagHandlerTy DiagHandler,
0661                StringRef YAMLFilePath, void *DiagContext = nullptr,
0662                IntrusiveRefCntPtr<FileSystem> ExternalFS = getRealFileSystem());
0663 
0664 struct YAMLVFSEntry {
0665   template <typename T1, typename T2>
0666   YAMLVFSEntry(T1 &&VPath, T2 &&RPath, bool IsDirectory = false)
0667       : VPath(std::forward<T1>(VPath)), RPath(std::forward<T2>(RPath)),
0668         IsDirectory(IsDirectory) {}
0669   std::string VPath;
0670   std::string RPath;
0671   bool IsDirectory = false;
0672 };
0673 
0674 class RedirectingFSDirIterImpl;
0675 class RedirectingFileSystemParser;
0676 
0677 /// A virtual file system parsed from a YAML file.
0678 ///
0679 /// Currently, this class allows creating virtual files and directories. Virtual
0680 /// files map to existing external files in \c ExternalFS, and virtual
0681 /// directories may either map to existing directories in \c ExternalFS or list
0682 /// their contents in the form of other virtual directories and/or files.
0683 ///
0684 /// The basic structure of the parsed file is:
0685 /// \verbatim
0686 /// {
0687 ///   'version': <version number>,
0688 ///   <optional configuration>
0689 ///   'roots': [
0690 ///              <directory entries>
0691 ///            ]
0692 /// }
0693 /// \endverbatim
0694 /// The roots may be absolute or relative. If relative they will be made
0695 /// absolute against either current working directory or the directory where
0696 /// the Overlay YAML file is located, depending on the 'root-relative'
0697 /// configuration.
0698 ///
0699 /// All configuration options are optional.
0700 ///   'case-sensitive': <boolean, default=(true for Posix, false for Windows)>
0701 ///   'use-external-names': <boolean, default=true>
0702 ///   'root-relative': <string, one of 'cwd' or 'overlay-dir', default='cwd'>
0703 ///   'overlay-relative': <boolean, default=false>
0704 ///   'fallthrough': <boolean, default=true, deprecated - use 'redirecting-with'
0705 ///                   instead>
0706 ///   'redirecting-with': <string, one of 'fallthrough', 'fallback', or
0707 ///                        'redirect-only', default='fallthrough'>
0708 ///
0709 /// To clarify, 'root-relative' option will prepend the current working
0710 /// directory, or the overlay directory to the 'roots->name' field only if
0711 /// 'roots->name' is a relative path. On the other hand, when 'overlay-relative'
0712 /// is set to 'true', external paths will always be prepended with the overlay
0713 /// directory, even if external paths are not relative paths. The
0714 /// 'root-relative' option has no interaction with the 'overlay-relative'
0715 /// option.
0716 ///
0717 /// Virtual directories that list their contents are represented as
0718 /// \verbatim
0719 /// {
0720 ///   'type': 'directory',
0721 ///   'name': <string>,
0722 ///   'contents': [ <file or directory entries> ]
0723 /// }
0724 /// \endverbatim
0725 /// The default attributes for such virtual directories are:
0726 /// \verbatim
0727 /// MTime = now() when created
0728 /// Perms = 0777
0729 /// User = Group = 0
0730 /// Size = 0
0731 /// UniqueID = unspecified unique value
0732 /// \endverbatim
0733 /// When a path prefix matches such a directory, the next component in the path
0734 /// is matched against the entries in the 'contents' array.
0735 ///
0736 /// Re-mapped directories, on the other hand, are represented as
0737 /// /// \verbatim
0738 /// {
0739 ///   'type': 'directory-remap',
0740 ///   'name': <string>,
0741 ///   'use-external-name': <boolean>, # Optional
0742 ///   'external-contents': <path to external directory>
0743 /// }
0744 /// \endverbatim
0745 /// and inherit their attributes from the external directory. When a path
0746 /// prefix matches such an entry, the unmatched components are appended to the
0747 /// 'external-contents' path, and the resulting path is looked up in the
0748 /// external file system instead.
0749 ///
0750 /// Re-mapped files are represented as
0751 /// \verbatim
0752 /// {
0753 ///   'type': 'file',
0754 ///   'name': <string>,
0755 ///   'use-external-name': <boolean>, # Optional
0756 ///   'external-contents': <path to external file>
0757 /// }
0758 /// \endverbatim
0759 /// Their attributes and file contents are determined by looking up the file at
0760 /// their 'external-contents' path in the external file system.
0761 ///
0762 /// For 'file', 'directory' and 'directory-remap' entries the 'name' field may
0763 /// contain multiple path components (e.g. /path/to/file). However, any
0764 /// directory in such a path that contains more than one child must be uniquely
0765 /// represented by a 'directory' entry.
0766 ///
0767 /// When the 'use-external-name' field is set, calls to \a vfs::File::status()
0768 /// give the external (remapped) filesystem name instead of the name the file
0769 /// was accessed by. This is an intentional leak through the \a
0770 /// RedirectingFileSystem abstraction layer. It enables clients to discover
0771 /// (and use) the external file location when communicating with users or tools
0772 /// that don't use the same VFS overlay.
0773 ///
0774 /// FIXME: 'use-external-name' causes behaviour that's inconsistent with how
0775 /// "real" filesystems behave. Maybe there should be a separate channel for
0776 /// this information.
0777 class RedirectingFileSystem
0778     : public RTTIExtends<RedirectingFileSystem, vfs::FileSystem> {
0779 public:
0780   static const char ID;
0781   enum EntryKind { EK_Directory, EK_DirectoryRemap, EK_File };
0782   enum NameKind { NK_NotSet, NK_External, NK_Virtual };
0783 
0784   /// The type of redirection to perform.
0785   enum class RedirectKind {
0786     /// Lookup the redirected path first (ie. the one specified in
0787     /// 'external-contents') and if that fails "fallthrough" to a lookup of the
0788     /// originally provided path.
0789     Fallthrough,
0790     /// Lookup the provided path first and if that fails, "fallback" to a
0791     /// lookup of the redirected path.
0792     Fallback,
0793     /// Only lookup the redirected path, do not lookup the originally provided
0794     /// path.
0795     RedirectOnly
0796   };
0797 
0798   /// The type of relative path used by Roots.
0799   enum class RootRelativeKind {
0800     /// The roots are relative to the current working directory.
0801     CWD,
0802     /// The roots are relative to the directory where the Overlay YAML file
0803     // locates.
0804     OverlayDir
0805   };
0806 
0807   /// A single file or directory in the VFS.
0808   class Entry {
0809     EntryKind Kind;
0810     std::string Name;
0811 
0812   public:
0813     Entry(EntryKind K, StringRef Name) : Kind(K), Name(Name) {}
0814     virtual ~Entry() = default;
0815 
0816     StringRef getName() const { return Name; }
0817     EntryKind getKind() const { return Kind; }
0818   };
0819 
0820   /// A directory in the vfs with explicitly specified contents.
0821   class DirectoryEntry : public Entry {
0822     std::vector<std::unique_ptr<Entry>> Contents;
0823     Status S;
0824 
0825   public:
0826     /// Constructs a directory entry with explicitly specified contents.
0827     DirectoryEntry(StringRef Name, std::vector<std::unique_ptr<Entry>> Contents,
0828                    Status S)
0829         : Entry(EK_Directory, Name), Contents(std::move(Contents)),
0830           S(std::move(S)) {}
0831 
0832     /// Constructs an empty directory entry.
0833     DirectoryEntry(StringRef Name, Status S)
0834         : Entry(EK_Directory, Name), S(std::move(S)) {}
0835 
0836     Status getStatus() { return S; }
0837 
0838     void addContent(std::unique_ptr<Entry> Content) {
0839       Contents.push_back(std::move(Content));
0840     }
0841 
0842     Entry *getLastContent() const { return Contents.back().get(); }
0843 
0844     using iterator = decltype(Contents)::iterator;
0845 
0846     iterator contents_begin() { return Contents.begin(); }
0847     iterator contents_end() { return Contents.end(); }
0848 
0849     static bool classof(const Entry *E) { return E->getKind() == EK_Directory; }
0850   };
0851 
0852   /// A file or directory in the vfs that is mapped to a file or directory in
0853   /// the external filesystem.
0854   class RemapEntry : public Entry {
0855     std::string ExternalContentsPath;
0856     NameKind UseName;
0857 
0858   protected:
0859     RemapEntry(EntryKind K, StringRef Name, StringRef ExternalContentsPath,
0860                NameKind UseName)
0861         : Entry(K, Name), ExternalContentsPath(ExternalContentsPath),
0862           UseName(UseName) {}
0863 
0864   public:
0865     StringRef getExternalContentsPath() const { return ExternalContentsPath; }
0866 
0867     /// Whether to use the external path as the name for this file or directory.
0868     bool useExternalName(bool GlobalUseExternalName) const {
0869       return UseName == NK_NotSet ? GlobalUseExternalName
0870                                   : (UseName == NK_External);
0871     }
0872 
0873     NameKind getUseName() const { return UseName; }
0874 
0875     static bool classof(const Entry *E) {
0876       switch (E->getKind()) {
0877       case EK_DirectoryRemap:
0878         [[fallthrough]];
0879       case EK_File:
0880         return true;
0881       case EK_Directory:
0882         return false;
0883       }
0884       llvm_unreachable("invalid entry kind");
0885     }
0886   };
0887 
0888   /// A directory in the vfs that maps to a directory in the external file
0889   /// system.
0890   class DirectoryRemapEntry : public RemapEntry {
0891   public:
0892     DirectoryRemapEntry(StringRef Name, StringRef ExternalContentsPath,
0893                         NameKind UseName)
0894         : RemapEntry(EK_DirectoryRemap, Name, ExternalContentsPath, UseName) {}
0895 
0896     static bool classof(const Entry *E) {
0897       return E->getKind() == EK_DirectoryRemap;
0898     }
0899   };
0900 
0901   /// A file in the vfs that maps to a file in the external file system.
0902   class FileEntry : public RemapEntry {
0903   public:
0904     FileEntry(StringRef Name, StringRef ExternalContentsPath, NameKind UseName)
0905         : RemapEntry(EK_File, Name, ExternalContentsPath, UseName) {}
0906 
0907     static bool classof(const Entry *E) { return E->getKind() == EK_File; }
0908   };
0909 
0910   /// Represents the result of a path lookup into the RedirectingFileSystem.
0911   struct LookupResult {
0912     /// Chain of parent directory entries for \c E.
0913     llvm::SmallVector<Entry *, 32> Parents;
0914 
0915     /// The entry the looked-up path corresponds to.
0916     Entry *E;
0917 
0918   private:
0919     /// When the found Entry is a DirectoryRemapEntry, stores the path in the
0920     /// external file system that the looked-up path in the virtual file system
0921     //  corresponds to.
0922     std::optional<std::string> ExternalRedirect;
0923 
0924   public:
0925     LookupResult(Entry *E, sys::path::const_iterator Start,
0926                  sys::path::const_iterator End);
0927 
0928     /// If the found Entry maps the input path to a path in the external
0929     /// file system (i.e. it is a FileEntry or DirectoryRemapEntry), returns
0930     /// that path.
0931     std::optional<StringRef> getExternalRedirect() const {
0932       if (isa<DirectoryRemapEntry>(E))
0933         return StringRef(*ExternalRedirect);
0934       if (auto *FE = dyn_cast<FileEntry>(E))
0935         return FE->getExternalContentsPath();
0936       return std::nullopt;
0937     }
0938 
0939     /// Get the (canonical) path of the found entry. This uses the as-written
0940     /// path components from the VFS specification.
0941     void getPath(llvm::SmallVectorImpl<char> &Path) const;
0942   };
0943 
0944 private:
0945   friend class RedirectingFSDirIterImpl;
0946   friend class RedirectingFileSystemParser;
0947 
0948   /// Canonicalize path by removing ".", "..", "./", components. This is
0949   /// a VFS request, do not bother about symlinks in the path components
0950   /// but canonicalize in order to perform the correct entry search.
0951   std::error_code makeCanonicalForLookup(SmallVectorImpl<char> &Path) const;
0952 
0953   /// Get the File status, or error, from the underlying external file system.
0954   /// This returns the status with the originally requested name, while looking
0955   /// up the entry using a potentially different path.
0956   ErrorOr<Status> getExternalStatus(const Twine &LookupPath,
0957                                     const Twine &OriginalPath) const;
0958 
0959   /// Make \a Path an absolute path.
0960   ///
0961   /// Makes \a Path absolute using the \a WorkingDir if it is not already.
0962   ///
0963   /// /absolute/path   => /absolute/path
0964   /// relative/../path => <WorkingDir>/relative/../path
0965   ///
0966   /// \param WorkingDir  A path that will be used as the base Dir if \a Path
0967   ///                    is not already absolute.
0968   /// \param Path A path that is modified to be an absolute path.
0969   /// \returns success if \a path has been made absolute, otherwise a
0970   ///          platform-specific error_code.
0971   std::error_code makeAbsolute(StringRef WorkingDir,
0972                                SmallVectorImpl<char> &Path) const;
0973 
0974   // In a RedirectingFileSystem, keys can be specified in Posix or Windows
0975   // style (or even a mixture of both), so this comparison helper allows
0976   // slashes (representing a root) to match backslashes (and vice versa).  Note
0977   // that, other than the root, path components should not contain slashes or
0978   // backslashes.
0979   bool pathComponentMatches(llvm::StringRef lhs, llvm::StringRef rhs) const {
0980     if ((CaseSensitive ? lhs == rhs : lhs.equals_insensitive(rhs)))
0981       return true;
0982     return (lhs == "/" && rhs == "\\") || (lhs == "\\" && rhs == "/");
0983   }
0984 
0985   /// The root(s) of the virtual file system.
0986   std::vector<std::unique_ptr<Entry>> Roots;
0987 
0988   /// The current working directory of the file system.
0989   std::string WorkingDirectory;
0990 
0991   /// The file system to use for external references.
0992   IntrusiveRefCntPtr<FileSystem> ExternalFS;
0993 
0994   /// This represents the directory path that the YAML file is located.
0995   /// This will be prefixed to each 'external-contents' if IsRelativeOverlay
0996   /// is set. This will also be prefixed to each 'roots->name' if RootRelative
0997   /// is set to RootRelativeKind::OverlayDir and the path is relative.
0998   std::string OverlayFileDir;
0999 
1000   /// @name Configuration
1001   /// @{
1002 
1003   /// Whether to perform case-sensitive comparisons.
1004   ///
1005   /// Currently, case-insensitive matching only works correctly with ASCII.
1006   bool CaseSensitive = is_style_posix(sys::path::Style::native);
1007 
1008   /// IsRelativeOverlay marks whether a OverlayFileDir path must
1009   /// be prefixed in every 'external-contents' when reading from YAML files.
1010   bool IsRelativeOverlay = false;
1011 
1012   /// Whether to use to use the value of 'external-contents' for the
1013   /// names of files.  This global value is overridable on a per-file basis.
1014   bool UseExternalNames = true;
1015 
1016   /// True if this FS has redirected a lookup. This does not include
1017   /// fallthrough.
1018   mutable bool HasBeenUsed = false;
1019 
1020   /// Used to enable or disable updating `HasBeenUsed`.
1021   bool UsageTrackingActive = false;
1022 
1023   /// Determines the lookups to perform, as well as their order. See
1024   /// \c RedirectKind for details.
1025   RedirectKind Redirection = RedirectKind::Fallthrough;
1026 
1027   /// Determine the prefix directory if the roots are relative paths. See
1028   /// \c RootRelativeKind for details.
1029   RootRelativeKind RootRelative = RootRelativeKind::CWD;
1030   /// @}
1031 
1032   RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS);
1033 
1034   /// Looks up the path <tt>[Start, End)</tt> in \p From, possibly recursing
1035   /// into the contents of \p From if it is a directory. Returns a LookupResult
1036   /// giving the matched entry and, if that entry is a FileEntry or
1037   /// DirectoryRemapEntry, the path it redirects to in the external file system.
1038   ErrorOr<LookupResult>
1039   lookupPathImpl(llvm::sys::path::const_iterator Start,
1040                  llvm::sys::path::const_iterator End, Entry *From,
1041                  llvm::SmallVectorImpl<Entry *> &Entries) const;
1042 
1043   /// Get the status for a path with the provided \c LookupResult.
1044   ErrorOr<Status> status(const Twine &LookupPath, const Twine &OriginalPath,
1045                          const LookupResult &Result);
1046 
1047 public:
1048   /// Looks up \p Path in \c Roots and returns a LookupResult giving the
1049   /// matched entry and, if the entry was a FileEntry or DirectoryRemapEntry,
1050   /// the path it redirects to in the external file system.
1051   ErrorOr<LookupResult> lookupPath(StringRef Path) const;
1052 
1053   /// Parses \p Buffer, which is expected to be in YAML format and
1054   /// returns a virtual file system representing its contents.
1055   static std::unique_ptr<RedirectingFileSystem>
1056   create(std::unique_ptr<MemoryBuffer> Buffer,
1057          SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath,
1058          void *DiagContext, IntrusiveRefCntPtr<FileSystem> ExternalFS);
1059 
1060   /// Redirect each of the remapped files from first to second.
1061   static std::unique_ptr<RedirectingFileSystem>
1062   create(ArrayRef<std::pair<std::string, std::string>> RemappedFiles,
1063          bool UseExternalNames, FileSystem &ExternalFS);
1064 
1065   ErrorOr<Status> status(const Twine &Path) override;
1066   bool exists(const Twine &Path) override;
1067   ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
1068 
1069   std::error_code getRealPath(const Twine &Path,
1070                               SmallVectorImpl<char> &Output) override;
1071 
1072   llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override;
1073 
1074   std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
1075 
1076   std::error_code isLocal(const Twine &Path, bool &Result) override;
1077 
1078   std::error_code makeAbsolute(SmallVectorImpl<char> &Path) const override;
1079 
1080   directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
1081 
1082   void setOverlayFileDir(StringRef PrefixDir);
1083 
1084   StringRef getOverlayFileDir() const;
1085 
1086   /// Sets the redirection kind to \c Fallthrough if true or \c RedirectOnly
1087   /// otherwise. Will removed in the future, use \c setRedirection instead.
1088   void setFallthrough(bool Fallthrough);
1089 
1090   void setRedirection(RedirectingFileSystem::RedirectKind Kind);
1091 
1092   std::vector<llvm::StringRef> getRoots() const;
1093 
1094   bool hasBeenUsed() const { return HasBeenUsed; };
1095   void clearHasBeenUsed() { HasBeenUsed = false; }
1096 
1097   void setUsageTrackingActive(bool Active) { UsageTrackingActive = Active; }
1098 
1099   void printEntry(raw_ostream &OS, Entry *E, unsigned IndentLevel = 0) const;
1100 
1101 protected:
1102   void printImpl(raw_ostream &OS, PrintType Type,
1103                  unsigned IndentLevel) const override;
1104   void visitChildFileSystems(VisitCallbackTy Callback) override;
1105 };
1106 
1107 /// Collect all pairs of <virtual path, real path> entries from the
1108 /// \p YAMLFilePath. This is used by the module dependency collector to forward
1109 /// the entries into the reproducer output VFS YAML file.
1110 void collectVFSFromYAML(
1111     std::unique_ptr<llvm::MemoryBuffer> Buffer,
1112     llvm::SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath,
1113     SmallVectorImpl<YAMLVFSEntry> &CollectedEntries,
1114     void *DiagContext = nullptr,
1115     IntrusiveRefCntPtr<FileSystem> ExternalFS = getRealFileSystem());
1116 
1117 class YAMLVFSWriter {
1118   std::vector<YAMLVFSEntry> Mappings;
1119   std::optional<bool> IsCaseSensitive;
1120   std::optional<bool> IsOverlayRelative;
1121   std::optional<bool> UseExternalNames;
1122   std::string OverlayDir;
1123 
1124   void addEntry(StringRef VirtualPath, StringRef RealPath, bool IsDirectory);
1125 
1126 public:
1127   YAMLVFSWriter() = default;
1128 
1129   void addFileMapping(StringRef VirtualPath, StringRef RealPath);
1130   void addDirectoryMapping(StringRef VirtualPath, StringRef RealPath);
1131 
1132   void setCaseSensitivity(bool CaseSensitive) {
1133     IsCaseSensitive = CaseSensitive;
1134   }
1135 
1136   void setUseExternalNames(bool UseExtNames) { UseExternalNames = UseExtNames; }
1137 
1138   void setOverlayDir(StringRef OverlayDirectory) {
1139     IsOverlayRelative = true;
1140     OverlayDir.assign(OverlayDirectory.str());
1141   }
1142 
1143   const std::vector<YAMLVFSEntry> &getMappings() const { return Mappings; }
1144 
1145   void write(llvm::raw_ostream &OS);
1146 };
1147 
1148 /// File system that tracks the number of calls to the underlying file system.
1149 /// This is particularly useful when wrapped around \c RealFileSystem to add
1150 /// lightweight tracking of expensive syscalls.
1151 class TracingFileSystem
1152     : public llvm::RTTIExtends<TracingFileSystem, ProxyFileSystem> {
1153 public:
1154   static const char ID;
1155 
1156   std::size_t NumStatusCalls = 0;
1157   std::size_t NumOpenFileForReadCalls = 0;
1158   std::size_t NumDirBeginCalls = 0;
1159   std::size_t NumGetRealPathCalls = 0;
1160   std::size_t NumExistsCalls = 0;
1161   std::size_t NumIsLocalCalls = 0;
1162 
1163   TracingFileSystem(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
1164       : RTTIExtends(std::move(FS)) {}
1165 
1166   ErrorOr<Status> status(const Twine &Path) override {
1167     ++NumStatusCalls;
1168     return ProxyFileSystem::status(Path);
1169   }
1170 
1171   ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override {
1172     ++NumOpenFileForReadCalls;
1173     return ProxyFileSystem::openFileForRead(Path);
1174   }
1175 
1176   directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override {
1177     ++NumDirBeginCalls;
1178     return ProxyFileSystem::dir_begin(Dir, EC);
1179   }
1180 
1181   std::error_code getRealPath(const Twine &Path,
1182                               SmallVectorImpl<char> &Output) override {
1183     ++NumGetRealPathCalls;
1184     return ProxyFileSystem::getRealPath(Path, Output);
1185   }
1186 
1187   bool exists(const Twine &Path) override {
1188     ++NumExistsCalls;
1189     return ProxyFileSystem::exists(Path);
1190   }
1191 
1192   std::error_code isLocal(const Twine &Path, bool &Result) override {
1193     ++NumIsLocalCalls;
1194     return ProxyFileSystem::isLocal(Path, Result);
1195   }
1196 
1197 protected:
1198   void printImpl(raw_ostream &OS, PrintType Type,
1199                  unsigned IndentLevel) const override;
1200 };
1201 
1202 } // namespace vfs
1203 } // namespace llvm
1204 
1205 #endif // LLVM_SUPPORT_VIRTUALFILESYSTEM_H