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 11*0b57cec5SDimitry Andric #include "lldb/Utility/LLDBAssert.h" 12*0b57cec5SDimitry Andric #include "lldb/Utility/TildeExpressionResolver.h" 13*0b57cec5SDimitry Andric 14*0b57cec5SDimitry Andric #include "llvm/Support/Errc.h" 15*0b57cec5SDimitry Andric #include "llvm/Support/Errno.h" 16*0b57cec5SDimitry Andric #include "llvm/Support/Error.h" 17*0b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 18*0b57cec5SDimitry Andric #include "llvm/Support/Path.h" 19*0b57cec5SDimitry Andric #include "llvm/Support/Program.h" 20*0b57cec5SDimitry Andric #include "llvm/Support/Threading.h" 21*0b57cec5SDimitry Andric 22*0b57cec5SDimitry Andric #include <errno.h> 23*0b57cec5SDimitry Andric #include <fcntl.h> 24*0b57cec5SDimitry Andric #include <limits.h> 25*0b57cec5SDimitry Andric #include <stdarg.h> 26*0b57cec5SDimitry Andric #include <stdio.h> 27*0b57cec5SDimitry Andric 28*0b57cec5SDimitry Andric #ifdef _WIN32 29*0b57cec5SDimitry Andric #include "lldb/Host/windows/windows.h" 30*0b57cec5SDimitry Andric #else 31*0b57cec5SDimitry Andric #include <sys/ioctl.h> 32*0b57cec5SDimitry Andric #include <sys/stat.h> 33*0b57cec5SDimitry Andric #include <termios.h> 34*0b57cec5SDimitry Andric #include <unistd.h> 35*0b57cec5SDimitry Andric #endif 36*0b57cec5SDimitry Andric 37*0b57cec5SDimitry Andric #include <algorithm> 38*0b57cec5SDimitry Andric #include <fstream> 39*0b57cec5SDimitry Andric #include <vector> 40*0b57cec5SDimitry Andric 41*0b57cec5SDimitry Andric using namespace lldb; 42*0b57cec5SDimitry Andric using namespace lldb_private; 43*0b57cec5SDimitry Andric using namespace llvm; 44*0b57cec5SDimitry Andric 45*0b57cec5SDimitry Andric FileSystem &FileSystem::Instance() { return *InstanceImpl(); } 46*0b57cec5SDimitry Andric 47*0b57cec5SDimitry Andric void FileSystem::Initialize() { 48*0b57cec5SDimitry Andric lldbassert(!InstanceImpl() && "Already initialized."); 49*0b57cec5SDimitry Andric InstanceImpl().emplace(); 50*0b57cec5SDimitry Andric } 51*0b57cec5SDimitry Andric 529dba64beSDimitry Andric void FileSystem::Initialize(std::shared_ptr<FileCollector> collector) { 53*0b57cec5SDimitry Andric lldbassert(!InstanceImpl() && "Already initialized."); 54*0b57cec5SDimitry Andric InstanceImpl().emplace(collector); 55*0b57cec5SDimitry Andric } 56*0b57cec5SDimitry Andric 57*0b57cec5SDimitry Andric llvm::Error FileSystem::Initialize(const FileSpec &mapping) { 58*0b57cec5SDimitry Andric lldbassert(!InstanceImpl() && "Already initialized."); 59*0b57cec5SDimitry Andric 60*0b57cec5SDimitry Andric llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer = 61*0b57cec5SDimitry Andric llvm::vfs::getRealFileSystem()->getBufferForFile(mapping.GetPath()); 62*0b57cec5SDimitry Andric 63*0b57cec5SDimitry Andric if (!buffer) 64*0b57cec5SDimitry Andric return llvm::errorCodeToError(buffer.getError()); 65*0b57cec5SDimitry Andric 66*0b57cec5SDimitry Andric InstanceImpl().emplace(llvm::vfs::getVFSFromYAML(std::move(buffer.get()), 67*0b57cec5SDimitry Andric nullptr, mapping.GetPath()), 68*0b57cec5SDimitry Andric true); 69*0b57cec5SDimitry Andric 70*0b57cec5SDimitry Andric return llvm::Error::success(); 71*0b57cec5SDimitry Andric } 72*0b57cec5SDimitry Andric 73*0b57cec5SDimitry Andric void FileSystem::Initialize(IntrusiveRefCntPtr<vfs::FileSystem> fs) { 74*0b57cec5SDimitry Andric lldbassert(!InstanceImpl() && "Already initialized."); 75*0b57cec5SDimitry Andric InstanceImpl().emplace(fs); 76*0b57cec5SDimitry Andric } 77*0b57cec5SDimitry Andric 78*0b57cec5SDimitry Andric void FileSystem::Terminate() { 79*0b57cec5SDimitry Andric lldbassert(InstanceImpl() && "Already terminated."); 80*0b57cec5SDimitry Andric InstanceImpl().reset(); 81*0b57cec5SDimitry Andric } 82*0b57cec5SDimitry Andric 83*0b57cec5SDimitry Andric Optional<FileSystem> &FileSystem::InstanceImpl() { 84*0b57cec5SDimitry Andric static Optional<FileSystem> g_fs; 85*0b57cec5SDimitry Andric return g_fs; 86*0b57cec5SDimitry Andric } 87*0b57cec5SDimitry Andric 88*0b57cec5SDimitry Andric vfs::directory_iterator FileSystem::DirBegin(const FileSpec &file_spec, 89*0b57cec5SDimitry Andric std::error_code &ec) { 905ffd83dbSDimitry Andric if (!file_spec) { 915ffd83dbSDimitry Andric ec = std::error_code(static_cast<int>(errc::no_such_file_or_directory), 925ffd83dbSDimitry Andric std::system_category()); 935ffd83dbSDimitry Andric return {}; 945ffd83dbSDimitry Andric } 95*0b57cec5SDimitry Andric return DirBegin(file_spec.GetPath(), ec); 96*0b57cec5SDimitry Andric } 97*0b57cec5SDimitry Andric 98*0b57cec5SDimitry Andric vfs::directory_iterator FileSystem::DirBegin(const Twine &dir, 99*0b57cec5SDimitry Andric std::error_code &ec) { 100*0b57cec5SDimitry Andric return m_fs->dir_begin(dir, ec); 101*0b57cec5SDimitry Andric } 102*0b57cec5SDimitry Andric 103*0b57cec5SDimitry Andric llvm::ErrorOr<vfs::Status> 104*0b57cec5SDimitry Andric FileSystem::GetStatus(const FileSpec &file_spec) const { 1055ffd83dbSDimitry Andric if (!file_spec) 1065ffd83dbSDimitry Andric return std::error_code(static_cast<int>(errc::no_such_file_or_directory), 1075ffd83dbSDimitry Andric std::system_category()); 108*0b57cec5SDimitry Andric return GetStatus(file_spec.GetPath()); 109*0b57cec5SDimitry Andric } 110*0b57cec5SDimitry Andric 111*0b57cec5SDimitry Andric llvm::ErrorOr<vfs::Status> FileSystem::GetStatus(const Twine &path) const { 112*0b57cec5SDimitry Andric return m_fs->status(path); 113*0b57cec5SDimitry Andric } 114*0b57cec5SDimitry Andric 115*0b57cec5SDimitry Andric sys::TimePoint<> 116*0b57cec5SDimitry Andric FileSystem::GetModificationTime(const FileSpec &file_spec) const { 1175ffd83dbSDimitry Andric if (!file_spec) 1185ffd83dbSDimitry Andric return sys::TimePoint<>(); 119*0b57cec5SDimitry Andric return GetModificationTime(file_spec.GetPath()); 120*0b57cec5SDimitry Andric } 121*0b57cec5SDimitry Andric 122*0b57cec5SDimitry Andric sys::TimePoint<> FileSystem::GetModificationTime(const Twine &path) const { 123*0b57cec5SDimitry Andric ErrorOr<vfs::Status> status = m_fs->status(path); 124*0b57cec5SDimitry Andric if (!status) 125*0b57cec5SDimitry Andric return sys::TimePoint<>(); 126*0b57cec5SDimitry Andric return status->getLastModificationTime(); 127*0b57cec5SDimitry Andric } 128*0b57cec5SDimitry Andric 129*0b57cec5SDimitry Andric uint64_t FileSystem::GetByteSize(const FileSpec &file_spec) const { 1305ffd83dbSDimitry Andric if (!file_spec) 1315ffd83dbSDimitry Andric return 0; 132*0b57cec5SDimitry Andric return GetByteSize(file_spec.GetPath()); 133*0b57cec5SDimitry Andric } 134*0b57cec5SDimitry Andric 135*0b57cec5SDimitry Andric uint64_t FileSystem::GetByteSize(const Twine &path) const { 136*0b57cec5SDimitry Andric ErrorOr<vfs::Status> status = m_fs->status(path); 137*0b57cec5SDimitry Andric if (!status) 138*0b57cec5SDimitry Andric return 0; 139*0b57cec5SDimitry Andric return status->getSize(); 140*0b57cec5SDimitry Andric } 141*0b57cec5SDimitry Andric 142*0b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const FileSpec &file_spec) const { 143*0b57cec5SDimitry Andric return GetPermissions(file_spec.GetPath()); 144*0b57cec5SDimitry Andric } 145*0b57cec5SDimitry Andric 146*0b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const FileSpec &file_spec, 147*0b57cec5SDimitry Andric std::error_code &ec) const { 1485ffd83dbSDimitry Andric if (!file_spec) 1495ffd83dbSDimitry Andric return sys::fs::perms::perms_not_known; 150*0b57cec5SDimitry Andric return GetPermissions(file_spec.GetPath(), ec); 151*0b57cec5SDimitry Andric } 152*0b57cec5SDimitry Andric 153*0b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const Twine &path) const { 154*0b57cec5SDimitry Andric std::error_code ec; 155*0b57cec5SDimitry Andric return GetPermissions(path, ec); 156*0b57cec5SDimitry Andric } 157*0b57cec5SDimitry Andric 158*0b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const Twine &path, 159*0b57cec5SDimitry Andric std::error_code &ec) const { 160*0b57cec5SDimitry Andric ErrorOr<vfs::Status> status = m_fs->status(path); 161*0b57cec5SDimitry Andric if (!status) { 162*0b57cec5SDimitry Andric ec = status.getError(); 163*0b57cec5SDimitry Andric return sys::fs::perms::perms_not_known; 164*0b57cec5SDimitry Andric } 165*0b57cec5SDimitry Andric return status->getPermissions(); 166*0b57cec5SDimitry Andric } 167*0b57cec5SDimitry Andric 168*0b57cec5SDimitry Andric bool FileSystem::Exists(const Twine &path) const { return m_fs->exists(path); } 169*0b57cec5SDimitry Andric 170*0b57cec5SDimitry Andric bool FileSystem::Exists(const FileSpec &file_spec) const { 1715ffd83dbSDimitry Andric return file_spec && Exists(file_spec.GetPath()); 172*0b57cec5SDimitry Andric } 173*0b57cec5SDimitry Andric 174*0b57cec5SDimitry Andric bool FileSystem::Readable(const Twine &path) const { 175*0b57cec5SDimitry Andric return GetPermissions(path) & sys::fs::perms::all_read; 176*0b57cec5SDimitry Andric } 177*0b57cec5SDimitry Andric 178*0b57cec5SDimitry Andric bool FileSystem::Readable(const FileSpec &file_spec) const { 1795ffd83dbSDimitry Andric return file_spec && Readable(file_spec.GetPath()); 180*0b57cec5SDimitry Andric } 181*0b57cec5SDimitry Andric 182*0b57cec5SDimitry Andric bool FileSystem::IsDirectory(const Twine &path) const { 183*0b57cec5SDimitry Andric ErrorOr<vfs::Status> status = m_fs->status(path); 184*0b57cec5SDimitry Andric if (!status) 185*0b57cec5SDimitry Andric return false; 186*0b57cec5SDimitry Andric return status->isDirectory(); 187*0b57cec5SDimitry Andric } 188*0b57cec5SDimitry Andric 189*0b57cec5SDimitry Andric bool FileSystem::IsDirectory(const FileSpec &file_spec) const { 1905ffd83dbSDimitry Andric return file_spec && IsDirectory(file_spec.GetPath()); 191*0b57cec5SDimitry Andric } 192*0b57cec5SDimitry Andric 193*0b57cec5SDimitry Andric bool FileSystem::IsLocal(const Twine &path) const { 194*0b57cec5SDimitry Andric bool b = false; 195*0b57cec5SDimitry Andric m_fs->isLocal(path, b); 196*0b57cec5SDimitry Andric return b; 197*0b57cec5SDimitry Andric } 198*0b57cec5SDimitry Andric 199*0b57cec5SDimitry Andric bool FileSystem::IsLocal(const FileSpec &file_spec) const { 2005ffd83dbSDimitry Andric return file_spec && IsLocal(file_spec.GetPath()); 201*0b57cec5SDimitry Andric } 202*0b57cec5SDimitry Andric 203*0b57cec5SDimitry Andric void FileSystem::EnumerateDirectory(Twine path, bool find_directories, 204*0b57cec5SDimitry Andric bool find_files, bool find_other, 205*0b57cec5SDimitry Andric EnumerateDirectoryCallbackType callback, 206*0b57cec5SDimitry Andric void *callback_baton) { 207*0b57cec5SDimitry Andric std::error_code EC; 208*0b57cec5SDimitry Andric vfs::recursive_directory_iterator Iter(*m_fs, path, EC); 209*0b57cec5SDimitry Andric vfs::recursive_directory_iterator End; 210*0b57cec5SDimitry Andric for (; Iter != End && !EC; Iter.increment(EC)) { 211*0b57cec5SDimitry Andric const auto &Item = *Iter; 212*0b57cec5SDimitry Andric ErrorOr<vfs::Status> Status = m_fs->status(Item.path()); 213*0b57cec5SDimitry Andric if (!Status) 214*0b57cec5SDimitry Andric break; 215*0b57cec5SDimitry Andric if (!find_files && Status->isRegularFile()) 216*0b57cec5SDimitry Andric continue; 217*0b57cec5SDimitry Andric if (!find_directories && Status->isDirectory()) 218*0b57cec5SDimitry Andric continue; 219*0b57cec5SDimitry Andric if (!find_other && Status->isOther()) 220*0b57cec5SDimitry Andric continue; 221*0b57cec5SDimitry Andric 222*0b57cec5SDimitry Andric auto Result = callback(callback_baton, Status->getType(), Item.path()); 223*0b57cec5SDimitry Andric if (Result == eEnumerateDirectoryResultQuit) 224*0b57cec5SDimitry Andric return; 225*0b57cec5SDimitry Andric if (Result == eEnumerateDirectoryResultNext) { 226*0b57cec5SDimitry Andric // Default behavior is to recurse. Opt out if the callback doesn't want 227*0b57cec5SDimitry Andric // this behavior. 228*0b57cec5SDimitry Andric Iter.no_push(); 229*0b57cec5SDimitry Andric } 230*0b57cec5SDimitry Andric } 231*0b57cec5SDimitry Andric } 232*0b57cec5SDimitry Andric 233*0b57cec5SDimitry Andric std::error_code FileSystem::MakeAbsolute(SmallVectorImpl<char> &path) const { 234*0b57cec5SDimitry Andric return m_fs->makeAbsolute(path); 235*0b57cec5SDimitry Andric } 236*0b57cec5SDimitry Andric 237*0b57cec5SDimitry Andric std::error_code FileSystem::MakeAbsolute(FileSpec &file_spec) const { 238*0b57cec5SDimitry Andric SmallString<128> path; 239*0b57cec5SDimitry Andric file_spec.GetPath(path, false); 240*0b57cec5SDimitry Andric 241*0b57cec5SDimitry Andric auto EC = MakeAbsolute(path); 242*0b57cec5SDimitry Andric if (EC) 243*0b57cec5SDimitry Andric return EC; 244*0b57cec5SDimitry Andric 245*0b57cec5SDimitry Andric FileSpec new_file_spec(path, file_spec.GetPathStyle()); 246*0b57cec5SDimitry Andric file_spec = new_file_spec; 247*0b57cec5SDimitry Andric return {}; 248*0b57cec5SDimitry Andric } 249*0b57cec5SDimitry Andric 250*0b57cec5SDimitry Andric std::error_code FileSystem::GetRealPath(const Twine &path, 251*0b57cec5SDimitry Andric SmallVectorImpl<char> &output) const { 252*0b57cec5SDimitry Andric return m_fs->getRealPath(path, output); 253*0b57cec5SDimitry Andric } 254*0b57cec5SDimitry Andric 255*0b57cec5SDimitry Andric void FileSystem::Resolve(SmallVectorImpl<char> &path) { 256*0b57cec5SDimitry Andric if (path.empty()) 257*0b57cec5SDimitry Andric return; 258*0b57cec5SDimitry Andric 259*0b57cec5SDimitry Andric // Resolve tilde in path. 260*0b57cec5SDimitry Andric SmallString<128> resolved(path.begin(), path.end()); 261*0b57cec5SDimitry Andric StandardTildeExpressionResolver Resolver; 262*0b57cec5SDimitry Andric Resolver.ResolveFullPath(llvm::StringRef(path.begin(), path.size()), 263*0b57cec5SDimitry Andric resolved); 264*0b57cec5SDimitry Andric 265*0b57cec5SDimitry Andric // Try making the path absolute if it exists. 266*0b57cec5SDimitry Andric SmallString<128> absolute(resolved.begin(), resolved.end()); 267*0b57cec5SDimitry Andric MakeAbsolute(absolute); 268*0b57cec5SDimitry Andric 269*0b57cec5SDimitry Andric path.clear(); 270*0b57cec5SDimitry Andric if (Exists(absolute)) { 271*0b57cec5SDimitry Andric path.append(absolute.begin(), absolute.end()); 272*0b57cec5SDimitry Andric } else { 273*0b57cec5SDimitry Andric path.append(resolved.begin(), resolved.end()); 274*0b57cec5SDimitry Andric } 275*0b57cec5SDimitry Andric } 276*0b57cec5SDimitry Andric 277*0b57cec5SDimitry Andric void FileSystem::Resolve(FileSpec &file_spec) { 2785ffd83dbSDimitry Andric if (!file_spec) 2795ffd83dbSDimitry Andric return; 2805ffd83dbSDimitry Andric 281*0b57cec5SDimitry Andric // Extract path from the FileSpec. 282*0b57cec5SDimitry Andric SmallString<128> path; 283*0b57cec5SDimitry Andric file_spec.GetPath(path); 284*0b57cec5SDimitry Andric 285*0b57cec5SDimitry Andric // Resolve the path. 286*0b57cec5SDimitry Andric Resolve(path); 287*0b57cec5SDimitry Andric 288*0b57cec5SDimitry Andric // Update the FileSpec with the resolved path. 289*0b57cec5SDimitry Andric if (file_spec.GetFilename().IsEmpty()) 290*0b57cec5SDimitry Andric file_spec.GetDirectory().SetString(path); 291*0b57cec5SDimitry Andric else 292*0b57cec5SDimitry Andric file_spec.SetPath(path); 293*0b57cec5SDimitry Andric file_spec.SetIsResolved(true); 294*0b57cec5SDimitry Andric } 295*0b57cec5SDimitry Andric 296*0b57cec5SDimitry Andric std::shared_ptr<DataBufferLLVM> 297*0b57cec5SDimitry Andric FileSystem::CreateDataBuffer(const llvm::Twine &path, uint64_t size, 298*0b57cec5SDimitry Andric uint64_t offset) { 2995ffd83dbSDimitry Andric Collect(path); 300*0b57cec5SDimitry Andric 301*0b57cec5SDimitry Andric const bool is_volatile = !IsLocal(path); 302*0b57cec5SDimitry Andric const ErrorOr<std::string> external_path = GetExternalPath(path); 303*0b57cec5SDimitry Andric 304*0b57cec5SDimitry Andric if (!external_path) 305*0b57cec5SDimitry Andric return nullptr; 306*0b57cec5SDimitry Andric 307*0b57cec5SDimitry Andric std::unique_ptr<llvm::WritableMemoryBuffer> buffer; 308*0b57cec5SDimitry Andric if (size == 0) { 309*0b57cec5SDimitry Andric auto buffer_or_error = 310*0b57cec5SDimitry Andric llvm::WritableMemoryBuffer::getFile(*external_path, -1, is_volatile); 311*0b57cec5SDimitry Andric if (!buffer_or_error) 312*0b57cec5SDimitry Andric return nullptr; 313*0b57cec5SDimitry Andric buffer = std::move(*buffer_or_error); 314*0b57cec5SDimitry Andric } else { 315*0b57cec5SDimitry Andric auto buffer_or_error = llvm::WritableMemoryBuffer::getFileSlice( 316*0b57cec5SDimitry Andric *external_path, size, offset, is_volatile); 317*0b57cec5SDimitry Andric if (!buffer_or_error) 318*0b57cec5SDimitry Andric return nullptr; 319*0b57cec5SDimitry Andric buffer = std::move(*buffer_or_error); 320*0b57cec5SDimitry Andric } 321*0b57cec5SDimitry Andric return std::shared_ptr<DataBufferLLVM>(new DataBufferLLVM(std::move(buffer))); 322*0b57cec5SDimitry Andric } 323*0b57cec5SDimitry Andric 324*0b57cec5SDimitry Andric std::shared_ptr<DataBufferLLVM> 325*0b57cec5SDimitry Andric FileSystem::CreateDataBuffer(const FileSpec &file_spec, uint64_t size, 326*0b57cec5SDimitry Andric uint64_t offset) { 327*0b57cec5SDimitry Andric return CreateDataBuffer(file_spec.GetPath(), size, offset); 328*0b57cec5SDimitry Andric } 329*0b57cec5SDimitry Andric 330*0b57cec5SDimitry Andric bool FileSystem::ResolveExecutableLocation(FileSpec &file_spec) { 331*0b57cec5SDimitry Andric // If the directory is set there's nothing to do. 332*0b57cec5SDimitry Andric ConstString directory = file_spec.GetDirectory(); 333*0b57cec5SDimitry Andric if (directory) 334*0b57cec5SDimitry Andric return false; 335*0b57cec5SDimitry Andric 336*0b57cec5SDimitry Andric // We cannot look for a file if there's no file name. 337*0b57cec5SDimitry Andric ConstString filename = file_spec.GetFilename(); 338*0b57cec5SDimitry Andric if (!filename) 339*0b57cec5SDimitry Andric return false; 340*0b57cec5SDimitry Andric 341*0b57cec5SDimitry Andric // Search for the file on the host. 342*0b57cec5SDimitry Andric const std::string filename_str(filename.GetCString()); 343*0b57cec5SDimitry Andric llvm::ErrorOr<std::string> error_or_path = 344*0b57cec5SDimitry Andric llvm::sys::findProgramByName(filename_str); 345*0b57cec5SDimitry Andric if (!error_or_path) 346*0b57cec5SDimitry Andric return false; 347*0b57cec5SDimitry Andric 348*0b57cec5SDimitry Andric // findProgramByName returns "." if it can't find the file. 349*0b57cec5SDimitry Andric llvm::StringRef path = *error_or_path; 350*0b57cec5SDimitry Andric llvm::StringRef parent = llvm::sys::path::parent_path(path); 351*0b57cec5SDimitry Andric if (parent.empty() || parent == ".") 352*0b57cec5SDimitry Andric return false; 353*0b57cec5SDimitry Andric 354*0b57cec5SDimitry Andric // Make sure that the result exists. 355*0b57cec5SDimitry Andric FileSpec result(*error_or_path); 356*0b57cec5SDimitry Andric if (!Exists(result)) 357*0b57cec5SDimitry Andric return false; 358*0b57cec5SDimitry Andric 359*0b57cec5SDimitry Andric file_spec = result; 360*0b57cec5SDimitry Andric return true; 361*0b57cec5SDimitry Andric } 362*0b57cec5SDimitry Andric 363*0b57cec5SDimitry Andric static int OpenWithFS(const FileSystem &fs, const char *path, int flags, 364*0b57cec5SDimitry Andric int mode) { 365*0b57cec5SDimitry Andric return const_cast<FileSystem &>(fs).Open(path, flags, mode); 366*0b57cec5SDimitry Andric } 367*0b57cec5SDimitry Andric 368*0b57cec5SDimitry Andric static int GetOpenFlags(uint32_t options) { 369*0b57cec5SDimitry Andric const bool read = options & File::eOpenOptionRead; 370*0b57cec5SDimitry Andric const bool write = options & File::eOpenOptionWrite; 371*0b57cec5SDimitry Andric 372*0b57cec5SDimitry Andric int open_flags = 0; 373*0b57cec5SDimitry Andric if (write) { 374*0b57cec5SDimitry Andric if (read) 375*0b57cec5SDimitry Andric open_flags |= O_RDWR; 376*0b57cec5SDimitry Andric else 377*0b57cec5SDimitry Andric open_flags |= O_WRONLY; 378*0b57cec5SDimitry Andric 379*0b57cec5SDimitry Andric if (options & File::eOpenOptionAppend) 380*0b57cec5SDimitry Andric open_flags |= O_APPEND; 381*0b57cec5SDimitry Andric 382*0b57cec5SDimitry Andric if (options & File::eOpenOptionTruncate) 383*0b57cec5SDimitry Andric open_flags |= O_TRUNC; 384*0b57cec5SDimitry Andric 385*0b57cec5SDimitry Andric if (options & File::eOpenOptionCanCreate) 386*0b57cec5SDimitry Andric open_flags |= O_CREAT; 387*0b57cec5SDimitry Andric 388*0b57cec5SDimitry Andric if (options & File::eOpenOptionCanCreateNewOnly) 389*0b57cec5SDimitry Andric open_flags |= O_CREAT | O_EXCL; 390*0b57cec5SDimitry Andric } else if (read) { 391*0b57cec5SDimitry Andric open_flags |= O_RDONLY; 392*0b57cec5SDimitry Andric 393*0b57cec5SDimitry Andric #ifndef _WIN32 394*0b57cec5SDimitry Andric if (options & File::eOpenOptionDontFollowSymlinks) 395*0b57cec5SDimitry Andric open_flags |= O_NOFOLLOW; 396*0b57cec5SDimitry Andric #endif 397*0b57cec5SDimitry Andric } 398*0b57cec5SDimitry Andric 399*0b57cec5SDimitry Andric #ifndef _WIN32 400*0b57cec5SDimitry Andric if (options & File::eOpenOptionNonBlocking) 401*0b57cec5SDimitry Andric open_flags |= O_NONBLOCK; 402*0b57cec5SDimitry Andric if (options & File::eOpenOptionCloseOnExec) 403*0b57cec5SDimitry Andric open_flags |= O_CLOEXEC; 404*0b57cec5SDimitry Andric #else 405*0b57cec5SDimitry Andric open_flags |= O_BINARY; 406*0b57cec5SDimitry Andric #endif 407*0b57cec5SDimitry Andric 408*0b57cec5SDimitry Andric return open_flags; 409*0b57cec5SDimitry Andric } 410*0b57cec5SDimitry Andric 411*0b57cec5SDimitry Andric static mode_t GetOpenMode(uint32_t permissions) { 412*0b57cec5SDimitry Andric mode_t mode = 0; 413*0b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsUserRead) 414*0b57cec5SDimitry Andric mode |= S_IRUSR; 415*0b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsUserWrite) 416*0b57cec5SDimitry Andric mode |= S_IWUSR; 417*0b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsUserExecute) 418*0b57cec5SDimitry Andric mode |= S_IXUSR; 419*0b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsGroupRead) 420*0b57cec5SDimitry Andric mode |= S_IRGRP; 421*0b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsGroupWrite) 422*0b57cec5SDimitry Andric mode |= S_IWGRP; 423*0b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsGroupExecute) 424*0b57cec5SDimitry Andric mode |= S_IXGRP; 425*0b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsWorldRead) 426*0b57cec5SDimitry Andric mode |= S_IROTH; 427*0b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsWorldWrite) 428*0b57cec5SDimitry Andric mode |= S_IWOTH; 429*0b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsWorldExecute) 430*0b57cec5SDimitry Andric mode |= S_IXOTH; 431*0b57cec5SDimitry Andric return mode; 432*0b57cec5SDimitry Andric } 433*0b57cec5SDimitry Andric 4349dba64beSDimitry Andric Expected<FileUP> FileSystem::Open(const FileSpec &file_spec, 4359dba64beSDimitry Andric File::OpenOptions options, 436*0b57cec5SDimitry Andric uint32_t permissions, bool should_close_fd) { 4375ffd83dbSDimitry Andric Collect(file_spec.GetPath()); 438*0b57cec5SDimitry Andric 439*0b57cec5SDimitry Andric const int open_flags = GetOpenFlags(options); 440*0b57cec5SDimitry Andric const mode_t open_mode = 441*0b57cec5SDimitry Andric (open_flags & O_CREAT) ? GetOpenMode(permissions) : 0; 442*0b57cec5SDimitry Andric 443*0b57cec5SDimitry Andric auto path = GetExternalPath(file_spec); 444*0b57cec5SDimitry Andric if (!path) 4459dba64beSDimitry Andric return errorCodeToError(path.getError()); 446*0b57cec5SDimitry Andric 447*0b57cec5SDimitry Andric int descriptor = llvm::sys::RetryAfterSignal( 448*0b57cec5SDimitry Andric -1, OpenWithFS, *this, path->c_str(), open_flags, open_mode); 449*0b57cec5SDimitry 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); 458*0b57cec5SDimitry Andric } 459*0b57cec5SDimitry Andric 460*0b57cec5SDimitry Andric ErrorOr<std::string> FileSystem::GetExternalPath(const llvm::Twine &path) { 461*0b57cec5SDimitry Andric if (!m_mapped) 462*0b57cec5SDimitry Andric return path.str(); 463*0b57cec5SDimitry Andric 464*0b57cec5SDimitry Andric // If VFS mapped we know the underlying FS is a RedirectingFileSystem. 465*0b57cec5SDimitry Andric ErrorOr<vfs::RedirectingFileSystem::Entry *> E = 466*0b57cec5SDimitry Andric static_cast<vfs::RedirectingFileSystem &>(*m_fs).lookupPath(path); 467*0b57cec5SDimitry Andric if (!E) { 468*0b57cec5SDimitry Andric if (E.getError() == llvm::errc::no_such_file_or_directory) { 469*0b57cec5SDimitry Andric return path.str(); 470*0b57cec5SDimitry Andric } 471*0b57cec5SDimitry Andric return E.getError(); 472*0b57cec5SDimitry Andric } 473*0b57cec5SDimitry Andric 474*0b57cec5SDimitry Andric auto *F = dyn_cast<vfs::RedirectingFileSystem::RedirectingFileEntry>(*E); 475*0b57cec5SDimitry Andric if (!F) 476*0b57cec5SDimitry Andric return make_error_code(llvm::errc::not_supported); 477*0b57cec5SDimitry Andric 478*0b57cec5SDimitry Andric return F->getExternalContentsPath().str(); 479*0b57cec5SDimitry Andric } 480*0b57cec5SDimitry Andric 481*0b57cec5SDimitry Andric ErrorOr<std::string> FileSystem::GetExternalPath(const FileSpec &file_spec) { 482*0b57cec5SDimitry Andric return GetExternalPath(file_spec.GetPath()); 483*0b57cec5SDimitry Andric } 4845ffd83dbSDimitry Andric 4855ffd83dbSDimitry Andric void FileSystem::Collect(const FileSpec &file_spec) { 4865ffd83dbSDimitry Andric Collect(file_spec.GetPath()); 4875ffd83dbSDimitry Andric } 4885ffd83dbSDimitry Andric 4895ffd83dbSDimitry Andric void FileSystem::Collect(const llvm::Twine &file) { 4905ffd83dbSDimitry Andric if (!m_collector) 4915ffd83dbSDimitry Andric return; 4925ffd83dbSDimitry Andric 4935ffd83dbSDimitry Andric if (llvm::sys::fs::is_directory(file)) 4945ffd83dbSDimitry Andric m_collector->addDirectory(file); 4955ffd83dbSDimitry Andric else 4965ffd83dbSDimitry Andric m_collector->addFile(file); 4975ffd83dbSDimitry Andric } 498