2 个稳定版本

1.1.0 2024年6月8日
1.0.0 2024年5月6日
0.1.1 2024年5月6日
0.1.0 2024年5月6日

#310文件系统

Download history 278/week @ 2024-05-01 58/week @ 2024-05-08 2/week @ 2024-05-15 9/week @ 2024-05-22 176/week @ 2024-06-05 15/week @ 2024-06-12 2/week @ 2024-06-19 1/week @ 2024-06-26 32/week @ 2024-07-03

234 每月下载量

MIT 许可证

1MB
4K SLoC

一个跨平台的 rust ext4 crate

环境

wsl2 ubuntu22.04

rust 版本 nightly-2024-06-01

rustc 1.80.0-nightly (ada5e2c7b 2024-05-31)

运行示例

git clone https://github.com/yuoo655/ext4_rs.git
sh run.sh

fuse 示例

git clone https://github.com/yuoo655/ext4libtest.git
cd ext4libtest
sh gen_img.sh
# cargo run /path/to/mountpoint
cargo run ./foo/

特性

操作 支持情况
挂载
打开
关闭
列出目录
创建目录
读取文件
读取链接
创建文件
写入文件
链接
解除链接
文件截断
删除文件
卸载
删除目录

如何使用(dev 分支中的旧接口)

实现 BlockDevice Trait

#[derive(Debug)]
pub struct Disk {}

impl BlockDevice for Disk {
    fn read_offset(&self, offset: usize) -> Vec<u8> {
        use std::fs::OpenOptions;
        use std::io::{Read, Seek};
        let mut file = OpenOptions::new()
            .read(true)
            .write(true)
            .open("ex4.img")
            .unwrap();
        let mut buf = vec![0u8; BLOCK_SIZE as usize];
        let _r = file.seek(std::io::SeekFrom::Start(offset as u64));
        let _r = file.read_exact(&mut buf);

        buf
    }

    fn write_offset(&self, offset: usize, data: &[u8]) {
        use std::fs::OpenOptions;
        use std::io::{Seek, Write};
        let mut file = OpenOptions::new()
            .read(true)
            .write(true)
            .open("ex4.img")
            .unwrap();

        let _r = file.seek(std::io::SeekFrom::Start(offset as u64));
        let _r = file.write_all(&data);
    }
}

打开 ext4

let disk = Arc::new(Disk {});
let ext4 = Ext4::open(disk);

读取常规文件

let path = "/test_files/1.txt";
let mut ext4_file = Ext4File::new();
let r = ext4.ext4_open(&mut ext4_file, path, "r+", false);
assert!(r.is_ok(), "open file error {:?}", r.err());

let mut read_buf = vec![0u8; 0x20000000];
let mut read_cnt = 0;
let r = ext4.ext4_file_read(&mut ext4_file, &mut read_buf, 0x20000000, &mut read_cnt);
assert!(r.is_ok(), "open file error {:?}", r.err());
log::info!("----read link file----");
let path = "/test_files/linktest";
let mut ext4_file = Ext4File::new();
let r = ext4.ext4_open(&mut ext4_file, path, "r+", false);
assert!(r.is_ok(), "open link error {:?}", r.err());

let mut read_buf = vec![0u8; 0x1000];
let mut read_cnt = 0;
let r = ext4.ext4_file_read(&mut ext4_file, &mut read_buf, 0x1000, &mut read_cnt);
assert!(r.is_ok(), "read link error {:?}", r.err());
log::info!("read data sample {:x?}", &read_buf[0..10]);

创建目录

for i in 0..10 {
    let path = format!("dirtest{}", i);
    let path = path.as_str();
    let r = ext4.ext4_dir_mk(&path);
    assert!(r.is_ok(), "dir make error {:?}", r.err());
}

文件写入测试

const WRITE_SIZE: usize = 0x400000;
let path = format!("dirtest{}/write_{}.txt", i, i);
let path = path.as_str();
let mut ext4_file = Ext4File::new();
let r = ext4.ext4_open(&mut ext4_file, path, "w+", true);
assert!(r.is_ok(), "open file error {:?}", r.err());

let write_data = vec![0x41 + i as u8; WRITE_SIZE];
ext4.ext4_file_write(&mut ext4_file, &write_data, WRITE_SIZE);

// test
let r = ext4.ext4_open(&mut ext4_file, path, "r+", false);
assert!(r.is_ok(), "open file error {:?}", r.err());

let mut read_buf = vec![0u8; WRITE_SIZE];
let mut read_cnt = 0;
let r = ext4.ext4_file_read(&mut ext4_file, &mut read_buf, WRITE_SIZE, &mut read_cnt);
assert!(r.is_ok(), "open file error {:?}", r.err());
assert_eq!(write_data, read_buf);

列出

let path = "test_files";
let mut ext4_file = Ext4File::new();
let r = ext4.ext4_open(&mut ext4_file, path, "r+", false);
assert!(r.is_ok(), "open link error {:?}", r.err());

let de = ext4.read_dir_entry(ext4_file.inode as _);
for i in de.iter() {
    log::info!("{:?}", i.get_name());
}

删除文件

let path = "test_files/file_to_remove";
let r = ext4.ext4_file_remove(&path);

删除目录

let path = "dir_to_remove";
// remove dir from root inode 2
let r = ext4.ext4_dir_remove(2, &path);

依赖