1 //===-- FileSystem.cpp ------------------------------------------*- 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 
10 #include "lldb/Host/FileSystem.h"
11 
12 #include "lldb/Utility/LLDBAssert.h"
13 #include "lldb/Utility/TildeExpressionResolver.h"
14 
15 #include "llvm/Support/Errno.h"
16 #include "llvm/Support/FileSystem.h"
17 #include "llvm/Support/Path.h"
18 #include "llvm/Support/Program.h"
19 #include "llvm/Support/Threading.h"
20 
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <limits.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 
27 #ifdef _WIN32
28 #include "lldb/Host/windows/windows.h"
29 #else
30 #include <sys/ioctl.h>
31 #include <sys/stat.h>
32 #include <termios.h>
33 #include <unistd.h>
34 #endif
35 
36 #include <algorithm>
37 #include <fstream>
38 #include <vector>
39 
40 using namespace lldb;
41 using namespace lldb_private;
42 using namespace llvm;
43 
44 FileSystem &FileSystem::Instance() { return *InstanceImpl(); }
45 
46 void FileSystem::Initialize() {
47   lldbassert(!InstanceImpl() && "Already initialized.");
48   InstanceImpl().emplace();
49 }
50 
51 void FileSystem::Initialize(IntrusiveRefCntPtr<vfs::FileSystem> fs) {
52   lldbassert(!InstanceImpl() && "Already initialized.");
53   InstanceImpl().emplace(fs);
54 }
55 
56 void FileSystem::Terminate() {
57   lldbassert(InstanceImpl() && "Already terminated.");
58   InstanceImpl().reset();
59 }
60 
61 Optional<FileSystem> &FileSystem::InstanceImpl() {
62   static Optional<FileSystem> g_fs;
63   return g_fs;
64 }
65 
66 vfs::directory_iterator FileSystem::DirBegin(const FileSpec &file_spec,
67                                              std::error_code &ec) {
68   return DirBegin(file_spec.GetPath(), ec);
69 }
70 
71 vfs::directory_iterator FileSystem::DirBegin(const Twine &dir,
72                                              std::error_code &ec) {
73   return m_fs->dir_begin(dir, ec);
74 }
75 
76 llvm::ErrorOr<vfs::Status>
77 FileSystem::GetStatus(const FileSpec &file_spec) const {
78   return GetStatus(file_spec.GetPath());
79 }
80 
81 llvm::ErrorOr<vfs::Status> FileSystem::GetStatus(const Twine &path) const {
82   return m_fs->status(path);
83 }
84 
85 sys::TimePoint<>
86 FileSystem::GetModificationTime(const FileSpec &file_spec) const {
87   return GetModificationTime(file_spec.GetPath());
88 }
89 
90 sys::TimePoint<> FileSystem::GetModificationTime(const Twine &path) const {
91   ErrorOr<vfs::Status> status = m_fs->status(path);
92   if (!status)
93     return sys::TimePoint<>();
94   return status->getLastModificationTime();
95 }
96 
97 uint64_t FileSystem::GetByteSize(const FileSpec &file_spec) const {
98   return GetByteSize(file_spec.GetPath());
99 }
100 
101 uint64_t FileSystem::GetByteSize(const Twine &path) const {
102   ErrorOr<vfs::Status> status = m_fs->status(path);
103   if (!status)
104     return 0;
105   return status->getSize();
106 }
107 
108 uint32_t FileSystem::GetPermissions(const FileSpec &file_spec) const {
109   return GetPermissions(file_spec.GetPath());
110 }
111 
112 uint32_t FileSystem::GetPermissions(const FileSpec &file_spec,
113                                     std::error_code &ec) const {
114   return GetPermissions(file_spec.GetPath(), ec);
115 }
116 
117 uint32_t FileSystem::GetPermissions(const Twine &path) const {
118   std::error_code ec;
119   return GetPermissions(path, ec);
120 }
121 
122 uint32_t FileSystem::GetPermissions(const Twine &path,
123                                     std::error_code &ec) const {
124   ErrorOr<vfs::Status> status = m_fs->status(path);
125   if (!status) {
126     ec = status.getError();
127     return sys::fs::perms::perms_not_known;
128   }
129   return status->getPermissions();
130 }
131 
132 bool FileSystem::Exists(const Twine &path) const { return m_fs->exists(path); }
133 
134 bool FileSystem::Exists(const FileSpec &file_spec) const {
135   return Exists(file_spec.GetPath());
136 }
137 
138 bool FileSystem::Readable(const Twine &path) const {
139   return GetPermissions(path) & sys::fs::perms::all_read;
140 }
141 
142 bool FileSystem::Readable(const FileSpec &file_spec) const {
143   return Readable(file_spec.GetPath());
144 }
145 
146 bool FileSystem::IsDirectory(const Twine &path) const {
147   ErrorOr<vfs::Status> status = m_fs->status(path);
148   if (!status)
149     return false;
150   return status->isDirectory();
151 }
152 
153 bool FileSystem::IsDirectory(const FileSpec &file_spec) const {
154   return IsDirectory(file_spec.GetPath());
155 }
156 
157 bool FileSystem::IsLocal(const Twine &path) const {
158   bool b = false;
159   m_fs->isLocal(path, b);
160   return b;
161 }
162 
163 bool FileSystem::IsLocal(const FileSpec &file_spec) const {
164   return IsLocal(file_spec.GetPath());
165 }
166 
167 void FileSystem::EnumerateDirectory(Twine path, bool find_directories,
168                                     bool find_files, bool find_other,
169                                     EnumerateDirectoryCallbackType callback,
170                                     void *callback_baton) {
171   std::error_code EC;
172   vfs::recursive_directory_iterator Iter(*m_fs, path, EC);
173   vfs::recursive_directory_iterator End;
174   for (; Iter != End && !EC; Iter.increment(EC)) {
175     const auto &Item = *Iter;
176     ErrorOr<vfs::Status> Status = m_fs->status(Item.path());
177     if (!Status)
178       break;
179     if (!find_files && Status->isRegularFile())
180       continue;
181     if (!find_directories && Status->isDirectory())
182       continue;
183     if (!find_other && Status->isOther())
184       continue;
185 
186     auto Result = callback(callback_baton, Status->getType(), Item.path());
187     if (Result == eEnumerateDirectoryResultQuit)
188       return;
189     if (Result == eEnumerateDirectoryResultNext) {
190       // Default behavior is to recurse. Opt out if the callback doesn't want
191       // this behavior.
192       Iter.no_push();
193     }
194   }
195 }
196 
197 std::error_code FileSystem::MakeAbsolute(SmallVectorImpl<char> &path) const {
198   return m_fs->makeAbsolute(path);
199 }
200 
201 std::error_code FileSystem::MakeAbsolute(FileSpec &file_spec) const {
202   SmallString<128> path;
203   file_spec.GetPath(path, false);
204 
205   auto EC = MakeAbsolute(path);
206   if (EC)
207     return EC;
208 
209   FileSpec new_file_spec(path, file_spec.GetPathStyle());
210   file_spec = new_file_spec;
211   return {};
212 }
213 
214 std::error_code FileSystem::GetRealPath(const Twine &path,
215                                         SmallVectorImpl<char> &output) const {
216   return m_fs->getRealPath(path, output);
217 }
218 
219 void FileSystem::Resolve(SmallVectorImpl<char> &path) {
220   if (path.empty())
221     return;
222 
223   // Resolve tilde.
224   SmallString<128> original_path(path.begin(), path.end());
225   StandardTildeExpressionResolver Resolver;
226   Resolver.ResolveFullPath(original_path, path);
227 
228   // Try making the path absolute if it exists.
229   SmallString<128> absolute_path(path.begin(), path.end());
230   MakeAbsolute(path);
231   if (!Exists(path)) {
232     path.clear();
233     path.append(original_path.begin(), original_path.end());
234   }
235 }
236 
237 void FileSystem::Resolve(FileSpec &file_spec) {
238   // Extract path from the FileSpec.
239   SmallString<128> path;
240   file_spec.GetPath(path);
241 
242   // Resolve the path.
243   Resolve(path);
244 
245   // Update the FileSpec with the resolved path.
246   file_spec.SetPath(path);
247   file_spec.SetIsResolved(true);
248 }
249 
250 std::shared_ptr<DataBufferLLVM>
251 FileSystem::CreateDataBuffer(const llvm::Twine &path, uint64_t size,
252                              uint64_t offset) {
253   const bool is_volatile = !IsLocal(path);
254 
255   std::unique_ptr<llvm::WritableMemoryBuffer> buffer;
256   if (size == 0) {
257     auto buffer_or_error =
258         llvm::WritableMemoryBuffer::getFile(path, -1, is_volatile);
259     if (!buffer_or_error)
260       return nullptr;
261     buffer = std::move(*buffer_or_error);
262   } else {
263     auto buffer_or_error = llvm::WritableMemoryBuffer::getFileSlice(
264         path, size, offset, is_volatile);
265     if (!buffer_or_error)
266       return nullptr;
267     buffer = std::move(*buffer_or_error);
268   }
269   return std::shared_ptr<DataBufferLLVM>(new DataBufferLLVM(std::move(buffer)));
270 }
271 
272 std::shared_ptr<DataBufferLLVM>
273 FileSystem::CreateDataBuffer(const FileSpec &file_spec, uint64_t size,
274                              uint64_t offset) {
275   return CreateDataBuffer(file_spec.GetPath(), size, offset);
276 }
277 
278 bool FileSystem::ResolveExecutableLocation(FileSpec &file_spec) {
279   // If the directory is set there's nothing to do.
280   const ConstString &directory = file_spec.GetDirectory();
281   if (directory)
282     return false;
283 
284   // We cannot look for a file if there's no file name.
285   const ConstString &filename = file_spec.GetFilename();
286   if (!filename)
287     return false;
288 
289   // Search for the file on the host.
290   const std::string filename_str(filename.GetCString());
291   llvm::ErrorOr<std::string> error_or_path =
292       llvm::sys::findProgramByName(filename_str);
293   if (!error_or_path)
294     return false;
295 
296   // findProgramByName returns "." if it can't find the file.
297   llvm::StringRef path = *error_or_path;
298   llvm::StringRef parent = llvm::sys::path::parent_path(path);
299   if (parent.empty() || parent == ".")
300     return false;
301 
302   // Make sure that the result exists.
303   FileSpec result(*error_or_path);
304   if (!Exists(result))
305     return false;
306 
307   file_spec = result;
308   return true;
309 }
310 
311 static int OpenWithFS(const FileSystem &fs, const char *path, int flags,
312                       int mode) {
313   return const_cast<FileSystem &>(fs).Open(path, flags, mode);
314 }
315 
316 static int GetOpenFlags(uint32_t options) {
317   const bool read = options & File::eOpenOptionRead;
318   const bool write = options & File::eOpenOptionWrite;
319 
320   int open_flags = 0;
321   if (write) {
322     if (read)
323       open_flags |= O_RDWR;
324     else
325       open_flags |= O_WRONLY;
326 
327     if (options & File::eOpenOptionAppend)
328       open_flags |= O_APPEND;
329 
330     if (options & File::eOpenOptionTruncate)
331       open_flags |= O_TRUNC;
332 
333     if (options & File::eOpenOptionCanCreate)
334       open_flags |= O_CREAT;
335 
336     if (options & File::eOpenOptionCanCreateNewOnly)
337       open_flags |= O_CREAT | O_EXCL;
338   } else if (read) {
339     open_flags |= O_RDONLY;
340 
341 #ifndef _WIN32
342     if (options & File::eOpenOptionDontFollowSymlinks)
343       open_flags |= O_NOFOLLOW;
344 #endif
345   }
346 
347 #ifndef _WIN32
348   if (options & File::eOpenOptionNonBlocking)
349     open_flags |= O_NONBLOCK;
350   if (options & File::eOpenOptionCloseOnExec)
351     open_flags |= O_CLOEXEC;
352 #else
353   open_flags |= O_BINARY;
354 #endif
355 
356   return open_flags;
357 }
358 
359 static mode_t GetOpenMode(uint32_t permissions) {
360   mode_t mode = 0;
361   if (permissions & lldb::eFilePermissionsUserRead)
362     mode |= S_IRUSR;
363   if (permissions & lldb::eFilePermissionsUserWrite)
364     mode |= S_IWUSR;
365   if (permissions & lldb::eFilePermissionsUserExecute)
366     mode |= S_IXUSR;
367   if (permissions & lldb::eFilePermissionsGroupRead)
368     mode |= S_IRGRP;
369   if (permissions & lldb::eFilePermissionsGroupWrite)
370     mode |= S_IWGRP;
371   if (permissions & lldb::eFilePermissionsGroupExecute)
372     mode |= S_IXGRP;
373   if (permissions & lldb::eFilePermissionsWorldRead)
374     mode |= S_IROTH;
375   if (permissions & lldb::eFilePermissionsWorldWrite)
376     mode |= S_IWOTH;
377   if (permissions & lldb::eFilePermissionsWorldExecute)
378     mode |= S_IXOTH;
379   return mode;
380 }
381 
382 Status FileSystem::Open(File &File, const FileSpec &file_spec, uint32_t options,
383                         uint32_t permissions) {
384   if (File.IsValid())
385     File.Close();
386 
387   const int open_flags = GetOpenFlags(options);
388   const mode_t open_mode =
389       (open_flags & O_CREAT) ? GetOpenMode(permissions) : 0;
390   const std::string path = file_spec.GetPath();
391 
392   int descriptor = llvm::sys::RetryAfterSignal(
393       -1, OpenWithFS, *this, path.c_str(), open_flags, open_mode);
394 
395   Status error;
396   if (!File::DescriptorIsValid(descriptor)) {
397     File.SetDescriptor(descriptor, false);
398     error.SetErrorToErrno();
399   } else {
400     File.SetDescriptor(descriptor, true);
401     File.SetOptions(options);
402   }
403   return error;
404 }
405