diff --git a/CMakeLists.txt b/CMakeLists.txt index 1084a72..b8cff36 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,7 @@ if(NOT(WITHOUT_TEST)) test-src/integration/test_link.cpp test-src/integration/test_rename.cpp test-src/integration/test_chmod.cpp + test-src/integration/test_chown.cpp ) target_include_directories(integration_tests PRIVATE test-src/integration ${GTEST_INCLUDE_DIRS} ${GMOCK_INCLUDE_DIRS}) diff --git a/src/webfuse/provider.cpp b/src/webfuse/provider.cpp index f513452..1407695 100644 --- a/src/webfuse/provider.cpp +++ b/src/webfuse/provider.cpp @@ -76,6 +76,9 @@ public: case request_type::chmod: fs_chmod(reader, writer); break; + case request_type::chown: + fs_chown(reader, writer); + break; case request_type::readdir: fs_readdir(reader, writer); break; @@ -159,6 +162,16 @@ private: writer.write_i32(result); } + void fs_chown(messagereader & reader, messagewriter & writer) + { + auto const path = reader.read_str(); + auto const uid = static_cast(reader.read_u32()); + auto const gid = static_cast(reader.read_u32()); + + auto const result = fs_.chown(path, uid, gid); + writer.write_i32(result); + } + void fs_readdir(messagereader & reader, messagewriter & writer) { auto const path = reader.read_str(); diff --git a/test-src/integration/test_chown.cpp b/test-src/integration/test_chown.cpp new file mode 100644 index 0000000..74407d7 --- /dev/null +++ b/test-src/integration/test_chown.cpp @@ -0,0 +1,79 @@ +#include "webfuse/webfuse.hpp" +#include "webfuse/test/fixture.hpp" +#include "webfuse/test/filesystem_mock.hpp" + +#include + +using testing::_; +using testing::Return; +using testing::Invoke; +using testing::AnyNumber; + +TEST(chown, success) +{ + bool link_created = false; + + webfuse::filesystem_mock fs; + EXPECT_CALL(fs, access("/",_)).Times(AnyNumber()).WillRepeatedly(Return(0)); + EXPECT_CALL(fs, getattr(_,_)).WillRepeatedly(Invoke([&link_created](std::string const & path, struct stat * attr){ + memset(reinterpret_cast(attr),0, sizeof(struct stat)); + + if (path == "/") + { + attr->st_nlink = 1; + attr->st_mode = S_IFDIR | 0755; + return 0; + } + if (path == "/some_file") + { + attr->st_nlink = 1; + attr->st_mode = S_IFREG | 0755; + return 0; + } + else + { + return -ENOENT; + } + })); + EXPECT_CALL(fs, chown("/some_file", 42, 42)).WillOnce(Return(0)); + + webfuse::fixture fixture(fs); + auto const path = fixture.get_path() + "/some_file"; + + ASSERT_EQ(0, ::chown(path.c_str(), 42, 42)); +} + +TEST(chown, fail) +{ + bool link_created = false; + + webfuse::filesystem_mock fs; + EXPECT_CALL(fs, access("/",_)).Times(AnyNumber()).WillRepeatedly(Return(0)); + EXPECT_CALL(fs, getattr(_,_)).WillRepeatedly(Invoke([&link_created](std::string const & path, struct stat * attr){ + memset(reinterpret_cast(attr),0, sizeof(struct stat)); + + if (path == "/") + { + attr->st_nlink = 1; + attr->st_mode = S_IFDIR | 0755; + return 0; + } + if (path == "/some_file") + { + attr->st_nlink = 1; + attr->st_mode = S_IFREG | 0755; + return 0; + } + else + { + return -ENOENT; + } + })); + EXPECT_CALL(fs, chown("/some_file", 42, 42)).WillOnce(Return(-EACCES)); + + webfuse::fixture fixture(fs); + auto const path = fixture.get_path() + "/some_file"; + + ASSERT_NE(0, ::chown(path.c_str(), 42, 42)); + ASSERT_EQ(EACCES, errno); +}