diff options
Diffstat (limited to 'libappfuse')
-rw-r--r-- | libappfuse/FuseAppLoop.cc | 345 | ||||
-rw-r--r-- | libappfuse/include/libappfuse/FuseAppLoop.h | 48 | ||||
-rw-r--r-- | libappfuse/tests/FuseAppLoopTest.cc | 111 |
3 files changed, 277 insertions, 227 deletions
diff --git a/libappfuse/FuseAppLoop.cc b/libappfuse/FuseAppLoop.cc index a31880e41..b6bc191b7 100644 --- a/libappfuse/FuseAppLoop.cc +++ b/libappfuse/FuseAppLoop.cc | |||
@@ -16,205 +16,232 @@ | |||
16 | 16 | ||
17 | #include "libappfuse/FuseAppLoop.h" | 17 | #include "libappfuse/FuseAppLoop.h" |
18 | 18 | ||
19 | #include <sys/eventfd.h> | ||
19 | #include <sys/stat.h> | 20 | #include <sys/stat.h> |
20 | 21 | ||
21 | #include <android-base/logging.h> | 22 | #include <android-base/logging.h> |
22 | #include <android-base/unique_fd.h> | 23 | #include <android-base/unique_fd.h> |
23 | 24 | ||
25 | #include "libappfuse/EpollController.h" | ||
26 | |||
24 | namespace android { | 27 | namespace android { |
25 | namespace fuse { | 28 | namespace fuse { |
26 | 29 | ||
27 | namespace { | 30 | namespace { |
28 | 31 | ||
29 | void HandleLookUp(FuseBuffer* buffer, FuseAppLoopCallback* callback) { | 32 | bool HandleLookUp(FuseAppLoop* loop, FuseBuffer* buffer, FuseAppLoopCallback* callback) { |
30 | // AppFuse does not support directory structure now. | 33 | // AppFuse does not support directory structure now. |
31 | // It can lookup only files under the mount point. | 34 | // It can lookup only files under the mount point. |
32 | if (buffer->request.header.nodeid != FUSE_ROOT_ID) { | 35 | if (buffer->request.header.nodeid != FUSE_ROOT_ID) { |
33 | LOG(ERROR) << "Nodeid is not FUSE_ROOT_ID."; | 36 | LOG(ERROR) << "Nodeid is not FUSE_ROOT_ID."; |
34 | buffer->response.Reset(0, -ENOENT, buffer->request.header.unique); | 37 | return loop->ReplySimple(buffer->request.header.unique, -ENOENT); |
35 | return; | 38 | } |
36 | } | ||
37 | |||
38 | // Ensure that the filename ends with 0. | ||
39 | const size_t filename_length = | ||
40 | buffer->request.header.len - sizeof(fuse_in_header); | ||
41 | if (buffer->request.lookup_name[filename_length - 1] != 0) { | ||
42 | LOG(ERROR) << "File name does not end with 0."; | ||
43 | buffer->response.Reset(0, -ENOENT, buffer->request.header.unique); | ||
44 | return; | ||
45 | } | ||
46 | |||
47 | const uint64_t inode = | ||
48 | static_cast<uint64_t>(atol(buffer->request.lookup_name)); | ||
49 | if (inode == 0 || inode == LONG_MAX) { | ||
50 | LOG(ERROR) << "Invalid filename"; | ||
51 | buffer->response.Reset(0, -ENOENT, buffer->request.header.unique); | ||
52 | return; | ||
53 | } | ||
54 | |||
55 | const int64_t size = callback->OnGetSize(inode); | ||
56 | if (size < 0) { | ||
57 | buffer->response.Reset(0, size, buffer->request.header.unique); | ||
58 | return; | ||
59 | } | ||
60 | |||
61 | buffer->response.Reset(sizeof(fuse_entry_out), 0, | ||
62 | buffer->request.header.unique); | ||
63 | buffer->response.entry_out.nodeid = inode; | ||
64 | buffer->response.entry_out.attr_valid = 10; | ||
65 | buffer->response.entry_out.entry_valid = 10; | ||
66 | buffer->response.entry_out.attr.ino = inode; | ||
67 | buffer->response.entry_out.attr.mode = S_IFREG | 0777; | ||
68 | buffer->response.entry_out.attr.size = size; | ||
69 | } | ||
70 | 39 | ||
71 | void HandleGetAttr(FuseBuffer* buffer, FuseAppLoopCallback* callback) { | 40 | // Ensure that the filename ends with 0. |
72 | const uint64_t nodeid = buffer->request.header.nodeid; | 41 | const size_t filename_length = buffer->request.header.len - sizeof(fuse_in_header); |
73 | int64_t size; | 42 | if (buffer->request.lookup_name[filename_length - 1] != 0) { |
74 | uint32_t mode; | 43 | LOG(ERROR) << "File name does not end with 0."; |
75 | if (nodeid == FUSE_ROOT_ID) { | 44 | return loop->ReplySimple(buffer->request.header.unique, -ENOENT); |
76 | size = 0; | 45 | } |
77 | mode = S_IFDIR | 0777; | 46 | |
78 | } else { | 47 | const uint64_t inode = static_cast<uint64_t>(atol(buffer->request.lookup_name)); |
79 | size = callback->OnGetSize(buffer->request.header.nodeid); | 48 | if (inode == 0 || inode == LONG_MAX) { |
80 | if (size < 0) { | 49 | LOG(ERROR) << "Invalid filename"; |
81 | buffer->response.Reset(0, size, buffer->request.header.unique); | 50 | return loop->ReplySimple(buffer->request.header.unique, -ENOENT); |
82 | return; | ||
83 | } | 51 | } |
84 | mode = S_IFREG | 0777; | ||
85 | } | ||
86 | |||
87 | buffer->response.Reset(sizeof(fuse_attr_out), 0, | ||
88 | buffer->request.header.unique); | ||
89 | buffer->response.attr_out.attr_valid = 10; | ||
90 | buffer->response.attr_out.attr.ino = nodeid; | ||
91 | buffer->response.attr_out.attr.mode = mode; | ||
92 | buffer->response.attr_out.attr.size = size; | ||
93 | } | ||
94 | 52 | ||
95 | void HandleOpen(FuseBuffer* buffer, FuseAppLoopCallback* callback) { | 53 | callback->OnLookup(buffer->request.header.unique, inode); |
96 | const int32_t file_handle = callback->OnOpen(buffer->request.header.nodeid); | 54 | return true; |
97 | if (file_handle < 0) { | ||
98 | buffer->response.Reset(0, file_handle, buffer->request.header.unique); | ||
99 | return; | ||
100 | } | ||
101 | buffer->response.Reset(sizeof(fuse_open_out), kFuseSuccess, | ||
102 | buffer->request.header.unique); | ||
103 | buffer->response.open_out.fh = file_handle; | ||
104 | } | 55 | } |
105 | 56 | ||
106 | void HandleFsync(FuseBuffer* buffer, FuseAppLoopCallback* callback) { | 57 | bool HandleGetAttr(FuseAppLoop* loop, FuseBuffer* buffer, FuseAppLoopCallback* callback) { |
107 | buffer->response.Reset(0, callback->OnFsync(buffer->request.header.nodeid), | 58 | if (buffer->request.header.nodeid == FUSE_ROOT_ID) { |
108 | buffer->request.header.unique); | 59 | return loop->ReplyGetAttr(buffer->request.header.unique, buffer->request.header.nodeid, 0, |
60 | S_IFDIR | 0777); | ||
61 | } else { | ||
62 | callback->OnGetAttr(buffer->request.header.unique, buffer->request.header.nodeid); | ||
63 | return true; | ||
64 | } | ||
109 | } | 65 | } |
110 | 66 | ||
111 | void HandleRelease(FuseBuffer* buffer, FuseAppLoopCallback* callback) { | 67 | bool HandleRead(FuseAppLoop* loop, FuseBuffer* buffer, FuseAppLoopCallback* callback) { |
112 | buffer->response.Reset(0, callback->OnRelease(buffer->request.header.nodeid), | 68 | if (buffer->request.read_in.size > kFuseMaxRead) { |
113 | buffer->request.header.unique); | 69 | return loop->ReplySimple(buffer->request.header.unique, -EINVAL); |
70 | } | ||
71 | |||
72 | callback->OnRead(buffer->request.header.unique, buffer->request.header.nodeid, | ||
73 | buffer->request.read_in.offset, buffer->request.read_in.size); | ||
74 | return true; | ||
114 | } | 75 | } |
115 | 76 | ||
116 | void HandleRead(FuseBuffer* buffer, FuseAppLoopCallback* callback) { | 77 | bool HandleWrite(FuseAppLoop* loop, FuseBuffer* buffer, FuseAppLoopCallback* callback) { |
117 | const uint64_t unique = buffer->request.header.unique; | 78 | if (buffer->request.write_in.size > kFuseMaxWrite) { |
118 | const uint64_t nodeid = buffer->request.header.nodeid; | 79 | return loop->ReplySimple(buffer->request.header.unique, -EINVAL); |
119 | const uint64_t offset = buffer->request.read_in.offset; | 80 | } |
120 | const uint32_t size = buffer->request.read_in.size; | 81 | |
121 | 82 | callback->OnWrite(buffer->request.header.unique, buffer->request.header.nodeid, | |
122 | if (size > kFuseMaxRead) { | 83 | buffer->request.write_in.offset, buffer->request.write_in.size, |
123 | buffer->response.Reset(0, -EINVAL, buffer->request.header.unique); | 84 | buffer->request.write_data); |
124 | return; | 85 | return true; |
125 | } | ||
126 | |||
127 | const int32_t read_size = callback->OnRead(nodeid, offset, size, | ||
128 | buffer->response.read_data); | ||
129 | if (read_size < 0) { | ||
130 | buffer->response.Reset(0, read_size, buffer->request.header.unique); | ||
131 | return; | ||
132 | } | ||
133 | |||
134 | buffer->response.ResetHeader(read_size, kFuseSuccess, unique); | ||
135 | } | 86 | } |
136 | 87 | ||
137 | void HandleWrite(FuseBuffer* buffer, FuseAppLoopCallback* callback) { | 88 | bool HandleMessage(FuseAppLoop* loop, FuseBuffer* buffer, int fd, FuseAppLoopCallback* callback) { |
138 | const uint64_t unique = buffer->request.header.unique; | 89 | if (!buffer->request.Read(fd)) { |
139 | const uint64_t nodeid = buffer->request.header.nodeid; | 90 | return false; |
140 | const uint64_t offset = buffer->request.write_in.offset; | 91 | } |
141 | const uint32_t size = buffer->request.write_in.size; | 92 | |
142 | 93 | const uint32_t opcode = buffer->request.header.opcode; | |
143 | if (size > kFuseMaxWrite) { | 94 | LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode; |
144 | buffer->response.Reset(0, -EINVAL, buffer->request.header.unique); | 95 | switch (opcode) { |
145 | return; | 96 | case FUSE_FORGET: |
146 | } | 97 | // Do not reply to FUSE_FORGET. |
147 | 98 | return true; | |
148 | const int32_t write_size = callback->OnWrite(nodeid, offset, size, | 99 | |
149 | buffer->request.write_data); | 100 | case FUSE_LOOKUP: |
150 | if (write_size < 0) { | 101 | return HandleLookUp(loop, buffer, callback); |
151 | buffer->response.Reset(0, write_size, buffer->request.header.unique); | 102 | |
152 | return; | 103 | case FUSE_GETATTR: |
153 | } | 104 | return HandleGetAttr(loop, buffer, callback); |
154 | 105 | ||
155 | buffer->response.Reset(sizeof(fuse_write_out), kFuseSuccess, unique); | 106 | case FUSE_OPEN: |
156 | buffer->response.write_out.size = write_size; | 107 | callback->OnOpen(buffer->request.header.unique, buffer->request.header.nodeid); |
108 | return true; | ||
109 | |||
110 | case FUSE_READ: | ||
111 | return HandleRead(loop, buffer, callback); | ||
112 | |||
113 | case FUSE_WRITE: | ||
114 | return HandleWrite(loop, buffer, callback); | ||
115 | |||
116 | case FUSE_RELEASE: | ||
117 | callback->OnRelease(buffer->request.header.unique, buffer->request.header.nodeid); | ||
118 | return true; | ||
119 | |||
120 | case FUSE_FSYNC: | ||
121 | callback->OnFsync(buffer->request.header.unique, buffer->request.header.nodeid); | ||
122 | return true; | ||
123 | |||
124 | default: | ||
125 | buffer->HandleNotImpl(); | ||
126 | return buffer->response.Write(fd); | ||
127 | } | ||
157 | } | 128 | } |
158 | 129 | ||
159 | } // namespace | 130 | } // namespace |
160 | 131 | ||
161 | bool StartFuseAppLoop(int raw_fd, FuseAppLoopCallback* callback) { | 132 | FuseAppLoopCallback::~FuseAppLoopCallback() = default; |
162 | base::unique_fd fd(raw_fd); | 133 | |
163 | FuseBuffer buffer; | 134 | FuseAppLoop::FuseAppLoop(base::unique_fd&& fd) : fd_(std::move(fd)) {} |
164 | 135 | ||
165 | LOG(DEBUG) << "Start fuse loop."; | 136 | void FuseAppLoop::Break() { |
166 | while (callback->IsActive()) { | 137 | const int64_t value = 1; |
167 | if (!buffer.request.Read(fd)) { | 138 | if (write(break_fd_, &value, sizeof(value)) == -1) { |
168 | return false; | 139 | PLOG(ERROR) << "Failed to send a break event"; |
169 | } | 140 | } |
141 | } | ||
170 | 142 | ||
171 | const uint32_t opcode = buffer.request.header.opcode; | 143 | bool FuseAppLoop::ReplySimple(uint64_t unique, int32_t result) { |
172 | LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode; | 144 | if (result == -ENOSYS) { |
173 | switch (opcode) { | 145 | // We should not return -ENOSYS because the kernel stops delivering FUSE |
174 | case FUSE_FORGET: | 146 | // command after receiving -ENOSYS as a result for the command. |
175 | // Do not reply to FUSE_FORGET. | 147 | result = -EBADF; |
176 | continue; | 148 | } |
149 | FuseSimpleResponse response; | ||
150 | response.Reset(0, result, unique); | ||
151 | return response.Write(fd_); | ||
152 | } | ||
177 | 153 | ||
178 | case FUSE_LOOKUP: | 154 | bool FuseAppLoop::ReplyLookup(uint64_t unique, uint64_t inode, int64_t size) { |
179 | HandleLookUp(&buffer, callback); | 155 | FuseSimpleResponse response; |
180 | break; | 156 | response.Reset(sizeof(fuse_entry_out), 0, unique); |
157 | response.entry_out.nodeid = inode; | ||
158 | response.entry_out.attr_valid = 10; | ||
159 | response.entry_out.entry_valid = 10; | ||
160 | response.entry_out.attr.ino = inode; | ||
161 | response.entry_out.attr.mode = S_IFREG | 0777; | ||
162 | response.entry_out.attr.size = size; | ||
163 | return response.Write(fd_); | ||
164 | } | ||
181 | 165 | ||
182 | case FUSE_GETATTR: | 166 | bool FuseAppLoop::ReplyGetAttr(uint64_t unique, uint64_t inode, int64_t size, int mode) { |
183 | HandleGetAttr(&buffer, callback); | 167 | CHECK(mode == (S_IFREG | 0777) || mode == (S_IFDIR | 0777)); |
184 | break; | 168 | FuseSimpleResponse response; |
169 | response.Reset(sizeof(fuse_attr_out), 0, unique); | ||
170 | response.attr_out.attr_valid = 10; | ||
171 | response.attr_out.attr.ino = inode; | ||
172 | response.attr_out.attr.mode = mode; | ||
173 | response.attr_out.attr.size = size; | ||
174 | return response.Write(fd_); | ||
175 | } | ||
185 | 176 | ||
186 | case FUSE_OPEN: | 177 | bool FuseAppLoop::ReplyOpen(uint64_t unique, uint64_t fh) { |
187 | HandleOpen(&buffer, callback); | 178 | FuseSimpleResponse response; |
188 | break; | 179 | response.Reset(sizeof(fuse_open_out), kFuseSuccess, unique); |
180 | response.open_out.fh = fh; | ||
181 | return response.Write(fd_); | ||
182 | } | ||
189 | 183 | ||
190 | case FUSE_READ: | 184 | bool FuseAppLoop::ReplyWrite(uint64_t unique, uint32_t size) { |
191 | HandleRead(&buffer, callback); | 185 | CHECK(size <= kFuseMaxWrite); |
192 | break; | 186 | FuseSimpleResponse response; |
187 | response.Reset(sizeof(fuse_write_out), kFuseSuccess, unique); | ||
188 | response.write_out.size = size; | ||
189 | return response.Write(fd_); | ||
190 | } | ||
193 | 191 | ||
194 | case FUSE_WRITE: | 192 | bool FuseAppLoop::ReplyRead(uint64_t unique, uint32_t size, const void* data) { |
195 | HandleWrite(&buffer, callback); | 193 | CHECK(size <= kFuseMaxRead); |
196 | break; | 194 | FuseSimpleResponse response; |
195 | response.ResetHeader(size, kFuseSuccess, unique); | ||
196 | return response.WriteWithBody(fd_, sizeof(FuseResponse), data); | ||
197 | } | ||
197 | 198 | ||
198 | case FUSE_RELEASE: | 199 | void FuseAppLoop::Start(FuseAppLoopCallback* callback) { |
199 | HandleRelease(&buffer, callback); | 200 | break_fd_.reset(eventfd(/* initval */ 0, EFD_CLOEXEC)); |
200 | break; | 201 | if (break_fd_.get() == -1) { |
202 | PLOG(ERROR) << "Failed to open FD for break event"; | ||
203 | return; | ||
204 | } | ||
205 | |||
206 | base::unique_fd epoll_fd(epoll_create1(EPOLL_CLOEXEC)); | ||
207 | if (epoll_fd.get() == -1) { | ||
208 | PLOG(ERROR) << "Failed to open FD for epoll"; | ||
209 | return; | ||
210 | } | ||
201 | 211 | ||
202 | case FUSE_FSYNC: | 212 | int last_event; |
203 | HandleFsync(&buffer, callback); | 213 | int break_event; |
204 | break; | ||
205 | 214 | ||
206 | default: | 215 | std::unique_ptr<EpollController> epoll_controller(new EpollController(std::move(epoll_fd))); |
207 | buffer.HandleNotImpl(); | 216 | if (!epoll_controller->AddFd(fd_, EPOLLIN, &last_event)) { |
208 | break; | 217 | return; |
218 | } | ||
219 | if (!epoll_controller->AddFd(break_fd_, EPOLLIN, &break_event)) { | ||
220 | return; | ||
209 | } | 221 | } |
210 | 222 | ||
211 | if (!buffer.response.Write(fd)) { | 223 | last_event = 0; |
212 | LOG(ERROR) << "Failed to write a response to the device."; | 224 | break_event = 0; |
213 | return false; | 225 | |
226 | FuseBuffer buffer; | ||
227 | while (true) { | ||
228 | if (!epoll_controller->Wait(1)) { | ||
229 | break; | ||
230 | } | ||
231 | last_event = 0; | ||
232 | *reinterpret_cast<int*>(epoll_controller->events()[0].data.ptr) = | ||
233 | epoll_controller->events()[0].events; | ||
234 | |||
235 | if (break_event != 0 || (last_event & ~EPOLLIN) != 0) { | ||
236 | break; | ||
237 | } | ||
238 | |||
239 | if (!HandleMessage(this, &buffer, fd_, callback)) { | ||
240 | break; | ||
241 | } | ||
214 | } | 242 | } |
215 | } | ||
216 | 243 | ||
217 | return true; | 244 | LOG(VERBOSE) << "FuseAppLoop exit"; |
218 | } | 245 | } |
219 | 246 | ||
220 | } // namespace fuse | 247 | } // namespace fuse |
diff --git a/libappfuse/include/libappfuse/FuseAppLoop.h b/libappfuse/include/libappfuse/FuseAppLoop.h index c3edfcc32..f2ef2b5c5 100644 --- a/libappfuse/include/libappfuse/FuseAppLoop.h +++ b/libappfuse/include/libappfuse/FuseAppLoop.h | |||
@@ -17,23 +17,51 @@ | |||
17 | #ifndef ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_ | 17 | #ifndef ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_ |
18 | #define ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_ | 18 | #define ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_ |
19 | 19 | ||
20 | #include <memory> | ||
21 | #include <mutex> | ||
22 | |||
23 | #include <android-base/unique_fd.h> | ||
24 | |||
20 | #include "libappfuse/FuseBuffer.h" | 25 | #include "libappfuse/FuseBuffer.h" |
21 | 26 | ||
22 | namespace android { | 27 | namespace android { |
23 | namespace fuse { | 28 | namespace fuse { |
24 | 29 | ||
30 | class EpollController; | ||
31 | |||
25 | class FuseAppLoopCallback { | 32 | class FuseAppLoopCallback { |
26 | public: | 33 | public: |
27 | virtual bool IsActive() = 0; | 34 | virtual void OnLookup(uint64_t unique, uint64_t inode) = 0; |
28 | virtual int64_t OnGetSize(uint64_t inode) = 0; | 35 | virtual void OnGetAttr(uint64_t unique, uint64_t inode) = 0; |
29 | virtual int32_t OnFsync(uint64_t inode) = 0; | 36 | virtual void OnFsync(uint64_t unique, uint64_t inode) = 0; |
30 | virtual int32_t OnWrite( | 37 | virtual void OnWrite(uint64_t unique, uint64_t inode, uint64_t offset, uint32_t size, |
31 | uint64_t inode, uint64_t offset, uint32_t size, const void* data) = 0; | 38 | const void* data) = 0; |
32 | virtual int32_t OnRead( | 39 | virtual void OnRead(uint64_t unique, uint64_t inode, uint64_t offset, uint32_t size) = 0; |
33 | uint64_t inode, uint64_t offset, uint32_t size, void* data) = 0; | 40 | virtual void OnOpen(uint64_t unique, uint64_t inode) = 0; |
34 | virtual int32_t OnOpen(uint64_t inode) = 0; | 41 | virtual void OnRelease(uint64_t unique, uint64_t inode) = 0; |
35 | virtual int32_t OnRelease(uint64_t inode) = 0; | 42 | virtual ~FuseAppLoopCallback(); |
36 | virtual ~FuseAppLoopCallback() = default; | 43 | }; |
44 | |||
45 | class FuseAppLoop final { | ||
46 | public: | ||
47 | FuseAppLoop(base::unique_fd&& fd); | ||
48 | |||
49 | void Start(FuseAppLoopCallback* callback); | ||
50 | void Break(); | ||
51 | |||
52 | bool ReplySimple(uint64_t unique, int32_t result); | ||
53 | bool ReplyLookup(uint64_t unique, uint64_t inode, int64_t size); | ||
54 | bool ReplyGetAttr(uint64_t unique, uint64_t inode, int64_t size, int mode); | ||
55 | bool ReplyOpen(uint64_t unique, uint64_t fh); | ||
56 | bool ReplyWrite(uint64_t unique, uint32_t size); | ||
57 | bool ReplyRead(uint64_t unique, uint32_t size, const void* data); | ||
58 | |||
59 | private: | ||
60 | base::unique_fd fd_; | ||
61 | base::unique_fd break_fd_; | ||
62 | |||
63 | // Lock for multi-threading. | ||
64 | std::mutex mutex_; | ||
37 | }; | 65 | }; |
38 | 66 | ||
39 | bool StartFuseAppLoop(int fd, FuseAppLoopCallback* callback); | 67 | bool StartFuseAppLoop(int fd, FuseAppLoopCallback* callback); |
diff --git a/libappfuse/tests/FuseAppLoopTest.cc b/libappfuse/tests/FuseAppLoopTest.cc index 64dd81330..98e36652a 100644 --- a/libappfuse/tests/FuseAppLoopTest.cc +++ b/libappfuse/tests/FuseAppLoopTest.cc | |||
@@ -23,6 +23,9 @@ | |||
23 | #include <gtest/gtest.h> | 23 | #include <gtest/gtest.h> |
24 | #include <thread> | 24 | #include <thread> |
25 | 25 | ||
26 | #include "libappfuse/EpollController.h" | ||
27 | #include "libappfuse/FuseBridgeLoop.h" | ||
28 | |||
26 | namespace android { | 29 | namespace android { |
27 | namespace fuse { | 30 | namespace fuse { |
28 | namespace { | 31 | namespace { |
@@ -37,82 +40,61 @@ struct CallbackRequest { | |||
37 | class Callback : public FuseAppLoopCallback { | 40 | class Callback : public FuseAppLoopCallback { |
38 | public: | 41 | public: |
39 | std::vector<CallbackRequest> requests; | 42 | std::vector<CallbackRequest> requests; |
43 | FuseAppLoop* loop; | ||
40 | 44 | ||
41 | bool IsActive() override { | 45 | void OnGetAttr(uint64_t seq, uint64_t inode) override { |
42 | return true; | 46 | EXPECT_NE(FUSE_ROOT_ID, static_cast<int>(inode)); |
47 | EXPECT_TRUE(loop->ReplyGetAttr(seq, inode, kTestFileSize, S_IFREG | 0777)); | ||
43 | } | 48 | } |
44 | 49 | ||
45 | int64_t OnGetSize(uint64_t inode) override { | 50 | void OnLookup(uint64_t unique, uint64_t inode) override { |
46 | if (inode == FUSE_ROOT_ID) { | 51 | EXPECT_NE(FUSE_ROOT_ID, static_cast<int>(inode)); |
47 | return 0; | 52 | EXPECT_TRUE(loop->ReplyLookup(unique, inode, kTestFileSize)); |
48 | } else { | ||
49 | return kTestFileSize; | ||
50 | } | ||
51 | } | 53 | } |
52 | 54 | ||
53 | int32_t OnFsync(uint64_t inode) override { | 55 | void OnFsync(uint64_t seq, uint64_t inode) override { |
54 | requests.push_back({ | 56 | requests.push_back({.code = FUSE_FSYNC, .inode = inode}); |
55 | .code = FUSE_FSYNC, | 57 | loop->ReplySimple(seq, 0); |
56 | .inode = inode | ||
57 | }); | ||
58 | return 0; | ||
59 | } | 58 | } |
60 | 59 | ||
61 | int32_t OnWrite(uint64_t inode, | 60 | void OnWrite(uint64_t seq, uint64_t inode, uint64_t offset ATTRIBUTE_UNUSED, |
62 | uint64_t offset ATTRIBUTE_UNUSED, | 61 | uint32_t size ATTRIBUTE_UNUSED, const void* data ATTRIBUTE_UNUSED) override { |
63 | uint32_t size ATTRIBUTE_UNUSED, | 62 | requests.push_back({.code = FUSE_WRITE, .inode = inode}); |
64 | const void* data ATTRIBUTE_UNUSED) override { | 63 | loop->ReplyWrite(seq, 0); |
65 | requests.push_back({ | ||
66 | .code = FUSE_WRITE, | ||
67 | .inode = inode | ||
68 | }); | ||
69 | return 0; | ||
70 | } | 64 | } |
71 | 65 | ||
72 | int32_t OnRead(uint64_t inode, | 66 | void OnRead(uint64_t seq, uint64_t inode, uint64_t offset ATTRIBUTE_UNUSED, |
73 | uint64_t offset ATTRIBUTE_UNUSED, | 67 | uint32_t size ATTRIBUTE_UNUSED) override { |
74 | uint32_t size ATTRIBUTE_UNUSED, | 68 | requests.push_back({.code = FUSE_READ, .inode = inode}); |
75 | void* data ATTRIBUTE_UNUSED) override { | 69 | loop->ReplySimple(seq, 0); |
76 | requests.push_back({ | ||
77 | .code = FUSE_READ, | ||
78 | .inode = inode | ||
79 | }); | ||
80 | return 0; | ||
81 | } | 70 | } |
82 | 71 | ||
83 | int32_t OnOpen(uint64_t inode) override { | 72 | void OnOpen(uint64_t seq, uint64_t inode) override { |
84 | requests.push_back({ | 73 | requests.push_back({.code = FUSE_OPEN, .inode = inode}); |
85 | .code = FUSE_OPEN, | 74 | loop->ReplyOpen(seq, inode); |
86 | .inode = inode | ||
87 | }); | ||
88 | return 0; | ||
89 | } | 75 | } |
90 | 76 | ||
91 | int32_t OnRelease(uint64_t inode) override { | 77 | void OnRelease(uint64_t seq, uint64_t inode) override { |
92 | requests.push_back({ | 78 | requests.push_back({.code = FUSE_RELEASE, .inode = inode}); |
93 | .code = FUSE_RELEASE, | 79 | loop->ReplySimple(seq, 0); |
94 | .inode = inode | ||
95 | }); | ||
96 | return 0; | ||
97 | } | 80 | } |
98 | }; | 81 | }; |
99 | 82 | ||
100 | class FuseAppLoopTest : public ::testing::Test { | 83 | class FuseAppLoopTest : public ::testing::Test { |
101 | private: | ||
102 | std::thread thread_; | ||
103 | |||
104 | protected: | 84 | protected: |
105 | base::unique_fd sockets_[2]; | 85 | std::thread thread_; |
106 | Callback callback_; | 86 | base::unique_fd sockets_[2]; |
107 | FuseRequest request_; | 87 | Callback callback_; |
108 | FuseResponse response_; | 88 | FuseRequest request_; |
109 | 89 | FuseResponse response_; | |
110 | void SetUp() override { | 90 | std::unique_ptr<FuseAppLoop> loop_; |
111 | base::SetMinimumLogSeverity(base::VERBOSE); | 91 | |
112 | ASSERT_TRUE(SetupMessageSockets(&sockets_)); | 92 | void SetUp() override { |
113 | thread_ = std::thread([this] { | 93 | base::SetMinimumLogSeverity(base::VERBOSE); |
114 | StartFuseAppLoop(sockets_[1].release(), &callback_); | 94 | ASSERT_TRUE(SetupMessageSockets(&sockets_)); |
115 | }); | 95 | loop_.reset(new FuseAppLoop(std::move(sockets_[1]))); |
96 | callback_.loop = loop_.get(); | ||
97 | thread_ = std::thread([this] { loop_->Start(&callback_); }); | ||
116 | } | 98 | } |
117 | 99 | ||
118 | void CheckCallback( | 100 | void CheckCallback( |
@@ -300,5 +282,18 @@ TEST_F(FuseAppLoopTest, Write) { | |||
300 | CheckCallback(sizeof(fuse_write_in), FUSE_WRITE, sizeof(fuse_write_out)); | 282 | CheckCallback(sizeof(fuse_write_in), FUSE_WRITE, sizeof(fuse_write_out)); |
301 | } | 283 | } |
302 | 284 | ||
285 | TEST_F(FuseAppLoopTest, Break) { | ||
286 | // Ensure that the loop started. | ||
287 | request_.Reset(sizeof(fuse_open_in), FUSE_OPEN, 1); | ||
288 | request_.header.nodeid = 10; | ||
289 | ASSERT_TRUE(request_.Write(sockets_[0])); | ||
290 | ASSERT_TRUE(response_.Read(sockets_[0])); | ||
291 | |||
292 | loop_->Break(); | ||
293 | if (thread_.joinable()) { | ||
294 | thread_.join(); | ||
295 | } | ||
296 | } | ||
297 | |||
303 | } // namespace fuse | 298 | } // namespace fuse |
304 | } // namespace android | 299 | } // namespace android |