diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 | 
| commit | e6d1592492a3a379186bfb02bd0f4eda0669c0d5 (patch) | |
| tree | 599ab169a01f1c86eda9adc774edaedde2f2db5b /lib/Support/VirtualFileSystem.cpp | |
| parent | 1a56a5ead7a2e84bee8240f5f6b033b5f1707154 (diff) | |
Notes
Diffstat (limited to 'lib/Support/VirtualFileSystem.cpp')
| -rw-r--r-- | lib/Support/VirtualFileSystem.cpp | 159 | 
1 files changed, 102 insertions, 57 deletions
| diff --git a/lib/Support/VirtualFileSystem.cpp b/lib/Support/VirtualFileSystem.cpp index f2a8a1bb27af..5d3480e97148 100644 --- a/lib/Support/VirtualFileSystem.cpp +++ b/lib/Support/VirtualFileSystem.cpp @@ -1,9 +1,8 @@  //===- VirtualFileSystem.cpp - Virtual File System Layer ------------------===//  // -//                     The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception  //  //===----------------------------------------------------------------------===//  // @@ -57,8 +56,10 @@  using namespace llvm;  using namespace llvm::vfs; +using llvm::sys::fs::file_t;  using llvm::sys::fs::file_status;  using llvm::sys::fs::file_type; +using llvm::sys::fs::kInvalidFile;  using llvm::sys::fs::perms;  using llvm::sys::fs::UniqueID; @@ -67,19 +68,19 @@ Status::Status(const file_status &Status)        User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()),        Type(Status.type()), Perms(Status.permissions()) {} -Status::Status(StringRef Name, UniqueID UID, sys::TimePoint<> MTime, +Status::Status(const Twine &Name, UniqueID UID, sys::TimePoint<> MTime,                 uint32_t User, uint32_t Group, uint64_t Size, file_type Type,                 perms Perms) -    : Name(Name), UID(UID), MTime(MTime), User(User), Group(Group), Size(Size), -      Type(Type), Perms(Perms) {} +    : Name(Name.str()), UID(UID), MTime(MTime), User(User), Group(Group), +      Size(Size), Type(Type), Perms(Perms) {} -Status Status::copyWithNewName(const Status &In, StringRef NewName) { +Status Status::copyWithNewName(const Status &In, const Twine &NewName) {    return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),                  In.getUser(), In.getGroup(), In.getSize(), In.getType(),                  In.getPermissions());  } -Status Status::copyWithNewName(const file_status &In, StringRef NewName) { +Status Status::copyWithNewName(const file_status &In, const Twine &NewName) {    return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),                  In.getUser(), In.getGroup(), In.getSize(), In.type(),                  In.permissions()); @@ -171,15 +172,15 @@ namespace {  class RealFile : public File {    friend class RealFileSystem; -  int FD; +  file_t FD;    Status S;    std::string RealName; -  RealFile(int FD, StringRef NewName, StringRef NewRealPathName) +  RealFile(file_t FD, StringRef NewName, StringRef NewRealPathName)        : FD(FD), S(NewName, {}, {}, {}, {}, {},                    llvm::sys::fs::file_type::status_error, {}),          RealName(NewRealPathName.str()) { -    assert(FD >= 0 && "Invalid or inactive file descriptor"); +    assert(FD != kInvalidFile && "Invalid or inactive file descriptor");    }  public: @@ -199,7 +200,7 @@ public:  RealFile::~RealFile() { close(); }  ErrorOr<Status> RealFile::status() { -  assert(FD != -1 && "cannot stat closed file"); +  assert(FD != kInvalidFile && "cannot stat closed file");    if (!S.isStatusKnown()) {      file_status RealStatus;      if (std::error_code EC = sys::fs::status(FD, RealStatus)) @@ -216,22 +217,41 @@ ErrorOr<std::string> RealFile::getName() {  ErrorOr<std::unique_ptr<MemoryBuffer>>  RealFile::getBuffer(const Twine &Name, int64_t FileSize,                      bool RequiresNullTerminator, bool IsVolatile) { -  assert(FD != -1 && "cannot get buffer for closed file"); +  assert(FD != kInvalidFile && "cannot get buffer for closed file");    return MemoryBuffer::getOpenFile(FD, Name, FileSize, RequiresNullTerminator,                                     IsVolatile);  }  std::error_code RealFile::close() { -  std::error_code EC = sys::Process::SafelyCloseFileDescriptor(FD); -  FD = -1; +  std::error_code EC = sys::fs::closeFile(FD); +  FD = kInvalidFile;    return EC;  }  namespace { -/// The file system according to your operating system. +/// A file system according to your operating system. +/// This may be linked to the process's working directory, or maintain its own. +/// +/// Currently, its own working directory is emulated by storing the path and +/// sending absolute paths to llvm::sys::fs:: functions. +/// A more principled approach would be to push this down a level, modelling +/// the working dir as an llvm::sys::fs::WorkingDir or similar. +/// This would enable the use of openat()-style functions on some platforms.  class RealFileSystem : public FileSystem {  public: +  explicit RealFileSystem(bool LinkCWDToProcess) { +    if (!LinkCWDToProcess) { +      SmallString<128> PWD, RealPWD; +      if (llvm::sys::fs::current_path(PWD)) +        return; // Awful, but nothing to do here. +      if (llvm::sys::fs::real_path(PWD, RealPWD)) +        WD = {PWD, PWD}; +      else +        WD = {PWD, RealPWD}; +    } +  } +    ErrorOr<Status> status(const Twine &Path) override;    ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;    directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override; @@ -243,72 +263,95 @@ public:                                SmallVectorImpl<char> &Output) const override;  private: -  mutable std::mutex CWDMutex; -  mutable std::string CWDCache; +  // If this FS has its own working dir, use it to make Path absolute. +  // The returned twine is safe to use as long as both Storage and Path live. +  Twine adjustPath(const Twine &Path, SmallVectorImpl<char> &Storage) const { +    if (!WD) +      return Path; +    Path.toVector(Storage); +    sys::fs::make_absolute(WD->Resolved, Storage); +    return Storage; +  } + +  struct WorkingDirectory { +    // The current working directory, without symlinks resolved. (echo $PWD). +    SmallString<128> Specified; +    // The current working directory, with links resolved. (readlink .). +    SmallString<128> Resolved; +  }; +  Optional<WorkingDirectory> WD;  };  } // namespace  ErrorOr<Status> RealFileSystem::status(const Twine &Path) { +  SmallString<256> Storage;    sys::fs::file_status RealStatus; -  if (std::error_code EC = sys::fs::status(Path, RealStatus)) +  if (std::error_code EC = +          sys::fs::status(adjustPath(Path, Storage), RealStatus))      return EC; -  return Status::copyWithNewName(RealStatus, Path.str()); +  return Status::copyWithNewName(RealStatus, Path);  }  ErrorOr<std::unique_ptr<File>>  RealFileSystem::openFileForRead(const Twine &Name) { -  int FD; -  SmallString<256> RealName; -  if (std::error_code EC = -          sys::fs::openFileForRead(Name, FD, sys::fs::OF_None, &RealName)) -    return EC; -  return std::unique_ptr<File>(new RealFile(FD, Name.str(), RealName.str())); +  SmallString<256> RealName, Storage; +  Expected<file_t> FDOrErr = sys::fs::openNativeFileForRead( +      adjustPath(Name, Storage), sys::fs::OF_None, &RealName); +  if (!FDOrErr) +    return errorToErrorCode(FDOrErr.takeError()); +  return std::unique_ptr<File>( +      new RealFile(*FDOrErr, Name.str(), RealName.str()));  }  llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory() const { -  std::lock_guard<std::mutex> Lock(CWDMutex); -  if (!CWDCache.empty()) -    return CWDCache; -  SmallString<256> Dir; +  if (WD) +    return WD->Specified.str(); + +  SmallString<128> Dir;    if (std::error_code EC = llvm::sys::fs::current_path(Dir))      return EC; -  CWDCache = Dir.str(); -  return CWDCache; +  return Dir.str();  }  std::error_code RealFileSystem::setCurrentWorkingDirectory(const Twine &Path) { -  // FIXME: chdir is thread hostile; on the other hand, creating the same -  // behavior as chdir is complex: chdir resolves the path once, thus -  // guaranteeing that all subsequent relative path operations work -  // on the same path the original chdir resulted in. This makes a -  // difference for example on network filesystems, where symlinks might be -  // switched during runtime of the tool. Fixing this depends on having a -  // file system abstraction that allows openat() style interactions. -  if (auto EC = llvm::sys::fs::set_current_path(Path)) -    return EC; - -  // Invalidate cache. -  std::lock_guard<std::mutex> Lock(CWDMutex); -  CWDCache.clear(); +  if (!WD) +    return llvm::sys::fs::set_current_path(Path); + +  SmallString<128> Absolute, Resolved, Storage; +  adjustPath(Path, Storage).toVector(Absolute); +  bool IsDir; +  if (auto Err = llvm::sys::fs::is_directory(Absolute, IsDir)) +    return Err; +  if (!IsDir) +    return std::make_error_code(std::errc::not_a_directory); +  if (auto Err = llvm::sys::fs::real_path(Absolute, Resolved)) +    return Err; +  WD = {Absolute, Resolved};    return std::error_code();  }  std::error_code RealFileSystem::isLocal(const Twine &Path, bool &Result) { -  return llvm::sys::fs::is_local(Path, Result); +  SmallString<256> Storage; +  return llvm::sys::fs::is_local(adjustPath(Path, Storage), Result);  }  std::error_code  RealFileSystem::getRealPath(const Twine &Path,                              SmallVectorImpl<char> &Output) const { -  return llvm::sys::fs::real_path(Path, Output); +  SmallString<256> Storage; +  return llvm::sys::fs::real_path(adjustPath(Path, Storage), Output);  }  IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() { -  static IntrusiveRefCntPtr<FileSystem> FS = new RealFileSystem(); +  static IntrusiveRefCntPtr<FileSystem> FS(new RealFileSystem(true));    return FS;  } +std::unique_ptr<FileSystem> vfs::createPhysicalFileSystem() { +  return llvm::make_unique<RealFileSystem>(false); +} +  namespace {  class RealFSDirIter : public llvm::vfs::detail::DirIterImpl { @@ -334,7 +377,9 @@ public:  directory_iterator RealFileSystem::dir_begin(const Twine &Dir,                                               std::error_code &EC) { -  return directory_iterator(std::make_shared<RealFSDirIter>(Dir, EC)); +  SmallString<128> Storage; +  return directory_iterator( +      std::make_shared<RealFSDirIter>(adjustPath(Dir, Storage), EC));  }  //===-----------------------------------------------------------------------===/ @@ -511,7 +556,7 @@ public:    /// Return the \p Status for this node. \p RequestedName should be the name    /// through which the caller referred to this node. It will override    /// \p Status::Name in the return value, to mimic the behavior of \p RealFile. -  Status getStatus(StringRef RequestedName) const { +  Status getStatus(const Twine &RequestedName) const {      return Status::copyWithNewName(Stat, RequestedName);    }    llvm::MemoryBuffer *getBuffer() const { return Buffer.get(); } @@ -585,7 +630,7 @@ public:    /// Return the \p Status for this node. \p RequestedName should be the name    /// through which the caller referred to this node. It will override    /// \p Status::Name in the return value, to mimic the behavior of \p RealFile. -  Status getStatus(StringRef RequestedName) const { +  Status getStatus(const Twine &RequestedName) const {      return Status::copyWithNewName(Stat, RequestedName);    }    InMemoryNode *getChild(StringRef Name) { @@ -619,7 +664,7 @@ public:  };  namespace { -Status getNodeStatus(const InMemoryNode *Node, StringRef RequestedName) { +Status getNodeStatus(const InMemoryNode *Node, const Twine &RequestedName) {    if (auto Dir = dyn_cast<detail::InMemoryDirectory>(Node))      return Dir->getStatus(RequestedName);    if (auto File = dyn_cast<detail::InMemoryFile>(Node)) @@ -817,7 +862,7 @@ bool InMemoryFileSystem::addHardLink(const Twine &FromPath,  llvm::ErrorOr<Status> InMemoryFileSystem::status(const Twine &Path) {    auto Node = lookupInMemoryNode(*this, Root.get(), Path);    if (Node) -    return detail::getNodeStatus(*Node, Path.str()); +    return detail::getNodeStatus(*Node, Path);    return Node.getError();  } @@ -1237,7 +1282,7 @@ class llvm::vfs::RedirectingFileSystemParser {          EntryArrayContents;      std::string ExternalContentsPath;      std::string Name; -    yaml::Node *NameValueNode; +    yaml::Node *NameValueNode = nullptr;      auto UseExternalName =          RedirectingFileSystem::RedirectingFileEntry::NK_NotSet;      RedirectingFileSystem::EntryKind Kind; @@ -1633,7 +1678,7 @@ static Status getRedirectedFileStatus(const Twine &Path, bool UseExternalNames,                                        Status ExternalStatus) {    Status S = ExternalStatus;    if (!UseExternalNames) -    S = Status::copyWithNewName(S, Path.str()); +    S = Status::copyWithNewName(S, Path);    S.IsVFSMapped = true;    return S;  } @@ -1650,7 +1695,7 @@ ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path,      return S;    } else { // directory      auto *DE = cast<RedirectingFileSystem::RedirectingDirectoryEntry>(E); -    return Status::copyWithNewName(DE->getStatus(), Path.str()); +    return Status::copyWithNewName(DE->getStatus(), Path);    }  } | 
