aboutsummaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/fusefrontend/file.go21
-rw-r--r--internal/fusefrontend/node.go114
-rw-r--r--internal/fusefrontend/node_open_create.go108
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
+}