Coverage Report

Created: 2022-01-25 06:29

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Host/common/FileSystem.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- FileSystem.cpp ----------------------------------------------------===//
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
11
#include "lldb/Utility/LLDBAssert.h"
12
#include "lldb/Utility/TildeExpressionResolver.h"
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 <cerrno>
23
#include <climits>
24
#include <cstdarg>
25
#include <cstdio>
26
#include <fcntl.h>
27
28
#ifdef _WIN32
29
#include "lldb/Host/windows/windows.h"
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
2.38M
FileSystem &FileSystem::Instance() { return *InstanceImpl(); }
46
47
3.64k
void FileSystem::Initialize() {
48
3.64k
  lldbassert(!InstanceImpl() && "Already initialized.");
49
3.64k
  InstanceImpl().emplace();
50
3.64k
}
51
52
19
void FileSystem::Initialize(std::shared_ptr<FileCollectorBase> collector) {
53
19
  lldbassert(!InstanceImpl() && "Already initialized.");
54
19
  InstanceImpl().emplace(collector);
55
19
}
56
57
0
llvm::Error FileSystem::Initialize(const FileSpec &mapping) {
58
0
  lldbassert(!InstanceImpl() && "Already initialized.");
59
60
0
  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer =
61
0
      llvm::vfs::getRealFileSystem()->getBufferForFile(mapping.GetPath());
62
63
0
  if (!buffer)
64
0
    return llvm::errorCodeToError(buffer.getError());
65
66
0
  InstanceImpl().emplace(llvm::vfs::getVFSFromYAML(std::move(buffer.get()),
67
0
                                                   nullptr, mapping.GetPath()),
68
0
                         true);
69
70
0
  return llvm::Error::success();
71
0
}
72
73
14
void FileSystem::Initialize(IntrusiveRefCntPtr<vfs::FileSystem> fs) {
74
14
  lldbassert(!InstanceImpl() && "Already initialized.");
75
14
  InstanceImpl().emplace(fs);
76
14
}
77
78
3.67k
void FileSystem::Terminate() {
79
3.67k
  lldbassert(InstanceImpl() && "Already terminated.");
80
3.67k
  InstanceImpl().reset();
81
3.67k
}
82
83
2.40M
Optional<FileSystem> &FileSystem::InstanceImpl() {
84
2.40M
  static Optional<FileSystem> g_fs;
85
2.40M
  return g_fs;
86
2.40M
}
87
88
vfs::directory_iterator FileSystem::DirBegin(const FileSpec &file_spec,
89
1
                                             std::error_code &ec) {
90
1
  if (!file_spec) {
91
1
    ec = std::error_code(static_cast<int>(errc::no_such_file_or_directory),
92
1
                         std::system_category());
93
1
    return {};
94
1
  }
95
0
  return DirBegin(file_spec.GetPath(), ec);
96
1
}
97
98
vfs::directory_iterator FileSystem::DirBegin(const Twine &dir,
99
19
                                             std::error_code &ec) {
100
19
  return m_fs->dir_begin(dir, ec);
101
19
}
102
103
llvm::ErrorOr<vfs::Status>
104
1
FileSystem::GetStatus(const FileSpec &file_spec) const {
105
1
  if (!file_spec)
106
1
    return std::error_code(static_cast<int>(errc::no_such_file_or_directory),
107
1
                           std::system_category());
108
0
  return GetStatus(file_spec.GetPath());
109
1
}
110
111
276
llvm::ErrorOr<vfs::Status> FileSystem::GetStatus(const Twine &path) const {
112
276
  return m_fs->status(path);
113
276
}
114
115
sys::TimePoint<>
116
48.7k
FileSystem::GetModificationTime(const FileSpec &file_spec) const {
117
48.7k
  if (!file_spec)
118
9
    return sys::TimePoint<>();
119
48.7k
  return GetModificationTime(file_spec.GetPath());
120
48.7k
}
121
122
48.7k
sys::TimePoint<> FileSystem::GetModificationTime(const Twine &path) const {
123
48.7k
  ErrorOr<vfs::Status> status = m_fs->status(path);
124
48.7k
  if (!status)
125
6.02k
    return sys::TimePoint<>();
126
42.7k
  return status->getLastModificationTime();
127
48.7k
}
128
129
723k
uint64_t FileSystem::GetByteSize(const FileSpec &file_spec) const {
130
723k
  if (!file_spec)
131
36
    return 0;
132
723k
  return GetByteSize(file_spec.GetPath());
133
723k
}
134
135
723k
uint64_t FileSystem::GetByteSize(const Twine &path) const {
136
723k
  ErrorOr<vfs::Status> status = m_fs->status(path);
137
723k
  if (!status)
138
2.78k
    return 0;
139
721k
  return status->getSize();
140
723k
}
141
142
39
uint32_t FileSystem::GetPermissions(const FileSpec &file_spec) const {
143
39
  return GetPermissions(file_spec.GetPath());
144
39
}
145
146
uint32_t FileSystem::GetPermissions(const FileSpec &file_spec,
147
0
                                    std::error_code &ec) const {
148
0
  if (!file_spec)
149
0
    return sys::fs::perms::perms_not_known;
150
0
  return GetPermissions(file_spec.GetPath(), ec);
151
0
}
152
153
45
uint32_t FileSystem::GetPermissions(const Twine &path) const {
154
45
  std::error_code ec;
155
45
  return GetPermissions(path, ec);
156
45
}
157
158
uint32_t FileSystem::GetPermissions(const Twine &path,
159
45
                                    std::error_code &ec) const {
160
45
  ErrorOr<vfs::Status> status = m_fs->status(path);
161
45
  if (!status) {
162
37
    ec = status.getError();
163
37
    return sys::fs::perms::perms_not_known;
164
37
  }
165
8
  return status->getPermissions();
166
45
}
167
168
1.16M
bool FileSystem::Exists(const Twine &path) const { return m_fs->exists(path); }
169
170
578k
bool FileSystem::Exists(const FileSpec &file_spec) const {
171
578k
  return file_spec && 
Exists(file_spec.GetPath())563k
;
172
578k
}
173
174
5
bool FileSystem::Readable(const Twine &path) const {
175
5
  return GetPermissions(path) & sys::fs::perms::all_read;
176
5
}
177
178
4
bool FileSystem::Readable(const FileSpec &file_spec) const {
179
4
  return file_spec && 
Readable(file_spec.GetPath())3
;
180
4
}
181
182
159k
bool FileSystem::IsDirectory(const Twine &path) const {
183
159k
  ErrorOr<vfs::Status> status = m_fs->status(path);
184
159k
  if (!status)
185
1.32k
    return false;
186
157k
  return status->isDirectory();
187
159k
}
188
189
155k
bool FileSystem::IsDirectory(const FileSpec &file_spec) const {
190
155k
  return file_spec && 
IsDirectory(file_spec.GetPath())155k
;
191
155k
}
192
193
64.0k
bool FileSystem::IsLocal(const Twine &path) const {
194
64.0k
  bool b = false;
195
64.0k
  m_fs->isLocal(path, b);
196
64.0k
  return b;
197
64.0k
}
198
199
1
bool FileSystem::IsLocal(const FileSpec &file_spec) const {
200
1
  return file_spec && 
IsLocal(file_spec.GetPath())0
;
201
1
}
202
203
void FileSystem::EnumerateDirectory(Twine path, bool find_directories,
204
                                    bool find_files, bool find_other,
205
                                    EnumerateDirectoryCallbackType callback,
206
89
                                    void *callback_baton) {
207
89
  std::error_code EC;
208
89
  vfs::recursive_directory_iterator Iter(*m_fs, path, EC);
209
89
  vfs::recursive_directory_iterator End;
210
162
  for (; Iter != End && 
!EC73
;
Iter.increment(EC)73
) {
211
73
    const auto &Item = *Iter;
212
73
    ErrorOr<vfs::Status> Status = m_fs->status(Item.path());
213
73
    if (!Status)
214
0
      break;
215
73
    if (!find_files && 
Status->isRegularFile()69
)
216
0
      continue;
217
73
    if (!find_directories && 
Status->isDirectory()0
)
218
0
      continue;
219
73
    if (!find_other && 
Status->isOther()69
)
220
0
      continue;
221
222
73
    auto Result = callback(callback_baton, Status->getType(), Item.path());
223
73
    if (Result == eEnumerateDirectoryResultQuit)
224
0
      return;
225
73
    if (Result == eEnumerateDirectoryResultNext) {
226
      // Default behavior is to recurse. Opt out if the callback doesn't want
227
      // this behavior.
228
73
      Iter.no_push();
229
73
    }
230
73
  }
231
89
}
232
233
602k
std::error_code FileSystem::MakeAbsolute(SmallVectorImpl<char> &path) const {
234
602k
  return m_fs->makeAbsolute(path);
235
602k
}
236
237
1
std::error_code FileSystem::MakeAbsolute(FileSpec &file_spec) const {
238
1
  SmallString<128> path;
239
1
  file_spec.GetPath(path, false);
240
241
1
  auto EC = MakeAbsolute(path);
242
1
  if (EC)
243
0
    return EC;
244
245
1
  FileSpec new_file_spec(path, file_spec.GetPathStyle());
246
1
  file_spec = new_file_spec;
247
1
  return {};
248
1
}
249
250
std::error_code FileSystem::GetRealPath(const Twine &path,
251
0
                                        SmallVectorImpl<char> &output) const {
252
0
  return m_fs->getRealPath(path, output);
253
0
}
254
255
602k
void FileSystem::Resolve(SmallVectorImpl<char> &path) {
256
602k
  if (path.empty())
257
0
    return;
258
259
  // Resolve tilde in path.
260
602k
  SmallString<128> resolved(path.begin(), path.end());
261
602k
  StandardTildeExpressionResolver Resolver;
262
602k
  Resolver.ResolveFullPath(llvm::StringRef(path.begin(), path.size()),
263
602k
                           resolved);
264
265
  // Try making the path absolute if it exists.
266
602k
  SmallString<128> absolute(resolved.begin(), resolved.end());
267
602k
  MakeAbsolute(absolute);
268
269
602k
  path.clear();
270
602k
  if (Exists(absolute)) {
271
440k
    path.append(absolute.begin(), absolute.end());
272
440k
  } else {
273
161k
    path.append(resolved.begin(), resolved.end());
274
161k
  }
275
602k
}
276
277
608k
void FileSystem::Resolve(FileSpec &file_spec) {
278
608k
  if (!file_spec)
279
6.11k
    return;
280
281
  // Extract path from the FileSpec.
282
602k
  SmallString<128> path;
283
602k
  file_spec.GetPath(path);
284
285
  // Resolve the path.
286
602k
  Resolve(path);
287
288
  // Update the FileSpec with the resolved path.
289
602k
  if (file_spec.GetFilename().IsEmpty())
290
755
    file_spec.GetDirectory().SetString(path);
291
601k
  else
292
601k
    file_spec.SetPath(path);
293
602k
  file_spec.SetIsResolved(true);
294
602k
}
295
296
std::shared_ptr<DataBufferLLVM>
297
FileSystem::CreateDataBuffer(const llvm::Twine &path, uint64_t size,
298
64.0k
                             uint64_t offset) {
299
64.0k
  Collect(path);
300
301
64.0k
  const bool is_volatile = !IsLocal(path);
302
64.0k
  const ErrorOr<std::string> external_path = GetExternalPath(path);
303
304
64.0k
  if (!external_path)
305
0
    return nullptr;
306
307
64.0k
  std::unique_ptr<llvm::WritableMemoryBuffer> buffer;
308
64.0k
  if (size == 0) {
309
3.44k
    auto buffer_or_error =
310
3.44k
        llvm::WritableMemoryBuffer::getFile(*external_path, is_volatile);
311
3.44k
    if (!buffer_or_error)
312
0
      return nullptr;
313
3.44k
    buffer = std::move(*buffer_or_error);
314
60.6k
  } else {
315
60.6k
    auto buffer_or_error = llvm::WritableMemoryBuffer::getFileSlice(
316
60.6k
        *external_path, size, offset, is_volatile);
317
60.6k
    if (!buffer_or_error)
318
1.76k
      return nullptr;
319
58.8k
    buffer = std::move(*buffer_or_error);
320
58.8k
  }
321
62.3k
  return std::shared_ptr<DataBufferLLVM>(new DataBufferLLVM(std::move(buffer)));
322
64.0k
}
323
324
std::shared_ptr<DataBufferLLVM>
325
FileSystem::CreateDataBuffer(const FileSpec &file_spec, uint64_t size,
326
3.45k
                             uint64_t offset) {
327
3.45k
  return CreateDataBuffer(file_spec.GetPath(), size, offset);
328
3.45k
}
329
330
1.46k
bool FileSystem::ResolveExecutableLocation(FileSpec &file_spec) {
331
  // If the directory is set there's nothing to do.
332
1.46k
  ConstString directory = file_spec.GetDirectory();
333
1.46k
  if (directory)
334
1.42k
    return false;
335
336
  // We cannot look for a file if there's no file name.
337
40
  ConstString filename = file_spec.GetFilename();
338
40
  if (!filename)
339
36
    return false;
340
341
  // Search for the file on the host.
342
4
  const std::string filename_str(filename.GetCString());
343
4
  llvm::ErrorOr<std::string> error_or_path =
344
4
      llvm::sys::findProgramByName(filename_str);
345
4
  if (!error_or_path)
346
3
    return false;
347
348
  // findProgramByName returns "." if it can't find the file.
349
1
  llvm::StringRef path = *error_or_path;
350
1
  llvm::StringRef parent = llvm::sys::path::parent_path(path);
351
1
  if (parent.empty() || parent == ".")
352
0
    return false;
353
354
  // Make sure that the result exists.
355
1
  FileSpec result(*error_or_path);
356
1
  if (!Exists(result))
357
0
    return false;
358
359
1
  file_spec = result;
360
1
  return true;
361
1
}
362
363
3.43k
bool FileSystem::GetHomeDirectory(SmallVectorImpl<char> &path) const {
364
3.43k
  if (!m_home_directory.empty()) {
365
0
    path.assign(m_home_directory.begin(), m_home_directory.end());
366
0
    return true;
367
0
  }
368
3.43k
  return llvm::sys::path::home_directory(path);
369
3.43k
}
370
371
0
bool FileSystem::GetHomeDirectory(FileSpec &file_spec) const {
372
0
  SmallString<128> home_dir;
373
0
  if (!GetHomeDirectory(home_dir))
374
0
    return false;
375
0
  file_spec.SetPath(home_dir);
376
0
  return true;
377
0
}
378
379
static int OpenWithFS(const FileSystem &fs, const char *path, int flags,
380
10.8k
                      int mode) {
381
10.8k
  return const_cast<FileSystem &>(fs).Open(path, flags, mode);
382
10.8k
}
383
384
10.8k
static int GetOpenFlags(File::OpenOptions options) {
385
10.8k
  int open_flags = 0;
386
10.8k
  File::OpenOptions rw =
387
10.8k
      options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
388
10.8k
                 File::eOpenOptionReadWrite);
