ahrightos-fs 0.1.0

Portable filesystem, block-device, and IPC primitives for the AhRightOS teaching kernel.
Documentation
//! 全局文件系统管理器
//!
//! 提供统一的文件系统访问接口,支持多文件系统挂载

use super::blkfs::BlkFS;
use super::block_dev::BlockDeviceHandle;
use super::disk_format::{detect_disk_format, DiskFormat};
use super::file::{FileError, FileType};
use super::inode::Inode;
use super::ramfs::{RamFS, RamInode};
use super::virtualfs::{default_devtmpfs, default_procfs, default_sysfs, VirtualFileSystem};
use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec::Vec;
use lazy_static::lazy_static;
use spin::Mutex;

const BASE_DIRS: [&str; 7] = ["home", "tmp", "dev", "mnt", "proc", "sys", "run"];

/// BlkFS mount policy.
///
/// The default (`OpenOrCreate`) preserves the old teaching behavior: open an
/// existing AhRightOS BlkFS image when the device already contains one, otherwise
/// format a fresh BlkFS.  More explicit modes let labs and kernel syscalls
/// distinguish "only mount an already-formatted image" from "format this device
/// now".
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BlkFsMountMode {
    /// Open an existing BlkFS, or create one only when the device is blank.
    OpenOrCreate,
    /// Open only; return an error instead of formatting an unrecognized device.
    OpenOnly,
    /// Always format a new BlkFS before mounting.
    Format,
}

/// Options for mounting an AhRightOS-native BlkFS instance.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct BlkFsMountOptions {
    /// Policy used to interpret or initialize the target block device.
    pub mode: BlkFsMountMode,
}

impl BlkFsMountOptions {
    pub const fn open_or_create() -> Self {
        Self {
            mode: BlkFsMountMode::OpenOrCreate,
        }
    }

    pub const fn open_only() -> Self {
        Self {
            mode: BlkFsMountMode::OpenOnly,
        }
    }

    pub const fn format() -> Self {
        Self {
            mode: BlkFsMountMode::Format,
        }
    }
}

impl Default for BlkFsMountOptions {
    fn default() -> Self {
        Self::open_or_create()
    }
}

/// 挂载点 — 将一个文件系统挂载到指定路径
pub struct MountPoint {
    /// 挂载路径 (如 "/mnt")
    pub path: String,
    /// 挂载的文件系统类型标识
    pub fs_type: FsType,
    /// BlkFS 实例 (如果是块设备文件系统)
    pub blkfs: Option<Arc<BlkFS>>,
    /// VirtualFS 实例 (如果是 procfs/sysfs/devtmpfs 等伪文件系统)
    pub virtualfs: Option<Arc<dyn VirtualFileSystem>>,
}

/// 文件系统类型
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FsType {
    RamFS,
    BlkFS,
    ProcFS,
    SysFS,
    DevTmpFS,
}

impl FsType {
    fn matches_virtualfs_name(self, name: &str) -> bool {
        matches!(
            (self, name),
            (FsType::ProcFS, "procfs") | (FsType::SysFS, "sysfs") | (FsType::DevTmpFS, "devtmpfs")
        )
    }
}

/// 文件系统管理器
///
/// 管理全局文件系统实例和挂载表
pub struct FileSystemManager {
    /// 根目录 (RamFS)
    pub root: Arc<Mutex<RamInode>>,
    /// RamFS实例
    pub ramfs: Arc<RamFS>,
    /// 挂载表
    pub mounts: Vec<MountPoint>,
}

impl FileSystemManager {
    /// 创建新的文件系统管理器
    pub fn new(ramfs: Arc<RamFS>) -> Self {
        let root = ramfs.root();
        FileSystemManager {
            root,
            ramfs,
            mounts: Vec::new(),
        }
    }

    /// 获取根目录
    pub fn root(&self) -> Arc<Mutex<RamInode>> {
        self.root.clone()
    }

    /// 获取RamFS实例
    pub fn ramfs(&self) -> Arc<RamFS> {
        self.ramfs.clone()
    }

    fn ensure_ramfs_directory(&self, name: &str) -> Result<bool, &'static str> {
        if name.is_empty() || name.contains('/') {
            return Err("Invalid directory name");
        }

