1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//! ЄДИНЕ місце в крейті, де guest отримує (чи не отримує) права на диск —
//! §3.9: "читання — read-only preopen кореня репозиторію (або хостові
//! імпорти, коли треба вужче)". Кожен із чотирьох `Wasm*::call*`
//! (`detector.rs`/`verify.rs`/`ast_facts.rs`/`t0.rs`) будує `Store` для
//! guest-виклику РІВНО через [`no_filesystem_ctx`] — жодної іншої точки
//! конструювання `WasiCtx` у крейті немає, тож "мутуючий guest" не
//! потребує домовленості чи ревʼю: щоб він з'явився, хтось мусив би
//! змінити ЦЮ функцію (видно в diff).
use ;
/// `WasiCtx` **без жодного preopen** — guest не отримує файлової
/// capability взагалі.
///
/// # Чому не read-only preopen, як було на p2
///
/// §3.9 називає два шляхи читання для guest-а: широкий (read-only preopen
/// кореня репозиторію) і вузький (хостові імпорти, "коли треба вужче").
/// До переходу на WASI p3 тут стояв перший: `preopened_dir(repo_root, "/",
/// FsPerms::ReadOnly)`.
///
/// На p3 широкий шлях **непрацездатний**: у `wasmtime-wasi` 48 будь-який
/// `wasi:filesystem` `open-at` трапить компонент — не лише заборонений
/// запис, а й звичайне читання наявного файлу. Перевірено побайтово:
/// preopen до p3 доходить (спільний `get_directories` читає той самий
/// `ctx.preopens`), версії інтерфейсу збігаються (`wasi:filesystem@0.3.0`
/// з обох боків), сигнатура `open-at` і варіанти `error-code` ідентичні —
/// і все одно trap. Модуль `wasmtime_wasi::p3` сам себе оголошує
/// "experimental, unstable and incomplete"; це воно й є.
///
/// Тож крейт бере ДРУГИЙ шлях, який §3.9 передбачає явно: guest читає
/// через вузький `host-fs.read-file` (`crate::host_state`, доккоментар
/// `wit/host.wit`), який іде НЕ через `WasiCtx`, а напряму host-side
/// `std::fs` — і на p3 працює.
///
/// # Чому це ПОСИЛЕННЯ межі, а не вимушена поступка
///
/// Раніше guest мав реальну файлову capability, і "не може писати" було
/// властивістю ПРАВ на неї: хтось міг би розширити `FsPerms` і межа
/// поїхала б. Тепер capability немає взагалі — відкривати нічого, бо в
/// таблиці немає жодного каталогу. Запис не "заборонений перевіркою", він
/// невиразимий: guest не має з чого почати шлях.
///
/// Побічний ефект, який робить це придатним до життя: без preopen `std::fs`
/// у guest-і повертає ЧИСТУ помилку (`No such file or directory`), а не
/// трапить — саме тому, що libc відмовляє на резолві шляху, не доходячи до
/// зламаного `open-at`. Тобто legітимний guest, який промацує файлову
/// систему (`if let Ok(..) = fs::read(optional)`), спокійно йде в гілку
/// `else`, а не гине.
///
/// `wasi:filesystem` при цьому лишається ЗАЛІНКОВАНОЮ (`p3::add_to_linker`
/// у кожному `Wasm*::from_file`) — не з примхи: guest на `wasm32-wasip3`
/// імпортує її безумовно (рантайм `std` лінкує `wasi:filesystem/types` і
/// `preopens` незалежно від того, чи код їх кличе), і без цих імпортів
/// компонент не інстанціюється взагалі. Ми даємо інтерфейс і не даємо
/// жодного каталогу — різниця між "функція існує" і "є що нею відкрити".
pub