Coverage Report

Created: 2023-09-30 09:22

/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/DataBufferLLVM.h"
12
13
#include "llvm/Support/Errc.h"
14
#include "llvm/Support/Errno.h"
15
#include "llvm/Support/Error.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 <cerrno>
22
#include <climits>
23
#include <cstdarg>
24
#include <cstdio>
25
#include <fcntl.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 <optional>
39
#include <vector>
40
41
using namespace lldb;
42
using namespace lldb_private;
43
using namespace llvm;
44
45
2.01M
FileSystem &FileSystem::Instance() { return *InstanceImpl(); }
46
47
4.24k
void FileSystem::Terminate() {
48
4.24k
  lldbassert(InstanceImpl() && "Already terminated.");
49
4.24k
  InstanceImpl().reset();
50
4.24k
}
51
52
2.03M
std::optional<FileSystem> &FileSystem::InstanceImpl() {
53
2.03M
  static std::optional<FileSystem> g_fs;
54
2.03M
  return g_fs;
55
2.03M
}
56
57
vfs::directory_iterator FileSystem::DirBegin(const FileSpec &file_spec,
58
1
                                             std::error_code &ec) {
59
1
  if (!file_spec) {
60
1
    ec = std::error_code(static_cast<int>(errc::no_such_file_or_directory),
61
1
                         std::system_category());
62
1
    return {};
63
1
  }
64
0
  return DirBegin(file_spec.GetPath(), ec);
65
1
}
66
67
vfs::directory_iterator FileSystem::DirBegin(const Twine &dir,
68
21
                                             std::error_code &ec) {
69
21
  return m_fs->dir_begin(dir, ec);
70
21
}
71
72
llvm::ErrorOr<vfs::Status>
73
1
FileSystem::GetStatus(const FileSpec &file_spec) const {
74
1
  if (!file_spec)
75
1
    return std::error_code(static_cast<int>(errc::no_such_file_or_directory),
76
1
                           std::system_category());
77
0
  return GetStatus(file_spec.GetPath());
78
1
}
79
80
325
llvm::ErrorOr<vfs::Status> FileSystem::GetStatus(const Twine &path) const {
81
325
  return m_fs->status(path);
82
325
}
83
84
sys::TimePoint<>
85
41.2k
FileSystem::GetModificationTime(const FileSpec &file_spec) const {
86
41.2k
  if (!file_spec)
87
10
    return sys::TimePoint<>();
88
41.2k
  return GetModificationTime(file_spec.GetPath());
89
41.2k
}
90
91
41.2k
sys::TimePoint<> FileSystem::GetModificationTime(const Twine &path) const {
92
41.2k
  ErrorOr<vfs::Status> status = m_fs->status(path);
93
41.2k
  if (!status)
94
4.83k
    return sys::TimePoint<>();
95
36.3k
  return status->getLastModificationTime();
96
41.2k
}
97
98
605k
uint64_t FileSystem::GetByteSize(const FileSpec &file_spec) const {
99
605k
  if (!file_spec)
100
47
    return 0;
101
605k
  return GetByteSize(file_spec.GetPath());
102
605k
}
103
104
605k
uint64_t FileSystem::GetByteSize(const Twine &path) const {
105
605k
  ErrorOr<vfs::Status> status = m_fs->status(path);
106
605k
  if (!status)
107
2.30k
    return 0;
108
602k
  return status->getSize();
109
605k
}
110
111
51
uint32_t FileSystem::GetPermissions(const FileSpec &file_spec) const {
112
51
  return GetPermissions(file_spec.GetPath());
113
51
}
114
115
uint32_t FileSystem::GetPermissions(const FileSpec &file_spec,
116
0
                                    std::error_code &ec) const {
117
0
  if (!file_spec)
118
0
    return sys::fs::perms::perms_not_known;
119
0
  return GetPermissions(file_spec.GetPath(), ec);
120
0
}
121
122
57
uint32_t FileSystem::GetPermissions(const Twine &path) const {
123
57
  std::error_code ec;
124
57
  return GetPermissions(path, ec);
125
57
}
126
127
uint32_t FileSystem::GetPermissions(const Twine &path,
128
57
                                    std::error_code &ec) const {
129
57
  ErrorOr<vfs::Status> status = m_fs->status(path);
130
57
  if (!status) {
131
48
    ec = status.getError();
132
48
    return sys::fs::perms::perms_not_known;
133
48
  }
134
9
  return status->getPermissions();
135
57
}
136
137
991k
bool FileSystem::Exists(const Twine &path) const { return m_fs->exists(path); }
138
139
489k
bool FileSystem::Exists(const FileSpec &file_spec) const {
140
489k
  return file_spec && 
Exists(file_spec.GetPath())475k
;
141
489k
}
142
143
5
bool FileSystem::Readable(const Twine &path) const {
144
5
  return GetPermissions(path) & sys::fs::perms::all_read;
145
5
}
146
147
4
bool FileSystem::Readable(const FileSpec &file_spec) const {
148
4
  return file_spec && 
Readable(file_spec.GetPath())3
;
149
4
}
150
151
130k
bool FileSystem::IsDirectory(const Twine &path) const {
152
130k
  ErrorOr<vfs::Status> status = m_fs->status(path);
153
130k
  if (!status)
154
593
    return false;
155
129k
  return status->isDirectory();
156
130k
}
157
158
126k
bool FileSystem::IsDirectory(const FileSpec &file_spec) const {
159
126k
  return file_spec && 
IsDirectory(file_spec.GetPath())126k
;
160
126k
}
161
162
63.7k
bool FileSystem::IsLocal(const Twine &path) const {
163
63.7k
  bool b = false;
164
63.7k
  m_fs->isLocal(path, b);
165
63.7k
  return b;
166
63.7k
}
167
168
1
bool FileSystem::IsLocal(const FileSpec &file_spec) const {
169
1
  return file_spec && 
IsLocal(file_spec.GetPath())0
;
170
1
}
171
172
void FileSystem::EnumerateDirectory(Twine path, bool find_directories,
173
                                    bool find_files, bool find_other,
174
                                    EnumerateDirectoryCallbackType callback,
175
2.05k
                                    void *callback_baton) {
176
2.05k
  std::error_code EC;
177
2.05k
  vfs::recursive_directory_iterator Iter(*m_fs, path, EC);
178
2.05k
  vfs::recursive_directory_iterator End;
179
2.59k
  for (; Iter != End && 
!EC539
;
Iter.increment(EC)539
) {
180
539
    const auto &Item = *Iter;
181
539
    ErrorOr<vfs::Status> Status = m_fs->status(Item.path());
182
539
    if (!Status)
183
1
      continue;
184
538
    if (!find_files && 
Status->isRegularFile()534
)
185
0
      continue;
186
538
    if (!find_directories && 
Status->isDirectory()0
)
187
0
      continue;
188
538
    if (!find_other && 
Status->isOther()81
)
189
0
      continue;
190
191
538
    auto Result = callback(callback_baton, Status->getType(), Item.path());
192
538
    if (Result == eEnumerateDirectoryResultQuit)
193
0
      return;
194
538
    if (Result == eEnumerateDirectoryResultNext) {
195
      // Default behavior is to recurse. Opt out if the callback doesn't want
196
      // this behavior.
197
538
      Iter.no_push();
198
538
    }
199
538
  }
200
2.05k
}
201
202
513k
std::error_code FileSystem::MakeAbsolute(SmallVectorImpl<char> &path) const {
203
513k
  return m_fs->makeAbsolute(path);
204
513k
}
205
206
1
std::error_code FileSystem::MakeAbsolute(FileSpec &file_spec) const {
207
1
  SmallString<128> path;
208
1
  file_spec.GetPath(path, false);
209
210
1
  auto EC = MakeAbsolute(path);
211
1
  if (EC)
212
0
    return EC;
213
214
1
  FileSpec new_file_spec(path, file_spec.GetPathStyle());
215
1
  file_spec = new_file_spec;
216
1
  return {};
217
1
}
218
219
std::error_code FileSystem::GetRealPath(const Twine &path,
220
0
                                        SmallVectorImpl<char> &output) const {
221
0
  return m_fs->getRealPath(path, output);
222
0
}
223
224
513k
void FileSystem::Resolve(SmallVectorImpl<char> &path) {
225
513k
  if (path.empty())
226
0
    return;
227
228
  // Resolve tilde in path.
229
513k
  SmallString<128> resolved(path.begin(), path.end());
230
513k
  assert(m_tilde_resolver && "must initialize tilde resolver in constructor");
231
513k
  m_tilde_resolver->ResolveFullPath(llvm::StringRef(path.begin(), path.size()),
232
513k
                                    resolved);
233
234
  // Try making the path absolute if it exists.
235
513k
  SmallString<128> absolute(resolved.begin(), resolved.end());
236
513k
  MakeAbsolute(absolute);
237
238
513k
  path.clear();
239
513k
  if (Exists(absolute)) {
240
368k
    path.append(absolute.begin(), absolute.end());
241
368k
  } else {
242
145k
    path.append(resolved.begin(), resolved.end());
243
145k
  }
244
513k
}
245
246
519k
void FileSystem::Resolve(FileSpec &file_spec) {
247
519k
  if (!file_spec)
248
6.22k
    return;
249
250
  // Extract path from the FileSpec.
251
513k
  SmallString<128> path;
252
513k
  file_spec.GetPath(path);
253
254
  // Resolve the path.
255
513k
  Resolve(path);
256
257
  // Update the FileSpec with the resolved path.
258
513k
  if (file_spec.GetFilename().IsEmpty())
259
813
    file_spec.SetDirectory(path);
260
512k
  else
261
512k
    file_spec.SetPath(path);
262
513k
  file_spec.SetIsResolved(true);
263
513k
}
264
265
template <typename T>
266
static std::unique_ptr<T> GetMemoryBuffer(const llvm::Twine &path,
267
                                          uint64_t size, uint64_t offset,
268
63.7k
                                          bool is_volatile) {
269
63.7k
  std::unique_ptr<T> buffer;
270
63.7k
  if (size == 0) {
271
3.75k
    auto buffer_or_error = T::getFile(path, is_volatile);
272
3.75k
    if (!buffer_or_error)
273
0
      return nullptr;
274
3.75k
    buffer = std::move(*buffer_or_error);
275
60.0k
  } else {
276
60.0k
    auto buffer_or_error = T::getFileSlice(path, size, offset, is_volatile);
277
60.0k
    if (!buffer_or_error)
278
1.96k
      return nullptr;
279
58.0k
    buffer = std::move(*buffer_or_error);
280
58.0k
  }
281
61.8k
  return buffer;
282
63.7k
}
FileSystem.cpp:std::__1::unique_ptr<llvm::WritableMemoryBuffer, std::__1::default_delete<llvm::WritableMemoryBuffer> > GetMemoryBuffer<llvm::WritableMemoryBuffer>(llvm::Twine const&, unsigned long long, unsigned long long, bool)
Line
Count
Source
268
2.46k
                                          bool is_volatile) {
269
2.46k
  std::unique_ptr<T> buffer;
270
2.46k
  if (size == 0) {
271
2.08k
    auto buffer_or_error = T::getFile(path, is_volatile);
272
2.08k
    if (!buffer_or_error)
273
0
      return nullptr;
274
2.08k
    buffer = std::move(*buffer_or_error);
275
2.08k
  } else {
276
374
    auto buffer_or_error = T::getFileSlice(path, size, offset, is_volatile);
277
374
    if (!buffer_or_error)
278
0
      return nullptr;
279
374
    buffer = std::move(*buffer_or_error);
280
374
  }
281
2.46k
  return buffer;
282
2.46k
}
FileSystem.cpp:std::__1::unique_ptr<llvm::MemoryBuffer, std::__1::default_delete<llvm::MemoryBuffer> > GetMemoryBuffer<llvm::MemoryBuffer>(llvm::Twine const&, unsigned long long, unsigned long long, bool)
Line
Count
Source
268
61.3k
                                          bool is_volatile) {
269
61.3k
  std::unique_ptr<T> buffer;
270
61.3k
  if (size == 0) {
271
1.66k
    auto buffer_or_error = T::getFile(path, is_volatile);
272
1.66k
    if (!buffer_or_error)
273
0
      return nullptr;
274
1.66k
    buffer = std::move(*buffer_or_error);
275
59.6k
  } else {
276
59.6k
    auto buffer_or_error = T::getFileSlice(path, size, offset, is_volatile);
277
59.6k
    if (!buffer_or_error)
278
1.96k
      return nullptr;
279
57.7k
    buffer = std::move(*buffer_or_error);
280
57.7k
  }
281
59.3k
  return buffer;
282
61.3k
}
283
284
std::shared_ptr<WritableDataBuffer>
285
FileSystem::CreateWritableDataBuffer(const llvm::Twine &path, uint64_t size,
286
2.46k
                                     uint64_t offset) {
287
2.46k
  const bool is_volatile = !IsLocal(path);
288
2.46k
  auto buffer = GetMemoryBuffer<llvm::WritableMemoryBuffer>(path, size, offset,
289
2.46k
                                                            is_volatile);
290
2.46k
  if (!buffer)
291
0
    return {};
292
2.46k
  return std::shared_ptr<WritableDataBufferLLVM>(
293
2.46k
      new WritableDataBufferLLVM(std::move(buffer)));
294
2.46k
}
295
296
std::shared_ptr<DataBuffer>
297
FileSystem::CreateDataBuffer(const llvm::Twine &path, uint64_t size,
298
61.3k
                             uint64_t offset) {
299
61.3k
  const bool is_volatile = !IsLocal(path);
300
61.3k
  auto buffer =
301
61.3k
      GetMemoryBuffer<llvm::MemoryBuffer>(path, size, offset, is_volatile);
302
61.3k
  if (!buffer)
303
1.96k
    return {};
304
59.3k
  return std::shared_ptr<DataBufferLLVM>(new DataBufferLLVM(std::move(buffer)));
305
61.3k
}
306
307
std::shared_ptr<WritableDataBuffer>
308
FileSystem::CreateWritableDataBuffer(const FileSpec &file_spec, uint64_t size,
309
2.08k
                                     uint64_t offset) {
310
2.08k
  return CreateWritableDataBuffer(file_spec.GetPath(), size, offset);
311
2.08k
}
312
313
std::shared_ptr<DataBuffer>
314
FileSystem::CreateDataBuffer(const FileSpec &file_spec, uint64_t size,
315
1.68k
                             uint64_t offset) {
316
1.68k
  return CreateDataBuffer(file_spec.GetPath(), size, offset);
317
1.68k
}
318
319
750
bool FileSystem::ResolveExecutableLocation(FileSpec &file_spec) {
320
  // If the directory is set there's nothing to do.
321
750
  ConstString directory = file_spec.GetDirectory();
322
750
  if (directory)
323
698
    return false;
324
325
  // We cannot look for a file if there's no file name.
326
52
  ConstString filename = file_spec.GetFilename();
327
52
  if (!filename)
328
47
    return false;
329
330
  // Search for the file on the host.
331
5
  const std::string filename_str(filename.GetCString());
332
5
  llvm::ErrorOr<std::string> error_or_path =
333
5
      llvm::sys::findProgramByName(filename_str);
334
5
  if (!error_or_path)
335
4
    return false;
336
337
  // findProgramByName returns "." if it can't find the file.
338
1
  llvm::StringRef path = *error_or_path;
339
1
  llvm::StringRef parent = llvm::sys::path::parent_path(path);
340
1
  if (parent.empty() || parent == ".")
341
0
    return false;
342
343
  // Make sure that the result exists.
344
1
  FileSpec result(*error_or_path);
345
1
  if (!Exists(result))
346
0
    return false;
347
348
1
  file_spec = result;
349
1
  return true;
350
1
}
351
352
3.93k
bool FileSystem::GetHomeDirectory(SmallVectorImpl<char> &path) const {
353
3.93k
  if (!m_home_directory.empty()) {
354
0
    path.assign(m_home_directory.begin(), m_home_directory.end());
355
0
    return true;
356
0
  }
357
3.93k
  return llvm::sys::path::home_directory(path);
358
3.93k
}
359
360
0
bool FileSystem::GetHomeDirectory(FileSpec &file_spec) const {
361
0
  SmallString<128> home_dir;
362
0
  if (!GetHomeDirectory(home_dir))
363
0
    return false;
364
0
  file_spec.SetPath(home_dir);
365
0
  return true;
366
0
}
367
368
static int OpenWithFS(const FileSystem &fs, const char *path, int flags,
369
12.6k
                      int mode) {
370
12.6k
  return const_cast<FileSystem &>(fs).Open(path, flags, mode);
371
12.6k
}
372
373
12.6k
static int GetOpenFlags(File::OpenOptions options) {
374
12.6k
  int open_flags = 0;
375
12.6k
  File::OpenOptions rw =
376
12.6k
      options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
377
12.6k
                 File::eOpenOptionReadWrite);
