From 05a92f6d98b2c934d0a869d20faa65074985c818 Mon Sep 17 00:00:00 2001 From: Nicola Bonelli Date: Fri, 22 Oct 2021 11:07:50 +0200 Subject: [PATCH 1/5] Code cleanup and typos fixed. --- conversions.go | 2 +- fuseops/ops.go | 6 +++--- fusetesting/parallel.go | 4 ++-- internal/buffer/in_message_darwin.go | 2 +- internal/fusekernel/fuse_kernel.go | 2 +- mount_config.go | 2 +- mount_darwin.go | 7 ++----- samples/flushfs/flush_fs.go | 4 ++-- samples/forgetfs/forget_fs.go | 8 ++++---- samples/hellofs/hello_fs.go | 14 +++++++------- samples/memfs/memfs_go18_test.go | 1 + samples/roloopbackfs/inode.go | 1 - samples/roloopbackfs/roloopbackfs.go | 4 ++-- unmount_std.go | 1 + 14 files changed, 28 insertions(+), 30 deletions(-) diff --git a/conversions.go b/conversions.go index dddb3c05..d9e6cb15 100644 --- a/conversions.go +++ b/conversions.go @@ -527,7 +527,7 @@ func convertInMessage( return nil, errors.New("Corrupt OpSetxattr") } - name, value := payload[:i], payload[i+1:len(payload)] + name, value := payload[:i], payload[i+1:] o = &fuseops.SetXattrOp{ Inode: fuseops.InodeID(inMsg.Header().Nodeid), diff --git a/fuseops/ops.go b/fuseops/ops.go index 8af3d51e..7902a0e0 100644 --- a/fuseops/ops.go +++ b/fuseops/ops.go @@ -311,7 +311,7 @@ type CreateFileOp struct { // The handle may be supplied in future ops like ReadFileOp that contain a // file handle. The file system must ensure this ID remains valid until a // later call to ReleaseFileHandle. - Handle HandleID + Handle HandleID OpContext OpContext } @@ -787,8 +787,8 @@ type SyncFileOp struct { // return any errors that occur. type FlushFileOp struct { // The file and handle being flushed. - Inode InodeID - Handle HandleID + Inode InodeID + Handle HandleID OpContext OpContext } diff --git a/fusetesting/parallel.go b/fusetesting/parallel.go index 8d129309..7e6a1011 100644 --- a/fusetesting/parallel.go +++ b/fusetesting/parallel.go @@ -76,7 +76,7 @@ func RunCreateInParallelTest_NoTruncate( AssertEq(nil, err) idsSeen := make(map[byte]struct{}) - for i, _ := range contents { + for i := range contents { id := contents[i] AssertLt(id, numWorkers) @@ -147,7 +147,7 @@ func RunCreateInParallelTest_Truncate( AssertEq(nil, err) idsSeen := make(map[byte]struct{}) - for i, _ := range contents { + for i := range contents { id := contents[i] AssertLt(id, numWorkers) diff --git a/internal/buffer/in_message_darwin.go b/internal/buffer/in_message_darwin.go index af37a02e..df2e7866 100644 --- a/internal/buffer/in_message_darwin.go +++ b/internal/buffer/in_message_darwin.go @@ -14,7 +14,7 @@ package buffer -// The maximum fuse write request size that InMessage can acommodate. +// The maximum fuse write request size that InMessage can accommodate. // // Experimentally, OS X appears to cap the size of writes to 1 MiB, regardless // of whether a larger size is specified in the mount options. diff --git a/internal/fusekernel/fuse_kernel.go b/internal/fusekernel/fuse_kernel.go index e2d55ece..77951b5c 100644 --- a/internal/fusekernel/fuse_kernel.go +++ b/internal/fusekernel/fuse_kernel.go @@ -7,7 +7,7 @@ This -- and only this -- header file may also be distributed under - the terms of the BSD Licence as follows: + the terms of the BSD License as follows: Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved. diff --git a/mount_config.go b/mount_config.go index d23224f0..fca6a542 100644 --- a/mount_config.go +++ b/mount_config.go @@ -153,7 +153,7 @@ type MountConfig struct { // Disable FUSE default permissions. // This is useful for situations where the backing data store (e.g., S3) doesn't - // actually utilise any form of qualifiable UNIX permissions. + // actually utilize any form of qualifiable UNIX permissions. DisableDefaultPermissions bool // OS X only. diff --git a/mount_darwin.go b/mount_darwin.go index 8558acf7..c0f7581d 100644 --- a/mount_darwin.go +++ b/mount_darwin.go @@ -113,7 +113,6 @@ func openOSXFUSEDev(devPrefix string) (dev *os.File, err error) { func convertMountArgs(daemonVar string, libVar string, cfg *MountConfig) ([]string, []string, error) { - // The mount helper doesn't understand any escaping. for k, v := range cfg.toMap() { if strings.Contains(k, ",") || strings.Contains(v, ",") { @@ -124,7 +123,7 @@ func convertMountArgs(daemonVar string, libVar string, } } - env := []string{ libVar+"=" } + env := []string{libVar + "="} if daemonVar != "" { env = append(env, daemonVar+"="+os.Args[0]) } @@ -135,7 +134,7 @@ func convertMountArgs(daemonVar string, libVar string, // // OSXFUSE seems to ignore InitResponse.MaxWrite, and uses // this instead. - "-o", "iosize="+strconv.FormatUint(buffer.MaxWriteSize, 10), + "-o", "iosize=" + strconv.FormatUint(buffer.MaxWriteSize, 10), } return argv, env, nil @@ -149,7 +148,6 @@ func callMount( cfg *MountConfig, dev *os.File, ready chan<- error) error { - argv, env, err := convertMountArgs(daemonVar, libVar, cfg) if err != nil { return err @@ -197,7 +195,6 @@ func callMountCommFD( libVar string, dir string, cfg *MountConfig) (*os.File, error) { - argv, env, err := convertMountArgs(daemonVar, libVar, cfg) if err != nil { return nil, err diff --git a/samples/flushfs/flush_fs.go b/samples/flushfs/flush_fs.go index 565afbb7..a0fd42f3 100644 --- a/samples/flushfs/flush_fs.go +++ b/samples/flushfs/flush_fs.go @@ -273,14 +273,14 @@ func (fs *flushFS) ReadDir( switch op.Inode { case fuseops.RootInodeID: dirents = []fuseutil.Dirent{ - fuseutil.Dirent{ + { Offset: 1, Inode: fooID, Name: "foo", Type: fuseutil.DT_File, }, - fuseutil.Dirent{ + { Offset: 2, Inode: barID, Name: "bar", diff --git a/samples/forgetfs/forget_fs.go b/samples/forgetfs/forget_fs.go index d2171ad1..b9314e56 100644 --- a/samples/forgetfs/forget_fs.go +++ b/samples/forgetfs/forget_fs.go @@ -42,19 +42,19 @@ func NewFileSystem() *ForgetFS { // Set up the actual file system. impl := &fsImpl{ inodes: map[fuseops.InodeID]*inode{ - cannedID_Root: &inode{ + cannedID_Root: { attributes: fuseops.InodeAttributes{ Nlink: 1, Mode: 0777 | os.ModeDir, }, }, - cannedID_Foo: &inode{ + cannedID_Foo: { attributes: fuseops.InodeAttributes{ Nlink: 1, Mode: 0777, }, }, - cannedID_Bar: &inode{ + cannedID_Bar: { attributes: fuseops.InodeAttributes{ Nlink: 1, Mode: 0777 | os.ModeDir, @@ -182,7 +182,7 @@ func (in *inode) Destroy() { // LOCKS_REQUIRED(fs.mu) func (fs *fsImpl) checkInvariants() { // INVARIANT: For each k in inodes, k < nextInodeID - for k, _ := range fs.inodes { + for k := range fs.inodes { if !(k < fs.nextInodeID) { panic("Unexpectedly large inode ID") } diff --git a/samples/hellofs/hello_fs.go b/samples/hellofs/hello_fs.go index dd6b7675..74c364e6 100644 --- a/samples/hellofs/hello_fs.go +++ b/samples/hellofs/hello_fs.go @@ -67,20 +67,20 @@ type inodeInfo struct { // We have a fixed directory structure. var gInodeInfo = map[fuseops.InodeID]inodeInfo{ // root - rootInode: inodeInfo{ + rootInode: { attributes: fuseops.InodeAttributes{ Nlink: 1, Mode: 0555 | os.ModeDir, }, dir: true, children: []fuseutil.Dirent{ - fuseutil.Dirent{ + { Offset: 1, Inode: helloInode, Name: "hello", Type: fuseutil.DT_File, }, - fuseutil.Dirent{ + { Offset: 2, Inode: dirInode, Name: "dir", @@ -90,7 +90,7 @@ var gInodeInfo = map[fuseops.InodeID]inodeInfo{ }, // hello - helloInode: inodeInfo{ + helloInode: { attributes: fuseops.InodeAttributes{ Nlink: 1, Mode: 0444, @@ -99,14 +99,14 @@ var gInodeInfo = map[fuseops.InodeID]inodeInfo{ }, // dir - dirInode: inodeInfo{ + dirInode: { attributes: fuseops.InodeAttributes{ Nlink: 1, Mode: 0555 | os.ModeDir, }, dir: true, children: []fuseutil.Dirent{ - fuseutil.Dirent{ + { Offset: 1, Inode: worldInode, Name: "world", @@ -116,7 +116,7 @@ var gInodeInfo = map[fuseops.InodeID]inodeInfo{ }, // world - worldInode: inodeInfo{ + worldInode: { attributes: fuseops.InodeAttributes{ Nlink: 1, Mode: 0444, diff --git a/samples/memfs/memfs_go18_test.go b/samples/memfs/memfs_go18_test.go index b8d1516b..54c67828 100644 --- a/samples/memfs/memfs_go18_test.go +++ b/samples/memfs/memfs_go18_test.go @@ -1,3 +1,4 @@ +//go:build go1.8 // +build go1.8 package memfs_test diff --git a/samples/roloopbackfs/inode.go b/samples/roloopbackfs/inode.go index 88d23923..59aa8041 100644 --- a/samples/roloopbackfs/inode.go +++ b/samples/roloopbackfs/inode.go @@ -121,7 +121,6 @@ func (in *inodeEntry) ListChildren(inodes *sync.Map) ([]*fuseutil.Dirent, error) } dirents := make([]*fuseutil.Dirent, len(children)) for i, child := range children { - childInode, err := getOrCreateInode(inodes, in.id, child.Name()) if err != nil || childInode == nil { return nil, nil diff --git a/samples/roloopbackfs/roloopbackfs.go b/samples/roloopbackfs/roloopbackfs.go index bd2e9daa..0e464750 100644 --- a/samples/roloopbackfs/roloopbackfs.go +++ b/samples/roloopbackfs/roloopbackfs.go @@ -15,11 +15,12 @@ package roloopbackfs import ( - "golang.org/x/net/context" "log" "os" "sync" + "golang.org/x/net/context" + "github.com/jacobsa/fuse" "github.com/jacobsa/fuse/fuseops" "github.com/jacobsa/fuse/fuseutil" @@ -37,7 +38,6 @@ var _ fuseutil.FileSystem = &readonlyLoopbackFs{} // Create a file system that mirrors an existing physical path, in a readonly mode func NewReadonlyLoopbackServer(loopbackPath string, logger *log.Logger) (server fuse.Server, err error) { - if _, err = os.Stat(loopbackPath); err != nil { return nil, err } diff --git a/unmount_std.go b/unmount_std.go index c8853554..9b350a1d 100644 --- a/unmount_std.go +++ b/unmount_std.go @@ -1,3 +1,4 @@ +//go:build !linux // +build !linux package fuse From 0bd55b174ee9e958cfc7347b52949042744337c2 Mon Sep 17 00:00:00 2001 From: Nicola Bonelli Date: Fri, 22 Oct 2021 12:29:28 +0200 Subject: [PATCH 2/5] OpContext extended with Uid and Gid. --- conversions.go | 301 ++++++++++++++++++++++++++++++++++--------------- fuseops/ops.go | 6 + 2 files changed, 215 insertions(+), 92 deletions(-) diff --git a/conversions.go b/conversions.go index d9e6cb15..944a30af 100644 --- a/conversions.go +++ b/conversions.go @@ -41,7 +41,9 @@ func convertInMessage( inMsg *buffer.InMessage, outMsg *buffer.OutMessage, protocol fusekernel.Protocol) (o interface{}, err error) { - switch inMsg.Header().Opcode { + hdr := inMsg.Header() + + switch hdr.Opcode { case fusekernel.OpLookup: buf := inMsg.ConsumeBytes(inMsg.Len()) n := len(buf) @@ -50,15 +52,23 @@ func convertInMessage( } o = &fuseops.LookUpInodeOp{ - Parent: fuseops.InodeID(inMsg.Header().Nodeid), - Name: string(buf[:n-1]), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Parent: fuseops.InodeID(hdr.Nodeid), + Name: string(buf[:n-1]), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } case fusekernel.OpGetattr: o = &fuseops.GetInodeAttributesOp{ - Inode: fuseops.InodeID(inMsg.Header().Nodeid), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Inode: fuseops.InodeID(hdr.Nodeid), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } case fusekernel.OpSetattr: @@ -69,8 +79,12 @@ func convertInMessage( } to := &fuseops.SetInodeAttributesOp{ - Inode: fuseops.InodeID(inMsg.Header().Nodeid), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Inode: fuseops.InodeID(hdr.Nodeid), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } o = to @@ -99,6 +113,14 @@ func convertInMessage( to.Handle = &t } + if valid&fusekernel.SetattrUid != 0 { + to.OpContext.Uid = in.Uid + } + + if valid&fusekernel.SetattrGid != 0 { + to.OpContext.Gid = in.Gid + } + case fusekernel.OpForget: type input fusekernel.ForgetIn in := (*input)(inMsg.Consume(unsafe.Sizeof(input{}))) @@ -107,9 +129,13 @@ func convertInMessage( } o = &fuseops.ForgetInodeOp{ - Inode: fuseops.InodeID(inMsg.Header().Nodeid), - N: in.Nlookup, - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Inode: fuseops.InodeID(hdr.Nodeid), + N: in.Nlookup, + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } case fusekernel.OpMkdir: @@ -126,7 +152,7 @@ func convertInMessage( name = name[:i] o = &fuseops.MkDirOp{ - Parent: fuseops.InodeID(inMsg.Header().Nodeid), + Parent: fuseops.InodeID(hdr.Nodeid), Name: string(name), // On Linux, vfs_mkdir calls through to the inode with at most @@ -135,8 +161,12 @@ func convertInMessage( // the fact that this is a directory is implicit in the fact that the // opcode is mkdir. But we want the correct mode to go through, so ensure // that os.ModeDir is set. - Mode: convertFileMode(in.Mode) | os.ModeDir, - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Mode: convertFileMode(in.Mode) | os.ModeDir, + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } case fusekernel.OpMknod: @@ -153,10 +183,14 @@ func convertInMessage( name = name[:i] o = &fuseops.MkNodeOp{ - Parent: fuseops.InodeID(inMsg.Header().Nodeid), - Name: string(name), - Mode: convertFileMode(in.Mode), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Parent: fuseops.InodeID(hdr.Nodeid), + Name: string(name), + Mode: convertFileMode(in.Mode), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } case fusekernel.OpCreate: @@ -173,10 +207,14 @@ func convertInMessage( name = name[:i] o = &fuseops.CreateFileOp{ - Parent: fuseops.InodeID(inMsg.Header().Nodeid), - Name: string(name), - Mode: convertFileMode(in.Mode), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Parent: fuseops.InodeID(hdr.Nodeid), + Name: string(name), + Mode: convertFileMode(in.Mode), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } case fusekernel.OpSymlink: @@ -192,10 +230,14 @@ func convertInMessage( newName, target := names[0:i], names[i+1:len(names)-1] o = &fuseops.CreateSymlinkOp{ - Parent: fuseops.InodeID(inMsg.Header().Nodeid), - Name: string(newName), - Target: string(target), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Parent: fuseops.InodeID(hdr.Nodeid), + Name: string(newName), + Target: string(target), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } case fusekernel.OpRename: @@ -220,11 +262,15 @@ func convertInMessage( oldName, newName := names[:i], names[i+1:len(names)-1] o = &fuseops.RenameOp{ - OldParent: fuseops.InodeID(inMsg.Header().Nodeid), + OldParent: fuseops.InodeID(hdr.Nodeid), OldName: string(oldName), NewParent: fuseops.InodeID(in.Newdir), NewName: string(newName), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } case fusekernel.OpUnlink: @@ -235,9 +281,13 @@ func convertInMessage( } o = &fuseops.UnlinkOp{ - Parent: fuseops.InodeID(inMsg.Header().Nodeid), - Name: string(buf[:n-1]), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Parent: fuseops.InodeID(hdr.Nodeid), + Name: string(buf[:n-1]), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } case fusekernel.OpRmdir: @@ -248,21 +298,33 @@ func convertInMessage( } o = &fuseops.RmDirOp{ - Parent: fuseops.InodeID(inMsg.Header().Nodeid), - Name: string(buf[:n-1]), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Parent: fuseops.InodeID(hdr.Nodeid), + Name: string(buf[:n-1]), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } case fusekernel.OpOpen: o = &fuseops.OpenFileOp{ - Inode: fuseops.InodeID(inMsg.Header().Nodeid), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Inode: fuseops.InodeID(hdr.Nodeid), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } case fusekernel.OpOpendir: o = &fuseops.OpenDirOp{ - Inode: fuseops.InodeID(inMsg.Header().Nodeid), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Inode: fuseops.InodeID(hdr.Nodeid), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } case fusekernel.OpRead: @@ -272,10 +334,14 @@ func convertInMessage( } to := &fuseops.ReadFileOp{ - Inode: fuseops.InodeID(inMsg.Header().Nodeid), - Handle: fuseops.HandleID(in.Fh), - Offset: int64(in.Offset), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Inode: fuseops.InodeID(hdr.Nodeid), + Handle: fuseops.HandleID(in.Fh), + Offset: int64(in.Offset), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } o = to @@ -297,10 +363,14 @@ func convertInMessage( } to := &fuseops.ReadDirOp{ - Inode: fuseops.InodeID(inMsg.Header().Nodeid), - Handle: fuseops.HandleID(in.Fh), - Offset: fuseops.DirOffset(in.Offset), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Inode: fuseops.InodeID(hdr.Nodeid), + Handle: fuseops.HandleID(in.Fh), + Offset: fuseops.DirOffset(in.Offset), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } o = to @@ -323,8 +393,12 @@ func convertInMessage( } o = &fuseops.ReleaseFileHandleOp{ - Handle: fuseops.HandleID(in.Fh), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Handle: fuseops.HandleID(in.Fh), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } case fusekernel.OpReleasedir: @@ -335,8 +409,12 @@ func convertInMessage( } o = &fuseops.ReleaseDirHandleOp{ - Handle: fuseops.HandleID(in.Fh), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Handle: fuseops.HandleID(in.Fh), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } case fusekernel.OpWrite: @@ -351,11 +429,15 @@ func convertInMessage( } o = &fuseops.WriteFileOp{ - Inode: fuseops.InodeID(inMsg.Header().Nodeid), - Handle: fuseops.HandleID(in.Fh), - Data: buf, - Offset: int64(in.Offset), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Inode: fuseops.InodeID(hdr.Nodeid), + Handle: fuseops.HandleID(in.Fh), + Data: buf, + Offset: int64(in.Offset), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } case fusekernel.OpFsync, fusekernel.OpFsyncdir: @@ -366,9 +448,13 @@ func convertInMessage( } o = &fuseops.SyncFileOp{ - Inode: fuseops.InodeID(inMsg.Header().Nodeid), - Handle: fuseops.HandleID(in.Fh), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Inode: fuseops.InodeID(hdr.Nodeid), + Handle: fuseops.HandleID(in.Fh), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } case fusekernel.OpFlush: @@ -379,15 +465,23 @@ func convertInMessage( } o = &fuseops.FlushFileOp{ - Inode: fuseops.InodeID(inMsg.Header().Nodeid), - Handle: fuseops.HandleID(in.Fh), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Inode: fuseops.InodeID(hdr.Nodeid), + Handle: fuseops.HandleID(in.Fh), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } case fusekernel.OpReadlink: o = &fuseops.ReadSymlinkOp{ - Inode: fuseops.InodeID(inMsg.Header().Nodeid), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Inode: fuseops.InodeID(hdr.Nodeid), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } case fusekernel.OpStatfs: @@ -435,10 +529,14 @@ func convertInMessage( } o = &fuseops.CreateLinkOp{ - Parent: fuseops.InodeID(inMsg.Header().Nodeid), - Name: string(name), - Target: fuseops.InodeID(in.Oldnodeid), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Parent: fuseops.InodeID(hdr.Nodeid), + Name: string(name), + Target: fuseops.InodeID(in.Oldnodeid), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } case fusekernel.OpRemovexattr: @@ -449,9 +547,13 @@ func convertInMessage( } o = &fuseops.RemoveXattrOp{ - Inode: fuseops.InodeID(inMsg.Header().Nodeid), - Name: string(buf[:n-1]), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Inode: fuseops.InodeID(hdr.Nodeid), + Name: string(buf[:n-1]), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } case fusekernel.OpGetxattr: @@ -469,9 +571,13 @@ func convertInMessage( name = name[:i] to := &fuseops.GetXattrOp{ - Inode: fuseops.InodeID(inMsg.Header().Nodeid), - Name: string(name), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Inode: fuseops.InodeID(hdr.Nodeid), + Name: string(name), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } o = to @@ -494,8 +600,12 @@ func convertInMessage( } to := &fuseops.ListXattrOp{ - Inode: fuseops.InodeID(inMsg.Header().Nodeid), - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Inode: fuseops.InodeID(hdr.Nodeid), + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } o = to @@ -530,11 +640,15 @@ func convertInMessage( name, value := payload[:i], payload[i+1:] o = &fuseops.SetXattrOp{ - Inode: fuseops.InodeID(inMsg.Header().Nodeid), - Name: string(name), - Value: value, - Flags: in.Flags, - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Inode: fuseops.InodeID(hdr.Nodeid), + Name: string(name), + Value: value, + Flags: in.Flags, + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, } case fusekernel.OpFallocate: type input fusekernel.FallocateIn @@ -544,18 +658,23 @@ func convertInMessage( } o = &fuseops.FallocateOp{ - Inode: fuseops.InodeID(inMsg.Header().Nodeid), - Handle: fuseops.HandleID(in.Fh), - Offset: in.Offset, - Length: in.Length, - Mode: in.Mode, - OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, + Inode: fuseops.InodeID(hdr.Nodeid), + Handle: fuseops.HandleID(in.Fh), + Offset: in.Offset, + Length: in.Length, + Mode: in.Mode, + OpContext: fuseops.OpContext{ + Pid: hdr.Pid, + Uid: hdr.Uid, + Gid: hdr.Gid, + }, + } } default: o = &unknownOp{ - OpCode: inMsg.Header().Opcode, - Inode: fuseops.InodeID(inMsg.Header().Nodeid), + OpCode: hdr.Opcode, + Inode: fuseops.InodeID(hdr.Nodeid), } } @@ -604,10 +723,8 @@ func (c *Connection) kernelResponse( // header. m.ShrinkTo(buffer.OutMessageHeaderSize) } - } - - // Otherwise, fill in the rest of the response. - if opErr == nil { + } else { + // Otherwise, fill in the rest of the response. c.kernelResponseForOp(m, op) } diff --git a/fuseops/ops.go b/fuseops/ops.go index 7902a0e0..5ffe802f 100644 --- a/fuseops/ops.go +++ b/fuseops/ops.go @@ -29,6 +29,12 @@ type OpContext struct { // PID of the process that is invoking the operation. // Not filled in case of a writepage operation. Pid uint32 + + // UID of the calling process. + Uid uint32 + + // GID of the calling process. + Gid uint32 } // Return statistics about the file system's capacity and available resources. From e16e55ce3b07e929938f3aa988700ded74587142 Mon Sep 17 00:00:00 2001 From: Nicola Bonelli Date: Fri, 22 Oct 2021 12:30:54 +0200 Subject: [PATCH 3/5] POSIX locking support enabled. --- connection.go | 6 ++ conversions.go | 80 +++++++++++++++++++++++++ debug.go | 5 ++ flock_darwin.go | 32 ++++++++++ flock_linux.go | 32 ++++++++++ fuseops/ops.go | 36 +++++++++++ fuseops/simple_types.go | 23 +++++++ fuseutil/file_system.go | 4 ++ fuseutil/not_implemented_file_system.go | 7 +++ internal/fusekernel/fuse_kernel.go | 6 +- mount_config.go | 4 ++ 11 files changed, 232 insertions(+), 3 deletions(-) create mode 100644 flock_darwin.go create mode 100644 flock_linux.go diff --git a/connection.go b/connection.go index 885ab49a..f87da4c9 100644 --- a/connection.go +++ b/connection.go @@ -193,6 +193,12 @@ func (c *Connection) Init() error { initOp.Flags |= fusekernel.InitNoOpendirSupport } + // enable posix locking... + if c.cfg.EnableFileLocking { + initOp.Flags |= fusekernel.InitFlockLocks + initOp.Flags |= fusekernel.InitPosixLocks + } + c.Reply(ctx, nil) return nil } diff --git a/conversions.go b/conversions.go index 944a30af..ee5393d3 100644 --- a/conversions.go +++ b/conversions.go @@ -669,8 +669,74 @@ func convertInMessage( Gid: hdr.Gid, }, } + + case fusekernel.OpGetlk: + type input fusekernel.LkIn + in := (*input)(inMsg.Consume(fusekernel.LkInSize(protocol))) + if in == nil { + err = errors.New("Corrupt OpGetlk") + return + } + + o = &fuseops.FileLockOp{ + Start: in.Lk.Start, + End: in.Lk.End, + Cmd: fuseops.FileLockGet, + Type: MapFlockType(in.Lk.Type), + Inode: fuseops.InodeID(inMsg.Header().Nodeid), + Handle: fuseops.HandleID(in.Fh), + Owner: in.Owner, + OpContext: fuseops.OpContext{ + Pid: in.Lk.Pid, // pid comes from kernel message + Uid: hdr.Uid, + Gid: hdr.Gid, + }, + } + + case fusekernel.OpSetlk: + type input fusekernel.LkIn + in := (*input)(inMsg.Consume(fusekernel.LkInSize(protocol))) + if in == nil { + err = errors.New("Corrupt OpSetlk") + return + } + + o = &fuseops.FileLockOp{ + Start: in.Lk.Start, + End: in.Lk.End, + Cmd: fuseops.FileLockSet, + Type: MapFlockType(in.Lk.Type), + Inode: fuseops.InodeID(inMsg.Header().Nodeid), + Handle: fuseops.HandleID(in.Fh), + Owner: in.Owner, + OpContext: fuseops.OpContext{ + Pid: in.Lk.Pid, // pid comes from kernel message + Uid: hdr.Uid, + Gid: hdr.Gid, + }, + } + case fusekernel.OpSetlkw: + type input fusekernel.LkIn + in := (*input)(inMsg.Consume(fusekernel.LkInSize(protocol))) + if in == nil { + err = errors.New("Corrupt OpSetlkw") + return } + o = &fuseops.FileLockOp{ + Start: in.Lk.Start, + End: in.Lk.End, + Cmd: fuseops.FileLockSetw, + Type: MapFlockType(in.Lk.Type), + Inode: fuseops.InodeID(inMsg.Header().Nodeid), + Handle: fuseops.HandleID(in.Fh), + Owner: in.Owner, + OpContext: fuseops.OpContext{ + Pid: in.Lk.Pid, // pid comes from kernel message + Uid: hdr.Uid, + Gid: hdr.Gid, + }, + } default: o = &unknownOp{ OpCode: hdr.Opcode, @@ -920,6 +986,20 @@ func (c *Connection) kernelResponseForOp( out.TimeGran = 1 out.MaxPages = o.MaxPages + case *fuseops.FileLockOp: + if o.Cmd == fuseops.FileLockGet { + out := (*fusekernel.FileLock)(m.Grow(int(unsafe.Sizeof(fusekernel.FileLock{})))) + if o.Type == fuseops.F_UNLOCK { + out.Start = 0 + out.End = 0 + } else { + out.Start = o.Start + out.End = o.End + } + out.Type = UnmapFlockType(o.Type) + out.Pid = o.OpContext.Pid + } + default: panic(fmt.Sprintf("Unexpected op: %#v", op)) } diff --git a/debug.go b/debug.go index 2a4dcc0d..327b5b36 100644 --- a/debug.go +++ b/debug.go @@ -115,6 +115,11 @@ func describeRequest(op interface{}) (s string) { addComponent("offset %d", typed.Offset) addComponent("length %d", typed.Length) addComponent("mode %d", typed.Mode) + + case *fuseops.FileLockOp: + addComponent("handle %d", typed.Handle) + addComponent("locktype %d", typed.Type) + addComponent("owner %d", typed.Type) } // Use just the name if there is no extra info. diff --git a/flock_darwin.go b/flock_darwin.go new file mode 100644 index 00000000..89be8736 --- /dev/null +++ b/flock_darwin.go @@ -0,0 +1,32 @@ +package fuse + +import ( + "fmt" + + "github.com/jacobsa/fuse/fuseops" +) + +func MapFlockType(t uint32) fuseops.FileLockType { + switch t { + case 1: + return fuseops.F_RDLOCK + case 2: + return fuseops.F_UNLOCK + case 3: + return fuseops.F_WRLOCK + } + panic("MapFLockType: unknown type " + fmt.Sprintf("%d", t)) +} + +func UnmapFlockType(t fuseops.FileLockType) uint32 { + var ret uint32 + switch t { + case fuseops.F_RDLOCK: + ret = 1 + case fuseops.F_WRLOCK: + ret = 3 + case fuseops.F_UNLOCK: + ret = 2 + } + return ret +} diff --git a/flock_linux.go b/flock_linux.go new file mode 100644 index 00000000..4dd3e227 --- /dev/null +++ b/flock_linux.go @@ -0,0 +1,32 @@ +package fuse + +import ( + "fmt" + + "github.com/jacobsa/fuse/fuseops" +) + +func MapFlockType(t uint32) fuseops.FileLockType { + switch t { + case 0: + return fuseops.F_RDLOCK + case 1: + return fuseops.F_WRLOCK + case 2: + return fuseops.F_UNLOCK + } + panic("MapFLockType: unknown type " + fmt.Sprintf("%d", t) + "!") +} + +func UnmapFlockType(t fuseops.FileLockType) uint32 { + var ret uint32 + switch t { + case fuseops.F_RDLOCK: + ret = 0 + case fuseops.F_WRLOCK: + ret = 1 + case fuseops.F_UNLOCK: + ret = 2 + } + return ret +} diff --git a/fuseops/ops.go b/fuseops/ops.go index 5ffe802f..8f276735 100644 --- a/fuseops/ops.go +++ b/fuseops/ops.go @@ -929,3 +929,39 @@ type FallocateOp struct { Mode uint32 OpContext OpContext } + +type FileLockCmd int + +const ( + FileLockGet FileLockCmd = iota + FileLockSet + FileLockSetw +) + +func (f FileLockCmd) String() string { + var ret string + switch f { + case FileLockGet: + ret = "FileLockGet" + case FileLockSet: + ret = "FileLockSet" + case FileLockSetw: + ret = "FileLockSetw" + } + return ret +} + +type FileLockOp struct { + // File lock arguments + + Start uint64 + End uint64 + Cmd FileLockCmd + Type FileLockType + + Inode InodeID + Handle HandleID + Owner uint64 + + OpContext OpContext +} diff --git a/fuseops/simple_types.go b/fuseops/simple_types.go index 5f5cdbf0..3fd014eb 100644 --- a/fuseops/simple_types.go +++ b/fuseops/simple_types.go @@ -220,3 +220,26 @@ type ChildInodeEntry struct { // default. See notes on MountConfig.EnableVnodeCaching for more. EntryExpiration time.Time } + +// Posix Locking types.. + +type FileLockType uint32 // L_TYPE + +const ( + F_RDLOCK FileLockType = iota + F_WRLOCK + F_UNLOCK +) + +func (f FileLockType) String() string { + var ret string + switch f { + case F_RDLOCK: + ret = "RDLOCK" + case F_WRLOCK: + ret = "WRLOCK" + case F_UNLOCK: + ret = "UNLOCK" + } + return ret +} diff --git a/fuseutil/file_system.go b/fuseutil/file_system.go index 5eb8bcaa..b5a59257 100644 --- a/fuseutil/file_system.go +++ b/fuseutil/file_system.go @@ -62,6 +62,7 @@ type FileSystem interface { ListXattr(context.Context, *fuseops.ListXattrOp) error SetXattr(context.Context, *fuseops.SetXattrOp) error Fallocate(context.Context, *fuseops.FallocateOp) error + LockFile(context.Context, *fuseops.FileLockOp) error // Regard all inodes (including the root inode) as having their lookup counts // decremented to zero, and clean up any resources associated with the file @@ -219,6 +220,9 @@ func (s *fileSystemServer) handleOp( case *fuseops.FallocateOp: err = s.fs.Fallocate(ctx, typed) + + case *fuseops.FileLockOp: + err = s.fs.LockFile(ctx, typed) } c.Reply(ctx, err) diff --git a/fuseutil/not_implemented_file_system.go b/fuseutil/not_implemented_file_system.go index 4d29cfaf..fca03ee5 100644 --- a/fuseutil/not_implemented_file_system.go +++ b/fuseutil/not_implemented_file_system.go @@ -200,3 +200,10 @@ func (fs *NotImplementedFileSystem) Fallocate( func (fs *NotImplementedFileSystem) Destroy() { } + +func (fs *NotImplementedFileSystem) LockFile( + ctx context.Context, + op *fuseops.FileLockOp) (err error) { + err = fuse.ENOSYS + return +} diff --git a/internal/fusekernel/fuse_kernel.go b/internal/fusekernel/fuse_kernel.go index 77951b5c..b04c5b69 100644 --- a/internal/fusekernel/fuse_kernel.go +++ b/internal/fusekernel/fuse_kernel.go @@ -66,7 +66,7 @@ type Kstatfs struct { Spare [6]uint32 } -type fileLock struct { +type FileLock struct { Start uint64 End uint64 Type uint32 @@ -683,7 +683,7 @@ type FallocateIn struct { type LkIn struct { Fh uint64 Owner uint64 - Lk fileLock + Lk FileLock LkFlags uint32 padding uint32 } @@ -698,7 +698,7 @@ func LkInSize(p Protocol) uintptr { } type LkOut struct { - Lk fileLock + Lk FileLock } type AccessIn struct { diff --git a/mount_config.go b/mount_config.go index fca6a542..514e170e 100644 --- a/mount_config.go +++ b/mount_config.go @@ -113,6 +113,10 @@ type MountConfig struct { // syscall doesn't return until the file system returns. DisableWritebackCaching bool + // Enable Posix file locking + + EnableFileLocking bool + // OS X only. // // Normally on OS X we mount with the novncache option From 5165280c02f399669b0d09398f4407b30a71bfd3 Mon Sep 17 00:00:00 2001 From: Nicola Bonelli Date: Fri, 22 Oct 2021 12:32:40 +0200 Subject: [PATCH 4/5] BugFix: ensure that mount component is not empty. --- mount_config.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mount_config.go b/mount_config.go index 514e170e..fe8fa66b 100644 --- a/mount_config.go +++ b/mount_config.go @@ -267,11 +267,12 @@ func mapToOptionsString(opts map[string]string) string { k = escapeOptionsKey(k) component := k - if v != "" { - component = fmt.Sprintf("%s=%s", k, v) + if component != "" { + if v != "" { + component = fmt.Sprintf("%s=%s", k, v) + } + components = append(components, component) } - - components = append(components, component) } return strings.Join(components, ",") From 8f860d161339918c64b73103d4e8b19782061b75 Mon Sep 17 00:00:00 2001 From: Nicola Bonelli Date: Wed, 27 Oct 2021 17:18:08 +0200 Subject: [PATCH 5/5] BugFix: OpRename workaround for macFuse 4.2.1 --- conversions.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/conversions.go b/conversions.go index ee5393d3..aa38b3fc 100644 --- a/conversions.go +++ b/conversions.go @@ -248,10 +248,29 @@ func convertInMessage( } names := inMsg.ConsumeBytes(inMsg.Len()) + // names should be "old\x00new\x00" if len(names) < 4 { return nil, errors.New("Corrupt OpRename") } + + // macFuse 4.2.1 workaround: the kernel implementation is buggy. + // It call OpRename with the data type of OpRename2. The workaround consists + // in skipping the first 8 bytes of names (which are zeroes). + + if len(names) > 8 { + if names[0] == '\x00' && + names[1] == '\x00' && + names[2] == '\x00' && + names[3] == '\x00' && + names[4] == '\x00' && + names[5] == '\x00' && + names[6] == '\x00' && + names[7] == '\x00' { + names = names[8:] + } + } + if names[len(names)-1] != '\x00' { return nil, errors.New("Corrupt OpRename") }