1cfca06d7SDimitry Andric //===-- FileSystem.cpp ----------------------------------------------------===//
25e95aa85SEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65e95aa85SEd Maste //
75e95aa85SEd Maste //===----------------------------------------------------------------------===//
85e95aa85SEd Maste
95e95aa85SEd Maste #include "lldb/Host/FileSystem.h"
105e95aa85SEd Maste
11145449b1SDimitry Andric #include "lldb/Utility/DataBufferLLVM.h"
1294994d37SDimitry Andric
135f29bb8aSDimitry Andric #include "llvm/Support/Errc.h"
1494994d37SDimitry Andric #include "llvm/Support/Errno.h"
155f29bb8aSDimitry Andric #include "llvm/Support/Error.h"
1614f1b3e8SDimitry Andric #include "llvm/Support/FileSystem.h"
1794994d37SDimitry Andric #include "llvm/Support/Path.h"
1894994d37SDimitry Andric #include "llvm/Support/Program.h"
1994994d37SDimitry Andric #include "llvm/Support/Threading.h"
2094994d37SDimitry Andric
21344a3780SDimitry Andric #include <cerrno>
22344a3780SDimitry Andric #include <climits>
23344a3780SDimitry Andric #include <cstdarg>
24344a3780SDimitry Andric #include <cstdio>
2594994d37SDimitry Andric #include <fcntl.h>
2694994d37SDimitry Andric
2794994d37SDimitry Andric #ifdef _WIN32
2894994d37SDimitry Andric #include "lldb/Host/windows/windows.h"
2994994d37SDimitry Andric #else
3094994d37SDimitry Andric #include <sys/ioctl.h>
3194994d37SDimitry Andric #include <sys/stat.h>
3294994d37SDimitry Andric #include <termios.h>
3394994d37SDimitry Andric #include <unistd.h>
3494994d37SDimitry Andric #endif
355e95aa85SEd Maste
365e95aa85SEd Maste #include <algorithm>
375e95aa85SEd Maste #include <fstream>
38e3b55780SDimitry Andric #include <optional>
395e95aa85SEd Maste #include <vector>
405e95aa85SEd Maste
415e95aa85SEd Maste using namespace lldb;
425e95aa85SEd Maste using namespace lldb_private;
4394994d37SDimitry Andric using namespace llvm;
445e95aa85SEd Maste
Instance()4594994d37SDimitry Andric FileSystem &FileSystem::Instance() { return *InstanceImpl(); }
4694994d37SDimitry Andric
Terminate()4794994d37SDimitry Andric void FileSystem::Terminate() {
4894994d37SDimitry Andric lldbassert(InstanceImpl() && "Already terminated.");
4994994d37SDimitry Andric InstanceImpl().reset();
5094994d37SDimitry Andric }
5194994d37SDimitry Andric
InstanceImpl()52e3b55780SDimitry Andric std::optional<FileSystem> &FileSystem::InstanceImpl() {
53e3b55780SDimitry Andric static std::optional<FileSystem> g_fs;
5494994d37SDimitry Andric return g_fs;
5594994d37SDimitry Andric }
5694994d37SDimitry Andric
DirBegin(const FileSpec & file_spec,std::error_code & ec)5794994d37SDimitry Andric vfs::directory_iterator FileSystem::DirBegin(const FileSpec &file_spec,
5894994d37SDimitry Andric std::error_code &ec) {
59cfca06d7SDimitry Andric if (!file_spec) {
60cfca06d7SDimitry Andric ec = std::error_code(static_cast<int>(errc::no_such_file_or_directory),
61cfca06d7SDimitry Andric std::system_category());
62cfca06d7SDimitry Andric return {};
63cfca06d7SDimitry Andric }
6494994d37SDimitry Andric return DirBegin(file_spec.GetPath(), ec);
6594994d37SDimitry Andric }
6694994d37SDimitry Andric
DirBegin(const Twine & dir,std::error_code & ec)6794994d37SDimitry Andric vfs::directory_iterator FileSystem::DirBegin(const Twine &dir,
6894994d37SDimitry Andric std::error_code &ec) {
6994994d37SDimitry Andric return m_fs->dir_begin(dir, ec);
7094994d37SDimitry Andric }
7194994d37SDimitry Andric
7294994d37SDimitry Andric llvm::ErrorOr<vfs::Status>
GetStatus(const FileSpec & file_spec) const7394994d37SDimitry Andric FileSystem::GetStatus(const FileSpec &file_spec) const {
74cfca06d7SDimitry Andric if (!file_spec)
75cfca06d7SDimitry Andric return std::error_code(static_cast<int>(errc::no_such_file_or_directory),
76cfca06d7SDimitry Andric std::system_category());
7794994d37SDimitry Andric return GetStatus(file_spec.GetPath());
7894994d37SDimitry Andric }
7994994d37SDimitry Andric
GetStatus(const Twine & path) const8094994d37SDimitry Andric llvm::ErrorOr<vfs::Status> FileSystem::GetStatus(const Twine &path) const {
8194994d37SDimitry Andric return m_fs->status(path);
8294994d37SDimitry Andric }
8394994d37SDimitry Andric
8494994d37SDimitry Andric sys::TimePoint<>
GetModificationTime(const FileSpec & file_spec) const8594994d37SDimitry Andric FileSystem::GetModificationTime(const FileSpec &file_spec) const {
86cfca06d7SDimitry Andric if (!file_spec)
87cfca06d7SDimitry Andric return sys::TimePoint<>();
8894994d37SDimitry Andric return GetModificationTime(file_spec.GetPath());
8994994d37SDimitry Andric }
9094994d37SDimitry Andric
GetModificationTime(const Twine & path) const9194994d37SDimitry Andric sys::TimePoint<> FileSystem::GetModificationTime(const Twine &path) const {
9294994d37SDimitry Andric ErrorOr<vfs::Status> status = m_fs->status(path);
9394994d37SDimitry Andric if (!status)
9494994d37SDimitry Andric return sys::TimePoint<>();
9594994d37SDimitry Andric return status->getLastModificationTime();
9694994d37SDimitry Andric }
9794994d37SDimitry Andric
GetByteSize(const FileSpec & file_spec) const9894994d37SDimitry Andric uint64_t FileSystem::GetByteSize(const FileSpec &file_spec) const {
99cfca06d7SDimitry Andric if (!file_spec)
100cfca06d7SDimitry Andric return 0;
10194994d37SDimitry Andric return GetByteSize(file_spec.GetPath());
10294994d37SDimitry Andric }
10394994d37SDimitry Andric
GetByteSize(const Twine & path) const10494994d37SDimitry Andric uint64_t FileSystem::GetByteSize(const Twine &path) const {
10594994d37SDimitry Andric ErrorOr<vfs::Status> status = m_fs->status(path);
10694994d37SDimitry Andric if (!status)
10794994d37SDimitry Andric return 0;
10894994d37SDimitry Andric return status->getSize();
10994994d37SDimitry Andric }
11094994d37SDimitry Andric
GetPermissions(const FileSpec & file_spec) const11194994d37SDimitry Andric uint32_t FileSystem::GetPermissions(const FileSpec &file_spec) const {
11294994d37SDimitry Andric return GetPermissions(file_spec.GetPath());
11394994d37SDimitry Andric }
11494994d37SDimitry Andric
GetPermissions(const FileSpec & file_spec,std::error_code & ec) const11594994d37SDimitry Andric uint32_t FileSystem::GetPermissions(const FileSpec &file_spec,
11694994d37SDimitry Andric std::error_code &ec) const {
117cfca06d7SDimitry Andric if (!file_spec)
118cfca06d7SDimitry Andric return sys::fs::perms::perms_not_known;
11994994d37SDimitry Andric return GetPermissions(file_spec.GetPath(), ec);
12094994d37SDimitry Andric }
12194994d37SDimitry Andric
GetPermissions(const Twine & path) const12294994d37SDimitry Andric uint32_t FileSystem::GetPermissions(const Twine &path) const {
12394994d37SDimitry Andric std::error_code ec;
12494994d37SDimitry Andric return GetPermissions(path, ec);
12594994d37SDimitry Andric }
12694994d37SDimitry Andric
GetPermissions(const Twine & path,std::error_code & ec) const12794994d37SDimitry Andric uint32_t FileSystem::GetPermissions(const Twine &path,
12894994d37SDimitry Andric std::error_code &ec) const {
12994994d37SDimitry Andric ErrorOr<vfs::Status> status = m_fs->status(path);
13094994d37SDimitry Andric if (!status) {
13194994d37SDimitry Andric ec = status.getError();
13294994d37SDimitry Andric return sys::fs::perms::perms_not_known;
13394994d37SDimitry Andric }
13494994d37SDimitry Andric return status->getPermissions();
13594994d37SDimitry Andric }
13694994d37SDimitry Andric
Exists(const Twine & path) const13794994d37SDimitry Andric bool FileSystem::Exists(const Twine &path) const { return m_fs->exists(path); }
13894994d37SDimitry Andric
Exists(const FileSpec & file_spec) const13994994d37SDimitry Andric bool FileSystem::Exists(const FileSpec &file_spec) const {
140cfca06d7SDimitry Andric return file_spec && Exists(file_spec.GetPath());
14194994d37SDimitry Andric }
14294994d37SDimitry Andric
Readable(const Twine & path) const14394994d37SDimitry Andric bool FileSystem::Readable(const Twine &path) const {
14494994d37SDimitry Andric return GetPermissions(path) & sys::fs::perms::all_read;
14594994d37SDimitry Andric }
14694994d37SDimitry Andric
Readable(const FileSpec & file_spec) const14794994d37SDimitry Andric bool FileSystem::Readable(const FileSpec &file_spec) const {
148cfca06d7SDimitry Andric return file_spec && Readable(file_spec.GetPath());
14994994d37SDimitry Andric }
15094994d37SDimitry Andric
IsDirectory(const Twine & path) const15194994d37SDimitry Andric bool FileSystem::IsDirectory(const Twine &path) const {
15294994d37SDimitry Andric ErrorOr<vfs::Status> status = m_fs->status(path);
15394994d37SDimitry Andric if (!status)
15494994d37SDimitry Andric return false;
15594994d37SDimitry Andric return status->isDirectory();
15694994d37SDimitry Andric }
15794994d37SDimitry Andric
IsDirectory(const FileSpec & file_spec) const15894994d37SDimitry Andric bool FileSystem::IsDirectory(const FileSpec &file_spec) const {
159cfca06d7SDimitry Andric return file_spec && IsDirectory(file_spec.GetPath());
16094994d37SDimitry Andric }
16194994d37SDimitry Andric
IsLocal(const Twine & path) const16294994d37SDimitry Andric bool FileSystem::IsLocal(const Twine &path) const {
16394994d37SDimitry Andric bool b = false;
16494994d37SDimitry Andric m_fs->isLocal(path, b);
16594994d37SDimitry Andric return b;
16694994d37SDimitry Andric }
16794994d37SDimitry Andric
IsLocal(const FileSpec & file_spec) const16894994d37SDimitry Andric bool FileSystem::IsLocal(const FileSpec &file_spec) const {
169cfca06d7SDimitry Andric return file_spec && IsLocal(file_spec.GetPath());
17094994d37SDimitry Andric }
17194994d37SDimitry Andric
EnumerateDirectory(Twine path,bool find_directories,bool find_files,bool find_other,EnumerateDirectoryCallbackType callback,void * callback_baton)17294994d37SDimitry Andric void FileSystem::EnumerateDirectory(Twine path, bool find_directories,
17394994d37SDimitry Andric bool find_files, bool find_other,
17494994d37SDimitry Andric EnumerateDirectoryCallbackType callback,
17594994d37SDimitry Andric void *callback_baton) {
17694994d37SDimitry Andric std::error_code EC;
17794994d37SDimitry Andric vfs::recursive_directory_iterator Iter(*m_fs, path, EC);
17894994d37SDimitry Andric vfs::recursive_directory_iterator End;
17994994d37SDimitry Andric for (; Iter != End && !EC; Iter.increment(EC)) {
18094994d37SDimitry Andric const auto &Item = *Iter;
18194994d37SDimitry Andric ErrorOr<vfs::Status> Status = m_fs->status(Item.path());
18294994d37SDimitry Andric if (!Status)
1837fa27ce4SDimitry Andric continue;
18494994d37SDimitry Andric if (!find_files && Status->isRegularFile())
18594994d37SDimitry Andric continue;
18694994d37SDimitry Andric if (!find_directories && Status->isDirectory())
18794994d37SDimitry Andric continue;
18894994d37SDimitry Andric if (!find_other && Status->isOther())
18994994d37SDimitry Andric continue;
19094994d37SDimitry Andric
19194994d37SDimitry Andric auto Result = callback(callback_baton, Status->getType(), Item.path());
19294994d37SDimitry Andric if (Result == eEnumerateDirectoryResultQuit)
19394994d37SDimitry Andric return;
19494994d37SDimitry Andric if (Result == eEnumerateDirectoryResultNext) {
19594994d37SDimitry Andric // Default behavior is to recurse. Opt out if the callback doesn't want
19694994d37SDimitry Andric // this behavior.
19794994d37SDimitry Andric Iter.no_push();
19894994d37SDimitry Andric }
19994994d37SDimitry Andric }
20094994d37SDimitry Andric }
20194994d37SDimitry Andric
MakeAbsolute(SmallVectorImpl<char> & path) const20294994d37SDimitry Andric std::error_code FileSystem::MakeAbsolute(SmallVectorImpl<char> &path) const {
20394994d37SDimitry Andric return m_fs->makeAbsolute(path);
20494994d37SDimitry Andric }
20594994d37SDimitry Andric
MakeAbsolute(FileSpec & file_spec) const20694994d37SDimitry Andric std::error_code FileSystem::MakeAbsolute(FileSpec &file_spec) const {
20794994d37SDimitry Andric SmallString<128> path;
20894994d37SDimitry Andric file_spec.GetPath(path, false);
20994994d37SDimitry Andric
21094994d37SDimitry Andric auto EC = MakeAbsolute(path);
21194994d37SDimitry Andric if (EC)
21294994d37SDimitry Andric return EC;
21394994d37SDimitry Andric
21494994d37SDimitry Andric FileSpec new_file_spec(path, file_spec.GetPathStyle());
21594994d37SDimitry Andric file_spec = new_file_spec;
21694994d37SDimitry Andric return {};
21794994d37SDimitry Andric }
21894994d37SDimitry Andric
GetRealPath(const Twine & path,SmallVectorImpl<char> & output) const21994994d37SDimitry Andric std::error_code FileSystem::GetRealPath(const Twine &path,
22094994d37SDimitry Andric SmallVectorImpl<char> &output) const {
22194994d37SDimitry Andric return m_fs->getRealPath(path, output);
22294994d37SDimitry Andric }
22394994d37SDimitry Andric
Resolve(SmallVectorImpl<char> & path)22494994d37SDimitry Andric void FileSystem::Resolve(SmallVectorImpl<char> &path) {
22594994d37SDimitry Andric if (path.empty())
22694994d37SDimitry Andric return;
22794994d37SDimitry Andric
2285f29bb8aSDimitry Andric // Resolve tilde in path.
2295f29bb8aSDimitry Andric SmallString<128> resolved(path.begin(), path.end());
2307fa27ce4SDimitry Andric assert(m_tilde_resolver && "must initialize tilde resolver in constructor");
2317fa27ce4SDimitry Andric m_tilde_resolver->ResolveFullPath(llvm::StringRef(path.begin(), path.size()),
2325f29bb8aSDimitry Andric resolved);
23394994d37SDimitry Andric
23494994d37SDimitry Andric // Try making the path absolute if it exists.
2355f29bb8aSDimitry Andric SmallString<128> absolute(resolved.begin(), resolved.end());
2365f29bb8aSDimitry Andric MakeAbsolute(absolute);
2375f29bb8aSDimitry Andric
23894994d37SDimitry Andric path.clear();
2395f29bb8aSDimitry Andric if (Exists(absolute)) {
2405f29bb8aSDimitry Andric path.append(absolute.begin(), absolute.end());
2415f29bb8aSDimitry Andric } else {
2425f29bb8aSDimitry Andric path.append(resolved.begin(), resolved.end());
24394994d37SDimitry Andric }
24494994d37SDimitry Andric }
24594994d37SDimitry Andric
Resolve(FileSpec & file_spec)24694994d37SDimitry Andric void FileSystem::Resolve(FileSpec &file_spec) {
247cfca06d7SDimitry Andric if (!file_spec)
248cfca06d7SDimitry Andric return;
249cfca06d7SDimitry Andric
25094994d37SDimitry Andric // Extract path from the FileSpec.
25194994d37SDimitry Andric SmallString<128> path;
25294994d37SDimitry Andric file_spec.GetPath(path);
25394994d37SDimitry Andric
25494994d37SDimitry Andric // Resolve the path.
25594994d37SDimitry Andric Resolve(path);
25694994d37SDimitry Andric
25794994d37SDimitry Andric // Update the FileSpec with the resolved path.
2585f29bb8aSDimitry Andric if (file_spec.GetFilename().IsEmpty())
259e3b55780SDimitry Andric file_spec.SetDirectory(path);
2605f29bb8aSDimitry Andric else
26194994d37SDimitry Andric file_spec.SetPath(path);
26294994d37SDimitry Andric }
26394994d37SDimitry Andric
264145449b1SDimitry Andric template <typename T>
GetMemoryBuffer(const llvm::Twine & path,uint64_t size,uint64_t offset,bool is_volatile)265145449b1SDimitry Andric static std::unique_ptr<T> GetMemoryBuffer(const llvm::Twine &path,
266145449b1SDimitry Andric uint64_t size, uint64_t offset,
267145449b1SDimitry Andric bool is_volatile) {
268145449b1SDimitry Andric std::unique_ptr<T> buffer;
26994994d37SDimitry Andric if (size == 0) {
270145449b1SDimitry Andric auto buffer_or_error = T::getFile(path, is_volatile);
27194994d37SDimitry Andric if (!buffer_or_error)
27294994d37SDimitry Andric return nullptr;
27394994d37SDimitry Andric buffer = std::move(*buffer_or_error);
27494994d37SDimitry Andric } else {
275145449b1SDimitry Andric auto buffer_or_error = T::getFileSlice(path, size, offset, is_volatile);
27694994d37SDimitry Andric if (!buffer_or_error)
27794994d37SDimitry Andric return nullptr;
27894994d37SDimitry Andric buffer = std::move(*buffer_or_error);
27994994d37SDimitry Andric }
280145449b1SDimitry Andric return buffer;
281145449b1SDimitry Andric }
282145449b1SDimitry Andric
283145449b1SDimitry Andric std::shared_ptr<WritableDataBuffer>
CreateWritableDataBuffer(const llvm::Twine & path,uint64_t size,uint64_t offset)284145449b1SDimitry Andric FileSystem::CreateWritableDataBuffer(const llvm::Twine &path, uint64_t size,
285145449b1SDimitry Andric uint64_t offset) {
286145449b1SDimitry Andric const bool is_volatile = !IsLocal(path);
287145449b1SDimitry Andric auto buffer = GetMemoryBuffer<llvm::WritableMemoryBuffer>(path, size, offset,
288145449b1SDimitry Andric is_volatile);
289145449b1SDimitry Andric if (!buffer)
290145449b1SDimitry Andric return {};
291145449b1SDimitry Andric return std::shared_ptr<WritableDataBufferLLVM>(
292145449b1SDimitry Andric new WritableDataBufferLLVM(std::move(buffer)));
293145449b1SDimitry Andric }
294145449b1SDimitry Andric
295145449b1SDimitry Andric std::shared_ptr<DataBuffer>
CreateDataBuffer(const llvm::Twine & path,uint64_t size,uint64_t offset)296145449b1SDimitry Andric FileSystem::CreateDataBuffer(const llvm::Twine &path, uint64_t size,
297145449b1SDimitry Andric uint64_t offset) {
298145449b1SDimitry Andric const bool is_volatile = !IsLocal(path);
299145449b1SDimitry Andric auto buffer =
300145449b1SDimitry Andric GetMemoryBuffer<llvm::MemoryBuffer>(path, size, offset, is_volatile);
301145449b1SDimitry Andric if (!buffer)
302145449b1SDimitry Andric return {};
30394994d37SDimitry Andric return std::shared_ptr<DataBufferLLVM>(new DataBufferLLVM(std::move(buffer)));
30494994d37SDimitry Andric }
30594994d37SDimitry Andric
306145449b1SDimitry Andric std::shared_ptr<WritableDataBuffer>
CreateWritableDataBuffer(const FileSpec & file_spec,uint64_t size,uint64_t offset)307145449b1SDimitry Andric FileSystem::CreateWritableDataBuffer(const FileSpec &file_spec, uint64_t size,
308145449b1SDimitry Andric uint64_t offset) {
309145449b1SDimitry Andric return CreateWritableDataBuffer(file_spec.GetPath(), size, offset);
310145449b1SDimitry Andric }
311145449b1SDimitry Andric
312145449b1SDimitry Andric std::shared_ptr<DataBuffer>
CreateDataBuffer(const FileSpec & file_spec,uint64_t size,uint64_t offset)31394994d37SDimitry Andric FileSystem::CreateDataBuffer(const FileSpec &file_spec, uint64_t size,
31494994d37SDimitry Andric uint64_t offset) {
31594994d37SDimitry Andric return CreateDataBuffer(file_spec.GetPath(), size, offset);
31694994d37SDimitry Andric }
31794994d37SDimitry Andric
ResolveExecutableLocation(FileSpec & file_spec)31894994d37SDimitry Andric bool FileSystem::ResolveExecutableLocation(FileSpec &file_spec) {
31994994d37SDimitry Andric // If the directory is set there's nothing to do.
3205f29bb8aSDimitry Andric ConstString directory = file_spec.GetDirectory();
32194994d37SDimitry Andric if (directory)
32294994d37SDimitry Andric return false;
32394994d37SDimitry Andric
32494994d37SDimitry Andric // We cannot look for a file if there's no file name.
3255f29bb8aSDimitry Andric ConstString filename = file_spec.GetFilename();
32694994d37SDimitry Andric if (!filename)
32794994d37SDimitry Andric return false;
32894994d37SDimitry Andric
32994994d37SDimitry Andric // Search for the file on the host.
33094994d37SDimitry Andric const std::string filename_str(filename.GetCString());
33194994d37SDimitry Andric llvm::ErrorOr<std::string> error_or_path =
33294994d37SDimitry Andric llvm::sys::findProgramByName(filename_str);
33394994d37SDimitry Andric if (!error_or_path)
33494994d37SDimitry Andric return false;
33594994d37SDimitry Andric
33694994d37SDimitry Andric // findProgramByName returns "." if it can't find the file.
33794994d37SDimitry Andric llvm::StringRef path = *error_or_path;
33894994d37SDimitry Andric llvm::StringRef parent = llvm::sys::path::parent_path(path);
33994994d37SDimitry Andric if (parent.empty() || parent == ".")
34094994d37SDimitry Andric return false;
34194994d37SDimitry Andric
34294994d37SDimitry Andric // Make sure that the result exists.
34394994d37SDimitry Andric FileSpec result(*error_or_path);
34494994d37SDimitry Andric if (!Exists(result))
34594994d37SDimitry Andric return false;
34694994d37SDimitry Andric
34794994d37SDimitry Andric file_spec = result;
34894994d37SDimitry Andric return true;
34994994d37SDimitry Andric }
35094994d37SDimitry Andric
GetHomeDirectory(SmallVectorImpl<char> & path) const351b60736ecSDimitry Andric bool FileSystem::GetHomeDirectory(SmallVectorImpl<char> &path) const {
352b60736ecSDimitry Andric if (!m_home_directory.empty()) {
353b60736ecSDimitry Andric path.assign(m_home_directory.begin(), m_home_directory.end());
354b60736ecSDimitry Andric return true;
355b60736ecSDimitry Andric }
356b60736ecSDimitry Andric return llvm::sys::path::home_directory(path);
357b60736ecSDimitry Andric }
358b60736ecSDimitry Andric
GetHomeDirectory(FileSpec & file_spec) const359b60736ecSDimitry Andric bool FileSystem::GetHomeDirectory(FileSpec &file_spec) const {
360b60736ecSDimitry Andric SmallString<128> home_dir;
361b60736ecSDimitry Andric if (!GetHomeDirectory(home_dir))
362b60736ecSDimitry Andric return false;
363b60736ecSDimitry Andric file_spec.SetPath(home_dir);
364b60736ecSDimitry Andric return true;
365b60736ecSDimitry Andric }
366b60736ecSDimitry Andric
OpenWithFS(const FileSystem & fs,const char * path,int flags,int mode)36794994d37SDimitry Andric static int OpenWithFS(const FileSystem &fs, const char *path, int flags,
36894994d37SDimitry Andric int mode) {
36994994d37SDimitry Andric return const_cast<FileSystem &>(fs).Open(path, flags, mode);
37094994d37SDimitry Andric }
37194994d37SDimitry Andric
GetOpenFlags(File::OpenOptions options)372c0981da4SDimitry Andric static int GetOpenFlags(File::OpenOptions options) {
37394994d37SDimitry Andric int open_flags = 0;
374c0981da4SDimitry Andric File::OpenOptions rw =
375c0981da4SDimitry Andric options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
376c0981da4SDimitry Andric File::eOpenOptionReadWrite);
377c0981da4SDimitry Andric if (rw == File::eOpenOptionWriteOnly || rw == File::eOpenOptionReadWrite) {
378c0981da4SDimitry Andric if (rw == File::eOpenOptionReadWrite)
37994994d37SDimitry Andric open_flags |= O_RDWR;
38094994d37SDimitry Andric else
38194994d37SDimitry Andric open_flags |= O_WRONLY;
38294994d37SDimitry Andric
38394994d37SDimitry Andric if (options & File::eOpenOptionAppend)
38494994d37SDimitry Andric open_flags |= O_APPEND;
38594994d37SDimitry Andric
38694994d37SDimitry Andric if (options & File::eOpenOptionTruncate)
38794994d37SDimitry Andric open_flags |= O_TRUNC;
38894994d37SDimitry Andric
38994994d37SDimitry Andric if (options & File::eOpenOptionCanCreate)
39094994d37SDimitry Andric open_flags |= O_CREAT;
39194994d37SDimitry Andric
39294994d37SDimitry Andric if (options & File::eOpenOptionCanCreateNewOnly)
39394994d37SDimitry Andric open_flags |= O_CREAT | O_EXCL;
394c0981da4SDimitry Andric } else if (rw == File::eOpenOptionReadOnly) {
39594994d37SDimitry Andric open_flags |= O_RDONLY;
39694994d37SDimitry Andric
39794994d37SDimitry Andric #ifndef _WIN32
39894994d37SDimitry Andric if (options & File::eOpenOptionDontFollowSymlinks)
39994994d37SDimitry Andric open_flags |= O_NOFOLLOW;
40094994d37SDimitry Andric #endif
40194994d37SDimitry Andric }
40294994d37SDimitry Andric
40394994d37SDimitry Andric #ifndef _WIN32
40494994d37SDimitry Andric if (options & File::eOpenOptionNonBlocking)
40594994d37SDimitry Andric open_flags |= O_NONBLOCK;
40694994d37SDimitry Andric if (options & File::eOpenOptionCloseOnExec)
40794994d37SDimitry Andric open_flags |= O_CLOEXEC;
40894994d37SDimitry Andric #else
40994994d37SDimitry Andric open_flags |= O_BINARY;
41094994d37SDimitry Andric #endif
41194994d37SDimitry Andric
41294994d37SDimitry Andric return open_flags;
41394994d37SDimitry Andric }
41494994d37SDimitry Andric
GetOpenMode(uint32_t permissions)41594994d37SDimitry Andric static mode_t GetOpenMode(uint32_t permissions) {
41694994d37SDimitry Andric mode_t mode = 0;
41794994d37SDimitry Andric if (permissions & lldb::eFilePermissionsUserRead)
41894994d37SDimitry Andric mode |= S_IRUSR;
41994994d37SDimitry Andric if (permissions & lldb::eFilePermissionsUserWrite)
42094994d37SDimitry Andric mode |= S_IWUSR;
42194994d37SDimitry Andric if (permissions & lldb::eFilePermissionsUserExecute)
42294994d37SDimitry Andric mode |= S_IXUSR;
42394994d37SDimitry Andric if (permissions & lldb::eFilePermissionsGroupRead)
42494994d37SDimitry Andric mode |= S_IRGRP;
42594994d37SDimitry Andric if (permissions & lldb::eFilePermissionsGroupWrite)
42694994d37SDimitry Andric mode |= S_IWGRP;
42794994d37SDimitry Andric if (permissions & lldb::eFilePermissionsGroupExecute)
42894994d37SDimitry Andric mode |= S_IXGRP;
42994994d37SDimitry Andric if (permissions & lldb::eFilePermissionsWorldRead)
43094994d37SDimitry Andric mode |= S_IROTH;
43194994d37SDimitry Andric if (permissions & lldb::eFilePermissionsWorldWrite)
43294994d37SDimitry Andric mode |= S_IWOTH;
43394994d37SDimitry Andric if (permissions & lldb::eFilePermissionsWorldExecute)
43494994d37SDimitry Andric mode |= S_IXOTH;
43594994d37SDimitry Andric return mode;
43694994d37SDimitry Andric }
43794994d37SDimitry Andric
Open(const FileSpec & file_spec,File::OpenOptions options,uint32_t permissions,bool should_close_fd)438ead24645SDimitry Andric Expected<FileUP> FileSystem::Open(const FileSpec &file_spec,
439ead24645SDimitry Andric File::OpenOptions options,
4405f29bb8aSDimitry Andric uint32_t permissions, bool should_close_fd) {
44194994d37SDimitry Andric const int open_flags = GetOpenFlags(options);
44294994d37SDimitry Andric const mode_t open_mode =
44394994d37SDimitry Andric (open_flags & O_CREAT) ? GetOpenMode(permissions) : 0;
4445f29bb8aSDimitry Andric
445145449b1SDimitry Andric auto path = file_spec.GetPath();
44694994d37SDimitry Andric
44794994d37SDimitry Andric int descriptor = llvm::sys::RetryAfterSignal(
448145449b1SDimitry Andric -1, OpenWithFS, *this, path.c_str(), open_flags, open_mode);
44994994d37SDimitry Andric
450ead24645SDimitry Andric if (!File::DescriptorIsValid(descriptor))
451ead24645SDimitry Andric return llvm::errorCodeToError(
452ead24645SDimitry Andric std::error_code(errno, std::system_category()));
453ead24645SDimitry Andric
454ead24645SDimitry Andric auto file = std::unique_ptr<File>(
455ead24645SDimitry Andric new NativeFile(descriptor, options, should_close_fd));
456ead24645SDimitry Andric assert(file->IsValid());
457ead24645SDimitry Andric return std::move(file);
45814f1b3e8SDimitry Andric }
4595f29bb8aSDimitry Andric
SetHomeDirectory(std::string home_directory)460b60736ecSDimitry Andric void FileSystem::SetHomeDirectory(std::string home_directory) {
461b60736ecSDimitry Andric m_home_directory = std::move(home_directory);
462b60736ecSDimitry Andric }
46377fc4c14SDimitry Andric
RemoveFile(const FileSpec & file_spec)46477fc4c14SDimitry Andric Status FileSystem::RemoveFile(const FileSpec &file_spec) {
46577fc4c14SDimitry Andric return RemoveFile(file_spec.GetPath());
46677fc4c14SDimitry Andric }
46777fc4c14SDimitry Andric
RemoveFile(const llvm::Twine & path)46877fc4c14SDimitry Andric Status FileSystem::RemoveFile(const llvm::Twine &path) {
46977fc4c14SDimitry Andric return Status(llvm::sys::fs::remove(path));
47077fc4c14SDimitry Andric }
471