diff options
| author | Jakob Unterwurzacher | 2020-07-05 20:05:07 +0200 | 
|---|---|---|
| committer | Jakob Unterwurzacher | 2020-07-05 20:10:53 +0200 | 
| commit | 63f68a0fcd514b7cf96a485016c2db23c60c3405 (patch) | |
| tree | b3c7cdb39fcec34250036a1d5cdef8321c79fe6e | |
| parent | c22e78ee41f4c5a91429bb83c6be3e60b4c2a20f (diff) | |
v2api: implement Setattr
| -rw-r--r-- | internal/fusefrontend/file2.go | 47 | ||||
| -rw-r--r-- | internal/fusefrontend/file2_allocate_truncate.go | 4 | ||||
| -rw-r--r-- | internal/fusefrontend/file2_setattr.go | 83 | ||||
| -rw-r--r-- | internal/fusefrontend/node.go | 16 | ||||
| -rw-r--r-- | internal/fusefrontend/node_api_check.go | 1 | 
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)) | 
