aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/system/link.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/system/link.go')
-rw-r--r--internal/system/link.go50
1 files changed, 50 insertions, 0 deletions
diff --git a/internal/system/link.go b/internal/system/link.go
new file mode 100644
index 00000000..a13adaae
--- /dev/null
+++ b/internal/system/link.go
@@ -0,0 +1,50 @@
+package system
+
+import (
+ "fmt"
+
+ "hakurei.app/container/check"
+ "hakurei.app/hst"
+)
+
+// Link calls LinkFileType with the [Process] criteria.
+func (sys *I) Link(oldname, newname *check.Absolute) *I {
+ return sys.LinkFileType(Process, oldname, newname)
+}
+
+// LinkFileType maintains a hardlink until its [Enablement] is no longer satisfied.
+func (sys *I) LinkFileType(et hst.Enablement, oldname, newname *check.Absolute) *I {
+ sys.ops = append(sys.ops, &hardlinkOp{et, newname.String(), oldname.String()})
+ return sys
+}
+
+// hardlinkOp implements [I.LinkFileType].
+type hardlinkOp struct {
+ et hst.Enablement
+ dst, src string
+}
+
+func (l *hardlinkOp) Type() hst.Enablement { return l.et }
+
+func (l *hardlinkOp) apply(sys *I) error {
+ sys.msg.Verbose("linking", l)
+ return newOpError("hardlink", sys.link(l.src, l.dst), false)
+}
+
+func (l *hardlinkOp) revert(sys *I, ec *Criteria) error {
+ if ec.hasType(l.Type()) {
+ sys.msg.Verbosef("removing hard link %q", l.dst)
+ return newOpError("hardlink", sys.remove(l.dst), true)
+ } else {
+ sys.msg.Verbosef("skipping hard link %q", l.dst)
+ return nil
+ }
+}
+
+func (l *hardlinkOp) Is(o Op) bool {
+ target, ok := o.(*hardlinkOp)
+ return ok && l != nil && target != nil && *l == *target
+}
+
+func (l *hardlinkOp) Path() string { return l.src }
+func (l *hardlinkOp) String() string { return fmt.Sprintf("%q from %q", l.dst, l.src) }