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
28namespace android {
29namespace fuse {
30namespace {
31
32class 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
43class 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
132TEST_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
145TEST_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
160TEST_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
198TEST_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