rule_file.bend
bend-osdev-apparmor@0.1.0.0 · 506 lines · 63 definitions
1
2
3
4
5
6
7
8
9
10import Base
11import bend-osdev-apparmor@0.1.0.0/text.bend as X
12import bend-osdev-apparmor@0.1.0.0/glob.bend as G
13import bend-osdev-apparmor@0.1.0.0/perm.bend as P
14import bend-osdev-apparmor@0.1.0.0/token.bend as T
15import bend-osdev-apparmor@0.1.0.0/error.bend as E
16import bend-osdev-apparmor@0.1.0.0/rule.bend as R
17
18type AaXFallback is Data:
19 AaFbNone{}
20 AaFbIx{}
21 AaFbUx{}
22
23
24
25type AaXMode is Data:
26 AaXIx{}
27 AaXUx{scrub: Bool}
28 AaXPx{scrub: Bool, fb: AaXFallback}
29 AaXCx{scrub: Bool, fb: AaXFallback}
30
31
32
33type AaFileRule is Data:
34 AaFileRule{qual: P.AaQual, text: List<&2, U32>, path: G.AaGlob, perms: P.AaPerms, exec: Maybe<&2, AaXMode>, target: Maybe<&2, List<&2, U32>>}
35
36
37
38type AaFileQuery is Data:
39 AaFileQuery{path: List<&2, U32>, owner: Bool, req: P.AaPerms}
40
41def AaFile.r() -> Nat:
42 0n
43
44def AaFile.w() -> Nat:
45 1n
46
47def AaFile.a() -> Nat:
48 2n
49
50def AaFile.l() -> Nat:
51 3n
52
53def AaFile.k() -> Nat:
54 4n
55
56def AaFile.m() -> Nat:
57 5n
58
59def AaFile.x() -> Nat:
60 6n
61
62def AaFile.letters() -> List<&2, String>:
63 ["r", "w", "a", "l", "k", "m", "x"]
64
65
66
67def AaXFallback.eq(a: AaXFallback, b: AaXFallback) -> Bool:
68 match a b:
69 case AaFbNone{} AaFbNone{}:
70 True{}
71 case AaFbIx{} AaFbIx{}:
72 True{}
73 case AaFbUx{} AaFbUx{}:
74 True{}
75 case _ _:
76 False{}
77
78def AaXMode.eq(a: AaXMode, b: AaXMode) -> Bool:
79 match a b:
80 case AaXIx{} AaXIx{}:
81 True{}
82 case AaXUx{s} AaXUx{t}:
83 Bool.not(Bool.xor(s, t))
84 case AaXPx{s, f} AaXPx{t, g}:
85 Bool.and(Bool.not(Bool.xor(s, t)), AaXFallback.eq(f, g))
86 case AaXCx{s, f} AaXCx{t, g}:
87 Bool.and(Bool.not(Bool.xor(s, t)), AaXFallback.eq(f, g))
88 case _ _:
89 False{}
90
91def AaXMode.show.fb(f: AaXFallback, up: Bool) -> String:
92 match f:
93 case AaFbNone{}:
94 ""
95 case AaFbIx{}:
96 "i"
97 case AaFbUx{}:
98 Bool.pick(String, up, "U", "u")
99
100def AaXMode.show(m: AaXMode) -> String:
101 match m:
102 case AaXIx{}:
103 "ix"
104 case AaXUx{s}:
105 Bool.pick(String, s, "Ux", "ux")
106 case AaXPx{+s, f}:
107 Bool.pick(String, s, "P", "p") ++ AaXMode.show.fb(f, s) ++ "x"
108 case AaXCx{+s, f}:
109 Bool.pick(String, s, "C", "c") ++ AaXMode.show.fb(f, s) ++ "x"
110
111
112
113
114type AaFpSt is Data:
115 AaFpBase{}
116 AaFpI{}
117 AaFpLp{}
118 AaFpLpi{}
119 AaFpLpu{}
120 AaFpUp{}
121 AaFpUpi{}
122 AaFpUpU{}
123 AaFpLc{}
124 AaFpLci{}
125 AaFpLcu{}
126 AaFpUc{}
127 AaFpUci{}
128 AaFpUcU{}
129 AaFpLu{}
130 AaFpUu{}
131
132type AaFp is Data:
133 AaFp{st: AaFpSt, r: Bool, w: Bool, a: Bool, l: Bool, k: Bool, m: Bool, exec: Maybe<&2, AaXMode>, bare: Bool, ok: Bool}
134
135def AaFp.fail(f: AaFp) -> AaFp:
136 match f:
137 case AaFp{st, r, w, a, l, k, m, e, b, ok}:
138 AaFp{AaFpBase{}, r, w, a, l, k, m, e, b, False{}}
139
140def AaFp.go(f: AaFp, s: AaFpSt) -> AaFp:
141 match f:
142 case AaFp{st, r, w, a, l, k, m, e, b, ok}:
143 AaFp{s, r, w, a, l, k, m, e, b, ok}
144
145def AaFp.exec.go(e: Maybe<&2, AaXMode>, x: AaXMode, r: Bool, w: Bool, a: Bool, l: Bool, k: Bool, m: Bool, b: Bool, ok: Bool) -> AaFp:
146 match e:
147 case None{}:
148 AaFp{AaFpBase{}, r, w, a, l, k, m, Some{x}, b, ok}
149 case Some{y}:
150 AaFp{AaFpBase{}, r, w, a, l, k, m, Some{y}, b, False{}}
151
152def AaFp.exec(f: AaFp, x: AaXMode) -> AaFp:
153 match f:
154 case AaFp{st, r, w, a, l, k, m, e, b, ok}:
155 AaFp.exec.go(e, x, r, w, a, l, k, m, b, ok)
156
157
158def AaFp.bit(f: AaFp, n: Nat) -> AaFp:
159 match f:
160 case AaFp{st, r, w, a, l, k, m, e, b, ok}:
161 match n:
162 case 0n:
163 AaFp{AaFpBase{}, True{}, w, a, l, k, m, e, b, ok}
164 case 1n+n1:
165 match n1:
166 case 0n:
167 AaFp{AaFpBase{}, r, True{}, a, l, k, m, e, b, ok}
168 case 1n+n2:
169 match n2:
170 case 0n:
171 AaFp{AaFpBase{}, r, w, True{}, l, k, m, e, b, ok}
172 case 1n+n3:
173 match n3:
174 case 0n:
175 AaFp{AaFpBase{}, r, w, a, True{}, k, m, e, b, ok}
176 case 1n+n4:
177 match n4:
178 case 0n:
179 AaFp{AaFpBase{}, r, w, a, l, True{}, m, e, b, ok}
180 case 1n+n5:
181 match n5:
182 case 0n:
183 AaFp{AaFpBase{}, r, w, a, l, k, True{}, e, b, ok}
184 case 1n+n6:
185 AaFp{AaFpBase{}, r, w, a, l, k, m, e, True{}, ok}
186
187def AaFp.base(+f: AaFp, +h: U32) -> AaFp:
188 Bool.pick(AaFp, U32.is_eq(h, 114), AaFp.bit(f, 0n), Bool.pick(AaFp, U32.is_eq(h, 119), AaFp.bit(f, 1n), Bool.pick(AaFp, U32.is_eq(h, 97), AaFp.bit(f, 2n), Bool.pick(AaFp, U32.is_eq(h, 108), AaFp.bit(f, 3n), Bool.pick(AaFp, U32.is_eq(h, 107), AaFp.bit(f, 4n), Bool.pick(AaFp, U32.is_eq(h, 109), AaFp.bit(f, 5n), Bool.pick(AaFp, U32.is_eq(h, 120), AaFp.bit(f, 6n), Bool.pick(AaFp, U32.is_eq(h, 105), AaFp.go(f, AaFpI{}), Bool.pick(AaFp, U32.is_eq(h, 112), AaFp.go(f, AaFpLp{}), Bool.pick(AaFp, U32.is_eq(h, 80), AaFp.go(f, AaFpUp{}), Bool.pick(AaFp, U32.is_eq(h, 99), AaFp.go(f, AaFpLc{}), Bool.pick(AaFp, U32.is_eq(h, 67), AaFp.go(f, AaFpUc{}), Bool.pick(AaFp, U32.is_eq(h, 117), AaFp.go(f, AaFpLu{}), Bool.pick(AaFp, U32.is_eq(h, 85), AaFp.go(f, AaFpUu{}), AaFp.fail(f)))))))))))))))
189
190
191def AaFp.x(+f: AaFp, +h: U32, x: AaXMode) -> AaFp:
192 Bool.pick(AaFp, U32.is_eq(h, 120), AaFp.exec(f, x), AaFp.fail(f))
193
194def AaFp.ext(+f: AaFp, +h: U32, x: AaXMode, +ci: U32, si: AaFpSt, +cu: U32, su: AaFpSt) -> AaFp:
195 Bool.pick(AaFp, U32.is_eq(h, 120), AaFp.exec(f, x), Bool.pick(AaFp, U32.is_eq(h, ci), AaFp.go(f, si), Bool.pick(AaFp, U32.is_eq(h, cu), AaFp.go(f, su), AaFp.fail(f))))
196
197def AaFp.step.st(s: AaFpSt, +f: AaFp, +h: U32) -> AaFp:
198 match s:
199 case AaFpBase{}:
200 AaFp.base(f, h)
201 case AaFpI{}:
202 AaFp.x(f, h, AaXIx{})
203 case AaFpLp{}:
204 AaFp.ext(f, h, AaXPx{False{}, AaFbNone{}}, 105, AaFpLpi{}, 117, AaFpLpu{})
205 case AaFpLpi{}:
206 AaFp.x(f, h, AaXPx{False{}, AaFbIx{}})
207 case AaFpLpu{}:
208 AaFp.x(f, h, AaXPx{False{}, AaFbUx{}})
209 case AaFpUp{}:
210 AaFp.ext(f, h, AaXPx{True{}, AaFbNone{}}, 105, AaFpUpi{}, 85, AaFpUpU{})
211 case AaFpUpi{}:
212 AaFp.x(f, h, AaXPx{True{}, AaFbIx{}})
213 case AaFpUpU{}:
214 AaFp.x(f, h, AaXPx{True{}, AaFbUx{}})
215 case AaFpLc{}:
216 AaFp.ext(f, h, AaXCx{False{}, AaFbNone{}}, 105, AaFpLci{}, 117, AaFpLcu{})
217 case AaFpLci{}:
218 AaFp.x(f, h, AaXCx{False{}, AaFbIx{}})
219 case AaFpLcu{}:
220 AaFp.x(f, h, AaXCx{False{}, AaFbUx{}})
221 case AaFpUc{}:
222 AaFp.ext(f, h, AaXCx{True{}, AaFbNone{}}, 105, AaFpUci{}, 85, AaFpUcU{})
223 case AaFpUci{}:
224 AaFp.x(f, h, AaXCx{True{}, AaFbIx{}})
225 case AaFpUcU{}:
226 AaFp.x(f, h, AaXCx{True{}, AaFbUx{}})
227 case AaFpLu{}:
228 AaFp.x(f, h, AaXUx{False{}})
229 case AaFpUu{}:
230 AaFp.x(f, h, AaXUx{True{}})
231
232def AaFp.step(f: AaFp, +h: U32) -> AaFp:
233 match f:
234 case AaFp{st, r, w, a, l, k, m, e, b, ok}:
235 AaFp.step.st(st, AaFp{AaFpBase{}, r, w, a, l, k, m, e, b, ok}, h)
236
237def AaFp.run(xs: List<&2, U32>, f: AaFp) -> AaFp:
238 match xs:
239 case Nil{}:
240 f
241 case Con{+h, t}:
242 AaFp.run(t, AaFp.step(f, h))
243
244
245type AaFPerms is Data:
246 AaFPerms{perms: P.AaPerms, exec: Maybe<&2, AaXMode>}
247
248def AaFp.is_some(m: Maybe<&2, AaXMode>) -> Bool:
249 match m:
250 case None{}:
251 False{}
252 case Some{x}:
253 True{}
254
255def AaFp.base_st(s: AaFpSt) -> Bool:
256 match s:
257 case AaFpBase{}:
258 True{}
259 case _:
260 False{}
261
262
263
264def AaFp.result(f: AaFp, +deny: Bool, src: E.AaSrc) -> Result<&2, &2, E.AaError, AaFPerms>:
265 match f:
266 case AaFp{st, +r, +w, +a, +l, +k, +m, +e, +b, ok}:
267 +ex = AaFp.is_some(e)
268 +good = Bool.and(ok, Bool.and(AaFp.base_st(st), Bool.and(Bool.not(Bool.and(w, a)), Bool.and(Bool.not(Bool.and(deny, ex)), Bool.and(Bool.not(Bool.and(Bool.not(deny), b)), Bool.and(Bool.not(Bool.and(ex, b)), Bool.or(r, Bool.or(w, Bool.or(a, Bool.or(l, Bool.or(k, Bool.or(m, Bool.or(ex, b)))))))))))))
269 Bool.pick(Result<&2, &2, E.AaError, AaFPerms>, good, Done{AaFPerms{P.AaPerms.of_bits([r, w, Bool.or(w, a), l, k, m, Bool.or(ex, b)]), e}}, Fail{E.AaSrc.perms(src)})
270
271
272def AaFile.parse_perms(xs: List<&2, U32>, +deny: Bool, src: E.AaSrc) -> Result<&2, &2, E.AaError, AaFPerms>:
273 AaFp.result(AaFp.run(xs, AaFp{AaFpBase{}, False{}, False{}, False{}, False{}, False{}, False{}, None{}, False{}, True{}}), deny, src)
274
275
276
277def AaFile.letter(+h: U32) -> Maybe<&2, Nat>:
278 Bool.pick(Maybe<&2, Nat>, U32.is_eq(h, 114), Some{0n}, Bool.pick(Maybe<&2, Nat>, U32.is_eq(h, 119), Some{1n}, Bool.pick(Maybe<&2, Nat>, U32.is_eq(h, 97), Some{2n}, Bool.pick(Maybe<&2, Nat>, U32.is_eq(h, 108), Some{3n}, Bool.pick(Maybe<&2, Nat>, U32.is_eq(h, 107), Some{4n}, Bool.pick(Maybe<&2, Nat>, U32.is_eq(h, 109), Some{5n}, Bool.pick(Maybe<&2, Nat>, U32.is_eq(h, 120), Some{6n}, None{})))))))
279
280def AaFile.perms.add(m: Maybe<&2, P.AaPerms>, l: Maybe<&2, Nat>) -> Maybe<&2, P.AaPerms>:
281 match m:
282 case None{}:
283 None{}
284 case Some{p}:
285 match l:
286 case None{}:
287 None{}
288 case Some{i}:
289 Some{P.AaPerms.add(p, i)}
290
291def AaFile.perms.go(xs: List<&2, U32>, acc: Maybe<&2, P.AaPerms>) -> Maybe<&2, P.AaPerms>:
292 match xs:
293 case Nil{}:
294 acc
295 case Con{+h, t}:
296 AaFile.perms.go(t, AaFile.perms.add(acc, AaFile.letter(h)))
297
298def AaFile.perms(s: String) -> P.AaPerms:
299 Maybe.default(&2, P.AaPerms, AaFile.perms.go(X.AaText.of_string(s), Some{P.AaPerms.none()}), P.AaPerms.none())
300
301
302
303
304
305def AaFile.is_path(t: T.AaTerm) -> Bool:
306 match t:
307 case T.AaTmWord{+w}:
308 Bool.or(U32.is_eq(X.AaText.head(w), 47), U32.is_eq(X.AaText.head(w), 123))
309 case T.AaTmQuoted{q}:
310 True{}
311 case T.AaTmList{xs}:
312 False{}
313 case T.AaTmCond{k, v}:
314 False{}
315 case T.AaTmArrow{}:
316 False{}
317
318def AaFile.word(t: T.AaTerm, src: E.AaSrc) -> Result<&2, &2, E.AaError, List<&2, U32>>:
319 match t:
320 case T.AaTmWord{w}:
321 Done{w}
322 case T.AaTmQuoted{q}:
323 Fail{E.AaSrc.perms(src)}
324 case T.AaTmList{xs}:
325 Fail{E.AaSrc.syntax(src)}
326 case T.AaTmCond{k, v}:
327 Fail{E.AaSrc.syntax(src)}
328 case T.AaTmArrow{}:
329 Fail{E.AaSrc.syntax(src)}
330
331def AaFile.path_text(t: T.AaTerm, src: E.AaSrc) -> Result<&2, &2, E.AaError, List<&2, U32>>:
332 match t:
333 case T.AaTmWord{w}:
334 Done{w}
335 case T.AaTmQuoted{q}:
336 Done{q}
337 case T.AaTmList{xs}:
338 Fail{E.AaSrc.syntax(src)}
339 case T.AaTmCond{k, v}:
340 Fail{E.AaSrc.syntax(src)}
341 case T.AaTmArrow{}:
342 Fail{E.AaSrc.syntax(src)}
343
344
345def AaFile.rooted.go(alts: List<&2, List<&2, G.AaGTok>>) -> Bool:
346 match alts:
347 case Nil{}:
348 True{}
349 case Con{a, t}:
350 match a:
351 case Nil{}:
352 False{}
353 case Con{tok, r}:
354 match tok:
355 case G.AaGChar{c}:
356 Bool.and(U32.is_eq(c, 47), AaFile.rooted.go(t))
357 case _:
358 False{}
359
360def AaFile.rooted(g: G.AaGlob) -> Bool:
361 match g:
362 case G.AaGlob{alts, lit}:
363 AaFile.rooted.go(alts)
364
365def AaFile.check_rooted(+g: G.AaGlob, src: E.AaSrc) -> Result<&2, &2, E.AaError, G.AaGlob>:
366 Bool.pick(Result<&2, &2, E.AaError, G.AaGlob>, AaFile.rooted(g), Done{g}, Fail{E.AaSrc.syntax(src)})
367
368
369
370
371def AaFile.target.check(t: Maybe<&2, List<&2, U32>>, +lead: Bool, fp: AaFPerms, src: E.AaSrc) -> Result<&2, &2, E.AaError, AaFPerms>:
372 match t:
373 case None{}:
374 Done{fp}
375 case Some{x}:
376 match fp:
377 case AaFPerms{+p, +e}:
378 Bool.pick(Result<&2, &2, E.AaError, AaFPerms>, Bool.and(AaFp.is_some(e), Bool.not(Bool.and(lead, P.AaPerms.has(p, 3n)))), Done{AaFPerms{p, e}}, Fail{E.AaSrc.perms(src)})
379
380def AaFile.build.go(fp: AaFPerms, q: P.AaQual, ptext: List<&2, U32>, g: G.AaGlob, target: Maybe<&2, List<&2, U32>>) -> Result<&2, &2, E.AaError, AaFileRule>:
381 match fp:
382 case AaFPerms{p, e}:
383 Done{AaFileRule{q, ptext, g, p, e, target}}
384
385def AaFile.build(+q: P.AaQual, +ptext: List<&2, U32>, pw: List<&2, U32>, +target: Maybe<&2, List<&2, U32>>, +lead: Bool, +src: E.AaSrc) -> Result<&2, &2, E.AaError, AaFileRule>:
386 do Result<&2, &2, E.AaError, AaFileRule>:
387 g0 : G.AaGlob <- R.AaRule.glob_text(ptext, src)
388 g : G.AaGlob <- AaFile.check_rooted(g0, src)
389 fp0 : AaFPerms <- AaFile.parse_perms(pw, P.AaQual.deny(q), src)
390 fp : AaFPerms <- AaFile.target.check(target, lead, fp0, src)
391 AaFile.build.go(fp, q, ptext, g, target)
392
393def AaFile.pair.go(q: P.AaQual, pt: T.AaTerm, wt: T.AaTerm, target: Maybe<&2, List<&2, U32>>, lead: Bool, +src: E.AaSrc) -> Result<&2, &2, E.AaError, AaFileRule>:
394 do Result<&2, &2, E.AaError, AaFileRule>:
395 ptext : List<&2, U32> <- AaFile.path_text(pt, src)
396 pw : List<&2, U32> <- AaFile.word(wt, src)
397 AaFile.build(q, ptext, pw, target, lead, src)
398
399
400def AaFile.pair(+q: P.AaQual, +a: T.AaTerm, +b: T.AaTerm, +target: Maybe<&2, List<&2, U32>>, +src: E.AaSrc) -> Result<&2, &2, E.AaError, AaFileRule>:
401 Bool.pick(Result<&2, &2, E.AaError, AaFileRule>, AaFile.is_path(a), AaFile.pair.go(q, a, b, target, False{}, src), AaFile.pair.go(q, b, a, target, True{}, src))
402
403
404
405def AaFile.all(q: P.AaQual) -> AaFileRule:
406 match q:
407 case P.AaQual{a, +d, o}:
408 AaFileRule{P.AaQual{a, d, o}, Nil{}, G.AaGlob.all(), P.AaPerms.of_bits([True{}, True{}, True{}, True{}, True{}, True{}, True{}]), Bool.pick(Maybe<&2, AaXMode>, d, None{}, Some{AaXIx{}}), None{}}
409
410def AaFile.target(t: T.AaTerm, src: E.AaSrc) -> Result<&2, &2, E.AaError, List<&2, U32>>:
411 AaFile.path_text(t, src)
412
413def AaFile.parse.arrow(ok: Bool, +q: P.AaQual, +a: T.AaTerm, +b: T.AaTerm, tgt: T.AaTerm, +src: E.AaSrc) -> Result<&2, &2, E.AaError, AaFileRule>:
414 match ok:
415 case False{}:
416 Fail{E.AaSrc.syntax(src)}
417 case True{}:
418 do Result<&2, &2, E.AaError, AaFileRule>:
419 t : List<&2, U32> <- AaFile.target(tgt, src)
420 AaFile.pair(q, a, b, Some{t}, src)
421
422
423def AaFile.parse(ts: List<&2, T.AaTerm>, +q: P.AaQual, +src: E.AaSrc) -> Result<&2, &2, E.AaError, AaFileRule>:
424 match ts:
425 case Nil{}:
426 Done{AaFile.all(q)}
427 case Con{a, r1}:
428 match r1:
429 case Nil{}:
430 Fail{E.AaSrc.syntax(src)}
431 case Con{b, r2}:
432 match r2:
433 case Nil{}:
434 AaFile.pair(q, a, b, None{}, src)
435 case Con{arrow, r3}:
436 match r3:
437 case Nil{}:
438 Fail{E.AaSrc.syntax(src)}
439 case Con{tgt, r4}:
440 match r4:
441 case Nil{}:
442 AaFile.parse.arrow(T.AaTerm.is_arrow(arrow), q, a, b, tgt, src)
443 case Con{x, r5}:
444 Fail{E.AaSrc.syntax(src)}
445
446
447
448def AaFileRule.qual(r: AaFileRule) -> P.AaQual:
449 match r:
450 case AaFileRule{q, t, g, p, e, tg}:
451 q
452
453def AaFileRule.matches(r: AaFileRule, q: AaFileQuery) -> Bool:
454 match r:
455 case AaFileRule{qu, t, g, p, e, tg}:
456 match q:
457 case AaFileQuery{path, owner, req}:
458 Bool.and(Bool.or(Bool.not(P.AaQual.owner(qu)), owner), G.AaGlob.matches(g, path))
459
460def AaFileRule.matching.go(hit: Bool, r: AaFileRule, rest: List<&2, AaFileRule>) -> List<&2, AaFileRule>:
461 match hit:
462 case True{}:
463 Con{r, rest}
464 case False{}:
465 rest
466
467
468def AaFileRule.matching(rs: List<&2, AaFileRule>, +q: AaFileQuery) -> List<&2, AaFileRule>:
469 match rs:
470 case Nil{}:
471 Nil{}
472 case Con{+r, t}:
473 AaFileRule.matching.go(AaFileRule.matches(r, q), r, AaFileRule.matching(t, q))
474
475def AaFileRule.grant(r: AaFileRule) -> P.AaGrant:
476 match r:
477 case AaFileRule{q, t, g, p, e, tg}:
478 P.AaGrant.of(q, p)
479
480def AaFileRule.grants.of(rs: List<&2, AaFileRule>) -> List<&2, P.AaGrant>:
481 match rs:
482 case Nil{}:
483 Nil{}
484 case Con{r, t}:
485 Con{AaFileRule.grant(r), AaFileRule.grants.of(t)}
486
487
488def AaFileRule.grants(rs: List<&2, AaFileRule>, +q: AaFileQuery) -> List<&2, P.AaGrant>:
489 AaFileRule.grants.of(AaFileRule.matching(rs, q))
490
491def AaFileRule.append(xs: List<&2, AaFileRule>, ys: List<&2, AaFileRule>) -> List<&2, AaFileRule>:
492 match xs:
493 case Nil{}:
494 ys
495 case Con{h, t}:
496 Con{h, AaFileRule.append(t, ys)}
497
498def AaFileQuery.req(q: AaFileQuery) -> P.AaPerms:
499 match q:
500 case AaFileQuery{p, o, r}:
501 r
502
503def AaFileQuery.path(q: AaFileQuery) -> List<&2, U32>:
504 match q:
505 case AaFileQuery{p, o, r}:
506 p