aboutsummaryrefslogtreecommitdiffhomepage
path: root/system/tmpfiles.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-02-17 19:00:43 +0900
committerOphestra <cat@gensokyo.uk>2025-02-17 19:00:43 +0900
commit90cb01b2748550228d0bc179691a19ebb996fc36 (patch)
tree06a2e17b578312c3f0734bf4c476e3c2eb5f6908 /system/tmpfiles.go
parentb1e1d5627e6532ec719c761846d7f38fe93fcadd (diff)
system: move out of internal
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'system/tmpfiles.go')
-rw-r--r--system/tmpfiles.go76
1 files changed, 76 insertions, 0 deletions
diff --git a/system/tmpfiles.go b/system/tmpfiles.go
new file mode 100644
index 00000000..636943bc
--- /dev/null
+++ b/system/tmpfiles.go
@@ -0,0 +1,76 @@
+package system
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "syscall"
+)
+
+// CopyFile registers an Op that copies from src.
+// A buffer is initialised with size cap and the Op faults if bytes read exceed n.
+func (sys *I) CopyFile(payload *[]byte, src string, cap int, n int64) *I {
+ buf := new(bytes.Buffer)
+ buf.Grow(cap)
+
+ sys.lock.Lock()
+ sys.ops = append(sys.ops, &Tmpfile{payload, src, n, buf})
+ sys.lock.Unlock()
+
+ return sys
+}
+
+type Tmpfile struct {
+ payload *[]byte
+ src string
+
+ n int64
+ buf *bytes.Buffer
+}
+
+func (t *Tmpfile) Type() Enablement { return Process }
+func (t *Tmpfile) apply(sys *I) error {
+ sys.println("copying", t)
+
+ if t.payload == nil {
+ // this is a misuse of the API; do not return an error message
+ return errors.New("invalid payload")
+ }
+
+ if b, err := os.Stat(t.src); err != nil {
+ return sys.wrapErrSuffix(err,
+ fmt.Sprintf("cannot stat %q:", t.src))
+ } else {
+ if b.IsDir() {
+ return sys.wrapErrSuffix(syscall.EISDIR,
+ fmt.Sprintf("%q is a directory", t.src))
+ }
+ if s := b.Size(); s > t.n {
+ return sys.wrapErrSuffix(syscall.ENOMEM,
+ fmt.Sprintf("file %q is too long: %d > %d",
+ t.src, s, t.n))
+ }
+ }
+
+ if f, err := os.Open(t.src); err != nil {
+ return sys.wrapErrSuffix(err,
+ fmt.Sprintf("cannot open %q:", t.src))
+ } else if _, err = io.CopyN(t.buf, f, t.n); err != nil {
+ return sys.wrapErrSuffix(err,
+ fmt.Sprintf("cannot read from %q:", t.src))
+ }
+
+ *t.payload = t.buf.Bytes()
+ return nil
+}
+func (t *Tmpfile) revert(*I, *Criteria) error { t.buf.Reset(); return nil }
+
+func (t *Tmpfile) Is(o Op) bool {
+ t0, ok := o.(*Tmpfile)
+ return ok && t0 != nil &&
+ t.src == t0.src && t.n == t0.n
+}
+func (t *Tmpfile) Path() string { return t.src }
+func (t *Tmpfile) String() string { return fmt.Sprintf("up to %d bytes from %q", t.n, t.src) }