Home | History | Annotate | Line # | Download | only in Support
      1 //===- VirtualFileSystem.cpp - Virtual File System Layer ------------------===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // This file implements the VirtualFileSystem interface.
     10 //
     11 //===----------------------------------------------------------------------===//
     12 
     13 #include "llvm/Support/VirtualFileSystem.h"
     14 #include "llvm/ADT/ArrayRef.h"
     15 #include "llvm/ADT/DenseMap.h"
     16 #include "llvm/ADT/IntrusiveRefCntPtr.h"
     17 #include "llvm/ADT/None.h"
     18 #include "llvm/ADT/Optional.h"
     19 #include "llvm/ADT/STLExtras.h"
     20 #include "llvm/ADT/SmallString.h"
     21 #include "llvm/ADT/SmallVector.h"
     22 #include "llvm/ADT/StringRef.h"
     23 #include "llvm/ADT/StringSet.h"
     24 #include "llvm/ADT/Twine.h"
     25 #include "llvm/ADT/iterator_range.h"
     26 #include "llvm/Config/llvm-config.h"
     27 #include "llvm/Support/Casting.h"
     28 #include "llvm/Support/Chrono.h"
     29 #include "llvm/Support/Compiler.h"
     30 #include "llvm/Support/Debug.h"
     31 #include "llvm/Support/Errc.h"
     32 #include "llvm/Support/ErrorHandling.h"
     33 #include "llvm/Support/ErrorOr.h"
     34 #include "llvm/Support/FileSystem.h"
     35 #include "llvm/Support/MemoryBuffer.h"
     36 #include "llvm/Support/Path.h"
     37 #include "llvm/Support/Process.h"
     38 #include "llvm/Support/SMLoc.h"
     39 #include "llvm/Support/SourceMgr.h"
     40 #include "llvm/Support/YAMLParser.h"
     41 #include "llvm/Support/raw_ostream.h"
     42 #include <algorithm>
     43 #include <atomic>
     44 #include <cassert>
     45 #include <cstdint>
     46 #include <iterator>
     47 #include <limits>
     48 #include <map>
     49 #include <memory>
     50 #include <mutex>
     51 #include <string>
     52 #include <system_error>
     53 #include <utility>
     54 #include <vector>
     55 
     56 using namespace llvm;
     57 using namespace llvm::vfs;
     58 
     59 using llvm::sys::fs::file_t;
     60 using llvm::sys::fs::file_status;
     61 using llvm::sys::fs::file_type;
     62 using llvm::sys::fs::kInvalidFile;
     63 using llvm::sys::fs::perms;
     64 using llvm::sys::fs::UniqueID;
     65 
     66 Status::Status(const file_status &Status)
     67     : UID(Status.getUniqueID()), MTime(Status.getLastModificationTime()),
     68       User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()),
     69       Type(Status.type()), Perms(Status.permissions()) {}
     70 
     71 Status::Status(const Twine &Name, UniqueID UID, sys::TimePoint<> MTime,
     72                uint32_t User, uint32_t Group, uint64_t Size, file_type Type,
     73                perms Perms)
     74     : Name(Name.str()), UID(UID), MTime(MTime), User(User), Group(Group),
     75       Size(Size), Type(Type), Perms(Perms) {}
     76 
     77 Status Status::copyWithNewName(const Status &In, const Twine &NewName) {
     78   return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
     79                 In.getUser(), In.getGroup(), In.getSize(), In.getType(),
     80                 In.getPermissions());
     81 }
     82 
     83 Status Status::copyWithNewName(const file_status &In, const Twine &NewName) {
     84   return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
     85                 In.getUser(), In.getGroup(), In.getSize(), In.type(),
     86                 In.permissions());
     87 }
     88 
     89 bool Status::equivalent(const Status &Other) const {
     90   assert(isStatusKnown() && Other.isStatusKnown());
     91   return getUniqueID() == Other.getUniqueID();
     92 }
     93 
     94 bool Status::isDirectory() const { return Type == file_type::directory_file; }
     95 
     96 bool Status::isRegularFile() const { return Type == file_type::regular_file; }
     97 
     98 bool Status::isOther() const {
     99   return exists() && !isRegularFile() && !isDirectory() && !isSymlink();
    100 }
    101 
    102 bool Status::isSymlink() const { return Type == file_type::symlink_file; }
    103 
    104 bool Status::isStatusKnown() const { return Type != file_type::status_error; }
    105 
    106 bool Status::exists() const {
    107   return isStatusKnown() && Type != file_type::file_not_found;
    108 }
    109 
    110 File::~File() = default;
    111 
    112 FileSystem::~FileSystem() = default;
    113 
    114 ErrorOr<std::unique_ptr<MemoryBuffer>>
    115 FileSystem::getBufferForFile(const llvm::Twine &Name, int64_t FileSize,
    116                              bool RequiresNullTerminator, bool IsVolatile) {
    117   auto F = openFileForRead(Name);
    118   if (!F)
    119     return F.getError();
    120 
    121   return (*F)->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile);
    122 }
    123 
    124 std::error_code FileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const {
    125   if (llvm::sys::path::is_absolute(Path))
    126     return {};
    127 
    128   auto WorkingDir = getCurrentWorkingDirectory();
    129   if (!WorkingDir)
    130     return WorkingDir.getError();
    131 
    132   llvm::sys::fs::make_absolute(WorkingDir.get(), Path);
    133   return {};
    134 }
    135 
    136 std::error_code FileSystem::getRealPath(const Twine &Path,
    137                                         SmallVectorImpl<char> &Output) const {
    138   return errc::operation_not_permitted;
    139 }
    140 
    141 std::error_code FileSystem::isLocal(const Twine &Path, bool &Result) {
    142   return errc::operation_not_permitted;
    143 }
    144 
    145 bool FileSystem::exists(const Twine &Path) {
    146   auto Status = status(Path);
    147   return Status && Status->exists();
    148 }
    149 
    150 #ifndef NDEBUG
    151 static bool isTraversalComponent(StringRef Component) {
    152   return Component.equals("..") || Component.equals(".");
    153 }
    154 
    155 static bool pathHasTraversal(StringRef Path) {
    156   using namespace llvm::sys;
    157 
    158   for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path)))
    159     if (isTraversalComponent(Comp))
    160       return true;
    161   return false;
    162 }
    163 #endif
    164 
    165 //===-----------------------------------------------------------------------===/
    166 // RealFileSystem implementation
    167 //===-----------------------------------------------------------------------===/
    168 
    169 namespace {
    170 
    171 /// Wrapper around a raw file descriptor.
    172 class RealFile : public File {
    173   friend class RealFileSystem;
    174 
    175   file_t FD;
    176   Status S;
    177   std::string RealName;
    178 
    179   RealFile(file_t RawFD, StringRef NewName, StringRef NewRealPathName)
    180       : FD(RawFD), S(NewName, {}, {}, {}, {}, {},
    181                      llvm::sys::fs::file_type::status_error, {}),
    182         RealName(NewRealPathName.str()) {
    183     assert(FD != kInvalidFile && "Invalid or inactive file descriptor");
    184   }
    185 
    186 public:
    187   ~RealFile() override;
    188 
    189   ErrorOr<Status> status() override;
    190   ErrorOr<std::string> getName() override;
    191   ErrorOr<std::unique_ptr<MemoryBuffer>> getBuffer(const Twine &Name,
    192                                                    int64_t FileSize,
    193                                                    bool RequiresNullTerminator,
    194                                                    bool IsVolatile) override;
    195   std::error_code close() override;
    196 };
    197 
    198 } // namespace
    199 
    200 RealFile::~RealFile() { close(); }
    201 
    202 ErrorOr<Status> RealFile::status() {
    203   assert(FD != kInvalidFile && "cannot stat closed file");
    204   if (!S.isStatusKnown()) {
    205     file_status RealStatus;
    206     if (std::error_code EC = sys::fs::status(FD, RealStatus))
    207       return EC;
    208     S = Status::copyWithNewName(RealStatus, S.getName());
    209   }
    210   return S;
    211 }
    212 
    213 ErrorOr<std::string> RealFile::getName() {
    214   return RealName.empty() ? S.getName().str() : RealName;
    215 }
    216 
    217 ErrorOr<std::unique_ptr<MemoryBuffer>>
    218 RealFile::getBuffer(const Twine &Name, int64_t FileSize,
    219                     bool RequiresNullTerminator, bool IsVolatile) {
    220   assert(FD != kInvalidFile && "cannot get buffer for closed file");
    221   return MemoryBuffer::getOpenFile(FD, Name, FileSize, RequiresNullTerminator,
    222                                    IsVolatile);
    223 }
    224 
    225 std::error_code RealFile::close() {
    226   std::error_code EC = sys::fs::closeFile(FD);
    227   FD = kInvalidFile;
    228   return EC;
    229 }
    230 
    231 namespace {
    232 
    233 /// A file system according to your operating system.
    234 /// This may be linked to the process's working directory, or maintain its own.
    235 ///
    236 /// Currently, its own working directory is emulated by storing the path and
    237 /// sending absolute paths to llvm::sys::fs:: functions.
    238 /// A more principled approach would be to push this down a level, modelling
    239 /// the working dir as an llvm::sys::fs::WorkingDir or similar.
    240 /// This would enable the use of openat()-style functions on some platforms.
    241 class RealFileSystem : public FileSystem {
    242 public:
    243   explicit RealFileSystem(bool LinkCWDToProcess) {
    244     if (!LinkCWDToProcess) {
    245       SmallString<128> PWD, RealPWD;
    246       if (llvm::sys::fs::current_path(PWD))
    247         return; // Awful, but nothing to do here.
    248       if (llvm::sys::fs::real_path(PWD, RealPWD))
    249         WD = {PWD, PWD};
    250       else
    251         WD = {PWD, RealPWD};
    252     }
    253   }
    254 
    255   ErrorOr<Status> status(const Twine &Path) override;
    256   ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
    257   directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
    258 
    259   llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override;
    260   std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
    261   std::error_code isLocal(const Twine &Path, bool &Result) override;
    262   std::error_code getRealPath(const Twine &Path,
    263                               SmallVectorImpl<char> &Output) const override;
    264 
    265 private:
    266   // If this FS has its own working dir, use it to make Path absolute.
    267   // The returned twine is safe to use as long as both Storage and Path live.
    268   Twine adjustPath(const Twine &Path, SmallVectorImpl<char> &Storage) const {
    269     if (!WD)
    270       return Path;
    271     Path.toVector(Storage);
    272     sys::fs::make_absolute(WD->Resolved, Storage);
    273     return Storage;
    274   }
    275 
    276   struct WorkingDirectory {
    277     // The current working directory, without symlinks resolved. (echo $PWD).
    278     SmallString<128> Specified;
    279     // The current working directory, with links resolved. (readlink .).
    280     SmallString<128> Resolved;
    281   };
    282   Optional<WorkingDirectory> WD;
    283 };
    284 
    285 } // namespace
    286 
    287 ErrorOr<Status> RealFileSystem::status(const Twine &Path) {
    288   SmallString<256> Storage;
    289   sys::fs::file_status RealStatus;
    290   if (std::error_code EC =
    291           sys::fs::status(adjustPath(Path, Storage), RealStatus))
    292     return EC;
    293   return Status::copyWithNewName(RealStatus, Path);
    294 }
    295 
    296 ErrorOr<std::unique_ptr<File>>
    297 RealFileSystem::openFileForRead(const Twine &Name) {
    298   SmallString<256> RealName, Storage;
    299   Expected<file_t> FDOrErr = sys::fs::openNativeFileForRead(
    300       adjustPath(Name, Storage), sys::fs::OF_None, &RealName);
    301   if (!FDOrErr)
    302     return errorToErrorCode(FDOrErr.takeError());
    303   return std::unique_ptr<File>(
    304       new RealFile(*FDOrErr, Name.str(), RealName.str()));
    305 }
    306 
    307 llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory() const {
    308   if (WD)
    309     return std::string(WD->Specified.str());
    310 
    311   SmallString<128> Dir;
    312   if (std::error_code EC = llvm::sys::fs::current_path(Dir))
    313     return EC;
    314   return std::string(Dir.str());
    315 }
    316 
    317 std::error_code RealFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
    318   if (!WD)
    319     return llvm::sys::fs::set_current_path(Path);
    320 
    321   SmallString<128> Absolute, Resolved, Storage;
    322   adjustPath(Path, Storage).toVector(Absolute);
    323   bool IsDir;
    324   if (auto Err = llvm::sys::fs::is_directory(Absolute, IsDir))
    325     return Err;
    326   if (!IsDir)
    327     return std::make_error_code(std::errc::not_a_directory);
    328   if (auto Err = llvm::sys::fs::real_path(Absolute, Resolved))
    329     return Err;
    330   WD = {Absolute, Resolved};
    331   return std::error_code();
    332 }
    333 
    334 std::error_code RealFileSystem::isLocal(const Twine &Path, bool &Result) {
    335   SmallString<256> Storage;
    336   return llvm::sys::fs::is_local(adjustPath(Path, Storage), Result);
    337 }
    338 
    339 std::error_code
    340 RealFileSystem::getRealPath(const Twine &Path,
    341                             SmallVectorImpl<char> &Output) const {
    342   SmallString<256> Storage;
    343   return llvm::sys::fs::real_path(adjustPath(Path, Storage), Output);
    344 }
    345 
    346 IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
    347   static IntrusiveRefCntPtr<FileSystem> FS(new RealFileSystem(true));
    348   return FS;
    349 }
    350 
    351 std::unique_ptr<FileSystem> vfs::createPhysicalFileSystem() {
    352   return std::make_unique<RealFileSystem>(false);
    353 }
    354 
    355 namespace {
    356 
    357 class RealFSDirIter : public llvm::vfs::detail::DirIterImpl {
    358   llvm::sys::fs::directory_iterator Iter;
    359 
    360 public:
    361   RealFSDirIter(const Twine &Path, std::error_code &EC) : Iter(Path, EC) {
    362     if (Iter != llvm::sys::fs::directory_iterator())
    363       CurrentEntry = directory_entry(Iter->path(), Iter->type());
    364   }
    365 
    366   std::error_code increment() override {
    367     std::error_code EC;
    368     Iter.increment(EC);
    369     CurrentEntry = (Iter == llvm::sys::fs::directory_iterator())
    370                        ? directory_entry()
    371                        : directory_entry(Iter->path(), Iter->type());
    372     return EC;
    373   }
    374 };
    375 
    376 } // namespace
    377 
    378 directory_iterator RealFileSystem::dir_begin(const Twine &Dir,
    379                                              std::error_code &EC) {
    380   SmallString<128> Storage;
    381   return directory_iterator(
    382       std::make_shared<RealFSDirIter>(adjustPath(Dir, Storage), EC));
    383 }
    384 
    385 //===-----------------------------------------------------------------------===/
    386 // OverlayFileSystem implementation
    387 //===-----------------------------------------------------------------------===/
    388 
    389 OverlayFileSystem::OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> BaseFS) {
    390   FSList.push_back(std::move(BaseFS));
    391 }
    392 
    393 void OverlayFileSystem::pushOverlay(IntrusiveRefCntPtr<FileSystem> FS) {
    394   FSList.push_back(FS);
    395   // Synchronize added file systems by duplicating the working directory from
    396   // the first one in the list.
    397   FS->setCurrentWorkingDirectory(getCurrentWorkingDirectory().get());
    398 }
    399 
    400 ErrorOr<Status> OverlayFileSystem::status(const Twine &Path) {
    401   // FIXME: handle symlinks that cross file systems
    402   for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
    403     ErrorOr<Status> Status = (*I)->status(Path);
    404     if (Status || Status.getError() != llvm::errc::no_such_file_or_directory)
    405       return Status;
    406   }
    407   return make_error_code(llvm::errc::no_such_file_or_directory);
    408 }
    409 
    410 ErrorOr<std::unique_ptr<File>>
    411 OverlayFileSystem::openFileForRead(const llvm::Twine &Path) {
    412   // FIXME: handle symlinks that cross file systems
    413   for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
    414     auto Result = (*I)->openFileForRead(Path);
    415     if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
    416       return Result;
    417   }
    418   return make_error_code(llvm::errc::no_such_file_or_directory);
    419 }
    420 
    421 llvm::ErrorOr<std::string>
    422 OverlayFileSystem::getCurrentWorkingDirectory() const {
    423   // All file systems are synchronized, just take the first working directory.
    424   return FSList.front()->getCurrentWorkingDirectory();
    425 }
    426 
    427 std::error_code
    428 OverlayFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
    429   for (auto &FS : FSList)
    430     if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))
    431       return EC;
    432   return {};
    433 }
    434 
    435 std::error_code OverlayFileSystem::isLocal(const Twine &Path, bool &Result) {
    436   for (auto &FS : FSList)
    437     if (FS->exists(Path))
    438       return FS->isLocal(Path, Result);
    439   return errc::no_such_file_or_directory;
    440 }
    441 
    442 std::error_code
    443 OverlayFileSystem::getRealPath(const Twine &Path,
    444                                SmallVectorImpl<char> &Output) const {
    445   for (auto &FS : FSList)
    446     if (FS->exists(Path))
    447       return FS->getRealPath(Path, Output);
    448   return errc::no_such_file_or_directory;
    449 }
    450 
    451 llvm::vfs::detail::DirIterImpl::~DirIterImpl() = default;
    452 
    453 namespace {
    454 
    455 /// Combines and deduplicates directory entries across multiple file systems.
    456 class CombiningDirIterImpl : public llvm::vfs::detail::DirIterImpl {
    457   using FileSystemPtr = llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>;
    458 
    459   /// File systems to check for entries in. Processed in reverse order.
    460   SmallVector<FileSystemPtr, 8> FSList;
    461   /// The directory iterator for the current filesystem.
    462   directory_iterator CurrentDirIter;
    463   /// The path of the directory to iterate the entries of.
    464   std::string DirPath;
    465   /// The set of names already returned as entries.
    466   llvm::StringSet<> SeenNames;
    467 
    468   /// Sets \c CurrentDirIter to an iterator of \c DirPath in the next file
    469   /// system in the list, or leaves it as is (at its end position) if we've
    470   /// already gone through them all.
    471   std::error_code incrementFS() {
    472     while (!FSList.empty()) {
    473       std::error_code EC;
    474       CurrentDirIter = FSList.back()->dir_begin(DirPath, EC);
    475       FSList.pop_back();
    476       if (EC && EC != errc::no_such_file_or_directory)
    477         return EC;
    478       if (CurrentDirIter != directory_iterator())
    479         break; // found
    480     }
    481     return {};
    482   }
    483 
    484   std::error_code incrementDirIter(bool IsFirstTime) {
    485     assert((IsFirstTime || CurrentDirIter != directory_iterator()) &&
    486            "incrementing past end");
    487     std::error_code EC;
    488     if (!IsFirstTime)
    489       CurrentDirIter.increment(EC);
    490     if (!EC && CurrentDirIter == directory_iterator())
    491       EC = incrementFS();
    492     return EC;
    493   }
    494 
    495   std::error_code incrementImpl(bool IsFirstTime) {
    496     while (true) {
    497       std::error_code EC = incrementDirIter(IsFirstTime);
    498       if (EC || CurrentDirIter == directory_iterator()) {
    499         CurrentEntry = directory_entry();
    500         return EC;
    501       }
    502       CurrentEntry = *CurrentDirIter;
    503       StringRef Name = llvm::sys::path::filename(CurrentEntry.path());
    504       if (SeenNames.insert(Name).second)
    505         return EC; // name not seen before
    506     }
    507     llvm_unreachable("returned above");
    508   }
    509 
    510 public:
    511   CombiningDirIterImpl(ArrayRef<FileSystemPtr> FileSystems, std::string Dir,
    512                        std::error_code &EC)
    513       : FSList(FileSystems.begin(), FileSystems.end()),
    514         DirPath(std::move(Dir)) {
    515     if (!FSList.empty()) {
    516       CurrentDirIter = FSList.back()->dir_begin(DirPath, EC);
    517       FSList.pop_back();
    518       if (!EC || EC == errc::no_such_file_or_directory)
    519         EC = incrementImpl(true);
    520     }
    521   }
    522 
    523   CombiningDirIterImpl(directory_iterator FirstIter, FileSystemPtr Fallback,
    524                        std::string FallbackDir, std::error_code &EC)
    525       : FSList({Fallback}), CurrentDirIter(FirstIter),
    526         DirPath(std::move(FallbackDir)) {
    527     if (!EC || EC == errc::no_such_file_or_directory)
    528       EC = incrementImpl(true);
    529   }
    530 
    531   std::error_code increment() override { return incrementImpl(false); }
    532 };
    533 
    534 } // namespace
    535 
    536 directory_iterator OverlayFileSystem::dir_begin(const Twine &Dir,
    537                                                 std::error_code &EC) {
    538   return directory_iterator(
    539       std::make_shared<CombiningDirIterImpl>(FSList, Dir.str(), EC));
    540 }
    541 
    542 void ProxyFileSystem::anchor() {}
    543 
    544 namespace llvm {
    545 namespace vfs {
    546 
    547 namespace detail {
    548 
    549 enum InMemoryNodeKind { IME_File, IME_Directory, IME_HardLink };
    550 
    551 /// The in memory file system is a tree of Nodes. Every node can either be a
    552 /// file , hardlink or a directory.
    553 class InMemoryNode {
    554   InMemoryNodeKind Kind;
    555   std::string FileName;
    556 
    557 public:
    558   InMemoryNode(llvm::StringRef FileName, InMemoryNodeKind Kind)
    559       : Kind(Kind), FileName(std::string(llvm::sys::path::filename(FileName))) {
    560   }
    561   virtual ~InMemoryNode() = default;
    562 
    563   /// Get the filename of this node (the name without the directory part).
    564   StringRef getFileName() const { return FileName; }
    565   InMemoryNodeKind getKind() const { return Kind; }
    566   virtual std::string toString(unsigned Indent) const = 0;
    567 };
    568 
    569 class InMemoryFile : public InMemoryNode {
    570   Status Stat;
    571   std::unique_ptr<llvm::MemoryBuffer> Buffer;
    572 
    573 public:
    574   InMemoryFile(Status Stat, std::unique_ptr<llvm::MemoryBuffer> Buffer)
    575       : InMemoryNode(Stat.getName(), IME_File), Stat(std::move(Stat)),
    576         Buffer(std::move(Buffer)) {}
    577 
    578   /// Return the \p Status for this node. \p RequestedName should be the name
    579   /// through which the caller referred to this node. It will override
    580   /// \p Status::Name in the return value, to mimic the behavior of \p RealFile.
    581   Status getStatus(const Twine &RequestedName) const {
    582     return Status::copyWithNewName(Stat, RequestedName);
    583   }
    584   llvm::MemoryBuffer *getBuffer() const { return Buffer.get(); }
    585 
    586   std::string toString(unsigned Indent) const override {
    587     return (std::string(Indent, ' ') + Stat.getName() + "\n").str();
    588   }
    589 
    590   static bool classof(const InMemoryNode *N) {
    591     return N->getKind() == IME_File;
    592   }
    593 };
    594 
    595 namespace {
    596 
    597 class InMemoryHardLink : public InMemoryNode {
    598   const InMemoryFile &ResolvedFile;
    599 
    600 public:
    601   InMemoryHardLink(StringRef Path, const InMemoryFile &ResolvedFile)
    602       : InMemoryNode(Path, IME_HardLink), ResolvedFile(ResolvedFile) {}
    603   const InMemoryFile &getResolvedFile() const { return ResolvedFile; }
    604 
    605   std::string toString(unsigned Indent) const override {
    606     return std::string(Indent, ' ') + "HardLink to -> " +
    607            ResolvedFile.toString(0);
    608   }
    609 
    610   static bool classof(const InMemoryNode *N) {
    611     return N->getKind() == IME_HardLink;
    612   }
    613 };
    614 
    615 /// Adapt a InMemoryFile for VFS' File interface.  The goal is to make
    616 /// \p InMemoryFileAdaptor mimic as much as possible the behavior of
    617 /// \p RealFile.
    618 class InMemoryFileAdaptor : public File {
    619   const InMemoryFile &Node;
    620   /// The name to use when returning a Status for this file.
    621   std::string RequestedName;
    622 
    623 public:
    624   explicit InMemoryFileAdaptor(const InMemoryFile &Node,
    625                                std::string RequestedName)
    626       : Node(Node), RequestedName(std::move(RequestedName)) {}
    627 
    628   llvm::ErrorOr<Status> status() override {
    629     return Node.getStatus(RequestedName);
    630   }
    631 
    632   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
    633   getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
    634             bool IsVolatile) override {
    635     llvm::MemoryBuffer *Buf = Node.getBuffer();
    636     return llvm::MemoryBuffer::getMemBuffer(
    637         Buf->getBuffer(), Buf->getBufferIdentifier(), RequiresNullTerminator);
    638   }
    639 
    640   std::error_code close() override { return {}; }
    641 };
    642 } // namespace
    643 
    644 class InMemoryDirectory : public InMemoryNode {
    645   Status Stat;
    646   llvm::StringMap<std::unique_ptr<InMemoryNode>> Entries;
    647 
    648 public:
    649   InMemoryDirectory(Status Stat)
    650       : InMemoryNode(Stat.getName(), IME_Directory), Stat(std::move(Stat)) {}
    651 
    652   /// Return the \p Status for this node. \p RequestedName should be the name
    653   /// through which the caller referred to this node. It will override
    654   /// \p Status::Name in the return value, to mimic the behavior of \p RealFile.
    655   Status getStatus(const Twine &RequestedName) const {
    656     return Status::copyWithNewName(Stat, RequestedName);
    657   }
    658   InMemoryNode *getChild(StringRef Name) {
    659     auto I = Entries.find(Name);
    660     if (I != Entries.end())
    661       return I->second.get();
    662     return nullptr;
    663   }
    664 
    665   InMemoryNode *addChild(StringRef Name, std::unique_ptr<InMemoryNode> Child) {
    666     return Entries.insert(make_pair(Name, std::move(Child)))
    667         .first->second.get();
    668   }
    669 
    670   using const_iterator = decltype(Entries)::const_iterator;
    671 
    672   const_iterator begin() const { return Entries.begin(); }
    673   const_iterator end() const { return Entries.end(); }
    674 
    675   std::string toString(unsigned Indent) const override {
    676     std::string Result =
    677         (std::string(Indent, ' ') + Stat.getName() + "\n").str();
    678     for (const auto &Entry : Entries)
    679       Result += Entry.second->toString(Indent + 2);
    680     return Result;
    681   }
    682 
    683   static bool classof(const InMemoryNode *N) {
    684     return N->getKind() == IME_Directory;
    685   }
    686 };
    687 
    688 namespace {
    689 Status getNodeStatus(const InMemoryNode *Node, const Twine &RequestedName) {
    690   if (auto Dir = dyn_cast<detail::InMemoryDirectory>(Node))
    691     return Dir->getStatus(RequestedName);
    692   if (auto File = dyn_cast<detail::InMemoryFile>(Node))
    693     return File->getStatus(RequestedName);
    694   if (auto Link = dyn_cast<detail::InMemoryHardLink>(Node))
    695     return Link->getResolvedFile().getStatus(RequestedName);
    696   llvm_unreachable("Unknown node type");
    697 }
    698 } // namespace
    699 } // namespace detail
    700 
    701 InMemoryFileSystem::InMemoryFileSystem(bool UseNormalizedPaths)
    702     : Root(new detail::InMemoryDirectory(
    703           Status("", getNextVirtualUniqueID(), llvm::sys::TimePoint<>(), 0, 0,
    704                  0, llvm::sys::fs::file_type::directory_file,
    705                  llvm::sys::fs::perms::all_all))),
    706       UseNormalizedPaths(UseNormalizedPaths) {}
    707 
    708 InMemoryFileSystem::~InMemoryFileSystem() = default;
    709 
    710 std::string InMemoryFileSystem::toString() const {
    711   return Root->toString(/*Indent=*/0);
    712 }
    713 
    714 bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
    715                                  std::unique_ptr<llvm::MemoryBuffer> Buffer,
    716                                  Optional<uint32_t> User,
    717                                  Optional<uint32_t> Group,
    718                                  Optional<llvm::sys::fs::file_type> Type,
    719                                  Optional<llvm::sys::fs::perms> Perms,
    720                                  const detail::InMemoryFile *HardLinkTarget) {
    721   SmallString<128> Path;
    722   P.toVector(Path);
    723 
    724   // Fix up relative paths. This just prepends the current working directory.
    725   std::error_code EC = makeAbsolute(Path);
    726   assert(!EC);
    727   (void)EC;
    728 
    729   if (useNormalizedPaths())
    730     llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
    731 
    732   if (Path.empty())
    733     return false;
    734 
    735   detail::InMemoryDirectory *Dir = Root.get();
    736   auto I = llvm::sys::path::begin(Path), E = sys::path::end(Path);
    737   const auto ResolvedUser = User.getValueOr(0);
    738   const auto ResolvedGroup = Group.getValueOr(0);
    739   const auto ResolvedType = Type.getValueOr(sys::fs::file_type::regular_file);
    740   const auto ResolvedPerms = Perms.getValueOr(sys::fs::all_all);
    741   assert(!(HardLinkTarget && Buffer) && "HardLink cannot have a buffer");
    742   // Any intermediate directories we create should be accessible by
    743   // the owner, even if Perms says otherwise for the final path.
    744   const auto NewDirectoryPerms = ResolvedPerms | sys::fs::owner_all;
    745   while (true) {
    746     StringRef Name = *I;
    747     detail::InMemoryNode *Node = Dir->getChild(Name);
    748     ++I;
    749     if (!Node) {
    750       if (I == E) {
    751         // End of the path.
    752         std::unique_ptr<detail::InMemoryNode> Child;
    753         if (HardLinkTarget)
    754           Child.reset(new detail::InMemoryHardLink(P.str(), *HardLinkTarget));
    755         else {
    756           // Create a new file or directory.
    757           Status Stat(P.str(), getNextVirtualUniqueID(),
    758                       llvm::sys::toTimePoint(ModificationTime), ResolvedUser,
    759                       ResolvedGroup, Buffer->getBufferSize(), ResolvedType,
    760                       ResolvedPerms);
    761           if (ResolvedType == sys::fs::file_type::directory_file) {
    762             Child.reset(new detail::InMemoryDirectory(std::move(Stat)));
    763           } else {
    764             Child.reset(
    765                 new detail::InMemoryFile(std::move(Stat), std::move(Buffer)));
    766           }
    767         }
    768         Dir->addChild(Name, std::move(Child));
    769         return true;
    770       }
    771 
    772       // Create a new directory. Use the path up to here.
    773       Status Stat(
    774           StringRef(Path.str().begin(), Name.end() - Path.str().begin()),
    775           getNextVirtualUniqueID(), llvm::sys::toTimePoint(ModificationTime),
    776           ResolvedUser, ResolvedGroup, 0, sys::fs::file_type::directory_file,
    777           NewDirectoryPerms);
    778       Dir = cast<detail::InMemoryDirectory>(Dir->addChild(
    779           Name, std::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
    780       continue;
    781     }
    782 
    783     if (auto *NewDir = dyn_cast<detail::InMemoryDirectory>(Node)) {
    784       Dir = NewDir;
    785     } else {
    786       assert((isa<detail::InMemoryFile>(Node) ||
    787               isa<detail::InMemoryHardLink>(Node)) &&
    788              "Must be either file, hardlink or directory!");
    789 
    790       // Trying to insert a directory in place of a file.
    791       if (I != E)
    792         return false;
    793 
    794       // Return false only if the new file is different from the existing one.
    795       if (auto Link = dyn_cast<detail::InMemoryHardLink>(Node)) {
    796         return Link->getResolvedFile().getBuffer()->getBuffer() ==
    797                Buffer->getBuffer();
    798       }
    799       return cast<detail::InMemoryFile>(Node)->getBuffer()->getBuffer() ==
    800              Buffer->getBuffer();
    801     }
    802   }
    803 }
    804 
    805 bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
    806                                  std::unique_ptr<llvm::MemoryBuffer> Buffer,
    807                                  Optional<uint32_t> User,
    808                                  Optional<uint32_t> Group,
    809                                  Optional<llvm::sys::fs::file_type> Type,
    810                                  Optional<llvm::sys::fs::perms> Perms) {
    811   return addFile(P, ModificationTime, std::move(Buffer), User, Group, Type,
    812                  Perms, /*HardLinkTarget=*/nullptr);
    813 }
    814 
    815 bool InMemoryFileSystem::addFileNoOwn(const Twine &P, time_t ModificationTime,
    816                                       const llvm::MemoryBufferRef &Buffer,
    817                                       Optional<uint32_t> User,
    818                                       Optional<uint32_t> Group,
    819                                       Optional<llvm::sys::fs::file_type> Type,
    820                                       Optional<llvm::sys::fs::perms> Perms) {
    821   return addFile(P, ModificationTime, llvm::MemoryBuffer::getMemBuffer(Buffer),
    822                  std::move(User), std::move(Group), std::move(Type),
    823                  std::move(Perms));
    824 }
    825 
    826 static ErrorOr<const detail::InMemoryNode *>
    827 lookupInMemoryNode(const InMemoryFileSystem &FS, detail::InMemoryDirectory *Dir,
    828                    const Twine &P) {
    829   SmallString<128> Path;
    830   P.toVector(Path);
    831 
    832   // Fix up relative paths. This just prepends the current working directory.
    833   std::error_code EC = FS.makeAbsolute(Path);
    834   assert(!EC);
    835   (void)EC;
    836 
    837   if (FS.useNormalizedPaths())
    838     llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
    839 
    840   if (Path.empty())
    841     return Dir;
    842 
    843   auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path);
    844   while (true) {
    845     detail::InMemoryNode *Node = Dir->getChild(*I);
    846     ++I;
    847     if (!Node)
    848       return errc::no_such_file_or_directory;
    849 
    850     // Return the file if it's at the end of the path.
    851     if (auto File = dyn_cast<detail::InMemoryFile>(Node)) {
    852       if (I == E)
    853         return File;
    854       return errc::no_such_file_or_directory;
    855     }
    856 
    857     // If Node is HardLink then return the resolved file.
    858     if (auto File = dyn_cast<detail::InMemoryHardLink>(Node)) {
    859       if (I == E)
    860         return &File->getResolvedFile();
    861       return errc::no_such_file_or_directory;
    862     }
    863     // Traverse directories.
    864     Dir = cast<detail::InMemoryDirectory>(Node);
    865     if (I == E)
    866       return Dir;
    867   }
    868 }
    869 
    870 bool InMemoryFileSystem::addHardLink(const Twine &FromPath,
    871                                      const Twine &ToPath) {
    872   auto FromNode = lookupInMemoryNode(*this, Root.get(), FromPath);
    873   auto ToNode = lookupInMemoryNode(*this, Root.get(), ToPath);
    874   // FromPath must not have been added before. ToPath must have been added
    875   // before. Resolved ToPath must be a File.
    876   if (!ToNode || FromNode || !isa<detail::InMemoryFile>(*ToNode))
    877     return false;
    878   return this->addFile(FromPath, 0, nullptr, None, None, None, None,
    879                        cast<detail::InMemoryFile>(*ToNode));
    880 }
    881 
    882 llvm::ErrorOr<Status> InMemoryFileSystem::status(const Twine &Path) {
    883   auto Node = lookupInMemoryNode(*this, Root.get(), Path);
    884   if (Node)
    885     return detail::getNodeStatus(*Node, Path);
    886   return Node.getError();
    887 }
    888 
    889 llvm::ErrorOr<std::unique_ptr<File>>
    890 InMemoryFileSystem::openFileForRead(const Twine &Path) {
    891   auto Node = lookupInMemoryNode(*this, Root.get(), Path);
    892   if (!Node)
    893     return Node.getError();
    894 
    895   // When we have a file provide a heap-allocated wrapper for the memory buffer
    896   // to match the ownership semantics for File.
    897   if (auto *F = dyn_cast<detail::InMemoryFile>(*Node))
    898     return std::unique_ptr<File>(
    899         new detail::InMemoryFileAdaptor(*F, Path.str()));
    900 
    901   // FIXME: errc::not_a_file?
    902   return make_error_code(llvm::errc::invalid_argument);
    903 }
    904 
    905 namespace {
    906 
    907 /// Adaptor from InMemoryDir::iterator to directory_iterator.
    908 class InMemoryDirIterator : public llvm::vfs::detail::DirIterImpl {
    909   detail::InMemoryDirectory::const_iterator I;
    910   detail::InMemoryDirectory::const_iterator E;
    911   std::string RequestedDirName;
    912 
    913   void setCurrentEntry() {
    914     if (I != E) {
    915       SmallString<256> Path(RequestedDirName);
    916       llvm::sys::path::append(Path, I->second->getFileName());
    917       sys::fs::file_type Type = sys::fs::file_type::type_unknown;
    918       switch (I->second->getKind()) {
    919       case detail::IME_File:
    920       case detail::IME_HardLink:
    921         Type = sys::fs::file_type::regular_file;
    922         break;
    923       case detail::IME_Directory:
    924         Type = sys::fs::file_type::directory_file;
    925         break;
    926       }
    927       CurrentEntry = directory_entry(std::string(Path.str()), Type);
    928     } else {
    929       // When we're at the end, make CurrentEntry invalid and DirIterImpl will
    930       // do the rest.
    931       CurrentEntry = directory_entry();
    932     }
    933   }
    934 
    935 public:
    936   InMemoryDirIterator() = default;
    937 
    938   explicit InMemoryDirIterator(const detail::InMemoryDirectory &Dir,
    939                                std::string RequestedDirName)
    940       : I(Dir.begin()), E(Dir.end()),
    941         RequestedDirName(std::move(RequestedDirName)) {
    942     setCurrentEntry();
    943   }
    944 
    945   std::error_code increment() override {
    946     ++I;
    947     setCurrentEntry();
    948     return {};
    949   }
    950 };
    951 
    952 } // namespace
    953 
    954 directory_iterator InMemoryFileSystem::dir_begin(const Twine &Dir,
    955                                                  std::error_code &EC) {
    956   auto Node = lookupInMemoryNode(*this, Root.get(), Dir);
    957   if (!Node) {
    958     EC = Node.getError();
    959     return directory_iterator(std::make_shared<InMemoryDirIterator>());
    960   }
    961 
    962   if (auto *DirNode = dyn_cast<detail::InMemoryDirectory>(*Node))
    963     return directory_iterator(
    964         std::make_shared<InMemoryDirIterator>(*DirNode, Dir.str()));
    965 
    966   EC = make_error_code(llvm::errc::not_a_directory);
    967   return directory_iterator(std::make_shared<InMemoryDirIterator>());
    968 }
    969 
    970 std::error_code InMemoryFileSystem::setCurrentWorkingDirectory(const Twine &P) {
    971   SmallString<128> Path;
    972   P.toVector(Path);
    973 
    974   // Fix up relative paths. This just prepends the current working directory.
    975   std::error_code EC = makeAbsolute(Path);
    976   assert(!EC);
    977   (void)EC;
    978 
    979   if (useNormalizedPaths())
    980     llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
    981 
    982   if (!Path.empty())
    983     WorkingDirectory = std::string(Path.str());
    984   return {};
    985 }
    986 
    987 std::error_code
    988 InMemoryFileSystem::getRealPath(const Twine &Path,
    989                                 SmallVectorImpl<char> &Output) const {
    990   auto CWD = getCurrentWorkingDirectory();
    991   if (!CWD || CWD->empty())
    992     return errc::operation_not_permitted;
    993   Path.toVector(Output);
    994   if (auto EC = makeAbsolute(Output))
    995     return EC;
    996   llvm::sys::path::remove_dots(Output, /*remove_dot_dot=*/true);
    997   return {};
    998 }
    999 
   1000 std::error_code InMemoryFileSystem::isLocal(const Twine &Path, bool &Result) {
   1001   Result = false;
   1002   return {};
   1003 }
   1004 
   1005 } // namespace vfs
   1006 } // namespace llvm
   1007 
   1008 //===-----------------------------------------------------------------------===/
   1009 // RedirectingFileSystem implementation
   1010 //===-----------------------------------------------------------------------===/
   1011 
   1012 namespace {
   1013 
   1014 static llvm::sys::path::Style getExistingStyle(llvm::StringRef Path) {
   1015   // Detect the path style in use by checking the first separator.
   1016   llvm::sys::path::Style style = llvm::sys::path::Style::native;
   1017   const size_t n = Path.find_first_of("/\\");
   1018   if (n != static_cast<size_t>(-1))
   1019     style = (Path[n] == '/') ? llvm::sys::path::Style::posix
   1020                              : llvm::sys::path::Style::windows;
   1021   return style;
   1022 }
   1023 
   1024 /// Removes leading "./" as well as path components like ".." and ".".
   1025 static llvm::SmallString<256> canonicalize(llvm::StringRef Path) {
   1026   // First detect the path style in use by checking the first separator.
   1027   llvm::sys::path::Style style = getExistingStyle(Path);
   1028 
   1029   // Now remove the dots.  Explicitly specifying the path style prevents the
   1030   // direction of the slashes from changing.
   1031   llvm::SmallString<256> result =
   1032       llvm::sys::path::remove_leading_dotslash(Path, style);
   1033   llvm::sys::path::remove_dots(result, /*remove_dot_dot=*/true, style);
   1034   return result;
   1035 }
   1036 
   1037 } // anonymous namespace
   1038 
   1039 
   1040 RedirectingFileSystem::RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> FS)
   1041     : ExternalFS(std::move(FS)) {
   1042   if (ExternalFS)
   1043     if (auto ExternalWorkingDirectory =
   1044             ExternalFS->getCurrentWorkingDirectory()) {
   1045       WorkingDirectory = *ExternalWorkingDirectory;
   1046     }
   1047 }
   1048 
   1049 /// Directory iterator implementation for \c RedirectingFileSystem's
   1050 /// directory entries.
   1051 class llvm::vfs::RedirectingFSDirIterImpl
   1052     : public llvm::vfs::detail::DirIterImpl {
   1053   std::string Dir;
   1054   RedirectingFileSystem::DirectoryEntry::iterator Current, End;
   1055 
   1056   std::error_code incrementImpl(bool IsFirstTime) {
   1057     assert((IsFirstTime || Current != End) && "cannot iterate past end");
   1058     if (!IsFirstTime)
   1059       ++Current;
   1060     if (Current != End) {
   1061       SmallString<128> PathStr(Dir);
   1062       llvm::sys::path::append(PathStr, (*Current)->getName());
   1063       sys::fs::file_type Type = sys::fs::file_type::type_unknown;
   1064       switch ((*Current)->getKind()) {
   1065       case RedirectingFileSystem::EK_Directory:
   1066         LLVM_FALLTHROUGH;
   1067       case RedirectingFileSystem::EK_DirectoryRemap:
   1068         Type = sys::fs::file_type::directory_file;
   1069         break;
   1070       case RedirectingFileSystem::EK_File:
   1071         Type = sys::fs::file_type::regular_file;
   1072         break;
   1073       }
   1074       CurrentEntry = directory_entry(std::string(PathStr.str()), Type);
   1075     } else {
   1076       CurrentEntry = directory_entry();
   1077     }
   1078     return {};
   1079   };
   1080 
   1081 public:
   1082   RedirectingFSDirIterImpl(
   1083       const Twine &Path, RedirectingFileSystem::DirectoryEntry::iterator Begin,
   1084       RedirectingFileSystem::DirectoryEntry::iterator End, std::error_code &EC)
   1085       : Dir(Path.str()), Current(Begin), End(End) {
   1086     EC = incrementImpl(/*IsFirstTime=*/true);
   1087   }
   1088 
   1089   std::error_code increment() override {
   1090     return incrementImpl(/*IsFirstTime=*/false);
   1091   }
   1092 };
   1093 
   1094 /// Directory iterator implementation for \c RedirectingFileSystem's
   1095 /// directory remap entries that maps the paths reported by the external
   1096 /// file system's directory iterator back to the virtual directory's path.
   1097 class RedirectingFSDirRemapIterImpl : public llvm::vfs::detail::DirIterImpl {
   1098   std::string Dir;
   1099   llvm::sys::path::Style DirStyle;
   1100   llvm::vfs::directory_iterator ExternalIter;
   1101 
   1102 public:
   1103   RedirectingFSDirRemapIterImpl(std::string DirPath,
   1104                                 llvm::vfs::directory_iterator ExtIter)
   1105       : Dir(std::move(DirPath)), DirStyle(getExistingStyle(Dir)),
   1106         ExternalIter(ExtIter) {
   1107     if (ExternalIter != llvm::vfs::directory_iterator())
   1108       setCurrentEntry();
   1109   }
   1110 
   1111   void setCurrentEntry() {
   1112     StringRef ExternalPath = ExternalIter->path();
   1113     llvm::sys::path::Style ExternalStyle = getExistingStyle(ExternalPath);
   1114     StringRef File = llvm::sys::path::filename(ExternalPath, ExternalStyle);
   1115 
   1116     SmallString<128> NewPath(Dir);
   1117     llvm::sys::path::append(NewPath, DirStyle, File);
   1118 
   1119     CurrentEntry = directory_entry(std::string(NewPath), ExternalIter->type());
   1120   }
   1121 
   1122   std::error_code increment() override {
   1123     std::error_code EC;
   1124     ExternalIter.increment(EC);
   1125     if (!EC && ExternalIter != llvm::vfs::directory_iterator())
   1126       setCurrentEntry();
   1127     else
   1128       CurrentEntry = directory_entry();
   1129     return EC;
   1130   }
   1131 };
   1132 
   1133 llvm::ErrorOr<std::string>
   1134 RedirectingFileSystem::getCurrentWorkingDirectory() const {
   1135   return WorkingDirectory;
   1136 }
   1137 
   1138 std::error_code
   1139 RedirectingFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
   1140   // Don't change the working directory if the path doesn't exist.
   1141   if (!exists(Path))
   1142     return errc::no_such_file_or_directory;
   1143 
   1144   SmallString<128> AbsolutePath;
   1145   Path.toVector(AbsolutePath);
   1146   if (std::error_code EC = makeAbsolute(AbsolutePath))
   1147     return EC;
   1148   WorkingDirectory = std::string(AbsolutePath.str());
   1149   return {};
   1150 }
   1151 
   1152 std::error_code RedirectingFileSystem::isLocal(const Twine &Path_,
   1153                                                bool &Result) {
   1154   SmallString<256> Path;
   1155   Path_.toVector(Path);
   1156 
   1157   if (std::error_code EC = makeCanonical(Path))
   1158     return {};
   1159 
   1160   return ExternalFS->isLocal(Path, Result);
   1161 }
   1162 
   1163 std::error_code RedirectingFileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const {
   1164   if (llvm::sys::path::is_absolute(Path, llvm::sys::path::Style::posix) ||
   1165       llvm::sys::path::is_absolute(Path, llvm::sys::path::Style::windows))
   1166     return {};
   1167 
   1168   auto WorkingDir = getCurrentWorkingDirectory();
   1169   if (!WorkingDir)
   1170     return WorkingDir.getError();
   1171 
   1172   // We can't use sys::fs::make_absolute because that assumes the path style
   1173   // is native and there is no way to override that.  Since we know WorkingDir
   1174   // is absolute, we can use it to determine which style we actually have and
   1175   // append Path ourselves.
   1176   sys::path::Style style = sys::path::Style::windows;
   1177   if (sys::path::is_absolute(WorkingDir.get(), sys::path::Style::posix)) {
   1178     style = sys::path::Style::posix;
   1179   }
   1180 
   1181   std::string Result = WorkingDir.get();
   1182   StringRef Dir(Result);
   1183   if (!Dir.endswith(sys::path::get_separator(style))) {
   1184     Result += sys::path::get_separator(style);
   1185   }
   1186   Result.append(Path.data(), Path.size());
   1187   Path.assign(Result.begin(), Result.end());
   1188 
   1189   return {};
   1190 }
   1191 
   1192 directory_iterator RedirectingFileSystem::dir_begin(const Twine &Dir,
   1193                                                     std::error_code &EC) {
   1194   SmallString<256> Path;
   1195   Dir.toVector(Path);
   1196 
   1197   EC = makeCanonical(Path);
   1198   if (EC)
   1199     return {};
   1200 
   1201   ErrorOr<RedirectingFileSystem::LookupResult> Result = lookupPath(Path);
   1202   if (!Result) {
   1203     EC = Result.getError();
   1204     if (shouldFallBackToExternalFS(EC))
   1205       return ExternalFS->dir_begin(Path, EC);
   1206     return {};
   1207   }
   1208 
   1209   // Use status to make sure the path exists and refers to a directory.
   1210   ErrorOr<Status> S = status(Path, *Result);
   1211   if (!S) {
   1212     if (shouldFallBackToExternalFS(S.getError(), Result->E))
   1213       return ExternalFS->dir_begin(Dir, EC);
   1214     EC = S.getError();
   1215     return {};
   1216   }
   1217   if (!S->isDirectory()) {
   1218     EC = std::error_code(static_cast<int>(errc::not_a_directory),
   1219                          std::system_category());
   1220     return {};
   1221   }
   1222 
   1223   // Create the appropriate directory iterator based on whether we found a
   1224   // DirectoryRemapEntry or DirectoryEntry.
   1225   directory_iterator DirIter;
   1226   if (auto ExtRedirect = Result->getExternalRedirect()) {
   1227     auto RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
   1228     DirIter = ExternalFS->dir_begin(*ExtRedirect, EC);
   1229 
   1230     if (!RE->useExternalName(UseExternalNames)) {
   1231       // Update the paths in the results to use the virtual directory's path.
   1232       DirIter =
   1233           directory_iterator(std::make_shared<RedirectingFSDirRemapIterImpl>(
   1234               std::string(Path), DirIter));
   1235     }
   1236   } else {
   1237     auto DE = cast<DirectoryEntry>(Result->E);
   1238     DirIter = directory_iterator(std::make_shared<RedirectingFSDirIterImpl>(
   1239         Path, DE->contents_begin(), DE->contents_end(), EC));
   1240   }
   1241 
   1242   if (!shouldUseExternalFS())
   1243     return DirIter;
   1244   return directory_iterator(std::make_shared<CombiningDirIterImpl>(
   1245       DirIter, ExternalFS, std::string(Path), EC));
   1246 }
   1247 
   1248 void RedirectingFileSystem::setExternalContentsPrefixDir(StringRef PrefixDir) {
   1249   ExternalContentsPrefixDir = PrefixDir.str();
   1250 }
   1251 
   1252 StringRef RedirectingFileSystem::getExternalContentsPrefixDir() const {
   1253   return ExternalContentsPrefixDir;
   1254 }
   1255 
   1256 void RedirectingFileSystem::setFallthrough(bool Fallthrough) {
   1257   IsFallthrough = Fallthrough;
   1258 }
   1259 
   1260 std::vector<StringRef> RedirectingFileSystem::getRoots() const {
   1261   std::vector<StringRef> R;
   1262   for (const auto &Root : Roots)
   1263     R.push_back(Root->getName());
   1264   return R;
   1265 }
   1266 
   1267 void RedirectingFileSystem::dump(raw_ostream &OS) const {
   1268   for (const auto &Root : Roots)
   1269     dumpEntry(OS, Root.get());
   1270 }
   1271 
   1272 void RedirectingFileSystem::dumpEntry(raw_ostream &OS,
   1273                                       RedirectingFileSystem::Entry *E,
   1274                                       int NumSpaces) const {
   1275   StringRef Name = E->getName();
   1276   for (int i = 0, e = NumSpaces; i < e; ++i)
   1277     OS << " ";
   1278   OS << "'" << Name.str().c_str() << "'"
   1279      << "\n";
   1280 
   1281   if (E->getKind() == RedirectingFileSystem::EK_Directory) {
   1282     auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(E);
   1283     assert(DE && "Should be a directory");
   1284 
   1285     for (std::unique_ptr<Entry> &SubEntry :
   1286          llvm::make_range(DE->contents_begin(), DE->contents_end()))
   1287       dumpEntry(OS, SubEntry.get(), NumSpaces + 2);
   1288   }
   1289 }
   1290 
   1291 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
   1292 LLVM_DUMP_METHOD void RedirectingFileSystem::dump() const { dump(dbgs()); }
   1293 #endif
   1294 
   1295 /// A helper class to hold the common YAML parsing state.
   1296 class llvm::vfs::RedirectingFileSystemParser {
   1297   yaml::Stream &Stream;
   1298 
   1299   void error(yaml::Node *N, const Twine &Msg) { Stream.printError(N, Msg); }
   1300 
   1301   // false on error
   1302   bool parseScalarString(yaml::Node *N, StringRef &Result,
   1303                          SmallVectorImpl<char> &Storage) {
   1304     const auto *S = dyn_cast<yaml::ScalarNode>(N);
   1305 
   1306     if (!S) {
   1307       error(N, "expected string");
   1308       return false;
   1309     }
   1310     Result = S->getValue(Storage);
   1311     return true;
   1312   }
   1313 
   1314   // false on error
   1315   bool parseScalarBool(yaml::Node *N, bool &Result) {
   1316     SmallString<5> Storage;
   1317     StringRef Value;
   1318     if (!parseScalarString(N, Value, Storage))
   1319       return false;
   1320 
   1321     if (Value.equals_lower("true") || Value.equals_lower("on") ||
   1322         Value.equals_lower("yes") || Value == "1") {
   1323       Result = true;
   1324       return true;
   1325     } else if (Value.equals_lower("false") || Value.equals_lower("off") ||
   1326                Value.equals_lower("no") || Value == "0") {
   1327       Result = false;
   1328       return true;
   1329     }
   1330 
   1331     error(N, "expected boolean value");
   1332     return false;
   1333   }
   1334 
   1335   struct KeyStatus {
   1336     bool Required;
   1337     bool Seen = false;
   1338 
   1339     KeyStatus(bool Required = false) : Required(Required) {}
   1340   };
   1341 
   1342   using KeyStatusPair = std::pair<StringRef, KeyStatus>;
   1343 
   1344   // false on error
   1345   bool checkDuplicateOrUnknownKey(yaml::Node *KeyNode, StringRef Key,
   1346                                   DenseMap<StringRef, KeyStatus> &Keys) {
   1347     if (!Keys.count(Key)) {
   1348       error(KeyNode, "unknown key");
   1349       return false;
   1350     }
   1351     KeyStatus &S = Keys[Key];
   1352     if (S.Seen) {
   1353       error(KeyNode, Twine("duplicate key '") + Key + "'");
   1354       return false;
   1355     }
   1356     S.Seen = true;
   1357     return true;
   1358   }
   1359 
   1360   // false on error
   1361   bool checkMissingKeys(yaml::Node *Obj, DenseMap<StringRef, KeyStatus> &Keys) {
   1362     for (const auto &I : Keys) {
   1363       if (I.second.Required && !I.second.Seen) {
   1364         error(Obj, Twine("missing key '") + I.first + "'");
   1365         return false;
   1366       }
   1367     }
   1368     return true;
   1369   }
   1370 
   1371 public:
   1372   static RedirectingFileSystem::Entry *
   1373   lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name,
   1374                       RedirectingFileSystem::Entry *ParentEntry = nullptr) {
   1375     if (!ParentEntry) { // Look for a existent root
   1376       for (const auto &Root : FS->Roots) {
   1377         if (Name.equals(Root->getName())) {
   1378           ParentEntry = Root.get();
   1379           return ParentEntry;
   1380         }
   1381       }
   1382     } else { // Advance to the next component
   1383       auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
   1384       for (std::unique_ptr<RedirectingFileSystem::Entry> &Content :
   1385            llvm::make_range(DE->contents_begin(), DE->contents_end())) {
   1386         auto *DirContent =
   1387             dyn_cast<RedirectingFileSystem::DirectoryEntry>(Content.get());
   1388         if (DirContent && Name.equals(Content->getName()))
   1389           return DirContent;
   1390       }
   1391     }
   1392 
   1393     // ... or create a new one
   1394     std::unique_ptr<RedirectingFileSystem::Entry> E =
   1395         std::make_unique<RedirectingFileSystem::DirectoryEntry>(
   1396             Name, Status("", getNextVirtualUniqueID(),
   1397                          std::chrono::system_clock::now(), 0, 0, 0,
   1398                          file_type::directory_file, sys::fs::all_all));
   1399 
   1400     if (!ParentEntry) { // Add a new root to the overlay
   1401       FS->Roots.push_back(std::move(E));
   1402       ParentEntry = FS->Roots.back().get();
   1403       return ParentEntry;
   1404     }
   1405 
   1406     auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
   1407     DE->addContent(std::move(E));
   1408     return DE->getLastContent();
   1409   }
   1410 
   1411 private:
   1412   void uniqueOverlayTree(RedirectingFileSystem *FS,
   1413                          RedirectingFileSystem::Entry *SrcE,
   1414                          RedirectingFileSystem::Entry *NewParentE = nullptr) {
   1415     StringRef Name = SrcE->getName();
   1416     switch (SrcE->getKind()) {
   1417     case RedirectingFileSystem::EK_Directory: {
   1418       auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
   1419       // Empty directories could be present in the YAML as a way to
   1420       // describe a file for a current directory after some of its subdir
   1421       // is parsed. This only leads to redundant walks, ignore it.
   1422       if (!Name.empty())
   1423         NewParentE = lookupOrCreateEntry(FS, Name, NewParentE);
   1424       for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
   1425            llvm::make_range(DE->contents_begin(), DE->contents_end()))
   1426         uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
   1427       break;
   1428     }
   1429     case RedirectingFileSystem::EK_DirectoryRemap: {
   1430       assert(NewParentE && "Parent entry must exist");
   1431       auto *DR = cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
   1432       auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
   1433       DE->addContent(
   1434           std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
   1435               Name, DR->getExternalContentsPath(), DR->getUseName()));
   1436       break;
   1437     }
   1438     case RedirectingFileSystem::EK_File: {
   1439       assert(NewParentE && "Parent entry must exist");
   1440       auto *FE = cast<RedirectingFileSystem::FileEntry>(SrcE);
   1441       auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
   1442       DE->addContent(std::make_unique<RedirectingFileSystem::FileEntry>(
   1443           Name, FE->getExternalContentsPath(), FE->getUseName()));
   1444       break;
   1445     }
   1446     }
   1447   }
   1448 
   1449   std::unique_ptr<RedirectingFileSystem::Entry>
   1450   parseEntry(yaml::Node *N, RedirectingFileSystem *FS, bool IsRootEntry) {
   1451     auto *M = dyn_cast<yaml::MappingNode>(N);
   1452     if (!M) {
   1453       error(N, "expected mapping node for file or directory entry");
   1454       return nullptr;
   1455     }
   1456 
   1457     KeyStatusPair Fields[] = {
   1458         KeyStatusPair("name", true),
   1459         KeyStatusPair("type", true),
   1460         KeyStatusPair("contents", false),
   1461         KeyStatusPair("external-contents", false),
   1462         KeyStatusPair("use-external-name", false),
   1463     };
   1464 
   1465     DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
   1466 
   1467     enum { CF_NotSet, CF_List, CF_External } ContentsField = CF_NotSet;
   1468     std::vector<std::unique_ptr<RedirectingFileSystem::Entry>>
   1469         EntryArrayContents;
   1470     SmallString<256> ExternalContentsPath;
   1471     SmallString<256> Name;
   1472     yaml::Node *NameValueNode = nullptr;
   1473     auto UseExternalName = RedirectingFileSystem::NK_NotSet;
   1474     RedirectingFileSystem::EntryKind Kind;
   1475 
   1476     for (auto &I : *M) {
   1477       StringRef Key;
   1478       // Reuse the buffer for key and value, since we don't look at key after
   1479       // parsing value.
   1480       SmallString<256> Buffer;
   1481       if (!parseScalarString(I.getKey(), Key, Buffer))
   1482         return nullptr;
   1483 
   1484       if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys))
   1485         return nullptr;
   1486 
   1487       StringRef Value;
   1488       if (Key == "name") {
   1489         if (!parseScalarString(I.getValue(), Value, Buffer))
   1490           return nullptr;
   1491 
   1492         NameValueNode = I.getValue();
   1493         // Guarantee that old YAML files containing paths with ".." and "."
   1494         // are properly canonicalized before read into the VFS.
   1495         Name = canonicalize(Value).str();
   1496       } else if (Key == "type") {
   1497         if (!parseScalarString(I.getValue(), Value, Buffer))
   1498           return nullptr;
   1499         if (Value == "file")
   1500           Kind = RedirectingFileSystem::EK_File;
   1501         else if (Value == "directory")
   1502           Kind = RedirectingFileSystem::EK_Directory;
   1503         else if (Value == "directory-remap")
   1504           Kind = RedirectingFileSystem::EK_DirectoryRemap;
   1505         else {
   1506           error(I.getValue(), "unknown value for 'type'");
   1507           return nullptr;
   1508         }
   1509       } else if (Key == "contents") {
   1510         if (ContentsField != CF_NotSet) {
   1511           error(I.getKey(),
   1512                 "entry already has 'contents' or 'external-contents'");
   1513           return nullptr;
   1514         }
   1515         ContentsField = CF_List;
   1516         auto *Contents = dyn_cast<yaml::SequenceNode>(I.getValue());
   1517         if (!Contents) {
   1518           // FIXME: this is only for directories, what about files?
   1519           error(I.getValue(), "expected array");
   1520           return nullptr;
   1521         }
   1522 
   1523         for (auto &I : *Contents) {
   1524           if (std::unique_ptr<RedirectingFileSystem::Entry> E =
   1525                   parseEntry(&I, FS, /*IsRootEntry*/ false))
   1526             EntryArrayContents.push_back(std::move(E));
   1527           else
   1528             return nullptr;
   1529         }
   1530       } else if (Key == "external-contents") {
   1531         if (ContentsField != CF_NotSet) {
   1532           error(I.getKey(),
   1533                 "entry already has 'contents' or 'external-contents'");
   1534           return nullptr;
   1535         }
   1536         ContentsField = CF_External;
   1537         if (!parseScalarString(I.getValue(), Value, Buffer))
   1538           return nullptr;
   1539 
   1540         SmallString<256> FullPath;
   1541         if (FS->IsRelativeOverlay) {
   1542           FullPath = FS->getExternalContentsPrefixDir();
   1543           assert(!FullPath.empty() &&
   1544                  "External contents prefix directory must exist");
   1545           llvm::sys::path::append(FullPath, Value);
   1546         } else {
   1547           FullPath = Value;
   1548         }
   1549 
   1550         // Guarantee that old YAML files containing paths with ".." and "."
   1551         // are properly canonicalized before read into the VFS.
   1552         FullPath = canonicalize(FullPath);
   1553         ExternalContentsPath = FullPath.str();
   1554       } else if (Key == "use-external-name") {
   1555         bool Val;
   1556         if (!parseScalarBool(I.getValue(), Val))
   1557           return nullptr;
   1558         UseExternalName = Val ? RedirectingFileSystem::NK_External
   1559                               : RedirectingFileSystem::NK_Virtual;
   1560       } else {
   1561         llvm_unreachable("key missing from Keys");
   1562       }
   1563     }
   1564 
   1565     if (Stream.failed())
   1566       return nullptr;
   1567 
   1568     // check for missing keys
   1569     if (ContentsField == CF_NotSet) {
   1570       error(N, "missing key 'contents' or 'external-contents'");
   1571       return nullptr;
   1572     }
   1573     if (!checkMissingKeys(N, Keys))
   1574       return nullptr;
   1575 
   1576     // check invalid configuration
   1577     if (Kind == RedirectingFileSystem::EK_Directory &&
   1578         UseExternalName != RedirectingFileSystem::NK_NotSet) {
   1579       error(N, "'use-external-name' is not supported for 'directory' entries");
   1580       return nullptr;
   1581     }
   1582 
   1583     if (Kind == RedirectingFileSystem::EK_DirectoryRemap &&
   1584         ContentsField == CF_List) {
   1585       error(N, "'contents' is not supported for 'directory-remap' entries");
   1586       return nullptr;
   1587     }
   1588 
   1589     sys::path::Style path_style = sys::path::Style::native;
   1590     if (IsRootEntry) {
   1591       // VFS root entries may be in either Posix or Windows style.  Figure out
   1592       // which style we have, and use it consistently.
   1593       if (sys::path::is_absolute(Name, sys::path::Style::posix)) {
   1594         path_style = sys::path::Style::posix;
   1595       } else if (sys::path::is_absolute(Name, sys::path::Style::windows)) {
   1596         path_style = sys::path::Style::windows;
   1597       } else {
   1598         assert(NameValueNode && "Name presence should be checked earlier");
   1599         error(NameValueNode,
   1600               "entry with relative path at the root level is not discoverable");
   1601         return nullptr;
   1602       }
   1603     }
   1604 
   1605     // Remove trailing slash(es), being careful not to remove the root path
   1606     StringRef Trimmed(Name);
   1607     size_t RootPathLen = sys::path::root_path(Trimmed, path_style).size();
   1608     while (Trimmed.size() > RootPathLen &&
   1609            sys::path::is_separator(Trimmed.back(), path_style))
   1610       Trimmed = Trimmed.slice(0, Trimmed.size() - 1);
   1611 
   1612     // Get the last component
   1613     StringRef LastComponent = sys::path::filename(Trimmed, path_style);
   1614 
   1615     std::unique_ptr<RedirectingFileSystem::Entry> Result;
   1616     switch (Kind) {
   1617     case RedirectingFileSystem::EK_File:
   1618       Result = std::make_unique<RedirectingFileSystem::FileEntry>(
   1619           LastComponent, std::move(ExternalContentsPath), UseExternalName);
   1620       break;
   1621     case RedirectingFileSystem::EK_DirectoryRemap:
   1622       Result = std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
   1623           LastComponent, std::move(ExternalContentsPath), UseExternalName);
   1624       break;
   1625     case RedirectingFileSystem::EK_Directory:
   1626       Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
   1627           LastComponent, std::move(EntryArrayContents),
   1628           Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(),
   1629                  0, 0, 0, file_type::directory_file, sys::fs::all_all));
   1630       break;
   1631     }
   1632 
   1633     StringRef Parent = sys::path::parent_path(Trimmed, path_style);
   1634     if (Parent.empty())
   1635       return Result;
   1636 
   1637     // if 'name' contains multiple components, create implicit directory entries
   1638     for (sys::path::reverse_iterator I = sys::path::rbegin(Parent, path_style),
   1639                                      E = sys::path::rend(Parent);
   1640          I != E; ++I) {
   1641       std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> Entries;
   1642       Entries.push_back(std::move(Result));
   1643       Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
   1644           *I, std::move(Entries),
   1645           Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(),
   1646                  0, 0, 0, file_type::directory_file, sys::fs::all_all));
   1647     }
   1648     return Result;
   1649   }
   1650 
   1651 public:
   1652   RedirectingFileSystemParser(yaml::Stream &S) : Stream(S) {}
   1653 
   1654   // false on error
   1655   bool parse(yaml::Node *Root, RedirectingFileSystem *FS) {
   1656     auto *Top = dyn_cast<yaml::MappingNode>(Root);
   1657     if (!Top) {
   1658       error(Root, "expected mapping node");
   1659       return false;
   1660     }
   1661 
   1662     KeyStatusPair Fields[] = {
   1663         KeyStatusPair("version", true),
   1664         KeyStatusPair("case-sensitive", false),
   1665         KeyStatusPair("use-external-names", false),
   1666         KeyStatusPair("overlay-relative", false),
   1667         KeyStatusPair("fallthrough", false),
   1668         KeyStatusPair("roots", true),
   1669     };
   1670 
   1671     DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
   1672     std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> RootEntries;
   1673 
   1674     // Parse configuration and 'roots'
   1675     for (auto &I : *Top) {
   1676       SmallString<10> KeyBuffer;
   1677       StringRef Key;
   1678       if (!parseScalarString(I.getKey(), Key, KeyBuffer))
   1679         return false;
   1680 
   1681       if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys))
   1682         return false;
   1683 
   1684       if (Key == "roots") {
   1685         auto *Roots = dyn_cast<yaml::SequenceNode>(I.getValue());
   1686         if (!Roots) {
   1687           error(I.getValue(), "expected array");
   1688           return false;
   1689         }
   1690 
   1691         for (auto &I : *Roots) {
   1692           if (std::unique_ptr<RedirectingFileSystem::Entry> E =
   1693                   parseEntry(&I, FS, /*IsRootEntry*/ true))
   1694             RootEntries.push_back(std::move(E));
   1695           else
   1696             return false;
   1697         }
   1698       } else if (Key == "version") {
   1699         StringRef VersionString;
   1700         SmallString<4> Storage;
   1701         if (!parseScalarString(I.getValue(), VersionString, Storage))
   1702           return false;
   1703         int Version;
   1704         if (VersionString.getAsInteger<int>(10, Version)) {
   1705           error(I.getValue(), "expected integer");
   1706           return false;
   1707         }
   1708         if (Version < 0) {
   1709           error(I.getValue(), "invalid version number");
   1710           return false;
   1711         }
   1712         if (Version != 0) {
   1713           error(I.getValue(), "version mismatch, expected 0");
   1714           return false;
   1715         }
   1716       } else if (Key == "case-sensitive") {
   1717         if (!parseScalarBool(I.getValue(), FS->CaseSensitive))
   1718           return false;
   1719       } else if (Key == "overlay-relative") {
   1720         if (!parseScalarBool(I.getValue(), FS->IsRelativeOverlay))
   1721           return false;
   1722       } else if (Key == "use-external-names") {
   1723         if (!parseScalarBool(I.getValue(), FS->UseExternalNames))
   1724           return false;
   1725       } else if (Key == "fallthrough") {
   1726         if (!parseScalarBool(I.getValue(), FS->IsFallthrough))
   1727           return false;
   1728       } else {
   1729         llvm_unreachable("key missing from Keys");
   1730       }
   1731     }
   1732 
   1733     if (Stream.failed())
   1734       return false;
   1735 
   1736     if (!checkMissingKeys(Top, Keys))
   1737       return false;
   1738 
   1739     // Now that we sucessefully parsed the YAML file, canonicalize the internal
   1740     // representation to a proper directory tree so that we can search faster
   1741     // inside the VFS.
   1742     for (auto &E : RootEntries)
   1743       uniqueOverlayTree(FS, E.get());
   1744 
   1745     return true;
   1746   }
   1747 };
   1748 
   1749 std::unique_ptr<RedirectingFileSystem>
   1750 RedirectingFileSystem::create(std::unique_ptr<MemoryBuffer> Buffer,
   1751                               SourceMgr::DiagHandlerTy DiagHandler,
   1752                               StringRef YAMLFilePath, void *DiagContext,
   1753                               IntrusiveRefCntPtr<FileSystem> ExternalFS) {
   1754   SourceMgr SM;
   1755   yaml::Stream Stream(Buffer->getMemBufferRef(), SM);
   1756 
   1757   SM.setDiagHandler(DiagHandler, DiagContext);
   1758   yaml::document_iterator DI = Stream.begin();
   1759   yaml::Node *Root = DI->getRoot();
   1760   if (DI == Stream.end() || !Root) {
   1761     SM.PrintMessage(SMLoc(), SourceMgr::DK_Error, "expected root node");
   1762     return nullptr;
   1763   }
   1764 
   1765   RedirectingFileSystemParser P(Stream);
   1766 
   1767   std::unique_ptr<RedirectingFileSystem> FS(
   1768       new RedirectingFileSystem(ExternalFS));
   1769 
   1770   if (!YAMLFilePath.empty()) {
   1771     // Use the YAML path from -ivfsoverlay to compute the dir to be prefixed
   1772     // to each 'external-contents' path.
   1773     //
   1774     // Example:
   1775     //    -ivfsoverlay dummy.cache/vfs/vfs.yaml
   1776     // yields:
   1777     //  FS->ExternalContentsPrefixDir => /<absolute_path_to>/dummy.cache/vfs
   1778     //
   1779     SmallString<256> OverlayAbsDir = sys::path::parent_path(YAMLFilePath);
   1780     std::error_code EC = llvm::sys::fs::make_absolute(OverlayAbsDir);
   1781     assert(!EC && "Overlay dir final path must be absolute");
   1782     (void)EC;
   1783     FS->setExternalContentsPrefixDir(OverlayAbsDir);
   1784   }
   1785 
   1786   if (!P.parse(Root, FS.get()))
   1787     return nullptr;
   1788 
   1789   return FS;
   1790 }
   1791 
   1792 std::unique_ptr<RedirectingFileSystem> RedirectingFileSystem::create(
   1793     ArrayRef<std::pair<std::string, std::string>> RemappedFiles,
   1794     bool UseExternalNames, FileSystem &ExternalFS) {
   1795   std::unique_ptr<RedirectingFileSystem> FS(
   1796       new RedirectingFileSystem(&ExternalFS));
   1797   FS->UseExternalNames = UseExternalNames;
   1798 
   1799   StringMap<RedirectingFileSystem::Entry *> Entries;
   1800 
   1801   for (auto &Mapping : llvm::reverse(RemappedFiles)) {
   1802     SmallString<128> From = StringRef(Mapping.first);
   1803     SmallString<128> To = StringRef(Mapping.second);
   1804     {
   1805       auto EC = ExternalFS.makeAbsolute(From);
   1806       (void)EC;
   1807       assert(!EC && "Could not make absolute path");
   1808     }
   1809 
   1810     // Check if we've already mapped this file. The first one we see (in the
   1811     // reverse iteration) wins.
   1812     RedirectingFileSystem::Entry *&ToEntry = Entries[From];
   1813     if (ToEntry)
   1814       continue;
   1815 
   1816     // Add parent directories.
   1817     RedirectingFileSystem::Entry *Parent = nullptr;
   1818     StringRef FromDirectory = llvm::sys::path::parent_path(From);
   1819     for (auto I = llvm::sys::path::begin(FromDirectory),
   1820               E = llvm::sys::path::end(FromDirectory);
   1821          I != E; ++I) {
   1822       Parent = RedirectingFileSystemParser::lookupOrCreateEntry(FS.get(), *I,
   1823                                                                 Parent);
   1824     }
   1825     assert(Parent && "File without a directory?");
   1826     {
   1827       auto EC = ExternalFS.makeAbsolute(To);
   1828       (void)EC;
   1829       assert(!EC && "Could not make absolute path");
   1830     }
   1831 
   1832     // Add the file.
   1833     auto NewFile = std::make_unique<RedirectingFileSystem::FileEntry>(
   1834         llvm::sys::path::filename(From), To,
   1835         UseExternalNames ? RedirectingFileSystem::NK_External
   1836                          : RedirectingFileSystem::NK_Virtual);
   1837     ToEntry = NewFile.get();
   1838     cast<RedirectingFileSystem::DirectoryEntry>(Parent)->addContent(
   1839         std::move(NewFile));
   1840   }
   1841 
   1842   return FS;
   1843 }
   1844 
   1845 RedirectingFileSystem::LookupResult::LookupResult(
   1846     Entry *E, sys::path::const_iterator Start, sys::path::const_iterator End)
   1847     : E(E) {
   1848   assert(E != nullptr);
   1849   // If the matched entry is a DirectoryRemapEntry, set ExternalRedirect to the
   1850   // path of the directory it maps to in the external file system plus any
   1851   // remaining path components in the provided iterator.
   1852   if (auto *DRE = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(E)) {
   1853     SmallString<256> Redirect(DRE->getExternalContentsPath());
   1854     sys::path::append(Redirect, Start, End,
   1855                       getExistingStyle(DRE->getExternalContentsPath()));
   1856     ExternalRedirect = std::string(Redirect);
   1857   }
   1858 }
   1859 
   1860 bool RedirectingFileSystem::shouldFallBackToExternalFS(
   1861     std::error_code EC, RedirectingFileSystem::Entry *E) const {
   1862   if (E && !isa<RedirectingFileSystem::DirectoryRemapEntry>(E))
   1863     return false;
   1864   return shouldUseExternalFS() && EC == llvm::errc::no_such_file_or_directory;
   1865 }
   1866 
   1867 std::error_code
   1868 RedirectingFileSystem::makeCanonical(SmallVectorImpl<char> &Path) const {
   1869   if (std::error_code EC = makeAbsolute(Path))
   1870     return EC;
   1871 
   1872   llvm::SmallString<256> CanonicalPath =
   1873       canonicalize(StringRef(Path.data(), Path.size()));
   1874   if (CanonicalPath.empty())
   1875     return make_error_code(llvm::errc::invalid_argument);
   1876 
   1877   Path.assign(CanonicalPath.begin(), CanonicalPath.end());
   1878   return {};
   1879 }
   1880 
   1881 ErrorOr<RedirectingFileSystem::LookupResult>
   1882 RedirectingFileSystem::lookupPath(StringRef Path) const {
   1883   sys::path::const_iterator Start = sys::path::begin(Path);
   1884   sys::path::const_iterator End = sys::path::end(Path);
   1885   for (const auto &Root : Roots) {
   1886     ErrorOr<RedirectingFileSystem::LookupResult> Result =
   1887         lookupPathImpl(Start, End, Root.get());
   1888     if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
   1889       return Result;
   1890   }
   1891   return make_error_code(llvm::errc::no_such_file_or_directory);
   1892 }
   1893 
   1894 ErrorOr<RedirectingFileSystem::LookupResult>
   1895 RedirectingFileSystem::lookupPathImpl(
   1896     sys::path::const_iterator Start, sys::path::const_iterator End,
   1897     RedirectingFileSystem::Entry *From) const {
   1898   assert(!isTraversalComponent(*Start) &&
   1899          !isTraversalComponent(From->getName()) &&
   1900          "Paths should not contain traversal components");
   1901 
   1902   StringRef FromName = From->getName();
   1903 
   1904   // Forward the search to the next component in case this is an empty one.
   1905   if (!FromName.empty()) {
   1906     if (!pathComponentMatches(*Start, FromName))
   1907       return make_error_code(llvm::errc::no_such_file_or_directory);
   1908 
   1909     ++Start;
   1910 
   1911     if (Start == End) {
   1912       // Match!
   1913       return LookupResult(From, Start, End);
   1914     }
   1915   }
   1916 
   1917   if (isa<RedirectingFileSystem::FileEntry>(From))
   1918     return make_error_code(llvm::errc::not_a_directory);
   1919 
   1920   if (isa<RedirectingFileSystem::DirectoryRemapEntry>(From))
   1921     return LookupResult(From, Start, End);
   1922 
   1923   auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(From);
   1924   for (const std::unique_ptr<RedirectingFileSystem::Entry> &DirEntry :
   1925        llvm::make_range(DE->contents_begin(), DE->contents_end())) {
   1926     ErrorOr<RedirectingFileSystem::LookupResult> Result =
   1927         lookupPathImpl(Start, End, DirEntry.get());
   1928     if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
   1929       return Result;
   1930   }
   1931 
   1932   return make_error_code(llvm::errc::no_such_file_or_directory);
   1933 }
   1934 
   1935 static Status getRedirectedFileStatus(const Twine &Path, bool UseExternalNames,
   1936                                       Status ExternalStatus) {
   1937   Status S = ExternalStatus;
   1938   if (!UseExternalNames)
   1939     S = Status::copyWithNewName(S, Path);
   1940   S.IsVFSMapped = true;
   1941   return S;
   1942 }
   1943 
   1944 ErrorOr<Status> RedirectingFileSystem::status(
   1945     const Twine &Path, const RedirectingFileSystem::LookupResult &Result) {
   1946   if (Optional<StringRef> ExtRedirect = Result.getExternalRedirect()) {
   1947     ErrorOr<Status> S = ExternalFS->status(*ExtRedirect);
   1948     if (!S)
   1949       return S;
   1950     auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result.E);
   1951     return getRedirectedFileStatus(Path, RE->useExternalName(UseExternalNames),
   1952                                    *S);
   1953   }
   1954 
   1955   auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(Result.E);
   1956   return Status::copyWithNewName(DE->getStatus(), Path);
   1957 }
   1958 
   1959 ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path_) {
   1960   SmallString<256> Path;
   1961   Path_.toVector(Path);
   1962 
   1963   if (std::error_code EC = makeCanonical(Path))
   1964     return EC;
   1965 
   1966   ErrorOr<RedirectingFileSystem::LookupResult> Result = lookupPath(Path);
   1967   if (!Result) {
   1968     if (shouldFallBackToExternalFS(Result.getError()))
   1969       return ExternalFS->status(Path);
   1970     return Result.getError();
   1971   }
   1972 
   1973   ErrorOr<Status> S = status(Path, *Result);
   1974   if (!S && shouldFallBackToExternalFS(S.getError(), Result->E))
   1975     S = ExternalFS->status(Path);
   1976   return S;
   1977 }
   1978 
   1979 namespace {
   1980 
   1981 /// Provide a file wrapper with an overriden status.
   1982 class FileWithFixedStatus : public File {
   1983   std::unique_ptr<File> InnerFile;
   1984   Status S;
   1985 
   1986 public:
   1987   FileWithFixedStatus(std::unique_ptr<File> InnerFile, Status S)
   1988       : InnerFile(std::move(InnerFile)), S(std::move(S)) {}
   1989 
   1990   ErrorOr<Status> status() override { return S; }
   1991   ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
   1992 
   1993   getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
   1994             bool IsVolatile) override {
   1995     return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
   1996                                 IsVolatile);
   1997   }
   1998 
   1999   std::error_code close() override { return InnerFile->close(); }
   2000 };
   2001 
   2002 } // namespace
   2003 
   2004 ErrorOr<std::unique_ptr<File>>
   2005 RedirectingFileSystem::openFileForRead(const Twine &Path_) {
   2006   SmallString<256> Path;
   2007   Path_.toVector(Path);
   2008 
   2009   if (std::error_code EC = makeCanonical(Path))
   2010     return EC;
   2011 
   2012   ErrorOr<RedirectingFileSystem::LookupResult> Result = lookupPath(Path);
   2013   if (!Result) {
   2014     if (shouldFallBackToExternalFS(Result.getError()))
   2015       return ExternalFS->openFileForRead(Path);
   2016     return Result.getError();
   2017   }
   2018 
   2019   if (!Result->getExternalRedirect()) // FIXME: errc::not_a_file?
   2020     return make_error_code(llvm::errc::invalid_argument);
   2021 
   2022   StringRef ExtRedirect = *Result->getExternalRedirect();
   2023   auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
   2024 
   2025   auto ExternalFile = ExternalFS->openFileForRead(ExtRedirect);
   2026   if (!ExternalFile) {
   2027     if (shouldFallBackToExternalFS(ExternalFile.getError(), Result->E))
   2028       return ExternalFS->openFileForRead(Path);
   2029     return ExternalFile;
   2030   }
   2031 
   2032   auto ExternalStatus = (*ExternalFile)->status();
   2033   if (!ExternalStatus)
   2034     return ExternalStatus.getError();
   2035 
   2036   // FIXME: Update the status with the name and VFSMapped.
   2037   Status S = getRedirectedFileStatus(
   2038       Path, RE->useExternalName(UseExternalNames), *ExternalStatus);
   2039   return std::unique_ptr<File>(
   2040       std::make_unique<FileWithFixedStatus>(std::move(*ExternalFile), S));
   2041 }
   2042 
   2043 std::error_code
   2044 RedirectingFileSystem::getRealPath(const Twine &Path_,
   2045                                    SmallVectorImpl<char> &Output) const {
   2046   SmallString<256> Path;
   2047   Path_.toVector(Path);
   2048 
   2049   if (std::error_code EC = makeCanonical(Path))
   2050     return EC;
   2051 
   2052   ErrorOr<RedirectingFileSystem::LookupResult> Result = lookupPath(Path);
   2053   if (!Result) {
   2054     if (shouldFallBackToExternalFS(Result.getError()))
   2055       return ExternalFS->getRealPath(Path, Output);
   2056     return Result.getError();
   2057   }
   2058 
   2059   // If we found FileEntry or DirectoryRemapEntry, look up the mapped
   2060   // path in the external file system.
   2061   if (auto ExtRedirect = Result->getExternalRedirect()) {
   2062     auto P = ExternalFS->getRealPath(*ExtRedirect, Output);
   2063     if (!P && shouldFallBackToExternalFS(P, Result->E)) {
   2064       return ExternalFS->getRealPath(Path, Output);
   2065     }
   2066     return P;
   2067   }
   2068 
   2069   // If we found a DirectoryEntry, still fall back to ExternalFS if allowed,
   2070   // because directories don't have a single external contents path.
   2071   return shouldUseExternalFS() ? ExternalFS->getRealPath(Path, Output)
   2072                                : llvm::errc::invalid_argument;
   2073 }
   2074 
   2075 std::unique_ptr<FileSystem>
   2076 vfs::getVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,
   2077                     SourceMgr::DiagHandlerTy DiagHandler,
   2078                     StringRef YAMLFilePath, void *DiagContext,
   2079                     IntrusiveRefCntPtr<FileSystem> ExternalFS) {
   2080   return RedirectingFileSystem::create(std::move(Buffer), DiagHandler,
   2081                                        YAMLFilePath, DiagContext,
   2082                                        std::move(ExternalFS));
   2083 }
   2084 
   2085 static void getVFSEntries(RedirectingFileSystem::Entry *SrcE,
   2086                           SmallVectorImpl<StringRef> &Path,
   2087                           SmallVectorImpl<YAMLVFSEntry> &Entries) {
   2088   auto Kind = SrcE->getKind();
   2089   if (Kind == RedirectingFileSystem::EK_Directory) {
   2090     auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
   2091     assert(DE && "Must be a directory");
   2092     for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
   2093          llvm::make_range(DE->contents_begin(), DE->contents_end())) {
   2094       Path.push_back(SubEntry->getName());
   2095       getVFSEntries(SubEntry.get(), Path, Entries);
   2096       Path.pop_back();
   2097     }
   2098     return;
   2099   }
   2100 
   2101   if (Kind == RedirectingFileSystem::EK_DirectoryRemap) {
   2102     auto *DR = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
   2103     assert(DR && "Must be a directory remap");
   2104     SmallString<128> VPath;
   2105     for (auto &Comp : Path)
   2106       llvm::sys::path::append(VPath, Comp);
   2107     Entries.push_back(
   2108         YAMLVFSEntry(VPath.c_str(), DR->getExternalContentsPath()));
   2109     return;
   2110   }
   2111 
   2112   assert(Kind == RedirectingFileSystem::EK_File && "Must be a EK_File");
   2113   auto *FE = dyn_cast<RedirectingFileSystem::FileEntry>(SrcE);
   2114   assert(FE && "Must be a file");
   2115   SmallString<128> VPath;
   2116   for (auto &Comp : Path)
   2117     llvm::sys::path::append(VPath, Comp);
   2118   Entries.push_back(YAMLVFSEntry(VPath.c_str(), FE->getExternalContentsPath()));
   2119 }
   2120 
   2121 void vfs::collectVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,
   2122                              SourceMgr::DiagHandlerTy DiagHandler,
   2123                              StringRef YAMLFilePath,
   2124                              SmallVectorImpl<YAMLVFSEntry> &CollectedEntries,
   2125                              void *DiagContext,
   2126                              IntrusiveRefCntPtr<FileSystem> ExternalFS) {
   2127   std::unique_ptr<RedirectingFileSystem> VFS = RedirectingFileSystem::create(
   2128       std::move(Buffer), DiagHandler, YAMLFilePath, DiagContext,
   2129       std::move(ExternalFS));
   2130   if (!VFS)
   2131     return;
   2132   ErrorOr<RedirectingFileSystem::LookupResult> RootResult =
   2133       VFS->lookupPath("/");
   2134   if (!RootResult)
   2135     return;
   2136   SmallVector<StringRef, 8> Components;
   2137   Components.push_back("/");
   2138   getVFSEntries(RootResult->E, Components, CollectedEntries);
   2139 }
   2140 
   2141 UniqueID vfs::getNextVirtualUniqueID() {
   2142   static std::atomic<unsigned> UID;
   2143   unsigned ID = ++UID;
   2144   // The following assumes that uint64_t max will never collide with a real
   2145   // dev_t value from the OS.
   2146   return UniqueID(std::numeric_limits<uint64_t>::max(), ID);
   2147 }
   2148 
   2149 void YAMLVFSWriter::addEntry(StringRef VirtualPath, StringRef RealPath,
   2150                              bool IsDirectory) {
   2151   assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute");
   2152   assert(sys::path::is_absolute(RealPath) && "real path not absolute");
   2153   assert(!pathHasTraversal(VirtualPath) && "path traversal is not supported");
   2154   Mappings.emplace_back(VirtualPath, RealPath, IsDirectory);
   2155 }
   2156 
   2157 void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) {
   2158   addEntry(VirtualPath, RealPath, /*IsDirectory=*/false);
   2159 }
   2160 
   2161 void YAMLVFSWriter::addDirectoryMapping(StringRef VirtualPath,
   2162                                         StringRef RealPath) {
   2163   addEntry(VirtualPath, RealPath, /*IsDirectory=*/true);
   2164 }
   2165 
   2166 namespace {
   2167 
   2168 class JSONWriter {
   2169   llvm::raw_ostream &OS;
   2170   SmallVector<StringRef, 16> DirStack;
   2171 
   2172   unsigned getDirIndent() { return 4 * DirStack.size(); }
   2173   unsigned getFileIndent() { return 4 * (DirStack.size() + 1); }
   2174   bool containedIn(StringRef Parent, StringRef Path);
   2175   StringRef containedPart(StringRef Parent, StringRef Path);
   2176   void startDirectory(StringRef Path);
   2177   void endDirectory();
   2178   void writeEntry(StringRef VPath, StringRef RPath);
   2179 
   2180 public:
   2181   JSONWriter(llvm::raw_ostream &OS) : OS(OS) {}
   2182 
   2183   void write(ArrayRef<YAMLVFSEntry> Entries, Optional<bool> UseExternalNames,
   2184              Optional<bool> IsCaseSensitive, Optional<bool> IsOverlayRelative,
   2185              StringRef OverlayDir);
   2186 };
   2187 
   2188 } // namespace
   2189 
   2190 bool JSONWriter::containedIn(StringRef Parent, StringRef Path) {
   2191   using namespace llvm::sys;
   2192 
   2193   // Compare each path component.
   2194   auto IParent = path::begin(Parent), EParent = path::end(Parent);
   2195   for (auto IChild = path::begin(Path), EChild = path::end(Path);
   2196        IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
   2197     if (*IParent != *IChild)
   2198       return false;
   2199   }
   2200   // Have we exhausted the parent path?
   2201   return IParent == EParent;
   2202 }
   2203 
   2204 StringRef JSONWriter::containedPart(StringRef Parent, StringRef Path) {
   2205   assert(!Parent.empty());
   2206   assert(containedIn(Parent, Path));
   2207   return Path.slice(Parent.size() + 1, StringRef::npos);
   2208 }
   2209 
   2210 void JSONWriter::startDirectory(StringRef Path) {
   2211   StringRef Name =
   2212       DirStack.empty() ? Path : containedPart(DirStack.back(), Path);
   2213   DirStack.push_back(Path);
   2214   unsigned Indent = getDirIndent();
   2215   OS.indent(Indent) << "{\n";
   2216   OS.indent(Indent + 2) << "'type': 'directory',\n";
   2217   OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(Name) << "\",\n";
   2218   OS.indent(Indent + 2) << "'contents': [\n";
   2219 }
   2220 
   2221 void JSONWriter::endDirectory() {
   2222   unsigned Indent = getDirIndent();
   2223   OS.indent(Indent + 2) << "]\n";
   2224   OS.indent(Indent) << "}";
   2225 
   2226   DirStack.pop_back();
   2227 }
   2228 
   2229 void JSONWriter::writeEntry(StringRef VPath, StringRef RPath) {
   2230   unsigned Indent = getFileIndent();
   2231   OS.indent(Indent) << "{\n";
   2232   OS.indent(Indent + 2) << "'type': 'file',\n";
   2233   OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(VPath) << "\",\n";
   2234   OS.indent(Indent + 2) << "'external-contents': \""
   2235                         << llvm::yaml::escape(RPath) << "\"\n";
   2236   OS.indent(Indent) << "}";
   2237 }
   2238 
   2239 void JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries,
   2240                        Optional<bool> UseExternalNames,
   2241                        Optional<bool> IsCaseSensitive,
   2242                        Optional<bool> IsOverlayRelative,
   2243                        StringRef OverlayDir) {
   2244   using namespace llvm::sys;
   2245 
   2246   OS << "{\n"
   2247         "  'version': 0,\n";
   2248   if (IsCaseSensitive.hasValue())
   2249     OS << "  'case-sensitive': '"
   2250        << (IsCaseSensitive.getValue() ? "true" : "false") << "',\n";
   2251   if (UseExternalNames.hasValue())
   2252     OS << "  'use-external-names': '"
   2253        << (UseExternalNames.getValue() ? "true" : "false") << "',\n";
   2254   bool UseOverlayRelative = false;
   2255   if (IsOverlayRelative.hasValue()) {
   2256     UseOverlayRelative = IsOverlayRelative.getValue();
   2257     OS << "  'overlay-relative': '" << (UseOverlayRelative ? "true" : "false")
   2258        << "',\n";
   2259   }
   2260   OS << "  'roots': [\n";
   2261 
   2262   if (!Entries.empty()) {
   2263     const YAMLVFSEntry &Entry = Entries.front();
   2264 
   2265     startDirectory(
   2266       Entry.IsDirectory ? Entry.VPath : path::parent_path(Entry.VPath)
   2267     );
   2268 
   2269     StringRef RPath = Entry.RPath;
   2270     if (UseOverlayRelative) {
   2271       unsigned OverlayDirLen = OverlayDir.size();
   2272       assert(RPath.substr(0, OverlayDirLen) == OverlayDir &&
   2273              "Overlay dir must be contained in RPath");
   2274       RPath = RPath.slice(OverlayDirLen, RPath.size());
   2275     }
   2276 
   2277     bool IsCurrentDirEmpty = true;
   2278     if (!Entry.IsDirectory) {
   2279       writeEntry(path::filename(Entry.VPath), RPath);
   2280       IsCurrentDirEmpty = false;
   2281     }
   2282 
   2283     for (const auto &Entry : Entries.slice(1)) {
   2284       StringRef Dir =
   2285           Entry.IsDirectory ? Entry.VPath : path::parent_path(Entry.VPath);
   2286       if (Dir == DirStack.back()) {
   2287         if (!IsCurrentDirEmpty) {
   2288           OS << ",\n";
   2289         }
   2290       } else {
   2291         bool IsDirPoppedFromStack = false;
   2292         while (!DirStack.empty() && !containedIn(DirStack.back(), Dir)) {
   2293           OS << "\n";
   2294           endDirectory();
   2295           IsDirPoppedFromStack = true;
   2296         }
   2297         if (IsDirPoppedFromStack || !IsCurrentDirEmpty) {
   2298           OS << ",\n";
   2299         }
   2300         startDirectory(Dir);
   2301         IsCurrentDirEmpty = true;
   2302       }
   2303       StringRef RPath = Entry.RPath;
   2304       if (UseOverlayRelative) {
   2305         unsigned OverlayDirLen = OverlayDir.size();
   2306         assert(RPath.substr(0, OverlayDirLen) == OverlayDir &&
   2307                "Overlay dir must be contained in RPath");
   2308         RPath = RPath.slice(OverlayDirLen, RPath.size());
   2309       }
   2310       if (!Entry.IsDirectory) {
   2311         writeEntry(path::filename(Entry.VPath), RPath);
   2312         IsCurrentDirEmpty = false;
   2313       }
   2314     }
   2315 
   2316     while (!DirStack.empty()) {
   2317       OS << "\n";
   2318       endDirectory();
   2319     }
   2320     OS << "\n";
   2321   }
   2322 
   2323   OS << "  ]\n"
   2324      << "}\n";
   2325 }
   2326 
   2327 void YAMLVFSWriter::write(llvm::raw_ostream &OS) {
   2328   llvm::sort(Mappings, [](const YAMLVFSEntry &LHS, const YAMLVFSEntry &RHS) {
   2329     return LHS.VPath < RHS.VPath;
   2330   });
   2331 
   2332   JSONWriter(OS).write(Mappings, UseExternalNames, IsCaseSensitive,
   2333                        IsOverlayRelative, OverlayDir);
   2334 }
   2335 
   2336 vfs::recursive_directory_iterator::recursive_directory_iterator(
   2337     FileSystem &FS_, const Twine &Path, std::error_code &EC)
   2338     : FS(&FS_) {
   2339   directory_iterator I = FS->dir_begin(Path, EC);
   2340   if (I != directory_iterator()) {
   2341     State = std::make_shared<detail::RecDirIterState>();
   2342     State->Stack.push(I);
   2343   }
   2344 }
   2345 
   2346 vfs::recursive_directory_iterator &
   2347 recursive_directory_iterator::increment(std::error_code &EC) {
   2348   assert(FS && State && !State->Stack.empty() && "incrementing past end");
   2349   assert(!State->Stack.top()->path().empty() && "non-canonical end iterator");
   2350   vfs::directory_iterator End;
   2351 
   2352   if (State->HasNoPushRequest)
   2353     State->HasNoPushRequest = false;
   2354   else {
   2355     if (State->Stack.top()->type() == sys::fs::file_type::directory_file) {
   2356       vfs::directory_iterator I = FS->dir_begin(State->Stack.top()->path(), EC);
   2357       if (I != End) {
   2358         State->Stack.push(I);
   2359         return *this;
   2360       }
   2361     }
   2362   }
   2363 
   2364   while (!State->Stack.empty() && State->Stack.top().increment(EC) == End)
   2365     State->Stack.pop();
   2366 
   2367   if (State->Stack.empty())
   2368     State.reset(); // end iterator
   2369 
   2370   return *this;
   2371 }
   2372