brintos

brintos / llvm-project-archived public Read only

0
0
Text · 13.7 KiB · 00919fe Raw
471 lines · cpp
1//===-- FileSystem.cpp ----------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Host/FileSystem.h"10 11#include "lldb/Utility/DataBufferLLVM.h"12 13#include "llvm/Support/Errc.h"14#include "llvm/Support/Errno.h"15#include "llvm/Support/Error.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 <cerrno>22#include <climits>23#include <cstdarg>24#include <cstdio>25#include <fcntl.h>26 27#ifdef _WIN3228#include "lldb/Host/windows/windows.h"29#else30#include <sys/ioctl.h>31#include <sys/stat.h>32#include <termios.h>33#include <unistd.h>34#endif35 36#include <algorithm>37#include <fstream>38#include <memory>39#include <optional>40#include <vector>41 42using namespace lldb;43using namespace lldb_private;44using namespace llvm;45 46FileSystem &FileSystem::Instance() { return *InstanceImpl(); }47 48void FileSystem::Terminate() {49  lldbassert(InstanceImpl() && "Already terminated.");50  InstanceImpl().reset();51}52 53std::optional<FileSystem> &FileSystem::InstanceImpl() {54  static std::optional<FileSystem> g_fs;55  return g_fs;56}57 58vfs::directory_iterator FileSystem::DirBegin(const FileSpec &file_spec,59                                             std::error_code &ec) {60  if (!file_spec) {61    ec = std::error_code(static_cast<int>(errc::no_such_file_or_directory),62                         std::system_category());63    return {};64  }65  return DirBegin(file_spec.GetPath(), ec);66}67 68vfs::directory_iterator FileSystem::DirBegin(const Twine &dir,69                                             std::error_code &ec) {70  return m_fs->dir_begin(dir, ec);71}72 73llvm::ErrorOr<vfs::Status>74FileSystem::GetStatus(const FileSpec &file_spec) const {75  if (!file_spec)76    return std::error_code(static_cast<int>(errc::no_such_file_or_directory),77                           std::system_category());78  return GetStatus(file_spec.GetPath());79}80 81llvm::ErrorOr<vfs::Status> FileSystem::GetStatus(const Twine &path) const {82  return m_fs->status(path);83}84 85sys::TimePoint<>86FileSystem::GetModificationTime(const FileSpec &file_spec) const {87  if (!file_spec)88    return sys::TimePoint<>();89  return GetModificationTime(file_spec.GetPath());90}91 92sys::TimePoint<> FileSystem::GetModificationTime(const Twine &path) const {93  ErrorOr<vfs::Status> status = m_fs->status(path);94  if (!status)95    return sys::TimePoint<>();96  return status->getLastModificationTime();97}98 99uint64_t FileSystem::GetByteSize(const FileSpec &file_spec) const {100  if (!file_spec)101    return 0;102  return GetByteSize(file_spec.GetPath());103}104 105uint64_t FileSystem::GetByteSize(const Twine &path) const {106  ErrorOr<vfs::Status> status = m_fs->status(path);107  if (!status)108    return 0;109  return status->getSize();110}111 112uint32_t FileSystem::GetPermissions(const FileSpec &file_spec) const {113  return GetPermissions(file_spec.GetPath());114}115 116uint32_t FileSystem::GetPermissions(const FileSpec &file_spec,117                                    std::error_code &ec) const {118  if (!file_spec)119    return sys::fs::perms::perms_not_known;120  return GetPermissions(file_spec.GetPath(), ec);121}122 123uint32_t FileSystem::GetPermissions(const Twine &path) const {124  std::error_code ec;125  return GetPermissions(path, ec);126}127 128uint32_t FileSystem::GetPermissions(const Twine &path,129                                    std::error_code &ec) const {130  ErrorOr<vfs::Status> status = m_fs->status(path);131  if (!status) {132    ec = status.getError();133    return sys::fs::perms::perms_not_known;134  }135  return status->getPermissions();136}137 138bool FileSystem::Exists(const Twine &path) const { return m_fs->exists(path); }139 140bool FileSystem::Exists(const FileSpec &file_spec) const {141  return file_spec && Exists(file_spec.GetPath());142}143 144bool FileSystem::Readable(const Twine &path) const {145  return GetPermissions(path) & sys::fs::perms::all_read;146}147 148bool FileSystem::Readable(const FileSpec &file_spec) const {149  return file_spec && Readable(file_spec.GetPath());150}151 152bool FileSystem::IsDirectory(const Twine &path) const {153  ErrorOr<vfs::Status> status = m_fs->status(path);154  if (!status)155    return false;156  return status->isDirectory();157}158 159bool FileSystem::IsDirectory(const FileSpec &file_spec) const {160  return file_spec && IsDirectory(file_spec.GetPath());161}162 163bool FileSystem::IsLocal(const Twine &path) const {164  bool b = false;165  m_fs->isLocal(path, b);166  return b;167}168 169bool FileSystem::IsLocal(const FileSpec &file_spec) const {170  return file_spec && IsLocal(file_spec.GetPath());171}172 173void FileSystem::EnumerateDirectory(Twine path, bool find_directories,174                                    bool find_files, bool find_other,175                                    EnumerateDirectoryCallbackType callback,176                                    void *callback_baton) {177  std::error_code EC;178  vfs::recursive_directory_iterator Iter(*m_fs, path, EC);179  vfs::recursive_directory_iterator End;180  for (; Iter != End && !EC; Iter.increment(EC)) {181    const auto &Item = *Iter;182    ErrorOr<vfs::Status> Status = m_fs->status(Item.path());183    if (!Status)184      continue;185    if (!find_files && Status->isRegularFile())186      continue;187    if (!find_directories && Status->isDirectory())188      continue;189    if (!find_other && Status->isOther())190      continue;191 192    auto Result = callback(callback_baton, Status->getType(), Item.path());193    if (Result == eEnumerateDirectoryResultQuit)194      return;195    if (Result == eEnumerateDirectoryResultNext) {196      // Default behavior is to recurse. Opt out if the callback doesn't want197      // this behavior.198      Iter.no_push();199    }200  }201}202 203std::error_code FileSystem::MakeAbsolute(SmallVectorImpl<char> &path) const {204  return m_fs->makeAbsolute(path);205}206 207std::error_code FileSystem::MakeAbsolute(FileSpec &file_spec) const {208  SmallString<128> path;209  file_spec.GetPath(path, false);210 211  auto EC = MakeAbsolute(path);212  if (EC)213    return EC;214 215  FileSpec new_file_spec(path, file_spec.GetPathStyle());216  file_spec = new_file_spec;217  return {};218}219 220std::error_code FileSystem::GetRealPath(const Twine &path,221                                        SmallVectorImpl<char> &output) const {222  return m_fs->getRealPath(path, output);223}224 225void FileSystem::Resolve(SmallVectorImpl<char> &path) {226  if (path.empty())227    return;228 229  // Resolve tilde in path.230  SmallString<128> resolved(path.begin(), path.end());231  assert(m_tilde_resolver && "must initialize tilde resolver in constructor");232  m_tilde_resolver->ResolveFullPath(llvm::StringRef(path.begin(), path.size()),233                                    resolved);234 235  // Try making the path absolute if it exists.236  SmallString<128> absolute(resolved.begin(), resolved.end());237  MakeAbsolute(absolute);238 239  path.clear();240  if (Exists(absolute)) {241    path.append(absolute.begin(), absolute.end());242  } else {243    path.append(resolved.begin(), resolved.end());244  }245}246 247void FileSystem::Resolve(FileSpec &file_spec) {248  if (!file_spec)249    return;250 251  // Extract path from the FileSpec.252  SmallString<128> path;253  file_spec.GetPath(path);254 255  // Resolve the path.256  Resolve(path);257 258  // Update the FileSpec with the resolved path.259  if (file_spec.GetFilename().IsEmpty())260    file_spec.SetDirectory(path);261  else262    file_spec.SetPath(path);263}264 265template <typename T>266static std::unique_ptr<T> GetMemoryBuffer(const llvm::Twine &path,267                                          uint64_t size, uint64_t offset,268                                          bool is_volatile) {269  std::unique_ptr<T> buffer;270  if (size == 0) {271    auto buffer_or_error = T::getFile(path, is_volatile);272    if (!buffer_or_error)273      return nullptr;274    buffer = std::move(*buffer_or_error);275  } else {276    auto buffer_or_error = T::getFileSlice(path, size, offset, is_volatile);277    if (!buffer_or_error)278      return nullptr;279    buffer = std::move(*buffer_or_error);280  }281  return buffer;282}283 284std::shared_ptr<WritableDataBuffer>285FileSystem::CreateWritableDataBuffer(const llvm::Twine &path, uint64_t size,286                                     uint64_t offset) {287  const bool is_volatile = !IsLocal(path);288  auto buffer = GetMemoryBuffer<llvm::WritableMemoryBuffer>(path, size, offset,289                                                            is_volatile);290  if (!buffer)291    return {};292  return std::make_shared<WritableDataBufferLLVM>(std::move(buffer));293}294 295std::shared_ptr<DataBuffer>296FileSystem::CreateDataBuffer(const llvm::Twine &path, uint64_t size,297                             uint64_t offset) {298  const bool is_volatile = !IsLocal(path);299  auto buffer =300      GetMemoryBuffer<llvm::MemoryBuffer>(path, size, offset, is_volatile);301  if (!buffer)302    return {};303  return std::make_shared<DataBufferLLVM>(std::move(buffer));304}305 306std::shared_ptr<WritableDataBuffer>307FileSystem::CreateWritableDataBuffer(const FileSpec &file_spec, uint64_t size,308                                     uint64_t offset) {309  return CreateWritableDataBuffer(file_spec.GetPath(), size, offset);310}311 312std::shared_ptr<DataBuffer>313FileSystem::CreateDataBuffer(const FileSpec &file_spec, uint64_t size,314                             uint64_t offset) {315  return CreateDataBuffer(file_spec.GetPath(), size, offset);316}317 318bool FileSystem::ResolveExecutableLocation(FileSpec &file_spec) {319  // If the directory is set there's nothing to do.320  ConstString directory = file_spec.GetDirectory();321  if (directory)322    return false;323 324  // We cannot look for a file if there's no file name.325  ConstString filename = file_spec.GetFilename();326  if (!filename)327    return false;328 329  // Search for the file on the host.330  const std::string filename_str(filename.GetCString());331  llvm::ErrorOr<std::string> error_or_path =332      llvm::sys::findProgramByName(filename_str);333  if (!error_or_path)334    return false;335 336  // findProgramByName returns "." if it can't find the file.337  llvm::StringRef path = *error_or_path;338  llvm::StringRef parent = llvm::sys::path::parent_path(path);339  if (parent.empty() || parent == ".")340    return false;341 342  // Make sure that the result exists.343  FileSpec result(*error_or_path);344  if (!Exists(result))345    return false;346 347  file_spec = result;348  return true;349}350 351bool FileSystem::GetHomeDirectory(SmallVectorImpl<char> &path) const {352  if (!m_home_directory.empty()) {353    path.assign(m_home_directory.begin(), m_home_directory.end());354    return true;355  }356  return llvm::sys::path::home_directory(path);357}358 359bool FileSystem::GetHomeDirectory(FileSpec &file_spec) const {360  SmallString<128> home_dir;361  if (!GetHomeDirectory(home_dir))362    return false;363  file_spec.SetPath(home_dir);364  return true;365}366 367static int OpenWithFS(const FileSystem &fs, const char *path, int flags,368                      int mode) {369  return const_cast<FileSystem &>(fs).Open(path, flags, mode);370}371 372static int GetOpenFlags(File::OpenOptions options) {373  int open_flags = 0;374  File::OpenOptions rw =375      options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |376                 File::eOpenOptionReadWrite);377  if (rw == File::eOpenOptionWriteOnly || rw == File::eOpenOptionReadWrite) {378    if (rw == File::eOpenOptionReadWrite)379      open_flags |= O_RDWR;380    else381      open_flags |= O_WRONLY;382 383    if (options & File::eOpenOptionAppend)384      open_flags |= O_APPEND;385 386    if (options & File::eOpenOptionTruncate)387      open_flags |= O_TRUNC;388 389    if (options & File::eOpenOptionCanCreate)390      open_flags |= O_CREAT;391 392    if (options & File::eOpenOptionCanCreateNewOnly)393      open_flags |= O_CREAT | O_EXCL;394  } else if (rw == File::eOpenOptionReadOnly) {395    open_flags |= O_RDONLY;396 397#ifndef _WIN32398    if (options & File::eOpenOptionDontFollowSymlinks)399      open_flags |= O_NOFOLLOW;400#endif401  }402 403#ifndef _WIN32404  if (options & File::eOpenOptionNonBlocking)405    open_flags |= O_NONBLOCK;406  if (options & File::eOpenOptionCloseOnExec)407    open_flags |= O_CLOEXEC;408#else409  open_flags |= O_BINARY;410#endif411 412  return open_flags;413}414 415static mode_t GetOpenMode(uint32_t permissions) {416  mode_t mode = 0;417  if (permissions & lldb::eFilePermissionsUserRead)418    mode |= S_IRUSR;419  if (permissions & lldb::eFilePermissionsUserWrite)420    mode |= S_IWUSR;421  if (permissions & lldb::eFilePermissionsUserExecute)422    mode |= S_IXUSR;423  if (permissions & lldb::eFilePermissionsGroupRead)424    mode |= S_IRGRP;425  if (permissions & lldb::eFilePermissionsGroupWrite)426    mode |= S_IWGRP;427  if (permissions & lldb::eFilePermissionsGroupExecute)428    mode |= S_IXGRP;429  if (permissions & lldb::eFilePermissionsWorldRead)430    mode |= S_IROTH;431  if (permissions & lldb::eFilePermissionsWorldWrite)432    mode |= S_IWOTH;433  if (permissions & lldb::eFilePermissionsWorldExecute)434    mode |= S_IXOTH;435  return mode;436}437 438Expected<FileUP> FileSystem::Open(const FileSpec &file_spec,439                                  File::OpenOptions options,440                                  uint32_t permissions, bool should_close_fd) {441  const int open_flags = GetOpenFlags(options);442  const mode_t open_mode =443      (open_flags & O_CREAT) ? GetOpenMode(permissions) : 0;444 445  auto path = file_spec.GetPath();446 447  int descriptor = llvm::sys::RetryAfterSignal(448      -1, OpenWithFS, *this, path.c_str(), open_flags, open_mode);449 450  if (!File::DescriptorIsValid(descriptor))451    return llvm::errorCodeToError(452        std::error_code(errno, std::system_category()));453 454  auto file = std::unique_ptr<File>(455      new NativeFile(descriptor, options, should_close_fd));456  assert(file->IsValid());457  return std::move(file);458}459 460void FileSystem::SetHomeDirectory(std::string home_directory) {461  m_home_directory = std::move(home_directory);462}463 464Status FileSystem::RemoveFile(const FileSpec &file_spec) {465  return RemoveFile(file_spec.GetPath());466}467 468Status FileSystem::RemoveFile(const llvm::Twine &path) {469  return Status(llvm::sys::fs::remove(path));470}471