//===- VirtualFileSystem.h - Virtual File System Layer ----------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // /// \file /// Defines the virtual file system interface vfs::FileSystem. // //===----------------------------------------------------------------------===// #ifndef LLVM_SUPPORT_VIRTUALFILESYSTEM_H #define LLVM_SUPPORT_VIRTUALFILESYSTEM_H #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Chrono.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/ExtensibleRTTI.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/SourceMgr.h" #include <cassert> #include <cstdint> #include <ctime> #include <memory> #include <optional> #include <string> #include <system_error> #include <utility> #include <vector> namespace llvm { class MemoryBuffer; class MemoryBufferRef; class Twine; namespace vfs { /// The result of a \p status operation. class Status { … }; /// Represents an open file. class File { … }; /// A member of a directory, yielded by a directory_iterator. /// Only information available on most platforms is included. class directory_entry { … }; namespace detail { /// An interface for virtual file systems to provide an iterator over the /// (non-recursive) contents of a directory. struct DirIterImpl { … }; } // namespace detail /// An input iterator over the entries in a virtual path, similar to /// llvm::sys::fs::directory_iterator. class directory_iterator { … }; class FileSystem; namespace detail { /// Keeps state for the recursive_directory_iterator. struct RecDirIterState { … }; } // end namespace detail /// An input iterator over the recursive contents of a virtual path, /// similar to llvm::sys::fs::recursive_directory_iterator. class recursive_directory_iterator { … }; /// The virtual file system interface. class FileSystem : public llvm::ThreadSafeRefCountedBase<FileSystem>, public RTTIExtends<FileSystem, RTTIRoot> { … }; /// Gets an \p vfs::FileSystem for the 'real' file system, as seen by /// the operating system. /// The working directory is linked to the process's working directory. /// (This is usually thread-hostile). IntrusiveRefCntPtr<FileSystem> getRealFileSystem(); /// Create an \p vfs::FileSystem for the 'real' file system, as seen by /// the operating system. /// It has its own working directory, independent of (but initially equal to) /// that of the process. std::unique_ptr<FileSystem> createPhysicalFileSystem(); /// A file system that allows overlaying one \p AbstractFileSystem on top /// of another. /// /// Consists of a stack of >=1 \p FileSystem objects, which are treated as being /// one merged file system. When there is a directory that exists in more than /// one file system, the \p OverlayFileSystem contains a directory containing /// the union of their contents. The attributes (permissions, etc.) of the /// top-most (most recently added) directory are used. When there is a file /// that exists in more than one file system, the file in the top-most file /// system overrides the other(s). class OverlayFileSystem : public RTTIExtends<OverlayFileSystem, FileSystem> { … }; /// By default, this delegates all calls to the underlying file system. This /// is useful when derived file systems want to override some calls and still /// proxy other calls. class ProxyFileSystem : public RTTIExtends<ProxyFileSystem, FileSystem> { … }; namespace detail { class InMemoryDirectory; class InMemoryNode; struct NewInMemoryNodeInfo { … }; class NamedNodeOrError { … }; } // namespace detail /// An in-memory file system. class InMemoryFileSystem : public RTTIExtends<InMemoryFileSystem, FileSystem> { … }; /// Get a globally unique ID for a virtual file or directory. llvm::sys::fs::UniqueID getNextVirtualUniqueID(); /// Gets a \p FileSystem for a virtual file system described in YAML /// format. std::unique_ptr<FileSystem> getVFSFromYAML(std::unique_ptr<llvm::MemoryBuffer> Buffer, llvm::SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, void *DiagContext = nullptr, IntrusiveRefCntPtr<FileSystem> ExternalFS = getRealFileSystem()); struct YAMLVFSEntry { … }; class RedirectingFSDirIterImpl; class RedirectingFileSystemParser; /// A virtual file system parsed from a YAML file. /// /// Currently, this class allows creating virtual files and directories. Virtual /// files map to existing external files in \c ExternalFS, and virtual /// directories may either map to existing directories in \c ExternalFS or list /// their contents in the form of other virtual directories and/or files. /// /// The basic structure of the parsed file is: /// \verbatim /// { /// 'version': <version number>, /// <optional configuration> /// 'roots': [ /// <directory entries> /// ] /// } /// \endverbatim /// The roots may be absolute or relative. If relative they will be made /// absolute against either current working directory or the directory where /// the Overlay YAML file is located, depending on the 'root-relative' /// configuration. /// /// All configuration options are optional. /// 'case-sensitive': <boolean, default=(true for Posix, false for Windows)> /// 'use-external-names': <boolean, default=true> /// 'root-relative': <string, one of 'cwd' or 'overlay-dir', default='cwd'> /// 'overlay-relative': <boolean, default=false> /// 'fallthrough': <boolean, default=true, deprecated - use 'redirecting-with' /// instead> /// 'redirecting-with': <string, one of 'fallthrough', 'fallback', or /// 'redirect-only', default='fallthrough'> /// /// To clarify, 'root-relative' option will prepend the current working /// directory, or the overlay directory to the 'roots->name' field only if /// 'roots->name' is a relative path. On the other hand, when 'overlay-relative' /// is set to 'true', external paths will always be prepended with the overlay /// directory, even if external paths are not relative paths. The /// 'root-relative' option has no interaction with the 'overlay-relative' /// option. /// /// Virtual directories that list their contents are represented as /// \verbatim /// { /// 'type': 'directory', /// 'name': <string>, /// 'contents': [ <file or directory entries> ] /// } /// \endverbatim /// The default attributes for such virtual directories are: /// \verbatim /// MTime = now() when created /// Perms = 0777 /// User = Group = 0 /// Size = 0 /// UniqueID = unspecified unique value /// \endverbatim /// When a path prefix matches such a directory, the next component in the path /// is matched against the entries in the 'contents' array. /// /// Re-mapped directories, on the other hand, are represented as /// /// \verbatim /// { /// 'type': 'directory-remap', /// 'name': <string>, /// 'use-external-name': <boolean>, # Optional /// 'external-contents': <path to external directory> /// } /// \endverbatim /// and inherit their attributes from the external directory. When a path /// prefix matches such an entry, the unmatched components are appended to the /// 'external-contents' path, and the resulting path is looked up in the /// external file system instead. /// /// Re-mapped files are represented as /// \verbatim /// { /// 'type': 'file', /// 'name': <string>, /// 'use-external-name': <boolean>, # Optional /// 'external-contents': <path to external file> /// } /// \endverbatim /// Their attributes and file contents are determined by looking up the file at /// their 'external-contents' path in the external file system. /// /// For 'file', 'directory' and 'directory-remap' entries the 'name' field may /// contain multiple path components (e.g. /path/to/file). However, any /// directory in such a path that contains more than one child must be uniquely /// represented by a 'directory' entry. /// /// When the 'use-external-name' field is set, calls to \a vfs::File::status() /// give the external (remapped) filesystem name instead of the name the file /// was accessed by. This is an intentional leak through the \a /// RedirectingFileSystem abstraction layer. It enables clients to discover /// (and use) the external file location when communicating with users or tools /// that don't use the same VFS overlay. /// /// FIXME: 'use-external-name' causes behaviour that's inconsistent with how /// "real" filesystems behave. Maybe there should be a separate channel for /// this information. class RedirectingFileSystem : public RTTIExtends<RedirectingFileSystem, vfs::FileSystem> { … }; /// Collect all pairs of <virtual path, real path> entries from the /// \p YAMLFilePath. This is used by the module dependency collector to forward /// the entries into the reproducer output VFS YAML file. void collectVFSFromYAML( std::unique_ptr<llvm::MemoryBuffer> Buffer, llvm::SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, SmallVectorImpl<YAMLVFSEntry> &CollectedEntries, void *DiagContext = nullptr, IntrusiveRefCntPtr<FileSystem> ExternalFS = getRealFileSystem()); class YAMLVFSWriter { … }; /// File system that tracks the number of calls to the underlying file system. /// This is particularly useful when wrapped around \c RealFileSystem to add /// lightweight tracking of expensive syscalls. class TracingFileSystem : public llvm::RTTIExtends<TracingFileSystem, ProxyFileSystem> { … }; } // namespace vfs } // namespace llvm #endif // LLVM_SUPPORT_VIRTUALFILESYSTEM_H