fusefronted: move Create() and Open() to new file
And deduplicate the code a little.
This commit is contained in:
parent
47a4d33f24
commit
3b9a1b628b
@ -53,18 +53,31 @@ type File struct {
|
|||||||
rootNode *RootNode
|
rootNode *RootNode
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFile returns a new go-fuse File instance.
|
// NewFile returns a new go-fuse File instance based on an already-open file
|
||||||
func NewFile(fd *os.File, rn *RootNode, st *syscall.Stat_t) *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)
|
qi := inomap.QInoFromStat(st)
|
||||||
e := openfiletable.Register(qi)
|
e := openfiletable.Register(qi)
|
||||||
|
|
||||||
return &File{
|
osFile := os.NewFile(uintptr(fd), cName)
|
||||||
fd: fd,
|
|
||||||
|
f = &File{
|
||||||
|
fd: osFile,
|
||||||
contentEnc: rn.contentEnc,
|
contentEnc: rn.contentEnc,
|
||||||
qIno: qi,
|
qIno: qi,
|
||||||
fileTableEntry: e,
|
fileTableEntry: e,
|
||||||
rootNode: rn,
|
rootNode: rn,
|
||||||
}
|
}
|
||||||
|
return f, st, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// intFd - return the backing file descriptor as an integer.
|
// intFd - return the backing file descriptor as an integer.
|
||||||
|
@ -2,7 +2,6 @@ package fusefrontend
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"os"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
@ -78,69 +77,6 @@ func (n *Node) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut)
|
|||||||
return 0
|
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.
|
// Unlink - FUSE call. Delete a file.
|
||||||
//
|
//
|
||||||
// Symlink-safe through use of Unlinkat().
|
// 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)
|
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, ...
|
// 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) {
|
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
|
// Use the fd if the kernel gave us one
|
||||||
|
108
internal/fusefrontend/node_open_create.go
Normal file
108
internal/fusefrontend/node_open_create.go
Normal file
@ -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
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user