Files
rust-based-os-comp2022/guide/source/chapter6/1fs-interface.rst

113 lines
4.4 KiB
ReStructuredText
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
文件系统接口
=================================================
简易文件与目录抽象
-------------------------------------------------
与课堂所学相比,我们实现的文件系统进行了很大的简化:
- 扁平化:仅存在根目录 ``/`` 一个目录,所有的文件都放在根目录内。直接以文件名索引文件。
- 不设置用户和用户组概念,不记录文件访问/修改的任何时间戳,不支持软硬链接。
- 只实现了最基本的文件系统相关系统调用。
打开与读写文件的系统调用
--------------------------------------------------
打开文件
++++++++++++++++++++++++++++++++++++++++++++++++++
.. code-block:: rust
/// 功能:打开一个常规文件,并返回可以访问它的文件描述符。
/// 参数path 描述要打开的文件的文件名(简单起见,文件系统不需要支持目录,所有的文件都放在根目录 / 下),
/// flags 描述打开文件的标志,具体含义下面给出。
/// dirfd 和 mode 仅用于保证兼容性,忽略
/// 返回值:如果出现了错误则返回 -1否则返回打开常规文件的文件描述符。可能的错误原因是文件不存在。
/// syscall ID56
fn sys_openat(dirfd: usize, path: &str, flags: u32, mode: u32) -> isize
目前我们的内核支持以下几种标志(多种不同标志可能共存):
- 如果 ``flags`` 为 0则表示以只读模式 *RDONLY* 打开;
- 如果 ``flags`` 第 0 位被设置0x001表示以只写模式 *WRONLY* 打开;
- 如果 ``flags`` 第 1 位被设置0x002表示既可读又可写 *RDWR*
- 如果 ``flags`` 第 9 位被设置0x200表示允许创建文件 *CREATE* ,在找不到该文件的时候应创建文件;如果该文件已经存在则应该将该文件的大小归零;
- 如果 ``flags`` 第 10 位被设置0x400则在打开文件的时候应该清空文件的内容并将该文件的大小归零也即 *TRUNC*
在用户库 ``user_lib`` 中,我们将该系统调用封装为 ``open`` 接口:
.. code-block:: rust
// user/src/lib.rs
bitflags! {
pub struct OpenFlags: u32 {
const RDONLY = 0;
const WRONLY = 1 << 0;
const RDWR = 1 << 1;
const CREATE = 1 << 9;
const TRUNC = 1 << 10;
}
}
pub fn open(path: &str, flags: OpenFlags) -> isize {
sys_openat(AT_FDCWD as usize, path, flags.bits, OpenFlags::RDWR.bits)
}
借助 ``bitflags!`` 宏我们将一个 ``u32`` 的 flags 包装为一个 ``OpenFlags`` 结构体,可以从它的 ``bits`` 字段获得 ``u32`` 表示。
顺序读写文件
++++++++++++++++++++++++++++++++++++++++++++++++++
在打开一个文件之后,我们就可以用之前的 ``sys_read/sys_write`` 两个系统调用来对它进行读写了。本教程只实现文件的顺序读写,而不考虑随机读写。
以本章的测试用例 ``ch6b_filetest_simple`` 来介绍文件系统接口的使用方法:
.. code-block:: rust
:linenos:
// user/src/bin/ch6b_filetest_simple.rs
#![no_std]
#![no_main]
#[macro_use]
extern crate user_lib;
use user_lib::{
open,
close,
read,
write,
OpenFlags,
};
#[no_mangle]
pub fn main() -> i32 {
let test_str = "Hello, world!";
let filea = "filea\0";
let fd = open(filea, OpenFlags::CREATE | OpenFlags::WRONLY);
assert!(fd > 0);
let fd = fd as usize;
write(fd, test_str.as_bytes());
close(fd);
let fd = open(filea, OpenFlags::RDONLY);
assert!(fd > 0);
let fd = fd as usize;
let mut buffer = [0u8; 100];
let read_len = read(fd, &mut buffer) as usize;
close(fd);
assert_eq!(
test_str,
core::str::from_utf8(&buffer[..read_len]).unwrap(),
);
println!("file_test passed!");
0
}
- 第 20~25 行,我们以 *只写 + 创建* 的模式打开文件 ``filea`` ,向其中写入字符串 ``Hello, world!`` 而后关闭文件。
- 第 27~32 行,我们以只读 的方式将文件 ``filea`` 的内容读取到缓冲区 ``buffer`` 中。 ``filea`` 的总大小不超过缓冲区的大小,因此通过单次 ``read`` 即可将内容全部读出来而更常见的情况是需要进行多次 ``read`` ,直到返回值为 0 才能确认文件已被读取完毕。