package host import ( "errors" "os" "github.com/carlosframework/platform/internal/hostbox" "github.com/carlosframework/platform/internal/rootstate" ) // A binding changes only boot-local device and mount numbers. Durable records keep their // original identities; progress writes translate back to those identities. type servingParkBootBinding struct { Volume string `json:",omitempty"` Version int ID, BeforeBoot, BootID string BeforeParent, Parent servingArtifactDirectory } func servingParkReadBinding(state rootstate.Store, id string) (*servingParkBootBinding, error) { body, err := state.Read("current-" + id + ".json") if errors.Is(err, os.ErrNotExist) { return nil, nil } if err != nil { return nil, err } var b servingParkBootBinding if servingParkDecode(body, &b) != nil || b.Version != 1 || b.ID != id || !validServingParkBootID(b.BeforeBoot) || !validServingParkBootID(b.BootID) || (b.BeforeBoot == b.BootID && b.BeforeParent.Device != b.Parent.Device) || b.BeforeParent.Device == 0 || b.BeforeParent.Inode == 0 || b.BeforeParent.Mount == 0 || b.Parent.Device == 0 || b.Parent.Inode != b.BeforeParent.Inode || b.Parent.Mount == 0 { return nil, hostbox.ErrChanged } return &b, nil } func (b servingParkBootBinding) directory(d *servingArtifactDirectory, reverse bool) error { if *d == (servingArtifactDirectory{}) { return nil } from, to := b.BeforeParent, b.Parent if reverse { from, to = to, from } if d.Device != from.Device || d.Mount != from.Mount { return hostbox.ErrChanged } d.Device, d.Mount = to.Device, to.Mount return nil } func (b servingParkBootBinding) record(r *servingParkRecord, reverse bool) error { from, to := b.BeforeBoot, b.BootID if reverse { from, to = to, from } parent := b.BeforeParent if reverse { parent = b.Parent } if b.ID != "retirement-"+r.Authorization.ID || r.Source.BootID != from || r.Source.Parent != parent { return hostbox.ErrChanged } r.Source.BootID = to for _, d := range []*servingArtifactDirectory{&r.Source.Directory, &r.Source.Parent, &r.Namespace, &r.Event, &r.Authorization.Directory} { if err := b.directory(d, reverse); err != nil { return err } } // Copy before changing slices shared with a caller's immutable snapshot. r.Continuations = append([]servingParkContinuation(nil), r.Continuations...) for i := range r.Continuations { if err := b.directory(&r.Continuations[i].Authorization.Directory, reverse); err != nil { return err } } for i := range r.Source.Files { f := &r.Source.Files[i] if !f.Present { continue } d := servingArtifactDirectory{Device: f.Device, Inode: f.Inode, Mount: f.Mount} if err := b.directory(&d, reverse); err != nil { return err } f.Device, f.Mount = d.Device, d.Mount } return nil } func (l *servingParkLedger) bindRecord(r *servingParkRecord, reverse bool) error { if l.historical { return nil } b, err := servingParkReadBinding(l.state, "retirement-"+r.Authorization.ID) if err != nil || b == nil { return err } return b.record(r, reverse) }