mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Implement FUSE_RMDIR
Fixes #3587 Co-authored-by: Craig Chi <craigchi@google.com>
This commit is contained in:
committed by
Andrei Vagin
co-authored by
Craig Chi
parent
713400d6b0
commit
bc07df8887
@@ -569,3 +569,29 @@ func (r *FUSEMkdirIn) MarshalUnsafe(buf []byte) {
|
||||
func (r *FUSEMkdirIn) SizeBytes() int {
|
||||
return r.MkdirMeta.SizeBytes() + len(r.Name) + 1
|
||||
}
|
||||
|
||||
// FUSERmDirIn is the request sent by the kernel to the daemon
|
||||
// when trying to remove a directory.
|
||||
//
|
||||
// Dynamically-sized objects cannot be marshalled.
|
||||
type FUSERmDirIn struct {
|
||||
marshal.StubMarshallable
|
||||
|
||||
// Name is a directory name to be looked up.
|
||||
Name string
|
||||
}
|
||||
|
||||
// MarshalUnsafe serializes r.name to the dst buffer.
|
||||
func (r *FUSERmDirIn) MarshalUnsafe(buf []byte) {
|
||||
copy(buf, r.Name)
|
||||
}
|
||||
|
||||
// SizeBytes is the size of the memory representation of FUSERmDirIn.
|
||||
func (r *FUSERmDirIn) SizeBytes() int {
|
||||
return len(r.Name) + 1
|
||||
}
|
||||
|
||||
// UnmarshalUnsafe deserializes r.name from the src buffer.
|
||||
func (r *FUSERmDirIn) UnmarshalUnsafe(src []byte) {
|
||||
r.Name = string(src)
|
||||
}
|
||||
|
||||
@@ -426,6 +426,33 @@ func (i *inode) NewDir(ctx context.Context, name string, opts vfs.MkdirOptions)
|
||||
return i.newEntry(ctx, name, linux.S_IFDIR, linux.FUSE_MKDIR, &in)
|
||||
}
|
||||
|
||||
// RmDir implements kernfs.Inode.RmDir.
|
||||
func (i *inode) RmDir(ctx context.Context, name string, child *vfs.Dentry) error {
|
||||
fusefs := i.fs
|
||||
task, creds := kernel.TaskFromContext(ctx), auth.CredentialsFromContext(ctx)
|
||||
|
||||
in := linux.FUSERmDirIn{Name: name}
|
||||
req, err := fusefs.conn.NewRequest(creds, uint32(task.ThreadID()), i.NodeID, linux.FUSE_RMDIR, &in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := i.fs.conn.Call(task, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := res.Error(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO(Before merging): When creating new nodes, should we add nodes to the ordered children?
|
||||
// If so we'll probably need to call this. We will also need to add them with the writable flag when
|
||||
// appropriate.
|
||||
// return i.OrderedChildren.RmDir(ctx, name, child)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// newEntry calls FUSE server for entry creation and allocates corresponding entry according to response.
|
||||
// Shared by FUSE_MKNOD, FUSE_MKDIR, FUSE_SYMLINK, FUSE_LINK and FUSE_LOOKUP.
|
||||
func (i *inode) newEntry(ctx context.Context, name string, fileType linux.FileMode, opcode linux.FUSEOpcode, payload marshal.Marshallable) (*vfs.Dentry, error) {
|
||||
|
||||
@@ -657,6 +657,10 @@ func (fs *Filesystem) RenameAt(ctx context.Context, rp *vfs.ResolvingPath, oldPa
|
||||
func (fs *Filesystem) RmdirAt(ctx context.Context, rp *vfs.ResolvingPath) error {
|
||||
fs.mu.Lock()
|
||||
defer fs.mu.Unlock()
|
||||
|
||||
// Store the name before walkExistingLocked as rp will be advanced past the
|
||||
// name in the following call.
|
||||
name := rp.Component()
|
||||
vfsd, inode, err := fs.walkExistingLocked(ctx, rp)
|
||||
fs.processDeferredDecRefsLocked(ctx)
|
||||
if err != nil {
|
||||
@@ -686,7 +690,8 @@ func (fs *Filesystem) RmdirAt(ctx context.Context, rp *vfs.ResolvingPath) error
|
||||
if err := virtfs.PrepareDeleteDentry(mntns, vfsd); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := parentDentry.inode.RmDir(ctx, rp.Component(), vfsd); err != nil {
|
||||
|
||||
if err := parentDentry.inode.RmDir(ctx, name, vfsd); err != nil {
|
||||
virtfs.AbortDeleteDentry(vfsd)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -41,3 +41,9 @@ syscall_test(
|
||||
fuse = "True",
|
||||
test = "//test/fuse/linux:read_test",
|
||||
)
|
||||
|
||||
syscall_test(
|
||||
test = "//test/fuse/linux:rmdir_test",
|
||||
vfs2 = "True",
|
||||
fuse = "True",
|
||||
)
|
||||
|
||||
@@ -98,6 +98,20 @@ cc_binary(
|
||||
],
|
||||
)
|
||||
|
||||
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_library(
|
||||
name = "fuse_base",
|
||||
testonly = 1,
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
// 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 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_);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace testing
|
||||
} // namespace gvisor
|
||||
Reference in New Issue
Block a user