        match self.ramfs.lookup(self.root.clone(), name) {
            Ok(inode) => {
                if inode.lock().file_type() == FileType::Directory {
                    Ok(false)
                } else {
                    Err("Path exists but is not a directory")
                }
            }
            Err(FileError::NotFound) => self
                .ramfs
                .create_directory(self.root.clone(), String::from(name))
                .map(|_| true)
                .map_err(|_| "Failed to create directory"),
            Err(_) => Err("Failed to inspect directory"),
        }
    }

    fn rollback_created_ramfs_directory(&self, name: &str, created: bool) {
        if created {
            let _ = self.ramfs.remove(self.root.clone(), name);
        }
    }

    fn normalize_mount_path(path: &str) -> Result<(String, String), &'static str> {
        let trimmed = path.trim();
        if !trimmed.starts_with('/') {
            return Err("Mount path must be absolute");
        }

        let dir_name = trimmed.trim_matches('/');
        if dir_name.is_empty() {
            return Err("Cannot mount over root");
        }
        if dir_name.contains('/') {
            return Err("Nested mount paths are not supported");
        }

        let mut mount_path = String::from("/");
        mount_path.push_str(dir_name);
        Ok((mount_path, String::from(dir_name)))
    }

    /// 挂载一个块设备文件系统(兼容旧接口)
    ///
    /// # 参数
    /// - `path`: 挂载路径(在RamFS中创建目录作为挂载点)
    /// - `dev`: 块设备句柄
    ///
    /// 先尝试打开已有文件系统;如果设备未格式化,则创建新文件系统。
    pub fn mount_blkfs(&mut self, path: &str, dev: BlockDeviceHandle) -> Result<(), &'static str> {
        self.mount_blkfs_with_options(path, dev, BlkFsMountOptions::default())
    }

    /// 按显式策略挂载一个 AhRightOS-native BlkFS。
    ///
    /// `OpenOnly` 适合把 QEMU `virtio-blk` 镜像当作“真实磁盘镜像”挂载:
    /// 如果镜像不是 BlkFS,内核会清晰失败而不会误格式化。`Format` 必须由
    /// 调用者显式指定,用于实验中的重新格式化场景。
    pub fn mount_blkfs_with_options(
        &mut self,
        path: &str,
        dev: BlockDeviceHandle,
        options: BlkFsMountOptions,
    ) -> Result<(), &'static str> {
        let (mount_path, dir_name) = Self::normalize_mount_path(path)?;
        if self.mounts.iter().any(|m| m.path == mount_path) {
            return Err("Mount point already exists");
        }

        let created_mount_dir = self.ensure_ramfs_directory(&dir_name)?;

        let format =
            match detect_disk_format(&dev).map_err(|_| "Failed to inspect block device format") {
                Ok(format) => format,
                Err(err) => {
                    self.rollback_created_ramfs_directory(&dir_name, created_mount_dir);
                    return Err(err);
                }
            };
        let blkfs_result = match options.mode {
            BlkFsMountMode::OpenOrCreate => match format {
                DiskFormat::BlkFS => BlkFS::open(dev).map_err(|_| "Failed to open BlkFS"),
                DiskFormat::Blank => BlkFS::create(dev).map_err(|_| "Failed to create BlkFS"),
                other => Err(unsupported_disk_format_error(other)),
            },
            BlkFsMountMode::OpenOnly => match format {
                DiskFormat::BlkFS => BlkFS::open(dev).map_err(|_| "Failed to open BlkFS"),
                other => Err(unsupported_disk_format_error(other)),
            },
            BlkFsMountMode::Format => BlkFS::create(dev).map_err(|_| "Failed to create BlkFS"),
        };
        let blkfs = match blkfs_result {
            Ok(blkfs) => Arc::new(blkfs),
            Err(err) => {
                self.rollback_created_ramfs_directory(&dir_name, created_mount_dir);
                return Err(err);
            }
        };

        self.mounts.push(MountPoint {
            path: mount_path,
            fs_type: FsType::BlkFS,
            blkfs: Some(blkfs),
            virtualfs: None,
        });

        Ok(())
    }

    /// 挂载一个虚拟文件系统(如 procfs/sysfs/devtmpfs)。
    pub fn mount_virtualfs(
        &mut self,
        path: &str,
        fs_type: FsType,
        virtualfs: Arc<dyn VirtualFileSystem>,
    ) -> Result<(), &'static str> {
        let (mount_path, dir_name) = Self::normalize_mount_path(path)?;
        if !matches!(fs_type, FsType::ProcFS | FsType::SysFS | FsType::DevTmpFS) {
            return Err("Invalid virtual filesystem type");
        }
        if !fs_type.matches_virtualfs_name(virtualfs.name()) {
            return Err("Virtual filesystem type mismatch");
        }
        if self.mounts.iter().any(|m| m.path == mount_path) {
            return Err("Mount point already exists");
        }

        self.ensure_ramfs_directory(&dir_name)?;
        self.mounts.push(MountPoint {
            path: mount_path,
            fs_type,
            blkfs: None,
            virtualfs: Some(virtualfs),
        });

        Ok(())
    }

    fn ensure_virtualfs_mounted(
        &mut self,
        path: &str,
        fs_type: FsType,
        virtualfs: Arc<dyn VirtualFileSystem>,
    ) -> Result<(), &'static str> {
        let (mount_path, _) = Self::normalize_mount_path(path)?;
        if self.mounts.iter().any(|m| m.path == mount_path) {
            return Ok(());
        }
        self.mount_virtualfs(path, fs_type, virtualfs)
    }

    /// 获取指定路径的BlkFS(如果已挂载)
    pub fn get_blkfs(&self, path: &str) -> Option<Arc<BlkFS>> {
        self.mounts
            .iter()
            .find(|m| m.path == path && m.fs_type == FsType::BlkFS)
            .and_then(|m| m.blkfs.clone())
    }

    /// 卸载文件系统
    pub fn umount(&mut self, path: &str) -> Result<(), &'static str> {
        let (mount_path, _) = Self::normalize_mount_path(path)?;
        let idx = self
            .mounts
            .iter()
            .position(|m| m.path == mount_path)
            .ok_or("Mount point not found")?;
        if let Some(blkfs) = self.mounts[idx].blkfs.as_ref() {
            blkfs
                .sync()
                .map_err(|_| "Failed to flush mounted filesystem")?;
        }
        self.mounts.remove(idx);
        Ok(())
    }
}

