1 //===-- FileSystem.cpp ------------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/Host/FileSystem.h" 11 12 #include "lldb/Utility/LLDBAssert.h" 13 #include "lldb/Utility/TildeExpressionResolver.h" 14 15 #include "llvm/Support/FileSystem.h" 16 #include "llvm/Support/Path.h" 17 #include "llvm/Support/Program.h" 18 #include "llvm/Support/Threading.h" 19 20 #include <algorithm> 21 #include <fstream> 22 #include <vector> 23 24 using namespace lldb; 25 using namespace lldb_private; 26 using namespace llvm; 27 28 FileSystem &FileSystem::Instance() { return *InstanceImpl(); } 29 30 void FileSystem::Initialize() { 31 lldbassert(!InstanceImpl() && "Already initialized."); 32 InstanceImpl().emplace(); 33 } 34 35 void FileSystem::Initialize(IntrusiveRefCntPtr<vfs::FileSystem> fs) { 36 lldbassert(!InstanceImpl() && "Already initialized."); 37 InstanceImpl().emplace(fs); 38 } 39 40 void FileSystem::Terminate() { 41 lldbassert(InstanceImpl() && "Already terminated."); 42 InstanceImpl().reset(); 43 } 44 45 Optional<FileSystem> &FileSystem::InstanceImpl() { 46 static Optional<FileSystem> g_fs; 47 return g_fs; 48 } 49 50 void FileSystem::SetFileSystem(IntrusiveRefCntPtr<vfs::FileSystem> fs) { 51 m_fs = fs; 52 } 53 54 sys::TimePoint<> 55 FileSystem::GetModificationTime(const FileSpec &file_spec) const { 56 return GetModificationTime(file_spec.GetPath()); 57 } 58 59 sys::TimePoint<> FileSystem::GetModificationTime(const Twine &path) const { 60 ErrorOr<vfs::Status> status = m_fs->status(path); 61 if (!status) 62 return sys::TimePoint<>(); 63 return status->getLastModificationTime(); 64 } 65 66 uint64_t FileSystem::GetByteSize(const FileSpec &file_spec) const { 67 return GetByteSize(file_spec.GetPath()); 68 } 69 70 uint64_t FileSystem::GetByteSize(const Twine &path) const { 71 ErrorOr<vfs::Status> status = m_fs->status(path); 72 if (!status) 73 return 0; 74 return status->getSize(); 75 } 76 77 uint32_t FileSystem::GetPermissions(const FileSpec &file_spec) const { 78 return GetPermissions(file_spec.GetPath()); 79 } 80 81 uint32_t FileSystem::GetPermissions(const Twine &path) const { 82 ErrorOr<vfs::Status> status = m_fs->status(path); 83 if (!status) 84 return sys::fs::perms::perms_not_known; 85 return status->getPermissions(); 86 } 87 88 bool FileSystem::Exists(const Twine &path) const { return m_fs->exists(path); } 89 90 bool FileSystem::Exists(const FileSpec &file_spec) const { 91 return Exists(file_spec.GetPath()); 92 } 93 94 bool FileSystem::Readable(const Twine &path) const { 95 return GetPermissions(path) & sys::fs::perms::all_read; 96 } 97 98 bool FileSystem::Readable(const FileSpec &file_spec) const { 99 return Readable(file_spec.GetPath()); 100 } 101 102 void FileSystem::EnumerateDirectory(Twine path, bool find_directories, 103 bool find_files, bool find_other, 104 EnumerateDirectoryCallbackType callback, 105 void *callback_baton) { 106 std::error_code EC; 107 vfs::recursive_directory_iterator Iter(*m_fs, path, EC); 108 vfs::recursive_directory_iterator End; 109 for (; Iter != End && !EC; Iter.increment(EC)) { 110 const auto &Item = *Iter; 111 ErrorOr<vfs::Status> Status = m_fs->status(Item.path()); 112 if (!Status) 113 break; 114 if (!find_files && Status->isRegularFile()) 115 continue; 116 if (!find_directories && Status->isDirectory()) 117 continue; 118 if (!find_other && Status->isOther()) 119 continue; 120 121 auto Result = callback(callback_baton, Status->getType(), Item.path()); 122 if (Result == eEnumerateDirectoryResultQuit) 123 return; 124 if (Result == eEnumerateDirectoryResultNext) { 125 // Default behavior is to recurse. Opt out if the callback doesn't want 126 // this behavior. 127 Iter.no_push(); 128 } 129 } 130 } 131 132 std::error_code FileSystem::MakeAbsolute(SmallVectorImpl<char> &path) const { 133 return m_fs->makeAbsolute(path); 134 } 135 136 std::error_code FileSystem::MakeAbsolute(FileSpec &file_spec) const { 137 SmallString<128> path; 138 file_spec.GetPath(path, false); 139 140 auto EC = MakeAbsolute(path); 141 if (EC) 142 return EC; 143 144 FileSpec new_file_spec(path, false, file_spec.GetPathStyle()); 145 file_spec = new_file_spec; 146 return {}; 147 } 148 149 std::error_code FileSystem::GetRealPath(const Twine &path, 150 SmallVectorImpl<char> &output) const { 151 return m_fs->getRealPath(path, output); 152 } 153 154 void FileSystem::Resolve(SmallVectorImpl<char> &path) { 155 if (path.empty()) 156 return; 157 158 // Resolve tilde. 159 SmallString<128> original_path(path.begin(), path.end()); 160 StandardTildeExpressionResolver Resolver; 161 Resolver.ResolveFullPath(original_path, path); 162 163 // Try making the path absolute if it exists. 164 SmallString<128> absolute_path(path.begin(), path.end()); 165 MakeAbsolute(path); 166 if (!Exists(path)) { 167 path.clear(); 168 path.append(original_path.begin(), original_path.end()); 169 } 170 } 171 172 void FileSystem::Resolve(FileSpec &file_spec) { 173 // Extract path from the FileSpec. 174 SmallString<128> path; 175 file_spec.GetPath(path); 176 177 // Resolve the path. 178 Resolve(path); 179 180 // Update the FileSpec with the resolved path. 181 file_spec.SetPath(path); 182 } 183 184 bool FileSystem::ResolveExecutableLocation(FileSpec &file_spec) { 185 // If the directory is set there's nothing to do. 186 const ConstString &directory = file_spec.GetDirectory(); 187 if (directory) 188 return false; 189 190 // We cannot look for a file if there's no file name. 191 const ConstString &filename = file_spec.GetFilename(); 192 if (!filename) 193 return false; 194 195 // Search for the file on the host. 196 const std::string filename_str(filename.GetCString()); 197 llvm::ErrorOr<std::string> error_or_path = 198 llvm::sys::findProgramByName(filename_str); 199 if (!error_or_path) 200 return false; 201 202 // findProgramByName returns "." if it can't find the file. 203 llvm::StringRef path = *error_or_path; 204 llvm::StringRef parent = llvm::sys::path::parent_path(path); 205 if (parent.empty() || parent == ".") 206 return false; 207 208 // Make sure that the result exists. 209 FileSpec result(*error_or_path, false); 210 if (!Exists(result)) 211 return false; 212 213 file_spec = result; 214 return true; 215 } 216