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

Commit e1d24f84 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Add FuseAppLoop to libappfuse."

parents f4cdb6ae a0aecda1
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