summaryrefslogtreecommitdiffhomepage
path: root/test/fuse
diff options
context:
space:
mode:
Diffstat (limited to 'test/fuse')
-rw-r--r--test/fuse/BUILD78
-rw-r--r--test/fuse/README.md188
-rw-r--r--test/fuse/linux/BUILD242
-rw-r--r--test/fuse/linux/create_test.cc128
-rw-r--r--test/fuse/linux/fuse_base.cc447
-rw-r--r--test/fuse/linux/fuse_base.h251
-rw-r--r--test/fuse/linux/fuse_fd_util.cc61
-rw-r--r--test/fuse/linux/fuse_fd_util.h48
-rw-r--r--test/fuse/linux/mkdir_test.cc88
-rw-r--r--test/fuse/linux/mknod_test.cc107
-rw-r--r--test/fuse/linux/mount_test.cc41
-rw-r--r--test/fuse/linux/open_test.cc128
-rw-r--r--test/fuse/linux/read_test.cc390
-rw-r--r--test/fuse/linux/readdir_test.cc193
-rw-r--r--test/fuse/linux/readlink_test.cc85
-rw-r--r--test/fuse/linux/release_test.cc74
-rw-r--r--test/fuse/linux/rmdir_test.cc100
-rw-r--r--test/fuse/linux/setstat_test.cc338
-rw-r--r--test/fuse/linux/stat_test.cc229
-rw-r--r--test/fuse/linux/symlink_test.cc88
-rw-r--r--test/fuse/linux/unlink_test.cc107
-rw-r--r--test/fuse/linux/write_test.cc303
22 files changed, 0 insertions, 3714 deletions
diff --git a/test/fuse/BUILD b/test/fuse/BUILD
deleted file mode 100644
index 74500ec84..000000000
--- a/test/fuse/BUILD
+++ /dev/null
@@ -1,78 +0,0 @@
-load("//test/runner:defs.bzl", "syscall_test")
-
-package(licenses = ["notice"])
-
-syscall_test(
- fuse = "True",
- test = "//test/fuse/linux:stat_test",
-)
-
-syscall_test(
- fuse = "True",
- test = "//test/fuse/linux:open_test",
-)
-
-syscall_test(
- fuse = "True",
- test = "//test/fuse/linux:release_test",
-)
-
-syscall_test(
- fuse = "True",
- test = "//test/fuse/linux:mknod_test",
-)
-
-syscall_test(
- fuse = "True",
- test = "//test/fuse/linux:symlink_test",
-)
-
-syscall_test(
- fuse = "True",
- test = "//test/fuse/linux:readlink_test",
-)
-
-syscall_test(
- fuse = "True",
- test = "//test/fuse/linux:mkdir_test",
-)
-
-syscall_test(
- fuse = "True",
- test = "//test/fuse/linux:read_test",
-)
-
-syscall_test(
- fuse = "True",
- test = "//test/fuse/linux:write_test",
-)
-
-syscall_test(
- fuse = "True",
- test = "//test/fuse/linux:rmdir_test",
-)
-
-syscall_test(
- fuse = "True",
- test = "//test/fuse/linux:readdir_test",
-)
-
-syscall_test(
- fuse = "True",
- test = "//test/fuse/linux:create_test",
-)
-
-syscall_test(
- fuse = "True",
- test = "//test/fuse/linux:unlink_test",
-)
-
-syscall_test(
- fuse = "True",
- test = "//test/fuse/linux:setstat_test",
-)
-
-syscall_test(
- fuse = "True",
- test = "//test/fuse/linux:mount_test",
-)
diff --git a/test/fuse/README.md b/test/fuse/README.md
deleted file mode 100644
index 65add57e2..000000000
--- a/test/fuse/README.md
+++ /dev/null
@@ -1,188 +0,0 @@
-# gVisor FUSE Test Suite
-
-This is an integration test suite for fuse(4) filesystem. It runs under gVisor
-sandbox container with VFS2 and FUSE function enabled.
-
-This document describes the framework of FUSE integration test, how to use it,
-and the guidelines that should be followed when adding new testing features.
-
-## Integration Test Framework
-
-By inheriting the `FuseTest` class defined in `linux/fuse_base.h`, every test
-fixture can run in an environment with `mount_point_` mounted by a fake FUSE
-server. It creates a `socketpair(2)` to send and receive control commands and
-data between the client and the server. Because the FUSE server runs in the
-background thread, gTest cannot catch its assertion failure immediately. Thus,
-`TearDown()` function sends command to the FUSE server to check if all gTest
-assertion in the server are successful and all requests and preset responses are
-consumed.
-
-## Communication Diagram
-
-Diagram below describes how a testing thread communicates with the FUSE server
-to achieve integration test.
-
-For the following diagram, `>` means entering the function, `<` is leaving the
-function, and `=` indicates sequentially entering and leaving. Not necessarily
-follow exactly the below diagram due to the nature of a multi-threaded system,
-however, it is still helpful to know when the client waits for the server to
-complete a command and when the server awaits the next instruction.
-
-```
-| Client (Testing Thread) | Server (FUSE Server Thread)
-| |
-| >TEST_F() |
-| >SetUp() |
-| =MountFuse() |
-| >SetUpFuseServer() |
-| [create communication socket]|
-| =fork() | =fork()
-| [wait server complete] |
-| | =ServerConsumeFuseInit()
-| | =ServerCompleteWith()
-| <SetUpFuseServer() |
-| <SetUp() |
-| [testing main] |
-| | >ServerFuseLoop()
-| | [poll on socket and fd]
-| >SetServerResponse() |
-| [write data to socket] |
-| [wait server complete] |
-| | [socket event occurs]
-| | >ServerHandleCommand()
-| | >ServerReceiveResponse()
-| | [read data from socket]
-| | [save data to memory]
-| | <ServerReceiveResponse()
-| | =ServerCompleteWith()
-| <SetServerResponse() |
-| | <ServerHandleCommand()
-| >[Do fs operation] |
-| [wait for fs response] |
-| | [fd event occurs]
-| | >ServerProcessFuseRequest()
-| | =[read fs request]
-| | =[save fs request to memory]
-| | =[write fs response]
-| <[Do fs operation] |
-| | <ServerProcessFuseRequest()
-| |
-| =[Test fs operation result] |
-| |
-| >GetServerActualRequest() |
-| [write data to socket] |
-| [wait data from server] |
-| | [socket event occurs]
-| | >ServerHandleCommand()
-| | >ServerSendReceivedRequest()
-| | [write data to socket]
-| [read data from socket] |
-| [wait server complete] |
-| | <ServerSendReceivedRequest()
-| | =ServerCompleteWith()
-| <GetServerActualRequest() |
-| | <ServerHandleCommand()
-| |
-| =[Test actual request] |
-| |
-| >TearDown() |
-| ... |
-| >GetServerNumUnsentResponses() |
-| [write data to socket] |
-| [wait server complete] |
-| | [socket event arrive]
-| | >ServerHandleCommand()
-| | >ServerSendData()
-| | [write data to socket]
-| | <ServerSendData()
-| | =ServerCompleteWith()
-| [read data from socket] |
-| [test if all succeeded] |
-| <GetServerNumUnsentResponses() |
-| | <ServerHandleCommand()
-| =UnmountFuse() |
-| <TearDown() |
-| <TEST_F() |
-```
-
-## Running the tests
-
-Based on syscall tests, FUSE tests generate targets only with vfs2 and fuse
-enabled. The corresponding targets end in `_fuse`.
-
-For example, to run fuse test in `stat_test.cc`:
-
-```bash
-$ bazel test //test/fuse:stat_test_runsc_ptrace_vfs2_fuse
-```
-
-Test all targets tagged with fuse:
-
-```bash
-$ bazel test --test_tag_filters=fuse //test/fuse/...
-```
-
-## Writing a new FUSE test
-
-1. Add test targets in `BUILD` and `linux/BUILD`.
-2. Inherit your test from `FuseTest` base class. It allows you to:
- - Fork a fake FUSE server in background during each test setup.
- - Create a pair of sockets for communication and provide utility
- functions.
- - Stop FUSE server and check if error occurs in it after test completes.
-3. Build the expected opcode-response pairs of your FUSE operation.
-4. Call `SetServerResponse()` to preset the next expected opcode and response.
-5. Do real filesystem operations (FUSE is mounted at `mount_point_`).
-6. Check FUSE response and/or errors.
-7. Retrieve FUSE request by `GetServerActualRequest()`.
-8. Check if the request is as expected.
-
-A few customized matchers used in syscalls test are encouraged to test the
-outcome of filesystem operations. Such as:
-
-```cc
-SyscallSucceeds()
-SyscallSucceedsWithValue(...)
-SyscallFails()
-SyscallFailsWithErrno(...)
-```
-
-Please refer to [test/syscalls/README.md](../syscalls/README.md) for further
-details.
-
-## Writing a new FuseTestCmd
-
-A `FuseTestCmd` is a control protocol used in the communication between the
-testing thread and the FUSE server. Such commands are sent from the testing
-thread to the FUSE server to set up, control, or inspect the behavior of the
-FUSE server in response to a sequence of FUSE requests.
-
-The lifecycle of a command contains following steps:
-
-1. The testing thread sends a `FuseTestCmd` via socket and waits for
- completion.
-2. The FUSE server receives the command and does corresponding action.
-3. (Optional) The testing thread reads data from socket.
-4. The FUSE server sends a success indicator via socket after processing.
-5. The testing thread gets the success signal and continues testing.
-
-The success indicator, i.e. `WaitServerComplete()`, is crucial at the end of
-each `FuseTestCmd` sent from the testing thread. Because we don't want to begin
-filesystem operation if the requests have not been completely set up. Also, to
-test FUSE interactions in a sequential manner, concurrent requests are not
-supported now.
-
-To add a new `FuseTestCmd`, one must comply with following format:
-
-1. Add a new `FuseTestCmd` enum class item defined in `linux/fuse_base.h`
-2. Add a `SetServerXXX()` or `GetServerXXX()` public function in `FuseTest`.
- This is how the testing thread will call to send control message. Define how
- many bytes you want to send along with the command and what you will expect
- to receive. Finally it should block and wait for a success indicator from
- the FUSE server.
-3. Add a handler logic in the switch condition of `ServerHandleCommand()`. Use
- `ServerSendData()` or declare a new private function such as
- `ServerReceiveXXX()` or `ServerSendXXX()`. It is mandatory to set it private
- since only the FUSE server (forked from `FuseTest` base class) can call it.
- This is the server part of the specific `FuseTestCmd` and the format of the
- data should be consistent with what the client expects in the previous step.
diff --git a/test/fuse/linux/BUILD b/test/fuse/linux/BUILD
deleted file mode 100644
index d1fb178e8..000000000
--- a/test/fuse/linux/BUILD
+++ /dev/null
@@ -1,242 +0,0 @@
-load("//tools:defs.bzl", "cc_binary", "cc_library", "gtest")
-
-package(
- default_visibility = ["//:sandbox"],
- licenses = ["notice"],
-)
-
-cc_binary(
- name = "stat_test",
- testonly = 1,
- srcs = ["stat_test.cc"],
- deps = [
- gtest,
- ":fuse_fd_util",
- "//test/util:cleanup",
- "//test/util:fs_util",
- "//test/util:fuse_util",
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
-
-cc_binary(
- name = "open_test",
- testonly = 1,
- srcs = ["open_test.cc"],
- deps = [
- gtest,
- ":fuse_base",
- "//test/util:fuse_util",
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
-
-cc_binary(
- name = "release_test",
- testonly = 1,
- srcs = ["release_test.cc"],
- deps = [
- gtest,
- ":fuse_base",
- "//test/util:fuse_util",
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
-
-cc_binary(
- name = "mknod_test",
- testonly = 1,
- srcs = ["mknod_test.cc"],
- deps = [
- gtest,
- ":fuse_base",
- "//test/util:fuse_util",
- "//test/util:temp_umask",
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
-
-cc_binary(
- name = "symlink_test",
- testonly = 1,
- srcs = ["symlink_test.cc"],
- deps = [
- gtest,
- ":fuse_base",
- "//test/util:fuse_util",
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
-
-cc_binary(
- name = "readlink_test",
- testonly = 1,
- srcs = ["readlink_test.cc"],
- deps = [
- gtest,
- ":fuse_base",
- "//test/util:fuse_util",
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
-
-cc_binary(
- name = "mkdir_test",
- testonly = 1,
- srcs = ["mkdir_test.cc"],
- deps = [
- gtest,
- ":fuse_base",
- "//test/util:fuse_util",
- "//test/util:temp_umask",
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
-
-cc_binary(
- name = "setstat_test",
- testonly = 1,
- srcs = ["setstat_test.cc"],
- deps = [
- gtest,
- ":fuse_fd_util",
- "//test/util:cleanup",
- "//test/util:fs_util",
- "//test/util:fuse_util",
- "//test/util:temp_umask",
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
-
-cc_binary(
- name = "rmdir_test",
- testonly = 1,
- srcs = ["rmdir_test.cc"],
- deps = [
- gtest,
- ":fuse_base",
- "//test/util:fs_util",
- "//test/util:fuse_util",
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
-
-cc_binary(
- name = "readdir_test",
- testonly = 1,
- srcs = ["readdir_test.cc"],
- deps = [
- gtest,
- ":fuse_base",
- "//test/util:fs_util",
- "//test/util:fuse_util",
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
-
-cc_library(
- name = "fuse_base",
- testonly = 1,
- srcs = ["fuse_base.cc"],
- hdrs = ["fuse_base.h"],
- deps = [
- gtest,
- "//test/util:fuse_util",
- "//test/util:posix_error",
- "//test/util:temp_path",
- "//test/util:test_util",
- "@com_google_absl//absl/strings:str_format",
- ],
-)
-
-cc_library(
- name = "fuse_fd_util",
- testonly = 1,
- srcs = ["fuse_fd_util.cc"],
- hdrs = ["fuse_fd_util.h"],
- deps = [
- gtest,
- ":fuse_base",
- "//test/util:cleanup",
- "//test/util:file_descriptor",
- "//test/util:fuse_util",
- "//test/util:posix_error",
- ],
-)
-
-cc_binary(
- name = "read_test",
- testonly = 1,
- srcs = ["read_test.cc"],
- deps = [
- gtest,
- ":fuse_base",
- "//test/util:fuse_util",
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
-
-cc_binary(
- name = "write_test",
- testonly = 1,
- srcs = ["write_test.cc"],
- deps = [
- gtest,
- ":fuse_base",
- "//test/util:fuse_util",
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
-
-cc_binary(
- name = "create_test",
- testonly = 1,
- srcs = ["create_test.cc"],
- deps = [
- gtest,
- ":fuse_base",
- "//test/util:fs_util",
- "//test/util:fuse_util",
- "//test/util:temp_umask",
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
-
-cc_binary(
- name = "unlink_test",
- testonly = 1,
- srcs = ["unlink_test.cc"],
- deps = [
- gtest,
- ":fuse_base",
- "//test/util:fuse_util",
- "//test/util:temp_umask",
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
-
-cc_binary(
- name = "mount_test",
- testonly = 1,
- srcs = ["mount_test.cc"],
- deps = [
- gtest,
- "//test/util:temp_path",
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
diff --git a/test/fuse/linux/create_test.cc b/test/fuse/linux/create_test.cc
deleted file mode 100644
index 9a0219a58..000000000
--- a/test/fuse/linux/create_test.cc
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// 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 specific language governing permissions and
-// limitations under the License.
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/fuse.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-
-#include "gtest/gtest.h"
-#include "test/fuse/linux/fuse_base.h"
-#include "test/util/fs_util.h"
-#include "test/util/fuse_util.h"
-#include "test/util/temp_umask.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-class CreateTest : public FuseTest {
- protected:
- const std::string test_file_name_ = "test_file";
- const mode_t mode = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO;
-};
-
-TEST_F(CreateTest, CreateFile) {
- const std::string test_file_path =
- JoinPath(mount_point_.path().c_str(), test_file_name_);
-
- // Ensure the file doesn't exist.
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header),
- .error = -ENOENT,
- };
- auto iov_out = FuseGenerateIovecs(out_header);
- SetServerResponse(FUSE_LOOKUP, iov_out);
-
- // creat(2) is equal to open(2) with open_flags O_CREAT | O_WRONLY | O_TRUNC.
- const mode_t new_mask = S_IWGRP | S_IWOTH;
- const int open_flags = O_CREAT | O_WRONLY | O_TRUNC;
- out_header.error = 0;
- out_header.len = sizeof(struct fuse_out_header) +
- sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out);
- struct fuse_entry_out entry_payload = DefaultEntryOut(mode & ~new_mask, 2);
- struct fuse_open_out out_payload = {
- .fh = 1,
- .open_flags = open_flags,
- };
- iov_out = FuseGenerateIovecs(out_header, entry_payload, out_payload);
- SetServerResponse(FUSE_CREATE, iov_out);
-
- // kernfs generates a successive FUSE_OPEN after the file is created. Linux's
- // fuse kernel module will not send this FUSE_OPEN after creat(2).
- out_header.len =
- sizeof(struct fuse_out_header) + sizeof(struct fuse_open_out);
- iov_out = FuseGenerateIovecs(out_header, out_payload);
- SetServerResponse(FUSE_OPEN, iov_out);
-
- int fd;
- TempUmask mask(new_mask);
- EXPECT_THAT(fd = creat(test_file_path.c_str(), mode), SyscallSucceeds());
- EXPECT_THAT(fcntl(fd, F_GETFL),
- SyscallSucceedsWithValue(open_flags & O_ACCMODE));
-
- struct fuse_in_header in_header;
- struct fuse_create_in in_payload;
- std::vector<char> name(test_file_name_.size() + 1);
- auto iov_in = FuseGenerateIovecs(in_header, in_payload, name);
-
- // Skip the request of FUSE_LOOKUP.
- SkipServerActualRequest();
-
- // Get the first FUSE_CREATE.
- GetServerActualRequest(iov_in);
- EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload) +
- test_file_name_.size() + 1);
- EXPECT_EQ(in_header.opcode, FUSE_CREATE);
- EXPECT_EQ(in_payload.flags, open_flags);
- EXPECT_EQ(in_payload.mode, mode & ~new_mask);
- EXPECT_EQ(in_payload.umask, new_mask);
- EXPECT_EQ(std::string(name.data()), test_file_name_);
-
- // Get the successive FUSE_OPEN.
- struct fuse_open_in in_payload_open;
- iov_in = FuseGenerateIovecs(in_header, in_payload_open);
- GetServerActualRequest(iov_in);
- EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload_open));
- EXPECT_EQ(in_header.opcode, FUSE_OPEN);
- EXPECT_EQ(in_payload_open.flags, open_flags & O_ACCMODE);
-
- EXPECT_THAT(close(fd), SyscallSucceeds());
- // Skip the FUSE_RELEASE.
- SkipServerActualRequest();
-}
-
-TEST_F(CreateTest, CreateFileAlreadyExists) {
- const std::string test_file_path =
- JoinPath(mount_point_.path().c_str(), test_file_name_);
-
- const int open_flags = O_CREAT | O_EXCL;
-
- SetServerInodeLookup(test_file_name_);
-
- EXPECT_THAT(open(test_file_path.c_str(), mode, open_flags),
- SyscallFailsWithErrno(EEXIST));
-}
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/fuse/linux/fuse_base.cc b/test/fuse/linux/fuse_base.cc
deleted file mode 100644
index 5b45804e1..000000000
--- a/test/fuse/linux/fuse_base.cc
+++ /dev/null
@@ -1,447 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// 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 specific language governing permissions and
-// limitations under the License.
-
-#include "test/fuse/linux/fuse_base.h"
-
-#include <fcntl.h>
-#include <linux/fuse.h>
-#include <poll.h>
-#include <sys/mount.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-
-#include "gtest/gtest.h"
-#include "absl/strings/str_format.h"
-#include "test/util/fuse_util.h"
-#include "test/util/posix_error.h"
-#include "test/util/temp_path.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-void FuseTest::SetUp() {
- MountFuse();
- SetUpFuseServer();
-}
-
-void FuseTest::TearDown() {
- EXPECT_EQ(GetServerNumUnconsumedRequests(), 0);
- EXPECT_EQ(GetServerNumUnsentResponses(), 0);
- UnmountFuse();
-}
-
-// Sends 3 parts of data to the FUSE server:
-// 1. The `kSetResponse` command
-// 2. The expected opcode
-// 3. The fake FUSE response
-// Then waits for the FUSE server to notify its completion.
-void FuseTest::SetServerResponse(uint32_t opcode,
- std::vector<struct iovec>& iovecs) {
- uint32_t cmd = static_cast<uint32_t>(FuseTestCmd::kSetResponse);
- EXPECT_THAT(RetryEINTR(write)(sock_[0], &cmd, sizeof(cmd)),
- SyscallSucceedsWithValue(sizeof(cmd)));
-
- EXPECT_THAT(RetryEINTR(write)(sock_[0], &opcode, sizeof(opcode)),
- SyscallSucceedsWithValue(sizeof(opcode)));
-
- EXPECT_THAT(RetryEINTR(writev)(sock_[0], iovecs.data(), iovecs.size()),
- SyscallSucceeds());
-
- WaitServerComplete();
-}
-
-// Waits for the FUSE server to finish its blocking job and check if it
-// completes without errors.
-void FuseTest::WaitServerComplete() {
- uint32_t success;
- EXPECT_THAT(RetryEINTR(read)(sock_[0], &success, sizeof(success)),
- SyscallSucceedsWithValue(sizeof(success)));
- ASSERT_EQ(success, 1);
-}
-
-// Sends the `kGetRequest` command to the FUSE server, then reads the next
-// request into iovec struct. The order of calling this function should be
-// the same as the one of SetServerResponse().
-void FuseTest::GetServerActualRequest(std::vector<struct iovec>& iovecs) {
- uint32_t cmd = static_cast<uint32_t>(FuseTestCmd::kGetRequest);
- EXPECT_THAT(RetryEINTR(write)(sock_[0], &cmd, sizeof(cmd)),
- SyscallSucceedsWithValue(sizeof(cmd)));
-
- EXPECT_THAT(RetryEINTR(readv)(sock_[0], iovecs.data(), iovecs.size()),
- SyscallSucceeds());
-
- WaitServerComplete();
-}
-
-// Sends a FuseTestCmd command to the FUSE server, reads from the socket, and
-// returns the corresponding data.
-uint32_t FuseTest::GetServerData(uint32_t cmd) {
- uint32_t data;
- EXPECT_THAT(RetryEINTR(write)(sock_[0], &cmd, sizeof(cmd)),
- SyscallSucceedsWithValue(sizeof(cmd)));
-
- EXPECT_THAT(RetryEINTR(read)(sock_[0], &data, sizeof(data)),
- SyscallSucceedsWithValue(sizeof(data)));
-
- WaitServerComplete();
- return data;
-}
-
-uint32_t FuseTest::GetServerNumUnconsumedRequests() {
- return GetServerData(
- static_cast<uint32_t>(FuseTestCmd::kGetNumUnconsumedRequests));
-}
-
-uint32_t FuseTest::GetServerNumUnsentResponses() {
- return GetServerData(
- static_cast<uint32_t>(FuseTestCmd::kGetNumUnsentResponses));
-}
-
-uint32_t FuseTest::GetServerTotalReceivedBytes() {
- return GetServerData(
- static_cast<uint32_t>(FuseTestCmd::kGetTotalReceivedBytes));
-}
-
-// Sends the `kSkipRequest` command to the FUSE server, which would skip
-// current stored request data.
-void FuseTest::SkipServerActualRequest() {
- uint32_t cmd = static_cast<uint32_t>(FuseTestCmd::kSkipRequest);
- EXPECT_THAT(RetryEINTR(write)(sock_[0], &cmd, sizeof(cmd)),
- SyscallSucceedsWithValue(sizeof(cmd)));
-
- WaitServerComplete();
-}
-
-// Sends the `kSetInodeLookup` command, expected mode, and the path of the
-// inode to create under the mount point.
-void FuseTest::SetServerInodeLookup(const std::string& path, mode_t mode,
- uint64_t size) {
- uint32_t cmd = static_cast<uint32_t>(FuseTestCmd::kSetInodeLookup);
- EXPECT_THAT(RetryEINTR(write)(sock_[0], &cmd, sizeof(cmd)),
- SyscallSucceedsWithValue(sizeof(cmd)));
-
- EXPECT_THAT(RetryEINTR(write)(sock_[0], &mode, sizeof(mode)),
- SyscallSucceedsWithValue(sizeof(mode)));
-
- EXPECT_THAT(RetryEINTR(write)(sock_[0], &size, sizeof(size)),
- SyscallSucceedsWithValue(sizeof(size)));
-
- // Pad 1 byte for null-terminate c-string.
- EXPECT_THAT(RetryEINTR(write)(sock_[0], path.c_str(), path.size() + 1),
- SyscallSucceedsWithValue(path.size() + 1));
-
- WaitServerComplete();
-}
-
-void FuseTest::MountFuse(const char* mountOpts) {
- EXPECT_THAT(dev_fd_ = open("/dev/fuse", O_RDWR), SyscallSucceeds());
-
- std::string mount_opts = absl::StrFormat("fd=%d,%s", dev_fd_, mountOpts);
- mount_point_ = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
- EXPECT_THAT(mount("fuse", mount_point_.path().c_str(), "fuse",
- MS_NODEV | MS_NOSUID, mount_opts.c_str()),
- SyscallSucceeds());
-}
-
-void FuseTest::UnmountFuse() {
- EXPECT_THAT(umount(mount_point_.path().c_str()), SyscallSucceeds());
- // TODO(gvisor.dev/issue/3330): ensure the process is terminated successfully.
-}
-
-// Consumes the first FUSE request and returns the corresponding PosixError.
-PosixError FuseTest::ServerConsumeFuseInit(
- const struct fuse_init_out* out_payload) {
- std::vector<char> buf(FUSE_MIN_READ_BUFFER);
- RETURN_ERROR_IF_SYSCALL_FAIL(
- RetryEINTR(read)(dev_fd_, buf.data(), buf.size()));
-
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_init_out),
- .error = 0,
- .unique = 2,
- };
- // Returns a fake fuse_init_out with 7.0 version to avoid ECONNREFUSED
- // error in the initialization of FUSE connection.
- auto iov_out = FuseGenerateIovecs(
- out_header, *const_cast<struct fuse_init_out*>(out_payload));
-
- RETURN_ERROR_IF_SYSCALL_FAIL(
- RetryEINTR(writev)(dev_fd_, iov_out.data(), iov_out.size()));
- return NoError();
-}
-
-// Reads 1 expected opcode and a fake response from socket and save them into
-// the serial buffer of this testing instance.
-void FuseTest::ServerReceiveResponse() {
- ssize_t len;
- uint32_t opcode;
- std::vector<char> buf(FUSE_MIN_READ_BUFFER);
- EXPECT_THAT(RetryEINTR(read)(sock_[1], &opcode, sizeof(opcode)),
- SyscallSucceedsWithValue(sizeof(opcode)));
-
- EXPECT_THAT(len = RetryEINTR(read)(sock_[1], buf.data(), buf.size()),
- SyscallSucceeds());
-
- responses_.AddMemBlock(opcode, buf.data(), len);
-}
-
-// Writes 1 byte of success indicator through socket.
-void FuseTest::ServerCompleteWith(bool success) {
- uint32_t data = success ? 1 : 0;
- ServerSendData(data);
-}
-
-// ServerFuseLoop is the implementation of the fake FUSE server. Monitors 2
-// file descriptors: /dev/fuse and sock_[1]. Events from /dev/fuse are FUSE
-// requests and events from sock_[1] are FUSE testing commands, leading by
-// a FuseTestCmd data to indicate the command.
-void FuseTest::ServerFuseLoop() {
- const int nfds = 2;
- struct pollfd fds[nfds] = {
- {
- .fd = dev_fd_,
- .events = POLL_IN | POLLHUP | POLLERR | POLLNVAL,
- },
- {
- .fd = sock_[1],
- .events = POLL_IN | POLLHUP | POLLERR | POLLNVAL,
- },
- };
-
- while (true) {
- ASSERT_THAT(poll(fds, nfds, -1), SyscallSucceeds());
-
- for (int fd_idx = 0; fd_idx < nfds; ++fd_idx) {
- if (fds[fd_idx].revents == 0) continue;
-
- ASSERT_EQ(fds[fd_idx].revents, POLL_IN);
- if (fds[fd_idx].fd == sock_[1]) {
- ServerHandleCommand();
- } else if (fds[fd_idx].fd == dev_fd_) {
- ServerProcessFuseRequest();
- }
- }
- }
-}
-
-// SetUpFuseServer creates 1 socketpair and fork the process. The parent thread
-// becomes testing thread and the child thread becomes the FUSE server running
-// in background. These 2 threads are connected via socketpair. sock_[0] is
-// opened in testing thread and sock_[1] is opened in the FUSE server.
-void FuseTest::SetUpFuseServer(const struct fuse_init_out* payload) {
- ASSERT_THAT(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_), SyscallSucceeds());
-
- switch (fork()) {
- case -1:
- GTEST_FAIL();
- return;
- case 0:
- break;
- default:
- ASSERT_THAT(close(sock_[1]), SyscallSucceeds());
- WaitServerComplete();
- return;
- }
-
- // Begin child thread, i.e. the FUSE server.
- ASSERT_THAT(close(sock_[0]), SyscallSucceeds());
- ServerCompleteWith(ServerConsumeFuseInit(payload).ok());
- ServerFuseLoop();
- _exit(0);
-}
-
-void FuseTest::ServerSendData(uint32_t data) {
- EXPECT_THAT(RetryEINTR(write)(sock_[1], &data, sizeof(data)),
- SyscallSucceedsWithValue(sizeof(data)));
-}
-
-// Reads FuseTestCmd sent from testing thread and routes to correct handler.
-// Since each command should be a blocking operation, a `ServerCompleteWith()`
-// is required after the switch keyword.
-void FuseTest::ServerHandleCommand() {
- uint32_t cmd;
- EXPECT_THAT(RetryEINTR(read)(sock_[1], &cmd, sizeof(cmd)),
- SyscallSucceedsWithValue(sizeof(cmd)));
-
- switch (static_cast<FuseTestCmd>(cmd)) {
- case FuseTestCmd::kSetResponse:
- ServerReceiveResponse();
- break;
- case FuseTestCmd::kSetInodeLookup:
- ServerReceiveInodeLookup();
- break;
- case FuseTestCmd::kGetRequest:
- ServerSendReceivedRequest();
- break;
- case FuseTestCmd::kGetTotalReceivedBytes:
- ServerSendData(static_cast<uint32_t>(requests_.UsedBytes()));
- break;
- case FuseTestCmd::kGetNumUnconsumedRequests:
- ServerSendData(static_cast<uint32_t>(requests_.RemainingBlocks()));
- break;
- case FuseTestCmd::kGetNumUnsentResponses:
- ServerSendData(static_cast<uint32_t>(responses_.RemainingBlocks()));
- break;
- case FuseTestCmd::kSkipRequest:
- ServerSkipReceivedRequest();
- break;
- default:
- FAIL() << "Unknown FuseTestCmd " << cmd;
- break;
- }
-
- ServerCompleteWith(!HasFailure());
-}
-
-// Reads the expected file mode and the path of one file. Crafts a basic
-// `fuse_entry_out` memory block and inserts into a map for future use.
-// The FUSE server will always return this response if a FUSE_LOOKUP
-// request with this specific path comes in.
-void FuseTest::ServerReceiveInodeLookup() {
- mode_t mode;
- uint64_t size;
- std::vector<char> buf(FUSE_MIN_READ_BUFFER);
-
- EXPECT_THAT(RetryEINTR(read)(sock_[1], &mode, sizeof(mode)),
- SyscallSucceedsWithValue(sizeof(mode)));
-
- EXPECT_THAT(RetryEINTR(read)(sock_[1], &size, sizeof(size)),
- SyscallSucceedsWithValue(sizeof(size)));
-
- EXPECT_THAT(RetryEINTR(read)(sock_[1], buf.data(), buf.size()),
- SyscallSucceeds());
-
- std::string path(buf.data());
-
- uint32_t out_len =
- sizeof(struct fuse_out_header) + sizeof(struct fuse_entry_out);
- struct fuse_out_header out_header = {
- .len = out_len,
- .error = 0,
- };
- struct fuse_entry_out out_payload = DefaultEntryOut(mode, nodeid_);
- // Since this is only used in test, nodeid_ is simply increased by 1 to
- // comply with the unqiueness of different path.
- ++nodeid_;
-
- // Set the size.
- out_payload.attr.size = size;
-
- memcpy(buf.data(), &out_header, sizeof(out_header));
- memcpy(buf.data() + sizeof(out_header), &out_payload, sizeof(out_payload));
- lookups_.AddMemBlock(FUSE_LOOKUP, buf.data(), out_len);
- lookup_map_[path] = lookups_.Next();
-}
-
-// Sends the received request pointed by current cursor and advances cursor.
-void FuseTest::ServerSendReceivedRequest() {
- if (requests_.End()) {
- FAIL() << "No more received request.";
- return;
- }
- auto mem_block = requests_.Next();
- EXPECT_THAT(
- RetryEINTR(write)(sock_[1], requests_.DataAtOffset(mem_block.offset),
- mem_block.len),
- SyscallSucceedsWithValue(mem_block.len));
-}
-
-// Skip the request pointed by current cursor.
-void FuseTest::ServerSkipReceivedRequest() {
- if (requests_.End()) {
- FAIL() << "No more received request.";
- return;
- }
- requests_.Next();
-}
-
-// Handles FUSE request. Reads request from /dev/fuse, checks if it has the
-// same opcode as expected, and responds with the saved fake FUSE response.
-// The FUSE request is copied to the serial buffer and can be retrieved one-
-// by-one by calling GetServerActualRequest from testing thread.
-void FuseTest::ServerProcessFuseRequest() {
- ssize_t len;
- std::vector<char> buf(FUSE_MIN_READ_BUFFER);
-
- // Read FUSE request.
- EXPECT_THAT(len = RetryEINTR(read)(dev_fd_, buf.data(), buf.size()),
- SyscallSucceeds());
- fuse_in_header* in_header = reinterpret_cast<fuse_in_header*>(buf.data());
-
- // Check if this is a preset FUSE_LOOKUP path.
- if (in_header->opcode == FUSE_LOOKUP) {
- std::string path(buf.data() + sizeof(struct fuse_in_header));
- auto it = lookup_map_.find(path);
- if (it != lookup_map_.end()) {
- // Matches a preset path. Reply with fake data and skip saving the
- // request.
- ServerRespondFuseSuccess(lookups_, it->second, in_header->unique);
- return;
- }
- }
-
- requests_.AddMemBlock(in_header->opcode, buf.data(), len);
-
- if (in_header->opcode == FUSE_RELEASE || in_header->opcode == FUSE_RELEASEDIR)
- return;
- // Check if there is a corresponding response.
- if (responses_.End()) {
- GTEST_NONFATAL_FAILURE_("No more FUSE response is expected");
- ServerRespondFuseError(in_header->unique);
- return;
- }
- auto mem_block = responses_.Next();
- if (in_header->opcode != mem_block.opcode) {
- std::string message = absl::StrFormat("Expect opcode %d but got %d",
- mem_block.opcode, in_header->opcode);
- GTEST_NONFATAL_FAILURE_(message.c_str());
- // We won't get correct response if opcode is not expected. Send error
- // response here to avoid wrong parsing by VFS.
- ServerRespondFuseError(in_header->unique);
- return;
- }
-
- // Write FUSE response.
- ServerRespondFuseSuccess(responses_, mem_block, in_header->unique);
-}
-
-void FuseTest::ServerRespondFuseSuccess(FuseMemBuffer& mem_buf,
- const FuseMemBlock& block,
- uint64_t unique) {
- fuse_out_header* out_header =
- reinterpret_cast<fuse_out_header*>(mem_buf.DataAtOffset(block.offset));
-
- // Patch `unique` in fuse_out_header to avoid EINVAL caused by responding
- // with an unknown `unique`.
- out_header->unique = unique;
- EXPECT_THAT(RetryEINTR(write)(dev_fd_, out_header, block.len),
- SyscallSucceedsWithValue(block.len));
-}
-
-void FuseTest::ServerRespondFuseError(uint64_t unique) {
- fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header),
- .error = ENOSYS,
- .unique = unique,
- };
- EXPECT_THAT(RetryEINTR(write)(dev_fd_, &out_header, sizeof(out_header)),
- SyscallSucceedsWithValue(sizeof(out_header)));
-}
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/fuse/linux/fuse_base.h b/test/fuse/linux/fuse_base.h
deleted file mode 100644
index 6ad296ca2..000000000
--- a/test/fuse/linux/fuse_base.h
+++ /dev/null
@@ -1,251 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// 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 specific language governing permissions and
-// limitations under the License.
-
-#ifndef GVISOR_TEST_FUSE_FUSE_BASE_H_
-#define GVISOR_TEST_FUSE_FUSE_BASE_H_
-
-#include <linux/fuse.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-
-#include <iostream>
-#include <unordered_map>
-#include <vector>
-
-#include "gtest/gtest.h"
-#include "test/util/posix_error.h"
-#include "test/util/temp_path.h"
-
-namespace gvisor {
-namespace testing {
-
-constexpr char kMountOpts[] = "rootmode=755,user_id=0,group_id=0";
-
-constexpr struct fuse_init_out kDefaultFUSEInitOutPayload = {.major = 7};
-
-// Internal commands used to communicate between testing thread and the FUSE
-// server. See test/fuse/README.md for further detail.
-enum class FuseTestCmd {
- kSetResponse = 0,
- kSetInodeLookup,
- kGetRequest,
- kGetNumUnconsumedRequests,
- kGetNumUnsentResponses,
- kGetTotalReceivedBytes,
- kSkipRequest,
-};
-
-// Holds the information of a memory block in a serial buffer.
-struct FuseMemBlock {
- uint32_t opcode;
- size_t offset;
- size_t len;
-};
-
-// A wrapper of a simple serial buffer that can be used with read(2) and
-// write(2). Contains a cursor to indicate accessing. This class is not thread-
-// safe and can only be used in single-thread version.
-class FuseMemBuffer {
- public:
- FuseMemBuffer() : cursor_(0) {
- // To read from /dev/fuse, a buffer needs at least FUSE_MIN_READ_BUFFER
- // bytes to avoid EINVAL. FuseMemBuffer holds memory that can accommodate
- // a sequence of FUSE request/response, so it is initiated with double
- // minimal requirement.
- mem_.resize(FUSE_MIN_READ_BUFFER * 2);
- }
-
- // Returns whether there is no memory block.
- bool Empty() { return blocks_.empty(); }
-
- // Returns if there is no more remaining memory blocks.
- bool End() { return cursor_ == blocks_.size(); }
-
- // Returns how many bytes that have been received.
- size_t UsedBytes() {
- return Empty() ? 0 : blocks_.back().offset + blocks_.back().len;
- }
-
- // Returns the available bytes remains in the serial buffer.
- size_t AvailBytes() { return mem_.size() - UsedBytes(); }
-
- // Appends a memory block information that starts at the tail of the serial
- // buffer. /dev/fuse requires at least FUSE_MIN_READ_BUFFER bytes to read, or
- // it will issue EINVAL. If it is not enough, just double the buffer length.
- void AddMemBlock(uint32_t opcode, void* data, size_t len) {
- if (AvailBytes() < FUSE_MIN_READ_BUFFER) {
- mem_.resize(mem_.size() << 1);
- }
- size_t offset = UsedBytes();
- memcpy(mem_.data() + offset, data, len);
- blocks_.push_back(FuseMemBlock{opcode, offset, len});
- }
-
- // Returns the memory address at a specific offset. Used with read(2) or
- // write(2).
- char* DataAtOffset(size_t offset) { return mem_.data() + offset; }
-
- // Returns current memory block pointed by the cursor and increase by 1.
- FuseMemBlock Next() {
- if (End()) {
- std::cerr << "Buffer is already exhausted." << std::endl;
- return FuseMemBlock{};
- }
- return blocks_[cursor_++];
- }
-
- // Returns the number of the blocks that has not been requested.
- size_t RemainingBlocks() { return blocks_.size() - cursor_; }
-
- private:
- size_t cursor_;
- std::vector<FuseMemBlock> blocks_;
- std::vector<char> mem_;
-};
-
-// FuseTest base class is useful in FUSE integration test. Inherit this class
-// to automatically set up a fake FUSE server and use the member functions
-// to manipulate with it. Refer to test/fuse/README.md for detailed explanation.
-class FuseTest : public ::testing::Test {
- public:
- // nodeid_ is the ID of a fake inode. We starts from 2 since 1 is occupied by
- // the mount point.
- FuseTest() : nodeid_(2) {}
- void SetUp() override;
- void TearDown() override;
-
- // Called by the testing thread to set up a fake response for an expected
- // opcode via socket. This can be used multiple times to define a sequence of
- // expected FUSE reactions.
- void SetServerResponse(uint32_t opcode, std::vector<struct iovec>& iovecs);
-
- // Called by the testing thread to install a fake path under the mount point.
- // e.g. a file under /mnt/dir/file and moint point is /mnt, then it will look
- // up "dir/file" in this case.
- //
- // It sets a fixed response to the FUSE_LOOKUP requests issued with this
- // path, pretending there is an inode and avoid ENOENT when testing. If mode
- // is not given, it creates a regular file with mode 0600.
- void SetServerInodeLookup(const std::string& path,
- mode_t mode = S_IFREG | S_IRUSR | S_IWUSR,
- uint64_t size = 512);
-
- // Called by the testing thread to ask the FUSE server for its next received
- // FUSE request. Be sure to use the corresponding struct of iovec to receive
- // data from server.
- void GetServerActualRequest(std::vector<struct iovec>& iovecs);
-
- // Called by the testing thread to query the number of unconsumed requests in
- // the requests_ serial buffer of the FUSE server. TearDown() ensures all
- // FUSE requests received by the FUSE server were consumed by the testing
- // thread.
- uint32_t GetServerNumUnconsumedRequests();
-
- // Called by the testing thread to query the number of unsent responses in
- // the responses_ serial buffer of the FUSE server. TearDown() ensures all
- // preset FUSE responses were sent out by the FUSE server.
- uint32_t GetServerNumUnsentResponses();
-
- // Called by the testing thread to ask the FUSE server for its total received
- // bytes from /dev/fuse.
- uint32_t GetServerTotalReceivedBytes();
-
- // Called by the testing thread to ask the FUSE server to skip stored
- // request data.
- void SkipServerActualRequest();
-
- protected:
- TempPath mount_point_;
-
- // Opens /dev/fuse and inherit the file descriptor for the FUSE server.
- void MountFuse(const char* mountOpts = kMountOpts);
-
- // Creates a socketpair for communication and forks FUSE server.
- void SetUpFuseServer(
- const struct fuse_init_out* payload = &kDefaultFUSEInitOutPayload);
-
- // Unmounts the mountpoint of the FUSE server.
- void UnmountFuse();
-
- private:
- // Sends a FuseTestCmd and gets a uint32_t data from the FUSE server.
- inline uint32_t GetServerData(uint32_t cmd);
-
- // Waits for FUSE server to complete its processing. Complains if the FUSE
- // server responds any failure during tests.
- void WaitServerComplete();
-
- // The FUSE server stays here and waits next command or FUSE request until it
- // is terminated.
- void ServerFuseLoop();
-
- // Used by the FUSE server to tell testing thread if it is OK to proceed next
- // command. Will be issued after processing each FuseTestCmd.
- void ServerCompleteWith(bool success);
-
- // Consumes the first FUSE request when mounting FUSE. Replies with a
- // response with empty payload.
- PosixError ServerConsumeFuseInit(const struct fuse_init_out* payload);
-
- // A command switch that dispatch different FuseTestCmd to its handler.
- void ServerHandleCommand();
-
- // The FUSE server side's corresponding code of `SetServerResponse()`.
- // Handles `kSetResponse` command. Saves the fake response into its output
- // memory queue.
- void ServerReceiveResponse();
-
- // The FUSE server side's corresponding code of `SetServerInodeLookup()`.
- // Handles `kSetInodeLookup` command. Receives an expected file mode and
- // file path under the mount point.
- void ServerReceiveInodeLookup();
-
- // The FUSE server side's corresponding code of `GetServerActualRequest()`.
- // Handles `kGetRequest` command. Sends the next received request pointed by
- // the cursor.
- void ServerSendReceivedRequest();
-
- // Sends a uint32_t data via socket.
- inline void ServerSendData(uint32_t data);
-
- // The FUSE server side's corresponding code of `SkipServerActualRequest()`.
- // Handles `kSkipRequest` command. Skip the request pointed by current cursor.
- void ServerSkipReceivedRequest();
-
- // Handles FUSE request sent to /dev/fuse by its saved responses.
- void ServerProcessFuseRequest();
-
- // Responds to FUSE request with a saved data.
- void ServerRespondFuseSuccess(FuseMemBuffer& mem_buf,
- const FuseMemBlock& block, uint64_t unique);
-
- // Responds an error header to /dev/fuse when bad thing happens.
- void ServerRespondFuseError(uint64_t unique);
-
- int dev_fd_;
- int sock_[2];
-
- uint64_t nodeid_;
- std::unordered_map<std::string, FuseMemBlock> lookup_map_;
-
- FuseMemBuffer requests_;
- FuseMemBuffer responses_;
- FuseMemBuffer lookups_;
-};
-
-} // namespace testing
-} // namespace gvisor
-
-#endif // GVISOR_TEST_FUSE_FUSE_BASE_H_
diff --git a/test/fuse/linux/fuse_fd_util.cc b/test/fuse/linux/fuse_fd_util.cc
deleted file mode 100644
index 30d1157bb..000000000
--- a/test/fuse/linux/fuse_fd_util.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// 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 specific language governing permissions and
-// limitations under the License.
-
-#include "test/fuse/linux/fuse_fd_util.h"
-
-#include <fcntl.h>
-#include <linux/fuse.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-
-#include <string>
-#include <vector>
-
-#include "test/util/cleanup.h"
-#include "test/util/file_descriptor.h"
-#include "test/util/fuse_util.h"
-#include "test/util/posix_error.h"
-
-namespace gvisor {
-namespace testing {
-
-PosixErrorOr<FileDescriptor> FuseFdTest::OpenPath(const std::string &path,
- uint32_t flags, uint64_t fh) {
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_open_out),
- };
- struct fuse_open_out out_payload = {
- .fh = fh,
- .open_flags = flags,
- };
- auto iov_out = FuseGenerateIovecs(out_header, out_payload);
- SetServerResponse(FUSE_OPEN, iov_out);
-
- auto res = Open(path.c_str(), flags);
- if (res.ok()) {
- SkipServerActualRequest();
- }
- return res;
-}
-
-Cleanup FuseFdTest::CloseFD(FileDescriptor &fd) {
- return Cleanup([&] {
- close(fd.release());
- SkipServerActualRequest();
- });
-}
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/fuse/linux/fuse_fd_util.h b/test/fuse/linux/fuse_fd_util.h
deleted file mode 100644
index 066185c94..000000000
--- a/test/fuse/linux/fuse_fd_util.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// 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 specific language governing permissions and
-// limitations under the License.
-
-#ifndef GVISOR_TEST_FUSE_FUSE_FD_UTIL_H_
-#define GVISOR_TEST_FUSE_FUSE_FD_UTIL_H_
-
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <string>
-
-#include "test/fuse/linux/fuse_base.h"
-#include "test/util/cleanup.h"
-#include "test/util/file_descriptor.h"
-#include "test/util/posix_error.h"
-
-namespace gvisor {
-namespace testing {
-
-class FuseFdTest : public FuseTest {
- public:
- // Sets the FUSE server to respond to a FUSE_OPEN with corresponding flags and
- // fh. Then does a real file system open on the absolute path to get an fd.
- PosixErrorOr<FileDescriptor> OpenPath(const std::string &path,
- uint32_t flags = O_RDONLY,
- uint64_t fh = 1);
-
- // Returns a cleanup object that closes the fd when it is destroyed. After
- // the close is done, tells the FUSE server to skip this FUSE_RELEASE.
- Cleanup CloseFD(FileDescriptor &fd);
-};
-
-} // namespace testing
-} // namespace gvisor
-
-#endif // GVISOR_TEST_FUSE_FUSE_FD_UTIL_H_
diff --git a/test/fuse/linux/mkdir_test.cc b/test/fuse/linux/mkdir_test.cc
deleted file mode 100644
index 9647cb93f..000000000
--- a/test/fuse/linux/mkdir_test.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// 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 specific language governing permissions and
-// limitations under the License.
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/fuse.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-#include <vector>
-
-#include "gtest/gtest.h"
-#include "test/fuse/linux/fuse_base.h"
-#include "test/util/fuse_util.h"
-#include "test/util/temp_umask.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-class MkdirTest : public FuseTest {
- protected:
- const std::string test_dir_ = "test_dir";
- const mode_t perms_ = S_IRWXU | S_IRWXG | S_IRWXO;
-};
-
-TEST_F(MkdirTest, CreateDir) {
- const std::string test_dir_path_ =
- JoinPath(mount_point_.path().c_str(), test_dir_);
- const mode_t new_umask = 0077;
-
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_entry_out),
- };
- struct fuse_entry_out out_payload = DefaultEntryOut(S_IFDIR | perms_, 5);
- auto iov_out = FuseGenerateIovecs(out_header, out_payload);
- SetServerResponse(FUSE_MKDIR, iov_out);
- TempUmask mask(new_umask);
- ASSERT_THAT(mkdir(test_dir_path_.c_str(), 0777), SyscallSucceeds());
-
- struct fuse_in_header in_header;
- struct fuse_mkdir_in in_payload;
- std::vector<char> actual_dir(test_dir_.length() + 1);
- auto iov_in = FuseGenerateIovecs(in_header, in_payload, actual_dir);
- GetServerActualRequest(iov_in);
-
- EXPECT_EQ(in_header.len,
- sizeof(in_header) + sizeof(in_payload) + test_dir_.length() + 1);
- EXPECT_EQ(in_header.opcode, FUSE_MKDIR);
- EXPECT_EQ(in_payload.mode & 0777, perms_ & ~new_umask);
- EXPECT_EQ(in_payload.umask, new_umask);
- EXPECT_EQ(std::string(actual_dir.data()), test_dir_);
-}
-
-TEST_F(MkdirTest, FileTypeError) {
- const std::string test_dir_path_ =
- JoinPath(mount_point_.path().c_str(), test_dir_);
-
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_entry_out),
- };
- struct fuse_entry_out out_payload = DefaultEntryOut(S_IFREG | perms_, 5);
- auto iov_out = FuseGenerateIovecs(out_header, out_payload);
- SetServerResponse(FUSE_MKDIR, iov_out);
- ASSERT_THAT(mkdir(test_dir_path_.c_str(), 0777), SyscallFailsWithErrno(EIO));
- SkipServerActualRequest();
-}
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/fuse/linux/mknod_test.cc b/test/fuse/linux/mknod_test.cc
deleted file mode 100644
index 74c74d76b..000000000
--- a/test/fuse/linux/mknod_test.cc
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// 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 specific language governing permissions and
-// limitations under the License.
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/fuse.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-#include <vector>
-
-#include "gtest/gtest.h"
-#include "test/fuse/linux/fuse_base.h"
-#include "test/util/fuse_util.h"
-#include "test/util/temp_umask.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-class MknodTest : public FuseTest {
- protected:
- const std::string test_file_ = "test_file";
- const mode_t perms_ = S_IRWXU | S_IRWXG | S_IRWXO;
-};
-
-TEST_F(MknodTest, RegularFile) {
- const std::string test_file_path =
- JoinPath(mount_point_.path().c_str(), test_file_);
- const mode_t new_umask = 0077;
-
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_entry_out),
- };
- struct fuse_entry_out out_payload = DefaultEntryOut(S_IFREG | perms_, 5);
- auto iov_out = FuseGenerateIovecs(out_header, out_payload);
- SetServerResponse(FUSE_MKNOD, iov_out);
- TempUmask mask(new_umask);
- ASSERT_THAT(mknod(test_file_path.c_str(), perms_, 0), SyscallSucceeds());
-
- struct fuse_in_header in_header;
- struct fuse_mknod_in in_payload;
- std::vector<char> actual_file(test_file_.length() + 1);
- auto iov_in = FuseGenerateIovecs(in_header, in_payload, actual_file);
- GetServerActualRequest(iov_in);
-
- EXPECT_EQ(in_header.len,
- sizeof(in_header) + sizeof(in_payload) + test_file_.length() + 1);
- EXPECT_EQ(in_header.opcode, FUSE_MKNOD);
- EXPECT_EQ(in_payload.mode & 0777, perms_ & ~new_umask);
- EXPECT_EQ(in_payload.umask, new_umask);
- EXPECT_EQ(in_payload.rdev, 0);
- EXPECT_EQ(std::string(actual_file.data()), test_file_);
-}
-
-TEST_F(MknodTest, FileTypeError) {
- const std::string test_file_path =
- JoinPath(mount_point_.path().c_str(), test_file_);
-
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_entry_out),
- };
- // server return directory instead of regular file should cause an error.
- struct fuse_entry_out out_payload = DefaultEntryOut(S_IFDIR | perms_, 5);
- auto iov_out = FuseGenerateIovecs(out_header, out_payload);
- SetServerResponse(FUSE_MKNOD, iov_out);
- ASSERT_THAT(mknod(test_file_path.c_str(), perms_, 0),
- SyscallFailsWithErrno(EIO));
- SkipServerActualRequest();
-}
-
-TEST_F(MknodTest, NodeIDError) {
- const std::string test_file_path =
- JoinPath(mount_point_.path().c_str(), test_file_);
-
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_entry_out),
- };
- struct fuse_entry_out out_payload =
- DefaultEntryOut(S_IFREG | perms_, FUSE_ROOT_ID);
- auto iov_out = FuseGenerateIovecs(out_header, out_payload);
- SetServerResponse(FUSE_MKNOD, iov_out);
- ASSERT_THAT(mknod(test_file_path.c_str(), perms_, 0),
- SyscallFailsWithErrno(EIO));
- SkipServerActualRequest();
-}
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/fuse/linux/mount_test.cc b/test/fuse/linux/mount_test.cc
deleted file mode 100644
index a5c2fbb01..000000000
--- a/test/fuse/linux/mount_test.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// 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 specific language governing permissions and
-// limitations under the License.
-
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/mount.h>
-
-#include "gtest/gtest.h"
-#include "test/util/temp_path.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-TEST(FuseMount, FDNotParsable) {
- int devfd;
- EXPECT_THAT(devfd = open("/dev/fuse", O_RDWR), SyscallSucceeds());
- std::string mount_opts = "fd=thiscantbeparsed";
- TempPath mount_dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
- EXPECT_THAT(mount("fuse", mount_dir.path().c_str(), "fuse",
- MS_NODEV | MS_NOSUID, mount_opts.c_str()),
- SyscallFailsWithErrno(EINVAL));
-}
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/fuse/linux/open_test.cc b/test/fuse/linux/open_test.cc
deleted file mode 100644
index 4b0c4a805..000000000
--- a/test/fuse/linux/open_test.cc
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// 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 specific language governing permissions and
-// limitations under the License.
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/fuse.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-
-#include "gtest/gtest.h"
-#include "test/fuse/linux/fuse_base.h"
-#include "test/util/fuse_util.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-class OpenTest : public FuseTest {
- // OpenTest doesn't care the release request when close a fd,
- // so doesn't check leftover requests when tearing down.
- void TearDown() { UnmountFuse(); }
-
- protected:
- const std::string test_file_ = "test_file";
- const mode_t regular_file_ = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO;
-
- struct fuse_open_out out_payload_ = {
- .fh = 1,
- .open_flags = O_RDWR,
- };
-};
-
-TEST_F(OpenTest, RegularFile) {
- const std::string test_file_path =
- JoinPath(mount_point_.path().c_str(), test_file_);
- SetServerInodeLookup(test_file_, regular_file_);
-
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_open_out),
- };
- auto iov_out = FuseGenerateIovecs(out_header, out_payload_);
- SetServerResponse(FUSE_OPEN, iov_out);
- FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_path.c_str(), O_RDWR));
-
- struct fuse_in_header in_header;
- struct fuse_open_in in_payload;
- auto iov_in = FuseGenerateIovecs(in_header, in_payload);
- GetServerActualRequest(iov_in);
-
- EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload));
- EXPECT_EQ(in_header.opcode, FUSE_OPEN);
- EXPECT_EQ(in_payload.flags, O_RDWR);
- EXPECT_THAT(fcntl(fd.get(), F_GETFL), SyscallSucceedsWithValue(O_RDWR));
-}
-
-TEST_F(OpenTest, SetNoOpen) {
- const std::string test_file_path =
- JoinPath(mount_point_.path().c_str(), test_file_);
- SetServerInodeLookup(test_file_, regular_file_);
-
- // ENOSYS indicates open is not implemented.
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_open_out),
- .error = -ENOSYS,
- };
- auto iov_out = FuseGenerateIovecs(out_header, out_payload_);
- SetServerResponse(FUSE_OPEN, iov_out);
- ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_path.c_str(), O_RDWR));
- SkipServerActualRequest();
-
- // check open doesn't send new request.
- uint32_t recieved_before = GetServerTotalReceivedBytes();
- ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_path.c_str(), O_RDWR));
- EXPECT_EQ(GetServerTotalReceivedBytes(), recieved_before);
-}
-
-TEST_F(OpenTest, OpenFail) {
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_open_out),
- .error = -ENOENT,
- };
-
- auto iov_out = FuseGenerateIovecs(out_header, out_payload_);
- SetServerResponse(FUSE_OPENDIR, iov_out);
- ASSERT_THAT(open(mount_point_.path().c_str(), O_RDWR),
- SyscallFailsWithErrno(ENOENT));
-
- struct fuse_in_header in_header;
- struct fuse_open_in in_payload;
- auto iov_in = FuseGenerateIovecs(in_header, in_payload);
- GetServerActualRequest(iov_in);
-
- EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload));
- EXPECT_EQ(in_header.opcode, FUSE_OPENDIR);
- EXPECT_EQ(in_payload.flags, O_RDWR);
-}
-
-TEST_F(OpenTest, DirectoryFlagOnRegularFile) {
- const std::string test_file_path =
- JoinPath(mount_point_.path().c_str(), test_file_);
-
- SetServerInodeLookup(test_file_, regular_file_);
- ASSERT_THAT(open(test_file_path.c_str(), O_RDWR | O_DIRECTORY),
- SyscallFailsWithErrno(ENOTDIR));
-}
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/fuse/linux/read_test.cc b/test/fuse/linux/read_test.cc
deleted file mode 100644
index 88fc299d8..000000000
--- a/test/fuse/linux/read_test.cc
+++ /dev/null
@@ -1,390 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// 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 specific language governing permissions and
-// limitations under the License.
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/fuse.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-#include <vector>
-
-#include "gtest/gtest.h"
-#include "test/fuse/linux/fuse_base.h"
-#include "test/util/fuse_util.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-class ReadTest : public FuseTest {
- void SetUp() override {
- FuseTest::SetUp();
- test_file_path_ = JoinPath(mount_point_.path().c_str(), test_file_);
- }
-
- // TearDown overrides the parent's function
- // to skip checking the unconsumed release request at the end.
- void TearDown() override { UnmountFuse(); }
-
- protected:
- const std::string test_file_ = "test_file";
- const mode_t test_file_mode_ = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO;
- const uint64_t test_fh_ = 1;
- const uint32_t open_flag_ = O_RDWR;
-
- std::string test_file_path_;
-
- PosixErrorOr<FileDescriptor> OpenTestFile(const std::string &path,
- uint64_t size = 512) {
- SetServerInodeLookup(test_file_, test_file_mode_, size);
-
- struct fuse_out_header out_header_open = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_open_out),
- };
- struct fuse_open_out out_payload_open = {
- .fh = test_fh_,
- .open_flags = open_flag_,
- };
- auto iov_out_open = FuseGenerateIovecs(out_header_open, out_payload_open);
- SetServerResponse(FUSE_OPEN, iov_out_open);
-
- auto res = Open(path.c_str(), open_flag_);
- if (res.ok()) {
- SkipServerActualRequest();
- }
- return res;
- }
-};
-
-class ReadTestSmallMaxRead : public ReadTest {
- void SetUp() override {
- MountFuse(mountOpts);
- SetUpFuseServer();
- test_file_path_ = JoinPath(mount_point_.path().c_str(), test_file_);
- }
-
- protected:
- constexpr static char mountOpts[] =
- "rootmode=755,user_id=0,group_id=0,max_read=4096";
- // 4096 is hard-coded as the max_read in mount options.
- const int size_fragment = 4096;
-};
-
-TEST_F(ReadTest, ReadWhole) {
- auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_));
-
- // Prepare for the read.
- const int n_read = 5;
- std::vector<char> data(n_read);
- RandomizeBuffer(data.data(), data.size());
- struct fuse_out_header out_header_read = {
- .len =
- static_cast<uint32_t>(sizeof(struct fuse_out_header) + data.size()),
- };
- auto iov_out_read = FuseGenerateIovecs(out_header_read, data);
- SetServerResponse(FUSE_READ, iov_out_read);
-
- // Read the whole "file".
- std::vector<char> buf(n_read);
- EXPECT_THAT(read(fd.get(), buf.data(), n_read),
- SyscallSucceedsWithValue(n_read));
-
- // Check the read request.
- struct fuse_in_header in_header_read;
- struct fuse_read_in in_payload_read;
- auto iov_in = FuseGenerateIovecs(in_header_read, in_payload_read);
- GetServerActualRequest(iov_in);
-
- EXPECT_EQ(in_payload_read.fh, test_fh_);
- EXPECT_EQ(in_header_read.len,
- sizeof(in_header_read) + sizeof(in_payload_read));
- EXPECT_EQ(in_header_read.opcode, FUSE_READ);
- EXPECT_EQ(in_payload_read.offset, 0);
- EXPECT_EQ(buf, data);
-}
-
-TEST_F(ReadTest, ReadPartial) {
- auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_));
-
- // Prepare for the read.
- const int n_data = 10;
- std::vector<char> data(n_data);
- RandomizeBuffer(data.data(), data.size());
- // Note: due to read ahead, current read implementation will treat any
- // response that is longer than requested as correct (i.e. not reach the EOF).
- // Therefore, the test below should make sure the size to read does not exceed
- // n_data.
- struct fuse_out_header out_header_read = {
- .len =
- static_cast<uint32_t>(sizeof(struct fuse_out_header) + data.size()),
- };
- auto iov_out_read = FuseGenerateIovecs(out_header_read, data);
- struct fuse_in_header in_header_read;
- struct fuse_read_in in_payload_read;
- auto iov_in = FuseGenerateIovecs(in_header_read, in_payload_read);
-
- std::vector<char> buf(n_data);
-
- // Read 1 bytes.
- SetServerResponse(FUSE_READ, iov_out_read);
- EXPECT_THAT(read(fd.get(), buf.data(), 1), SyscallSucceedsWithValue(1));
-
- // Check the 1-byte read request.
- GetServerActualRequest(iov_in);
- EXPECT_EQ(in_payload_read.fh, test_fh_);
- EXPECT_EQ(in_header_read.len,
- sizeof(in_header_read) + sizeof(in_payload_read));
- EXPECT_EQ(in_header_read.opcode, FUSE_READ);
- EXPECT_EQ(in_payload_read.offset, 0);
-
- // Read 3 bytes.
- SetServerResponse(FUSE_READ, iov_out_read);
- EXPECT_THAT(read(fd.get(), buf.data(), 3), SyscallSucceedsWithValue(3));
-
- // Check the 3-byte read request.
- GetServerActualRequest(iov_in);
- EXPECT_EQ(in_payload_read.fh, test_fh_);
- EXPECT_EQ(in_payload_read.offset, 1);
-
- // Read 5 bytes.
- SetServerResponse(FUSE_READ, iov_out_read);
- EXPECT_THAT(read(fd.get(), buf.data(), 5), SyscallSucceedsWithValue(5));
-
- // Check the 5-byte read request.
- GetServerActualRequest(iov_in);
- EXPECT_EQ(in_payload_read.fh, test_fh_);
- EXPECT_EQ(in_payload_read.offset, 4);
-}
-
-TEST_F(ReadTest, PRead) {
- const int file_size = 512;
- auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_, file_size));
-
- // Prepare for the read.
- const int n_read = 5;
- std::vector<char> data(n_read);
- RandomizeBuffer(data.data(), data.size());
- struct fuse_out_header out_header_read = {
- .len =
- static_cast<uint32_t>(sizeof(struct fuse_out_header) + data.size()),
- };
- auto iov_out_read = FuseGenerateIovecs(out_header_read, data);
- SetServerResponse(FUSE_READ, iov_out_read);
-
- // Read some bytes.
- std::vector<char> buf(n_read);
- const int offset_read = file_size >> 1;
- EXPECT_THAT(pread(fd.get(), buf.data(), n_read, offset_read),
- SyscallSucceedsWithValue(n_read));
-
- // Check the read request.
- struct fuse_in_header in_header_read;
- struct fuse_read_in in_payload_read;
- auto iov_in = FuseGenerateIovecs(in_header_read, in_payload_read);
- GetServerActualRequest(iov_in);
-
- EXPECT_EQ(in_payload_read.fh, test_fh_);
- EXPECT_EQ(in_header_read.len,
- sizeof(in_header_read) + sizeof(in_payload_read));
- EXPECT_EQ(in_header_read.opcode, FUSE_READ);
- EXPECT_EQ(in_payload_read.offset, offset_read);
- EXPECT_EQ(buf, data);
-}
-
-TEST_F(ReadTest, ReadZero) {
- auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_));
-
- // Issue the read.
- std::vector<char> buf;
- EXPECT_THAT(read(fd.get(), buf.data(), 0), SyscallSucceedsWithValue(0));
-}
-
-TEST_F(ReadTest, ReadShort) {
- auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_));
-
- // Prepare for the short read.
- const int n_read = 5;
- std::vector<char> data(n_read >> 1);
- RandomizeBuffer(data.data(), data.size());
- struct fuse_out_header out_header_read = {
- .len =
- static_cast<uint32_t>(sizeof(struct fuse_out_header) + data.size()),
- };
- auto iov_out_read = FuseGenerateIovecs(out_header_read, data);
- SetServerResponse(FUSE_READ, iov_out_read);
-
- // Read the whole "file".
- std::vector<char> buf(n_read);
- EXPECT_THAT(read(fd.get(), buf.data(), n_read),
- SyscallSucceedsWithValue(data.size()));
-
- // Check the read request.
- struct fuse_in_header in_header_read;
- struct fuse_read_in in_payload_read;
- auto iov_in = FuseGenerateIovecs(in_header_read, in_payload_read);
- GetServerActualRequest(iov_in);
-
- EXPECT_EQ(in_payload_read.fh, test_fh_);
- EXPECT_EQ(in_header_read.len,
- sizeof(in_header_read) + sizeof(in_payload_read));
- EXPECT_EQ(in_header_read.opcode, FUSE_READ);
- EXPECT_EQ(in_payload_read.offset, 0);
- std::vector<char> short_buf(buf.begin(), buf.begin() + data.size());
- EXPECT_EQ(short_buf, data);
-}
-
-TEST_F(ReadTest, ReadShortEOF) {
- auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_));
-
- // Prepare for the short read.
- struct fuse_out_header out_header_read = {
- .len = static_cast<uint32_t>(sizeof(struct fuse_out_header)),
- };
- auto iov_out_read = FuseGenerateIovecs(out_header_read);
- SetServerResponse(FUSE_READ, iov_out_read);
-
- // Read the whole "file".
- const int n_read = 10;
- std::vector<char> buf(n_read);
- EXPECT_THAT(read(fd.get(), buf.data(), n_read), SyscallSucceedsWithValue(0));
-
- // Check the read request.
- struct fuse_in_header in_header_read;
- struct fuse_read_in in_payload_read;
- auto iov_in = FuseGenerateIovecs(in_header_read, in_payload_read);
- GetServerActualRequest(iov_in);
-
- EXPECT_EQ(in_payload_read.fh, test_fh_);
- EXPECT_EQ(in_header_read.len,
- sizeof(in_header_read) + sizeof(in_payload_read));
- EXPECT_EQ(in_header_read.opcode, FUSE_READ);
- EXPECT_EQ(in_payload_read.offset, 0);
-}
-
-TEST_F(ReadTestSmallMaxRead, ReadSmallMaxRead) {
- const int n_fragment = 10;
- const int n_read = size_fragment * n_fragment;
-
- auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_, n_read));
-
- // Prepare for the read.
- std::vector<char> data(size_fragment);
- RandomizeBuffer(data.data(), data.size());
- struct fuse_out_header out_header_read = {
- .len =
- static_cast<uint32_t>(sizeof(struct fuse_out_header) + data.size()),
- };
- auto iov_out_read = FuseGenerateIovecs(out_header_read, data);
-
- for (int i = 0; i < n_fragment; ++i) {
- SetServerResponse(FUSE_READ, iov_out_read);
- }
-
- // Read the whole "file".
- std::vector<char> buf(n_read);
- EXPECT_THAT(read(fd.get(), buf.data(), n_read),
- SyscallSucceedsWithValue(n_read));
-
- ASSERT_EQ(GetServerNumUnsentResponses(), 0);
- ASSERT_EQ(GetServerNumUnconsumedRequests(), n_fragment);
-
- // Check each read segment.
- struct fuse_in_header in_header_read;
- struct fuse_read_in in_payload_read;
- auto iov_in = FuseGenerateIovecs(in_header_read, in_payload_read);
-
- for (int i = 0; i < n_fragment; ++i) {
- GetServerActualRequest(iov_in);
- EXPECT_EQ(in_payload_read.fh, test_fh_);
- EXPECT_EQ(in_header_read.len,
- sizeof(in_header_read) + sizeof(in_payload_read));
- EXPECT_EQ(in_header_read.opcode, FUSE_READ);
- EXPECT_EQ(in_payload_read.offset, i * size_fragment);
- EXPECT_EQ(in_payload_read.size, size_fragment);
-
- auto it = buf.begin() + i * size_fragment;
- EXPECT_EQ(std::vector<char>(it, it + size_fragment), data);
- }
-}
-
-TEST_F(ReadTestSmallMaxRead, ReadSmallMaxReadShort) {
- const int n_fragment = 10;
- const int n_read = size_fragment * n_fragment;
-
- auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_, n_read));
-
- // Prepare for the read.
- std::vector<char> data(size_fragment);
- RandomizeBuffer(data.data(), data.size());
- struct fuse_out_header out_header_read = {
- .len =
- static_cast<uint32_t>(sizeof(struct fuse_out_header) + data.size()),
- };
- auto iov_out_read = FuseGenerateIovecs(out_header_read, data);
-
- for (int i = 0; i < n_fragment - 1; ++i) {
- SetServerResponse(FUSE_READ, iov_out_read);
- }
-
- // The last fragment is a short read.
- std::vector<char> half_data(data.begin(), data.begin() + (data.size() >> 1));
- struct fuse_out_header out_header_read_short = {
- .len = static_cast<uint32_t>(sizeof(struct fuse_out_header) +
- half_data.size()),
- };
- auto iov_out_read_short =
- FuseGenerateIovecs(out_header_read_short, half_data);
- SetServerResponse(FUSE_READ, iov_out_read_short);
-
- // Read the whole "file".
- std::vector<char> buf(n_read);
- EXPECT_THAT(read(fd.get(), buf.data(), n_read),
- SyscallSucceedsWithValue(n_read - (data.size() >> 1)));
-
- ASSERT_EQ(GetServerNumUnsentResponses(), 0);
- ASSERT_EQ(GetServerNumUnconsumedRequests(), n_fragment);
-
- // Check each read segment.
- struct fuse_in_header in_header_read;
- struct fuse_read_in in_payload_read;
- auto iov_in = FuseGenerateIovecs(in_header_read, in_payload_read);
-
- for (int i = 0; i < n_fragment; ++i) {
- GetServerActualRequest(iov_in);
- EXPECT_EQ(in_payload_read.fh, test_fh_);
- EXPECT_EQ(in_header_read.len,
- sizeof(in_header_read) + sizeof(in_payload_read));
- EXPECT_EQ(in_header_read.opcode, FUSE_READ);
- EXPECT_EQ(in_payload_read.offset, i * size_fragment);
- EXPECT_EQ(in_payload_read.size, size_fragment);
-
- auto it = buf.begin() + i * size_fragment;
- if (i != n_fragment - 1) {
- EXPECT_EQ(std::vector<char>(it, it + data.size()), data);
- } else {
- EXPECT_EQ(std::vector<char>(it, it + half_data.size()), half_data);
- }
- }
-}
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/fuse/linux/readdir_test.cc b/test/fuse/linux/readdir_test.cc
deleted file mode 100644
index 2afb4b062..000000000
--- a/test/fuse/linux/readdir_test.cc
+++ /dev/null
@@ -1,193 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// 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 specific language governing permissions and
-// limitations under the License.
-
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/fuse.h>
-#include <linux/unistd.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-
-#include "gtest/gtest.h"
-#include "test/fuse/linux/fuse_base.h"
-#include "test/util/fuse_util.h"
-#include "test/util/test_util.h"
-
-#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
-#define FUSE_DIRENT_ALIGN(x) \
- (((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1))
-#define FUSE_DIRENT_SIZE(d) FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-class ReaddirTest : public FuseTest {
- public:
- void fill_fuse_dirent(char *buf, const char *name, uint64_t ino) {
- size_t namelen = strlen(name);
- size_t entlen = FUSE_NAME_OFFSET + namelen;
- size_t entlen_padded = FUSE_DIRENT_ALIGN(entlen);
- struct fuse_dirent *dirent;
-
- dirent = reinterpret_cast<struct fuse_dirent *>(buf);
- dirent->ino = ino;
- dirent->namelen = namelen;
- memcpy(dirent->name, name, namelen);
- memset(dirent->name + namelen, 0, entlen_padded - entlen);
- }
-
- protected:
- const std::string test_dir_name_ = "test_dir";
-};
-
-TEST_F(ReaddirTest, SingleEntry) {
- const std::string test_dir_path =
- JoinPath(mount_point_.path().c_str(), test_dir_name_);
-
- const uint64_t ino_dir = 1024;
- // We need to make sure the test dir is a directory that can be found.
- mode_t expected_mode =
- S_IFDIR | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
- struct fuse_attr dir_attr = {
- .ino = ino_dir,
- .size = 512,
- .blocks = 4,
- .mode = expected_mode,
- .blksize = 4096,
- };
-
- // We need to make sure the test dir is a directory that can be found.
- struct fuse_out_header lookup_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_entry_out),
- };
- struct fuse_entry_out lookup_payload = {
- .nodeid = 1,
- .entry_valid = true,
- .attr_valid = true,
- .attr = dir_attr,
- };
-
- struct fuse_out_header open_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_open_out),
- };
- struct fuse_open_out open_payload = {
- .fh = 1,
- };
- auto iov_out = FuseGenerateIovecs(lookup_header, lookup_payload);
- SetServerResponse(FUSE_LOOKUP, iov_out);
-
- iov_out = FuseGenerateIovecs(open_header, open_payload);
- SetServerResponse(FUSE_OPENDIR, iov_out);
-
- FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(test_dir_path.c_str(), O_RDONLY));
-
- // The open command makes two syscalls. Lookup the dir file and open.
- // We don't need to inspect those headers in this test.
- SkipServerActualRequest(); // LOOKUP.
- SkipServerActualRequest(); // OPENDIR.
-
- // Readdir test code.
- std::string dot = ".";
- std::string dot_dot = "..";
- std::string test_file = "testFile";
-
- // Figure out how many dirents to send over and allocate them appropriately.
- // Each dirent has a dynamic name and a static metadata part. The dirent size
- // is aligned to being a multiple of 8.
- size_t dot_file_dirent_size =
- FUSE_DIRENT_ALIGN(dot.length() + FUSE_NAME_OFFSET);
- size_t dot_dot_file_dirent_size =
- FUSE_DIRENT_ALIGN(dot_dot.length() + FUSE_NAME_OFFSET);
- size_t test_file_dirent_size =
- FUSE_DIRENT_ALIGN(test_file.length() + FUSE_NAME_OFFSET);
-
- // Create an appropriately sized payload.
- size_t readdir_payload_size =
- test_file_dirent_size + dot_file_dirent_size + dot_dot_file_dirent_size;
- std::vector<char> readdir_payload_vec(readdir_payload_size);
- char *readdir_payload = readdir_payload_vec.data();
-
- // Use fake ino for other directories.
- fill_fuse_dirent(readdir_payload, dot.c_str(), ino_dir - 2);
- fill_fuse_dirent(readdir_payload + dot_file_dirent_size, dot_dot.c_str(),
- ino_dir - 1);
- fill_fuse_dirent(
- readdir_payload + dot_file_dirent_size + dot_dot_file_dirent_size,
- test_file.c_str(), ino_dir);
-
- struct fuse_out_header readdir_header = {
- .len = uint32_t(sizeof(struct fuse_out_header) + readdir_payload_size),
- };
- struct fuse_out_header readdir_header_break = {
- .len = uint32_t(sizeof(struct fuse_out_header)),
- };
-
- iov_out = FuseGenerateIovecs(readdir_header, readdir_payload_vec);
- SetServerResponse(FUSE_READDIR, iov_out);
-
- iov_out = FuseGenerateIovecs(readdir_header_break);
- SetServerResponse(FUSE_READDIR, iov_out);
-
- std::vector<char> buf(4090, 0);
- int nread, off = 0, i = 0;
- EXPECT_THAT(
- nread = syscall(__NR_getdents64, fd.get(), buf.data(), buf.size()),
- SyscallSucceeds());
- for (; off < nread;) {
- struct dirent64 *ent = (struct dirent64 *)(buf.data() + off);
- off += ent->d_reclen;
- switch (i++) {
- case 0:
- EXPECT_EQ(std::string(ent->d_name), dot);
- break;
- case 1:
- EXPECT_EQ(std::string(ent->d_name), dot_dot);
- break;
- case 2:
- EXPECT_EQ(std::string(ent->d_name), test_file);
- break;
- }
- }
-
- EXPECT_THAT(
- nread = syscall(__NR_getdents64, fd.get(), buf.data(), buf.size()),
- SyscallSucceedsWithValue(0));
-
- SkipServerActualRequest(); // READDIR.
- SkipServerActualRequest(); // READDIR with no data.
-
- // Clean up.
- fd.reset(-1);
-
- struct fuse_in_header in_header;
- struct fuse_release_in in_payload;
-
- auto iov_in = FuseGenerateIovecs(in_header, in_payload);
- GetServerActualRequest(iov_in);
- EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload));
- EXPECT_EQ(in_header.opcode, FUSE_RELEASEDIR);
-}
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/fuse/linux/readlink_test.cc b/test/fuse/linux/readlink_test.cc
deleted file mode 100644
index 2cba8fc23..000000000
--- a/test/fuse/linux/readlink_test.cc
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// 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 specific language governing permissions and
-// limitations under the License.
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/fuse.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-#include <vector>
-
-#include "gtest/gtest.h"
-#include "test/fuse/linux/fuse_base.h"
-#include "test/util/fuse_util.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-class ReadlinkTest : public FuseTest {
- protected:
- const std::string test_file_ = "test_file_";
- const mode_t perms_ = S_IRWXU | S_IRWXG | S_IRWXO;
-};
-
-TEST_F(ReadlinkTest, ReadSymLink) {
- const std::string symlink_path =
- JoinPath(mount_point_.path().c_str(), test_file_);
- SetServerInodeLookup(test_file_, S_IFLNK | perms_);
-
- struct fuse_out_header out_header = {
- .len = static_cast<uint32_t>(sizeof(struct fuse_out_header)) +
- static_cast<uint32_t>(test_file_.length()) + 1,
- };
- std::string link = test_file_;
- auto iov_out = FuseGenerateIovecs(out_header, link);
- SetServerResponse(FUSE_READLINK, iov_out);
- const std::string actual_link =
- ASSERT_NO_ERRNO_AND_VALUE(ReadLink(symlink_path));
-
- struct fuse_in_header in_header;
- auto iov_in = FuseGenerateIovecs(in_header);
- GetServerActualRequest(iov_in);
-
- EXPECT_EQ(in_header.len, sizeof(in_header));
- EXPECT_EQ(in_header.opcode, FUSE_READLINK);
- EXPECT_EQ(0, memcmp(actual_link.c_str(), link.data(), link.size()));
-
- // next readlink should have link cached, so shouldn't have new request to
- // server.
- uint32_t recieved_before = GetServerTotalReceivedBytes();
- ASSERT_NO_ERRNO(ReadLink(symlink_path));
- EXPECT_EQ(GetServerTotalReceivedBytes(), recieved_before);
-}
-
-TEST_F(ReadlinkTest, NotSymlink) {
- const std::string test_file_path =
- JoinPath(mount_point_.path().c_str(), test_file_);
- SetServerInodeLookup(test_file_, S_IFREG | perms_);
-
- std::vector<char> buf(PATH_MAX + 1);
- ASSERT_THAT(readlink(test_file_path.c_str(), buf.data(), PATH_MAX),
- SyscallFailsWithErrno(EINVAL));
-}
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/fuse/linux/release_test.cc b/test/fuse/linux/release_test.cc
deleted file mode 100644
index b5adb0870..000000000
--- a/test/fuse/linux/release_test.cc
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// 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 specific language governing permissions and
-// limitations under the License.
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/fuse.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-#include <vector>
-
-#include "gtest/gtest.h"
-#include "test/fuse/linux/fuse_base.h"
-#include "test/util/fuse_util.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-class ReleaseTest : public FuseTest {
- protected:
- const std::string test_file_ = "test_file";
-};
-
-TEST_F(ReleaseTest, RegularFile) {
- const std::string test_file_path =
- JoinPath(mount_point_.path().c_str(), test_file_);
- SetServerInodeLookup(test_file_, S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO);
-
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_open_out),
- };
- struct fuse_open_out out_payload = {
- .fh = 1,
- .open_flags = O_RDWR,
- };
- auto iov_out = FuseGenerateIovecs(out_header, out_payload);
- SetServerResponse(FUSE_OPEN, iov_out);
- FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_path, O_RDWR));
- SkipServerActualRequest();
- ASSERT_THAT(close(fd.release()), SyscallSucceeds());
-
- struct fuse_in_header in_header;
- struct fuse_release_in in_payload;
- auto iov_in = FuseGenerateIovecs(in_header, in_payload);
- GetServerActualRequest(iov_in);
-
- EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload));
- EXPECT_EQ(in_header.opcode, FUSE_RELEASE);
- EXPECT_EQ(in_payload.flags, O_RDWR);
- EXPECT_EQ(in_payload.fh, 1);
-}
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/fuse/linux/rmdir_test.cc b/test/fuse/linux/rmdir_test.cc
deleted file mode 100644
index e3200e446..000000000
--- a/test/fuse/linux/rmdir_test.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// 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 specific language governing permissions and
-// limitations under the License.
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/fuse.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-
-#include <string>
-#include <vector>
-
-#include "gtest/gtest.h"
-#include "test/fuse/linux/fuse_base.h"
-#include "test/util/fs_util.h"
-#include "test/util/fuse_util.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-class RmDirTest : public FuseTest {
- protected:
- const std::string test_dir_name_ = "test_dir";
- const std::string test_subdir_ = "test_subdir";
- const mode_t test_dir_mode_ = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO;
-};
-
-TEST_F(RmDirTest, NormalRmDir) {
- const std::string test_dir_path_ =
- JoinPath(mount_point_.path().c_str(), test_dir_name_);
-
- SetServerInodeLookup(test_dir_name_, test_dir_mode_);
-
- // RmDir code.
- struct fuse_out_header rmdir_header = {
- .len = sizeof(struct fuse_out_header),
- };
-
- auto iov_out = FuseGenerateIovecs(rmdir_header);
- SetServerResponse(FUSE_RMDIR, iov_out);
-
- ASSERT_THAT(rmdir(test_dir_path_.c_str()), SyscallSucceeds());
-
- struct fuse_in_header in_header;
- std::vector<char> actual_dirname(test_dir_name_.length() + 1);
- auto iov_in = FuseGenerateIovecs(in_header, actual_dirname);
- GetServerActualRequest(iov_in);
-
- EXPECT_EQ(in_header.len, sizeof(in_header) + test_dir_name_.length() + 1);
- EXPECT_EQ(in_header.opcode, FUSE_RMDIR);
- EXPECT_EQ(std::string(actual_dirname.data()), test_dir_name_);
-}
-
-TEST_F(RmDirTest, NormalRmDirSubdir) {
- SetServerInodeLookup(test_subdir_, S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
- const std::string test_dir_path_ =
- JoinPath(mount_point_.path().c_str(), test_subdir_, test_dir_name_);
- SetServerInodeLookup(test_dir_name_, test_dir_mode_);
-
- // RmDir code.
- struct fuse_out_header rmdir_header = {
- .len = sizeof(struct fuse_out_header),
- };
-
- auto iov_out = FuseGenerateIovecs(rmdir_header);
- SetServerResponse(FUSE_RMDIR, iov_out);
-
- ASSERT_THAT(rmdir(test_dir_path_.c_str()), SyscallSucceeds());
-
- struct fuse_in_header in_header;
- std::vector<char> actual_dirname(test_dir_name_.length() + 1);
- auto iov_in = FuseGenerateIovecs(in_header, actual_dirname);
- GetServerActualRequest(iov_in);
-
- EXPECT_EQ(in_header.len, sizeof(in_header) + test_dir_name_.length() + 1);
- EXPECT_EQ(in_header.opcode, FUSE_RMDIR);
- EXPECT_EQ(std::string(actual_dirname.data()), test_dir_name_);
-}
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/fuse/linux/setstat_test.cc b/test/fuse/linux/setstat_test.cc
deleted file mode 100644
index 68301c775..000000000
--- a/test/fuse/linux/setstat_test.cc
+++ /dev/null
@@ -1,338 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// 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 specific language governing permissions and
-// limitations under the License.
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/fuse.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-#include <utime.h>
-
-#include <string>
-#include <vector>
-
-#include "gtest/gtest.h"
-#include "test/fuse/linux/fuse_fd_util.h"
-#include "test/util/cleanup.h"
-#include "test/util/fs_util.h"
-#include "test/util/fuse_util.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-class SetStatTest : public FuseFdTest {
- public:
- void SetUp() override {
- FuseFdTest::SetUp();
- test_dir_path_ = JoinPath(mount_point_.path(), test_dir_);
- test_file_path_ = JoinPath(mount_point_.path(), test_file_);
- }
-
- protected:
- const uint64_t fh = 23;
- const std::string test_dir_ = "testdir";
- const std::string test_file_ = "testfile";
- const mode_t test_dir_mode_ = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR;
- const mode_t test_file_mode_ = S_IFREG | S_IRUSR | S_IWUSR | S_IXUSR;
-
- std::string test_dir_path_;
- std::string test_file_path_;
-};
-
-TEST_F(SetStatTest, ChmodDir) {
- // Set up fixture.
- SetServerInodeLookup(test_dir_, test_dir_mode_);
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out),
- .error = 0,
- };
- mode_t set_mode = S_IRGRP | S_IWGRP | S_IXGRP;
- struct fuse_attr_out out_payload = {
- .attr = DefaultFuseAttr(set_mode, 2),
- };
- auto iov_out = FuseGenerateIovecs(out_header, out_payload);
- SetServerResponse(FUSE_SETATTR, iov_out);
-
- // Make syscall.
- EXPECT_THAT(chmod(test_dir_path_.c_str(), set_mode), SyscallSucceeds());
-
- // Check FUSE request.
- struct fuse_in_header in_header;
- struct fuse_setattr_in in_payload;
- auto iov_in = FuseGenerateIovecs(in_header, in_payload);
-
- GetServerActualRequest(iov_in);
- EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload));
- EXPECT_EQ(in_header.opcode, FUSE_SETATTR);
- EXPECT_EQ(in_header.uid, 0);
- EXPECT_EQ(in_header.gid, 0);
- EXPECT_EQ(in_payload.valid, FATTR_MODE);
- EXPECT_EQ(in_payload.mode, S_IFDIR | set_mode);
-}
-
-TEST_F(SetStatTest, ChownDir) {
- // Set up fixture.
- SetServerInodeLookup(test_dir_, test_dir_mode_);
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out),
- .error = 0,
- };
- struct fuse_attr_out out_payload = {
- .attr = DefaultFuseAttr(test_dir_mode_, 2),
- };
- auto iov_out = FuseGenerateIovecs(out_header, out_payload);
- SetServerResponse(FUSE_SETATTR, iov_out);
-
- // Make syscall.
- EXPECT_THAT(chown(test_dir_path_.c_str(), 1025, 1025), SyscallSucceeds());
-
- // Check FUSE request.
- struct fuse_in_header in_header;
- struct fuse_setattr_in in_payload;
- auto iov_in = FuseGenerateIovecs(in_header, in_payload);
-
- GetServerActualRequest(iov_in);
- EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload));
- EXPECT_EQ(in_header.opcode, FUSE_SETATTR);
- EXPECT_EQ(in_header.uid, 0);
- EXPECT_EQ(in_header.gid, 0);
- EXPECT_EQ(in_payload.valid, FATTR_UID | FATTR_GID);
- EXPECT_EQ(in_payload.uid, 1025);
- EXPECT_EQ(in_payload.gid, 1025);
-}
-
-TEST_F(SetStatTest, TruncateFile) {
- // Set up fixture.
- SetServerInodeLookup(test_file_, test_file_mode_);
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out),
- .error = 0,
- };
- struct fuse_attr_out out_payload = {
- .attr = DefaultFuseAttr(S_IFREG | S_IRUSR | S_IWUSR, 2),
- };
- auto iov_out = FuseGenerateIovecs(out_header, out_payload);
- SetServerResponse(FUSE_SETATTR, iov_out);
-
- // Make syscall.
- EXPECT_THAT(truncate(test_file_path_.c_str(), 321), SyscallSucceeds());
-
- // Check FUSE request.
- struct fuse_in_header in_header;
- struct fuse_setattr_in in_payload;
- auto iov_in = FuseGenerateIovecs(in_header, in_payload);
-
- GetServerActualRequest(iov_in);
- EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload));
- EXPECT_EQ(in_header.opcode, FUSE_SETATTR);
- EXPECT_EQ(in_header.uid, 0);
- EXPECT_EQ(in_header.gid, 0);
- EXPECT_EQ(in_payload.valid, FATTR_SIZE);
- EXPECT_EQ(in_payload.size, 321);
-}
-
-TEST_F(SetStatTest, UtimeFile) {
- // Set up fixture.
- SetServerInodeLookup(test_file_, test_file_mode_);
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out),
- .error = 0,
- };
- struct fuse_attr_out out_payload = {
- .attr = DefaultFuseAttr(S_IFREG | S_IRUSR | S_IWUSR, 2),
- };
- auto iov_out = FuseGenerateIovecs(out_header, out_payload);
- SetServerResponse(FUSE_SETATTR, iov_out);
-
- // Make syscall.
- time_t expected_atime = 1597159766, expected_mtime = 1597159765;
- struct utimbuf times = {
- .actime = expected_atime,
- .modtime = expected_mtime,
- };
- EXPECT_THAT(utime(test_file_path_.c_str(), &times), SyscallSucceeds());
-
- // Check FUSE request.
- struct fuse_in_header in_header;
- struct fuse_setattr_in in_payload;
- auto iov_in = FuseGenerateIovecs(in_header, in_payload);
-
- GetServerActualRequest(iov_in);
- EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload));
- EXPECT_EQ(in_header.opcode, FUSE_SETATTR);
- EXPECT_EQ(in_header.uid, 0);
- EXPECT_EQ(in_header.gid, 0);
- EXPECT_EQ(in_payload.valid, FATTR_ATIME | FATTR_MTIME);
- EXPECT_EQ(in_payload.atime, expected_atime);
- EXPECT_EQ(in_payload.mtime, expected_mtime);
-}
-
-TEST_F(SetStatTest, UtimesFile) {
- // Set up fixture.
- SetServerInodeLookup(test_file_, test_file_mode_);
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out),
- .error = 0,
- };
- struct fuse_attr_out out_payload = {
- .attr = DefaultFuseAttr(test_file_mode_, 2),
- };
- auto iov_out = FuseGenerateIovecs(out_header, out_payload);
- SetServerResponse(FUSE_SETATTR, iov_out);
-
- // Make syscall.
- struct timeval expected_times[2] = {
- {
- .tv_sec = 1597159766,
- .tv_usec = 234945,
- },
- {
- .tv_sec = 1597159765,
- .tv_usec = 232341,
- },
- };
- EXPECT_THAT(utimes(test_file_path_.c_str(), expected_times),
- SyscallSucceeds());
-
- // Check FUSE request.
- struct fuse_in_header in_header;
- struct fuse_setattr_in in_payload;
- auto iov_in = FuseGenerateIovecs(in_header, in_payload);
-
- GetServerActualRequest(iov_in);
- EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload));
- EXPECT_EQ(in_header.opcode, FUSE_SETATTR);
- EXPECT_EQ(in_header.uid, 0);
- EXPECT_EQ(in_header.gid, 0);
- EXPECT_EQ(in_payload.valid, FATTR_ATIME | FATTR_MTIME);
- EXPECT_EQ(in_payload.atime, expected_times[0].tv_sec);
- EXPECT_EQ(in_payload.atimensec, expected_times[0].tv_usec * 1000);
- EXPECT_EQ(in_payload.mtime, expected_times[1].tv_sec);
- EXPECT_EQ(in_payload.mtimensec, expected_times[1].tv_usec * 1000);
-}
-
-TEST_F(SetStatTest, FtruncateFile) {
- // Set up fixture.
- SetServerInodeLookup(test_file_, test_file_mode_);
- auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenPath(test_file_path_, O_RDWR, fh));
- auto close_fd = CloseFD(fd);
-
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out),
- .error = 0,
- };
- struct fuse_attr_out out_payload = {
- .attr = DefaultFuseAttr(test_file_mode_, 2),
- };
- auto iov_out = FuseGenerateIovecs(out_header, out_payload);
- SetServerResponse(FUSE_SETATTR, iov_out);
-
- // Make syscall.
- EXPECT_THAT(ftruncate(fd.get(), 321), SyscallSucceeds());
-
- // Check FUSE request.
- struct fuse_in_header in_header;
- struct fuse_setattr_in in_payload;
- auto iov_in = FuseGenerateIovecs(in_header, in_payload);
-
- GetServerActualRequest(iov_in);
- EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload));
- EXPECT_EQ(in_header.opcode, FUSE_SETATTR);
- EXPECT_EQ(in_header.uid, 0);
- EXPECT_EQ(in_header.gid, 0);
- EXPECT_EQ(in_payload.valid, FATTR_SIZE | FATTR_FH);
- EXPECT_EQ(in_payload.fh, fh);
- EXPECT_EQ(in_payload.size, 321);
-}
-
-TEST_F(SetStatTest, FchmodFile) {
- // Set up fixture.
- SetServerInodeLookup(test_file_, test_file_mode_);
- auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenPath(test_file_path_, O_RDWR, fh));
- auto close_fd = CloseFD(fd);
-
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out),
- .error = 0,
- };
- mode_t set_mode = S_IROTH | S_IWOTH | S_IXOTH;
- struct fuse_attr_out out_payload = {
- .attr = DefaultFuseAttr(set_mode, 2),
- };
- auto iov_out = FuseGenerateIovecs(out_header, out_payload);
- SetServerResponse(FUSE_SETATTR, iov_out);
-
- // Make syscall.
- EXPECT_THAT(fchmod(fd.get(), set_mode), SyscallSucceeds());
-
- // Check FUSE request.
- struct fuse_in_header in_header;
- struct fuse_setattr_in in_payload;
- auto iov_in = FuseGenerateIovecs(in_header, in_payload);
-
- GetServerActualRequest(iov_in);
- EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload));
- EXPECT_EQ(in_header.opcode, FUSE_SETATTR);
- EXPECT_EQ(in_header.uid, 0);
- EXPECT_EQ(in_header.gid, 0);
- EXPECT_EQ(in_payload.valid, FATTR_MODE | FATTR_FH);
- EXPECT_EQ(in_payload.fh, fh);
- EXPECT_EQ(in_payload.mode, S_IFREG | set_mode);
-}
-
-TEST_F(SetStatTest, FchownFile) {
- // Set up fixture.
- SetServerInodeLookup(test_file_, test_file_mode_);
- auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenPath(test_file_path_, O_RDWR, fh));
- auto close_fd = CloseFD(fd);
-
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out),
- .error = 0,
- };
- struct fuse_attr_out out_payload = {
- .attr = DefaultFuseAttr(S_IFREG | S_IRUSR | S_IWUSR | S_IXUSR, 2),
- };
- auto iov_out = FuseGenerateIovecs(out_header, out_payload);
- SetServerResponse(FUSE_SETATTR, iov_out);
-
- // Make syscall.
- EXPECT_THAT(fchown(fd.get(), 1025, 1025), SyscallSucceeds());
-
- // Check FUSE request.
- struct fuse_in_header in_header;
- struct fuse_setattr_in in_payload;
- auto iov_in = FuseGenerateIovecs(in_header, in_payload);
-
- GetServerActualRequest(iov_in);
- EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload));
- EXPECT_EQ(in_header.opcode, FUSE_SETATTR);
- EXPECT_EQ(in_header.uid, 0);
- EXPECT_EQ(in_header.gid, 0);
- EXPECT_EQ(in_payload.valid, FATTR_UID | FATTR_GID | FATTR_FH);
- EXPECT_EQ(in_payload.fh, fh);
- EXPECT_EQ(in_payload.uid, 1025);
- EXPECT_EQ(in_payload.gid, 1025);
-}
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/fuse/linux/stat_test.cc b/test/fuse/linux/stat_test.cc
deleted file mode 100644
index 73321592b..000000000
--- a/test/fuse/linux/stat_test.cc
+++ /dev/null
@@ -1,229 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// 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 specific language governing permissions and
-// limitations under the License.
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/fuse.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-
-#include <vector>
-
-#include "gtest/gtest.h"
-#include "test/fuse/linux/fuse_fd_util.h"
-#include "test/util/cleanup.h"
-#include "test/util/fs_util.h"
-#include "test/util/fuse_util.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-class StatTest : public FuseFdTest {
- public:
- void SetUp() override {
- FuseFdTest::SetUp();
- test_file_path_ = JoinPath(mount_point_.path(), test_file_);
- }
-
- protected:
- bool StatsAreEqual(struct stat expected, struct stat actual) {
- // Device number will be dynamically allocated by kernel, we cannot know in
- // advance.
- actual.st_dev = expected.st_dev;
- return memcmp(&expected, &actual, sizeof(struct stat)) == 0;
- }
-
- const std::string test_file_ = "testfile";
- const mode_t expected_mode = S_IFREG | S_IRUSR | S_IWUSR;
- const uint64_t fh = 23;
-
- std::string test_file_path_;
-};
-
-TEST_F(StatTest, StatNormal) {
- // Set up fixture.
- struct fuse_attr attr = DefaultFuseAttr(expected_mode, 1);
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out),
- };
- struct fuse_attr_out out_payload = {
- .attr = attr,
- };
- auto iov_out = FuseGenerateIovecs(out_header, out_payload);
- SetServerResponse(FUSE_GETATTR, iov_out);
-
- // Make syscall.
- struct stat stat_buf;
- EXPECT_THAT(stat(mount_point_.path().c_str(), &stat_buf), SyscallSucceeds());
-
- // Check filesystem operation result.
- struct stat expected_stat = {
- .st_ino = attr.ino,
-#ifdef __aarch64__
- .st_mode = expected_mode,
- .st_nlink = attr.nlink,
-#else
- .st_nlink = attr.nlink,
- .st_mode = expected_mode,
-#endif
- .st_uid = attr.uid,
- .st_gid = attr.gid,
- .st_rdev = attr.rdev,
- .st_size = static_cast<off_t>(attr.size),
- .st_blksize = attr.blksize,
- .st_blocks = static_cast<blkcnt_t>(attr.blocks),
- .st_atim = (struct timespec){.tv_sec = static_cast<int>(attr.atime),
- .tv_nsec = attr.atimensec},
- .st_mtim = (struct timespec){.tv_sec = static_cast<int>(attr.mtime),
- .tv_nsec = attr.mtimensec},
- .st_ctim = (struct timespec){.tv_sec = static_cast<int>(attr.ctime),
- .tv_nsec = attr.ctimensec},
- };
- EXPECT_TRUE(StatsAreEqual(stat_buf, expected_stat));
-
- // Check FUSE request.
- struct fuse_in_header in_header;
- struct fuse_getattr_in in_payload;
- auto iov_in = FuseGenerateIovecs(in_header, in_payload);
-
- GetServerActualRequest(iov_in);
- EXPECT_EQ(in_header.opcode, FUSE_GETATTR);
- EXPECT_EQ(in_payload.getattr_flags, 0);
- EXPECT_EQ(in_payload.fh, 0);
-}
-
-TEST_F(StatTest, StatNotFound) {
- // Set up fixture.
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header),
- .error = -ENOENT,
- };
- auto iov_out = FuseGenerateIovecs(out_header);
- SetServerResponse(FUSE_GETATTR, iov_out);
-
- // Make syscall.
- struct stat stat_buf;
- EXPECT_THAT(stat(mount_point_.path().c_str(), &stat_buf),
- SyscallFailsWithErrno(ENOENT));
-
- // Check FUSE request.
- struct fuse_in_header in_header;
- struct fuse_getattr_in in_payload;
- auto iov_in = FuseGenerateIovecs(in_header, in_payload);
-
- GetServerActualRequest(iov_in);
- EXPECT_EQ(in_header.opcode, FUSE_GETATTR);
- EXPECT_EQ(in_payload.getattr_flags, 0);
- EXPECT_EQ(in_payload.fh, 0);
-}
-
-TEST_F(StatTest, FstatNormal) {
- // Set up fixture.
- SetServerInodeLookup(test_file_);
- auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenPath(test_file_path_, O_RDONLY, fh));
- auto close_fd = CloseFD(fd);
-
- struct fuse_attr attr = DefaultFuseAttr(expected_mode, 2);
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out),
- };
- struct fuse_attr_out out_payload = {
- .attr = attr,
- };
- auto iov_out = FuseGenerateIovecs(out_header, out_payload);
- SetServerResponse(FUSE_GETATTR, iov_out);
-
- // Make syscall.
- struct stat stat_buf;
- EXPECT_THAT(fstat(fd.get(), &stat_buf), SyscallSucceeds());
-
- // Check filesystem operation result.
- struct stat expected_stat = {
- .st_ino = attr.ino,
-#ifdef __aarch64__
- .st_mode = expected_mode,
- .st_nlink = attr.nlink,
-#else
- .st_nlink = attr.nlink,
- .st_mode = expected_mode,
-#endif
- .st_uid = attr.uid,
- .st_gid = attr.gid,
- .st_rdev = attr.rdev,
- .st_size = static_cast<off_t>(attr.size),
- .st_blksize = attr.blksize,
- .st_blocks = static_cast<blkcnt_t>(attr.blocks),
- .st_atim = (struct timespec){.tv_sec = static_cast<int>(attr.atime),
- .tv_nsec = attr.atimensec},
- .st_mtim = (struct timespec){.tv_sec = static_cast<int>(attr.mtime),
- .tv_nsec = attr.mtimensec},
- .st_ctim = (struct timespec){.tv_sec = static_cast<int>(attr.ctime),
- .tv_nsec = attr.ctimensec},
- };
- EXPECT_TRUE(StatsAreEqual(stat_buf, expected_stat));
-
- // Check FUSE request.
- struct fuse_in_header in_header;
- struct fuse_getattr_in in_payload;
- auto iov_in = FuseGenerateIovecs(in_header, in_payload);
-
- GetServerActualRequest(iov_in);
- EXPECT_EQ(in_header.opcode, FUSE_GETATTR);
- EXPECT_EQ(in_payload.getattr_flags, 0);
- EXPECT_EQ(in_payload.fh, 0);
-}
-
-TEST_F(StatTest, StatByFileHandle) {
- // Set up fixture.
- SetServerInodeLookup(test_file_, expected_mode, 0);
- auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenPath(test_file_path_, O_RDONLY, fh));
- auto close_fd = CloseFD(fd);
-
- struct fuse_attr attr = DefaultFuseAttr(expected_mode, 2, 0);
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out),
- };
- struct fuse_attr_out out_payload = {
- .attr = attr,
- };
- auto iov_out = FuseGenerateIovecs(out_header, out_payload);
- SetServerResponse(FUSE_GETATTR, iov_out);
-
- // Make syscall.
- std::vector<char> buf(1);
- // Since this is an empty file, it won't issue FUSE_READ. But a FUSE_GETATTR
- // will be issued before read completes.
- EXPECT_THAT(read(fd.get(), buf.data(), buf.size()), SyscallSucceeds());
-
- // Check FUSE request.
- struct fuse_in_header in_header;
- struct fuse_getattr_in in_payload;
- auto iov_in = FuseGenerateIovecs(in_header, in_payload);
-
- GetServerActualRequest(iov_in);
- EXPECT_EQ(in_header.opcode, FUSE_GETATTR);
- EXPECT_EQ(in_payload.getattr_flags, FUSE_GETATTR_FH);
- EXPECT_EQ(in_payload.fh, fh);
-}
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/fuse/linux/symlink_test.cc b/test/fuse/linux/symlink_test.cc
deleted file mode 100644
index 2c3a52987..000000000
--- a/test/fuse/linux/symlink_test.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// 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 specific language governing permissions and
-// limitations under the License.
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/fuse.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-#include <vector>
-
-#include "gtest/gtest.h"
-#include "test/fuse/linux/fuse_base.h"
-#include "test/util/fuse_util.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-class SymlinkTest : public FuseTest {
- protected:
- const std::string target_file_ = "target_file_";
- const std::string symlink_ = "symlink_";
- const mode_t perms_ = S_IRWXU | S_IRWXG | S_IRWXO;
-};
-
-TEST_F(SymlinkTest, CreateSymLink) {
- const std::string symlink_path =
- JoinPath(mount_point_.path().c_str(), symlink_);
-
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_entry_out),
- };
- struct fuse_entry_out out_payload = DefaultEntryOut(S_IFLNK | perms_, 5);
- auto iov_out = FuseGenerateIovecs(out_header, out_payload);
- SetServerResponse(FUSE_SYMLINK, iov_out);
- ASSERT_THAT(symlink(target_file_.c_str(), symlink_path.c_str()),
- SyscallSucceeds());
-
- struct fuse_in_header in_header;
- std::vector<char> actual_target_file(target_file_.length() + 1);
- std::vector<char> actual_symlink(symlink_.length() + 1);
- auto iov_in =
- FuseGenerateIovecs(in_header, actual_symlink, actual_target_file);
- GetServerActualRequest(iov_in);
-
- EXPECT_EQ(in_header.len,
- sizeof(in_header) + symlink_.length() + target_file_.length() + 2);
- EXPECT_EQ(in_header.opcode, FUSE_SYMLINK);
- EXPECT_EQ(std::string(actual_target_file.data()), target_file_);
- EXPECT_EQ(std::string(actual_symlink.data()), symlink_);
-}
-
-TEST_F(SymlinkTest, FileTypeError) {
- const std::string symlink_path =
- JoinPath(mount_point_.path().c_str(), symlink_);
-
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_entry_out),
- };
- struct fuse_entry_out out_payload = DefaultEntryOut(S_IFREG | perms_, 5);
- auto iov_out = FuseGenerateIovecs(out_header, out_payload);
- SetServerResponse(FUSE_SYMLINK, iov_out);
- ASSERT_THAT(symlink(target_file_.c_str(), symlink_path.c_str()),
- SyscallFailsWithErrno(EIO));
- SkipServerActualRequest();
-}
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/fuse/linux/unlink_test.cc b/test/fuse/linux/unlink_test.cc
deleted file mode 100644
index 13efbf7c7..000000000
--- a/test/fuse/linux/unlink_test.cc
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// 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 specific language governing permissions and
-// limitations under the License.
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/fuse.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-#include <vector>
-
-#include "gtest/gtest.h"
-#include "test/fuse/linux/fuse_base.h"
-#include "test/util/fuse_util.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-class UnlinkTest : public FuseTest {
- protected:
- const std::string test_file_ = "test_file";
- const std::string test_subdir_ = "test_subdir";
-};
-
-TEST_F(UnlinkTest, RegularFile) {
- const std::string test_file_path =
- JoinPath(mount_point_.path().c_str(), test_file_);
- SetServerInodeLookup(test_file_, S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO);
-
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header),
- };
- auto iov_out = FuseGenerateIovecs(out_header);
- SetServerResponse(FUSE_UNLINK, iov_out);
-
- ASSERT_THAT(unlink(test_file_path.c_str()), SyscallSucceeds());
- struct fuse_in_header in_header;
- std::vector<char> unlinked_file(test_file_.length() + 1);
- auto iov_in = FuseGenerateIovecs(in_header, unlinked_file);
- GetServerActualRequest(iov_in);
-
- EXPECT_EQ(in_header.len, sizeof(in_header) + test_file_.length() + 1);
- EXPECT_EQ(in_header.opcode, FUSE_UNLINK);
- EXPECT_EQ(std::string(unlinked_file.data()), test_file_);
-}
-
-TEST_F(UnlinkTest, RegularFileSubDir) {
- SetServerInodeLookup(test_subdir_, S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
- const std::string test_file_path =
- JoinPath(mount_point_.path().c_str(), test_subdir_, test_file_);
- SetServerInodeLookup(test_file_, S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO);
-
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header),
- };
- auto iov_out = FuseGenerateIovecs(out_header);
- SetServerResponse(FUSE_UNLINK, iov_out);
-
- ASSERT_THAT(unlink(test_file_path.c_str()), SyscallSucceeds());
- struct fuse_in_header in_header;
- std::vector<char> unlinked_file(test_file_.length() + 1);
- auto iov_in = FuseGenerateIovecs(in_header, unlinked_file);
- GetServerActualRequest(iov_in);
-
- EXPECT_EQ(in_header.len, sizeof(in_header) + test_file_.length() + 1);
- EXPECT_EQ(in_header.opcode, FUSE_UNLINK);
- EXPECT_EQ(std::string(unlinked_file.data()), test_file_);
-}
-
-TEST_F(UnlinkTest, NoFile) {
- const std::string test_file_path =
- JoinPath(mount_point_.path().c_str(), test_file_);
- SetServerInodeLookup(test_file_, S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO);
-
- struct fuse_out_header out_header = {
- .len = sizeof(struct fuse_out_header),
- .error = -ENOENT,
- };
- auto iov_out = FuseGenerateIovecs(out_header);
- SetServerResponse(FUSE_UNLINK, iov_out);
-
- ASSERT_THAT(unlink(test_file_path.c_str()), SyscallFailsWithErrno(ENOENT));
- SkipServerActualRequest();
-}
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/fuse/linux/write_test.cc b/test/fuse/linux/write_test.cc
deleted file mode 100644
index 1a62beb96..000000000
--- a/test/fuse/linux/write_test.cc
+++ /dev/null
@@ -1,303 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// 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 specific language governing permissions and
-// limitations under the License.
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/fuse.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-#include <vector>
-
-#include "gtest/gtest.h"
-#include "test/fuse/linux/fuse_base.h"
-#include "test/util/fuse_util.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-class WriteTest : public FuseTest {
- void SetUp() override {
- FuseTest::SetUp();
- test_file_path_ = JoinPath(mount_point_.path().c_str(), test_file_);
- }
-
- // TearDown overrides the parent's function
- // to skip checking the unconsumed release request at the end.
- void TearDown() override { UnmountFuse(); }
-
- protected:
- const std::string test_file_ = "test_file";
- const mode_t test_file_mode_ = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO;
- const uint64_t test_fh_ = 1;
- const uint32_t open_flag_ = O_RDWR;
-
- std::string test_file_path_;
-
- PosixErrorOr<FileDescriptor> OpenTestFile(const std::string &path,
- uint64_t size = 512) {
- SetServerInodeLookup(test_file_, test_file_mode_, size);
-
- struct fuse_out_header out_header_open = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_open_out),
- };
- struct fuse_open_out out_payload_open = {
- .fh = test_fh_,
- .open_flags = open_flag_,
- };
- auto iov_out_open = FuseGenerateIovecs(out_header_open, out_payload_open);
- SetServerResponse(FUSE_OPEN, iov_out_open);
-
- auto res = Open(path.c_str(), open_flag_);
- if (res.ok()) {
- SkipServerActualRequest();
- }
- return res;
- }
-};
-
-class WriteTestSmallMaxWrite : public WriteTest {
- void SetUp() override {
- MountFuse();
- SetUpFuseServer(&fuse_init_payload);
- test_file_path_ = JoinPath(mount_point_.path().c_str(), test_file_);
- }
-
- protected:
- const static uint32_t max_write_ = 4096;
- constexpr static struct fuse_init_out fuse_init_payload = {
- .major = 7,
- .max_write = max_write_,
- };
-
- const uint32_t size_fragment = max_write_;
-};
-
-TEST_F(WriteTest, WriteNormal) {
- auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_));
-
- // Prepare for the write.
- const int n_write = 10;
- struct fuse_out_header out_header_write = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_write_out),
- };
- struct fuse_write_out out_payload_write = {
- .size = n_write,
- };
- auto iov_out_write = FuseGenerateIovecs(out_header_write, out_payload_write);
- SetServerResponse(FUSE_WRITE, iov_out_write);
-
- // Issue the write.
- std::vector<char> buf(n_write);
- RandomizeBuffer(buf.data(), buf.size());
- EXPECT_THAT(write(fd.get(), buf.data(), n_write),
- SyscallSucceedsWithValue(n_write));
-
- // Check the write request.
- struct fuse_in_header in_header_write;
- struct fuse_write_in in_payload_write;
- std::vector<char> payload_buf(n_write);
- auto iov_in_write =
- FuseGenerateIovecs(in_header_write, in_payload_write, payload_buf);
- GetServerActualRequest(iov_in_write);
-
- EXPECT_EQ(in_payload_write.fh, test_fh_);
- EXPECT_EQ(in_header_write.len,
- sizeof(in_header_write) + sizeof(in_payload_write));
- EXPECT_EQ(in_header_write.opcode, FUSE_WRITE);
- EXPECT_EQ(in_payload_write.offset, 0);
- EXPECT_EQ(in_payload_write.size, n_write);
- EXPECT_EQ(buf, payload_buf);
-}
-
-TEST_F(WriteTest, WriteShort) {
- auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_));
-
- // Prepare for the write.
- const int n_write = 10, n_written = 5;
- struct fuse_out_header out_header_write = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_write_out),
- };
- struct fuse_write_out out_payload_write = {
- .size = n_written,
- };
- auto iov_out_write = FuseGenerateIovecs(out_header_write, out_payload_write);
- SetServerResponse(FUSE_WRITE, iov_out_write);
-
- // Issue the write.
- std::vector<char> buf(n_write);
- RandomizeBuffer(buf.data(), buf.size());
- EXPECT_THAT(write(fd.get(), buf.data(), n_write),
- SyscallSucceedsWithValue(n_written));
-
- // Check the write request.
- struct fuse_in_header in_header_write;
- struct fuse_write_in in_payload_write;
- std::vector<char> payload_buf(n_write);
- auto iov_in_write =
- FuseGenerateIovecs(in_header_write, in_payload_write, payload_buf);
- GetServerActualRequest(iov_in_write);
-
- EXPECT_EQ(in_payload_write.fh, test_fh_);
- EXPECT_EQ(in_header_write.len,
- sizeof(in_header_write) + sizeof(in_payload_write));
- EXPECT_EQ(in_header_write.opcode, FUSE_WRITE);
- EXPECT_EQ(in_payload_write.offset, 0);
- EXPECT_EQ(in_payload_write.size, n_write);
- EXPECT_EQ(buf, payload_buf);
-}
-
-TEST_F(WriteTest, WriteShortZero) {
- auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_));
-
- // Prepare for the write.
- const int n_write = 10;
- struct fuse_out_header out_header_write = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_write_out),
- };
- struct fuse_write_out out_payload_write = {
- .size = 0,
- };
- auto iov_out_write = FuseGenerateIovecs(out_header_write, out_payload_write);
- SetServerResponse(FUSE_WRITE, iov_out_write);
-
- // Issue the write.
- std::vector<char> buf(n_write);
- RandomizeBuffer(buf.data(), buf.size());
- EXPECT_THAT(write(fd.get(), buf.data(), n_write), SyscallFailsWithErrno(EIO));
-
- // Check the write request.
- struct fuse_in_header in_header_write;
- struct fuse_write_in in_payload_write;
- std::vector<char> payload_buf(n_write);
- auto iov_in_write =
- FuseGenerateIovecs(in_header_write, in_payload_write, payload_buf);
- GetServerActualRequest(iov_in_write);
-
- EXPECT_EQ(in_payload_write.fh, test_fh_);
- EXPECT_EQ(in_header_write.len,
- sizeof(in_header_write) + sizeof(in_payload_write));
- EXPECT_EQ(in_header_write.opcode, FUSE_WRITE);
- EXPECT_EQ(in_payload_write.offset, 0);
- EXPECT_EQ(in_payload_write.size, n_write);
- EXPECT_EQ(buf, payload_buf);
-}
-
-TEST_F(WriteTest, WriteZero) {
- auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_));
-
- // Issue the write.
- std::vector<char> buf(0);
- EXPECT_THAT(write(fd.get(), buf.data(), 0), SyscallSucceedsWithValue(0));
-}
-
-TEST_F(WriteTest, PWrite) {
- const int file_size = 512;
- auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_, file_size));
-
- // Prepare for the write.
- const int n_write = 10;
- struct fuse_out_header out_header_write = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_write_out),
- };
- struct fuse_write_out out_payload_write = {
- .size = n_write,
- };
- auto iov_out_write = FuseGenerateIovecs(out_header_write, out_payload_write);
- SetServerResponse(FUSE_WRITE, iov_out_write);
-
- // Issue the write.
- std::vector<char> buf(n_write);
- RandomizeBuffer(buf.data(), buf.size());
- const int offset_write = file_size >> 1;
- EXPECT_THAT(pwrite(fd.get(), buf.data(), n_write, offset_write),
- SyscallSucceedsWithValue(n_write));
-
- // Check the write request.
- struct fuse_in_header in_header_write;
- struct fuse_write_in in_payload_write;
- std::vector<char> payload_buf(n_write);
- auto iov_in_write =
- FuseGenerateIovecs(in_header_write, in_payload_write, payload_buf);
- GetServerActualRequest(iov_in_write);
-
- EXPECT_EQ(in_payload_write.fh, test_fh_);
- EXPECT_EQ(in_header_write.len,
- sizeof(in_header_write) + sizeof(in_payload_write));
- EXPECT_EQ(in_header_write.opcode, FUSE_WRITE);
- EXPECT_EQ(in_payload_write.offset, offset_write);
- EXPECT_EQ(in_payload_write.size, n_write);
- EXPECT_EQ(buf, payload_buf);
-}
-
-TEST_F(WriteTestSmallMaxWrite, WriteSmallMaxWrie) {
- const int n_fragment = 10;
- const int n_write = size_fragment * n_fragment;
-
- auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenTestFile(test_file_path_, n_write));
-
- // Prepare for the write.
- struct fuse_out_header out_header_write = {
- .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_write_out),
- };
- struct fuse_write_out out_payload_write = {
- .size = size_fragment,
- };
- auto iov_out_write = FuseGenerateIovecs(out_header_write, out_payload_write);
-
- for (int i = 0; i < n_fragment; ++i) {
- SetServerResponse(FUSE_WRITE, iov_out_write);
- }
-
- // Issue the write.
- std::vector<char> buf(n_write);
- RandomizeBuffer(buf.data(), buf.size());
- EXPECT_THAT(write(fd.get(), buf.data(), n_write),
- SyscallSucceedsWithValue(n_write));
-
- ASSERT_EQ(GetServerNumUnsentResponses(), 0);
- ASSERT_EQ(GetServerNumUnconsumedRequests(), n_fragment);
-
- // Check the write request.
- struct fuse_in_header in_header_write;
- struct fuse_write_in in_payload_write;
- std::vector<char> payload_buf(size_fragment);
- auto iov_in_write =
- FuseGenerateIovecs(in_header_write, in_payload_write, payload_buf);
-
- for (int i = 0; i < n_fragment; ++i) {
- GetServerActualRequest(iov_in_write);
-
- EXPECT_EQ(in_payload_write.fh, test_fh_);
- EXPECT_EQ(in_header_write.len,
- sizeof(in_header_write) + sizeof(in_payload_write));
- EXPECT_EQ(in_header_write.opcode, FUSE_WRITE);
- EXPECT_EQ(in_payload_write.offset, i * size_fragment);
- EXPECT_EQ(in_payload_write.size, size_fragment);
-
- auto it = buf.begin() + i * size_fragment;
- EXPECT_EQ(std::vector<char>(it, it + size_fragment), payload_buf);
- }
-}
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor