Home | History | Annotate | Download | only in libappfuse
      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