Implement final fixes and close out the implemetation roadmap

This commit is contained in:
2026-07-17 23:16:16 -05:00
parent 604c7a7945
commit 9fa9154dda
14 changed files with 463 additions and 879 deletions

View File

@@ -11,6 +11,7 @@ import (
"os"
"path/filepath"
"strings"
"syscall"
"gitea.maximumdirect.net/eric/notarius/internal/core/source"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
@@ -50,7 +51,7 @@ func (s *filesystemStore) Load(sourceDigest string) (pipeline.ChunkPlanRecord, p
}
defer root.Close()
state, err := inspectDirectory(root, digestDir)
digestRoot, state, err := openDigestRoot(root, digestDir, false)
if err != nil {
return pipeline.ChunkPlanRecord{}, pipeline.ChunkPlanDecision{}, fmt.Errorf("inspect chunk plan directory: %w", err)
}
@@ -60,11 +61,11 @@ func (s *filesystemStore) Load(sourceDigest string) (pipeline.ChunkPlanRecord, p
if state == entryRejected {
return invalidDecision()
}
defer digestRoot.Close()
target := planPath(digestDir)
state, err = inspectPlan(root, target)
data, state, err := readPlan(digestRoot)
if err != nil {
return pipeline.ChunkPlanRecord{}, pipeline.ChunkPlanDecision{}, fmt.Errorf("inspect chunk plan file: %w", err)
return pipeline.ChunkPlanRecord{}, pipeline.ChunkPlanDecision{}, fmt.Errorf("read chunk plan: %w", err)
}
if state == entryMissing {
return pipeline.ChunkPlanRecord{}, pipeline.ChunkPlanDecision{Status: pipeline.ChunkPlanMissing, Reason: lookupReason(pipeline.ChunkPlanMissing)}, nil
@@ -73,14 +74,6 @@ func (s *filesystemStore) Load(sourceDigest string) (pipeline.ChunkPlanRecord, p
return invalidDecision()
}
data, err := root.ReadFile(target)
if err != nil {
if os.IsNotExist(err) {
return pipeline.ChunkPlanRecord{}, pipeline.ChunkPlanDecision{Status: pipeline.ChunkPlanMissing, Reason: lookupReason(pipeline.ChunkPlanMissing)}, nil
}
return pipeline.ChunkPlanRecord{}, pipeline.ChunkPlanDecision{}, fmt.Errorf("read chunk plan: %w", err)
}
var record pipeline.ChunkPlanRecord
decoder := json.NewDecoder(bytes.NewReader(data))
decoder.DisallowUnknownFields()
@@ -116,11 +109,15 @@ func (s *filesystemStore) Save(record pipeline.ChunkPlanRecord) error {
return fmt.Errorf("open chunk plan root: %w", err)
}
defer root.Close()
if err := ensureDirectory(root, digestDir); err != nil {
digestRoot, state, err := openDigestRoot(root, digestDir, true)
if err != nil {
return fmt.Errorf("prepare chunk plan directory: %w", err)
}
target := planPath(digestDir)
state, err := inspectPlan(root, target)
if state == entryRejected {
return fmt.Errorf("chunk plan directory has an unsupported type")
}
defer digestRoot.Close()
state, err = inspectPlan(digestRoot, planFileName)
if err != nil {
return fmt.Errorf("inspect chunk plan file: %w", err)
}
@@ -131,7 +128,7 @@ func (s *filesystemStore) Save(record pipeline.ChunkPlanRecord) error {
if writer == nil {
writer = writeAtomic
}
if err := writer(root, target, data); err != nil {
if err := writer(digestRoot, planFileName, data); err != nil {
return fmt.Errorf("write chunk plan: %w", err)
}
return nil
@@ -174,52 +171,89 @@ const (
entryRejected
)
func inspectDirectory(root *os.Root, digestDir string) (entryState, error) {
func inspectDirectory(root *os.Root, digestDir string) (entryState, os.FileInfo, error) {
info, err := root.Lstat(digestDir)
if err != nil {
if os.IsNotExist(err) {
return entryMissing, nil
return entryMissing, nil, nil
}
return entryPresent, err
return entryPresent, nil, err
}
if info.Mode()&os.ModeSymlink != 0 || !info.IsDir() {
return entryRejected, nil
return entryRejected, info, nil
}
return entryPresent, nil
return entryPresent, info, nil
}
func ensureDirectory(root *os.Root, digestDir string) error {
type digestOpenHooks struct {
BeforeOpen func() error
}
func openDigestRoot(root *os.Root, digestDir string, create bool) (*os.Root, entryState, error) {
return openDigestRootWithHooks(root, digestDir, create, digestOpenHooks{})
}
func openDigestRootWithHooks(root *os.Root, digestDir string, create bool, hooks digestOpenHooks) (*os.Root, entryState, error) {
for {
state, err := inspectDirectory(root, digestDir)
state, before, err := inspectDirectory(root, digestDir)
if err != nil {
return err
return nil, entryPresent, err
}
switch state {
case entryRejected:
return fmt.Errorf("chunk plan directory has an unsupported type")
return nil, entryRejected, nil
case entryMissing:
if !create {
return nil, entryMissing, nil
}
if err := root.Mkdir(digestDir, 0o700); err != nil && !errors.Is(err, os.ErrExist) {
return err
return nil, entryPresent, err
}
continue
}
directory, err := root.Open(digestDir)
if hooks.BeforeOpen != nil {
if err := hooks.BeforeOpen(); err != nil {
return nil, entryPresent, err
}
}
digestRoot, err := root.OpenRoot(digestDir)
if err != nil {
return err
return nil, entryPresent, err
}
info, statErr := directory.Stat()
if statErr == nil && !info.IsDir() {
statErr = fmt.Errorf("chunk plan directory has an unsupported type")
opened, statErr := digestRoot.Stat(".")
afterState, after, afterErr := inspectDirectory(root, digestDir)
if statErr != nil || afterErr != nil {
_ = digestRoot.Close()
if statErr != nil {
return nil, entryPresent, statErr
}
return nil, entryPresent, afterErr
}
if statErr == nil {
statErr = directory.Chmod(0o700)
if afterState != entryPresent || !os.SameFile(before, after) || !os.SameFile(opened, after) {
_ = digestRoot.Close()
if afterState == entryRejected {
return nil, entryRejected, nil
}
continue
}
closeErr := directory.Close()
if statErr != nil {
return statErr
if create {
directory, openErr := digestRoot.Open(".")
if openErr != nil {
_ = digestRoot.Close()
return nil, entryPresent, openErr
}
chmodErr := directory.Chmod(0o700)
closeErr := directory.Close()
if chmodErr != nil || closeErr != nil {
_ = digestRoot.Close()
if chmodErr != nil {
return nil, entryPresent, chmodErr
}
return nil, entryPresent, closeErr
}
}
return closeErr
return digestRoot, entryPresent, nil
}
}
@@ -237,8 +271,54 @@ func inspectPlan(root *os.Root, target string) (entryState, error) {
return entryPresent, nil
}
func planPath(digestDir string) string {
return digestDir + "/" + planFileName
type planReadHooks struct {
BeforeOpen func() error
}
func readPlan(root *os.Root) ([]byte, entryState, error) {
return readPlanWithHooks(root, planReadHooks{})
}
func readPlanWithHooks(root *os.Root, hooks planReadHooks) ([]byte, entryState, error) {
state, err := inspectPlan(root, planFileName)
if err != nil || state != entryPresent {
return nil, state, err
}
if hooks.BeforeOpen != nil {
if err := hooks.BeforeOpen(); err != nil {
return nil, entryPresent, err
}
}
file, err := root.OpenFile(planFileName, os.O_RDONLY|syscall.O_NOFOLLOW|syscall.O_NONBLOCK, 0)
if err != nil {
if os.IsNotExist(err) {
return nil, entryMissing, nil
}
if errors.Is(err, syscall.ELOOP) {
return nil, entryRejected, nil
}
return nil, entryPresent, err
}
defer file.Close()
opened, err := file.Stat()
if err != nil {
return nil, entryPresent, err
}
if !opened.Mode().IsRegular() {
return nil, entryRejected, nil
}
currentState, currentErr := inspectPlan(root, planFileName)
if currentErr != nil {
return nil, entryPresent, currentErr
}
if currentState == entryRejected {
return nil, entryRejected, nil
}
data, err := io.ReadAll(file)
if err != nil {
return nil, entryPresent, err
}
return data, entryPresent, nil
}
func digestPathSegment(digest string) (string, error) {