mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Add VFS2 plumbing for extended attributes.
PiperOrigin-RevId: 286281274
This commit is contained in:
@@ -443,6 +443,42 @@ func (fs *filesystem) UnlinkAt(ctx context.Context, rp *vfs.ResolvingPath) error
|
||||
return syserror.EROFS
|
||||
}
|
||||
|
||||
// ListxattrAt implements vfs.FilesystemImpl.ListxattrAt.
|
||||
func (fs *filesystem) ListxattrAt(ctx context.Context, rp *vfs.ResolvingPath) ([]string, error) {
|
||||
_, _, err := fs.walk(rp, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, syserror.ENOTSUP
|
||||
}
|
||||
|
||||
// GetxattrAt implements vfs.FilesystemImpl.GetxattrAt.
|
||||
func (fs *filesystem) GetxattrAt(ctx context.Context, rp *vfs.ResolvingPath, name string) (string, error) {
|
||||
_, _, err := fs.walk(rp, false)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "", syserror.ENOTSUP
|
||||
}
|
||||
|
||||
// SetxattrAt implements vfs.FilesystemImpl.SetxattrAt.
|
||||
func (fs *filesystem) SetxattrAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.SetxattrOptions) error {
|
||||
_, _, err := fs.walk(rp, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return syserror.ENOTSUP
|
||||
}
|
||||
|
||||
// RemovexattrAt implements vfs.FilesystemImpl.RemovexattrAt.
|
||||
func (fs *filesystem) RemovexattrAt(ctx context.Context, rp *vfs.ResolvingPath, name string) error {
|
||||
_, _, err := fs.walk(rp, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return syserror.ENOTSUP
|
||||
}
|
||||
|
||||
// PrependPath implements vfs.FilesystemImpl.PrependPath.
|
||||
func (fs *filesystem) PrependPath(ctx context.Context, vfsroot, vd vfs.VirtualDentry, b *fspath.Builder) error {
|
||||
fs.mu.RLock()
|
||||
|
||||
@@ -683,6 +683,58 @@ func (fs *Filesystem) UnlinkAt(ctx context.Context, rp *vfs.ResolvingPath) error
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListxattrAt implements vfs.FilesystemImpl.ListxattrAt.
|
||||
func (fs *Filesystem) ListxattrAt(ctx context.Context, rp *vfs.ResolvingPath) ([]string, error) {
|
||||
fs.mu.RLock()
|
||||
_, _, err := fs.walkExistingLocked(ctx, rp)
|
||||
fs.mu.RUnlock()
|
||||
fs.processDeferredDecRefs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// kernfs currently does not support extended attributes.
|
||||
return nil, syserror.ENOTSUP
|
||||
}
|
||||
|
||||
// GetxattrAt implements vfs.FilesystemImpl.GetxattrAt.
|
||||
func (fs *Filesystem) GetxattrAt(ctx context.Context, rp *vfs.ResolvingPath, name string) (string, error) {
|
||||
fs.mu.RLock()
|
||||
_, _, err := fs.walkExistingLocked(ctx, rp)
|
||||
fs.mu.RUnlock()
|
||||
fs.processDeferredDecRefs()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// kernfs currently does not support extended attributes.
|
||||
return "", syserror.ENOTSUP
|
||||
}
|
||||
|
||||
// SetxattrAt implements vfs.FilesystemImpl.SetxattrAt.
|
||||
func (fs *Filesystem) SetxattrAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.SetxattrOptions) error {
|
||||
fs.mu.RLock()
|
||||
_, _, err := fs.walkExistingLocked(ctx, rp)
|
||||
fs.mu.RUnlock()
|
||||
fs.processDeferredDecRefs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// kernfs currently does not support extended attributes.
|
||||
return syserror.ENOTSUP
|
||||
}
|
||||
|
||||
// RemovexattrAt implements vfs.FilesystemImpl.RemovexattrAt.
|
||||
func (fs *Filesystem) RemovexattrAt(ctx context.Context, rp *vfs.ResolvingPath, name string) error {
|
||||
fs.mu.RLock()
|
||||
_, _, err := fs.walkExistingLocked(ctx, rp)
|
||||
fs.mu.RUnlock()
|
||||
fs.processDeferredDecRefs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// kernfs currently does not support extended attributes.
|
||||
return syserror.ENOTSUP
|
||||
}
|
||||
|
||||
// PrependPath implements vfs.FilesystemImpl.PrependPath.
|
||||
func (fs *Filesystem) PrependPath(ctx context.Context, vfsroot, vd vfs.VirtualDentry, b *fspath.Builder) error {
|
||||
fs.mu.RLock()
|
||||
|
||||
@@ -584,6 +584,54 @@ func (fs *filesystem) UnlinkAt(ctx context.Context, rp *vfs.ResolvingPath) error
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListxattrAt implements vfs.FilesystemImpl.ListxattrAt.
|
||||
func (fs *filesystem) ListxattrAt(ctx context.Context, rp *vfs.ResolvingPath) ([]string, error) {
|
||||
fs.mu.RLock()
|
||||
defer fs.mu.RUnlock()
|
||||
_, _, err := walkExistingLocked(rp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// TODO(b/127675828): support extended attributes
|
||||
return nil, syserror.ENOTSUP
|
||||
}
|
||||
|
||||
// GetxattrAt implements vfs.FilesystemImpl.GetxattrAt.
|
||||
func (fs *filesystem) GetxattrAt(ctx context.Context, rp *vfs.ResolvingPath, name string) (string, error) {
|
||||
fs.mu.RLock()
|
||||
defer fs.mu.RUnlock()
|
||||
_, _, err := walkExistingLocked(rp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// TODO(b/127675828): support extended attributes
|
||||
return "", syserror.ENOTSUP
|
||||
}
|
||||
|
||||
// SetxattrAt implements vfs.FilesystemImpl.SetxattrAt.
|
||||
func (fs *filesystem) SetxattrAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.SetxattrOptions) error {
|
||||
fs.mu.RLock()
|
||||
defer fs.mu.RUnlock()
|
||||
_, _, err := walkExistingLocked(rp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO(b/127675828): support extended attributes
|
||||
return syserror.ENOTSUP
|
||||
}
|
||||
|
||||
// RemovexattrAt implements vfs.FilesystemImpl.RemovexattrAt.
|
||||
func (fs *filesystem) RemovexattrAt(ctx context.Context, rp *vfs.ResolvingPath, name string) error {
|
||||
fs.mu.RLock()
|
||||
defer fs.mu.RUnlock()
|
||||
_, _, err := walkExistingLocked(rp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO(b/127675828): support extended attributes
|
||||
return syserror.ENOTSUP
|
||||
}
|
||||
|
||||
// PrependPath implements vfs.FilesystemImpl.PrependPath.
|
||||
func (fs *filesystem) PrependPath(ctx context.Context, vfsroot, vd vfs.VirtualDentry, b *fspath.Builder) error {
|
||||
fs.mu.RLock()
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/sentry/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/memmap"
|
||||
"gvisor.dev/gvisor/pkg/sentry/usermem"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
)
|
||||
|
||||
@@ -212,7 +213,21 @@ type FileDescriptionImpl interface {
|
||||
// Ioctl implements the ioctl(2) syscall.
|
||||
Ioctl(ctx context.Context, uio usermem.IO, args arch.SyscallArguments) (uintptr, error)
|
||||
|
||||
// TODO: extended attributes; file locking
|
||||
// Listxattr returns all extended attribute names for the file.
|
||||
Listxattr(ctx context.Context) ([]string, error)
|
||||
|
||||
// Getxattr returns the value associated with the given extended attribute
|
||||
// for the file.
|
||||
Getxattr(ctx context.Context, name string) (string, error)
|
||||
|
||||
// Setxattr changes the value associated with the given extended attribute
|
||||
// for the file.
|
||||
Setxattr(ctx context.Context, opts SetxattrOptions) error
|
||||
|
||||
// Removexattr removes the given extended attribute from the file.
|
||||
Removexattr(ctx context.Context, name string) error
|
||||
|
||||
// TODO: file locking
|
||||
}
|
||||
|
||||
// Dirent holds the information contained in struct linux_dirent64.
|
||||
@@ -329,6 +344,38 @@ func (fd *FileDescription) Ioctl(ctx context.Context, uio usermem.IO, args arch.
|
||||
return fd.impl.Ioctl(ctx, uio, args)
|
||||
}
|
||||
|
||||
// Listxattr returns all extended attribute names for the file represented by
|
||||
// fd.
|
||||
func (fd *FileDescription) Listxattr(ctx context.Context) ([]string, error) {
|
||||
names, err := fd.impl.Listxattr(ctx)
|
||||
if err == syserror.ENOTSUP {
|
||||
// Linux doesn't actually return ENOTSUP in this case; instead,
|
||||
// fs/xattr.c:vfs_listxattr() falls back to allowing the security
|
||||
// subsystem to return security extended attributes, which by default
|
||||
// don't exist.
|
||||
return nil, nil
|
||||
}
|
||||
return names, err
|
||||
}
|
||||
|
||||
// Getxattr returns the value associated with the given extended attribute for
|
||||
// the file represented by fd.
|
||||
func (fd *FileDescription) Getxattr(ctx context.Context, name string) (string, error) {
|
||||
return fd.impl.Getxattr(ctx, name)
|
||||
}
|
||||
|
||||
// Setxattr changes the value associated with the given extended attribute for
|
||||
// the file represented by fd.
|
||||
func (fd *FileDescription) Setxattr(ctx context.Context, opts SetxattrOptions) error {
|
||||
return fd.impl.Setxattr(ctx, opts)
|
||||
}
|
||||
|
||||
// Removexattr removes the given extended attribute from the file represented
|
||||
// by fd.
|
||||
func (fd *FileDescription) Removexattr(ctx context.Context, name string) error {
|
||||
return fd.impl.Removexattr(ctx, name)
|
||||
}
|
||||
|
||||
// SyncFS instructs the filesystem containing fd to execute the semantics of
|
||||
// syncfs(2).
|
||||
func (fd *FileDescription) SyncFS(ctx context.Context) error {
|
||||
|
||||
@@ -127,6 +127,31 @@ func (FileDescriptionDefaultImpl) Ioctl(ctx context.Context, uio usermem.IO, arg
|
||||
return 0, syserror.ENOTTY
|
||||
}
|
||||
|
||||
// Listxattr implements FileDescriptionImpl.Listxattr analogously to
|
||||
// inode_operations::listxattr == NULL in Linux.
|
||||
func (FileDescriptionDefaultImpl) Listxattr(ctx context.Context) ([]string, error) {
|
||||
// This isn't exactly accurate; see FileDescription.Listxattr.
|
||||
return nil, syserror.ENOTSUP
|
||||
}
|
||||
|
||||
// Getxattr implements FileDescriptionImpl.Getxattr analogously to
|
||||
// inode::i_opflags & IOP_XATTR == 0 in Linux.
|
||||
func (FileDescriptionDefaultImpl) Getxattr(ctx context.Context, name string) (string, error) {
|
||||
return "", syserror.ENOTSUP
|
||||
}
|
||||
|
||||
// Setxattr implements FileDescriptionImpl.Setxattr analogously to
|
||||
// inode::i_opflags & IOP_XATTR == 0 in Linux.
|
||||
func (FileDescriptionDefaultImpl) Setxattr(ctx context.Context, opts SetxattrOptions) error {
|
||||
return syserror.ENOTSUP
|
||||
}
|
||||
|
||||
// Removexattr implements FileDescriptionImpl.Removexattr analogously to
|
||||
// inode::i_opflags & IOP_XATTR == 0 in Linux.
|
||||
func (FileDescriptionDefaultImpl) Removexattr(ctx context.Context, name string) error {
|
||||
return syserror.ENOTSUP
|
||||
}
|
||||
|
||||
// DirectoryFileDescriptionDefaultImpl may be embedded by implementations of
|
||||
// FileDescriptionImpl that always represent directories to obtain
|
||||
// implementations of non-directory I/O methods that return EISDIR.
|
||||
|
||||
@@ -186,6 +186,20 @@ type FilesystemImpl interface {
|
||||
// UnlinkAt removes the non-directory file at rp.
|
||||
UnlinkAt(ctx context.Context, rp *ResolvingPath) error
|
||||
|
||||
// ListxattrAt returns all extended attribute names for the file at rp.
|
||||
ListxattrAt(ctx context.Context, rp *ResolvingPath) ([]string, error)
|
||||
|
||||
// GetxattrAt returns the value associated with the given extended
|
||||
// attribute for the file at rp.
|
||||
GetxattrAt(ctx context.Context, rp *ResolvingPath, name string) (string, error)
|
||||
|
||||
// SetxattrAt changes the value associated with the given extended
|
||||
// attribute for the file at rp.
|
||||
SetxattrAt(ctx context.Context, rp *ResolvingPath, opts SetxattrOptions) error
|
||||
|
||||
// RemovexattrAt removes the given extended attribute from the file at rp.
|
||||
RemovexattrAt(ctx context.Context, rp *ResolvingPath, name string) error
|
||||
|
||||
// PrependPath prepends a path from vd to vd.Mount().Root() to b.
|
||||
//
|
||||
// If vfsroot.Ok(), it is the contextual VFS root; if it is encountered
|
||||
@@ -208,7 +222,7 @@ type FilesystemImpl interface {
|
||||
// Preconditions: vd.Mount().Filesystem().Impl() == this FilesystemImpl.
|
||||
PrependPath(ctx context.Context, vfsroot, vd VirtualDentry, b *fspath.Builder) error
|
||||
|
||||
// TODO: extended attributes; inotify_add_watch(); bind()
|
||||
// TODO: inotify_add_watch(); bind()
|
||||
}
|
||||
|
||||
// PrependPathAtVFSRootError is returned by implementations of
|
||||
|
||||
@@ -101,6 +101,20 @@ type SetStatOptions struct {
|
||||
Stat linux.Statx
|
||||
}
|
||||
|
||||
// SetxattrOptions contains options to VirtualFilesystem.SetxattrAt(),
|
||||
// FilesystemImpl.SetxattrAt(), FileDescription.Setxattr(), and
|
||||
// FileDescriptionImpl.Setxattr().
|
||||
type SetxattrOptions struct {
|
||||
// Name is the name of the extended attribute being mutated.
|
||||
Name string
|
||||
|
||||
// Value is the extended attribute's new value.
|
||||
Value string
|
||||
|
||||
// Flags contains flags as specified for setxattr/lsetxattr/fsetxattr(2).
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
// StatOptions contains options to VirtualFilesystem.StatAt(),
|
||||
// FilesystemImpl.StatAt(), FileDescription.Stat(), and
|
||||
// FileDescriptionImpl.Stat().
|
||||
|
||||
@@ -117,6 +117,26 @@ func (fs *FDTestFilesystem) UnlinkAt(ctx context.Context, rp *ResolvingPath) err
|
||||
return syserror.EPERM
|
||||
}
|
||||
|
||||
// ListxattrAt implements FilesystemImpl.ListxattrAt.
|
||||
func (fs *FDTestFilesystem) ListxattrAt(ctx context.Context, rp *ResolvingPath) ([]string, error) {
|
||||
return nil, syserror.EPERM
|
||||
}
|
||||
|
||||
// GetxattrAt implements FilesystemImpl.GetxattrAt.
|
||||
func (fs *FDTestFilesystem) GetxattrAt(ctx context.Context, rp *ResolvingPath, name string) (string, error) {
|
||||
return "", syserror.EPERM
|
||||
}
|
||||
|
||||
// SetxattrAt implements FilesystemImpl.SetxattrAt.
|
||||
func (fs *FDTestFilesystem) SetxattrAt(ctx context.Context, rp *ResolvingPath, opts SetxattrOptions) error {
|
||||
return syserror.EPERM
|
||||
}
|
||||
|
||||
// RemovexattrAt implements FilesystemImpl.RemovexattrAt.
|
||||
func (fs *FDTestFilesystem) RemovexattrAt(ctx context.Context, rp *ResolvingPath, name string) error {
|
||||
return syserror.EPERM
|
||||
}
|
||||
|
||||
// PrependPath implements FilesystemImpl.PrependPath.
|
||||
func (fs *FDTestFilesystem) PrependPath(ctx context.Context, vfsroot, vd VirtualDentry, b *fspath.Builder) error {
|
||||
b.PrependComponent(fmt.Sprintf("vfs.fdTestDentry:%p", vd.dentry.impl.(*fdTestDentry)))
|
||||
|
||||
@@ -440,6 +440,93 @@ func (vfs *VirtualFilesystem) UnlinkAt(ctx context.Context, creds *auth.Credenti
|
||||
}
|
||||
}
|
||||
|
||||
// ListxattrAt returns all extended attribute names for the file at the given
|
||||
// path.
|
||||
func (vfs *VirtualFilesystem) ListxattrAt(ctx context.Context, creds *auth.Credentials, pop *PathOperation) ([]string, error) {
|
||||
rp, err := vfs.getResolvingPath(creds, pop)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for {
|
||||
names, err := rp.mount.fs.impl.ListxattrAt(ctx, rp)
|
||||
if err == nil {
|
||||
vfs.putResolvingPath(rp)
|
||||
return names, nil
|
||||
}
|
||||
if err == syserror.ENOTSUP {
|
||||
// Linux doesn't actually return ENOTSUP in this case; instead,
|
||||
// fs/xattr.c:vfs_listxattr() falls back to allowing the security
|
||||
// subsystem to return security extended attributes, which by
|
||||
// default don't exist.
|
||||
vfs.putResolvingPath(rp)
|
||||
return nil, nil
|
||||
}
|
||||
if !rp.handleError(err) {
|
||||
vfs.putResolvingPath(rp)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetxattrAt returns the value associated with the given extended attribute
|
||||
// for the file at the given path.
|
||||
func (vfs *VirtualFilesystem) GetxattrAt(ctx context.Context, creds *auth.Credentials, pop *PathOperation, name string) (string, error) {
|
||||
rp, err := vfs.getResolvingPath(creds, pop)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for {
|
||||
val, err := rp.mount.fs.impl.GetxattrAt(ctx, rp, name)
|
||||
if err == nil {
|
||||
vfs.putResolvingPath(rp)
|
||||
return val, nil
|
||||
}
|
||||
if !rp.handleError(err) {
|
||||
vfs.putResolvingPath(rp)
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetxattrAt changes the value associated with the given extended attribute
|
||||
// for the file at the given path.
|
||||
func (vfs *VirtualFilesystem) SetxattrAt(ctx context.Context, creds *auth.Credentials, pop *PathOperation, opts *SetxattrOptions) error {
|
||||
rp, err := vfs.getResolvingPath(creds, pop)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
err := rp.mount.fs.impl.SetxattrAt(ctx, rp, *opts)
|
||||
if err == nil {
|
||||
vfs.putResolvingPath(rp)
|
||||
return nil
|
||||
}
|
||||
if !rp.handleError(err) {
|
||||
vfs.putResolvingPath(rp)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RemovexattrAt removes the given extended attribute from the file at rp.
|
||||
func (vfs *VirtualFilesystem) RemovexattrAt(ctx context.Context, creds *auth.Credentials, pop *PathOperation, name string) error {
|
||||
rp, err := vfs.getResolvingPath(creds, pop)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
err := rp.mount.fs.impl.RemovexattrAt(ctx, rp, name)
|
||||
if err == nil {
|
||||
vfs.putResolvingPath(rp)
|
||||
return nil
|
||||
}
|
||||
if !rp.handleError(err) {
|
||||
vfs.putResolvingPath(rp)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SyncAllFilesystems has the semantics of Linux's sync(2).
|
||||
func (vfs *VirtualFilesystem) SyncAllFilesystems(ctx context.Context) error {
|
||||
fss := make(map[*Filesystem]struct{})
|
||||
|
||||
Reference in New Issue
Block a user