1use super::blkfs::BlkFS;
6use super::block_dev::BlockDeviceHandle;
7use super::disk_format::{detect_disk_format, DiskFormat};
8use super::file::{FileError, FileType};
9use super::inode::Inode;
10use super::ramfs::{RamFS, RamInode};
11use super::virtualfs::{default_devtmpfs, default_procfs, default_sysfs, VirtualFileSystem};
12use alloc::string::String;
13use alloc::sync::Arc;
14use alloc::vec::Vec;
15use lazy_static::lazy_static;
16use spin::Mutex;
17
18const BASE_DIRS: [&str; 7] = ["home", "tmp", "dev", "mnt", "proc", "sys", "run"];
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum BlkFsMountMode {
29 OpenOrCreate,
31 OpenOnly,
33 Format,
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39pub struct BlkFsMountOptions {
40 pub mode: BlkFsMountMode,
42}
43
44impl BlkFsMountOptions {
45 pub const fn open_or_create() -> Self {
46 Self {
47 mode: BlkFsMountMode::OpenOrCreate,
48 }
49 }
50
51 pub const fn open_only() -> Self {
52 Self {
53 mode: BlkFsMountMode::OpenOnly,
54 }
55 }
56
57 pub const fn format() -> Self {
58 Self {
59 mode: BlkFsMountMode::Format,
60 }
61 }
62}
63
64impl Default for BlkFsMountOptions {
65 fn default() -> Self {
66 Self::open_or_create()
67 }
68}
69
70pub struct MountPoint {
72 pub path: String,
74 pub fs_type: FsType,
76 pub blkfs: Option<Arc<BlkFS>>,
78 pub virtualfs: Option<Arc<dyn VirtualFileSystem>>,
80}
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq)]
84pub enum FsType {
85 RamFS,
86 BlkFS,
87 ProcFS,
88 SysFS,
89 DevTmpFS,
90}
91
92impl FsType {
93 fn matches_virtualfs_name(self, name: &str) -> bool {
94 matches!(
95 (self, name),
96 (FsType::ProcFS, "procfs") | (FsType::SysFS, "sysfs") | (FsType::DevTmpFS, "devtmpfs")
97 )
98 }
99}
100
101pub struct FileSystemManager {
105 pub root: Arc<Mutex<RamInode>>,
107 pub ramfs: Arc<RamFS>,
109 pub mounts: Vec<MountPoint>,
111}
112
113impl FileSystemManager {
114 pub fn new(ramfs: Arc<RamFS>) -> Self {
116 let root = ramfs.root();
117 FileSystemManager {
118 root,
119 ramfs,
120 mounts: Vec::new(),
121 }
122 }
123
124 pub fn root(&self) -> Arc<Mutex<RamInode>> {
126 self.root.clone()
127 }
128
129 pub fn ramfs(&self) -> Arc<RamFS> {
131 self.ramfs.clone()
132 }
133
134 fn ensure_ramfs_directory(&self, name: &str) -> Result<bool, &'static str> {
135 if name.is_empty() || name.contains('/') {
136 return Err("Invalid directory name");
137 }
138
139 match self.ramfs.lookup(self.root.clone(), name) {
140 Ok(inode) => {
141 if inode.lock().file_type() == FileType::Directory {
142 Ok(false)
143 } else {
144 Err("Path exists but is not a directory")
145 }
146 }
147 Err(FileError::NotFound) => self
148 .ramfs
149 .create_directory(self.root.clone(), String::from(name))
150 .map(|_| true)
151 .map_err(|_| "Failed to create directory"),
152 Err(_) => Err("Failed to inspect directory"),
153 }
154 }
155
156 fn rollback_created_ramfs_directory(&self, name: &str, created: bool) {
157 if created {
158 let _ = self.ramfs.remove(self.root.clone(), name);
159 }
160 }
161
162 fn normalize_mount_path(path: &str) -> Result<(String, String), &'static str> {
163 let trimmed = path.trim();
164 if !trimmed.starts_with('/') {
165 return Err("Mount path must be absolute");
166 }
167
168 let dir_name = trimmed.trim_matches('/');
169 if dir_name.is_empty() {
170 return Err("Cannot mount over root");
171 }
172 if dir_name.contains('/') {
173 return Err("Nested mount paths are not supported");
174 }
175
176 let mut mount_path = String::from("/");
177 mount_path.push_str(dir_name);
178 Ok((mount_path, String::from(dir_name)))
179 }
180
181 pub fn mount_blkfs(&mut self, path: &str, dev: BlockDeviceHandle) -> Result<(), &'static str> {
189 self.mount_blkfs_with_options(path, dev, BlkFsMountOptions::default())
190 }
191
192 pub fn mount_blkfs_with_options(
198 &mut self,
199 path: &str,
200 dev: BlockDeviceHandle,
201 options: BlkFsMountOptions,
202 ) -> Result<(), &'static str> {
203 let (mount_path, dir_name) = Self::normalize_mount_path(path)?;
204 if self.mounts.iter().any(|m| m.path == mount_path) {
205 return Err("Mount point already exists");
206 }
207
208 let created_mount_dir = self.ensure_ramfs_directory(&dir_name)?;
209
210 let format =
211 match detect_disk_format(&dev).map_err(|_| "Failed to inspect block device format") {
212 Ok(format) => format,
213 Err(err) => {
214 self.rollback_created_ramfs_directory(&dir_name, created_mount_dir);
215 return Err(err);
216 }
217 };
218 let blkfs_result = match options.mode {
219 BlkFsMountMode::OpenOrCreate => match format {
220 DiskFormat::BlkFS => BlkFS::open(dev).map_err(|_| "Failed to open BlkFS"),
221 DiskFormat::Blank => BlkFS::create(dev).map_err(|_| "Failed to create BlkFS"),
222 other => Err(unsupported_disk_format_error(other)),
223 },
224 BlkFsMountMode::OpenOnly => match format {
225 DiskFormat::BlkFS => BlkFS::open(dev).map_err(|_| "Failed to open BlkFS"),
226 other => Err(unsupported_disk_format_error(other)),
227 },
228 BlkFsMountMode::Format => BlkFS::create(dev).map_err(|_| "Failed to create BlkFS"),
229 };
230 let blkfs = match blkfs_result {
231 Ok(blkfs) => Arc::new(blkfs),
232 Err(err) => {
233 self.rollback_created_ramfs_directory(&dir_name, created_mount_dir);
234 return Err(err);
235 }
236 };
237
238 self.mounts.push(MountPoint {
239 path: mount_path,
240 fs_type: FsType::BlkFS,
241 blkfs: Some(blkfs),
242 virtualfs: None,
243 });
244
245 Ok(())
246 }
247
248 pub fn mount_virtualfs(
250 &mut self,
251 path: &str,
252 fs_type: FsType,
253 virtualfs: Arc<dyn VirtualFileSystem>,
254 ) -> Result<(), &'static str> {
255 let (mount_path, dir_name) = Self::normalize_mount_path(path)?;
256 if !matches!(fs_type, FsType::ProcFS | FsType::SysFS | FsType::DevTmpFS) {
257 return Err("Invalid virtual filesystem type");
258 }
259 if !fs_type.matches_virtualfs_name(virtualfs.name()) {
260 return Err("Virtual filesystem type mismatch");
261 }
262 if self.mounts.iter().any(|m| m.path == mount_path) {
263 return Err("Mount point already exists");
264 }
265
266 self.ensure_ramfs_directory(&dir_name)?;
267 self.mounts.push(MountPoint {
268 path: mount_path,
269 fs_type,
270 blkfs: None,
271 virtualfs: Some(virtualfs),
272 });
273
274 Ok(())
275 }
276
277 fn ensure_virtualfs_mounted(
278 &mut self,
279 path: &str,
280 fs_type: FsType,
281 virtualfs: Arc<dyn VirtualFileSystem>,
282 ) -> Result<(), &'static str> {
283 let (mount_path, _) = Self::normalize_mount_path(path)?;
284 if self.mounts.iter().any(|m| m.path == mount_path) {
285 return Ok(());
286 }
287 self.mount_virtualfs(path, fs_type, virtualfs)
288 }
289
290 pub fn get_blkfs(&self, path: &str) -> Option<Arc<BlkFS>> {
292 self.mounts
293 .iter()
294 .find(|m| m.path == path && m.fs_type == FsType::BlkFS)
295 .and_then(|m| m.blkfs.clone())
296 }
297
298 pub fn umount(&mut self, path: &str) -> Result<(), &'static str> {
300 let (mount_path, _) = Self::normalize_mount_path(path)?;
301 let idx = self
302 .mounts
303 .iter()
304 .position(|m| m.path == mount_path)
305 .ok_or("Mount point not found")?;
306 if let Some(blkfs) = self.mounts[idx].blkfs.as_ref() {
307 blkfs
308 .sync()
309 .map_err(|_| "Failed to flush mounted filesystem")?;
310 }
311 self.mounts.remove(idx);
312 Ok(())
313 }
314}
315
316fn unsupported_disk_format_error(format: DiskFormat) -> &'static str {
317 match format {
318 DiskFormat::Blank => "Device is blank (not BlkFS)",
319 DiskFormat::BlkFS => "Failed to open BlkFS",
320 DiskFormat::InvalidBlkFS => "Invalid BlkFS superblock",
321 DiskFormat::TooSmall => "Device is too small for BlkFS",
322 DiskFormat::MasterBootRecord => "Unsupported MBR partition table",
323 DiskFormat::GuidPartitionTable => "Unsupported GPT partition table",
324 DiskFormat::FatFamily => "Unsupported FAT filesystem",
325 DiskFormat::ExtFamily => "Unsupported ext-family filesystem",
326 DiskFormat::Unknown => "Unsupported or unknown disk format",
327 }
328}
329
330lazy_static! {
331 pub static ref FS_MANAGER: Mutex<FileSystemManager> = {
335 let ramfs = Arc::new(RamFS::new());
336 let manager = FileSystemManager::new(ramfs);
337 Mutex::new(manager)
338 };
339}
340
341pub fn init_filesystem() {
345 let mut manager = FS_MANAGER.lock();
346 for dir in BASE_DIRS {
347 manager
348 .ensure_ramfs_directory(dir)
349 .expect("Failed to initialize base directory");
350 }
351 manager
352 .ensure_virtualfs_mounted("/proc", FsType::ProcFS, default_procfs())
353 .expect("Failed to mount procfs");
354 manager
355 .ensure_virtualfs_mounted("/sys", FsType::SysFS, default_sysfs())
356 .expect("Failed to mount sysfs");
357 manager
358 .ensure_virtualfs_mounted("/dev", FsType::DevTmpFS, default_devtmpfs())
359 .expect("Failed to mount devtmpfs");
360}