Merge "Add static assert to check if FuseBuffer is standard layout union." am: a0967504f9 am: 83e2cfdf52
am: f5cab9d7f1

Change-Id: I7c06ccbd2363cb071214d10e8683ce377c2b8dab
diff --git a/libappfuse/FuseBuffer.cc b/libappfuse/FuseBuffer.cc
index ca47aa8..74fe756 100644
--- a/libappfuse/FuseBuffer.cc
+++ b/libappfuse/FuseBuffer.cc
@@ -21,6 +21,7 @@
 #include <unistd.h>
 
 #include <algorithm>
+#include <type_traits>
 
 #include <android-base/logging.h>
 #include <android-base/macros.h>
@@ -28,9 +29,14 @@
 namespace android {
 namespace fuse {
 
-template <typename T, typename Header>
-bool FuseMessage<T, Header>::CheckHeaderLength() const {
-  if (sizeof(Header) <= header.len && header.len <= sizeof(T)) {
+static_assert(
+    std::is_standard_layout<FuseBuffer>::value,
+    "FuseBuffer must be standard layout union.");
+
+template <typename T>
+bool FuseMessage<T>::CheckHeaderLength() const {
+  const auto& header = static_cast<const T*>(this)->header;
+  if (sizeof(header) <= header.len && header.len <= sizeof(T)) {
     return true;
   } else {
     LOG(ERROR) << "Packet size is invalid=" << header.len;
@@ -38,9 +44,10 @@
   }
 }
 
-template <typename T, typename Header>
-bool FuseMessage<T, Header>::CheckResult(
+template <typename T>
+bool FuseMessage<T>::CheckResult(
     int result, const char* operation_name) const {
+  const auto& header = static_cast<const T*>(this)->header;
   if (result >= 0 && static_cast<uint32_t>(result) == header.len) {
     return true;
   } else {
@@ -51,14 +58,15 @@
   }
 }
 
-template <typename T, typename Header>
-bool FuseMessage<T, Header>::Read(int fd) {
+template <typename T>
+bool FuseMessage<T>::Read(int fd) {
   const ssize_t result = TEMP_FAILURE_RETRY(::read(fd, this, sizeof(T)));
   return CheckHeaderLength() && CheckResult(result, "read");
 }
 
-template <typename T, typename Header>
-bool FuseMessage<T, Header>::Write(int fd) const {
+template <typename T>
+bool FuseMessage<T>::Write(int fd) const {
+  const auto& header = static_cast<const T*>(this)->header;
   if (!CheckHeaderLength()) {
     return false;
   }
@@ -66,8 +74,8 @@
   return CheckResult(result, "write");
 }
 
-template struct FuseMessage<FuseRequest, fuse_in_header>;
-template struct FuseMessage<FuseResponse, fuse_out_header>;
+template class FuseMessage<FuseRequest>;
+template class FuseMessage<FuseResponse>;
 
 void FuseRequest::Reset(
     uint32_t data_length, uint32_t opcode, uint64_t unique) {
diff --git a/libappfuse/include/libappfuse/FuseBuffer.h b/libappfuse/include/libappfuse/FuseBuffer.h
index 1464142..e7f620c 100644
--- a/libappfuse/include/libappfuse/FuseBuffer.h
+++ b/libappfuse/include/libappfuse/FuseBuffer.h
@@ -28,9 +28,9 @@
 constexpr size_t kFuseMaxRead = 128 * 1024;
 constexpr int32_t kFuseSuccess = 0;
 
-template<typename T, typename Header>
-struct FuseMessage {
-  Header header;
+template<typename T>
+class FuseMessage {
+ public:
   bool Read(int fd);
   bool Write(int fd) const;
  private:
@@ -40,7 +40,8 @@
 
 // FuseRequest represents file operation requests from /dev/fuse. It starts
 // from fuse_in_header. The body layout depends on the operation code.
-struct FuseRequest final : public FuseMessage<FuseRequest, fuse_in_header> {
+struct FuseRequest : public FuseMessage<FuseRequest> {
+  fuse_in_header header;
   union {
     // for FUSE_WRITE
     struct {
@@ -61,7 +62,8 @@
 
 // FuseResponse represents file operation responses to /dev/fuse. It starts
 // from fuse_out_header. The body layout depends on the operation code.
-struct FuseResponse final : public FuseMessage<FuseResponse, fuse_out_header> {
+struct FuseResponse : public FuseMessage<FuseResponse> {
+  fuse_out_header header;
   union {
     // for FUSE_INIT
     fuse_init_out init_out;