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/FuseAppLoop.h" 18 19 #include <sys/eventfd.h> 20 #include <sys/stat.h> 21 22 #include <android-base/logging.h> 23 #include <android-base/unique_fd.h> 24 25 #include "libappfuse/EpollController.h" 26 27 namespace android { 28 namespace fuse { 29 30 namespace { 31 32 bool HandleLookUp(FuseAppLoop* loop, FuseBuffer* buffer, FuseAppLoopCallback* callback) { 33 // AppFuse does not support directory structure now. 34 // It can lookup only files under the mount point. 35 if (buffer->request.header.nodeid != FUSE_ROOT_ID) { 36 LOG(ERROR) << "Nodeid is not FUSE_ROOT_ID."; 37 return loop->ReplySimple(buffer->request.header.unique, -ENOENT); 38 } 39 40 // Ensure that the filename ends with 0. 41 const size_t filename_length = buffer->request.header.len - sizeof(fuse_in_header); 42 if (buffer->request.lookup_name[filename_length - 1] != 0) { 43 LOG(ERROR) << "File name does not end with 0."; 44 return loop->ReplySimple(buffer->request.header.unique, -ENOENT); 45 } 46 47 const uint64_t inode = static_cast<uint64_t>(atol(buffer->request.lookup_name)); 48 if (inode == 0 || inode == LONG_MAX) { 49 LOG(ERROR) << "Invalid filename"; 50 return loop->ReplySimple(buffer->request.header.unique, -ENOENT); 51 } 52 53 callback->OnLookup(buffer->request.header.unique, inode); 54 return true; 55 } 56 57 bool HandleGetAttr(FuseAppLoop* loop, FuseBuffer* buffer, FuseAppLoopCallback* callback) { 58 if (buffer->request.header.nodeid == FUSE_ROOT_ID) { 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 } 65 } 66 67 bool HandleRead(FuseAppLoop* loop, FuseBuffer* buffer, FuseAppLoopCallback* callback) { 68 if (buffer->request.read_in.size > kFuseMaxRead) { 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; 75 } 76 77 bool HandleWrite(FuseAppLoop* loop, FuseBuffer* buffer, FuseAppLoopCallback* callback) { 78 if (buffer->request.write_in.size > kFuseMaxWrite) { 79 return loop->ReplySimple(buffer->request.header.unique, -EINVAL); 80 } 81 82 callback->OnWrite(buffer->request.header.unique, buffer->request.header.nodeid, 83 buffer->request.write_in.offset, buffer->request.write_in.size, 84 buffer->request.write_data); 85 return true; 86 } 87 88 bool HandleMessage(FuseAppLoop* loop, FuseBuffer* buffer, int fd, FuseAppLoopCallback* callback) { 89 if (!buffer->request.Read(fd)) { 90 return false; 91 } 92 93 const uint32_t opcode = buffer->request.header.opcode; 94 LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode; 95 switch (opcode) { 96 case FUSE_FORGET: 97 // Do not reply to FUSE_FORGET. 98 return true; 99 100 case FUSE_LOOKUP: 101 return HandleLookUp(loop, buffer, callback); 102 103 case FUSE_GETATTR: 104 return HandleGetAttr(loop, buffer, callback); 105 106 case FUSE_OPEN: 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 } 128 } 129 130 } // namespace 131 132 FuseAppLoopCallback::~FuseAppLoopCallback() = default; 133 134 FuseAppLoop::FuseAppLoop(base::unique_fd&& fd) : fd_(std::move(fd)) {} 135 136 void FuseAppLoop::Break() { 137 const int64_t value = 1; 138 if (write(break_fd_, &value, sizeof(value)) == -1) { 139 PLOG(ERROR) << "Failed to send a break event"; 140 } 141 } 142 143 bool FuseAppLoop::ReplySimple(uint64_t unique, int32_t result) { 144 if (result == -ENOSYS) { 145 // We should not return -ENOSYS because the kernel stops delivering FUSE 146 // command after receiving -ENOSYS as a result for the command. 147 result = -EBADF; 148 } 149 FuseSimpleResponse response; 150 response.Reset(0, result, unique); 151 return response.Write(fd_); 152 } 153 154 bool FuseAppLoop::ReplyLookup(uint64_t unique, uint64_t inode, int64_t size) { 155 FuseSimpleResponse response; 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 } 165 166 bool FuseAppLoop::ReplyGetAttr(uint64_t unique, uint64_t inode, int64_t size, int mode) { 167 CHECK(mode == (S_IFREG | 0777) || mode == (S_IFDIR | 0777)); 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 } 176 177 bool FuseAppLoop::ReplyOpen(uint64_t unique, uint64_t fh) { 178 FuseSimpleResponse response; 179 response.Reset(sizeof(fuse_open_out), kFuseSuccess, unique); 180 response.open_out.fh = fh; 181 return response.Write(fd_); 182 } 183 184 bool FuseAppLoop::ReplyWrite(uint64_t unique, uint32_t size) { 185 CHECK(size <= kFuseMaxWrite); 186 FuseSimpleResponse response; 187 response.Reset(sizeof(fuse_write_out), kFuseSuccess, unique); 188 response.write_out.size = size; 189 return response.Write(fd_); 190 } 191 192 bool FuseAppLoop::ReplyRead(uint64_t unique, uint32_t size, const void* data) { 193 CHECK(size <= kFuseMaxRead); 194 FuseSimpleResponse response; 195 response.ResetHeader(size, kFuseSuccess, unique); 196 return response.WriteWithBody(fd_, sizeof(FuseResponse), data); 197 } 198 199 void FuseAppLoop::Start(FuseAppLoopCallback* callback) { 200 break_fd_.reset(eventfd(/* initval */ 0, EFD_CLOEXEC)); 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 } 211 212 int last_event; 213 int break_event; 214 215 std::unique_ptr<EpollController> epoll_controller(new EpollController(std::move(epoll_fd))); 216 if (!epoll_controller->AddFd(fd_, EPOLLIN, &last_event)) { 217 return; 218 } 219 if (!epoll_controller->AddFd(break_fd_, EPOLLIN, &break_event)) { 220 return; 221 } 222 223 last_event = 0; 224 break_event = 0; 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 } 242 } 243 244 LOG(VERBOSE) << "FuseAppLoop exit"; 245 } 246 247 } // namespace fuse 248 } // namespace android 249