Skip to main content

starnix_core/vfs/
fs_registry.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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(&current_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}