diff options
Diffstat (limited to 'llvm/lib/Support/VirtualFileSystem.cpp')
-rw-r--r-- | llvm/lib/Support/VirtualFileSystem.cpp | 103 |
1 files changed, 73 insertions, 30 deletions
diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp index afa02752031..1f5c622cfaa 100644 --- a/llvm/lib/Support/VirtualFileSystem.cpp +++ b/llvm/lib/Support/VirtualFileSystem.cpp @@ -228,9 +228,28 @@ std::error_code RealFile::close() { 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; @@ -242,15 +261,32 @@ 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()); } @@ -258,56 +294,61 @@ ErrorOr<Status> RealFileSystem::status(const Twine &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)) + SmallString<256> RealName, Storage; + if (std::error_code EC = sys::fs::openFileForRead( + adjustPath(Name, Storage), FD, sys::fs::OF_None, &RealName)) return EC; return std::unique_ptr<File>(new RealFile(FD, 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 { @@ -333,7 +374,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)); } //===-----------------------------------------------------------------------===/ |