Author: benhamilton Date: Thu Nov 9 08:01:16 2017 New Revision: 317800 URL: http://llvm.org/viewvc/llvm-project?rev=317800&view=rev Log: [VirtualFileSystem] InMemoryFileSystem::addFile(): Type and Perms
Summary: This implements a FIXME in InMemoryFileSystem::addFile(), allowing clients to specify User, Group, Type, and/or Perms when creating a file in an in-memory filesystem. New tests included. Ran tests with: % ninja BasicTests && ./tools/clang/unittests/Basic/BasicTests Fixes PR#35172 (https://bugs.llvm.org/show_bug.cgi?id=35172) Reviewers: bkramer, hokein Reviewed By: bkramer, hokein Subscribers: alexfh Differential Revision: https://reviews.llvm.org/D39572 Modified: cfe/trunk/include/clang/Basic/VirtualFileSystem.h cfe/trunk/lib/Basic/VirtualFileSystem.cpp cfe/trunk/unittests/Basic/VirtualFileSystemTest.cpp Modified: cfe/trunk/include/clang/Basic/VirtualFileSystem.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/VirtualFileSystem.h?rev=317800&r1=317799&r2=317800&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/VirtualFileSystem.h (original) +++ cfe/trunk/include/clang/Basic/VirtualFileSystem.h Thu Nov 9 08:01:16 2017 @@ -320,15 +320,25 @@ public: ~InMemoryFileSystem() override; /// Add a buffer to the VFS with a path. The VFS owns the buffer. + /// If present, User, Group, Type and Perms apply to the newly-created file. /// \return true if the file was successfully added, false if the file already /// exists in the file system with different contents. bool addFile(const Twine &Path, time_t ModificationTime, - std::unique_ptr<llvm::MemoryBuffer> Buffer); + std::unique_ptr<llvm::MemoryBuffer> Buffer, + Optional<uint32_t> User = None, Optional<uint32_t> Group = None, + Optional<llvm::sys::fs::file_type> Type = None, + Optional<llvm::sys::fs::perms> Perms = None); /// Add a buffer to the VFS with a path. The VFS does not own the buffer. + /// If present, User, Group, Type and Perms apply to the newly-created file. /// \return true if the file was successfully added, false if the file already /// exists in the file system with different contents. bool addFileNoOwn(const Twine &Path, time_t ModificationTime, - llvm::MemoryBuffer *Buffer); + llvm::MemoryBuffer *Buffer, + Optional<uint32_t> User = None, + Optional<uint32_t> Group = None, + Optional<llvm::sys::fs::file_type> Type = None, + Optional<llvm::sys::fs::perms> Perms = None); + std::string toString() const; /// Return true if this file system normalizes . and .. in paths. bool useNormalizedPaths() const { return UseNormalizedPaths; } Modified: cfe/trunk/lib/Basic/VirtualFileSystem.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/VirtualFileSystem.cpp?rev=317800&r1=317799&r2=317800&view=diff ============================================================================== --- cfe/trunk/lib/Basic/VirtualFileSystem.cpp (original) +++ cfe/trunk/lib/Basic/VirtualFileSystem.cpp Thu Nov 9 08:01:16 2017 @@ -493,7 +493,11 @@ std::string InMemoryFileSystem::toString } bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime, - std::unique_ptr<llvm::MemoryBuffer> Buffer) { + std::unique_ptr<llvm::MemoryBuffer> Buffer, + Optional<uint32_t> User, + Optional<uint32_t> Group, + Optional<llvm::sys::fs::file_type> Type, + Optional<llvm::sys::fs::perms> Perms) { SmallString<128> Path; P.toVector(Path); @@ -509,7 +513,14 @@ bool InMemoryFileSystem::addFile(const T return false; detail::InMemoryDirectory *Dir = Root.get(); - auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path); + auto I = llvm::sys::path::begin(Path), E = sys::path::end(Path); + const auto ResolvedUser = User.getValueOr(0); + const auto ResolvedGroup = Group.getValueOr(0); + const auto ResolvedType = Type.getValueOr(sys::fs::file_type::regular_file); + const auto ResolvedPerms = Perms.getValueOr(sys::fs::all_all); + // Any intermediate directories we create should be accessible by + // the owner, even if Perms says otherwise for the final path. + const auto NewDirectoryPerms = ResolvedPerms | sys::fs::owner_all; while (true) { StringRef Name = *I; detail::InMemoryNode *Node = Dir->getChild(Name); @@ -517,24 +528,21 @@ bool InMemoryFileSystem::addFile(const T if (!Node) { if (I == E) { // End of the path, create a new file. - // FIXME: expose the status details in the interface. Status Stat(P.str(), getNextVirtualUniqueID(), - llvm::sys::toTimePoint(ModificationTime), 0, 0, - Buffer->getBufferSize(), - llvm::sys::fs::file_type::regular_file, - llvm::sys::fs::all_all); + llvm::sys::toTimePoint(ModificationTime), ResolvedUser, + ResolvedGroup, Buffer->getBufferSize(), ResolvedType, + ResolvedPerms); Dir->addChild(Name, llvm::make_unique<detail::InMemoryFile>( std::move(Stat), std::move(Buffer))); return true; } // Create a new directory. Use the path up to here. - // FIXME: expose the status details in the interface. Status Stat( StringRef(Path.str().begin(), Name.end() - Path.str().begin()), - getNextVirtualUniqueID(), llvm::sys::toTimePoint(ModificationTime), 0, - 0, Buffer->getBufferSize(), llvm::sys::fs::file_type::directory_file, - llvm::sys::fs::all_all); + getNextVirtualUniqueID(), llvm::sys::toTimePoint(ModificationTime), + ResolvedUser, ResolvedGroup, Buffer->getBufferSize(), + sys::fs::file_type::directory_file, NewDirectoryPerms); Dir = cast<detail::InMemoryDirectory>(Dir->addChild( Name, llvm::make_unique<detail::InMemoryDirectory>(std::move(Stat)))); continue; @@ -558,10 +566,16 @@ bool InMemoryFileSystem::addFile(const T } bool InMemoryFileSystem::addFileNoOwn(const Twine &P, time_t ModificationTime, - llvm::MemoryBuffer *Buffer) { + llvm::MemoryBuffer *Buffer, + Optional<uint32_t> User, + Optional<uint32_t> Group, + Optional<llvm::sys::fs::file_type> Type, + Optional<llvm::sys::fs::perms> Perms) { return addFile(P, ModificationTime, llvm::MemoryBuffer::getMemBuffer( - Buffer->getBuffer(), Buffer->getBufferIdentifier())); + Buffer->getBuffer(), Buffer->getBufferIdentifier()), + std::move(User), std::move(Group), std::move(Type), + std::move(Perms)); } static ErrorOr<detail::InMemoryNode *> Modified: cfe/trunk/unittests/Basic/VirtualFileSystemTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Basic/VirtualFileSystemTest.cpp?rev=317800&r1=317799&r2=317800&view=diff ============================================================================== --- cfe/trunk/unittests/Basic/VirtualFileSystemTest.cpp (original) +++ cfe/trunk/unittests/Basic/VirtualFileSystemTest.cpp Thu Nov 9 08:01:16 2017 @@ -760,6 +760,75 @@ TEST_F(InMemoryFileSystemTest, WorkingDi NormalizedFS.getCurrentWorkingDirectory().get())); } +TEST_F(InMemoryFileSystemTest, AddFileWithUser) { + FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), 0xFEEDFACE); + auto Stat = FS.status("/a"); + ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString(); + ASSERT_TRUE(Stat->isDirectory()); + ASSERT_EQ(0xFEEDFACE, Stat->getUser()); + Stat = FS.status("/a/b"); + ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString(); + ASSERT_TRUE(Stat->isDirectory()); + ASSERT_EQ(0xFEEDFACE, Stat->getUser()); + Stat = FS.status("/a/b/c"); + ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString(); + ASSERT_TRUE(Stat->isRegularFile()); + ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions()); + ASSERT_EQ(0xFEEDFACE, Stat->getUser()); +} + +TEST_F(InMemoryFileSystemTest, AddFileWithGroup) { + FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, 0xDABBAD00); + auto Stat = FS.status("/a"); + ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString(); + ASSERT_TRUE(Stat->isDirectory()); + ASSERT_EQ(0xDABBAD00, Stat->getGroup()); + Stat = FS.status("/a/b"); + ASSERT_TRUE(Stat->isDirectory()); + ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString(); + ASSERT_EQ(0xDABBAD00, Stat->getGroup()); + Stat = FS.status("/a/b/c"); + ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString(); + ASSERT_TRUE(Stat->isRegularFile()); + ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions()); + ASSERT_EQ(0xDABBAD00, Stat->getGroup()); +} + +TEST_F(InMemoryFileSystemTest, AddFileWithFileType) { + FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None, + sys::fs::file_type::socket_file); + auto Stat = FS.status("/a"); + ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString(); + ASSERT_TRUE(Stat->isDirectory()); + Stat = FS.status("/a/b"); + ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString(); + ASSERT_TRUE(Stat->isDirectory()); + Stat = FS.status("/a/b/c"); + ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString(); + ASSERT_EQ(sys::fs::file_type::socket_file, Stat->getType()); + ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions()); +} + +TEST_F(InMemoryFileSystemTest, AddFileWithPerms) { + FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None, + None, sys::fs::perms::owner_read | sys::fs::perms::owner_write); + auto Stat = FS.status("/a"); + ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString(); + ASSERT_TRUE(Stat->isDirectory()); + ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write | + sys::fs::perms::owner_exe, Stat->getPermissions()); + Stat = FS.status("/a/b"); + ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString(); + ASSERT_TRUE(Stat->isDirectory()); + ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write | + sys::fs::perms::owner_exe, Stat->getPermissions()); + Stat = FS.status("/a/b/c"); + ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString(); + ASSERT_TRUE(Stat->isRegularFile()); + ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write, + Stat->getPermissions()); +} + // NOTE: in the tests below, we use '//root/' as our root directory, since it is // a legal *absolute* path on Windows as well as *nix. class VFSFromYAMLTest : public ::testing::Test { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits