| 1 | //go:build linux |
| 2 | |
| 3 | package host |
| 4 | |
| 5 | import ( |
| 6 | "crypto/sha256" |
| 7 | "encoding/hex" |
| 8 | "fmt" |
| 9 | "path/filepath" |
| 10 | "strings" |
| 11 | |
| 12 | "github.com/carlosframework/platform/internal/hostbox" |
| 13 | "github.com/carlosframework/platform/internal/hostclaim" |
| 14 | "github.com/carlosframework/platform/internal/hostguard" |
| 15 | "github.com/carlosframework/platform/internal/instancefs" |
| 16 | "github.com/carlosframework/platform/internal/provision" |
| 17 | "golang.org/x/sys/unix" |
| 18 | ) |
| 19 | |
| 20 | // servingParkStateDirectory accepts only root installation and root inventory |
| 21 | // snapshots. The root handler reads both locally under host authority; |
| 22 | // this function is not a transport decoder and accepts no registry row. |
| 23 | func servingParkStateDirectory(data string, o hostclaim.Observed, installation hostguard.RootInstallation, in hostbox.StopInventory, revision uint64, actor hostbox.Actor) (servingArtifactDirectory, error) { |
| 24 | var zero servingArtifactDirectory |
| 25 | current, err := servingWriterIdentity(o, actor.Box, actor.Region) |
| 26 | if err != nil { |
| 27 | return zero, err |
| 28 | } |
| 29 | if !filepath.IsAbs(data) || filepath.Clean(data) != data || strings.ContainsAny(current.Host, "/\\\x00") || current.Host == "." || current.Host == ".." { |
| 30 | return zero, hostbox.ErrChanged |
| 31 | } |
| 32 | h := o.Claim.Holder |
| 33 | if h.Family != "instance" || installation.Migration == 0 || installation.Empty || installation.Host != current.Host || installation.Incarnation != current.Incarnation || installation.Stamp == 0 || installation.Stamp > current.Stamp || installation.Account != h.Account || installation.App != h.App || installation.Record != h.Key || installation.Box != actor.Box || installation.Enrollment != actor.Enrollment || actor.Enrollment == "" || actor.Revision == 0 || actor.Binding == "" || revision == 0 || installation.InventoryRevision != revision { |
| 34 | return zero, hostbox.ErrChanged |
| 35 | } |
| 36 | if installation.Stamp != current.Stamp { |
| 37 | if _, err := servingPredecessor(o.Claim, current, installation.Stamp, ""); err != nil { |
| 38 | return zero, err |
| 39 | } |
| 40 | } |
| 41 | if !in.Complete || in.Host != installation.Host || in.Incarnation != installation.Incarnation || in.InstallationStamp != installation.Stamp || in.Box != actor.Box || in.Enrollment != actor.Enrollment || in.DirectoryRevision != actor.Binding { |
| 42 | return zero, hostbox.ErrTypedInventory |
| 43 | } |
| 44 | relative := filepath.ToSlash(filepath.Join("instances", provision.InstanceID(current.Host))) |
| 45 | sum := sha256.Sum256([]byte(fmt.Sprintf("%s\x00%s\x00%d\x00%s", in.Host, in.Incarnation, in.InstallationStamp, in.Box))) |
| 46 | owner := hex.EncodeToString(sum[:]) |
| 47 | var selected hostbox.StopInventoryEntry |
| 48 | for _, entry := range in.Entries { |
| 49 | if entry.Kind != "path" || entry.ManagedRoot != "data" || entry.RelativePath != relative { |
| 50 | continue |
| 51 | } |
| 52 | if selected.ArtifactID != "" || entry.ArtifactID == "" || entry.Ownership != owner || entry.Materialization != "materialized" || entry.Type != unix.S_IFDIR || entry.Device == 0 || entry.Inode == 0 { |
| 53 | return zero, hostbox.ErrTypedInventory |
| 54 | } |
| 55 | selected = entry |
| 56 | } |
| 57 | if selected.ArtifactID == "" { |
| 58 | return zero, hostbox.ErrTypedInventory |
| 59 | } |
| 60 | dir, err := instancefs.OpenDirBeneath(data, relative) |
| 61 | if err != nil { |
| 62 | return zero, err |
| 63 | } |
| 64 | defer dir.Close() |
| 65 | id, err := servingParkDirID(dir) |
| 66 | if err != nil { |
| 67 | return zero, err |
| 68 | } |
| 69 | if id.Device != selected.Device || id.Inode != selected.Inode { |
| 70 | return zero, hostbox.ErrChanged |
| 71 | } |
| 72 | return id, nil |
| 73 | } |
| 74 | |