xref: /freebsd-src/contrib/llvm-project/lldb/source/Host/common/FileSystem.cpp (revision cb14a3fe5122c879eae1fb480ed7ce82a699ddb6)
15ffd83dbSDimitry Andric //===-- FileSystem.cpp ----------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/Host/FileSystem.h"
100b57cec5SDimitry Andric 
1181ad6265SDimitry Andric #include "lldb/Utility/DataBufferLLVM.h"
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "llvm/Support/Errc.h"
140b57cec5SDimitry Andric #include "llvm/Support/Errno.h"
150b57cec5SDimitry Andric #include "llvm/Support/Error.h"
160b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
170b57cec5SDimitry Andric #include "llvm/Support/Path.h"
180b57cec5SDimitry Andric #include "llvm/Support/Program.h"
190b57cec5SDimitry Andric #include "llvm/Support/Threading.h"
200b57cec5SDimitry Andric 
21fe6060f1SDimitry Andric #include <cerrno>
22fe6060f1SDimitry Andric #include <climits>
23fe6060f1SDimitry Andric #include <cstdarg>
24fe6060f1SDimitry Andric #include <cstdio>
250b57cec5SDimitry Andric #include <fcntl.h>
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric #ifdef _WIN32
280b57cec5SDimitry Andric #include "lldb/Host/windows/windows.h"
290b57cec5SDimitry Andric #else
300b57cec5SDimitry Andric #include <sys/ioctl.h>
310b57cec5SDimitry Andric #include <sys/stat.h>
320b57cec5SDimitry Andric #include <termios.h>
330b57cec5SDimitry Andric #include <unistd.h>
340b57cec5SDimitry Andric #endif
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric #include <algorithm>
370b57cec5SDimitry Andric #include <fstream>
38bdd1243dSDimitry Andric #include <optional>
390b57cec5SDimitry Andric #include <vector>
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric using namespace lldb;
420b57cec5SDimitry Andric using namespace lldb_private;
430b57cec5SDimitry Andric using namespace llvm;
440b57cec5SDimitry Andric 
Instance()450b57cec5SDimitry Andric FileSystem &FileSystem::Instance() { return *InstanceImpl(); }
460b57cec5SDimitry Andric 
Terminate()470b57cec5SDimitry Andric void FileSystem::Terminate() {
480b57cec5SDimitry Andric   lldbassert(InstanceImpl() && "Already terminated.");
490b57cec5SDimitry Andric   InstanceImpl().reset();
500b57cec5SDimitry Andric }
510b57cec5SDimitry Andric 
InstanceImpl()52bdd1243dSDimitry Andric std::optional<FileSystem> &FileSystem::InstanceImpl() {
53bdd1243dSDimitry Andric   static std::optional<FileSystem> g_fs;
540b57cec5SDimitry Andric   return g_fs;
550b57cec5SDimitry Andric }
560b57cec5SDimitry Andric 
DirBegin(const FileSpec & file_spec,std::error_code & ec)570b57cec5SDimitry Andric vfs::directory_iterator FileSystem::DirBegin(const FileSpec &file_spec,
580b57cec5SDimitry Andric                                              std::error_code &ec) {
595ffd83dbSDimitry Andric   if (!file_spec) {
605ffd83dbSDimitry Andric     ec = std::error_code(static_cast<int>(errc::no_such_file_or_directory),
615ffd83dbSDimitry Andric                          std::system_category());
625ffd83dbSDimitry Andric     return {};
635ffd83dbSDimitry Andric   }
640b57cec5SDimitry Andric   return DirBegin(file_spec.GetPath(), ec);
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric 
DirBegin(const Twine & dir,std::error_code & ec)670b57cec5SDimitry Andric vfs::directory_iterator FileSystem::DirBegin(const Twine &dir,
680b57cec5SDimitry Andric                                              std::error_code &ec) {
690b57cec5SDimitry Andric   return m_fs->dir_begin(dir, ec);
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric llvm::ErrorOr<vfs::Status>
GetStatus(const FileSpec & file_spec) const730b57cec5SDimitry Andric FileSystem::GetStatus(const FileSpec &file_spec) const {
745ffd83dbSDimitry Andric   if (!file_spec)
755ffd83dbSDimitry Andric     return std::error_code(static_cast<int>(errc::no_such_file_or_directory),
765ffd83dbSDimitry Andric                            std::system_category());
770b57cec5SDimitry Andric   return GetStatus(file_spec.GetPath());
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric 
GetStatus(const Twine & path) const800b57cec5SDimitry Andric llvm::ErrorOr<vfs::Status> FileSystem::GetStatus(const Twine &path) const {
810b57cec5SDimitry Andric   return m_fs->status(path);
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric sys::TimePoint<>
GetModificationTime(const FileSpec & file_spec) const850b57cec5SDimitry Andric FileSystem::GetModificationTime(const FileSpec &file_spec) const {
865ffd83dbSDimitry Andric   if (!file_spec)
875ffd83dbSDimitry Andric     return sys::TimePoint<>();
880b57cec5SDimitry Andric   return GetModificationTime(file_spec.GetPath());
890b57cec5SDimitry Andric }
900b57cec5SDimitry Andric 
GetModificationTime(const Twine & path) const910b57cec5SDimitry Andric sys::TimePoint<> FileSystem::GetModificationTime(const Twine &path) const {
920b57cec5SDimitry Andric   ErrorOr<vfs::Status> status = m_fs->status(path);
930b57cec5SDimitry Andric   if (!status)
940b57cec5SDimitry Andric     return sys::TimePoint<>();
950b57cec5SDimitry Andric   return status->getLastModificationTime();
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric 
GetByteSize(const FileSpec & file_spec) const980b57cec5SDimitry Andric uint64_t FileSystem::GetByteSize(const FileSpec &file_spec) const {
995ffd83dbSDimitry Andric   if (!file_spec)
1005ffd83dbSDimitry Andric     return 0;
1010b57cec5SDimitry Andric   return GetByteSize(file_spec.GetPath());
1020b57cec5SDimitry Andric }
1030b57cec5SDimitry Andric 
GetByteSize(const Twine & path) const1040b57cec5SDimitry Andric uint64_t FileSystem::GetByteSize(const Twine &path) const {
1050b57cec5SDimitry Andric   ErrorOr<vfs::Status> status = m_fs->status(path);
1060b57cec5SDimitry Andric   if (!status)
1070b57cec5SDimitry Andric     return 0;
1080b57cec5SDimitry Andric   return status->getSize();
1090b57cec5SDimitry Andric }
1100b57cec5SDimitry Andric 
GetPermissions(const FileSpec & file_spec) const1110b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const FileSpec &file_spec) const {
1120b57cec5SDimitry Andric   return GetPermissions(file_spec.GetPath());
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric 
GetPermissions(const FileSpec & file_spec,std::error_code & ec) const1150b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const FileSpec &file_spec,
1160b57cec5SDimitry Andric                                     std::error_code &ec) const {
1175ffd83dbSDimitry Andric   if (!file_spec)
1185ffd83dbSDimitry Andric     return sys::fs::perms::perms_not_known;
1190b57cec5SDimitry Andric   return GetPermissions(file_spec.GetPath(), ec);
1200b57cec5SDimitry Andric }
1210b57cec5SDimitry Andric 
GetPermissions(const Twine & path) const1220b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const Twine &path) const {
1230b57cec5SDimitry Andric   std::error_code ec;
1240b57cec5SDimitry Andric   return GetPermissions(path, ec);
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric 
GetPermissions(const Twine & path,std::error_code & ec) const1270b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const Twine &path,
1280b57cec5SDimitry Andric                                     std::error_code &ec) const {
1290b57cec5SDimitry Andric   ErrorOr<vfs::Status> status = m_fs->status(path);
1300b57cec5SDimitry Andric   if (!status) {
1310b57cec5SDimitry Andric     ec = status.getError();
1320b57cec5SDimitry Andric     return sys::fs::perms::perms_not_known;
1330b57cec5SDimitry Andric   }
1340b57cec5SDimitry Andric   return status->getPermissions();
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric 
Exists(const Twine & path) const1370b57cec5SDimitry Andric bool FileSystem::Exists(const Twine &path) const { return m_fs->exists(path); }
1380b57cec5SDimitry Andric 
Exists(const FileSpec & file_spec) const1390b57cec5SDimitry Andric bool FileSystem::Exists(const FileSpec &file_spec) const {
1405ffd83dbSDimitry Andric   return file_spec && Exists(file_spec.GetPath());
1410b57cec5SDimitry Andric }
1420b57cec5SDimitry Andric 
Readable(const Twine & path) const1430b57cec5SDimitry Andric bool FileSystem::Readable(const Twine &path) const {
1440b57cec5SDimitry Andric   return GetPermissions(path) & sys::fs::perms::all_read;
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric 
Readable(const FileSpec & file_spec) const1470b57cec5SDimitry Andric bool FileSystem::Readable(const FileSpec &file_spec) const {
1485ffd83dbSDimitry Andric   return file_spec && Readable(file_spec.GetPath());
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric 
IsDirectory(const Twine & path) const1510b57cec5SDimitry Andric bool FileSystem::IsDirectory(const Twine &path) const {
1520b57cec5SDimitry Andric   ErrorOr<vfs::Status> status = m_fs->status(path);
1530b57cec5SDimitry Andric   if (!status)
1540b57cec5SDimitry Andric     return false;
1550b57cec5SDimitry Andric   return status->isDirectory();
1560b57cec5SDimitry Andric }
1570b57cec5SDimitry Andric 
IsDirectory(const FileSpec & file_spec) const1580b57cec5SDimitry Andric bool FileSystem::IsDirectory(const FileSpec &file_spec) const {
1595ffd83dbSDimitry Andric   return file_spec && IsDirectory(file_spec.GetPath());
1600b57cec5SDimitry Andric }
1610b57cec5SDimitry Andric 
IsLocal(const Twine & path) const1620b57cec5SDimitry Andric bool FileSystem::IsLocal(const Twine &path) const {
1630b57cec5SDimitry Andric   bool b = false;
1640b57cec5SDimitry Andric   m_fs->isLocal(path, b);
1650b57cec5SDimitry Andric   return b;
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric 
IsLocal(const FileSpec & file_spec) const1680b57cec5SDimitry Andric bool FileSystem::IsLocal(const FileSpec &file_spec) const {
1695ffd83dbSDimitry Andric   return file_spec && IsLocal(file_spec.GetPath());
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric 
EnumerateDirectory(Twine path,bool find_directories,bool find_files,bool find_other,EnumerateDirectoryCallbackType callback,void * callback_baton)1720b57cec5SDimitry Andric void FileSystem::EnumerateDirectory(Twine path, bool find_directories,
1730b57cec5SDimitry Andric                                     bool find_files, bool find_other,
1740b57cec5SDimitry Andric                                     EnumerateDirectoryCallbackType callback,
1750b57cec5SDimitry Andric                                     void *callback_baton) {
1760b57cec5SDimitry Andric   std::error_code EC;
1770b57cec5SDimitry Andric   vfs::recursive_directory_iterator Iter(*m_fs, path, EC);
1780b57cec5SDimitry Andric   vfs::recursive_directory_iterator End;
1790b57cec5SDimitry Andric   for (; Iter != End && !EC; Iter.increment(EC)) {
1800b57cec5SDimitry Andric     const auto &Item = *Iter;
1810b57cec5SDimitry Andric     ErrorOr<vfs::Status> Status = m_fs->status(Item.path());
1820b57cec5SDimitry Andric     if (!Status)
183*06c3fb27SDimitry Andric       continue;
1840b57cec5SDimitry Andric     if (!find_files && Status->isRegularFile())
1850b57cec5SDimitry Andric       continue;
1860b57cec5SDimitry Andric     if (!find_directories && Status->isDirectory())
1870b57cec5SDimitry Andric       continue;
1880b57cec5SDimitry Andric     if (!find_other && Status->isOther())
1890b57cec5SDimitry Andric       continue;
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric     auto Result = callback(callback_baton, Status->getType(), Item.path());
1920b57cec5SDimitry Andric     if (Result == eEnumerateDirectoryResultQuit)
1930b57cec5SDimitry Andric       return;
1940b57cec5SDimitry Andric     if (Result == eEnumerateDirectoryResultNext) {
1950b57cec5SDimitry Andric       // Default behavior is to recurse. Opt out if the callback doesn't want
1960b57cec5SDimitry Andric       // this behavior.
1970b57cec5SDimitry Andric       Iter.no_push();
1980b57cec5SDimitry Andric     }
1990b57cec5SDimitry Andric   }
2000b57cec5SDimitry Andric }
2010b57cec5SDimitry Andric 
MakeAbsolute(SmallVectorImpl<char> & path) const2020b57cec5SDimitry Andric std::error_code FileSystem::MakeAbsolute(SmallVectorImpl<char> &path) const {
2030b57cec5SDimitry Andric   return m_fs->makeAbsolute(path);
2040b57cec5SDimitry Andric }
2050b57cec5SDimitry Andric 
MakeAbsolute(FileSpec & file_spec) const2060b57cec5SDimitry Andric std::error_code FileSystem::MakeAbsolute(FileSpec &file_spec) const {
2070b57cec5SDimitry Andric   SmallString<128> path;
2080b57cec5SDimitry Andric   file_spec.GetPath(path, false);
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric   auto EC = MakeAbsolute(path);
2110b57cec5SDimitry Andric   if (EC)
2120b57cec5SDimitry Andric     return EC;
2130b57cec5SDimitry Andric 
2140b57cec5SDimitry Andric   FileSpec new_file_spec(path, file_spec.GetPathStyle());
2150b57cec5SDimitry Andric   file_spec = new_file_spec;
2160b57cec5SDimitry Andric   return {};
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric 
GetRealPath(const Twine & path,SmallVectorImpl<char> & output) const2190b57cec5SDimitry Andric std::error_code FileSystem::GetRealPath(const Twine &path,
2200b57cec5SDimitry Andric                                         SmallVectorImpl<char> &output) const {
2210b57cec5SDimitry Andric   return m_fs->getRealPath(path, output);
2220b57cec5SDimitry Andric }
2230b57cec5SDimitry Andric 
Resolve(SmallVectorImpl<char> & path)2240b57cec5SDimitry Andric void FileSystem::Resolve(SmallVectorImpl<char> &path) {
2250b57cec5SDimitry Andric   if (path.empty())
2260b57cec5SDimitry Andric     return;
2270b57cec5SDimitry Andric 
2280b57cec5SDimitry Andric   // Resolve tilde in path.
2290b57cec5SDimitry Andric   SmallString<128> resolved(path.begin(), path.end());
230*06c3fb27SDimitry Andric   assert(m_tilde_resolver && "must initialize tilde resolver in constructor");
231*06c3fb27SDimitry Andric   m_tilde_resolver->ResolveFullPath(llvm::StringRef(path.begin(), path.size()),
2320b57cec5SDimitry Andric                                     resolved);
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric   // Try making the path absolute if it exists.
2350b57cec5SDimitry Andric   SmallString<128> absolute(resolved.begin(), resolved.end());
2360b57cec5SDimitry Andric   MakeAbsolute(absolute);
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   path.clear();
2390b57cec5SDimitry Andric   if (Exists(absolute)) {
2400b57cec5SDimitry Andric     path.append(absolute.begin(), absolute.end());
2410b57cec5SDimitry Andric   } else {
2420b57cec5SDimitry Andric     path.append(resolved.begin(), resolved.end());
2430b57cec5SDimitry Andric   }
2440b57cec5SDimitry Andric }
2450b57cec5SDimitry Andric 
Resolve(FileSpec & file_spec)2460b57cec5SDimitry Andric void FileSystem::Resolve(FileSpec &file_spec) {
2475ffd83dbSDimitry Andric   if (!file_spec)
2485ffd83dbSDimitry Andric     return;
2495ffd83dbSDimitry Andric 
2500b57cec5SDimitry Andric   // Extract path from the FileSpec.
2510b57cec5SDimitry Andric   SmallString<128> path;
2520b57cec5SDimitry Andric   file_spec.GetPath(path);
2530b57cec5SDimitry Andric 
2540b57cec5SDimitry Andric   // Resolve the path.
2550b57cec5SDimitry Andric   Resolve(path);
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric   // Update the FileSpec with the resolved path.
2580b57cec5SDimitry Andric   if (file_spec.GetFilename().IsEmpty())
259bdd1243dSDimitry Andric     file_spec.SetDirectory(path);
2600b57cec5SDimitry Andric   else
2610b57cec5SDimitry Andric     file_spec.SetPath(path);
2620b57cec5SDimitry Andric }
2630b57cec5SDimitry Andric 
26481ad6265SDimitry Andric template <typename T>
GetMemoryBuffer(const llvm::Twine & path,uint64_t size,uint64_t offset,bool is_volatile)26581ad6265SDimitry Andric static std::unique_ptr<T> GetMemoryBuffer(const llvm::Twine &path,
26681ad6265SDimitry Andric                                           uint64_t size, uint64_t offset,
26781ad6265SDimitry Andric                                           bool is_volatile) {
26881ad6265SDimitry Andric   std::unique_ptr<T> buffer;
2690b57cec5SDimitry Andric   if (size == 0) {
27081ad6265SDimitry Andric     auto buffer_or_error = T::getFile(path, is_volatile);
2710b57cec5SDimitry Andric     if (!buffer_or_error)
2720b57cec5SDimitry Andric       return nullptr;
2730b57cec5SDimitry Andric     buffer = std::move(*buffer_or_error);
2740b57cec5SDimitry Andric   } else {
27581ad6265SDimitry Andric     auto buffer_or_error = T::getFileSlice(path, size, offset, is_volatile);
2760b57cec5SDimitry Andric     if (!buffer_or_error)
2770b57cec5SDimitry Andric       return nullptr;
2780b57cec5SDimitry Andric     buffer = std::move(*buffer_or_error);
2790b57cec5SDimitry Andric   }
28081ad6265SDimitry Andric   return buffer;
28181ad6265SDimitry Andric }
28281ad6265SDimitry Andric 
28381ad6265SDimitry Andric std::shared_ptr<WritableDataBuffer>
CreateWritableDataBuffer(const llvm::Twine & path,uint64_t size,uint64_t offset)28481ad6265SDimitry Andric FileSystem::CreateWritableDataBuffer(const llvm::Twine &path, uint64_t size,
28581ad6265SDimitry Andric                                      uint64_t offset) {
28681ad6265SDimitry Andric   const bool is_volatile = !IsLocal(path);
28781ad6265SDimitry Andric   auto buffer = GetMemoryBuffer<llvm::WritableMemoryBuffer>(path, size, offset,
28881ad6265SDimitry Andric                                                             is_volatile);
28981ad6265SDimitry Andric   if (!buffer)
29081ad6265SDimitry Andric     return {};
29181ad6265SDimitry Andric   return std::shared_ptr<WritableDataBufferLLVM>(
29281ad6265SDimitry Andric       new WritableDataBufferLLVM(std::move(buffer)));
29381ad6265SDimitry Andric }
29481ad6265SDimitry Andric 
29581ad6265SDimitry Andric std::shared_ptr<DataBuffer>
CreateDataBuffer(const llvm::Twine & path,uint64_t size,uint64_t offset)29681ad6265SDimitry Andric FileSystem::CreateDataBuffer(const llvm::Twine &path, uint64_t size,
29781ad6265SDimitry Andric                              uint64_t offset) {
29881ad6265SDimitry Andric   const bool is_volatile = !IsLocal(path);
29981ad6265SDimitry Andric   auto buffer =
30081ad6265SDimitry Andric       GetMemoryBuffer<llvm::MemoryBuffer>(path, size, offset, is_volatile);
30181ad6265SDimitry Andric   if (!buffer)
30281ad6265SDimitry Andric     return {};
3030b57cec5SDimitry Andric   return std::shared_ptr<DataBufferLLVM>(new DataBufferLLVM(std::move(buffer)));
3040b57cec5SDimitry Andric }
3050b57cec5SDimitry Andric 
30681ad6265SDimitry Andric std::shared_ptr<WritableDataBuffer>
CreateWritableDataBuffer(const FileSpec & file_spec,uint64_t size,uint64_t offset)30781ad6265SDimitry Andric FileSystem::CreateWritableDataBuffer(const FileSpec &file_spec, uint64_t size,
30881ad6265SDimitry Andric                                      uint64_t offset) {
30981ad6265SDimitry Andric   return CreateWritableDataBuffer(file_spec.GetPath(), size, offset);
31081ad6265SDimitry Andric }
31181ad6265SDimitry Andric 
31281ad6265SDimitry Andric std::shared_ptr<DataBuffer>
CreateDataBuffer(const FileSpec & file_spec,uint64_t size,uint64_t offset)3130b57cec5SDimitry Andric FileSystem::CreateDataBuffer(const FileSpec &file_spec, uint64_t size,
3140b57cec5SDimitry Andric                              uint64_t offset) {
3150b57cec5SDimitry Andric   return CreateDataBuffer(file_spec.GetPath(), size, offset);
3160b57cec5SDimitry Andric }
3170b57cec5SDimitry Andric 
ResolveExecutableLocation(FileSpec & file_spec)3180b57cec5SDimitry Andric bool FileSystem::ResolveExecutableLocation(FileSpec &file_spec) {
3190b57cec5SDimitry Andric   // If the directory is set there's nothing to do.
3200b57cec5SDimitry Andric   ConstString directory = file_spec.GetDirectory();
3210b57cec5SDimitry Andric   if (directory)
3220b57cec5SDimitry Andric     return false;
3230b57cec5SDimitry Andric 
3240b57cec5SDimitry Andric   // We cannot look for a file if there's no file name.
3250b57cec5SDimitry Andric   ConstString filename = file_spec.GetFilename();
3260b57cec5SDimitry Andric   if (!filename)
3270b57cec5SDimitry Andric     return false;
3280b57cec5SDimitry Andric 
3290b57cec5SDimitry Andric   // Search for the file on the host.
3300b57cec5SDimitry Andric   const std::string filename_str(filename.GetCString());
3310b57cec5SDimitry Andric   llvm::ErrorOr<std::string> error_or_path =
3320b57cec5SDimitry Andric       llvm::sys::findProgramByName(filename_str);
3330b57cec5SDimitry Andric   if (!error_or_path)
3340b57cec5SDimitry Andric     return false;
3350b57cec5SDimitry Andric 
3360b57cec5SDimitry Andric   // findProgramByName returns "." if it can't find the file.
3370b57cec5SDimitry Andric   llvm::StringRef path = *error_or_path;
3380b57cec5SDimitry Andric   llvm::StringRef parent = llvm::sys::path::parent_path(path);
3390b57cec5SDimitry Andric   if (parent.empty() || parent == ".")
3400b57cec5SDimitry Andric     return false;
3410b57cec5SDimitry Andric 
3420b57cec5SDimitry Andric   // Make sure that the result exists.
3430b57cec5SDimitry Andric   FileSpec result(*error_or_path);
3440b57cec5SDimitry Andric   if (!Exists(result))
3450b57cec5SDimitry Andric     return false;
3460b57cec5SDimitry Andric 
3470b57cec5SDimitry Andric   file_spec = result;
3480b57cec5SDimitry Andric   return true;
3490b57cec5SDimitry Andric }
3500b57cec5SDimitry Andric 
GetHomeDirectory(SmallVectorImpl<char> & path) const351e8d8bef9SDimitry Andric bool FileSystem::GetHomeDirectory(SmallVectorImpl<char> &path) const {
352e8d8bef9SDimitry Andric   if (!m_home_directory.empty()) {
353e8d8bef9SDimitry Andric     path.assign(m_home_directory.begin(), m_home_directory.end());
354e8d8bef9SDimitry Andric     return true;
355e8d8bef9SDimitry Andric   }
356e8d8bef9SDimitry Andric   return llvm::sys::path::home_directory(path);
357e8d8bef9SDimitry Andric }
358e8d8bef9SDimitry Andric 
GetHomeDirectory(FileSpec & file_spec) const359e8d8bef9SDimitry Andric bool FileSystem::GetHomeDirectory(FileSpec &file_spec) const {
360e8d8bef9SDimitry Andric   SmallString<128> home_dir;
361e8d8bef9SDimitry Andric   if (!GetHomeDirectory(home_dir))
362e8d8bef9SDimitry Andric     return false;
363e8d8bef9SDimitry Andric   file_spec.SetPath(home_dir);
364e8d8bef9SDimitry Andric   return true;
365e8d8bef9SDimitry Andric }
366e8d8bef9SDimitry Andric 
OpenWithFS(const FileSystem & fs,const char * path,int flags,int mode)3670b57cec5SDimitry Andric static int OpenWithFS(const FileSystem &fs, const char *path, int flags,
3680b57cec5SDimitry Andric                       int mode) {
3690b57cec5SDimitry Andric   return const_cast<FileSystem &>(fs).Open(path, flags, mode);
3700b57cec5SDimitry Andric }
3710b57cec5SDimitry Andric 
GetOpenFlags(File::OpenOptions options)372349cc55cSDimitry Andric static int GetOpenFlags(File::OpenOptions options) {
3730b57cec5SDimitry Andric   int open_flags = 0;
374349cc55cSDimitry Andric   File::OpenOptions rw =
375349cc55cSDimitry Andric       options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
376349cc55cSDimitry Andric                  File::eOpenOptionReadWrite);
377349cc55cSDimitry Andric   if (rw == File::eOpenOptionWriteOnly || rw == File::eOpenOptionReadWrite) {
378349cc55cSDimitry Andric     if (rw == File::eOpenOptionReadWrite)
3790b57cec5SDimitry Andric       open_flags |= O_RDWR;
3800b57cec5SDimitry Andric     else
3810b57cec5SDimitry Andric       open_flags |= O_WRONLY;
3820b57cec5SDimitry Andric 
3830b57cec5SDimitry Andric     if (options & File::eOpenOptionAppend)
3840b57cec5SDimitry Andric       open_flags |= O_APPEND;
3850b57cec5SDimitry Andric 
3860b57cec5SDimitry Andric     if (options & File::eOpenOptionTruncate)
3870b57cec5SDimitry Andric       open_flags |= O_TRUNC;
3880b57cec5SDimitry Andric 
3890b57cec5SDimitry Andric     if (options & File::eOpenOptionCanCreate)
3900b57cec5SDimitry Andric       open_flags |= O_CREAT;
3910b57cec5SDimitry Andric 
3920b57cec5SDimitry Andric     if (options & File::eOpenOptionCanCreateNewOnly)
3930b57cec5SDimitry Andric       open_flags |= O_CREAT | O_EXCL;
394349cc55cSDimitry Andric   } else if (rw == File::eOpenOptionReadOnly) {
3950b57cec5SDimitry Andric     open_flags |= O_RDONLY;
3960b57cec5SDimitry Andric 
3970b57cec5SDimitry Andric #ifndef _WIN32
3980b57cec5SDimitry Andric     if (options & File::eOpenOptionDontFollowSymlinks)
3990b57cec5SDimitry Andric       open_flags |= O_NOFOLLOW;
4000b57cec5SDimitry Andric #endif
4010b57cec5SDimitry Andric   }
4020b57cec5SDimitry Andric 
4030b57cec5SDimitry Andric #ifndef _WIN32
4040b57cec5SDimitry Andric   if (options & File::eOpenOptionNonBlocking)
4050b57cec5SDimitry Andric     open_flags |= O_NONBLOCK;
4060b57cec5SDimitry Andric   if (options & File::eOpenOptionCloseOnExec)
4070b57cec5SDimitry Andric     open_flags |= O_CLOEXEC;
4080b57cec5SDimitry Andric #else
4090b57cec5SDimitry Andric   open_flags |= O_BINARY;
4100b57cec5SDimitry Andric #endif
4110b57cec5SDimitry Andric 
4120b57cec5SDimitry Andric   return open_flags;
4130b57cec5SDimitry Andric }
4140b57cec5SDimitry Andric 
GetOpenMode(uint32_t permissions)4150b57cec5SDimitry Andric static mode_t GetOpenMode(uint32_t permissions) {
4160b57cec5SDimitry Andric   mode_t mode = 0;
4170b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsUserRead)
4180b57cec5SDimitry Andric     mode |= S_IRUSR;
4190b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsUserWrite)
4200b57cec5SDimitry Andric     mode |= S_IWUSR;
4210b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsUserExecute)
4220b57cec5SDimitry Andric     mode |= S_IXUSR;
4230b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsGroupRead)
4240b57cec5SDimitry Andric     mode |= S_IRGRP;
4250b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsGroupWrite)
4260b57cec5SDimitry Andric     mode |= S_IWGRP;
4270b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsGroupExecute)
4280b57cec5SDimitry Andric     mode |= S_IXGRP;
4290b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsWorldRead)
4300b57cec5SDimitry Andric     mode |= S_IROTH;
4310b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsWorldWrite)
4320b57cec5SDimitry Andric     mode |= S_IWOTH;
4330b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsWorldExecute)
4340b57cec5SDimitry Andric     mode |= S_IXOTH;
4350b57cec5SDimitry Andric   return mode;
4360b57cec5SDimitry Andric }
4370b57cec5SDimitry Andric 
Open(const FileSpec & file_spec,File::OpenOptions options,uint32_t permissions,bool should_close_fd)4389dba64beSDimitry Andric Expected<FileUP> FileSystem::Open(const FileSpec &file_spec,
4399dba64beSDimitry Andric                                   File::OpenOptions options,
4400b57cec5SDimitry Andric                                   uint32_t permissions, bool should_close_fd) {
4410b57cec5SDimitry Andric   const int open_flags = GetOpenFlags(options);
4420b57cec5SDimitry Andric   const mode_t open_mode =
4430b57cec5SDimitry Andric       (open_flags & O_CREAT) ? GetOpenMode(permissions) : 0;
4440b57cec5SDimitry Andric 
44581ad6265SDimitry Andric   auto path = file_spec.GetPath();
4460b57cec5SDimitry Andric 
4470b57cec5SDimitry Andric   int descriptor = llvm::sys::RetryAfterSignal(
44881ad6265SDimitry Andric       -1, OpenWithFS, *this, path.c_str(), open_flags, open_mode);
4490b57cec5SDimitry Andric 
4509dba64beSDimitry Andric   if (!File::DescriptorIsValid(descriptor))
4519dba64beSDimitry Andric     return llvm::errorCodeToError(
4529dba64beSDimitry Andric         std::error_code(errno, std::system_category()));
4539dba64beSDimitry Andric 
4549dba64beSDimitry Andric   auto file = std::unique_ptr<File>(
4559dba64beSDimitry Andric       new NativeFile(descriptor, options, should_close_fd));
4569dba64beSDimitry Andric   assert(file->IsValid());
4579dba64beSDimitry Andric   return std::move(file);
4580b57cec5SDimitry Andric }
4590b57cec5SDimitry Andric 
SetHomeDirectory(std::string home_directory)460e8d8bef9SDimitry Andric void FileSystem::SetHomeDirectory(std::string home_directory) {
461e8d8bef9SDimitry Andric   m_home_directory = std::move(home_directory);
462e8d8bef9SDimitry Andric }
4630eae32dcSDimitry Andric 
RemoveFile(const FileSpec & file_spec)4640eae32dcSDimitry Andric Status FileSystem::RemoveFile(const FileSpec &file_spec) {
4650eae32dcSDimitry Andric   return RemoveFile(file_spec.GetPath());
4660eae32dcSDimitry Andric }
4670eae32dcSDimitry Andric 
RemoveFile(const llvm::Twine & path)4680eae32dcSDimitry Andric Status FileSystem::RemoveFile(const llvm::Twine &path) {
4690eae32dcSDimitry Andric   return Status(llvm::sys::fs::remove(path));
4700eae32dcSDimitry Andric }
471