kaish_kernel/vfs/
builtin_fs.rs1use std::io;
4use std::path::{Path, PathBuf};
5use std::sync::Arc;
6
7use async_trait::async_trait;
8
9use crate::tools::ToolRegistry;
10use super::traits::{DirEntry, Filesystem};
11
12pub struct BuiltinFs {
14 tools: Arc<ToolRegistry>,
15}
16
17impl BuiltinFs {
18 pub fn new(tools: Arc<ToolRegistry>) -> Self {
19 Self { tools }
20 }
21}
22
23#[async_trait]
24impl Filesystem for BuiltinFs {
25 async fn read(&self, path: &Path) -> io::Result<Vec<u8>> {
26 let name = path.to_str().unwrap_or("");
27 if self.tools.get(name).is_some() {
28 Ok(format!("#!/v/bin — kaish builtin: {}\n", name).into_bytes())
29 } else {
30 Err(io::Error::new(io::ErrorKind::NotFound, "builtin not found"))
31 }
32 }
33
34 async fn write(&self, _path: &Path, _data: &[u8]) -> io::Result<()> {
35 Err(io::Error::new(io::ErrorKind::PermissionDenied, "/v/bin is read-only"))
36 }
37
38 async fn list(&self, path: &Path) -> io::Result<Vec<DirEntry>> {
39 let p = path.to_str().unwrap_or("");
40 if !p.is_empty() && p != "." {
41 return Err(io::Error::new(io::ErrorKind::NotFound, "not a directory"));
42 }
43 let mut entries: Vec<DirEntry> = self.tools.names().iter().map(|name| {
44 DirEntry::file(name.to_string(), 0)
45 }).collect();
46 entries.sort_by(|a, b| a.name.cmp(&b.name));
47 Ok(entries)
48 }
49
50 async fn stat(&self, path: &Path) -> io::Result<DirEntry> {
51 let name = path.to_str().unwrap_or("");
52 if name.is_empty() || name == "." {
53 return Ok(DirEntry::directory("."));
54 }
55 if self.tools.get(name).is_some() {
56 Ok(DirEntry::file(name, 0))
57 } else {
58 Err(io::Error::new(io::ErrorKind::NotFound, "builtin not found"))
59 }
60 }
61
62 async fn mkdir(&self, _path: &Path) -> io::Result<()> {
63 Err(io::Error::new(io::ErrorKind::PermissionDenied, "/v/bin is read-only"))
64 }
65
66 async fn remove(&self, _path: &Path) -> io::Result<()> {
67 Err(io::Error::new(io::ErrorKind::PermissionDenied, "/v/bin is read-only"))
68 }
69
70 fn read_only(&self) -> bool {
71 true
72 }
73
74 fn real_path(&self, _path: &Path) -> Option<PathBuf> {
75 None
76 }
77}