All checks were successful
Test / Create distribution (push) Successful in 58s
Test / Sandbox (push) Successful in 2m34s
Test / Hakurei (push) Successful in 3m40s
Test / ShareFS (push) Successful in 3m49s
Test / Sandbox (race detector) (push) Successful in 4m55s
Test / Hakurei (race detector) (push) Successful in 5m54s
Test / Flake checks (push) Successful in 1m29s
No operation require further filesystem interaction for now. Signed-off-by: Ophestra <cat@gensokyo.uk>
236 lines
5.1 KiB
Go
236 lines
5.1 KiB
Go
package rosa
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"runtime"
|
|
"runtime/debug"
|
|
"strconv"
|
|
"sync"
|
|
"syscall"
|
|
"unique"
|
|
"unsafe"
|
|
|
|
"hakurei.app/internal/pkg"
|
|
"hakurei.app/message"
|
|
)
|
|
|
|
// wordSize is the boundary which binary segments are always aligned to.
|
|
const wordSize = 8
|
|
|
|
// padSize returns the padding size for aligning sz.
|
|
func padSize[T int | int64](sz T) T {
|
|
return (wordSize - (sz)%wordSize) % wordSize
|
|
}
|
|
|
|
// WriteReport writes a report of all available [PArtifact] to w.
|
|
func WriteReport(msg message.Msg, w io.Writer, c *pkg.Cache) error {
|
|
var (
|
|
zero [wordSize]byte
|
|
buf [len(pkg.ID{}) + wordSize]byte
|
|
)
|
|
for i := range PresetEnd {
|
|
a := Std.Load(PArtifact(i))
|
|
if _, ok := a.(pkg.FileArtifact); ok {
|
|
msg.Verbosef("skipping file artifact %s", artifactsM[i].Name)
|
|
continue
|
|
}
|
|
|
|
id := c.Ident(a)
|
|
|
|
var f *os.File
|
|
if r, err := c.OpenStatus(a); err != nil {
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
msg.Verbosef("artifact %s unavailable", artifactsM[i].Name)
|
|
continue
|
|
}
|
|
return err
|
|
} else {
|
|
f = r.(*os.File)
|
|
}
|
|
|
|
msg.Verbosef("writing artifact %s...", artifactsM[i].Name)
|
|
|
|
var sz int64
|
|
if fi, err := f.Stat(); err != nil {
|
|
_ = f.Close()
|
|
return err
|
|
} else {
|
|
sz = fi.Size()
|
|
}
|
|
|
|
*(*pkg.ID)(buf[:]) = id.Value()
|
|
binary.LittleEndian.PutUint64(buf[len(pkg.ID{}):], uint64(sz))
|
|
if _, err := w.Write(buf[:]); err != nil {
|
|
_ = f.Close()
|
|
return err
|
|
}
|
|
|
|
if n, err := io.Copy(w, f); err != nil {
|
|
_ = f.Close()
|
|
return err
|
|
} else if n != sz {
|
|
_ = f.Close()
|
|
return fmt.Errorf("strange status file copy: %d != %d", n, sz)
|
|
} else if err = f.Close(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if psz := padSize(sz); psz > 0 {
|
|
if _, err := w.Write(zero[:psz]); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// existence of status implies cured artifact
|
|
var n int
|
|
if pathname, _, err := c.Cure(a); err != nil {
|
|
return err
|
|
} else if n, err = pkg.Flatten(
|
|
os.DirFS(pathname.String()), ".",
|
|
io.Discard,
|
|
); err != nil {
|
|
return err
|
|
}
|
|
binary.LittleEndian.PutUint64(buf[:], uint64(n))
|
|
if _, err := w.Write(buf[:wordSize]); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Report provides efficient access to a report file populated by [WriteReport].
|
|
type Report struct {
|
|
// Slice backed by the underlying file.
|
|
//
|
|
// Access must be prepared by HandleAccess.
|
|
data []byte
|
|
|
|
// Offsets into data for each identifier.
|
|
offsets map[unique.Handle[pkg.ID]]int
|
|
|
|
// Outcome of a call to Close.
|
|
closeErr error
|
|
// Synchronises calls to Close.
|
|
closeOnce sync.Once
|
|
}
|
|
|
|
// OpenReport opens a file populated by [WriteReport]
|
|
func OpenReport(pathname string) (rp *Report, err error) {
|
|
var f *os.File
|
|
if f, err = os.Open(pathname); err != nil {
|
|
return
|
|
}
|
|
|
|
var fi os.FileInfo
|
|
if fi, err = f.Stat(); err != nil {
|
|
_ = f.Close()
|
|
return
|
|
}
|
|
|
|
var r Report
|
|
if r.data, err = syscall.Mmap(
|
|
int(f.Fd()),
|
|
0,
|
|
int(fi.Size()),
|
|
syscall.PROT_READ,
|
|
syscall.MAP_PRIVATE,
|
|
); err != nil {
|
|
_ = f.Close()
|
|
return
|
|
}
|
|
|
|
if err = f.Close(); err != nil {
|
|
_ = r.Close()
|
|
return
|
|
}
|
|
|
|
defer r.HandleAccess(&err)()
|
|
|
|
var offset int
|
|
r.offsets = make(map[unique.Handle[pkg.ID]]int)
|
|
for offset < len(r.data) {
|
|
id := unique.Make((pkg.ID)(r.data[offset:]))
|
|
offset += len(pkg.ID{})
|
|
r.offsets[id] = offset
|
|
offset += int(binary.LittleEndian.Uint64(r.data[offset:])) + wordSize
|
|
offset += padSize(offset)
|
|
offset += wordSize
|
|
}
|
|
return &r, nil
|
|
}
|
|
|
|
// ReportIOError describes an I/O error while accessing a [Report].
|
|
type ReportIOError struct {
|
|
Offset int
|
|
Err error
|
|
}
|
|
|
|
// Unwrap returns the underlying runtime error.
|
|
func (e *ReportIOError) Unwrap() error { return e.Err }
|
|
|
|
// Error returns a description of the error offset.
|
|
func (e *ReportIOError) Error() string {
|
|
return "report I/O error at offset " + strconv.Itoa(e.Offset)
|
|
}
|
|
|
|
// HandleAccess prepares for accessing memory returned by a method of [Report]
|
|
// and returns a function that must be deferred by the caller.
|
|
func (r *Report) HandleAccess(errP *error) func() {
|
|
pof := debug.SetPanicOnFault(true)
|
|
return func() {
|
|
debug.SetPanicOnFault(pof)
|
|
|
|
v := recover()
|
|
if v == nil {
|
|
return
|
|
}
|
|
|
|
if err, ok := v.(error); !ok {
|
|
panic(v)
|
|
} else if *errP != nil {
|
|
return
|
|
} else {
|
|
*errP = err
|
|
}
|
|
|
|
var runtimeError interface {
|
|
Addr() uintptr
|
|
runtime.Error
|
|
}
|
|
if errors.As(*errP, &runtimeError) {
|
|
offset := int(runtimeError.Addr() - uintptr(unsafe.Pointer(unsafe.SliceData(r.data))))
|
|
// best effort for fragile uintptr
|
|
if offset >= 0 {
|
|
*errP = &ReportIOError{offset, *errP}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ArtifactOf returns information of a [pkg.Artifact] corresponding to id.
|
|
func (r *Report) ArtifactOf(id unique.Handle[pkg.ID]) (status []byte, n int64) {
|
|
if offset, ok := r.offsets[id]; !ok {
|
|
n = -1
|
|
} else {
|
|
sz := int(binary.LittleEndian.Uint64(r.data[offset:]))
|
|
offset += wordSize
|
|
|
|
status = r.data[offset : offset+sz]
|
|
offset += sz + padSize(sz)
|
|
|
|
n = int64(binary.LittleEndian.Uint64(r.data[offset:]))
|
|
}
|
|
return
|
|
}
|
|
|
|
// Close closes the underlying file and releases all associated resources.
|
|
func (r *Report) Close() error {
|
|
r.closeOnce.Do(func() { r.closeErr = syscall.Munmap(r.data) })
|
|
return r.closeErr
|
|
}
|