Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1eda7847 authored by Daichi Hirono's avatar Daichi Hirono Committed by android-build-merger
Browse files

Merge "Add FuseAppLoop to libappfuse."

am: e1d24f84

Change-Id: Ic15e0ca892a1432fa82cfd80737cbf95a976fab4
parents 771d6ea5 e1d24f84
Loading
Loading
Loading
Loading
+10 −2
Original line number Diff line number Diff line
@@ -15,12 +15,20 @@ cc_library_shared {
    name: "libappfuse",
    defaults: ["libappfuse_defaults"],
    export_include_dirs: ["include"],
    srcs: ["FuseBuffer.cc", "FuseBridgeLoop.cc"]
    srcs: [
        "FuseAppLoop.cc",
        "FuseBuffer.cc",
        "FuseBridgeLoop.cc",
    ]
}

cc_test {
    name: "libappfuse_test",
    defaults: ["libappfuse_defaults"],
    shared_libs: ["libappfuse"],
    srcs: ["tests/FuseBridgeLoopTest.cc", "tests/FuseBufferTest.cc"]
    srcs: [
        "tests/FuseAppLoopTest.cc",
        "tests/FuseBridgeLoopTest.cc",
        "tests/FuseBufferTest.cc",
    ]
}
+221 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specic language governing permissions and
 * limitations under the License.
 */

#include "libappfuse/FuseAppLoop.h"

#include <sys/stat.h>

#include <android-base/logging.h>
#include <android-base/unique_fd.h>

