LLDB  mainline
common/FileSystem.cpp
Go to the documentation of this file.
1 //===-- FileSystem.cpp ------------------------------------------*- 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 #include "lldb/Host/FileSystem.h"
10 
13 
14 #include "llvm/Support/Errc.h"
15 #include "llvm/Support/Errno.h"
16 #include "llvm/Support/Error.h"
17 #include "llvm/Support/FileSystem.h"
18 #include "llvm/Support/Path.h"
19 #include "llvm/Support/Program.h"
20 #include "llvm/Support/Threading.h"
21 
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <limits.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 
28 #ifdef _WIN32
30 #else
31 #include <sys/ioctl.h>
32 #include <sys/stat.h>
33 #include <termios.h>
34 #include <unistd.h>
35 #endif
36 
37 #include <algorithm>
38 #include <fstream>
39 #include <vector>
40 
41 using namespace lldb;
42 using namespace lldb_private;
43 using namespace llvm;
44 
45 FileSystem &FileSystem::Instance() { return *InstanceImpl(); }
46 
47 void FileSystem::Initialize() {
48  lldbassert(!InstanceImpl() && "Already initialized.");
49  InstanceImpl().emplace();
50 }
51 
52 void FileSystem::Initialize(FileCollector &collector) {
53  lldbassert(!InstanceImpl() && "Already initialized.");
54  InstanceImpl().emplace(collector);
55 }
56 
57 llvm::Error FileSystem::Initialize(const FileSpec &mapping) {
58  lldbassert(!InstanceImpl() && "Already initialized.");
59 
60  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer =
61  llvm::vfs::getRealFileSystem()->getBufferForFile(mapping.GetPath());
62 
63  if (!buffer)
64  return llvm::errorCodeToError(buffer.getError());
65 
66  InstanceImpl().emplace(
67  llvm::vfs::getVFSFromYAML(std::move(buffer.get()), nullptr, ""), true);
68 
69  return llvm::Error::success();
70 }
71 
72 void FileSystem::Initialize(IntrusiveRefCntPtr<vfs::FileSystem> fs) {
73  lldbassert(!InstanceImpl() && "Already initialized.");
74  InstanceImpl().emplace(fs);
75 }
76 
77 void FileSystem::Terminate() {
78  lldbassert(InstanceImpl() && "Already terminated.");
79  InstanceImpl().reset();
80 }
81 
82 Optional<FileSystem> &FileSystem::InstanceImpl() {
83  static Optional<FileSystem> g_fs;
84  return g_fs;
85 }
86 
87 vfs::directory_iterator FileSystem::DirBegin(const FileSpec &file_spec,
88  std::error_code &ec) {
89  return DirBegin(file_spec.GetPath(), ec);
90 }
91 
92 vfs::directory_iterator FileSystem::DirBegin(const Twine &dir,
93  std::error_code &ec) {
94  return m_fs->dir_begin(dir, ec);
95 }
96 
97 llvm::ErrorOr<vfs::Status>
98 FileSystem::GetStatus(const FileSpec &file_spec) const {
99  return GetStatus(file_spec.GetPath());
100 }
101 
102 llvm::ErrorOr<vfs::Status> FileSystem::GetStatus(const Twine &path) const {
103  return m_fs->status(path);
104 }
105 
106 sys::TimePoint<>
107 FileSystem::GetModificationTime(const FileSpec &file_spec) const {
108  return GetModificationTime(file_spec.GetPath());
109 }
110 
111 sys::TimePoint<> FileSystem::GetModificationTime(const Twine &path) const {
112  ErrorOr<vfs::Status> status = m_fs->status(path);
113  if (!status)
114  return sys::TimePoint<>();
115  return status->getLastModificationTime();
116 }
117 
118 uint64_t FileSystem::GetByteSize(const FileSpec &file_spec) const {
119  return GetByteSize(file_spec.GetPath());
120 }
121 
122 uint64_t FileSystem::GetByteSize(const Twine &path) const {
123  ErrorOr<vfs::Status> status = m_fs->status(path);
124  if (!status)
125  return 0;
126  return status->getSize();
127 }
128 
130  return GetPermissions(file_spec.GetPath());
131 }
132 
134  std::error_code &ec) const {
135  return GetPermissions(file_spec.GetPath(), ec);
136 }
137 
138 uint32_t FileSystem::GetPermissions(const Twine &path) const {
139  std::error_code ec;
140  return GetPermissions(path, ec);
141 }
142 
143 uint32_t FileSystem::GetPermissions(const Twine &path,
144  std::error_code &ec) const {
145  ErrorOr<vfs::Status> status = m_fs->status(path);
146  if (!status) {
147  ec = status.getError();
148  return sys::fs::perms::perms_not_known;
149  }
150  return status->getPermissions();
151 }
152 
153 bool FileSystem::Exists(const Twine &path) const { return m_fs->exists(path); }
154 
155 bool FileSystem::Exists(const FileSpec &file_spec) const {
156  return Exists(file_spec.GetPath());
157 }
158 
159 bool FileSystem::Readable(const Twine &path) const {
160  return GetPermissions(path) & sys::fs::perms::all_read;
161 }
162 
163 bool FileSystem::Readable(const FileSpec &file_spec) const {
164  return Readable(file_spec.GetPath());
165 }
166 
167 bool FileSystem::IsDirectory(const Twine &path) const {
168  ErrorOr<vfs::Status> status = m_fs->status(path);
169  if (!status)
170  return false;
171  return status->isDirectory();
172 }
173 
174 bool FileSystem::IsDirectory(const FileSpec &file_spec) const {
175  return IsDirectory(file_spec.GetPath());
176 }
177 
178 bool FileSystem::IsLocal(const Twine &path) const {
179  bool b = false;
180  m_fs->isLocal(path, b);
181  return b;
182 }
183 
184 bool FileSystem::IsLocal(const FileSpec &file_spec) const {
185  return IsLocal(file_spec.GetPath());
186 }
187 
188 void FileSystem::EnumerateDirectory(Twine path, bool find_directories,
189  bool find_files, bool find_other,
190  EnumerateDirectoryCallbackType callback,
191  void *callback_baton) {
192  std::error_code EC;
193  vfs::recursive_directory_iterator Iter(*m_fs, path, EC);
194  vfs::recursive_directory_iterator End;
195  for (; Iter != End && !EC; Iter.increment(EC)) {
196  const auto &Item = *Iter;
197  ErrorOr<vfs::Status> Status = m_fs->status(Item.path());
198  if (!Status)
199  break;
200  if (!find_files && Status->isRegularFile())
201  continue;
202  if (!find_directories && Status->isDirectory())
203  continue;
204  if (!find_other && Status->isOther())
205  continue;
206 
207  auto Result = callback(callback_baton, Status->getType(), Item.path());
208  if (Result == eEnumerateDirectoryResultQuit)
209  return;
210  if (Result == eEnumerateDirectoryResultNext) {
211  // Default behavior is to recurse. Opt out if the callback doesn't want
212  // this behavior.
213  Iter.no_push();
214  }
215  }
216 }
217 
218 std::error_code FileSystem::MakeAbsolute(SmallVectorImpl<char> &path) const {
219  return m_fs->makeAbsolute(path);
220 }
221 
222 std::error_code FileSystem::MakeAbsolute(FileSpec &file_spec) const {
223  SmallString<128> path;
224  file_spec.GetPath(path, false);
225 
226  auto EC = MakeAbsolute(path);
227  if (EC)
228  return EC;
229 
230  FileSpec new_file_spec(path, file_spec.GetPathStyle());
231  file_spec = new_file_spec;
232  return {};
233 }
234 
235 std::error_code FileSystem::GetRealPath(const Twine &path,
236  SmallVectorImpl<char> &output) const {
237  return m_fs->getRealPath(path, output);
238 }
239 
240 void FileSystem::Resolve(SmallVectorImpl<char> &path) {
241  if (path.empty())
242  return;
243 
244  // Resolve tilde.
245  SmallString<128> original_path(path.begin(), path.end());
247  Resolver.ResolveFullPath(original_path, path);
248 
249  // Try making the path absolute if it exists.
250  SmallString<128> absolute_path(path.begin(), path.end());
251  MakeAbsolute(path);
252  if (!Exists(path)) {
253  path.clear();
254  path.append(original_path.begin(), original_path.end());
255  }
256 }
257 
258 void FileSystem::Resolve(FileSpec &file_spec) {
259  // Extract path from the FileSpec.
260  SmallString<128> path;
261  file_spec.GetPath(path);
262 
263  // Resolve the path.
264  Resolve(path);
265 
266  // Update the FileSpec with the resolved path.
267  if (file_spec.GetFilename().IsEmpty())
268  file_spec.GetDirectory().SetString(path);
269  else
270  file_spec.SetPath(path);
271  file_spec.SetIsResolved(true);
272 }
273 
274 std::shared_ptr<DataBufferLLVM>
275 FileSystem::CreateDataBuffer(const llvm::Twine &path, uint64_t size,
276  uint64_t offset) {
277  if (m_collector)
278  m_collector->AddFile(path);
279 
280  const bool is_volatile = !IsLocal(path);
281  const ErrorOr<std::string> external_path = GetExternalPath(path);
282 
283  if (!external_path)
284  return nullptr;
285 
286  std::unique_ptr<llvm::WritableMemoryBuffer> buffer;
287  if (size == 0) {
288  auto buffer_or_error =
289  llvm::WritableMemoryBuffer::getFile(*external_path, -1, is_volatile);
290  if (!buffer_or_error)
291  return nullptr;
292  buffer = std::move(*buffer_or_error);
293  } else {
294  auto buffer_or_error = llvm::WritableMemoryBuffer::getFileSlice(
295  *external_path, size, offset, is_volatile);
296  if (!buffer_or_error)
297  return nullptr;
298  buffer = std::move(*buffer_or_error);
299  }
300  return std::shared_ptr<DataBufferLLVM>(new DataBufferLLVM(std::move(buffer)));
301 }
302 
303 std::shared_ptr<DataBufferLLVM>
304 FileSystem::CreateDataBuffer(const FileSpec &file_spec, uint64_t size,
305  uint64_t offset) {
306  return CreateDataBuffer(file_spec.GetPath(), size, offset);
307 }
308 
309 bool FileSystem::ResolveExecutableLocation(FileSpec &file_spec) {
310  // If the directory is set there's nothing to do.
311  ConstString directory = file_spec.GetDirectory();
312  if (directory)
313  return false;
314 
315  // We cannot look for a file if there's no file name.
316  ConstString filename = file_spec.GetFilename();
317  if (!filename)
318  return false;
319 
320  // Search for the file on the host.
321  const std::string filename_str(filename.GetCString());
322  llvm::ErrorOr<std::string> error_or_path =
323  llvm::sys::findProgramByName(filename_str);
324  if (!error_or_path)
325  return false;
326 
327  // findProgramByName returns "." if it can't find the file.
328  llvm::StringRef path = *error_or_path;
329  llvm::StringRef parent = llvm::sys::path::parent_path(path);
330  if (parent.empty() || parent == ".")
331  return false;
332 
333  // Make sure that the result exists.
334  FileSpec result(*error_or_path);
335  if (!Exists(result))
336  return false;
337 
338  file_spec = result;
339  return true;
340 }
341 
342 static int OpenWithFS(const FileSystem &fs, const char *path, int flags,
343  int mode) {
344  return const_cast<FileSystem &>(fs).Open(path, flags, mode);
345 }
346 
347 static int GetOpenFlags(uint32_t options) {
348  const bool read = options & File::eOpenOptionRead;
349  const bool write = options & File::eOpenOptionWrite;
350 
351  int open_flags = 0;
352  if (write) {
353  if (read)
354  open_flags |= O_RDWR;
355  else
356  open_flags |= O_WRONLY;
357 
358  if (options & File::eOpenOptionAppend)
359  open_flags |= O_APPEND;
360 
361  if (options & File::eOpenOptionTruncate)
362  open_flags |= O_TRUNC;
363 
364  if (options & File::eOpenOptionCanCreate)
365  open_flags |= O_CREAT;
366 
367  if (options & File::eOpenOptionCanCreateNewOnly)
368  open_flags |= O_CREAT | O_EXCL;
369  } else if (read) {
370  open_flags |= O_RDONLY;
371 
372 #ifndef _WIN32
373  if (options & File::eOpenOptionDontFollowSymlinks)
374  open_flags |= O_NOFOLLOW;
375 #endif
376  }
377 
378 #ifndef _WIN32
379  if (options & File::eOpenOptionNonBlocking)
380  open_flags |= O_NONBLOCK;
381  if (options & File::eOpenOptionCloseOnExec)
382  open_flags |= O_CLOEXEC;
383 #else
384  open_flags |= O_BINARY;
385 #endif
386 
387  return open_flags;
388 }
389 
390 static mode_t GetOpenMode(uint32_t permissions) {
391  mode_t mode = 0;
392  if (permissions & lldb::eFilePermissionsUserRead)
393  mode |= S_IRUSR;
394  if (permissions & lldb::eFilePermissionsUserWrite)
395  mode |= S_IWUSR;
396  if (permissions & lldb::eFilePermissionsUserExecute)
397  mode |= S_IXUSR;
398  if (permissions & lldb::eFilePermissionsGroupRead)
399  mode |= S_IRGRP;
400  if (permissions & lldb::eFilePermissionsGroupWrite)
401  mode |= S_IWGRP;
402  if (permissions & lldb::eFilePermissionsGroupExecute)
403  mode |= S_IXGRP;
404  if (permissions & lldb::eFilePermissionsWorldRead)
405  mode |= S_IROTH;
406  if (permissions & lldb::eFilePermissionsWorldWrite)
407  mode |= S_IWOTH;
408  if (permissions & lldb::eFilePermissionsWorldExecute)
409  mode |= S_IXOTH;
410  return mode;
411 }
412 
413 Status FileSystem::Open(File &File, const FileSpec &file_spec, uint32_t options,
414  uint32_t permissions, bool should_close_fd) {
415  if (m_collector)
416  m_collector->AddFile(file_spec);
417 
418  if (File.IsValid())
419  File.Close();
420 
421  const int open_flags = GetOpenFlags(options);
422  const mode_t open_mode =
423  (open_flags & O_CREAT) ? GetOpenMode(permissions) : 0;
424 
425  auto path = GetExternalPath(file_spec);
426  if (!path)
427  return Status(path.getError());
428 
429  int descriptor = llvm::sys::RetryAfterSignal(
430  -1, OpenWithFS, *this, path->c_str(), open_flags, open_mode);
431 
432  Status error;
433  if (!File::DescriptorIsValid(descriptor)) {
434  File.SetDescriptor(descriptor, false);
435  error.SetErrorToErrno();
436  } else {
437  File.SetDescriptor(descriptor, should_close_fd);
438  File.SetOptions(options);
439  }
440  return error;
441 }
442 
443 ErrorOr<std::string> FileSystem::GetExternalPath(const llvm::Twine &path) {
444  if (!m_mapped)
445  return path.str();
446 
447  // If VFS mapped we know the underlying FS is a RedirectingFileSystem.
448  ErrorOr<vfs::RedirectingFileSystem::Entry *> E =
449  static_cast<vfs::RedirectingFileSystem &>(*m_fs).lookupPath(path);
450  if (!E) {
451  if (E.getError() == llvm::errc::no_such_file_or_directory) {
452  return path.str();
453  }
454  return E.getError();
455  }
456 
457  auto *F = dyn_cast<vfs::RedirectingFileSystem::RedirectingFileEntry>(*E);
458  if (!F)
459  return make_error_code(llvm::errc::not_supported);
460 
461  return F->getExternalContentsPath().str();
462 }
463 
464 ErrorOr<std::string> FileSystem::GetExternalPath(const FileSpec &file_spec) {
465  return GetExternalPath(file_spec.GetPath());
466 }
ConstString & GetFilename()
Filename string get accessor.
Definition: FileSpec.cpp:369
void SetString(const llvm::StringRef &s)
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
Definition: Debugger.h:71
#define lldbassert(x)
Definition: LLDBAssert.h:15
#define O_NONBLOCK
llvm::Error Error
static int OpenWithFS(const FileSystem &fs, const char *path, int flags, int mode)
A file utility class.
Definition: FileSpec.h:55
A file class.
Definition: File.h:29
void SetOptions(uint32_t options)
Definition: File.h:365
static Permissions GetPermissions(const ELFSectionHeader &H)
Status Close() override
Definition: File.cpp:158
void SetIsResolved(bool is_resolved)
Set if the file path has been resolved or not.
Definition: FileSpec.h:403
Collects files into a directory and generates a mapping that can be used by the VFS.
Definition: FileCollector.h:26
#define S_IRGRP
#define S_IXOTH
static mode_t GetOpenMode(uint32_t permissions)
ConstString & GetDirectory()
Directory string get accessor.
Definition: FileSpec.cpp:363
bool ResolveFullPath(llvm::StringRef Expr, llvm::SmallVectorImpl< char > &Output)
Resolve an entire path that begins with a tilde expression, replacing the username portion with the m...
Style GetPathStyle() const
Definition: FileSpec.cpp:360
A uniqued constant string class.
Definition: ConstString.h:38
void SetPath(llvm::StringRef p)
Temporary helper for FileSystem change.
Definition: FileSpec.h:296
const char * GetCString() const
Get the string value as a C string.
Definition: ConstString.h:247
Definition: SBAddress.h:15
void SetDescriptor(int fd, bool transfer_ownership)
Definition: File.cpp:96
bool IsValid() const override
Definition: File.h:78
#define S_IXGRP
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:376
static int GetOpenFlags(uint32_t options)
bool IsEmpty() const
Test for empty string.
Definition: ConstString.h:340
#define S_IWGRP
#define S_IROTH
#define S_IWOTH
An error handling class.
Definition: Status.h:44