r201618 - Initial implementation of virtual file system
Ben Langmuir
blangmuir at apple.com
Wed Feb 19 07:42:45 PST 2014
On Feb 19, 2014, at 6:30 AM, Aaron Ballman <aaron at aaronballman.com> wrote:
> On Tue, Feb 18, 2014 at 7:10 PM, Ben Langmuir <blangmuir at apple.com> 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
More information about the cfe-commits
mailing list