Author: d0k Date: Mon Oct 5 08:55:20 2015 New Revision: 249316 URL: http://llvm.org/viewvc/llvm-project?rev=249316&view=rev Log: [VFS] Add working directories to every virtual file system.
For RealFileSystem this is getcwd()/chdir(), the synthetic file systems can make up one for themselves. OverlayFileSystem now synchronizes the working directories when a new FS is added to the overlay or the overlay working directory is set. This allows purely artificial file systems that have zero ties to the underlying disks. Differential Revision: http://reviews.llvm.org/D13430 Modified: cfe/trunk/include/clang/Basic/VirtualFileSystem.h cfe/trunk/lib/Basic/VirtualFileSystem.cpp cfe/trunk/unittests/Basic/VirtualFileSystemTest.cpp Modified: cfe/trunk/include/clang/Basic/VirtualFileSystem.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/VirtualFileSystem.h?rev=249316&r1=249315&r2=249316&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/VirtualFileSystem.h (original) +++ cfe/trunk/include/clang/Basic/VirtualFileSystem.h Mon Oct 5 08:55:20 2015 @@ -199,6 +199,25 @@ public: /// \note The 'end' iterator is directory_iterator(). virtual directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) = 0; + + /// Set the working directory. This will affect all following operations on + /// this file system and may propagate down for nested file systems. + virtual std::error_code setCurrentWorkingDirectory(const Twine &Path) = 0; + /// Get the working directory of this file system. + virtual llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const = 0; + + /// Make \a Path an absolute path. + /// + /// Makes \a Path absolute using the current directory if it is not already. + /// An empty \a Path will result in the current directory. + /// + /// /absolute/path => /absolute/path + /// relative/../path => <current-directory>/relative/../path + /// + /// \param Path A path that is modified to be an absolute path. + /// \returns success if \a path has been made absolute, otherwise a + /// platform-specific error_code. + std::error_code makeAbsolute(SmallVectorImpl<char> &Path) const; }; /// \brief Gets an \p vfs::FileSystem for the 'real' file system, as seen by @@ -230,6 +249,8 @@ public: llvm::ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override; directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override; + llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override; + std::error_code setCurrentWorkingDirectory(const Twine &Path) override; typedef FileSystemList::reverse_iterator iterator; @@ -248,6 +269,7 @@ class InMemoryDirectory; /// An in-memory file system. class InMemoryFileSystem : public FileSystem { std::unique_ptr<detail::InMemoryDirectory> Root; + std::string WorkingDirectory; public: InMemoryFileSystem(); @@ -260,6 +282,13 @@ public: llvm::ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override; directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override; + llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override { + return WorkingDirectory; + } + std::error_code setCurrentWorkingDirectory(const Twine &Path) override { + WorkingDirectory = Path.str(); + return std::error_code(); + } }; /// \brief Get a globally unique ID for a virtual file or directory. Modified: cfe/trunk/lib/Basic/VirtualFileSystem.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/VirtualFileSystem.cpp?rev=249316&r1=249315&r2=249316&view=diff ============================================================================== --- cfe/trunk/lib/Basic/VirtualFileSystem.cpp (original) +++ cfe/trunk/lib/Basic/VirtualFileSystem.cpp Mon Oct 5 08:55:20 2015 @@ -89,6 +89,14 @@ FileSystem::getBufferForFile(const llvm: return (*F)->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile); } +std::error_code FileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const { + auto WorkingDir = getCurrentWorkingDirectory(); + if (!WorkingDir) + return WorkingDir.getError(); + + return llvm::sys::fs::make_absolute(WorkingDir.get(), Path); +} + //===-----------------------------------------------------------------------===/ // RealFileSystem implementation //===-----------------------------------------------------------------------===/ @@ -160,6 +168,9 @@ public: 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; + + llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override; + std::error_code setCurrentWorkingDirectory(const Twine &Path) override; }; } // end anonymous namespace @@ -178,6 +189,28 @@ RealFileSystem::openFileForRead(const Tw return std::unique_ptr<File>(new RealFile(FD, Name.str())); } +llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory() const { + SmallString<256> Dir; + if (std::error_code EC = llvm::sys::fs::current_path(Dir)) + return EC; + return Dir.str().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. + SmallString<256> Storage; + StringRef Dir = Path.toNullTerminatedStringRef(Storage); + if (int Err = ::chdir(Dir.data())) + return std::error_code(Err, std::generic_category()); + return std::error_code(); +} + IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() { static IntrusiveRefCntPtr<FileSystem> FS = new RealFileSystem(); return FS; @@ -224,11 +257,14 @@ directory_iterator RealFileSystem::dir_b // OverlayFileSystem implementation //===-----------------------------------------------------------------------===/ OverlayFileSystem::OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> BaseFS) { - pushOverlay(BaseFS); + FSList.push_back(BaseFS); } void OverlayFileSystem::pushOverlay(IntrusiveRefCntPtr<FileSystem> FS) { FSList.push_back(FS); + // Synchronize added file systems by duplicating the working directory from + // the first one in the list. + FS->setCurrentWorkingDirectory(getCurrentWorkingDirectory().get()); } ErrorOr<Status> OverlayFileSystem::status(const Twine &Path) { @@ -252,6 +288,19 @@ OverlayFileSystem::openFileForRead(const return make_error_code(llvm::errc::no_such_file_or_directory); } +llvm::ErrorOr<std::string> +OverlayFileSystem::getCurrentWorkingDirectory() const { + // All file systems are synchronized, just take the first working directory. + return FSList.front()->getCurrentWorkingDirectory(); +} +std::error_code +OverlayFileSystem::setCurrentWorkingDirectory(const Twine &Path) { + for (auto &FS : FSList) + if (std::error_code EC = FS->setCurrentWorkingDirectory(Path)) + return EC; + return std::error_code(); +} + clang::vfs::detail::DirIterImpl::~DirIterImpl() { } namespace { @@ -431,7 +480,7 @@ void InMemoryFileSystem::addFile(const T P.toVector(Path); // Fix up relative paths. This just prepends the current working directory. - std::error_code EC = sys::fs::make_absolute(Path); + std::error_code EC = makeAbsolute(Path); assert(!EC); (void)EC; @@ -473,12 +522,13 @@ void InMemoryFileSystem::addFile(const T } static ErrorOr<detail::InMemoryNode *> -lookupInMemoryNode(detail::InMemoryDirectory *Dir, const Twine &P) { +lookupInMemoryNode(const InMemoryFileSystem &FS, detail::InMemoryDirectory *Dir, + const Twine &P) { SmallString<128> Path; P.toVector(Path); // Fix up relative paths. This just prepends the current working directory. - std::error_code EC = sys::fs::make_absolute(Path); + std::error_code EC = FS.makeAbsolute(Path); assert(!EC); (void)EC; @@ -504,7 +554,7 @@ lookupInMemoryNode(detail::InMemoryDirec } llvm::ErrorOr<Status> InMemoryFileSystem::status(const Twine &Path) { - auto Node = lookupInMemoryNode(Root.get(), Path); + auto Node = lookupInMemoryNode(*this, Root.get(), Path); if (Node) return (*Node)->getStatus(); return Node.getError(); @@ -512,7 +562,7 @@ llvm::ErrorOr<Status> InMemoryFileSystem llvm::ErrorOr<std::unique_ptr<File>> InMemoryFileSystem::openFileForRead(const Twine &Path) { - auto Node = lookupInMemoryNode(Root.get(), Path); + auto Node = lookupInMemoryNode(*this, Root.get(), Path); if (!Node) return Node.getError(); @@ -551,7 +601,7 @@ public: directory_iterator InMemoryFileSystem::dir_begin(const Twine &Dir, std::error_code &EC) { - auto Node = lookupInMemoryNode(Root.get(), Dir); + auto Node = lookupInMemoryNode(*this, Root.get(), Dir); if (!Node) { EC = Node.getError(); return directory_iterator(std::make_shared<InMemoryDirIterator>()); @@ -742,6 +792,13 @@ public: ErrorOr<Status> status(const Twine &Path) override; ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override; + llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override { + return ExternalFS->getCurrentWorkingDirectory(); + } + std::error_code setCurrentWorkingDirectory(const Twine &Path) override { + return ExternalFS->setCurrentWorkingDirectory(Path); + } + directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override{ ErrorOr<Entry *> E = lookupPath(Dir); if (!E) { @@ -1114,7 +1171,7 @@ ErrorOr<Entry *> VFSFromYAML::lookupPath Path_.toVector(Path); // Handle relative paths - if (std::error_code EC = sys::fs::make_absolute(Path)) + if (std::error_code EC = makeAbsolute(Path)) return EC; if (Path.empty()) Modified: cfe/trunk/unittests/Basic/VirtualFileSystemTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Basic/VirtualFileSystemTest.cpp?rev=249316&r1=249315&r2=249316&view=diff ============================================================================== --- cfe/trunk/unittests/Basic/VirtualFileSystemTest.cpp (original) +++ cfe/trunk/unittests/Basic/VirtualFileSystemTest.cpp Mon Oct 5 08:55:20 2015 @@ -43,6 +43,12 @@ public: openFileForRead(const Twine &Path) override { llvm_unreachable("unimplemented"); } + llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override { + return std::string(); + } + std::error_code setCurrentWorkingDirectory(const Twine &Path) override { + return std::error_code(); + } struct DirIterImpl : public clang::vfs::detail::DirIterImpl { std::map<std::string, vfs::Status> &FilesAndDirs; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits