diff options
author | Ridwan Sharif <ridwanmsharif@google.com> | 2020-08-11 12:13:01 -0400 |
---|---|---|
committer | Andrei Vagin <avagin@gmail.com> | 2020-09-11 13:35:25 -0700 |
commit | a94377620401aee2b3e37d16f90054f7ddc756da (patch) | |
tree | 7655d7965f54facdd3ca08f760090d335651a10c /pkg | |
parent | 74e229c56ceb488a61a1b42d8f7da2d58c3c5418 (diff) |
Implement FUSE_RMDIR
Fixes #3587
Co-authored-by: Craig Chi <craigchi@google.com>
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/abi/linux/fuse.go | 26 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/fuse/fusefs.go | 27 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/kernfs/filesystem.go | 7 |
3 files changed, 59 insertions, 1 deletions
diff --git a/pkg/abi/linux/fuse.go b/pkg/abi/linux/fuse.go index 0ece7b756..c75debb8c 100644 --- a/pkg/abi/linux/fuse.go +++ b/pkg/abi/linux/fuse.go @@ -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) +} diff --git a/pkg/sentry/fsimpl/fuse/fusefs.go b/pkg/sentry/fsimpl/fuse/fusefs.go index 65e22ba4d..c55ea927a 100644 --- a/pkg/sentry/fsimpl/fuse/fusefs.go +++ b/pkg/sentry/fsimpl/fuse/fusefs.go @@ -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) { diff --git a/pkg/sentry/fsimpl/kernfs/filesystem.go b/pkg/sentry/fsimpl/kernfs/filesystem.go index 7aaf1146d..2823c3b1a 100644 --- a/pkg/sentry/fsimpl/kernfs/filesystem.go +++ b/pkg/sentry/fsimpl/kernfs/filesystem.go @@ -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 } |