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