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