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