389
10.8k
  if (rw == File::eOpenOptionWriteOnly || 
rw == File::eOpenOptionReadWrite5.68k
) {
390
5.18k
    if (rw == File::eOpenOptionReadWrite)
391
0
      open_flags |= O_RDWR;
392
5.18k
    else
393
5.18k
      open_flags |= O_WRONLY;
394
395
5.18k
    if (options & File::eOpenOptionAppend)
396
4
      open_flags |= O_APPEND;
397
398
5.18k
    if (options & File::eOpenOptionTruncate)
399
62
      open_flags |= O_TRUNC;
400
401
5.18k
    if (options & File::eOpenOptionCanCreate)
402
69
      open_flags |= O_CREAT;
403
404
5.18k
    if (options & File::eOpenOptionCanCreateNewOnly)
405
0
      open_flags |= O_CREAT | O_EXCL;
406
5.68k
  } else if (rw == File::eOpenOptionReadOnly) {
407
5.68k
    open_flags |= O_RDONLY;
408
409
5.68k
#ifndef _WIN32
410
5.68k
    if (options & File::eOpenOptionDontFollowSymlinks)
411
0
      open_flags |= O_NOFOLLOW;
412
5.68k
#endif
413
5.68k
  }
414
415
10.8k
#ifndef _WIN32
416
10.8k
  if (options & File::eOpenOptionNonBlocking)
