Skip to main content

strat9_kernel/vfs/
scheme_router.rs

1//! Scheme Router (SR) - central registry for all schemes.
2//!
3//! The Scheme Router manages scheme registration and provides
4//! a unified interface for mounting schemes in the VFS namespace.
5//!
6//! # Usage
7//!
8//! ```rust,no_run
9//! // Register a scheme
10//! let scheme_id = scheme_router::register("my_scheme", my_scheme);
11//!
12//! // Mount at a path
13//! mount_scheme("my_scheme", "/my/path")?;
14//! ```
15
16use crate::{
17    ipc::port::PortId,
18    sync::SpinLock,
19    syscall::error::SyscallError,
20    vfs::scheme::{DynScheme, IpcScheme, KernelScheme},
21};
22use alloc::{collections::BTreeMap, string::String, sync::Arc, vec::Vec};
23use spin::RwLock;
24
25/// Scheme registry entry
26pub struct SchemeEntry {
27    pub name: String,
28    pub scheme: DynScheme,
29}
30
31/// Global scheme router
32static SCHEME_ROUTER: RwLock<SchemeRouter> = RwLock::new(SchemeRouter::new());
33static INITFS_KERNEL_SCHEME: SpinLock<Option<Arc<KernelScheme>>> = SpinLock::new(None);
34
35/// Scheme router state
36pub struct SchemeRouter {
37    /// Registered schemes by name
38    schemes: BTreeMap<String, SchemeEntry>,
39    /// Next scheme ID
40    next_id: u64,
41}
42
43impl SchemeRouter {
44    /// Creates a new instance.
45    const fn new() -> Self {
46        Self {
47            schemes: BTreeMap::new(),
48            next_id: 1,
49        }
50    }
51
52    /// Register a new scheme
53    pub fn register(&mut self, name: &str, scheme: DynScheme) -> Result<u64, SyscallError> {
54        if self.schemes.contains_key(name) {
55            return Err(SyscallError::AlreadyExists);
56        }
57
58        let id = self.next_id;
59        self.next_id += 1;
60
61        self.schemes.insert(
62            String::from(name),
63            SchemeEntry {
64                name: String::from(name),
65                scheme,
66            },
67        );
68
69        Ok(id)
70    }
71
72    /// Get a scheme by name
73    pub fn get(&self, name: &str) -> Option<DynScheme> {
74        self.schemes.get(name).map(|e| e.scheme.clone())
75    }
76
77    /// List all registered schemes
78    pub fn list(&self) -> Vec<String> {
79        self.schemes.keys().cloned().collect()
80    }
81
82    /// Unregister a scheme
83    pub fn unregister(&mut self, name: &str) -> Result<(), SyscallError> {
84        self.schemes
85            .remove(name)
86            .map(|_| ())
87            .ok_or(SyscallError::BadHandle)
88    }
89}
90
91/// Register a scheme globally
92pub fn register_scheme(name: &str, scheme: DynScheme) -> Result<u64, SyscallError> {
93    SCHEME_ROUTER.write().register(name, scheme)
94}
95
96/// Get a scheme by name
97pub fn get_scheme(name: &str) -> Option<DynScheme> {
98    SCHEME_ROUTER.read().get(name)
99}
100
101/// Mount a registered scheme at a path
102pub fn mount_scheme(name: &str, path: &str) -> Result<(), SyscallError> {
103    let scheme = get_scheme(name).ok_or(SyscallError::BadHandle)?;
104    crate::vfs::mount::mount(path, scheme)
105}
106
107/// Initialize built-in schemes
108pub fn init_builtin_schemes() -> Result<(), SyscallError> {
109    // Create kernel scheme for /initfs
110    let kernel_scheme = Arc::new(KernelScheme::new());
111    register_scheme("kernel", kernel_scheme.clone())?;
112    mount_scheme("kernel", "/initfs")?;
113    *INITFS_KERNEL_SCHEME.lock() = Some(kernel_scheme);
114
115    log::info!("[SchemeRouter] Built-in schemes initialized");
116    Ok(())
117}
118
119/// Register a static file in the kernel-backed /initfs scheme.
120pub fn register_initfs_file(path: &str, base: *const u8, len: usize) -> Result<(), SyscallError> {
121    let scheme = INITFS_KERNEL_SCHEME
122        .lock()
123        .clone()
124        .ok_or(SyscallError::BadHandle)?;
125    scheme.register(path, base, len);
126    Ok(())
127}
128
129/// Create and register an IPC scheme for a userspace server
130pub fn register_ipc_scheme(name: &str, port_id: PortId) -> Result<u64, SyscallError> {
131    let ipc_scheme = Arc::new(IpcScheme::new(port_id));
132    register_scheme(name, ipc_scheme)
133}
134
135/// List all registered schemes (for debugging)
136pub fn list_schemes() -> Vec<String> {
137    SCHEME_ROUTER.read().list()
138}