forked from OSchip/llvm-project
[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 llvm-svn: 317800
This commit is contained in:
parent
d4102df9ad
commit
e5af5bde71
|
@ -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; }
|
||||
|
|
|
@ -493,7 +493,11 @@ std::string InMemoryFileSystem::toString() const {
|
|||
}
|
||||
|
||||
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 Twine &P, time_t ModificationTime,
|
|||
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 Twine &P, time_t ModificationTime,
|
|||
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 Twine &P, time_t ModificationTime,
|
|||
}
|
||||
|
||||
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 *>
|
||||
|
|
|
@ -760,6 +760,75 @@ TEST_F(InMemoryFileSystemTest, WorkingDirectory) {
|
|||
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 {
|
||||
|
|
Loading…
Reference in New Issue