378
12.6k
  if (rw == File::eOpenOptionWriteOnly || 
rw == File::eOpenOptionReadWrite6.76k
) {
379
5.84k
    if (rw == File::eOpenOptionReadWrite)
380
0
      open_flags |= O_RDWR;
381
5.84k
    else
382
5.84k
      open_flags |= O_WRONLY;
383
384
5.84k
    if (options & File::eOpenOptionAppend)
385
4
      open_flags |= O_APPEND;
386
387
5.84k
    if (options & File::eOpenOptionTruncate)
388
55
      open_flags |= O_TRUNC;
389
390
5.84k
    if (options & File::eOpenOptionCanCreate)
391
77
      open_flags |= O_CREAT;
392
393
5.84k
    if (options & File::eOpenOptionCanCreateNewOnly)
394
0
      open_flags |= O_CREAT | O_EXCL;
395
6.76k
  } else if (rw == File::eOpenOptionReadOnly) {
396
6.76k
    open_flags |= O_RDONLY;
397
398
6.76k
#ifndef _WIN32
399
6.76k
    if (options & File::eOpenOptionDontFollowSymlinks)
400
0
      open_flags |= O_NOFOLLOW;
401
6.76k
#endif
402
6.76k
  }
403
404
12.6k
#ifndef _WIN32
405
12.6k
  if (options & File::eOpenOptionNonBlocking)
