serve nfs: fix incorrect user id and group id exported to NFS #7973

Before this change all exports were exported as root and the --uid and
--gid flags of the VFS were ignored.

This fixes the issue by exporting the UID and GID correctly which
default to the current user and group unless set explicitly.
This commit is contained in:
Nick Craig-Wood 2024-08-20 18:01:46 +01:00
parent 802a938bd1
commit 6ba3e24853

View File

@ -3,6 +3,7 @@
package nfs package nfs
import ( import (
"math"
"os" "os"
"path" "path"
"strings" "strings"
@ -13,8 +14,34 @@ import (
"github.com/rclone/rclone/fs/log" "github.com/rclone/rclone/fs/log"
"github.com/rclone/rclone/vfs" "github.com/rclone/rclone/vfs"
"github.com/rclone/rclone/vfs/vfscommon" "github.com/rclone/rclone/vfs/vfscommon"
"github.com/willscott/go-nfs/file"
) )
// setSys sets the Sys() call up for the vfs.Node passed in
//
// The billy abstraction layer does not extend to exposing `uid` and `gid`
// ownership of files. If ownership is important to your file system, you
// will need to ensure that the `os.FileInfo` meets additional constraints.
// In particular, the `Sys()` escape hatch is queried by this library, and
// if your file system populates a [`syscall.Stat_t`](https://golang.org/pkg/syscall/#Stat_t)
// concrete struct, the ownership specified in that object will be used.
// It can also return a file.FileInfo which is easier to manage cross platform
func setSys(fi os.FileInfo) {
node, ok := fi.(vfs.Node)
if !ok {
fs.Errorf(fi, "internal error: %T is not a vfs.Node", fi)
}
vfs := node.VFS()
// Set the UID and GID for the node passed in from the VFS defaults.
stat := file.FileInfo{
Nlink: 1,
UID: vfs.Opt.UID,
GID: vfs.Opt.GID,
Fileid: math.MaxUint64, // without this mounting doesn't work on Linux
}
node.SetSys(&stat)
}
// FS is our wrapper around the VFS to properly support billy.Filesystem interface // FS is our wrapper around the VFS to properly support billy.Filesystem interface
type FS struct { type FS struct {
vfs *vfs.VFS vfs *vfs.VFS
@ -23,7 +50,14 @@ type FS struct {
// ReadDir implements read dir // ReadDir implements read dir
func (f *FS) ReadDir(path string) (dir []os.FileInfo, err error) { func (f *FS) ReadDir(path string) (dir []os.FileInfo, err error) {
defer log.Trace(path, "")("items=%d, err=%v", &dir, &err) defer log.Trace(path, "")("items=%d, err=%v", &dir, &err)
return f.vfs.ReadDir(path) dir, err = f.vfs.ReadDir(path)
if err != nil {
return nil, err
}
for _, fi := range dir {
setSys(fi)
}
return dir, nil
} }
// Create implements creating new files // Create implements creating new files
@ -47,7 +81,12 @@ func (f *FS) OpenFile(filename string, flag int, perm os.FileMode) (node billy.F
// Stat gets the file stat // Stat gets the file stat
func (f *FS) Stat(filename string) (fi os.FileInfo, err error) { func (f *FS) Stat(filename string) (fi os.FileInfo, err error) {
defer log.Trace(filename, "")("fi=%v, err=%v", &fi, &err) defer log.Trace(filename, "")("fi=%v, err=%v", &fi, &err)
return f.vfs.Stat(filename) fi, err = f.vfs.Stat(filename)
if err != nil {
return nil, err
}
setSys(fi)
return fi, nil
} }
// Rename renames a file // Rename renames a file
@ -95,7 +134,12 @@ func (f *FS) MkdirAll(filename string, perm os.FileMode) (err error) {
// Lstat gets the stats for symlink // Lstat gets the stats for symlink
func (f *FS) Lstat(filename string) (fi os.FileInfo, err error) { func (f *FS) Lstat(filename string) (fi os.FileInfo, err error) {
defer log.Trace(filename, "")("fi=%v, err=%v", &fi, &err) defer log.Trace(filename, "")("fi=%v, err=%v", &fi, &err)
return f.vfs.Stat(filename) fi, err = f.vfs.Stat(filename)
if err != nil {
return nil, err
}
setSys(fi)
return fi, nil
} }
// Symlink is not supported over NFS // Symlink is not supported over NFS