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