Index: llvm/lib/Support/VirtualFileSystem.cpp =================================================================== --- llvm/lib/Support/VirtualFileSystem.cpp +++ llvm/lib/Support/VirtualFileSystem.cpp @@ -1682,14 +1682,23 @@ if (std::error_code EC = makeAbsolute(Path)) return EC; + // Now that we have an absolute path we can examine it to determine the + // path style. + sys::path::Style path_style = sys::path::Style::native; + if (sys::path::is_absolute(Path, sys::path::Style::posix)) { + path_style = sys::path::Style::posix; + } else if (sys::path::is_absolute(Path, sys::path::Style::windows)) { + path_style = sys::path::Style::windows; + } + // Canonicalize path by removing ".", "..", "./", components. This is // a VFS request, do not bother about symlinks in the path components // but canonicalize in order to perform the correct entry search. - Path = canonicalize(Path); + llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true, path_style); if (Path.empty()) return make_error_code(llvm::errc::invalid_argument); - sys::path::const_iterator Start = sys::path::begin(Path); + sys::path::const_iterator Start = sys::path::begin(Path, path_style); sys::path::const_iterator End = sys::path::end(Path); for (const auto &Root : Roots) { ErrorOr Result = Index: llvm/unittests/Support/VirtualFileSystemTest.cpp =================================================================== --- llvm/unittests/Support/VirtualFileSystemTest.cpp +++ llvm/unittests/Support/VirtualFileSystemTest.cpp @@ -2188,3 +2188,93 @@ Status = FS->status("foo/a"); ASSERT_TRUE(Status.getError()); } + +TEST_F(VFSFromYAMLTest, BackslashWindowsPath) { + IntrusiveRefCntPtr Lower(new DummyFileSystem()); + Lower->addRegularFile("c:\\root\\foo\\bar\\a"); + IntrusiveRefCntPtr FS = getFromYAMLString( + "{ 'roots': [\n" + "{\n" + " 'type': 'directory',\n" + " 'name': 'c:\\root\\',\n" + " 'contents': [ {\n" + " 'type': 'file',\n" + " 'name': 'file1',\n" + " 'external-contents': 'c:\\root\\foo\\bar\\a'\n" + " }\n" + " ]\n" + "}\n" + "]\n" + "}", + Lower); + ASSERT_TRUE(FS.get() != nullptr); + + IntrusiveRefCntPtr O( + new vfs::OverlayFileSystem(Lower)); + O->pushOverlay(FS); + + ErrorOr S = O->status("c:\\root\\foo\\..\\file1"); + ASSERT_FALSE(S.getError()); + EXPECT_EQ("c:\\root\\foo\\bar\\a", S->getName()); + EXPECT_TRUE(S->IsVFSMapped); + + S = O->status("c:/root/foo/../file1"); + ASSERT_FALSE(S.getError()); + EXPECT_EQ("c:\\root\\foo\\bar\\a", S->getName()); + EXPECT_TRUE(S->IsVFSMapped); + + S = O->status("c:/root/foo\\..\\file1"); + ASSERT_FALSE(S.getError()); + EXPECT_EQ("c:\\root\\foo\\bar\\a", S->getName()); + EXPECT_TRUE(S->IsVFSMapped); + + S = O->status("c:\\root\\foo/../file1"); + ASSERT_FALSE(S.getError()); + EXPECT_EQ("c:\\root\\foo\\bar\\a", S->getName()); + EXPECT_TRUE(S->IsVFSMapped); +} + +TEST_F(VFSFromYAMLTest, ForwardslashWindowsPath) { + IntrusiveRefCntPtr Lower(new DummyFileSystem()); + Lower->addRegularFile("c:/root/foo/bar/a"); + IntrusiveRefCntPtr FS = getFromYAMLString( + "{ 'roots': [\n" + "{\n" + " 'type': 'directory',\n" + " 'name': 'c:/root/',\n" + " 'contents': [ {\n" + " 'type': 'file',\n" + " 'name': 'file1',\n" + " 'external-contents': 'c:/root/foo/bar/a'\n" + " }\n" + " ]\n" + "}\n" + "]\n" + "}", + Lower); + ASSERT_TRUE(FS.get() != nullptr); + + IntrusiveRefCntPtr O( + new vfs::OverlayFileSystem(Lower)); + O->pushOverlay(FS); + + ErrorOr S = O->status("c:\\root\\foo\\..\\file1"); + ASSERT_FALSE(S.getError()); + EXPECT_EQ("c:/root/foo/bar/a", S->getName()); + EXPECT_TRUE(S->IsVFSMapped); + + S = O->status("c:/root/foo/../file1"); + ASSERT_FALSE(S.getError()); + EXPECT_EQ("c:/root/foo/bar/a", S->getName()); + EXPECT_TRUE(S->IsVFSMapped); + + S = O->status("c:/root/foo\\..\\file1"); + ASSERT_FALSE(S.getError()); + EXPECT_EQ("c:/root/foo/bar/a", S->getName()); + EXPECT_TRUE(S->IsVFSMapped); + + S = O->status("c:\\root\\foo/../file1"); + ASSERT_FALSE(S.getError()); + EXPECT_EQ("c:/root/foo/bar/a", S->getName()); + EXPECT_TRUE(S->IsVFSMapped); +}