1651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//===- VirtualFileSystem.cpp - Virtual File System Layer --------*- C++ -*-===//
2651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//
3651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//                     The LLVM Compiler Infrastructure
4651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//
5651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// This file is distributed under the University of Illinois Open Source
6651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// License. See LICENSE.TXT for details.
7651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//
8651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//===----------------------------------------------------------------------===//
9651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// This file implements the VirtualFileSystem interface.
10651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//===----------------------------------------------------------------------===//
11651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
12651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "clang/Basic/VirtualFileSystem.h"
13651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "llvm/ADT/DenseMap.h"
146bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines#include "llvm/ADT/iterator_range.h"
15651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "llvm/ADT/STLExtras.h"
16651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "llvm/ADT/StringExtras.h"
17ef8225444452a1486bd721f3285301fe84643b00Stephen Hines#include "llvm/ADT/StringSet.h"
18ef8225444452a1486bd721f3285301fe84643b00Stephen Hines#include "llvm/Support/Errc.h"
19651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "llvm/Support/MemoryBuffer.h"
20651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "llvm/Support/Path.h"
21651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "llvm/Support/YAMLParser.h"
22651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include <atomic>
23651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include <memory>
24651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
25651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesusing namespace clang;
26651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesusing namespace clang::vfs;
27651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesusing namespace llvm;
28651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesusing llvm::sys::fs::file_status;
29651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesusing llvm::sys::fs::file_type;
30651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesusing llvm::sys::fs::perms;
31651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesusing llvm::sys::fs::UniqueID;
32651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
33651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesStatus::Status(const file_status &Status)
34651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    : UID(Status.getUniqueID()), MTime(Status.getLastModificationTime()),
35651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()),
366bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      Type(Status.type()), Perms(Status.permissions()), IsVFSMapped(false)  {}
37651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
38651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesStatus::Status(StringRef Name, StringRef ExternalName, UniqueID UID,
39651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines               sys::TimeValue MTime, uint32_t User, uint32_t Group,
40651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines               uint64_t Size, file_type Type, perms Perms)
41651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    : Name(Name), UID(UID), MTime(MTime), User(User), Group(Group), Size(Size),
426bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      Type(Type), Perms(Perms), IsVFSMapped(false) {}
43651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
44651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesbool Status::equivalent(const Status &Other) const {
45651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return getUniqueID() == Other.getUniqueID();
46651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
47651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesbool Status::isDirectory() const {
48651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return Type == file_type::directory_file;
49651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
50651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesbool Status::isRegularFile() const {
51651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return Type == file_type::regular_file;
52651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
53651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesbool Status::isOther() const {
54651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return exists() && !isRegularFile() && !isDirectory() && !isSymlink();
55651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
56651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesbool Status::isSymlink() const {
57651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return Type == file_type::symlink_file;
58651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
59651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesbool Status::isStatusKnown() const {
60651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return Type != file_type::status_error;
61651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
62651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesbool Status::exists() const {
63651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return isStatusKnown() && Type != file_type::file_not_found;
64651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
65651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
66651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesFile::~File() {}
67651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
68651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesFileSystem::~FileSystem() {}
69651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
70ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesstd::error_code FileSystem::getBufferForFile(
71ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    const llvm::Twine &Name, std::unique_ptr<MemoryBuffer> &Result,
72ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    int64_t FileSize, bool RequiresNullTerminator, bool IsVolatile) {
73651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  std::unique_ptr<File> F;
74ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  if (std::error_code EC = openFileForRead(Name, F))
75651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return EC;
76651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
77ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code EC =
78ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      F->getBuffer(Name, Result, FileSize, RequiresNullTerminator, IsVolatile);
79651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return EC;
80651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
81651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
82651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//===-----------------------------------------------------------------------===/
83651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// RealFileSystem implementation
84651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//===-----------------------------------------------------------------------===/
85651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
86651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesnamespace {
87651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \brief Wrapper around a raw file descriptor.
88651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesclass RealFile : public File {
89651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  int FD;
90651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Status S;
91651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  friend class RealFileSystem;
92651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  RealFile(int FD) : FD(FD) {
93651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    assert(FD >= 0 && "Invalid or inactive file descriptor");
94651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
95651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
96651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinespublic:
97651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ~RealFile();
98651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ErrorOr<Status> status() override;
99ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code getBuffer(const Twine &Name,
100ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                            std::unique_ptr<MemoryBuffer> &Result,
101ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                            int64_t FileSize = -1,
102ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                            bool RequiresNullTerminator = true,
103ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                            bool IsVolatile = false) override;
104ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code close() override;
105651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  void setName(StringRef Name) override;
106651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines};
107651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines} // end anonymous namespace
108651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesRealFile::~RealFile() { close(); }
109651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
110651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesErrorOr<Status> RealFile::status() {
111651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  assert(FD != -1 && "cannot stat closed file");
112651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (!S.isStatusKnown()) {
113651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    file_status RealStatus;
114ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    if (std::error_code EC = sys::fs::status(FD, RealStatus))
115651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return EC;
116651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    Status NewS(RealStatus);
117651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    NewS.setName(S.getName());
118651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    S = std::move(NewS);
119651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
120651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return S;
121651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
122651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
123ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesstd::error_code RealFile::getBuffer(const Twine &Name,
124ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                    std::unique_ptr<MemoryBuffer> &Result,
125ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                    int64_t FileSize,
126ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                    bool RequiresNullTerminator,
127ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                    bool IsVolatile) {
128651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  assert(FD != -1 && "cannot get buffer for closed file");
129ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
130ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      MemoryBuffer::getOpenFile(FD, Name.str().c_str(), FileSize,
131ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                RequiresNullTerminator, IsVolatile);
132ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  if (std::error_code EC = BufferOrErr.getError())
133ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    return EC;
134ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Result = std::move(BufferOrErr.get());
135ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  return std::error_code();
136651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
137651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
138651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// FIXME: This is terrible, we need this for ::close.
139651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#if !defined(_MSC_VER) && !defined(__MINGW32__)
140651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include <unistd.h>
141651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include <sys/uio.h>
142651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#else
143651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include <io.h>
144651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#ifndef S_ISFIFO
145651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#define S_ISFIFO(x) (0)
146651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#endif
147651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#endif
148ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesstd::error_code RealFile::close() {
149651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (::close(FD))
150ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    return std::error_code(errno, std::generic_category());
151651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FD = -1;
152ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  return std::error_code();
153651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
154651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
155651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesvoid RealFile::setName(StringRef Name) {
156651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  S.setName(Name);
157651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
158651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
159651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesnamespace {
160651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \brief The file system according to your operating system.
161651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesclass RealFileSystem : public FileSystem {
162651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinespublic:
163651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ErrorOr<Status> status(const Twine &Path) override;
164ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code openFileForRead(const Twine &Path,
165ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                  std::unique_ptr<File> &Result) override;
166ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
167651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines};
168651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines} // end anonymous namespace
169651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
170651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesErrorOr<Status> RealFileSystem::status(const Twine &Path) {
171651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  sys::fs::file_status RealStatus;
172ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  if (std::error_code EC = sys::fs::status(Path, RealStatus))
173651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return EC;
174651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Status Result(RealStatus);
175651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Result.setName(Path.str());
176651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return Result;
177651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
178651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
179ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesstd::error_code RealFileSystem::openFileForRead(const Twine &Name,
180ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                                std::unique_ptr<File> &Result) {
181651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  int FD;
182ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  if (std::error_code EC = sys::fs::openFileForRead(Name, FD))
183651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return EC;
184651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Result.reset(new RealFile(FD));
185651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Result->setName(Name.str());
186ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  return std::error_code();
187651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
188651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
189651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesIntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
190651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  static IntrusiveRefCntPtr<FileSystem> FS = new RealFileSystem();
191651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return FS;
192651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
193651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
194ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesnamespace {
195ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesclass RealFSDirIter : public clang::vfs::detail::DirIterImpl {
196ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::string Path;
197ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  llvm::sys::fs::directory_iterator Iter;
198ef8225444452a1486bd721f3285301fe84643b00Stephen Hinespublic:
199ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  RealFSDirIter(const Twine &_Path, std::error_code &EC)
200ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      : Path(_Path.str()), Iter(Path, EC) {
201ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    if (!EC && Iter != llvm::sys::fs::directory_iterator()) {
202ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      llvm::sys::fs::file_status S;
203ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      EC = Iter->status(S);
204ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      if (!EC) {
205ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        CurrentEntry = Status(S);
206ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        CurrentEntry.setName(Iter->path());
207ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      }
208ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    }
209ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
210ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
211ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code increment() override {
212ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    std::error_code EC;
213ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    Iter.increment(EC);
214ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    if (EC) {
215ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      return EC;
216ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    } else if (Iter == llvm::sys::fs::directory_iterator()) {
217ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      CurrentEntry = Status();
218ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    } else {
219ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      llvm::sys::fs::file_status S;
220ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      EC = Iter->status(S);
221ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      CurrentEntry = Status(S);
222ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      CurrentEntry.setName(Iter->path());
223ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    }
224ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    return EC;
225ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
226ef8225444452a1486bd721f3285301fe84643b00Stephen Hines};
227ef8225444452a1486bd721f3285301fe84643b00Stephen Hines}
228ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
229ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesdirectory_iterator RealFileSystem::dir_begin(const Twine &Dir,
230ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                             std::error_code &EC) {
231ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  return directory_iterator(std::make_shared<RealFSDirIter>(Dir, EC));
232ef8225444452a1486bd721f3285301fe84643b00Stephen Hines}
233ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
234651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//===-----------------------------------------------------------------------===/
235651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// OverlayFileSystem implementation
236651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//===-----------------------------------------------------------------------===/
237651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesOverlayFileSystem::OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> BaseFS) {
238651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  pushOverlay(BaseFS);
239651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
240651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
241651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesvoid OverlayFileSystem::pushOverlay(IntrusiveRefCntPtr<FileSystem> FS) {
242651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FSList.push_back(FS);
243651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
244651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
245651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesErrorOr<Status> OverlayFileSystem::status(const Twine &Path) {
246651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // FIXME: handle symlinks that cross file systems
247651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
248651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    ErrorOr<Status> Status = (*I)->status(Path);
249ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    if (Status || Status.getError() != llvm::errc::no_such_file_or_directory)
250651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return Status;
251651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
252ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  return make_error_code(llvm::errc::no_such_file_or_directory);
253651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
254651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
255ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesstd::error_code
256ef8225444452a1486bd721f3285301fe84643b00Stephen HinesOverlayFileSystem::openFileForRead(const llvm::Twine &Path,
257ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                   std::unique_ptr<File> &Result) {
258651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // FIXME: handle symlinks that cross file systems
259651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
260ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    std::error_code EC = (*I)->openFileForRead(Path, Result);
261ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    if (!EC || EC != llvm::errc::no_such_file_or_directory)
262651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return EC;
263651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
264ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  return make_error_code(llvm::errc::no_such_file_or_directory);
265ef8225444452a1486bd721f3285301fe84643b00Stephen Hines}
266ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
267ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesclang::vfs::detail::DirIterImpl::~DirIterImpl() { }
268ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
269ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesnamespace {
270ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesclass OverlayFSDirIterImpl : public clang::vfs::detail::DirIterImpl {
271ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  OverlayFileSystem &Overlays;
272ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::string Path;
273ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  OverlayFileSystem::iterator CurrentFS;
274ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  directory_iterator CurrentDirIter;
275ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  llvm::StringSet<> SeenNames;
276ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
277ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code incrementFS() {
278ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    assert(CurrentFS != Overlays.overlays_end() && "incrementing past end");
279ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    ++CurrentFS;
280ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    for (auto E = Overlays.overlays_end(); CurrentFS != E; ++CurrentFS) {
281ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      std::error_code EC;
282ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC);
283ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      if (EC && EC != errc::no_such_file_or_directory)
284ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        return EC;
285ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      if (CurrentDirIter != directory_iterator())
286ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        break; // found
287ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    }
288ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    return std::error_code();
289ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
290ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
291ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code incrementDirIter(bool IsFirstTime) {
292ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    assert((IsFirstTime || CurrentDirIter != directory_iterator()) &&
293ef8225444452a1486bd721f3285301fe84643b00Stephen Hines           "incrementing past end");
294ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    std::error_code EC;
295ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    if (!IsFirstTime)
296ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      CurrentDirIter.increment(EC);
297ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    if (!EC && CurrentDirIter == directory_iterator())
298ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      EC = incrementFS();
299ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    return EC;
300ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
301ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
302ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code incrementImpl(bool IsFirstTime) {
303ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    while (true) {
304ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      std::error_code EC = incrementDirIter(IsFirstTime);
305ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      if (EC || CurrentDirIter == directory_iterator()) {
306ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        CurrentEntry = Status();
307ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        return EC;
308ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      }
309ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      CurrentEntry = *CurrentDirIter;
310ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      StringRef Name = llvm::sys::path::filename(CurrentEntry.getName());
311ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      if (SeenNames.insert(Name))
312ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        return EC; // name not seen before
313ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    }
314ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    llvm_unreachable("returned above");
315ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
316ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
317ef8225444452a1486bd721f3285301fe84643b00Stephen Hinespublic:
318ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  OverlayFSDirIterImpl(const Twine &Path, OverlayFileSystem &FS,
319ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                       std::error_code &EC)
320ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      : Overlays(FS), Path(Path.str()), CurrentFS(Overlays.overlays_begin()) {
321ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC);
322ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    EC = incrementImpl(true);
323ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
324ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
325ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code increment() override { return incrementImpl(false); }
326ef8225444452a1486bd721f3285301fe84643b00Stephen Hines};
327ef8225444452a1486bd721f3285301fe84643b00Stephen Hines} // end anonymous namespace
328ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
329ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesdirectory_iterator OverlayFileSystem::dir_begin(const Twine &Dir,
330ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                                std::error_code &EC) {
331ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  return directory_iterator(
332ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      std::make_shared<OverlayFSDirIterImpl>(Dir, *this, EC));
333651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
334651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
335651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//===-----------------------------------------------------------------------===/
336651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// VFSFromYAML implementation
337651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//===-----------------------------------------------------------------------===/
338651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
339651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// Allow DenseMap<StringRef, ...>.  This is useful below because we know all the
340651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// strings are literals and will outlive the map, and there is no reason to
341651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// store them.
342651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesnamespace llvm {
343651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  template<>
344651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  struct DenseMapInfo<StringRef> {
345651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    // This assumes that "" will never be a valid key.
346651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    static inline StringRef getEmptyKey() { return StringRef(""); }
347651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    static inline StringRef getTombstoneKey() { return StringRef(); }
348651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    static unsigned getHashValue(StringRef Val) { return HashString(Val); }
349651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    static bool isEqual(StringRef LHS, StringRef RHS) { return LHS == RHS; }
350651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  };
351651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
352651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
353651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesnamespace {
354651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
355651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesenum EntryKind {
356651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EK_Directory,
357651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EK_File
358651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines};
359651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
360651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \brief A single file or directory in the VFS.
361651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesclass Entry {
362651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EntryKind Kind;
363651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  std::string Name;
364651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
365651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinespublic:
366651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  virtual ~Entry();
367651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Entry(EntryKind K, StringRef Name) : Kind(K), Name(Name) {}
368651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  StringRef getName() const { return Name; }
369651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EntryKind getKind() const { return Kind; }
370651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines};
371651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
372651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesclass DirectoryEntry : public Entry {
373651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  std::vector<Entry *> Contents;
374651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Status S;
375651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
376651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinespublic:
377651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  virtual ~DirectoryEntry();
378651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  DirectoryEntry(StringRef Name, std::vector<Entry *> Contents, Status S)
379651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      : Entry(EK_Directory, Name), Contents(std::move(Contents)),
380651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        S(std::move(S)) {}
381651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Status getStatus() { return S; }
382651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  typedef std::vector<Entry *>::iterator iterator;
383651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  iterator contents_begin() { return Contents.begin(); }
384651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  iterator contents_end() { return Contents.end(); }
385651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  static bool classof(const Entry *E) { return E->getKind() == EK_Directory; }
386651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines};
387651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
388651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesclass FileEntry : public Entry {
389651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinespublic:
390651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  enum NameKind {
391651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    NK_NotSet,
392651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    NK_External,
393651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    NK_Virtual
394651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  };
395651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesprivate:
396651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  std::string ExternalContentsPath;
397651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  NameKind UseName;
398651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinespublic:
399651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FileEntry(StringRef Name, StringRef ExternalContentsPath, NameKind UseName)
400651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      : Entry(EK_File, Name), ExternalContentsPath(ExternalContentsPath),
401651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        UseName(UseName) {}
402651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  StringRef getExternalContentsPath() const { return ExternalContentsPath; }
403651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// \brief whether to use the external path as the name for this file.
404651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  bool useExternalName(bool GlobalUseExternalName) const {
405651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return UseName == NK_NotSet ? GlobalUseExternalName
406651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                                : (UseName == NK_External);
407651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
408651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  static bool classof(const Entry *E) { return E->getKind() == EK_File; }
409651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines};
410651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
411ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesclass VFSFromYAML;
412ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
413ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesclass VFSFromYamlDirIterImpl : public clang::vfs::detail::DirIterImpl {
414ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::string Dir;
415ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  VFSFromYAML &FS;
416ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  DirectoryEntry::iterator Current, End;
417ef8225444452a1486bd721f3285301fe84643b00Stephen Hinespublic:
418ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  VFSFromYamlDirIterImpl(const Twine &Path, VFSFromYAML &FS,
419ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                         DirectoryEntry::iterator Begin,
420ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                         DirectoryEntry::iterator End, std::error_code &EC);
421ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code increment() override;
422ef8225444452a1486bd721f3285301fe84643b00Stephen Hines};
423ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
424651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \brief A virtual file system parsed from a YAML file.
425651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///
426651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// Currently, this class allows creating virtual directories and mapping
427651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// virtual file paths to existing external files, available in \c ExternalFS.
428651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///
429651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// The basic structure of the parsed file is:
430651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \verbatim
431651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// {
432651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'version': <version number>,
433651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   <optional configuration>
434651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'roots': [
435651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///              <directory entries>
436651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///            ]
437651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// }
438651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \endverbatim
439651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///
440651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// All configuration options are optional.
441651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'case-sensitive': <boolean, default=true>
442651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'use-external-names': <boolean, default=true>
443651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///
444651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// Virtual directories are represented as
445651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \verbatim
446651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// {
447651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'type': 'directory',
448651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'name': <string>,
449651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'contents': [ <file or directory entries> ]
450651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// }
451651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \endverbatim
452651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///
453651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// The default attributes for virtual directories are:
454651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \verbatim
455651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// MTime = now() when created
456651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// Perms = 0777
457651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// User = Group = 0
458651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// Size = 0
459651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// UniqueID = unspecified unique value
460651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \endverbatim
461651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///
462651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// Re-mapped files are represented as
463651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \verbatim
464651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// {
465651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'type': 'file',
466651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'name': <string>,
467651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'use-external-name': <boolean> # Optional
468651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'external-contents': <path to external file>)
469651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// }
470651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \endverbatim
471651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///
472651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// and inherit their attributes from the external contents.
473651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///
474651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// In both cases, the 'name' field may contain multiple path components (e.g.
475651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// /path/to/file). However, any directory that contains more than one child
476651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// must be uniquely represented by a directory entry.
477651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesclass VFSFromYAML : public vfs::FileSystem {
478651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  std::vector<Entry *> Roots; ///< The root(s) of the virtual file system.
479651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// \brief The file system to use for external references.
480651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<FileSystem> ExternalFS;
481651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
482651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// @name Configuration
483651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// @{
484651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
485651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// \brief Whether to perform case-sensitive comparisons.
486651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ///
487651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// Currently, case-insensitive matching only works correctly with ASCII.
488651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  bool CaseSensitive;
489651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
490651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// \brief Whether to use to use the value of 'external-contents' for the
491651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// names of files.  This global value is overridable on a per-file basis.
492651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  bool UseExternalNames;
493651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// @}
494651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
495651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  friend class VFSFromYAMLParser;
496651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
497651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesprivate:
498651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  VFSFromYAML(IntrusiveRefCntPtr<FileSystem> ExternalFS)
499651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      : ExternalFS(ExternalFS), CaseSensitive(true), UseExternalNames(true) {}
500651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
501651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// \brief Looks up \p Path in \c Roots.
502651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ErrorOr<Entry *> lookupPath(const Twine &Path);
503651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
504651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// \brief Looks up the path <tt>[Start, End)</tt> in \p From, possibly
505651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// recursing into the contents of \p From if it is a directory.
506651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ErrorOr<Entry *> lookupPath(sys::path::const_iterator Start,
507651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                              sys::path::const_iterator End, Entry *From);
508651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
509ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  /// \brief Get the status of a given an \c Entry.
510ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ErrorOr<Status> status(const Twine &Path, Entry *E);
511ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
512651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinespublic:
513651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ~VFSFromYAML();
514651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
515651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// \brief Parses \p Buffer, which is expected to be in YAML format and
516651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// returns a virtual file system representing its contents.
517651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ///
518651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// Takes ownership of \p Buffer.
519651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  static VFSFromYAML *create(MemoryBuffer *Buffer,
520651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                             SourceMgr::DiagHandlerTy DiagHandler,
521651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                             void *DiagContext,
522651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                             IntrusiveRefCntPtr<FileSystem> ExternalFS);
523651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
524651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ErrorOr<Status> status(const Twine &Path) override;
525ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code openFileForRead(const Twine &Path,
526ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                  std::unique_ptr<File> &Result) override;
527ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
528ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override{
529ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    ErrorOr<Entry *> E = lookupPath(Dir);
530ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    if (!E) {
531ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      EC = E.getError();
532ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      return directory_iterator();
533ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    }
534ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    ErrorOr<Status> S = status(Dir, *E);
535ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    if (!S) {
536ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      EC = S.getError();
537ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      return directory_iterator();
538ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    }
539ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    if (!S->isDirectory()) {
540ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      EC = std::error_code(static_cast<int>(errc::not_a_directory),
541ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                           std::system_category());
542ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      return directory_iterator();
543ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    }
544ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
545ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    DirectoryEntry *D = cast<DirectoryEntry>(*E);
546ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    return directory_iterator(std::make_shared<VFSFromYamlDirIterImpl>(Dir,
547ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        *this, D->contents_begin(), D->contents_end(), EC));
548ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
549651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines};
550651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
551651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \brief A helper class to hold the common YAML parsing state.
552651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesclass VFSFromYAMLParser {
553651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  yaml::Stream &Stream;
554651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
555651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  void error(yaml::Node *N, const Twine &Msg) {
556651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    Stream.printError(N, Msg);
557651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
558651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
559651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // false on error
560651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  bool parseScalarString(yaml::Node *N, StringRef &Result,
561651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                         SmallVectorImpl<char> &Storage) {
562651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    yaml::ScalarNode *S = dyn_cast<yaml::ScalarNode>(N);
563651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (!S) {
564651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      error(N, "expected string");
565651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return false;
566651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
567651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    Result = S->getValue(Storage);
568651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return true;
569651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
570651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
571651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // false on error
572651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  bool parseScalarBool(yaml::Node *N, bool &Result) {
573651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    SmallString<5> Storage;
574651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    StringRef Value;
575651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (!parseScalarString(N, Value, Storage))
576651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return false;
577651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
578651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (Value.equals_lower("true") || Value.equals_lower("on") ||
579651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        Value.equals_lower("yes") || Value == "1") {
580651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Result = true;
581651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return true;
582651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    } else if (Value.equals_lower("false") || Value.equals_lower("off") ||
583651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines               Value.equals_lower("no") || Value == "0") {
584651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Result = false;
585651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return true;
586651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
587651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
588651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    error(N, "expected boolean value");
589651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return false;
590651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
591651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
592651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  struct KeyStatus {
593651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    KeyStatus(bool Required=false) : Required(Required), Seen(false) {}
594651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    bool Required;
595651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    bool Seen;
596651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  };
597651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  typedef std::pair<StringRef, KeyStatus> KeyStatusPair;
598651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
599651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // false on error
600651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  bool checkDuplicateOrUnknownKey(yaml::Node *KeyNode, StringRef Key,
601651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                                  DenseMap<StringRef, KeyStatus> &Keys) {
602651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (!Keys.count(Key)) {
603651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      error(KeyNode, "unknown key");
604651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return false;
605651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
606651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    KeyStatus &S = Keys[Key];
607651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (S.Seen) {
608651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      error(KeyNode, Twine("duplicate key '") + Key + "'");
609651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return false;
610651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
611651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    S.Seen = true;
612651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return true;
613651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
614651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
615651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // false on error
616651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  bool checkMissingKeys(yaml::Node *Obj, DenseMap<StringRef, KeyStatus> &Keys) {
617651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    for (DenseMap<StringRef, KeyStatus>::iterator I = Keys.begin(),
618651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines         E = Keys.end();
619651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines         I != E; ++I) {
620651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      if (I->second.Required && !I->second.Seen) {
621651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        error(Obj, Twine("missing key '") + I->first + "'");
622651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        return false;
623651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      }
624651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
625651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return true;
626651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
627651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
628651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Entry *parseEntry(yaml::Node *N) {
629651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    yaml::MappingNode *M = dyn_cast<yaml::MappingNode>(N);
630651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (!M) {
631651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      error(N, "expected mapping node for file or directory entry");
6326bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      return nullptr;
633651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
634651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
635651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    KeyStatusPair Fields[] = {
636651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      KeyStatusPair("name", true),
637651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      KeyStatusPair("type", true),
638651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      KeyStatusPair("contents", false),
639651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      KeyStatusPair("external-contents", false),
640651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      KeyStatusPair("use-external-name", false),
641651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    };
642651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
643651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    DenseMap<StringRef, KeyStatus> Keys(
644651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        &Fields[0], Fields + sizeof(Fields)/sizeof(Fields[0]));
645651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
646651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    bool HasContents = false; // external or otherwise
647651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    std::vector<Entry *> EntryArrayContents;
648651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    std::string ExternalContentsPath;
649651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    std::string Name;
650651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    FileEntry::NameKind UseExternalName = FileEntry::NK_NotSet;
651651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    EntryKind Kind;
652651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
653651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    for (yaml::MappingNode::iterator I = M->begin(), E = M->end(); I != E;
654651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines         ++I) {
655651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      StringRef Key;
656651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      // Reuse the buffer for key and value, since we don't look at key after
657651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      // parsing value.
658651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      SmallString<256> Buffer;
659651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      if (!parseScalarString(I->getKey(), Key, Buffer))
6606bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        return nullptr;
661651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
662651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      if (!checkDuplicateOrUnknownKey(I->getKey(), Key, Keys))
6636bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        return nullptr;
664651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
665651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      StringRef Value;
666651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      if (Key == "name") {
667651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (!parseScalarString(I->getValue(), Value, Buffer))
6686bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          return nullptr;
669651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        Name = Value;
670651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      } else if (Key == "type") {
671651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (!parseScalarString(I->getValue(), Value, Buffer))
6726bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          return nullptr;
673651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (Value == "file")
674651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          Kind = EK_File;
675651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        else if (Value == "directory")
676651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          Kind = EK_Directory;
677651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        else {
678651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          error(I->getValue(), "unknown value for 'type'");
6796bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          return nullptr;
680651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
681651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      } else if (Key == "contents") {
682651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (HasContents) {
683651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          error(I->getKey(),
684651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                "entry already has 'contents' or 'external-contents'");
6856bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          return nullptr;
686651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
687651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        HasContents = true;
688651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        yaml::SequenceNode *Contents =
689651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines            dyn_cast<yaml::SequenceNode>(I->getValue());
690651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (!Contents) {
691651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          // FIXME: this is only for directories, what about files?
692651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          error(I->getValue(), "expected array");
6936bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          return nullptr;
694651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
695651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
696651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        for (yaml::SequenceNode::iterator I = Contents->begin(),
697651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                                          E = Contents->end();
698651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines             I != E; ++I) {
699651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          if (Entry *E = parseEntry(&*I))
700651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines            EntryArrayContents.push_back(E);
701651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          else
7026bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            return nullptr;
703651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
704651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      } else if (Key == "external-contents") {
705651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (HasContents) {
706651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          error(I->getKey(),
707651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                "entry already has 'contents' or 'external-contents'");
7086bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          return nullptr;
709651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
710651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        HasContents = true;
711651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (!parseScalarString(I->getValue(), Value, Buffer))
7126bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          return nullptr;
713651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        ExternalContentsPath = Value;
714651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      } else if (Key == "use-external-name") {
715651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        bool Val;
716651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (!parseScalarBool(I->getValue(), Val))
7176bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          return nullptr;
718651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        UseExternalName = Val ? FileEntry::NK_External : FileEntry::NK_Virtual;
719651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      } else {
720651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        llvm_unreachable("key missing from Keys");
721651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      }
722651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
723651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
724651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (Stream.failed())
7256bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      return nullptr;
726651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
727651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    // check for missing keys
728651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (!HasContents) {
729651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      error(N, "missing key 'contents' or 'external-contents'");
7306bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      return nullptr;
731651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
732651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (!checkMissingKeys(N, Keys))
7336bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      return nullptr;
734651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
735651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    // check invalid configuration
736651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (Kind == EK_Directory && UseExternalName != FileEntry::NK_NotSet) {
737651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      error(N, "'use-external-name' is not supported for directories");
7386bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      return nullptr;
739651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
740651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
741651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    // Remove trailing slash(es), being careful not to remove the root path
742651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    StringRef Trimmed(Name);
743651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    size_t RootPathLen = sys::path::root_path(Trimmed).size();
744651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    while (Trimmed.size() > RootPathLen &&
745651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines           sys::path::is_separator(Trimmed.back()))
746651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Trimmed = Trimmed.slice(0, Trimmed.size()-1);
747651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    // Get the last component
748651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    StringRef LastComponent = sys::path::filename(Trimmed);
749651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
7506bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    Entry *Result = nullptr;
751651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    switch (Kind) {
752651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    case EK_File:
753651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Result = new FileEntry(LastComponent, std::move(ExternalContentsPath),
754651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                             UseExternalName);
755651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      break;
756651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    case EK_Directory:
757651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Result = new DirectoryEntry(LastComponent, std::move(EntryArrayContents),
758651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          Status("", "", getNextVirtualUniqueID(), sys::TimeValue::now(), 0, 0,
759651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                 0, file_type::directory_file, sys::fs::all_all));
760651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      break;
761651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
762651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
763651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    StringRef Parent = sys::path::parent_path(Trimmed);
764651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (Parent.empty())
765651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return Result;
766651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
767651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    // if 'name' contains multiple components, create implicit directory entries
768651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    for (sys::path::reverse_iterator I = sys::path::rbegin(Parent),
769651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                                     E = sys::path::rend(Parent);
770651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines         I != E; ++I) {
771651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Result = new DirectoryEntry(*I, llvm::makeArrayRef(Result),
772651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          Status("", "", getNextVirtualUniqueID(), sys::TimeValue::now(), 0, 0,
773651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                 0, file_type::directory_file, sys::fs::all_all));
774651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
775651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return Result;
776651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
777651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
778651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinespublic:
779651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  VFSFromYAMLParser(yaml::Stream &S) : Stream(S) {}
780651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
781651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // false on error
782651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  bool parse(yaml::Node *Root, VFSFromYAML *FS) {
783651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    yaml::MappingNode *Top = dyn_cast<yaml::MappingNode>(Root);
784651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (!Top) {
785651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      error(Root, "expected mapping node");
786651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return false;
787651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
788651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
789651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    KeyStatusPair Fields[] = {
790651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      KeyStatusPair("version", true),
791651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      KeyStatusPair("case-sensitive", false),
792651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      KeyStatusPair("use-external-names", false),
793651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      KeyStatusPair("roots", true),
794651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    };
795651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
796651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    DenseMap<StringRef, KeyStatus> Keys(
797651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        &Fields[0], Fields + sizeof(Fields)/sizeof(Fields[0]));
798651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
799651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    // Parse configuration and 'roots'
800651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    for (yaml::MappingNode::iterator I = Top->begin(), E = Top->end(); I != E;
801651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines         ++I) {
802651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      SmallString<10> KeyBuffer;
803651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      StringRef Key;
804651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      if (!parseScalarString(I->getKey(), Key, KeyBuffer))
805651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        return false;
806651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
807651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      if (!checkDuplicateOrUnknownKey(I->getKey(), Key, Keys))
808651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        return false;
809651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
810651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      if (Key == "roots") {
811651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        yaml::SequenceNode *Roots = dyn_cast<yaml::SequenceNode>(I->getValue());
812651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (!Roots) {
813651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          error(I->getValue(), "expected array");
814651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          return false;
815651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
816651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
817651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        for (yaml::SequenceNode::iterator I = Roots->begin(), E = Roots->end();
818651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines             I != E; ++I) {
819651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          if (Entry *E = parseEntry(&*I))
820651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines            FS->Roots.push_back(E);
821651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          else
822651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines            return false;
823651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
824651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      } else if (Key == "version") {
825651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        StringRef VersionString;
826651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        SmallString<4> Storage;
827651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (!parseScalarString(I->getValue(), VersionString, Storage))
828651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          return false;
829651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        int Version;
830651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (VersionString.getAsInteger<int>(10, Version)) {
831651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          error(I->getValue(), "expected integer");
832651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          return false;
833651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
834651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (Version < 0) {
835651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          error(I->getValue(), "invalid version number");
836651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          return false;
837651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
838651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (Version != 0) {
839651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          error(I->getValue(), "version mismatch, expected 0");
840651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          return false;
841651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
842651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      } else if (Key == "case-sensitive") {
843651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (!parseScalarBool(I->getValue(), FS->CaseSensitive))
844651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          return false;
845651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      } else if (Key == "use-external-names") {
846651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (!parseScalarBool(I->getValue(), FS->UseExternalNames))
847651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          return false;
848651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      } else {
849651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        llvm_unreachable("key missing from Keys");
850651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      }
851651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
852651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
853651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (Stream.failed())
854651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return false;
855651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
856651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (!checkMissingKeys(Top, Keys))
857651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return false;
858651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return true;
859651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
860651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines};
861651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines} // end of anonymous namespace
862651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
863651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesEntry::~Entry() {}
864651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesDirectoryEntry::~DirectoryEntry() { llvm::DeleteContainerPointers(Contents); }
865651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
866651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesVFSFromYAML::~VFSFromYAML() { llvm::DeleteContainerPointers(Roots); }
867651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
868651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesVFSFromYAML *VFSFromYAML::create(MemoryBuffer *Buffer,
869651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                                 SourceMgr::DiagHandlerTy DiagHandler,
870651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                                 void *DiagContext,
871651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                                 IntrusiveRefCntPtr<FileSystem> ExternalFS) {
872651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
873651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  SourceMgr SM;
874651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  yaml::Stream Stream(Buffer, SM);
875651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
876651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  SM.setDiagHandler(DiagHandler, DiagContext);
877651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  yaml::document_iterator DI = Stream.begin();
878651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  yaml::Node *Root = DI->getRoot();
879651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (DI == Stream.end() || !Root) {
880651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    SM.PrintMessage(SMLoc(), SourceMgr::DK_Error, "expected root node");
8816bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    return nullptr;
882651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
883651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
884651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  VFSFromYAMLParser P(Stream);
885651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
886651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  std::unique_ptr<VFSFromYAML> FS(new VFSFromYAML(ExternalFS));
887651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (!P.parse(Root, FS.get()))
8886bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    return nullptr;
889651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
890651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return FS.release();
891651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
892651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
893651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesErrorOr<Entry *> VFSFromYAML::lookupPath(const Twine &Path_) {
894651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  SmallString<256> Path;
895651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Path_.toVector(Path);
896651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
897651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // Handle relative paths
898ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  if (std::error_code EC = sys::fs::make_absolute(Path))
899651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return EC;
900651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
901651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (Path.empty())
902ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    return make_error_code(llvm::errc::invalid_argument);
903651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
904651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  sys::path::const_iterator Start = sys::path::begin(Path);
905651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  sys::path::const_iterator End = sys::path::end(Path);
906651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  for (std::vector<Entry *>::iterator I = Roots.begin(), E = Roots.end();
907651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines       I != E; ++I) {
908651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    ErrorOr<Entry *> Result = lookupPath(Start, End, *I);
909ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
910651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return Result;
911651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
912ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  return make_error_code(llvm::errc::no_such_file_or_directory);
913651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
914651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
915651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesErrorOr<Entry *> VFSFromYAML::lookupPath(sys::path::const_iterator Start,
916651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                                         sys::path::const_iterator End,
917651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                                         Entry *From) {
918651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (Start->equals("."))
919651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    ++Start;
920651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
921651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // FIXME: handle ..
922651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (CaseSensitive ? !Start->equals(From->getName())
923651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                    : !Start->equals_lower(From->getName()))
924651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    // failure to match
925ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    return make_error_code(llvm::errc::no_such_file_or_directory);
926651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
927651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ++Start;
928651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
929651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (Start == End) {
930651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    // Match!
931651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return From;
932651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
933651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
934651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  DirectoryEntry *DE = dyn_cast<DirectoryEntry>(From);
935651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (!DE)
936ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    return make_error_code(llvm::errc::not_a_directory);
937651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
938651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  for (DirectoryEntry::iterator I = DE->contents_begin(),
939651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                                E = DE->contents_end();
940651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines       I != E; ++I) {
941651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    ErrorOr<Entry *> Result = lookupPath(Start, End, *I);
942ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
943651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return Result;
944651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
945ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  return make_error_code(llvm::errc::no_such_file_or_directory);
946651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
947651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
948ef8225444452a1486bd721f3285301fe84643b00Stephen HinesErrorOr<Status> VFSFromYAML::status(const Twine &Path, Entry *E) {
949ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  assert(E != nullptr);
950651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  std::string PathStr(Path.str());
951ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  if (FileEntry *F = dyn_cast<FileEntry>(E)) {
952651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    ErrorOr<Status> S = ExternalFS->status(F->getExternalContentsPath());
953651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    assert(!S || S->getName() == F->getExternalContentsPath());
954651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (S && !F->useExternalName(UseExternalNames))
955651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      S->setName(PathStr);
9566bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if (S)
9576bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      S->IsVFSMapped = true;
958651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return S;
959651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  } else { // directory
960ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    DirectoryEntry *DE = cast<DirectoryEntry>(E);
961651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    Status S = DE->getStatus();
962651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    S.setName(PathStr);
963651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return S;
964651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
965651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
966651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
967ef8225444452a1486bd721f3285301fe84643b00Stephen HinesErrorOr<Status> VFSFromYAML::status(const Twine &Path) {
968ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ErrorOr<Entry *> Result = lookupPath(Path);
969ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  if (!Result)
970ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    return Result.getError();
971ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  return status(Path, *Result);
972ef8225444452a1486bd721f3285301fe84643b00Stephen Hines}
973ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
974ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesstd::error_code
975ef8225444452a1486bd721f3285301fe84643b00Stephen HinesVFSFromYAML::openFileForRead(const Twine &Path,
976ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                             std::unique_ptr<vfs::File> &Result) {
977651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ErrorOr<Entry *> E = lookupPath(Path);
978651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (!E)
979651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return E.getError();
980651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
981651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FileEntry *F = dyn_cast<FileEntry>(*E);
982651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (!F) // FIXME: errc::not_a_file?
983ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    return make_error_code(llvm::errc::invalid_argument);
984651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
985ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  if (std::error_code EC =
986ef8225444452a1486bd721f3285301fe84643b00Stephen Hines          ExternalFS->openFileForRead(F->getExternalContentsPath(), Result))
987651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return EC;
988651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
989651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (!F->useExternalName(UseExternalNames))
990651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    Result->setName(Path.str());
991651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
992ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  return std::error_code();
993651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
994651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
995651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesIntrusiveRefCntPtr<FileSystem>
996651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesvfs::getVFSFromYAML(MemoryBuffer *Buffer, SourceMgr::DiagHandlerTy DiagHandler,
997651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                    void *DiagContext,
998651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                    IntrusiveRefCntPtr<FileSystem> ExternalFS) {
999651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return VFSFromYAML::create(Buffer, DiagHandler, DiagContext, ExternalFS);
1000651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
1001651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1002651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesUniqueID vfs::getNextVirtualUniqueID() {
1003651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  static std::atomic<unsigned> UID;
1004651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  unsigned ID = ++UID;
1005651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // The following assumes that uint64_t max will never collide with a real
1006651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // dev_t value from the OS.
1007651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return UniqueID(std::numeric_limits<uint64_t>::max(), ID);
1008651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
10096bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
10106bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines#ifndef NDEBUG
10116bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesstatic bool pathHasTraversal(StringRef Path) {
10126bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  using namespace llvm::sys;
10136bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path)))
10146bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if (Comp == "." || Comp == "..")
10156bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      return true;
10166bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  return false;
10176bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
10186bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines#endif
10196bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
10206bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesvoid YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) {
10216bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute");
10226bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  assert(sys::path::is_absolute(RealPath) && "real path not absolute");
10236bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  assert(!pathHasTraversal(VirtualPath) && "path traversal is not supported");
10246bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  Mappings.emplace_back(VirtualPath, RealPath);
10256bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
10266bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
10276bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesnamespace {
10286bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesclass JSONWriter {
10296bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  llvm::raw_ostream &OS;
10306bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  SmallVector<StringRef, 16> DirStack;
10316bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  inline unsigned getDirIndent() { return 4 * DirStack.size(); }
10326bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  inline unsigned getFileIndent() { return 4 * (DirStack.size() + 1); }
10336bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  bool containedIn(StringRef Parent, StringRef Path);
10346bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  StringRef containedPart(StringRef Parent, StringRef Path);
10356bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  void startDirectory(StringRef Path);
10366bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  void endDirectory();
10376bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  void writeEntry(StringRef VPath, StringRef RPath);
10386bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
10396bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinespublic:
10406bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  JSONWriter(llvm::raw_ostream &OS) : OS(OS) {}
10416bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  void write(ArrayRef<YAMLVFSEntry> Entries, Optional<bool> IsCaseSensitive);
10426bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines};
10436bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
10446bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
10456bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesbool JSONWriter::containedIn(StringRef Parent, StringRef Path) {
10466bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  using namespace llvm::sys;
10476bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  // Compare each path component.
10486bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  auto IParent = path::begin(Parent), EParent = path::end(Parent);
10496bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  for (auto IChild = path::begin(Path), EChild = path::end(Path);
10506bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines       IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
10516bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if (*IParent != *IChild)
10526bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      return false;
10536bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  }
10546bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  // Have we exhausted the parent path?
10556bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  return IParent == EParent;
10566bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
10576bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
10586bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen HinesStringRef JSONWriter::containedPart(StringRef Parent, StringRef Path) {
10596bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  assert(!Parent.empty());
10606bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  assert(containedIn(Parent, Path));
10616bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  return Path.slice(Parent.size() + 1, StringRef::npos);
10626bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
10636bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
10646bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesvoid JSONWriter::startDirectory(StringRef Path) {
10656bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  StringRef Name =
10666bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      DirStack.empty() ? Path : containedPart(DirStack.back(), Path);
10676bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  DirStack.push_back(Path);
10686bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  unsigned Indent = getDirIndent();
10696bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent) << "{\n";
10706bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent + 2) << "'type': 'directory',\n";
10716bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(Name) << "\",\n";
10726bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent + 2) << "'contents': [\n";
10736bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
10746bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
10756bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesvoid JSONWriter::endDirectory() {
10766bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  unsigned Indent = getDirIndent();
10776bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent + 2) << "]\n";
10786bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent) << "}";
10796bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
10806bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  DirStack.pop_back();
10816bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
10826bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
10836bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesvoid JSONWriter::writeEntry(StringRef VPath, StringRef RPath) {
10846bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  unsigned Indent = getFileIndent();
10856bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent) << "{\n";
10866bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent + 2) << "'type': 'file',\n";
10876bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(VPath) << "\",\n";
10886bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent + 2) << "'external-contents': \""
10896bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                        << llvm::yaml::escape(RPath) << "\"\n";
10906bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent) << "}";
10916bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
10926bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
10936bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesvoid JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries,
10946bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                       Optional<bool> IsCaseSensitive) {
10956bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  using namespace llvm::sys;
10966bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
10976bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS << "{\n"
10986bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        "  'version': 0,\n";
10996bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  if (IsCaseSensitive.hasValue())
11006bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    OS << "  'case-sensitive': '"
11016bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines       << (IsCaseSensitive.getValue() ? "true" : "false") << "',\n";
11026bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS << "  'roots': [\n";
11036bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
11046bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  if (Entries.empty())
11056bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    return;
11066bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
11076bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  const YAMLVFSEntry &Entry = Entries.front();
11086bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  startDirectory(path::parent_path(Entry.VPath));
11096bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  writeEntry(path::filename(Entry.VPath), Entry.RPath);
11106bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
11116bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  for (const auto &Entry : Entries.slice(1)) {
11126bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    StringRef Dir = path::parent_path(Entry.VPath);
11136bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if (Dir == DirStack.back())
11146bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      OS << ",\n";
11156bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    else {
11166bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      while (!DirStack.empty() && !containedIn(DirStack.back(), Dir)) {
11176bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        OS << "\n";
11186bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        endDirectory();
11196bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      }
11206bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      OS << ",\n";
11216bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      startDirectory(Dir);
11226bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
11236bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    writeEntry(path::filename(Entry.VPath), Entry.RPath);
11246bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  }
11256bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
11266bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  while (!DirStack.empty()) {
11276bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    OS << "\n";
11286bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    endDirectory();
11296bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  }
11306bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
11316bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS << "\n"
11326bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines     << "  ]\n"
11336bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines     << "}\n";
11346bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
11356bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
11366bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesvoid YAMLVFSWriter::write(llvm::raw_ostream &OS) {
11376bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  std::sort(Mappings.begin(), Mappings.end(),
11386bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            [](const YAMLVFSEntry &LHS, const YAMLVFSEntry &RHS) {
11396bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    return LHS.VPath < RHS.VPath;
11406bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  });
11416bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
11426bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  JSONWriter(OS).write(Mappings, IsCaseSensitive);
11436bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
1144ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
1145ef8225444452a1486bd721f3285301fe84643b00Stephen HinesVFSFromYamlDirIterImpl::VFSFromYamlDirIterImpl(const Twine &_Path,
1146ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                               VFSFromYAML &FS,
1147ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                               DirectoryEntry::iterator Begin,
1148ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                               DirectoryEntry::iterator End,
1149ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                               std::error_code &EC)
1150ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    : Dir(_Path.str()), FS(FS), Current(Begin), End(End) {
1151ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  if (Current != End) {
1152ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    SmallString<128> PathStr(Dir);
1153ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    llvm::sys::path::append(PathStr, (*Current)->getName());
1154ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    llvm::ErrorOr<vfs::Status> S = FS.status(PathStr.str());
1155ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    if (S)
1156ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      CurrentEntry = *S;
1157ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    else
1158ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      EC = S.getError();
1159ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
1160ef8225444452a1486bd721f3285301fe84643b00Stephen Hines}
1161ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
1162ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesstd::error_code VFSFromYamlDirIterImpl::increment() {
1163ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  assert(Current != End && "cannot iterate past end");
1164ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  if (++Current != End) {
1165ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    SmallString<128> PathStr(Dir);
1166ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    llvm::sys::path::append(PathStr, (*Current)->getName());
1167ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    llvm::ErrorOr<vfs::Status> S = FS.status(PathStr.str());
1168ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    if (!S)
1169ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      return S.getError();
1170ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    CurrentEntry = *S;
1171ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  } else {
1172ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    CurrentEntry = Status();
1173ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
1174ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  return std::error_code();
1175ef8225444452a1486bd721f3285301fe84643b00Stephen Hines}
1176ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
1177ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesvfs::recursive_directory_iterator::recursive_directory_iterator(FileSystem &FS_,
1178ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                                           const Twine &Path,
1179ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                                           std::error_code &EC)
1180ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    : FS(&FS_) {
1181ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  directory_iterator I = FS->dir_begin(Path, EC);
1182ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  if (!EC && I != directory_iterator()) {
1183ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    State = std::make_shared<IterState>();
1184ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    State->push(I);
1185ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
1186ef8225444452a1486bd721f3285301fe84643b00Stephen Hines}
1187ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
1188ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesvfs::recursive_directory_iterator &
1189ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesrecursive_directory_iterator::increment(std::error_code &EC) {
1190ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  assert(FS && State && !State->empty() && "incrementing past end");
1191ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  assert(State->top()->isStatusKnown() && "non-canonical end iterator");
1192ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  vfs::directory_iterator End;
1193ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  if (State->top()->isDirectory()) {
1194ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    vfs::directory_iterator I = FS->dir_begin(State->top()->getName(), EC);
1195ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    if (EC)
1196ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      return *this;
1197ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    if (I != End) {
1198ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      State->push(I);
1199ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      return *this;
1200ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    }
1201ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
1202ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
1203ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  while (!State->empty() && State->top().increment(EC) == End)
1204ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    State->pop();
1205ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
1206ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  if (State->empty())
1207ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    State.reset(); // end iterator
1208ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
1209ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  return *this;
1210ef8225444452a1486bd721f3285301fe84643b00Stephen Hines}
1211