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