v2api: implement Setattr
This commit is contained in:
parent
c22e78ee41
commit
63f68a0fcd
|
@ -4,6 +4,7 @@ package fusefrontend
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
@ -11,10 +12,9 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
|
||||||
|
|
||||||
|
"github.com/hanwen/go-fuse/v2/fs"
|
||||||
"github.com/hanwen/go-fuse/v2/fuse"
|
"github.com/hanwen/go-fuse/v2/fuse"
|
||||||
"github.com/hanwen/go-fuse/v2/fuse/nodefs"
|
|
||||||
|
|
||||||
"github.com/rfjakob/gocryptfs/internal/contentenc"
|
"github.com/rfjakob/gocryptfs/internal/contentenc"
|
||||||
"github.com/rfjakob/gocryptfs/internal/inomap"
|
"github.com/rfjakob/gocryptfs/internal/inomap"
|
||||||
|
@ -25,9 +25,6 @@ import (
|
||||||
"github.com/rfjakob/gocryptfs/internal/tlog"
|
"github.com/rfjakob/gocryptfs/internal/tlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ nodefs.File = &File{} // Verify that interface is implemented.
|
|
||||||
|
|
||||||
// File - based on loopbackFile in go-fuse/fuse/nodefs/files.go
|
|
||||||
type File2 struct {
|
type File2 struct {
|
||||||
fd *os.File
|
fd *os.File
|
||||||
// Has Release() already been called on this file? This also means that the
|
// Has Release() already been called on this file? This also means that the
|
||||||
|
@ -53,10 +50,6 @@ type File2 struct {
|
||||||
lastOpCount uint64
|
lastOpCount uint64
|
||||||
// Parent filesystem
|
// Parent filesystem
|
||||||
rootNode *RootNode
|
rootNode *RootNode
|
||||||
// We embed a nodefs.NewDefaultFile() that returns ENOSYS for every operation we
|
|
||||||
// have not implemented. This prevents build breakage when the go-fuse library
|
|
||||||
// adds new methods to the nodefs.File interface.
|
|
||||||
nodefs.File
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFile returns a new go-fuse File instance.
|
// NewFile returns a new go-fuse File instance.
|
||||||
|
@ -70,7 +63,6 @@ func NewFile2(fd *os.File, rn *RootNode, st *syscall.Stat_t) *File2 {
|
||||||
qIno: qi,
|
qIno: qi,
|
||||||
fileTableEntry: e,
|
fileTableEntry: e,
|
||||||
rootNode: rn,
|
rootNode: rn,
|
||||||
File: nodefs.NewDefaultFile(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,27 +419,8 @@ func (f *File2) Fsync(flags int) (code fuse.Status) {
|
||||||
return fuse.ToStatus(syscall.Fsync(f.intFd()))
|
return fuse.ToStatus(syscall.Fsync(f.intFd()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chmod FUSE call
|
// Getattr FUSE call (like stat)
|
||||||
func (f *File2) Chmod(mode uint32) fuse.Status {
|
func (f *File2) Getattr(ctx context.Context, a *fuse.AttrOut) syscall.Errno {
|
||||||
f.fdLock.RLock()
|
|
||||||
defer f.fdLock.RUnlock()
|
|
||||||
|
|
||||||
// os.File.Chmod goes through the "syscallMode" translation function that messes
|
|
||||||
// up the suid and sgid bits. So use syscall.Fchmod directly.
|
|
||||||
err := syscall.Fchmod(f.intFd(), mode)
|
|
||||||
return fuse.ToStatus(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Chown FUSE call
|
|
||||||
func (f *File2) Chown(uid uint32, gid uint32) fuse.Status {
|
|
||||||
f.fdLock.RLock()
|
|
||||||
defer f.fdLock.RUnlock()
|
|
||||||
|
|
||||||
return fuse.ToStatus(f.fd.Chown(int(uid), int(gid)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAttr FUSE call (like stat)
|
|
||||||
func (f *File2) GetAttr(a *fuse.Attr) fuse.Status {
|
|
||||||
f.fdLock.RLock()
|
f.fdLock.RLock()
|
||||||
defer f.fdLock.RUnlock()
|
defer f.fdLock.RUnlock()
|
||||||
|
|
||||||
|
@ -455,7 +428,7 @@ func (f *File2) GetAttr(a *fuse.Attr) fuse.Status {
|
||||||
st := syscall.Stat_t{}
|
st := syscall.Stat_t{}
|
||||||
err := syscall.Fstat(f.intFd(), &st)
|
err := syscall.Fstat(f.intFd(), &st)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fuse.ToStatus(err)
|
return fs.ToErrno(err)
|
||||||
}
|
}
|
||||||
f.rootNode.inoMap.TranslateStat(&st)
|
f.rootNode.inoMap.TranslateStat(&st)
|
||||||
a.FromStat(&st)
|
a.FromStat(&st)
|
||||||
|
@ -464,13 +437,5 @@ func (f *File2) GetAttr(a *fuse.Attr) fuse.Status {
|
||||||
a.Owner = *f.rootNode.args.ForceOwner
|
a.Owner = *f.rootNode.args.ForceOwner
|
||||||
}
|
}
|
||||||
|
|
||||||
return fuse.OK
|
return 0
|
||||||
}
|
|
||||||
|
|
||||||
// Utimens FUSE call
|
|
||||||
func (f *File2) Utimens(a *time.Time, m *time.Time) fuse.Status {
|
|
||||||
f.fdLock.RLock()
|
|
||||||
defer f.fdLock.RUnlock()
|
|
||||||
err := syscallcompat.FutimesNano(f.intFd(), a, m)
|
|
||||||
return fuse.ToStatus(err)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,8 +81,8 @@ func (f *File2) Allocate(off uint64, sz uint64, mode uint32) fuse.Status {
|
||||||
return f.truncateGrowFile(oldPlainSz, newPlainSz)
|
return f.truncateGrowFile(oldPlainSz, newPlainSz)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Truncate - FUSE call
|
// truncate - called from Setattr.
|
||||||
func (f *File2) Truncate(newSize uint64) fuse.Status {
|
func (f *File2) truncate(newSize uint64) fuse.Status {
|
||||||
f.fdLock.RLock()
|
f.fdLock.RLock()
|
||||||
defer f.fdLock.RUnlock()
|
defer f.fdLock.RUnlock()
|
||||||
if f.released {
|
if f.released {
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
package fusefrontend
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/hanwen/go-fuse/v2/fs"
|
||||||
|
"github.com/hanwen/go-fuse/v2/fuse"
|
||||||
|
|
||||||
|
"github.com/rfjakob/gocryptfs/internal/syscallcompat"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (f *File2) Setattr(ctx context.Context, in *fuse.SetAttrIn, out *fuse.AttrOut) (errno syscall.Errno) {
|
||||||
|
errno = f.setAttr(ctx, in)
|
||||||
|
if errno != 0 {
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
return f.Getattr(ctx, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *File2) setAttr(ctx context.Context, in *fuse.SetAttrIn) (errno syscall.Errno) {
|
||||||
|
f.fdLock.RLock()
|
||||||
|
defer f.fdLock.RUnlock()
|
||||||
|
if f.released {
|
||||||
|
return syscall.EBADF
|
||||||
|
}
|
||||||
|
f.fileTableEntry.ContentLock.Lock()
|
||||||
|
defer f.fileTableEntry.ContentLock.Unlock()
|
||||||
|
|
||||||
|
// chmod(2) & fchmod(2)
|
||||||
|
if mode, ok := in.GetMode(); ok {
|
||||||
|
errno = fs.ToErrno(syscall.Fchmod(f.intFd(), mode))
|
||||||
|
if errno != 0 {
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// chown(2) & fchown(2)
|
||||||
|
uid32, uOk := in.GetUID()
|
||||||
|
gid32, gOk := in.GetGID()
|
||||||
|
if uOk || gOk {
|
||||||
|
uid := -1
|
||||||
|
gid := -1
|
||||||
|
|
||||||
|
if uOk {
|
||||||
|
uid = int(uid32)
|
||||||
|
}
|
||||||
|
if gOk {
|
||||||
|
gid = int(gid32)
|
||||||
|
}
|
||||||
|
errno = fs.ToErrno(syscall.Fchown(f.intFd(), uid, gid))
|
||||||
|
if errno != 0 {
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// utimens(2)
|
||||||
|
mtime, mok := in.GetMTime()
|
||||||
|
atime, aok := in.GetATime()
|
||||||
|
if mok || aok {
|
||||||
|
ap := &atime
|
||||||
|
mp := &mtime
|
||||||
|
if !aok {
|
||||||
|
ap = nil
|
||||||
|
}
|
||||||
|
if !mok {
|
||||||
|
mp = nil
|
||||||
|
}
|
||||||
|
errno = fs.ToErrno(syscallcompat.FutimesNano(f.intFd(), ap, mp))
|
||||||
|
if errno != 0 {
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// truncate(2)
|
||||||
|
if sz, ok := in.GetSize(); ok {
|
||||||
|
errno = syscall.Errno(f.truncate(sz))
|
||||||
|
if errno != 0 {
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
|
@ -266,3 +266,19 @@ func (n *Node) Open(ctx context.Context, flags uint32) (fh fs.FileHandle, fuseFl
|
||||||
fh = NewFile2(f, rn, &st)
|
fh = NewFile2(f, rn, &st)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setattr - FUSE call. Called for chmod, truncate, utimens, ...
|
||||||
|
func (n *Node) Setattr(ctx context.Context, f fs.FileHandle, in *fuse.SetAttrIn, out *fuse.AttrOut) (errno syscall.Errno) {
|
||||||
|
var f2 *File2
|
||||||
|
if f != nil {
|
||||||
|
f2 = f.(*File2)
|
||||||
|
} else {
|
||||||
|
f, _, errno := n.Open(ctx, syscall.O_RDWR)
|
||||||
|
if errno != 0 {
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
f2 = f.(*File2)
|
||||||
|
defer f2.Release()
|
||||||
|
}
|
||||||
|
return f2.Setattr(ctx, in, out)
|
||||||
|
}
|
||||||
|
|
|
@ -15,3 +15,4 @@ var _ = (fs.NodeUnlinker)((*Node)(nil))
|
||||||
var _ = (fs.NodeReadlinker)((*Node)(nil))
|
var _ = (fs.NodeReadlinker)((*Node)(nil))
|
||||||
var _ = (fs.NodeOpener)((*Node)(nil))
|
var _ = (fs.NodeOpener)((*Node)(nil))
|
||||||
var _ = (fs.NodeOpendirer)((*Node)(nil))
|
var _ = (fs.NodeOpendirer)((*Node)(nil))
|
||||||
|
var _ = (fs.NodeSetattrer)((*Node)(nil))
|
||||||
|
|
Loading…
Reference in New Issue