r201618 - Initial implementation of virtual file system
Juergen Ributzka
juergen at apple.com
Wed Feb 19 21:35:24 PST 2014
Hi Ben,
I reverted your changes in r201755, because an assertion in your code kept failing on our internal build bots. I send you a separate email with the failing build bot.
-Juergen
On Feb 18, 2014, at 4: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();
> +}
> +bool Status::isSymlink() const {
> + return Type == file_type::symlink_file;
> +}
> +bool Status::isStatusKnown() const {
> + return Type != file_type::status_error;
> +}
> +bool Status::exists() const {
> + return isStatusKnown() && Type != file_type::file_not_found;
> +}
> +
> +File::~File() {}
> +
> +FileSystem::~FileSystem() {}
> +
> +error_code FileSystem::getBufferForFile(const llvm::Twine &Name,
> + OwningPtr<MemoryBuffer> &Result,
> + int64_t FileSize,
> + bool RequiresNullTerminator) {
> + llvm::OwningPtr<File> F;
> + if (error_code EC = openFileForRead(Name, F))
> + return EC;
> +
> + error_code EC = F->getBuffer(Name, Result, FileSize, RequiresNullTerminator);
> + return EC;
> +}
> +
> +//===-----------------------------------------------------------------------===/
> +// RealFileSystem implementation
> +//===-----------------------------------------------------------------------===/
> +
> +/// \brief Wrapper around a raw file descriptor.
> +class RealFile : public File {
> + int FD;
> + friend class RealFileSystem;
> + RealFile(int FD) : FD(FD) {
> + assert(FD >= 0 && "Invalid or inactive file descriptor");
> + }
> +public:
> + ~RealFile();
> + ErrorOr<Status> status() LLVM_OVERRIDE;
> + error_code getBuffer(const Twine &Name, OwningPtr<MemoryBuffer> &Result,
> + int64_t FileSize = -1,
> + bool RequiresNullTerminator = true) LLVM_OVERRIDE;
> + error_code close() LLVM_OVERRIDE;
> +};
> +RealFile::~RealFile() {
> + close();
> +}
> +
> +ErrorOr<Status> RealFile::status() {
> + assert(FD != -1 && "cannot stat closed file");
> + file_status RealStatus;
> + if (error_code EC = sys::fs::status(FD, RealStatus))
> + return EC;
> + return Status(RealStatus);
> +}
> +
> +error_code RealFile::getBuffer(const Twine &Name,
> + OwningPtr<MemoryBuffer> &Result,
> + int64_t FileSize, bool RequiresNullTerminator) {
> + assert(FD != -1 && "cannot get buffer for closed file");
> + return MemoryBuffer::getOpenFile(FD, Name.str().c_str(), Result, FileSize,
> + RequiresNullTerminator);
> +}
> +
> +// 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
> +error_code RealFile::close() {
> + if (::close(FD))
> + return error_code(errno, system_category());
> + FD = -1;
> + return error_code::success();
> +}
> +
> +/// \brief The file system according to your operating system.
> +class RealFileSystem : public FileSystem {
> +public:
> + ErrorOr<Status> status(const Twine &Path) LLVM_OVERRIDE;
> + error_code openFileForRead(const Twine &Path, OwningPtr<File> &Result)
> + LLVM_OVERRIDE;
> +};
> +
> +ErrorOr<Status> RealFileSystem::status(const Twine &Path) {
> + sys::fs::file_status RealStatus;
> + if (error_code EC = sys::fs::status(Path, RealStatus))
> + return EC;
> + Status Result(RealStatus);
> + Result.setName(Path.str());
> + Result.setExternalName(Path.str());
> + return Result;
> +}
> +
> +error_code RealFileSystem::openFileForRead(const Twine &Name,
> + OwningPtr<File> &Result) {
> + int FD;
> + if (error_code EC = sys::fs::openFileForRead(Name, FD))
> + return EC;
> + Result.reset(new RealFile(FD));
> + return error_code::success();
> +}
> +
> +IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
> + static IntrusiveRefCntPtr<FileSystem> FS = new RealFileSystem();
> + return FS;
> +}
>
> Modified: cfe/trunk/lib/Frontend/ASTUnit.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/ASTUnit.cpp?rev=201618&r1=201617&r2=201618&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Frontend/ASTUnit.cpp (original)
> +++ cfe/trunk/lib/Frontend/ASTUnit.cpp Tue Feb 18 18:10:30 2014
> @@ -20,6 +20,7 @@
> #include "clang/Basic/Diagnostic.h"
> #include "clang/Basic/TargetInfo.h"
> #include "clang/Basic/TargetOptions.h"
> +#include "clang/Basic/VirtualFileSystem.h"
> #include "clang/Frontend/CompilerInstance.h"
> #include "clang/Frontend/FrontendActions.h"
> #include "clang/Frontend/FrontendDiagnostic.h"
> @@ -37,7 +38,6 @@
> #include "llvm/ADT/StringSet.h"
> #include "llvm/Support/Atomic.h"
> #include "llvm/Support/CrashRecoveryContext.h"
> -#include "llvm/Support/FileSystem.h"
> #include "llvm/Support/Host.h"
> #include "llvm/Support/MemoryBuffer.h"
> #include "llvm/Support/Mutex.h"
> @@ -1421,7 +1421,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBuff
> REnd = PreprocessorOpts.remapped_file_end();
> !AnyFileChanged && R != REnd;
> ++R) {
> - llvm::sys::fs::file_status Status;
> + vfs::Status Status;
> if (FileMgr->getNoncachedStatValue(R->second, Status)) {
> // If we can't stat the file we're remapping to, assume that something
> // horrible happened.
> @@ -1457,7 +1457,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBuff
> }
>
> // The file was not remapped; check whether it has changed on disk.
> - llvm::sys::fs::file_status Status;
> + vfs::Status Status;
> if (FileMgr->getNoncachedStatValue(F->first(), Status)) {
> // If we can't stat the file, assume that something horrible happened.
> AnyFileChanged = true;
>
> Modified: cfe/trunk/lib/Frontend/CacheTokens.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CacheTokens.cpp?rev=201618&r1=201617&r2=201618&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Frontend/CacheTokens.cpp (original)
> +++ cfe/trunk/lib/Frontend/CacheTokens.cpp Tue Feb 18 18:10:30 2014
> @@ -516,8 +516,8 @@ public:
> ~StatListener() {}
>
> LookupResult 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);
>
> if (Result == CacheMissing) // Failed 'stat'.
> PM.insert(PTHEntryKeyVariant(Path), PTHEntry());
>
> Modified: cfe/trunk/lib/Frontend/ChainedIncludesSource.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/ChainedIncludesSource.cpp?rev=201618&r1=201617&r2=201618&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Frontend/ChainedIncludesSource.cpp (original)
> +++ cfe/trunk/lib/Frontend/ChainedIncludesSource.cpp Tue Feb 18 18:10:30 2014
> @@ -101,6 +101,7 @@ ChainedIncludesSource *ChainedIncludesSo
> Clang->setDiagnostics(Diags.getPtr());
> Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
> &Clang->getTargetOpts()));
> + Clang->createVirtualFileSystem();
> Clang->createFileManager();
> Clang->createSourceManager(Clang->getFileManager());
> Clang->createPreprocessor();
>
> Modified: cfe/trunk/lib/Frontend/CompilerInstance.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInstance.cpp?rev=201618&r1=201617&r2=201618&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Frontend/CompilerInstance.cpp (original)
> +++ cfe/trunk/lib/Frontend/CompilerInstance.cpp Tue Feb 18 18:10:30 2014
> @@ -194,9 +194,14 @@ CompilerInstance::createDiagnostics(Diag
> return Diags;
> }
>
> +void CompilerInstance::createVirtualFileSystem() {
> + VirtualFileSystem = vfs::getRealFileSystem();
> +}
> +
> // File Manager
>
> void CompilerInstance::createFileManager() {
> + assert(hasVirtualFileSystem() && "expected virtual file system");
> FileMgr = new FileManager(getFileSystemOpts());
> }
>
> @@ -867,6 +872,8 @@ static void compileModule(CompilerInstan
> ImportingInstance.getDiagnosticClient()),
> /*ShouldOwnClient=*/true);
>
> + Instance.setVirtualFileSystem(&ImportingInstance.getVirtualFileSystem());
> +
> // Note that this module is part of the module build stack, so that we
> // can detect cycles in the module graph.
> Instance.createFileManager(); // FIXME: Adopt file manager from importer?
>
> Modified: cfe/trunk/lib/Frontend/FrontendAction.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendAction.cpp?rev=201618&r1=201617&r2=201618&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Frontend/FrontendAction.cpp (original)
> +++ cfe/trunk/lib/Frontend/FrontendAction.cpp Tue Feb 18 18:10:30 2014
> @@ -159,7 +159,6 @@ ASTConsumer* FrontendAction::CreateWrapp
> return new MultiplexConsumer(Consumers);
> }
>
> -
> bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
> const FrontendInputFile &Input) {
> assert(!Instance && "Already processing a source file!");
> @@ -213,6 +212,8 @@ bool FrontendAction::BeginSourceFile(Com
> }
>
> // Set up the file and source managers, if needed.
> + if (!CI.hasVirtualFileSystem())
> + CI.createVirtualFileSystem();
> if (!CI.hasFileManager())
> CI.createFileManager();
> if (!CI.hasSourceManager())
>
> Modified: cfe/trunk/lib/Lex/PTHLexer.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PTHLexer.cpp?rev=201618&r1=201617&r2=201618&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Lex/PTHLexer.cpp (original)
> +++ cfe/trunk/lib/Lex/PTHLexer.cpp Tue Feb 18 18:10:30 2014
> @@ -675,13 +675,13 @@ public:
> ~PTHStatCache() {}
>
> LookupResult getStat(const char *Path, FileData &Data, bool isFile,
> - int *FileDescriptor) {
> + vfs::File **F, vfs::FileSystem &FS) {
> // Do the lookup for the file's data in the PTH file.
> CacheTy::iterator I = Cache.find(Path);
>
> // If we don't get a hit in the PTH file just forward to 'stat'.
> if (I == Cache.end())
> - return statChained(Path, Data, isFile, FileDescriptor);
> + return statChained(Path, Data, isFile, F, FS);
>
> const PTHStatData &D = *I;
>
>
> Modified: cfe/trunk/lib/Serialization/ModuleManager.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ModuleManager.cpp?rev=201618&r1=201617&r2=201618&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Serialization/ModuleManager.cpp (original)
> +++ cfe/trunk/lib/Serialization/ModuleManager.cpp Tue Feb 18 18:10:30 2014
> @@ -89,7 +89,7 @@ ModuleManager::addModule(StringRef FileN
> New->InputFilesValidationTimestamp = 0;
> if (New->Kind == MK_Module) {
> std::string TimestampFilename = New->getTimestampFilename();
> - llvm::sys::fs::file_status Status;
> + vfs::Status Status;
> // A cached stat value would be fine as well.
> if (!FileMgr.getNoncachedStatValue(TimestampFilename, Status))
> New->InputFilesValidationTimestamp =
>
> Modified: cfe/trunk/unittests/Basic/FileManagerTest.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Basic/FileManagerTest.cpp?rev=201618&r1=201617&r2=201618&view=diff
> ==============================================================================
> --- cfe/trunk/unittests/Basic/FileManagerTest.cpp (original)
> +++ cfe/trunk/unittests/Basic/FileManagerTest.cpp Tue Feb 18 18:10:30 2014
> @@ -48,7 +48,7 @@ public:
>
> // Implement FileSystemStatCache::getStat().
> virtual LookupResult getStat(const char *Path, FileData &Data, bool isFile,
> - int *FileDescriptor) {
> + vfs::File **F, vfs::FileSystem &FS) {
> if (StatCalls.count(Path) != 0) {
> Data = StatCalls[Path];
> return CacheExists;
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list