180814287SRaphael Isemann //===-- FileSystem.cpp ----------------------------------------------------===//
27a9e7621SOleksiy Vyalov //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67a9e7621SOleksiy Vyalov //
77a9e7621SOleksiy Vyalov //===----------------------------------------------------------------------===//
87a9e7621SOleksiy Vyalov 
97a9e7621SOleksiy Vyalov #include "lldb/Host/FileSystem.h"
107a9e7621SOleksiy Vyalov 
110bca15a3SJonas Devlieghere #include "lldb/Utility/LLDBAssert.h"
1246376966SJonas Devlieghere #include "lldb/Utility/TildeExpressionResolver.h"
1346376966SJonas Devlieghere 
1446575176SJonas Devlieghere #include "llvm/Support/Errc.h"
1550bc1ed2SJonas Devlieghere #include "llvm/Support/Errno.h"
1646575176SJonas Devlieghere #include "llvm/Support/Error.h"
171408bf72SPavel Labath #include "llvm/Support/FileSystem.h"
182c22c800SJonas Devlieghere #include "llvm/Support/Path.h"
192c22c800SJonas Devlieghere #include "llvm/Support/Program.h"
2046376966SJonas Devlieghere #include "llvm/Support/Threading.h"
217a9e7621SOleksiy Vyalov 
2250bc1ed2SJonas Devlieghere #include <errno.h>
2350bc1ed2SJonas Devlieghere #include <fcntl.h>
2450bc1ed2SJonas Devlieghere #include <limits.h>
2550bc1ed2SJonas Devlieghere #include <stdarg.h>
2650bc1ed2SJonas Devlieghere #include <stdio.h>
2750bc1ed2SJonas Devlieghere 
2850bc1ed2SJonas Devlieghere #ifdef _WIN32
2950bc1ed2SJonas Devlieghere #include "lldb/Host/windows/windows.h"
3050bc1ed2SJonas Devlieghere #else
3150bc1ed2SJonas Devlieghere #include <sys/ioctl.h>
3250bc1ed2SJonas Devlieghere #include <sys/stat.h>
3350bc1ed2SJonas Devlieghere #include <termios.h>
3450bc1ed2SJonas Devlieghere #include <unistd.h>
3550bc1ed2SJonas Devlieghere #endif
3650bc1ed2SJonas Devlieghere 
376801be33SOleksiy Vyalov #include <algorithm>
387a9e7621SOleksiy Vyalov #include <fstream>
397a9e7621SOleksiy Vyalov #include <vector>
407a9e7621SOleksiy Vyalov 
417a9e7621SOleksiy Vyalov using namespace lldb;
427a9e7621SOleksiy Vyalov using namespace lldb_private;
4346376966SJonas Devlieghere using namespace llvm;
447a9e7621SOleksiy Vyalov 
4546376966SJonas Devlieghere FileSystem &FileSystem::Instance() { return *InstanceImpl(); }
4646376966SJonas Devlieghere 
4746376966SJonas Devlieghere void FileSystem::Initialize() {
480bca15a3SJonas Devlieghere   lldbassert(!InstanceImpl() && "Already initialized.");
4946376966SJonas Devlieghere   InstanceImpl().emplace();
5046376966SJonas Devlieghere }
5146376966SJonas Devlieghere 
5273811d32SJonas Devlieghere void FileSystem::Initialize(std::shared_ptr<FileCollectorBase> collector) {
5346575176SJonas Devlieghere   lldbassert(!InstanceImpl() && "Already initialized.");
5446575176SJonas Devlieghere   InstanceImpl().emplace(collector);
5546575176SJonas Devlieghere }
5646575176SJonas Devlieghere 
5746575176SJonas Devlieghere llvm::Error FileSystem::Initialize(const FileSpec &mapping) {
5846575176SJonas Devlieghere   lldbassert(!InstanceImpl() && "Already initialized.");
5946575176SJonas Devlieghere 
6046575176SJonas Devlieghere   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer =
6146575176SJonas Devlieghere       llvm::vfs::getRealFileSystem()->getBufferForFile(mapping.GetPath());
6246575176SJonas Devlieghere 
6346575176SJonas Devlieghere   if (!buffer)
6446575176SJonas Devlieghere     return llvm::errorCodeToError(buffer.getError());
6546575176SJonas Devlieghere 
66c470ac50SJonas Devlieghere   InstanceImpl().emplace(llvm::vfs::getVFSFromYAML(std::move(buffer.get()),
67c470ac50SJonas Devlieghere                                                    nullptr, mapping.GetPath()),
68c470ac50SJonas Devlieghere                          true);
6946575176SJonas Devlieghere 
7046575176SJonas Devlieghere   return llvm::Error::success();
7146575176SJonas Devlieghere }
7246575176SJonas Devlieghere 
7346376966SJonas Devlieghere void FileSystem::Initialize(IntrusiveRefCntPtr<vfs::FileSystem> fs) {
740bca15a3SJonas Devlieghere   lldbassert(!InstanceImpl() && "Already initialized.");
7546376966SJonas Devlieghere   InstanceImpl().emplace(fs);
7646376966SJonas Devlieghere }
7746376966SJonas Devlieghere 
7846376966SJonas Devlieghere void FileSystem::Terminate() {
790bca15a3SJonas Devlieghere   lldbassert(InstanceImpl() && "Already terminated.");
8046376966SJonas Devlieghere   InstanceImpl().reset();
8146376966SJonas Devlieghere }
8246376966SJonas Devlieghere 
8346376966SJonas Devlieghere Optional<FileSystem> &FileSystem::InstanceImpl() {
8446376966SJonas Devlieghere   static Optional<FileSystem> g_fs;
8546376966SJonas Devlieghere   return g_fs;
8646376966SJonas Devlieghere }
8746376966SJonas Devlieghere 
88edaf2bccSJonas Devlieghere vfs::directory_iterator FileSystem::DirBegin(const FileSpec &file_spec,
89edaf2bccSJonas Devlieghere                                              std::error_code &ec) {
90d144087cSJonas Devlieghere   if (!file_spec) {
91d144087cSJonas Devlieghere     ec = std::error_code(static_cast<int>(errc::no_such_file_or_directory),
92d144087cSJonas Devlieghere                          std::system_category());
93d144087cSJonas Devlieghere     return {};
94d144087cSJonas Devlieghere   }
95edaf2bccSJonas Devlieghere   return DirBegin(file_spec.GetPath(), ec);
96edaf2bccSJonas Devlieghere }
97edaf2bccSJonas Devlieghere 
98edaf2bccSJonas Devlieghere vfs::directory_iterator FileSystem::DirBegin(const Twine &dir,
99edaf2bccSJonas Devlieghere                                              std::error_code &ec) {
100edaf2bccSJonas Devlieghere   return m_fs->dir_begin(dir, ec);
101edaf2bccSJonas Devlieghere }
102edaf2bccSJonas Devlieghere 
103edaf2bccSJonas Devlieghere llvm::ErrorOr<vfs::Status>
104edaf2bccSJonas Devlieghere FileSystem::GetStatus(const FileSpec &file_spec) const {
105d144087cSJonas Devlieghere   if (!file_spec)
106d144087cSJonas Devlieghere     return std::error_code(static_cast<int>(errc::no_such_file_or_directory),
107d144087cSJonas Devlieghere                            std::system_category());
108edaf2bccSJonas Devlieghere   return GetStatus(file_spec.GetPath());
109edaf2bccSJonas Devlieghere }
110edaf2bccSJonas Devlieghere 
111edaf2bccSJonas Devlieghere llvm::ErrorOr<vfs::Status> FileSystem::GetStatus(const Twine &path) const {
112edaf2bccSJonas Devlieghere   return m_fs->status(path);
113edaf2bccSJonas Devlieghere }
114edaf2bccSJonas Devlieghere 
11546376966SJonas Devlieghere sys::TimePoint<>
116010b56beSJonas Devlieghere FileSystem::GetModificationTime(const FileSpec &file_spec) const {
117d144087cSJonas Devlieghere   if (!file_spec)
118d144087cSJonas Devlieghere     return sys::TimePoint<>();
119010b56beSJonas Devlieghere   return GetModificationTime(file_spec.GetPath());
12046376966SJonas Devlieghere }
12146376966SJonas Devlieghere 
122010b56beSJonas Devlieghere sys::TimePoint<> FileSystem::GetModificationTime(const Twine &path) const {
12346376966SJonas Devlieghere   ErrorOr<vfs::Status> status = m_fs->status(path);
12446376966SJonas Devlieghere   if (!status)
12546376966SJonas Devlieghere     return sys::TimePoint<>();
12646376966SJonas Devlieghere   return status->getLastModificationTime();
12746376966SJonas Devlieghere }
12846376966SJonas Devlieghere 
12946376966SJonas Devlieghere uint64_t FileSystem::GetByteSize(const FileSpec &file_spec) const {
130d144087cSJonas Devlieghere   if (!file_spec)
131d144087cSJonas Devlieghere     return 0;
13246376966SJonas Devlieghere   return GetByteSize(file_spec.GetPath());
13346376966SJonas Devlieghere }
13446376966SJonas Devlieghere 
13546376966SJonas Devlieghere uint64_t FileSystem::GetByteSize(const Twine &path) const {
13646376966SJonas Devlieghere   ErrorOr<vfs::Status> status = m_fs->status(path);
13746376966SJonas Devlieghere   if (!status)
13846376966SJonas Devlieghere     return 0;
13946376966SJonas Devlieghere   return status->getSize();
14046376966SJonas Devlieghere }
14146376966SJonas Devlieghere 
14246376966SJonas Devlieghere uint32_t FileSystem::GetPermissions(const FileSpec &file_spec) const {
14346376966SJonas Devlieghere   return GetPermissions(file_spec.GetPath());
14446376966SJonas Devlieghere }
14546376966SJonas Devlieghere 
14673ed6071SJonas Devlieghere uint32_t FileSystem::GetPermissions(const FileSpec &file_spec,
14773ed6071SJonas Devlieghere                                     std::error_code &ec) const {
148d144087cSJonas Devlieghere   if (!file_spec)
149d144087cSJonas Devlieghere     return sys::fs::perms::perms_not_known;
15073ed6071SJonas Devlieghere   return GetPermissions(file_spec.GetPath(), ec);
15173ed6071SJonas Devlieghere }
15273ed6071SJonas Devlieghere 
15346376966SJonas Devlieghere uint32_t FileSystem::GetPermissions(const Twine &path) const {
15473ed6071SJonas Devlieghere   std::error_code ec;
15573ed6071SJonas Devlieghere   return GetPermissions(path, ec);
15673ed6071SJonas Devlieghere }
15773ed6071SJonas Devlieghere 
15873ed6071SJonas Devlieghere uint32_t FileSystem::GetPermissions(const Twine &path,
15973ed6071SJonas Devlieghere                                     std::error_code &ec) const {
16046376966SJonas Devlieghere   ErrorOr<vfs::Status> status = m_fs->status(path);
16173ed6071SJonas Devlieghere   if (!status) {
16273ed6071SJonas Devlieghere     ec = status.getError();
16346376966SJonas Devlieghere     return sys::fs::perms::perms_not_known;
16473ed6071SJonas Devlieghere   }
16546376966SJonas Devlieghere   return status->getPermissions();
16646376966SJonas Devlieghere }
16746376966SJonas Devlieghere 
16846376966SJonas Devlieghere bool FileSystem::Exists(const Twine &path) const { return m_fs->exists(path); }
16946376966SJonas Devlieghere 
17046376966SJonas Devlieghere bool FileSystem::Exists(const FileSpec &file_spec) const {
171d144087cSJonas Devlieghere   return file_spec && Exists(file_spec.GetPath());
17246376966SJonas Devlieghere }
17346376966SJonas Devlieghere 
17446376966SJonas Devlieghere bool FileSystem::Readable(const Twine &path) const {
17546376966SJonas Devlieghere   return GetPermissions(path) & sys::fs::perms::all_read;
17646376966SJonas Devlieghere }
17746376966SJonas Devlieghere 
17846376966SJonas Devlieghere bool FileSystem::Readable(const FileSpec &file_spec) const {
179d144087cSJonas Devlieghere   return file_spec && Readable(file_spec.GetPath());
18046376966SJonas Devlieghere }
18146376966SJonas Devlieghere 
1823a58d898SJonas Devlieghere bool FileSystem::IsDirectory(const Twine &path) const {
1833a58d898SJonas Devlieghere   ErrorOr<vfs::Status> status = m_fs->status(path);
1843a58d898SJonas Devlieghere   if (!status)
1853a58d898SJonas Devlieghere     return false;
1863a58d898SJonas Devlieghere   return status->isDirectory();
1873a58d898SJonas Devlieghere }
1883a58d898SJonas Devlieghere 
1893a58d898SJonas Devlieghere bool FileSystem::IsDirectory(const FileSpec &file_spec) const {
190d144087cSJonas Devlieghere   return file_spec && IsDirectory(file_spec.GetPath());
1913a58d898SJonas Devlieghere }
1923a58d898SJonas Devlieghere 
19387e403aaSJonas Devlieghere bool FileSystem::IsLocal(const Twine &path) const {
19487e403aaSJonas Devlieghere   bool b = false;
19587e403aaSJonas Devlieghere   m_fs->isLocal(path, b);
19687e403aaSJonas Devlieghere   return b;
19787e403aaSJonas Devlieghere }
19887e403aaSJonas Devlieghere 
19987e403aaSJonas Devlieghere bool FileSystem::IsLocal(const FileSpec &file_spec) const {
200d144087cSJonas Devlieghere   return file_spec && IsLocal(file_spec.GetPath());
20187e403aaSJonas Devlieghere }
20287e403aaSJonas Devlieghere 
2039ca491daSJonas Devlieghere void FileSystem::EnumerateDirectory(Twine path, bool find_directories,
2049ca491daSJonas Devlieghere                                     bool find_files, bool find_other,
2059ca491daSJonas Devlieghere                                     EnumerateDirectoryCallbackType callback,
2069ca491daSJonas Devlieghere                                     void *callback_baton) {
2079ca491daSJonas Devlieghere   std::error_code EC;
2089ca491daSJonas Devlieghere   vfs::recursive_directory_iterator Iter(*m_fs, path, EC);
2099ca491daSJonas Devlieghere   vfs::recursive_directory_iterator End;
2109ca491daSJonas Devlieghere   for (; Iter != End && !EC; Iter.increment(EC)) {
2119ca491daSJonas Devlieghere     const auto &Item = *Iter;
2129ca491daSJonas Devlieghere     ErrorOr<vfs::Status> Status = m_fs->status(Item.path());
2139ca491daSJonas Devlieghere     if (!Status)
2149ca491daSJonas Devlieghere       break;
2159ca491daSJonas Devlieghere     if (!find_files && Status->isRegularFile())
2169ca491daSJonas Devlieghere       continue;
2179ca491daSJonas Devlieghere     if (!find_directories && Status->isDirectory())
2189ca491daSJonas Devlieghere       continue;
2199ca491daSJonas Devlieghere     if (!find_other && Status->isOther())
2209ca491daSJonas Devlieghere       continue;
2219ca491daSJonas Devlieghere 
2229ca491daSJonas Devlieghere     auto Result = callback(callback_baton, Status->getType(), Item.path());
2239ca491daSJonas Devlieghere     if (Result == eEnumerateDirectoryResultQuit)
2249ca491daSJonas Devlieghere       return;
2259ca491daSJonas Devlieghere     if (Result == eEnumerateDirectoryResultNext) {
2269ca491daSJonas Devlieghere       // Default behavior is to recurse. Opt out if the callback doesn't want
2279ca491daSJonas Devlieghere       // this behavior.
2289ca491daSJonas Devlieghere       Iter.no_push();
2299ca491daSJonas Devlieghere     }
2309ca491daSJonas Devlieghere   }
2319ca491daSJonas Devlieghere }
2329ca491daSJonas Devlieghere 
23346376966SJonas Devlieghere std::error_code FileSystem::MakeAbsolute(SmallVectorImpl<char> &path) const {
23446376966SJonas Devlieghere   return m_fs->makeAbsolute(path);
23546376966SJonas Devlieghere }
23646376966SJonas Devlieghere 
23746376966SJonas Devlieghere std::error_code FileSystem::MakeAbsolute(FileSpec &file_spec) const {
23846376966SJonas Devlieghere   SmallString<128> path;
23946376966SJonas Devlieghere   file_spec.GetPath(path, false);
24046376966SJonas Devlieghere 
24146376966SJonas Devlieghere   auto EC = MakeAbsolute(path);
24246376966SJonas Devlieghere   if (EC)
24346376966SJonas Devlieghere     return EC;
24446376966SJonas Devlieghere 
2458f3be7a3SJonas Devlieghere   FileSpec new_file_spec(path, file_spec.GetPathStyle());
24646376966SJonas Devlieghere   file_spec = new_file_spec;
24746376966SJonas Devlieghere   return {};
24846376966SJonas Devlieghere }
24946376966SJonas Devlieghere 
25046376966SJonas Devlieghere std::error_code FileSystem::GetRealPath(const Twine &path,
25172787ac6SJonas Devlieghere                                         SmallVectorImpl<char> &output) const {
25272787ac6SJonas Devlieghere   return m_fs->getRealPath(path, output);
25346376966SJonas Devlieghere }
25446376966SJonas Devlieghere 
25546376966SJonas Devlieghere void FileSystem::Resolve(SmallVectorImpl<char> &path) {
25646376966SJonas Devlieghere   if (path.empty())
25746376966SJonas Devlieghere     return;
25846376966SJonas Devlieghere 
259feb99530SJonas Devlieghere   // Resolve tilde in path.
260feb99530SJonas Devlieghere   SmallString<128> resolved(path.begin(), path.end());
26172787ac6SJonas Devlieghere   StandardTildeExpressionResolver Resolver;
262feb99530SJonas Devlieghere   Resolver.ResolveFullPath(llvm::StringRef(path.begin(), path.size()),
263feb99530SJonas Devlieghere                            resolved);
26446376966SJonas Devlieghere 
26546376966SJonas Devlieghere   // Try making the path absolute if it exists.
266feb99530SJonas Devlieghere   SmallString<128> absolute(resolved.begin(), resolved.end());
267feb99530SJonas Devlieghere   MakeAbsolute(absolute);
268feb99530SJonas Devlieghere 
26946376966SJonas Devlieghere   path.clear();
270feb99530SJonas Devlieghere   if (Exists(absolute)) {
271feb99530SJonas Devlieghere     path.append(absolute.begin(), absolute.end());
272feb99530SJonas Devlieghere   } else {
273feb99530SJonas Devlieghere     path.append(resolved.begin(), resolved.end());
27446376966SJonas Devlieghere   }
27546376966SJonas Devlieghere }
27646376966SJonas Devlieghere 
27746376966SJonas Devlieghere void FileSystem::Resolve(FileSpec &file_spec) {
278d144087cSJonas Devlieghere   if (!file_spec)
279d144087cSJonas Devlieghere     return;
280d144087cSJonas Devlieghere 
28146376966SJonas Devlieghere   // Extract path from the FileSpec.
28246376966SJonas Devlieghere   SmallString<128> path;
28346376966SJonas Devlieghere   file_spec.GetPath(path);
28446376966SJonas Devlieghere 
28546376966SJonas Devlieghere   // Resolve the path.
28646376966SJonas Devlieghere   Resolve(path);
28746376966SJonas Devlieghere 
28846376966SJonas Devlieghere   // Update the FileSpec with the resolved path.
28981d03f3aSAdrian Prantl   if (file_spec.GetFilename().IsEmpty())
29081d03f3aSAdrian Prantl     file_spec.GetDirectory().SetString(path);
29181d03f3aSAdrian Prantl   else
29246376966SJonas Devlieghere     file_spec.SetPath(path);
2938f3be7a3SJonas Devlieghere   file_spec.SetIsResolved(true);
2941408bf72SPavel Labath }
2952c22c800SJonas Devlieghere 
29687e403aaSJonas Devlieghere std::shared_ptr<DataBufferLLVM>
29787e403aaSJonas Devlieghere FileSystem::CreateDataBuffer(const llvm::Twine &path, uint64_t size,
29887e403aaSJonas Devlieghere                              uint64_t offset) {
2991f80e515SJonas Devlieghere   Collect(path);
30046575176SJonas Devlieghere 
30187e403aaSJonas Devlieghere   const bool is_volatile = !IsLocal(path);
30246575176SJonas Devlieghere   const ErrorOr<std::string> external_path = GetExternalPath(path);
30346575176SJonas Devlieghere 
30446575176SJonas Devlieghere   if (!external_path)
30546575176SJonas Devlieghere     return nullptr;
30687e403aaSJonas Devlieghere 
30787e403aaSJonas Devlieghere   std::unique_ptr<llvm::WritableMemoryBuffer> buffer;
30887e403aaSJonas Devlieghere   if (size == 0) {
30987e403aaSJonas Devlieghere     auto buffer_or_error =
310*c83cd8feSAbhina Sreeskantharajan         llvm::WritableMemoryBuffer::getFile(*external_path, is_volatile);
31187e403aaSJonas Devlieghere     if (!buffer_or_error)
31287e403aaSJonas Devlieghere       return nullptr;
31387e403aaSJonas Devlieghere     buffer = std::move(*buffer_or_error);
31487e403aaSJonas Devlieghere   } else {
31587e403aaSJonas Devlieghere     auto buffer_or_error = llvm::WritableMemoryBuffer::getFileSlice(
31646575176SJonas Devlieghere         *external_path, size, offset, is_volatile);
31787e403aaSJonas Devlieghere     if (!buffer_or_error)
31887e403aaSJonas Devlieghere       return nullptr;
31987e403aaSJonas Devlieghere     buffer = std::move(*buffer_or_error);
32087e403aaSJonas Devlieghere   }
32187e403aaSJonas Devlieghere   return std::shared_ptr<DataBufferLLVM>(new DataBufferLLVM(std::move(buffer)));
32287e403aaSJonas Devlieghere }
32387e403aaSJonas Devlieghere 
32487e403aaSJonas Devlieghere std::shared_ptr<DataBufferLLVM>
32587e403aaSJonas Devlieghere FileSystem::CreateDataBuffer(const FileSpec &file_spec, uint64_t size,
32687e403aaSJonas Devlieghere                              uint64_t offset) {
32787e403aaSJonas Devlieghere   return CreateDataBuffer(file_spec.GetPath(), size, offset);
32887e403aaSJonas Devlieghere }
32987e403aaSJonas Devlieghere 
3302c22c800SJonas Devlieghere bool FileSystem::ResolveExecutableLocation(FileSpec &file_spec) {
3312c22c800SJonas Devlieghere   // If the directory is set there's nothing to do.
3320e4c4821SAdrian Prantl   ConstString directory = file_spec.GetDirectory();
3332c22c800SJonas Devlieghere   if (directory)
3342c22c800SJonas Devlieghere     return false;
3352c22c800SJonas Devlieghere 
3362c22c800SJonas Devlieghere   // We cannot look for a file if there's no file name.
3370e4c4821SAdrian Prantl   ConstString filename = file_spec.GetFilename();
3382c22c800SJonas Devlieghere   if (!filename)
3392c22c800SJonas Devlieghere     return false;
3402c22c800SJonas Devlieghere 
3412c22c800SJonas Devlieghere   // Search for the file on the host.
3422c22c800SJonas Devlieghere   const std::string filename_str(filename.GetCString());
3432c22c800SJonas Devlieghere   llvm::ErrorOr<std::string> error_or_path =
3442c22c800SJonas Devlieghere       llvm::sys::findProgramByName(filename_str);
3452c22c800SJonas Devlieghere   if (!error_or_path)
3462c22c800SJonas Devlieghere     return false;
3472c22c800SJonas Devlieghere 
3482c22c800SJonas Devlieghere   // findProgramByName returns "." if it can't find the file.
3492c22c800SJonas Devlieghere   llvm::StringRef path = *error_or_path;
3502c22c800SJonas Devlieghere   llvm::StringRef parent = llvm::sys::path::parent_path(path);
3512c22c800SJonas Devlieghere   if (parent.empty() || parent == ".")
3522c22c800SJonas Devlieghere     return false;
3532c22c800SJonas Devlieghere 
3542c22c800SJonas Devlieghere   // Make sure that the result exists.
3558f3be7a3SJonas Devlieghere   FileSpec result(*error_or_path);
3562c22c800SJonas Devlieghere   if (!Exists(result))
3572c22c800SJonas Devlieghere     return false;
3582c22c800SJonas Devlieghere 
3592c22c800SJonas Devlieghere   file_spec = result;
3602c22c800SJonas Devlieghere   return true;
3612c22c800SJonas Devlieghere }
36250bc1ed2SJonas Devlieghere 
363921c1b7dSJonas Devlieghere bool FileSystem::GetHomeDirectory(SmallVectorImpl<char> &path) const {
36473af341bSJonas Devlieghere   if (!m_home_directory.empty()) {
36573af341bSJonas Devlieghere     path.assign(m_home_directory.begin(), m_home_directory.end());
36673af341bSJonas Devlieghere     return true;
36773af341bSJonas Devlieghere   }
368921c1b7dSJonas Devlieghere   return llvm::sys::path::home_directory(path);
369921c1b7dSJonas Devlieghere }
370921c1b7dSJonas Devlieghere 
371921c1b7dSJonas Devlieghere bool FileSystem::GetHomeDirectory(FileSpec &file_spec) const {
372921c1b7dSJonas Devlieghere   SmallString<128> home_dir;
373921c1b7dSJonas Devlieghere   if (!GetHomeDirectory(home_dir))
374921c1b7dSJonas Devlieghere     return false;
375921c1b7dSJonas Devlieghere   file_spec.SetPath(home_dir);
376921c1b7dSJonas Devlieghere   return true;
377921c1b7dSJonas Devlieghere }
378921c1b7dSJonas Devlieghere 
37950bc1ed2SJonas Devlieghere static int OpenWithFS(const FileSystem &fs, const char *path, int flags,
38050bc1ed2SJonas Devlieghere                       int mode) {
38150bc1ed2SJonas Devlieghere   return const_cast<FileSystem &>(fs).Open(path, flags, mode);
38250bc1ed2SJonas Devlieghere }
38350bc1ed2SJonas Devlieghere 
38450bc1ed2SJonas Devlieghere static int GetOpenFlags(uint32_t options) {
38550bc1ed2SJonas Devlieghere   const bool read = options & File::eOpenOptionRead;
38650bc1ed2SJonas Devlieghere   const bool write = options & File::eOpenOptionWrite;
38750bc1ed2SJonas Devlieghere 
38850bc1ed2SJonas Devlieghere   int open_flags = 0;
38950bc1ed2SJonas Devlieghere   if (write) {
39050bc1ed2SJonas Devlieghere     if (read)
39150bc1ed2SJonas Devlieghere       open_flags |= O_RDWR;
39250bc1ed2SJonas Devlieghere     else
39350bc1ed2SJonas Devlieghere       open_flags |= O_WRONLY;
39450bc1ed2SJonas Devlieghere 
39550bc1ed2SJonas Devlieghere     if (options & File::eOpenOptionAppend)
39650bc1ed2SJonas Devlieghere       open_flags |= O_APPEND;
39750bc1ed2SJonas Devlieghere 
39850bc1ed2SJonas Devlieghere     if (options & File::eOpenOptionTruncate)
39950bc1ed2SJonas Devlieghere       open_flags |= O_TRUNC;
40050bc1ed2SJonas Devlieghere 
40150bc1ed2SJonas Devlieghere     if (options & File::eOpenOptionCanCreate)
40250bc1ed2SJonas Devlieghere       open_flags |= O_CREAT;
40350bc1ed2SJonas Devlieghere 
40450bc1ed2SJonas Devlieghere     if (options & File::eOpenOptionCanCreateNewOnly)
40550bc1ed2SJonas Devlieghere       open_flags |= O_CREAT | O_EXCL;
40650bc1ed2SJonas Devlieghere   } else if (read) {
40750bc1ed2SJonas Devlieghere     open_flags |= O_RDONLY;
40850bc1ed2SJonas Devlieghere 
40950bc1ed2SJonas Devlieghere #ifndef _WIN32
41050bc1ed2SJonas Devlieghere     if (options & File::eOpenOptionDontFollowSymlinks)
41150bc1ed2SJonas Devlieghere       open_flags |= O_NOFOLLOW;
41250bc1ed2SJonas Devlieghere #endif
41350bc1ed2SJonas Devlieghere   }
41450bc1ed2SJonas Devlieghere 
41550bc1ed2SJonas Devlieghere #ifndef _WIN32
41650bc1ed2SJonas Devlieghere   if (options & File::eOpenOptionNonBlocking)
41750bc1ed2SJonas Devlieghere     open_flags |= O_NONBLOCK;
41850bc1ed2SJonas Devlieghere   if (options & File::eOpenOptionCloseOnExec)
41950bc1ed2SJonas Devlieghere     open_flags |= O_CLOEXEC;
42050bc1ed2SJonas Devlieghere #else
42150bc1ed2SJonas Devlieghere   open_flags |= O_BINARY;
42250bc1ed2SJonas Devlieghere #endif
42350bc1ed2SJonas Devlieghere 
42450bc1ed2SJonas Devlieghere   return open_flags;
42550bc1ed2SJonas Devlieghere }
42650bc1ed2SJonas Devlieghere 
42750bc1ed2SJonas Devlieghere static mode_t GetOpenMode(uint32_t permissions) {
42850bc1ed2SJonas Devlieghere   mode_t mode = 0;
42950bc1ed2SJonas Devlieghere   if (permissions & lldb::eFilePermissionsUserRead)
43050bc1ed2SJonas Devlieghere     mode |= S_IRUSR;
43150bc1ed2SJonas Devlieghere   if (permissions & lldb::eFilePermissionsUserWrite)
43250bc1ed2SJonas Devlieghere     mode |= S_IWUSR;
43350bc1ed2SJonas Devlieghere   if (permissions & lldb::eFilePermissionsUserExecute)
43450bc1ed2SJonas Devlieghere     mode |= S_IXUSR;
43550bc1ed2SJonas Devlieghere   if (permissions & lldb::eFilePermissionsGroupRead)
43650bc1ed2SJonas Devlieghere     mode |= S_IRGRP;
43750bc1ed2SJonas Devlieghere   if (permissions & lldb::eFilePermissionsGroupWrite)
43850bc1ed2SJonas Devlieghere     mode |= S_IWGRP;
43950bc1ed2SJonas Devlieghere   if (permissions & lldb::eFilePermissionsGroupExecute)
44050bc1ed2SJonas Devlieghere     mode |= S_IXGRP;
44150bc1ed2SJonas Devlieghere   if (permissions & lldb::eFilePermissionsWorldRead)
44250bc1ed2SJonas Devlieghere     mode |= S_IROTH;
44350bc1ed2SJonas Devlieghere   if (permissions & lldb::eFilePermissionsWorldWrite)
44450bc1ed2SJonas Devlieghere     mode |= S_IWOTH;
44550bc1ed2SJonas Devlieghere   if (permissions & lldb::eFilePermissionsWorldExecute)
44650bc1ed2SJonas Devlieghere     mode |= S_IXOTH;
44750bc1ed2SJonas Devlieghere   return mode;
44850bc1ed2SJonas Devlieghere }
44950bc1ed2SJonas Devlieghere 
45062c9fe42SLawrence D'Anna Expected<FileUP> FileSystem::Open(const FileSpec &file_spec,
45162c9fe42SLawrence D'Anna                                   File::OpenOptions options,
4523a142495SAaron Smith                                   uint32_t permissions, bool should_close_fd) {
4531f80e515SJonas Devlieghere   Collect(file_spec.GetPath());
45446575176SJonas Devlieghere 
45550bc1ed2SJonas Devlieghere   const int open_flags = GetOpenFlags(options);
45650bc1ed2SJonas Devlieghere   const mode_t open_mode =
45750bc1ed2SJonas Devlieghere       (open_flags & O_CREAT) ? GetOpenMode(permissions) : 0;
45846575176SJonas Devlieghere 
45946575176SJonas Devlieghere   auto path = GetExternalPath(file_spec);
46046575176SJonas Devlieghere   if (!path)
4612fce1137SLawrence D'Anna     return errorCodeToError(path.getError());
46250bc1ed2SJonas Devlieghere 
46350bc1ed2SJonas Devlieghere   int descriptor = llvm::sys::RetryAfterSignal(
46446575176SJonas Devlieghere       -1, OpenWithFS, *this, path->c_str(), open_flags, open_mode);
46550bc1ed2SJonas Devlieghere 
4662fce1137SLawrence D'Anna   if (!File::DescriptorIsValid(descriptor))
4672fce1137SLawrence D'Anna     return llvm::errorCodeToError(
4682fce1137SLawrence D'Anna         std::error_code(errno, std::system_category()));
4692fce1137SLawrence D'Anna 
470f913fd6eSLawrence D'Anna   auto file = std::unique_ptr<File>(
471f913fd6eSLawrence D'Anna       new NativeFile(descriptor, options, should_close_fd));
4722fce1137SLawrence D'Anna   assert(file->IsValid());
4732fce1137SLawrence D'Anna   return std::move(file);
47450bc1ed2SJonas Devlieghere }
47546575176SJonas Devlieghere 
47646575176SJonas Devlieghere ErrorOr<std::string> FileSystem::GetExternalPath(const llvm::Twine &path) {
47746575176SJonas Devlieghere   if (!m_mapped)
47846575176SJonas Devlieghere     return path.str();
47946575176SJonas Devlieghere 
48046575176SJonas Devlieghere   // If VFS mapped we know the underlying FS is a RedirectingFileSystem.
481ecb00a77SNathan Hawes   ErrorOr<vfs::RedirectingFileSystem::LookupResult> Result =
4823a50ed84SJonas Devlieghere       static_cast<vfs::RedirectingFileSystem &>(*m_fs).lookupPath(path.str());
483ecb00a77SNathan Hawes   if (!Result) {
484ecb00a77SNathan Hawes     if (Result.getError() == llvm::errc::no_such_file_or_directory) {
48546575176SJonas Devlieghere       return path.str();
48646575176SJonas Devlieghere     }
487ecb00a77SNathan Hawes     return Result.getError();
48846575176SJonas Devlieghere   }
48946575176SJonas Devlieghere 
490ecb00a77SNathan Hawes   if (Optional<StringRef> ExtRedirect = Result->getExternalRedirect())
491ecb00a77SNathan Hawes     return std::string(*ExtRedirect);
49246575176SJonas Devlieghere   return make_error_code(llvm::errc::not_supported);
49346575176SJonas Devlieghere }
49446575176SJonas Devlieghere 
49546575176SJonas Devlieghere ErrorOr<std::string> FileSystem::GetExternalPath(const FileSpec &file_spec) {
49646575176SJonas Devlieghere   return GetExternalPath(file_spec.GetPath());
49746575176SJonas Devlieghere }
4984c2b0a63SJonas Devlieghere 
4991f80e515SJonas Devlieghere void FileSystem::Collect(const FileSpec &file_spec) {
5001f80e515SJonas Devlieghere   Collect(file_spec.GetPath());
5011f80e515SJonas Devlieghere }
5021f80e515SJonas Devlieghere 
5031f80e515SJonas Devlieghere void FileSystem::Collect(const llvm::Twine &file) {
504ab22f71dSJonas Devlieghere   if (!m_collector)
505ab22f71dSJonas Devlieghere     return;
506ab22f71dSJonas Devlieghere 
507ab22f71dSJonas Devlieghere   if (llvm::sys::fs::is_directory(file))
508ab22f71dSJonas Devlieghere     m_collector->addDirectory(file);
509ab22f71dSJonas Devlieghere   else
5104c2b0a63SJonas Devlieghere     m_collector->addFile(file);
5114c2b0a63SJonas Devlieghere }
51273af341bSJonas Devlieghere 
51373af341bSJonas Devlieghere void FileSystem::SetHomeDirectory(std::string home_directory) {
51473af341bSJonas Devlieghere   m_home_directory = std::move(home_directory);
51573af341bSJonas Devlieghere }
516