diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp --- a/llvm/lib/Support/VirtualFileSystem.cpp +++ b/llvm/lib/Support/VirtualFileSystem.cpp @@ -257,12 +257,12 @@ 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}; + if (std::error_code EC = llvm::sys::fs::current_path(PWD)) + WD = EC; + else if (llvm::sys::fs::real_path(PWD, RealPWD)) + WD = WorkingDirectory{PWD, PWD}; else - WD = {PWD, RealPWD}; + WD = WorkingDirectory{PWD, RealPWD}; } } @@ -284,10 +284,10 @@ // 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 &Storage) const { - if (!WD) + if (!WD || !*WD) return Path; Path.toVector(Storage); - sys::fs::make_absolute(WD->Resolved, Storage); + sys::fs::make_absolute(WD->get().Resolved, Storage); return Storage; } @@ -297,7 +297,7 @@ // The current working directory, with links resolved. (readlink .). SmallString<128> Resolved; }; - std::optional WD; + std::optional> WD; }; } // namespace @@ -323,8 +323,10 @@ } llvm::ErrorOr RealFileSystem::getCurrentWorkingDirectory() const { + if (WD && *WD) + return std::string(WD->get().Specified.str()); if (WD) - return std::string(WD->Specified.str()); + return WD->getError(); SmallString<128> Dir; if (std::error_code EC = llvm::sys::fs::current_path(Dir)) @@ -345,7 +347,7 @@ 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}; + WD = WorkingDirectory{Absolute, Resolved}; return std::error_code(); } diff --git a/llvm/unittests/Support/VirtualFileSystemTest.cpp b/llvm/unittests/Support/VirtualFileSystemTest.cpp --- a/llvm/unittests/Support/VirtualFileSystemTest.cpp +++ b/llvm/unittests/Support/VirtualFileSystemTest.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/VirtualFileSystem.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/Config/llvm-config.h" #include "llvm/Support/Errc.h" #include "llvm/Support/MemoryBuffer.h" @@ -526,6 +527,31 @@ ASSERT_EQ(CIt, vfs::directory_iterator()); } +TEST(VirtualFileSystemTest, PhysicalFileSystemWorkingDirFailure) { + TempDir D2("d2", /*Unique*/ true); + SmallString<128> WD, PrevWD; + ASSERT_EQ(sys::fs::current_path(PrevWD), std::error_code()); + ASSERT_EQ(sys::fs::createUniqueDirectory("d1", WD), std::error_code()); + ASSERT_EQ(sys::fs::set_current_path(WD), std::error_code()); + auto Restore = + llvm::make_scope_exit([&] { sys::fs::set_current_path(PrevWD); }); + + // Delete the working directory to create an error. + ASSERT_EQ(sys::fs::remove_directories(WD), std::error_code()); + + // Verify that we still get two separate working directories. + auto FS1 = vfs::createPhysicalFileSystem(); + auto FS2 = vfs::createPhysicalFileSystem(); + ASSERT_EQ(FS1->getCurrentWorkingDirectory().getError(), + errc::no_such_file_or_directory); + ASSERT_EQ(FS1->setCurrentWorkingDirectory(D2.path()), std::error_code()); + ASSERT_EQ(FS1->getCurrentWorkingDirectory().get(), D2.path()); + EXPECT_EQ(FS2->getCurrentWorkingDirectory().getError(), + errc::no_such_file_or_directory); + SmallString<128> WD2; + EXPECT_EQ(sys::fs::current_path(WD2), errc::no_such_file_or_directory); +} + TEST(VirtualFileSystemTest, BrokenSymlinkRealFSIteration) { TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true); IntrusiveRefCntPtr FS = vfs::getRealFileSystem();