aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/fusefrontend/node.go76
-rw-r--r--internal/fusefrontend/node_api_check.go2
-rw-r--r--internal/fusefrontend/node_dir_ops.go10
-rw-r--r--internal/syscallcompat/sys_linux.go14
4 files changed, 81 insertions, 21 deletions
diff --git a/internal/fusefrontend/node.go b/internal/fusefrontend/node.go
index bdc30b3..c4a80dd 100644
--- a/internal/fusefrontend/node.go
+++ b/internal/fusefrontend/node.go
@@ -102,6 +102,23 @@ func (n *Node) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut)
return 0
}
+// newChild attaches a new child inode to n.
+// The passed-in `st` will be modified to get a unique inode number.
+func (n *Node) newChild(ctx context.Context, st *syscall.Stat_t, out *fuse.EntryOut) *fs.Inode {
+ // Get unique inode number
+ rn := n.rootNode()
+ 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{}
+ return n.NewInode(ctx, node, id)
+}
+
// Create - FUSE call. Creates a new file.
//
// Symlink-safe through the use of Openat().
@@ -153,17 +170,7 @@ func (n *Node) Create(ctx context.Context, name string, flags uint32, mode uint3
errno = fs.ToErrno(err)
return
}
- // 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)
+ ch := n.newChild(ctx, &st, out)
f := os.NewFile(uintptr(fd), cName)
return ch, NewFile2(f, rn, &st), 0, 0
@@ -296,3 +303,50 @@ func (n *Node) Statfs(ctx context.Context, out *fuse.StatfsOut) syscall.Errno {
out.FromStatfsT(&st)
return 0
}
+
+// Mknod - FUSE call. Create a device file.
+//
+// Symlink-safe through use of Mknodat().
+func (n *Node) Mknod(ctx context.Context, name string, mode, rdev uint32, out *fuse.EntryOut) (inode *fs.Inode, errno syscall.Errno) {
+ dirfd, cName, errno := n.prepareAtSyscall("")
+ if errno != 0 {
+ return
+ }
+ defer syscall.Close(dirfd)
+
+ // Make sure context is nil if we don't want to preserve the owner
+ rn := n.rootNode()
+ if !rn.args.PreserveOwner {
+ ctx = nil
+ }
+
+ // Create ".name" file to store long file name (except in PlaintextNames mode)
+ var err error
+ if !rn.args.PlaintextNames && nametransform.IsLongContent(cName) {
+ err := rn.nameTransform.WriteLongNameAt(dirfd, cName, name)
+ if err != nil {
+ errno = fs.ToErrno(err)
+ return
+ }
+ // Create "gocryptfs.longfile." device node
+ err = syscallcompat.MknodatUserCtx(dirfd, cName, mode, int(rdev), ctx)
+ if err != nil {
+ nametransform.DeleteLongNameAt(dirfd, cName)
+ }
+ } else {
+ // Create regular device node
+ err = syscallcompat.MknodatUserCtx(dirfd, cName, mode, int(rdev), ctx)
+ }
+ if err != nil {
+ errno = fs.ToErrno(err)
+ return
+ }
+
+ st, err := syscallcompat.Fstatat2(dirfd, cName, unix.AT_SYMLINK_NOFOLLOW)
+ if err != nil {
+ errno = fs.ToErrno(err)
+ return
+ }
+ inode = n.newChild(ctx, st, out)
+ return inode, 0
+}
diff --git a/internal/fusefrontend/node_api_check.go b/internal/fusefrontend/node_api_check.go
index 384badc..d99564f 100644
--- a/internal/fusefrontend/node_api_check.go
+++ b/internal/fusefrontend/node_api_check.go
@@ -17,6 +17,7 @@ var _ = (fs.NodeOpener)((*Node)(nil))
var _ = (fs.NodeOpendirer)((*Node)(nil))
var _ = (fs.NodeSetattrer)((*Node)(nil))
var _ = (fs.NodeStatfser)((*Node)(nil))
+var _ = (fs.NodeMknoder)((*Node)(nil))
/* TODO
var _ = (fs.NodeGetxattrer)((*Node)(nil))
@@ -24,7 +25,6 @@ var _ = (fs.NodeSetxattrer)((*Node)(nil))
var _ = (fs.NodeRemovexattrer)((*Node)(nil))
var _ = (fs.NodeListxattrer)((*Node)(nil))
var _ = (fs.NodeCopyFileRanger)((*Node)(nil))
-var _ = (fs.NodeMknoder)((*Node)(nil))
var _ = (fs.NodeLinker)((*Node)(nil))
var _ = (fs.NodeSymlinker)((*Node)(nil))
var _ = (fs.NodeRenamer)((*Node)(nil))
diff --git a/internal/fusefrontend/node_dir_ops.go b/internal/fusefrontend/node_dir_ops.go
index 32e5e86..df8f060 100644
--- a/internal/fusefrontend/node_dir_ops.go
+++ b/internal/fusefrontend/node_dir_ops.go
@@ -115,16 +115,8 @@ func (n *Node) Mkdir(ctx context.Context, name string, mode uint32, out *fuse.En
tlog.Warn.Printf("Mkdir %q: Fstat failed: %v", cName, err)
return nil, fs.ToErrno(err)
}
- 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)
+ ch := n.newChild(ctx, &st, out)
// Set mode
if origMode != mode {
diff --git a/internal/syscallcompat/sys_linux.go b/internal/syscallcompat/sys_linux.go
index c82480e..5a23084 100644
--- a/internal/syscallcompat/sys_linux.go
+++ b/internal/syscallcompat/sys_linux.go
@@ -136,6 +136,20 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
return syscall.Mknodat(dirfd, path, mode, dev)
}
+// MknodatUserCtx is a tries to extract a fuse.Context from the generic ctx and
+// calls OpenatUser.
+func MknodatUserCtx(dirfd int, path string, mode uint32, dev int, ctx context.Context) (err error) {
+ var ctx2 *fuse.Context
+ if ctx != nil {
+ if caller, ok := fuse.FromContext(ctx); ok {
+ ctx2 = &fuse.Context{
+ Caller: *caller,
+ }
+ }
+ }
+ return MknodatUser(dirfd, path, mode, dev, ctx2)
+}
+
// MknodatUser runs the Mknodat syscall in the context of a different user.
func MknodatUser(dirfd int, path string, mode uint32, dev int, context *fuse.Context) (err error) {
if context != nil {