diff options
| author | Jakob Unterwurzacher | 2021-03-21 09:31:05 +0100 | 
|---|---|---|
| committer | Jakob Unterwurzacher | 2021-03-21 09:31:05 +0100 | 
| commit | 3b9a1b628b11a9deb03a8fe7e6022e75b16ded49 (patch) | |
| tree | caac22d00043bc9ffaf568fdd1f0388df7eb8cf7 /internal | |
| parent | 47a4d33f24509ac9db6b924f84a7102cbe0f98c3 (diff) | |
fusefronted: move Create() and Open() to new file
And deduplicate the code a little.
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/fusefrontend/file.go | 21 | ||||
| -rw-r--r-- | internal/fusefrontend/node.go | 114 | ||||
| -rw-r--r-- | internal/fusefrontend/node_open_create.go | 108 | 
3 files changed, 125 insertions, 118 deletions
| diff --git a/internal/fusefrontend/file.go b/internal/fusefrontend/file.go index 98e5802..33a3cbe 100644 --- a/internal/fusefrontend/file.go +++ b/internal/fusefrontend/file.go @@ -53,18 +53,31 @@ type File struct {  	rootNode *RootNode  } -// NewFile returns a new go-fuse File instance. -func NewFile(fd *os.File, rn *RootNode, st *syscall.Stat_t) *File { +// NewFile returns a new go-fuse File instance based on an already-open file +// descriptor. NewFile internally calls Fstat() on the fd. The resulting Stat_t +// is returned because node.Create() needs it. +// +// `cName` is only used for error logging and may be left blank. +func NewFile(fd int, cName string, rn *RootNode) (f *File, st *syscall.Stat_t, errno syscall.Errno) { +	// Need device number and inode number for openfiletable locking +	st = &syscall.Stat_t{} +	if err := syscall.Fstat(fd, st); err != nil { +		errno = fs.ToErrno(err) +		return +	}  	qi := inomap.QInoFromStat(st)  	e := openfiletable.Register(qi) -	return &File{ -		fd:             fd, +	osFile := os.NewFile(uintptr(fd), cName) + +	f = &File{ +		fd:             osFile,  		contentEnc:     rn.contentEnc,  		qIno:           qi,  		fileTableEntry: e,  		rootNode:       rn,  	} +	return f, st, 0  }  // intFd - return the backing file descriptor as an integer. diff --git a/internal/fusefrontend/node.go b/internal/fusefrontend/node.go index 2e5d370..5a7edc8 100644 --- a/internal/fusefrontend/node.go +++ b/internal/fusefrontend/node.go @@ -2,7 +2,6 @@ package fusefrontend  import (  	"context" -	"os"  	"syscall"  	"golang.org/x/sys/unix" @@ -78,69 +77,6 @@ func (n *Node) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut)  	return 0  } -// Create - FUSE call. Creates a new file. -// -// Symlink-safe through the use of Openat(). -func (n *Node) Create(ctx context.Context, name string, flags uint32, mode uint32, out *fuse.EntryOut) (inode *fs.Inode, fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) { -	dirfd, cName, errno := n.prepareAtSyscall(name) -	if errno != 0 { -		return -	} -	defer syscall.Close(dirfd) - -	var err error -	fd := -1 -	// Make sure context is nil if we don't want to preserve the owner -	rn := n.rootNode() -	if !rn.args.PreserveOwner { -		ctx = nil -	} -	newFlags := rn.mangleOpenFlags(flags) -	// Handle long file name -	ctx2 := toFuseCtx(ctx) -	if !rn.args.PlaintextNames && nametransform.IsLongContent(cName) { -		// Create ".name" -		err = rn.nameTransform.WriteLongNameAt(dirfd, cName, name) -		if err != nil { -			return nil, nil, 0, fs.ToErrno(err) -		} -		// Create content -		fd, err = syscallcompat.OpenatUser(dirfd, cName, newFlags|syscall.O_CREAT|syscall.O_EXCL, mode, ctx2) -		if err != nil { -			nametransform.DeleteLongNameAt(dirfd, cName) -		} -	} else { -		// Create content, normal (short) file name -		fd, err = syscallcompat.OpenatUser(dirfd, cName, newFlags|syscall.O_CREAT|syscall.O_EXCL, mode, ctx2) -	} -	if err != nil { -		// xfstests generic/488 triggers this -		if err == syscall.EMFILE { -			var lim syscall.Rlimit -			syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim) -			tlog.Warn.Printf("Create %q: too many open files. Current \"ulimit -n\": %d", cName, lim.Cur) -		} -		return nil, nil, 0, fs.ToErrno(err) -	} - -	// Get device number and inode number into `st` -	var st syscall.Stat_t -	err = syscall.Fstat(fd, &st) -	if err != nil { -		errno = fs.ToErrno(err) -		return -	} -	// Save original stat values before newChild() translates the inode number. -	// For an open fd, we assume the inode number cannot change behind our back, -	// even in `-sharedstorage` mode. -	origSt := st - -	ch := n.newChild(ctx, &st, out) - -	f := os.NewFile(uintptr(fd), cName) -	return ch, NewFile(f, rn, &origSt), 0, 0 -} -  // Unlink - FUSE call. Delete a file.  //  // Symlink-safe through use of Unlinkat(). @@ -179,56 +115,6 @@ func (n *Node) Readlink(ctx context.Context) (out []byte, errno syscall.Errno) {  	return n.readlink(dirfd, cName)  } -// Open - FUSE call. Open already-existing file. -// -// Symlink-safe through Openat(). -func (n *Node) Open(ctx context.Context, flags uint32) (fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) { -	dirfd, cName, errno := n.prepareAtSyscall("") -	if errno != 0 { -		return -	} -	defer syscall.Close(dirfd) - -	rn := n.rootNode() -	newFlags := rn.mangleOpenFlags(flags) -	// Taking this lock makes sure we don't race openWriteOnlyFile() -	rn.openWriteOnlyLock.RLock() -	defer rn.openWriteOnlyLock.RUnlock() - -	if rn.args.KernelCache { -		fuseFlags = fuse.FOPEN_KEEP_CACHE -	} - -	// Open backing file -	fd, err := syscallcompat.Openat(dirfd, cName, newFlags, 0) -	// Handle a few specific errors -	if err != nil { -		if err == syscall.EMFILE { -			var lim syscall.Rlimit -			syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim) -			tlog.Warn.Printf("Open %q: too many open files. Current \"ulimit -n\": %d", cName, lim.Cur) -		} -		if err == syscall.EACCES && (int(flags)&syscall.O_ACCMODE) == syscall.O_WRONLY { -			fd, err = rn.openWriteOnlyFile(dirfd, cName, newFlags) -		} -	} -	// Could not handle the error? Bail out -	if err != nil { -		errno = fs.ToErrno(err) -		return -	} - -	var st syscall.Stat_t -	err = syscall.Fstat(fd, &st) -	if err != nil { -		errno = fs.ToErrno(err) -		return -	} -	f := os.NewFile(uintptr(fd), cName) -	fh = NewFile(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) {  	// Use the fd if the kernel gave us one diff --git a/internal/fusefrontend/node_open_create.go b/internal/fusefrontend/node_open_create.go new file mode 100644 index 0000000..8b31932 --- /dev/null +++ b/internal/fusefrontend/node_open_create.go @@ -0,0 +1,108 @@ +package fusefrontend + +import ( +	"context" +	"syscall" + +	"github.com/hanwen/go-fuse/v2/fs" +	"github.com/hanwen/go-fuse/v2/fuse" + +	"github.com/rfjakob/gocryptfs/internal/nametransform" +	"github.com/rfjakob/gocryptfs/internal/syscallcompat" +	"github.com/rfjakob/gocryptfs/internal/tlog" +) + +// Open - FUSE call. Open already-existing file. +// +// Symlink-safe through Openat(). +func (n *Node) Open(ctx context.Context, flags uint32) (fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) { +	dirfd, cName, errno := n.prepareAtSyscall("") +	if errno != 0 { +		return +	} +	defer syscall.Close(dirfd) + +	rn := n.rootNode() +	newFlags := rn.mangleOpenFlags(flags) +	// Taking this lock makes sure we don't race openWriteOnlyFile() +	rn.openWriteOnlyLock.RLock() +	defer rn.openWriteOnlyLock.RUnlock() + +	if rn.args.KernelCache { +		fuseFlags = fuse.FOPEN_KEEP_CACHE +	} + +	// Open backing file +	fd, err := syscallcompat.Openat(dirfd, cName, newFlags, 0) +	// Handle a few specific errors +	if err != nil { +		if err == syscall.EMFILE { +			var lim syscall.Rlimit +			syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim) +			tlog.Warn.Printf("Open %q: too many open files. Current \"ulimit -n\": %d", cName, lim.Cur) +		} +		if err == syscall.EACCES && (int(flags)&syscall.O_ACCMODE) == syscall.O_WRONLY { +			fd, err = rn.openWriteOnlyFile(dirfd, cName, newFlags) +		} +	} +	// Could not handle the error? Bail out +	if err != nil { +		errno = fs.ToErrno(err) +		return +	} +	fh, _, errno = NewFile(fd, cName, rn) +	return fh, fuseFlags, errno +} + +// Create - FUSE call. Creates a new file. +// +// Symlink-safe through the use of Openat(). +func (n *Node) Create(ctx context.Context, name string, flags uint32, mode uint32, out *fuse.EntryOut) (inode *fs.Inode, fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) { +	dirfd, cName, errno := n.prepareAtSyscall(name) +	if errno != 0 { +		return +	} +	defer syscall.Close(dirfd) + +	var err error +	fd := -1 +	// Make sure context is nil if we don't want to preserve the owner +	rn := n.rootNode() +	if !rn.args.PreserveOwner { +		ctx = nil +	} +	newFlags := rn.mangleOpenFlags(flags) +	// Handle long file name +	ctx2 := toFuseCtx(ctx) +	if !rn.args.PlaintextNames && nametransform.IsLongContent(cName) { +		// Create ".name" +		err = rn.nameTransform.WriteLongNameAt(dirfd, cName, name) +		if err != nil { +			return nil, nil, 0, fs.ToErrno(err) +		} +		// Create content +		fd, err = syscallcompat.OpenatUser(dirfd, cName, newFlags|syscall.O_CREAT|syscall.O_EXCL, mode, ctx2) +		if err != nil { +			nametransform.DeleteLongNameAt(dirfd, cName) +		} +	} else { +		// Create content, normal (short) file name +		fd, err = syscallcompat.OpenatUser(dirfd, cName, newFlags|syscall.O_CREAT|syscall.O_EXCL, mode, ctx2) +	} +	if err != nil { +		// xfstests generic/488 triggers this +		if err == syscall.EMFILE { +			var lim syscall.Rlimit +			syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim) +			tlog.Warn.Printf("Create %q: too many open files. Current \"ulimit -n\": %d", cName, lim.Cur) +		} +		return nil, nil, 0, fs.ToErrno(err) +	} + +	fh, st, errno := NewFile(fd, cName, rn) +	if errno != 0 { +		return +	} +	inode = n.newChild(ctx, st, out) +	return inode, fh, fuseFlags, errno +} | 
