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 ASSERT_TRUE(request_.Write(dev_sockets_[0])); 71 72 memset(&response_, 0, sizeof(FuseResponse)); 73 ASSERT_TRUE(response_.Read(dev_sockets_[0])); 74 EXPECT_EQ(-ENOSYS, response_.header.error); 75 } 76 77 void CheckProxy(uint32_t opcode) { 78 SCOPED_TRACE((std::ostringstream() << "opcode: " << opcode).str()); 79 80 memset(&request_, 0, sizeof(FuseRequest)); 81 request_.header.opcode = opcode; 82 request_.header.unique = opcode; // Use opcode as unique. 83 request_.header.len = sizeof(fuse_in_header); 84 ASSERT_TRUE(request_.Write(dev_sockets_[0])); 85 86 memset(&request_, 0, sizeof(FuseRequest)); 87 ASSERT_TRUE(request_.Read(proxy_sockets_[1])); 88 EXPECT_EQ(opcode, request_.header.opcode); 89 EXPECT_EQ(opcode, request_.header.unique); 90 91 memset(&response_, 0, sizeof(FuseResponse)); 92 response_.header.len = sizeof(fuse_out_header); 93 response_.header.unique = opcode; // Use opcode as unique. 94 response_.header.error = kFuseSuccess; 95 ASSERT_TRUE(response_.Write(proxy_sockets_[1])); 96 97 memset(&response_, 0, sizeof(FuseResponse)); 98 ASSERT_TRUE(response_.Read(dev_sockets_[0])); 99 EXPECT_EQ(opcode, response_.header.unique); 100 EXPECT_EQ(kFuseSuccess, response_.header.error); 101 } 102 103 void SendInitRequest(uint64_t unique) { 104 memset(&request_, 0, sizeof(FuseRequest)); 105 request_.header.opcode = FUSE_INIT; 106 request_.header.unique = unique; 107 request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_init_in); 108 request_.init_in.major = FUSE_KERNEL_VERSION; 109 request_.init_in.minor = FUSE_KERNEL_MINOR_VERSION; 110 ASSERT_TRUE(request_.Write(dev_sockets_[0])); 111 } 112 113 void Close() { 114 dev_sockets_[0].reset(); 115 dev_sockets_[1].reset(); 116 proxy_sockets_[0].reset(); 117 proxy_sockets_[1].reset(); 118 if (thread_.joinable()) { 119 thread_.join(); 120 } 121 ASSERT_TRUE(callback_.closed); 122 } 123 124 void TearDown() override { 125 Close(); 126 } 127 }; 128 129 } // namespace 130 131 TEST_F(FuseBridgeLoopTest, FuseInit) { 132 SendInitRequest(1u); 133 134 memset(&response_, 0, sizeof(FuseResponse)); 135 ASSERT_TRUE(response_.Read(dev_sockets_[0])); 136 EXPECT_EQ(kFuseSuccess, response_.header.error); 137 EXPECT_EQ(1u, response_.header.unique); 138 139 // Unmount. 140 Close(); 141 EXPECT_TRUE(callback_.mounted); 142 } 143 144 TEST_F(FuseBridgeLoopTest, FuseForget) { 145 memset(&request_, 0, sizeof(FuseRequest)); 146 request_.header.opcode = FUSE_FORGET; 147 request_.header.unique = 1u; 148 request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_forget_in); 149 ASSERT_TRUE(request_.Write(dev_sockets_[0])); 150 151 SendInitRequest(2u); 152 153 memset(&response_, 0, sizeof(FuseResponse)); 154 ASSERT_TRUE(response_.Read(dev_sockets_[0])); 155 EXPECT_EQ(2u, response_.header.unique) << 156 "The loop must not respond to FUSE_FORGET"; 157 } 158 159 TEST_F(FuseBridgeLoopTest, FuseNotImpl) { 160 CheckNotImpl(FUSE_SETATTR); 161 CheckNotImpl(FUSE_READLINK); 162 CheckNotImpl(FUSE_SYMLINK); 163 CheckNotImpl(FUSE_MKNOD); 164 CheckNotImpl(FUSE_MKDIR); 165 CheckNotImpl(FUSE_UNLINK); 166 CheckNotImpl(FUSE_RMDIR); 167 CheckNotImpl(FUSE_RENAME); 168 CheckNotImpl(FUSE_LINK); 169 CheckNotImpl(FUSE_STATFS); 170 CheckNotImpl(FUSE_SETXATTR); 171 CheckNotImpl(FUSE_GETXATTR); 172 CheckNotImpl(FUSE_LISTXATTR); 173 CheckNotImpl(FUSE_REMOVEXATTR); 174 CheckNotImpl(FUSE_FLUSH); 175 CheckNotImpl(FUSE_OPENDIR); 176 CheckNotImpl(FUSE_READDIR); 177 CheckNotImpl(FUSE_RELEASEDIR); 178 CheckNotImpl(FUSE_FSYNCDIR); 179 CheckNotImpl(FUSE_GETLK); 180 CheckNotImpl(FUSE_SETLK); 181 CheckNotImpl(FUSE_SETLKW); 182 CheckNotImpl(FUSE_ACCESS); 183 CheckNotImpl(FUSE_CREATE); 184 CheckNotImpl(FUSE_INTERRUPT); 185 CheckNotImpl(FUSE_BMAP); 186 CheckNotImpl(FUSE_DESTROY); 187 CheckNotImpl(FUSE_IOCTL); 188 CheckNotImpl(FUSE_POLL); 189 CheckNotImpl(FUSE_NOTIFY_REPLY); 190 CheckNotImpl(FUSE_BATCH_FORGET); 191 CheckNotImpl(FUSE_FALLOCATE); 192 CheckNotImpl(FUSE_READDIRPLUS); 193 CheckNotImpl(FUSE_RENAME2); 194 CheckNotImpl(FUSE_LSEEK); 195 } 196 197 TEST_F(FuseBridgeLoopTest, Proxy) { 198 CheckProxy(FUSE_LOOKUP); 199 CheckProxy(FUSE_GETATTR); 200 CheckProxy(FUSE_READ); 201 CheckProxy(FUSE_WRITE); 202 CheckProxy(FUSE_FSYNC); 203 204 // Invoke FUSE_OPEN and FUSE_RELEASE at last as the loop will exit when all files are closed. 205 CheckProxy(FUSE_OPEN); 206 CheckProxy(FUSE_RELEASE); 207 208 // Ensure the loop exits. 209 Close(); 210 } 211 212 } // namespace fuse 213 } // namespace android 214