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;
Callback()36 Callback() : mounted(false), closed(false) {}
37
OnMount(int)38 void OnMount(int /*mount_id*/) override { mounted = true; }
39
OnClosed(int)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
SetUp()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
CheckNotImpl(uint32_t opcode)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
CheckProxy(uint32_t opcode)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
SendInitRequest(uint64_t unique)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
Close()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
TearDown()124 void TearDown() override {
125 Close();
126 }
127 };
128
129 } // namespace
130
TEST_F(FuseBridgeLoopTest,FuseInit)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
TEST_F(FuseBridgeLoopTest,FuseForget)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
TEST_F(FuseBridgeLoopTest,FuseNotImpl)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
TEST_F(FuseBridgeLoopTest,Proxy)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