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