xref: /src/contrib/llvm-project/lldb/source/Host/common/FileSystem.cpp (revision cb14a3fe5122c879eae1fb480ed7ce82a699ddb6)
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