From 0bb22bd50ea7264684fa8c35b34fcc380e9d2cdc Mon Sep 17 00:00:00 2001 From: Daichi Hirono Date: Wed, 22 Mar 2017 16:41:46 +0900 Subject: [PATCH] Add FuseMessage::WriteWithBody function The funciton is going to be used to write FUSE header with external body. Bug: 35229514 Test: libappfuse_tests Change-Id: I303022b555deca960b8e08f26140a5ef10133efe --- libappfuse/FuseBuffer.cc | 64 +++++++++++++++------- libappfuse/include/libappfuse/FuseBuffer.h | 44 ++++++++------- 2 files changed, 66 insertions(+), 42 deletions(-) diff --git a/libappfuse/FuseBuffer.cc b/libappfuse/FuseBuffer.cc index 13cfc88ec..5bc549743 100644 --- a/libappfuse/FuseBuffer.cc +++ b/libappfuse/FuseBuffer.cc @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -34,9 +35,9 @@ namespace fuse { namespace { template -bool CheckHeaderLength(const FuseMessage* self, const char* name) { +bool CheckHeaderLength(const FuseMessage* self, const char* name, size_t max_size) { const auto& header = static_cast(self)->header; - if (header.len >= sizeof(header) && header.len <= sizeof(T)) { + if (header.len >= sizeof(header) && header.len <= max_size) { return true; } else { LOG(ERROR) << "Invalid header length is found in " << name << ": " << header.len; @@ -68,7 +69,7 @@ ResultOrAgain ReadInternal(FuseMessage* self, int fd, int sockflag) { return ResultOrAgain::kFailure; } - if (!CheckHeaderLength(self, "Read")) { + if (!CheckHeaderLength(self, "Read", sizeof(T))) { return ResultOrAgain::kFailure; } @@ -81,15 +82,26 @@ ResultOrAgain ReadInternal(FuseMessage* self, int fd, int sockflag) { } template -ResultOrAgain WriteInternal(const FuseMessage* self, int fd, int sockflag) { - if (!CheckHeaderLength(self, "Write")) { +ResultOrAgain WriteInternal(const FuseMessage* self, int fd, int sockflag, const void* data, + size_t max_size) { + if (!CheckHeaderLength(self, "Write", max_size)) { return ResultOrAgain::kFailure; } const char* const buf = reinterpret_cast(self); const auto& header = static_cast(self)->header; - const int result = sockflag ? TEMP_FAILURE_RETRY(send(fd, buf, header.len, sockflag)) - : TEMP_FAILURE_RETRY(write(fd, buf, header.len)); + + int result; + if (sockflag) { + CHECK(data == nullptr); + result = TEMP_FAILURE_RETRY(send(fd, buf, header.len, sockflag)); + } else if (data) { + const struct iovec vec[] = {{const_cast(buf), sizeof(header)}, + {const_cast(data), header.len - sizeof(header)}}; + result = TEMP_FAILURE_RETRY(writev(fd, vec, arraysize(vec))); + } else { + result = TEMP_FAILURE_RETRY(write(fd, buf, header.len)); + } if (result == -1) { if (errno == EAGAIN) { @@ -143,17 +155,20 @@ ResultOrAgain FuseMessage::ReadOrAgain(int fd) { template bool FuseMessage::Write(int fd) const { - return WriteInternal(this, fd, 0) == ResultOrAgain::kSuccess; + return WriteInternal(this, fd, 0, nullptr, sizeof(T)) == ResultOrAgain::kSuccess; +} + +template +bool FuseMessage::WriteWithBody(int fd, size_t max_size, const void* data) const { + CHECK(data != nullptr); + return WriteInternal(this, fd, 0, data, max_size) == ResultOrAgain::kSuccess; } template ResultOrAgain FuseMessage::WriteOrAgain(int fd) const { - return WriteInternal(this, fd, MSG_DONTWAIT); + return WriteInternal(this, fd, MSG_DONTWAIT, nullptr, sizeof(T)); } -template class FuseMessage; -template class FuseMessage; - void FuseRequest::Reset( uint32_t data_length, uint32_t opcode, uint64_t unique) { memset(this, 0, sizeof(fuse_in_header) + data_length); @@ -162,17 +177,18 @@ void FuseRequest::Reset( header.unique = unique; } -void FuseResponse::ResetHeader( - uint32_t data_length, int32_t error, uint64_t unique) { - CHECK_LE(error, 0) << "error should be zero or negative."; - header.len = sizeof(fuse_out_header) + data_length; - header.error = error; - header.unique = unique; +template +void FuseResponseBase::ResetHeader(uint32_t data_length, int32_t error, uint64_t unique) { + CHECK_LE(error, 0) << "error should be zero or negative."; + header.len = sizeof(fuse_out_header) + data_length; + header.error = error; + header.unique = unique; } -void FuseResponse::Reset(uint32_t data_length, int32_t error, uint64_t unique) { - memset(this, 0, sizeof(fuse_out_header) + data_length); - ResetHeader(data_length, error, unique); +template +void FuseResponseBase::Reset(uint32_t data_length, int32_t error, uint64_t unique) { + memset(this, 0, sizeof(fuse_out_header) + data_length); + ResetHeader(data_length, error, unique); } void FuseBuffer::HandleInit() { @@ -222,5 +238,11 @@ void FuseBuffer::HandleNotImpl() { response.Reset(0, -ENOSYS, unique); } +template class FuseMessage; +template class FuseMessage; +template class FuseMessage; +template struct FuseResponseBase<0u>; +template struct FuseResponseBase; + } // namespace fuse } // namespace android diff --git a/libappfuse/include/libappfuse/FuseBuffer.h b/libappfuse/include/libappfuse/FuseBuffer.h index fbb05d633..7a70bf3b4 100644 --- a/libappfuse/include/libappfuse/FuseBuffer.h +++ b/libappfuse/include/libappfuse/FuseBuffer.h @@ -43,11 +43,9 @@ class FuseMessage { public: bool Read(int fd); bool Write(int fd) const; + bool WriteWithBody(int fd, size_t max_size, const void* data) const; ResultOrAgain ReadOrAgain(int fd); ResultOrAgain WriteOrAgain(int fd) const; - -private: - bool CheckHeaderLength(const char* name) const; }; // FuseRequest represents file operation requests from /dev/fuse. It starts @@ -74,26 +72,30 @@ struct FuseRequest : public FuseMessage { // FuseResponse represents file operation responses to /dev/fuse. It starts // from fuse_out_header. The body layout depends on the operation code. -struct FuseResponse : public FuseMessage { - fuse_out_header header; - union { - // for FUSE_INIT - fuse_init_out init_out; - // for FUSE_LOOKUP - fuse_entry_out entry_out; - // for FUSE_GETATTR - fuse_attr_out attr_out; - // for FUSE_OPEN - fuse_open_out open_out; - // for FUSE_READ - char read_data[kFuseMaxRead]; - // for FUSE_WRITE - fuse_write_out write_out; - }; - void Reset(uint32_t data_length, int32_t error, uint64_t unique); - void ResetHeader(uint32_t data_length, int32_t error, uint64_t unique); +template +struct FuseResponseBase : public FuseMessage> { + fuse_out_header header; + union { + // for FUSE_INIT + fuse_init_out init_out; + // for FUSE_LOOKUP + fuse_entry_out entry_out; + // for FUSE_GETATTR + fuse_attr_out attr_out; + // for FUSE_OPEN + fuse_open_out open_out; + // for FUSE_READ + char read_data[N]; + // for FUSE_WRITE + fuse_write_out write_out; + }; + void Reset(uint32_t data_length, int32_t error, uint64_t unique); + void ResetHeader(uint32_t data_length, int32_t error, uint64_t unique); }; +using FuseResponse = FuseResponseBase; +using FuseSimpleResponse = FuseResponseBase<0u>; + // To reduce memory usage, FuseBuffer shares the memory region for request and // response. union FuseBuffer final {