benlangmuir added you to the CC list for the revision "Some infrastructure work
for virtual file system (now on phab)".
Hi doug.gregor, klimek, gribozavr,
Adding to Phabricator at Manuel's suggestion. Original thread here:
http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20140210/098787.html.
Summary of changes since the original patch:
- Since the symlink issue that Dmitri pointed out is going to be a bigger fix,
I've pulled all the OverlayFileSystem bits out of this patch. I was hoping to
start getting some testing for a half-baked overlay fs, but this issue
convinced me it wasn't worth the trouble.
- Moved static status queries to be methods of Status
- Some smaller stuff from the reviews (e.g. using LLVM_OVERRIDE)
http://llvm-reviews.chandlerc.com/D2745
Files:
include/clang/Basic/FileManager.h
include/clang/Basic/FileSystemStatCache.h
include/clang/Basic/VirtualFileSystem.h
include/clang/Frontend/CompilerInstance.h
lib/Basic/CMakeLists.txt
lib/Basic/FileManager.cpp
lib/Basic/FileSystemStatCache.cpp
lib/Basic/VirtualFileSystem.cpp
lib/Frontend/ASTUnit.cpp
lib/Frontend/CacheTokens.cpp
lib/Frontend/ChainedIncludesSource.cpp
lib/Frontend/CompilerInstance.cpp
lib/Frontend/FrontendAction.cpp
lib/Lex/PTHLexer.cpp
unittests/Basic/FileManagerTest.cpp
Index: include/clang/Basic/FileManager.h
===================================================================
--- include/clang/Basic/FileManager.h
+++ include/clang/Basic/FileManager.h
@@ -17,14 +17,14 @@
#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"
#include "llvm/ADT/SmallVector.h"
#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>
@@ -119,6 +119,7 @@
/// as a single file.
///
class FileManager : public RefCountedBase<FileManager> {
+ IntrusiveRefCntPtr<AbstractFileSystem> FS;
FileSystemOptions FileSystemOpts;
class UniqueDirContainer;
@@ -179,7 +180,8 @@
void addAncestorsAsVirtualDirs(StringRef Path);
public:
- FileManager(const FileSystemOptions &FileSystemOpts);
+ FileManager(const FileSystemOptions &FileSystemOpts,
+ llvm::IntrusiveRefCntPtr<AbstractFileSystem> FS = 0);
~FileManager();
/// \brief Installs the provided FileSystemStatCache object within
@@ -248,7 +250,7 @@
///
/// \returns false on success, true on error.
bool getNoncachedStatValue(StringRef Path,
- llvm::sys::fs::file_status &Result);
+ AbstractFileSystem::Status &Result);
/// \brief Remove the real file \p Entry from the cache.
void invalidateCache(const FileEntry *Entry);
Index: include/clang/Basic/FileSystemStatCache.h
===================================================================
--- include/clang/Basic/FileSystemStatCache.h
+++ include/clang/Basic/FileSystemStatCache.h
@@ -24,6 +24,8 @@
namespace clang {
+class AbstractFileSystem;
+
struct FileData {
uint64_t Size;
time_t ModTime;
@@ -60,7 +62,8 @@
/// implementation can optionally fill in FileDescriptor with a valid
/// descriptor and the client guarantees that it will close it.
static bool get(const char *Path, FileData &Data, bool isFile,
- int *FileDescriptor, FileSystemStatCache *Cache);
+ int *FileDescriptor, FileSystemStatCache *Cache,
+ AbstractFileSystem &FS);
/// \brief Sets the next stat call cache in the chain of stat caches.
/// Takes ownership of the given stat cache.
@@ -78,17 +81,17 @@
protected:
virtual LookupResult getStat(const char *Path, FileData &Data, bool isFile,
- int *FileDescriptor) = 0;
+ int *FileDescriptor, AbstractFileSystem &FS) = 0;
LookupResult statChained(const char *Path, FileData &Data, bool isFile,
- int *FileDescriptor) {
+ int *FileDescriptor, AbstractFileSystem &FS) {
if (FileSystemStatCache *Next = getNextStatCache())
- return Next->getStat(Path, Data, isFile, FileDescriptor);
+ return Next->getStat(Path, Data, isFile, FileDescriptor, 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, FileDescriptor, 0, FS) ? CacheMissing
+ : CacheExists;
}
};
@@ -107,7 +110,7 @@
iterator end() const { return StatCalls.end(); }
virtual LookupResult getStat(const char *Path, FileData &Data, bool isFile,
- int *FileDescriptor);
+ int *FileDescriptor, AbstractFileSystem &FS);
};
} // end namespace clang
Index: include/clang/Basic/VirtualFileSystem.h
===================================================================
--- /dev/null
+++ include/clang/Basic/VirtualFileSystem.h
@@ -0,0 +1,189 @@
+//===- 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 AbstractFileSystem.
+//===----------------------------------------------------------------------===//
+
+#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"
+
+namespace llvm {
+template <typename T> class OwningPtr;
+class MemoryBuffer;
+}
+
+namespace clang {
+
+/// \brief The virtual file system interface, modeled on llvm::sys::fs.
+class AbstractFileSystem : public llvm::RefCountedBase<AbstractFileSystem> {
+public:
+ /// \brief The result of a \p status operation.
+ ///
+ /// In addition to providing the usual stat information, this class provides
+ /// \p Name and \p RealName fields, which can be used by clients that need
+ /// to differentiate between the name that this object was looked up by,
+ /// and the real name of this object on disk (if there is one).
+ class Status {
+ std::string Name;
+ std::string 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;
+
+ 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 real name of this file/directory on disk, if
+ /// there is one.
+ llvm::StringRef getRealName() const { return RealName; }
+
+ void setName(llvm::StringRef N) { Name = N; }
+ void setRealName(llvm::StringRef N) { RealName = N; }
+
+ /// @name Status interface from llvm::sys::fs
+ /// @{
+ llvm::sys::fs::file_type type() const { return Type; }
+ llvm::sys::fs::perms permissions() 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 type(llvm::sys::fs::file_type v) { Type = v; }
+ void permissions(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 is_directory() const;
+ bool is_regular_file() const;
+ bool is_other() const;
+ bool is_symlink() const;
+ bool status_known() const;
+ bool exists() const;
+ /// }
+ };
+
+ /// \brief A type representing an open file.
+ /// FIXME: right now we only support real files, so this is just an alias for
+ /// a raw operating system file descriptor.
+ typedef int FileDescriptor;
+
+ virtual ~AbstractFileSystem();
+
+ /// @name Convenience methods
+ /// @{
+ /// Convencience method for users that don't need to differentiate between
+ /// errors and a negative result.
+ bool exists(const llvm::Twine &Path) {
+ bool Result;
+ return !exists(Path, Result) && Result;
+ }
+ bool equivalent(const llvm::Twine &A, const llvm::Twine &B) {
+ bool Result;
+ return !equivalent(A, B, Result) && Result;
+ }
+ bool is_directory(const llvm::Twine &Path) {
+ bool Result;
+ return !is_directory(Path, Result) && Result;
+ }
+ bool is_regular_file(const llvm::Twine &Path) {
+ bool Result;
+ return !is_regular_file(Path, Result) && Result;
+ }
+ bool is_other(const llvm::Twine &Path) {
+ bool Result;
+ return !is_other(Path, Result) && Result;
+ }
+ bool is_symlink(const llvm::Twine &Path) {
+ bool Result;
+ return !is_symlink(Path, Result) && Result;
+ }
+ bool status_known(const llvm::Twine &Path) {
+ bool Result;
+ return !status_known(Path, Result) && Result;
+ }
+ /// @}
+ /// @name Operations on open files
+ /// This is the public interface. \see{Open file interface} for the interface
+ /// for subclasses.
+ /// @{
+ llvm::error_code status(FileDescriptor FD, Status &Result);
+ llvm::error_code getBufferForFile(FileDescriptor FD, const llvm::Twine &Name,
+ llvm::OwningPtr<llvm::MemoryBuffer> &Result,
+ int64_t FileSize = -1,
+ bool RequiresNullTerminator = true);
+ /// @}
+ /// @name Virtual file system interface
+ /// @{
+ virtual llvm::error_code status(const llvm::Twine &Path, Status &Result) = 0;
+ virtual llvm::error_code openFileForRead(const llvm::Twine &Path,
+ FileDescriptor &ResultFD) = 0;
+ virtual llvm::error_code getBufferForFile(
+ const llvm::Twine &Name, llvm::OwningPtr<llvm::MemoryBuffer> &Result,
+ int64_t FileSize = -1, bool RequiresNullTerminator = true) = 0;
+ /// @}
+ /// @name Operations implmented on top of \p status
+ /// @{
+
+ llvm::error_code exists(const llvm::Twine &Path, bool &Result);
+ llvm::error_code equivalent(const llvm::Twine &A, const llvm::Twine &B,
+ bool &Result);
+
+ llvm::error_code is_directory(const llvm::Twine &Path, bool &Result);
+ llvm::error_code is_regular_file(const llvm::Twine &Path, bool &Result);
+ llvm::error_code is_other(const llvm::Twine &Path, bool &Result);
+ llvm::error_code is_symlink(const llvm::Twine &Path, bool &Result);
+ llvm::error_code file_size(const llvm::Twine &Path, uint64_t &Result);
+ llvm::error_code status_known(const llvm::Twine &Path, bool &Result);
+ llvm::error_code getUniqueID(const llvm::Twine &Path,
+ llvm::sys::fs::UniqueID &Result);
+ /// @}
+
+protected:
+ /// @name Open file interface
+ /// These methods are intended to be implemented by file systems that provide
+ /// a source of openable files. FIXME: right now only \p RealFileSystem does
+ /// this.
+ /// @{
+
+ /// \brief Get the \p Status of an open file.
+ virtual llvm::error_code statusOfOpenFile(FileDescriptor FD, Status &Result);
+
+ /// \brief Get a \p MemoryBuffer for an open file.
+ virtual llvm::error_code
+ getBufferForOpenFile(FileDescriptor FD, const llvm::Twine &Name,
+ llvm::OwningPtr<llvm::MemoryBuffer> &Result,
+ int64_t FileSize = -1,
+ bool RequiresNullTerminator = true);
+ /// @}
+};
+
+/// \brief Gets an \p AbstractFileSystem for the 'real' file system, as seen by
+/// the operating system.
+llvm::IntrusiveRefCntPtr<AbstractFileSystem> getRealFileSystem();
+
+} // end namespace clang
+#endif // LLVM_CLANG_BASIC_VIRTUAL_FILE_SYSTEM_H
Index: include/clang/Frontend/CompilerInstance.h
===================================================================
--- include/clang/Frontend/CompilerInstance.h
+++ include/clang/Frontend/CompilerInstance.h
@@ -75,6 +75,9 @@
/// The target being compiled for.
IntrusiveRefCntPtr<TargetInfo> Target;
+ /// The virtual file system.
+ IntrusiveRefCntPtr<AbstractFileSystem> VirtualFileSystem;
+
/// The file manager.
IntrusiveRefCntPtr<FileManager> FileMgr;
@@ -314,6 +317,23 @@
void setTarget(TargetInfo *Value);
/// }
+ /// @name Virtual File System
+ /// {
+
+ bool hasVirtualFileSystem() const { return VirtualFileSystem != 0; }
+
+ AbstractFileSystem &getVirtualFileSystem() const {
+ assert(hasVirtualFileSystem() &&
+ "Compiler instance has no virtual file system");
+ return *VirtualFileSystem;
+ }
+
+ /// \brief Replace the current virtual file system.
+ void setVirtualFileSystem(IntrusiveRefCntPtr<AbstractFileSystem> FS) {
+ VirtualFileSystem = FS;
+ }
+
+ /// }
/// @name File Manager
/// {
@@ -527,6 +547,10 @@
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();
Index: lib/Basic/CMakeLists.txt
===================================================================
--- lib/Basic/CMakeLists.txt
+++ lib/Basic/CMakeLists.txt
@@ -23,6 +23,7 @@
TokenKinds.cpp
Version.cpp
VersionTuple.cpp
+ VirtualFileSystem.cpp
)
# Determine Subversion revision.
Index: lib/Basic/FileManager.cpp
===================================================================
--- lib/Basic/FileManager.cpp
+++ lib/Basic/FileManager.cpp
@@ -101,13 +101,19 @@
// Common logic.
//===----------------------------------------------------------------------===//
-FileManager::FileManager(const FileSystemOptions &FSO)
- : FileSystemOpts(FSO),
+FileManager::FileManager(const FileSystemOptions &FSO,
+ IntrusiveRefCntPtr<AbstractFileSystem> 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 = getRealFileSystem();
}
FileManager::~FileManager() {
@@ -445,7 +451,7 @@
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);
+ ec = FS->getBufferForFile(Entry->FD, Filename, Result, FileSize);
if (ErrorStr)
*ErrorStr = ec.message();
@@ -457,15 +463,15 @@
// 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();
}
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,15 +482,15 @@
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();
}
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();
@@ -501,21 +507,21 @@
// absolute!
if (FileSystemOpts.WorkingDir.empty())
return FileSystemStatCache::get(Path, Data, isFile, FileDescriptor,
- StatCache.get());
+ StatCache.get(), *FS);
SmallString<128> FilePath(Path);
FixupRelativePath(FilePath);
return FileSystemStatCache::get(FilePath.c_str(), Data, isFile,
- FileDescriptor, StatCache.get());
+ FileDescriptor, StatCache.get(), *FS);
}
bool FileManager::getNoncachedStatValue(StringRef Path,
- llvm::sys::fs::file_status &Result) {
+ AbstractFileSystem::Status &Result) {
SmallString<128> FilePath(Path);
FixupRelativePath(FilePath);
- return llvm::sys::fs::status(FilePath.c_str(), Result);
+ return FS->status(FilePath.c_str(), Result);
}
void FileManager::invalidateCache(const FileEntry *Entry) {
Index: lib/Basic/FileSystemStatCache.cpp
===================================================================
--- lib/Basic/FileSystemStatCache.cpp
+++ lib/Basic/FileSystemStatCache.cpp
@@ -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,12 +30,12 @@
void FileSystemStatCache::anchor() { }
-static void copyStatusToFileData(const llvm::sys::fs::file_status &Status,
+static void copyStatusToFileData(const AbstractFileSystem::Status &Status,
FileData &Data) {
Data.Size = Status.getSize();
Data.ModTime = Status.getLastModificationTime().toEpochTime();
Data.UniqueID = Status.getUniqueID();
- Data.IsDirectory = is_directory(Status);
+ Data.IsDirectory = Status.is_directory();
Data.IsNamedPipe = Status.type() == llvm::sys::fs::file_type::fifo_file;
Data.InPCH = false;
}
@@ -50,18 +50,19 @@
/// 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) {
+ int *FileDescriptor, FileSystemStatCache *Cache,
+ AbstractFileSystem &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);
+ R = Cache->getStat(Path, Data, isFile, FileDescriptor, FS);
else if (isForDir || !FileDescriptor) {
// 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)) {
+ AbstractFileSystem::Status Status;
+ if (FS.status(Path, Status)) {
R = CacheMissing;
} else {
R = CacheExists;
@@ -75,17 +76,17 @@
//
// 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::error_code EC = FS.openFileForRead(Path, *FileDescriptor);
if (EC) {
// If the open fails, our "stat" fails.
R = CacheMissing;
} else {
// 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)) {
+ AbstractFileSystem::Status Status;
+ if (!FS.status(*FileDescriptor, Status)) {
R = CacheExists;
copyStatusToFileData(Status, Data);
} else {
@@ -118,8 +119,8 @@
MemorizeStatCalls::LookupResult
MemorizeStatCalls::getStat(const char *Path, FileData &Data, bool isFile,
- int *FileDescriptor) {
- LookupResult Result = statChained(Path, Data, isFile, FileDescriptor);
+ int *FileDescriptor, AbstractFileSystem &FS) {
+ LookupResult Result = statChained(Path, Data, isFile, FileDescriptor, 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
Index: lib/Basic/VirtualFileSystem.cpp
===================================================================
--- /dev/null
+++ lib/Basic/VirtualFileSystem.cpp
@@ -0,0 +1,229 @@
+//===- 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 llvm;
+using llvm::sys::fs::file_status;
+using llvm::sys::fs::file_type;
+using llvm::sys::fs::perms;
+using llvm::sys::fs::UniqueID;
+
+AbstractFileSystem::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()) {}
+
+AbstractFileSystem::Status::Status(StringRef Name, StringRef RealName,
+ UniqueID UID, sys::TimeValue MTime,
+ uint32_t User, uint32_t Group, uint64_t Size,
+ file_type Type, perms Perms)
+ : Name(Name), RealName(RealName), UID(UID), MTime(MTime), User(User),
+ Group(Group), Size(Size), Type(Type), Perms(Perms) {}
+
+bool AbstractFileSystem::Status::equivalent(
+ const AbstractFileSystem::Status &Other) const {
+ return getUniqueID() == Other.getUniqueID();
+}
+bool AbstractFileSystem::Status::is_directory() const {
+ return type() == file_type::directory_file;
+}
+bool AbstractFileSystem::Status::is_regular_file() const {
+ return type() == file_type::regular_file;
+}
+bool AbstractFileSystem::Status::is_other() const {
+ return type() == exists() && !is_regular_file() && !is_directory() &&
+ !is_symlink();
+}
+bool AbstractFileSystem::Status::is_symlink() const {
+ return type() == file_type::symlink_file;
+}
+bool AbstractFileSystem::Status::status_known() const {
+ return type() != file_type::status_error;
+}
+bool AbstractFileSystem::Status::exists() const {
+ return status_known() && type() != file_type::file_not_found;
+}
+
+AbstractFileSystem::~AbstractFileSystem() {}
+
+error_code AbstractFileSystem::exists(const Twine &Path, bool &Result) {
+ Status S;
+ if (error_code EC = status(Path, S))
+ return EC;
+ Result = S.exists();
+ return error_code::success();
+}
+
+error_code AbstractFileSystem::equivalent(const Twine &A, const Twine &B,
+ bool &Result) {
+ Status SA, SB;
+ if (error_code EC = status(A, SA))
+ return EC;
+ if (error_code EC = status(B, SB))
+ return EC;
+ Result = SA.equivalent(SB);
+ return error_code::success();
+}
+error_code AbstractFileSystem::is_directory(const Twine &Path, bool &Result) {
+ Status S;
+ if (error_code EC = status(Path, S))
+ return EC;
+ Result = S.is_directory();
+ return error_code::success();
+}
+error_code AbstractFileSystem::is_regular_file(const Twine &Path,
+ bool &Result) {
+ Status S;
+ if (error_code EC = status(Path, S))
+ return EC;
+ Result = S.is_regular_file();
+ return error_code::success();
+}
+error_code AbstractFileSystem::is_other(const llvm::Twine &Path, bool &Result) {
+ Status S;
+ if (error_code EC = status(Path, S))
+ return EC;
+ Result = S.is_other();
+ return error_code::success();
+}
+error_code AbstractFileSystem::is_symlink(const llvm::Twine &Path,
+ bool &Result) {
+ Status S;
+ if (error_code EC = status(Path, S))
+ return EC;
+ Result = S.is_symlink();
+ return error_code::success();
+}
+error_code AbstractFileSystem::file_size(const Twine &Path, uint64_t &Result) {
+ Status S;
+ if (error_code EC = status(Path, S))
+ return EC;
+ Result = S.getSize();
+ return error_code::success();
+}
+error_code AbstractFileSystem::status_known(const Twine &Path, bool &Result) {
+ Status S;
+ if (error_code EC = status(Path, S))
+ return EC;
+ Result = S.status_known();
+ return error_code::success();
+}
+error_code AbstractFileSystem::getUniqueID(const Twine &Path,
+ UniqueID &Result) {
+ Status S;
+ if (error_code EC = status(Path, S))
+ return EC;
+ Result = S.getUniqueID();
+ return error_code::success();
+}
+
+error_code AbstractFileSystem::status(AbstractFileSystem::FileDescriptor FD,
+ AbstractFileSystem::Status &Result) {
+ // FIXME: when we support virtual files, use information from the FD to lookup
+ // which AbstractFileSystem to perform this operation on.
+ return getRealFileSystem()->statusOfOpenFile(FD, Result);
+}
+
+error_code AbstractFileSystem::getBufferForFile(
+ FileDescriptor FD, const llvm::Twine &Name,
+ llvm::OwningPtr<llvm::MemoryBuffer> &Result, int64_t FileSize,
+ bool RequiresNullTerminator) {
+ // FIXME: when we support virtual files, use information from the FD to lookup
+ // which AbstractFileSystem to perform this operation on.
+ return getRealFileSystem()->getBufferForOpenFile(FD, Name, Result, FileSize,
+ RequiresNullTerminator);
+}
+
+error_code
+AbstractFileSystem::statusOfOpenFile(AbstractFileSystem::FileDescriptor FD,
+ AbstractFileSystem::Status &Result) {
+ llvm_unreachable("status for open file not provided");
+}
+
+error_code AbstractFileSystem::getBufferForOpenFile(
+ FileDescriptor FD, const llvm::Twine &Name,
+ llvm::OwningPtr<llvm::MemoryBuffer> &Result, int64_t FileSize,
+ bool RequiresNullTerminator) {
+ llvm_unreachable("get buffer for open file not provided");
+}
+
+//===-----------------------------------------------------------------------===/
+// RealFileSystem implementation
+//===-----------------------------------------------------------------------===/
+
+/// \brief The file system according to your operating system.
+class RealFileSystem : public AbstractFileSystem {
+public:
+ error_code status(const Twine &Path, Status &Result) LLVM_OVERRIDE;
+ error_code statusOfOpenFile(FileDescriptor FD, Status &Result) LLVM_OVERRIDE;
+ error_code openFileForRead(const Twine &Path,
+ FileDescriptor &ResultFD) LLVM_OVERRIDE;
+
+protected:
+ error_code getBufferForFile(const Twine &Name,
+ OwningPtr<MemoryBuffer> &Result,
+ int64_t FileSize = -1,
+ bool RequiresNullTerminator = true) LLVM_OVERRIDE;
+ error_code
+ getBufferForOpenFile(FileDescriptor FD, const Twine &Name,
+ OwningPtr<MemoryBuffer> &Result, int64_t FileSize = -1,
+ bool RequiresNullTerminator = true) LLVM_OVERRIDE;
+};
+
+IntrusiveRefCntPtr<AbstractFileSystem> clang::getRealFileSystem() {
+ static IntrusiveRefCntPtr<AbstractFileSystem> FS = new RealFileSystem();
+ return FS;
+}
+
+error_code RealFileSystem::status(const Twine &Path,
+ AbstractFileSystem::Status &Result) {
+ sys::fs::file_status RealStatus;
+ error_code EC = sys::fs::status(Path, RealStatus);
+ Result = AbstractFileSystem::Status(RealStatus);
+ Result.setName(Path.str());
+ Result.setRealName(Path.str());
+ return EC;
+}
+
+error_code
+RealFileSystem::statusOfOpenFile(AbstractFileSystem::FileDescriptor FD,
+ AbstractFileSystem::Status &Result) {
+ sys::fs::file_status RealStatus;
+ error_code EC = sys::fs::status(FD, RealStatus);
+ Result = AbstractFileSystem::Status(RealStatus);
+ return EC;
+}
+
+error_code
+RealFileSystem::openFileForRead(const Twine &Name,
+ AbstractFileSystem::FileDescriptor &ResultFD) {
+ return llvm::sys::fs::openFileForRead(Name, ResultFD);
+}
+
+error_code RealFileSystem::getBufferForFile(const Twine &Name,
+ OwningPtr<MemoryBuffer> &Result,
+ int64_t FileSize,
+ bool RequiresNullTerminator) {
+ return MemoryBuffer::getFile(Name, Result, FileSize, RequiresNullTerminator);
+}
+error_code RealFileSystem::getBufferForOpenFile(
+ AbstractFileSystem::FileDescriptor FD, const Twine &Name,
+ OwningPtr<MemoryBuffer> &Result, int64_t FileSize,
+ bool RequiresNullTerminator) {
+ return MemoryBuffer::getOpenFile(FD, Name.str().c_str(), Result, FileSize,
+ RequiresNullTerminator);
+}
Index: lib/Frontend/ASTUnit.cpp
===================================================================
--- lib/Frontend/ASTUnit.cpp
+++ lib/Frontend/ASTUnit.cpp
@@ -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"
@@ -1463,7 +1463,7 @@
REnd = PreprocessorOpts.remapped_file_end();
!AnyFileChanged && R != REnd;
++R) {
- llvm::sys::fs::file_status Status;
+ AbstractFileSystem::Status Status;
if (FileMgr->getNoncachedStatValue(R->second, Status)) {
// If we can't stat the file we're remapping to, assume that something
// horrible happened.
@@ -1499,7 +1499,7 @@
}
// The file was not remapped; check whether it has changed on disk.
- llvm::sys::fs::file_status Status;
+ AbstractFileSystem::Status Status;
if (FileMgr->getNoncachedStatValue(F->first(), Status)) {
// If we can't stat the file, assume that something horrible happened.
AnyFileChanged = true;
Index: lib/Frontend/CacheTokens.cpp
===================================================================
--- lib/Frontend/CacheTokens.cpp
+++ lib/Frontend/CacheTokens.cpp
@@ -516,8 +516,8 @@
~StatListener() {}
LookupResult getStat(const char *Path, FileData &Data, bool isFile,
- int *FileDescriptor) {
- LookupResult Result = statChained(Path, Data, isFile, FileDescriptor);
+ int *FileDescriptor, AbstractFileSystem &FS) {
+ LookupResult Result = statChained(Path, Data, isFile, FileDescriptor, FS);
if (Result == CacheMissing) // Failed 'stat'.
PM.insert(PTHEntryKeyVariant(Path), PTHEntry());
Index: lib/Frontend/ChainedIncludesSource.cpp
===================================================================
--- lib/Frontend/ChainedIncludesSource.cpp
+++ lib/Frontend/ChainedIncludesSource.cpp
@@ -101,6 +101,7 @@
Clang->setDiagnostics(Diags.getPtr());
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
&Clang->getTargetOpts()));
+ Clang->createVirtualFileSystem();
Clang->createFileManager();
Clang->createSourceManager(Clang->getFileManager());
Clang->createPreprocessor();
Index: lib/Frontend/CompilerInstance.cpp
===================================================================
--- lib/Frontend/CompilerInstance.cpp
+++ lib/Frontend/CompilerInstance.cpp
@@ -194,9 +194,14 @@
return Diags;
}
+void CompilerInstance::createVirtualFileSystem() {
+ VirtualFileSystem = getRealFileSystem();
+}
+
// File Manager
void CompilerInstance::createFileManager() {
+ assert(hasVirtualFileSystem() && "expected virtual file system");
FileMgr = new FileManager(getFileSystemOpts());
}
@@ -867,6 +872,8 @@
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?
Index: lib/Frontend/FrontendAction.cpp
===================================================================
--- lib/Frontend/FrontendAction.cpp
+++ lib/Frontend/FrontendAction.cpp
@@ -159,7 +159,6 @@
return new MultiplexConsumer(Consumers);
}
-
bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
const FrontendInputFile &Input) {
assert(!Instance && "Already processing a source file!");
@@ -213,6 +212,8 @@
}
// Set up the file and source managers, if needed.
+ if (!CI.hasVirtualFileSystem())
+ CI.createVirtualFileSystem();
if (!CI.hasFileManager())
CI.createFileManager();
if (!CI.hasSourceManager())
Index: lib/Lex/PTHLexer.cpp
===================================================================
--- lib/Lex/PTHLexer.cpp
+++ lib/Lex/PTHLexer.cpp
@@ -675,13 +675,13 @@
~PTHStatCache() {}
LookupResult getStat(const char *Path, FileData &Data, bool isFile,
- int *FileDescriptor) {
+ int *FileDescriptor, AbstractFileSystem &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, FileDescriptor, FS);
const PTHStatData &D = *I;
Index: unittests/Basic/FileManagerTest.cpp
===================================================================
--- unittests/Basic/FileManagerTest.cpp
+++ unittests/Basic/FileManagerTest.cpp
@@ -48,7 +48,7 @@
// Implement FileSystemStatCache::getStat().
virtual LookupResult getStat(const char *Path, FileData &Data, bool isFile,
- int *FileDescriptor) {
+ int *FileDescriptor, AbstractFileSystem &FS) {
if (StatCalls.count(Path) != 0) {
Data = StatCalls[Path];
return CacheExists;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits