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