namespace android {
namespace fuse {

namespace {

void HandleLookUp(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
  // AppFuse does not support directory structure now.
  // It can lookup only files under the mount point.
  if (buffer->request.header.nodeid != FUSE_ROOT_ID) {
    LOG(ERROR) << "Nodeid is not FUSE_ROOT_ID.";
    buffer->response.Reset(0, -ENOENT, buffer->request.header.unique);
    return;
  }

  // Ensure that the filename ends with 0.
  const size_t filename_length =
      buffer->request.header.len - sizeof(fuse_in_header);
  if (buffer->request.lookup_name[filename_length - 1] != 0) {
    LOG(ERROR) << "File name does not end with 0.";
    buffer->response.Reset(0, -ENOENT, buffer->request.header.unique);
    return;
  }

  const uint64_t inode =
      static_cast<uint64_t>(atol(buffer->request.lookup_name));
  if (inode == 0 || inode == LONG_MAX) {
    LOG(ERROR) << "Invalid filename";
    buffer->response.Reset(0, -ENOENT, buffer->request.header.unique);
    return;
  }

  const int64_t size = callback->OnGetSize(inode);
  if (size < 0) {
    buffer->response.Reset(0, size, buffer->request.header.unique);
    return;
  }

  buffer->response.Reset(sizeof(fuse_entry_out), 0,
                         buffer->request.header.unique);
  buffer->response.entry_out.nodeid = inode;
  buffer->response.entry_out.attr_valid = 10;
  buffer->response.entry_out.entry_valid = 10;
  buffer->response.entry_out.attr.ino = inode;
  buffer->response.entry_out.attr.mode = S_IFREG | 0777;
  buffer->response.entry_out.attr.size = size;
}

void HandleGetAttr(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
  const uint64_t nodeid = buffer->request.header.nodeid;
  int64_t size;
  uint32_t mode;
  if (nodeid == FUSE_ROOT_ID) {
    size = 0;
    mode = S_IFDIR | 0777;
  } else {
    size = callback->OnGetSize(buffer->request.header.nodeid);
    if (size < 0) {
      buffer->response.Reset(0, size, buffer->request.header.unique);
      return;
    }
    mode = S_IFREG | 0777;
  }

  buffer->response.Reset(sizeof(fuse_attr_out), 0,
                         buffer->request.header.unique);
  buffer->response.attr_out.attr_valid = 10;
  buffer->response.attr_out.attr.ino = nodeid;
  buffer->response.attr_out.attr.mode = mode;
  buffer->response.attr_out.attr.size = size;
}

void HandleOpen(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
  const int32_t file_handle = callback->OnOpen(buffer->request.header.nodeid);
  if (file_handle < 0) {
    buffer->response.Reset(0, file_handle, buffer->request.header.unique);
    return;
  }
  buffer->response.Reset(sizeof(fuse_open_out), kFuseSuccess,
                         buffer->request.header.unique);
  buffer->response.open_out.fh = file_handle;
}

void HandleFsync(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
  buffer->response.Reset(0, callback->OnFsync(buffer->request.header.nodeid),
                         buffer->request.header.unique);
}

void HandleRelease(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
  buffer->response.Reset(0, callback->OnRelease(buffer->request.header.nodeid),
                         buffer->request.header.unique);
}

void HandleRead(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
  const uint64_t unique = buffer->request.header.unique;
  const uint64_t nodeid = buffer->request.header.nodeid;
  const uint64_t offset = buffer->request.read_in.offset;
  const uint32_t size = buffer->request.read_in.size;

  if (size > kFuseMaxRead) {
    buffer->response.Reset(0, -EINVAL, buffer->request.header.unique);
    return;
  }

  const int32_t read_size = callback->OnRead(nodeid, offset, size,
                                             buffer->response.read_data);
  if (read_size < 0) {
    buffer->response.Reset(0, read_size, buffer->request.header.unique);
    return;
  }

  buffer->response.ResetHeader(read_size, kFuseSuccess, unique);
}

void HandleWrite(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
  const uint64_t unique = buffer->request.header.unique;
  const uint64_t nodeid = buffer->request.header.nodeid;
  const uint64_t offset = buffer->request.write_in.offset;
  const uint32_t size = buffer->request.write_in.size;

  if (size > kFuseMaxWrite) {
    buffer->response.Reset(0, -EINVAL, buffer->request.header.unique);
    return;
  }

  const int32_t write_size = callback->OnWrite(nodeid, offset, size,
                                               buffer->request.write_data);
  if (write_size < 0) {
    buffer->response.Reset(0, write_size, buffer->request.header.unique);
    return;
  }

  buffer->response.Reset(sizeof(fuse_write_out), kFuseSuccess, unique);
  buffer->response.write_out.size = write_size;
}

} // namespace

bool StartFuseAppLoop(int raw_fd, FuseAppLoopCallback* callback) {
  base::unique_fd fd(raw_fd);
  FuseBuffer buffer;

  LOG(DEBUG) << "Start fuse loop.";
  while (callback->IsActive()) {
    if (!buffer.request.Read(fd)) {
      return false;
    }

    const uint32_t opcode = buffer.request.header.opcode;
    LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode;
    switch (opcode) {
      case FUSE_FORGET:
        // Do not reply to FUSE_FORGET.
        continue;

      case FUSE_LOOKUP:
        HandleLookUp(&buffer, callback);
        break;

      case FUSE_GETATTR:
        HandleGetAttr(&buffer, callback);
        break;

      case FUSE_OPEN:
        HandleOpen(&buffer, callback);
        break;

      case FUSE_READ:
        HandleRead(&buffer, callback);
        break;

      case FUSE_WRITE:
        HandleWrite(&buffer, callback);
        break;

      case FUSE_RELEASE:
        HandleRelease(&buffer, callback);
        break;

      case FUSE_FSYNC:
        HandleFsync(&buffer, callback);
        break;

      default:
        buffer.HandleNotImpl();
        break;
    }

    if (!buffer.response.Write(fd)) {
      LOG(ERROR) << "Failed to write a response to the device.";
      return false;
    }
  }

  return true;
}

}  // namespace fuse
}  // namespace android
+17 −8
Original line number Diff line number Diff line
@@ -25,14 +25,15 @@ bool FuseBridgeLoop::Start(
    int raw_dev_fd, int raw_proxy_fd, FuseBridgeLoop::Callback* callback) {
  base::unique_fd dev_fd(raw_dev_fd);
  base::unique_fd proxy_fd(raw_proxy_fd);
  fuse::FuseBuffer buffer;

  LOG(DEBUG) << "Start fuse loop.";
  while (true) {
    if (!buffer_.request.Read(dev_fd)) {
    if (!buffer.request.Read(dev_fd)) {
      return false;
    }

    const uint32_t opcode = buffer_.request.header.opcode;
    const uint32_t opcode = buffer.request.header.opcode;
    LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode;
    switch (opcode) {
      case FUSE_FORGET:
@@ -45,27 +46,27 @@ bool FuseBridgeLoop::Start(
      case FUSE_READ:
      case FUSE_WRITE:
      case FUSE_RELEASE:
      case FUSE_FLUSH:
        if (!buffer_.request.Write(proxy_fd)) {
      case FUSE_FSYNC:
        if (!buffer.request.Write(proxy_fd)) {
          LOG(ERROR) << "Failed to write a request to the proxy.";
          return false;
        }
        if (!buffer_.response.Read(proxy_fd)) {
        if (!buffer.response.Read(proxy_fd)) {
          LOG(ERROR) << "Failed to read a response from the proxy.";
          return false;
        }
        break;

      case FUSE_INIT:
        buffer_.HandleInit();
        buffer.HandleInit();
        break;

      default:
        buffer_.HandleNotImpl();
        buffer.HandleNotImpl();
        break;
    }

    if (!buffer_.response.Write(dev_fd)) {
    if (!buffer.response.Write(dev_fd)) {
      LOG(ERROR) << "Failed to write a response to the device.";
      return false;
    }
@@ -76,4 +77,12 @@ bool FuseBridgeLoop::Start(
  }
}

namespace fuse {

bool StartFuseBridgeLoop(
    int raw_dev_fd, int raw_proxy_fd, FuseBridgeLoopCallback* callback) {
  return FuseBridgeLoop().Start(raw_dev_fd, raw_proxy_fd, callback);
}

}  // namespace fuse
}  // namespace android
+11 −1
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <android-base/macros.h>

namespace android {
namespace fuse {

template <typename T, typename Header>
bool FuseMessage<T, Header>::CheckHeaderLength() const {
@@ -44,7 +45,7 @@ bool FuseMessage<T, Header>::CheckResult(
    return true;
  } else {
    PLOG(ERROR) << "Failed to " << operation_name
        << " a packet from FD. result=" << result << " header.len="
        << " a packet. result=" << result << " header.len="
        << header.len;
    return false;
  }
@@ -68,6 +69,14 @@ bool FuseMessage<T, Header>::Write(int fd) const {
template struct FuseMessage<FuseRequest, fuse_in_header>;
template struct FuseMessage<FuseResponse, fuse_out_header>;

void FuseRequest::Reset(
    uint32_t data_length, uint32_t opcode, uint64_t unique) {
  memset(this, 0, sizeof(fuse_in_header) + data_length);
  header.len = sizeof(fuse_in_header) + data_length;
  header.opcode = opcode;
  header.unique = unique;
}

void FuseResponse::ResetHeader(
    uint32_t data_length, int32_t error, uint64_t unique) {
  CHECK_LE(error, 0) << "error should be zero or negative.";
@@ -133,4 +142,5 @@ void FuseBuffer::HandleNotImpl() {
  response.Reset(0, -ENOSYS, unique);
}

}  // namespace fuse
}  // namespace android
+44 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specic language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_
#define ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_

#include "libappfuse/FuseBuffer.h"

namespace android {
namespace fuse {

class FuseAppLoopCallback {
 public:
  virtual bool IsActive() = 0;
  virtual int64_t OnGetSize(uint64_t inode) = 0;
  virtual int32_t OnFsync(uint64_t inode) = 0;
  virtual int32_t OnWrite(
      uint64_t inode, uint64_t offset, uint32_t size, const void* data) = 0;
  virtual int32_t OnRead(
      uint64_t inode, uint64_t offset, uint32_t size, void* data) = 0;
  virtual int32_t OnOpen(uint64_t inode) = 0;
  virtual int32_t OnRelease(uint64_t inode) = 0;
  virtual ~FuseAppLoopCallback() = default;
};

bool StartFuseAppLoop(int fd, FuseAppLoopCallback* callback);

}  // namespace fuse
}  // namespace android

#endif  // ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_
Loading