xref: /minix3/external/bsd/llvm/dist/clang/lib/Basic/VirtualFileSystem.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc //===- VirtualFileSystem.cpp - Virtual File System Layer --------*- C++ -*-===//
2*0a6a1f1dSLionel Sambuc //
3*0a6a1f1dSLionel Sambuc //                     The LLVM Compiler Infrastructure
4*0a6a1f1dSLionel Sambuc //
5*0a6a1f1dSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6*0a6a1f1dSLionel Sambuc // License. See LICENSE.TXT for details.
7*0a6a1f1dSLionel Sambuc //
8*0a6a1f1dSLionel Sambuc //===----------------------------------------------------------------------===//
9*0a6a1f1dSLionel Sambuc // This file implements the VirtualFileSystem interface.
10*0a6a1f1dSLionel Sambuc //===----------------------------------------------------------------------===//
11*0a6a1f1dSLionel Sambuc 
12*0a6a1f1dSLionel Sambuc #include "clang/Basic/VirtualFileSystem.h"
13*0a6a1f1dSLionel Sambuc #include "llvm/ADT/DenseMap.h"
14*0a6a1f1dSLionel Sambuc #include "llvm/ADT/STLExtras.h"
15*0a6a1f1dSLionel Sambuc #include "llvm/ADT/StringExtras.h"
16*0a6a1f1dSLionel Sambuc #include "llvm/ADT/StringSet.h"
17*0a6a1f1dSLionel Sambuc #include "llvm/ADT/iterator_range.h"
18*0a6a1f1dSLionel Sambuc #include "llvm/Support/Errc.h"
19*0a6a1f1dSLionel Sambuc #include "llvm/Support/MemoryBuffer.h"
20*0a6a1f1dSLionel Sambuc #include "llvm/Support/Path.h"
21*0a6a1f1dSLionel Sambuc #include "llvm/Support/YAMLParser.h"
22*0a6a1f1dSLionel Sambuc #if !defined(_LIBCPP_HAS_NO_THREADS) && defined(__minix)
23*0a6a1f1dSLionel Sambuc #include <atomic>
24*0a6a1f1dSLionel Sambuc #endif // !defined(_LIBCPP_HAS_NO_THREADS) && defined(__minix)
25*0a6a1f1dSLionel Sambuc #include <memory>
26*0a6a1f1dSLionel Sambuc 
27*0a6a1f1dSLionel Sambuc using namespace clang;
28*0a6a1f1dSLionel Sambuc using namespace clang::vfs;
29*0a6a1f1dSLionel Sambuc using namespace llvm;
30*0a6a1f1dSLionel Sambuc using llvm::sys::fs::file_status;
31*0a6a1f1dSLionel Sambuc using llvm::sys::fs::file_type;
32*0a6a1f1dSLionel Sambuc using llvm::sys::fs::perms;
33*0a6a1f1dSLionel Sambuc using llvm::sys::fs::UniqueID;
34*0a6a1f1dSLionel Sambuc 
Status(const file_status & Status)35*0a6a1f1dSLionel Sambuc Status::Status(const file_status &Status)
36*0a6a1f1dSLionel Sambuc     : UID(Status.getUniqueID()), MTime(Status.getLastModificationTime()),
37*0a6a1f1dSLionel Sambuc       User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()),
38*0a6a1f1dSLionel Sambuc       Type(Status.type()), Perms(Status.permissions()), IsVFSMapped(false)  {}
39*0a6a1f1dSLionel Sambuc 
Status(StringRef Name,StringRef ExternalName,UniqueID UID,sys::TimeValue MTime,uint32_t User,uint32_t Group,uint64_t Size,file_type Type,perms Perms)40*0a6a1f1dSLionel Sambuc Status::Status(StringRef Name, StringRef ExternalName, UniqueID UID,
41*0a6a1f1dSLionel Sambuc                sys::TimeValue MTime, uint32_t User, uint32_t Group,
42*0a6a1f1dSLionel Sambuc                uint64_t Size, file_type Type, perms Perms)
43*0a6a1f1dSLionel Sambuc     : Name(Name), UID(UID), MTime(MTime), User(User), Group(Group), Size(Size),
44*0a6a1f1dSLionel Sambuc       Type(Type), Perms(Perms), IsVFSMapped(false) {}
45*0a6a1f1dSLionel Sambuc 
equivalent(const Status & Other) const46*0a6a1f1dSLionel Sambuc bool Status::equivalent(const Status &Other) const {
47*0a6a1f1dSLionel Sambuc   return getUniqueID() == Other.getUniqueID();
48*0a6a1f1dSLionel Sambuc }
isDirectory() const49*0a6a1f1dSLionel Sambuc bool Status::isDirectory() const {
50*0a6a1f1dSLionel Sambuc   return Type == file_type::directory_file;
51*0a6a1f1dSLionel Sambuc }
isRegularFile() const52*0a6a1f1dSLionel Sambuc bool Status::isRegularFile() const {
53*0a6a1f1dSLionel Sambuc   return Type == file_type::regular_file;
54*0a6a1f1dSLionel Sambuc }
isOther() const55*0a6a1f1dSLionel Sambuc bool Status::isOther() const {
56*0a6a1f1dSLionel Sambuc   return exists() && !isRegularFile() && !isDirectory() && !isSymlink();
57*0a6a1f1dSLionel Sambuc }
isSymlink() const58*0a6a1f1dSLionel Sambuc bool Status::isSymlink() const {
59*0a6a1f1dSLionel Sambuc   return Type == file_type::symlink_file;
60*0a6a1f1dSLionel Sambuc }
isStatusKnown() const61*0a6a1f1dSLionel Sambuc bool Status::isStatusKnown() const {
62*0a6a1f1dSLionel Sambuc   return Type != file_type::status_error;
63*0a6a1f1dSLionel Sambuc }
exists() const64*0a6a1f1dSLionel Sambuc bool Status::exists() const {
65*0a6a1f1dSLionel Sambuc   return isStatusKnown() && Type != file_type::file_not_found;
66*0a6a1f1dSLionel Sambuc }
67*0a6a1f1dSLionel Sambuc 
~File()68*0a6a1f1dSLionel Sambuc File::~File() {}
69*0a6a1f1dSLionel Sambuc 
~FileSystem()70*0a6a1f1dSLionel Sambuc FileSystem::~FileSystem() {}
71*0a6a1f1dSLionel Sambuc 
72*0a6a1f1dSLionel Sambuc ErrorOr<std::unique_ptr<MemoryBuffer>>
getBufferForFile(const llvm::Twine & Name,int64_t FileSize,bool RequiresNullTerminator,bool IsVolatile)73*0a6a1f1dSLionel Sambuc FileSystem::getBufferForFile(const llvm::Twine &Name, int64_t FileSize,
74*0a6a1f1dSLionel Sambuc                              bool RequiresNullTerminator, bool IsVolatile) {
75*0a6a1f1dSLionel Sambuc   auto F = openFileForRead(Name);
76*0a6a1f1dSLionel Sambuc   if (!F)
77*0a6a1f1dSLionel Sambuc     return F.getError();
78*0a6a1f1dSLionel Sambuc 
79*0a6a1f1dSLionel Sambuc   return (*F)->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile);
80*0a6a1f1dSLionel Sambuc }
81*0a6a1f1dSLionel Sambuc 
82*0a6a1f1dSLionel Sambuc //===-----------------------------------------------------------------------===/
83*0a6a1f1dSLionel Sambuc // RealFileSystem implementation
84*0a6a1f1dSLionel Sambuc //===-----------------------------------------------------------------------===/
85*0a6a1f1dSLionel Sambuc 
86*0a6a1f1dSLionel Sambuc namespace {
87*0a6a1f1dSLionel Sambuc /// \brief Wrapper around a raw file descriptor.
88*0a6a1f1dSLionel Sambuc class RealFile : public File {
89*0a6a1f1dSLionel Sambuc   int FD;
90*0a6a1f1dSLionel Sambuc   Status S;
91*0a6a1f1dSLionel Sambuc   friend class RealFileSystem;
RealFile(int FD)92*0a6a1f1dSLionel Sambuc   RealFile(int FD) : FD(FD) {
93*0a6a1f1dSLionel Sambuc     assert(FD >= 0 && "Invalid or inactive file descriptor");
94*0a6a1f1dSLionel Sambuc   }
95*0a6a1f1dSLionel Sambuc 
96*0a6a1f1dSLionel Sambuc public:
97*0a6a1f1dSLionel Sambuc   ~RealFile();
98*0a6a1f1dSLionel Sambuc   ErrorOr<Status> status() override;
99*0a6a1f1dSLionel Sambuc   ErrorOr<std::unique_ptr<MemoryBuffer>>
100*0a6a1f1dSLionel Sambuc   getBuffer(const Twine &Name, int64_t FileSize = -1,
101*0a6a1f1dSLionel Sambuc             bool RequiresNullTerminator = true,
102*0a6a1f1dSLionel Sambuc             bool IsVolatile = false) override;
103*0a6a1f1dSLionel Sambuc   std::error_code close() override;
104*0a6a1f1dSLionel Sambuc   void setName(StringRef Name) override;
105*0a6a1f1dSLionel Sambuc };
106*0a6a1f1dSLionel Sambuc } // end anonymous namespace
~RealFile()107*0a6a1f1dSLionel Sambuc RealFile::~RealFile() { close(); }
108*0a6a1f1dSLionel Sambuc 
status()109*0a6a1f1dSLionel Sambuc ErrorOr<Status> RealFile::status() {
110*0a6a1f1dSLionel Sambuc   assert(FD != -1 && "cannot stat closed file");
111*0a6a1f1dSLionel Sambuc   if (!S.isStatusKnown()) {
112*0a6a1f1dSLionel Sambuc     file_status RealStatus;
113*0a6a1f1dSLionel Sambuc     if (std::error_code EC = sys::fs::status(FD, RealStatus))
114*0a6a1f1dSLionel Sambuc       return EC;
115*0a6a1f1dSLionel Sambuc     Status NewS(RealStatus);
116*0a6a1f1dSLionel Sambuc     NewS.setName(S.getName());
117*0a6a1f1dSLionel Sambuc     S = std::move(NewS);
118*0a6a1f1dSLionel Sambuc   }
119*0a6a1f1dSLionel Sambuc   return S;
120*0a6a1f1dSLionel Sambuc }
121*0a6a1f1dSLionel Sambuc 
122*0a6a1f1dSLionel Sambuc ErrorOr<std::unique_ptr<MemoryBuffer>>
getBuffer(const Twine & Name,int64_t FileSize,bool RequiresNullTerminator,bool IsVolatile)123*0a6a1f1dSLionel Sambuc RealFile::getBuffer(const Twine &Name, int64_t FileSize,
124*0a6a1f1dSLionel Sambuc                     bool RequiresNullTerminator, bool IsVolatile) {
125*0a6a1f1dSLionel Sambuc   assert(FD != -1 && "cannot get buffer for closed file");
126*0a6a1f1dSLionel Sambuc   return MemoryBuffer::getOpenFile(FD, Name, FileSize, RequiresNullTerminator,
127*0a6a1f1dSLionel Sambuc                                    IsVolatile);
128*0a6a1f1dSLionel Sambuc }
129*0a6a1f1dSLionel Sambuc 
130*0a6a1f1dSLionel Sambuc // FIXME: This is terrible, we need this for ::close.
131*0a6a1f1dSLionel Sambuc #if !defined(_MSC_VER) && !defined(__MINGW32__)
132*0a6a1f1dSLionel Sambuc #include <unistd.h>
133*0a6a1f1dSLionel Sambuc #include <sys/uio.h>
134*0a6a1f1dSLionel Sambuc #else
135*0a6a1f1dSLionel Sambuc #include <io.h>
136*0a6a1f1dSLionel Sambuc #ifndef S_ISFIFO
137*0a6a1f1dSLionel Sambuc #define S_ISFIFO(x) (0)
138*0a6a1f1dSLionel Sambuc #endif
139*0a6a1f1dSLionel Sambuc #endif
close()140*0a6a1f1dSLionel Sambuc std::error_code RealFile::close() {
141*0a6a1f1dSLionel Sambuc   if (::close(FD))
142*0a6a1f1dSLionel Sambuc     return std::error_code(errno, std::generic_category());
143*0a6a1f1dSLionel Sambuc   FD = -1;
144*0a6a1f1dSLionel Sambuc   return std::error_code();
145*0a6a1f1dSLionel Sambuc }
146*0a6a1f1dSLionel Sambuc 
setName(StringRef Name)147*0a6a1f1dSLionel Sambuc void RealFile::setName(StringRef Name) {
148*0a6a1f1dSLionel Sambuc   S.setName(Name);
149*0a6a1f1dSLionel Sambuc }
150*0a6a1f1dSLionel Sambuc 
151*0a6a1f1dSLionel Sambuc namespace {
152*0a6a1f1dSLionel Sambuc /// \brief The file system according to your operating system.
153*0a6a1f1dSLionel Sambuc class RealFileSystem : public FileSystem {
154*0a6a1f1dSLionel Sambuc public:
155*0a6a1f1dSLionel Sambuc   ErrorOr<Status> status(const Twine &Path) override;
156*0a6a1f1dSLionel Sambuc   ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
157*0a6a1f1dSLionel Sambuc   directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
158*0a6a1f1dSLionel Sambuc };
159*0a6a1f1dSLionel Sambuc } // end anonymous namespace
160*0a6a1f1dSLionel Sambuc 
status(const Twine & Path)161*0a6a1f1dSLionel Sambuc ErrorOr<Status> RealFileSystem::status(const Twine &Path) {
162*0a6a1f1dSLionel Sambuc   sys::fs::file_status RealStatus;
163*0a6a1f1dSLionel Sambuc   if (std::error_code EC = sys::fs::status(Path, RealStatus))
164*0a6a1f1dSLionel Sambuc     return EC;
165*0a6a1f1dSLionel Sambuc   Status Result(RealStatus);
166*0a6a1f1dSLionel Sambuc   Result.setName(Path.str());
167*0a6a1f1dSLionel Sambuc   return Result;
168*0a6a1f1dSLionel Sambuc }
169*0a6a1f1dSLionel Sambuc 
170*0a6a1f1dSLionel Sambuc ErrorOr<std::unique_ptr<File>>
openFileForRead(const Twine & Name)171*0a6a1f1dSLionel Sambuc RealFileSystem::openFileForRead(const Twine &Name) {
172*0a6a1f1dSLionel Sambuc   int FD;
173*0a6a1f1dSLionel Sambuc   if (std::error_code EC = sys::fs::openFileForRead(Name, FD))
174*0a6a1f1dSLionel Sambuc     return EC;
175*0a6a1f1dSLionel Sambuc   std::unique_ptr<File> Result(new RealFile(FD));
176*0a6a1f1dSLionel Sambuc   Result->setName(Name.str());
177*0a6a1f1dSLionel Sambuc   return std::move(Result);
178*0a6a1f1dSLionel Sambuc }
179*0a6a1f1dSLionel Sambuc 
getRealFileSystem()180*0a6a1f1dSLionel Sambuc IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
181*0a6a1f1dSLionel Sambuc   static IntrusiveRefCntPtr<FileSystem> FS = new RealFileSystem();
182*0a6a1f1dSLionel Sambuc   return FS;
183*0a6a1f1dSLionel Sambuc }
184*0a6a1f1dSLionel Sambuc 
185*0a6a1f1dSLionel Sambuc namespace {
186*0a6a1f1dSLionel Sambuc class RealFSDirIter : public clang::vfs::detail::DirIterImpl {
187*0a6a1f1dSLionel Sambuc   std::string Path;
188*0a6a1f1dSLionel Sambuc   llvm::sys::fs::directory_iterator Iter;
189*0a6a1f1dSLionel Sambuc public:
RealFSDirIter(const Twine & _Path,std::error_code & EC)190*0a6a1f1dSLionel Sambuc   RealFSDirIter(const Twine &_Path, std::error_code &EC)
191*0a6a1f1dSLionel Sambuc       : Path(_Path.str()), Iter(Path, EC) {
192*0a6a1f1dSLionel Sambuc     if (!EC && Iter != llvm::sys::fs::directory_iterator()) {
193*0a6a1f1dSLionel Sambuc       llvm::sys::fs::file_status S;
194*0a6a1f1dSLionel Sambuc       EC = Iter->status(S);
195*0a6a1f1dSLionel Sambuc       if (!EC) {
196*0a6a1f1dSLionel Sambuc         CurrentEntry = Status(S);
197*0a6a1f1dSLionel Sambuc         CurrentEntry.setName(Iter->path());
198*0a6a1f1dSLionel Sambuc       }
199*0a6a1f1dSLionel Sambuc     }
200*0a6a1f1dSLionel Sambuc   }
201*0a6a1f1dSLionel Sambuc 
increment()202*0a6a1f1dSLionel Sambuc   std::error_code increment() override {
203*0a6a1f1dSLionel Sambuc     std::error_code EC;
204*0a6a1f1dSLionel Sambuc     Iter.increment(EC);
205*0a6a1f1dSLionel Sambuc     if (EC) {
206*0a6a1f1dSLionel Sambuc       return EC;
207*0a6a1f1dSLionel Sambuc     } else if (Iter == llvm::sys::fs::directory_iterator()) {
208*0a6a1f1dSLionel Sambuc       CurrentEntry = Status();
209*0a6a1f1dSLionel Sambuc     } else {
210*0a6a1f1dSLionel Sambuc       llvm::sys::fs::file_status S;
211*0a6a1f1dSLionel Sambuc       EC = Iter->status(S);
212*0a6a1f1dSLionel Sambuc       CurrentEntry = Status(S);
213*0a6a1f1dSLionel Sambuc       CurrentEntry.setName(Iter->path());
214*0a6a1f1dSLionel Sambuc     }
215*0a6a1f1dSLionel Sambuc     return EC;
216*0a6a1f1dSLionel Sambuc   }
217*0a6a1f1dSLionel Sambuc };
218*0a6a1f1dSLionel Sambuc }
219*0a6a1f1dSLionel Sambuc 
dir_begin(const Twine & Dir,std::error_code & EC)220*0a6a1f1dSLionel Sambuc directory_iterator RealFileSystem::dir_begin(const Twine &Dir,
221*0a6a1f1dSLionel Sambuc                                              std::error_code &EC) {
222*0a6a1f1dSLionel Sambuc   return directory_iterator(std::make_shared<RealFSDirIter>(Dir, EC));
223*0a6a1f1dSLionel Sambuc }
224*0a6a1f1dSLionel Sambuc 
225*0a6a1f1dSLionel Sambuc //===-----------------------------------------------------------------------===/
226*0a6a1f1dSLionel Sambuc // OverlayFileSystem implementation
227*0a6a1f1dSLionel Sambuc //===-----------------------------------------------------------------------===/
OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> BaseFS)228*0a6a1f1dSLionel Sambuc OverlayFileSystem::OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> BaseFS) {
229*0a6a1f1dSLionel Sambuc   pushOverlay(BaseFS);
230*0a6a1f1dSLionel Sambuc }
231*0a6a1f1dSLionel Sambuc 
pushOverlay(IntrusiveRefCntPtr<FileSystem> FS)232*0a6a1f1dSLionel Sambuc void OverlayFileSystem::pushOverlay(IntrusiveRefCntPtr<FileSystem> FS) {
233*0a6a1f1dSLionel Sambuc   FSList.push_back(FS);
234*0a6a1f1dSLionel Sambuc }
235*0a6a1f1dSLionel Sambuc 
status(const Twine & Path)236*0a6a1f1dSLionel Sambuc ErrorOr<Status> OverlayFileSystem::status(const Twine &Path) {
237*0a6a1f1dSLionel Sambuc   // FIXME: handle symlinks that cross file systems
238*0a6a1f1dSLionel Sambuc   for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
239*0a6a1f1dSLionel Sambuc     ErrorOr<Status> Status = (*I)->status(Path);
240*0a6a1f1dSLionel Sambuc     if (Status || Status.getError() != llvm::errc::no_such_file_or_directory)
241*0a6a1f1dSLionel Sambuc       return Status;
242*0a6a1f1dSLionel Sambuc   }
243*0a6a1f1dSLionel Sambuc   return make_error_code(llvm::errc::no_such_file_or_directory);
244*0a6a1f1dSLionel Sambuc }
245*0a6a1f1dSLionel Sambuc 
246*0a6a1f1dSLionel Sambuc ErrorOr<std::unique_ptr<File>>
openFileForRead(const llvm::Twine & Path)247*0a6a1f1dSLionel Sambuc OverlayFileSystem::openFileForRead(const llvm::Twine &Path) {
248*0a6a1f1dSLionel Sambuc   // FIXME: handle symlinks that cross file systems
249*0a6a1f1dSLionel Sambuc   for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
250*0a6a1f1dSLionel Sambuc     auto Result = (*I)->openFileForRead(Path);
251*0a6a1f1dSLionel Sambuc     if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
252*0a6a1f1dSLionel Sambuc       return Result;
253*0a6a1f1dSLionel Sambuc   }
254*0a6a1f1dSLionel Sambuc   return make_error_code(llvm::errc::no_such_file_or_directory);
255*0a6a1f1dSLionel Sambuc }
256*0a6a1f1dSLionel Sambuc 
~DirIterImpl()257*0a6a1f1dSLionel Sambuc clang::vfs::detail::DirIterImpl::~DirIterImpl() { }
258*0a6a1f1dSLionel Sambuc 
259*0a6a1f1dSLionel Sambuc namespace {
260*0a6a1f1dSLionel Sambuc class OverlayFSDirIterImpl : public clang::vfs::detail::DirIterImpl {
261*0a6a1f1dSLionel Sambuc   OverlayFileSystem &Overlays;
262*0a6a1f1dSLionel Sambuc   std::string Path;
263*0a6a1f1dSLionel Sambuc   OverlayFileSystem::iterator CurrentFS;
264*0a6a1f1dSLionel Sambuc   directory_iterator CurrentDirIter;
265*0a6a1f1dSLionel Sambuc   llvm::StringSet<> SeenNames;
266*0a6a1f1dSLionel Sambuc 
incrementFS()267*0a6a1f1dSLionel Sambuc   std::error_code incrementFS() {
268*0a6a1f1dSLionel Sambuc     assert(CurrentFS != Overlays.overlays_end() && "incrementing past end");
269*0a6a1f1dSLionel Sambuc     ++CurrentFS;
270*0a6a1f1dSLionel Sambuc     for (auto E = Overlays.overlays_end(); CurrentFS != E; ++CurrentFS) {
271*0a6a1f1dSLionel Sambuc       std::error_code EC;
272*0a6a1f1dSLionel Sambuc       CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC);
273*0a6a1f1dSLionel Sambuc       if (EC && EC != errc::no_such_file_or_directory)
274*0a6a1f1dSLionel Sambuc         return EC;
275*0a6a1f1dSLionel Sambuc       if (CurrentDirIter != directory_iterator())
276*0a6a1f1dSLionel Sambuc         break; // found
277*0a6a1f1dSLionel Sambuc     }
278*0a6a1f1dSLionel Sambuc     return std::error_code();
279*0a6a1f1dSLionel Sambuc   }
280*0a6a1f1dSLionel Sambuc 
incrementDirIter(bool IsFirstTime)281*0a6a1f1dSLionel Sambuc   std::error_code incrementDirIter(bool IsFirstTime) {
282*0a6a1f1dSLionel Sambuc     assert((IsFirstTime || CurrentDirIter != directory_iterator()) &&
283*0a6a1f1dSLionel Sambuc            "incrementing past end");
284*0a6a1f1dSLionel Sambuc     std::error_code EC;
285*0a6a1f1dSLionel Sambuc     if (!IsFirstTime)
286*0a6a1f1dSLionel Sambuc       CurrentDirIter.increment(EC);
287*0a6a1f1dSLionel Sambuc     if (!EC && CurrentDirIter == directory_iterator())
288*0a6a1f1dSLionel Sambuc       EC = incrementFS();
289*0a6a1f1dSLionel Sambuc     return EC;
290*0a6a1f1dSLionel Sambuc   }
291*0a6a1f1dSLionel Sambuc 
incrementImpl(bool IsFirstTime)292*0a6a1f1dSLionel Sambuc   std::error_code incrementImpl(bool IsFirstTime) {
293*0a6a1f1dSLionel Sambuc     while (true) {
294*0a6a1f1dSLionel Sambuc       std::error_code EC = incrementDirIter(IsFirstTime);
295*0a6a1f1dSLionel Sambuc       if (EC || CurrentDirIter == directory_iterator()) {
296*0a6a1f1dSLionel Sambuc         CurrentEntry = Status();
297*0a6a1f1dSLionel Sambuc         return EC;
298*0a6a1f1dSLionel Sambuc       }
299*0a6a1f1dSLionel Sambuc       CurrentEntry = *CurrentDirIter;
300*0a6a1f1dSLionel Sambuc       StringRef Name = llvm::sys::path::filename(CurrentEntry.getName());
301*0a6a1f1dSLionel Sambuc       if (SeenNames.insert(Name).second)
302*0a6a1f1dSLionel Sambuc         return EC; // name not seen before
303*0a6a1f1dSLionel Sambuc     }
304*0a6a1f1dSLionel Sambuc     llvm_unreachable("returned above");
305*0a6a1f1dSLionel Sambuc   }
306*0a6a1f1dSLionel Sambuc 
307*0a6a1f1dSLionel Sambuc public:
OverlayFSDirIterImpl(const Twine & Path,OverlayFileSystem & FS,std::error_code & EC)308*0a6a1f1dSLionel Sambuc   OverlayFSDirIterImpl(const Twine &Path, OverlayFileSystem &FS,
309*0a6a1f1dSLionel Sambuc                        std::error_code &EC)
310*0a6a1f1dSLionel Sambuc       : Overlays(FS), Path(Path.str()), CurrentFS(Overlays.overlays_begin()) {
311*0a6a1f1dSLionel Sambuc     CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC);
312*0a6a1f1dSLionel Sambuc     EC = incrementImpl(true);
313*0a6a1f1dSLionel Sambuc   }
314*0a6a1f1dSLionel Sambuc 
increment()315*0a6a1f1dSLionel Sambuc   std::error_code increment() override { return incrementImpl(false); }
316*0a6a1f1dSLionel Sambuc };
317*0a6a1f1dSLionel Sambuc } // end anonymous namespace
318*0a6a1f1dSLionel Sambuc 
dir_begin(const Twine & Dir,std::error_code & EC)319*0a6a1f1dSLionel Sambuc directory_iterator OverlayFileSystem::dir_begin(const Twine &Dir,
320*0a6a1f1dSLionel Sambuc                                                 std::error_code &EC) {
321*0a6a1f1dSLionel Sambuc   return directory_iterator(
322*0a6a1f1dSLionel Sambuc       std::make_shared<OverlayFSDirIterImpl>(Dir, *this, EC));
323*0a6a1f1dSLionel Sambuc }
324*0a6a1f1dSLionel Sambuc 
325*0a6a1f1dSLionel Sambuc //===-----------------------------------------------------------------------===/
326*0a6a1f1dSLionel Sambuc // VFSFromYAML implementation
327*0a6a1f1dSLionel Sambuc //===-----------------------------------------------------------------------===/
328*0a6a1f1dSLionel Sambuc 
329*0a6a1f1dSLionel Sambuc // Allow DenseMap<StringRef, ...>.  This is useful below because we know all the
330*0a6a1f1dSLionel Sambuc // strings are literals and will outlive the map, and there is no reason to
331*0a6a1f1dSLionel Sambuc // store them.
332*0a6a1f1dSLionel Sambuc namespace llvm {
333*0a6a1f1dSLionel Sambuc   template<>
334*0a6a1f1dSLionel Sambuc   struct DenseMapInfo<StringRef> {
335*0a6a1f1dSLionel Sambuc     // This assumes that "" will never be a valid key.
getEmptyKeyllvm::DenseMapInfo336*0a6a1f1dSLionel Sambuc     static inline StringRef getEmptyKey() { return StringRef(""); }
getTombstoneKeyllvm::DenseMapInfo337*0a6a1f1dSLionel Sambuc     static inline StringRef getTombstoneKey() { return StringRef(); }
getHashValuellvm::DenseMapInfo338*0a6a1f1dSLionel Sambuc     static unsigned getHashValue(StringRef Val) { return HashString(Val); }
isEqualllvm::DenseMapInfo339*0a6a1f1dSLionel Sambuc     static bool isEqual(StringRef LHS, StringRef RHS) { return LHS == RHS; }
340*0a6a1f1dSLionel Sambuc   };
341*0a6a1f1dSLionel Sambuc }
342*0a6a1f1dSLionel Sambuc 
343*0a6a1f1dSLionel Sambuc namespace {
344*0a6a1f1dSLionel Sambuc 
345*0a6a1f1dSLionel Sambuc enum EntryKind {
346*0a6a1f1dSLionel Sambuc   EK_Directory,
347*0a6a1f1dSLionel Sambuc   EK_File
348*0a6a1f1dSLionel Sambuc };
349*0a6a1f1dSLionel Sambuc 
350*0a6a1f1dSLionel Sambuc /// \brief A single file or directory in the VFS.
351*0a6a1f1dSLionel Sambuc class Entry {
352*0a6a1f1dSLionel Sambuc   EntryKind Kind;
353*0a6a1f1dSLionel Sambuc   std::string Name;
354*0a6a1f1dSLionel Sambuc 
355*0a6a1f1dSLionel Sambuc public:
356*0a6a1f1dSLionel Sambuc   virtual ~Entry();
Entry(EntryKind K,StringRef Name)357*0a6a1f1dSLionel Sambuc   Entry(EntryKind K, StringRef Name) : Kind(K), Name(Name) {}
getName() const358*0a6a1f1dSLionel Sambuc   StringRef getName() const { return Name; }
getKind() const359*0a6a1f1dSLionel Sambuc   EntryKind getKind() const { return Kind; }
360*0a6a1f1dSLionel Sambuc };
361*0a6a1f1dSLionel Sambuc 
362*0a6a1f1dSLionel Sambuc class DirectoryEntry : public Entry {
363*0a6a1f1dSLionel Sambuc   std::vector<Entry *> Contents;
364*0a6a1f1dSLionel Sambuc   Status S;
365*0a6a1f1dSLionel Sambuc 
366*0a6a1f1dSLionel Sambuc public:
367*0a6a1f1dSLionel Sambuc   virtual ~DirectoryEntry();
DirectoryEntry(StringRef Name,std::vector<Entry * > Contents,Status S)368*0a6a1f1dSLionel Sambuc   DirectoryEntry(StringRef Name, std::vector<Entry *> Contents, Status S)
369*0a6a1f1dSLionel Sambuc       : Entry(EK_Directory, Name), Contents(std::move(Contents)),
370*0a6a1f1dSLionel Sambuc         S(std::move(S)) {}
getStatus()371*0a6a1f1dSLionel Sambuc   Status getStatus() { return S; }
372*0a6a1f1dSLionel Sambuc   typedef std::vector<Entry *>::iterator iterator;
contents_begin()373*0a6a1f1dSLionel Sambuc   iterator contents_begin() { return Contents.begin(); }
contents_end()374*0a6a1f1dSLionel Sambuc   iterator contents_end() { return Contents.end(); }
classof(const Entry * E)375*0a6a1f1dSLionel Sambuc   static bool classof(const Entry *E) { return E->getKind() == EK_Directory; }
376*0a6a1f1dSLionel Sambuc };
377*0a6a1f1dSLionel Sambuc 
378*0a6a1f1dSLionel Sambuc class FileEntry : public Entry {
379*0a6a1f1dSLionel Sambuc public:
380*0a6a1f1dSLionel Sambuc   enum NameKind {
381*0a6a1f1dSLionel Sambuc     NK_NotSet,
382*0a6a1f1dSLionel Sambuc     NK_External,
383*0a6a1f1dSLionel Sambuc     NK_Virtual
384*0a6a1f1dSLionel Sambuc   };
385*0a6a1f1dSLionel Sambuc private:
386*0a6a1f1dSLionel Sambuc   std::string ExternalContentsPath;
387*0a6a1f1dSLionel Sambuc   NameKind UseName;
388*0a6a1f1dSLionel Sambuc public:
FileEntry(StringRef Name,StringRef ExternalContentsPath,NameKind UseName)389*0a6a1f1dSLionel Sambuc   FileEntry(StringRef Name, StringRef ExternalContentsPath, NameKind UseName)
390*0a6a1f1dSLionel Sambuc       : Entry(EK_File, Name), ExternalContentsPath(ExternalContentsPath),
391*0a6a1f1dSLionel Sambuc         UseName(UseName) {}
getExternalContentsPath() const392*0a6a1f1dSLionel Sambuc   StringRef getExternalContentsPath() const { return ExternalContentsPath; }
393*0a6a1f1dSLionel Sambuc   /// \brief whether to use the external path as the name for this file.
useExternalName(bool GlobalUseExternalName) const394*0a6a1f1dSLionel Sambuc   bool useExternalName(bool GlobalUseExternalName) const {
395*0a6a1f1dSLionel Sambuc     return UseName == NK_NotSet ? GlobalUseExternalName
396*0a6a1f1dSLionel Sambuc                                 : (UseName == NK_External);
397*0a6a1f1dSLionel Sambuc   }
classof(const Entry * E)398*0a6a1f1dSLionel Sambuc   static bool classof(const Entry *E) { return E->getKind() == EK_File; }
399*0a6a1f1dSLionel Sambuc };
400*0a6a1f1dSLionel Sambuc 
401*0a6a1f1dSLionel Sambuc class VFSFromYAML;
402*0a6a1f1dSLionel Sambuc 
403*0a6a1f1dSLionel Sambuc class VFSFromYamlDirIterImpl : public clang::vfs::detail::DirIterImpl {
404*0a6a1f1dSLionel Sambuc   std::string Dir;
405*0a6a1f1dSLionel Sambuc   VFSFromYAML &FS;
406*0a6a1f1dSLionel Sambuc   DirectoryEntry::iterator Current, End;
407*0a6a1f1dSLionel Sambuc public:
408*0a6a1f1dSLionel Sambuc   VFSFromYamlDirIterImpl(const Twine &Path, VFSFromYAML &FS,
409*0a6a1f1dSLionel Sambuc                          DirectoryEntry::iterator Begin,
410*0a6a1f1dSLionel Sambuc                          DirectoryEntry::iterator End, std::error_code &EC);
411*0a6a1f1dSLionel Sambuc   std::error_code increment() override;
412*0a6a1f1dSLionel Sambuc };
413*0a6a1f1dSLionel Sambuc 
414*0a6a1f1dSLionel Sambuc /// \brief A virtual file system parsed from a YAML file.
415*0a6a1f1dSLionel Sambuc ///
416*0a6a1f1dSLionel Sambuc /// Currently, this class allows creating virtual directories and mapping
417*0a6a1f1dSLionel Sambuc /// virtual file paths to existing external files, available in \c ExternalFS.
418*0a6a1f1dSLionel Sambuc ///
419*0a6a1f1dSLionel Sambuc /// The basic structure of the parsed file is:
420*0a6a1f1dSLionel Sambuc /// \verbatim
421*0a6a1f1dSLionel Sambuc /// {
422*0a6a1f1dSLionel Sambuc ///   'version': <version number>,
423*0a6a1f1dSLionel Sambuc ///   <optional configuration>
424*0a6a1f1dSLionel Sambuc ///   'roots': [
425*0a6a1f1dSLionel Sambuc ///              <directory entries>
426*0a6a1f1dSLionel Sambuc ///            ]
427*0a6a1f1dSLionel Sambuc /// }
428*0a6a1f1dSLionel Sambuc /// \endverbatim
429*0a6a1f1dSLionel Sambuc ///
430*0a6a1f1dSLionel Sambuc /// All configuration options are optional.
431*0a6a1f1dSLionel Sambuc ///   'case-sensitive': <boolean, default=true>
432*0a6a1f1dSLionel Sambuc ///   'use-external-names': <boolean, default=true>
433*0a6a1f1dSLionel Sambuc ///
434*0a6a1f1dSLionel Sambuc /// Virtual directories are represented as
435*0a6a1f1dSLionel Sambuc /// \verbatim
436*0a6a1f1dSLionel Sambuc /// {
437*0a6a1f1dSLionel Sambuc ///   'type': 'directory',
438*0a6a1f1dSLionel Sambuc ///   'name': <string>,
439*0a6a1f1dSLionel Sambuc ///   'contents': [ <file or directory entries> ]
440*0a6a1f1dSLionel Sambuc /// }
441*0a6a1f1dSLionel Sambuc /// \endverbatim
442*0a6a1f1dSLionel Sambuc ///
443*0a6a1f1dSLionel Sambuc /// The default attributes for virtual directories are:
444*0a6a1f1dSLionel Sambuc /// \verbatim
445*0a6a1f1dSLionel Sambuc /// MTime = now() when created
446*0a6a1f1dSLionel Sambuc /// Perms = 0777
447*0a6a1f1dSLionel Sambuc /// User = Group = 0
448*0a6a1f1dSLionel Sambuc /// Size = 0
449*0a6a1f1dSLionel Sambuc /// UniqueID = unspecified unique value
450*0a6a1f1dSLionel Sambuc /// \endverbatim
451*0a6a1f1dSLionel Sambuc ///
452*0a6a1f1dSLionel Sambuc /// Re-mapped files are represented as
453*0a6a1f1dSLionel Sambuc /// \verbatim
454*0a6a1f1dSLionel Sambuc /// {
455*0a6a1f1dSLionel Sambuc ///   'type': 'file',
456*0a6a1f1dSLionel Sambuc ///   'name': <string>,
457*0a6a1f1dSLionel Sambuc ///   'use-external-name': <boolean> # Optional
458*0a6a1f1dSLionel Sambuc ///   'external-contents': <path to external file>)
459*0a6a1f1dSLionel Sambuc /// }
460*0a6a1f1dSLionel Sambuc /// \endverbatim
461*0a6a1f1dSLionel Sambuc ///
462*0a6a1f1dSLionel Sambuc /// and inherit their attributes from the external contents.
463*0a6a1f1dSLionel Sambuc ///
464*0a6a1f1dSLionel Sambuc /// In both cases, the 'name' field may contain multiple path components (e.g.
465*0a6a1f1dSLionel Sambuc /// /path/to/file). However, any directory that contains more than one child
466*0a6a1f1dSLionel Sambuc /// must be uniquely represented by a directory entry.
467*0a6a1f1dSLionel Sambuc class VFSFromYAML : public vfs::FileSystem {
468*0a6a1f1dSLionel Sambuc   std::vector<Entry *> Roots; ///< The root(s) of the virtual file system.
469*0a6a1f1dSLionel Sambuc   /// \brief The file system to use for external references.
470*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<FileSystem> ExternalFS;
471*0a6a1f1dSLionel Sambuc 
472*0a6a1f1dSLionel Sambuc   /// @name Configuration
473*0a6a1f1dSLionel Sambuc   /// @{
474*0a6a1f1dSLionel Sambuc 
475*0a6a1f1dSLionel Sambuc   /// \brief Whether to perform case-sensitive comparisons.
476*0a6a1f1dSLionel Sambuc   ///
477*0a6a1f1dSLionel Sambuc   /// Currently, case-insensitive matching only works correctly with ASCII.
478*0a6a1f1dSLionel Sambuc   bool CaseSensitive;
479*0a6a1f1dSLionel Sambuc 
480*0a6a1f1dSLionel Sambuc   /// \brief Whether to use to use the value of 'external-contents' for the
481*0a6a1f1dSLionel Sambuc   /// names of files.  This global value is overridable on a per-file basis.
482*0a6a1f1dSLionel Sambuc   bool UseExternalNames;
483*0a6a1f1dSLionel Sambuc   /// @}
484*0a6a1f1dSLionel Sambuc 
485*0a6a1f1dSLionel Sambuc   friend class VFSFromYAMLParser;
486*0a6a1f1dSLionel Sambuc 
487*0a6a1f1dSLionel Sambuc private:
VFSFromYAML(IntrusiveRefCntPtr<FileSystem> ExternalFS)488*0a6a1f1dSLionel Sambuc   VFSFromYAML(IntrusiveRefCntPtr<FileSystem> ExternalFS)
489*0a6a1f1dSLionel Sambuc       : ExternalFS(ExternalFS), CaseSensitive(true), UseExternalNames(true) {}
490*0a6a1f1dSLionel Sambuc 
491*0a6a1f1dSLionel Sambuc   /// \brief Looks up \p Path in \c Roots.
492*0a6a1f1dSLionel Sambuc   ErrorOr<Entry *> lookupPath(const Twine &Path);
493*0a6a1f1dSLionel Sambuc 
494*0a6a1f1dSLionel Sambuc   /// \brief Looks up the path <tt>[Start, End)</tt> in \p From, possibly
495*0a6a1f1dSLionel Sambuc   /// recursing into the contents of \p From if it is a directory.
496*0a6a1f1dSLionel Sambuc   ErrorOr<Entry *> lookupPath(sys::path::const_iterator Start,
497*0a6a1f1dSLionel Sambuc                               sys::path::const_iterator End, Entry *From);
498*0a6a1f1dSLionel Sambuc 
499*0a6a1f1dSLionel Sambuc   /// \brief Get the status of a given an \c Entry.
500*0a6a1f1dSLionel Sambuc   ErrorOr<Status> status(const Twine &Path, Entry *E);
501*0a6a1f1dSLionel Sambuc 
502*0a6a1f1dSLionel Sambuc public:
503*0a6a1f1dSLionel Sambuc   ~VFSFromYAML();
504*0a6a1f1dSLionel Sambuc 
505*0a6a1f1dSLionel Sambuc   /// \brief Parses \p Buffer, which is expected to be in YAML format and
506*0a6a1f1dSLionel Sambuc   /// returns a virtual file system representing its contents.
507*0a6a1f1dSLionel Sambuc   static VFSFromYAML *create(std::unique_ptr<MemoryBuffer> Buffer,
508*0a6a1f1dSLionel Sambuc                              SourceMgr::DiagHandlerTy DiagHandler,
509*0a6a1f1dSLionel Sambuc                              void *DiagContext,
510*0a6a1f1dSLionel Sambuc                              IntrusiveRefCntPtr<FileSystem> ExternalFS);
511*0a6a1f1dSLionel Sambuc 
512*0a6a1f1dSLionel Sambuc   ErrorOr<Status> status(const Twine &Path) override;
513*0a6a1f1dSLionel Sambuc   ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
514*0a6a1f1dSLionel Sambuc 
dir_begin(const Twine & Dir,std::error_code & EC)515*0a6a1f1dSLionel Sambuc   directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override{
516*0a6a1f1dSLionel Sambuc     ErrorOr<Entry *> E = lookupPath(Dir);
517*0a6a1f1dSLionel Sambuc     if (!E) {
518*0a6a1f1dSLionel Sambuc       EC = E.getError();
519*0a6a1f1dSLionel Sambuc       return directory_iterator();
520*0a6a1f1dSLionel Sambuc     }
521*0a6a1f1dSLionel Sambuc     ErrorOr<Status> S = status(Dir, *E);
522*0a6a1f1dSLionel Sambuc     if (!S) {
523*0a6a1f1dSLionel Sambuc       EC = S.getError();
524*0a6a1f1dSLionel Sambuc       return directory_iterator();
525*0a6a1f1dSLionel Sambuc     }
526*0a6a1f1dSLionel Sambuc     if (!S->isDirectory()) {
527*0a6a1f1dSLionel Sambuc       EC = std::error_code(static_cast<int>(errc::not_a_directory),
528*0a6a1f1dSLionel Sambuc                            std::system_category());
529*0a6a1f1dSLionel Sambuc       return directory_iterator();
530*0a6a1f1dSLionel Sambuc     }
531*0a6a1f1dSLionel Sambuc 
532*0a6a1f1dSLionel Sambuc     DirectoryEntry *D = cast<DirectoryEntry>(*E);
533*0a6a1f1dSLionel Sambuc     return directory_iterator(std::make_shared<VFSFromYamlDirIterImpl>(Dir,
534*0a6a1f1dSLionel Sambuc         *this, D->contents_begin(), D->contents_end(), EC));
535*0a6a1f1dSLionel Sambuc   }
536*0a6a1f1dSLionel Sambuc };
537*0a6a1f1dSLionel Sambuc 
538*0a6a1f1dSLionel Sambuc /// \brief A helper class to hold the common YAML parsing state.
539*0a6a1f1dSLionel Sambuc class VFSFromYAMLParser {
540*0a6a1f1dSLionel Sambuc   yaml::Stream &Stream;
541*0a6a1f1dSLionel Sambuc 
error(yaml::Node * N,const Twine & Msg)542*0a6a1f1dSLionel Sambuc   void error(yaml::Node *N, const Twine &Msg) {
543*0a6a1f1dSLionel Sambuc     Stream.printError(N, Msg);
544*0a6a1f1dSLionel Sambuc   }
545*0a6a1f1dSLionel Sambuc 
546*0a6a1f1dSLionel Sambuc   // false on error
parseScalarString(yaml::Node * N,StringRef & Result,SmallVectorImpl<char> & Storage)547*0a6a1f1dSLionel Sambuc   bool parseScalarString(yaml::Node *N, StringRef &Result,
548*0a6a1f1dSLionel Sambuc                          SmallVectorImpl<char> &Storage) {
549*0a6a1f1dSLionel Sambuc     yaml::ScalarNode *S = dyn_cast<yaml::ScalarNode>(N);
550*0a6a1f1dSLionel Sambuc     if (!S) {
551*0a6a1f1dSLionel Sambuc       error(N, "expected string");
552*0a6a1f1dSLionel Sambuc       return false;
553*0a6a1f1dSLionel Sambuc     }
554*0a6a1f1dSLionel Sambuc     Result = S->getValue(Storage);
555*0a6a1f1dSLionel Sambuc     return true;
556*0a6a1f1dSLionel Sambuc   }
557*0a6a1f1dSLionel Sambuc 
558*0a6a1f1dSLionel Sambuc   // false on error
parseScalarBool(yaml::Node * N,bool & Result)559*0a6a1f1dSLionel Sambuc   bool parseScalarBool(yaml::Node *N, bool &Result) {
560*0a6a1f1dSLionel Sambuc     SmallString<5> Storage;
561*0a6a1f1dSLionel Sambuc     StringRef Value;
562*0a6a1f1dSLionel Sambuc     if (!parseScalarString(N, Value, Storage))
563*0a6a1f1dSLionel Sambuc       return false;
564*0a6a1f1dSLionel Sambuc 
565*0a6a1f1dSLionel Sambuc     if (Value.equals_lower("true") || Value.equals_lower("on") ||
566*0a6a1f1dSLionel Sambuc         Value.equals_lower("yes") || Value == "1") {
567*0a6a1f1dSLionel Sambuc       Result = true;
568*0a6a1f1dSLionel Sambuc       return true;
569*0a6a1f1dSLionel Sambuc     } else if (Value.equals_lower("false") || Value.equals_lower("off") ||
570*0a6a1f1dSLionel Sambuc                Value.equals_lower("no") || Value == "0") {
571*0a6a1f1dSLionel Sambuc       Result = false;
572*0a6a1f1dSLionel Sambuc       return true;
573*0a6a1f1dSLionel Sambuc     }
574*0a6a1f1dSLionel Sambuc 
575*0a6a1f1dSLionel Sambuc     error(N, "expected boolean value");
576*0a6a1f1dSLionel Sambuc     return false;
577*0a6a1f1dSLionel Sambuc   }
578*0a6a1f1dSLionel Sambuc 
579*0a6a1f1dSLionel Sambuc   struct KeyStatus {
KeyStatus__anonfd6d57aa0511::VFSFromYAMLParser::KeyStatus580*0a6a1f1dSLionel Sambuc     KeyStatus(bool Required=false) : Required(Required), Seen(false) {}
581*0a6a1f1dSLionel Sambuc     bool Required;
582*0a6a1f1dSLionel Sambuc     bool Seen;
583*0a6a1f1dSLionel Sambuc   };
584*0a6a1f1dSLionel Sambuc   typedef std::pair<StringRef, KeyStatus> KeyStatusPair;
585*0a6a1f1dSLionel Sambuc 
586*0a6a1f1dSLionel Sambuc   // false on error
checkDuplicateOrUnknownKey(yaml::Node * KeyNode,StringRef Key,DenseMap<StringRef,KeyStatus> & Keys)587*0a6a1f1dSLionel Sambuc   bool checkDuplicateOrUnknownKey(yaml::Node *KeyNode, StringRef Key,
588*0a6a1f1dSLionel Sambuc                                   DenseMap<StringRef, KeyStatus> &Keys) {
589*0a6a1f1dSLionel Sambuc     if (!Keys.count(Key)) {
590*0a6a1f1dSLionel Sambuc       error(KeyNode, "unknown key");
591*0a6a1f1dSLionel Sambuc       return false;
592*0a6a1f1dSLionel Sambuc     }
593*0a6a1f1dSLionel Sambuc     KeyStatus &S = Keys[Key];
594*0a6a1f1dSLionel Sambuc     if (S.Seen) {
595*0a6a1f1dSLionel Sambuc       error(KeyNode, Twine("duplicate key '") + Key + "'");
596*0a6a1f1dSLionel Sambuc       return false;
597*0a6a1f1dSLionel Sambuc     }
598*0a6a1f1dSLionel Sambuc     S.Seen = true;
599*0a6a1f1dSLionel Sambuc     return true;
600*0a6a1f1dSLionel Sambuc   }
601*0a6a1f1dSLionel Sambuc 
602*0a6a1f1dSLionel Sambuc   // false on error
checkMissingKeys(yaml::Node * Obj,DenseMap<StringRef,KeyStatus> & Keys)603*0a6a1f1dSLionel Sambuc   bool checkMissingKeys(yaml::Node *Obj, DenseMap<StringRef, KeyStatus> &Keys) {
604*0a6a1f1dSLionel Sambuc     for (DenseMap<StringRef, KeyStatus>::iterator I = Keys.begin(),
605*0a6a1f1dSLionel Sambuc          E = Keys.end();
606*0a6a1f1dSLionel Sambuc          I != E; ++I) {
607*0a6a1f1dSLionel Sambuc       if (I->second.Required && !I->second.Seen) {
608*0a6a1f1dSLionel Sambuc         error(Obj, Twine("missing key '") + I->first + "'");
609*0a6a1f1dSLionel Sambuc         return false;
610*0a6a1f1dSLionel Sambuc       }
611*0a6a1f1dSLionel Sambuc     }
612*0a6a1f1dSLionel Sambuc     return true;
613*0a6a1f1dSLionel Sambuc   }
614*0a6a1f1dSLionel Sambuc 
parseEntry(yaml::Node * N)615*0a6a1f1dSLionel Sambuc   Entry *parseEntry(yaml::Node *N) {
616*0a6a1f1dSLionel Sambuc     yaml::MappingNode *M = dyn_cast<yaml::MappingNode>(N);
617*0a6a1f1dSLionel Sambuc     if (!M) {
618*0a6a1f1dSLionel Sambuc       error(N, "expected mapping node for file or directory entry");
619*0a6a1f1dSLionel Sambuc       return nullptr;
620*0a6a1f1dSLionel Sambuc     }
621*0a6a1f1dSLionel Sambuc 
622*0a6a1f1dSLionel Sambuc     KeyStatusPair Fields[] = {
623*0a6a1f1dSLionel Sambuc       KeyStatusPair("name", true),
624*0a6a1f1dSLionel Sambuc       KeyStatusPair("type", true),
625*0a6a1f1dSLionel Sambuc       KeyStatusPair("contents", false),
626*0a6a1f1dSLionel Sambuc       KeyStatusPair("external-contents", false),
627*0a6a1f1dSLionel Sambuc       KeyStatusPair("use-external-name", false),
628*0a6a1f1dSLionel Sambuc     };
629*0a6a1f1dSLionel Sambuc 
630*0a6a1f1dSLionel Sambuc     DenseMap<StringRef, KeyStatus> Keys(
631*0a6a1f1dSLionel Sambuc         &Fields[0], Fields + sizeof(Fields)/sizeof(Fields[0]));
632*0a6a1f1dSLionel Sambuc 
633*0a6a1f1dSLionel Sambuc     bool HasContents = false; // external or otherwise
634*0a6a1f1dSLionel Sambuc     std::vector<Entry *> EntryArrayContents;
635*0a6a1f1dSLionel Sambuc     std::string ExternalContentsPath;
636*0a6a1f1dSLionel Sambuc     std::string Name;
637*0a6a1f1dSLionel Sambuc     FileEntry::NameKind UseExternalName = FileEntry::NK_NotSet;
638*0a6a1f1dSLionel Sambuc     EntryKind Kind;
639*0a6a1f1dSLionel Sambuc 
640*0a6a1f1dSLionel Sambuc     for (yaml::MappingNode::iterator I = M->begin(), E = M->end(); I != E;
641*0a6a1f1dSLionel Sambuc          ++I) {
642*0a6a1f1dSLionel Sambuc       StringRef Key;
643*0a6a1f1dSLionel Sambuc       // Reuse the buffer for key and value, since we don't look at key after
644*0a6a1f1dSLionel Sambuc       // parsing value.
645*0a6a1f1dSLionel Sambuc       SmallString<256> Buffer;
646*0a6a1f1dSLionel Sambuc       if (!parseScalarString(I->getKey(), Key, Buffer))
647*0a6a1f1dSLionel Sambuc         return nullptr;
648*0a6a1f1dSLionel Sambuc 
649*0a6a1f1dSLionel Sambuc       if (!checkDuplicateOrUnknownKey(I->getKey(), Key, Keys))
650*0a6a1f1dSLionel Sambuc         return nullptr;
651*0a6a1f1dSLionel Sambuc 
652*0a6a1f1dSLionel Sambuc       StringRef Value;
653*0a6a1f1dSLionel Sambuc       if (Key == "name") {
654*0a6a1f1dSLionel Sambuc         if (!parseScalarString(I->getValue(), Value, Buffer))
655*0a6a1f1dSLionel Sambuc           return nullptr;
656*0a6a1f1dSLionel Sambuc         Name = Value;
657*0a6a1f1dSLionel Sambuc       } else if (Key == "type") {
658*0a6a1f1dSLionel Sambuc         if (!parseScalarString(I->getValue(), Value, Buffer))
659*0a6a1f1dSLionel Sambuc           return nullptr;
660*0a6a1f1dSLionel Sambuc         if (Value == "file")
661*0a6a1f1dSLionel Sambuc           Kind = EK_File;
662*0a6a1f1dSLionel Sambuc         else if (Value == "directory")
663*0a6a1f1dSLionel Sambuc           Kind = EK_Directory;
664*0a6a1f1dSLionel Sambuc         else {
665*0a6a1f1dSLionel Sambuc           error(I->getValue(), "unknown value for 'type'");
666*0a6a1f1dSLionel Sambuc           return nullptr;
667*0a6a1f1dSLionel Sambuc         }
668*0a6a1f1dSLionel Sambuc       } else if (Key == "contents") {
669*0a6a1f1dSLionel Sambuc         if (HasContents) {
670*0a6a1f1dSLionel Sambuc           error(I->getKey(),
671*0a6a1f1dSLionel Sambuc                 "entry already has 'contents' or 'external-contents'");
672*0a6a1f1dSLionel Sambuc           return nullptr;
673*0a6a1f1dSLionel Sambuc         }
674*0a6a1f1dSLionel Sambuc         HasContents = true;
675*0a6a1f1dSLionel Sambuc         yaml::SequenceNode *Contents =
676*0a6a1f1dSLionel Sambuc             dyn_cast<yaml::SequenceNode>(I->getValue());
677*0a6a1f1dSLionel Sambuc         if (!Contents) {
678*0a6a1f1dSLionel Sambuc           // FIXME: this is only for directories, what about files?
679*0a6a1f1dSLionel Sambuc           error(I->getValue(), "expected array");
680*0a6a1f1dSLionel Sambuc           return nullptr;
681*0a6a1f1dSLionel Sambuc         }
682*0a6a1f1dSLionel Sambuc 
683*0a6a1f1dSLionel Sambuc         for (yaml::SequenceNode::iterator I = Contents->begin(),
684*0a6a1f1dSLionel Sambuc                                           E = Contents->end();
685*0a6a1f1dSLionel Sambuc              I != E; ++I) {
686*0a6a1f1dSLionel Sambuc           if (Entry *E = parseEntry(&*I))
687*0a6a1f1dSLionel Sambuc             EntryArrayContents.push_back(E);
688*0a6a1f1dSLionel Sambuc           else
689*0a6a1f1dSLionel Sambuc             return nullptr;
690*0a6a1f1dSLionel Sambuc         }
691*0a6a1f1dSLionel Sambuc       } else if (Key == "external-contents") {
692*0a6a1f1dSLionel Sambuc         if (HasContents) {
693*0a6a1f1dSLionel Sambuc           error(I->getKey(),
694*0a6a1f1dSLionel Sambuc                 "entry already has 'contents' or 'external-contents'");
695*0a6a1f1dSLionel Sambuc           return nullptr;
696*0a6a1f1dSLionel Sambuc         }
697*0a6a1f1dSLionel Sambuc         HasContents = true;
698*0a6a1f1dSLionel Sambuc         if (!parseScalarString(I->getValue(), Value, Buffer))
699*0a6a1f1dSLionel Sambuc           return nullptr;
700*0a6a1f1dSLionel Sambuc         ExternalContentsPath = Value;
701*0a6a1f1dSLionel Sambuc       } else if (Key == "use-external-name") {
702*0a6a1f1dSLionel Sambuc         bool Val;
703*0a6a1f1dSLionel Sambuc         if (!parseScalarBool(I->getValue(), Val))
704*0a6a1f1dSLionel Sambuc           return nullptr;
705*0a6a1f1dSLionel Sambuc         UseExternalName = Val ? FileEntry::NK_External : FileEntry::NK_Virtual;
706*0a6a1f1dSLionel Sambuc       } else {
707*0a6a1f1dSLionel Sambuc         llvm_unreachable("key missing from Keys");
708*0a6a1f1dSLionel Sambuc       }
709*0a6a1f1dSLionel Sambuc     }
710*0a6a1f1dSLionel Sambuc 
711*0a6a1f1dSLionel Sambuc     if (Stream.failed())
712*0a6a1f1dSLionel Sambuc       return nullptr;
713*0a6a1f1dSLionel Sambuc 
714*0a6a1f1dSLionel Sambuc     // check for missing keys
715*0a6a1f1dSLionel Sambuc     if (!HasContents) {
716*0a6a1f1dSLionel Sambuc       error(N, "missing key 'contents' or 'external-contents'");
717*0a6a1f1dSLionel Sambuc       return nullptr;
718*0a6a1f1dSLionel Sambuc     }
719*0a6a1f1dSLionel Sambuc     if (!checkMissingKeys(N, Keys))
720*0a6a1f1dSLionel Sambuc       return nullptr;
721*0a6a1f1dSLionel Sambuc 
722*0a6a1f1dSLionel Sambuc     // check invalid configuration
723*0a6a1f1dSLionel Sambuc     if (Kind == EK_Directory && UseExternalName != FileEntry::NK_NotSet) {
724*0a6a1f1dSLionel Sambuc       error(N, "'use-external-name' is not supported for directories");
725*0a6a1f1dSLionel Sambuc       return nullptr;
726*0a6a1f1dSLionel Sambuc     }
727*0a6a1f1dSLionel Sambuc 
728*0a6a1f1dSLionel Sambuc     // Remove trailing slash(es), being careful not to remove the root path
729*0a6a1f1dSLionel Sambuc     StringRef Trimmed(Name);
730*0a6a1f1dSLionel Sambuc     size_t RootPathLen = sys::path::root_path(Trimmed).size();
731*0a6a1f1dSLionel Sambuc     while (Trimmed.size() > RootPathLen &&
732*0a6a1f1dSLionel Sambuc            sys::path::is_separator(Trimmed.back()))
733*0a6a1f1dSLionel Sambuc       Trimmed = Trimmed.slice(0, Trimmed.size()-1);
734*0a6a1f1dSLionel Sambuc     // Get the last component
735*0a6a1f1dSLionel Sambuc     StringRef LastComponent = sys::path::filename(Trimmed);
736*0a6a1f1dSLionel Sambuc 
737*0a6a1f1dSLionel Sambuc     Entry *Result = nullptr;
738*0a6a1f1dSLionel Sambuc     switch (Kind) {
739*0a6a1f1dSLionel Sambuc     case EK_File:
740*0a6a1f1dSLionel Sambuc       Result = new FileEntry(LastComponent, std::move(ExternalContentsPath),
741*0a6a1f1dSLionel Sambuc                              UseExternalName);
742*0a6a1f1dSLionel Sambuc       break;
743*0a6a1f1dSLionel Sambuc     case EK_Directory:
744*0a6a1f1dSLionel Sambuc       Result = new DirectoryEntry(LastComponent, std::move(EntryArrayContents),
745*0a6a1f1dSLionel Sambuc           Status("", "", getNextVirtualUniqueID(), sys::TimeValue::now(), 0, 0,
746*0a6a1f1dSLionel Sambuc                  0, file_type::directory_file, sys::fs::all_all));
747*0a6a1f1dSLionel Sambuc       break;
748*0a6a1f1dSLionel Sambuc     }
749*0a6a1f1dSLionel Sambuc 
750*0a6a1f1dSLionel Sambuc     StringRef Parent = sys::path::parent_path(Trimmed);
751*0a6a1f1dSLionel Sambuc     if (Parent.empty())
752*0a6a1f1dSLionel Sambuc       return Result;
753*0a6a1f1dSLionel Sambuc 
754*0a6a1f1dSLionel Sambuc     // if 'name' contains multiple components, create implicit directory entries
755*0a6a1f1dSLionel Sambuc     for (sys::path::reverse_iterator I = sys::path::rbegin(Parent),
756*0a6a1f1dSLionel Sambuc                                      E = sys::path::rend(Parent);
757*0a6a1f1dSLionel Sambuc          I != E; ++I) {
758*0a6a1f1dSLionel Sambuc       Result = new DirectoryEntry(*I, llvm::makeArrayRef(Result),
759*0a6a1f1dSLionel Sambuc           Status("", "", getNextVirtualUniqueID(), sys::TimeValue::now(), 0, 0,
760*0a6a1f1dSLionel Sambuc                  0, file_type::directory_file, sys::fs::all_all));
761*0a6a1f1dSLionel Sambuc     }
762*0a6a1f1dSLionel Sambuc     return Result;
763*0a6a1f1dSLionel Sambuc   }
764*0a6a1f1dSLionel Sambuc 
765*0a6a1f1dSLionel Sambuc public:
VFSFromYAMLParser(yaml::Stream & S)766*0a6a1f1dSLionel Sambuc   VFSFromYAMLParser(yaml::Stream &S) : Stream(S) {}
767*0a6a1f1dSLionel Sambuc 
768*0a6a1f1dSLionel Sambuc   // false on error
parse(yaml::Node * Root,VFSFromYAML * FS)769*0a6a1f1dSLionel Sambuc   bool parse(yaml::Node *Root, VFSFromYAML *FS) {
770*0a6a1f1dSLionel Sambuc     yaml::MappingNode *Top = dyn_cast<yaml::MappingNode>(Root);
771*0a6a1f1dSLionel Sambuc     if (!Top) {
772*0a6a1f1dSLionel Sambuc       error(Root, "expected mapping node");
773*0a6a1f1dSLionel Sambuc       return false;
774*0a6a1f1dSLionel Sambuc     }
775*0a6a1f1dSLionel Sambuc 
776*0a6a1f1dSLionel Sambuc     KeyStatusPair Fields[] = {
777*0a6a1f1dSLionel Sambuc       KeyStatusPair("version", true),
778*0a6a1f1dSLionel Sambuc       KeyStatusPair("case-sensitive", false),
779*0a6a1f1dSLionel Sambuc       KeyStatusPair("use-external-names", false),
780*0a6a1f1dSLionel Sambuc       KeyStatusPair("roots", true),
781*0a6a1f1dSLionel Sambuc     };
782*0a6a1f1dSLionel Sambuc 
783*0a6a1f1dSLionel Sambuc     DenseMap<StringRef, KeyStatus> Keys(
784*0a6a1f1dSLionel Sambuc         &Fields[0], Fields + sizeof(Fields)/sizeof(Fields[0]));
785*0a6a1f1dSLionel Sambuc 
786*0a6a1f1dSLionel Sambuc     // Parse configuration and 'roots'
787*0a6a1f1dSLionel Sambuc     for (yaml::MappingNode::iterator I = Top->begin(), E = Top->end(); I != E;
788*0a6a1f1dSLionel Sambuc          ++I) {
789*0a6a1f1dSLionel Sambuc       SmallString<10> KeyBuffer;
790*0a6a1f1dSLionel Sambuc       StringRef Key;
791*0a6a1f1dSLionel Sambuc       if (!parseScalarString(I->getKey(), Key, KeyBuffer))
792*0a6a1f1dSLionel Sambuc         return false;
793*0a6a1f1dSLionel Sambuc 
794*0a6a1f1dSLionel Sambuc       if (!checkDuplicateOrUnknownKey(I->getKey(), Key, Keys))
795*0a6a1f1dSLionel Sambuc         return false;
796*0a6a1f1dSLionel Sambuc 
797*0a6a1f1dSLionel Sambuc       if (Key == "roots") {
798*0a6a1f1dSLionel Sambuc         yaml::SequenceNode *Roots = dyn_cast<yaml::SequenceNode>(I->getValue());
799*0a6a1f1dSLionel Sambuc         if (!Roots) {
800*0a6a1f1dSLionel Sambuc           error(I->getValue(), "expected array");
801*0a6a1f1dSLionel Sambuc           return false;
802*0a6a1f1dSLionel Sambuc         }
803*0a6a1f1dSLionel Sambuc 
804*0a6a1f1dSLionel Sambuc         for (yaml::SequenceNode::iterator I = Roots->begin(), E = Roots->end();
805*0a6a1f1dSLionel Sambuc              I != E; ++I) {
806*0a6a1f1dSLionel Sambuc           if (Entry *E = parseEntry(&*I))
807*0a6a1f1dSLionel Sambuc             FS->Roots.push_back(E);
808*0a6a1f1dSLionel Sambuc           else
809*0a6a1f1dSLionel Sambuc             return false;
810*0a6a1f1dSLionel Sambuc         }
811*0a6a1f1dSLionel Sambuc       } else if (Key == "version") {
812*0a6a1f1dSLionel Sambuc         StringRef VersionString;
813*0a6a1f1dSLionel Sambuc         SmallString<4> Storage;
814*0a6a1f1dSLionel Sambuc         if (!parseScalarString(I->getValue(), VersionString, Storage))
815*0a6a1f1dSLionel Sambuc           return false;
816*0a6a1f1dSLionel Sambuc         int Version;
817*0a6a1f1dSLionel Sambuc         if (VersionString.getAsInteger<int>(10, Version)) {
818*0a6a1f1dSLionel Sambuc           error(I->getValue(), "expected integer");
819*0a6a1f1dSLionel Sambuc           return false;
820*0a6a1f1dSLionel Sambuc         }
821*0a6a1f1dSLionel Sambuc         if (Version < 0) {
822*0a6a1f1dSLionel Sambuc           error(I->getValue(), "invalid version number");
823*0a6a1f1dSLionel Sambuc           return false;
824*0a6a1f1dSLionel Sambuc         }
825*0a6a1f1dSLionel Sambuc         if (Version != 0) {
826*0a6a1f1dSLionel Sambuc           error(I->getValue(), "version mismatch, expected 0");
827*0a6a1f1dSLionel Sambuc           return false;
828*0a6a1f1dSLionel Sambuc         }
829*0a6a1f1dSLionel Sambuc       } else if (Key == "case-sensitive") {
830*0a6a1f1dSLionel Sambuc         if (!parseScalarBool(I->getValue(), FS->CaseSensitive))
831*0a6a1f1dSLionel Sambuc           return false;
832*0a6a1f1dSLionel Sambuc       } else if (Key == "use-external-names") {
833*0a6a1f1dSLionel Sambuc         if (!parseScalarBool(I->getValue(), FS->UseExternalNames))
834*0a6a1f1dSLionel Sambuc           return false;
835*0a6a1f1dSLionel Sambuc       } else {
836*0a6a1f1dSLionel Sambuc         llvm_unreachable("key missing from Keys");
837*0a6a1f1dSLionel Sambuc       }
838*0a6a1f1dSLionel Sambuc     }
839*0a6a1f1dSLionel Sambuc 
840*0a6a1f1dSLionel Sambuc     if (Stream.failed())
841*0a6a1f1dSLionel Sambuc       return false;
842*0a6a1f1dSLionel Sambuc 
843*0a6a1f1dSLionel Sambuc     if (!checkMissingKeys(Top, Keys))
844*0a6a1f1dSLionel Sambuc       return false;
845*0a6a1f1dSLionel Sambuc     return true;
846*0a6a1f1dSLionel Sambuc   }
847*0a6a1f1dSLionel Sambuc };
848*0a6a1f1dSLionel Sambuc } // end of anonymous namespace
849*0a6a1f1dSLionel Sambuc 
~Entry()850*0a6a1f1dSLionel Sambuc Entry::~Entry() {}
~DirectoryEntry()851*0a6a1f1dSLionel Sambuc DirectoryEntry::~DirectoryEntry() { llvm::DeleteContainerPointers(Contents); }
852*0a6a1f1dSLionel Sambuc 
~VFSFromYAML()853*0a6a1f1dSLionel Sambuc VFSFromYAML::~VFSFromYAML() { llvm::DeleteContainerPointers(Roots); }
854*0a6a1f1dSLionel Sambuc 
create(std::unique_ptr<MemoryBuffer> Buffer,SourceMgr::DiagHandlerTy DiagHandler,void * DiagContext,IntrusiveRefCntPtr<FileSystem> ExternalFS)855*0a6a1f1dSLionel Sambuc VFSFromYAML *VFSFromYAML::create(std::unique_ptr<MemoryBuffer> Buffer,
856*0a6a1f1dSLionel Sambuc                                  SourceMgr::DiagHandlerTy DiagHandler,
857*0a6a1f1dSLionel Sambuc                                  void *DiagContext,
858*0a6a1f1dSLionel Sambuc                                  IntrusiveRefCntPtr<FileSystem> ExternalFS) {
859*0a6a1f1dSLionel Sambuc 
860*0a6a1f1dSLionel Sambuc   SourceMgr SM;
861*0a6a1f1dSLionel Sambuc   yaml::Stream Stream(Buffer->getMemBufferRef(), SM);
862*0a6a1f1dSLionel Sambuc 
863*0a6a1f1dSLionel Sambuc   SM.setDiagHandler(DiagHandler, DiagContext);
864*0a6a1f1dSLionel Sambuc   yaml::document_iterator DI = Stream.begin();
865*0a6a1f1dSLionel Sambuc   yaml::Node *Root = DI->getRoot();
866*0a6a1f1dSLionel Sambuc   if (DI == Stream.end() || !Root) {
867*0a6a1f1dSLionel Sambuc     SM.PrintMessage(SMLoc(), SourceMgr::DK_Error, "expected root node");
868*0a6a1f1dSLionel Sambuc     return nullptr;
869*0a6a1f1dSLionel Sambuc   }
870*0a6a1f1dSLionel Sambuc 
871*0a6a1f1dSLionel Sambuc   VFSFromYAMLParser P(Stream);
872*0a6a1f1dSLionel Sambuc 
873*0a6a1f1dSLionel Sambuc   std::unique_ptr<VFSFromYAML> FS(new VFSFromYAML(ExternalFS));
874*0a6a1f1dSLionel Sambuc   if (!P.parse(Root, FS.get()))
875*0a6a1f1dSLionel Sambuc     return nullptr;
876*0a6a1f1dSLionel Sambuc 
877*0a6a1f1dSLionel Sambuc   return FS.release();
878*0a6a1f1dSLionel Sambuc }
879*0a6a1f1dSLionel Sambuc 
lookupPath(const Twine & Path_)880*0a6a1f1dSLionel Sambuc ErrorOr<Entry *> VFSFromYAML::lookupPath(const Twine &Path_) {
881*0a6a1f1dSLionel Sambuc   SmallString<256> Path;
882*0a6a1f1dSLionel Sambuc   Path_.toVector(Path);
883*0a6a1f1dSLionel Sambuc 
884*0a6a1f1dSLionel Sambuc   // Handle relative paths
885*0a6a1f1dSLionel Sambuc   if (std::error_code EC = sys::fs::make_absolute(Path))
886*0a6a1f1dSLionel Sambuc     return EC;
887*0a6a1f1dSLionel Sambuc 
888*0a6a1f1dSLionel Sambuc   if (Path.empty())
889*0a6a1f1dSLionel Sambuc     return make_error_code(llvm::errc::invalid_argument);
890*0a6a1f1dSLionel Sambuc 
891*0a6a1f1dSLionel Sambuc   sys::path::const_iterator Start = sys::path::begin(Path);
892*0a6a1f1dSLionel Sambuc   sys::path::const_iterator End = sys::path::end(Path);
893*0a6a1f1dSLionel Sambuc   for (std::vector<Entry *>::iterator I = Roots.begin(), E = Roots.end();
894*0a6a1f1dSLionel Sambuc        I != E; ++I) {
895*0a6a1f1dSLionel Sambuc     ErrorOr<Entry *> Result = lookupPath(Start, End, *I);
896*0a6a1f1dSLionel Sambuc     if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
897*0a6a1f1dSLionel Sambuc       return Result;
898*0a6a1f1dSLionel Sambuc   }
899*0a6a1f1dSLionel Sambuc   return make_error_code(llvm::errc::no_such_file_or_directory);
900*0a6a1f1dSLionel Sambuc }
901*0a6a1f1dSLionel Sambuc 
lookupPath(sys::path::const_iterator Start,sys::path::const_iterator End,Entry * From)902*0a6a1f1dSLionel Sambuc ErrorOr<Entry *> VFSFromYAML::lookupPath(sys::path::const_iterator Start,
903*0a6a1f1dSLionel Sambuc                                          sys::path::const_iterator End,
904*0a6a1f1dSLionel Sambuc                                          Entry *From) {
905*0a6a1f1dSLionel Sambuc   if (Start->equals("."))
906*0a6a1f1dSLionel Sambuc     ++Start;
907*0a6a1f1dSLionel Sambuc 
908*0a6a1f1dSLionel Sambuc   // FIXME: handle ..
909*0a6a1f1dSLionel Sambuc   if (CaseSensitive ? !Start->equals(From->getName())
910*0a6a1f1dSLionel Sambuc                     : !Start->equals_lower(From->getName()))
911*0a6a1f1dSLionel Sambuc     // failure to match
912*0a6a1f1dSLionel Sambuc     return make_error_code(llvm::errc::no_such_file_or_directory);
913*0a6a1f1dSLionel Sambuc 
914*0a6a1f1dSLionel Sambuc   ++Start;
915*0a6a1f1dSLionel Sambuc 
916*0a6a1f1dSLionel Sambuc   if (Start == End) {
917*0a6a1f1dSLionel Sambuc     // Match!
918*0a6a1f1dSLionel Sambuc     return From;
919*0a6a1f1dSLionel Sambuc   }
920*0a6a1f1dSLionel Sambuc 
921*0a6a1f1dSLionel Sambuc   DirectoryEntry *DE = dyn_cast<DirectoryEntry>(From);
922*0a6a1f1dSLionel Sambuc   if (!DE)
923*0a6a1f1dSLionel Sambuc     return make_error_code(llvm::errc::not_a_directory);
924*0a6a1f1dSLionel Sambuc 
925*0a6a1f1dSLionel Sambuc   for (DirectoryEntry::iterator I = DE->contents_begin(),
926*0a6a1f1dSLionel Sambuc                                 E = DE->contents_end();
927*0a6a1f1dSLionel Sambuc        I != E; ++I) {
928*0a6a1f1dSLionel Sambuc     ErrorOr<Entry *> Result = lookupPath(Start, End, *I);
929*0a6a1f1dSLionel Sambuc     if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
930*0a6a1f1dSLionel Sambuc       return Result;
931*0a6a1f1dSLionel Sambuc   }
932*0a6a1f1dSLionel Sambuc   return make_error_code(llvm::errc::no_such_file_or_directory);
933*0a6a1f1dSLionel Sambuc }
934*0a6a1f1dSLionel Sambuc 
status(const Twine & Path,Entry * E)935*0a6a1f1dSLionel Sambuc ErrorOr<Status> VFSFromYAML::status(const Twine &Path, Entry *E) {
936*0a6a1f1dSLionel Sambuc   assert(E != nullptr);
937*0a6a1f1dSLionel Sambuc   std::string PathStr(Path.str());
938*0a6a1f1dSLionel Sambuc   if (FileEntry *F = dyn_cast<FileEntry>(E)) {
939*0a6a1f1dSLionel Sambuc     ErrorOr<Status> S = ExternalFS->status(F->getExternalContentsPath());
940*0a6a1f1dSLionel Sambuc     assert(!S || S->getName() == F->getExternalContentsPath());
941*0a6a1f1dSLionel Sambuc     if (S && !F->useExternalName(UseExternalNames))
942*0a6a1f1dSLionel Sambuc       S->setName(PathStr);
943*0a6a1f1dSLionel Sambuc     if (S)
944*0a6a1f1dSLionel Sambuc       S->IsVFSMapped = true;
945*0a6a1f1dSLionel Sambuc     return S;
946*0a6a1f1dSLionel Sambuc   } else { // directory
947*0a6a1f1dSLionel Sambuc     DirectoryEntry *DE = cast<DirectoryEntry>(E);
948*0a6a1f1dSLionel Sambuc     Status S = DE->getStatus();
949*0a6a1f1dSLionel Sambuc     S.setName(PathStr);
950*0a6a1f1dSLionel Sambuc     return S;
951*0a6a1f1dSLionel Sambuc   }
952*0a6a1f1dSLionel Sambuc }
953*0a6a1f1dSLionel Sambuc 
status(const Twine & Path)954*0a6a1f1dSLionel Sambuc ErrorOr<Status> VFSFromYAML::status(const Twine &Path) {
955*0a6a1f1dSLionel Sambuc   ErrorOr<Entry *> Result = lookupPath(Path);
956*0a6a1f1dSLionel Sambuc   if (!Result)
957*0a6a1f1dSLionel Sambuc     return Result.getError();
958*0a6a1f1dSLionel Sambuc   return status(Path, *Result);
959*0a6a1f1dSLionel Sambuc }
960*0a6a1f1dSLionel Sambuc 
openFileForRead(const Twine & Path)961*0a6a1f1dSLionel Sambuc ErrorOr<std::unique_ptr<File>> VFSFromYAML::openFileForRead(const Twine &Path) {
962*0a6a1f1dSLionel Sambuc   ErrorOr<Entry *> E = lookupPath(Path);
963*0a6a1f1dSLionel Sambuc   if (!E)
964*0a6a1f1dSLionel Sambuc     return E.getError();
965*0a6a1f1dSLionel Sambuc 
966*0a6a1f1dSLionel Sambuc   FileEntry *F = dyn_cast<FileEntry>(*E);
967*0a6a1f1dSLionel Sambuc   if (!F) // FIXME: errc::not_a_file?
968*0a6a1f1dSLionel Sambuc     return make_error_code(llvm::errc::invalid_argument);
969*0a6a1f1dSLionel Sambuc 
970*0a6a1f1dSLionel Sambuc   auto Result = ExternalFS->openFileForRead(F->getExternalContentsPath());
971*0a6a1f1dSLionel Sambuc   if (!Result)
972*0a6a1f1dSLionel Sambuc     return Result;
973*0a6a1f1dSLionel Sambuc 
974*0a6a1f1dSLionel Sambuc   if (!F->useExternalName(UseExternalNames))
975*0a6a1f1dSLionel Sambuc     (*Result)->setName(Path.str());
976*0a6a1f1dSLionel Sambuc 
977*0a6a1f1dSLionel Sambuc   return Result;
978*0a6a1f1dSLionel Sambuc }
979*0a6a1f1dSLionel Sambuc 
980*0a6a1f1dSLionel Sambuc IntrusiveRefCntPtr<FileSystem>
getVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,SourceMgr::DiagHandlerTy DiagHandler,void * DiagContext,IntrusiveRefCntPtr<FileSystem> ExternalFS)981*0a6a1f1dSLionel Sambuc vfs::getVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,
982*0a6a1f1dSLionel Sambuc                     SourceMgr::DiagHandlerTy DiagHandler, void *DiagContext,
983*0a6a1f1dSLionel Sambuc                     IntrusiveRefCntPtr<FileSystem> ExternalFS) {
984*0a6a1f1dSLionel Sambuc   return VFSFromYAML::create(std::move(Buffer), DiagHandler, DiagContext,
985*0a6a1f1dSLionel Sambuc                              ExternalFS);
986*0a6a1f1dSLionel Sambuc }
987*0a6a1f1dSLionel Sambuc 
getNextVirtualUniqueID()988*0a6a1f1dSLionel Sambuc UniqueID vfs::getNextVirtualUniqueID() {
989*0a6a1f1dSLionel Sambuc #if !defined(_LIBCPP_HAS_NO_THREADS) && defined(__minix)
990*0a6a1f1dSLionel Sambuc   static std::atomic<unsigned> UID;
991*0a6a1f1dSLionel Sambuc #else
992*0a6a1f1dSLionel Sambuc   static unsigned UID;
993*0a6a1f1dSLionel Sambuc #endif // !defined(_LIBCPP_HAS_NO_THREADS) && defined(__minix)
994*0a6a1f1dSLionel Sambuc   unsigned ID = ++UID;
995*0a6a1f1dSLionel Sambuc   // The following assumes that uint64_t max will never collide with a real
996*0a6a1f1dSLionel Sambuc   // dev_t value from the OS.
997*0a6a1f1dSLionel Sambuc   return UniqueID(std::numeric_limits<uint64_t>::max(), ID);
998*0a6a1f1dSLionel Sambuc }
999*0a6a1f1dSLionel Sambuc 
1000*0a6a1f1dSLionel Sambuc #ifndef NDEBUG
pathHasTraversal(StringRef Path)1001*0a6a1f1dSLionel Sambuc static bool pathHasTraversal(StringRef Path) {
1002*0a6a1f1dSLionel Sambuc   using namespace llvm::sys;
1003*0a6a1f1dSLionel Sambuc   for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path)))
1004*0a6a1f1dSLionel Sambuc     if (Comp == "." || Comp == "..")
1005*0a6a1f1dSLionel Sambuc       return true;
1006*0a6a1f1dSLionel Sambuc   return false;
1007*0a6a1f1dSLionel Sambuc }
1008*0a6a1f1dSLionel Sambuc #endif
1009*0a6a1f1dSLionel Sambuc 
addFileMapping(StringRef VirtualPath,StringRef RealPath)1010*0a6a1f1dSLionel Sambuc void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) {
1011*0a6a1f1dSLionel Sambuc   assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute");
1012*0a6a1f1dSLionel Sambuc   assert(sys::path::is_absolute(RealPath) && "real path not absolute");
1013*0a6a1f1dSLionel Sambuc   assert(!pathHasTraversal(VirtualPath) && "path traversal is not supported");
1014*0a6a1f1dSLionel Sambuc   Mappings.emplace_back(VirtualPath, RealPath);
1015*0a6a1f1dSLionel Sambuc }
1016*0a6a1f1dSLionel Sambuc 
1017*0a6a1f1dSLionel Sambuc namespace {
1018*0a6a1f1dSLionel Sambuc class JSONWriter {
1019*0a6a1f1dSLionel Sambuc   llvm::raw_ostream &OS;
1020*0a6a1f1dSLionel Sambuc   SmallVector<StringRef, 16> DirStack;
getDirIndent()1021*0a6a1f1dSLionel Sambuc   inline unsigned getDirIndent() { return 4 * DirStack.size(); }
getFileIndent()1022*0a6a1f1dSLionel Sambuc   inline unsigned getFileIndent() { return 4 * (DirStack.size() + 1); }
1023*0a6a1f1dSLionel Sambuc   bool containedIn(StringRef Parent, StringRef Path);
1024*0a6a1f1dSLionel Sambuc   StringRef containedPart(StringRef Parent, StringRef Path);
1025*0a6a1f1dSLionel Sambuc   void startDirectory(StringRef Path);
1026*0a6a1f1dSLionel Sambuc   void endDirectory();
1027*0a6a1f1dSLionel Sambuc   void writeEntry(StringRef VPath, StringRef RPath);
1028*0a6a1f1dSLionel Sambuc 
1029*0a6a1f1dSLionel Sambuc public:
JSONWriter(llvm::raw_ostream & OS)1030*0a6a1f1dSLionel Sambuc   JSONWriter(llvm::raw_ostream &OS) : OS(OS) {}
1031*0a6a1f1dSLionel Sambuc   void write(ArrayRef<YAMLVFSEntry> Entries, Optional<bool> IsCaseSensitive);
1032*0a6a1f1dSLionel Sambuc };
1033*0a6a1f1dSLionel Sambuc }
1034*0a6a1f1dSLionel Sambuc 
containedIn(StringRef Parent,StringRef Path)1035*0a6a1f1dSLionel Sambuc bool JSONWriter::containedIn(StringRef Parent, StringRef Path) {
1036*0a6a1f1dSLionel Sambuc   using namespace llvm::sys;
1037*0a6a1f1dSLionel Sambuc   // Compare each path component.
1038*0a6a1f1dSLionel Sambuc   auto IParent = path::begin(Parent), EParent = path::end(Parent);
1039*0a6a1f1dSLionel Sambuc   for (auto IChild = path::begin(Path), EChild = path::end(Path);
1040*0a6a1f1dSLionel Sambuc        IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
1041*0a6a1f1dSLionel Sambuc     if (*IParent != *IChild)
1042*0a6a1f1dSLionel Sambuc       return false;
1043*0a6a1f1dSLionel Sambuc   }
1044*0a6a1f1dSLionel Sambuc   // Have we exhausted the parent path?
1045*0a6a1f1dSLionel Sambuc   return IParent == EParent;
1046*0a6a1f1dSLionel Sambuc }
1047*0a6a1f1dSLionel Sambuc 
containedPart(StringRef Parent,StringRef Path)1048*0a6a1f1dSLionel Sambuc StringRef JSONWriter::containedPart(StringRef Parent, StringRef Path) {
1049*0a6a1f1dSLionel Sambuc   assert(!Parent.empty());
1050*0a6a1f1dSLionel Sambuc   assert(containedIn(Parent, Path));
1051*0a6a1f1dSLionel Sambuc   return Path.slice(Parent.size() + 1, StringRef::npos);
1052*0a6a1f1dSLionel Sambuc }
1053*0a6a1f1dSLionel Sambuc 
startDirectory(StringRef Path)1054*0a6a1f1dSLionel Sambuc void JSONWriter::startDirectory(StringRef Path) {
1055*0a6a1f1dSLionel Sambuc   StringRef Name =
1056*0a6a1f1dSLionel Sambuc       DirStack.empty() ? Path : containedPart(DirStack.back(), Path);
1057*0a6a1f1dSLionel Sambuc   DirStack.push_back(Path);
1058*0a6a1f1dSLionel Sambuc   unsigned Indent = getDirIndent();
1059*0a6a1f1dSLionel Sambuc   OS.indent(Indent) << "{\n";
1060*0a6a1f1dSLionel Sambuc   OS.indent(Indent + 2) << "'type': 'directory',\n";
1061*0a6a1f1dSLionel Sambuc   OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(Name) << "\",\n";
1062*0a6a1f1dSLionel Sambuc   OS.indent(Indent + 2) << "'contents': [\n";
1063*0a6a1f1dSLionel Sambuc }
1064*0a6a1f1dSLionel Sambuc 
endDirectory()1065*0a6a1f1dSLionel Sambuc void JSONWriter::endDirectory() {
1066*0a6a1f1dSLionel Sambuc   unsigned Indent = getDirIndent();
1067*0a6a1f1dSLionel Sambuc   OS.indent(Indent + 2) << "]\n";
1068*0a6a1f1dSLionel Sambuc   OS.indent(Indent) << "}";
1069*0a6a1f1dSLionel Sambuc 
1070*0a6a1f1dSLionel Sambuc   DirStack.pop_back();
1071*0a6a1f1dSLionel Sambuc }
1072*0a6a1f1dSLionel Sambuc 
writeEntry(StringRef VPath,StringRef RPath)1073*0a6a1f1dSLionel Sambuc void JSONWriter::writeEntry(StringRef VPath, StringRef RPath) {
1074*0a6a1f1dSLionel Sambuc   unsigned Indent = getFileIndent();
1075*0a6a1f1dSLionel Sambuc   OS.indent(Indent) << "{\n";
1076*0a6a1f1dSLionel Sambuc   OS.indent(Indent + 2) << "'type': 'file',\n";
1077*0a6a1f1dSLionel Sambuc   OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(VPath) << "\",\n";
1078*0a6a1f1dSLionel Sambuc   OS.indent(Indent + 2) << "'external-contents': \""
1079*0a6a1f1dSLionel Sambuc                         << llvm::yaml::escape(RPath) << "\"\n";
1080*0a6a1f1dSLionel Sambuc   OS.indent(Indent) << "}";
1081*0a6a1f1dSLionel Sambuc }
1082*0a6a1f1dSLionel Sambuc 
write(ArrayRef<YAMLVFSEntry> Entries,Optional<bool> IsCaseSensitive)1083*0a6a1f1dSLionel Sambuc void JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries,
1084*0a6a1f1dSLionel Sambuc                        Optional<bool> IsCaseSensitive) {
1085*0a6a1f1dSLionel Sambuc   using namespace llvm::sys;
1086*0a6a1f1dSLionel Sambuc 
1087*0a6a1f1dSLionel Sambuc   OS << "{\n"
1088*0a6a1f1dSLionel Sambuc         "  'version': 0,\n";
1089*0a6a1f1dSLionel Sambuc   if (IsCaseSensitive.hasValue())
1090*0a6a1f1dSLionel Sambuc     OS << "  'case-sensitive': '"
1091*0a6a1f1dSLionel Sambuc        << (IsCaseSensitive.getValue() ? "true" : "false") << "',\n";
1092*0a6a1f1dSLionel Sambuc   OS << "  'roots': [\n";
1093*0a6a1f1dSLionel Sambuc 
1094*0a6a1f1dSLionel Sambuc   if (!Entries.empty()) {
1095*0a6a1f1dSLionel Sambuc     const YAMLVFSEntry &Entry = Entries.front();
1096*0a6a1f1dSLionel Sambuc     startDirectory(path::parent_path(Entry.VPath));
1097*0a6a1f1dSLionel Sambuc     writeEntry(path::filename(Entry.VPath), Entry.RPath);
1098*0a6a1f1dSLionel Sambuc 
1099*0a6a1f1dSLionel Sambuc     for (const auto &Entry : Entries.slice(1)) {
1100*0a6a1f1dSLionel Sambuc       StringRef Dir = path::parent_path(Entry.VPath);
1101*0a6a1f1dSLionel Sambuc       if (Dir == DirStack.back())
1102*0a6a1f1dSLionel Sambuc         OS << ",\n";
1103*0a6a1f1dSLionel Sambuc       else {
1104*0a6a1f1dSLionel Sambuc         while (!DirStack.empty() && !containedIn(DirStack.back(), Dir)) {
1105*0a6a1f1dSLionel Sambuc           OS << "\n";
1106*0a6a1f1dSLionel Sambuc           endDirectory();
1107*0a6a1f1dSLionel Sambuc         }
1108*0a6a1f1dSLionel Sambuc         OS << ",\n";
1109*0a6a1f1dSLionel Sambuc         startDirectory(Dir);
1110*0a6a1f1dSLionel Sambuc       }
1111*0a6a1f1dSLionel Sambuc       writeEntry(path::filename(Entry.VPath), Entry.RPath);
1112*0a6a1f1dSLionel Sambuc     }
1113*0a6a1f1dSLionel Sambuc 
1114*0a6a1f1dSLionel Sambuc     while (!DirStack.empty()) {
1115*0a6a1f1dSLionel Sambuc       OS << "\n";
1116*0a6a1f1dSLionel Sambuc       endDirectory();
1117*0a6a1f1dSLionel Sambuc     }
1118*0a6a1f1dSLionel Sambuc     OS << "\n";
1119*0a6a1f1dSLionel Sambuc   }
1120*0a6a1f1dSLionel Sambuc 
1121*0a6a1f1dSLionel Sambuc   OS << "  ]\n"
1122*0a6a1f1dSLionel Sambuc      << "}\n";
1123*0a6a1f1dSLionel Sambuc }
1124*0a6a1f1dSLionel Sambuc 
write(llvm::raw_ostream & OS)1125*0a6a1f1dSLionel Sambuc void YAMLVFSWriter::write(llvm::raw_ostream &OS) {
1126*0a6a1f1dSLionel Sambuc   std::sort(Mappings.begin(), Mappings.end(),
1127*0a6a1f1dSLionel Sambuc             [](const YAMLVFSEntry &LHS, const YAMLVFSEntry &RHS) {
1128*0a6a1f1dSLionel Sambuc     return LHS.VPath < RHS.VPath;
1129*0a6a1f1dSLionel Sambuc   });
1130*0a6a1f1dSLionel Sambuc 
1131*0a6a1f1dSLionel Sambuc   JSONWriter(OS).write(Mappings, IsCaseSensitive);
1132*0a6a1f1dSLionel Sambuc }
1133*0a6a1f1dSLionel Sambuc 
VFSFromYamlDirIterImpl(const Twine & _Path,VFSFromYAML & FS,DirectoryEntry::iterator Begin,DirectoryEntry::iterator End,std::error_code & EC)1134*0a6a1f1dSLionel Sambuc VFSFromYamlDirIterImpl::VFSFromYamlDirIterImpl(const Twine &_Path,
1135*0a6a1f1dSLionel Sambuc                                                VFSFromYAML &FS,
1136*0a6a1f1dSLionel Sambuc                                                DirectoryEntry::iterator Begin,
1137*0a6a1f1dSLionel Sambuc                                                DirectoryEntry::iterator End,
1138*0a6a1f1dSLionel Sambuc                                                std::error_code &EC)
1139*0a6a1f1dSLionel Sambuc     : Dir(_Path.str()), FS(FS), Current(Begin), End(End) {
1140*0a6a1f1dSLionel Sambuc   if (Current != End) {
1141*0a6a1f1dSLionel Sambuc     SmallString<128> PathStr(Dir);
1142*0a6a1f1dSLionel Sambuc     llvm::sys::path::append(PathStr, (*Current)->getName());
1143*0a6a1f1dSLionel Sambuc     llvm::ErrorOr<vfs::Status> S = FS.status(PathStr.str());
1144*0a6a1f1dSLionel Sambuc     if (S)
1145*0a6a1f1dSLionel Sambuc       CurrentEntry = *S;
1146*0a6a1f1dSLionel Sambuc     else
1147*0a6a1f1dSLionel Sambuc       EC = S.getError();
1148*0a6a1f1dSLionel Sambuc   }
1149*0a6a1f1dSLionel Sambuc }
1150*0a6a1f1dSLionel Sambuc 
increment()1151*0a6a1f1dSLionel Sambuc std::error_code VFSFromYamlDirIterImpl::increment() {
1152*0a6a1f1dSLionel Sambuc   assert(Current != End && "cannot iterate past end");
1153*0a6a1f1dSLionel Sambuc   if (++Current != End) {
1154*0a6a1f1dSLionel Sambuc     SmallString<128> PathStr(Dir);
1155*0a6a1f1dSLionel Sambuc     llvm::sys::path::append(PathStr, (*Current)->getName());
1156*0a6a1f1dSLionel Sambuc     llvm::ErrorOr<vfs::Status> S = FS.status(PathStr.str());
1157*0a6a1f1dSLionel Sambuc     if (!S)
1158*0a6a1f1dSLionel Sambuc       return S.getError();
1159*0a6a1f1dSLionel Sambuc     CurrentEntry = *S;
1160*0a6a1f1dSLionel Sambuc   } else {
1161*0a6a1f1dSLionel Sambuc     CurrentEntry = Status();
1162*0a6a1f1dSLionel Sambuc   }
1163*0a6a1f1dSLionel Sambuc   return std::error_code();
1164*0a6a1f1dSLionel Sambuc }
1165*0a6a1f1dSLionel Sambuc 
recursive_directory_iterator(FileSystem & FS_,const Twine & Path,std::error_code & EC)1166*0a6a1f1dSLionel Sambuc vfs::recursive_directory_iterator::recursive_directory_iterator(FileSystem &FS_,
1167*0a6a1f1dSLionel Sambuc                                                            const Twine &Path,
1168*0a6a1f1dSLionel Sambuc                                                            std::error_code &EC)
1169*0a6a1f1dSLionel Sambuc     : FS(&FS_) {
1170*0a6a1f1dSLionel Sambuc   directory_iterator I = FS->dir_begin(Path, EC);
1171*0a6a1f1dSLionel Sambuc   if (!EC && I != directory_iterator()) {
1172*0a6a1f1dSLionel Sambuc     State = std::make_shared<IterState>();
1173*0a6a1f1dSLionel Sambuc     State->push(I);
1174*0a6a1f1dSLionel Sambuc   }
1175*0a6a1f1dSLionel Sambuc }
1176*0a6a1f1dSLionel Sambuc 
1177*0a6a1f1dSLionel Sambuc vfs::recursive_directory_iterator &
increment(std::error_code & EC)1178*0a6a1f1dSLionel Sambuc recursive_directory_iterator::increment(std::error_code &EC) {
1179*0a6a1f1dSLionel Sambuc   assert(FS && State && !State->empty() && "incrementing past end");
1180*0a6a1f1dSLionel Sambuc   assert(State->top()->isStatusKnown() && "non-canonical end iterator");
1181*0a6a1f1dSLionel Sambuc   vfs::directory_iterator End;
1182*0a6a1f1dSLionel Sambuc   if (State->top()->isDirectory()) {
1183*0a6a1f1dSLionel Sambuc     vfs::directory_iterator I = FS->dir_begin(State->top()->getName(), EC);
1184*0a6a1f1dSLionel Sambuc     if (EC)
1185*0a6a1f1dSLionel Sambuc       return *this;
1186*0a6a1f1dSLionel Sambuc     if (I != End) {
1187*0a6a1f1dSLionel Sambuc       State->push(I);
1188*0a6a1f1dSLionel Sambuc       return *this;
1189*0a6a1f1dSLionel Sambuc     }
1190*0a6a1f1dSLionel Sambuc   }
1191*0a6a1f1dSLionel Sambuc 
1192*0a6a1f1dSLionel Sambuc   while (!State->empty() && State->top().increment(EC) == End)
1193*0a6a1f1dSLionel Sambuc     State->pop();
1194*0a6a1f1dSLionel Sambuc 
1195*0a6a1f1dSLionel Sambuc   if (State->empty())
1196*0a6a1f1dSLionel Sambuc     State.reset(); // end iterator
1197*0a6a1f1dSLionel Sambuc 
1198*0a6a1f1dSLionel Sambuc   return *this;
1199*0a6a1f1dSLionel Sambuc }
1200