aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/fusefrontend/file2.go47
-rw-r--r--internal/fusefrontend/file2_allocate_truncate.go4
-rw-r--r--internal/fusefrontend/file2_setattr.go83
-rw-r--r--internal/fusefrontend/node.go16
-rw-r--r--internal/fusefrontend/node_api_check.go1
5 files changed, 108 insertions, 43 deletions
diff --git a/internal/fusefrontend/file2.go b/internal/fusefrontend/file2.go
index 2882732..7fe3d3a 100644
--- a/internal/fusefrontend/file2.go
+++ b/internal/fusefrontend/file2.go
@@ -4,6 +4,7 @@ package fusefrontend
import (
"bytes"
+ "context"
"encoding/hex"
"fmt"
"io"
@@ -11,10 +12,9 @@ import (
"os"
"sync"
"syscall"
- "time"
+ "github.com/hanwen/go-fuse/v2/fs"
"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/inomap"
@@ -25,9 +25,6 @@ import (
"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 {
fd *os.File
// Has Release() already been called on this file? This also means that the
@@ -53,10 +50,6 @@ type File2 struct {
lastOpCount uint64
// Parent filesystem
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.
@@ -70,7 +63,6 @@ func NewFile2(fd *os.File, rn *RootNode, st *syscall.Stat_t) *File2 {
qIno: qi,
fileTableEntry: e,
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()))
}
-// Chmod FUSE call
-func (f *File2) Chmod(mode uint32) fuse.Status {
- 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 {
+// Getattr FUSE call (like stat)
+func (f *File2) Getattr(ctx context.Context, a *fuse.AttrOut) syscall.Errno {
f.fdLock.RLock()
defer f.fdLock.RUnlock()
@@ -455,7 +428,7 @@ func (f *File2) GetAttr(a *fuse.Attr) fuse.Status {
st := syscall.Stat_t{}
err := syscall.Fstat(f.intFd(), &st)
if err != nil {
- return fuse.ToStatus(err)
+ return fs.ToErrno(err)
}
f.rootNode.inoMap.TranslateStat(&st)
a.FromStat(&st)
@@ -464,13 +437,5 @@ func (f *File2) GetAttr(a *fuse.Attr) fuse.Status {
a.Owner = *f.rootNode.args.ForceOwner
}
- return fuse.OK
-}
-
-// 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)
+ return 0
}
diff --git a/internal/fusefrontend/file2_allocate_truncate.go b/internal/fusefrontend/file2_allocate_truncate.go
index f799a3e..9a3d7d1 100644
--- a/internal/fusefrontend/file2_allocate_truncate.go
+++ b/internal/fusefrontend/file2_allocate_truncate.go
@@ -81,8 +81,8 @@ func (f *File2) Allocate(off uint64, sz uint64, mode uint32) fuse.Status {
return f.truncateGrowFile(oldPlainSz, newPlainSz)
}
-// Truncate - FUSE call
-func (f *File2) Truncate(newSize uint64) fuse.Status {
+// truncate - called from Setattr.
+func (f *File2) truncate(newSize uint64) fuse.Status {
f.fdLock.RLock()
defer f.fdLock.RUnlock()
if f.released {
diff --git a/internal/fusefrontend/file2_setattr.go b/internal/fusefrontend/file2_setattr.go
new file mode 100644
index 0000000..c341e53
--- /dev/null
+++ b/internal/fusefrontend/file2_setattr.go
@@ -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
+}
diff --git a/internal/fusefrontend/node.go b/internal/fusefrontend/node.go
index 239ec54..dae38df 100644
--- a/internal/fusefrontend/node.go
+++ b/internal/fusefrontend/node.go
@@ -266,3 +266,19 @@ func (n *Node) Open(ctx context.Context, flags uint32) (fh fs.FileHandle, fuseFl
fh = NewFile2(f, rn, &st)
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)
+}
diff --git a/internal/fusefrontend/node_api_check.go b/internal/fusefrontend/node_api_check.go
index d9facb7..2b3d02b 100644
--- a/internal/fusefrontend/node_api_check.go
+++ b/internal/fusefrontend/node_api_check.go
@@ -15,3 +15,4 @@ var _ = (fs.NodeUnlinker)((*Node)(nil))
var _ = (fs.NodeReadlinker)((*Node)(nil))
var _ = (fs.NodeOpener)((*Node)(nil))
var _ = (fs.NodeOpendirer)((*Node)(nil))
+var _ = (fs.NodeSetattrer)((*Node)(nil))