diff options
| author | Ophestra <cat@gensokyo.uk> | 2026-10-13 22:58:19 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2026-10-13 22:58:19 +0900 |
| commit | fadb42ec8daeeb8a576582d274cd4aeb64e535c0 (patch) | |
| tree | 20db92adde637b3d1bc7a931d0551590e80456cf /internal/system/mkdir.go | |
| parent | 40e4c9031652731622315e778a9bcace6cea6cb3 (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.go | 40 |
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 } |
