1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! [ArceOS](https://github.com/rcore-os/arceos) filesystem module.
//!
//! It provides unified filesystem operations for various filesystems.
//!
//! # Cargo Features
//!
//! - `fatfs`: Use [FAT] as the main filesystem and mount it on `/`. This feature
//!    is **enabled** by default.
//! - `devfs`: Mount [`axfs_devfs::DeviceFileSystem`] on `/dev`. This feature is
//!    **enabled** by default.
//! - `ramfs`: Mount [`axfs_ramfs::RamFileSystem`] on `/tmp`. This feature is
//!    **enabled** by default.
//! - `myfs`: Allow users to define their custom filesystems to override the
//!    default. In this case, [`MyFileSystemIf`] is required to be implemented
//!    to create and initialize other filesystems. This feature is **disabled** by
//!    by default, but it will override other filesystem selection features if
//!    both are enabled.
//!
//! [FAT]: https://en.wikipedia.org/wiki/File_Allocation_Table
//! [`MyFileSystemIf`]: fops::MyFileSystemIf

#![cfg_attr(all(not(test), not(doc)), no_std)]
#![feature(doc_auto_cfg)]

#[macro_use]
extern crate log;
extern crate alloc;

mod dev;
mod fs;
mod root;

pub mod api;
pub mod fops;

use axdriver::{prelude::*, AxDeviceContainer};

/// Initializes filesystems by block devices.
pub fn init_filesystems(
    #[allow(unused, unused_mut)] mut blk_devs: AxDeviceContainer<AxBlockDevice>,
) {
    #[cfg(not(feature = "user"))]
    {
        info!("Initialize filesystems...");

        let dev = blk_devs.take_one().expect("No block device found!");
        info!("  use block device 0: {:?}", dev.device_name());
        self::root::init_rootfs(self::dev::Disk::new(dev));
    }
}

#[cfg(feature = "user")]
pub use user::user_init;
#[cfg(feature = "user")]
mod user {
    use axerrno::{AxError, AxResult};
    use axio::{Read, Seek, Write};
    use driver_block::{DevError, DevResult};
    use libax::io::File;

    /// Initializes filesystems in user mode.
    pub fn user_init() {
        let dev = AxBlockDeviceMock::new().unwrap();
        super::root::init_rootfs(super::dev::Disk::new(dev));
    }

    pub struct AxBlockDeviceMock {
        file: File,
        block_size: usize,
        num_blocks: u64,
    }

    impl AxBlockDeviceMock {
        fn new() -> AxResult<Self> {
            let mut block_size: usize = 0;
            assert_eq!(
                File::open("dev:/disk/block_size")
                    .map_err(|_| AxError::Unsupported)?
                    .read_data(&mut block_size),
                Ok(core::mem::size_of_val(&block_size))
            );

            let mut num_blocks: u64 = 0;
            assert_eq!(
                File::open("dev:/disk/num_blocks")
                    .map_err(|_| AxError::Unsupported)?
                    .read_data(&mut num_blocks),
                Ok(core::mem::size_of_val(&num_blocks))
            );

            Ok(AxBlockDeviceMock {
                file: File::open("dev:/disk").map_err(|_| AxError::Unsupported)?,
                block_size,
                num_blocks,
            })
        }
        pub fn block_size(&self) -> usize {
            self.block_size
        }

        pub fn num_blocks(&self) -> u64 {
            self.num_blocks
        }

        pub fn read_block(&mut self, block_id: u64, buf: &mut [u8]) -> DevResult {
            self.file
                .seek(axio::SeekFrom::Start(block_id * self.block_size as u64))
                .map_err(map_err)?;
            self.file.read_exact(buf).map_err(map_err)
        }
        pub fn write_block(&mut self, block_id: u64, buf: &[u8]) -> DevResult {
            self.file
                .seek(axio::SeekFrom::Start(block_id * self.block_size as u64))
                .map_err(map_err)?;
            self.file.write_all(buf).map_err(map_err)
        }
    }

    fn map_err(e: AxError) -> DevError {
        match e {
            AxError::WouldBlock => DevError::Again,
            AxError::AlreadyExists => DevError::AlreadyExists,
            AxError::BadState => DevError::BadState,
            AxError::InvalidInput => DevError::InvalidParam,
            AxError::Io => DevError::Io,
            AxError::NoMemory => DevError::NoMemory,
            AxError::ResourceBusy => DevError::ResourceBusy,
            AxError::Unsupported => DevError::Unsupported,
            _ => DevError::Io,
        }
    }
}