ilya-biryukov updated this revision to Diff 109524.
ilya-biryukov added a comment.
Added a very rough prototype of vfs::RealFileSystem not using openat.
Not ready for submission yet, wanted to start discussion about Windows
implementation.
https://reviews.llvm.org/D36226
Files:
include/clang/Basic/VirtualFileSystem.h
lib/Basic/VirtualFileSystem.cpp
unittests/Basic/VirtualFileSystemTest.cpp
Index: unittests/Basic/VirtualFileSystemTest.cpp
===================================================================
--- unittests/Basic/VirtualFileSystemTest.cpp
+++ unittests/Basic/VirtualFileSystemTest.cpp
@@ -12,6 +12,7 @@
#include "llvm/Support/Errc.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/SourceMgr.h"
#include "gtest/gtest.h"
#include <map>
@@ -477,6 +478,75 @@
}
#endif
+TEST(VirtualFileSystemTest, ThreadFriendlyRealFSWorkingDirTest) {
+ ScopedDir TestDirectory("thread-friendly-vfs-test", /*Unique*/ true);
+
+ SmallString<128> PathA = TestDirectory.Path;
+ llvm::sys::path::append(PathA, "a");
+ SmallString<128> PathAC = PathA;
+ llvm::sys::path::append(PathAC, "c");
+ SmallString<128> PathB = TestDirectory.Path;
+ llvm::sys::path::append(PathB, "b");
+ SmallString<128> PathBD = PathB;
+ llvm::sys::path::append(PathBD, "d");
+
+ ScopedDir A(PathA);
+ ScopedDir AC(PathAC);
+ ScopedDir B(PathB);
+ ScopedDir BD(PathBD);
+
+ IntrusiveRefCntPtr<vfs::FileSystem> FSA = vfs::createThreadFriendlyRealFS();
+ // setCurrentWorkingDirectory should fininsh without error
+ ASSERT_TRUE(!FSA->setCurrentWorkingDirectory(Twine(A)));
+
+ IntrusiveRefCntPtr<vfs::FileSystem> FSB = vfs::createThreadFriendlyRealFS();
+ // setCurrentWorkingDirectory should fininsh without error
+ ASSERT_TRUE(!FSB->setCurrentWorkingDirectory(Twine(B)));
+
+ ASSERT_TRUE(FSA->getCurrentWorkingDirectory());
+ EXPECT_EQ(*FSA->getCurrentWorkingDirectory(), StringRef(A));
+
+ ASSERT_TRUE(FSB->getCurrentWorkingDirectory());
+ EXPECT_EQ(*FSB->getCurrentWorkingDirectory(), StringRef(B));
+
+ auto C = FSA->status("c");
+ // a/c should be found in FSA
+ ASSERT_TRUE(!!C);
+ // name of 'c' must be relative
+ EXPECT_EQ(C->getName(), "c");
+ EXPECT_TRUE(C->isDirectory());
+
+ // "a", "b" and "d" should not be found in FSA.
+ EXPECT_FALSE(!!FSA->status("a"));
+ EXPECT_FALSE(!!FSA->status("b"));
+ EXPECT_FALSE(!!FSA->status("d"));
+
+ auto D = FSB->status("d");
+ // b/d should be found in FSB
+ ASSERT_TRUE(!!D);
+ // name of 'd' must be relative
+ EXPECT_EQ(D->getName(), "d");
+ EXPECT_TRUE(D->isDirectory());
+
+ // "a", "b" and "c" should not be found in FSB.
+ EXPECT_FALSE(!!FSB->status("a"));
+ EXPECT_FALSE(!!FSB->status("b"));
+ EXPECT_FALSE(!!FSB->status("c"));
+
+ SmallString<128> RelPathC = StringRef("..");
+ llvm::sys::path::append(RelPathC, "a", "c");
+ auto RelCFromFSA = FSA->status(RelPathC);
+ ASSERT_TRUE(!!RelCFromFSA);
+ EXPECT_EQ(RelCFromFSA->getName(), StringRef(RelPathC));
+
+ auto RelCFromFSB = FSB->status(RelPathC);
+ ASSERT_TRUE(!!RelCFromFSB);
+ EXPECT_EQ(RelCFromFSB->getName(), StringRef(RelPathC));
+
+ EXPECT_TRUE(C->equivalent(*RelCFromFSA));
+ EXPECT_TRUE(C->equivalent(*RelCFromFSB));
+}
+
template <typename DirIter>
static void checkContents(DirIter I, ArrayRef<StringRef> ExpectedOut) {
std::error_code EC;
Index: lib/Basic/VirtualFileSystem.cpp
===================================================================
--- lib/Basic/VirtualFileSystem.cpp
+++ lib/Basic/VirtualFileSystem.cpp
@@ -189,59 +189,88 @@
/// \brief The file system according to your operating system.
class RealFileSystem : public FileSystem {
public:
+ RealFileSystem();
+ ~RealFileSystem();
+
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;
+
+private:
+ std::string WorkingDir;
+ int WorkingDirFD;
};
} // end anonymous namespace
+RealFileSystem::RealFileSystem() {
+ SmallString<128> CWD;
+
+ auto Err = llvm::sys::fs::openDirectoryForAt(".", /*ref*/WorkingDirFD, &CWD);
+ // TODO: handle errors gracefully.
+ assert(!Err && "couldn't open CWD'");
+
+ WorkingDir = CWD.str();
+}
+
+RealFileSystem::~RealFileSystem() {
+ sys::Process::SafelyCloseFileDescriptor(WorkingDirFD);
+}
+
ErrorOr<Status> RealFileSystem::status(const Twine &Path) {
sys::fs::file_status RealStatus;
- if (std::error_code EC = sys::fs::status(Path, RealStatus))
+ // TODO: handle errors gracefully.
+ if (std::error_code EC = sys::fs::status_at(WorkingDirFD, Path, RealStatus))
return EC;
return Status::copyWithNewName(RealStatus, Path.str());
}
ErrorOr<std::unique_ptr<File>>
RealFileSystem::openFileForRead(const Twine &Name) {
int FD;
SmallString<256> RealName;
- if (std::error_code EC = sys::fs::openFileForRead(Name, FD, &RealName))
+ // TODO: handle errors gracefully.
+ if (std::error_code EC = sys::fs::openFileForRead(WorkingDirFD, Name, FD, &RealName))
return EC;
return std::unique_ptr<File>(new RealFile(FD, Name.str(), RealName.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();
+ // TODO: Handle errors.
+ return WorkingDir;
+ // 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.
- return llvm::sys::fs::set_current_path(Path);
+ SmallString<128> CWD;
+ auto Err = llvm::sys::fs::openFileForRead(Path, /*ref*/WorkingDirFD, &CWD);
+ if (Err)
+ return Err;
+
+ // TODO: handle errors
+ WorkingDir = CWD.str();
+ return std::error_code();
}
IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
static IntrusiveRefCntPtr<FileSystem> FS = new RealFileSystem();
return FS;
}
+IntrusiveRefCntPtr<FileSystem> vfs::createThreadFriendlyRealFS() {
+ return new RealFileSystem();
+}
+
namespace {
class RealFSDirIter : public clang::vfs::detail::DirIterImpl {
llvm::sys::fs::directory_iterator Iter;
public:
- RealFSDirIter(const Twine &Path, std::error_code &EC) : Iter(Path, EC) {
+ RealFSDirIter(int WorkingDirFD, const Twine &Path, std::error_code &EC) : Iter(WorkingDirFD, Path, EC) {
if (!EC && Iter != llvm::sys::fs::directory_iterator()) {
llvm::sys::fs::file_status S;
EC = Iter->status(S);
@@ -268,7 +297,7 @@
directory_iterator RealFileSystem::dir_begin(const Twine &Dir,
std::error_code &EC) {
- return directory_iterator(std::make_shared<RealFSDirIter>(Dir, EC));
+ return directory_iterator(std::make_shared<RealFSDirIter>(WorkingDirFD, Dir, EC));
}
//===-----------------------------------------------------------------------===/
Index: include/clang/Basic/VirtualFileSystem.h
===================================================================
--- include/clang/Basic/VirtualFileSystem.h
+++ include/clang/Basic/VirtualFileSystem.h
@@ -265,6 +265,15 @@
/// the operating system.
IntrusiveRefCntPtr<FileSystem> getRealFileSystem();
+/// \brief Creates a \p vfs::FileSystem for the 'real' file system that does not
+/// change to global state of the program on calls to
+/// setCurrentWorkingDirectory(). Internally it has to do more paths
+/// manipulations than the vfs::FileSystem returned by getRealFileSystem(). Note
+/// that returned instance of vfs::FileSystem is not thread-safe.
+/// Thread-friendly refers to the fact that it does not use global
+/// WorkingDirectory.
+IntrusiveRefCntPtr<FileSystem> createThreadFriendlyRealFS();
+
/// \brief A file system that allows overlaying one \p AbstractFileSystem on top
/// of another.
///
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits