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/Errno.h" 16 #include "llvm/Support/FileSystem.h" 17 #include "llvm/Support/Path.h" 18 #include "llvm/Support/Program.h" 19 #include "llvm/Support/Threading.h" 20 21 #include <errno.h> 22 #include <fcntl.h> 23 #include <limits.h> 24 #include <stdarg.h> 25 #include <stdio.h> 26 27 #ifdef _WIN32 28 #include "lldb/Host/windows/windows.h" 29 #else 30 #include <sys/ioctl.h> 31 #include <sys/stat.h> 32 #include <termios.h> 33 #include <unistd.h> 34 #endif 35 36 #include <algorithm> 37 #include <fstream> 38 #include <vector> 39 40 using namespace lldb; 41 using namespace lldb_private; 42 using namespace llvm; 43 44 FileSystem &FileSystem::Instance() { return *InstanceImpl(); } 45 46 void FileSystem::Initialize() { 47 lldbassert(!InstanceImpl() && "Already initialized."); 48 InstanceImpl().emplace(); 49 } 50 51 void FileSystem::Initialize(IntrusiveRefCntPtr<vfs::FileSystem> fs) { 52 lldbassert(!InstanceImpl() && "Already initialized."); 53 InstanceImpl().emplace(fs); 54 } 55 56 void FileSystem::Terminate() { 57 lldbassert(InstanceImpl() && "Already terminated."); 58 InstanceImpl().reset(); 59 } 60 61 Optional<FileSystem> &FileSystem::InstanceImpl() { 62 static Optional<FileSystem> g_fs; 63 return g_fs; 64 } 65 66 sys::TimePoint<> 67 FileSystem::GetModificationTime(const FileSpec &file_spec, 68 bool nanosecond_precision) const { 69 return GetModificationTime(file_spec.GetPath(), nanosecond_precision); 70 } 71 72 sys::TimePoint<> 73 FileSystem::GetModificationTime(const Twine &path, 74 bool nanosecond_precision) const { 75 ErrorOr<vfs::Status> status = m_fs->status(path); 76 if (!status) 77 return sys::TimePoint<>(); 78 if (nanosecond_precision) 79 return status->getLastModificationTime(); 80 else 81 return std::chrono::time_point_cast<std::chrono::seconds>( 82 status->getLastModificationTime()); 83 } 84 85 uint64_t FileSystem::GetByteSize(const FileSpec &file_spec) const { 86 return GetByteSize(file_spec.GetPath()); 87 } 88 89 uint64_t FileSystem::GetByteSize(const Twine &path) const { 90 ErrorOr<vfs::Status> status = m_fs->status(path); 91 if (!status) 92 return 0; 93 return status->getSize(); 94 } 95 96 uint32_t FileSystem::GetPermissions(const FileSpec &file_spec) const { 97 return GetPermissions(file_spec.GetPath()); 98 } 99 100 uint32_t FileSystem::GetPermissions(const FileSpec &file_spec, 101 std::error_code &ec) const { 102 return GetPermissions(file_spec.GetPath(), ec); 103 } 104 105 uint32_t FileSystem::GetPermissions(const Twine &path) const { 106 std::error_code ec; 107 return GetPermissions(path, ec); 108 } 109 110 uint32_t FileSystem::GetPermissions(const Twine &path, 111 std::error_code &ec) const { 112 ErrorOr<vfs::Status> status = m_fs->status(path); 113 if (!status) { 114 ec = status.getError(); 115 return sys::fs::perms::perms_not_known; 116 } 117 return status->getPermissions(); 118 } 119 120 bool FileSystem::Exists(const Twine &path) const { return m_fs->exists(path); } 121 122 bool FileSystem::Exists(const FileSpec &file_spec) const { 123 return Exists(file_spec.GetPath()); 124 } 125 126 bool FileSystem::Readable(const Twine &path) const { 127 return GetPermissions(path) & sys::fs::perms::all_read; 128 } 129 130 bool FileSystem::Readable(const FileSpec &file_spec) const { 131 return Readable(file_spec.GetPath()); 132 } 133 134 bool FileSystem::IsDirectory(const Twine &path) const { 135 ErrorOr<vfs::Status> status = m_fs->status(path); 136 if (!status) 137 return false; 138 return status->isDirectory(); 139 } 140 141 bool FileSystem::IsDirectory(const FileSpec &file_spec) const { 142 return IsDirectory(file_spec.GetPath()); 143 } 144 145 bool FileSystem::IsLocal(const Twine &path) const { 146 bool b = false; 147 m_fs->isLocal(path, b); 148 return b; 149 } 150 151 bool FileSystem::IsLocal(const FileSpec &file_spec) const { 152 return IsLocal(file_spec.GetPath()); 153 } 154 155 void FileSystem::EnumerateDirectory(Twine path, bool find_directories, 156 bool find_files, bool find_other, 157 EnumerateDirectoryCallbackType callback, 158 void *callback_baton) { 159 std::error_code EC; 160 vfs::recursive_directory_iterator Iter(*m_fs, path, EC); 161 vfs::recursive_directory_iterator End; 162 for (; Iter != End && !EC; Iter.increment(EC)) { 163 const auto &Item = *Iter; 164 ErrorOr<vfs::Status> Status = m_fs->status(Item.path()); 165 if (!Status) 166 break; 167 if (!find_files && Status->isRegularFile()) 168 continue; 169 if (!find_directories && Status->isDirectory()) 170 continue; 171 if (!find_other && Status->isOther()) 172 continue; 173 174 auto Result = callback(callback_baton, Status->getType(), Item.path()); 175 if (Result == eEnumerateDirectoryResultQuit) 176 return; 177 if (Result == eEnumerateDirectoryResultNext) { 178 // Default behavior is to recurse. Opt out if the callback doesn't want 179 // this behavior. 180 Iter.no_push(); 181 } 182 } 183 } 184 185 std::error_code FileSystem::MakeAbsolute(SmallVectorImpl<char> &path) const { 186 return m_fs->makeAbsolute(path); 187 } 188 189 std::error_code FileSystem::MakeAbsolute(FileSpec &file_spec) const { 190 SmallString<128> path; 191 file_spec.GetPath(path, false); 192 193 auto EC = MakeAbsolute(path); 194 if (EC) 195 return EC; 196 197 FileSpec new_file_spec(path, file_spec.GetPathStyle()); 198 file_spec = new_file_spec; 199 return {}; 200 } 201 202 std::error_code FileSystem::GetRealPath(const Twine &path, 203 SmallVectorImpl<char> &output) const { 204 return m_fs->getRealPath(path, output); 205 } 206 207 void FileSystem::Resolve(SmallVectorImpl<char> &path) { 208 if (path.empty()) 209 return; 210 211 // Resolve tilde. 212 SmallString<128> original_path(path.begin(), path.end()); 213 StandardTildeExpressionResolver Resolver; 214 Resolver.ResolveFullPath(original_path, path); 215 216 // Try making the path absolute if it exists. 217 SmallString<128> absolute_path(path.begin(), path.end()); 218 MakeAbsolute(path); 219 if (!Exists(path)) { 220 path.clear(); 221 path.append(original_path.begin(), original_path.end()); 222 } 223 } 224 225 void FileSystem::Resolve(FileSpec &file_spec) { 226 // Extract path from the FileSpec. 227 SmallString<128> path; 228 file_spec.GetPath(path); 229 230 // Resolve the path. 231 Resolve(path); 232 233 // Update the FileSpec with the resolved path. 234 file_spec.SetPath(path); 235 file_spec.SetIsResolved(true); 236 } 237 238 std::shared_ptr<DataBufferLLVM> 239 FileSystem::CreateDataBuffer(const llvm::Twine &path, uint64_t size, 240 uint64_t offset) { 241 const bool is_volatile = !IsLocal(path); 242 243 std::unique_ptr<llvm::WritableMemoryBuffer> buffer; 244 if (size == 0) { 245 auto buffer_or_error = 246 llvm::WritableMemoryBuffer::getFile(path, -1, is_volatile); 247 if (!buffer_or_error) 248 return nullptr; 249 buffer = std::move(*buffer_or_error); 250 } else { 251 auto buffer_or_error = llvm::WritableMemoryBuffer::getFileSlice( 252 path, size, offset, is_volatile); 253 if (!buffer_or_error) 254 return nullptr; 255 buffer = std::move(*buffer_or_error); 256 } 257 return std::shared_ptr<DataBufferLLVM>(new DataBufferLLVM(std::move(buffer))); 258 } 259 260 std::shared_ptr<DataBufferLLVM> 261 FileSystem::CreateDataBuffer(const FileSpec &file_spec, uint64_t size, 262 uint64_t offset) { 263 return CreateDataBuffer(file_spec.GetPath(), size, offset); 264 } 265 266 bool FileSystem::ResolveExecutableLocation(FileSpec &file_spec) { 267 // If the directory is set there's nothing to do. 268 const ConstString &directory = file_spec.GetDirectory(); 269 if (directory) 270 return false; 271 272 // We cannot look for a file if there's no file name. 273 const ConstString &filename = file_spec.GetFilename(); 274 if (!filename) 275 return false; 276 277 // Search for the file on the host. 278 const std::string filename_str(filename.GetCString()); 279 llvm::ErrorOr<std::string> error_or_path = 280 llvm::sys::findProgramByName(filename_str); 281 if (!error_or_path) 282 return false; 283 284 // findProgramByName returns "." if it can't find the file. 285 llvm::StringRef path = *error_or_path; 286 llvm::StringRef parent = llvm::sys::path::parent_path(path); 287 if (parent.empty() || parent == ".") 288 return false; 289 290 // Make sure that the result exists. 291 FileSpec result(*error_or_path); 292 if (!Exists(result)) 293 return false; 294 295 file_spec = result; 296 return true; 297 } 298 299 static int OpenWithFS(const FileSystem &fs, const char *path, int flags, 300 int mode) { 301 return const_cast<FileSystem &>(fs).Open(path, flags, mode); 302 } 303 304 static int GetOpenFlags(uint32_t options) { 305 const bool read = options & File::eOpenOptionRead; 306 const bool write = options & File::eOpenOptionWrite; 307 308 int open_flags = 0; 309 if (write) { 310 if (read) 311 open_flags |= O_RDWR; 312 else 313 open_flags |= O_WRONLY; 314 315 if (options & File::eOpenOptionAppend) 316 open_flags |= O_APPEND; 317 318 if (options & File::eOpenOptionTruncate) 319 open_flags |= O_TRUNC; 320 321 if (options & File::eOpenOptionCanCreate) 322 open_flags |= O_CREAT; 323 324 if (options & File::eOpenOptionCanCreateNewOnly) 325 open_flags |= O_CREAT | O_EXCL; 326 } else if (read) { 327 open_flags |= O_RDONLY; 328 329 #ifndef _WIN32 330 if (options & File::eOpenOptionDontFollowSymlinks) 331 open_flags |= O_NOFOLLOW; 332 #endif 333 } 334 335 #ifndef _WIN32 336 if (options & File::eOpenOptionNonBlocking) 337 open_flags |= O_NONBLOCK; 338 if (options & File::eOpenOptionCloseOnExec) 339 open_flags |= O_CLOEXEC; 340 #else 341 open_flags |= O_BINARY; 342 #endif 343 344 return open_flags; 345 } 346 347 static mode_t GetOpenMode(uint32_t permissions) { 348 mode_t mode = 0; 349 if (permissions & lldb::eFilePermissionsUserRead) 350 mode |= S_IRUSR; 351 if (permissions & lldb::eFilePermissionsUserWrite) 352 mode |= S_IWUSR; 353 if (permissions & lldb::eFilePermissionsUserExecute) 354 mode |= S_IXUSR; 355 if (permissions & lldb::eFilePermissionsGroupRead) 356 mode |= S_IRGRP; 357 if (permissions & lldb::eFilePermissionsGroupWrite) 358 mode |= S_IWGRP; 359 if (permissions & lldb::eFilePermissionsGroupExecute) 360 mode |= S_IXGRP; 361 if (permissions & lldb::eFilePermissionsWorldRead) 362 mode |= S_IROTH; 363 if (permissions & lldb::eFilePermissionsWorldWrite) 364 mode |= S_IWOTH; 365 if (permissions & lldb::eFilePermissionsWorldExecute) 366 mode |= S_IXOTH; 367 return mode; 368 } 369 370 Status FileSystem::Open(File &File, const FileSpec &file_spec, uint32_t options, 371 uint32_t permissions) { 372 if (File.IsValid()) 373 File.Close(); 374 375 const int open_flags = GetOpenFlags(options); 376 const mode_t open_mode = 377 (open_flags & O_CREAT) ? GetOpenMode(permissions) : 0; 378 const std::string path = file_spec.GetPath(); 379 380 int descriptor = llvm::sys::RetryAfterSignal( 381 -1, OpenWithFS, *this, path.c_str(), open_flags, open_mode); 382 383 Status error; 384 if (!File::DescriptorIsValid(descriptor)) { 385 File.SetDescriptor(descriptor, false); 386 error.SetErrorToErrno(); 387 } else { 388 File.SetDescriptor(descriptor, true); 389 File.SetOptions(options); 390 } 391 return error; 392 } 393