aboutsummaryrefslogtreecommitdiff
path: root/internal/fusefrontend/node_dir_ops.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/fusefrontend/node_dir_ops.go')
-rw-r--r--internal/fusefrontend/node_dir_ops.go94
1 files changed, 52 insertions, 42 deletions
diff --git a/internal/fusefrontend/node_dir_ops.go b/internal/fusefrontend/node_dir_ops.go
index 5cf58ea..8cc158d 100644
--- a/internal/fusefrontend/node_dir_ops.go
+++ b/internal/fusefrontend/node_dir_ops.go
@@ -68,66 +68,76 @@ func (n *Node) Mkdir(ctx context.Context, name string, mode uint32, out *fuse.En
if rn.args.PreserveOwner {
caller, _ = fuse.FromContext(ctx)
}
- if rn.args.PlaintextNames {
- err = syscallcompat.MkdiratUser(dirfd, cName, mode, caller)
- return nil, fs.ToErrno(err)
- }
- // We need write and execute permissions to create gocryptfs.diriv.
- // Also, we need read permissions to open the directory (to avoid
- // race-conditions between getting and setting the mode).
- origMode := mode
- mode = mode | 0700
+ var st syscall.Stat_t
- // Handle long file name
- if nametransform.IsLongContent(cName) {
- // Create ".name"
- err = rn.nameTransform.WriteLongNameAt(dirfd, cName, newPath)
+ if rn.args.PlaintextNames {
+ err = syscallcompat.MkdiratUser(dirfd, cName, mode, caller)
if err != nil {
return nil, fs.ToErrno(err)
}
-
- // Create directory
- err = rn.mkdirWithIv(dirfd, cName, mode, caller)
+ var ust unix.Stat_t
+ err = syscallcompat.Fstatat(dirfd, cName, &ust, unix.AT_SYMLINK_NOFOLLOW)
if err != nil {
- nametransform.DeleteLongNameAt(dirfd, cName)
return nil, fs.ToErrno(err)
}
+ st = syscallcompat.Unix2syscall(ust)
} else {
- err = rn.mkdirWithIv(dirfd, cName, mode, caller)
+ // We need write and execute permissions to create gocryptfs.diriv.
+ // Also, we need read permissions to open the directory (to avoid
+ // race-conditions between getting and setting the mode).
+ origMode := mode
+ mode = mode | 0700
+
+ // Handle long file name
+ if nametransform.IsLongContent(cName) {
+ // Create ".name"
+ err = rn.nameTransform.WriteLongNameAt(dirfd, cName, newPath)
+ if err != nil {
+ return nil, fs.ToErrno(err)
+ }
+
+ // Create directory
+ err = rn.mkdirWithIv(dirfd, cName, mode, caller)
+ if err != nil {
+ nametransform.DeleteLongNameAt(dirfd, cName)
+ return nil, fs.ToErrno(err)
+ }
+ } else {
+ err = rn.mkdirWithIv(dirfd, cName, mode, caller)
+ if err != nil {
+ return nil, fs.ToErrno(err)
+ }
+ }
+
+ fd, err := syscallcompat.Openat(dirfd, cName,
+ syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0)
if err != nil {
+ tlog.Warn.Printf("Mkdir %q: Openat failed: %v", cName, err)
return nil, fs.ToErrno(err)
}
- }
+ defer syscall.Close(fd)
- fd, err := syscallcompat.Openat(dirfd, cName,
- syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0)
- if err != nil {
- tlog.Warn.Printf("Mkdir %q: Openat failed: %v", cName, err)
- return nil, fs.ToErrno(err)
- }
- defer syscall.Close(fd)
+ err = syscall.Fstat(fd, &st)
+ if err != nil {
+ tlog.Warn.Printf("Mkdir %q: Fstat failed: %v", cName, err)
+ return nil, fs.ToErrno(err)
+ }
- // Get unique inode number
- var st syscall.Stat_t
- err = syscall.Fstat(fd, &st)
- if err != nil {
- tlog.Warn.Printf("Mkdir %q: Fstat failed: %v", cName, err)
- return nil, fs.ToErrno(err)
+ // Fix permissions
+ if origMode != mode {
+ // Preserve SGID bit if it was set due to inheritance.
+ origMode = uint32(st.Mode&^0777) | origMode
+ err = syscall.Fchmod(fd, origMode)
+ if err != nil {
+ tlog.Warn.Printf("Mkdir %q: Fchmod %#o -> %#o failed: %v", cName, mode, origMode, err)
+ }
+ }
}
+
// Create child node
ch := n.newChild(ctx, &st, out)
- // Set mode
- if origMode != mode {
- // Preserve SGID bit if it was set due to inheritance.
- origMode = uint32(st.Mode&^0777) | origMode
- err = syscall.Fchmod(fd, origMode)
- if err != nil {
- tlog.Warn.Printf("Mkdir %q: Fchmod %#o -> %#o failed: %v", cName, mode, origMode, err)
- }
- }
-
return ch, 0
}