Index: llvm/trunk/lib/Support/VirtualFileSystem.cpp =================================================================== --- llvm/trunk/lib/Support/VirtualFileSystem.cpp +++ llvm/trunk/lib/Support/VirtualFileSystem.cpp @@ -1164,14 +1164,14 @@ /// Looks up the path [Start, End) in \p From, possibly /// recursing into the contents of \p From if it is a directory. ErrorOr lookupPath(sys::path::const_iterator Start, - sys::path::const_iterator End, Entry *From); + sys::path::const_iterator End, Entry *From) const; /// Get the status of a given an \c Entry. ErrorOr status(const Twine &Path, Entry *E); public: /// Looks up \p Path in \c Roots. - ErrorOr lookupPath(const Twine &Path); + ErrorOr lookupPath(const Twine &Path) const; /// Parses \p Buffer, which is expected to be in YAML format and /// returns a virtual file system representing its contents. @@ -1183,6 +1183,9 @@ ErrorOr status(const Twine &Path) override; ErrorOr> openFileForRead(const Twine &Path) override; + std::error_code getRealPath(const Twine &Path, + SmallVectorImpl &Output) const override; + llvm::ErrorOr getCurrentWorkingDirectory() const override { return ExternalFS->getCurrentWorkingDirectory(); } @@ -1726,7 +1729,7 @@ return FS.release(); } -ErrorOr RedirectingFileSystem::lookupPath(const Twine &Path_) { +ErrorOr RedirectingFileSystem::lookupPath(const Twine &Path_) const { SmallString<256> Path; Path_.toVector(Path); @@ -1757,7 +1760,8 @@ ErrorOr RedirectingFileSystem::lookupPath(sys::path::const_iterator Start, - sys::path::const_iterator End, Entry *From) { + sys::path::const_iterator End, + Entry *From) const { #ifndef _WIN32 assert(!isTraversalComponent(*Start) && !isTraversalComponent(From->getName()) && @@ -1890,6 +1894,27 @@ llvm::make_unique(std::move(*Result), S)); } +std::error_code +RedirectingFileSystem::getRealPath(const Twine &Path, + SmallVectorImpl &Output) const { + ErrorOr Result = lookupPath(Path); + if (!Result) { + if (IsFallthrough && + Result.getError() == llvm::errc::no_such_file_or_directory) { + return ExternalFS->getRealPath(Path, Output); + } + return Result.getError(); + } + + if (auto *F = dyn_cast(*Result)) { + return ExternalFS->getRealPath(F->getExternalContentsPath(), Output); + } + // Even if there is a directory entry, fall back to ExternalFS if allowed, + // because directories don't have a single external contents path. + return IsFallthrough ? ExternalFS->getRealPath(Path, Output) + : llvm::errc::invalid_argument; +} + IntrusiveRefCntPtr vfs::getVFSFromYAML(std::unique_ptr Buffer, SourceMgr::DiagHandlerTy DiagHandler, Index: llvm/trunk/unittests/Support/VirtualFileSystemTest.cpp =================================================================== --- llvm/trunk/unittests/Support/VirtualFileSystemTest.cpp +++ llvm/trunk/unittests/Support/VirtualFileSystemTest.cpp @@ -1775,3 +1775,49 @@ checkContents(FS->dir_begin("//root/foo", EC), {"//root/foo/a", "//root/foo/b"}); } + +TEST_F(VFSFromYAMLTest, GetRealPath) { + IntrusiveRefCntPtr Lower(new DummyFileSystem()); + Lower->addDirectory("/dir/"); + Lower->addRegularFile("/foo"); + Lower->addSymlink("/link"); + IntrusiveRefCntPtr FS = getFromYAMLString( + "{ 'use-external-names': false,\n" + " 'roots': [\n" + "{\n" + " 'type': 'directory',\n" + " 'name': '/root/',\n" + " 'contents': [ {\n" + " 'type': 'file',\n" + " 'name': 'bar',\n" + " 'external-contents': '/link'\n" + " }\n" + " ]\n" + "},\n" + "{\n" + " 'type': 'directory',\n" + " 'name': '/dir/',\n" + " 'contents': []\n" + "}\n" + "]\n" + "}", + Lower); + ASSERT_TRUE(FS.get() != nullptr); + + // Regular file present in underlying file system. + SmallString<16> RealPath; + EXPECT_FALSE(FS->getRealPath("/foo", RealPath)); + EXPECT_EQ(RealPath.str(), "/foo"); + + // File present in YAML pointing to symlink in underlying file system. + EXPECT_FALSE(FS->getRealPath("/root/bar", RealPath)); + EXPECT_EQ(RealPath.str(), "/symlink"); + + // Directories should fall back to the underlying file system is possible. + EXPECT_FALSE(FS->getRealPath("/dir/", RealPath)); + EXPECT_EQ(RealPath.str(), "/dir/"); + + // Try a non-existing file. + EXPECT_EQ(FS->getRealPath("/non_existing", RealPath), + errc::no_such_file_or_directory); +}