Home | History | Annotate | Download | only in Basic
      1 //===- VirtualFileSystem.cpp - Virtual File System Layer --------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 // This file implements the VirtualFileSystem interface.
     10 //===----------------------------------------------------------------------===//
     11 
     12 #include "clang/Basic/VirtualFileSystem.h"
     13 #include "clang/Basic/FileManager.h"
     14 #include "llvm/ADT/DenseMap.h"
     15 #include "llvm/ADT/STLExtras.h"
     16 #include "llvm/ADT/StringExtras.h"
     17 #include "llvm/ADT/StringSet.h"
     18 #include "llvm/ADT/iterator_range.h"
     19 #include "llvm/Support/Errc.h"
     20 #include "llvm/Support/MemoryBuffer.h"
     21 #include "llvm/Support/Path.h"
     22 #include "llvm/Support/YAMLParser.h"
     23 #include "llvm/Config/llvm-config.h"
     24 #include <atomic>
     25 #include <memory>
     26 
     27 // For chdir.
     28 #ifdef LLVM_ON_WIN32
     29 #  include <direct.h>
     30 #else
     31 #  include <unistd.h>
     32 #endif
     33 
     34 using namespace clang;
     35 using namespace clang::vfs;
     36 using namespace llvm;
     37 using llvm::sys::fs::file_status;
     38 using llvm::sys::fs::file_type;
     39 using llvm::sys::fs::perms;
     40 using llvm::sys::fs::UniqueID;
     41 
     42 Status::Status(const file_status &Status)
     43     : UID(Status.getUniqueID()), MTime(Status.getLastModificationTime()),
     44       User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()),
     45       Type(Status.type()), Perms(Status.permissions()), IsVFSMapped(false)  {}
     46 
     47 Status::Status(StringRef Name, UniqueID UID, sys::TimeValue MTime,
     48                uint32_t User, uint32_t Group, uint64_t Size, file_type Type,
     49                perms Perms)
     50     : Name(Name), UID(UID), MTime(MTime), User(User), Group(Group), Size(Size),
     51       Type(Type), Perms(Perms), IsVFSMapped(false) {}
     52 
     53 Status Status::copyWithNewName(const Status &In, StringRef NewName) {
     54   return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
     55                 In.getUser(), In.getGroup(), In.getSize(), In.getType(),
     56                 In.getPermissions());
     57 }
     58 
     59 Status Status::copyWithNewName(const file_status &In, StringRef NewName) {
     60   return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
     61                 In.getUser(), In.getGroup(), In.getSize(), In.type(),
     62                 In.permissions());
     63 }
     64 
     65 bool Status::equivalent(const Status &Other) const {
     66   return getUniqueID() == Other.getUniqueID();
     67 }
     68 bool Status::isDirectory() const {
     69   return Type == file_type::directory_file;
     70 }
     71 bool Status::isRegularFile() const {
     72   return Type == file_type::regular_file;
     73 }
     74 bool Status::isOther() const {
     75   return exists() && !isRegularFile() && !isDirectory() && !isSymlink();
     76 }
     77 bool Status::isSymlink() const {
     78   return Type == file_type::symlink_file;
     79 }
     80 bool Status::isStatusKnown() const {
     81   return Type != file_type::status_error;
     82 }
     83 bool Status::exists() const {
     84   return isStatusKnown() && Type != file_type::file_not_found;
     85 }
     86 
     87 File::~File() {}
     88 
     89 FileSystem::~FileSystem() {}
     90 
     91 ErrorOr<std::unique_ptr<MemoryBuffer>>
     92 FileSystem::getBufferForFile(const llvm::Twine &Name, int64_t FileSize,
     93                              bool RequiresNullTerminator, bool IsVolatile) {
     94   auto F = openFileForRead(Name);
     95   if (!F)
     96     return F.getError();
     97 
     98   return (*F)->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile);
     99 }
    100 
    101 std::error_code FileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const {
    102   auto WorkingDir = getCurrentWorkingDirectory();
    103   if (!WorkingDir)
    104     return WorkingDir.getError();
    105 
    106   return llvm::sys::fs::make_absolute(WorkingDir.get(), Path);
    107 }
    108 
    109 bool FileSystem::exists(const Twine &Path) {
    110   auto Status = status(Path);
    111   return Status && Status->exists();
    112 }
    113 
    114 //===-----------------------------------------------------------------------===/
    115 // RealFileSystem implementation
    116 //===-----------------------------------------------------------------------===/
    117 
    118 namespace {
    119 /// \brief Wrapper around a raw file descriptor.
    120 class RealFile : public File {
    121   int FD;
    122   Status S;
    123   friend class RealFileSystem;
    124   RealFile(int FD, StringRef NewName)
    125       : FD(FD), S(NewName, {}, {}, {}, {}, {},
    126                   llvm::sys::fs::file_type::status_error, {}) {
    127     assert(FD >= 0 && "Invalid or inactive file descriptor");
    128   }
    129 
    130 public:
    131   ~RealFile() override;
    132   ErrorOr<Status> status() override;
    133   ErrorOr<std::unique_ptr<MemoryBuffer>> getBuffer(const Twine &Name,
    134                                                    int64_t FileSize,
    135                                                    bool RequiresNullTerminator,
    136                                                    bool IsVolatile) override;
    137   std::error_code close() override;
    138 };
    139 } // end anonymous namespace
    140 RealFile::~RealFile() { close(); }
    141 
    142 ErrorOr<Status> RealFile::status() {
    143   assert(FD != -1 && "cannot stat closed file");
    144   if (!S.isStatusKnown()) {
    145     file_status RealStatus;
    146     if (std::error_code EC = sys::fs::status(FD, RealStatus))
    147       return EC;
    148     S = Status::copyWithNewName(RealStatus, S.getName());
    149   }
    150   return S;
    151 }
    152 
    153 ErrorOr<std::unique_ptr<MemoryBuffer>>
    154 RealFile::getBuffer(const Twine &Name, int64_t FileSize,
    155                     bool RequiresNullTerminator, bool IsVolatile) {
    156   assert(FD != -1 && "cannot get buffer for closed file");
    157   return MemoryBuffer::getOpenFile(FD, Name, FileSize, RequiresNullTerminator,
    158                                    IsVolatile);
    159 }
    160 
    161 // FIXME: This is terrible, we need this for ::close.
    162 #if !defined(_MSC_VER) && !defined(__MINGW32__)
    163 #include <unistd.h>
    164 #include <sys/uio.h>
    165 #else
    166 #include <io.h>
    167 #ifndef S_ISFIFO
    168 #define S_ISFIFO(x) (0)
    169 #endif
    170 #endif
    171 std::error_code RealFile::close() {
    172   if (::close(FD))
    173     return std::error_code(errno, std::generic_category());
    174   FD = -1;
    175   return std::error_code();
    176 }
    177 
    178 namespace {
    179 /// \brief The file system according to your operating system.
    180 class RealFileSystem : public FileSystem {
    181 public:
    182   ErrorOr<Status> status(const Twine &Path) override;
    183   ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
    184   directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
    185 
    186   llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override;
    187   std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
    188 };
    189 } // end anonymous namespace
    190 
    191 ErrorOr<Status> RealFileSystem::status(const Twine &Path) {
    192   sys::fs::file_status RealStatus;
    193   if (std::error_code EC = sys::fs::status(Path, RealStatus))
    194     return EC;
    195   return Status::copyWithNewName(RealStatus, Path.str());
    196 }
    197 
    198 ErrorOr<std::unique_ptr<File>>
    199 RealFileSystem::openFileForRead(const Twine &Name) {
    200   int FD;
    201   if (std::error_code EC = sys::fs::openFileForRead(Name, FD))
    202     return EC;
    203   return std::unique_ptr<File>(new RealFile(FD, Name.str()));
    204 }
    205 
    206 llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory() const {
    207   SmallString<256> Dir;
    208   if (std::error_code EC = llvm::sys::fs::current_path(Dir))
    209     return EC;
    210   return Dir.str().str();
    211 }
    212 
    213 std::error_code RealFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
    214   // FIXME: chdir is thread hostile; on the other hand, creating the same
    215   // behavior as chdir is complex: chdir resolves the path once, thus
    216   // guaranteeing that all subsequent relative path operations work
    217   // on the same path the original chdir resulted in. This makes a
    218   // difference for example on network filesystems, where symlinks might be
    219   // switched during runtime of the tool. Fixing this depends on having a
    220   // file system abstraction that allows openat() style interactions.
    221   SmallString<256> Storage;
    222   StringRef Dir = Path.toNullTerminatedStringRef(Storage);
    223   if (int Err = ::chdir(Dir.data()))
    224     return std::error_code(Err, std::generic_category());
    225   return std::error_code();
    226 }
    227 
    228 IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
    229   static IntrusiveRefCntPtr<FileSystem> FS = new RealFileSystem();
    230   return FS;
    231 }
    232 
    233 namespace {
    234 class RealFSDirIter : public clang::vfs::detail::DirIterImpl {
    235   std::string Path;
    236   llvm::sys::fs::directory_iterator Iter;
    237 public:
    238   RealFSDirIter(const Twine &_Path, std::error_code &EC)
    239       : Path(_Path.str()), Iter(Path, EC) {
    240     if (!EC && Iter != llvm::sys::fs::directory_iterator()) {
    241       llvm::sys::fs::file_status S;
    242       EC = Iter->status(S);
    243       if (!EC)
    244         CurrentEntry = Status::copyWithNewName(S, Iter->path());
    245     }
    246   }
    247 
    248   std::error_code increment() override {
    249     std::error_code EC;
    250     Iter.increment(EC);
    251     if (EC) {
    252       return EC;
    253     } else if (Iter == llvm::sys::fs::directory_iterator()) {
    254       CurrentEntry = Status();
    255     } else {
    256       llvm::sys::fs::file_status S;
    257       EC = Iter->status(S);
    258       CurrentEntry = Status::copyWithNewName(S, Iter->path());
    259     }
    260     return EC;
    261   }
    262 };
    263 }
    264 
    265 directory_iterator RealFileSystem::dir_begin(const Twine &Dir,
    266                                              std::error_code &EC) {
    267   return directory_iterator(std::make_shared<RealFSDirIter>(Dir, EC));
    268 }
    269 
    270 //===-----------------------------------------------------------------------===/
    271 // OverlayFileSystem implementation
    272 //===-----------------------------------------------------------------------===/
    273 OverlayFileSystem::OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> BaseFS) {
    274   FSList.push_back(BaseFS);
    275 }
    276 
    277 void OverlayFileSystem::pushOverlay(IntrusiveRefCntPtr<FileSystem> FS) {
    278   FSList.push_back(FS);
    279   // Synchronize added file systems by duplicating the working directory from
    280   // the first one in the list.
    281   FS->setCurrentWorkingDirectory(getCurrentWorkingDirectory().get());
    282 }
    283 
    284 ErrorOr<Status> OverlayFileSystem::status(const Twine &Path) {
    285   // FIXME: handle symlinks that cross file systems
    286   for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
    287     ErrorOr<Status> Status = (*I)->status(Path);
    288     if (Status || Status.getError() != llvm::errc::no_such_file_or_directory)
    289       return Status;
    290   }
    291   return make_error_code(llvm::errc::no_such_file_or_directory);
    292 }
    293 
    294 ErrorOr<std::unique_ptr<File>>
    295 OverlayFileSystem::openFileForRead(const llvm::Twine &Path) {
    296   // FIXME: handle symlinks that cross file systems
    297   for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
    298     auto Result = (*I)->openFileForRead(Path);
    299     if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
    300       return Result;
    301   }
    302   return make_error_code(llvm::errc::no_such_file_or_directory);
    303 }
    304 
    305 llvm::ErrorOr<std::string>
    306 OverlayFileSystem::getCurrentWorkingDirectory() const {
    307   // All file systems are synchronized, just take the first working directory.
    308   return FSList.front()->getCurrentWorkingDirectory();
    309 }
    310 std::error_code
    311 OverlayFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
    312   for (auto &FS : FSList)
    313     if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))
    314       return EC;
    315   return std::error_code();
    316 }
    317 
    318 clang::vfs::detail::DirIterImpl::~DirIterImpl() { }
    319 
    320 namespace {
    321 class OverlayFSDirIterImpl : public clang::vfs::detail::DirIterImpl {
    322   OverlayFileSystem &Overlays;
    323   std::string Path;
    324   OverlayFileSystem::iterator CurrentFS;
    325   directory_iterator CurrentDirIter;
    326   llvm::StringSet<> SeenNames;
    327 
    328   std::error_code incrementFS() {
    329     assert(CurrentFS != Overlays.overlays_end() && "incrementing past end");
    330     ++CurrentFS;
    331     for (auto E = Overlays.overlays_end(); CurrentFS != E; ++CurrentFS) {
    332       std::error_code EC;
    333       CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC);
    334       if (EC && EC != errc::no_such_file_or_directory)
    335         return EC;
    336       if (CurrentDirIter != directory_iterator())
    337         break; // found
    338     }
    339     return std::error_code();
    340   }
    341 
    342   std::error_code incrementDirIter(bool IsFirstTime) {
    343     assert((IsFirstTime || CurrentDirIter != directory_iterator()) &&
    344            "incrementing past end");
    345     std::error_code EC;
    346     if (!IsFirstTime)
    347       CurrentDirIter.increment(EC);
    348     if (!EC && CurrentDirIter == directory_iterator())
    349       EC = incrementFS();
    350     return EC;
    351   }
    352 
    353   std::error_code incrementImpl(bool IsFirstTime) {
    354     while (true) {
    355       std::error_code EC = incrementDirIter(IsFirstTime);
    356       if (EC || CurrentDirIter == directory_iterator()) {
    357         CurrentEntry = Status();
    358         return EC;
    359       }
    360       CurrentEntry = *CurrentDirIter;
    361       StringRef Name = llvm::sys::path::filename(CurrentEntry.getName());
    362       if (SeenNames.insert(Name).second)
    363         return EC; // name not seen before
    364     }
    365     llvm_unreachable("returned above");
    366   }
    367 
    368 public:
    369   OverlayFSDirIterImpl(const Twine &Path, OverlayFileSystem &FS,
    370                        std::error_code &EC)
    371       : Overlays(FS), Path(Path.str()), CurrentFS(Overlays.overlays_begin()) {
    372     CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC);
    373     EC = incrementImpl(true);
    374   }
    375 
    376   std::error_code increment() override { return incrementImpl(false); }
    377 };
    378 } // end anonymous namespace
    379 
    380 directory_iterator OverlayFileSystem::dir_begin(const Twine &Dir,
    381                                                 std::error_code &EC) {
    382   return directory_iterator(
    383       std::make_shared<OverlayFSDirIterImpl>(Dir, *this, EC));
    384 }
    385 
    386 namespace clang {
    387 namespace vfs {
    388 namespace detail {
    389 
    390 enum InMemoryNodeKind { IME_File, IME_Directory };
    391 
    392 /// The in memory file system is a tree of Nodes. Every node can either be a
    393 /// file or a directory.
    394 class InMemoryNode {
    395   Status Stat;
    396   InMemoryNodeKind Kind;
    397 
    398 public:
    399   InMemoryNode(Status Stat, InMemoryNodeKind Kind)
    400       : Stat(std::move(Stat)), Kind(Kind) {}
    401   virtual ~InMemoryNode() {}
    402   const Status &getStatus() const { return Stat; }
    403   InMemoryNodeKind getKind() const { return Kind; }
    404   virtual std::string toString(unsigned Indent) const = 0;
    405 };
    406 
    407 namespace {
    408 class InMemoryFile : public InMemoryNode {
    409   std::unique_ptr<llvm::MemoryBuffer> Buffer;
    410 
    411 public:
    412   InMemoryFile(Status Stat, std::unique_ptr<llvm::MemoryBuffer> Buffer)
    413       : InMemoryNode(std::move(Stat), IME_File), Buffer(std::move(Buffer)) {}
    414 
    415   llvm::MemoryBuffer *getBuffer() { return Buffer.get(); }
    416   std::string toString(unsigned Indent) const override {
    417     return (std::string(Indent, ' ') + getStatus().getName() + "\n").str();
    418   }
    419   static bool classof(const InMemoryNode *N) {
    420     return N->getKind() == IME_File;
    421   }
    422 };
    423 
    424 /// Adapt a InMemoryFile for VFS' File interface.
    425 class InMemoryFileAdaptor : public File {
    426   InMemoryFile &Node;
    427 
    428 public:
    429   explicit InMemoryFileAdaptor(InMemoryFile &Node) : Node(Node) {}
    430 
    431   llvm::ErrorOr<Status> status() override { return Node.getStatus(); }
    432   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
    433   getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
    434             bool IsVolatile) override {
    435     llvm::MemoryBuffer *Buf = Node.getBuffer();
    436     return llvm::MemoryBuffer::getMemBuffer(
    437         Buf->getBuffer(), Buf->getBufferIdentifier(), RequiresNullTerminator);
    438   }
    439   std::error_code close() override { return std::error_code(); }
    440 };
    441 } // end anonymous namespace
    442 
    443 class InMemoryDirectory : public InMemoryNode {
    444   std::map<std::string, std::unique_ptr<InMemoryNode>> Entries;
    445 
    446 public:
    447   InMemoryDirectory(Status Stat)
    448       : InMemoryNode(std::move(Stat), IME_Directory) {}
    449   InMemoryNode *getChild(StringRef Name) {
    450     auto I = Entries.find(Name);
    451     if (I != Entries.end())
    452       return I->second.get();
    453     return nullptr;
    454   }
    455   InMemoryNode *addChild(StringRef Name, std::unique_ptr<InMemoryNode> Child) {
    456     return Entries.insert(make_pair(Name, std::move(Child)))
    457         .first->second.get();
    458   }
    459 
    460   typedef decltype(Entries)::const_iterator const_iterator;
    461   const_iterator begin() const { return Entries.begin(); }
    462   const_iterator end() const { return Entries.end(); }
    463 
    464   std::string toString(unsigned Indent) const override {
    465     std::string Result =
    466         (std::string(Indent, ' ') + getStatus().getName() + "\n").str();
    467     for (const auto &Entry : Entries) {
    468       Result += Entry.second->toString(Indent + 2);
    469     }
    470     return Result;
    471   }
    472   static bool classof(const InMemoryNode *N) {
    473     return N->getKind() == IME_Directory;
    474   }
    475 };
    476 }
    477 
    478 InMemoryFileSystem::InMemoryFileSystem(bool UseNormalizedPaths)
    479     : Root(new detail::InMemoryDirectory(
    480           Status("", getNextVirtualUniqueID(), llvm::sys::TimeValue::MinTime(),
    481                  0, 0, 0, llvm::sys::fs::file_type::directory_file,
    482                  llvm::sys::fs::perms::all_all))),
    483       UseNormalizedPaths(UseNormalizedPaths) {}
    484 
    485 InMemoryFileSystem::~InMemoryFileSystem() {}
    486 
    487 std::string InMemoryFileSystem::toString() const {
    488   return Root->toString(/*Indent=*/0);
    489 }
    490 
    491 bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
    492                                  std::unique_ptr<llvm::MemoryBuffer> Buffer) {
    493   SmallString<128> Path;
    494   P.toVector(Path);
    495 
    496   // Fix up relative paths. This just prepends the current working directory.
    497   std::error_code EC = makeAbsolute(Path);
    498   assert(!EC);
    499   (void)EC;
    500 
    501   if (useNormalizedPaths())
    502     llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
    503 
    504   if (Path.empty())
    505     return false;
    506 
    507   detail::InMemoryDirectory *Dir = Root.get();
    508   auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path);
    509   while (true) {
    510     StringRef Name = *I;
    511     detail::InMemoryNode *Node = Dir->getChild(Name);
    512     ++I;
    513     if (!Node) {
    514       if (I == E) {
    515         // End of the path, create a new file.
    516         // FIXME: expose the status details in the interface.
    517         Status Stat(P.str(), getNextVirtualUniqueID(),
    518                     llvm::sys::TimeValue(ModificationTime, 0), 0, 0,
    519                     Buffer->getBufferSize(),
    520                     llvm::sys::fs::file_type::regular_file,
    521                     llvm::sys::fs::all_all);
    522         Dir->addChild(Name, llvm::make_unique<detail::InMemoryFile>(
    523                                 std::move(Stat), std::move(Buffer)));
    524         return true;
    525       }
    526 
    527       // Create a new directory. Use the path up to here.
    528       // FIXME: expose the status details in the interface.
    529       Status Stat(
    530           StringRef(Path.str().begin(), Name.end() - Path.str().begin()),
    531           getNextVirtualUniqueID(), llvm::sys::TimeValue(ModificationTime, 0),
    532           0, 0, Buffer->getBufferSize(),
    533           llvm::sys::fs::file_type::directory_file, llvm::sys::fs::all_all);
    534       Dir = cast<detail::InMemoryDirectory>(Dir->addChild(
    535           Name, llvm::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
    536       continue;
    537     }
    538 
    539     if (auto *NewDir = dyn_cast<detail::InMemoryDirectory>(Node)) {
    540       Dir = NewDir;
    541     } else {
    542       assert(isa<detail::InMemoryFile>(Node) &&
    543              "Must be either file or directory!");
    544 
    545       // Trying to insert a directory in place of a file.
    546       if (I != E)
    547         return false;
    548 
    549       // Return false only if the new file is different from the existing one.
    550       return cast<detail::InMemoryFile>(Node)->getBuffer()->getBuffer() ==
    551              Buffer->getBuffer();
    552     }
    553   }
    554 }
    555 
    556 bool InMemoryFileSystem::addFileNoOwn(const Twine &P, time_t ModificationTime,
    557                                       llvm::MemoryBuffer *Buffer) {
    558   return addFile(P, ModificationTime,
    559                  llvm::MemoryBuffer::getMemBuffer(
    560                      Buffer->getBuffer(), Buffer->getBufferIdentifier()));
    561 }
    562 
    563 static ErrorOr<detail::InMemoryNode *>
    564 lookupInMemoryNode(const InMemoryFileSystem &FS, detail::InMemoryDirectory *Dir,
    565                    const Twine &P) {
    566   SmallString<128> Path;
    567   P.toVector(Path);
    568 
    569   // Fix up relative paths. This just prepends the current working directory.
    570   std::error_code EC = FS.makeAbsolute(Path);
    571   assert(!EC);
    572   (void)EC;
    573 
    574   if (FS.useNormalizedPaths())
    575     llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
    576 
    577   if (Path.empty())
    578     return Dir;
    579 
    580   auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path);
    581   while (true) {
    582     detail::InMemoryNode *Node = Dir->getChild(*I);
    583     ++I;
    584     if (!Node)
    585       return errc::no_such_file_or_directory;
    586 
    587     // Return the file if it's at the end of the path.
    588     if (auto File = dyn_cast<detail::InMemoryFile>(Node)) {
    589       if (I == E)
    590         return File;
    591       return errc::no_such_file_or_directory;
    592     }
    593 
    594     // Traverse directories.
    595     Dir = cast<detail::InMemoryDirectory>(Node);
    596     if (I == E)
    597       return Dir;
    598   }
    599 }
    600 
    601 llvm::ErrorOr<Status> InMemoryFileSystem::status(const Twine &Path) {
    602   auto Node = lookupInMemoryNode(*this, Root.get(), Path);
    603   if (Node)
    604     return (*Node)->getStatus();
    605   return Node.getError();
    606 }
    607 
    608 llvm::ErrorOr<std::unique_ptr<File>>
    609 InMemoryFileSystem::openFileForRead(const Twine &Path) {
    610   auto Node = lookupInMemoryNode(*this, Root.get(), Path);
    611   if (!Node)
    612     return Node.getError();
    613 
    614   // When we have a file provide a heap-allocated wrapper for the memory buffer
    615   // to match the ownership semantics for File.
    616   if (auto *F = dyn_cast<detail::InMemoryFile>(*Node))
    617     return std::unique_ptr<File>(new detail::InMemoryFileAdaptor(*F));
    618 
    619   // FIXME: errc::not_a_file?
    620   return make_error_code(llvm::errc::invalid_argument);
    621 }
    622 
    623 namespace {
    624 /// Adaptor from InMemoryDir::iterator to directory_iterator.
    625 class InMemoryDirIterator : public clang::vfs::detail::DirIterImpl {
    626   detail::InMemoryDirectory::const_iterator I;
    627   detail::InMemoryDirectory::const_iterator E;
    628 
    629 public:
    630   InMemoryDirIterator() {}
    631   explicit InMemoryDirIterator(detail::InMemoryDirectory &Dir)
    632       : I(Dir.begin()), E(Dir.end()) {
    633     if (I != E)
    634       CurrentEntry = I->second->getStatus();
    635   }
    636 
    637   std::error_code increment() override {
    638     ++I;
    639     // When we're at the end, make CurrentEntry invalid and DirIterImpl will do
    640     // the rest.
    641     CurrentEntry = I != E ? I->second->getStatus() : Status();
    642     return std::error_code();
    643   }
    644 };
    645 } // end anonymous namespace
    646 
    647 directory_iterator InMemoryFileSystem::dir_begin(const Twine &Dir,
    648                                                  std::error_code &EC) {
    649   auto Node = lookupInMemoryNode(*this, Root.get(), Dir);
    650   if (!Node) {
    651     EC = Node.getError();
    652     return directory_iterator(std::make_shared<InMemoryDirIterator>());
    653   }
    654 
    655   if (auto *DirNode = dyn_cast<detail::InMemoryDirectory>(*Node))
    656     return directory_iterator(std::make_shared<InMemoryDirIterator>(*DirNode));
    657 
    658   EC = make_error_code(llvm::errc::not_a_directory);
    659   return directory_iterator(std::make_shared<InMemoryDirIterator>());
    660 }
    661 }
    662 }
    663 
    664 //===-----------------------------------------------------------------------===/
    665 // RedirectingFileSystem implementation
    666 //===-----------------------------------------------------------------------===/
    667 
    668 namespace {
    669 
    670 enum EntryKind {
    671   EK_Directory,
    672   EK_File
    673 };
    674 
    675 /// \brief A single file or directory in the VFS.
    676 class Entry {
    677   EntryKind Kind;
    678   std::string Name;
    679 
    680 public:
    681   virtual ~Entry();
    682   Entry(EntryKind K, StringRef Name) : Kind(K), Name(Name) {}
    683   StringRef getName() const { return Name; }
    684   EntryKind getKind() const { return Kind; }
    685 };
    686 
    687 class RedirectingDirectoryEntry : public Entry {
    688   std::vector<std::unique_ptr<Entry>> Contents;
    689   Status S;
    690 
    691 public:
    692   RedirectingDirectoryEntry(StringRef Name,
    693                             std::vector<std::unique_ptr<Entry>> Contents,
    694                             Status S)
    695       : Entry(EK_Directory, Name), Contents(std::move(Contents)),
    696         S(std::move(S)) {}
    697   Status getStatus() { return S; }
    698   typedef decltype(Contents)::iterator iterator;
    699   iterator contents_begin() { return Contents.begin(); }
    700   iterator contents_end() { return Contents.end(); }
    701   static bool classof(const Entry *E) { return E->getKind() == EK_Directory; }
    702 };
    703 
    704 class RedirectingFileEntry : public Entry {
    705 public:
    706   enum NameKind {
    707     NK_NotSet,
    708     NK_External,
    709     NK_Virtual
    710   };
    711 private:
    712   std::string ExternalContentsPath;
    713   NameKind UseName;
    714 public:
    715   RedirectingFileEntry(StringRef Name, StringRef ExternalContentsPath,
    716                        NameKind UseName)
    717       : Entry(EK_File, Name), ExternalContentsPath(ExternalContentsPath),
    718         UseName(UseName) {}
    719   StringRef getExternalContentsPath() const { return ExternalContentsPath; }
    720   /// \brief whether to use the external path as the name for this file.
    721   bool useExternalName(bool GlobalUseExternalName) const {
    722     return UseName == NK_NotSet ? GlobalUseExternalName
    723                                 : (UseName == NK_External);
    724   }
    725   static bool classof(const Entry *E) { return E->getKind() == EK_File; }
    726 };
    727 
    728 class RedirectingFileSystem;
    729 
    730 class VFSFromYamlDirIterImpl : public clang::vfs::detail::DirIterImpl {
    731   std::string Dir;
    732   RedirectingFileSystem &FS;
    733   RedirectingDirectoryEntry::iterator Current, End;
    734 
    735 public:
    736   VFSFromYamlDirIterImpl(const Twine &Path, RedirectingFileSystem &FS,
    737                          RedirectingDirectoryEntry::iterator Begin,
    738                          RedirectingDirectoryEntry::iterator End,
    739                          std::error_code &EC);
    740   std::error_code increment() override;
    741 };
    742 
    743 /// \brief A virtual file system parsed from a YAML file.
    744 ///
    745 /// Currently, this class allows creating virtual directories and mapping
    746 /// virtual file paths to existing external files, available in \c ExternalFS.
    747 ///
    748 /// The basic structure of the parsed file is:
    749 /// \verbatim
    750 /// {
    751 ///   'version': <version number>,
    752 ///   <optional configuration>
    753 ///   'roots': [
    754 ///              <directory entries>
    755 ///            ]
    756 /// }
    757 /// \endverbatim
    758 ///
    759 /// All configuration options are optional.
    760 ///   'case-sensitive': <boolean, default=true>
    761 ///   'use-external-names': <boolean, default=true>
    762 ///
    763 /// Virtual directories are represented as
    764 /// \verbatim
    765 /// {
    766 ///   'type': 'directory',
    767 ///   'name': <string>,
    768 ///   'contents': [ <file or directory entries> ]
    769 /// }
    770 /// \endverbatim
    771 ///
    772 /// The default attributes for virtual directories are:
    773 /// \verbatim
    774 /// MTime = now() when created
    775 /// Perms = 0777
    776 /// User = Group = 0
    777 /// Size = 0
    778 /// UniqueID = unspecified unique value
    779 /// \endverbatim
    780 ///
    781 /// Re-mapped files are represented as
    782 /// \verbatim
    783 /// {
    784 ///   'type': 'file',
    785 ///   'name': <string>,
    786 ///   'use-external-name': <boolean> # Optional
    787 ///   'external-contents': <path to external file>)
    788 /// }
    789 /// \endverbatim
    790 ///
    791 /// and inherit their attributes from the external contents.
    792 ///
    793 /// In both cases, the 'name' field may contain multiple path components (e.g.
    794 /// /path/to/file). However, any directory that contains more than one child
    795 /// must be uniquely represented by a directory entry.
    796 class RedirectingFileSystem : public vfs::FileSystem {
    797   /// The root(s) of the virtual file system.
    798   std::vector<std::unique_ptr<Entry>> Roots;
    799   /// \brief The file system to use for external references.
    800   IntrusiveRefCntPtr<FileSystem> ExternalFS;
    801 
    802   /// @name Configuration
    803   /// @{
    804 
    805   /// \brief Whether to perform case-sensitive comparisons.
    806   ///
    807   /// Currently, case-insensitive matching only works correctly with ASCII.
    808   bool CaseSensitive;
    809 
    810   /// \brief Whether to use to use the value of 'external-contents' for the
    811   /// names of files.  This global value is overridable on a per-file basis.
    812   bool UseExternalNames;
    813   /// @}
    814 
    815   friend class RedirectingFileSystemParser;
    816 
    817 private:
    818   RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS)
    819       : ExternalFS(ExternalFS), CaseSensitive(true), UseExternalNames(true) {}
    820 
    821   /// \brief Looks up \p Path in \c Roots.
    822   ErrorOr<Entry *> lookupPath(const Twine &Path);
    823 
    824   /// \brief Looks up the path <tt>[Start, End)</tt> in \p From, possibly
    825   /// recursing into the contents of \p From if it is a directory.
    826   ErrorOr<Entry *> lookupPath(sys::path::const_iterator Start,
    827                               sys::path::const_iterator End, Entry *From);
    828 
    829   /// \brief Get the status of a given an \c Entry.
    830   ErrorOr<Status> status(const Twine &Path, Entry *E);
    831 
    832 public:
    833   /// \brief Parses \p Buffer, which is expected to be in YAML format and
    834   /// returns a virtual file system representing its contents.
    835   static RedirectingFileSystem *
    836   create(std::unique_ptr<MemoryBuffer> Buffer,
    837          SourceMgr::DiagHandlerTy DiagHandler, void *DiagContext,
    838          IntrusiveRefCntPtr<FileSystem> ExternalFS);
    839 
    840   ErrorOr<Status> status(const Twine &Path) override;
    841   ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
    842 
    843   llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
    844     return ExternalFS->getCurrentWorkingDirectory();
    845   }
    846   std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
    847     return ExternalFS->setCurrentWorkingDirectory(Path);
    848   }
    849 
    850   directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override{
    851     ErrorOr<Entry *> E = lookupPath(Dir);
    852     if (!E) {
    853       EC = E.getError();
    854       return directory_iterator();
    855     }
    856     ErrorOr<Status> S = status(Dir, *E);
    857     if (!S) {
    858       EC = S.getError();
    859       return directory_iterator();
    860     }
    861     if (!S->isDirectory()) {
    862       EC = std::error_code(static_cast<int>(errc::not_a_directory),
    863                            std::system_category());
    864       return directory_iterator();
    865     }
    866 
    867     auto *D = cast<RedirectingDirectoryEntry>(*E);
    868     return directory_iterator(std::make_shared<VFSFromYamlDirIterImpl>(Dir,
    869         *this, D->contents_begin(), D->contents_end(), EC));
    870   }
    871 };
    872 
    873 /// \brief A helper class to hold the common YAML parsing state.
    874 class RedirectingFileSystemParser {
    875   yaml::Stream &Stream;
    876 
    877   void error(yaml::Node *N, const Twine &Msg) {
    878     Stream.printError(N, Msg);
    879   }
    880 
    881   // false on error
    882   bool parseScalarString(yaml::Node *N, StringRef &Result,
    883                          SmallVectorImpl<char> &Storage) {
    884     yaml::ScalarNode *S = dyn_cast<yaml::ScalarNode>(N);
    885     if (!S) {
    886       error(N, "expected string");
    887       return false;
    888     }
    889     Result = S->getValue(Storage);
    890     return true;
    891   }
    892 
    893   // false on error
    894   bool parseScalarBool(yaml::Node *N, bool &Result) {
    895     SmallString<5> Storage;
    896     StringRef Value;
    897     if (!parseScalarString(N, Value, Storage))
    898       return false;
    899 
    900     if (Value.equals_lower("true") || Value.equals_lower("on") ||
    901         Value.equals_lower("yes") || Value == "1") {
    902       Result = true;
    903       return true;
    904     } else if (Value.equals_lower("false") || Value.equals_lower("off") ||
    905                Value.equals_lower("no") || Value == "0") {
    906       Result = false;
    907       return true;
    908     }
    909 
    910     error(N, "expected boolean value");
    911     return false;
    912   }
    913 
    914   struct KeyStatus {
    915     KeyStatus(bool Required=false) : Required(Required), Seen(false) {}
    916     bool Required;
    917     bool Seen;
    918   };
    919   typedef std::pair<StringRef, KeyStatus> KeyStatusPair;
    920 
    921   // false on error
    922   bool checkDuplicateOrUnknownKey(yaml::Node *KeyNode, StringRef Key,
    923                                   DenseMap<StringRef, KeyStatus> &Keys) {
    924     if (!Keys.count(Key)) {
    925       error(KeyNode, "unknown key");
    926       return false;
    927     }
    928     KeyStatus &S = Keys[Key];
    929     if (S.Seen) {
    930       error(KeyNode, Twine("duplicate key '") + Key + "'");
    931       return false;
    932     }
    933     S.Seen = true;
    934     return true;
    935   }
    936 
    937   // false on error
    938   bool checkMissingKeys(yaml::Node *Obj, DenseMap<StringRef, KeyStatus> &Keys) {
    939     for (DenseMap<StringRef, KeyStatus>::iterator I = Keys.begin(),
    940          E = Keys.end();
    941          I != E; ++I) {
    942       if (I->second.Required && !I->second.Seen) {
    943         error(Obj, Twine("missing key '") + I->first + "'");
    944         return false;
    945       }
    946     }
    947     return true;
    948   }
    949 
    950   std::unique_ptr<Entry> parseEntry(yaml::Node *N) {
    951     yaml::MappingNode *M = dyn_cast<yaml::MappingNode>(N);
    952     if (!M) {
    953       error(N, "expected mapping node for file or directory entry");
    954       return nullptr;
    955     }
    956 
    957     KeyStatusPair Fields[] = {
    958       KeyStatusPair("name", true),
    959       KeyStatusPair("type", true),
    960       KeyStatusPair("contents", false),
    961       KeyStatusPair("external-contents", false),
    962       KeyStatusPair("use-external-name", false),
    963     };
    964 
    965     DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
    966 
    967     bool HasContents = false; // external or otherwise
    968     std::vector<std::unique_ptr<Entry>> EntryArrayContents;
    969     std::string ExternalContentsPath;
    970     std::string Name;
    971     auto UseExternalName = RedirectingFileEntry::NK_NotSet;
    972     EntryKind Kind;
    973 
    974     for (yaml::MappingNode::iterator I = M->begin(), E = M->end(); I != E;
    975          ++I) {
    976       StringRef Key;
    977       // Reuse the buffer for key and value, since we don't look at key after
    978       // parsing value.
    979       SmallString<256> Buffer;
    980       if (!parseScalarString(I->getKey(), Key, Buffer))
    981         return nullptr;
    982 
    983       if (!checkDuplicateOrUnknownKey(I->getKey(), Key, Keys))
    984         return nullptr;
    985 
    986       StringRef Value;
    987       if (Key == "name") {
    988         if (!parseScalarString(I->getValue(), Value, Buffer))
    989           return nullptr;
    990         Name = Value;
    991       } else if (Key == "type") {
    992         if (!parseScalarString(I->getValue(), Value, Buffer))
    993           return nullptr;
    994         if (Value == "file")
    995           Kind = EK_File;
    996         else if (Value == "directory")
    997           Kind = EK_Directory;
    998         else {
    999           error(I->getValue(), "unknown value for 'type'");
   1000           return nullptr;
   1001         }
   1002       } else if (Key == "contents") {
   1003         if (HasContents) {
   1004           error(I->getKey(),
   1005                 "entry already has 'contents' or 'external-contents'");
   1006           return nullptr;
   1007         }
   1008         HasContents = true;
   1009         yaml::SequenceNode *Contents =
   1010             dyn_cast<yaml::SequenceNode>(I->getValue());
   1011         if (!Contents) {
   1012           // FIXME: this is only for directories, what about files?
   1013           error(I->getValue(), "expected array");
   1014           return nullptr;
   1015         }
   1016 
   1017         for (yaml::SequenceNode::iterator I = Contents->begin(),
   1018                                           E = Contents->end();
   1019              I != E; ++I) {
   1020           if (std::unique_ptr<Entry> E = parseEntry(&*I))
   1021             EntryArrayContents.push_back(std::move(E));
   1022           else
   1023             return nullptr;
   1024         }
   1025       } else if (Key == "external-contents") {
   1026         if (HasContents) {
   1027           error(I->getKey(),
   1028                 "entry already has 'contents' or 'external-contents'");
   1029           return nullptr;
   1030         }
   1031         HasContents = true;
   1032         if (!parseScalarString(I->getValue(), Value, Buffer))
   1033           return nullptr;
   1034         ExternalContentsPath = Value;
   1035       } else if (Key == "use-external-name") {
   1036         bool Val;
   1037         if (!parseScalarBool(I->getValue(), Val))
   1038           return nullptr;
   1039         UseExternalName = Val ? RedirectingFileEntry::NK_External
   1040                               : RedirectingFileEntry::NK_Virtual;
   1041       } else {
   1042         llvm_unreachable("key missing from Keys");
   1043       }
   1044     }
   1045 
   1046     if (Stream.failed())
   1047       return nullptr;
   1048 
   1049     // check for missing keys
   1050     if (!HasContents) {
   1051       error(N, "missing key 'contents' or 'external-contents'");
   1052       return nullptr;
   1053     }
   1054     if (!checkMissingKeys(N, Keys))
   1055       return nullptr;
   1056 
   1057     // check invalid configuration
   1058     if (Kind == EK_Directory &&
   1059         UseExternalName != RedirectingFileEntry::NK_NotSet) {
   1060       error(N, "'use-external-name' is not supported for directories");
   1061       return nullptr;
   1062     }
   1063 
   1064     // Remove trailing slash(es), being careful not to remove the root path
   1065     StringRef Trimmed(Name);
   1066     size_t RootPathLen = sys::path::root_path(Trimmed).size();
   1067     while (Trimmed.size() > RootPathLen &&
   1068            sys::path::is_separator(Trimmed.back()))
   1069       Trimmed = Trimmed.slice(0, Trimmed.size()-1);
   1070     // Get the last component
   1071     StringRef LastComponent = sys::path::filename(Trimmed);
   1072 
   1073     std::unique_ptr<Entry> Result;
   1074     switch (Kind) {
   1075     case EK_File:
   1076       Result = llvm::make_unique<RedirectingFileEntry>(
   1077           LastComponent, std::move(ExternalContentsPath), UseExternalName);
   1078       break;
   1079     case EK_Directory:
   1080       Result = llvm::make_unique<RedirectingDirectoryEntry>(
   1081           LastComponent, std::move(EntryArrayContents),
   1082           Status("", getNextVirtualUniqueID(), sys::TimeValue::now(), 0, 0, 0,
   1083                  file_type::directory_file, sys::fs::all_all));
   1084       break;
   1085     }
   1086 
   1087     StringRef Parent = sys::path::parent_path(Trimmed);
   1088     if (Parent.empty())
   1089       return Result;
   1090 
   1091     // if 'name' contains multiple components, create implicit directory entries
   1092     for (sys::path::reverse_iterator I = sys::path::rbegin(Parent),
   1093                                      E = sys::path::rend(Parent);
   1094          I != E; ++I) {
   1095       std::vector<std::unique_ptr<Entry>> Entries;
   1096       Entries.push_back(std::move(Result));
   1097       Result = llvm::make_unique<RedirectingDirectoryEntry>(
   1098           *I, std::move(Entries),
   1099           Status("", getNextVirtualUniqueID(), sys::TimeValue::now(), 0, 0, 0,
   1100                  file_type::directory_file, sys::fs::all_all));
   1101     }
   1102     return Result;
   1103   }
   1104 
   1105 public:
   1106   RedirectingFileSystemParser(yaml::Stream &S) : Stream(S) {}
   1107 
   1108   // false on error
   1109   bool parse(yaml::Node *Root, RedirectingFileSystem *FS) {
   1110     yaml::MappingNode *Top = dyn_cast<yaml::MappingNode>(Root);
   1111     if (!Top) {
   1112       error(Root, "expected mapping node");
   1113       return false;
   1114     }
   1115 
   1116     KeyStatusPair Fields[] = {
   1117       KeyStatusPair("version", true),
   1118       KeyStatusPair("case-sensitive", false),
   1119       KeyStatusPair("use-external-names", false),
   1120       KeyStatusPair("roots", true),
   1121     };
   1122 
   1123     DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
   1124 
   1125     // Parse configuration and 'roots'
   1126     for (yaml::MappingNode::iterator I = Top->begin(), E = Top->end(); I != E;
   1127          ++I) {
   1128       SmallString<10> KeyBuffer;
   1129       StringRef Key;
   1130       if (!parseScalarString(I->getKey(), Key, KeyBuffer))
   1131         return false;
   1132 
   1133       if (!checkDuplicateOrUnknownKey(I->getKey(), Key, Keys))
   1134         return false;
   1135 
   1136       if (Key == "roots") {
   1137         yaml::SequenceNode *Roots = dyn_cast<yaml::SequenceNode>(I->getValue());
   1138         if (!Roots) {
   1139           error(I->getValue(), "expected array");
   1140           return false;
   1141         }
   1142 
   1143         for (yaml::SequenceNode::iterator I = Roots->begin(), E = Roots->end();
   1144              I != E; ++I) {
   1145           if (std::unique_ptr<Entry> E = parseEntry(&*I))
   1146             FS->Roots.push_back(std::move(E));
   1147           else
   1148             return false;
   1149         }
   1150       } else if (Key == "version") {
   1151         StringRef VersionString;
   1152         SmallString<4> Storage;
   1153         if (!parseScalarString(I->getValue(), VersionString, Storage))
   1154           return false;
   1155         int Version;
   1156         if (VersionString.getAsInteger<int>(10, Version)) {
   1157           error(I->getValue(), "expected integer");
   1158           return false;
   1159         }
   1160         if (Version < 0) {
   1161           error(I->getValue(), "invalid version number");
   1162           return false;
   1163         }
   1164         if (Version != 0) {
   1165           error(I->getValue(), "version mismatch, expected 0");
   1166           return false;
   1167         }
   1168       } else if (Key == "case-sensitive") {
   1169         if (!parseScalarBool(I->getValue(), FS->CaseSensitive))
   1170           return false;
   1171       } else if (Key == "use-external-names") {
   1172         if (!parseScalarBool(I->getValue(), FS->UseExternalNames))
   1173           return false;
   1174       } else {
   1175         llvm_unreachable("key missing from Keys");
   1176       }
   1177     }
   1178 
   1179     if (Stream.failed())
   1180       return false;
   1181 
   1182     if (!checkMissingKeys(Top, Keys))
   1183       return false;
   1184     return true;
   1185   }
   1186 };
   1187 } // end of anonymous namespace
   1188 
   1189 Entry::~Entry() = default;
   1190 
   1191 RedirectingFileSystem *RedirectingFileSystem::create(
   1192     std::unique_ptr<MemoryBuffer> Buffer, SourceMgr::DiagHandlerTy DiagHandler,
   1193     void *DiagContext, IntrusiveRefCntPtr<FileSystem> ExternalFS) {
   1194 
   1195   SourceMgr SM;
   1196   yaml::Stream Stream(Buffer->getMemBufferRef(), SM);
   1197 
   1198   SM.setDiagHandler(DiagHandler, DiagContext);
   1199   yaml::document_iterator DI = Stream.begin();
   1200   yaml::Node *Root = DI->getRoot();
   1201   if (DI == Stream.end() || !Root) {
   1202     SM.PrintMessage(SMLoc(), SourceMgr::DK_Error, "expected root node");
   1203     return nullptr;
   1204   }
   1205 
   1206   RedirectingFileSystemParser P(Stream);
   1207 
   1208   std::unique_ptr<RedirectingFileSystem> FS(
   1209       new RedirectingFileSystem(ExternalFS));
   1210   if (!P.parse(Root, FS.get()))
   1211     return nullptr;
   1212 
   1213   return FS.release();
   1214 }
   1215 
   1216 ErrorOr<Entry *> RedirectingFileSystem::lookupPath(const Twine &Path_) {
   1217   SmallString<256> Path;
   1218   Path_.toVector(Path);
   1219 
   1220   // Handle relative paths
   1221   if (std::error_code EC = makeAbsolute(Path))
   1222     return EC;
   1223 
   1224   if (Path.empty())
   1225     return make_error_code(llvm::errc::invalid_argument);
   1226 
   1227   sys::path::const_iterator Start = sys::path::begin(Path);
   1228   sys::path::const_iterator End = sys::path::end(Path);
   1229   for (const std::unique_ptr<Entry> &Root : Roots) {
   1230     ErrorOr<Entry *> Result = lookupPath(Start, End, Root.get());
   1231     if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
   1232       return Result;
   1233   }
   1234   return make_error_code(llvm::errc::no_such_file_or_directory);
   1235 }
   1236 
   1237 ErrorOr<Entry *>
   1238 RedirectingFileSystem::lookupPath(sys::path::const_iterator Start,
   1239                                   sys::path::const_iterator End, Entry *From) {
   1240   if (Start->equals("."))
   1241     ++Start;
   1242 
   1243   // FIXME: handle ..
   1244   if (CaseSensitive ? !Start->equals(From->getName())
   1245                     : !Start->equals_lower(From->getName()))
   1246     // failure to match
   1247     return make_error_code(llvm::errc::no_such_file_or_directory);
   1248 
   1249   ++Start;
   1250 
   1251   if (Start == End) {
   1252     // Match!
   1253     return From;
   1254   }
   1255 
   1256   auto *DE = dyn_cast<RedirectingDirectoryEntry>(From);
   1257   if (!DE)
   1258     return make_error_code(llvm::errc::not_a_directory);
   1259 
   1260   for (const std::unique_ptr<Entry> &DirEntry :
   1261        llvm::make_range(DE->contents_begin(), DE->contents_end())) {
   1262     ErrorOr<Entry *> Result = lookupPath(Start, End, DirEntry.get());
   1263     if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
   1264       return Result;
   1265   }
   1266   return make_error_code(llvm::errc::no_such_file_or_directory);
   1267 }
   1268 
   1269 static Status getRedirectedFileStatus(const Twine &Path, bool UseExternalNames,
   1270                                       Status ExternalStatus) {
   1271   Status S = ExternalStatus;
   1272   if (!UseExternalNames)
   1273     S = Status::copyWithNewName(S, Path.str());
   1274   S.IsVFSMapped = true;
   1275   return S;
   1276 }
   1277 
   1278 ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path, Entry *E) {
   1279   assert(E != nullptr);
   1280   if (auto *F = dyn_cast<RedirectingFileEntry>(E)) {
   1281     ErrorOr<Status> S = ExternalFS->status(F->getExternalContentsPath());
   1282     assert(!S || S->getName() == F->getExternalContentsPath());
   1283     if (S)
   1284       return getRedirectedFileStatus(Path, F->useExternalName(UseExternalNames),
   1285                                      *S);
   1286     return S;
   1287   } else { // directory
   1288     auto *DE = cast<RedirectingDirectoryEntry>(E);
   1289     return Status::copyWithNewName(DE->getStatus(), Path.str());
   1290   }
   1291 }
   1292 
   1293 ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path) {
   1294   ErrorOr<Entry *> Result = lookupPath(Path);
   1295   if (!Result)
   1296     return Result.getError();
   1297   return status(Path, *Result);
   1298 }
   1299 
   1300 namespace {
   1301 /// Provide a file wrapper with an overriden status.
   1302 class FileWithFixedStatus : public File {
   1303   std::unique_ptr<File> InnerFile;
   1304   Status S;
   1305 
   1306 public:
   1307   FileWithFixedStatus(std::unique_ptr<File> InnerFile, Status S)
   1308       : InnerFile(std::move(InnerFile)), S(S) {}
   1309 
   1310   ErrorOr<Status> status() override { return S; }
   1311   ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
   1312   getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
   1313             bool IsVolatile) override {
   1314     return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
   1315                                 IsVolatile);
   1316   }
   1317   std::error_code close() override { return InnerFile->close(); }
   1318 };
   1319 } // end anonymous namespace
   1320 
   1321 ErrorOr<std::unique_ptr<File>>
   1322 RedirectingFileSystem::openFileForRead(const Twine &Path) {
   1323   ErrorOr<Entry *> E = lookupPath(Path);
   1324   if (!E)
   1325     return E.getError();
   1326 
   1327   auto *F = dyn_cast<RedirectingFileEntry>(*E);
   1328   if (!F) // FIXME: errc::not_a_file?
   1329     return make_error_code(llvm::errc::invalid_argument);
   1330 
   1331   auto Result = ExternalFS->openFileForRead(F->getExternalContentsPath());
   1332   if (!Result)
   1333     return Result;
   1334 
   1335   auto ExternalStatus = (*Result)->status();
   1336   if (!ExternalStatus)
   1337     return ExternalStatus.getError();
   1338 
   1339   // FIXME: Update the status with the name and VFSMapped.
   1340   Status S = getRedirectedFileStatus(Path, F->useExternalName(UseExternalNames),
   1341                                      *ExternalStatus);
   1342   return std::unique_ptr<File>(
   1343       llvm::make_unique<FileWithFixedStatus>(std::move(*Result), S));
   1344 }
   1345 
   1346 IntrusiveRefCntPtr<FileSystem>
   1347 vfs::getVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,
   1348                     SourceMgr::DiagHandlerTy DiagHandler, void *DiagContext,
   1349                     IntrusiveRefCntPtr<FileSystem> ExternalFS) {
   1350   return RedirectingFileSystem::create(std::move(Buffer), DiagHandler,
   1351                                        DiagContext, ExternalFS);
   1352 }
   1353 
   1354 UniqueID vfs::getNextVirtualUniqueID() {
   1355   static std::atomic<unsigned> UID;
   1356   unsigned ID = ++UID;
   1357   // The following assumes that uint64_t max will never collide with a real
   1358   // dev_t value from the OS.
   1359   return UniqueID(std::numeric_limits<uint64_t>::max(), ID);
   1360 }
   1361 
   1362 #ifndef NDEBUG
   1363 static bool pathHasTraversal(StringRef Path) {
   1364   using namespace llvm::sys;
   1365   for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path)))
   1366     if (Comp == "." || Comp == "..")
   1367       return true;
   1368   return false;
   1369 }
   1370 #endif
   1371 
   1372 void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) {
   1373   assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute");
   1374   assert(sys::path::is_absolute(RealPath) && "real path not absolute");
   1375   assert(!pathHasTraversal(VirtualPath) && "path traversal is not supported");
   1376   Mappings.emplace_back(VirtualPath, RealPath);
   1377 }
   1378 
   1379 namespace {
   1380 class JSONWriter {
   1381   llvm::raw_ostream &OS;
   1382   SmallVector<StringRef, 16> DirStack;
   1383   inline unsigned getDirIndent() { return 4 * DirStack.size(); }
   1384   inline unsigned getFileIndent() { return 4 * (DirStack.size() + 1); }
   1385   bool containedIn(StringRef Parent, StringRef Path);
   1386   StringRef containedPart(StringRef Parent, StringRef Path);
   1387   void startDirectory(StringRef Path);
   1388   void endDirectory();
   1389   void writeEntry(StringRef VPath, StringRef RPath);
   1390 
   1391 public:
   1392   JSONWriter(llvm::raw_ostream &OS) : OS(OS) {}
   1393   void write(ArrayRef<YAMLVFSEntry> Entries, Optional<bool> IsCaseSensitive);
   1394 };
   1395 }
   1396 
   1397 bool JSONWriter::containedIn(StringRef Parent, StringRef Path) {
   1398   using namespace llvm::sys;
   1399   // Compare each path component.
   1400   auto IParent = path::begin(Parent), EParent = path::end(Parent);
   1401   for (auto IChild = path::begin(Path), EChild = path::end(Path);
   1402        IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
   1403     if (*IParent != *IChild)
   1404       return false;
   1405   }
   1406   // Have we exhausted the parent path?
   1407   return IParent == EParent;
   1408 }
   1409 
   1410 StringRef JSONWriter::containedPart(StringRef Parent, StringRef Path) {
   1411   assert(!Parent.empty());
   1412   assert(containedIn(Parent, Path));
   1413   return Path.slice(Parent.size() + 1, StringRef::npos);
   1414 }
   1415 
   1416 void JSONWriter::startDirectory(StringRef Path) {
   1417   StringRef Name =
   1418       DirStack.empty() ? Path : containedPart(DirStack.back(), Path);
   1419   DirStack.push_back(Path);
   1420   unsigned Indent = getDirIndent();
   1421   OS.indent(Indent) << "{\n";
   1422   OS.indent(Indent + 2) << "'type': 'directory',\n";
   1423   OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(Name) << "\",\n";
   1424   OS.indent(Indent + 2) << "'contents': [\n";
   1425 }
   1426 
   1427 void JSONWriter::endDirectory() {
   1428   unsigned Indent = getDirIndent();
   1429   OS.indent(Indent + 2) << "]\n";
   1430   OS.indent(Indent) << "}";
   1431 
   1432   DirStack.pop_back();
   1433 }
   1434 
   1435 void JSONWriter::writeEntry(StringRef VPath, StringRef RPath) {
   1436   unsigned Indent = getFileIndent();
   1437   OS.indent(Indent) << "{\n";
   1438   OS.indent(Indent + 2) << "'type': 'file',\n";
   1439   OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(VPath) << "\",\n";
   1440   OS.indent(Indent + 2) << "'external-contents': \""
   1441                         << llvm::yaml::escape(RPath) << "\"\n";
   1442   OS.indent(Indent) << "}";
   1443 }
   1444 
   1445 void JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries,
   1446                        Optional<bool> IsCaseSensitive) {
   1447   using namespace llvm::sys;
   1448 
   1449   OS << "{\n"
   1450         "  'version': 0,\n";
   1451   if (IsCaseSensitive.hasValue())
   1452     OS << "  'case-sensitive': '"
   1453        << (IsCaseSensitive.getValue() ? "true" : "false") << "',\n";
   1454   OS << "  'roots': [\n";
   1455 
   1456   if (!Entries.empty()) {
   1457     const YAMLVFSEntry &Entry = Entries.front();
   1458     startDirectory(path::parent_path(Entry.VPath));
   1459     writeEntry(path::filename(Entry.VPath), Entry.RPath);
   1460 
   1461     for (const auto &Entry : Entries.slice(1)) {
   1462       StringRef Dir = path::parent_path(Entry.VPath);
   1463       if (Dir == DirStack.back())
   1464         OS << ",\n";
   1465       else {
   1466         while (!DirStack.empty() && !containedIn(DirStack.back(), Dir)) {
   1467           OS << "\n";
   1468           endDirectory();
   1469         }
   1470         OS << ",\n";
   1471         startDirectory(Dir);
   1472       }
   1473       writeEntry(path::filename(Entry.VPath), Entry.RPath);
   1474     }
   1475 
   1476     while (!DirStack.empty()) {
   1477       OS << "\n";
   1478       endDirectory();
   1479     }
   1480     OS << "\n";
   1481   }
   1482 
   1483   OS << "  ]\n"
   1484      << "}\n";
   1485 }
   1486 
   1487 void YAMLVFSWriter::write(llvm::raw_ostream &OS) {
   1488   std::sort(Mappings.begin(), Mappings.end(),
   1489             [](const YAMLVFSEntry &LHS, const YAMLVFSEntry &RHS) {
   1490     return LHS.VPath < RHS.VPath;
   1491   });
   1492 
   1493   JSONWriter(OS).write(Mappings, IsCaseSensitive);
   1494 }
   1495 
   1496 VFSFromYamlDirIterImpl::VFSFromYamlDirIterImpl(
   1497     const Twine &_Path, RedirectingFileSystem &FS,
   1498     RedirectingDirectoryEntry::iterator Begin,
   1499     RedirectingDirectoryEntry::iterator End, std::error_code &EC)
   1500     : Dir(_Path.str()), FS(FS), Current(Begin), End(End) {
   1501   if (Current != End) {
   1502     SmallString<128> PathStr(Dir);
   1503     llvm::sys::path::append(PathStr, (*Current)->getName());
   1504     llvm::ErrorOr<vfs::Status> S = FS.status(PathStr);
   1505     if (S)
   1506       CurrentEntry = *S;
   1507     else
   1508       EC = S.getError();
   1509   }
   1510 }
   1511 
   1512 std::error_code VFSFromYamlDirIterImpl::increment() {
   1513   assert(Current != End && "cannot iterate past end");
   1514   if (++Current != End) {
   1515     SmallString<128> PathStr(Dir);
   1516     llvm::sys::path::append(PathStr, (*Current)->getName());
   1517     llvm::ErrorOr<vfs::Status> S = FS.status(PathStr);
   1518     if (!S)
   1519       return S.getError();
   1520     CurrentEntry = *S;
   1521   } else {
   1522     CurrentEntry = Status();
   1523   }
   1524   return std::error_code();
   1525 }
   1526 
   1527 vfs::recursive_directory_iterator::recursive_directory_iterator(FileSystem &FS_,
   1528                                                            const Twine &Path,
   1529                                                            std::error_code &EC)
   1530     : FS(&FS_) {
   1531   directory_iterator I = FS->dir_begin(Path, EC);
   1532   if (!EC && I != directory_iterator()) {
   1533     State = std::make_shared<IterState>();
   1534     State->push(I);
   1535   }
   1536 }
   1537 
   1538 vfs::recursive_directory_iterator &
   1539 recursive_directory_iterator::increment(std::error_code &EC) {
   1540   assert(FS && State && !State->empty() && "incrementing past end");
   1541   assert(State->top()->isStatusKnown() && "non-canonical end iterator");
   1542   vfs::directory_iterator End;
   1543   if (State->top()->isDirectory()) {
   1544     vfs::directory_iterator I = FS->dir_begin(State->top()->getName(), EC);
   1545     if (EC)
   1546       return *this;
   1547     if (I != End) {
   1548       State->push(I);
   1549       return *this;
   1550     }
   1551   }
   1552 
   1553   while (!State->empty() && State->top().increment(EC) == End)
   1554     State->pop();
   1555 
   1556   if (State->empty())
   1557     State.reset(); // end iterator
   1558 
   1559   return *this;
   1560 }
   1561