1 //===-- FileSystem.h --------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLDB_HOST_FILESYSTEM_H
10 #define LLDB_HOST_FILESYSTEM_H
11 
12 #include "lldb/Host/File.h"
13 #include "lldb/Utility/DataBuffer.h"
14 #include "lldb/Utility/FileSpec.h"
15 #include "lldb/Utility/LLDBAssert.h"
16 #include "lldb/Utility/Status.h"
17 #include "lldb/Utility/TildeExpressionResolver.h"
18 
19 #include "llvm/Support/Chrono.h"
20 #include "llvm/Support/VirtualFileSystem.h"
21 
22 #include "lldb/lldb-types.h"
23 
24 #include <cstdint>
25 #include <cstdio>
26 #include <optional>
27 #include <sys/stat.h>
28 
29 namespace lldb_private {
30 class FileSystem {
31 public:
32   static const char *DEV_NULL;
33   static const char *PATH_CONVERSION_ERROR;
34 
35   FileSystem()
36       : m_fs(llvm::vfs::getRealFileSystem()),
37         m_tilde_resolver(std::make_unique<StandardTildeExpressionResolver>()) {}
38   FileSystem(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs)
39       : m_fs(std::move(fs)),
40         m_tilde_resolver(std::make_unique<StandardTildeExpressionResolver>()) {}
41   FileSystem(std::unique_ptr<TildeExpressionResolver> tilde_resolver)
42       : m_fs(llvm::vfs::getRealFileSystem()),
43         m_tilde_resolver(std::move(tilde_resolver)) {}
44 
45   FileSystem(const FileSystem &fs) = delete;
46   FileSystem &operator=(const FileSystem &fs) = delete;
47 
48   static FileSystem &Instance();
49 
50   template <class... T> static void Initialize(T &&...t) {
51     lldbassert(!InstanceImpl() && "Already initialized.");
52     InstanceImpl().emplace(std::forward<T>(t)...);
53   }
54   static void Terminate();
55 
56   Status Symlink(const FileSpec &src, const FileSpec &dst);
57   Status Readlink(const FileSpec &src, FileSpec &dst);
58 
59   Status ResolveSymbolicLink(const FileSpec &src, FileSpec &dst);
60 
61   /// Wraps ::fopen in a platform-independent way.
62   FILE *Fopen(const char *path, const char *mode);
63 
64   /// Wraps ::open in a platform-independent way.
65   int Open(const char *path, int flags, int mode = 0600);
66 
67   llvm::Expected<std::unique_ptr<File>>
68   Open(const FileSpec &file_spec, File::OpenOptions options,
69        uint32_t permissions = lldb::eFilePermissionsFileDefault,
70        bool should_close_fd = true);
71 
72   /// Get a directory iterator.
73   /// \{
74   llvm::vfs::directory_iterator DirBegin(const FileSpec &file_spec,
75                                          std::error_code &ec);
76   llvm::vfs::directory_iterator DirBegin(const llvm::Twine &dir,
77                                          std::error_code &ec);
78   /// \}
79 
80   /// Returns the Status object for the given file.
81   /// \{
82   llvm::ErrorOr<llvm::vfs::Status> GetStatus(const FileSpec &file_spec) const;
83   llvm::ErrorOr<llvm::vfs::Status> GetStatus(const llvm::Twine &path) const;
84   /// \}
85 
86   /// Returns the modification time of the given file.
87   /// \{
88   llvm::sys::TimePoint<> GetModificationTime(const FileSpec &file_spec) const;
89   llvm::sys::TimePoint<> GetModificationTime(const llvm::Twine &path) const;
90   /// \}
91 
92   /// Returns the on-disk size of the given file in bytes.
93   /// \{
94   uint64_t GetByteSize(const FileSpec &file_spec) const;
95   uint64_t GetByteSize(const llvm::Twine &path) const;
96   /// \}
97 
98   /// Return the current permissions of the given file.
99   ///
100   /// Returns a bitmask for the current permissions of the file (zero or more
101   /// of the permission bits defined in File::Permissions).
102   /// \{
103   uint32_t GetPermissions(const FileSpec &file_spec) const;
104   uint32_t GetPermissions(const llvm::Twine &path) const;
105   uint32_t GetPermissions(const FileSpec &file_spec, std::error_code &ec) const;
106   uint32_t GetPermissions(const llvm::Twine &path, std::error_code &ec) const;
107   /// \}
108 
109   /// Returns whether the given file exists.
110   /// \{
111   bool Exists(const FileSpec &file_spec) const;
112   bool Exists(const llvm::Twine &path) const;
113   /// \}
114 
115   /// Returns whether the given file is readable.
116   /// \{
117   bool Readable(const FileSpec &file_spec) const;
118   bool Readable(const llvm::Twine &path) const;
119   /// \}
120 
121   /// Returns whether the given path is a directory.
122   /// \{
123   bool IsDirectory(const FileSpec &file_spec) const;
124   bool IsDirectory(const llvm::Twine &path) const;
125   /// \}
126 
127   /// Returns whether the given path is local to the file system.
128   /// \{
129   bool IsLocal(const FileSpec &file_spec) const;
130   bool IsLocal(const llvm::Twine &path) const;
131   /// \}
132 
133   /// Make the given file path absolute.
134   /// \{
135   std::error_code MakeAbsolute(llvm::SmallVectorImpl<char> &path) const;
136   std::error_code MakeAbsolute(FileSpec &file_spec) const;
137   /// \}
138 
139   /// Resolve path to make it canonical.
140   /// \{
141   void Resolve(llvm::SmallVectorImpl<char> &path);
142   void Resolve(FileSpec &file_spec);
143   /// \}
144 
145   /// Remove a single file.
146   ///
147   /// The path must specify a file and not a directory.
148   /// \{
149   Status RemoveFile(const FileSpec &file_spec);
150   Status RemoveFile(const llvm::Twine &path);
151   /// \}
152 
153   //// Create memory buffer from path.
154   /// \{
155   std::shared_ptr<DataBuffer> CreateDataBuffer(const llvm::Twine &path,
156                                                uint64_t size = 0,
157                                                uint64_t offset = 0);
158   std::shared_ptr<DataBuffer> CreateDataBuffer(const FileSpec &file_spec,
159                                                uint64_t size = 0,
160                                                uint64_t offset = 0);
161   std::shared_ptr<WritableDataBuffer>
162   CreateWritableDataBuffer(const llvm::Twine &path, uint64_t size = 0,
163                            uint64_t offset = 0);
164   std::shared_ptr<WritableDataBuffer>
165   CreateWritableDataBuffer(const FileSpec &file_spec, uint64_t size = 0,
166                            uint64_t offset = 0);
167   /// \}
168 
169   /// Call into the Host to see if it can help find the file.
170   bool ResolveExecutableLocation(FileSpec &file_spec);
171 
172   /// Get the user home directory.
173   bool GetHomeDirectory(llvm::SmallVectorImpl<char> &path) const;
174   bool GetHomeDirectory(FileSpec &file_spec) const;
175 
176   enum EnumerateDirectoryResult {
177     /// Enumerate next entry in the current directory.
178     eEnumerateDirectoryResultNext,
179     /// Recurse into the current entry if it is a directory or symlink, or next
180     /// if not.
181     eEnumerateDirectoryResultEnter,
182     /// Stop directory enumerations at any level.
183     eEnumerateDirectoryResultQuit
184   };
185 
186   typedef EnumerateDirectoryResult (*EnumerateDirectoryCallbackType)(
187       void *baton, llvm::sys::fs::file_type file_type, llvm::StringRef);
188 
189   typedef std::function<EnumerateDirectoryResult(
190       llvm::sys::fs::file_type file_type, llvm::StringRef)>
191       DirectoryCallback;
192 
193   void EnumerateDirectory(llvm::Twine path, bool find_directories,
194                           bool find_files, bool find_other,
195                           EnumerateDirectoryCallbackType callback,
196                           void *callback_baton);
197 
198   std::error_code GetRealPath(const llvm::Twine &path,
199                               llvm::SmallVectorImpl<char> &output) const;
200 
201   llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> GetVirtualFileSystem() {
202     return m_fs;
203   }
204 
205   void SetHomeDirectory(std::string home_directory);
206 
207 private:
208   static std::optional<FileSystem> &InstanceImpl();
209   llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> m_fs;
210   std::unique_ptr<TildeExpressionResolver> m_tilde_resolver;
211   std::string m_home_directory;
212 };
213 } // namespace lldb_private
214 
215 #endif
216