diff options
| -rw-r--r-- | internal/fusefrontend/node.go | 76 | ||||
| -rw-r--r-- | internal/fusefrontend/node_api_check.go | 2 | ||||
| -rw-r--r-- | internal/fusefrontend/node_dir_ops.go | 10 | ||||
| -rw-r--r-- | internal/syscallcompat/sys_linux.go | 14 | 
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 { | 
