aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/system/acl.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/system/acl.go')
-rw-r--r--internal/system/acl.go69
1 files changed, 69 insertions, 0 deletions
diff --git a/internal/system/acl.go b/internal/system/acl.go
new file mode 100644
index 00000000..854e812b
--- /dev/null
+++ b/internal/system/acl.go
@@ -0,0 +1,69 @@
+package system
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "slices"
+
+ "hakurei.app/container/check"
+ "hakurei.app/hst"
+ "hakurei.app/internal/system/acl"
+)
+
+// UpdatePerm calls UpdatePermType with the [Process] criteria.
+func (sys *I) UpdatePerm(path *check.Absolute, perms ...acl.Perm) *I {
+ sys.UpdatePermType(Process, path, perms...)
+ return sys
+}
+
+// UpdatePermType maintains [acl.Perms] on a file until its [Enablement] is no longer satisfied.
+func (sys *I) UpdatePermType(et hst.Enablement, path *check.Absolute, perms ...acl.Perm) *I {
+ sys.ops = append(sys.ops, &aclUpdateOp{et, path.String(), perms})
+ return sys
+}
+
+// aclUpdateOp implements [I.UpdatePermType].
+type aclUpdateOp struct {
+ et hst.Enablement
+ path string
+ perms acl.Perms
+}
+
+func (a *aclUpdateOp) Type() hst.Enablement { return a.et }
+
+func (a *aclUpdateOp) apply(sys *I) error {
+ sys.msg.Verbose("applying ACL", a)
+ return newOpError("acl", sys.aclUpdate(a.path, sys.uid, a.perms...), false)
+}
+
+func (a *aclUpdateOp) revert(sys *I, ec *Criteria) error {
+ if ec.hasType(a.Type()) {
+ sys.msg.Verbose("stripping ACL", a)
+ err := sys.aclUpdate(a.path, sys.uid)
+ if errors.Is(err, os.ErrNotExist) {
+ // the ACL is effectively stripped if the file no longer exists
+ sys.msg.Verbosef("target of ACL %s no longer exists", a)
+ err = nil
+ }
+ return newOpError("acl", err, true)
+ } else {
+ sys.msg.Verbose("skipping ACL", a)
+ return nil
+ }
+}
+
+func (a *aclUpdateOp) Is(o Op) bool {
+ target, ok := o.(*aclUpdateOp)
+ return ok && a != nil && target != nil &&
+ a.et == target.et &&
+ a.path == target.path &&
+ slices.Equal(a.perms, target.perms)
+}
+
+func (a *aclUpdateOp) Path() string { return a.path }
+
+func (a *aclUpdateOp) String() string {
+ return fmt.Sprintf("%s type: %s path: %q",
+ a.perms, TypeString(a.et), a.path)
+}