diff options
Diffstat (limited to 'internal/fusefrontend/node.go')
-rw-r--r-- | internal/fusefrontend/node.go | 71 |
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 +} |