aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/system/mkdir.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-10-13 22:58:19 +0900
committerOphestra <cat@gensokyo.uk>2026-10-13 22:58:19 +0900
commitfadb42ec8daeeb8a576582d274cd4aeb64e535c0 (patch)
tree20db92adde637b3d1bc7a931d0551590e80456cf /internal/system/mkdir.go
parent40e4c9031652731622315e778a9bcace6cea6cb3 (diff)
internal/system: skip superfluous chmod
A successful chmod clobbers acl mask, breaking the fast path. This change also fixes the ACL race. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/system/mkdir.go')
-rw-r--r--internal/system/mkdir.go40
1 files changed, 31 insertions, 9 deletions
diff --git a/internal/system/mkdir.go b/internal/system/mkdir.go
index 81b89d58..ecbfc876 100644
--- a/internal/system/mkdir.go
+++ b/internal/system/mkdir.go
@@ -4,21 +4,33 @@ import (
"errors"
"fmt"
"os"
+ "syscall"
"hakurei.app/check"
"hakurei.app/hst"
)
// Ensure ensures the existence of a directory.
-func (sys *I) Ensure(name *check.Absolute, perm os.FileMode) *I {
- sys.ops = append(sys.ops, &mkdirOp{User, name.String(), perm, false})
+func (sys *I) Ensure(name *check.Absolute, perm os.FileMode, skipChmod bool) *I {
+ sys.ops = append(sys.ops, &mkdirOp{
+ et: User,
+ path: name.String(),
+ perm: perm,
+ skipChmod: skipChmod,
+ })
return sys
}
// Ephemeral ensures the existence of a directory until its [hst.Enablements] is
// no longer satisfied.
-func (sys *I) Ephemeral(et hst.Enablements, name *check.Absolute, perm os.FileMode) *I {
- sys.ops = append(sys.ops, &mkdirOp{et, name.String(), perm, true})
+func (sys *I) Ephemeral(et hst.Enablements, name *check.Absolute, perm os.FileMode, skipChmod bool) *I {
+ sys.ops = append(sys.ops, &mkdirOp{
+ et: et,
+ path: name.String(),
+ perm: perm,
+ ephemeral: true,
+ skipChmod: skipChmod,
+ })
return sys
}
@@ -28,6 +40,7 @@ type mkdirOp struct {
path string
perm os.FileMode
ephemeral bool
+ skipChmod bool
}
func (m *mkdirOp) Type() hst.Enablements { return m.et }
@@ -35,12 +48,21 @@ func (m *mkdirOp) Type() hst.Enablements { return m.et }
func (m *mkdirOp) apply(sys *I) error {
sys.msg.Verbose("ensuring directory", m)
- if err := sys.mkdir(m.path, m.perm); err != nil {
- if !errors.Is(err, os.ErrExist) {
- return newOpError("mkdir", err, false)
+ if fi, err := sys.stat(m.path); err == nil {
+ if !fi.IsDir() {
+ return newOpError("mkdir", syscall.ENOTDIR, false)
+ }
+ if !m.skipChmod && fi.Mode().Perm() != m.perm {
+ // directory exists, ensure mode
+ return newOpError("mkdir", sys.chmod(m.path, m.perm), false)
}
- // directory exists, ensure mode
- return newOpError("mkdir", sys.chmod(m.path, m.perm), false)
+ return nil
+ } else if !errors.Is(err, os.ErrNotExist) {
+ return newOpError("mkdir", err, false)
+ }
+
+ if err := sys.mkdir(m.path, m.perm); err != nil {
+ return newOpError("mkdir", err, false)
} else {
return nil
}