On Feb 19, 2014, at 6:30 AM, Aaron Ballman <[email protected]> wrote:
> On Tue, Feb 18, 2014 at 7:10 PM, Ben Langmuir <[email protected]> wrote: >> Author: benlangmuir >> Date: Tue Feb 18 18:10:30 2014 >> New Revision: 201618 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=201618&view=rev >> Log: >> Initial implementation of virtual file system >> >> This adds the minimum virtual file system support to start migrating >> FileManager onto the VFS. >> >> Originally discussed here: >> http://lists.cs.uiuc.edu/pipermail/cfe-dev/2014-February/035188.html >> >> Differential Revision: http://llvm-reviews.chandlerc.com/D2745 >> >> Added: >> cfe/trunk/include/clang/Basic/VirtualFileSystem.h >> cfe/trunk/lib/Basic/VirtualFileSystem.cpp >> Modified: >> cfe/trunk/include/clang/Basic/FileManager.h >> cfe/trunk/include/clang/Basic/FileSystemStatCache.h >> cfe/trunk/include/clang/Frontend/CompilerInstance.h >> cfe/trunk/lib/Basic/CMakeLists.txt >> cfe/trunk/lib/Basic/FileManager.cpp >> cfe/trunk/lib/Basic/FileSystemStatCache.cpp >> cfe/trunk/lib/Frontend/ASTUnit.cpp >> cfe/trunk/lib/Frontend/CacheTokens.cpp >> cfe/trunk/lib/Frontend/ChainedIncludesSource.cpp >> cfe/trunk/lib/Frontend/CompilerInstance.cpp >> cfe/trunk/lib/Frontend/FrontendAction.cpp >> cfe/trunk/lib/Lex/PTHLexer.cpp >> cfe/trunk/lib/Serialization/ModuleManager.cpp >> cfe/trunk/unittests/Basic/FileManagerTest.cpp >> >> Modified: cfe/trunk/include/clang/Basic/FileManager.h >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/FileManager.h?rev=201618&r1=201617&r2=201618&view=diff >> ============================================================================== >> --- cfe/trunk/include/clang/Basic/FileManager.h (original) >> +++ cfe/trunk/include/clang/Basic/FileManager.h Tue Feb 18 18:10:30 2014 >> @@ -17,6 +17,7 @@ >> >> #include "clang/Basic/FileSystemOptions.h" >> #include "clang/Basic/LLVM.h" >> +#include "clang/Basic/VirtualFileSystem.h" >> #include "llvm/ADT/DenseMap.h" >> #include "llvm/ADT/IntrusiveRefCntPtr.h" >> #include "llvm/ADT/OwningPtr.h" >> @@ -24,7 +25,6 @@ >> #include "llvm/ADT/StringMap.h" >> #include "llvm/ADT/StringRef.h" >> #include "llvm/Support/Allocator.h" >> -#include "llvm/Support/FileSystem.h" >> // FIXME: Enhance libsystem to support inode and other fields in stat. >> #include <sys/types.h> >> >> @@ -55,7 +55,7 @@ public: >> /// \brief Cached information about one file (either on disk >> /// or in the virtual file system). >> /// >> -/// If the 'FD' member is valid, then this FileEntry has an open file >> +/// If the 'File' member is valid, then this FileEntry has an open file >> /// descriptor for the file. >> class FileEntry { >> const char *Name; // Name of the file. >> @@ -67,31 +67,33 @@ class FileEntry { >> bool IsNamedPipe; >> bool InPCH; >> >> - /// FD - The file descriptor for the file entry if it is opened and owned >> - /// by the FileEntry. If not, this is set to -1. >> - mutable int FD; >> + /// \brief The open file, if it is owned by the \p FileEntry. >> + mutable OwningPtr<vfs::File> File; >> friend class FileManager; >> >> + void closeFile() const { >> + File.reset(0); // rely on destructor to close File >> + } >> + >> public: >> FileEntry(llvm::sys::fs::UniqueID UniqueID, bool IsNamedPipe, bool InPCH) >> - : Name(0), UniqueID(UniqueID), IsNamedPipe(IsNamedPipe), InPCH(InPCH), >> - FD(-1) {} >> + : Name(0), UniqueID(UniqueID), IsNamedPipe(IsNamedPipe), InPCH(InPCH) >> + {} >> // Add a default constructor for use with llvm::StringMap >> FileEntry() >> - : Name(0), UniqueID(0, 0), IsNamedPipe(false), InPCH(false), FD(-1) {} >> + : Name(0), UniqueID(0, 0), IsNamedPipe(false), InPCH(false) >> + {} >> >> FileEntry(const FileEntry &FE) { >> memcpy(this, &FE, sizeof(FE)); >> - assert(FD == -1 && "Cannot copy a file-owning FileEntry"); >> + assert(!File && "Cannot copy a file-owning FileEntry"); >> } >> >> void operator=(const FileEntry &FE) { >> memcpy(this, &FE, sizeof(FE)); >> - assert(FD == -1 && "Cannot assign a file-owning FileEntry"); >> + assert(!File && "Cannot assign a file-owning FileEntry"); >> } >> >> - ~FileEntry(); >> - >> const char *getName() const { return Name; } >> off_t getSize() const { return Size; } >> unsigned getUID() const { return UID; } >> @@ -119,6 +121,7 @@ struct FileData; >> /// as a single file. >> /// >> class FileManager : public RefCountedBase<FileManager> { >> + IntrusiveRefCntPtr<vfs::FileSystem> FS; >> FileSystemOptions FileSystemOpts; >> >> class UniqueDirContainer; >> @@ -172,14 +175,15 @@ class FileManager : public RefCountedBas >> OwningPtr<FileSystemStatCache> StatCache; >> >> bool getStatValue(const char *Path, FileData &Data, bool isFile, >> - int *FileDescriptor); >> + vfs::File **F); >> >> /// Add all ancestors of the given path (pointing to either a file >> /// or a directory) as virtual directories. >> void addAncestorsAsVirtualDirs(StringRef Path); >> >> public: >> - FileManager(const FileSystemOptions &FileSystemOpts); >> + FileManager(const FileSystemOptions &FileSystemOpts, >> + llvm::IntrusiveRefCntPtr<vfs::FileSystem> FS = 0); >> ~FileManager(); >> >> /// \brief Installs the provided FileSystemStatCache object within >> @@ -248,7 +252,7 @@ public: >> /// >> /// \returns false on success, true on error. >> bool getNoncachedStatValue(StringRef Path, >> - llvm::sys::fs::file_status &Result); >> + vfs::Status &Result); >> >> /// \brief Remove the real file \p Entry from the cache. >> void invalidateCache(const FileEntry *Entry); >> >> Modified: cfe/trunk/include/clang/Basic/FileSystemStatCache.h >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/FileSystemStatCache.h?rev=201618&r1=201617&r2=201618&view=diff >> ============================================================================== >> --- cfe/trunk/include/clang/Basic/FileSystemStatCache.h (original) >> +++ cfe/trunk/include/clang/Basic/FileSystemStatCache.h Tue Feb 18 18:10:30 >> 2014 >> @@ -24,6 +24,11 @@ >> >> namespace clang { >> >> +namespace vfs { >> +class File; >> +class FileSystem; >> +} >> + >> struct FileData { >> uint64_t Size; >> time_t ModTime; >> @@ -57,10 +62,11 @@ public: >> /// If isFile is true, then this lookup should only return success for >> files >> /// (not directories). If it is false this lookup should only return >> /// success for directories (not files). On a successful file lookup, the >> - /// implementation can optionally fill in FileDescriptor with a valid >> - /// descriptor and the client guarantees that it will close it. >> + /// implementation can optionally fill in \p F with a valid \p File >> object and >> + /// the client guarantees that it will close it. >> static bool get(const char *Path, FileData &Data, bool isFile, >> - int *FileDescriptor, FileSystemStatCache *Cache); >> + vfs::File **F, FileSystemStatCache *Cache, >> + vfs::FileSystem &FS); >> >> /// \brief Sets the next stat call cache in the chain of stat caches. >> /// Takes ownership of the given stat cache. >> @@ -78,17 +84,16 @@ public: >> >> protected: >> virtual LookupResult getStat(const char *Path, FileData &Data, bool isFile, >> - int *FileDescriptor) = 0; >> + vfs::File **F, vfs::FileSystem &FS) = 0; >> >> LookupResult statChained(const char *Path, FileData &Data, bool isFile, >> - int *FileDescriptor) { >> + vfs::File **F, vfs::FileSystem &FS) { >> if (FileSystemStatCache *Next = getNextStatCache()) >> - return Next->getStat(Path, Data, isFile, FileDescriptor); >> + return Next->getStat(Path, Data, isFile, F, FS); >> >> // If we hit the end of the list of stat caches to try, just compute and >> // return it without a cache. >> - return get(Path, Data, isFile, FileDescriptor, 0) ? CacheMissing >> - : CacheExists; >> + return get(Path, Data, isFile, F, 0, FS) ? CacheMissing : CacheExists; >> } >> }; >> >> @@ -107,7 +112,7 @@ public: >> iterator end() const { return StatCalls.end(); } >> >> virtual LookupResult getStat(const char *Path, FileData &Data, bool isFile, >> - int *FileDescriptor); >> + vfs::File **F, vfs::FileSystem &FS); >> }; >> >> } // end namespace clang >> >> Added: cfe/trunk/include/clang/Basic/VirtualFileSystem.h >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/VirtualFileSystem.h?rev=201618&view=auto >> ============================================================================== >> --- cfe/trunk/include/clang/Basic/VirtualFileSystem.h (added) >> +++ cfe/trunk/include/clang/Basic/VirtualFileSystem.h Tue Feb 18 18:10:30 >> 2014 >> @@ -0,0 +1,127 @@ >> +//===- VirtualFileSystem.h - Virtual File System Layer ----------*- C++ >> -*-===// >> +// >> +// The LLVM Compiler Infrastructure >> +// >> +// This file is distributed under the University of Illinois Open Source >> +// License. See LICENSE.TXT for details. >> +// >> +//===----------------------------------------------------------------------===// >> +/// \file >> +/// \brief Defines the virtual file system interface vfs::FileSystem. >> +//===----------------------------------------------------------------------===// >> + >> +#ifndef LLVM_CLANG_BASIC_VIRTUAL_FILE_SYSTEM_H >> +#define LLVM_CLANG_BASIC_VIRTUAL_FILE_SYSTEM_H >> + >> +#include "llvm/ADT/IntrusiveRefCntPtr.h" >> +#include "llvm/Support/FileSystem.h" >> +#include "llvm/Support/ErrorOr.h" >> + >> +namespace llvm { >> +template <typename T> class OwningPtr; >> +class MemoryBuffer; >> +} >> + >> +namespace clang { >> +namespace vfs { >> + >> +/// \brief The result of a \p status operation. >> +class Status { >> + std::string Name; >> + std::string ExternalName; >> + llvm::sys::fs::UniqueID UID; >> + llvm::sys::TimeValue MTime; >> + uint32_t User; >> + uint32_t Group; >> + uint64_t Size; >> + llvm::sys::fs::file_type Type; >> + llvm::sys::fs::perms Perms; >> + >> +public: >> + Status() : Type(llvm::sys::fs::file_type::status_error) {} >> + Status(const llvm::sys::fs::file_status &Status); >> + Status(llvm::StringRef Name, llvm::StringRef RealName, >> + llvm::sys::fs::UniqueID UID, llvm::sys::TimeValue MTime, >> + uint32_t User, uint32_t Group, uint64_t Size, >> + llvm::sys::fs::file_type Type, llvm::sys::fs::perms Perms); >> + >> + /// \brief Returns the name this status was looked up by. >> + llvm::StringRef getName() const { return Name; } >> + >> + /// \brief Returns the name to use outside the compiler. >> + /// >> + /// For example, in diagnostics or debug info we should use this name. >> + llvm::StringRef getExternalName() const { return ExternalName; } >> + >> + void setName(llvm::StringRef N) { Name = N; } >> + void setExternalName(llvm::StringRef N) { ExternalName = N; } >> + >> + /// @name Status interface from llvm::sys::fs >> + /// @{ >> + llvm::sys::fs::file_type getType() const { return Type; } >> + llvm::sys::fs::perms getPermissions() const { return Perms; } >> + llvm::sys::TimeValue getLastModificationTime() const { return MTime; } >> + llvm::sys::fs::UniqueID getUniqueID() const { return UID; } >> + uint32_t getUser() const { return User; } >> + uint32_t getGroup() const { return Group; } >> + uint64_t getSize() const { return Size; } >> + void setType(llvm::sys::fs::file_type v) { Type = v; } >> + void setPermissions(llvm::sys::fs::perms p) { Perms = p; } >> + /// @} >> + /// @name Status queries >> + /// These are static queries in llvm::sys::fs. >> + /// @{ >> + bool equivalent(const Status &Other) const; >> + bool isDirectory() const; >> + bool isRegularFile() const; >> + bool isOther() const; >> + bool isSymlink() const; >> + bool isStatusKnown() const; >> + bool exists() const; >> + /// @} >> +}; >> + >> +/// \brief Represents an open file. >> +class File { >> +public: >> + /// \brief Destroy the file after closing it (if open). >> + /// Sub-classes should generally call close() inside their destructors. >> We >> + /// cannot do that from the base class, since close is virtual. >> + virtual ~File(); >> + /// \brief Get the status of the file. >> + virtual llvm::ErrorOr<Status> status() = 0; >> + /// \brief Get the contents of the file as a \p MemoryBuffer. >> + virtual llvm::error_code >> + getBuffer(const llvm::Twine &Name, >> + llvm::OwningPtr<llvm::MemoryBuffer> &Result, int64_t FileSize = >> -1, >> + bool RequiresNullTerminator = true) = 0; >> + /// \brief Closes the file. >> + virtual llvm::error_code close() = 0; >> +}; >> + >> +/// \brief The virtual file system interface. >> +class FileSystem : public llvm::RefCountedBase<FileSystem> { >> +public: >> + virtual ~FileSystem(); >> + >> + /// \brief Get the status of the entry at \p Path, if one exists. >> + virtual llvm::ErrorOr<Status> status(const llvm::Twine &Path) = 0; >> + /// \brief Get a \p File object for the file at \p Path, if one exists. >> + virtual llvm::error_code openFileForRead(const llvm::Twine &Path, >> + llvm::OwningPtr<File> &Result) = >> 0; >> + >> + /// This is a convenience method that opens a file, gets its content and >> then >> + /// closes the file. >> + llvm::error_code getBufferForFile(const llvm::Twine &Name, >> + llvm::OwningPtr<llvm::MemoryBuffer> >> &Result, >> + int64_t FileSize = -1, >> + bool RequiresNullTerminator = true); >> +}; >> + >> +/// \brief Gets an \p vfs::FileSystem for the 'real' file system, as seen by >> +/// the operating system. >> +llvm::IntrusiveRefCntPtr<FileSystem> getRealFileSystem(); >> + >> +} // end namespace vfs >> +} // end namespace clang >> +#endif // LLVM_CLANG_BASIC_VIRTUAL_FILE_SYSTEM_H >> >> Modified: cfe/trunk/include/clang/Frontend/CompilerInstance.h >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CompilerInstance.h?rev=201618&r1=201617&r2=201618&view=diff >> ============================================================================== >> --- cfe/trunk/include/clang/Frontend/CompilerInstance.h (original) >> +++ cfe/trunk/include/clang/Frontend/CompilerInstance.h Tue Feb 18 18:10:30 >> 2014 >> @@ -75,6 +75,9 @@ class CompilerInstance : public ModuleLo >> /// The target being compiled for. >> IntrusiveRefCntPtr<TargetInfo> Target; >> >> + /// The virtual file system. >> + IntrusiveRefCntPtr<vfs::FileSystem> VirtualFileSystem; >> + >> /// The file manager. >> IntrusiveRefCntPtr<FileManager> FileMgr; >> >> @@ -314,6 +317,23 @@ public: >> void setTarget(TargetInfo *Value); >> >> /// } >> + /// @name Virtual File System >> + /// { >> + >> + bool hasVirtualFileSystem() const { return VirtualFileSystem != 0; } >> + >> + vfs::FileSystem &getVirtualFileSystem() const { >> + assert(hasVirtualFileSystem() && >> + "Compiler instance has no virtual file system"); >> + return *VirtualFileSystem; >> + } >> + >> + /// \brief Replace the current virtual file system. >> + void setVirtualFileSystem(IntrusiveRefCntPtr<vfs::FileSystem> FS) { >> + VirtualFileSystem = FS; >> + } >> + >> + /// } >> /// @name File Manager >> /// { >> >> @@ -527,6 +547,10 @@ public: >> bool ShouldOwnClient = true, >> const CodeGenOptions *CodeGenOpts = 0); >> >> + /// Create a virtual file system and replace any existing one with it. >> + /// The default is to use the real file system. >> + void createVirtualFileSystem(); >> + >> /// Create the file manager and replace any existing one with it. >> void createFileManager(); >> >> >> Modified: cfe/trunk/lib/Basic/CMakeLists.txt >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/CMakeLists.txt?rev=201618&r1=201617&r2=201618&view=diff >> ============================================================================== >> --- cfe/trunk/lib/Basic/CMakeLists.txt (original) >> +++ cfe/trunk/lib/Basic/CMakeLists.txt Tue Feb 18 18:10:30 2014 >> @@ -23,6 +23,7 @@ add_clang_library(clangBasic >> TokenKinds.cpp >> Version.cpp >> VersionTuple.cpp >> + VirtualFileSystem.cpp >> ) >> >> # Determine Subversion revision. >> >> Modified: cfe/trunk/lib/Basic/FileManager.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/FileManager.cpp?rev=201618&r1=201617&r2=201618&view=diff >> ============================================================================== >> --- cfe/trunk/lib/Basic/FileManager.cpp (original) >> +++ cfe/trunk/lib/Basic/FileManager.cpp Tue Feb 18 18:10:30 2014 >> @@ -30,19 +30,6 @@ >> #include <set> >> #include <string> >> >> -// FIXME: This is terrible, we need this for ::close. >> -#if !defined(_MSC_VER) && !defined(__MINGW32__) >> -#include <unistd.h> >> -#include <sys/uio.h> >> -#else >> -#include <io.h> >> -#ifndef S_ISFIFO >> -#define S_ISFIFO(x) (0) >> -#endif >> -#endif >> -#if defined(LLVM_ON_UNIX) >> -#include <limits.h> >> -#endif >> using namespace clang; >> >> // FIXME: Enhance libsystem to support inode and other fields. >> @@ -57,12 +44,6 @@ using namespace clang; >> #define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1) >> >> >> -FileEntry::~FileEntry() { >> - // If this FileEntry owns an open file descriptor that never got used, >> close >> - // it. >> - if (FD != -1) ::close(FD); >> -} >> - >> class FileManager::UniqueDirContainer { >> /// UniqueDirs - Cache from ID's to existing directories/files. >> std::map<llvm::sys::fs::UniqueID, DirectoryEntry> UniqueDirs; >> @@ -101,13 +82,19 @@ public: >> // Common logic. >> //===----------------------------------------------------------------------===// >> >> -FileManager::FileManager(const FileSystemOptions &FSO) >> - : FileSystemOpts(FSO), >> +FileManager::FileManager(const FileSystemOptions &FSO, >> + IntrusiveRefCntPtr<vfs::FileSystem> FS) >> + : FS(FS), FileSystemOpts(FSO), >> UniqueRealDirs(*new UniqueDirContainer()), >> UniqueRealFiles(*new UniqueFileContainer()), >> SeenDirEntries(64), SeenFileEntries(64), NextFileUID(0) { >> NumDirLookups = NumFileLookups = 0; >> NumDirCacheMisses = NumFileCacheMisses = 0; >> + >> + // If the caller doesn't provide a virtual file system, just grab the real >> + // file system. >> + if (!FS) >> + this->FS = vfs::getRealFileSystem(); >> } >> >> FileManager::~FileManager() { >> @@ -309,10 +296,9 @@ const FileEntry *FileManager::getFile(St >> // FIXME: This will reduce the # syscalls. >> >> // Nope, there isn't. Check to see if the file exists. >> - int FileDescriptor = -1; >> + vfs::File *F = 0; >> FileData Data; >> - if (getStatValue(InterndFileName, Data, true, >> - openFile ? &FileDescriptor : 0)) { >> + if (getStatValue(InterndFileName, Data, true, openFile ? &F : 0)) { >> // There's no real file at the given path. >> if (!CacheFailure) >> SeenFileEntries.erase(Filename); >> @@ -320,10 +306,7 @@ const FileEntry *FileManager::getFile(St >> return 0; >> } >> >> - if (FileDescriptor != -1 && !openFile) { >> - close(FileDescriptor); >> - FileDescriptor = -1; >> - } >> + assert(openFile || !F && "undesired open file"); >> >> // It exists. See if we have already opened a file with the same inode. >> // This occurs when one dir is symlinked to another, for example. >> @@ -333,8 +316,8 @@ const FileEntry *FileManager::getFile(St >> NamedFileEnt.setValue(&UFE); >> if (UFE.getName()) { // Already have an entry with this inode, return it. >> // If the stat process opened the file, close it to avoid a FD leak. >> - if (FileDescriptor != -1) >> - close(FileDescriptor); >> + if (F) >> + delete F; >> >> return &UFE; >> } >> @@ -347,7 +330,7 @@ const FileEntry *FileManager::getFile(St >> UFE.ModTime = Data.ModTime; >> UFE.Dir = DirInfo; >> UFE.UID = NextFileUID++; >> - UFE.FD = FileDescriptor; >> + UFE.File.reset(F); >> return &UFE; >> } >> >> @@ -393,10 +376,8 @@ FileManager::getVirtualFile(StringRef Fi >> // If we had already opened this file, close it now so we don't >> // leak the descriptor. We're not going to use the file >> // descriptor anyway, since this is a virtual file. >> - if (UFE->FD != -1) { >> - close(UFE->FD); >> - UFE->FD = -1; >> - } >> + if (UFE->File) >> + UFE->closeFile(); >> >> // If we already have an entry with this inode, return it. >> if (UFE->getName()) >> @@ -414,7 +395,7 @@ FileManager::getVirtualFile(StringRef Fi >> UFE->ModTime = ModificationTime; >> UFE->Dir = DirInfo; >> UFE->UID = NextFileUID++; >> - UFE->FD = -1; >> + UFE->File.reset(); >> return UFE; >> } >> >> @@ -444,20 +425,18 @@ getBufferForFile(const FileEntry *Entry, >> >> const char *Filename = Entry->getName(); >> // If the file is already open, use the open file descriptor. >> - if (Entry->FD != -1) { >> - ec = llvm::MemoryBuffer::getOpenFile(Entry->FD, Filename, Result, >> FileSize); >> + if (Entry->File) { >> + ec = Entry->File->getBuffer(Filename, Result, FileSize); >> if (ErrorStr) >> *ErrorStr = ec.message(); >> - >> - close(Entry->FD); >> - Entry->FD = -1; >> + Entry->closeFile(); >> return Result.take(); >> } >> >> // Otherwise, open the file. >> >> if (FileSystemOpts.WorkingDir.empty()) { >> - ec = llvm::MemoryBuffer::getFile(Filename, Result, FileSize); >> + ec = FS->getBufferForFile(Filename, Result, FileSize); >> if (ec && ErrorStr) >> *ErrorStr = ec.message(); >> return Result.take(); >> @@ -465,7 +444,7 @@ getBufferForFile(const FileEntry *Entry, >> >> SmallString<128> FilePath(Entry->getName()); >> FixupRelativePath(FilePath); >> - ec = llvm::MemoryBuffer::getFile(FilePath.str(), Result, FileSize); >> + ec = FS->getBufferForFile(FilePath.str(), Result, FileSize); >> if (ec && ErrorStr) >> *ErrorStr = ec.message(); >> return Result.take(); >> @@ -476,7 +455,7 @@ getBufferForFile(StringRef Filename, std >> OwningPtr<llvm::MemoryBuffer> Result; >> llvm::error_code ec; >> if (FileSystemOpts.WorkingDir.empty()) { >> - ec = llvm::MemoryBuffer::getFile(Filename, Result); >> + ec = FS->getBufferForFile(Filename, Result); >> if (ec && ErrorStr) >> *ErrorStr = ec.message(); >> return Result.take(); >> @@ -484,7 +463,7 @@ getBufferForFile(StringRef Filename, std >> >> SmallString<128> FilePath(Filename); >> FixupRelativePath(FilePath); >> - ec = llvm::MemoryBuffer::getFile(FilePath.c_str(), Result); >> + ec = FS->getBufferForFile(FilePath.c_str(), Result); >> if (ec && ErrorStr) >> *ErrorStr = ec.message(); >> return Result.take(); >> @@ -496,26 +475,29 @@ getBufferForFile(StringRef Filename, std >> /// false if it's an existent real file. If FileDescriptor is NULL, >> /// do directory look-up instead of file look-up. >> bool FileManager::getStatValue(const char *Path, FileData &Data, bool isFile, >> - int *FileDescriptor) { >> + vfs::File **F) { >> // FIXME: FileSystemOpts shouldn't be passed in here, all paths should be >> // absolute! >> if (FileSystemOpts.WorkingDir.empty()) >> - return FileSystemStatCache::get(Path, Data, isFile, FileDescriptor, >> - StatCache.get()); >> + return FileSystemStatCache::get(Path, Data, isFile, F,StatCache.get(), >> *FS); >> >> SmallString<128> FilePath(Path); >> FixupRelativePath(FilePath); >> >> - return FileSystemStatCache::get(FilePath.c_str(), Data, isFile, >> - FileDescriptor, StatCache.get()); >> + return FileSystemStatCache::get(FilePath.c_str(), Data, isFile, F, >> + StatCache.get(), *FS); >> } >> >> bool FileManager::getNoncachedStatValue(StringRef Path, >> - llvm::sys::fs::file_status &Result) >> { >> + vfs::Status &Result) { >> SmallString<128> FilePath(Path); >> FixupRelativePath(FilePath); >> >> - return llvm::sys::fs::status(FilePath.c_str(), Result); >> + llvm::ErrorOr<vfs::Status> S = FS->status(FilePath.c_str()); >> + if (!S) >> + return true; >> + Result = *S; >> + return false; >> } >> >> void FileManager::invalidateCache(const FileEntry *Entry) { >> >> Modified: cfe/trunk/lib/Basic/FileSystemStatCache.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/FileSystemStatCache.cpp?rev=201618&r1=201617&r2=201618&view=diff >> ============================================================================== >> --- cfe/trunk/lib/Basic/FileSystemStatCache.cpp (original) >> +++ cfe/trunk/lib/Basic/FileSystemStatCache.cpp Tue Feb 18 18:10:30 2014 >> @@ -12,7 +12,7 @@ >> //===----------------------------------------------------------------------===// >> >> #include "clang/Basic/FileSystemStatCache.h" >> -#include "llvm/Support/FileSystem.h" >> +#include "clang/Basic/VirtualFileSystem.h" >> #include "llvm/Support/Path.h" >> >> // FIXME: This is terrible, we need this for ::close. >> @@ -30,13 +30,13 @@ using namespace clang; >> >> void FileSystemStatCache::anchor() { } >> >> -static void copyStatusToFileData(const llvm::sys::fs::file_status &Status, >> +static void copyStatusToFileData(const vfs::Status &Status, >> FileData &Data) { >> Data.Size = Status.getSize(); >> Data.ModTime = Status.getLastModificationTime().toEpochTime(); >> Data.UniqueID = Status.getUniqueID(); >> - Data.IsDirectory = is_directory(Status); >> - Data.IsNamedPipe = Status.type() == llvm::sys::fs::file_type::fifo_file; >> + Data.IsDirectory = Status.isDirectory(); >> + Data.IsNamedPipe = Status.getType() == >> llvm::sys::fs::file_type::fifo_file; >> Data.InPCH = false; >> } >> >> @@ -50,22 +50,23 @@ static void copyStatusToFileData(const l >> /// implementation can optionally fill in FileDescriptor with a valid >> /// descriptor and the client guarantees that it will close it. >> bool FileSystemStatCache::get(const char *Path, FileData &Data, bool isFile, >> - int *FileDescriptor, FileSystemStatCache >> *Cache) { >> + vfs::File **F, FileSystemStatCache *Cache, >> + vfs::FileSystem &FS) { >> LookupResult R; >> bool isForDir = !isFile; >> >> // If we have a cache, use it to resolve the stat query. >> if (Cache) >> - R = Cache->getStat(Path, Data, isFile, FileDescriptor); >> - else if (isForDir || !FileDescriptor) { >> + R = Cache->getStat(Path, Data, isFile, F, FS); >> + else if (isForDir || !F) { >> // If this is a directory or a file descriptor is not needed and we have >> // no cache, just go to the file system. >> - llvm::sys::fs::file_status Status; >> - if (llvm::sys::fs::status(Path, Status)) { >> + llvm::ErrorOr<vfs::Status> Status = FS.status(Path); >> + if (!Status) { >> R = CacheMissing; >> } else { >> R = CacheExists; >> - copyStatusToFileData(Status, Data); >> + copyStatusToFileData(*Status, Data); >> } >> } else { >> // Otherwise, we have to go to the filesystem. We can always just use >> @@ -75,7 +76,8 @@ bool FileSystemStatCache::get(const char >> // >> // Because of this, check to see if the file exists with 'open'. If the >> // open succeeds, use fstat to get the stat info. >> - llvm::error_code EC = llvm::sys::fs::openFileForRead(Path, >> *FileDescriptor); >> + llvm::OwningPtr<vfs::File> OwnedFile; >> + llvm::error_code EC = FS.openFileForRead(Path, OwnedFile); >> >> if (EC) { >> // If the open fails, our "stat" fails. >> @@ -84,16 +86,16 @@ bool FileSystemStatCache::get(const char >> // Otherwise, the open succeeded. Do an fstat to get the information >> // about the file. We'll end up returning the open file descriptor to >> the >> // client to do what they please with it. >> - llvm::sys::fs::file_status Status; >> - if (!llvm::sys::fs::status(*FileDescriptor, Status)) { >> + llvm::ErrorOr<vfs::Status> Status = OwnedFile->status(); >> + if (Status) { >> R = CacheExists; >> - copyStatusToFileData(Status, Data); >> + copyStatusToFileData(*Status, Data); >> + *F = OwnedFile.take(); >> } else { >> // fstat rarely fails. If it does, claim the initial open didn't >> // succeed. >> R = CacheMissing; >> - ::close(*FileDescriptor); >> - *FileDescriptor = -1; >> + *F = 0; >> } >> } >> } >> @@ -105,9 +107,9 @@ bool FileSystemStatCache::get(const char >> // demands. >> if (Data.IsDirectory != isForDir) { >> // If not, close the file if opened. >> - if (FileDescriptor && *FileDescriptor != -1) { >> - ::close(*FileDescriptor); >> - *FileDescriptor = -1; >> + if (F && *F) { >> + (*F)->close(); >> + *F = 0; >> } >> >> return true; >> @@ -118,8 +120,8 @@ bool FileSystemStatCache::get(const char >> >> MemorizeStatCalls::LookupResult >> MemorizeStatCalls::getStat(const char *Path, FileData &Data, bool isFile, >> - int *FileDescriptor) { >> - LookupResult Result = statChained(Path, Data, isFile, FileDescriptor); >> + vfs::File **F, vfs::FileSystem &FS) { >> + LookupResult Result = statChained(Path, Data, isFile, F, FS); >> >> // Do not cache failed stats, it is easy to construct common inconsistent >> // situations if we do, and they are not important for PCH performance >> (which >> >> Added: cfe/trunk/lib/Basic/VirtualFileSystem.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/VirtualFileSystem.cpp?rev=201618&view=auto >> ============================================================================== >> --- cfe/trunk/lib/Basic/VirtualFileSystem.cpp (added) >> +++ cfe/trunk/lib/Basic/VirtualFileSystem.cpp Tue Feb 18 18:10:30 2014 >> @@ -0,0 +1,162 @@ >> +//===- VirtualFileSystem.cpp - Virtual File System Layer --------*- C++ >> -*-===// >> +// >> +// The LLVM Compiler Infrastructure >> +// >> +// This file is distributed under the University of Illinois Open Source >> +// License. See LICENSE.TXT for details. >> +// >> +//===----------------------------------------------------------------------===// >> +// This file implements the VirtualFileSystem interface. >> +//===----------------------------------------------------------------------===// >> + >> +#include "clang/Basic/VirtualFileSystem.h" >> +#include "llvm/ADT/OwningPtr.h" >> +#include "llvm/Support/MemoryBuffer.h" >> +#include "llvm/Support/SourceMgr.h" >> +#include "llvm/Support/Path.h" >> + >> +using namespace clang; >> +using namespace clang::vfs; >> +using namespace llvm; >> +using llvm::sys::fs::file_status; >> +using llvm::sys::fs::file_type; >> +using llvm::sys::fs::perms; >> +using llvm::sys::fs::UniqueID; >> + >> +Status::Status(const file_status &Status) >> + : UID(Status.getUniqueID()), MTime(Status.getLastModificationTime()), >> + User(Status.getUser()), Group(Status.getGroup()), >> Size(Status.getSize()), >> + Type(Status.type()), Perms(Status.permissions()) {} >> + >> +Status::Status(StringRef Name, StringRef ExternalName, >> + UniqueID UID, sys::TimeValue MTime, >> + uint32_t User, uint32_t Group, uint64_t Size, >> + file_type Type, perms Perms) >> + : Name(Name), ExternalName(ExternalName), UID(UID), MTime(MTime), >> + User(User), Group(Group), Size(Size), Type(Type), Perms(Perms) {} >> + >> +bool Status::equivalent(const Status &Other) const { >> + return getUniqueID() == Other.getUniqueID(); >> +} >> +bool Status::isDirectory() const { >> + return Type == file_type::directory_file; >> +} >> +bool Status::isRegularFile() const { >> + return Type == file_type::regular_file; >> +} >> +bool Status::isOther() const { >> + return Type == exists() && !isRegularFile() && !isDirectory() && >> !isSymlink(); > > I'm not certain I understand what Type == exists() is meant to test. > Is this a typo? > > FWIW, it yields warnings in MSVC, so this should be resolved: Warning > 1 warning C4805: '==' : unsafe mix of type 'int' and type 'bool' in > operation > > ~Aaron Sorry, yes this was a typo. Fixed in r201685 .FYI this issue was also PR18895. Ben _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
