15ffd83dbSDimitry Andric //===-- FileSystem.cpp ----------------------------------------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric 9*0b57cec5SDimitry Andric #include "lldb/Host/FileSystem.h" 10*0b57cec5SDimitry Andric 1181ad6265SDimitry Andric #include "lldb/Utility/DataBufferLLVM.h" 12*0b57cec5SDimitry Andric #include "lldb/Utility/LLDBAssert.h" 13*0b57cec5SDimitry Andric #include "lldb/Utility/TildeExpressionResolver.h" 14*0b57cec5SDimitry Andric 15*0b57cec5SDimitry Andric #include "llvm/Support/Errc.h" 16*0b57cec5SDimitry Andric #include "llvm/Support/Errno.h" 17*0b57cec5SDimitry Andric #include "llvm/Support/Error.h" 18*0b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 19*0b57cec5SDimitry Andric #include "llvm/Support/Path.h" 20*0b57cec5SDimitry Andric #include "llvm/Support/Program.h" 21*0b57cec5SDimitry Andric #include "llvm/Support/Threading.h" 22*0b57cec5SDimitry Andric 23fe6060f1SDimitry Andric #include <cerrno> 24fe6060f1SDimitry Andric #include <climits> 25fe6060f1SDimitry Andric #include <cstdarg> 26fe6060f1SDimitry Andric #include <cstdio> 27*0b57cec5SDimitry Andric #include <fcntl.h> 28*0b57cec5SDimitry Andric 29*0b57cec5SDimitry Andric #ifdef _WIN32 30*0b57cec5SDimitry Andric #include "lldb/Host/windows/windows.h" 31*0b57cec5SDimitry Andric #else 32*0b57cec5SDimitry Andric #include <sys/ioctl.h> 33*0b57cec5SDimitry Andric #include <sys/stat.h> 34*0b57cec5SDimitry Andric #include <termios.h> 35*0b57cec5SDimitry Andric #include <unistd.h> 36*0b57cec5SDimitry Andric #endif 37*0b57cec5SDimitry Andric 38*0b57cec5SDimitry Andric #include <algorithm> 39*0b57cec5SDimitry Andric #include <fstream> 40bdd1243dSDimitry Andric #include <optional> 41*0b57cec5SDimitry Andric #include <vector> 42*0b57cec5SDimitry Andric 43*0b57cec5SDimitry Andric using namespace lldb; 44*0b57cec5SDimitry Andric using namespace lldb_private; 45*0b57cec5SDimitry Andric using namespace llvm; 46*0b57cec5SDimitry Andric 47*0b57cec5SDimitry Andric FileSystem &FileSystem::Instance() { return *InstanceImpl(); } 48*0b57cec5SDimitry Andric 49*0b57cec5SDimitry Andric void FileSystem::Initialize() { 50*0b57cec5SDimitry Andric lldbassert(!InstanceImpl() && "Already initialized."); 51*0b57cec5SDimitry Andric InstanceImpl().emplace(); 52*0b57cec5SDimitry Andric } 53*0b57cec5SDimitry Andric 54*0b57cec5SDimitry Andric void FileSystem::Initialize(IntrusiveRefCntPtr<vfs::FileSystem> fs) { 55*0b57cec5SDimitry Andric lldbassert(!InstanceImpl() && "Already initialized."); 56*0b57cec5SDimitry Andric InstanceImpl().emplace(fs); 57*0b57cec5SDimitry Andric } 58*0b57cec5SDimitry Andric 59*0b57cec5SDimitry Andric void FileSystem::Terminate() { 60*0b57cec5SDimitry Andric lldbassert(InstanceImpl() && "Already terminated."); 61*0b57cec5SDimitry Andric InstanceImpl().reset(); 62*0b57cec5SDimitry Andric } 63*0b57cec5SDimitry Andric 64bdd1243dSDimitry Andric std::optional<FileSystem> &FileSystem::InstanceImpl() { 65bdd1243dSDimitry Andric static std::optional<FileSystem> g_fs; 66*0b57cec5SDimitry Andric return g_fs; 67*0b57cec5SDimitry Andric } 68*0b57cec5SDimitry Andric 69*0b57cec5SDimitry Andric vfs::directory_iterator FileSystem::DirBegin(const FileSpec &file_spec, 70*0b57cec5SDimitry Andric std::error_code &ec) { 715ffd83dbSDimitry Andric if (!file_spec) { 725ffd83dbSDimitry Andric ec = std::error_code(static_cast<int>(errc::no_such_file_or_directory), 735ffd83dbSDimitry Andric std::system_category()); 745ffd83dbSDimitry Andric return {}; 755ffd83dbSDimitry Andric } 76*0b57cec5SDimitry Andric return DirBegin(file_spec.GetPath(), ec); 77*0b57cec5SDimitry Andric } 78*0b57cec5SDimitry Andric 79*0b57cec5SDimitry Andric vfs::directory_iterator FileSystem::DirBegin(const Twine &dir, 80*0b57cec5SDimitry Andric std::error_code &ec) { 81*0b57cec5SDimitry Andric return m_fs->dir_begin(dir, ec); 82*0b57cec5SDimitry Andric } 83*0b57cec5SDimitry Andric 84*0b57cec5SDimitry Andric llvm::ErrorOr<vfs::Status> 85*0b57cec5SDimitry Andric FileSystem::GetStatus(const FileSpec &file_spec) const { 865ffd83dbSDimitry Andric if (!file_spec) 875ffd83dbSDimitry Andric return std::error_code(static_cast<int>(errc::no_such_file_or_directory), 885ffd83dbSDimitry Andric std::system_category()); 89*0b57cec5SDimitry Andric return GetStatus(file_spec.GetPath()); 90*0b57cec5SDimitry Andric } 91*0b57cec5SDimitry Andric 92*0b57cec5SDimitry Andric llvm::ErrorOr<vfs::Status> FileSystem::GetStatus(const Twine &path) const { 93*0b57cec5SDimitry Andric return m_fs->status(path); 94*0b57cec5SDimitry Andric } 95*0b57cec5SDimitry Andric 96*0b57cec5SDimitry Andric sys::TimePoint<> 97*0b57cec5SDimitry Andric FileSystem::GetModificationTime(const FileSpec &file_spec) const { 985ffd83dbSDimitry Andric if (!file_spec) 995ffd83dbSDimitry Andric return sys::TimePoint<>(); 100*0b57cec5SDimitry Andric return GetModificationTime(file_spec.GetPath()); 101*0b57cec5SDimitry Andric } 102*0b57cec5SDimitry Andric 103*0b57cec5SDimitry Andric sys::TimePoint<> FileSystem::GetModificationTime(const Twine &path) const { 104*0b57cec5SDimitry Andric ErrorOr<vfs::Status> status = m_fs->status(path); 105*0b57cec5SDimitry Andric if (!status) 106*0b57cec5SDimitry Andric return sys::TimePoint<>(); 107*0b57cec5SDimitry Andric return status->getLastModificationTime(); 108*0b57cec5SDimitry Andric } 109*0b57cec5SDimitry Andric 110*0b57cec5SDimitry Andric uint64_t FileSystem::GetByteSize(const FileSpec &file_spec) const { 1115ffd83dbSDimitry Andric if (!file_spec) 1125ffd83dbSDimitry Andric return 0; 113*0b57cec5SDimitry Andric return GetByteSize(file_spec.GetPath()); 114*0b57cec5SDimitry Andric } 115*0b57cec5SDimitry Andric 116*0b57cec5SDimitry Andric uint64_t FileSystem::GetByteSize(const Twine &path) const { 117*0b57cec5SDimitry Andric ErrorOr<vfs::Status> status = m_fs->status(path); 118*0b57cec5SDimitry Andric if (!status) 119*0b57cec5SDimitry Andric return 0; 120*0b57cec5SDimitry Andric return status->getSize(); 121*0b57cec5SDimitry Andric } 122*0b57cec5SDimitry Andric 123*0b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const FileSpec &file_spec) const { 124*0b57cec5SDimitry Andric return GetPermissions(file_spec.GetPath()); 125*0b57cec5SDimitry Andric } 126*0b57cec5SDimitry Andric 127*0b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const FileSpec &file_spec, 128*0b57cec5SDimitry Andric std::error_code &ec) const { 1295ffd83dbSDimitry Andric if (!file_spec) 1305ffd83dbSDimitry Andric return sys::fs::perms::perms_not_known; 131*0b57cec5SDimitry Andric return GetPermissions(file_spec.GetPath(), ec); 132*0b57cec5SDimitry Andric } 133*0b57cec5SDimitry Andric 134*0b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const Twine &path) const { 135*0b57cec5SDimitry Andric std::error_code ec; 136*0b57cec5SDimitry Andric return GetPermissions(path, ec); 137*0b57cec5SDimitry Andric } 138*0b57cec5SDimitry Andric 139*0b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const Twine &path, 140*0b57cec5SDimitry Andric std::error_code &ec) const { 141*0b57cec5SDimitry Andric ErrorOr<vfs::Status> status = m_fs->status(path); 142*0b57cec5SDimitry Andric if (!status) { 143*0b57cec5SDimitry Andric ec = status.getError(); 144*0b57cec5SDimitry Andric return sys::fs::perms::perms_not_known; 145*0b57cec5SDimitry Andric } 146*0b57cec5SDimitry Andric return status->getPermissions(); 147*0b57cec5SDimitry Andric } 148*0b57cec5SDimitry Andric 149*0b57cec5SDimitry Andric bool FileSystem::Exists(const Twine &path) const { return m_fs->exists(path); } 150*0b57cec5SDimitry Andric 151*0b57cec5SDimitry Andric bool FileSystem::Exists(const FileSpec &file_spec) const { 1525ffd83dbSDimitry Andric return file_spec && Exists(file_spec.GetPath()); 153*0b57cec5SDimitry Andric } 154*0b57cec5SDimitry Andric 155*0b57cec5SDimitry Andric bool FileSystem::Readable(const Twine &path) const { 156*0b57cec5SDimitry Andric return GetPermissions(path) & sys::fs::perms::all_read; 157*0b57cec5SDimitry Andric } 158*0b57cec5SDimitry Andric 159*0b57cec5SDimitry Andric bool FileSystem::Readable(const FileSpec &file_spec) const { 1605ffd83dbSDimitry Andric return file_spec && Readable(file_spec.GetPath()); 161*0b57cec5SDimitry Andric } 162*0b57cec5SDimitry Andric 163*0b57cec5SDimitry Andric bool FileSystem::IsDirectory(const Twine &path) const { 164*0b57cec5SDimitry Andric ErrorOr<vfs::Status> status = m_fs->status(path); 165*0b57cec5SDimitry Andric if (!status) 166*0b57cec5SDimitry Andric return false; 167*0b57cec5SDimitry Andric return status->isDirectory(); 168*0b57cec5SDimitry Andric } 169*0b57cec5SDimitry Andric 170*0b57cec5SDimitry Andric bool FileSystem::IsDirectory(const FileSpec &file_spec) const { 1715ffd83dbSDimitry Andric return file_spec && IsDirectory(file_spec.GetPath()); 172*0b57cec5SDimitry Andric } 173*0b57cec5SDimitry Andric 174*0b57cec5SDimitry Andric bool FileSystem::IsLocal(const Twine &path) const { 175*0b57cec5SDimitry Andric bool b = false; 176*0b57cec5SDimitry Andric m_fs->isLocal(path, b); 177*0b57cec5SDimitry Andric return b; 178*0b57cec5SDimitry Andric } 179*0b57cec5SDimitry Andric 180*0b57cec5SDimitry Andric bool FileSystem::IsLocal(const FileSpec &file_spec) const { 1815ffd83dbSDimitry Andric return file_spec && IsLocal(file_spec.GetPath()); 182*0b57cec5SDimitry Andric } 183*0b57cec5SDimitry Andric 184*0b57cec5SDimitry Andric void FileSystem::EnumerateDirectory(Twine path, bool find_directories, 185*0b57cec5SDimitry Andric bool find_files, bool find_other, 186*0b57cec5SDimitry Andric EnumerateDirectoryCallbackType callback, 187*0b57cec5SDimitry Andric void *callback_baton) { 188*0b57cec5SDimitry Andric std::error_code EC; 189*0b57cec5SDimitry Andric vfs::recursive_directory_iterator Iter(*m_fs, path, EC); 190*0b57cec5SDimitry Andric vfs::recursive_directory_iterator End; 191*0b57cec5SDimitry Andric for (; Iter != End && !EC; Iter.increment(EC)) { 192*0b57cec5SDimitry Andric const auto &Item = *Iter; 193*0b57cec5SDimitry Andric ErrorOr<vfs::Status> Status = m_fs->status(Item.path()); 194*0b57cec5SDimitry Andric if (!Status) 195*0b57cec5SDimitry Andric break; 196*0b57cec5SDimitry Andric if (!find_files && Status->isRegularFile()) 197*0b57cec5SDimitry Andric continue; 198*0b57cec5SDimitry Andric if (!find_directories && Status->isDirectory()) 199*0b57cec5SDimitry Andric continue; 200*0b57cec5SDimitry Andric if (!find_other && Status->isOther()) 201*0b57cec5SDimitry Andric continue; 202*0b57cec5SDimitry Andric 203*0b57cec5SDimitry Andric auto Result = callback(callback_baton, Status->getType(), Item.path()); 204*0b57cec5SDimitry Andric if (Result == eEnumerateDirectoryResultQuit) 205*0b57cec5SDimitry Andric return; 206*0b57cec5SDimitry Andric if (Result == eEnumerateDirectoryResultNext) { 207*0b57cec5SDimitry Andric // Default behavior is to recurse. Opt out if the callback doesn't want 208*0b57cec5SDimitry Andric // this behavior. 209*0b57cec5SDimitry Andric Iter.no_push(); 210*0b57cec5SDimitry Andric } 211*0b57cec5SDimitry Andric } 212*0b57cec5SDimitry Andric } 213*0b57cec5SDimitry Andric 214*0b57cec5SDimitry Andric std::error_code FileSystem::MakeAbsolute(SmallVectorImpl<char> &path) const { 215*0b57cec5SDimitry Andric return m_fs->makeAbsolute(path); 216*0b57cec5SDimitry Andric } 217*0b57cec5SDimitry Andric 218*0b57cec5SDimitry Andric std::error_code FileSystem::MakeAbsolute(FileSpec &file_spec) const { 219*0b57cec5SDimitry Andric SmallString<128> path; 220*0b57cec5SDimitry Andric file_spec.GetPath(path, false); 221*0b57cec5SDimitry Andric 222*0b57cec5SDimitry Andric auto EC = MakeAbsolute(path); 223*0b57cec5SDimitry Andric if (EC) 224*0b57cec5SDimitry Andric return EC; 225*0b57cec5SDimitry Andric 226*0b57cec5SDimitry Andric FileSpec new_file_spec(path, file_spec.GetPathStyle()); 227*0b57cec5SDimitry Andric file_spec = new_file_spec; 228*0b57cec5SDimitry Andric return {}; 229*0b57cec5SDimitry Andric } 230*0b57cec5SDimitry Andric 231*0b57cec5SDimitry Andric std::error_code FileSystem::GetRealPath(const Twine &path, 232*0b57cec5SDimitry Andric SmallVectorImpl<char> &output) const { 233*0b57cec5SDimitry Andric return m_fs->getRealPath(path, output); 234*0b57cec5SDimitry Andric } 235*0b57cec5SDimitry Andric 236*0b57cec5SDimitry Andric void FileSystem::Resolve(SmallVectorImpl<char> &path) { 237*0b57cec5SDimitry Andric if (path.empty()) 238*0b57cec5SDimitry Andric return; 239*0b57cec5SDimitry Andric 240*0b57cec5SDimitry Andric // Resolve tilde in path. 241*0b57cec5SDimitry Andric SmallString<128> resolved(path.begin(), path.end()); 242*0b57cec5SDimitry Andric StandardTildeExpressionResolver Resolver; 243*0b57cec5SDimitry Andric Resolver.ResolveFullPath(llvm::StringRef(path.begin(), path.size()), 244*0b57cec5SDimitry Andric resolved); 245*0b57cec5SDimitry Andric 246*0b57cec5SDimitry Andric // Try making the path absolute if it exists. 247*0b57cec5SDimitry Andric SmallString<128> absolute(resolved.begin(), resolved.end()); 248*0b57cec5SDimitry Andric MakeAbsolute(absolute); 249*0b57cec5SDimitry Andric 250*0b57cec5SDimitry Andric path.clear(); 251*0b57cec5SDimitry Andric if (Exists(absolute)) { 252*0b57cec5SDimitry Andric path.append(absolute.begin(), absolute.end()); 253*0b57cec5SDimitry Andric } else { 254*0b57cec5SDimitry Andric path.append(resolved.begin(), resolved.end()); 255*0b57cec5SDimitry Andric } 256*0b57cec5SDimitry Andric } 257*0b57cec5SDimitry Andric 258*0b57cec5SDimitry Andric void FileSystem::Resolve(FileSpec &file_spec) { 2595ffd83dbSDimitry Andric if (!file_spec) 2605ffd83dbSDimitry Andric return; 2615ffd83dbSDimitry Andric 262*0b57cec5SDimitry Andric // Extract path from the FileSpec. 263*0b57cec5SDimitry Andric SmallString<128> path; 264*0b57cec5SDimitry Andric file_spec.GetPath(path); 265*0b57cec5SDimitry Andric 266*0b57cec5SDimitry Andric // Resolve the path. 267*0b57cec5SDimitry Andric Resolve(path); 268*0b57cec5SDimitry Andric 269*0b57cec5SDimitry Andric // Update the FileSpec with the resolved path. 270*0b57cec5SDimitry Andric if (file_spec.GetFilename().IsEmpty()) 271bdd1243dSDimitry Andric file_spec.SetDirectory(path); 272*0b57cec5SDimitry Andric else 273*0b57cec5SDimitry Andric file_spec.SetPath(path); 274*0b57cec5SDimitry Andric file_spec.SetIsResolved(true); 275*0b57cec5SDimitry Andric } 276*0b57cec5SDimitry Andric 27781ad6265SDimitry Andric template <typename T> 27881ad6265SDimitry Andric static std::unique_ptr<T> GetMemoryBuffer(const llvm::Twine &path, 27981ad6265SDimitry Andric uint64_t size, uint64_t offset, 28081ad6265SDimitry Andric bool is_volatile) { 28181ad6265SDimitry Andric std::unique_ptr<T> buffer; 282*0b57cec5SDimitry Andric if (size == 0) { 28381ad6265SDimitry Andric auto buffer_or_error = T::getFile(path, is_volatile); 284*0b57cec5SDimitry Andric if (!buffer_or_error) 285*0b57cec5SDimitry Andric return nullptr; 286*0b57cec5SDimitry Andric buffer = std::move(*buffer_or_error); 287*0b57cec5SDimitry Andric } else { 28881ad6265SDimitry Andric auto buffer_or_error = T::getFileSlice(path, size, offset, is_volatile); 289*0b57cec5SDimitry Andric if (!buffer_or_error) 290*0b57cec5SDimitry Andric return nullptr; 291*0b57cec5SDimitry Andric buffer = std::move(*buffer_or_error); 292*0b57cec5SDimitry Andric } 29381ad6265SDimitry Andric return buffer; 29481ad6265SDimitry Andric } 29581ad6265SDimitry Andric 29681ad6265SDimitry Andric std::shared_ptr<WritableDataBuffer> 29781ad6265SDimitry Andric FileSystem::CreateWritableDataBuffer(const llvm::Twine &path, uint64_t size, 29881ad6265SDimitry Andric uint64_t offset) { 29981ad6265SDimitry Andric const bool is_volatile = !IsLocal(path); 30081ad6265SDimitry Andric auto buffer = GetMemoryBuffer<llvm::WritableMemoryBuffer>(path, size, offset, 30181ad6265SDimitry Andric is_volatile); 30281ad6265SDimitry Andric if (!buffer) 30381ad6265SDimitry Andric return {}; 30481ad6265SDimitry Andric return std::shared_ptr<WritableDataBufferLLVM>( 30581ad6265SDimitry Andric new WritableDataBufferLLVM(std::move(buffer))); 30681ad6265SDimitry Andric } 30781ad6265SDimitry Andric 30881ad6265SDimitry Andric std::shared_ptr<DataBuffer> 30981ad6265SDimitry Andric FileSystem::CreateDataBuffer(const llvm::Twine &path, uint64_t size, 31081ad6265SDimitry Andric uint64_t offset) { 31181ad6265SDimitry Andric const bool is_volatile = !IsLocal(path); 31281ad6265SDimitry Andric auto buffer = 31381ad6265SDimitry Andric GetMemoryBuffer<llvm::MemoryBuffer>(path, size, offset, is_volatile); 31481ad6265SDimitry Andric if (!buffer) 31581ad6265SDimitry Andric return {}; 316*0b57cec5SDimitry Andric return std::shared_ptr<DataBufferLLVM>(new DataBufferLLVM(std::move(buffer))); 317*0b57cec5SDimitry Andric } 318*0b57cec5SDimitry Andric 31981ad6265SDimitry Andric std::shared_ptr<WritableDataBuffer> 32081ad6265SDimitry Andric FileSystem::CreateWritableDataBuffer(const FileSpec &file_spec, uint64_t size, 32181ad6265SDimitry Andric uint64_t offset) { 32281ad6265SDimitry Andric return CreateWritableDataBuffer(file_spec.GetPath(), size, offset); 32381ad6265SDimitry Andric } 32481ad6265SDimitry Andric 32581ad6265SDimitry Andric std::shared_ptr<DataBuffer> 326*0b57cec5SDimitry Andric FileSystem::CreateDataBuffer(const FileSpec &file_spec, uint64_t size, 327*0b57cec5SDimitry Andric uint64_t offset) { 328*0b57cec5SDimitry Andric return CreateDataBuffer(file_spec.GetPath(), size, offset); 329*0b57cec5SDimitry Andric } 330*0b57cec5SDimitry Andric 331*0b57cec5SDimitry Andric bool FileSystem::ResolveExecutableLocation(FileSpec &file_spec) { 332*0b57cec5SDimitry Andric // If the directory is set there's nothing to do. 333*0b57cec5SDimitry Andric ConstString directory = file_spec.GetDirectory(); 334*0b57cec5SDimitry Andric if (directory) 335*0b57cec5SDimitry Andric return false; 336*0b57cec5SDimitry Andric 337*0b57cec5SDimitry Andric // We cannot look for a file if there's no file name. 338*0b57cec5SDimitry Andric ConstString filename = file_spec.GetFilename(); 339*0b57cec5SDimitry Andric if (!filename) 340*0b57cec5SDimitry Andric return false; 341*0b57cec5SDimitry Andric 342*0b57cec5SDimitry Andric // Search for the file on the host. 343*0b57cec5SDimitry Andric const std::string filename_str(filename.GetCString()); 344*0b57cec5SDimitry Andric llvm::ErrorOr<std::string> error_or_path = 345*0b57cec5SDimitry Andric llvm::sys::findProgramByName(filename_str); 346*0b57cec5SDimitry Andric if (!error_or_path) 347*0b57cec5SDimitry Andric return false; 348*0b57cec5SDimitry Andric 349*0b57cec5SDimitry Andric // findProgramByName returns "." if it can't find the file. 350*0b57cec5SDimitry Andric llvm::StringRef path = *error_or_path; 351*0b57cec5SDimitry Andric llvm::StringRef parent = llvm::sys::path::parent_path(path); 352*0b57cec5SDimitry Andric if (parent.empty() || parent == ".") 353*0b57cec5SDimitry Andric return false; 354*0b57cec5SDimitry Andric 355*0b57cec5SDimitry Andric // Make sure that the result exists. 356*0b57cec5SDimitry Andric FileSpec result(*error_or_path); 357*0b57cec5SDimitry Andric if (!Exists(result)) 358*0b57cec5SDimitry Andric return false; 359*0b57cec5SDimitry Andric 360*0b57cec5SDimitry Andric file_spec = result; 361*0b57cec5SDimitry Andric return true; 362*0b57cec5SDimitry Andric } 363*0b57cec5SDimitry Andric 364e8d8bef9SDimitry Andric bool FileSystem::GetHomeDirectory(SmallVectorImpl<char> &path) const { 365e8d8bef9SDimitry Andric if (!m_home_directory.empty()) { 366e8d8bef9SDimitry Andric path.assign(m_home_directory.begin(), m_home_directory.end()); 367e8d8bef9SDimitry Andric return true; 368e8d8bef9SDimitry Andric } 369e8d8bef9SDimitry Andric return llvm::sys::path::home_directory(path); 370e8d8bef9SDimitry Andric } 371e8d8bef9SDimitry Andric 372e8d8bef9SDimitry Andric bool FileSystem::GetHomeDirectory(FileSpec &file_spec) const { 373e8d8bef9SDimitry Andric SmallString<128> home_dir; 374e8d8bef9SDimitry Andric if (!GetHomeDirectory(home_dir)) 375e8d8bef9SDimitry Andric return false; 376e8d8bef9SDimitry Andric file_spec.SetPath(home_dir); 377e8d8bef9SDimitry Andric return true; 378e8d8bef9SDimitry Andric } 379e8d8bef9SDimitry Andric 380*0b57cec5SDimitry Andric static int OpenWithFS(const FileSystem &fs, const char *path, int flags, 381*0b57cec5SDimitry Andric int mode) { 382*0b57cec5SDimitry Andric return const_cast<FileSystem &>(fs).Open(path, flags, mode); 383*0b57cec5SDimitry Andric } 384*0b57cec5SDimitry Andric 385349cc55cSDimitry Andric static int GetOpenFlags(File::OpenOptions options) { 386*0b57cec5SDimitry Andric int open_flags = 0; 387349cc55cSDimitry Andric File::OpenOptions rw = 388349cc55cSDimitry Andric options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly | 389349cc55cSDimitry Andric File::eOpenOptionReadWrite); 390349cc55cSDimitry Andric if (rw == File::eOpenOptionWriteOnly || rw == File::eOpenOptionReadWrite) { 391349cc55cSDimitry Andric if (rw == File::eOpenOptionReadWrite) 392*0b57cec5SDimitry Andric open_flags |= O_RDWR; 393*0b57cec5SDimitry Andric else 394*0b57cec5SDimitry Andric open_flags |= O_WRONLY; 395*0b57cec5SDimitry Andric 396*0b57cec5SDimitry Andric if (options & File::eOpenOptionAppend) 397*0b57cec5SDimitry Andric open_flags |= O_APPEND; 398*0b57cec5SDimitry Andric 399*0b57cec5SDimitry Andric if (options & File::eOpenOptionTruncate) 400*0b57cec5SDimitry Andric open_flags |= O_TRUNC; 401*0b57cec5SDimitry Andric 402*0b57cec5SDimitry Andric if (options & File::eOpenOptionCanCreate) 403*0b57cec5SDimitry Andric open_flags |= O_CREAT; 404*0b57cec5SDimitry Andric 405*0b57cec5SDimitry Andric if (options & File::eOpenOptionCanCreateNewOnly) 406*0b57cec5SDimitry Andric open_flags |= O_CREAT | O_EXCL; 407349cc55cSDimitry Andric } else if (rw == File::eOpenOptionReadOnly) { 408*0b57cec5SDimitry Andric open_flags |= O_RDONLY; 409*0b57cec5SDimitry Andric 410*0b57cec5SDimitry Andric #ifndef _WIN32 411*0b57cec5SDimitry Andric if (options & File::eOpenOptionDontFollowSymlinks) 412*0b57cec5SDimitry Andric open_flags |= O_NOFOLLOW; 413*0b57cec5SDimitry Andric #endif 414*0b57cec5SDimitry Andric } 415*0b57cec5SDimitry Andric 416*0b57cec5SDimitry Andric #ifndef _WIN32 417*0b57cec5SDimitry Andric if (options & File::eOpenOptionNonBlocking) 418*0b57cec5SDimitry Andric open_flags |= O_NONBLOCK; 419*0b57cec5SDimitry Andric if (options & File::eOpenOptionCloseOnExec) 420*0b57cec5SDimitry Andric open_flags |= O_CLOEXEC; 421*0b57cec5SDimitry Andric #else 422*0b57cec5SDimitry Andric open_flags |= O_BINARY; 423*0b57cec5SDimitry Andric #endif 424*0b57cec5SDimitry Andric 425*0b57cec5SDimitry Andric return open_flags; 426*0b57cec5SDimitry Andric } 427*0b57cec5SDimitry Andric 428*0b57cec5SDimitry Andric static mode_t GetOpenMode(uint32_t permissions) { 429*0b57cec5SDimitry Andric mode_t mode = 0; 430*0b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsUserRead) 431*0b57cec5SDimitry Andric mode |= S_IRUSR; 432*0b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsUserWrite) 433*0b57cec5SDimitry Andric mode |= S_IWUSR; 434*0b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsUserExecute) 435*0b57cec5SDimitry Andric mode |= S_IXUSR; 436*0b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsGroupRead) 437*0b57cec5SDimitry Andric mode |= S_IRGRP; 438*0b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsGroupWrite) 439*0b57cec5SDimitry Andric mode |= S_IWGRP; 440*0b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsGroupExecute) 441*0b57cec5SDimitry Andric mode |= S_IXGRP; 442*0b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsWorldRead) 443*0b57cec5SDimitry Andric mode |= S_IROTH; 444*0b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsWorldWrite) 445*0b57cec5SDimitry Andric mode |= S_IWOTH; 446*0b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsWorldExecute) 447*0b57cec5SDimitry Andric mode |= S_IXOTH; 448*0b57cec5SDimitry Andric return mode; 449*0b57cec5SDimitry Andric } 450*0b57cec5SDimitry Andric 4519dba64beSDimitry Andric Expected<FileUP> FileSystem::Open(const FileSpec &file_spec, 4529dba64beSDimitry Andric File::OpenOptions options, 453*0b57cec5SDimitry Andric uint32_t permissions, bool should_close_fd) { 454*0b57cec5SDimitry Andric const int open_flags = GetOpenFlags(options); 455*0b57cec5SDimitry Andric const mode_t open_mode = 456*0b57cec5SDimitry Andric (open_flags & O_CREAT) ? GetOpenMode(permissions) : 0; 457*0b57cec5SDimitry Andric 45881ad6265SDimitry Andric auto path = file_spec.GetPath(); 459*0b57cec5SDimitry Andric 460*0b57cec5SDimitry Andric int descriptor = llvm::sys::RetryAfterSignal( 46181ad6265SDimitry Andric -1, OpenWithFS, *this, path.c_str(), open_flags, open_mode); 462*0b57cec5SDimitry Andric 4639dba64beSDimitry Andric if (!File::DescriptorIsValid(descriptor)) 4649dba64beSDimitry Andric return llvm::errorCodeToError( 4659dba64beSDimitry Andric std::error_code(errno, std::system_category())); 4669dba64beSDimitry Andric 4679dba64beSDimitry Andric auto file = std::unique_ptr<File>( 4689dba64beSDimitry Andric new NativeFile(descriptor, options, should_close_fd)); 4699dba64beSDimitry Andric assert(file->IsValid()); 4709dba64beSDimitry Andric return std::move(file); 471*0b57cec5SDimitry Andric } 472*0b57cec5SDimitry Andric 473e8d8bef9SDimitry Andric void FileSystem::SetHomeDirectory(std::string home_directory) { 474e8d8bef9SDimitry Andric m_home_directory = std::move(home_directory); 475e8d8bef9SDimitry Andric } 4760eae32dcSDimitry Andric 4770eae32dcSDimitry Andric Status FileSystem::RemoveFile(const FileSpec &file_spec) { 4780eae32dcSDimitry Andric return RemoveFile(file_spec.GetPath()); 4790eae32dcSDimitry Andric } 4800eae32dcSDimitry Andric 4810eae32dcSDimitry Andric Status FileSystem::RemoveFile(const llvm::Twine &path) { 4820eae32dcSDimitry Andric return Status(llvm::sys::fs::remove(path)); 4830eae32dcSDimitry Andric } 484