1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specic language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "libappfuse/FuseBridgeLoop.h" 18 19 #include <sys/socket.h> 20 21 #include <sstream> 22 #include <thread> 23 24 #include <android-base/logging.h> 25 #include <android-base/unique_fd.h> 26 #include <gtest/gtest.h> 27 28 namespace android { 29 namespace fuse { 30 namespace { 31 32 class Callback : public FuseBridgeLoopCallback { 33 public: 34 bool mounted; 35 bool closed; 36 Callback() : mounted(false), closed(false) {} 37 38 void OnMount(int /*mount_id*/) override { mounted = true; } 39 40 void OnClosed(int /* mount_id */) override { closed = true; } 41 }; 42 43 class FuseBridgeLoopTest : public ::testing::Test { 44 protected: 45 base::unique_fd dev_sockets_[2]; 46 base::unique_fd proxy_sockets_[2]; 47 Callback callback_; 48 std::thread thread_; 49 50 FuseRequest request_; 51 FuseResponse response_; 52 53 void SetUp() override { 54 base::SetMinimumLogSeverity(base::VERBOSE); 55 ASSERT_TRUE(SetupMessageSockets(&dev_sockets_)); 56 ASSERT_TRUE(SetupMessageSockets(&proxy_sockets_)); 57 thread_ = std::thread([this] { 58 FuseBridgeLoop loop; 59 loop.AddBridge(1, std::move(dev_sockets_[1]), std::move(proxy_sockets_[0])); 60 loop.Start(&callback_); 61 }); 62 } 63 64 void CheckNotImpl(uint32_t opcode) { 65 SCOPED_TRACE((std::ostringstream() << "opcode: " << opcode).str()); 66 67 memset(&request_, 0, sizeof(FuseRequest)); 68 request_.header.opcode = opcode; 69 request_.header.len = sizeof(fuse_in_header); 70 request_.header.unique = 1; 71 ASSERT_TRUE(request_.Write(dev_sockets_[0])); 72 73 memset(&response_, 0, sizeof(FuseResponse)); 74 ASSERT_TRUE(response_.Read(dev_sockets_[0])); 75 EXPECT_EQ(-ENOSYS, response_.header.error); 76 } 77 78 void CheckProxy(uint32_t opcode) { 79 SCOPED_TRACE((std::ostringstream() << "opcode: " << opcode).str()); 80 81 memset(&request_, 0, sizeof(FuseRequest)); 82 request_.header.opcode = opcode; 83 request_.header.unique = opcode; // Use opcode as unique. 84 request_.header.len = sizeof(fuse_in_header); 85 ASSERT_TRUE(request_.Write(dev_sockets_[0])); 86 87 memset(&request_, 0, sizeof(FuseRequest)); 88 ASSERT_TRUE(request_.Read(proxy_sockets_[1])); 89 EXPECT_EQ(opcode, request_.header.opcode); 90 EXPECT_EQ(opcode, request_.header.unique); 91 92 memset(&response_, 0, sizeof(FuseResponse)); 93 response_.header.len = sizeof(fuse_out_header); 94 response_.header.unique = opcode; // Use opcode as unique. 95 response_.header.error = kFuseSuccess; 96 ASSERT_TRUE(response_.Write(proxy_sockets_[1])); 97 98 memset(&response_, 0, sizeof(FuseResponse)); 99 ASSERT_TRUE(response_.Read(dev_sockets_[0])); 100 EXPECT_EQ(opcode, response_.header.unique); 101 EXPECT_EQ(kFuseSuccess, response_.header.error); 102 } 103 104 void SendInitRequest(uint64_t unique) { 105 memset(&request_, 0, sizeof(FuseRequest)); 106 request_.header.opcode = FUSE_INIT; 107 request_.header.unique = unique; 108 request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_init_in); 109 request_.init_in.major = FUSE_KERNEL_VERSION; 110 request_.init_in.minor = FUSE_KERNEL_MINOR_VERSION; 111 ASSERT_TRUE(request_.Write(dev_sockets_[0])); 112 } 113 114 void Close() { 115 dev_sockets_[0].reset(); 116 dev_sockets_[1].reset(); 117 proxy_sockets_[0].reset(); 118 proxy_sockets_[1].reset(); 119 if (thread_.joinable()) { 120 thread_.join(); 121 } 122 ASSERT_TRUE(callback_.closed); 123 } 124 125 void TearDown() override { 126 Close(); 127 } 128 }; 129 130 } // namespace 131 132 TEST_F(FuseBridgeLoopTest, FuseInit) { 133 SendInitRequest(1u); 134 135 memset(&response_, 0, sizeof(FuseResponse)); 136 ASSERT_TRUE(response_.Read(dev_sockets_[0])); 137 EXPECT_EQ(kFuseSuccess, response_.header.error); 138 EXPECT_EQ(1u, response_.header.unique); 139 140 // Unmount. 141 Close(); 142 EXPECT_TRUE(callback_.mounted); 143 } 144 145 TEST_F(FuseBridgeLoopTest, FuseForget) { 146 memset(&request_, 0, sizeof(FuseRequest)); 147 request_.header.opcode = FUSE_FORGET; 148 request_.header.unique = 1u; 149 request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_forget_in); 150 ASSERT_TRUE(request_.Write(dev_sockets_[0])); 151 152 SendInitRequest(2u); 153 154 memset(&response_, 0, sizeof(FuseResponse)); 155 ASSERT_TRUE(response_.Read(dev_sockets_[0])); 156 EXPECT_EQ(2u, response_.header.unique) << 157 "The loop must not respond to FUSE_FORGET"; 158 } 159 160 TEST_F(FuseBridgeLoopTest, FuseNotImpl) { 161 CheckNotImpl(FUSE_SETATTR); 162 CheckNotImpl(FUSE_READLINK); 163 CheckNotImpl(FUSE_SYMLINK); 164 CheckNotImpl(FUSE_MKNOD); 165 CheckNotImpl(FUSE_MKDIR); 166 CheckNotImpl(FUSE_UNLINK); 167 CheckNotImpl(FUSE_RMDIR); 168 CheckNotImpl(FUSE_RENAME); 169 CheckNotImpl(FUSE_LINK); 170 CheckNotImpl(FUSE_STATFS); 171 CheckNotImpl(FUSE_SETXATTR); 172 CheckNotImpl(FUSE_GETXATTR); 173 CheckNotImpl(FUSE_LISTXATTR); 174 CheckNotImpl(FUSE_REMOVEXATTR); 175 CheckNotImpl(FUSE_FLUSH); 176 CheckNotImpl(FUSE_OPENDIR); 177 CheckNotImpl(FUSE_READDIR); 178 CheckNotImpl(FUSE_RELEASEDIR); 179 CheckNotImpl(FUSE_FSYNCDIR); 180 CheckNotImpl(FUSE_GETLK); 181 CheckNotImpl(FUSE_SETLK); 182 CheckNotImpl(FUSE_SETLKW); 183 CheckNotImpl(FUSE_ACCESS); 184 CheckNotImpl(FUSE_CREATE); 185 CheckNotImpl(FUSE_INTERRUPT); 186 CheckNotImpl(FUSE_BMAP); 187 CheckNotImpl(FUSE_DESTROY); 188 CheckNotImpl(FUSE_IOCTL); 189 CheckNotImpl(FUSE_POLL); 190 CheckNotImpl(FUSE_NOTIFY_REPLY); 191 CheckNotImpl(FUSE_BATCH_FORGET); 192 CheckNotImpl(FUSE_FALLOCATE); 193 CheckNotImpl(FUSE_READDIRPLUS); 194 CheckNotImpl(FUSE_RENAME2); 195 CheckNotImpl(FUSE_LSEEK); 196 } 197 198 TEST_F(FuseBridgeLoopTest, Proxy) { 199 CheckProxy(FUSE_LOOKUP); 200 CheckProxy(FUSE_GETATTR); 201 CheckProxy(FUSE_READ); 202 CheckProxy(FUSE_WRITE); 203 CheckProxy(FUSE_FSYNC); 204 205 // Invoke FUSE_OPEN and FUSE_RELEASE at last as the loop will exit when all files are closed. 206 CheckProxy(FUSE_OPEN); 207 CheckProxy(FUSE_RELEASE); 208 209 // Ensure the loop exits. 210 Close(); 211 } 212 213 } // namespace fuse 214 } // namespace android 215