417
0
    open_flags |= O_NONBLOCK;
418
10.8k
  if (options & File::eOpenOptionCloseOnExec)
419
16
    open_flags |= O_CLOEXEC;
420
#else
421
  open_flags |= O_BINARY;
422
#endif
423
424
10.8k
  return open_flags;
425
10.8k
}
426
427
69
static mode_t GetOpenMode(uint32_t permissions) {
428
69
  mode_t mode = 0;
429
69
  if (permissions & lldb::eFilePermissionsUserRead)
430
69
    mode |= S_IRUSR;
431
69
  if (permissions & lldb::eFilePermissionsUserWrite)
432
69
    mode |= S_IWUSR;
433
69
  if (permissions & lldb::eFilePermissionsUserExecute)
434
0
    mode |= S_IXUSR;
435
69
  if (permissions & lldb::eFilePermissionsGroupRead)
436
0
    mode |= S_IRGRP;
437
69
  if (permissions & lldb::eFilePermissionsGroupWrite)
438
0
    mode |= S_IWGRP;
439
69
  if (permissions & lldb::eFilePermissionsGroupExecute)
440
0
    mode |= S_IXGRP;
441
69
  if (permissions & lldb::eFilePermissionsWorldRead)
442
0
    mode |= S_IROTH;
443
69
  if (permissions & lldb::eFilePermissionsWorldWrite)
444
0
    mode |= S_IWOTH;
445
69
  if (permissions & lldb::eFilePermissionsWorldExecute)
446
0
    mode |= S_IXOTH;
447
69
  return mode;
448
69
}
449
450
Expected<FileUP> FileSystem::Open(const FileSpec &file_spec,
451
                                  File::OpenOptions options,
452
10.8k
                                  uint32_t permissions, bool should_close_fd) {
453
10.8k
  Collect(file_spec.GetPath());
454
455
10.8k
  const int open_flags = GetOpenFlags(options);
456
10.8k
  const mode_t open_mode =
457
10.8k
      (open_flags & O_CREAT) ? 
GetOpenMode(permissions)69
:
010.8k
;
458
459
10.8k
  auto path = GetExternalPath(file_spec);
460
10.8k
  if (!path)
461
0
    return errorCodeToError(path.getError());
462
463
10.8k
  int descriptor = llvm::sys::RetryAfterSignal(
464
10.8k
      -1, OpenWithFS, *this, path->c_str(), open_flags, open_mode);
465
466
10.8k
  if (!File::DescriptorIsValid(descriptor))
467
7
    return llvm::errorCodeToError(
468
7
        std::error_code(errno, std::system_category()));
469
470
10.8k
  auto file = std::unique_ptr<File>(
471
10.8k
      new NativeFile(descriptor, options, should_close_fd));
472
10.8k
  assert(file->IsValid());
473
0
  return std::move(file);
474
10.8k
}
475
476
81.5k
ErrorOr<std::string> FileSystem::GetExternalPath(const llvm::Twine &path) {
477
81.5k
  if (!m_mapped)
478
81.5k
    return path.str();
479
480
  // If VFS mapped we know the underlying FS is a RedirectingFileSystem.
481
0
  ErrorOr<vfs::RedirectingFileSystem::LookupResult> Result =
482
0
      static_cast<vfs::RedirectingFileSystem &>(*m_fs).lookupPath(path.str());
483
0
  if (!Result) {
484
0
    if (Result.getError() == llvm::errc::no_such_file_or_directory) {
485
0
      return path.str();
486
0
    }
487
0
    return Result.getError();
488
0
  }
489
490
0
  if (Optional<StringRef> ExtRedirect = Result->getExternalRedirect())
491
0
    return std::string(*ExtRedirect);
492
0
  return make_error_code(llvm::errc::not_supported);
493
0
}
494
495
17.4k
ErrorOr<std::string> FileSystem::GetExternalPath(const FileSpec &file_spec) {
496
17.4k
  return GetExternalPath(file_spec.GetPath());
497
17.4k
}
498
499
1.73k
void FileSystem::Collect(const FileSpec &file_spec) {
500
1.73k
  Collect(file_spec.GetPath());
501
1.73k
}
502
503
87.7k
void FileSystem::Collect(const llvm::Twine &file) {
504
87.7k
  if (!m_collector)
505
87.3k
    return;
506
507
421
  if (llvm::sys::fs::is_directory(file))
508
0
    m_collector->addDirectory(file);
509
421
  else
510
421
    m_collector->addFile(file);
511
421
}
512
513
0
void FileSystem::SetHomeDirectory(std::string home_directory) {
514
0
  m_home_directory = std::move(home_directory);
515
0
}
516
517
1
Status FileSystem::RemoveFile(const FileSpec &file_spec) {
518
1
  return RemoveFile(file_spec.GetPath());
519
1
}
520
521
1
Status FileSystem::RemoveFile(const llvm::Twine &path) {
522
1
  return Status(llvm::sys::fs::remove(path));
523
1
}