All checks were successful
		
		
	
	Test / Create distribution (push) Successful in 46s
				
			Test / Sandbox (push) Successful in 2m29s
				
			Test / Hakurei (push) Successful in 3m26s
				
			Test / Sandbox (race detector) (push) Successful in 4m15s
				
			Test / Hpkg (push) Successful in 4m14s
				
			Test / Hakurei (race detector) (push) Successful in 5m3s
				
			Test / Flake checks (push) Successful in 1m21s
				
			This header improves the robustness of the format and significantly reduces cleanup overhead. Signed-off-by: Ophestra <cat@gensokyo.uk>
		
			
				
	
	
		
			87 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			87 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package state
 | |
| 
 | |
| import (
 | |
| 	"encoding/hex"
 | |
| 	"errors"
 | |
| 	"io"
 | |
| 	"os"
 | |
| 	"strconv"
 | |
| 	"syscall"
 | |
| 
 | |
| 	"hakurei.app/hst"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	// entryHeaderMagic are magic bytes at the beginning of the state entry file.
 | |
| 	entryHeaderMagic = "\x00\xff\xca\xfe"
 | |
| 	// entryHeaderRevision follows entryHeaderMagic and is incremented for revisions of the format.
 | |
| 	entryHeaderRevision = "\x00\x00"
 | |
| 	// entryHeaderSize is the fixed size of the header in bytes, including the enablement byte and its complement.
 | |
| 	entryHeaderSize = len(entryHeaderMagic+entryHeaderRevision) + 2
 | |
| )
 | |
| 
 | |
| // entryHeaderEncode encodes a state entry header for a [hst.Enablement] byte.
 | |
| func entryHeaderEncode(et hst.Enablement) *[entryHeaderSize]byte {
 | |
| 	data := [entryHeaderSize]byte([]byte(
 | |
| 		entryHeaderMagic + entryHeaderRevision + string([]hst.Enablement{et, ^et}),
 | |
| 	))
 | |
| 	return &data
 | |
| }
 | |
| 
 | |
| // entryHeaderDecode validates a state entry header and returns the [hst.Enablement] byte.
 | |
| func entryHeaderDecode(data *[entryHeaderSize]byte) (hst.Enablement, error) {
 | |
| 	if magic := data[:len(entryHeaderMagic)]; string(magic) != entryHeaderMagic {
 | |
| 		return 0, errors.New("invalid header " + hex.EncodeToString(magic))
 | |
| 	}
 | |
| 	if revision := data[len(entryHeaderMagic):len(entryHeaderMagic+entryHeaderRevision)]; string(revision) != entryHeaderRevision {
 | |
| 		return 0, errors.New("unexpected revision " + hex.EncodeToString(revision))
 | |
| 	}
 | |
| 
 | |
| 	et := data[len(entryHeaderMagic+entryHeaderRevision)]
 | |
| 	if et != ^data[len(entryHeaderMagic+entryHeaderRevision)+1] {
 | |
| 		return 0, errors.New("header enablement value is inconsistent")
 | |
| 	}
 | |
| 	return hst.Enablement(et), nil
 | |
| }
 | |
| 
 | |
| // EntrySizeError is returned for a file too small to hold a state entry header.
 | |
| type EntrySizeError struct {
 | |
| 	Name string
 | |
| 	Size int64
 | |
| }
 | |
| 
 | |
| func (e *EntrySizeError) Error() string {
 | |
| 	if e.Name == "" {
 | |
| 		return "state entry file is too short"
 | |
| 	}
 | |
| 	return "state entry file " + strconv.Quote(e.Name) + " is too short"
 | |
| }
 | |
| 
 | |
| // entryCheckFile checks whether [os.FileInfo] refers to a file that might hold [hst.State].
 | |
| func entryCheckFile(fi os.FileInfo) error {
 | |
| 	if fi.IsDir() {
 | |
| 		return syscall.EISDIR
 | |
| 	}
 | |
| 	if s := fi.Size(); s <= int64(entryHeaderSize) {
 | |
| 		return &EntrySizeError{Name: fi.Name(), Size: s}
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // entryReadHeader reads [hst.Enablement] from an [io.Reader].
 | |
| func entryReadHeader(r io.Reader) (hst.Enablement, error) {
 | |
| 	var data [entryHeaderSize]byte
 | |
| 	if n, err := r.Read(data[:]); err != nil {
 | |
| 		return 0, err
 | |
| 	} else if n != entryHeaderSize {
 | |
| 		return 0, &EntrySizeError{Size: int64(n)}
 | |
| 	}
 | |
| 	return entryHeaderDecode(&data)
 | |
| }
 | |
| 
 | |
| // entryWriteHeader writes [hst.Enablement] header to an [io.Writer].
 | |
| func entryWriteHeader(w io.Writer, et hst.Enablement) error {
 | |
| 	_, err := w.Write(entryHeaderEncode(et)[:])
 | |
| 	return err
 | |
| }
 |