17a9e7621SOleksiy Vyalov //===-- FileSystem.cpp ------------------------------------------*- C++ -*-===// 27a9e7621SOleksiy Vyalov // 37a9e7621SOleksiy Vyalov // The LLVM Compiler Infrastructure 47a9e7621SOleksiy Vyalov // 57a9e7621SOleksiy Vyalov // This file is distributed under the University of Illinois Open Source 67a9e7621SOleksiy Vyalov // License. See LICENSE.TXT for details. 77a9e7621SOleksiy Vyalov // 87a9e7621SOleksiy Vyalov //===----------------------------------------------------------------------===// 97a9e7621SOleksiy Vyalov 107a9e7621SOleksiy Vyalov #include "lldb/Host/FileSystem.h" 117a9e7621SOleksiy Vyalov 120bca15a3SJonas Devlieghere #include "lldb/Utility/LLDBAssert.h" 1346376966SJonas Devlieghere #include "lldb/Utility/TildeExpressionResolver.h" 1446376966SJonas Devlieghere 151408bf72SPavel Labath #include "llvm/Support/FileSystem.h" 16*2c22c800SJonas Devlieghere #include "llvm/Support/Path.h" 17*2c22c800SJonas Devlieghere #include "llvm/Support/Program.h" 1846376966SJonas Devlieghere #include "llvm/Support/Threading.h" 197a9e7621SOleksiy Vyalov 206801be33SOleksiy Vyalov #include <algorithm> 217a9e7621SOleksiy Vyalov #include <fstream> 227a9e7621SOleksiy Vyalov #include <vector> 237a9e7621SOleksiy Vyalov 247a9e7621SOleksiy Vyalov using namespace lldb; 257a9e7621SOleksiy Vyalov using namespace lldb_private; 2646376966SJonas Devlieghere using namespace llvm; 277a9e7621SOleksiy Vyalov 2846376966SJonas Devlieghere FileSystem &FileSystem::Instance() { return *InstanceImpl(); } 2946376966SJonas Devlieghere 3046376966SJonas Devlieghere void FileSystem::Initialize() { 310bca15a3SJonas Devlieghere lldbassert(!InstanceImpl() && "Already initialized."); 3246376966SJonas Devlieghere InstanceImpl().emplace(); 3346376966SJonas Devlieghere } 3446376966SJonas Devlieghere 3546376966SJonas Devlieghere void FileSystem::Initialize(IntrusiveRefCntPtr<vfs::FileSystem> fs) { 360bca15a3SJonas Devlieghere lldbassert(!InstanceImpl() && "Already initialized."); 3746376966SJonas Devlieghere InstanceImpl().emplace(fs); 3846376966SJonas Devlieghere } 3946376966SJonas Devlieghere 4046376966SJonas Devlieghere void FileSystem::Terminate() { 410bca15a3SJonas Devlieghere lldbassert(InstanceImpl() && "Already terminated."); 4246376966SJonas Devlieghere InstanceImpl().reset(); 4346376966SJonas Devlieghere } 4446376966SJonas Devlieghere 4546376966SJonas Devlieghere Optional<FileSystem> &FileSystem::InstanceImpl() { 4646376966SJonas Devlieghere static Optional<FileSystem> g_fs; 4746376966SJonas Devlieghere return g_fs; 4846376966SJonas Devlieghere } 4946376966SJonas Devlieghere 5046376966SJonas Devlieghere void FileSystem::SetFileSystem(IntrusiveRefCntPtr<vfs::FileSystem> fs) { 5146376966SJonas Devlieghere m_fs = fs; 5246376966SJonas Devlieghere } 5346376966SJonas Devlieghere 5446376966SJonas Devlieghere sys::TimePoint<> 5546376966SJonas Devlieghere FileSystem::GetModificationTime(const FileSpec &file_spec) const { 5646376966SJonas Devlieghere return GetModificationTime(file_spec.GetPath()); 5746376966SJonas Devlieghere } 5846376966SJonas Devlieghere 5946376966SJonas Devlieghere sys::TimePoint<> FileSystem::GetModificationTime(const Twine &path) const { 6046376966SJonas Devlieghere ErrorOr<vfs::Status> status = m_fs->status(path); 6146376966SJonas Devlieghere if (!status) 6246376966SJonas Devlieghere return sys::TimePoint<>(); 6346376966SJonas Devlieghere return status->getLastModificationTime(); 6446376966SJonas Devlieghere } 6546376966SJonas Devlieghere 6646376966SJonas Devlieghere uint64_t FileSystem::GetByteSize(const FileSpec &file_spec) const { 6746376966SJonas Devlieghere return GetByteSize(file_spec.GetPath()); 6846376966SJonas Devlieghere } 6946376966SJonas Devlieghere 7046376966SJonas Devlieghere uint64_t FileSystem::GetByteSize(const Twine &path) const { 7146376966SJonas Devlieghere ErrorOr<vfs::Status> status = m_fs->status(path); 7246376966SJonas Devlieghere if (!status) 7346376966SJonas Devlieghere return 0; 7446376966SJonas Devlieghere return status->getSize(); 7546376966SJonas Devlieghere } 7646376966SJonas Devlieghere 7746376966SJonas Devlieghere uint32_t FileSystem::GetPermissions(const FileSpec &file_spec) const { 7846376966SJonas Devlieghere return GetPermissions(file_spec.GetPath()); 7946376966SJonas Devlieghere } 8046376966SJonas Devlieghere 8146376966SJonas Devlieghere uint32_t FileSystem::GetPermissions(const Twine &path) const { 8246376966SJonas Devlieghere ErrorOr<vfs::Status> status = m_fs->status(path); 8346376966SJonas Devlieghere if (!status) 8446376966SJonas Devlieghere return sys::fs::perms::perms_not_known; 8546376966SJonas Devlieghere return status->getPermissions(); 8646376966SJonas Devlieghere } 8746376966SJonas Devlieghere 8846376966SJonas Devlieghere bool FileSystem::Exists(const Twine &path) const { return m_fs->exists(path); } 8946376966SJonas Devlieghere 9046376966SJonas Devlieghere bool FileSystem::Exists(const FileSpec &file_spec) const { 9146376966SJonas Devlieghere return Exists(file_spec.GetPath()); 9246376966SJonas Devlieghere } 9346376966SJonas Devlieghere 9446376966SJonas Devlieghere bool FileSystem::Readable(const Twine &path) const { 9546376966SJonas Devlieghere return GetPermissions(path) & sys::fs::perms::all_read; 9646376966SJonas Devlieghere } 9746376966SJonas Devlieghere 9846376966SJonas Devlieghere bool FileSystem::Readable(const FileSpec &file_spec) const { 9946376966SJonas Devlieghere return Readable(file_spec.GetPath()); 10046376966SJonas Devlieghere } 10146376966SJonas Devlieghere 1029ca491daSJonas Devlieghere void FileSystem::EnumerateDirectory(Twine path, bool find_directories, 1039ca491daSJonas Devlieghere bool find_files, bool find_other, 1049ca491daSJonas Devlieghere EnumerateDirectoryCallbackType callback, 1059ca491daSJonas Devlieghere void *callback_baton) { 1069ca491daSJonas Devlieghere std::error_code EC; 1079ca491daSJonas Devlieghere vfs::recursive_directory_iterator Iter(*m_fs, path, EC); 1089ca491daSJonas Devlieghere vfs::recursive_directory_iterator End; 1099ca491daSJonas Devlieghere for (; Iter != End && !EC; Iter.increment(EC)) { 1109ca491daSJonas Devlieghere const auto &Item = *Iter; 1119ca491daSJonas Devlieghere ErrorOr<vfs::Status> Status = m_fs->status(Item.path()); 1129ca491daSJonas Devlieghere if (!Status) 1139ca491daSJonas Devlieghere break; 1149ca491daSJonas Devlieghere if (!find_files && Status->isRegularFile()) 1159ca491daSJonas Devlieghere continue; 1169ca491daSJonas Devlieghere if (!find_directories && Status->isDirectory()) 1179ca491daSJonas Devlieghere continue; 1189ca491daSJonas Devlieghere if (!find_other && Status->isOther()) 1199ca491daSJonas Devlieghere continue; 1209ca491daSJonas Devlieghere 1219ca491daSJonas Devlieghere auto Result = callback(callback_baton, Status->getType(), Item.path()); 1229ca491daSJonas Devlieghere if (Result == eEnumerateDirectoryResultQuit) 1239ca491daSJonas Devlieghere return; 1249ca491daSJonas Devlieghere if (Result == eEnumerateDirectoryResultNext) { 1259ca491daSJonas Devlieghere // Default behavior is to recurse. Opt out if the callback doesn't want 1269ca491daSJonas Devlieghere // this behavior. 1279ca491daSJonas Devlieghere Iter.no_push(); 1289ca491daSJonas Devlieghere } 1299ca491daSJonas Devlieghere } 1309ca491daSJonas Devlieghere } 1319ca491daSJonas Devlieghere 13246376966SJonas Devlieghere std::error_code FileSystem::MakeAbsolute(SmallVectorImpl<char> &path) const { 13346376966SJonas Devlieghere return m_fs->makeAbsolute(path); 13446376966SJonas Devlieghere } 13546376966SJonas Devlieghere 13646376966SJonas Devlieghere std::error_code FileSystem::MakeAbsolute(FileSpec &file_spec) const { 13746376966SJonas Devlieghere SmallString<128> path; 13846376966SJonas Devlieghere file_spec.GetPath(path, false); 13946376966SJonas Devlieghere 14046376966SJonas Devlieghere auto EC = MakeAbsolute(path); 14146376966SJonas Devlieghere if (EC) 14246376966SJonas Devlieghere return EC; 14346376966SJonas Devlieghere 14446376966SJonas Devlieghere FileSpec new_file_spec(path, false, file_spec.GetPathStyle()); 14546376966SJonas Devlieghere file_spec = new_file_spec; 14646376966SJonas Devlieghere return {}; 14746376966SJonas Devlieghere } 14846376966SJonas Devlieghere 14946376966SJonas Devlieghere std::error_code FileSystem::GetRealPath(const Twine &path, 15046376966SJonas Devlieghere SmallVectorImpl<char> &output) const { 15146376966SJonas Devlieghere return m_fs->getRealPath(path, output); 15246376966SJonas Devlieghere } 15346376966SJonas Devlieghere 15446376966SJonas Devlieghere void FileSystem::Resolve(SmallVectorImpl<char> &path) { 15546376966SJonas Devlieghere if (path.empty()) 15646376966SJonas Devlieghere return; 15746376966SJonas Devlieghere 15846376966SJonas Devlieghere // Resolve tilde. 15946376966SJonas Devlieghere SmallString<128> original_path(path.begin(), path.end()); 16046376966SJonas Devlieghere StandardTildeExpressionResolver Resolver; 16146376966SJonas Devlieghere Resolver.ResolveFullPath(original_path, path); 16246376966SJonas Devlieghere 16346376966SJonas Devlieghere // Try making the path absolute if it exists. 16446376966SJonas Devlieghere SmallString<128> absolute_path(path.begin(), path.end()); 16546376966SJonas Devlieghere MakeAbsolute(path); 16646376966SJonas Devlieghere if (!Exists(path)) { 16746376966SJonas Devlieghere path.clear(); 16846376966SJonas Devlieghere path.append(original_path.begin(), original_path.end()); 16946376966SJonas Devlieghere } 17046376966SJonas Devlieghere } 17146376966SJonas Devlieghere 17246376966SJonas Devlieghere void FileSystem::Resolve(FileSpec &file_spec) { 17346376966SJonas Devlieghere // Extract path from the FileSpec. 17446376966SJonas Devlieghere SmallString<128> path; 17546376966SJonas Devlieghere file_spec.GetPath(path); 17646376966SJonas Devlieghere 17746376966SJonas Devlieghere // Resolve the path. 17846376966SJonas Devlieghere Resolve(path); 17946376966SJonas Devlieghere 18046376966SJonas Devlieghere // Update the FileSpec with the resolved path. 18146376966SJonas Devlieghere file_spec.SetPath(path); 1821408bf72SPavel Labath } 183*2c22c800SJonas Devlieghere 184*2c22c800SJonas Devlieghere bool FileSystem::ResolveExecutableLocation(FileSpec &file_spec) { 185*2c22c800SJonas Devlieghere // If the directory is set there's nothing to do. 186*2c22c800SJonas Devlieghere const ConstString &directory = file_spec.GetDirectory(); 187*2c22c800SJonas Devlieghere if (directory) 188*2c22c800SJonas Devlieghere return false; 189*2c22c800SJonas Devlieghere 190*2c22c800SJonas Devlieghere // We cannot look for a file if there's no file name. 191*2c22c800SJonas Devlieghere const ConstString &filename = file_spec.GetFilename(); 192*2c22c800SJonas Devlieghere if (!filename) 193*2c22c800SJonas Devlieghere return false; 194*2c22c800SJonas Devlieghere 195*2c22c800SJonas Devlieghere // Search for the file on the host. 196*2c22c800SJonas Devlieghere const std::string filename_str(filename.GetCString()); 197*2c22c800SJonas Devlieghere llvm::ErrorOr<std::string> error_or_path = 198*2c22c800SJonas Devlieghere llvm::sys::findProgramByName(filename_str); 199*2c22c800SJonas Devlieghere if (!error_or_path) 200*2c22c800SJonas Devlieghere return false; 201*2c22c800SJonas Devlieghere 202*2c22c800SJonas Devlieghere // findProgramByName returns "." if it can't find the file. 203*2c22c800SJonas Devlieghere llvm::StringRef path = *error_or_path; 204*2c22c800SJonas Devlieghere llvm::StringRef parent = llvm::sys::path::parent_path(path); 205*2c22c800SJonas Devlieghere if (parent.empty() || parent == ".") 206*2c22c800SJonas Devlieghere return false; 207*2c22c800SJonas Devlieghere 208*2c22c800SJonas Devlieghere // Make sure that the result exists. 209*2c22c800SJonas Devlieghere FileSpec result(*error_or_path, false); 210*2c22c800SJonas Devlieghere if (!Exists(result)) 211*2c22c800SJonas Devlieghere return false; 212*2c22c800SJonas Devlieghere 213*2c22c800SJonas Devlieghere file_spec = result; 214*2c22c800SJonas Devlieghere return true; 215*2c22c800SJonas Devlieghere } 216