starnix_core/vfs/
fs_registry.rs1use crate::security;
6use crate::task::CurrentTask;
7use crate::vfs::{FileSystemHandle, FileSystemOptions, FsStr, FsString};
8use starnix_sync::{FsRegistryLock, LockDepMutex};
9use starnix_uapi::errors::Errno;
10use starnix_uapi::fs_type::FileSystemTypeFlags;
11use std::collections::BTreeMap;
12use std::sync::Arc;
13
14type CreateFs = Arc<
15 dyn Fn(&CurrentTask, FileSystemOptions) -> Result<FileSystemHandle, Errno>
16 + Send
17 + Sync
18 + 'static,
19>;
20
21#[derive(Clone)]
22struct FsRegistryEntry {
23 flags: FileSystemTypeFlags,
24 create_fs: CreateFs,
25}
26
27#[derive(Default)]
28pub struct FsRegistry {
29 registry: LockDepMutex<BTreeMap<FsString, FsRegistryEntry>, FsRegistryLock>,
30}
31
32impl FsRegistry {
33 pub fn register<F>(&self, fs_type: &FsStr, flags: FileSystemTypeFlags, create_fs: F)
34 where
35 F: Fn(&CurrentTask, FileSystemOptions) -> Result<FileSystemHandle, Errno>
36 + Send
37 + Sync
38 + 'static,
39 {
40 let entry = FsRegistryEntry { flags, create_fs: Arc::new(create_fs) };
41 let existing = self.registry.lock().insert(fs_type.into(), entry);
42 assert!(existing.is_none());
43 }
44
45 pub fn create(
46 &self,
47 current_task: &CurrentTask,
48 fs_type: &FsStr,
49 options: FileSystemOptions,
50 ) -> Option<Result<FileSystemHandle, Errno>> {
51 let create_fs = self.registry.lock().get(fs_type).map(|e| Arc::clone(&e.create_fs))?;
52 Some(create_fs(current_task, options).and_then(|fs| {
53 assert_eq!(fs_type, fs.name(), "FileSystem::name() must match the registered name.");
54 security::file_system_resolve_security(¤t_task, &fs)?;
55 Ok(fs)
56 }))
57 }
58
59 pub fn list_all(&self) -> Vec<(FsString, FileSystemTypeFlags)> {
60 self.registry.lock().iter().map(|(name, entry)| (name.clone(), entry.flags)).collect()
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67
68 #[test]
69 fn test_fs_registry_list_all_flags() {
70 let registry = FsRegistry::default();
71 registry.register(
72 b"test_nodev".into(),
73 FileSystemTypeFlags::empty(),
74 |_task, _options| unreachable!(),
75 );
76 registry.register(
77 b"test_dev".into(),
78 FileSystemTypeFlags::REQUIRES_DEV,
79 |_task, _options| unreachable!(),
80 );
81
82 let list = registry.list_all();
83 assert_eq!(
84 list,
85 vec![
86 (b"test_dev".into(), FileSystemTypeFlags::REQUIRES_DEV),
87 (b"test_nodev".into(), FileSystemTypeFlags::empty()),
88 ]
89 );
90 }
91}