LCOV - code coverage report
Current view: top level - lib/Support - VirtualFileSystem.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 580 735 78.9 %
Date: 2018-10-20 13:21:21 Functions: 98 123 79.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===- VirtualFileSystem.cpp - Virtual File System Layer ------------------===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : //
      10             : // This file implements the VirtualFileSystem interface.
      11             : //
      12             : //===----------------------------------------------------------------------===//
      13             : 
      14             : #include "llvm/Support/VirtualFileSystem.h"
      15             : #include "llvm/ADT/ArrayRef.h"
      16             : #include "llvm/ADT/DenseMap.h"
      17             : #include "llvm/ADT/IntrusiveRefCntPtr.h"
      18             : #include "llvm/ADT/None.h"
      19             : #include "llvm/ADT/Optional.h"
      20             : #include "llvm/ADT/STLExtras.h"
      21             : #include "llvm/ADT/SmallString.h"
      22             : #include "llvm/ADT/SmallVector.h"
      23             : #include "llvm/ADT/StringRef.h"
      24             : #include "llvm/ADT/StringSet.h"
      25             : #include "llvm/ADT/Twine.h"
      26             : #include "llvm/ADT/iterator_range.h"
      27             : #include "llvm/Config/llvm-config.h"
      28             : #include "llvm/Support/Casting.h"
      29             : #include "llvm/Support/Chrono.h"
      30             : #include "llvm/Support/Compiler.h"
      31             : #include "llvm/Support/Debug.h"
      32             : #include "llvm/Support/Errc.h"
      33             : #include "llvm/Support/ErrorHandling.h"
      34             : #include "llvm/Support/ErrorOr.h"
      35             : #include "llvm/Support/FileSystem.h"
      36             : #include "llvm/Support/MemoryBuffer.h"
      37             : #include "llvm/Support/Path.h"
      38             : #include "llvm/Support/Process.h"
      39             : #include "llvm/Support/SMLoc.h"
      40             : #include "llvm/Support/SourceMgr.h"
      41             : #include "llvm/Support/YAMLParser.h"
      42             : #include "llvm/Support/raw_ostream.h"
      43             : #include <algorithm>
      44             : #include <atomic>
      45             : #include <cassert>
      46             : #include <cstdint>
      47             : #include <iterator>
      48             : #include <limits>
      49             : #include <map>
      50             : #include <memory>
      51             : #include <mutex>
      52             : #include <string>
      53             : #include <system_error>
      54             : #include <utility>
      55             : #include <vector>
      56             : 
      57             : using namespace llvm;
      58             : using namespace llvm::vfs;
      59             : 
      60             : using llvm::sys::fs::file_status;
      61             : using llvm::sys::fs::file_type;
      62             : using llvm::sys::fs::perms;
      63             : using llvm::sys::fs::UniqueID;
      64             : 
      65           0 : Status::Status(const file_status &Status)
      66           0 :     : UID(Status.getUniqueID()), MTime(Status.getLastModificationTime()),
      67           0 :       User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()),
      68           0 :       Type(Status.type()), Perms(Status.permissions()) {}
      69             : 
      70     2576874 : Status::Status(StringRef Name, UniqueID UID, sys::TimePoint<> MTime,
      71             :                uint32_t User, uint32_t Group, uint64_t Size, file_type Type,
      72     2576874 :                perms Perms)
      73             :     : Name(Name), UID(UID), MTime(MTime), User(User), Group(Group), Size(Size),
      74     2576877 :       Type(Type), Perms(Perms) {}
      75             : 
      76      114707 : Status Status::copyWithNewName(const Status &In, StringRef NewName) {
      77             :   return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
      78             :                 In.getUser(), In.getGroup(), In.getSize(), In.getType(),
      79      114707 :                 In.getPermissions());
      80             : }
      81             : 
      82     1489714 : Status Status::copyWithNewName(const file_status &In, StringRef NewName) {
      83             :   return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
      84             :                 In.getUser(), In.getGroup(), In.getSize(), In.type(),
      85     2979428 :                 In.permissions());
      86             : }
      87             : 
      88          16 : bool Status::equivalent(const Status &Other) const {
      89             :   assert(isStatusKnown() && Other.isStatusKnown());
      90          16 :   return getUniqueID() == Other.getUniqueID();
      91             : }
      92             : 
      93     1119911 : bool Status::isDirectory() const { return Type == file_type::directory_file; }
      94             : 
      95          12 : bool Status::isRegularFile() const { return Type == file_type::regular_file; }
      96             : 
      97           3 : bool Status::isOther() const {
      98           3 :   return exists() && !isRegularFile() && !isDirectory() && !isSymlink();
      99             : }
     100             : 
     101           7 : bool Status::isSymlink() const { return Type == file_type::symlink_file; }
     102             : 
     103     1214976 : bool Status::isStatusKnown() const { return Type != file_type::status_error; }
     104             : 
     105      476121 : bool Status::exists() const {
     106      476121 :   return isStatusKnown() && Type != file_type::file_not_found;
     107             : }
     108             : 
     109             : File::~File() = default;
     110             : 
     111             : FileSystem::~FileSystem() = default;
     112             : 
     113             : ErrorOr<std::unique_ptr<MemoryBuffer>>
     114      745483 : FileSystem::getBufferForFile(const llvm::Twine &Name, int64_t FileSize,
     115             :                              bool RequiresNullTerminator, bool IsVolatile) {
     116      745483 :   auto F = openFileForRead(Name);
     117      745492 :   if (!F)
     118      633655 :     return F.getError();
     119             : 
     120      111837 :   return (*F)->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile);
     121             : }
     122             : 
     123     1591724 : std::error_code FileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const {
     124     1591724 :   if (llvm::sys::path::is_absolute(Path))
     125     1348975 :     return {};
     126             : 
     127      242741 :   auto WorkingDir = getCurrentWorkingDirectory();
     128      242732 :   if (!WorkingDir)
     129             :     return WorkingDir.getError();
     130             : 
     131      242732 :   return llvm::sys::fs::make_absolute(WorkingDir.get(), Path);
     132             : }
     133             : 
     134          21 : std::error_code FileSystem::getRealPath(const Twine &Path,
     135             :                                         SmallVectorImpl<char> &Output) const {
     136          21 :   return errc::operation_not_permitted;
     137             : }
     138             : 
     139     1021947 : bool FileSystem::exists(const Twine &Path) {
     140     1021947 :   auto Status = status(Path);
     141     1021944 :   return Status && Status->exists();
     142             : }
     143             : 
     144             : #ifndef NDEBUG
     145             : static bool isTraversalComponent(StringRef Component) {
     146             :   return Component.equals("..") || Component.equals(".");
     147             : }
     148             : 
     149             : static bool pathHasTraversal(StringRef Path) {
     150             :   using namespace llvm::sys;
     151             : 
     152             :   for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path)))
     153             :     if (isTraversalComponent(Comp))
     154             :       return true;
     155             :   return false;
     156             : }
     157             : #endif
     158             : 
     159             : //===-----------------------------------------------------------------------===/
     160             : // RealFileSystem implementation
     161             : //===-----------------------------------------------------------------------===/
     162             : 
     163             : namespace {
     164             : 
     165             : /// Wrapper around a raw file descriptor.
     166             : class RealFile : public File {
     167             :   friend class RealFileSystem;
     168             : 
     169             :   int FD;
     170             :   Status S;
     171             :   std::string RealName;
     172             : 
     173      804534 :   RealFile(int FD, StringRef NewName, StringRef NewRealPathName)
     174      804534 :       : FD(FD), S(NewName, {}, {}, {}, {}, {},
     175             :                   llvm::sys::fs::file_type::status_error, {}),
     176     1609068 :         RealName(NewRealPathName.str()) {
     177             :     assert(FD >= 0 && "Invalid or inactive file descriptor");
     178      804534 :   }
     179             : 
     180             : public:
     181             :   ~RealFile() override;
     182             : 
     183             :   ErrorOr<Status> status() override;
     184             :   ErrorOr<std::string> getName() override;
     185             :   ErrorOr<std::unique_ptr<MemoryBuffer>> getBuffer(const Twine &Name,
     186             :                                                    int64_t FileSize,
     187             :                                                    bool RequiresNullTerminator,
     188             :                                                    bool IsVolatile) override;
     189             :   std::error_code close() override;
     190             : };
     191             : 
     192             : } // namespace
     193             : 
     194     1601514 : RealFile::~RealFile() { close(); }
     195             : 
     196      738852 : ErrorOr<Status> RealFile::status() {
     197             :   assert(FD != -1 && "cannot stat closed file");
     198      738852 :   if (!S.isStatusKnown()) {
     199      738851 :     file_status RealStatus;
     200      738851 :     if (std::error_code EC = sys::fs::status(FD, RealStatus))
     201           0 :       return EC;
     202     1477702 :     S = Status::copyWithNewName(RealStatus, S.getName());
     203             :   }
     204             :   return S;
     205             : }
     206             : 
     207      738750 : ErrorOr<std::string> RealFile::getName() {
     208      738750 :   return RealName.empty() ? S.getName().str() : RealName;
     209             : }
     210             : 
     211             : ErrorOr<std::unique_ptr<MemoryBuffer>>
     212      799403 : RealFile::getBuffer(const Twine &Name, int64_t FileSize,
     213             :                     bool RequiresNullTerminator, bool IsVolatile) {
     214             :   assert(FD != -1 && "cannot get buffer for closed file");
     215             :   return MemoryBuffer::getOpenFile(FD, Name, FileSize, RequiresNullTerminator,
     216      799403 :                                    IsVolatile);
     217             : }
     218             : 
     219           0 : std::error_code RealFile::close() {
     220      800757 :   std::error_code EC = sys::Process::SafelyCloseFileDescriptor(FD);
     221      800757 :   FD = -1;
     222           0 :   return EC;
     223             : }
     224             : 
     225             : namespace {
     226             : 
     227             : /// The file system according to your operating system.
     228       52237 : class RealFileSystem : public FileSystem {
     229             : public:
     230             :   ErrorOr<Status> status(const Twine &Path) override;
     231             :   ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
     232             :   directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
     233             : 
     234             :   llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override;
     235             :   std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
     236             :   std::error_code getRealPath(const Twine &Path,
     237             :                               SmallVectorImpl<char> &Output) const override;
     238             : 
     239             : private:
     240             :   mutable std::mutex CWDMutex;
     241             :   mutable std::string CWDCache;
     242             : };
     243             : 
     244             : } // namespace
     245             : 
     246     1508344 : ErrorOr<Status> RealFileSystem::status(const Twine &Path) {
     247     1508344 :   sys::fs::file_status RealStatus;
     248     1508344 :   if (std::error_code EC = sys::fs::status(Path, RealStatus))
     249      757478 :     return EC;
     250     2045895 :   return Status::copyWithNewName(RealStatus, Path.str());
     251             : }
     252             : 
     253             : ErrorOr<std::unique_ptr<File>>
     254     1965012 : RealFileSystem::openFileForRead(const Twine &Name) {
     255             :   int FD;
     256             :   SmallString<256> RealName;
     257     1965015 :   if (std::error_code EC =
     258     1965012 :           sys::fs::openFileForRead(Name, FD, sys::fs::OF_None, &RealName))
     259     1160481 :     return EC;
     260     1608923 :   return std::unique_ptr<File>(new RealFile(FD, Name.str(), RealName.str()));
     261             : }
     262             : 
     263       20509 : llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory() const {
     264       20509 :   std::lock_guard<std::mutex> Lock(CWDMutex);
     265       20509 :   if (!CWDCache.empty())
     266             :     return CWDCache;
     267             :   SmallString<256> Dir;
     268        6625 :   if (std::error_code EC = llvm::sys::fs::current_path(Dir))
     269           0 :     return EC;
     270       13250 :   CWDCache = Dir.str();
     271             :   return CWDCache;
     272             : }
     273             : 
     274       11019 : std::error_code RealFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
     275             :   // FIXME: chdir is thread hostile; on the other hand, creating the same
     276             :   // behavior as chdir is complex: chdir resolves the path once, thus
     277             :   // guaranteeing that all subsequent relative path operations work
     278             :   // on the same path the original chdir resulted in. This makes a
     279             :   // difference for example on network filesystems, where symlinks might be
     280             :   // switched during runtime of the tool. Fixing this depends on having a
     281             :   // file system abstraction that allows openat() style interactions.
     282       11019 :   if (auto EC = llvm::sys::fs::set_current_path(Path))
     283         115 :     return EC;
     284             : 
     285             :   // Invalidate cache.
     286       10904 :   std::lock_guard<std::mutex> Lock(CWDMutex);
     287             :   CWDCache.clear();
     288       10904 :   return std::error_code();
     289             : }
     290             : 
     291             : std::error_code
     292        1395 : RealFileSystem::getRealPath(const Twine &Path,
     293             :                             SmallVectorImpl<char> &Output) const {
     294        1395 :   return llvm::sys::fs::real_path(Path, Output);
     295             : }
     296             : 
     297       58972 : IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
     298       58972 :   static IntrusiveRefCntPtr<FileSystem> FS = new RealFileSystem();
     299       58972 :   return FS;
     300             : }
     301             : 
     302             : namespace {
     303             : 
     304             : class RealFSDirIter : public llvm::vfs::detail::DirIterImpl {
     305             :   llvm::sys::fs::directory_iterator Iter;
     306             : 
     307             : public:
     308     8640536 :   RealFSDirIter(const Twine &Path, std::error_code &EC) : Iter(Path, EC) {
     309     4319955 :     if (Iter != llvm::sys::fs::directory_iterator())
     310       80376 :       CurrentEntry = directory_entry(Iter->path(), Iter->type());
     311     4319955 :   }
     312             : 
     313       46475 :   std::error_code increment() override {
     314             :     std::error_code EC;
     315             :     Iter.increment(EC);
     316       46475 :     CurrentEntry = (Iter == llvm::sys::fs::directory_iterator())
     317       99239 :                        ? directory_entry()
     318             :                        : directory_entry(Iter->path(), Iter->type());
     319       46474 :     return EC;
     320             :   }
     321             : };
     322             : 
     323             : } // namespace
     324             : 
     325     4320265 : directory_iterator RealFileSystem::dir_begin(const Twine &Dir,
     326             :                                              std::error_code &EC) {
     327     8640536 :   return directory_iterator(std::make_shared<RealFSDirIter>(Dir, EC));
     328             : }
     329             : 
     330             : //===-----------------------------------------------------------------------===/
     331             : // OverlayFileSystem implementation
     332             : //===-----------------------------------------------------------------------===/
     333             : 
     334       11614 : OverlayFileSystem::OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> BaseFS) {
     335        5807 :   FSList.push_back(std::move(BaseFS));
     336        5807 : }
     337             : 
     338        5809 : void OverlayFileSystem::pushOverlay(IntrusiveRefCntPtr<FileSystem> FS) {
     339        5809 :   FSList.push_back(FS);
     340             :   // Synchronize added file systems by duplicating the working directory from
     341             :   // the first one in the list.
     342        5809 :   FS->setCurrentWorkingDirectory(getCurrentWorkingDirectory().get());
     343        5809 : }
     344             : 
     345      245162 : ErrorOr<Status> OverlayFileSystem::status(const Twine &Path) {
     346             :   // FIXME: handle symlinks that cross file systems
     347      585498 :   for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
     348      477643 :     ErrorOr<Status> Status = (*I)->status(Path);
     349      477638 :     if (Status || Status.getError() != llvm::errc::no_such_file_or_directory)
     350             :       return Status;
     351             :   }
     352      107855 :   return make_error_code(llvm::errc::no_such_file_or_directory);
     353             : }
     354             : 
     355             : ErrorOr<std::unique_ptr<File>>
     356      127408 : OverlayFileSystem::openFileForRead(const llvm::Twine &Path) {
     357             :   // FIXME: handle symlinks that cross file systems
     358      359222 :   for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
     359      248520 :     auto Result = (*I)->openFileForRead(Path);
     360      248525 :     if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
     361             :       return Result;
     362             :   }
     363      110702 :   return make_error_code(llvm::errc::no_such_file_or_directory);
     364             : }
     365             : 
     366             : llvm::ErrorOr<std::string>
     367       12180 : OverlayFileSystem::getCurrentWorkingDirectory() const {
     368             :   // All file systems are synchronized, just take the first working directory.
     369       12180 :   return FSList.front()->getCurrentWorkingDirectory();
     370             : }
     371             : 
     372             : std::error_code
     373        1602 : OverlayFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
     374        4806 :   for (auto &FS : FSList)
     375        3204 :     if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))
     376           0 :       return EC;
     377        1602 :   return {};
     378             : }
     379             : 
     380             : std::error_code
     381         112 : OverlayFileSystem::getRealPath(const Twine &Path,
     382             :                                SmallVectorImpl<char> &Output) const {
     383         148 :   for (auto &FS : FSList)
     384         141 :     if (FS->exists(Path))
     385         105 :       return FS->getRealPath(Path, Output);
     386           7 :   return errc::no_such_file_or_directory;
     387             : }
     388             : 
     389             : llvm::vfs::detail::DirIterImpl::~DirIterImpl() = default;
     390             : 
     391             : namespace {
     392             : 
     393             : class OverlayFSDirIterImpl : public llvm::vfs::detail::DirIterImpl {
     394             :   OverlayFileSystem &Overlays;
     395             :   std::string Path;
     396             :   OverlayFileSystem::iterator CurrentFS;
     397             :   directory_iterator CurrentDirIter;
     398             :   llvm::StringSet<> SeenNames;
     399             : 
     400      980504 :   std::error_code incrementFS() {
     401             :     assert(CurrentFS != Overlays.overlays_end() && "incrementing past end");
     402             :     ++CurrentFS;
     403     1946717 :     for (auto E = Overlays.overlays_end(); CurrentFS != E; ++CurrentFS) {
     404             :       std::error_code EC;
     405     1946732 :       CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC);
     406      973376 :       if (EC && EC != errc::no_such_file_or_directory)
     407           0 :         return EC;
     408      973376 :       if (CurrentDirIter != directory_iterator())
     409             :         break; // found
     410             :     }
     411      980514 :     return {};
     412             :   }
     413             : 
     414      980580 :   std::error_code incrementDirIter(bool IsFirstTime) {
     415             :     assert((IsFirstTime || CurrentDirIter != directory_iterator()) &&
     416             :            "incrementing past end");
     417             :     std::error_code EC;
     418      980580 :     if (!IsFirstTime)
     419        7235 :       CurrentDirIter.increment(EC);
     420     1961161 :     if (!EC && CurrentDirIter == directory_iterator())
     421      980502 :       EC = incrementFS();
     422      980594 :     return EC;
     423             :   }
     424             : 
     425      980569 :   std::error_code incrementImpl(bool IsFirstTime) {
     426             :     while (true) {
     427      980578 :       std::error_code EC = incrementDirIter(IsFirstTime);
     428     1961152 :       if (EC || CurrentDirIter == directory_iterator()) {
     429      973341 :         CurrentEntry = directory_entry();
     430      973409 :         return EC;
     431             :       }
     432             :       CurrentEntry = *CurrentDirIter;
     433        7237 :       StringRef Name = llvm::sys::path::filename(CurrentEntry.path());
     434        7237 :       if (SeenNames.insert(Name).second)
     435        7228 :         return EC; // name not seen before
     436           9 :     }
     437             :     llvm_unreachable("returned above");
     438             :   }
     439             : 
     440             : public:
     441      973349 :   OverlayFSDirIterImpl(const Twine &Path, OverlayFileSystem &FS,
     442             :                        std::error_code &EC)
     443     1946698 :       : Overlays(FS), Path(Path.str()), CurrentFS(Overlays.overlays_begin()) {
     444      973366 :     CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC);
     445      973350 :     EC = incrementImpl(true);
     446      973379 :   }
     447             : 
     448        7226 :   std::error_code increment() override { return incrementImpl(false); }
     449             : };
     450             : 
     451             : } // namespace
     452             : 
     453      973360 : directory_iterator OverlayFileSystem::dir_begin(const Twine &Dir,
     454             :                                                 std::error_code &EC) {
     455             :   return directory_iterator(
     456     1946718 :       std::make_shared<OverlayFSDirIterImpl>(Dir, *this, EC));
     457             : }
     458             : 
     459             : namespace llvm {
     460             : namespace vfs {
     461             : 
     462             : namespace detail {
     463             : 
     464             : enum InMemoryNodeKind { IME_File, IME_Directory, IME_HardLink };
     465             : 
     466             : /// The in memory file system is a tree of Nodes. Every node can either be a
     467             : /// file , hardlink or a directory.
     468             : class InMemoryNode {
     469             :   InMemoryNodeKind Kind;
     470             :   std::string FileName;
     471             : 
     472             : public:
     473      166253 :   InMemoryNode(llvm::StringRef FileName, InMemoryNodeKind Kind)
     474      166253 :       : Kind(Kind), FileName(llvm::sys::path::filename(FileName)) {}
     475           0 :   virtual ~InMemoryNode() = default;
     476             : 
     477             :   /// Get the filename of this node (the name without the directory part).
     478             :   StringRef getFileName() const { return FileName; }
     479           0 :   InMemoryNodeKind getKind() const { return Kind; }
     480             :   virtual std::string toString(unsigned Indent) const = 0;
     481             : };
     482             : 
     483             : class InMemoryFile : public InMemoryNode {
     484             :   Status Stat;
     485             :   std::unique_ptr<llvm::MemoryBuffer> Buffer;
     486             : 
     487             : public:
     488       62403 :   InMemoryFile(Status Stat, std::unique_ptr<llvm::MemoryBuffer> Buffer)
     489       62403 :       : InMemoryNode(Stat.getName(), IME_File), Stat(std::move(Stat)),
     490      124806 :         Buffer(std::move(Buffer)) {}
     491             : 
     492             :   /// Return the \p Status for this node. \p RequestedName should be the name
     493             :   /// through which the caller referred to this node. It will override
     494             :   /// \p Status::Name in the return value, to mimic the behavior of \p RealFile.
     495             :   Status getStatus(StringRef RequestedName) const {
     496       57965 :     return Status::copyWithNewName(Stat, RequestedName);
     497             :   }
     498             :   llvm::MemoryBuffer *getBuffer() const { return Buffer.get(); }
     499             : 
     500           0 :   std::string toString(unsigned Indent) const override {
     501           0 :     return (std::string(Indent, ' ') + Stat.getName() + "\n").str();
     502             :   }
     503             : 
     504             :   static bool classof(const InMemoryNode *N) {
     505     1443533 :     return N->getKind() == IME_File;
     506             :   }
     507             : };
     508             : 
     509             : namespace {
     510             : 
     511             : class InMemoryHardLink : public InMemoryNode {
     512             :   const InMemoryFile &ResolvedFile;
     513             : 
     514             : public:
     515             :   InMemoryHardLink(StringRef Path, const InMemoryFile &ResolvedFile)
     516           8 :       : InMemoryNode(Path, IME_HardLink), ResolvedFile(ResolvedFile) {}
     517           0 :   const InMemoryFile &getResolvedFile() const { return ResolvedFile; }
     518             : 
     519           0 :   std::string toString(unsigned Indent) const override {
     520           0 :     return std::string(Indent, ' ') + "HardLink to -> " +
     521           0 :            ResolvedFile.toString(0);
     522             :   }
     523             : 
     524             :   static bool classof(const InMemoryNode *N) {
     525         622 :     return N->getKind() == IME_HardLink;
     526             :   }
     527             : };
     528             : 
     529             : /// Adapt a InMemoryFile for VFS' File interface.  The goal is to make
     530             : /// \p InMemoryFileAdaptor mimic as much as possible the behavior of
     531             : /// \p RealFile.
     532             : class InMemoryFileAdaptor : public File {
     533             :   const InMemoryFile &Node;
     534             :   /// The name to use when returning a Status for this file.
     535             :   std::string RequestedName;
     536             : 
     537             : public:
     538             :   explicit InMemoryFileAdaptor(const InMemoryFile &Node,
     539             :                                std::string RequestedName)
     540       51625 :       : Node(Node), RequestedName(std::move(RequestedName)) {}
     541             : 
     542       10986 :   llvm::ErrorOr<Status> status() override {
     543       10986 :     return Node.getStatus(RequestedName);
     544             :   }
     545             : 
     546             :   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
     547       51615 :   getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
     548             :             bool IsVolatile) override {
     549       51615 :     llvm::MemoryBuffer *Buf = Node.getBuffer();
     550       51615 :     return llvm::MemoryBuffer::getMemBuffer(
     551       51615 :         Buf->getBuffer(), Buf->getBufferIdentifier(), RequiresNullTerminator);
     552             :   }
     553             : 
     554           0 :   std::error_code close() override { return {}; }
     555             : };
     556             : } // namespace
     557             : 
     558             : class InMemoryDirectory : public InMemoryNode {
     559             :   Status Stat;
     560             :   llvm::StringMap<std::unique_ptr<InMemoryNode>> Entries;
     561             : 
     562             : public:
     563      103842 :   InMemoryDirectory(Status Stat)
     564      207684 :       : InMemoryNode(Stat.getName(), IME_Directory), Stat(std::move(Stat)) {}
     565             : 
     566             :   /// Return the \p Status for this node. \p RequestedName should be the name
     567             :   /// through which the caller referred to this node. It will override
     568             :   /// \p Status::Name in the return value, to mimic the behavior of \p RealFile.
     569             :   Status getStatus(StringRef RequestedName) const {
     570       56354 :     return Status::copyWithNewName(Stat, RequestedName);
     571             :   }
     572     2984945 :   InMemoryNode *getChild(StringRef Name) {
     573     2984945 :     auto I = Entries.find(Name);
     574     5971762 :     if (I != Entries.end())
     575     1528276 :       return I->second.get();
     576             :     return nullptr;
     577             :   }
     578             : 
     579      115068 :   InMemoryNode *addChild(StringRef Name, std::unique_ptr<InMemoryNode> Child) {
     580      115068 :     return Entries.insert(make_pair(Name, std::move(Child)))
     581      115069 :         .first->second.get();
     582             :   }
     583             : 
     584             :   using const_iterator = decltype(Entries)::const_iterator;
     585             : 
     586           8 :   const_iterator begin() const { return Entries.begin(); }
     587           8 :   const_iterator end() const { return Entries.end(); }
     588             : 
     589           0 :   std::string toString(unsigned Indent) const override {
     590             :     std::string Result =
     591           0 :         (std::string(Indent, ' ') + Stat.getName() + "\n").str();
     592           0 :     for (const auto &Entry : Entries)
     593           0 :       Result += Entry.second->toString(Indent + 2);
     594           0 :     return Result;
     595             :   }
     596             : 
     597             :   static bool classof(const InMemoryNode *N) {
     598       85020 :     return N->getKind() == IME_Directory;
     599             :   }
     600             : };
     601             : 
     602             : namespace {
     603      103333 : Status getNodeStatus(const InMemoryNode *Node, StringRef RequestedName) {
     604             :   if (auto Dir = dyn_cast<detail::InMemoryDirectory>(Node))
     605       56354 :     return Dir->getStatus(RequestedName);
     606             :   if (auto File = dyn_cast<detail::InMemoryFile>(Node))
     607       46979 :     return File->getStatus(RequestedName);
     608             :   if (auto Link = dyn_cast<detail::InMemoryHardLink>(Node))
     609           0 :     return Link->getResolvedFile().getStatus(RequestedName);
     610           0 :   llvm_unreachable("Unknown node type");
     611             : }
     612             : } // namespace
     613             : } // namespace detail
     614             : 
     615       51183 : InMemoryFileSystem::InMemoryFileSystem(bool UseNormalizedPaths)
     616             :     : Root(new detail::InMemoryDirectory(
     617       51183 :           Status("", getNextVirtualUniqueID(), llvm::sys::TimePoint<>(), 0, 0,
     618             :                  0, llvm::sys::fs::file_type::directory_file,
     619       51183 :                  llvm::sys::fs::perms::all_all))),
     620       51183 :       UseNormalizedPaths(UseNormalizedPaths) {}
     621             : 
     622             : InMemoryFileSystem::~InMemoryFileSystem() = default;
     623             : 
     624           0 : std::string InMemoryFileSystem::toString() const {
     625           0 :   return Root->toString(/*Indent=*/0);
     626             : }
     627             : 
     628       63037 : bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
     629             :                                  std::unique_ptr<llvm::MemoryBuffer> Buffer,
     630             :                                  Optional<uint32_t> User,
     631             :                                  Optional<uint32_t> Group,
     632             :                                  Optional<llvm::sys::fs::file_type> Type,
     633             :                                  Optional<llvm::sys::fs::perms> Perms,
     634             :                                  const detail::InMemoryFile *HardLinkTarget) {
     635             :   SmallString<128> Path;
     636       63037 :   P.toVector(Path);
     637             : 
     638             :   // Fix up relative paths. This just prepends the current working directory.
     639       63035 :   std::error_code EC = makeAbsolute(Path);
     640             :   assert(!EC);
     641             :   (void)EC;
     642             : 
     643       63031 :   if (useNormalizedPaths())
     644       62990 :     llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
     645             : 
     646       63036 :   if (Path.empty())
     647             :     return false;
     648             : 
     649             :   detail::InMemoryDirectory *Dir = Root.get();
     650       63038 :   auto I = llvm::sys::path::begin(Path), E = sys::path::end(Path);
     651             :   const auto ResolvedUser = User.getValueOr(0);
     652             :   const auto ResolvedGroup = Group.getValueOr(0);
     653             :   const auto ResolvedType = Type.getValueOr(sys::fs::file_type::regular_file);
     654             :   const auto ResolvedPerms = Perms.getValueOr(sys::fs::all_all);
     655             :   assert(!(HardLinkTarget && Buffer) && "HardLink cannot have a buffer");
     656             :   // Any intermediate directories we create should be accessible by
     657             :   // the owner, even if Perms says otherwise for the final path.
     658             :   const auto NewDirectoryPerms = ResolvedPerms | sys::fs::owner_all;
     659             :   while (true) {
     660      200082 :     StringRef Name = *I;
     661      200082 :     detail::InMemoryNode *Node = Dir->getChild(Name);
     662      199504 :     ++I;
     663      200089 :     if (!Node) {
     664      115069 :       if (I == E) {
     665             :         // End of the path.
     666             :         std::unique_ptr<detail::InMemoryNode> Child;
     667       62415 :         if (HardLinkTarget)
     668          17 :           Child.reset(new detail::InMemoryHardLink(P.str(), *HardLinkTarget));
     669             :         else {
     670             :           // Create a new file or directory.
     671       62411 :           Status Stat(P.str(), getNextVirtualUniqueID(),
     672             :                       llvm::sys::toTimePoint(ModificationTime), ResolvedUser,
     673             :                       ResolvedGroup, Buffer->getBufferSize(), ResolvedType,
     674      187220 :                       ResolvedPerms);
     675       62410 :           if (ResolvedType == sys::fs::file_type::directory_file) {
     676          14 :             Child.reset(new detail::InMemoryDirectory(std::move(Stat)));
     677             :           } else {
     678       62401 :             Child.reset(
     679       62403 :                 new detail::InMemoryFile(std::move(Stat), std::move(Buffer)));
     680             :           }
     681             :         }
     682      124834 :         Dir->addChild(Name, std::move(Child));
     683             :         return true;
     684             :       }
     685             : 
     686             :       // Create a new directory. Use the path up to here.
     687             :       Status Stat(
     688       52652 :           StringRef(Path.str().begin(), Name.end() - Path.str().begin()),
     689             :           getNextVirtualUniqueID(), llvm::sys::toTimePoint(ModificationTime),
     690             :           ResolvedUser, ResolvedGroup, 0, sys::fs::file_type::directory_file,
     691       52652 :           NewDirectoryPerms);
     692      105303 :       Dir = cast<detail::InMemoryDirectory>(Dir->addChild(
     693      105303 :           Name, llvm::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
     694             :       continue;
     695             :     }
     696             : 
     697             :     if (auto *NewDir = dyn_cast<detail::InMemoryDirectory>(Node)) {
     698             :       Dir = NewDir;
     699             :     } else {
     700             :       assert((isa<detail::InMemoryFile>(Node) ||
     701             :               isa<detail::InMemoryHardLink>(Node)) &&
     702             :              "Must be either file, hardlink or directory!");
     703             : 
     704             :       // Trying to insert a directory in place of a file.
     705         624 :       if (I != E)
     706             :         return false;
     707             : 
     708             :       // Return false only if the new file is different from the existing one.
     709             :       if (auto Link = dyn_cast<detail::InMemoryHardLink>(Node)) {
     710           2 :         return Link->getResolvedFile().getBuffer()->getBuffer() ==
     711             :                Buffer->getBuffer();
     712             :       }
     713             :       return cast<detail::InMemoryFile>(Node)->getBuffer()->getBuffer() ==
     714             :              Buffer->getBuffer();
     715             :     }
     716             :   }
     717             : }
     718             : 
     719       63026 : bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
     720             :                                  std::unique_ptr<llvm::MemoryBuffer> Buffer,
     721             :                                  Optional<uint32_t> User,
     722             :                                  Optional<uint32_t> Group,
     723             :                                  Optional<llvm::sys::fs::file_type> Type,
     724             :                                  Optional<llvm::sys::fs::perms> Perms) {
     725       63026 :   return addFile(P, ModificationTime, std::move(Buffer), User, Group, Type,
     726       63030 :                  Perms, /*HardLinkTarget=*/nullptr);
     727             : }
     728             : 
     729         465 : bool InMemoryFileSystem::addFileNoOwn(const Twine &P, time_t ModificationTime,
     730             :                                       llvm::MemoryBuffer *Buffer,
     731             :                                       Optional<uint32_t> User,
     732             :                                       Optional<uint32_t> Group,
     733             :                                       Optional<llvm::sys::fs::file_type> Type,
     734             :                                       Optional<llvm::sys::fs::perms> Perms) {
     735         465 :   return addFile(P, ModificationTime,
     736         465 :                  llvm::MemoryBuffer::getMemBuffer(
     737         465 :                      Buffer->getBuffer(), Buffer->getBufferIdentifier()),
     738             :                  std::move(User), std::move(Group), std::move(Type),
     739         465 :                  std::move(Perms));
     740             : }
     741             : 
     742             : static ErrorOr<const detail::InMemoryNode *>
     743     1497620 : lookupInMemoryNode(const InMemoryFileSystem &FS, detail::InMemoryDirectory *Dir,
     744             :                    const Twine &P) {
     745             :   SmallString<128> Path;
     746     1497620 :   P.toVector(Path);
     747             : 
     748             :   // Fix up relative paths. This just prepends the current working directory.
     749     1497643 :   std::error_code EC = FS.makeAbsolute(Path);
     750             :   assert(!EC);
     751             :   (void)EC;
     752             : 
     753     1497592 :   if (FS.useNormalizedPaths())
     754     1497501 :     llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
     755             : 
     756     1497637 :   if (Path.empty())
     757             :     return Dir;
     758             : 
     759     1454218 :   auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path);
     760             :   while (true) {
     761     2786183 :     detail::InMemoryNode *Node = Dir->getChild(*I);
     762     2785502 :     ++I;
     763     2786076 :     if (!Node)
     764             :       return errc::no_such_file_or_directory;
     765             : 
     766             :     // Return the file if it's at the end of the path.
     767             :     if (auto File = dyn_cast<detail::InMemoryFile>(Node)) {
     768       98610 :       if (I == E)
     769             :         return File;
     770             :       return errc::no_such_file_or_directory;
     771             :     }
     772             : 
     773             :     // If Node is HardLink then return the resolved file.
     774             :     if (auto File = dyn_cast<detail::InMemoryHardLink>(Node)) {
     775           9 :       if (I == E)
     776           9 :         return &File->getResolvedFile();
     777             :       return errc::no_such_file_or_directory;
     778             :     }
     779             :     // Traverse directories.
     780             :     Dir = cast<detail::InMemoryDirectory>(Node);
     781     1344914 :     if (I == E)
     782             :       return Dir;
     783             :   }
     784             : }
     785             : 
     786          14 : bool InMemoryFileSystem::addHardLink(const Twine &FromPath,
     787             :                                      const Twine &ToPath) {
     788          14 :   auto FromNode = lookupInMemoryNode(*this, Root.get(), FromPath);
     789          14 :   auto ToNode = lookupInMemoryNode(*this, Root.get(), ToPath);
     790             :   // FromPath must not have been added before. ToPath must have been added
     791             :   // before. Resolved ToPath must be a File.
     792          14 :   if (!ToNode || FromNode || !isa<detail::InMemoryFile>(*ToNode))
     793             :     return false;
     794          18 :   return this->addFile(FromPath, 0, nullptr, None, None, None, None,
     795             :                        cast<detail::InMemoryFile>(*ToNode));
     796             : }
     797             : 
     798      344664 : llvm::ErrorOr<Status> InMemoryFileSystem::status(const Twine &Path) {
     799      344664 :   auto Node = lookupInMemoryNode(*this, Root.get(), Path);
     800      344662 :   if (Node)
     801      210534 :     return detail::getNodeStatus(*Node, Path.str());
     802      241329 :   return Node.getError();
     803             : }
     804             : 
     805             : llvm::ErrorOr<std::unique_ptr<File>>
     806      179890 : InMemoryFileSystem::openFileForRead(const Twine &Path) {
     807      179890 :   auto Node = lookupInMemoryNode(*this, Root.get(), Path);
     808      179887 :   if (!Node)
     809      128261 :     return Node.getError();
     810             : 
     811             :   // When we have a file provide a heap-allocated wrapper for the memory buffer
     812             :   // to match the ownership semantics for File.
     813       51626 :   if (auto *F = dyn_cast<detail::InMemoryFile>(*Node))
     814             :     return std::unique_ptr<File>(
     815      103250 :         new detail::InMemoryFileAdaptor(*F, Path.str()));
     816             : 
     817             :   // FIXME: errc::not_a_file?
     818           1 :   return make_error_code(llvm::errc::invalid_argument);
     819             : }
     820             : 
     821             : namespace {
     822             : 
     823             : /// Adaptor from InMemoryDir::iterator to directory_iterator.
     824             : class InMemoryDirIterator : public llvm::vfs::detail::DirIterImpl {
     825             :   detail::InMemoryDirectory::const_iterator I;
     826             :   detail::InMemoryDirectory::const_iterator E;
     827             :   std::string RequestedDirName;
     828             : 
     829          17 :   void setCurrentEntry() {
     830          17 :     if (I != E) {
     831             :       SmallString<256> Path(RequestedDirName);
     832          20 :       llvm::sys::path::append(Path, I->second->getFileName());
     833             :       sys::fs::file_type Type;
     834          10 :       switch (I->second->getKind()) {
     835           5 :       case detail::IME_File:
     836             :       case detail::IME_HardLink:
     837             :         Type = sys::fs::file_type::regular_file;
     838           5 :         break;
     839           5 :       case detail::IME_Directory:
     840             :         Type = sys::fs::file_type::directory_file;
     841           5 :         break;
     842             :       }
     843          10 :       CurrentEntry = directory_entry(Path.str(), Type);
     844             :     } else {
     845             :       // When we're at the end, make CurrentEntry invalid and DirIterImpl will
     846             :       // do the rest.
     847          14 :       CurrentEntry = directory_entry();
     848             :     }
     849          17 :   }
     850             : 
     851             : public:
     852           0 :   InMemoryDirIterator() = default;
     853             : 
     854           8 :   explicit InMemoryDirIterator(const detail::InMemoryDirectory &Dir,
     855             :                                std::string RequestedDirName)
     856          24 :       : I(Dir.begin()), E(Dir.end()),
     857           8 :         RequestedDirName(std::move(RequestedDirName)) {
     858           8 :     setCurrentEntry();
     859           8 :   }
     860             : 
     861           9 :   std::error_code increment() override {
     862             :     ++I;
     863           9 :     setCurrentEntry();
     864           9 :     return {};
     865             :   }
     866             : };
     867             : 
     868             : } // namespace
     869             : 
     870      973077 : directory_iterator InMemoryFileSystem::dir_begin(const Twine &Dir,
     871             :                                                  std::error_code &EC) {
     872      973077 :   auto Node = lookupInMemoryNode(*this, Root.get(), Dir);
     873      973074 :   if (!Node) {
     874      973066 :     EC = Node.getError();
     875     1946141 :     return directory_iterator(std::make_shared<InMemoryDirIterator>());
     876             :   }
     877             : 
     878           8 :   if (auto *DirNode = dyn_cast<detail::InMemoryDirectory>(*Node))
     879             :     return directory_iterator(
     880          24 :         std::make_shared<InMemoryDirIterator>(*DirNode, Dir.str()));
     881             : 
     882           0 :   EC = make_error_code(llvm::errc::not_a_directory);
     883           0 :   return directory_iterator(std::make_shared<InMemoryDirIterator>());
     884             : }
     885             : 
     886        7372 : std::error_code InMemoryFileSystem::setCurrentWorkingDirectory(const Twine &P) {
     887             :   SmallString<128> Path;
     888        7372 :   P.toVector(Path);
     889             : 
     890             :   // Fix up relative paths. This just prepends the current working directory.
     891        7372 :   std::error_code EC = makeAbsolute(Path);
     892             :   assert(!EC);
     893             :   (void)EC;
     894             : 
     895        7372 :   if (useNormalizedPaths())
     896        7369 :     llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
     897             : 
     898        7372 :   if (!Path.empty())
     899       14744 :     WorkingDirectory = Path.str();
     900        7372 :   return {};
     901             : }
     902             : 
     903             : std::error_code
     904          29 : InMemoryFileSystem::getRealPath(const Twine &Path,
     905             :                                 SmallVectorImpl<char> &Output) const {
     906          29 :   auto CWD = getCurrentWorkingDirectory();
     907          29 :   if (!CWD || CWD->empty())
     908           1 :     return errc::operation_not_permitted;
     909          28 :   Path.toVector(Output);
     910          28 :   if (auto EC = makeAbsolute(Output))
     911           0 :     return EC;
     912          28 :   llvm::sys::path::remove_dots(Output, /*remove_dot_dot=*/true);
     913          28 :   return {};
     914             : }
     915             : 
     916             : } // namespace vfs
     917             : } // namespace llvm
     918             : 
     919             : //===-----------------------------------------------------------------------===/
     920             : // RedirectingFileSystem implementation
     921             : //===-----------------------------------------------------------------------===/
     922             : 
     923             : namespace {
     924             : 
     925             : enum EntryKind { EK_Directory, EK_File };
     926             : 
     927             : /// A single file or directory in the VFS.
     928             : class Entry {
     929             :   EntryKind Kind;
     930             :   std::string Name;
     931             : 
     932             : public:
     933        2275 :   Entry(EntryKind K, StringRef Name) : Kind(K), Name(Name) {}
     934           0 :   virtual ~Entry() = default;
     935             : 
     936             :   StringRef getName() const { return Name; }
     937           0 :   EntryKind getKind() const { return Kind; }
     938             : };
     939             : 
     940           0 : class RedirectingDirectoryEntry : public Entry {
     941             :   std::vector<std::unique_ptr<Entry>> Contents;
     942             :   Status S;
     943             : 
     944             : public:
     945         891 :   RedirectingDirectoryEntry(StringRef Name,
     946             :                             std::vector<std::unique_ptr<Entry>> Contents,
     947             :                             Status S)
     948         891 :       : Entry(EK_Directory, Name), Contents(std::move(Contents)),
     949         891 :         S(std::move(S)) {}
     950         722 :   RedirectingDirectoryEntry(StringRef Name, Status S)
     951        1444 :       : Entry(EK_Directory, Name), S(std::move(S)) {}
     952             : 
     953         323 :   Status getStatus() { return S; }
     954             : 
     955             :   void addContent(std::unique_ptr<Entry> Content) {
     956         331 :     Contents.push_back(std::move(Content));
     957             :   }
     958             : 
     959             :   Entry *getLastContent() const { return Contents.back().get(); }
     960             : 
     961             :   using iterator = decltype(Contents)::iterator;
     962             : 
     963             :   iterator contents_begin() { return Contents.begin(); }
     964             :   iterator contents_end() { return Contents.end(); }
     965             : 
     966       12501 :   static bool classof(const Entry *E) { return E->getKind() == EK_Directory; }
     967             : };
     968             : 
     969           0 : class RedirectingFileEntry : public Entry {
     970             : public:
     971             :   enum NameKind { NK_NotSet, NK_External, NK_Virtual };
     972             : 
     973             : private:
     974             :   std::string ExternalContentsPath;
     975             :   NameKind UseName;
     976             : 
     977             : public:
     978         662 :   RedirectingFileEntry(StringRef Name, StringRef ExternalContentsPath,
     979             :                        NameKind UseName)
     980         662 :       : Entry(EK_File, Name), ExternalContentsPath(ExternalContentsPath),
     981         662 :         UseName(UseName) {}
     982             : 
     983             :   StringRef getExternalContentsPath() const { return ExternalContentsPath; }
     984             : 
     985             :   /// whether to use the external path as the name for this file.
     986             :   bool useExternalName(bool GlobalUseExternalName) const {
     987           4 :     return UseName == NK_NotSet ? GlobalUseExternalName
     988             :                                 : (UseName == NK_External);
     989             :   }
     990             : 
     991           0 :   NameKind getUseName() const { return UseName; }
     992             : 
     993         483 :   static bool classof(const Entry *E) { return E->getKind() == EK_File; }
     994             : };
     995             : 
     996             : class VFSFromYamlDirIterImpl : public llvm::vfs::detail::DirIterImpl {
     997             :   std::string Dir;
     998             :   RedirectingDirectoryEntry::iterator Current, End;
     999             : 
    1000             :   std::error_code incrementImpl();
    1001             : 
    1002             : public:
    1003             :   VFSFromYamlDirIterImpl(const Twine &Path,
    1004             :                          RedirectingDirectoryEntry::iterator Begin,
    1005             :                          RedirectingDirectoryEntry::iterator End,
    1006             :                          std::error_code &EC);
    1007             : 
    1008             :   std::error_code increment() override;
    1009             : };
    1010             : 
    1011             : /// A virtual file system parsed from a YAML file.
    1012             : ///
    1013             : /// Currently, this class allows creating virtual directories and mapping
    1014             : /// virtual file paths to existing external files, available in \c ExternalFS.
    1015             : ///
    1016             : /// The basic structure of the parsed file is:
    1017             : /// \verbatim
    1018             : /// {
    1019             : ///   'version': <version number>,
    1020             : ///   <optional configuration>
    1021             : ///   'roots': [
    1022             : ///              <directory entries>
    1023             : ///            ]
    1024             : /// }
    1025             : /// \endverbatim
    1026             : ///
    1027             : /// All configuration options are optional.
    1028             : ///   'case-sensitive': <boolean, default=true>
    1029             : ///   'use-external-names': <boolean, default=true>
    1030             : ///   'overlay-relative': <boolean, default=false>
    1031             : ///   'ignore-non-existent-contents': <boolean, default=true>
    1032             : ///
    1033             : /// Virtual directories are represented as
    1034             : /// \verbatim
    1035             : /// {
    1036             : ///   'type': 'directory',
    1037             : ///   'name': <string>,
    1038             : ///   'contents': [ <file or directory entries> ]
    1039             : /// }
    1040             : /// \endverbatim
    1041             : ///
    1042             : /// The default attributes for virtual directories are:
    1043             : /// \verbatim
    1044             : /// MTime = now() when created
    1045             : /// Perms = 0777
    1046             : /// User = Group = 0
    1047             : /// Size = 0
    1048             : /// UniqueID = unspecified unique value
    1049             : /// \endverbatim
    1050             : ///
    1051             : /// Re-mapped files are represented as
    1052             : /// \verbatim
    1053             : /// {
    1054             : ///   'type': 'file',
    1055             : ///   'name': <string>,
    1056             : ///   'use-external-name': <boolean> # Optional
    1057             : ///   'external-contents': <path to external file>
    1058             : /// }
    1059             : /// \endverbatim
    1060             : ///
    1061             : /// and inherit their attributes from the external contents.
    1062             : ///
    1063             : /// In both cases, the 'name' field may contain multiple path components (e.g.
    1064             : /// /path/to/file). However, any directory that contains more than one child
    1065             : /// must be uniquely represented by a directory entry.
    1066          34 : class RedirectingFileSystem : public vfs::FileSystem {
    1067             :   friend class RedirectingFileSystemParser;
    1068             : 
    1069             :   /// The root(s) of the virtual file system.
    1070             :   std::vector<std::unique_ptr<Entry>> Roots;
    1071             : 
    1072             :   /// The file system to use for external references.
    1073             :   IntrusiveRefCntPtr<FileSystem> ExternalFS;
    1074             : 
    1075             :   /// If IsRelativeOverlay is set, this represents the directory
    1076             :   /// path that should be prefixed to each 'external-contents' entry
    1077             :   /// when reading from YAML files.
    1078             :   std::string ExternalContentsPrefixDir;
    1079             : 
    1080             :   /// @name Configuration
    1081             :   /// @{
    1082             : 
    1083             :   /// Whether to perform case-sensitive comparisons.
    1084             :   ///
    1085             :   /// Currently, case-insensitive matching only works correctly with ASCII.
    1086             :   bool CaseSensitive = true;
    1087             : 
    1088             :   /// IsRelativeOverlay marks whether a ExternalContentsPrefixDir path must
    1089             :   /// be prefixed in every 'external-contents' when reading from YAML files.
    1090             :   bool IsRelativeOverlay = false;
    1091             : 
    1092             :   /// Whether to use to use the value of 'external-contents' for the
    1093             :   /// names of files.  This global value is overridable on a per-file basis.
    1094             :   bool UseExternalNames = true;
    1095             : 
    1096             :   /// Whether an invalid path obtained via 'external-contents' should
    1097             :   /// cause iteration on the VFS to stop. If 'true', the VFS should ignore
    1098             :   /// the entry and continue with the next. Allows YAML files to be shared
    1099             :   /// across multiple compiler invocations regardless of prior existent
    1100             :   /// paths in 'external-contents'. This global value is overridable on a
    1101             :   /// per-file basis.
    1102             :   bool IgnoreNonExistentContents = true;
    1103             :   /// @}
    1104             : 
    1105             :   /// Virtual file paths and external files could be canonicalized without "..",
    1106             :   /// "." and "./" in their paths. FIXME: some unittests currently fail on
    1107             :   /// win32 when using remove_dots and remove_leading_dotslash on paths.
    1108             :   bool UseCanonicalizedPaths =
    1109             : #ifdef _WIN32
    1110             :       false;
    1111             : #else
    1112             :       true;
    1113             : #endif
    1114             : 
    1115             : private:
    1116           0 :   RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS)
    1117           0 :       : ExternalFS(std::move(ExternalFS)) {}
    1118             : 
    1119             :   /// Looks up the path <tt>[Start, End)</tt> in \p From, possibly
    1120             :   /// recursing into the contents of \p From if it is a directory.
    1121             :   ErrorOr<Entry *> lookupPath(sys::path::const_iterator Start,
    1122             :                               sys::path::const_iterator End, Entry *From);
    1123             : 
    1124             :   /// Get the status of a given an \c Entry.
    1125             :   ErrorOr<Status> status(const Twine &Path, Entry *E);
    1126             : 
    1127             : public:
    1128             :   /// Looks up \p Path in \c Roots.
    1129             :   ErrorOr<Entry *> lookupPath(const Twine &Path);
    1130             : 
    1131             :   /// Parses \p Buffer, which is expected to be in YAML format and
    1132             :   /// returns a virtual file system representing its contents.
    1133             :   static RedirectingFileSystem *
    1134             :   create(std::unique_ptr<MemoryBuffer> Buffer,
    1135             :          SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath,
    1136             :          void *DiagContext, IntrusiveRefCntPtr<FileSystem> ExternalFS);
    1137             : 
    1138             :   ErrorOr<Status> status(const Twine &Path) override;
    1139             :   ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
    1140             : 
    1141          19 :   llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
    1142          19 :     return ExternalFS->getCurrentWorkingDirectory();
    1143             :   }
    1144             : 
    1145          59 :   std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
    1146          59 :     return ExternalFS->setCurrentWorkingDirectory(Path);
    1147             :   }
    1148             : 
    1149         305 :   directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override {
    1150         305 :     ErrorOr<Entry *> E = lookupPath(Dir);
    1151         305 :     if (!E) {
    1152         283 :       EC = E.getError();
    1153         283 :       return {};
    1154             :     }
    1155          22 :     ErrorOr<Status> S = status(Dir, *E);
    1156          22 :     if (!S) {
    1157           0 :       EC = S.getError();
    1158           0 :       return {};
    1159             :     }
    1160          22 :     if (!S->isDirectory()) {
    1161           0 :       EC = std::error_code(static_cast<int>(errc::not_a_directory),
    1162             :                            std::system_category());
    1163           0 :       return {};
    1164             :     }
    1165             : 
    1166          22 :     auto *D = cast<RedirectingDirectoryEntry>(*E);
    1167          22 :     return directory_iterator(std::make_shared<VFSFromYamlDirIterImpl>(
    1168          66 :         Dir, D->contents_begin(), D->contents_end(), EC));
    1169             :   }
    1170             : 
    1171          53 :   void setExternalContentsPrefixDir(StringRef PrefixDir) {
    1172         106 :     ExternalContentsPrefixDir = PrefixDir.str();
    1173          53 :   }
    1174             : 
    1175             :   StringRef getExternalContentsPrefixDir() const {
    1176             :     return ExternalContentsPrefixDir;
    1177             :   }
    1178             : 
    1179             :   bool ignoreNonExistentContents() const { return IgnoreNonExistentContents; }
    1180             : 
    1181             : #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
    1182             :   LLVM_DUMP_METHOD void dump() const {
    1183             :     for (const auto &Root : Roots)
    1184             :       dumpEntry(Root.get());
    1185             :   }
    1186             : 
    1187             :   LLVM_DUMP_METHOD void dumpEntry(Entry *E, int NumSpaces = 0) const {
    1188             :     StringRef Name = E->getName();
    1189             :     for (int i = 0, e = NumSpaces; i < e; ++i)
    1190             :       dbgs() << " ";
    1191             :     dbgs() << "'" << Name.str().c_str() << "'"
    1192             :            << "\n";
    1193             : 
    1194             :     if (E->getKind() == EK_Directory) {
    1195             :       auto *DE = dyn_cast<RedirectingDirectoryEntry>(E);
    1196             :       assert(DE && "Should be a directory");
    1197             : 
    1198             :       for (std::unique_ptr<Entry> &SubEntry :
    1199             :            llvm::make_range(DE->contents_begin(), DE->contents_end()))
    1200             :         dumpEntry(SubEntry.get(), NumSpaces + 2);
    1201             :     }
    1202             :   }
    1203             : #endif
    1204             : };
    1205             : 
    1206             : /// A helper class to hold the common YAML parsing state.
    1207             : class RedirectingFileSystemParser {
    1208             :   yaml::Stream &Stream;
    1209             : 
    1210           0 :   void error(yaml::Node *N, const Twine &Msg) { Stream.printError(N, Msg); }
    1211             : 
    1212             :   // false on error
    1213        3232 :   bool parseScalarString(yaml::Node *N, StringRef &Result,
    1214             :                          SmallVectorImpl<char> &Storage) {
    1215             :     const auto *S = dyn_cast<yaml::ScalarNode>(N);
    1216             : 
    1217             :     if (!S) {
    1218           3 :       error(N, "expected string");
    1219           3 :       return false;
    1220             :     }
    1221        3229 :     Result = S->getValue(Storage);
    1222        3229 :     return true;
    1223             :   }
    1224             : 
    1225             :   // false on error
    1226          48 :   bool parseScalarBool(yaml::Node *N, bool &Result) {
    1227             :     SmallString<5> Storage;
    1228          48 :     StringRef Value;
    1229          48 :     if (!parseScalarString(N, Value, Storage))
    1230             :       return false;
    1231             : 
    1232          79 :     if (Value.equals_lower("true") || Value.equals_lower("on") ||
    1233          31 :         Value.equals_lower("yes") || Value == "1") {
    1234          17 :       Result = true;
    1235          17 :       return true;
    1236          33 :     } else if (Value.equals_lower("false") || Value.equals_lower("off") ||
    1237           2 :                Value.equals_lower("no") || Value == "0") {
    1238          29 :       Result = false;
    1239          29 :       return true;
    1240             :     }
    1241             : 
    1242           2 :     error(N, "expected boolean value");
    1243           2 :     return false;
    1244             :   }
    1245             : 
    1246             :   struct KeyStatus {
    1247             :     bool Required;
    1248             :     bool Seen = false;
    1249             : 
    1250        2507 :     KeyStatus(bool Required = false) : Required(Required) {}
    1251             :   };
    1252             : 
    1253             :   using KeyStatusPair = std::pair<StringRef, KeyStatus>;
    1254             : 
    1255             :   // false on error
    1256        1744 :   bool checkDuplicateOrUnknownKey(yaml::Node *KeyNode, StringRef Key,
    1257             :                                   DenseMap<StringRef, KeyStatus> &Keys) {
    1258             :     if (!Keys.count(Key)) {
    1259           4 :       error(KeyNode, "unknown key");
    1260           4 :       return false;
    1261             :     }
    1262             :     KeyStatus &S = Keys[Key];
    1263        1740 :     if (S.Seen) {
    1264           3 :       error(KeyNode, Twine("duplicate key '") + Key + "'");
    1265           3 :       return false;
    1266             :     }
    1267        1737 :     S.Seen = true;
    1268        1737 :     return true;
    1269             :   }
    1270             : 
    1271             :   // false on error
    1272         560 :   bool checkMissingKeys(yaml::Node *Obj, DenseMap<StringRef, KeyStatus> &Keys) {
    1273        3970 :     for (const auto &I : Keys) {
    1274        2854 :       if (I.second.Required && !I.second.Seen) {
    1275           8 :         error(Obj, Twine("missing key '") + I.first + "'");
    1276           4 :         return false;
    1277             :       }
    1278             :     }
    1279         556 :     return true;
    1280             :   }
    1281             : 
    1282           0 :   Entry *lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name,
    1283             :                              Entry *ParentEntry = nullptr) {
    1284           0 :     if (!ParentEntry) { // Look for a existent root
    1285           0 :       for (const auto &Root : FS->Roots) {
    1286             :         if (Name.equals(Root->getName())) {
    1287             :           ParentEntry = Root.get();
    1288           0 :           return ParentEntry;
    1289             :         }
    1290             :       }
    1291             :     } else { // Advance to the next component
    1292             :       auto *DE = dyn_cast<RedirectingDirectoryEntry>(ParentEntry);
    1293             :       for (std::unique_ptr<Entry> &Content :
    1294           0 :            llvm::make_range(DE->contents_begin(), DE->contents_end())) {
    1295             :         auto *DirContent = dyn_cast<RedirectingDirectoryEntry>(Content.get());
    1296             :         if (DirContent && Name.equals(Content->getName()))
    1297           0 :           return DirContent;
    1298             :       }
    1299             :     }
    1300             : 
    1301             :     // ... or create a new one
    1302           0 :     std::unique_ptr<Entry> E = llvm::make_unique<RedirectingDirectoryEntry>(
    1303             :         Name,
    1304           0 :         Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(),
    1305             :                0, 0, 0, file_type::directory_file, sys::fs::all_all));
    1306             : 
    1307           0 :     if (!ParentEntry) { // Add a new root to the overlay
    1308           0 :       FS->Roots.push_back(std::move(E));
    1309             :       ParentEntry = FS->Roots.back().get();
    1310           0 :       return ParentEntry;
    1311             :     }
    1312             : 
    1313             :     auto *DE = dyn_cast<RedirectingDirectoryEntry>(ParentEntry);
    1314           0 :     DE->addContent(std::move(E));
    1315           0 :     return DE->getLastContent();
    1316             :   }
    1317             : 
    1318        1222 :   void uniqueOverlayTree(RedirectingFileSystem *FS, Entry *SrcE,
    1319             :                          Entry *NewParentE = nullptr) {
    1320        1222 :     StringRef Name = SrcE->getName();
    1321        1222 :     switch (SrcE->getKind()) {
    1322             :     case EK_Directory: {
    1323             :       auto *DE = dyn_cast<RedirectingDirectoryEntry>(SrcE);
    1324             :       assert(DE && "Must be a directory");
    1325             :       // Empty directories could be present in the YAML as a way to
    1326             :       // describe a file for a current directory after some of its subdir
    1327             :       // is parsed. This only leads to redundant walks, ignore it.
    1328         891 :       if (!Name.empty())
    1329         888 :         NewParentE = lookupOrCreateEntry(FS, Name, NewParentE);
    1330             :       for (std::unique_ptr<Entry> &SubEntry :
    1331        2033 :            llvm::make_range(DE->contents_begin(), DE->contents_end()))
    1332        1142 :         uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
    1333             :       break;
    1334             :     }
    1335             :     case EK_File: {
    1336             :       auto *FE = dyn_cast<RedirectingFileEntry>(SrcE);
    1337             :       assert(FE && "Must be a file");
    1338             :       assert(NewParentE && "Parent entry must exist");
    1339             :       auto *DE = dyn_cast<RedirectingDirectoryEntry>(NewParentE);
    1340         331 :       DE->addContent(llvm::make_unique<RedirectingFileEntry>(
    1341         662 :           Name, FE->getExternalContentsPath(), FE->getUseName()));
    1342         331 :       break;
    1343             :     }
    1344             :     }
    1345        1222 :   }
    1346             : 
    1347         510 :   std::unique_ptr<Entry> parseEntry(yaml::Node *N, RedirectingFileSystem *FS,
    1348             :                                     bool IsRootEntry) {
    1349             :     auto *M = dyn_cast<yaml::MappingNode>(N);
    1350             :     if (!M) {
    1351           2 :       error(N, "expected mapping node for file or directory entry");
    1352             :       return nullptr;
    1353             :     }
    1354             : 
    1355             :     KeyStatusPair Fields[] = {
    1356             :         KeyStatusPair("name", true),
    1357             :         KeyStatusPair("type", true),
    1358             :         KeyStatusPair("contents", false),
    1359             :         KeyStatusPair("external-contents", false),
    1360             :         KeyStatusPair("use-external-name", false),
    1361             :     };
    1362             : 
    1363         508 :     DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
    1364             : 
    1365             :     bool HasContents = false; // external or otherwise
    1366         508 :     std::vector<std::unique_ptr<Entry>> EntryArrayContents;
    1367             :     std::string ExternalContentsPath;
    1368             :     std::string Name;
    1369             :     yaml::Node *NameValueNode;
    1370             :     auto UseExternalName = RedirectingFileEntry::NK_NotSet;
    1371             :     EntryKind Kind;
    1372             : 
    1373        2017 :     for (auto &I : *M) {
    1374        1518 :       StringRef Key;
    1375             :       // Reuse the buffer for key and value, since we don't look at key after
    1376             :       // parsing value.
    1377             :       SmallString<256> Buffer;
    1378        1518 :       if (!parseScalarString(I.getKey(), Key, Buffer))
    1379             :         return nullptr;
    1380             : 
    1381        1518 :       if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys))
    1382             :         return nullptr;
    1383             : 
    1384        1516 :       StringRef Value;
    1385             :       if (Key == "name") {
    1386         505 :         if (!parseScalarString(I.getValue(), Value, Buffer))
    1387             :           return nullptr;
    1388             : 
    1389         504 :         NameValueNode = I.getValue();
    1390         504 :         if (FS->UseCanonicalizedPaths) {
    1391             :           SmallString<256> Path(Value);
    1392             :           // Guarantee that old YAML files containing paths with ".." and "."
    1393             :           // are properly canonicalized before read into the VFS.
    1394         504 :           Path = sys::path::remove_leading_dotslash(Path);
    1395         504 :           sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
    1396        1008 :           Name = Path.str();
    1397             :         } else {
    1398           0 :           Name = Value;
    1399             :         }
    1400             :       } else if (Key == "type") {
    1401         504 :         if (!parseScalarString(I.getValue(), Value, Buffer))
    1402             :           return nullptr;
    1403             :         if (Value == "file")
    1404             :           Kind = EK_File;
    1405             :         else if (Value == "directory")
    1406             :           Kind = EK_Directory;
    1407             :         else {
    1408           1 :           error(I.getValue(), "unknown value for 'type'");
    1409             :           return nullptr;
    1410             :         }
    1411             :       } else if (Key == "contents") {
    1412         166 :         if (HasContents) {
    1413           0 :           error(I.getKey(),
    1414             :                 "entry already has 'contents' or 'external-contents'");
    1415             :           return nullptr;
    1416             :         }
    1417             :         HasContents = true;
    1418         166 :         auto *Contents = dyn_cast<yaml::SequenceNode>(I.getValue());
    1419             :         if (!Contents) {
    1420             :           // FIXME: this is only for directories, what about files?
    1421           2 :           error(I.getValue(), "expected array");
    1422             :           return nullptr;
    1423             :         }
    1424             : 
    1425         576 :         for (auto &I : *Contents) {
    1426         413 :           if (std::unique_ptr<Entry> E =
    1427         413 :                   parseEntry(&I, FS, /*IsRootEntry*/ false))
    1428             :             EntryArrayContents.push_back(std::move(E));
    1429             :           else
    1430             :             return nullptr;
    1431             :         }
    1432             :       } else if (Key == "external-contents") {
    1433         337 :         if (HasContents) {
    1434           0 :           error(I.getKey(),
    1435             :                 "entry already has 'contents' or 'external-contents'");
    1436           2 :           return nullptr;
    1437             :         }
    1438             :         HasContents = true;
    1439         337 :         if (!parseScalarString(I.getValue(), Value, Buffer))
    1440             :           return nullptr;
    1441             : 
    1442             :         SmallString<256> FullPath;
    1443         335 :         if (FS->IsRelativeOverlay) {
    1444             :           FullPath = FS->getExternalContentsPrefixDir();
    1445             :           assert(!FullPath.empty() &&
    1446             :                  "External contents prefix directory must exist");
    1447          22 :           llvm::sys::path::append(FullPath, Value);
    1448             :         } else {
    1449             :           FullPath = Value;
    1450             :         }
    1451             : 
    1452         335 :         if (FS->UseCanonicalizedPaths) {
    1453             :           // Guarantee that old YAML files containing paths with ".." and "."
    1454             :           // are properly canonicalized before read into the VFS.
    1455         335 :           FullPath = sys::path::remove_leading_dotslash(FullPath);
    1456         335 :           sys::path::remove_dots(FullPath, /*remove_dot_dot=*/true);
    1457             :         }
    1458         670 :         ExternalContentsPath = FullPath.str();
    1459             :       } else if (Key == "use-external-name") {
    1460             :         bool Val;
    1461           4 :         if (!parseScalarBool(I.getValue(), Val))
    1462           0 :           return nullptr;
    1463           4 :         UseExternalName = Val ? RedirectingFileEntry::NK_External
    1464             :                               : RedirectingFileEntry::NK_Virtual;
    1465             :       } else {
    1466           0 :         llvm_unreachable("key missing from Keys");
    1467             :       }
    1468             :     }
    1469             : 
    1470         499 :     if (Stream.failed())
    1471             :       return nullptr;
    1472             : 
    1473             :     // check for missing keys
    1474         499 :     if (!HasContents) {
    1475           1 :       error(N, "missing key 'contents' or 'external-contents'");
    1476             :       return nullptr;
    1477             :     }
    1478         498 :     if (!checkMissingKeys(N, Keys))
    1479             :       return nullptr;
    1480             : 
    1481             :     // check invalid configuration
    1482         495 :     if (Kind == EK_Directory &&
    1483             :         UseExternalName != RedirectingFileEntry::NK_NotSet) {
    1484           0 :       error(N, "'use-external-name' is not supported for directories");
    1485             :       return nullptr;
    1486             :     }
    1487             : 
    1488         495 :     if (IsRootEntry && !sys::path::is_absolute(Name)) {
    1489             :       assert(NameValueNode && "Name presence should be checked earlier");
    1490           3 :       error(NameValueNode,
    1491             :             "entry with relative path at the root level is not discoverable");
    1492             :       return nullptr;
    1493             :     }
    1494             : 
    1495             :     // Remove trailing slash(es), being careful not to remove the root path
    1496             :     StringRef Trimmed(Name);
    1497         492 :     size_t RootPathLen = sys::path::root_path(Trimmed).size();
    1498         976 :     while (Trimmed.size() > RootPathLen &&
    1499         968 :            sys::path::is_separator(Trimmed.back()))
    1500           0 :       Trimmed = Trimmed.slice(0, Trimmed.size() - 1);
    1501             :     // Get the last component
    1502         492 :     StringRef LastComponent = sys::path::filename(Trimmed);
    1503             : 
    1504         492 :     std::unique_ptr<Entry> Result;
    1505         492 :     switch (Kind) {
    1506             :     case EK_File:
    1507         662 :       Result = llvm::make_unique<RedirectingFileEntry>(
    1508             :           LastComponent, std::move(ExternalContentsPath), UseExternalName);
    1509         331 :       break;
    1510         161 :     case EK_Directory:
    1511         322 :       Result = llvm::make_unique<RedirectingDirectoryEntry>(
    1512             :           LastComponent, std::move(EntryArrayContents),
    1513         161 :           Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(),
    1514             :                  0, 0, 0, file_type::directory_file, sys::fs::all_all));
    1515         161 :       break;
    1516             :     }
    1517             : 
    1518         492 :     StringRef Parent = sys::path::parent_path(Trimmed);
    1519         492 :     if (Parent.empty())
    1520             :       return Result;
    1521             : 
    1522             :     // if 'name' contains multiple components, create implicit directory entries
    1523         858 :     for (sys::path::reverse_iterator I = sys::path::rbegin(Parent),
    1524         128 :                                      E = sys::path::rend(Parent);
    1525        1588 :          I != E; ++I) {
    1526         730 :       std::vector<std::unique_ptr<Entry>> Entries;
    1527             :       Entries.push_back(std::move(Result));
    1528        1460 :       Result = llvm::make_unique<RedirectingDirectoryEntry>(
    1529             :           *I, std::move(Entries),
    1530        1460 :           Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(),
    1531             :                  0, 0, 0, file_type::directory_file, sys::fs::all_all));
    1532             :     }
    1533             :     return Result;
    1534             :   }
    1535             : 
    1536             : public:
    1537           0 :   RedirectingFileSystemParser(yaml::Stream &S) : Stream(S) {}
    1538             : 
    1539             :   // false on error
    1540          95 :   bool parse(yaml::Node *Root, RedirectingFileSystem *FS) {
    1541             :     auto *Top = dyn_cast<yaml::MappingNode>(Root);
    1542             :     if (!Top) {
    1543           0 :       error(Root, "expected mapping node");
    1544           0 :       return false;
    1545             :     }
    1546             : 
    1547             :     KeyStatusPair Fields[] = {
    1548             :         KeyStatusPair("version", true),
    1549             :         KeyStatusPair("case-sensitive", false),
    1550             :         KeyStatusPair("use-external-names", false),
    1551             :         KeyStatusPair("overlay-relative", false),
    1552             :         KeyStatusPair("ignore-non-existent-contents", false),
    1553             :         KeyStatusPair("roots", true),
    1554             :     };
    1555             : 
    1556          95 :     DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
    1557          95 :     std::vector<std::unique_ptr<Entry>> RootEntries;
    1558             : 
    1559             :     // Parse configuration and 'roots'
    1560         292 :     for (auto &I : *Top) {
    1561             :       SmallString<10> KeyBuffer;
    1562         226 :       StringRef Key;
    1563         226 :       if (!parseScalarString(I.getKey(), Key, KeyBuffer))
    1564             :         return false;
    1565             : 
    1566         226 :       if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys))
    1567             :         return false;
    1568             : 
    1569             :       if (Key == "roots") {
    1570          83 :         auto *Roots = dyn_cast<yaml::SequenceNode>(I.getValue());
    1571             :         if (!Roots) {
    1572           2 :           error(I.getValue(), "expected array");
    1573           2 :           return false;
    1574             :         }
    1575             : 
    1576         161 :         for (auto &I : *Roots) {
    1577          97 :           if (std::unique_ptr<Entry> E =
    1578          97 :                   parseEntry(&I, FS, /*IsRootEntry*/ true))
    1579             :             RootEntries.push_back(std::move(E));
    1580             :           else
    1581             :             return false;
    1582             :         }
    1583             :       } else if (Key == "version") {
    1584          94 :         StringRef VersionString;
    1585             :         SmallString<4> Storage;
    1586          94 :         if (!parseScalarString(I.getValue(), VersionString, Storage))
    1587             :           return false;
    1588             :         int Version;
    1589           1 :         if (VersionString.getAsInteger<int>(10, Version)) {
    1590           1 :           error(I.getValue(), "expected integer");
    1591           1 :           return false;
    1592             :         }
    1593          93 :         if (Version < 0) {
    1594           1 :           error(I.getValue(), "invalid version number");
    1595           1 :           return false;
    1596             :         }
    1597          92 :         if (Version != 0) {
    1598           1 :           error(I.getValue(), "version mismatch, expected 0");
    1599           1 :           return false;
    1600             :         }
    1601             :       } else if (Key == "case-sensitive") {
    1602          15 :         if (!parseScalarBool(I.getValue(), FS->CaseSensitive))
    1603             :           return false;
    1604             :       } else if (Key == "overlay-relative") {
    1605           4 :         if (!parseScalarBool(I.getValue(), FS->IsRelativeOverlay))
    1606             :           return false;
    1607             :       } else if (Key == "use-external-names") {
    1608          16 :         if (!parseScalarBool(I.getValue(), FS->UseExternalNames))
    1609             :           return false;
    1610             :       } else if (Key == "ignore-non-existent-contents") {
    1611           9 :         if (!parseScalarBool(I.getValue(), FS->IgnoreNonExistentContents))
    1612             :           return false;
    1613             :       } else {
    1614           0 :         llvm_unreachable("key missing from Keys");
    1615             :       }
    1616             :     }
    1617             : 
    1618          66 :     if (Stream.failed())
    1619             :       return false;
    1620             : 
    1621          62 :     if (!checkMissingKeys(Top, Keys))
    1622             :       return false;
    1623             : 
    1624             :     // Now that we sucessefully parsed the YAML file, canonicalize the internal
    1625             :     // representation to a proper directory tree so that we can search faster
    1626             :     // inside the VFS.
    1627         141 :     for (auto &E : RootEntries)
    1628          80 :       uniqueOverlayTree(FS, E.get());
    1629             : 
    1630             :     return true;
    1631             :   }
    1632             : };
    1633             : 
    1634             : } // namespace
    1635             : 
    1636             : RedirectingFileSystem *
    1637           0 : RedirectingFileSystem::create(std::unique_ptr<MemoryBuffer> Buffer,
    1638             :                               SourceMgr::DiagHandlerTy DiagHandler,
    1639             :                               StringRef YAMLFilePath, void *DiagContext,
    1640             :                               IntrusiveRefCntPtr<FileSystem> ExternalFS) {
    1641             :   SourceMgr SM;
    1642           0 :   yaml::Stream Stream(Buffer->getMemBufferRef(), SM);
    1643             : 
    1644             :   SM.setDiagHandler(DiagHandler, DiagContext);
    1645           0 :   yaml::document_iterator DI = Stream.begin();
    1646           0 :   yaml::Node *Root = DI->getRoot();
    1647           0 :   if (DI == Stream.end() || !Root) {
    1648           0 :     SM.PrintMessage(SMLoc(), SourceMgr::DK_Error, "expected root node");
    1649           0 :     return nullptr;
    1650             :   }
    1651             : 
    1652             :   RedirectingFileSystemParser P(Stream);
    1653             : 
    1654             :   std::unique_ptr<RedirectingFileSystem> FS(
    1655           0 :       new RedirectingFileSystem(std::move(ExternalFS)));
    1656             : 
    1657           0 :   if (!YAMLFilePath.empty()) {
    1658             :     // Use the YAML path from -ivfsoverlay to compute the dir to be prefixed
    1659             :     // to each 'external-contents' path.
    1660             :     //
    1661             :     // Example:
    1662             :     //    -ivfsoverlay dummy.cache/vfs/vfs.yaml
    1663             :     // yields:
    1664             :     //  FS->ExternalContentsPrefixDir => /<absolute_path_to>/dummy.cache/vfs
    1665             :     //
    1666           0 :     SmallString<256> OverlayAbsDir = sys::path::parent_path(YAMLFilePath);
    1667           0 :     std::error_code EC = llvm::sys::fs::make_absolute(OverlayAbsDir);
    1668             :     assert(!EC && "Overlay dir final path must be absolute");
    1669             :     (void)EC;
    1670           0 :     FS->setExternalContentsPrefixDir(OverlayAbsDir);
    1671             :   }
    1672             : 
    1673           0 :   if (!P.parse(Root, FS.get()))
    1674           0 :     return nullptr;
    1675             : 
    1676           0 :   return FS.release();
    1677             : }
    1678             : 
    1679        2234 : ErrorOr<Entry *> RedirectingFileSystem::lookupPath(const Twine &Path_) {
    1680             :   SmallString<256> Path;
    1681        2234 :   Path_.toVector(Path);
    1682             : 
    1683             :   // Handle relative paths
    1684        2234 :   if (std::error_code EC = makeAbsolute(Path))
    1685           0 :     return EC;
    1686             : 
    1687             :   // Canonicalize path by removing ".", "..", "./", etc components. This is
    1688             :   // a VFS request, do bot bother about symlinks in the path components
    1689             :   // but canonicalize in order to perform the correct entry search.
    1690        2234 :   if (UseCanonicalizedPaths) {
    1691        2234 :     Path = sys::path::remove_leading_dotslash(Path);
    1692        2234 :     sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
    1693             :   }
    1694             : 
    1695        2234 :   if (Path.empty())
    1696           0 :     return make_error_code(llvm::errc::invalid_argument);
    1697             : 
    1698        2234 :   sys::path::const_iterator Start = sys::path::begin(Path);
    1699        2234 :   sys::path::const_iterator End = sys::path::end(Path);
    1700        3985 :   for (const auto &Root : Roots) {
    1701        2234 :     ErrorOr<Entry *> Result = lookupPath(Start, End, Root.get());
    1702        2234 :     if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
    1703             :       return Result;
    1704             :   }
    1705        1751 :   return make_error_code(llvm::errc::no_such_file_or_directory);
    1706             : }
    1707             : 
    1708             : ErrorOr<Entry *>
    1709       15823 : RedirectingFileSystem::lookupPath(sys::path::const_iterator Start,
    1710             :                                   sys::path::const_iterator End, Entry *From) {
    1711             : #ifndef _WIN32
    1712             :   assert(!isTraversalComponent(*Start) &&
    1713             :          !isTraversalComponent(From->getName()) &&
    1714             :          "Paths should not contain traversal components");
    1715             : #else
    1716             :   // FIXME: this is here to support windows, remove it once canonicalized
    1717             :   // paths become globally default.
    1718             :   if (Start->equals("."))
    1719             :     ++Start;
    1720             : #endif
    1721             : 
    1722             :   StringRef FromName = From->getName();
    1723             : 
    1724             :   // Forward the search to the next component in case this is an empty one.
    1725       15823 :   if (!FromName.empty()) {
    1726       31646 :     if (CaseSensitive ? !Start->equals(FromName)
    1727        3811 :                       : !Start->equals_lower(FromName))
    1728             :       // failure to match
    1729        3170 :       return make_error_code(llvm::errc::no_such_file_or_directory);
    1730             : 
    1731       12653 :     ++Start;
    1732             : 
    1733       12653 :     if (Start == End) {
    1734             :       // Match!
    1735             :       return From;
    1736             :     }
    1737             :   }
    1738             : 
    1739             :   auto *DE = dyn_cast<RedirectingDirectoryEntry>(From);
    1740             :   if (!DE)
    1741           0 :     return make_error_code(llvm::errc::not_a_directory);
    1742             : 
    1743             :   for (const std::unique_ptr<Entry> &DirEntry :
    1744       22052 :        llvm::make_range(DE->contents_begin(), DE->contents_end())) {
    1745       13589 :     ErrorOr<Entry *> Result = lookupPath(Start, End, DirEntry.get());
    1746       13589 :     if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
    1747             :       return Result;
    1748             :   }
    1749        8463 :   return make_error_code(llvm::errc::no_such_file_or_directory);
    1750             : }
    1751             : 
    1752         158 : static Status getRedirectedFileStatus(const Twine &Path, bool UseExternalNames,
    1753             :                                       Status ExternalStatus) {
    1754         158 :   Status S = ExternalStatus;
    1755         158 :   if (!UseExternalNames)
    1756         192 :     S = Status::copyWithNewName(S, Path.str());
    1757         158 :   S.IsVFSMapped = true;
    1758         158 :   return S;
    1759             : }
    1760             : 
    1761         423 : ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path, Entry *E) {
    1762             :   assert(E != nullptr);
    1763             :   if (auto *F = dyn_cast<RedirectingFileEntry>(E)) {
    1764         300 :     ErrorOr<Status> S = ExternalFS->status(F->getExternalContentsPath());
    1765             :     assert(!S || S->getName() == F->getExternalContentsPath());
    1766         100 :     if (S)
    1767         294 :       return getRedirectedFileStatus(Path, F->useExternalName(UseExternalNames),
    1768             :                                      *S);
    1769             :     return S;
    1770             :   } else { // directory
    1771             :     auto *DE = cast<RedirectingDirectoryEntry>(E);
    1772        1222 :     return Status::copyWithNewName(DE->getStatus(), Path.str());
    1773             :   }
    1774             : }
    1775             : 
    1776        1475 : ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path) {
    1777        1475 :   ErrorOr<Entry *> Result = lookupPath(Path);
    1778        1475 :   if (!Result)
    1779        1074 :     return Result.getError();
    1780         401 :   return status(Path, *Result);
    1781             : }
    1782             : 
    1783             : namespace {
    1784             : 
    1785             : /// Provide a file wrapper with an overriden status.
    1786           0 : class FileWithFixedStatus : public File {
    1787             :   std::unique_ptr<File> InnerFile;
    1788             :   Status S;
    1789             : 
    1790             : public:
    1791             :   FileWithFixedStatus(std::unique_ptr<File> InnerFile, Status S)
    1792          60 :       : InnerFile(std::move(InnerFile)), S(std::move(S)) {}
    1793             : 
    1794          51 :   ErrorOr<Status> status() override { return S; }
    1795             :   ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
    1796             : 
    1797          55 :   getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
    1798             :             bool IsVolatile) override {
    1799             :     return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
    1800          55 :                                 IsVolatile);
    1801             :   }
    1802             : 
    1803           0 :   std::error_code close() override { return InnerFile->close(); }
    1804             : };
    1805             : 
    1806             : } // namespace
    1807             : 
    1808             : ErrorOr<std::unique_ptr<File>>
    1809         454 : RedirectingFileSystem::openFileForRead(const Twine &Path) {
    1810         454 :   ErrorOr<Entry *> E = lookupPath(Path);
    1811         454 :   if (!E)
    1812         394 :     return E.getError();
    1813             : 
    1814          60 :   auto *F = dyn_cast<RedirectingFileEntry>(*E);
    1815             :   if (!F) // FIXME: errc::not_a_file?
    1816           0 :     return make_error_code(llvm::errc::invalid_argument);
    1817             : 
    1818         180 :   auto Result = ExternalFS->openFileForRead(F->getExternalContentsPath());
    1819          60 :   if (!Result)
    1820             :     return Result;
    1821             : 
    1822          60 :   auto ExternalStatus = (*Result)->status();
    1823          60 :   if (!ExternalStatus)
    1824           0 :     return ExternalStatus.getError();
    1825             : 
    1826             :   // FIXME: Update the status with the name and VFSMapped.
    1827          60 :   Status S = getRedirectedFileStatus(Path, F->useExternalName(UseExternalNames),
    1828         120 :                                      *ExternalStatus);
    1829             :   return std::unique_ptr<File>(
    1830          60 :       llvm::make_unique<FileWithFixedStatus>(std::move(*Result), S));
    1831             : }
    1832             : 
    1833             : IntrusiveRefCntPtr<FileSystem>
    1834          95 : vfs::getVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,
    1835             :                     SourceMgr::DiagHandlerTy DiagHandler,
    1836             :                     StringRef YAMLFilePath, void *DiagContext,
    1837             :                     IntrusiveRefCntPtr<FileSystem> ExternalFS) {
    1838         190 :   return RedirectingFileSystem::create(std::move(Buffer), DiagHandler,
    1839             :                                        YAMLFilePath, DiagContext,
    1840          95 :                                        std::move(ExternalFS));
    1841             : }
    1842             : 
    1843           0 : static void getVFSEntries(Entry *SrcE, SmallVectorImpl<StringRef> &Path,
    1844             :                           SmallVectorImpl<YAMLVFSEntry> &Entries) {
    1845           0 :   auto Kind = SrcE->getKind();
    1846           0 :   if (Kind == EK_Directory) {
    1847             :     auto *DE = dyn_cast<RedirectingDirectoryEntry>(SrcE);
    1848             :     assert(DE && "Must be a directory");
    1849             :     for (std::unique_ptr<Entry> &SubEntry :
    1850           0 :          llvm::make_range(DE->contents_begin(), DE->contents_end())) {
    1851           0 :       Path.push_back(SubEntry->getName());
    1852           0 :       getVFSEntries(SubEntry.get(), Path, Entries);
    1853             :       Path.pop_back();
    1854             :     }
    1855           0 :     return;
    1856             :   }
    1857             : 
    1858             :   assert(Kind == EK_File && "Must be a EK_File");
    1859             :   auto *FE = dyn_cast<RedirectingFileEntry>(SrcE);
    1860             :   assert(FE && "Must be a file");
    1861             :   SmallString<128> VPath;
    1862           0 :   for (auto &Comp : Path)
    1863           0 :     llvm::sys::path::append(VPath, Comp);
    1864           0 :   Entries.push_back(YAMLVFSEntry(VPath.c_str(), FE->getExternalContentsPath()));
    1865             : }
    1866             : 
    1867           0 : void vfs::collectVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,
    1868             :                              SourceMgr::DiagHandlerTy DiagHandler,
    1869             :                              StringRef YAMLFilePath,
    1870             :                              SmallVectorImpl<YAMLVFSEntry> &CollectedEntries,
    1871             :                              void *DiagContext,
    1872             :                              IntrusiveRefCntPtr<FileSystem> ExternalFS) {
    1873           0 :   RedirectingFileSystem *VFS = RedirectingFileSystem::create(
    1874             :       std::move(Buffer), DiagHandler, YAMLFilePath, DiagContext,
    1875             :       std::move(ExternalFS));
    1876           0 :   ErrorOr<Entry *> RootE = VFS->lookupPath("/");
    1877           0 :   if (!RootE)
    1878             :     return;
    1879             :   SmallVector<StringRef, 8> Components;
    1880           0 :   Components.push_back("/");
    1881           0 :   getVFSEntries(*RootE, Components, CollectedEntries);
    1882             : }
    1883             : 
    1884      167852 : UniqueID vfs::getNextVirtualUniqueID() {
    1885      167852 :   static std::atomic<unsigned> UID;
    1886             :   unsigned ID = ++UID;
    1887             :   // The following assumes that uint64_t max will never collide with a real
    1888             :   // dev_t value from the OS.
    1889      167852 :   return UniqueID(std::numeric_limits<uint64_t>::max(), ID);
    1890             : }
    1891             : 
    1892         321 : void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) {
    1893             :   assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute");
    1894             :   assert(sys::path::is_absolute(RealPath) && "real path not absolute");
    1895             :   assert(!pathHasTraversal(VirtualPath) && "path traversal is not supported");
    1896         321 :   Mappings.emplace_back(VirtualPath, RealPath);
    1897         321 : }
    1898             : 
    1899             : namespace {
    1900             : 
    1901             : class JSONWriter {
    1902             :   llvm::raw_ostream &OS;
    1903             :   SmallVector<StringRef, 16> DirStack;
    1904             : 
    1905          94 :   unsigned getDirIndent() { return 4 * DirStack.size(); }
    1906         321 :   unsigned getFileIndent() { return 4 * (DirStack.size() + 1); }
    1907             :   bool containedIn(StringRef Parent, StringRef Path);
    1908             :   StringRef containedPart(StringRef Parent, StringRef Path);
    1909             :   void startDirectory(StringRef Path);
    1910             :   void endDirectory();
    1911             :   void writeEntry(StringRef VPath, StringRef RPath);
    1912             : 
    1913             : public:
    1914          17 :   JSONWriter(llvm::raw_ostream &OS) : OS(OS) {}
    1915             : 
    1916             :   void write(ArrayRef<YAMLVFSEntry> Entries, Optional<bool> UseExternalNames,
    1917             :              Optional<bool> IsCaseSensitive, Optional<bool> IsOverlayRelative,
    1918             :              Optional<bool> IgnoreNonExistentContents, StringRef OverlayDir);
    1919             : };
    1920             : 
    1921             : } // namespace
    1922             : 
    1923           0 : bool JSONWriter::containedIn(StringRef Parent, StringRef Path) {
    1924             :   using namespace llvm::sys;
    1925             : 
    1926             :   // Compare each path component.
    1927           0 :   auto IParent = path::begin(Parent), EParent = path::end(Parent);
    1928           0 :   for (auto IChild = path::begin(Path), EChild = path::end(Path);
    1929           0 :        IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
    1930             :     if (*IParent != *IChild)
    1931           0 :       return false;
    1932             :   }
    1933             :   // Have we exhausted the parent path?
    1934           0 :   return IParent == EParent;
    1935             : }
    1936             : 
    1937           0 : StringRef JSONWriter::containedPart(StringRef Parent, StringRef Path) {
    1938             :   assert(!Parent.empty());
    1939             :   assert(containedIn(Parent, Path));
    1940           0 :   return Path.slice(Parent.size() + 1, StringRef::npos);
    1941             : }
    1942             : 
    1943          47 : void JSONWriter::startDirectory(StringRef Path) {
    1944             :   StringRef Name =
    1945          47 :       DirStack.empty() ? Path : containedPart(DirStack.back(), Path);
    1946          47 :   DirStack.push_back(Path);
    1947             :   unsigned Indent = getDirIndent();
    1948          47 :   OS.indent(Indent) << "{\n";
    1949          47 :   OS.indent(Indent + 2) << "'type': 'directory',\n";
    1950          94 :   OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(Name) << "\",\n";
    1951          47 :   OS.indent(Indent + 2) << "'contents': [\n";
    1952          47 : }
    1953             : 
    1954          47 : void JSONWriter::endDirectory() {
    1955             :   unsigned Indent = getDirIndent();
    1956          47 :   OS.indent(Indent + 2) << "]\n";
    1957          47 :   OS.indent(Indent) << "}";
    1958             : 
    1959             :   DirStack.pop_back();
    1960          47 : }
    1961             : 
    1962         321 : void JSONWriter::writeEntry(StringRef VPath, StringRef RPath) {
    1963             :   unsigned Indent = getFileIndent();
    1964         321 :   OS.indent(Indent) << "{\n";
    1965         321 :   OS.indent(Indent + 2) << "'type': 'file',\n";
    1966         642 :   OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(VPath) << "\",\n";
    1967         321 :   OS.indent(Indent + 2) << "'external-contents': \""
    1968         642 :                         << llvm::yaml::escape(RPath) << "\"\n";
    1969         321 :   OS.indent(Indent) << "}";
    1970         321 : }
    1971             : 
    1972           0 : void JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries,
    1973             :                        Optional<bool> UseExternalNames,
    1974             :                        Optional<bool> IsCaseSensitive,
    1975             :                        Optional<bool> IsOverlayRelative,
    1976             :                        Optional<bool> IgnoreNonExistentContents,
    1977             :                        StringRef OverlayDir) {
    1978             :   using namespace llvm::sys;
    1979             : 
    1980           0 :   OS << "{\n"
    1981           0 :         "  'version': 0,\n";
    1982           0 :   if (IsCaseSensitive.hasValue())
    1983           0 :     OS << "  'case-sensitive': '"
    1984           0 :        << (IsCaseSensitive.getValue() ? "true" : "false") << "',\n";
    1985           0 :   if (UseExternalNames.hasValue())
    1986           0 :     OS << "  'use-external-names': '"
    1987           0 :        << (UseExternalNames.getValue() ? "true" : "false") << "',\n";
    1988             :   bool UseOverlayRelative = false;
    1989           0 :   if (IsOverlayRelative.hasValue()) {
    1990           0 :     UseOverlayRelative = IsOverlayRelative.getValue();
    1991           0 :     OS << "  'overlay-relative': '" << (UseOverlayRelative ? "true" : "false")
    1992           0 :        << "',\n";
    1993             :   }
    1994           0 :   if (IgnoreNonExistentContents.hasValue())
    1995           0 :     OS << "  'ignore-non-existent-contents': '"
    1996           0 :        << (IgnoreNonExistentContents.getValue() ? "true" : "false") << "',\n";
    1997           0 :   OS << "  'roots': [\n";
    1998             : 
    1999           0 :   if (!Entries.empty()) {
    2000             :     const YAMLVFSEntry &Entry = Entries.front();
    2001           0 :     startDirectory(path::parent_path(Entry.VPath));
    2002             : 
    2003             :     StringRef RPath = Entry.RPath;
    2004           0 :     if (UseOverlayRelative) {
    2005             :       unsigned OverlayDirLen = OverlayDir.size();
    2006             :       assert(RPath.substr(0, OverlayDirLen) == OverlayDir &&
    2007             :              "Overlay dir must be contained in RPath");
    2008           0 :       RPath = RPath.slice(OverlayDirLen, RPath.size());
    2009             :     }
    2010             : 
    2011           0 :     writeEntry(path::filename(Entry.VPath), RPath);
    2012             : 
    2013           0 :     for (const auto &Entry : Entries.slice(1)) {
    2014           0 :       StringRef Dir = path::parent_path(Entry.VPath);
    2015             :       if (Dir == DirStack.back())
    2016           0 :         OS << ",\n";
    2017             :       else {
    2018           0 :         while (!DirStack.empty() && !containedIn(DirStack.back(), Dir)) {
    2019           0 :           OS << "\n";
    2020           0 :           endDirectory();
    2021             :         }
    2022           0 :         OS << ",\n";
    2023           0 :         startDirectory(Dir);
    2024             :       }
    2025             :       StringRef RPath = Entry.RPath;
    2026           0 :       if (UseOverlayRelative) {
    2027             :         unsigned OverlayDirLen = OverlayDir.size();
    2028             :         assert(RPath.substr(0, OverlayDirLen) == OverlayDir &&
    2029             :                "Overlay dir must be contained in RPath");
    2030           0 :         RPath = RPath.slice(OverlayDirLen, RPath.size());
    2031             :       }
    2032           0 :       writeEntry(path::filename(Entry.VPath), RPath);
    2033             :     }
    2034             : 
    2035           0 :     while (!DirStack.empty()) {
    2036           0 :       OS << "\n";
    2037           0 :       endDirectory();
    2038             :     }
    2039           0 :     OS << "\n";
    2040             :   }
    2041             : 
    2042           0 :   OS << "  ]\n"
    2043           0 :      << "}\n";
    2044           0 : }
    2045             : 
    2046          17 : void YAMLVFSWriter::write(llvm::raw_ostream &OS) {
    2047             :   llvm::sort(Mappings, [](const YAMLVFSEntry &LHS, const YAMLVFSEntry &RHS) {
    2048           0 :     return LHS.VPath < RHS.VPath;
    2049             :   });
    2050             : 
    2051          17 :   JSONWriter(OS).write(Mappings, UseExternalNames, IsCaseSensitive,
    2052             :                        IsOverlayRelative, IgnoreNonExistentContents,
    2053             :                        OverlayDir);
    2054          17 : }
    2055             : 
    2056          22 : VFSFromYamlDirIterImpl::VFSFromYamlDirIterImpl(
    2057             :     const Twine &_Path, RedirectingDirectoryEntry::iterator Begin,
    2058          22 :     RedirectingDirectoryEntry::iterator End, std::error_code &EC)
    2059          22 :     : Dir(_Path.str()), Current(Begin), End(End) {
    2060          22 :   EC = incrementImpl();
    2061          22 : }
    2062             : 
    2063          41 : std::error_code VFSFromYamlDirIterImpl::increment() {
    2064             :   assert(Current != End && "cannot iterate past end");
    2065             :   ++Current;
    2066          41 :   return incrementImpl();
    2067             : }
    2068             : 
    2069          63 : std::error_code VFSFromYamlDirIterImpl::incrementImpl() {
    2070          63 :   while (Current != End) {
    2071             :     SmallString<128> PathStr(Dir);
    2072         123 :     llvm::sys::path::append(PathStr, (*Current)->getName());
    2073             :     sys::fs::file_type Type;
    2074          82 :     switch ((*Current)->getKind()) {
    2075           5 :     case EK_Directory:
    2076             :       Type = sys::fs::file_type::directory_file;
    2077           5 :       break;
    2078          36 :     case EK_File:
    2079             :       Type = sys::fs::file_type::regular_file;
    2080          36 :       break;
    2081             :     }
    2082          41 :     CurrentEntry = directory_entry(PathStr.str(), Type);
    2083             :     break;
    2084             :   }
    2085             : 
    2086          63 :   if (Current == End)
    2087          44 :     CurrentEntry = directory_entry();
    2088          63 :   return {};
    2089             : }
    2090             : 
    2091         276 : vfs::recursive_directory_iterator::recursive_directory_iterator(
    2092         276 :     FileSystem &FS_, const Twine &Path, std::error_code &EC)
    2093         276 :     : FS(&FS_) {
    2094         276 :   directory_iterator I = FS->dir_begin(Path, EC);
    2095         276 :   if (I != directory_iterator()) {
    2096         273 :     State = std::make_shared<IterState>();
    2097             :     State->push(I);
    2098             :   }
    2099         276 : }
    2100             : 
    2101             : vfs::recursive_directory_iterator &
    2102        1040 : recursive_directory_iterator::increment(std::error_code &EC) {
    2103             :   assert(FS && State && !State->empty() && "incrementing past end");
    2104             :   assert(!State->top()->path().empty() && "non-canonical end iterator");
    2105        1040 :   vfs::directory_iterator End;
    2106        1040 :   if (State->top()->type() == sys::fs::file_type::directory_file) {
    2107         294 :     vfs::directory_iterator I = FS->dir_begin(State->top()->path(), EC);
    2108          98 :     if (I != End) {
    2109             :       State->push(I);
    2110             :       return *this;
    2111             :     }
    2112             :   }
    2113             : 
    2114        1313 :   while (!State->empty() && State->top().increment(EC) == End)
    2115             :     State->pop();
    2116             : 
    2117         946 :   if (State->empty())
    2118             :     State.reset(); // end iterator
    2119             : 
    2120             :   return *this;
    2121             : }

Generated by: LCOV version 1.13