carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1//go:build linux
2
3package host
4
5import (
6 "errors"
7 "io"
8 "os"
9
10 "github.com/carlosframework/platform/internal/hostbox"
11 "golang.org/x/sys/unix"
12)
13
14const servingParkRootSearchLimit = 128
15
16// The namespace lock covers this lookup. Only the current root or the prior
17// root in a completed quarantine can contain an authorized event. Quarantine
18// retention itself never grants access to the obstruction's children.
19func (f *servingParkFS) eventRoot(r *servingParkRecord) (*os.File, servingParkNamespace, error) {
20 root, n, err := f.namespace()
21 if err != nil {
22 return nil, n, err
23 }
24 if n.Parent != r.Source.Parent {
25 root.Close()
26 return nil, n, hostbox.ErrChanged
27 }
28 if r.Namespace == (servingArtifactDirectory{}) || r.Namespace == n.Root {
29 // An old lost-rmdir reply cannot identify which namespace is absent.
30 // Preserve it until independent evidence resolves that ambiguity.
31 if r.Namespace == (servingArtifactDirectory{}) && r.EventRemoveIntent {
32 body, e := f.state.Read("namespace-quarantine.json")
33 if e == nil {
34 var q servingParkQuarantine
35 if servingParkDecode(body, &q) != nil || q.validate() != nil || q.Previous != nil {
36 root.Close()
37 return nil, n, hostbox.ErrChanged
38 }
39 } else if !errors.Is(e, os.ErrNotExist) {
40 root.Close()
41 return nil, n, e
42 }
43 }
44 return root, n, nil
45 }
46 root.Close()
47 return f.displacedRoot(r)
48}
49
50func (f *servingParkFS) displacedRoot(r *servingParkRecord) (*os.File, servingParkNamespace, error) {
51 var n servingParkNamespace
52 body, err := f.state.Read("namespace-quarantine.json")
53 if err != nil {
54 return nil, n, err
55 }
56 var q servingParkQuarantine
57 if servingParkDecode(body, &q) != nil || q.validate() != nil || !q.Complete || q.Previous == nil || q.Parent != r.Source.Parent || r.Namespace != (servingArtifactDirectory{}) && r.Namespace != q.Previous.Root {
58 return nil, n, hostbox.ErrChanged
59 }
60 n = *q.Previous
61 parent, id, err := f.parent()
62 if err != nil {
63 return nil, n, err
64 }
65 defer parent.Close()
66 var st unix.Stat_t
67 if err := unix.Fstat(int(parent.Fd()), &st); err != nil || id != n.Parent || st.Mode&0022 != 0 {
68 return nil, n, hostbox.ErrChanged
69 }
70 // Bound both memory and directory work. A larger parent remains blocked;
71 // no partial search is interpreted as absence or permission to replace.
72 names, err := parent.Readdirnames(servingParkRootSearchLimit + 1)
73 if len(names) > servingParkRootSearchLimit || err != nil && !errors.Is(err, io.EOF) {
74 return nil, n, hostbox.ErrChanged
75 }
76 var found *os.File
77 defer func() {
78 if found != nil {
79 found.Close()
80 }
81 }()
82 for _, name := range names {
83 var s unix.Statx_t
84 err := unix.Statx(int(parent.Fd()), name, unix.AT_SYMLINK_NOFOLLOW, unix.STATX_BASIC_STATS|unix.STATX_MNT_ID, &s)
85 if errors.Is(err, unix.ENOENT) {
86 continue
87 }
88 if err != nil {
89 return nil, n, err
90 }
91 candidate := servingArtifactDirectory{Device: unix.Mkdev(s.Dev_major, s.Dev_minor), Inode: s.Ino, Mount: s.Mnt_id}
92 if s.Mask&unix.STATX_MNT_ID == 0 || s.Mode&unix.S_IFMT != unix.S_IFDIR || candidate != n.Root {
93 continue
94 }
95 d, actual, err := f.privateDir(parent, name)
96 if err != nil {
97 return nil, n, err
98 }
99 if actual != n.Root || found != nil {
100 d.Close()
101 return nil, n, hostbox.ErrChanged
102 }
103 found = d
104 }
105 if found == nil {
106 return nil, n, hostbox.ErrChanged
107 }
108 check, current, err := f.parent()
109 if err != nil {
110 return nil, n, err
111 }
112 check.Close()
113 if current != n.Parent {
114 return nil, n, hostbox.ErrChanged
115 }
116 root := found
117 found = nil
118 return root, n, nil
119}
120
121// Upgrade old records only after event identity has been proved. Persist the
122// root before deletion so an absent event remains unambiguous on replay.
123func (f *servingParkFS) recordEventRoot(r *servingParkRecord, root *os.File, save func() error) error {
124 id, err := servingParkDirID(root)
125 if err != nil {
126 return err
127 }
128 if r.Namespace != (servingArtifactDirectory{}) {
129 if r.Namespace != id {
130 return hostbox.ErrChanged
131 }
132 return nil
133 }
134 r.Namespace = id
135 return save()
136}
137