clang  3.8.0
VirtualFileSystem.h
Go to the documentation of this file.
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_VIRTUALFILESYSTEM_H
14 #define LLVM_CLANG_BASIC_VIRTUALFILESYSTEM_H
15 
16 #include "clang/Basic/LLVM.h"
17 #include "llvm/ADT/IntrusiveRefCntPtr.h"
18 #include "llvm/ADT/Optional.h"
19 #include "llvm/Support/ErrorOr.h"
20 #include "llvm/Support/FileSystem.h"
21 #include "llvm/Support/SourceMgr.h"
22 #include "llvm/Support/raw_ostream.h"
23 
24 namespace llvm {
25 class MemoryBuffer;
26 }
27 
28 namespace clang {
29 namespace vfs {
30 
31 /// \brief The result of a \p status operation.
32 class Status {
33  std::string Name;
34  llvm::sys::fs::UniqueID UID;
35  llvm::sys::TimeValue MTime;
36  uint32_t User;
37  uint32_t Group;
38  uint64_t Size;
39  llvm::sys::fs::file_type Type;
40  llvm::sys::fs::perms Perms;
41 
42 public:
43  bool IsVFSMapped; // FIXME: remove when files support multiple names
44 
45 public:
46  Status() : Type(llvm::sys::fs::file_type::status_error) {}
47  Status(const llvm::sys::fs::file_status &Status);
48  Status(StringRef Name, llvm::sys::fs::UniqueID UID,
49  llvm::sys::TimeValue MTime, uint32_t User, uint32_t Group,
50  uint64_t Size, llvm::sys::fs::file_type Type,
51  llvm::sys::fs::perms Perms);
52 
53  /// Get a copy of a Status with a different name.
54  static Status copyWithNewName(const Status &In, StringRef NewName);
55  static Status copyWithNewName(const llvm::sys::fs::file_status &In,
56  StringRef NewName);
57 
58  /// \brief Returns the name that should be used for this file or directory.
59  StringRef getName() const { return Name; }
60 
61  /// @name Status interface from llvm::sys::fs
62  /// @{
63  llvm::sys::fs::file_type getType() const { return Type; }
64  llvm::sys::fs::perms getPermissions() const { return Perms; }
65  llvm::sys::TimeValue getLastModificationTime() const { return MTime; }
66  llvm::sys::fs::UniqueID getUniqueID() const { return UID; }
67  uint32_t getUser() const { return User; }
68  uint32_t getGroup() const { return Group; }
69  uint64_t getSize() const { return Size; }
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::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
95  getBuffer(const Twine &Name, int64_t FileSize = -1,
96  bool RequiresNullTerminator = true, bool IsVolatile = false) = 0;
97  /// \brief Closes the file.
98  virtual std::error_code close() = 0;
99 };
100 
101 namespace detail {
102 /// \brief An interface for virtual file systems to provide an iterator over the
103 /// (non-recursive) contents of a directory.
104 struct DirIterImpl {
105  virtual ~DirIterImpl();
106  /// \brief Sets \c CurrentEntry to the next entry in the directory on success,
107  /// or returns a system-defined \c error_code.
108  virtual std::error_code increment() = 0;
110 };
111 } // end namespace detail
112 
113 /// \brief An input iterator over the entries in a virtual path, similar to
114 /// llvm::sys::fs::directory_iterator.
116  std::shared_ptr<detail::DirIterImpl> Impl; // Input iterator semantics on copy
117 
118 public:
119  directory_iterator(std::shared_ptr<detail::DirIterImpl> I) : Impl(I) {
120  assert(Impl.get() != nullptr && "requires non-null implementation");
121  if (!Impl->CurrentEntry.isStatusKnown())
122  Impl.reset(); // Normalize the end iterator to Impl == nullptr.
123  }
124 
125  /// \brief Construct an 'end' iterator.
127 
128  /// \brief Equivalent to operator++, with an error code.
129  directory_iterator &increment(std::error_code &EC) {
130  assert(Impl && "attempting to increment past end");
131  EC = Impl->increment();
132  if (EC || !Impl->CurrentEntry.isStatusKnown())
133  Impl.reset(); // Normalize the end iterator to Impl == nullptr.
134  return *this;
135  }
136 
137  const Status &operator*() const { return Impl->CurrentEntry; }
138  const Status *operator->() const { return &Impl->CurrentEntry; }
139 
140  bool operator==(const directory_iterator &RHS) const {
141  if (Impl && RHS.Impl)
142  return Impl->CurrentEntry.equivalent(RHS.Impl->CurrentEntry);
143  return !Impl && !RHS.Impl;
144  }
145  bool operator!=(const directory_iterator &RHS) const {
146  return !(*this == RHS);
147  }
148 };
149 
150 class FileSystem;
151 
152 /// \brief An input iterator over the recursive contents of a virtual path,
153 /// similar to llvm::sys::fs::recursive_directory_iterator.
155  typedef std::stack<directory_iterator, std::vector<directory_iterator>>
156  IterState;
157 
158  FileSystem *FS;
159  std::shared_ptr<IterState> State; // Input iterator semantics on copy.
160 
161 public:
162  recursive_directory_iterator(FileSystem &FS, const Twine &Path,
163  std::error_code &EC);
164  /// \brief Construct an 'end' iterator.
166 
167  /// \brief Equivalent to operator++, with an error code.
168  recursive_directory_iterator &increment(std::error_code &EC);
169 
170  const Status &operator*() const { return *State->top(); }
171  const Status *operator->() const { return &*State->top(); }
172 
173  bool operator==(const recursive_directory_iterator &Other) const {
174  return State == Other.State; // identity
175  }
176  bool operator!=(const recursive_directory_iterator &RHS) const {
177  return !(*this == RHS);
178  }
179 };
180 
181 /// \brief The virtual file system interface.
182 class FileSystem : public llvm::ThreadSafeRefCountedBase<FileSystem> {
183 public:
184  virtual ~FileSystem();
185 
186  /// \brief Get the status of the entry at \p Path, if one exists.
187  virtual llvm::ErrorOr<Status> status(const Twine &Path) = 0;
188  /// \brief Get a \p File object for the file at \p Path, if one exists.
189  virtual llvm::ErrorOr<std::unique_ptr<File>>
190  openFileForRead(const Twine &Path) = 0;
191 
192  /// This is a convenience method that opens a file, gets its content and then
193  /// closes the file.
194  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
195  getBufferForFile(const Twine &Name, int64_t FileSize = -1,
196  bool RequiresNullTerminator = true, bool IsVolatile = false);
197 
198  /// \brief Get a directory_iterator for \p Dir.
199  /// \note The 'end' iterator is directory_iterator().
200  virtual directory_iterator dir_begin(const Twine &Dir,
201  std::error_code &EC) = 0;
202 
203  /// Set the working directory. This will affect all following operations on
204  /// this file system and may propagate down for nested file systems.
205  virtual std::error_code setCurrentWorkingDirectory(const Twine &Path) = 0;
206  /// Get the working directory of this file system.
207  virtual llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const = 0;
208 
209  /// Check whether a file exists. Provided for convenience.
210  bool exists(const Twine &Path);
211 
212  /// Make \a Path an absolute path.
213  ///
214  /// Makes \a Path absolute using the current directory if it is not already.
215  /// An empty \a Path will result in the current directory.
216  ///
217  /// /absolute/path => /absolute/path
218  /// relative/../path => <current-directory>/relative/../path
219  ///
220  /// \param Path A path that is modified to be an absolute path.
221  /// \returns success if \a path has been made absolute, otherwise a
222  /// platform-specific error_code.
223  std::error_code makeAbsolute(SmallVectorImpl<char> &Path) const;
224 };
225 
226 /// \brief Gets an \p vfs::FileSystem for the 'real' file system, as seen by
227 /// the operating system.
229 
230 /// \brief A file system that allows overlaying one \p AbstractFileSystem on top
231 /// of another.
232 ///
233 /// Consists of a stack of >=1 \p FileSystem objects, which are treated as being
234 /// one merged file system. When there is a directory that exists in more than
235 /// one file system, the \p OverlayFileSystem contains a directory containing
236 /// the union of their contents. The attributes (permissions, etc.) of the
237 /// top-most (most recently added) directory are used. When there is a file
238 /// that exists in more than one file system, the file in the top-most file
239 /// system overrides the other(s).
242  /// \brief The stack of file systems, implemented as a list in order of
243  /// their addition.
244  FileSystemList FSList;
245 
246 public:
248  /// \brief Pushes a file system on top of the stack.
250 
251  llvm::ErrorOr<Status> status(const Twine &Path) override;
252  llvm::ErrorOr<std::unique_ptr<File>>
253  openFileForRead(const Twine &Path) override;
254  directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
255  llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override;
256  std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
257 
258  typedef FileSystemList::reverse_iterator iterator;
259 
260  /// \brief Get an iterator pointing to the most recently added file system.
261  iterator overlays_begin() { return FSList.rbegin(); }
262 
263  /// \brief Get an iterator pointing one-past the least recently added file
264  /// system.
265  iterator overlays_end() { return FSList.rend(); }
266 };
267 
268 namespace detail {
269 class InMemoryDirectory;
270 } // end namespace detail
271 
272 /// An in-memory file system.
274  std::unique_ptr<detail::InMemoryDirectory> Root;
275  std::string WorkingDirectory;
276  bool UseNormalizedPaths = true;
277 
278 public:
279  explicit InMemoryFileSystem(bool UseNormalizedPaths = true);
280  ~InMemoryFileSystem() override;
281  /// Add a buffer to the VFS with a path. The VFS owns the buffer.
282  /// \return true if the file was successfully added, false if the file already
283  /// exists in the file system with different contents.
284  bool addFile(const Twine &Path, time_t ModificationTime,
285  std::unique_ptr<llvm::MemoryBuffer> Buffer);
286  /// Add a buffer to the VFS with a path. The VFS does not own the buffer.
287  /// \return true if the file was successfully added, false if the file already
288  /// exists in the file system with different contents.
289  bool addFileNoOwn(const Twine &Path, time_t ModificationTime,
290  llvm::MemoryBuffer *Buffer);
291  std::string toString() const;
292  /// Return true if this file system normalizes . and .. in paths.
293  bool useNormalizedPaths() const { return UseNormalizedPaths; }
294 
295  llvm::ErrorOr<Status> status(const Twine &Path) override;
296  llvm::ErrorOr<std::unique_ptr<File>>
297  openFileForRead(const Twine &Path) override;
298  directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
299  llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
300  return WorkingDirectory;
301  }
302  std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
303 };
304 
305 /// \brief Get a globally unique ID for a virtual file or directory.
306 llvm::sys::fs::UniqueID getNextVirtualUniqueID();
307 
308 /// \brief Gets a \p FileSystem for a virtual file system described in YAML
309 /// format.
311 getVFSFromYAML(std::unique_ptr<llvm::MemoryBuffer> Buffer,
312  llvm::SourceMgr::DiagHandlerTy DiagHandler,
313  void *DiagContext = nullptr,
315 
316 struct YAMLVFSEntry {
317  template <typename T1, typename T2> YAMLVFSEntry(T1 &&VPath, T2 &&RPath)
318  : VPath(std::forward<T1>(VPath)), RPath(std::forward<T2>(RPath)) {}
319  std::string VPath;
320  std::string RPath;
321 };
322 
324  std::vector<YAMLVFSEntry> Mappings;
325  Optional<bool> IsCaseSensitive;
326 
327 public:
329  void addFileMapping(StringRef VirtualPath, StringRef RealPath);
330  void setCaseSensitivity(bool CaseSensitive) {
331  IsCaseSensitive = CaseSensitive;
332  }
333  void write(llvm::raw_ostream &OS);
334 };
335 
336 } // end namespace vfs
337 } // end namespace clang
338 #endif
bool addFile(const Twine &Path, time_t ModificationTime, std::unique_ptr< llvm::MemoryBuffer > Buffer)
Add a buffer to the VFS with a path.
const Status * operator->() const
IntrusiveRefCntPtr< FileSystem > getRealFileSystem()
Gets an vfs::FileSystem for the 'real' file system, as seen by the operating system.
virtual llvm::ErrorOr< Status > status()=0
Get the status of the file.
The base class of the type hierarchy.
Definition: Type.h:1249
bool equivalent(const Status &Other) const
std::unique_ptr< llvm::MemoryBuffer > Buffer
bool isStatusKnown() const
uint32_t getUser() const
llvm::sys::TimeValue getLastModificationTime() const
virtual llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getBuffer(const Twine &Name, int64_t FileSize=-1, bool RequiresNullTerminator=true, bool IsVolatile=false)=0
Get the contents of the file as a MemoryBuffer.
virtual llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path)=0
Get a File object for the file at Path, if one exists.
virtual directory_iterator dir_begin(const Twine &Dir, std::error_code &EC)=0
Get a directory_iterator for Dir.
bool useNormalizedPaths() const
Return true if this file system normalizes . and .. in paths.
The virtual file system interface.
llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override
Get the working directory of this file system.
IntrusiveRefCntPtr< FileSystem > getVFSFromYAML(std::unique_ptr< llvm::MemoryBuffer > Buffer, llvm::SourceMgr::DiagHandlerTy DiagHandler, void *DiagContext=nullptr, IntrusiveRefCntPtr< FileSystem > ExternalFS=getRealFileSystem())
Gets a FileSystem for a virtual file system described in YAML format.
class LLVM_ALIGNAS(8) DependentTemplateSpecializationType const IdentifierInfo * Name
Represents a template specialization type whose template cannot be resolved, e.g. ...
Definition: Type.h:4381
void write(llvm::raw_ostream &OS)
virtual std::error_code close()=0
Closes the file.
An input iterator over the recursive contents of a virtual path, similar to llvm::sys::fs::recursive_...
directory_iterator(std::shared_ptr< detail::DirIterImpl > I)
An in-memory file system.
directory_iterator()
Construct an 'end' iterator.
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override
Get a directory_iterator for Dir.
bool addFileNoOwn(const Twine &Path, time_t ModificationTime, llvm::MemoryBuffer *Buffer)
Add a buffer to the VFS with a path.
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override
Get a directory_iterator for Dir.
A file system that allows overlaying one AbstractFileSystem on top of another.
virtual llvm::ErrorOr< Status > status(const Twine &Path)=0
Get the status of the entry at Path, if one exists.
directory_iterator & increment(std::error_code &EC)
Equivalent to operator++, with an error code.
llvm::sys::fs::file_type getType() const
void addFileMapping(StringRef VirtualPath, StringRef RealPath)
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
bool operator!=(const recursive_directory_iterator &RHS) const
FileSystemList::reverse_iterator iterator
llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override
Get a File object for the file at Path, if one exists.
The result of a status operation.
void pushOverlay(IntrusiveRefCntPtr< FileSystem > FS)
Pushes a file system on top of the stack.
detail::InMemoryDirectory::const_iterator I
recursive_directory_iterator()
Construct an 'end' iterator.
virtual std::error_code setCurrentWorkingDirectory(const Twine &Path)=0
Set the working directory.
llvm::sys::fs::UniqueID getUniqueID() const
virtual llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const =0
Get the working directory of this file system.
static Status copyWithNewName(const Status &In, StringRef NewName)
Get a copy of a Status with a different name.
iterator overlays_end()
Get an iterator pointing one-past the least recently added file system.
uint64_t getSize() const
Represents an open file.
void setCaseSensitivity(bool CaseSensitive)
llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override
Get the working directory of this file system.
InMemoryFileSystem(bool UseNormalizedPaths=true)
recursive_directory_iterator & increment(std::error_code &EC)
Equivalent to operator++, with an error code.
bool operator!=(const directory_iterator &RHS) const
llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override
Get a File object for the file at Path, if one exists.
uint32_t getGroup() const
iterator overlays_begin()
Get an iterator pointing to the most recently added file system.
bool isDirectory() const
YAMLVFSEntry(T1 &&VPath, T2 &&RPath)
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
Set the working directory.
bool isRegularFile() const
bool operator==(const directory_iterator &RHS) const
llvm::sys::fs::perms getPermissions() const
OverlayFileSystem(IntrusiveRefCntPtr< FileSystem > Base)
llvm::sys::fs::UniqueID getNextVirtualUniqueID()
Get a globally unique ID for a virtual file or directory.
const Status & operator*() const
bool exists(const Twine &Path)
Check whether a file exists. Provided for convenience.
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getBufferForFile(const Twine &Name, int64_t FileSize=-1, bool RequiresNullTerminator=true, bool IsVolatile=false)
This is a convenience method that opens a file, gets its content and then closes the file...
StringRef getName() const
Returns the name that should be used for this file or directory.
virtual ~File()
Destroy the file after closing it (if open).
An input iterator over the entries in a virtual path, similar to llvm::sys::fs::directory_iterator.
llvm::ErrorOr< Status > status(const Twine &Path) override
Get the status of the entry at Path, if one exists.
std::error_code setCurrentWorkingDirectory(const Twine &Path) override
Set the working directory.
bool operator==(const recursive_directory_iterator &Other) const
An interface for virtual file systems to provide an iterator over the (non-recursive) contents of a d...
llvm::ErrorOr< Status > status(const Twine &Path) override
Get the status of the entry at Path, if one exists.
virtual std::error_code increment()=0
Sets CurrentEntry to the next entry in the directory on success, or returns a system-defined error_co...
std::error_code makeAbsolute(SmallVectorImpl< char > &Path) const
Make Path an absolute path.