406
0
    open_flags |= O_NONBLOCK;
407
12.6k
  if (options & File::eOpenOptionCloseOnExec)
408
33
    open_flags |= O_CLOEXEC;
409
#else
410
  open_flags |= O_BINARY;
411
#endif
412
413
12.6k
  return open_flags;
414
12.6k
}
415
416
77
static mode_t GetOpenMode(uint32_t permissions) {
417
77
  mode_t mode = 0;
418
77
  if (permissions & lldb::eFilePermissionsUserRead)
419
77
    mode |= S_IRUSR;
420
77
  if (permissions & lldb::eFilePermissionsUserWrite)
421
77
    mode |= S_IWUSR;
422
77
  if (permissions & lldb::eFilePermissionsUserExecute)
423
0
    mode |= S_IXUSR;
424
77
  if (permissions & lldb::eFilePermissionsGroupRead)
425
1
    mode |= S_IRGRP;
426
77
  if (permissions & lldb::eFilePermissionsGroupWrite)
427
0
    mode |= S_IWGRP;
428
77
  if (permissions & lldb::eFilePermissionsGroupExecute)
429
0
    mode |= S_IXGRP;
430
77
  if (permissions & lldb::eFilePermissionsWorldRead)
431
1
    mode |= S_IROTH;
432
77
  if (permissions & lldb::eFilePermissionsWorldWrite)
433
0
    mode |= S_IWOTH;
434
77
  if (permissions & lldb::eFilePermissionsWorldExecute)
435
0
    mode |= S_IXOTH;
436
77
  return mode;
437
77
}
438
439
Expected<FileUP> FileSystem::Open(const FileSpec &file_spec,
440
                                  File::OpenOptions options,
441
12.6k
                                  uint32_t permissions, bool should_close_fd) {
442
12.6k
  const int open_flags = GetOpenFlags(options);
443
12.6k
  const mode_t open_mode =
444
12.6k
      (open_flags & O_CREAT) ? 
GetOpenMode(permissions)77
:
012.5k
;
445
446
12.6k
  auto path = file_spec.GetPath();
447
448
12.6k
  int descriptor = llvm::sys::RetryAfterSignal(
449
12.6k
      -1, OpenWithFS, *this, path.c_str(), open_flags, open_mode);
450
451
12.6k
  if (!File::DescriptorIsValid(descriptor))
452
7
    return llvm::errorCodeToError(
453
7
        std::error_code(errno, std::system_category()));
454
455
12.6k
  auto file = std::unique_ptr<File>(
456
12.6k
      new NativeFile(descriptor, options, should_close_fd));
457
12.6k
  assert(file->IsValid());
458
12.6k
  return std::move(file);
459
12.6k
}
460
461
0
void FileSystem::SetHomeDirectory(std::string home_directory) {
462
0
  m_home_directory = std::move(home_directory);
463
0
}
464
465
1
Status FileSystem::RemoveFile(const FileSpec &file_spec) {
466
1
  return RemoveFile(file_spec.GetPath());
467
1
}
468
469
1
Status FileSystem::RemoveFile(const llvm::Twine &path) {
470
1
  return Status(llvm::sys::fs::remove(path));
471
1
}