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);
+}