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