diff --git a/CMakeLists.txt b/CMakeLists.txt index 43a5ed8..de6f94a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,6 +89,7 @@ if(NOT(WITHOUT_TEST)) test-src/integration/test_write.cpp test-src/integration/test_mkdir.cpp test-src/integration/test_rmdir.cpp + test-src/integration/test_statfs.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 fbd3b7b..05cad76 100644 --- a/src/webfuse/provider.cpp +++ b/src/webfuse/provider.cpp @@ -4,6 +4,7 @@ #include #include +#include #include namespace webfuse @@ -118,6 +119,9 @@ public: case request_type::rmdir: fs_rmdir(reader, writer); break; + case request_type::statfs: + fs_statfs(reader, writer); + break; default: std::cout << "unknown request: " << ((int) req_type) << std::endl; break; @@ -353,6 +357,20 @@ private: } } + void fs_statfs(messagereader & reader, messagewriter & writer) + { + auto const path = reader.read_str(); + struct statvfs statistics; + memset(reinterpret_cast(&statistics), 0, sizeof(statistics)); + + auto const result = fs_.statfs(path, &statistics); + writer.write_i32(result); + if (0 == result) + { + writer.write_statistics(&statistics); + } + } + filesystem_i & fs_; ws_client client; }; diff --git a/src/webfuse/ws/messagewriter.cpp b/src/webfuse/ws/messagewriter.cpp index 3fc9586..59f5d01 100644 --- a/src/webfuse/ws/messagewriter.cpp +++ b/src/webfuse/ws/messagewriter.cpp @@ -190,6 +190,17 @@ void messagewriter::write_time(timespec const & value) write_u32(static_cast(value.tv_nsec)); } +void messagewriter::write_statistics(struct statvfs const * statistics) +{ + write_u64(statistics->f_bsize); + write_u64(statistics->f_frsize); + write_u64(statistics->f_blocks); + write_u64(statistics->f_bfree); + write_u64(statistics->f_bavail); + write_u64(statistics->f_files); + write_u64(statistics->f_ffree); + write_u64(statistics->f_namemax); +} unsigned char * messagewriter::get_data(size_t &size) { diff --git a/src/webfuse/ws/messagewriter.hpp b/src/webfuse/ws/messagewriter.hpp index 5b017d1..b89a327 100644 --- a/src/webfuse/ws/messagewriter.hpp +++ b/src/webfuse/ws/messagewriter.hpp @@ -5,6 +5,7 @@ #include "webfuse/response_type.hpp" #include +#include #include #include @@ -45,6 +46,7 @@ public: void write_gid(gid_t value); void write_openflags(int value); void write_time(timespec const & value); + void write_statistics(struct statvfs const * statistics); unsigned char * get_data(size_t &size); diff --git a/test-src/integration/test_statfs.cpp b/test-src/integration/test_statfs.cpp new file mode 100644 index 0000000..c112c09 --- /dev/null +++ b/test-src/integration/test_statfs.cpp @@ -0,0 +1,46 @@ +#include "webfuse/webfuse.hpp" +#include "webfuse/test/fixture.hpp" +#include "webfuse/test/filesystem_mock.hpp" + +#include + +#include + +#include +#include + + +using testing::_; +using testing::Return; +using testing::Invoke; +using testing::AnyNumber; +using testing::AtMost; + +TEST(statfs, success) +{ + webfuse::filesystem_mock fs; + EXPECT_CALL(fs, access("/",_)).Times(AnyNumber()).WillRepeatedly(Return(0)); + EXPECT_CALL(fs, getattr(_,_)).WillRepeatedly(Invoke([](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; + } + else + { + return -ENOENT; + } + })); + EXPECT_CALL(fs, statfs("/", _)).Times(AnyNumber()).WillRepeatedly(Invoke([](auto const &, struct statvfs * statistics){ + return 0; + })); + + webfuse::fixture fixture(fs); + auto const path = fixture.get_path() + "/"; + + struct statvfs statistics; + ASSERT_EQ(0, ::statvfs(path.c_str(), &statistics)); +}