starry_api/imp/fs/
mount.rs

1use core::ffi::{c_char, c_void};
2
3use alloc::vec::Vec;
4use axerrno::{LinuxError, LinuxResult};
5use axsync::Mutex;
6use linux_raw_sys::general::AT_FDCWD;
7
8use crate::{
9    path::{FilePath, handle_file_path},
10    ptr::UserConstPtr,
11};
12
13pub fn sys_mount(
14    source: UserConstPtr<c_char>,
15    target: UserConstPtr<c_char>,
16    fs_type: UserConstPtr<c_char>,
17    flags: i32,
18    _data: UserConstPtr<c_void>,
19) -> LinuxResult<isize> {
20    let source = source.get_as_str()?;
21    let target = target.get_as_str()?;
22    let fs_type = fs_type.get_as_str()?;
23    info!(
24        "sys_mount <= source: {}, target: {}, fs_type: {}, flags: {}",
25        source, target, fs_type, flags
26    );
27
28    let device_path = handle_file_path(AT_FDCWD, source)?;
29    let mount_path = handle_file_path(AT_FDCWD, target)?;
30    info!(
31        "mount {:?} to {:?} with fs_type={:?}",
32        device_path, mount_path, fs_type
33    );
34
35    if fs_type != "vfat" {
36        debug!("fs_type can only be vfat.");
37        return Err(LinuxError::EPERM);
38    }
39
40    if !mount_path.exists() {
41        debug!("mount path not exist");
42        return Err(LinuxError::EPERM);
43    }
44
45    if check_mounted(&mount_path) {
46        debug!("mount path includes mounted fs");
47        return Err(LinuxError::EPERM);
48    }
49
50    if !mount_fat_fs(&device_path, &mount_path) {
51        debug!("mount error");
52        return Err(LinuxError::EPERM);
53    }
54    Ok(0)
55}
56
57pub fn sys_umount2(target: UserConstPtr<c_char>, flags: i32) -> LinuxResult<isize> {
58    let target = target.get_as_str()?;
59    info!("sys_umount2 <= target: {}, flags: {}", target, flags);
60
61    let mount_path = handle_file_path(AT_FDCWD, target)?;
62    if flags != 0 {
63        debug!("flags unimplemented");
64        return Err(LinuxError::EPERM);
65    }
66
67    if !mount_path.exists() {
68        debug!("mount path not exist");
69        return Err(LinuxError::EPERM);
70    }
71
72    if !umount_fat_fs(&mount_path) {
73        debug!("umount error");
74        return Err(LinuxError::EPERM);
75    }
76    Ok(0)
77}
78
79/// Mounted File System
80/// "Mount" means read&write a file as a file system now
81struct MountedFs {
82    //pub inner: Arc<Mutex<FATFileSystem>>,
83    pub device: FilePath,
84    pub mnt_dir: FilePath,
85}
86
87impl MountedFs {
88    pub fn new(device: &FilePath, mnt_dir: &FilePath) -> Self {
89        Self {
90            device: device.clone(),
91            mnt_dir: mnt_dir.clone(),
92        }
93    }
94
95    #[allow(unused)]
96    pub fn device(&self) -> FilePath {
97        self.device.clone()
98    }
99
100    pub fn mnt_dir(&self) -> FilePath {
101        self.mnt_dir.clone()
102    }
103}
104
105/// List of mounted file system
106/// Note that the startup file system is not in the vec, but in mod.rs
107static MOUNTED: Mutex<Vec<MountedFs>> = Mutex::new(Vec::new());
108
109/// Mount a fatfs device
110pub fn mount_fat_fs(device_path: &FilePath, mount_path: &FilePath) -> bool {
111    // device_path needs symlink lookup, but mount_path does not
112    // only opened files will be added to the symlink table for now, so do not convert now
113    // debug!("mounting {} to {}", device_path.path(), mount_path.path());
114    // if let Some(true_device_path) = real_path(device_path) {
115    if mount_path.exists() {
116        MOUNTED.lock().push(MountedFs::new(device_path, mount_path));
117        info!(
118            "mounted {} to {}",
119            device_path.as_str(),
120            mount_path.as_str()
121        );
122        return true;
123    }
124    info!(
125        "mount failed: {} to {}",
126        device_path.as_str(),
127        mount_path.as_str()
128    );
129    false
130}
131
132/// unmount a fatfs device
133pub fn umount_fat_fs(mount_path: &FilePath) -> bool {
134    let mut mounted = MOUNTED.lock();
135    let length_before_deletion = mounted.len();
136    mounted.retain(|m| m.mnt_dir() != *mount_path);
137    length_before_deletion > mounted.len()
138}
139
140/// check if a path is mounted
141pub fn check_mounted(path: &FilePath) -> bool {
142    let mounted = MOUNTED.lock();
143    mounted.iter().any(|m| path.starts_with(&m.mnt_dir()))
144}