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 FileSpec &file_spec, 82 std::error_code &ec) const { 83 return GetPermissions(file_spec.GetPath(), ec); 84 } 85 86 uint32_t FileSystem::GetPermissions(const Twine &path) const { 87 std::error_code ec; 88 return GetPermissions(path, ec); 89 } 90 91 uint32_t FileSystem::GetPermissions(const Twine &path, 92 std::error_code &ec) const { 93 ErrorOr<vfs::Status> status = m_fs->status(path); 94 if (!status) { 95 ec = status.getError(); 96 return sys::fs::perms::perms_not_known; 97 } 98 return status->getPermissions(); 99 } 100 101 bool FileSystem::Exists(const Twine &path) const { return m_fs->exists(path); } 102 103 bool FileSystem::Exists(const FileSpec &file_spec) const { 104 return Exists(file_spec.GetPath()); 105 } 106 107 bool FileSystem::Readable(const Twine &path) const { 108 return GetPermissions(path) & sys::fs::perms::all_read; 109 } 110 111 bool FileSystem::Readable(const FileSpec &file_spec) const { 112 return Readable(file_spec.GetPath()); 113 } 114 115 void FileSystem::EnumerateDirectory(Twine path, bool find_directories, 116 bool find_files, bool find_other, 117 EnumerateDirectoryCallbackType callback, 118 void *callback_baton) { 119 std::error_code EC; 120 vfs::recursive_directory_iterator Iter(*m_fs, path, EC); 121 vfs::recursive_directory_iterator End; 122 for (; Iter != End && !EC; Iter.increment(EC)) { 123 const auto &Item = *Iter; 124 ErrorOr<vfs::Status> Status = m_fs->status(Item.path()); 125 if (!Status) 126 break; 127 if (!find_files && Status->isRegularFile()) 128 continue; 129 if (!find_directories && Status->isDirectory()) 130 continue; 131 if (!find_other && Status->isOther()) 132 continue; 133 134 auto Result = callback(callback_baton, Status->getType(), Item.path()); 135 if (Result == eEnumerateDirectoryResultQuit) 136 return; 137 if (Result == eEnumerateDirectoryResultNext) { 138 // Default behavior is to recurse. Opt out if the callback doesn't want 139 // this behavior. 140 Iter.no_push(); 141 } 142 } 143 } 144 145 std::error_code FileSystem::MakeAbsolute(SmallVectorImpl<char> &path) const { 146 return m_fs->makeAbsolute(path); 147 } 148 149 std::error_code FileSystem::MakeAbsolute(FileSpec &file_spec) const { 150 SmallString<128> path; 151 file_spec.GetPath(path, false); 152 153 auto EC = MakeAbsolute(path); 154 if (EC) 155 return EC; 156 157 FileSpec new_file_spec(path, file_spec.GetPathStyle()); 158 file_spec = new_file_spec; 159 return {}; 160 } 161 162 std::error_code FileSystem::GetRealPath(const Twine &path, 163 SmallVectorImpl<char> &output) const { 164 return m_fs->getRealPath(path, output); 165 } 166 167 void FileSystem::Resolve(SmallVectorImpl<char> &path) { 168 if (path.empty()) 169 return; 170 171 // Resolve tilde. 172 SmallString<128> original_path(path.begin(), path.end()); 173 StandardTildeExpressionResolver Resolver; 174 Resolver.ResolveFullPath(original_path, path); 175 176 // Try making the path absolute if it exists. 177 SmallString<128> absolute_path(path.begin(), path.end()); 178 MakeAbsolute(path); 179 if (!Exists(path)) { 180 path.clear(); 181 path.append(original_path.begin(), original_path.end()); 182 } 183 } 184 185 void FileSystem::Resolve(FileSpec &file_spec) { 186 // Extract path from the FileSpec. 187 SmallString<128> path; 188 file_spec.GetPath(path); 189 190 // Resolve the path. 191 Resolve(path); 192 193 // Update the FileSpec with the resolved path. 194 file_spec.SetPath(path); 195 file_spec.SetIsResolved(true); 196 } 197 198 bool FileSystem::ResolveExecutableLocation(FileSpec &file_spec) { 199 // If the directory is set there's nothing to do. 200 const ConstString &directory = file_spec.GetDirectory(); 201 if (directory) 202 return false; 203 204 // We cannot look for a file if there's no file name. 205 const ConstString &filename = file_spec.GetFilename(); 206 if (!filename) 207 return false; 208 209 // Search for the file on the host. 210 const std::string filename_str(filename.GetCString()); 211 llvm::ErrorOr<std::string> error_or_path = 212 llvm::sys::findProgramByName(filename_str); 213 if (!error_or_path) 214 return false; 215 216 // findProgramByName returns "." if it can't find the file. 217 llvm::StringRef path = *error_or_path; 218 llvm::StringRef parent = llvm::sys::path::parent_path(path); 219 if (parent.empty() || parent == ".") 220 return false; 221 222 // Make sure that the result exists. 223 FileSpec result(*error_or_path); 224 if (!Exists(result)) 225 return false; 226 227 file_spec = result; 228 return true; 229 } 230