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