fn unsupported_disk_format_error(format: DiskFormat) -> &'static str {
    match format {
        DiskFormat::Blank => "Device is blank (not BlkFS)",
        DiskFormat::BlkFS => "Failed to open BlkFS",
        DiskFormat::InvalidBlkFS => "Invalid BlkFS superblock",
        DiskFormat::TooSmall => "Device is too small for BlkFS",
        DiskFormat::MasterBootRecord => "Unsupported MBR partition table",
        DiskFormat::GuidPartitionTable => "Unsupported GPT partition table",
        DiskFormat::FatFamily => "Unsupported FAT filesystem",
        DiskFormat::ExtFamily => "Unsupported ext-family filesystem",
        DiskFormat::Unknown => "Unsupported or unknown disk format",
    }
}

lazy_static! {
    /// 全局文件系统管理器
    ///
    /// 在系统启动时初始化,支持RamFS + 可选的BlkFS挂载
    pub static ref FS_MANAGER: Mutex<FileSystemManager> = {
        let ramfs = Arc::new(RamFS::new());
        let manager = FileSystemManager::new(ramfs);
        Mutex::new(manager)
    };
}

/// 初始化文件系统
///
/// 创建基础目录结构
pub fn init_filesystem() {
    let mut manager = FS_MANAGER.lock();
    for dir in BASE_DIRS {
        manager
            .ensure_ramfs_directory(dir)
            .expect("Failed to initialize base directory");
    }
    manager
        .ensure_virtualfs_mounted("/proc", FsType::ProcFS, default_procfs())
        .expect("Failed to mount procfs");
    manager
        .ensure_virtualfs_mounted("/sys", FsType::SysFS, default_sysfs())
        .expect("Failed to mount sysfs");
    manager
        .ensure_virtualfs_mounted("/dev", FsType::DevTmpFS, default_devtmpfs())
        .expect("Failed to mount devtmpfs");
}