summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaichi Hirono2016-10-27 00:57:55 -0500
committerDaichi Hirono2016-10-27 01:04:15 -0500
commitc6134762975204ceebcf7949e364484833714345 (patch)
treeed01ec85a5175e2985e5e62986500da138d09d1d /libappfuse
parent7f8e819ded361e963df7aa648ca2c6d49c7b46b6 (diff)
downloadplatform-system-core-c6134762975204ceebcf7949e364484833714345.tar.gz
platform-system-core-c6134762975204ceebcf7949e364484833714345.tar.xz
platform-system-core-c6134762975204ceebcf7949e364484833714345.zip
Add FuseBridgeLoop to libappfuse.
The CL adds FuseBridgeLoop class to libappfuse, which is used in the system service to proxy fuse commands to applications. Bug: 29970149 Test: libappfuse_test Change-Id: I0708f608b3868721ab16ba4028fd2c17a6735af7
Diffstat (limited to 'libappfuse')
-rw-r--r--libappfuse/Android.bp4
-rw-r--r--libappfuse/FuseBridgeLoop.cc79
-rw-r--r--libappfuse/FuseBuffer.cc (renamed from libappfuse/AppFuse.cc)2
-rw-r--r--libappfuse/include/libappfuse/FuseBridgeLoop.h40
-rw-r--r--libappfuse/include/libappfuse/FuseBuffer.h (renamed from libappfuse/include/libappfuse/AppFuse.h)21
-rw-r--r--libappfuse/tests/FuseBridgeLoopTest.cc196
-rw-r--r--libappfuse/tests/FuseBufferTest.cc (renamed from libappfuse/tests/AppFuseTest.cc)2
7 files changed, 336 insertions, 8 deletions
diff --git a/libappfuse/Android.bp b/libappfuse/Android.bp
index 8d24af10d..8b4615405 100644
--- a/libappfuse/Android.bp
+++ b/libappfuse/Android.bp
@@ -15,12 +15,12 @@ cc_library_shared {
15 name: "libappfuse", 15 name: "libappfuse",
16 defaults: ["libappfuse_defaults"], 16 defaults: ["libappfuse_defaults"],
17 export_include_dirs: ["include"], 17 export_include_dirs: ["include"],
18 srcs: ["AppFuse.cc"] 18 srcs: ["FuseBuffer.cc", "FuseBridgeLoop.cc"]
19} 19}
20 20
21cc_test { 21cc_test {
22 name: "libappfuse_test", 22 name: "libappfuse_test",
23 defaults: ["libappfuse_defaults"], 23 defaults: ["libappfuse_defaults"],
24 shared_libs: ["libappfuse"], 24 shared_libs: ["libappfuse"],
25 srcs: ["tests/AppFuseTest.cc"] 25 srcs: ["tests/FuseBridgeLoopTest.cc", "tests/FuseBufferTest.cc"]
26} 26}
diff --git a/libappfuse/FuseBridgeLoop.cc b/libappfuse/FuseBridgeLoop.cc
new file mode 100644
index 000000000..332556dd1
--- /dev/null
+++ b/libappfuse/FuseBridgeLoop.cc
@@ -0,0 +1,79 @@
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 <android-base/logging.h>
20#include <android-base/unique_fd.h>
21
22namespace android {
23
24bool FuseBridgeLoop::Start(
25 int raw_dev_fd, int raw_proxy_fd, FuseBridgeLoop::Callback* callback) {
26 base::unique_fd dev_fd(raw_dev_fd);
27 base::unique_fd proxy_fd(raw_proxy_fd);
28
29 LOG(DEBUG) << "Start fuse loop.";
30 while (true) {
31 if (!buffer_.request.Read(dev_fd)) {
32 return false;
33 }
34
35 const uint32_t opcode = buffer_.request.header.opcode;
36 LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode;
37 switch (opcode) {
38 case FUSE_FORGET:
39 // Do not reply to FUSE_FORGET.
40 continue;
41
42 case FUSE_LOOKUP:
43 case FUSE_GETATTR:
44 case FUSE_OPEN:
45 case FUSE_READ:
46 case FUSE_WRITE:
47 case FUSE_RELEASE:
48 case FUSE_FLUSH:
49 if (!buffer_.request.Write(proxy_fd)) {
50 LOG(ERROR) << "Failed to write a request to the proxy.";
51 return false;
52 }
53 if (!buffer_.response.Read(proxy_fd)) {
54 LOG(ERROR) << "Failed to read a response from the proxy.";
55 return false;
56 }
57 break;
58
59 case FUSE_INIT:
60 buffer_.HandleInit();
61 break;
62
63 default:
64 buffer_.HandleNotImpl();
65 break;
66 }
67
68 if (!buffer_.response.Write(dev_fd)) {
69 LOG(ERROR) << "Failed to write a response to the device.";
70 return false;
71 }
72
73 if (opcode == FUSE_INIT) {
74 callback->OnMount();
75 }
76 }
77}
78
79} // namespace android
diff --git a/libappfuse/AppFuse.cc b/libappfuse/FuseBuffer.cc
index 8701c4800..45280a5cf 100644
--- a/libappfuse/AppFuse.cc
+++ b/libappfuse/FuseBuffer.cc
@@ -14,7 +14,7 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17#include "libappfuse/AppFuse.h" 17#include "libappfuse/FuseBuffer.h"
18 18
19#include <inttypes.h> 19#include <inttypes.h>
20#include <string.h> 20#include <string.h>
diff --git a/libappfuse/include/libappfuse/FuseBridgeLoop.h b/libappfuse/include/libappfuse/FuseBridgeLoop.h
new file mode 100644
index 000000000..200653252
--- /dev/null
+++ b/libappfuse/include/libappfuse/FuseBridgeLoop.h
@@ -0,0 +1,40 @@
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#ifndef ANDROID_LIBAPPFUSE_FUSEBRIDGELOOP_H_
18#define ANDROID_LIBAPPFUSE_FUSEBRIDGELOOP_H_
19
20#include "libappfuse/FuseBuffer.h"
21
22namespace android {
23
24class FuseBridgeLoop {
25 public:
26 class Callback {
27 public:
28 virtual void OnMount() = 0;
29 virtual ~Callback() = default;
30 };
31
32 bool Start(int dev_fd, int proxy_fd, Callback* callback);
33
34 private:
35 FuseBuffer buffer_;
36};
37
38} // namespace android
39
40#endif // ANDROID_LIBAPPFUSE_FUSEBRIDGELOOP_H_
diff --git a/libappfuse/include/libappfuse/AppFuse.h b/libappfuse/include/libappfuse/FuseBuffer.h
index b6af48d78..071b77715 100644
--- a/libappfuse/include/libappfuse/AppFuse.h
+++ b/libappfuse/include/libappfuse/FuseBuffer.h
@@ -14,8 +14,8 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17#ifndef ANDROID_LIBAPPFUSE_APPFUSE_H_ 17#ifndef ANDROID_LIBAPPFUSE_FUSEBUFFER_H_
18#define ANDROID_LIBAPPFUSE_APPFUSE_H_ 18#define ANDROID_LIBAPPFUSE_FUSEBUFFER_H_
19 19
20#include <linux/fuse.h> 20#include <linux/fuse.h>
21 21
@@ -46,7 +46,7 @@ struct FuseRequest : public FuseMessage<FuseRequest, fuse_in_header> {
46 fuse_open_in open_in; 46 fuse_open_in open_in;
47 fuse_init_in init_in; 47 fuse_init_in init_in;
48 fuse_read_in read_in; 48 fuse_read_in read_in;
49 char lookup_name[]; 49 char lookup_name[0];
50 }; 50 };
51}; 51};
52 52
@@ -71,6 +71,19 @@ union FuseBuffer {
71 void HandleNotImpl(); 71 void HandleNotImpl();
72}; 72};
73 73
74class FuseProxyLoop {
75 class IFuseProxyLoopCallback {
76 public:
77 virtual void OnMount() = 0;
78 virtual ~IFuseProxyLoopCallback() = default;
79 };
80
81 bool Start(int dev_fd, int proxy_fd, IFuseProxyLoopCallback* callback);
82
83 private:
84 FuseBuffer buffer_;
85};
86
74} // namespace android 87} // namespace android
75 88
76#endif // ANDROID_LIBAPPFUSE_APPFUSE_H_ 89#endif // ANDROID_LIBAPPFUSE_FUSEBUFFER_H_
diff --git a/libappfuse/tests/FuseBridgeLoopTest.cc b/libappfuse/tests/FuseBridgeLoopTest.cc
new file mode 100644
index 000000000..31e369041
--- /dev/null
+++ b/libappfuse/tests/FuseBridgeLoopTest.cc
@@ -0,0 +1,196 @@
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 <gtest/gtest.h>
25
26namespace android {
27
28class Callback : public FuseBridgeLoop::Callback {
29 public:
30 bool mounted;
31 Callback() : mounted(false) {}
32 void OnMount() override {
33 mounted = true;
34 }
35};
36
37class FuseBridgeLoopTest : public ::testing::Test {
38 protected:
39 int dev_sockets_[2];
40 int proxy_sockets_[2];
41 Callback callback_;
42 std::thread thread_;
43
44 FuseRequest request_;
45 FuseResponse response_;
46
47 void SetUp() {
48 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, dev_sockets_));
49 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, proxy_sockets_));
50 thread_ = std::thread([this] {
51 FuseBridgeLoop loop;
52 loop.Start(dev_sockets_[1], proxy_sockets_[0], &callback_);
53 });
54 }
55
56 void CheckNotImpl(uint32_t opcode) {
57 SCOPED_TRACE((std::ostringstream() << "opcode: " << opcode).str());
58
59 memset(&request_, 0, sizeof(FuseRequest));
60 request_.header.opcode = opcode;
61 request_.header.len = sizeof(fuse_in_header);
62 ASSERT_TRUE(request_.Write(dev_sockets_[0]));
63
64 memset(&response_, 0, sizeof(FuseResponse));
65 ASSERT_TRUE(response_.Read(dev_sockets_[0]));
66 EXPECT_EQ(-ENOSYS, response_.header.error);
67 }
68
69 void CheckProxy(uint32_t opcode) {
70 SCOPED_TRACE((std::ostringstream() << "opcode: " << opcode).str());
71
72 memset(&request_, 0, sizeof(FuseRequest));
73 request_.header.opcode = opcode;
74 request_.header.unique = opcode; // Use opcode as unique.
75 request_.header.len = sizeof(fuse_in_header);
76 ASSERT_TRUE(request_.Write(dev_sockets_[0]));
77
78 memset(&request_, 0, sizeof(FuseRequest));
79 ASSERT_TRUE(request_.Read(proxy_sockets_[1]));
80 EXPECT_EQ(opcode, request_.header.opcode);
81 EXPECT_EQ(opcode, request_.header.unique);
82
83 memset(&response_, 0, sizeof(FuseResponse));
84 response_.header.len = sizeof(fuse_out_header);
85 response_.header.unique = opcode; // Use opcode as unique.
86 response_.header.error = kFuseSuccess;
87 ASSERT_TRUE(response_.Write(proxy_sockets_[1]));
88
89 memset(&response_, 0, sizeof(FuseResponse));
90 ASSERT_TRUE(response_.Read(dev_sockets_[0]));
91 EXPECT_EQ(opcode, response_.header.unique);
92 EXPECT_EQ(kFuseSuccess, response_.header.error);
93 }
94
95 void SendInitRequest(uint64_t unique) {
96 memset(&request_, 0, sizeof(FuseRequest));
97 request_.header.opcode = FUSE_INIT;
98 request_.header.unique = unique;
99 request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_init_in);
100 request_.init_in.major = FUSE_KERNEL_VERSION;
101 request_.init_in.minor = FUSE_KERNEL_MINOR_VERSION;
102 ASSERT_TRUE(request_.Write(dev_sockets_[0]));
103 }
104
105 void Close() {
106 close(dev_sockets_[0]);
107 close(dev_sockets_[1]);
108 close(proxy_sockets_[0]);
109 close(proxy_sockets_[1]);
110 if (thread_.joinable()) {
111 thread_.join();
112 }
113 }
114
115 void TearDown() {
116 Close();
117 }
118};
119
120TEST_F(FuseBridgeLoopTest, FuseInit) {
121 SendInitRequest(1u);
122
123 memset(&response_, 0, sizeof(FuseResponse));
124 ASSERT_TRUE(response_.Read(dev_sockets_[0]));
125 EXPECT_EQ(kFuseSuccess, response_.header.error);
126 EXPECT_EQ(1u, response_.header.unique);
127
128 // Unmount.
129 Close();
130 EXPECT_TRUE(callback_.mounted);
131}
132
133TEST_F(FuseBridgeLoopTest, FuseForget) {
134 memset(&request_, 0, sizeof(FuseRequest));
135 request_.header.opcode = FUSE_FORGET;
136 request_.header.unique = 1u;
137 request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_forget_in);
138 ASSERT_TRUE(request_.Write(dev_sockets_[0]));
139
140 SendInitRequest(2u);
141
142 memset(&response_, 0, sizeof(FuseResponse));
143 ASSERT_TRUE(response_.Read(dev_sockets_[0]));
144 EXPECT_EQ(2u, response_.header.unique) <<
145 "The loop must not respond to FUSE_FORGET";
146}
147
148TEST_F(FuseBridgeLoopTest, FuseNotImpl) {
149 CheckNotImpl(FUSE_SETATTR);
150 CheckNotImpl(FUSE_READLINK);
151 CheckNotImpl(FUSE_SYMLINK);
152 CheckNotImpl(FUSE_MKNOD);
153 CheckNotImpl(FUSE_MKDIR);
154 CheckNotImpl(FUSE_UNLINK);
155 CheckNotImpl(FUSE_RMDIR);
156 CheckNotImpl(FUSE_RENAME);
157 CheckNotImpl(FUSE_LINK);
158 CheckNotImpl(FUSE_STATFS);
159 CheckNotImpl(FUSE_FSYNC);
160 CheckNotImpl(FUSE_SETXATTR);
161 CheckNotImpl(FUSE_GETXATTR);
162 CheckNotImpl(FUSE_LISTXATTR);
163 CheckNotImpl(FUSE_REMOVEXATTR);
164 CheckNotImpl(FUSE_OPENDIR);
165 CheckNotImpl(FUSE_READDIR);
166 CheckNotImpl(FUSE_RELEASEDIR);
167 CheckNotImpl(FUSE_FSYNCDIR);
168 CheckNotImpl(FUSE_GETLK);
169 CheckNotImpl(FUSE_SETLK);
170 CheckNotImpl(FUSE_SETLKW);
171 CheckNotImpl(FUSE_ACCESS);
172 CheckNotImpl(FUSE_CREATE);
173 CheckNotImpl(FUSE_INTERRUPT);
174 CheckNotImpl(FUSE_BMAP);
175 CheckNotImpl(FUSE_DESTROY);
176 CheckNotImpl(FUSE_IOCTL);
177 CheckNotImpl(FUSE_POLL);
178 CheckNotImpl(FUSE_NOTIFY_REPLY);
179 CheckNotImpl(FUSE_BATCH_FORGET);
180 CheckNotImpl(FUSE_FALLOCATE);
181 CheckNotImpl(FUSE_READDIRPLUS);
182 CheckNotImpl(FUSE_RENAME2);
183 CheckNotImpl(FUSE_LSEEK);
184}
185
186TEST_F(FuseBridgeLoopTest, Proxy) {
187 CheckProxy(FUSE_LOOKUP);
188 CheckProxy(FUSE_GETATTR);
189 CheckProxy(FUSE_OPEN);
190 CheckProxy(FUSE_READ);
191 CheckProxy(FUSE_WRITE);
192 CheckProxy(FUSE_RELEASE);
193 CheckProxy(FUSE_FLUSH);
194}
195
196} // android
diff --git a/libappfuse/tests/AppFuseTest.cc b/libappfuse/tests/FuseBufferTest.cc
index 8c2cc4712..1aacfe303 100644
--- a/libappfuse/tests/AppFuseTest.cc
+++ b/libappfuse/tests/FuseBufferTest.cc
@@ -14,7 +14,7 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17#include "libappfuse/AppFuse.h" 17#include "libappfuse/FuseBuffer.h"
18 18
19#include <fcntl.h> 19#include <fcntl.h>
20#include <string.h> 20#include <string.h>