Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 91e3d58

Browse files
committed
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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@201618 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 0003db2 commit 91e3d58

16 files changed

+423
-107
lines changed

Diff for: include/clang/Basic/FileManager.h

+19-15
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@
1717

1818
#include "clang/Basic/FileSystemOptions.h"
1919
#include "clang/Basic/LLVM.h"
20+
#include "clang/Basic/VirtualFileSystem.h"
2021
#include "llvm/ADT/DenseMap.h"
2122
#include "llvm/ADT/IntrusiveRefCntPtr.h"
2223
#include "llvm/ADT/OwningPtr.h"
2324
#include "llvm/ADT/SmallVector.h"
2425
#include "llvm/ADT/StringMap.h"
2526
#include "llvm/ADT/StringRef.h"
2627
#include "llvm/Support/Allocator.h"
27-
#include "llvm/Support/FileSystem.h"
2828
// FIXME: Enhance libsystem to support inode and other fields in stat.
2929
#include <sys/types.h>
3030

@@ -55,7 +55,7 @@ class DirectoryEntry {
5555
/// \brief Cached information about one file (either on disk
5656
/// or in the virtual file system).
5757
///
58-
/// If the 'FD' member is valid, then this FileEntry has an open file
58+
/// If the 'File' member is valid, then this FileEntry has an open file
5959
/// descriptor for the file.
6060
class FileEntry {
6161
const char *Name; // Name of the file.
@@ -67,31 +67,33 @@ class FileEntry {
6767
bool IsNamedPipe;
6868
bool InPCH;
6969

70-
/// FD - The file descriptor for the file entry if it is opened and owned
71-
/// by the FileEntry. If not, this is set to -1.
72-
mutable int FD;
70+
/// \brief The open file, if it is owned by the \p FileEntry.
71+
mutable OwningPtr<vfs::File> File;
7372
friend class FileManager;
7473

74+
void closeFile() const {
75+
File.reset(0); // rely on destructor to close File
76+
}
77+
7578
public:
7679
FileEntry(llvm::sys::fs::UniqueID UniqueID, bool IsNamedPipe, bool InPCH)
77-
: Name(0), UniqueID(UniqueID), IsNamedPipe(IsNamedPipe), InPCH(InPCH),
78-
FD(-1) {}
80+
: Name(0), UniqueID(UniqueID), IsNamedPipe(IsNamedPipe), InPCH(InPCH)
81+
{}
7982
// Add a default constructor for use with llvm::StringMap
8083
FileEntry()
81-
: Name(0), UniqueID(0, 0), IsNamedPipe(false), InPCH(false), FD(-1) {}
84+
: Name(0), UniqueID(0, 0), IsNamedPipe(false), InPCH(false)
85+
{}
8286

8387
FileEntry(const FileEntry &FE) {
8488
memcpy(this, &FE, sizeof(FE));
85-
assert(FD == -1 && "Cannot copy a file-owning FileEntry");
89+
assert(!File && "Cannot copy a file-owning FileEntry");
8690
}
8791

8892
void operator=(const FileEntry &FE) {
8993
memcpy(this, &FE, sizeof(FE));
90-
assert(FD == -1 && "Cannot assign a file-owning FileEntry");
94+
assert(!File && "Cannot assign a file-owning FileEntry");
9195
}
9296

93-
~FileEntry();
94-
9597
const char *getName() const { return Name; }
9698
off_t getSize() const { return Size; }
9799
unsigned getUID() const { return UID; }
@@ -119,6 +121,7 @@ struct FileData;
119121
/// as a single file.
120122
///
121123
class FileManager : public RefCountedBase<FileManager> {
124+
IntrusiveRefCntPtr<vfs::FileSystem> FS;
122125
FileSystemOptions FileSystemOpts;
123126

124127
class UniqueDirContainer;
@@ -172,14 +175,15 @@ class FileManager : public RefCountedBase<FileManager> {
172175
OwningPtr<FileSystemStatCache> StatCache;
173176

174177
bool getStatValue(const char *Path, FileData &Data, bool isFile,
175-
int *FileDescriptor);
178+
vfs::File **F);
176179

177180
/// Add all ancestors of the given path (pointing to either a file
178181
/// or a directory) as virtual directories.
179182
void addAncestorsAsVirtualDirs(StringRef Path);
180183

181184
public:
182-
FileManager(const FileSystemOptions &FileSystemOpts);
185+
FileManager(const FileSystemOptions &FileSystemOpts,
186+
llvm::IntrusiveRefCntPtr<vfs::FileSystem> FS = 0);
183187
~FileManager();
184188

185189
/// \brief Installs the provided FileSystemStatCache object within
@@ -248,7 +252,7 @@ class FileManager : public RefCountedBase<FileManager> {
248252
///
249253
/// \returns false on success, true on error.
250254
bool getNoncachedStatValue(StringRef Path,
251-
llvm::sys::fs::file_status &Result);
255+
vfs::Status &Result);
252256

253257
/// \brief Remove the real file \p Entry from the cache.
254258
void invalidateCache(const FileEntry *Entry);

Diff for: include/clang/Basic/FileSystemStatCache.h

+14-9
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@
2424

2525
namespace clang {
2626

27+
namespace vfs {
28+
class File;
29+
class FileSystem;
30+
}
31+
2732
struct FileData {
2833
uint64_t Size;
2934
time_t ModTime;
@@ -57,10 +62,11 @@ class FileSystemStatCache {
5762
/// If isFile is true, then this lookup should only return success for files
5863
/// (not directories). If it is false this lookup should only return
5964
/// success for directories (not files). On a successful file lookup, the
60-
/// implementation can optionally fill in FileDescriptor with a valid
61-
/// descriptor and the client guarantees that it will close it.
65+
/// implementation can optionally fill in \p F with a valid \p File object and
66+
/// the client guarantees that it will close it.
6267
static bool get(const char *Path, FileData &Data, bool isFile,
63-
int *FileDescriptor, FileSystemStatCache *Cache);
68+
vfs::File **F, FileSystemStatCache *Cache,
69+
vfs::FileSystem &FS);
6470

6571
/// \brief Sets the next stat call cache in the chain of stat caches.
6672
/// Takes ownership of the given stat cache.
@@ -78,17 +84,16 @@ class FileSystemStatCache {
7884

7985
protected:
8086
virtual LookupResult getStat(const char *Path, FileData &Data, bool isFile,
81-
int *FileDescriptor) = 0;
87+
vfs::File **F, vfs::FileSystem &FS) = 0;
8288

8389
LookupResult statChained(const char *Path, FileData &Data, bool isFile,
84-
int *FileDescriptor) {
90+
vfs::File **F, vfs::FileSystem &FS) {
8591
if (FileSystemStatCache *Next = getNextStatCache())
86-
return Next->getStat(Path, Data, isFile, FileDescriptor);
92+
return Next->getStat(Path, Data, isFile, F, FS);
8793

8894
// If we hit the end of the list of stat caches to try, just compute and
8995
// return it without a cache.
90-
return get(Path, Data, isFile, FileDescriptor, 0) ? CacheMissing
91-
: CacheExists;
96+
return get(Path, Data, isFile, F, 0, FS) ? CacheMissing : CacheExists;
9297
}
9398
};
9499

@@ -107,7 +112,7 @@ class MemorizeStatCalls : public FileSystemStatCache {
107112
iterator end() const { return StatCalls.end(); }
108113

109114
virtual LookupResult getStat(const char *Path, FileData &Data, bool isFile,
110-
int *FileDescriptor);
115+
vfs::File **F, vfs::FileSystem &FS);
111116
};
112117

113118
} // end namespace clang

Diff for: include/clang/Basic/VirtualFileSystem.h

+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
//===- VirtualFileSystem.h - Virtual File System Layer ----------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
/// \file
10+
/// \brief Defines the virtual file system interface vfs::FileSystem.
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_CLANG_BASIC_VIRTUAL_FILE_SYSTEM_H
14+
#define LLVM_CLANG_BASIC_VIRTUAL_FILE_SYSTEM_H
15+
16+
#include "llvm/ADT/IntrusiveRefCntPtr.h"
17+
#include "llvm/Support/FileSystem.h"
18+
#include "llvm/Support/ErrorOr.h"
19+
20+
namespace llvm {
21+
template <typename T> class OwningPtr;
22+
class MemoryBuffer;
23+
}
24+
25+
namespace clang {
26+
namespace vfs {
27+
28+
/// \brief The result of a \p status operation.
29+
class Status {
30+
std::string Name;
31+
std::string ExternalName;
32+
llvm::sys::fs::UniqueID UID;
33+
llvm::sys::TimeValue MTime;
34+
uint32_t User;
35+
uint32_t Group;
36+
uint64_t Size;
37+
llvm::sys::fs::file_type Type;
38+
llvm::sys::fs::perms Perms;
39+
40+
public:
41+
Status() : Type(llvm::sys::fs::file_type::status_error) {}
42+
Status(const llvm::sys::fs::file_status &Status);
43+
Status(llvm::StringRef Name, llvm::StringRef RealName,
44+
llvm::sys::fs::UniqueID UID, llvm::sys::TimeValue MTime,
45+
uint32_t User, uint32_t Group, uint64_t Size,
46+
llvm::sys::fs::file_type Type, llvm::sys::fs::perms Perms);
47+
48+
/// \brief Returns the name this status was looked up by.
49+
llvm::StringRef getName() const { return Name; }
50+
51+
/// \brief Returns the name to use outside the compiler.
52+
///
53+
/// For example, in diagnostics or debug info we should use this name.
54+
llvm::StringRef getExternalName() const { return ExternalName; }
55+
56+
void setName(llvm::StringRef N) { Name = N; }
57+
void setExternalName(llvm::StringRef N) { ExternalName = N; }
58+
59+
/// @name Status interface from llvm::sys::fs
60+
/// @{
61+
llvm::sys::fs::file_type getType() const { return Type; }
62+
llvm::sys::fs::perms getPermissions() const { return Perms; }
63+
llvm::sys::TimeValue getLastModificationTime() const { return MTime; }
64+
llvm::sys::fs::UniqueID getUniqueID() const { return UID; }
65+
uint32_t getUser() const { return User; }
66+
uint32_t getGroup() const { return Group; }
67+
uint64_t getSize() const { return Size; }
68+
void setType(llvm::sys::fs::file_type v) { Type = v; }
69+
void setPermissions(llvm::sys::fs::perms p) { Perms = p; }
70+
/// @}
71+
/// @name Status queries
72+
/// These are static queries in llvm::sys::fs.
73+
/// @{
74+
bool equivalent(const Status &Other) const;
75+
bool isDirectory() const;
76+
bool isRegularFile() const;
77+
bool isOther() const;
78+
bool isSymlink() const;
79+
bool isStatusKnown() const;
80+
bool exists() const;
81+
/// @}
82+
};
83+
84+
/// \brief Represents an open file.
85+
class File {
86+
public:
87+
/// \brief Destroy the file after closing it (if open).
88+
/// Sub-classes should generally call close() inside their destructors. We
89+
/// cannot do that from the base class, since close is virtual.
90+
virtual ~File();
91+
/// \brief Get the status of the file.
92+
virtual llvm::ErrorOr<Status> status() = 0;
93+
/// \brief Get the contents of the file as a \p MemoryBuffer.
94+
virtual llvm::error_code
95+
getBuffer(const llvm::Twine &Name,
96+
llvm::OwningPtr<llvm::MemoryBuffer> &Result, int64_t FileSize = -1,
97+
bool RequiresNullTerminator = true) = 0;
98+
/// \brief Closes the file.
99+
virtual llvm::error_code close() = 0;
100+
};
101+
102+
/// \brief The virtual file system interface.
103+
class FileSystem : public llvm::RefCountedBase<FileSystem> {
104+
public:
105+
virtual ~FileSystem();
106+
107+
/// \brief Get the status of the entry at \p Path, if one exists.
108+
virtual llvm::ErrorOr<Status> status(const llvm::Twine &Path) = 0;
109+
/// \brief Get a \p File object for the file at \p Path, if one exists.
110+
virtual llvm::error_code openFileForRead(const llvm::Twine &Path,
111+
llvm::OwningPtr<File> &Result) = 0;
112+
113+
/// This is a convenience method that opens a file, gets its content and then
114+
/// closes the file.
115+
llvm::error_code getBufferForFile(const llvm::Twine &Name,
116+
llvm::OwningPtr<llvm::MemoryBuffer> &Result,
117+
int64_t FileSize = -1,
118+
bool RequiresNullTerminator = true);
119+
};
120+
121+
/// \brief Gets an \p vfs::FileSystem for the 'real' file system, as seen by
122+
/// the operating system.
123+
llvm::IntrusiveRefCntPtr<FileSystem> getRealFileSystem();
124+
125+
} // end namespace vfs
126+
} // end namespace clang
127+
#endif // LLVM_CLANG_BASIC_VIRTUAL_FILE_SYSTEM_H

Diff for: include/clang/Frontend/CompilerInstance.h

+24
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ class CompilerInstance : public ModuleLoader {
7575
/// The target being compiled for.
7676
IntrusiveRefCntPtr<TargetInfo> Target;
7777

78+
/// The virtual file system.
79+
IntrusiveRefCntPtr<vfs::FileSystem> VirtualFileSystem;
80+
7881
/// The file manager.
7982
IntrusiveRefCntPtr<FileManager> FileMgr;
8083

@@ -313,6 +316,23 @@ class CompilerInstance : public ModuleLoader {
313316
/// Replace the current diagnostics engine.
314317
void setTarget(TargetInfo *Value);
315318

319+
/// }
320+
/// @name Virtual File System
321+
/// {
322+
323+
bool hasVirtualFileSystem() const { return VirtualFileSystem != 0; }
324+
325+
vfs::FileSystem &getVirtualFileSystem() const {
326+
assert(hasVirtualFileSystem() &&
327+
"Compiler instance has no virtual file system");
328+
return *VirtualFileSystem;
329+
}
330+
331+
/// \brief Replace the current virtual file system.
332+
void setVirtualFileSystem(IntrusiveRefCntPtr<vfs::FileSystem> FS) {
333+
VirtualFileSystem = FS;
334+
}
335+
316336
/// }
317337
/// @name File Manager
318338
/// {
@@ -527,6 +547,10 @@ class CompilerInstance : public ModuleLoader {
527547
bool ShouldOwnClient = true,
528548
const CodeGenOptions *CodeGenOpts = 0);
529549

550+
/// Create a virtual file system and replace any existing one with it.
551+
/// The default is to use the real file system.
552+
void createVirtualFileSystem();
553+
530554
/// Create the file manager and replace any existing one with it.
531555
void createFileManager();
532556

Diff for: lib/Basic/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ add_clang_library(clangBasic
2323
TokenKinds.cpp
2424
Version.cpp
2525
VersionTuple.cpp
26+
VirtualFileSystem.cpp
2627
)
2728

2829
# Determine Subversion revision.

0 commit comments

Comments
 (0)