Merge "Add FuseBridgeLoop to libappfuse."
This commit is contained in:
commit
b5ce6f02dd
7 changed files with 336 additions and 8 deletions
|
|
@ -15,12 +15,12 @@ cc_library_shared {
|
||||||
name: "libappfuse",
|
name: "libappfuse",
|
||||||
defaults: ["libappfuse_defaults"],
|
defaults: ["libappfuse_defaults"],
|
||||||
export_include_dirs: ["include"],
|
export_include_dirs: ["include"],
|
||||||
srcs: ["AppFuse.cc"]
|
srcs: ["FuseBuffer.cc", "FuseBridgeLoop.cc"]
|
||||||
}
|
}
|
||||||
|
|
||||||
cc_test {
|
cc_test {
|
||||||
name: "libappfuse_test",
|
name: "libappfuse_test",
|
||||||
defaults: ["libappfuse_defaults"],
|
defaults: ["libappfuse_defaults"],
|
||||||
shared_libs: ["libappfuse"],
|
shared_libs: ["libappfuse"],
|
||||||
srcs: ["tests/AppFuseTest.cc"]
|
srcs: ["tests/FuseBridgeLoopTest.cc", "tests/FuseBufferTest.cc"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
79
libappfuse/FuseBridgeLoop.cc
Normal file
79
libappfuse/FuseBridgeLoop.cc
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* 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/FuseBridgeLoop.h"
|
||||||
|
|
||||||
|
#include <android-base/logging.h>
|
||||||
|
#include <android-base/unique_fd.h>
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
LOG(DEBUG) << "Start fuse loop.";
|
||||||
|
while (true) {
|
||||||
|
if (!buffer_.request.Read(dev_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:
|
||||||
|
case FUSE_GETATTR:
|
||||||
|
case FUSE_OPEN:
|
||||||
|
case FUSE_READ:
|
||||||
|
case FUSE_WRITE:
|
||||||
|
case FUSE_RELEASE:
|
||||||
|
case FUSE_FLUSH:
|
||||||
|
if (!buffer_.request.Write(proxy_fd)) {
|
||||||
|
LOG(ERROR) << "Failed to write a request to the proxy.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!buffer_.response.Read(proxy_fd)) {
|
||||||
|
LOG(ERROR) << "Failed to read a response from the proxy.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FUSE_INIT:
|
||||||
|
buffer_.HandleInit();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
buffer_.HandleNotImpl();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buffer_.response.Write(dev_fd)) {
|
||||||
|
LOG(ERROR) << "Failed to write a response to the device.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opcode == FUSE_INIT) {
|
||||||
|
callback->OnMount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace android
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "libappfuse/AppFuse.h"
|
#include "libappfuse/FuseBuffer.h"
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
40
libappfuse/include/libappfuse/FuseBridgeLoop.h
Normal file
40
libappfuse/include/libappfuse/FuseBridgeLoop.h
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* 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_FUSEBRIDGELOOP_H_
|
||||||
|
#define ANDROID_LIBAPPFUSE_FUSEBRIDGELOOP_H_
|
||||||
|
|
||||||
|
#include "libappfuse/FuseBuffer.h"
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
class FuseBridgeLoop {
|
||||||
|
public:
|
||||||
|
class Callback {
|
||||||
|
public:
|
||||||
|
virtual void OnMount() = 0;
|
||||||
|
virtual ~Callback() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool Start(int dev_fd, int proxy_fd, Callback* callback);
|
||||||
|
|
||||||
|
private:
|
||||||
|
FuseBuffer buffer_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace android
|
||||||
|
|
||||||
|
#endif // ANDROID_LIBAPPFUSE_FUSEBRIDGELOOP_H_
|
||||||
|
|
@ -14,8 +14,8 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ANDROID_LIBAPPFUSE_APPFUSE_H_
|
#ifndef ANDROID_LIBAPPFUSE_FUSEBUFFER_H_
|
||||||
#define ANDROID_LIBAPPFUSE_APPFUSE_H_
|
#define ANDROID_LIBAPPFUSE_FUSEBUFFER_H_
|
||||||
|
|
||||||
#include <linux/fuse.h>
|
#include <linux/fuse.h>
|
||||||
|
|
||||||
|
|
@ -46,7 +46,7 @@ struct FuseRequest : public FuseMessage<FuseRequest, fuse_in_header> {
|
||||||
fuse_open_in open_in;
|
fuse_open_in open_in;
|
||||||
fuse_init_in init_in;
|
fuse_init_in init_in;
|
||||||
fuse_read_in read_in;
|
fuse_read_in read_in;
|
||||||
char lookup_name[];
|
char lookup_name[0];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -71,6 +71,19 @@ union FuseBuffer {
|
||||||
void HandleNotImpl();
|
void HandleNotImpl();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FuseProxyLoop {
|
||||||
|
class IFuseProxyLoopCallback {
|
||||||
|
public:
|
||||||
|
virtual void OnMount() = 0;
|
||||||
|
virtual ~IFuseProxyLoopCallback() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool Start(int dev_fd, int proxy_fd, IFuseProxyLoopCallback* callback);
|
||||||
|
|
||||||
|
private:
|
||||||
|
FuseBuffer buffer_;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
|
||||||
#endif // ANDROID_LIBAPPFUSE_APPFUSE_H_
|
#endif // ANDROID_LIBAPPFUSE_FUSEBUFFER_H_
|
||||||
196
libappfuse/tests/FuseBridgeLoopTest.cc
Normal file
196
libappfuse/tests/FuseBridgeLoopTest.cc
Normal file
|
|
@ -0,0 +1,196 @@
|
||||||
|
/*
|
||||||
|
* 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/FuseBridgeLoop.h"
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
class Callback : public FuseBridgeLoop::Callback {
|
||||||
|
public:
|
||||||
|
bool mounted;
|
||||||
|
Callback() : mounted(false) {}
|
||||||
|
void OnMount() override {
|
||||||
|
mounted = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class FuseBridgeLoopTest : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
int dev_sockets_[2];
|
||||||
|
int proxy_sockets_[2];
|
||||||
|
Callback callback_;
|
||||||
|
std::thread thread_;
|
||||||
|
|
||||||
|
FuseRequest request_;
|
||||||
|
FuseResponse response_;
|
||||||
|
|
||||||
|
void SetUp() {
|
||||||
|
ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, dev_sockets_));
|
||||||
|
ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, proxy_sockets_));
|
||||||
|
thread_ = std::thread([this] {
|
||||||
|
FuseBridgeLoop loop;
|
||||||
|
loop.Start(dev_sockets_[1], proxy_sockets_[0], &callback_);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckNotImpl(uint32_t opcode) {
|
||||||
|
SCOPED_TRACE((std::ostringstream() << "opcode: " << opcode).str());
|
||||||
|
|
||||||
|
memset(&request_, 0, sizeof(FuseRequest));
|
||||||
|
request_.header.opcode = opcode;
|
||||||
|
request_.header.len = sizeof(fuse_in_header);
|
||||||
|
ASSERT_TRUE(request_.Write(dev_sockets_[0]));
|
||||||
|
|
||||||
|
memset(&response_, 0, sizeof(FuseResponse));
|
||||||
|
ASSERT_TRUE(response_.Read(dev_sockets_[0]));
|
||||||
|
EXPECT_EQ(-ENOSYS, response_.header.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckProxy(uint32_t opcode) {
|
||||||
|
SCOPED_TRACE((std::ostringstream() << "opcode: " << opcode).str());
|
||||||
|
|
||||||
|
memset(&request_, 0, sizeof(FuseRequest));
|
||||||
|
request_.header.opcode = opcode;
|
||||||
|
request_.header.unique = opcode; // Use opcode as unique.
|
||||||
|
request_.header.len = sizeof(fuse_in_header);
|
||||||
|
ASSERT_TRUE(request_.Write(dev_sockets_[0]));
|
||||||
|
|
||||||
|
memset(&request_, 0, sizeof(FuseRequest));
|
||||||
|
ASSERT_TRUE(request_.Read(proxy_sockets_[1]));
|
||||||
|
EXPECT_EQ(opcode, request_.header.opcode);
|
||||||
|
EXPECT_EQ(opcode, request_.header.unique);
|
||||||
|
|
||||||
|
memset(&response_, 0, sizeof(FuseResponse));
|
||||||
|
response_.header.len = sizeof(fuse_out_header);
|
||||||
|
response_.header.unique = opcode; // Use opcode as unique.
|
||||||
|
response_.header.error = kFuseSuccess;
|
||||||
|
ASSERT_TRUE(response_.Write(proxy_sockets_[1]));
|
||||||
|
|
||||||
|
memset(&response_, 0, sizeof(FuseResponse));
|
||||||
|
ASSERT_TRUE(response_.Read(dev_sockets_[0]));
|
||||||
|
EXPECT_EQ(opcode, response_.header.unique);
|
||||||
|
EXPECT_EQ(kFuseSuccess, response_.header.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendInitRequest(uint64_t unique) {
|
||||||
|
memset(&request_, 0, sizeof(FuseRequest));
|
||||||
|
request_.header.opcode = FUSE_INIT;
|
||||||
|
request_.header.unique = unique;
|
||||||
|
request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_init_in);
|
||||||
|
request_.init_in.major = FUSE_KERNEL_VERSION;
|
||||||
|
request_.init_in.minor = FUSE_KERNEL_MINOR_VERSION;
|
||||||
|
ASSERT_TRUE(request_.Write(dev_sockets_[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Close() {
|
||||||
|
close(dev_sockets_[0]);
|
||||||
|
close(dev_sockets_[1]);
|
||||||
|
close(proxy_sockets_[0]);
|
||||||
|
close(proxy_sockets_[1]);
|
||||||
|
if (thread_.joinable()) {
|
||||||
|
thread_.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown() {
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(FuseBridgeLoopTest, FuseInit) {
|
||||||
|
SendInitRequest(1u);
|
||||||
|
|
||||||
|
memset(&response_, 0, sizeof(FuseResponse));
|
||||||
|
ASSERT_TRUE(response_.Read(dev_sockets_[0]));
|
||||||
|
EXPECT_EQ(kFuseSuccess, response_.header.error);
|
||||||
|
EXPECT_EQ(1u, response_.header.unique);
|
||||||
|
|
||||||
|
// Unmount.
|
||||||
|
Close();
|
||||||
|
EXPECT_TRUE(callback_.mounted);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FuseBridgeLoopTest, FuseForget) {
|
||||||
|
memset(&request_, 0, sizeof(FuseRequest));
|
||||||
|
request_.header.opcode = FUSE_FORGET;
|
||||||
|
request_.header.unique = 1u;
|
||||||
|
request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_forget_in);
|
||||||
|
ASSERT_TRUE(request_.Write(dev_sockets_[0]));
|
||||||
|
|
||||||
|
SendInitRequest(2u);
|
||||||
|
|
||||||
|
memset(&response_, 0, sizeof(FuseResponse));
|
||||||
|
ASSERT_TRUE(response_.Read(dev_sockets_[0]));
|
||||||
|
EXPECT_EQ(2u, response_.header.unique) <<
|
||||||
|
"The loop must not respond to FUSE_FORGET";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FuseBridgeLoopTest, FuseNotImpl) {
|
||||||
|
CheckNotImpl(FUSE_SETATTR);
|
||||||
|
CheckNotImpl(FUSE_READLINK);
|
||||||
|
CheckNotImpl(FUSE_SYMLINK);
|
||||||
|
CheckNotImpl(FUSE_MKNOD);
|
||||||
|
CheckNotImpl(FUSE_MKDIR);
|
||||||
|
CheckNotImpl(FUSE_UNLINK);
|
||||||
|
CheckNotImpl(FUSE_RMDIR);
|
||||||
|
CheckNotImpl(FUSE_RENAME);
|
||||||
|
CheckNotImpl(FUSE_LINK);
|
||||||
|
CheckNotImpl(FUSE_STATFS);
|
||||||
|
CheckNotImpl(FUSE_FSYNC);
|
||||||
|
CheckNotImpl(FUSE_SETXATTR);
|
||||||
|
CheckNotImpl(FUSE_GETXATTR);
|
||||||
|
CheckNotImpl(FUSE_LISTXATTR);
|
||||||
|
CheckNotImpl(FUSE_REMOVEXATTR);
|
||||||
|
CheckNotImpl(FUSE_OPENDIR);
|
||||||
|
CheckNotImpl(FUSE_READDIR);
|
||||||
|
CheckNotImpl(FUSE_RELEASEDIR);
|
||||||
|
CheckNotImpl(FUSE_FSYNCDIR);
|
||||||
|
CheckNotImpl(FUSE_GETLK);
|
||||||
|
CheckNotImpl(FUSE_SETLK);
|
||||||
|
CheckNotImpl(FUSE_SETLKW);
|
||||||
|
CheckNotImpl(FUSE_ACCESS);
|
||||||
|
CheckNotImpl(FUSE_CREATE);
|
||||||
|
CheckNotImpl(FUSE_INTERRUPT);
|
||||||
|
CheckNotImpl(FUSE_BMAP);
|
||||||
|
CheckNotImpl(FUSE_DESTROY);
|
||||||
|
CheckNotImpl(FUSE_IOCTL);
|
||||||
|
CheckNotImpl(FUSE_POLL);
|
||||||
|
CheckNotImpl(FUSE_NOTIFY_REPLY);
|
||||||
|
CheckNotImpl(FUSE_BATCH_FORGET);
|
||||||
|
CheckNotImpl(FUSE_FALLOCATE);
|
||||||
|
CheckNotImpl(FUSE_READDIRPLUS);
|
||||||
|
CheckNotImpl(FUSE_RENAME2);
|
||||||
|
CheckNotImpl(FUSE_LSEEK);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FuseBridgeLoopTest, Proxy) {
|
||||||
|
CheckProxy(FUSE_LOOKUP);
|
||||||
|
CheckProxy(FUSE_GETATTR);
|
||||||
|
CheckProxy(FUSE_OPEN);
|
||||||
|
CheckProxy(FUSE_READ);
|
||||||
|
CheckProxy(FUSE_WRITE);
|
||||||
|
CheckProxy(FUSE_RELEASE);
|
||||||
|
CheckProxy(FUSE_FLUSH);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // android
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "libappfuse/AppFuse.h"
|
#include "libappfuse/FuseBuffer.h"
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
Loading…
Add table
Reference in a new issue