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 _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
