summaryrefslogtreecommitdiff
path: root/internal/fusefrontend/node.go
diff options
context:
space:
mode:
authorJakob Unterwurzacher2020-06-21 13:25:12 +0200
committerJakob Unterwurzacher2020-06-21 13:25:12 +0200
commitf6ded09e36a679695354f4b9bc74242ef399be09 (patch)
tree4ed4c3986682a3b342152e3693dee8ba707dc276 /internal/fusefrontend/node.go
parent74a4accf0cc1fd3265abd8fa53b0721cd72c2158 (diff)
v2api: implement Create
Diffstat (limited to 'internal/fusefrontend/node.go')
-rw-r--r--internal/fusefrontend/node.go71
1 files changed, 71 insertions, 0 deletions
diff --git a/internal/fusefrontend/node.go b/internal/fusefrontend/node.go
index 9074f72..28e606a 100644
--- a/internal/fusefrontend/node.go
+++ b/internal/fusefrontend/node.go
@@ -2,6 +2,7 @@ package fusefrontend
import (
"context"
+ "os"
"path/filepath"
"syscall"
@@ -10,7 +11,9 @@ import (
"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"
)
// Node is a file or directory in the filesystem tree
@@ -31,6 +34,9 @@ func (n *Node) rootNode() *RootNode {
func (n *Node) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*fs.Inode, syscall.Errno) {
rn := n.rootNode()
p := filepath.Join(n.path(), name)
+ if rn.isFiltered(p) {
+ return nil, syscall.EPERM
+ }
dirfd, cName, err := rn.openBackingDir(p)
if err != nil {
return nil, fs.ToErrno(err)
@@ -71,3 +77,68 @@ func (n *Node) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut)
out.Attr.FromStat(st)
return 0
}
+
+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) {
+ rn := n.rootNode()
+ path := filepath.Join(n.path(), name)
+ if rn.isFiltered(path) {
+ return nil, nil, 0, syscall.EPERM
+ }
+ dirfd, cName, err := rn.openBackingDir(path)
+ if err != nil {
+ return nil, nil, 0, fs.ToErrno(err)
+ }
+ defer syscall.Close(dirfd)
+
+ fd := -1
+ // Make sure context is nil if we don't want to preserve the owner
+ if !rn.args.PreserveOwner {
+ ctx = nil
+ }
+ newFlags := rn.mangleOpenFlags(flags)
+ // Handle long file name
+ if !rn.args.PlaintextNames && nametransform.IsLongContent(cName) {
+ // Create ".name"
+ err = rn.nameTransform.WriteLongNameAt(dirfd, cName, path)
+ if err != nil {
+ return nil, nil, 0, fs.ToErrno(err)
+ }
+ // Create content
+ fd, err = syscallcompat.OpenatUserCtx(dirfd, cName, newFlags|syscall.O_CREAT|syscall.O_EXCL, mode, ctx)
+ if err != nil {
+ nametransform.DeleteLongNameAt(dirfd, cName)
+ }
+ } else {
+ // Create content, normal (short) file name
+ fd, err = syscallcompat.OpenatUserCtx(dirfd, cName, newFlags|syscall.O_CREAT|syscall.O_EXCL, mode, ctx)
+ }
+ 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`
+ st, err := syscallcompat.Fstatat2(dirfd, cName, unix.AT_SYMLINK_NOFOLLOW)
+ if err != nil {
+ return nil, nil, 0, fs.ToErrno(err)
+ }
+ // Get unique inode number
+ rn.inoMap.TranslateStat(st)
+ out.Attr.FromStat(st)
+ // Create child node
+ id := fs.StableAttr{
+ Mode: uint32(st.Mode),
+ Gen: 1,
+ Ino: st.Ino,
+ }
+ node := &Node{}
+ ch := n.NewInode(ctx, node, id)
+
+ f := os.NewFile(uintptr(fd), cName)
+ return ch, NewFile2(f, rn, st), 0, 0
+}