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"
13a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar#include "clang/Basic/FileManager.h"
14651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "llvm/ADT/DenseMap.h"
15651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "llvm/ADT/STLExtras.h"
16651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "llvm/ADT/StringExtras.h"
17c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines#include "llvm/ADT/StringSet.h"
180e2c34f92f00628d48968dfea096d36381f494cbStephen Hines#include "llvm/ADT/iterator_range.h"
19c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines#include "llvm/Support/Errc.h"
20651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "llvm/Support/MemoryBuffer.h"
21651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "llvm/Support/Path.h"
22651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "llvm/Support/YAMLParser.h"
23a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar#include "llvm/Config/llvm-config.h"
24651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include <atomic>
25651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include <memory>
26651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
27a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar// For chdir.
28a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar#ifdef LLVM_ON_WIN32
29a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar#  include <direct.h>
30a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar#else
31a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar#  include <unistd.h>
32a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar#endif
33a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
34651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesusing namespace clang;
35651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesusing namespace clang::vfs;
36651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesusing namespace llvm;
37651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesusing llvm::sys::fs::file_status;
38651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesusing llvm::sys::fs::file_type;
39651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesusing llvm::sys::fs::perms;
40651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesusing llvm::sys::fs::UniqueID;
41651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
42651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesStatus::Status(const file_status &Status)
43651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    : UID(Status.getUniqueID()), MTime(Status.getLastModificationTime()),
44651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()),
456bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      Type(Status.type()), Perms(Status.permissions()), IsVFSMapped(false)  {}
46651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
47a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga NainarStatus::Status(StringRef Name, UniqueID UID, sys::TimeValue MTime,
48a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar               uint32_t User, uint32_t Group, uint64_t Size, file_type Type,
49a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar               perms Perms)
50651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    : Name(Name), UID(UID), MTime(MTime), User(User), Group(Group), Size(Size),
516bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      Type(Type), Perms(Perms), IsVFSMapped(false) {}
52651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
53a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga NainarStatus Status::copyWithNewName(const Status &In, StringRef NewName) {
54a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
55a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                In.getUser(), In.getGroup(), In.getSize(), In.getType(),
56a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                In.getPermissions());
57a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar}
58a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
59a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga NainarStatus Status::copyWithNewName(const file_status &In, StringRef NewName) {
60a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
61a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                In.getUser(), In.getGroup(), In.getSize(), In.type(),
62a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                In.permissions());
63a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar}
64a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
65651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesbool Status::equivalent(const Status &Other) const {
66651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return getUniqueID() == Other.getUniqueID();
67651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
68651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesbool Status::isDirectory() const {
69651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return Type == file_type::directory_file;
70651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
71651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesbool Status::isRegularFile() const {
72651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return Type == file_type::regular_file;
73651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
74651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesbool Status::isOther() const {
75651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return exists() && !isRegularFile() && !isDirectory() && !isSymlink();
76651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
77651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesbool Status::isSymlink() const {
78651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return Type == file_type::symlink_file;
79651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
80651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesbool Status::isStatusKnown() const {
81651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return Type != file_type::status_error;
82651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
83651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesbool Status::exists() const {
84651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return isStatusKnown() && Type != file_type::file_not_found;
85651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
86651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
87651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesFile::~File() {}
88651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
89651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesFileSystem::~FileSystem() {}
90651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
91176edba5311f6eff0cad2631449885ddf4fbc9eaStephen HinesErrorOr<std::unique_ptr<MemoryBuffer>>
92176edba5311f6eff0cad2631449885ddf4fbc9eaStephen HinesFileSystem::getBufferForFile(const llvm::Twine &Name, int64_t FileSize,
93176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                             bool RequiresNullTerminator, bool IsVolatile) {
94176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  auto F = openFileForRead(Name);
95176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  if (!F)
96176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    return F.getError();
97176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
98176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  return (*F)->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile);
99651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
100651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
101a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarstd::error_code FileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const {
102a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  auto WorkingDir = getCurrentWorkingDirectory();
103a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  if (!WorkingDir)
104a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return WorkingDir.getError();
105a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
106a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  return llvm::sys::fs::make_absolute(WorkingDir.get(), Path);
107a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar}
108a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
109a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarbool FileSystem::exists(const Twine &Path) {
110a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  auto Status = status(Path);
111a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  return Status && Status->exists();
112a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar}
113a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
114651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//===-----------------------------------------------------------------------===/
115651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// RealFileSystem implementation
116651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//===-----------------------------------------------------------------------===/
117651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
118651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesnamespace {
119651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \brief Wrapper around a raw file descriptor.
120651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesclass RealFile : public File {
121651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  int FD;
122651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Status S;
123651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  friend class RealFileSystem;
124a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  RealFile(int FD, StringRef NewName)
125a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      : FD(FD), S(NewName, {}, {}, {}, {}, {},
126a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                  llvm::sys::fs::file_type::status_error, {}) {
127651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    assert(FD >= 0 && "Invalid or inactive file descriptor");
128651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
129651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
130651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinespublic:
13158878f85ab89b13e9eea4af3ccf055e42c557bc8Pirama Arumuga Nainar  ~RealFile() override;
132651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ErrorOr<Status> status() override;
133a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  ErrorOr<std::unique_ptr<MemoryBuffer>> getBuffer(const Twine &Name,
134a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                                                   int64_t FileSize,
135a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                                                   bool RequiresNullTerminator,
136a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                                                   bool IsVolatile) override;
137c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  std::error_code close() override;
138651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines};
139651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines} // end anonymous namespace
140651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesRealFile::~RealFile() { close(); }
141651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
142651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesErrorOr<Status> RealFile::status() {
143651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  assert(FD != -1 && "cannot stat closed file");
144651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (!S.isStatusKnown()) {
145651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    file_status RealStatus;
146c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (std::error_code EC = sys::fs::status(FD, RealStatus))
147651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return EC;
148a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    S = Status::copyWithNewName(RealStatus, S.getName());
149651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
150651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return S;
151651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
152651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
153176edba5311f6eff0cad2631449885ddf4fbc9eaStephen HinesErrorOr<std::unique_ptr<MemoryBuffer>>
154176edba5311f6eff0cad2631449885ddf4fbc9eaStephen HinesRealFile::getBuffer(const Twine &Name, int64_t FileSize,
155176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                    bool RequiresNullTerminator, bool IsVolatile) {
156651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  assert(FD != -1 && "cannot get buffer for closed file");
157176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  return MemoryBuffer::getOpenFile(FD, Name, FileSize, RequiresNullTerminator,
158176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                                   IsVolatile);
159651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
160651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
161651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// FIXME: This is terrible, we need this for ::close.
162651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#if !defined(_MSC_VER) && !defined(__MINGW32__)
163651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include <unistd.h>
164651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include <sys/uio.h>
165651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#else
166651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include <io.h>
167651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#ifndef S_ISFIFO
168651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#define S_ISFIFO(x) (0)
169651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#endif
170651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#endif
171c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesstd::error_code RealFile::close() {
172651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (::close(FD))
173c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    return std::error_code(errno, std::generic_category());
174651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FD = -1;
175c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  return std::error_code();
176651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
177651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
178651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesnamespace {
179651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \brief The file system according to your operating system.
180651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesclass RealFileSystem : public FileSystem {
181651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinespublic:
182651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ErrorOr<Status> status(const Twine &Path) override;
183176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
184c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
185a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
186a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override;
187a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
188651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines};
189651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines} // end anonymous namespace
190651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
191651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesErrorOr<Status> RealFileSystem::status(const Twine &Path) {
192651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  sys::fs::file_status RealStatus;
193c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  if (std::error_code EC = sys::fs::status(Path, RealStatus))
194651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return EC;
195a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  return Status::copyWithNewName(RealStatus, Path.str());
196651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
197651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
198176edba5311f6eff0cad2631449885ddf4fbc9eaStephen HinesErrorOr<std::unique_ptr<File>>
199176edba5311f6eff0cad2631449885ddf4fbc9eaStephen HinesRealFileSystem::openFileForRead(const Twine &Name) {
200651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  int FD;
201c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  if (std::error_code EC = sys::fs::openFileForRead(Name, FD))
202651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return EC;
203a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  return std::unique_ptr<File>(new RealFile(FD, Name.str()));
204a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar}
205a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
206a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarllvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory() const {
207a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  SmallString<256> Dir;
208a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  if (std::error_code EC = llvm::sys::fs::current_path(Dir))
209a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return EC;
210a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  return Dir.str().str();
211a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar}
212a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
213a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarstd::error_code RealFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
214a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  // FIXME: chdir is thread hostile; on the other hand, creating the same
215a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  // behavior as chdir is complex: chdir resolves the path once, thus
216a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  // guaranteeing that all subsequent relative path operations work
217a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  // on the same path the original chdir resulted in. This makes a
218a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  // difference for example on network filesystems, where symlinks might be
219a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  // switched during runtime of the tool. Fixing this depends on having a
220a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  // file system abstraction that allows openat() style interactions.
221a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  SmallString<256> Storage;
222a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  StringRef Dir = Path.toNullTerminatedStringRef(Storage);
223a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  if (int Err = ::chdir(Dir.data()))
224a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return std::error_code(Err, std::generic_category());
225a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  return std::error_code();
226651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
227651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
228651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesIntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
229651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  static IntrusiveRefCntPtr<FileSystem> FS = new RealFileSystem();
230651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return FS;
231651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
232651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
233c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesnamespace {
234c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesclass RealFSDirIter : public clang::vfs::detail::DirIterImpl {
235c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  std::string Path;
236c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  llvm::sys::fs::directory_iterator Iter;
237c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinespublic:
238c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  RealFSDirIter(const Twine &_Path, std::error_code &EC)
239c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      : Path(_Path.str()), Iter(Path, EC) {
240c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (!EC && Iter != llvm::sys::fs::directory_iterator()) {
241c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      llvm::sys::fs::file_status S;
242c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      EC = Iter->status(S);
243a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      if (!EC)
244a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar        CurrentEntry = Status::copyWithNewName(S, Iter->path());
245c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
246c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  }
247c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
248c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  std::error_code increment() override {
249c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    std::error_code EC;
250c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    Iter.increment(EC);
251c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (EC) {
252c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      return EC;
253c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    } else if (Iter == llvm::sys::fs::directory_iterator()) {
254c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      CurrentEntry = Status();
255c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    } else {
256c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      llvm::sys::fs::file_status S;
257c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      EC = Iter->status(S);
258a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      CurrentEntry = Status::copyWithNewName(S, Iter->path());
259c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
260c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    return EC;
261c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  }
262c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines};
263c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines}
264c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
265c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesdirectory_iterator RealFileSystem::dir_begin(const Twine &Dir,
266c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                                             std::error_code &EC) {
267c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  return directory_iterator(std::make_shared<RealFSDirIter>(Dir, EC));
268c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines}
269c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
270651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//===-----------------------------------------------------------------------===/
271651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// OverlayFileSystem implementation
272651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//===-----------------------------------------------------------------------===/
273651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesOverlayFileSystem::OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> BaseFS) {
274a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  FSList.push_back(BaseFS);
275651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
276651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
277651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesvoid OverlayFileSystem::pushOverlay(IntrusiveRefCntPtr<FileSystem> FS) {
278651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FSList.push_back(FS);
279a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  // Synchronize added file systems by duplicating the working directory from
280a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  // the first one in the list.
281a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  FS->setCurrentWorkingDirectory(getCurrentWorkingDirectory().get());
282651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
283651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
284651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesErrorOr<Status> OverlayFileSystem::status(const Twine &Path) {
285651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // FIXME: handle symlinks that cross file systems
286651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
287651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    ErrorOr<Status> Status = (*I)->status(Path);
288c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (Status || Status.getError() != llvm::errc::no_such_file_or_directory)
289651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return Status;
290651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
291c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  return make_error_code(llvm::errc::no_such_file_or_directory);
292651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
293651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
294176edba5311f6eff0cad2631449885ddf4fbc9eaStephen HinesErrorOr<std::unique_ptr<File>>
295176edba5311f6eff0cad2631449885ddf4fbc9eaStephen HinesOverlayFileSystem::openFileForRead(const llvm::Twine &Path) {
296651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // FIXME: handle symlinks that cross file systems
297651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
298176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    auto Result = (*I)->openFileForRead(Path);
299176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
300176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines      return Result;
301651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
302c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  return make_error_code(llvm::errc::no_such_file_or_directory);
303c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines}
304c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
305a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarllvm::ErrorOr<std::string>
306a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga NainarOverlayFileSystem::getCurrentWorkingDirectory() const {
307a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  // All file systems are synchronized, just take the first working directory.
308a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  return FSList.front()->getCurrentWorkingDirectory();
309a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar}
310a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarstd::error_code
311a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga NainarOverlayFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
312a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  for (auto &FS : FSList)
313a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))
314a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      return EC;
315a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  return std::error_code();
316a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar}
317a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
318c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesclang::vfs::detail::DirIterImpl::~DirIterImpl() { }
319c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
320c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesnamespace {
321c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesclass OverlayFSDirIterImpl : public clang::vfs::detail::DirIterImpl {
322c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  OverlayFileSystem &Overlays;
323c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  std::string Path;
324c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  OverlayFileSystem::iterator CurrentFS;
325c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  directory_iterator CurrentDirIter;
326c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  llvm::StringSet<> SeenNames;
327c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
328c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  std::error_code incrementFS() {
329c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    assert(CurrentFS != Overlays.overlays_end() && "incrementing past end");
330c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    ++CurrentFS;
331c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    for (auto E = Overlays.overlays_end(); CurrentFS != E; ++CurrentFS) {
332c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      std::error_code EC;
333c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC);
334c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      if (EC && EC != errc::no_such_file_or_directory)
335c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        return EC;
336c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      if (CurrentDirIter != directory_iterator())
337c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        break; // found
338c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
339c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    return std::error_code();
340c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  }
341c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
342c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  std::error_code incrementDirIter(bool IsFirstTime) {
343c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    assert((IsFirstTime || CurrentDirIter != directory_iterator()) &&
344c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines           "incrementing past end");
345c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    std::error_code EC;
346c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (!IsFirstTime)
347c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      CurrentDirIter.increment(EC);
348c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (!EC && CurrentDirIter == directory_iterator())
349c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      EC = incrementFS();
350c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    return EC;
351c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  }
352c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
353c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  std::error_code incrementImpl(bool IsFirstTime) {
354c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    while (true) {
355c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      std::error_code EC = incrementDirIter(IsFirstTime);
356c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      if (EC || CurrentDirIter == directory_iterator()) {
357c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        CurrentEntry = Status();
358c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        return EC;
359c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      }
360c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      CurrentEntry = *CurrentDirIter;
361c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      StringRef Name = llvm::sys::path::filename(CurrentEntry.getName());
362176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines      if (SeenNames.insert(Name).second)
363c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        return EC; // name not seen before
364c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
365c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    llvm_unreachable("returned above");
366c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  }
367c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
368c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinespublic:
369c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  OverlayFSDirIterImpl(const Twine &Path, OverlayFileSystem &FS,
370c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                       std::error_code &EC)
371c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      : Overlays(FS), Path(Path.str()), CurrentFS(Overlays.overlays_begin()) {
372c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC);
373c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    EC = incrementImpl(true);
374c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  }
375c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
376c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  std::error_code increment() override { return incrementImpl(false); }
377c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines};
378c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines} // end anonymous namespace
379c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
380c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesdirectory_iterator OverlayFileSystem::dir_begin(const Twine &Dir,
381c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                                                std::error_code &EC) {
382c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  return directory_iterator(
383c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      std::make_shared<OverlayFSDirIterImpl>(Dir, *this, EC));
384651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
385651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
386a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarnamespace clang {
387a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarnamespace vfs {
388a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarnamespace detail {
389651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
390a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarenum InMemoryNodeKind { IME_File, IME_Directory };
391a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
392a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar/// The in memory file system is a tree of Nodes. Every node can either be a
393a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar/// file or a directory.
394a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarclass InMemoryNode {
395a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  Status Stat;
396a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  InMemoryNodeKind Kind;
397a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
398a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarpublic:
399a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  InMemoryNode(Status Stat, InMemoryNodeKind Kind)
400a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      : Stat(std::move(Stat)), Kind(Kind) {}
401a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  virtual ~InMemoryNode() {}
402a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  const Status &getStatus() const { return Stat; }
403a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  InMemoryNodeKind getKind() const { return Kind; }
404a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  virtual std::string toString(unsigned Indent) const = 0;
405a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar};
406a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
407a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarnamespace {
408a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarclass InMemoryFile : public InMemoryNode {
409a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  std::unique_ptr<llvm::MemoryBuffer> Buffer;
410a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
411a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarpublic:
412a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  InMemoryFile(Status Stat, std::unique_ptr<llvm::MemoryBuffer> Buffer)
413a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      : InMemoryNode(std::move(Stat), IME_File), Buffer(std::move(Buffer)) {}
414a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
415a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  llvm::MemoryBuffer *getBuffer() { return Buffer.get(); }
416a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  std::string toString(unsigned Indent) const override {
417a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return (std::string(Indent, ' ') + getStatus().getName() + "\n").str();
418a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  }
419a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  static bool classof(const InMemoryNode *N) {
420a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return N->getKind() == IME_File;
421a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  }
422a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar};
423a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
424a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar/// Adapt a InMemoryFile for VFS' File interface.
425a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarclass InMemoryFileAdaptor : public File {
426a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  InMemoryFile &Node;
427a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
428a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarpublic:
429a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  explicit InMemoryFileAdaptor(InMemoryFile &Node) : Node(Node) {}
430a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
431a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  llvm::ErrorOr<Status> status() override { return Node.getStatus(); }
432a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
433a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
434a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar            bool IsVolatile) override {
435a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    llvm::MemoryBuffer *Buf = Node.getBuffer();
436a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return llvm::MemoryBuffer::getMemBuffer(
437a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar        Buf->getBuffer(), Buf->getBufferIdentifier(), RequiresNullTerminator);
438a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  }
439a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  std::error_code close() override { return std::error_code(); }
440a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar};
441a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar} // end anonymous namespace
442a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
443a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarclass InMemoryDirectory : public InMemoryNode {
444a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  std::map<std::string, std::unique_ptr<InMemoryNode>> Entries;
445a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
446a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarpublic:
447a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  InMemoryDirectory(Status Stat)
448a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      : InMemoryNode(std::move(Stat), IME_Directory) {}
449a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  InMemoryNode *getChild(StringRef Name) {
450a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    auto I = Entries.find(Name);
451a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    if (I != Entries.end())
452a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      return I->second.get();
453a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return nullptr;
454a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  }
455a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  InMemoryNode *addChild(StringRef Name, std::unique_ptr<InMemoryNode> Child) {
456a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return Entries.insert(make_pair(Name, std::move(Child)))
457a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar        .first->second.get();
458a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  }
459a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
460a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  typedef decltype(Entries)::const_iterator const_iterator;
461a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  const_iterator begin() const { return Entries.begin(); }
462a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  const_iterator end() const { return Entries.end(); }
463a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
464a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  std::string toString(unsigned Indent) const override {
465a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    std::string Result =
466a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar        (std::string(Indent, ' ') + getStatus().getName() + "\n").str();
467a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    for (const auto &Entry : Entries) {
468a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      Result += Entry.second->toString(Indent + 2);
469a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    }
470a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return Result;
471a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  }
472a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  static bool classof(const InMemoryNode *N) {
473a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return N->getKind() == IME_Directory;
474a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  }
475a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar};
476a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar}
477a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
478a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga NainarInMemoryFileSystem::InMemoryFileSystem(bool UseNormalizedPaths)
479a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    : Root(new detail::InMemoryDirectory(
480a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar          Status("", getNextVirtualUniqueID(), llvm::sys::TimeValue::MinTime(),
481a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                 0, 0, 0, llvm::sys::fs::file_type::directory_file,
482a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                 llvm::sys::fs::perms::all_all))),
483a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      UseNormalizedPaths(UseNormalizedPaths) {}
484a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
485a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga NainarInMemoryFileSystem::~InMemoryFileSystem() {}
486a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
487a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarstd::string InMemoryFileSystem::toString() const {
488a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  return Root->toString(/*Indent=*/0);
489a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar}
490a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
491a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarbool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
492a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                                 std::unique_ptr<llvm::MemoryBuffer> Buffer) {
493a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  SmallString<128> Path;
494a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  P.toVector(Path);
495a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
496a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  // Fix up relative paths. This just prepends the current working directory.
497a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  std::error_code EC = makeAbsolute(Path);
498a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  assert(!EC);
499a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  (void)EC;
500a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
501a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  if (useNormalizedPaths())
502a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
503a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
504a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  if (Path.empty())
505a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return false;
506a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
507a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  detail::InMemoryDirectory *Dir = Root.get();
508a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path);
509a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  while (true) {
510a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    StringRef Name = *I;
511a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    detail::InMemoryNode *Node = Dir->getChild(Name);
512a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    ++I;
513a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    if (!Node) {
514a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      if (I == E) {
515a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar        // End of the path, create a new file.
516a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar        // FIXME: expose the status details in the interface.
517a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar        Status Stat(P.str(), getNextVirtualUniqueID(),
518a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                    llvm::sys::TimeValue(ModificationTime, 0), 0, 0,
519a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                    Buffer->getBufferSize(),
520a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                    llvm::sys::fs::file_type::regular_file,
521a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                    llvm::sys::fs::all_all);
522a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar        Dir->addChild(Name, llvm::make_unique<detail::InMemoryFile>(
523a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                                std::move(Stat), std::move(Buffer)));
524a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar        return true;
525a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      }
526a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
527a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      // Create a new directory. Use the path up to here.
528a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      // FIXME: expose the status details in the interface.
529a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      Status Stat(
530a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar          StringRef(Path.str().begin(), Name.end() - Path.str().begin()),
531a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar          getNextVirtualUniqueID(), llvm::sys::TimeValue(ModificationTime, 0),
532a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar          0, 0, Buffer->getBufferSize(),
533a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar          llvm::sys::fs::file_type::directory_file, llvm::sys::fs::all_all);
534a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      Dir = cast<detail::InMemoryDirectory>(Dir->addChild(
535a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar          Name, llvm::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
536a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      continue;
537a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    }
538a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
539a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    if (auto *NewDir = dyn_cast<detail::InMemoryDirectory>(Node)) {
540a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      Dir = NewDir;
541a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    } else {
542a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      assert(isa<detail::InMemoryFile>(Node) &&
543a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar             "Must be either file or directory!");
544a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
545a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      // Trying to insert a directory in place of a file.
546a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      if (I != E)
547a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar        return false;
548a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
549a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      // Return false only if the new file is different from the existing one.
550a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      return cast<detail::InMemoryFile>(Node)->getBuffer()->getBuffer() ==
551a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar             Buffer->getBuffer();
552a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    }
553a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  }
554a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar}
555a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
556a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarbool InMemoryFileSystem::addFileNoOwn(const Twine &P, time_t ModificationTime,
557a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                                      llvm::MemoryBuffer *Buffer) {
558a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  return addFile(P, ModificationTime,
559a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                 llvm::MemoryBuffer::getMemBuffer(
560a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                     Buffer->getBuffer(), Buffer->getBufferIdentifier()));
561a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar}
562a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
563a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarstatic ErrorOr<detail::InMemoryNode *>
564a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga NainarlookupInMemoryNode(const InMemoryFileSystem &FS, detail::InMemoryDirectory *Dir,
565a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                   const Twine &P) {
566a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  SmallString<128> Path;
567a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  P.toVector(Path);
568a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
569a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  // Fix up relative paths. This just prepends the current working directory.
570a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  std::error_code EC = FS.makeAbsolute(Path);
571a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  assert(!EC);
572a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  (void)EC;
573a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
574a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  if (FS.useNormalizedPaths())
575a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
576a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
577a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  if (Path.empty())
578a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return Dir;
579a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
580a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path);
581a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  while (true) {
582a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    detail::InMemoryNode *Node = Dir->getChild(*I);
583a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    ++I;
584a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    if (!Node)
585a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      return errc::no_such_file_or_directory;
586a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
587a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    // Return the file if it's at the end of the path.
588a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    if (auto File = dyn_cast<detail::InMemoryFile>(Node)) {
589a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      if (I == E)
590a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar        return File;
591a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      return errc::no_such_file_or_directory;
592a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    }
593a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
594a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    // Traverse directories.
595a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    Dir = cast<detail::InMemoryDirectory>(Node);
596a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    if (I == E)
597a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      return Dir;
598a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  }
599a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar}
600a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
601a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarllvm::ErrorOr<Status> InMemoryFileSystem::status(const Twine &Path) {
602a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  auto Node = lookupInMemoryNode(*this, Root.get(), Path);
603a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  if (Node)
604a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return (*Node)->getStatus();
605a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  return Node.getError();
606a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar}
607a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
608a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarllvm::ErrorOr<std::unique_ptr<File>>
609a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga NainarInMemoryFileSystem::openFileForRead(const Twine &Path) {
610a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  auto Node = lookupInMemoryNode(*this, Root.get(), Path);
611a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  if (!Node)
612a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return Node.getError();
613a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
614a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  // When we have a file provide a heap-allocated wrapper for the memory buffer
615a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  // to match the ownership semantics for File.
616a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  if (auto *F = dyn_cast<detail::InMemoryFile>(*Node))
617a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return std::unique_ptr<File>(new detail::InMemoryFileAdaptor(*F));
618a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
619a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  // FIXME: errc::not_a_file?
620a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  return make_error_code(llvm::errc::invalid_argument);
621a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar}
622a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
623a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarnamespace {
624a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar/// Adaptor from InMemoryDir::iterator to directory_iterator.
625a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarclass InMemoryDirIterator : public clang::vfs::detail::DirIterImpl {
626a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  detail::InMemoryDirectory::const_iterator I;
627a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  detail::InMemoryDirectory::const_iterator E;
628a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
629a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarpublic:
630a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  InMemoryDirIterator() {}
631a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  explicit InMemoryDirIterator(detail::InMemoryDirectory &Dir)
632a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      : I(Dir.begin()), E(Dir.end()) {
633a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    if (I != E)
634a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      CurrentEntry = I->second->getStatus();
635a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  }
636a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
637a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  std::error_code increment() override {
638a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    ++I;
639a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    // When we're at the end, make CurrentEntry invalid and DirIterImpl will do
640a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    // the rest.
641a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    CurrentEntry = I != E ? I->second->getStatus() : Status();
642a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return std::error_code();
643a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  }
644a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar};
645a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar} // end anonymous namespace
646a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
647a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainardirectory_iterator InMemoryFileSystem::dir_begin(const Twine &Dir,
648a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                                                 std::error_code &EC) {
649a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  auto Node = lookupInMemoryNode(*this, Root.get(), Dir);
650a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  if (!Node) {
651a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    EC = Node.getError();
652a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return directory_iterator(std::make_shared<InMemoryDirIterator>());
653a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  }
654a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
655a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  if (auto *DirNode = dyn_cast<detail::InMemoryDirectory>(*Node))
656a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return directory_iterator(std::make_shared<InMemoryDirIterator>(*DirNode));
657a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
658a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  EC = make_error_code(llvm::errc::not_a_directory);
659a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  return directory_iterator(std::make_shared<InMemoryDirIterator>());
660a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar}
661a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar}
662651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
663651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
664a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar//===-----------------------------------------------------------------------===/
665a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar// RedirectingFileSystem implementation
666a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar//===-----------------------------------------------------------------------===/
667a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
668651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesnamespace {
669651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
670651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesenum EntryKind {
671651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EK_Directory,
672651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EK_File
673651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines};
674651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
675651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \brief A single file or directory in the VFS.
676651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesclass Entry {
677651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EntryKind Kind;
678651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  std::string Name;
679651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
680651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinespublic:
681651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  virtual ~Entry();
682651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Entry(EntryKind K, StringRef Name) : Kind(K), Name(Name) {}
683651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  StringRef getName() const { return Name; }
684651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EntryKind getKind() const { return Kind; }
685651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines};
686651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
687a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarclass RedirectingDirectoryEntry : public Entry {
688a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  std::vector<std::unique_ptr<Entry>> Contents;
689651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Status S;
690651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
691651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinespublic:
692a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  RedirectingDirectoryEntry(StringRef Name,
693a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                            std::vector<std::unique_ptr<Entry>> Contents,
694a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                            Status S)
695651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      : Entry(EK_Directory, Name), Contents(std::move(Contents)),
696651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        S(std::move(S)) {}
697651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Status getStatus() { return S; }
698a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  typedef decltype(Contents)::iterator iterator;
699651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  iterator contents_begin() { return Contents.begin(); }
700651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  iterator contents_end() { return Contents.end(); }
701651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  static bool classof(const Entry *E) { return E->getKind() == EK_Directory; }
702651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines};
703651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
704a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarclass RedirectingFileEntry : public Entry {
705651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinespublic:
706651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  enum NameKind {
707651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    NK_NotSet,
708651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    NK_External,
709651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    NK_Virtual
710651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  };
711651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesprivate:
712651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  std::string ExternalContentsPath;
713651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  NameKind UseName;
714651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinespublic:
715a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  RedirectingFileEntry(StringRef Name, StringRef ExternalContentsPath,
716a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                       NameKind UseName)
717651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      : Entry(EK_File, Name), ExternalContentsPath(ExternalContentsPath),
718651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        UseName(UseName) {}
719651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  StringRef getExternalContentsPath() const { return ExternalContentsPath; }
720651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// \brief whether to use the external path as the name for this file.
721651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  bool useExternalName(bool GlobalUseExternalName) const {
722651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return UseName == NK_NotSet ? GlobalUseExternalName
723651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                                : (UseName == NK_External);
724651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
725651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  static bool classof(const Entry *E) { return E->getKind() == EK_File; }
726651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines};
727651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
728a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarclass RedirectingFileSystem;
729c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
730c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesclass VFSFromYamlDirIterImpl : public clang::vfs::detail::DirIterImpl {
731c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  std::string Dir;
732a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  RedirectingFileSystem &FS;
733a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  RedirectingDirectoryEntry::iterator Current, End;
734a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
735c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinespublic:
736a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  VFSFromYamlDirIterImpl(const Twine &Path, RedirectingFileSystem &FS,
737a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                         RedirectingDirectoryEntry::iterator Begin,
738a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                         RedirectingDirectoryEntry::iterator End,
739a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                         std::error_code &EC);
740c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  std::error_code increment() override;
741c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines};
742c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
743651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \brief A virtual file system parsed from a YAML file.
744651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///
745651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// Currently, this class allows creating virtual directories and mapping
746651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// virtual file paths to existing external files, available in \c ExternalFS.
747651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///
748651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// The basic structure of the parsed file is:
749651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \verbatim
750651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// {
751651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'version': <version number>,
752651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   <optional configuration>
753651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'roots': [
754651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///              <directory entries>
755651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///            ]
756651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// }
757651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \endverbatim
758651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///
759651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// All configuration options are optional.
760651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'case-sensitive': <boolean, default=true>
761651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'use-external-names': <boolean, default=true>
762651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///
763651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// Virtual directories are represented as
764651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \verbatim
765651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// {
766651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'type': 'directory',
767651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'name': <string>,
768651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'contents': [ <file or directory entries> ]
769651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// }
770651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \endverbatim
771651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///
772651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// The default attributes for virtual directories are:
773651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \verbatim
774651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// MTime = now() when created
775651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// Perms = 0777
776651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// User = Group = 0
777651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// Size = 0
778651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// UniqueID = unspecified unique value
779651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \endverbatim
780651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///
781651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// Re-mapped files are represented as
782651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \verbatim
783651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// {
784651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'type': 'file',
785651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'name': <string>,
786651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'use-external-name': <boolean> # Optional
787651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///   'external-contents': <path to external file>)
788651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// }
789651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \endverbatim
790651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///
791651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// and inherit their attributes from the external contents.
792651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines///
793651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// In both cases, the 'name' field may contain multiple path components (e.g.
794651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// /path/to/file). However, any directory that contains more than one child
795651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// must be uniquely represented by a directory entry.
796a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarclass RedirectingFileSystem : public vfs::FileSystem {
797a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  /// The root(s) of the virtual file system.
798a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  std::vector<std::unique_ptr<Entry>> Roots;
799651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// \brief The file system to use for external references.
800651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<FileSystem> ExternalFS;
801651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
802651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// @name Configuration
803651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// @{
804651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
805651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// \brief Whether to perform case-sensitive comparisons.
806651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ///
807651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// Currently, case-insensitive matching only works correctly with ASCII.
808651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  bool CaseSensitive;
809651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
810651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// \brief Whether to use to use the value of 'external-contents' for the
811651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// names of files.  This global value is overridable on a per-file basis.
812651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  bool UseExternalNames;
813651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// @}
814651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
815a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  friend class RedirectingFileSystemParser;
816651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
817651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesprivate:
818a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS)
819651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      : ExternalFS(ExternalFS), CaseSensitive(true), UseExternalNames(true) {}
820651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
821651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// \brief Looks up \p Path in \c Roots.
822651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ErrorOr<Entry *> lookupPath(const Twine &Path);
823651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
824651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// \brief Looks up the path <tt>[Start, End)</tt> in \p From, possibly
825651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// recursing into the contents of \p From if it is a directory.
826651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ErrorOr<Entry *> lookupPath(sys::path::const_iterator Start,
827651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                              sys::path::const_iterator End, Entry *From);
828651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
829c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  /// \brief Get the status of a given an \c Entry.
830c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  ErrorOr<Status> status(const Twine &Path, Entry *E);
831c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
832651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinespublic:
833651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// \brief Parses \p Buffer, which is expected to be in YAML format and
834651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// returns a virtual file system representing its contents.
835a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  static RedirectingFileSystem *
836a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  create(std::unique_ptr<MemoryBuffer> Buffer,
837a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar         SourceMgr::DiagHandlerTy DiagHandler, void *DiagContext,
838a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar         IntrusiveRefCntPtr<FileSystem> ExternalFS);
839651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
840651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ErrorOr<Status> status(const Twine &Path) override;
841176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
842c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
843a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
844a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return ExternalFS->getCurrentWorkingDirectory();
845a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  }
846a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
847a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return ExternalFS->setCurrentWorkingDirectory(Path);
848a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  }
849a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
850c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override{
851c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    ErrorOr<Entry *> E = lookupPath(Dir);
852c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (!E) {
853c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      EC = E.getError();
854c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      return directory_iterator();
855c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
856c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    ErrorOr<Status> S = status(Dir, *E);
857c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (!S) {
858c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      EC = S.getError();
859c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      return directory_iterator();
860c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
861c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (!S->isDirectory()) {
862c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      EC = std::error_code(static_cast<int>(errc::not_a_directory),
863c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                           std::system_category());
864c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      return directory_iterator();
865c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
866c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
867a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    auto *D = cast<RedirectingDirectoryEntry>(*E);
868c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    return directory_iterator(std::make_shared<VFSFromYamlDirIterImpl>(Dir,
869c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        *this, D->contents_begin(), D->contents_end(), EC));
870c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  }
871651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines};
872651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
873651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \brief A helper class to hold the common YAML parsing state.
874a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarclass RedirectingFileSystemParser {
875651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  yaml::Stream &Stream;
876651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
877651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  void error(yaml::Node *N, const Twine &Msg) {
878651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    Stream.printError(N, Msg);
879651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
880651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
881651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // false on error
882651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  bool parseScalarString(yaml::Node *N, StringRef &Result,
883651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                         SmallVectorImpl<char> &Storage) {
884651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    yaml::ScalarNode *S = dyn_cast<yaml::ScalarNode>(N);
885651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (!S) {
886651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      error(N, "expected string");
887651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return false;
888651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
889651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    Result = S->getValue(Storage);
890651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return true;
891651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
892651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
893651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // false on error
894651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  bool parseScalarBool(yaml::Node *N, bool &Result) {
895651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    SmallString<5> Storage;
896651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    StringRef Value;
897651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (!parseScalarString(N, Value, Storage))
898651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return false;
899651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
900651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (Value.equals_lower("true") || Value.equals_lower("on") ||
901651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        Value.equals_lower("yes") || Value == "1") {
902651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Result = true;
903651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return true;
904651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    } else if (Value.equals_lower("false") || Value.equals_lower("off") ||
905651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines               Value.equals_lower("no") || Value == "0") {
906651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Result = false;
907651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return true;
908651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
909651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
910651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    error(N, "expected boolean value");
911651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return false;
912651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
913651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
914651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  struct KeyStatus {
915651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    KeyStatus(bool Required=false) : Required(Required), Seen(false) {}
916651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    bool Required;
917651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    bool Seen;
918651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  };
919651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  typedef std::pair<StringRef, KeyStatus> KeyStatusPair;
920651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
921651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // false on error
922651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  bool checkDuplicateOrUnknownKey(yaml::Node *KeyNode, StringRef Key,
923651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                                  DenseMap<StringRef, KeyStatus> &Keys) {
924651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (!Keys.count(Key)) {
925651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      error(KeyNode, "unknown key");
926651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return false;
927651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
928651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    KeyStatus &S = Keys[Key];
929651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (S.Seen) {
930651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      error(KeyNode, Twine("duplicate key '") + Key + "'");
931651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return false;
932651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
933651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    S.Seen = true;
934651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return true;
935651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
936651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
937651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // false on error
938651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  bool checkMissingKeys(yaml::Node *Obj, DenseMap<StringRef, KeyStatus> &Keys) {
939651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    for (DenseMap<StringRef, KeyStatus>::iterator I = Keys.begin(),
940651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines         E = Keys.end();
941651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines         I != E; ++I) {
942651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      if (I->second.Required && !I->second.Seen) {
943651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        error(Obj, Twine("missing key '") + I->first + "'");
944651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        return false;
945651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      }
946651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
947651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return true;
948651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
949651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
950a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  std::unique_ptr<Entry> parseEntry(yaml::Node *N) {
951651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    yaml::MappingNode *M = dyn_cast<yaml::MappingNode>(N);
952651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (!M) {
953651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      error(N, "expected mapping node for file or directory entry");
9546bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      return nullptr;
955651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
956651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
957651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    KeyStatusPair Fields[] = {
958651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      KeyStatusPair("name", true),
959651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      KeyStatusPair("type", true),
960651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      KeyStatusPair("contents", false),
961651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      KeyStatusPair("external-contents", false),
962651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      KeyStatusPair("use-external-name", false),
963651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    };
964651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
965a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
966651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
967651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    bool HasContents = false; // external or otherwise
968a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    std::vector<std::unique_ptr<Entry>> EntryArrayContents;
969651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    std::string ExternalContentsPath;
970651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    std::string Name;
971a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    auto UseExternalName = RedirectingFileEntry::NK_NotSet;
972651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    EntryKind Kind;
973651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
974651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    for (yaml::MappingNode::iterator I = M->begin(), E = M->end(); I != E;
975651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines         ++I) {
976651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      StringRef Key;
977651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      // Reuse the buffer for key and value, since we don't look at key after
978651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      // parsing value.
979651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      SmallString<256> Buffer;
980651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      if (!parseScalarString(I->getKey(), Key, Buffer))
9816bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        return nullptr;
982651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
983651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      if (!checkDuplicateOrUnknownKey(I->getKey(), Key, Keys))
9846bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        return nullptr;
985651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
986651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      StringRef Value;
987651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      if (Key == "name") {
988651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (!parseScalarString(I->getValue(), Value, Buffer))
9896bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          return nullptr;
990651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        Name = Value;
991651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      } else if (Key == "type") {
992651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (!parseScalarString(I->getValue(), Value, Buffer))
9936bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          return nullptr;
994651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (Value == "file")
995651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          Kind = EK_File;
996651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        else if (Value == "directory")
997651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          Kind = EK_Directory;
998651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        else {
999651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          error(I->getValue(), "unknown value for 'type'");
10006bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          return nullptr;
1001651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
1002651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      } else if (Key == "contents") {
1003651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (HasContents) {
1004651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          error(I->getKey(),
1005651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                "entry already has 'contents' or 'external-contents'");
10066bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          return nullptr;
1007651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
1008651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        HasContents = true;
1009651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        yaml::SequenceNode *Contents =
1010651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines            dyn_cast<yaml::SequenceNode>(I->getValue());
1011651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (!Contents) {
1012651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          // FIXME: this is only for directories, what about files?
1013651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          error(I->getValue(), "expected array");
10146bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          return nullptr;
1015651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
1016651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1017651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        for (yaml::SequenceNode::iterator I = Contents->begin(),
1018651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                                          E = Contents->end();
1019651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines             I != E; ++I) {
1020a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar          if (std::unique_ptr<Entry> E = parseEntry(&*I))
1021a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar            EntryArrayContents.push_back(std::move(E));
1022651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          else
10236bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            return nullptr;
1024651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
1025651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      } else if (Key == "external-contents") {
1026651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (HasContents) {
1027651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          error(I->getKey(),
1028651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                "entry already has 'contents' or 'external-contents'");
10296bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          return nullptr;
1030651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
1031651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        HasContents = true;
1032651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (!parseScalarString(I->getValue(), Value, Buffer))
10336bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          return nullptr;
1034651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        ExternalContentsPath = Value;
1035651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      } else if (Key == "use-external-name") {
1036651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        bool Val;
1037651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (!parseScalarBool(I->getValue(), Val))
10386bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines          return nullptr;
1039a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar        UseExternalName = Val ? RedirectingFileEntry::NK_External
1040a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                              : RedirectingFileEntry::NK_Virtual;
1041651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      } else {
1042651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        llvm_unreachable("key missing from Keys");
1043651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      }
1044651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
1045651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1046651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (Stream.failed())
10476bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      return nullptr;
1048651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1049651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    // check for missing keys
1050651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (!HasContents) {
1051651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      error(N, "missing key 'contents' or 'external-contents'");
10526bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      return nullptr;
1053651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
1054651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (!checkMissingKeys(N, Keys))
10556bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      return nullptr;
1056651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1057651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    // check invalid configuration
1058a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    if (Kind == EK_Directory &&
1059a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar        UseExternalName != RedirectingFileEntry::NK_NotSet) {
1060651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      error(N, "'use-external-name' is not supported for directories");
10616bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      return nullptr;
1062651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
1063651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1064651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    // Remove trailing slash(es), being careful not to remove the root path
1065651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    StringRef Trimmed(Name);
1066651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    size_t RootPathLen = sys::path::root_path(Trimmed).size();
1067651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    while (Trimmed.size() > RootPathLen &&
1068651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines           sys::path::is_separator(Trimmed.back()))
1069651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Trimmed = Trimmed.slice(0, Trimmed.size()-1);
1070651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    // Get the last component
1071651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    StringRef LastComponent = sys::path::filename(Trimmed);
1072651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1073a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    std::unique_ptr<Entry> Result;
1074651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    switch (Kind) {
1075651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    case EK_File:
1076a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      Result = llvm::make_unique<RedirectingFileEntry>(
1077a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar          LastComponent, std::move(ExternalContentsPath), UseExternalName);
1078651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      break;
1079651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    case EK_Directory:
1080a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      Result = llvm::make_unique<RedirectingDirectoryEntry>(
1081a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar          LastComponent, std::move(EntryArrayContents),
1082a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar          Status("", getNextVirtualUniqueID(), sys::TimeValue::now(), 0, 0, 0,
1083a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                 file_type::directory_file, sys::fs::all_all));
1084651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      break;
1085651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
1086651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1087651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    StringRef Parent = sys::path::parent_path(Trimmed);
1088651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (Parent.empty())
1089651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return Result;
1090651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1091651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    // if 'name' contains multiple components, create implicit directory entries
1092651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    for (sys::path::reverse_iterator I = sys::path::rbegin(Parent),
1093651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                                     E = sys::path::rend(Parent);
1094651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines         I != E; ++I) {
1095a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      std::vector<std::unique_ptr<Entry>> Entries;
1096a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      Entries.push_back(std::move(Result));
1097a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      Result = llvm::make_unique<RedirectingDirectoryEntry>(
1098a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar          *I, std::move(Entries),
1099a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar          Status("", getNextVirtualUniqueID(), sys::TimeValue::now(), 0, 0, 0,
1100a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                 file_type::directory_file, sys::fs::all_all));
1101651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
1102651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return Result;
1103651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
1104651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1105651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinespublic:
1106a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  RedirectingFileSystemParser(yaml::Stream &S) : Stream(S) {}
1107651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1108651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // false on error
1109a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  bool parse(yaml::Node *Root, RedirectingFileSystem *FS) {
1110651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    yaml::MappingNode *Top = dyn_cast<yaml::MappingNode>(Root);
1111651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (!Top) {
1112651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      error(Root, "expected mapping node");
1113651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return false;
1114651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
1115651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1116651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    KeyStatusPair Fields[] = {
1117651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      KeyStatusPair("version", true),
1118651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      KeyStatusPair("case-sensitive", false),
1119651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      KeyStatusPair("use-external-names", false),
1120651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      KeyStatusPair("roots", true),
1121651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    };
1122651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1123a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
1124651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1125651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    // Parse configuration and 'roots'
1126651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    for (yaml::MappingNode::iterator I = Top->begin(), E = Top->end(); I != E;
1127651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines         ++I) {
1128651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      SmallString<10> KeyBuffer;
1129651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      StringRef Key;
1130651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      if (!parseScalarString(I->getKey(), Key, KeyBuffer))
1131651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        return false;
1132651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1133651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      if (!checkDuplicateOrUnknownKey(I->getKey(), Key, Keys))
1134651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        return false;
1135651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1136651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      if (Key == "roots") {
1137651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        yaml::SequenceNode *Roots = dyn_cast<yaml::SequenceNode>(I->getValue());
1138651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (!Roots) {
1139651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          error(I->getValue(), "expected array");
1140651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          return false;
1141651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
1142651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1143651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        for (yaml::SequenceNode::iterator I = Roots->begin(), E = Roots->end();
1144651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines             I != E; ++I) {
1145a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar          if (std::unique_ptr<Entry> E = parseEntry(&*I))
1146a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar            FS->Roots.push_back(std::move(E));
1147651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          else
1148651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines            return false;
1149651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
1150651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      } else if (Key == "version") {
1151651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        StringRef VersionString;
1152651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        SmallString<4> Storage;
1153651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (!parseScalarString(I->getValue(), VersionString, Storage))
1154651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          return false;
1155651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        int Version;
1156651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (VersionString.getAsInteger<int>(10, Version)) {
1157651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          error(I->getValue(), "expected integer");
1158651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          return false;
1159651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
1160651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (Version < 0) {
1161651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          error(I->getValue(), "invalid version number");
1162651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          return false;
1163651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
1164651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (Version != 0) {
1165651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          error(I->getValue(), "version mismatch, expected 0");
1166651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          return false;
1167651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        }
1168651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      } else if (Key == "case-sensitive") {
1169651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (!parseScalarBool(I->getValue(), FS->CaseSensitive))
1170651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          return false;
1171651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      } else if (Key == "use-external-names") {
1172651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        if (!parseScalarBool(I->getValue(), FS->UseExternalNames))
1173651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          return false;
1174651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      } else {
1175651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        llvm_unreachable("key missing from Keys");
1176651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      }
1177651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
1178651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1179651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (Stream.failed())
1180651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return false;
1181651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1182651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (!checkMissingKeys(Top, Keys))
1183651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return false;
1184651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return true;
1185651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
1186651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines};
1187651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines} // end of anonymous namespace
1188651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1189a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga NainarEntry::~Entry() = default;
1190651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1191a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga NainarRedirectingFileSystem *RedirectingFileSystem::create(
1192a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    std::unique_ptr<MemoryBuffer> Buffer, SourceMgr::DiagHandlerTy DiagHandler,
1193a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    void *DiagContext, IntrusiveRefCntPtr<FileSystem> ExternalFS) {
1194651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1195651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  SourceMgr SM;
1196176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  yaml::Stream Stream(Buffer->getMemBufferRef(), SM);
1197651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1198651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  SM.setDiagHandler(DiagHandler, DiagContext);
1199651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  yaml::document_iterator DI = Stream.begin();
1200651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  yaml::Node *Root = DI->getRoot();
1201651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (DI == Stream.end() || !Root) {
1202651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    SM.PrintMessage(SMLoc(), SourceMgr::DK_Error, "expected root node");
12036bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    return nullptr;
1204651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
1205651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1206a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  RedirectingFileSystemParser P(Stream);
1207651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1208a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  std::unique_ptr<RedirectingFileSystem> FS(
1209a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      new RedirectingFileSystem(ExternalFS));
1210651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (!P.parse(Root, FS.get()))
12116bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    return nullptr;
1212651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1213651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return FS.release();
1214651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
1215651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1216a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga NainarErrorOr<Entry *> RedirectingFileSystem::lookupPath(const Twine &Path_) {
1217651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  SmallString<256> Path;
1218651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Path_.toVector(Path);
1219651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1220651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // Handle relative paths
1221a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  if (std::error_code EC = makeAbsolute(Path))
1222651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return EC;
1223651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1224651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (Path.empty())
1225c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    return make_error_code(llvm::errc::invalid_argument);
1226651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1227651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  sys::path::const_iterator Start = sys::path::begin(Path);
1228651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  sys::path::const_iterator End = sys::path::end(Path);
1229a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  for (const std::unique_ptr<Entry> &Root : Roots) {
1230a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    ErrorOr<Entry *> Result = lookupPath(Start, End, Root.get());
1231c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
1232651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return Result;
1233651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
1234c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  return make_error_code(llvm::errc::no_such_file_or_directory);
1235651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
1236651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1237a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga NainarErrorOr<Entry *>
1238a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga NainarRedirectingFileSystem::lookupPath(sys::path::const_iterator Start,
1239a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                                  sys::path::const_iterator End, Entry *From) {
1240651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (Start->equals("."))
1241651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    ++Start;
1242651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1243651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // FIXME: handle ..
1244651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (CaseSensitive ? !Start->equals(From->getName())
1245651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                    : !Start->equals_lower(From->getName()))
1246651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    // failure to match
1247c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    return make_error_code(llvm::errc::no_such_file_or_directory);
1248651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1249651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ++Start;
1250651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1251651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (Start == End) {
1252651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    // Match!
1253651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return From;
1254651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
1255651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1256a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  auto *DE = dyn_cast<RedirectingDirectoryEntry>(From);
1257651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (!DE)
1258c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    return make_error_code(llvm::errc::not_a_directory);
1259651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1260a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  for (const std::unique_ptr<Entry> &DirEntry :
1261a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar       llvm::make_range(DE->contents_begin(), DE->contents_end())) {
1262a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    ErrorOr<Entry *> Result = lookupPath(Start, End, DirEntry.get());
1263c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
1264651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return Result;
1265651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
1266c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  return make_error_code(llvm::errc::no_such_file_or_directory);
1267651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
1268651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1269a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarstatic Status getRedirectedFileStatus(const Twine &Path, bool UseExternalNames,
1270a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                                      Status ExternalStatus) {
1271a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  Status S = ExternalStatus;
1272a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  if (!UseExternalNames)
1273a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    S = Status::copyWithNewName(S, Path.str());
1274a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  S.IsVFSMapped = true;
1275a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  return S;
1276a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar}
1277a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
1278a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga NainarErrorOr<Status> RedirectingFileSystem::status(const Twine &Path, Entry *E) {
1279c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  assert(E != nullptr);
1280a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  if (auto *F = dyn_cast<RedirectingFileEntry>(E)) {
1281651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    ErrorOr<Status> S = ExternalFS->status(F->getExternalContentsPath());
1282651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    assert(!S || S->getName() == F->getExternalContentsPath());
12836bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if (S)
1284a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      return getRedirectedFileStatus(Path, F->useExternalName(UseExternalNames),
1285a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                                     *S);
1286651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return S;
1287651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  } else { // directory
1288a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    auto *DE = cast<RedirectingDirectoryEntry>(E);
1289a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return Status::copyWithNewName(DE->getStatus(), Path.str());
1290651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
1291651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
1292651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1293a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga NainarErrorOr<Status> RedirectingFileSystem::status(const Twine &Path) {
1294c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  ErrorOr<Entry *> Result = lookupPath(Path);
1295c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  if (!Result)
1296c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    return Result.getError();
1297c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  return status(Path, *Result);
1298c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines}
1299c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
1300a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarnamespace {
1301a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar/// Provide a file wrapper with an overriden status.
1302a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarclass FileWithFixedStatus : public File {
1303a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  std::unique_ptr<File> InnerFile;
1304a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  Status S;
1305a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
1306a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainarpublic:
1307a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  FileWithFixedStatus(std::unique_ptr<File> InnerFile, Status S)
1308a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      : InnerFile(std::move(InnerFile)), S(S) {}
1309a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
1310a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  ErrorOr<Status> status() override { return S; }
1311a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
1312a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
1313a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar            bool IsVolatile) override {
1314a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
1315a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                                IsVolatile);
1316a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  }
1317a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  std::error_code close() override { return InnerFile->close(); }
1318a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar};
1319a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar} // end anonymous namespace
1320a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar
1321a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga NainarErrorOr<std::unique_ptr<File>>
1322a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga NainarRedirectingFileSystem::openFileForRead(const Twine &Path) {
1323651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ErrorOr<Entry *> E = lookupPath(Path);
1324651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (!E)
1325651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return E.getError();
1326651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1327a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  auto *F = dyn_cast<RedirectingFileEntry>(*E);
1328651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  if (!F) // FIXME: errc::not_a_file?
1329c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    return make_error_code(llvm::errc::invalid_argument);
1330651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1331176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  auto Result = ExternalFS->openFileForRead(F->getExternalContentsPath());
1332176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  if (!Result)
1333176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    return Result;
1334651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1335a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  auto ExternalStatus = (*Result)->status();
1336a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  if (!ExternalStatus)
1337a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    return ExternalStatus.getError();
1338651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1339a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  // FIXME: Update the status with the name and VFSMapped.
1340a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  Status S = getRedirectedFileStatus(Path, F->useExternalName(UseExternalNames),
1341a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                                     *ExternalStatus);
1342a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  return std::unique_ptr<File>(
1343a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar      llvm::make_unique<FileWithFixedStatus>(std::move(*Result), S));
1344651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
1345651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1346651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesIntrusiveRefCntPtr<FileSystem>
1347176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hinesvfs::getVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,
1348176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines                    SourceMgr::DiagHandlerTy DiagHandler, void *DiagContext,
1349651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                    IntrusiveRefCntPtr<FileSystem> ExternalFS) {
1350a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar  return RedirectingFileSystem::create(std::move(Buffer), DiagHandler,
1351a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar                                       DiagContext, ExternalFS);
1352651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
1353651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
1354651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesUniqueID vfs::getNextVirtualUniqueID() {
1355651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  static std::atomic<unsigned> UID;
1356651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  unsigned ID = ++UID;
1357651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // The following assumes that uint64_t max will never collide with a real
1358651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // dev_t value from the OS.
1359651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  return UniqueID(std::numeric_limits<uint64_t>::max(), ID);
1360651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
13616bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
13626bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines#ifndef NDEBUG
13636bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesstatic bool pathHasTraversal(StringRef Path) {
13646bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  using namespace llvm::sys;
13656bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path)))
13666bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if (Comp == "." || Comp == "..")
13676bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      return true;
13686bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  return false;
13696bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
13706bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines#endif
13716bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
13726bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesvoid YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) {
13736bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute");
13746bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  assert(sys::path::is_absolute(RealPath) && "real path not absolute");
13756bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  assert(!pathHasTraversal(VirtualPath) && "path traversal is not supported");
13766bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  Mappings.emplace_back(VirtualPath, RealPath);
13776bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
13786bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
13796bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesnamespace {
13806bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesclass JSONWriter {
13816bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  llvm::raw_ostream &OS;
13826bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  SmallVector<StringRef, 16> DirStack;
13836bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  inline unsigned getDirIndent() { return 4 * DirStack.size(); }
13846bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  inline unsigned getFileIndent() { return 4 * (DirStack.size() + 1); }
13856bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  bool containedIn(StringRef Parent, StringRef Path);
13866bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  StringRef containedPart(StringRef Parent, StringRef Path);
13876bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  void startDirectory(StringRef Path);
13886bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  void endDirectory();
13896bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  void writeEntry(StringRef VPath, StringRef RPath);
13906bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
13916bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinespublic:
13926bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  JSONWriter(llvm::raw_ostream &OS) : OS(OS) {}
13936bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  void write(ArrayRef<YAMLVFSEntry> Entries, Optional<bool> IsCaseSensitive);
13946bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines};
13956bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
13966bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
13976bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesbool JSONWriter::containedIn(StringRef Parent, StringRef Path) {
13986bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  using namespace llvm::sys;
13996bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  // Compare each path component.
14006bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  auto IParent = path::begin(Parent), EParent = path::end(Parent);
14016bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  for (auto IChild = path::begin(Path), EChild = path::end(Path);
14026bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines       IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
14036bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    if (*IParent != *IChild)
14046bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      return false;
14056bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  }
14066bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  // Have we exhausted the parent path?
14076bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  return IParent == EParent;
14086bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
14096bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
14106bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen HinesStringRef JSONWriter::containedPart(StringRef Parent, StringRef Path) {
14116bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  assert(!Parent.empty());
14126bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  assert(containedIn(Parent, Path));
14136bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  return Path.slice(Parent.size() + 1, StringRef::npos);
14146bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
14156bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
14166bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesvoid JSONWriter::startDirectory(StringRef Path) {
14176bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  StringRef Name =
14186bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      DirStack.empty() ? Path : containedPart(DirStack.back(), Path);
14196bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  DirStack.push_back(Path);
14206bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  unsigned Indent = getDirIndent();
14216bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent) << "{\n";
14226bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent + 2) << "'type': 'directory',\n";
14236bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(Name) << "\",\n";
14246bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent + 2) << "'contents': [\n";
14256bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
14266bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
14276bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesvoid JSONWriter::endDirectory() {
14286bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  unsigned Indent = getDirIndent();
14296bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent + 2) << "]\n";
14306bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent) << "}";
14316bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
14326bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  DirStack.pop_back();
14336bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
14346bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
14356bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesvoid JSONWriter::writeEntry(StringRef VPath, StringRef RPath) {
14366bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  unsigned Indent = getFileIndent();
14376bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent) << "{\n";
14386bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent + 2) << "'type': 'file',\n";
14396bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(VPath) << "\",\n";
14406bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent + 2) << "'external-contents': \""
14416bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                        << llvm::yaml::escape(RPath) << "\"\n";
14426bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS.indent(Indent) << "}";
14436bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
14446bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
14456bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesvoid JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries,
14466bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                       Optional<bool> IsCaseSensitive) {
14476bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  using namespace llvm::sys;
14486bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
14496bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS << "{\n"
14506bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        "  'version': 0,\n";
14516bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  if (IsCaseSensitive.hasValue())
14526bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    OS << "  'case-sensitive': '"
14536bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines       << (IsCaseSensitive.getValue() ? "true" : "false") << "',\n";
14546bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  OS << "  'roots': [\n";
14556bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
1456176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  if (!Entries.empty()) {
1457176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    const YAMLVFSEntry &Entry = Entries.front();
1458176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    startDirectory(path::parent_path(Entry.VPath));
1459176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    writeEntry(path::filename(Entry.VPath), Entry.RPath);
1460176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines
1461176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    for (const auto &Entry : Entries.slice(1)) {
1462176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines      StringRef Dir = path::parent_path(Entry.VPath);
1463176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines      if (Dir == DirStack.back())
1464176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        OS << ",\n";
1465176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines      else {
1466176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        while (!DirStack.empty() && !containedIn(DirStack.back(), Dir)) {
1467176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines          OS << "\n";
1468176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines          endDirectory();
1469176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        }
1470176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        OS << ",\n";
1471176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines        startDirectory(Dir);
14726bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      }
1473176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines      writeEntry(path::filename(Entry.VPath), Entry.RPath);
14746bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
14756bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
1476176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    while (!DirStack.empty()) {
1477176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines      OS << "\n";
1478176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines      endDirectory();
1479176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines    }
14806bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    OS << "\n";
14816bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  }
14826bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
1483176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines  OS << "  ]\n"
14846bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines     << "}\n";
14856bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
14866bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
14876bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hinesvoid YAMLVFSWriter::write(llvm::raw_ostream &OS) {
14886bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  std::sort(Mappings.begin(), Mappings.end(),
14896bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            [](const YAMLVFSEntry &LHS, const YAMLVFSEntry &RHS) {
14906bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    return LHS.VPath < RHS.VPath;
14916bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  });
14926bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
14936bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  JSONWriter(OS).write(Mappings, IsCaseSensitive);
14946bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines}
1495c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
1496a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga NainarVFSFromYamlDirIterImpl::VFSFromYamlDirIterImpl(
1497a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    const Twine &_Path, RedirectingFileSystem &FS,
1498a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    RedirectingDirectoryEntry::iterator Begin,
1499a4de17562d13d7a8188108243c4cfbd52f33229aPirama Arumuga Nainar    RedirectingDirectoryEntry::iterator End, std::error_code &EC)
1500c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    : Dir(_Path.str()), FS(FS), Current(Begin), End(End) {
1501c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  if (Current != End) {
1502c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    SmallString<128> PathStr(Dir);
1503c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    llvm::sys::path::append(PathStr, (*Current)->getName());
15043ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    llvm::ErrorOr<vfs::Status> S = FS.status(PathStr);
1505c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (S)
1506c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      CurrentEntry = *S;
1507c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    else
1508c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      EC = S.getError();
1509c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  }
1510c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines}
1511c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
1512c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesstd::error_code VFSFromYamlDirIterImpl::increment() {
1513c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  assert(Current != End && "cannot iterate past end");
1514c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  if (++Current != End) {
1515c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    SmallString<128> PathStr(Dir);
1516c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    llvm::sys::path::append(PathStr, (*Current)->getName());
15173ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    llvm::ErrorOr<vfs::Status> S = FS.status(PathStr);
1518c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (!S)
1519c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      return S.getError();
1520c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    CurrentEntry = *S;
1521c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  } else {
1522c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    CurrentEntry = Status();
1523c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  }
1524c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  return std::error_code();
1525c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines}
1526c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
1527c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesvfs::recursive_directory_iterator::recursive_directory_iterator(FileSystem &FS_,
1528c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                                                           const Twine &Path,
1529c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines                                                           std::error_code &EC)
1530c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    : FS(&FS_) {
1531c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  directory_iterator I = FS->dir_begin(Path, EC);
1532c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  if (!EC && I != directory_iterator()) {
1533c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    State = std::make_shared<IterState>();
1534c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    State->push(I);
1535c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  }
1536c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines}
1537c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
1538c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesvfs::recursive_directory_iterator &
1539c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hinesrecursive_directory_iterator::increment(std::error_code &EC) {
1540c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  assert(FS && State && !State->empty() && "incrementing past end");
1541c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  assert(State->top()->isStatusKnown() && "non-canonical end iterator");
1542c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  vfs::directory_iterator End;
1543c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  if (State->top()->isDirectory()) {
1544c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    vfs::directory_iterator I = FS->dir_begin(State->top()->getName(), EC);
1545c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (EC)
1546c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      return *this;
1547c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    if (I != End) {
1548c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      State->push(I);
1549c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines      return *this;
1550c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    }
1551c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  }
1552c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
1553c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  while (!State->empty() && State->top().increment(EC) == End)
1554c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    State->pop();
1555c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
1556c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  if (State->empty())
1557c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines    State.reset(); // end iterator
1558c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
1559c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines  return *this;
1560c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines}
1561