فهرست منبع

refactor: divide ext4 into modules

liujingx 1 سال پیش
والد
کامیت
5471e30f9d

+ 6 - 5
src/constants.rs

@@ -4,10 +4,8 @@ use bitflags::bitflags;
 
 pub const EOK: usize = 0;
 
-#[allow(non_camel_case_types)]
-pub type ext4_lblk_t = u32;
-#[allow(non_camel_case_types)]
-pub type ext4_fsblk_t = u64;
+pub type Ext4LogicBlockId = u32;
+pub type Ext4FsBlockId = u64;
 
 pub const EXT4_INODE_FLAG_EXTENTS: usize = 0x00080000; /* Inode uses extents */
 pub const EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE: u16 = 32;
@@ -28,7 +26,7 @@ pub const EXT4_INODE_MODE_SOFTLINK: usize = 0xA000;
 pub const EXT4_INODE_MODE_SOCKET: usize = 0xC000;
 pub const EXT4_INODE_MODE_TYPE_MASK: u16 = 0xF000;
 
-pub const EXT_MAX_BLOCKS: ext4_lblk_t = core::u32::MAX;
+pub const EXT_MAX_BLOCKS: Ext4LogicBlockId = core::u32::MAX;
 
 /// Maximum bytes in a path
 pub const PATH_MAX: usize = 4096;
@@ -39,6 +37,9 @@ pub const NAME_MAX: usize = 255;
 /// The upper limit for resolving symbolic links
 pub const SYMLINKS_MAX: usize = 40;
 
+/// The inode number of root inode
+pub const EXT4_ROOT_INO: u32 = 2;
+
 #[allow(non_camel_case_types)]
 #[derive(Debug, PartialEq)]
 pub enum LibcOpenFlags {

+ 0 - 1405
src/ext4.rs

@@ -1,1405 +0,0 @@
-extern crate alloc;
-extern crate log;
-
-use crate::ext4_defs::*;
-use crate::constants::*;
-use crate::prelude::*;
-use crate::return_errno_with_message;
-use crate::utils::*;
-
-#[derive(Debug)]
-pub struct Ext4 {
-    pub block_device: Arc<dyn BlockDevice>,
-    pub super_block: Ext4Superblock,
-    pub block_groups: Vec<Ext4BlockGroup>,
-    pub inodes_per_group: u32,
-    pub blocks_per_group: u32,
-    pub inode_size: usize,
-    pub last_inode_bg_id: u32,
-    pub self_ref: Weak<Self>,
-    pub mount_point: Ext4MountPoint,
-}
-
-impl Ext4 {
-    /// Opens and loads an Ext4 from the `block_device`.
-    pub fn open(block_device: Arc<dyn BlockDevice>) -> Arc<Self> {
-        // Load the superblock
-        // TODO: if the main superblock is corrupted, should we load the backup?
-        let raw_data = block_device.read_offset(BASE_OFFSET);
-        let super_block = Ext4Superblock::try_from(raw_data).unwrap();
-
-        // log::info!("super_block: {:x?}", super_block);
-        let inodes_per_group = super_block.inodes_per_group();
-        let blocks_per_group = super_block.blocks_per_group();
-        let inode_size = super_block.inode_size();
-
-        // Load the block groups information
-        let load_block_groups =
-            |_fs: Weak<Ext4>, block_device: Arc<dyn BlockDevice>| -> Result<Vec<Ext4BlockGroup>> {
-                let block_groups_count = super_block.block_groups_count() as usize;
-                let mut block_groups = Vec::with_capacity(block_groups_count);
-                for idx in 0..block_groups_count {
-                    let block_group =
-                        Ext4BlockGroup::load(block_device.clone(), &super_block, idx).unwrap();
-                    block_groups.push(block_group);
-                }
-                Ok(block_groups)
-            };
-
-        let mount_point = Ext4MountPoint::new("/");
-
-        let ext4: Arc<Ext4> = Arc::new_cyclic(|weak_ref| Self {
-            super_block,
-            inodes_per_group,
-            blocks_per_group,
-            inode_size: inode_size as usize,
-            block_groups: load_block_groups(weak_ref.clone(), block_device.clone()).unwrap(),
-            block_device,
-            self_ref: weak_ref.clone(),
-            mount_point: mount_point,
-            last_inode_bg_id: 0,
-        });
-
-        ext4
-    }
-
-    // 使用libc库定义的常量
-    fn ext4_parse_flags(&self, flags: &str) -> Result<u32> {
-        match flags {
-            "r" | "rb" => Ok(O_RDONLY),
-            "w" | "wb" => Ok(O_WRONLY | O_CREAT | O_TRUNC),
-            "a" | "ab" => Ok(O_WRONLY | O_CREAT | O_APPEND),
-            "r+" | "rb+" | "r+b" => Ok(O_RDWR),
-            "w+" | "wb+" | "w+b" => Ok(O_RDWR | O_CREAT | O_TRUNC),
-            "a+" | "ab+" | "a+b" => Ok(O_RDWR | O_CREAT | O_APPEND),
-            _ => Err(Ext4Error::new(Errnum::EINVAL)),
-        }
-    }
-
-    // start transaction
-    pub fn ext4_trans_start(&self) {}
-
-    // stop transaction
-    pub fn ext4_trans_abort(&self) {}
-
-    pub fn update_super_block(&mut self) {
-        let raw_data = self.block_device.read_offset(BASE_OFFSET);
-        let super_block = Ext4Superblock::try_from(raw_data).unwrap();
-        self.super_block = super_block;
-    }
-
-    pub fn ext4_open(
-        &self,
-        file: &mut Ext4File,
-        path: &str,
-        flags: &str,
-        file_expect: bool,
-    ) -> Result<usize> {
-        // get mount point
-        let mut ptr = Box::new(self.mount_point.clone());
-        file.mp = Box::as_mut(&mut ptr) as *mut Ext4MountPoint;
-
-        // get open flags
-        let iflags = self.ext4_parse_flags(flags).unwrap();
-
-        // file for dir
-        let filetype = if file_expect {
-            DirEntryType::EXT4_DE_REG_FILE
-        } else {
-            DirEntryType::EXT4_DE_DIR
-        };
-
-        if iflags & O_CREAT != 0 {
-            self.ext4_trans_start();
-        }
-
-        let mut root_inode_ref = Ext4InodeRef::get_inode_ref(self.self_ref.clone(), 2);
-
-        let r = self.ext4_generic_open(file, path, iflags, filetype.bits(), &mut root_inode_ref);
-
-        r
-    }
-
-    pub fn ext4_dir_mk(&self, path: &str) -> Result<usize> {
-        let mut file = Ext4File::new();
-        let flags = "w";
-
-        let filetype = DirEntryType::EXT4_DE_DIR;
-
-        // get mount point
-        let mut ptr = Box::new(self.mount_point.clone());
-        file.mp = Box::as_mut(&mut ptr) as *mut Ext4MountPoint;
-
-        // get open flags
-        let iflags = self.ext4_parse_flags(flags).unwrap();
-
-        if iflags & O_CREAT != 0 {
-            self.ext4_trans_start();
-        }
-
-        let mut root_inode_ref = Ext4InodeRef::get_inode_ref(self.self_ref.clone(), 2);
-
-        let r = self.ext4_generic_open(
-            &mut file,
-            path,
-            iflags,
-            filetype.bits(),
-            &mut root_inode_ref,
-        );
-        r
-    }
-
-    pub fn ext4_generic_open(
-        &self,
-        file: &mut Ext4File,
-        path: &str,
-        iflags: u32,
-        ftype: u8,
-        parent_inode: &mut Ext4InodeRef,
-    ) -> Result<usize> {
-        let mut is_goal = false;
-
-        let mut data: Vec<u8> = Vec::with_capacity(BLOCK_SIZE);
-        let ext4_blk = Ext4Block {
-            logical_block_id: 0,
-            disk_block_id: 0,
-            block_data: &mut data,
-            dirty: true,
-        };
-        let de = Ext4DirEntry::default();
-        let mut dir_search_result = Ext4DirSearchResult::new(ext4_blk, de);
-
-        file.flags = iflags;
-
-        // load root inode
-        let root_inode_ref = Ext4InodeRef::get_inode_ref(self.self_ref.clone(), 2);
-
-        // if !parent_inode.is_none() {
-        //     parent_inode.unwrap().inode_num = root_inode_ref.inode_num;
-        // }
-
-        // search dir
-        let mut search_parent = root_inode_ref;
-        let mut search_path = ext4_path_skip(&path, ".");
-        let mut len;
-        loop {
-            search_path = ext4_path_skip(search_path, "/");
-            len = ext4_path_check(search_path, &mut is_goal);
-
-            let r = ext4_dir_find_entry(
-                &mut search_parent,
-                &search_path[..len as usize],
-                len as u32,
-                &mut dir_search_result,
-            );
-
-            // log::info!("dir_search_result.dentry {:?} r {:?}", dir_search_result.dentry, r);
-            if r != EOK {
-                // ext4_dir_destroy_result(&mut root_inode_ref, &mut dir_search_result);
-
-                if r != ENOENT {
-                    // dir search failed with error other than ENOENT
-                    return_errno_with_message!(Errnum::ENOTSUP, "dir search failed");
-                }
-
-                if !((iflags & O_CREAT) != 0) {
-                    return_errno_with_message!(Errnum::ENOENT, "file not found");
-                }
-
-                let mut child_inode_ref = Ext4InodeRef::new(self.self_ref.clone());
-
-                let r = if is_goal {
-                    ext4_fs_alloc_inode(&mut child_inode_ref, ftype)
-                } else {
-                    ext4_fs_alloc_inode(&mut child_inode_ref, DirEntryType::EXT4_DE_DIR.bits())
-                };
-
-                if r != EOK {
-                    return_errno_with_message!(Errnum::EALLOCFIAL, "alloc inode fail");
-                    // break;
-                }
-
-                ext4_fs_inode_blocks_init(&mut child_inode_ref);
-
-                let r = ext4_link(
-                    &mut search_parent,
-                    &mut child_inode_ref,
-                    &search_path[..len as usize],
-                    len as u32,
-                );
-
-                if r != EOK {
-                    /*Fail. Free new inode.*/
-                    return_errno_with_message!(Errnum::ELINKFIAL, "link fail");
-                }
-
-                ext4_fs_put_inode_ref_csum(&mut search_parent);
-                ext4_fs_put_inode_ref_csum(&mut child_inode_ref);
-                ext4_fs_put_inode_ref_csum(parent_inode);
-
-                continue;
-            }
-
-            let _name = get_name(
-                dir_search_result.dentry.name,
-                dir_search_result.dentry.name_len as usize,
-            )
-            .unwrap();
-            // log::info!("find de name{:?} de inode {:x?}", name, dir_search_result.dentry.inode);
-
-            if is_goal {
-                file.inode = dir_search_result.dentry.inode;
-                return Ok(EOK);
-            } else {
-                search_parent = Ext4InodeRef::get_inode_ref(
-                    self.self_ref.clone(),
-                    dir_search_result.dentry.inode,
-                );
-                search_path = &search_path[len..];
-            }
-        }
-    }
-
-    pub fn ext4_file_read(&self, ext4_file: &mut Ext4File) -> Vec<u8> {
-        // 创建一个空的向量,用于存储文件的内容
-        let mut file_data: Vec<u8> = Vec::new();
-
-        // 创建一个空的向量,用于存储文件的所有extent信息
-        let mut extents: Vec<Ext4Extent> = Vec::new();
-
-        let inode_ref = Ext4InodeRef::get_inode_ref(self.self_ref.clone(), ext4_file.inode);
-
-        ext4_find_all_extent(&inode_ref, &mut extents);
-
-        // 遍历extents向量,对每个extent,计算它的物理块号,然后调用read_block函数来读取数据块,并将结果追加到file_data向量中
-        for extent in extents {
-            // 获取extent的起始块号、块数和逻辑块号
-            let start_block = extent.start_lo as u64 | ((extent.start_hi as u64) << 32);
-            let block_count = extent.block_count as u64;
-            let logical_block = extent.first_block as u64;
-            // 计算extent的物理块号
-            let physical_block = start_block + logical_block;
-            // 从file中读取extent的所有数据块,并将结果追加到file_data向量中
-            for i in 0..block_count {
-                let block_num = physical_block + i;
-                let block_data = inode_ref
-                    .fs()
-                    .block_device
-                    .read_offset(block_num as usize * BLOCK_SIZE);
-                file_data.extend(block_data);
-            }
-        }
-        file_data
-    }
-
-    pub fn ext4_file_write(&self, ext4_file: &mut Ext4File, data: &[u8], size: usize) {
-        let super_block_data = self.block_device.read_offset(BASE_OFFSET);
-        let super_block = Ext4Superblock::try_from(super_block_data).unwrap();
-        let mut inode_ref = Ext4InodeRef::get_inode_ref(self.self_ref.clone(), ext4_file.inode);
-        let block_size = super_block.block_size() as usize;
-        let iblock_last = ext4_file.fpos as usize + size / block_size;
-        let mut iblk_idx = ext4_file.fpos as usize / block_size;
-        let ifile_blocks = ext4_file.fsize as usize + block_size - 1 / block_size;
-
-        let mut fblk = 0;
-        let mut fblock_start = 0;
-        let mut fblock_count = 0;
-
-        let mut size = size;
-        while size >= block_size {
-            while iblk_idx < iblock_last {
-                if iblk_idx < ifile_blocks {
-                    ext4_fs_append_inode_dblk(&mut inode_ref, &mut (iblk_idx as u32), &mut fblk);
-                }
-
-                iblk_idx += 1;
-
-                if fblock_start == 0 {
-                    fblock_start = fblk;
-                }
-                fblock_count += 1;
-            }
-            size -= block_size;
-        }
-
-        for i in 0..fblock_count {
-            let idx = i * BLOCK_SIZE as usize;
-            let offset = (fblock_start as usize + i as usize) * BLOCK_SIZE;
-            self.block_device
-                .write_offset(offset, &data[idx..(idx + BLOCK_SIZE as usize)]);
-        }
-        // inode_ref.inner.inode.size = fblock_count as u32 * BLOCK_SIZE as u32;
-        inode_ref.write_back_inode();
-        // let mut inode_ref = Ext4InodeRef::get_inode_ref(self.self_ref.clone(), ext4_file.inode);
-        let mut root_inode_ref = Ext4InodeRef::get_inode_ref(self.self_ref.clone(), 2);
-        root_inode_ref.write_back_inode();
-    }
-
-    pub fn ext4_file_remove(&self, _path: &str) -> Result<usize> {
-        return_errno_with_message!(Errnum::ENOTSUP, "not support");
-    }
-
-    pub fn ext4_dir_remove(&self, _path: &str) -> Result<usize> {
-        return_errno_with_message!(Errnum::ENOTSUP, "not support");
-    }
-}
-
-pub fn ext4_fs_put_inode_ref_csum(inode_ref: &mut Ext4InodeRef) {
-    inode_ref.write_back_inode();
-}
-
-pub fn ext4_fs_put_inode_ref(inode_ref: &mut Ext4InodeRef) {
-    inode_ref.write_back_inode_without_csum();
-}
-
-pub fn ext4_link(
-    parent: &mut Ext4InodeRef,
-    child: &mut Ext4InodeRef,
-    name: &str,
-    name_len: u32,
-) -> usize {
-    // log::info!("link parent inode {:x?} child inode {:x?} name {:?}", parent.inode_num, child.inode_num, name);
-    /* Add entry to parent directory */
-    let _r = ext4_dir_add_entry(parent, child, name, name_len);
-
-    /* Fill new dir -> add '.' and '..' entries.
-     * Also newly allocated inode should have 0 link count.
-    	*/
-    let mut is_dir = false;
-    if child.inner.inode.mode & EXT4_INODE_MODE_TYPE_MASK as u16 == EXT4_INODE_MODE_DIRECTORY as u16
-    {
-        is_dir = true;
-    }
-
-    if is_dir {
-        // add '.' and '..' entries
-        let fs = child.fs().self_ref.clone();
-        let mut child_inode_ref = Ext4InodeRef::new(fs);
-        child_inode_ref.inode_num = child.inode_num;
-        child_inode_ref.inner.inode = child.inner.inode.clone();
-
-        let _r = ext4_dir_add_entry(&mut child_inode_ref, child, ".", 1);
-        child.inner.inode.size = child_inode_ref.inner.inode.size;
-        child.inner.inode.block = child_inode_ref.inner.inode.block;
-        let _r = ext4_dir_add_entry(&mut child_inode_ref, parent, "..", 2);
-
-        child.inner.inode.links_count = 2;
-        parent.inner.inode.links_count += 1;
-
-        return EOK;
-    }
-
-    child.inner.inode.links_count += 1;
-    EOK
-}
-
-pub fn ext4_dir_add_entry(
-    parent: &mut Ext4InodeRef,
-    child: &mut Ext4InodeRef,
-    path: &str,
-    len: u32,
-) -> usize {
-    let mut iblock = 0;
-    let block_size = parent.fs().super_block.block_size();
-    let inode_size = parent.inner.inode.ext4_inode_get_size();
-    // let inode_size = parent.fs().super_block.inode_size_file(&parent.inner.inode);
-    let total_blocks = inode_size as u32 / block_size;
-
-    let mut fblock: ext4_fsblk_t = 0;
-
-    // log::info!("ext4_dir_add_entry parent inode {:x?} inode_size {:x?}", parent.inode_num, inode_size);
-    while iblock < total_blocks {
-        ext4_fs_get_inode_dblk_idx(parent, &mut iblock, &mut fblock, false);
-
-        // load_block
-        let mut data = parent
-            .fs()
-            .block_device
-            .read_offset(fblock as usize * BLOCK_SIZE);
-        let mut ext4_block = Ext4Block {
-            logical_block_id: iblock,
-            disk_block_id: fblock,
-            block_data: &mut data,
-            dirty: false,
-        };
-
-        let r = ext4_dir_try_insert_entry(parent, &mut ext4_block, child, path, len);
-
-        if r == EOK {
-            return EOK;
-            // break;
-        }
-        let mut data: Vec<u8> = Vec::with_capacity(BLOCK_SIZE);
-        let ext4_blk = Ext4Block {
-            logical_block_id: 0,
-            disk_block_id: 0,
-            block_data: &mut data,
-            dirty: true,
-        };
-        let de = Ext4DirEntry::default();
-        let mut dir_search_result = Ext4DirSearchResult::new(ext4_blk, de);
-
-        let r = ext4_dir_find_in_block(&mut ext4_block, path, len, &mut dir_search_result);
-
-        if r {
-            return EOK;
-        }
-
-        iblock += 1;
-    }
-
-    /* No free block found - needed to allocate next data block */
-    iblock = 0;
-    fblock = 0;
-
-    ext4_fs_append_inode_dblk(parent, &mut (iblock as u32), &mut fblock);
-
-    /* Load new block */
-    let block_device = parent.fs().block_device.clone();
-    let mut data = block_device.read_offset(fblock as usize * BLOCK_SIZE);
-    let mut ext4_block = Ext4Block {
-        logical_block_id: iblock,
-        disk_block_id: fblock,
-        block_data: &mut data,
-        dirty: false,
-    };
-
-    let mut new_entry = Ext4DirEntry::default();
-    let el = BLOCK_SIZE - size_of::<Ext4DirEntryTail>();
-    ext4_dir_write_entry(&mut new_entry, el as u16, &child, path, len);
-
-    copy_dir_entry_to_array(&new_entry, &mut ext4_block.block_data, 0);
-
-    // init tail
-    let ptr = ext4_block.block_data.as_mut_ptr();
-    let mut tail = unsafe {
-        *(ptr.add(BLOCK_SIZE - core::mem::size_of::<Ext4DirEntryTail>()) as *mut Ext4DirEntryTail)
-    };
-    tail.rec_len = size_of::<Ext4DirEntryTail>() as u16;
-    tail.reserved_ft = 0xDE;
-    tail.reserved_zero1 = 0;
-    tail.reserved_zero2 = 0;
-
-    tail.ext4_dir_set_csum(
-        &parent.fs().super_block,
-        &new_entry,
-        &ext4_block.block_data[..],
-    );
-
-    let tail_offset = BLOCK_SIZE - size_of::<Ext4DirEntryTail>();
-    copy_diren_tail_to_array(&tail, &mut ext4_block.block_data, tail_offset);
-
-    tail.ext4_dir_set_csum(
-        &parent.fs().super_block,
-        &new_entry,
-        &ext4_block.block_data[..],
-    );
-
-    ext4_block.sync_blk_to_disk(block_device.clone());
-
-    // struct ext4_block b;
-
-    EOK
-}
-
-pub fn ext4_dir_try_insert_entry(
-    parent: &Ext4InodeRef,
-    dst_blk: &mut Ext4Block,
-    child: &mut Ext4InodeRef,
-    name: &str,
-    name_len: u32,
-) -> usize {
-    let mut required_len = core::mem::size_of::<Ext4DirEntry>() + name_len as usize;
-
-    if required_len % 4 != 0 {
-        required_len += 4 - required_len % 4;
-    }
-
-    let mut offset = 0;
-
-    while offset < dst_blk.block_data.len() {
-        let mut de = Ext4DirEntry::try_from(&dst_blk.block_data[offset..]).unwrap();
-        if de.inode == 0 {
-            continue;
-        }
-        let inode = de.inode;
-        let rec_len = de.entry_len;
-
-        // 如果是有效的目录项,尝试分割它
-        if inode != 0 {
-            let used_len = de.name_len as usize;
-            let mut sz = core::mem::size_of::<Ext4FakeDirEntry>() + used_len as usize;
-
-            if used_len % 4 != 0 {
-                sz += 4 - used_len % 4;
-            }
-
-            let free_space = rec_len as usize - sz;
-
-            // 如果有足够的空闲空间
-            if free_space >= required_len {
-                let mut new_entry = Ext4DirEntry::default();
-
-                de.entry_len = sz as u16;
-                ext4_dir_write_entry(&mut new_entry, free_space as u16, &child, name, name_len);
-
-                // update parent new_de to blk_data
-                copy_dir_entry_to_array(&de, &mut dst_blk.block_data, offset);
-                copy_dir_entry_to_array(&new_entry, &mut dst_blk.block_data, offset + sz);
-
-                // set tail csum
-                let mut tail = Ext4DirEntryTail::from(&mut dst_blk.block_data, BLOCK_SIZE).unwrap();
-                let block_device = parent.fs().block_device.clone();
-                tail.ext4_dir_set_csum(
-                    &parent.fs().super_block,
-                    &de,
-                    &dst_blk.block_data[offset..],
-                );
-
-                let parent_de = Ext4DirEntry::try_from(&dst_blk.block_data[..]).unwrap();
-                tail.ext4_dir_set_csum(
-                    &parent.fs().super_block,
-                    &parent_de,
-                    &dst_blk.block_data[..],
-                );
-
-                let tail_offset = BLOCK_SIZE - size_of::<Ext4DirEntryTail>();
-                copy_diren_tail_to_array(&tail, &mut dst_blk.block_data, tail_offset);
-
-                // sync to disk
-                dst_blk.sync_blk_to_disk(block_device.clone());
-
-                return EOK;
-            }
-        }
-        offset = offset + de.entry_len as usize;
-    }
-
-    ENOSPC
-}
-
-// 写入一个ext4目录项
-pub fn ext4_dir_write_entry(
-    en: &mut Ext4DirEntry,
-    entry_len: u16,
-    child: &Ext4InodeRef,
-    name: &str,
-    name_len: u32,
-) {
-    let file_type = (child.inner.inode.mode & EXT4_INODE_MODE_TYPE_MASK) as usize;
-
-    // 设置目录项的类型
-    match file_type {
-        EXT4_INODE_MODE_FILE => en.inner.inode_type = DirEntryType::EXT4_DE_REG_FILE.bits(),
-        EXT4_INODE_MODE_DIRECTORY => en.inner.inode_type = DirEntryType::EXT4_DE_DIR.bits(),
-        EXT4_INODE_MODE_CHARDEV => en.inner.inode_type = DirEntryType::EXT4_DE_CHRDEV.bits(),
-        EXT4_INODE_MODE_BLOCKDEV => en.inner.inode_type = DirEntryType::EXT4_DE_BLKDEV.bits(),
-        EXT4_INODE_MODE_FIFO => en.inner.inode_type = DirEntryType::EXT4_DE_FIFO.bits(),
-        EXT4_INODE_MODE_SOCKET => en.inner.inode_type = DirEntryType::EXT4_DE_SOCK.bits(),
-        EXT4_INODE_MODE_SOFTLINK => en.inner.inode_type = DirEntryType::EXT4_DE_SYMLINK.bits(),
-        _ => log::info!("{}: unknown type", file_type),
-    }
-
-    en.inode = child.inode_num;
-    en.entry_len = entry_len;
-    en.name_len = name_len as u8;
-
-    let en_name_ptr = en.name.as_mut_ptr();
-    unsafe {
-        en_name_ptr.copy_from_nonoverlapping(name.as_ptr(), name_len as usize);
-    }
-    let _name = get_name(en.name, en.name_len as usize).unwrap();
-    // log::info!("ext4_dir_write_entry name {:?}", name);
-}
-
-pub fn ext4_fs_append_inode_dblk(
-    inode_ref: &mut Ext4InodeRef,
-    iblock: &mut ext4_lblk_t,
-    fblock: &mut ext4_fsblk_t,
-) {
-    let inode_size = inode_ref.inner.inode.ext4_inode_get_size();
-    let block_size = BLOCK_SIZE as u64;
-
-    *iblock = ((inode_size + block_size - 1) / block_size) as u32;
-
-    let mut current_fsblk: ext4_fsblk_t = 0;
-    ext4_extent_get_blocks(inode_ref, *iblock, 1, &mut current_fsblk, true, &mut 0);
-
-    let current_block = current_fsblk;
-    *fblock = current_block;
-
-    inode_ref
-        .inner
-        .inode
-        .ext4_inode_set_size(inode_size + BLOCK_SIZE as u64);
-
-    inode_ref.write_back_inode();
-
-    // let mut inode_ref = Ext4InodeRef::get_inode_ref(inode_ref.fs().self_ref.clone(), inode_ref.inode_num);
-
-    // log::info!("ext4_fs_append_inode_dblk inode {:x?} inode_size {:x?}", inode_ref.inode_num, inode_ref.inner.inode.size);
-    // log::info!("fblock {:x?}", fblock);
-}
-
-pub fn ext4_fs_inode_blocks_init(inode_ref: &mut Ext4InodeRef) {
-    // log::info!(
-    //     "ext4_fs_inode_blocks_init mode {:x?}",
-    //     inode_ref.inner.inode.mode
-    // );
-
-    let inode = &mut inode_ref.inner.inode;
-
-    let mode = inode.mode;
-
-    let inode_type = InodeMode::from_bits(mode & EXT4_INODE_MODE_TYPE_MASK as u16).unwrap();
-
-    match inode_type {
-        InodeMode::S_IFDIR => {}
-        InodeMode::S_IFREG => {}
-        /* Reset blocks array. For inode which is not directory or file, just
-         * fill in blocks with 0 */
-        _ => {
-            log::info!("inode_type {:?}", inode_type);
-            return;
-        }
-    }
-
-    /* Initialize extents */
-    inode.ext4_inode_set_flags(EXT4_INODE_FLAG_EXTENTS as u32);
-
-    /* Initialize extent root header */
-    inode.ext4_extent_tree_init();
-    // log::info!("inode iblock {:x?}", inode.block);
-
-    // inode_ref.dirty = true;
-}
-
-pub fn ext4_fs_alloc_inode(child_inode_ref: &mut Ext4InodeRef, filetype: u8) -> usize {
-    let mut is_dir = false;
-
-    let inode_size = child_inode_ref.fs().super_block.inode_size();
-    let extra_size = child_inode_ref.fs().super_block.extra_size();
-
-    if filetype == DirEntryType::EXT4_DE_DIR.bits() {
-        is_dir = true;
-    }
-
-    let mut index = 0;
-    let _rc = ext4_ialloc_alloc_inode(child_inode_ref.fs(), &mut index, is_dir);
-
-    child_inode_ref.inode_num = index;
-
-    let inode = &mut child_inode_ref.inner.inode;
-
-    /* Initialize i-node */
-
-    let mode = if is_dir {
-        0o777 | EXT4_INODE_MODE_DIRECTORY as u16
-    } else if filetype == 0x7 {
-        0o777 | EXT4_INODE_MODE_SOFTLINK as u16
-    } else {
-        let t = ext4_fs_correspond_inode_mode(filetype);
-        // log::info!("ext4_fs_correspond_inode_mode {:x?}", ext4_fs_correspond_inode_mode(filetype));
-        0o666 | t as u16
-    };
-
-    inode.ext4_inode_set_mode(mode);
-    inode.ext4_inode_set_links_cnt(0);
-    inode.ext4_inode_set_uid(0);
-    inode.ext4_inode_set_gid(0);
-    inode.ext4_inode_set_size(0);
-    inode.ext4_inode_set_access_time(0);
-    inode.ext4_inode_set_change_inode_time(0);
-    inode.ext4_inode_set_modif_time(0);
-    inode.ext4_inode_set_del_time(0);
-    inode.ext4_inode_set_flags(0);
-    inode.ext4_inode_set_generation(0);
-
-    if inode_size > EXT4_GOOD_OLD_INODE_SIZE {
-        let extra_size = extra_size;
-        inode.ext4_inode_set_extra_isize(extra_size);
-    }
-
-    EOK
-}
-pub fn ext4_dir_destroy_result(_inode_ref: &mut Ext4InodeRef, result: &mut Ext4DirSearchResult) {
-    result.block.logical_block_id = 0;
-    result.block.disk_block_id = 0;
-    result.dentry = Ext4DirEntry::default();
-}
-
-pub fn ext4_dir_find_entry(
-    parent: &mut Ext4InodeRef,
-    name: &str,
-    name_len: u32,
-    result: &mut Ext4DirSearchResult,
-) -> usize {
-    // log::info!("ext4_dir_find_entry parent {:x?} {:?}",parent.inode_num,  name);
-    let mut iblock = 0;
-    let mut fblock: ext4_fsblk_t = 0;
-
-    let inode_size: u32 = parent.inner.inode.size;
-    let total_blocks: u32 = inode_size / BLOCK_SIZE as u32;
-
-    while iblock < total_blocks {
-        ext4_fs_get_inode_dblk_idx(parent, &mut iblock, &mut fblock, false);
-
-        // load_block
-        let mut data = parent
-            .fs()
-            .block_device
-            .read_offset(fblock as usize * BLOCK_SIZE);
-        let mut ext4_block = Ext4Block {
-            logical_block_id: iblock,
-            disk_block_id: fblock,
-            block_data: &mut data,
-            dirty: false,
-        };
-
-        let r = ext4_dir_find_in_block(&mut ext4_block, name, name_len, result);
-        if r {
-            return EOK;
-        }
-
-        iblock += 1
-    }
-
-    ENOENT
-}
-
-pub fn ext4_extent_get_blocks(
-    inode_ref: &mut Ext4InodeRef,
-    iblock: ext4_lblk_t,
-    max_blocks: u32,
-    result: &mut ext4_fsblk_t,
-    create: bool,
-    blocks_count: &mut u32,
-) {
-    *result = 0;
-    *blocks_count = 0;
-
-    let mut path: Option<Vec<Ext4ExtentPath>> = None;
-    let err = ext4_find_extent(inode_ref, iblock, &mut path, 0);
-
-    let inode = &inode_ref.inner.inode;
-    // 确认ext4_find_extent成功执行
-    if err != EOK {
-        return;
-    }
-
-    let depth = unsafe { *ext4_inode_hdr(inode) }.depth as usize;
-    let mut path = path.unwrap();
-
-    if !path[depth].extent.is_null() {
-        let ex = unsafe { *path[depth].extent };
-        let ee_block = ex.first_block;
-        let ee_start = ext4_ext_pblock(&ex);
-        let ee_len = ext4_ext_get_actual_len(&ex);
-
-        if iblock >= ee_block && iblock < ee_block + ee_len as u32 {
-            let allocated = ee_len - (iblock - ee_block) as u16;
-            *blocks_count = allocated as u32;
-
-            if !create || ext4_ext_is_unwritten(&ex) {
-                *result = (iblock - ee_block + ee_start) as u64;
-                return;
-            }
-        }
-    }
-
-    // 如果没有找到对应的extent,并且create为true,则需要分配和插入新的extent
-    if create {
-        let next = EXT_MAX_BLOCKS;
-
-        let mut allocated = next - iblock;
-        if allocated > max_blocks {
-            allocated = max_blocks;
-        }
-
-        let mut newex: Ext4Extent = Ext4Extent::default();
-
-        let goal = 0;
-
-        let mut alloc_block = 0;
-        ext4_balloc_alloc_block(inode_ref, goal as u64, &mut alloc_block);
-
-        *result = alloc_block;
-
-        // 创建并插入新的extent
-        newex.first_block = iblock;
-        newex.start_lo = alloc_block as u32 & 0xffffffff;
-        newex.start_hi = (((alloc_block as u32) << 31) << 1) as u16;
-        newex.block_count = allocated as u16;
-
-        ext4_ext_insert_extent(inode_ref, &mut path[0], &newex, 0);
-    }
-}
-
-pub fn ext_inode_hdr(inode: &Ext4Inode) -> *const Ext4ExtentHeader {
-    let eh = &inode.block as *const [u32; 15] as *const Ext4ExtentHeader;
-    eh
-}
-
-pub fn ext_depth(inode: &Ext4Inode) -> u16 {
-    let header = ext_inode_hdr(inode);
-    unsafe { (*header).depth }
-}
-
-pub fn ext_last_extent(eh: *const Ext4ExtentHeader) -> *mut Ext4Extent {
-    // 如果头部为空,返回空指针
-    if eh.is_null() {
-        return ptr::null_mut();
-    }
-
-    // 获取头部的extent数
-    let count = unsafe { (*eh).entries_count };
-
-    // 如果extent数为0,返回空指针
-    if count == 0 {
-        return ptr::null_mut();
-    }
-
-    // 获取头部中第一个extent的指针
-    let first = ext_first_extent(eh);
-
-    // 返回头部中最后一个extent的指针,即第一个extent的指针加上extent数减一
-    return unsafe { first.add((count - 1) as usize) };
-}
-
-// ext_first_extent函数
-pub fn ext_first_extent(eh: *const Ext4ExtentHeader) -> *mut Ext4Extent {
-    // 如果头部为空,返回空指针
-    if eh.is_null() {
-        return ptr::null_mut();
-    }
-
-    // // 获取头部的extent数
-    // let count = unsafe { (*eh).entries_count };
-
-    // // 如果extent数为0,返回空指针
-    // if count == 0 {
-    //     return ptr::null_mut();
-    // }
-
-    // 返回头部中第一个extent的指针,即头部的指针加上头部的大小
-    return unsafe { (eh as *mut u8).add(mem::size_of::<Ext4ExtentHeader>()) as *mut Ext4Extent };
-}
-
-pub fn ext4_ext_pblock(ex: &Ext4Extent) -> u32 {
-    let mut block = ex.start_lo;
-    block |= ((ex.start_hi as u32) << 31) << 1;
-    block
-}
-
-pub fn ext4_ext_is_unwritten(ext: &Ext4Extent) -> bool {
-    // 返回extent是否是未写入的
-    ext.block_count > EXT_INIT_MAX_LEN
-}
-
-pub fn ext4_ext_get_actual_len(ext: &Ext4Extent) -> u16 {
-    // 返回extent的实际长度
-    if ext.block_count <= EXT_INIT_MAX_LEN {
-        ext.block_count
-    } else {
-        ext.block_count - EXT_INIT_MAX_LEN
-    }
-}
-
-pub fn ext4_ext_mark_unwritten(ext: *mut Ext4Extent) {
-    unsafe {
-        (*ext).block_count |= EXT_INIT_MAX_LEN;
-    }
-}
-
-pub fn ext4_ext_can_append(ex1: &Ext4Extent, ex2: &Ext4Extent) -> bool {
-    // 检查是否可以将ex2合并到ex1的后面
-    // log::info!(
-    //     "\n\npblock1={:x?} pblock2={:x?}",
-    //     ext4_ext_pblock(ex1),
-    //     ext4_ext_pblock(ex2)
-    // );
-    // log::info!(
-    //     "len1={:x?} len2={:x?}",
-    //     ext4_ext_get_actual_len(ex1),
-    //     ext4_ext_get_actual_len(ex2)
-    // );
-    // log::info!(
-    //     "first_block1={:x?} first_block2={:x?}",
-    //     ex1.first_block, ex2.first_block
-    // );
-    if ext4_ext_pblock(ex1) + ext4_ext_get_actual_len(ex1) as u32 != ext4_ext_pblock(ex2) {
-        return false;
-    }
-
-    if ext4_ext_is_unwritten(ex1) {
-        if ext4_ext_get_actual_len(ex1) + ext4_ext_get_actual_len(ex2) > EXT_UNWRITTEN_MAX_LEN {
-            return false;
-        }
-    } else if ext4_ext_get_actual_len(ex1) + ext4_ext_get_actual_len(ex2) > EXT_INIT_MAX_LEN {
-        return false;
-    }
-
-    // 检查逻辑块号是否连续
-    if ex1.first_block + ext4_ext_get_actual_len(ex1) as u32 != ex2.first_block {
-        return false;
-    }
-    return true;
-}
-
-pub fn ext4_ext_can_prepend(ex1: &Ext4Extent, ex2: &Ext4Extent) -> bool {
-    // 检查是否可以将ex2合并到ex1的前面
-    if ext4_ext_pblock(ex2) + ext4_ext_get_actual_len(ex2) as u32 != ext4_ext_pblock(ex1) {
-        return false;
-    }
-    if ext4_ext_is_unwritten(ex1) {
-        if ext4_ext_get_actual_len(ex1) + ext4_ext_get_actual_len(ex2) > EXT_UNWRITTEN_MAX_LEN {
-            return false;
-        }
-    } else if ext4_ext_get_actual_len(ex1) + ext4_ext_get_actual_len(ex2) > EXT_INIT_MAX_LEN {
-        return false;
-    }
-
-    // 检查逻辑块号是否连续
-    if ex2.first_block + ext4_ext_get_actual_len(ex2) as u32 != ex1.first_block {
-        return false;
-    }
-
-    // 如果以上条件都满足,返回true
-    true
-}
-
-pub fn ext4_ext_insert_extent(
-    inode_ref: &mut Ext4InodeRef,
-    path: &mut Ext4ExtentPath,
-    newext: &Ext4Extent,
-    flags: i32,
-) {
-    let depth = ext_depth(&inode_ref.inner.inode);
-    let mut need_split = false;
-
-    ext4_ext_insert_leaf(inode_ref, path, depth, newext, flags, &mut need_split);
-
-    inode_ref.write_back_inode_without_csum();
-}
-
-pub fn ext4_ext_insert_leaf(
-    _inode_ref: &mut Ext4InodeRef,
-    path: &mut Ext4ExtentPath,
-    _depth: u16,
-    newext: &Ext4Extent,
-    _flags: i32,
-    need_split: &mut bool,
-) -> usize {
-    let eh = path.header;
-    let ex = path.extent;
-    let _last_ex = ext_last_extent(eh);
-
-    let mut diskblock = newext.start_lo;
-    diskblock |= ((newext.start_hi as u32) << 31) << 1;
-
-    unsafe {
-        if !ex.is_null() && ext4_ext_can_append(&*(path.extent), newext) {
-            if ext4_ext_is_unwritten(&*(path.extent)) {
-                ext4_ext_mark_unwritten((*path).extent);
-            }
-            (*(path.extent)).block_count =
-                ext4_ext_get_actual_len(&*(path.extent)) + ext4_ext_get_actual_len(&newext);
-            (*path).p_block = diskblock as u64;
-            return EOK;
-        }
-
-        if !ex.is_null() && ext4_ext_can_prepend(&*(path.extent), newext) {
-            (*(path.extent)).block_count =
-                ext4_ext_get_actual_len(&*(path.extent)) + ext4_ext_get_actual_len(&newext);
-            (*path).p_block = diskblock as u64;
-
-            if ext4_ext_is_unwritten(&*(path.extent)) {
-                ext4_ext_mark_unwritten((*path).extent);
-            }
-            return EOK;
-        }
-    }
-
-    if ex.is_null() {
-        let first_extent = ext_first_extent(eh);
-        path.extent = first_extent;
-        // log::info!("first_extent {:x?}", unsafe{*first_extent});
-        unsafe {
-            if (*eh).entries_count == (*eh).max_entries_count {
-                *need_split = true;
-                return EIO;
-            } else {
-                *(path.extent) = *newext;
-            }
-        }
-    }
-
-    unsafe {
-        if (*eh).entries_count == (*eh).max_entries_count {
-            *need_split = true;
-            *(path.extent) = *newext;
-
-            (*path).p_block = diskblock as u64;
-            return EIO;
-        } else {
-            if ex.is_null() {
-                let first_extent = ext_first_extent(eh);
-                path.extent = first_extent;
-                *(path.extent) = *newext;
-            } else if newext.first_block > (*(path.extent)).first_block {
-                // insert after
-                let next_extent = ex.add(1);
-                path.extent = next_extent;
-            } else {
-            }
-        }
-
-        *(path.extent) = *newext;
-        (*eh).entries_count += 1;
-    }
-    unsafe {
-        *(path.extent) = *newext;
-    }
-
-    return EOK;
-}
-
-pub fn ext4_find_all_extent(inode_ref: &Ext4InodeRef, extents: &mut Vec<Ext4Extent>) {
-    let extent_header = Ext4ExtentHeader::try_from(&inode_ref.inner.inode.block[..2]).unwrap();
-    // log::info!("extent_header {:x?}", extent_header);
-    let data = &inode_ref.inner.inode.block;
-    let depth = extent_header.depth;
-
-    ext4_add_extent(inode_ref, depth, data, extents, true);
-}
-
-pub fn ext4_add_extent(
-    inode_ref: &Ext4InodeRef,
-    depth: u16,
-    data: &[u32],
-    extents: &mut Vec<Ext4Extent>,
-    _first_level: bool,
-) {
-    let extent_header = Ext4ExtentHeader::try_from(data).unwrap();
-    let extent_entries = extent_header.entries_count;
-    // log::info!("extent_entries {:x?}", extent_entries);
-    if depth == 0 {
-        for en in 0..extent_entries {
-            let idx = (3 + en * 3) as usize;
-            let extent = Ext4Extent::try_from(&data[idx..]).unwrap();
-
-            extents.push(extent)
-        }
-        return;
-    }
-
-    for en in 0..extent_entries {
-        let idx = (3 + en * 3) as usize;
-        if idx == 12 {
-            break;
-        }
-        let extent_index = Ext4ExtentIndex::try_from(&data[idx..]).unwrap();
-        let ei_leaf_lo = extent_index.leaf_lo;
-        let ei_leaf_hi = extent_index.leaf_hi;
-        let mut block = ei_leaf_lo;
-        block |= ((ei_leaf_hi as u32) << 31) << 1;
-        let data = inode_ref
-            .fs()
-            .block_device
-            .read_offset(block as usize * BLOCK_SIZE);
-        let data: Vec<u32> = unsafe { core::mem::transmute(data) };
-        ext4_add_extent(inode_ref, depth - 1, &data, extents, false);
-    }
-}
-
-pub fn ext4_idx_pblock(idx: *mut Ext4ExtentIndex) -> u64 {
-    // 如果索引为空,返回0
-    if idx.is_null() {
-        return 0;
-    }
-    // 获取索引的低32位物理块号
-    let mut pblock = unsafe { (*idx).leaf_lo } as u64;
-
-    // 如果支持64位物理块号,获取索引的高16位物理块号
-    let pblock_hi = unsafe { (*idx).leaf_hi };
-    pblock |= ((pblock_hi as ext4_fsblk_t) << 32) as u64;
-    // }
-
-    // 返回索引的物理块号
-    return pblock;
-}
-
-fn ext4_find_extent(
-    inode_ref: &mut Ext4InodeRef,
-    block: ext4_lblk_t,
-    orig_path: &mut Option<Vec<Ext4ExtentPath>>,
-    _flags: u32,
-) -> usize {
-    let inode = &inode_ref.inner.inode;
-    let mut _eh: &Ext4ExtentHeader;
-    let mut path = orig_path.take(); // Take the path out of the Option, which may replace it with None
-    let depth = unsafe { *ext4_inode_hdr(inode) }.depth;
-
-    let mut ppos = 0;
-    let mut i: u16;
-
-    let eh = &inode.block as *const [u32; 15] as *mut Ext4ExtentHeader;
-
-    if let Some(ref mut p) = path {
-        if depth > p[0].maxdepth {
-            p.clear();
-        }
-    }
-    if path.is_none() {
-        let path_depth = depth + 1;
-        path = Some(vec![Ext4ExtentPath::default(); path_depth as usize + 1]);
-        path.as_mut().unwrap()[0].maxdepth = path_depth;
-    }
-
-    let path = path.as_mut().unwrap();
-    path[0].header = eh;
-
-    i = depth;
-    while i > 0 {
-        ext4_ext_binsearch_idx(&mut path[ppos], block);
-        path[ppos].p_block = ext4_idx_pblock(path[ppos].index);
-        path[ppos].depth = i;
-        path[ppos].extent = core::ptr::null_mut();
-
-        i -= 1;
-        ppos += 1;
-    }
-
-    path[ppos].depth = i;
-    path[ppos].extent = core::ptr::null_mut();
-    path[ppos].index = core::ptr::null_mut();
-
-    ext4_ext_binsearch(&mut path[ppos], block);
-    if !path[ppos].extent.is_null() {
-        path[ppos].p_block = ext4_ext_pblock(&unsafe { *(path[ppos].extent) }) as u64;
-    }
-
-    *orig_path = Some(path.clone());
-
-    EOK
-}
-
-pub fn ext4_fs_get_inode_dblk_idx(
-    inode_ref: &mut Ext4InodeRef,
-    iblock: &mut ext4_lblk_t,
-    fblock: &mut ext4_fsblk_t,
-    _extent_create: bool,
-) -> usize {
-    let current_block: ext4_fsblk_t;
-    let mut current_fsblk: ext4_fsblk_t = 0;
-
-    let mut blocks_count = 0;
-    ext4_extent_get_blocks(
-        inode_ref,
-        *iblock,
-        1,
-        &mut current_fsblk,
-        false,
-        &mut blocks_count,
-    );
-
-    current_block = current_fsblk;
-    *fblock = current_block;
-
-    EOK
-}
-
-pub fn ext4_fs_get_inode_dblk_idx_internal(
-    inode_ref: &mut Ext4InodeRef,
-    iblock: &mut ext4_lblk_t,
-    _fblock: &mut ext4_fsblk_t,
-    extent_create: bool,
-    _support_unwritten: bool,
-) {
-    let mut current_fsblk: ext4_fsblk_t = 0;
-
-    let mut blocks_count = 0;
-    ext4_extent_get_blocks(
-        inode_ref,
-        *iblock,
-        1,
-        &mut current_fsblk,
-        extent_create,
-        &mut blocks_count,
-    );
-}
-
-pub fn ext4_dir_find_in_block(
-    block: &Ext4Block,
-    name: &str,
-    name_len: u32,
-    result: &mut Ext4DirSearchResult,
-) -> bool {
-    let mut offset = 0;
-
-    while offset < block.block_data.len() {
-        let de = Ext4DirEntry::try_from(&block.block_data[offset..]).unwrap();
-
-        offset = offset + de.entry_len as usize;
-        if de.inode == 0 {
-            continue;
-        }
-
-        let s = get_name(de.name, de.name_len as usize);
-
-        if let Ok(s) = s {
-            if name_len == de.name_len as u32 {
-                if name.to_string() == s {
-                    result.dentry = de;
-                    return true;
-                }
-            }
-        }
-    }
-
-    false
-}
-
-pub fn ext4_ialloc_alloc_inode(fs: Arc<Ext4>, index: &mut u32, is_dir: bool) {
-    let mut bgid = fs.last_inode_bg_id;
-    let bg_count = fs.super_block.block_groups_count();
-
-    while bgid <= bg_count {
-        if bgid == bg_count {
-            bgid = 0;
-            continue;
-        }
-
-        let block_device = fs.block_device.clone();
-
-        let raw_data = fs.block_device.read_offset(BASE_OFFSET);
-        let mut super_block = Ext4Superblock::try_from(raw_data).unwrap();
-
-        let mut bg =
-            Ext4BlockGroup::load(block_device.clone(), &super_block, bgid as usize).unwrap();
-
-        let mut free_inodes = bg.get_free_inodes_count();
-        let mut used_dirs = bg.get_used_dirs_count(&super_block);
-
-        if free_inodes > 0 {
-            let inode_bitmap_block = bg.get_inode_bitmap_block(&super_block);
-
-            let mut raw_data = fs
-                .block_device
-                .read_offset(inode_bitmap_block as usize * BLOCK_SIZE);
-
-            let inodes_in_bg = super_block.get_inodes_in_group_cnt(bgid);
-
-            let bitmap_size: u32 = inodes_in_bg / 0x8;
-
-            let mut bitmap_data = &mut raw_data[..bitmap_size as usize];
-
-            let mut idx_in_bg = 0 as u32;
-
-            ext4_bmap_bit_find_clr(bitmap_data, 0, inodes_in_bg, &mut idx_in_bg);
-            ext4_bmap_bit_set(&mut bitmap_data, idx_in_bg);
-
-            // update bitmap in disk
-            fs.block_device
-                .write_offset(inode_bitmap_block as usize * BLOCK_SIZE, &bitmap_data);
-
-            bg.set_block_group_ialloc_bitmap_csum(&super_block, &bitmap_data);
-
-            /* Modify filesystem counters */
-            free_inodes -= 1;
-            bg.set_free_inodes_count(&super_block, free_inodes);
-
-            /* Increment used directories counter */
-            if is_dir {
-                used_dirs += 1;
-                bg.set_used_dirs_count(&super_block, used_dirs);
-            }
-
-            /* Decrease unused inodes count */
-            let mut unused = bg.get_itable_unused(&super_block);
-            let free = inodes_in_bg - unused as u32;
-            if idx_in_bg >= free {
-                unused = inodes_in_bg - (idx_in_bg + 1);
-                bg.set_itable_unused(&super_block, unused);
-            }
-
-            bg.sync_to_disk_with_csum(block_device.clone(), bgid as usize, &super_block);
-            // bg.sync_block_group_to_disk(block_device.clone(), bgid as usize, &super_block);
-
-            /* Update superblock */
-            super_block.decrease_free_inodes_count();
-            // super_block.sync_super_block_to_disk(block_device.clone());
-
-            /* Compute the absolute i-nodex number */
-            let inodes_per_group = super_block.inodes_per_group();
-            let inode_num = bgid * inodes_per_group + (idx_in_bg + 1);
-            *index = inode_num;
-
-            // log::info!("alloc inode {:x?}", inode_num);
-            return;
-        }
-
-        bgid += 1;
-    }
-    log::info!("no free inode");
-}
-
-pub fn ext4_balloc_alloc_block(
-    inode_ref: &mut Ext4InodeRef,
-    goal: ext4_fsblk_t,
-    fblock: &mut ext4_fsblk_t,
-) {
-    // let mut alloc: ext4_fsblk_t = 0;
-    // let mut bmp_blk_adr: ext4_fsblk_t;
-    // let mut rel_blk_idx: u32 = 0;
-    // let mut free_blocks: u64;
-    // let mut r: i32;
-
-    let fs = inode_ref.fs();
-
-    let block_device = fs.block_device.clone();
-
-    let super_block_data = block_device.read_offset(BASE_OFFSET);
-    let mut super_block = Ext4Superblock::try_from(super_block_data).unwrap();
-
-    // let inodes_per_group = super_block.inodes_per_group();
-    let blocks_per_group = super_block.blocks_per_group();
-
-    let bgid = goal / blocks_per_group as u64;
-    let idx_in_bg = goal % blocks_per_group as u64;
-
-    let mut bg = Ext4BlockGroup::load(block_device.clone(), &super_block, bgid as usize).unwrap();
-
-    let block_bitmap_block = bg.get_block_bitmap_block(&super_block);
-    let mut raw_data = block_device.read_offset(block_bitmap_block as usize * BLOCK_SIZE);
-    let mut data: &mut Vec<u8> = &mut raw_data;
-    let mut rel_blk_idx = 0 as u32;
-
-    ext4_bmap_bit_find_clr(data, idx_in_bg as u32, 0x8000, &mut rel_blk_idx);
-    *fblock = rel_blk_idx as u64;
-    ext4_bmap_bit_set(&mut data, rel_blk_idx);
-
-    bg.set_block_group_balloc_bitmap_csum(&super_block, &data);
-    block_device.write_offset(block_bitmap_block as usize * BLOCK_SIZE, &data);
-
-    /* Update superblock free blocks count */
-    let super_blk_free_blocks = super_block.free_blocks_count();
-    // super_blk_free_blocks -= 1;
-    super_block.set_free_blocks_count(super_blk_free_blocks);
-    super_block.sync_to_disk(block_device.clone());
-
-    /* Update inode blocks (different block size!) count */
-    let mut inode_blocks = inode_ref.inner.inode.ext4_inode_get_blocks_count();
-    inode_blocks += 8;
-    inode_ref
-        .inner
-        .inode
-        .ext4_inode_set_blocks_count(inode_blocks as u32);
-    inode_ref.write_back_inode();
-
-    /* Update block group free blocks count */
-    let mut fb_cnt = bg.get_free_blocks_count();
-    fb_cnt -= 1;
-    bg.set_free_blocks_count(fb_cnt);
-    bg.sync_to_disk_with_csum(block_device, bgid as usize, &super_block);
-}

+ 259 - 0
src/ext4/alloc.rs

@@ -0,0 +1,259 @@
+use super::utils::*;
+use super::Ext4;
+use crate::constants::*;
+use crate::ext4_defs::*;
+use crate::prelude::*;
+
+impl Ext4 {
+    pub fn ext4_ialloc_alloc_inode(&self, index: &mut u32, is_dir: bool) {
+        let mut bgid = self.last_inode_bg_id;
+        let bg_count = self.super_block.block_groups_count();
+
+        while bgid <= bg_count {
+            if bgid == bg_count {
+                bgid = 0;
+                continue;
+            }
+
+            let block_device = self.block_device.clone();
+
+            let raw_data = self.block_device.read_offset(BASE_OFFSET);
+            let mut super_block = Ext4Superblock::try_from(raw_data).unwrap();
+
+            let mut bg =
+                Ext4BlockGroupDesc::load(block_device.clone(), &super_block, bgid as usize).unwrap();
+
+            let mut free_inodes = bg.get_free_inodes_count();
+            let mut used_dirs = bg.get_used_dirs_count(&super_block);
+
+            if free_inodes > 0 {
+                let inode_bitmap_block = bg.get_inode_bitmap_block(&super_block);
+
+                let mut raw_data = self
+                    .block_device
+                    .read_offset(inode_bitmap_block as usize * BLOCK_SIZE);
+
+                let inodes_in_bg = super_block.get_inodes_in_group_cnt(bgid);
+
+                let bitmap_size: u32 = inodes_in_bg / 0x8;
+
+                let mut bitmap_data = &mut raw_data[..bitmap_size as usize];
+
+                let mut idx_in_bg = 0 as u32;
+
+                ext4_bmap_bit_find_clr(bitmap_data, 0, inodes_in_bg, &mut idx_in_bg);
+                ext4_bmap_bit_set(&mut bitmap_data, idx_in_bg);
+
+                // update bitmap in disk
+                self.block_device
+                    .write_offset(inode_bitmap_block as usize * BLOCK_SIZE, &bitmap_data);
+
+                bg.set_block_group_ialloc_bitmap_csum(&super_block, &bitmap_data);
+
+                /* Modify filesystem counters */
+                free_inodes -= 1;
+                bg.set_free_inodes_count(&super_block, free_inodes);
+
+                /* Increment used directories counter */
+                if is_dir {
+                    used_dirs += 1;
+                    bg.set_used_dirs_count(&super_block, used_dirs);
+                }
+
+                /* Decrease unused inodes count */
+                let mut unused = bg.get_itable_unused(&super_block);
+                let free = inodes_in_bg - unused as u32;
+                if idx_in_bg >= free {
+                    unused = inodes_in_bg - (idx_in_bg + 1);
+                    bg.set_itable_unused(&super_block, unused);
+                }
+
+                bg.sync_to_disk_with_csum(block_device.clone(), bgid as usize, &super_block);
+                // bg.sync_block_group_to_disk(block_device.clone(), bgid as usize, &super_block);
+
+                /* Update superblock */
+                super_block.decrease_free_inodes_count();
+                // super_block.sync_super_block_to_disk(block_device.clone());
+
+                /* Compute the absolute i-nodex number */
+                let inodes_per_group = super_block.inodes_per_group();
+                let inode_num = bgid * inodes_per_group + (idx_in_bg + 1);
+                *index = inode_num;
+
+                // log::info!("alloc inode {:x?}", inode_num);
+                return;
+            }
+
+            bgid += 1;
+        }
+        log::info!("no free inode");
+    }
+
+    pub fn ext4_balloc_alloc_block(
+        &self,
+        inode_ref: &mut Ext4InodeRef,
+        goal: Ext4FsBlockId,
+        fblock: &mut Ext4FsBlockId,
+    ) {
+        // let mut alloc: ext4_fsblk_t = 0;
+        // let mut bmp_blk_adr: ext4_fsblk_t;
+        // let mut rel_blk_idx: u32 = 0;
+        // let mut free_blocks: u64;
+        // let mut r: i32;
+
+        let block_device = self.block_device.clone();
+
+        let super_block_data = block_device.read_offset(BASE_OFFSET);
+        let mut super_block = Ext4Superblock::try_from(super_block_data).unwrap();
+
+        // let inodes_per_group = super_block.inodes_per_group();
+        let blocks_per_group = super_block.blocks_per_group();
+
+        let bgid = goal / blocks_per_group as u64;
+        let idx_in_bg = goal % blocks_per_group as u64;
+
+        let mut bg =
+            Ext4BlockGroupDesc::load(block_device.clone(), &super_block, bgid as usize).unwrap();
+
+        let block_bitmap_block = bg.get_block_bitmap_block(&super_block);
+        let mut raw_data = block_device.read_offset(block_bitmap_block as usize * BLOCK_SIZE);
+        let mut data: &mut Vec<u8> = &mut raw_data;
+        let mut rel_blk_idx = 0 as u32;
+
+        ext4_bmap_bit_find_clr(data, idx_in_bg as u32, 0x8000, &mut rel_blk_idx);
+        *fblock = rel_blk_idx as u64;
+        ext4_bmap_bit_set(&mut data, rel_blk_idx);
+
+        bg.set_block_group_balloc_bitmap_csum(&super_block, &data);
+        block_device.write_offset(block_bitmap_block as usize * BLOCK_SIZE, &data);
+
+        /* Update superblock free blocks count */
+        let super_blk_free_blocks = super_block.free_blocks_count();
+        // super_blk_free_blocks -= 1;
+        super_block.set_free_blocks_count(super_blk_free_blocks);
+        super_block.sync_to_disk(block_device.clone());
+
+        /* Update inode blocks (different block size!) count */
+        let mut inode_blocks = inode_ref.inode.blocks_count();
+        inode_blocks += 8;
+        inode_ref
+            .inode
+            .set_blocks_count(inode_blocks as u32);
+        self.write_back_inode(inode_ref);
+
+        /* Update block group free blocks count */
+        let mut fb_cnt = bg.get_free_blocks_count();
+        fb_cnt -= 1;
+        bg.set_free_blocks_count(fb_cnt);
+        bg.sync_to_disk_with_csum(block_device, bgid as usize, &super_block);
+    }
+
+    pub fn ext4_fs_append_inode_dblk(
+        &self,
+        inode_ref: &mut Ext4InodeRef,
+        iblock: &mut Ext4LogicBlockId,
+        fblock: &mut Ext4FsBlockId,
+    ) {
+        let inode_size = inode_ref.inode.size();
+        let block_size = BLOCK_SIZE as u64;
+    
+        *iblock = ((inode_size + block_size - 1) / block_size) as u32;
+    
+        let mut current_fsblk: Ext4FsBlockId = 0;
+        self.ext4_extent_get_blocks(inode_ref, *iblock, 1, &mut current_fsblk, true, &mut 0);
+    
+        let current_block = current_fsblk;
+        *fblock = current_block;
+    
+        inode_ref
+            .inode
+            .set_size(inode_size + BLOCK_SIZE as u64);
+    
+        self.write_back_inode(inode_ref);
+    
+        // let mut inode_ref = Ext4InodeRef::get_inode_ref(inode_ref.fs().self_ref.clone(), inode_ref.inode_num);
+    
+        // log::info!("ext4_fs_append_inode_dblk inode {:x?} inode_size {:x?}", inode_ref.inode_num, inode_ref.inner.inode.size);
+        // log::info!("fblock {:x?}", fblock);
+    }
+    
+    pub fn ext4_fs_inode_blocks_init(inode_ref: &mut Ext4InodeRef) {
+        // log::info!(
+        //     "ext4_fs_inode_blocks_init mode {:x?}",
+        //     inode_ref.inner.inode.mode
+        // );
+    
+        let inode = &mut inode_ref.inode;
+        let mode = inode.mode;
+        let inode_type = InodeMode::from_bits(mode & EXT4_INODE_MODE_TYPE_MASK as u16).unwrap();
+    
+        match inode_type {
+            InodeMode::S_IFDIR => {}
+            InodeMode::S_IFREG => {}
+            /* Reset blocks array. For inode which is not directory or file, just
+             * fill in blocks with 0 */
+            _ => {
+                log::info!("inode_type {:?}", inode_type);
+                return;
+            }
+        }
+    
+        /* Initialize extents */
+        inode.set_flags(EXT4_INODE_FLAG_EXTENTS as u32);
+    
+        /* Initialize extent root header */
+        inode.extent_tree_init();
+        // log::info!("inode iblock {:x?}", inode.block);
+    
+        // inode_ref.dirty = true;
+    }
+    
+    pub fn ext4_fs_alloc_inode(&self, child_inode_ref: &mut Ext4InodeRef, filetype: u8) -> usize {
+        let mut is_dir = false;
+    
+        let inode_size = self.super_block.inode_size();
+        let extra_size = self.super_block.extra_size();
+    
+        if filetype == DirEntryType::EXT4_DE_DIR.bits() {
+            is_dir = true;
+        }
+    
+        let mut index = 0;
+        let _rc = self.ext4_ialloc_alloc_inode(&mut index, is_dir);
+    
+        child_inode_ref.inode_id = index;
+    
+        let inode = &mut child_inode_ref.inode;
+    
+        /* Initialize i-node */
+    
+        let mode = if is_dir {
+            0o777 | EXT4_INODE_MODE_DIRECTORY as u16
+        } else if filetype == 0x7 {
+            0o777 | EXT4_INODE_MODE_SOFTLINK as u16
+        } else {
+            let t = ext4_fs_correspond_inode_mode(filetype);
+            // log::info!("ext4_fs_correspond_inode_mode {:x?}", ext4_fs_correspond_inode_mode(filetype));
+            0o666 | t as u16
+        };
+    
+        inode.set_mode(mode);
+        inode.set_links_cnt(0);
+        inode.set_uid(0);
+        inode.set_gid(0);
+        inode.set_size(0);
+        inode.set_access_time(0);
+        inode.set_change_inode_time(0);
+        inode.set_modif_time(0);
+        inode.set_del_time(0);
+        inode.set_flags(0);
+        inode.set_generation(0);
+    
+        if inode_size > EXT4_GOOD_OLD_INODE_SIZE {
+            let extra_size = extra_size;
+            inode.set_extra_isize(extra_size);
+        }
+    
+        EOK
+    }
+}

+ 319 - 0
src/ext4/dir.rs

@@ -0,0 +1,319 @@
+use super::utils::*;
+use super::Ext4;
+use crate::constants::*;
+use crate::ext4_defs::*;
+use crate::prelude::*;
+
+impl Ext4 {
+    pub fn ext4_dir_mk(&self, path: &str) -> Result<usize> {
+        let mut file = Ext4File::new();
+        let flags = "w";
+
+        let filetype = DirEntryType::EXT4_DE_DIR;
+
+        // get mount point
+        let mut ptr = Box::new(self.mount_point.clone());
+        file.mp = Box::as_mut(&mut ptr) as *mut Ext4MountPoint;
+
+        // get open flags
+        let iflags = ext4_parse_flags(flags).unwrap();
+
+        if iflags & O_CREAT != 0 {
+            self.ext4_trans_start();
+        }
+
+        let mut root_inode_ref = self.get_root_inode_ref();
+
+        let r = self.ext4_generic_open(
+            &mut file,
+            path,
+            iflags,
+            filetype.bits(),
+            &mut root_inode_ref,
+        );
+        r
+    }
+
+    pub fn ext4_dir_add_entry(
+        &self,
+        parent: &mut Ext4InodeRef,
+        child: &mut Ext4InodeRef,
+        path: &str,
+        len: u32,
+    ) -> usize {
+        let mut iblock = 0;
+        let block_size = self.super_block.block_size();
+        let inode_size = parent.inode.size();
+        let total_blocks = inode_size as u32 / block_size;
+
+        let mut fblock: Ext4FsBlockId = 0;
+
+        // log::info!("ext4_dir_add_entry parent inode {:x?} inode_size {:x?}", parent.inode_num, inode_size);
+        while iblock < total_blocks {
+            self.ext4_fs_get_inode_dblk_idx(parent, &mut iblock, &mut fblock, false);
+
+            // load_block
+            let mut data = self.block_device.read_offset(fblock as usize * BLOCK_SIZE);
+            let mut ext4_block = Ext4Block {
+                logical_block_id: iblock,
+                disk_block_id: fblock,
+                block_data: &mut data,
+                dirty: false,
+            };
+            let r = self.ext4_dir_try_insert_entry(parent, &mut ext4_block, child, path, len);
+            if r == EOK {
+                return EOK;
+            }
+
+            let mut data: Vec<u8> = Vec::with_capacity(BLOCK_SIZE);
+            let ext4_blk = Ext4Block {
+                logical_block_id: 0,
+                disk_block_id: 0,
+                block_data: &mut data,
+                dirty: true,
+            };
+            let de = Ext4DirEntry::default();
+            let mut dir_search_result = Ext4DirSearchResult::new(ext4_blk, de);
+            let r = Self::ext4_dir_find_in_block(&mut ext4_block, path, len, &mut dir_search_result);
+            if r {
+                return EOK;
+            }
+
+            iblock += 1;
+        }
+
+        /* No free block found - needed to allocate next data block */
+        iblock = 0;
+        fblock = 0;
+
+        self.ext4_fs_append_inode_dblk(parent, &mut (iblock as u32), &mut fblock);
+
+        /* Load new block */
+        let block_device = self.block_device.clone();
+        let mut data = block_device.read_offset(fblock as usize * BLOCK_SIZE);
+        let mut ext4_block = Ext4Block {
+            logical_block_id: iblock,
+            disk_block_id: fblock,
+            block_data: &mut data,
+            dirty: false,
+        };
+
+        let mut new_entry = Ext4DirEntry::default();
+        let el = BLOCK_SIZE - size_of::<Ext4DirEntryTail>();
+        self.ext4_dir_write_entry(&mut new_entry, el as u16, &child, path, len);
+
+        copy_dir_entry_to_array(&new_entry, &mut ext4_block.block_data, 0);
+
+        // init tail
+        let ptr = ext4_block.block_data.as_mut_ptr();
+        let mut tail = unsafe {
+            *(ptr.add(BLOCK_SIZE - core::mem::size_of::<Ext4DirEntryTail>())
+                as *mut Ext4DirEntryTail)
+        };
+        tail.rec_len = size_of::<Ext4DirEntryTail>() as u16;
+        tail.reserved_ft = 0xDE;
+        tail.reserved_zero1 = 0;
+        tail.reserved_zero2 = 0;
+
+        tail.ext4_dir_set_csum(&self.super_block, &new_entry, &ext4_block.block_data[..]);
+
+        let tail_offset = BLOCK_SIZE - size_of::<Ext4DirEntryTail>();
+        copy_diren_tail_to_array(&tail, &mut ext4_block.block_data, tail_offset);
+
+        tail.ext4_dir_set_csum(&self.super_block, &new_entry, &ext4_block.block_data[..]);
+
+        ext4_block.sync_blk_to_disk(block_device.clone());
+
+        // struct ext4_block b;
+
+        EOK
+    }
+
+    pub fn ext4_dir_try_insert_entry(
+        &self,
+        _parent: &Ext4InodeRef,
+        dst_blk: &mut Ext4Block,
+        child: &mut Ext4InodeRef,
+        name: &str,
+        name_len: u32,
+    ) -> usize {
+        let mut required_len = core::mem::size_of::<Ext4DirEntry>() + name_len as usize;
+
+        if required_len % 4 != 0 {
+            required_len += 4 - required_len % 4;
+        }
+
+        let mut offset = 0;
+
+        while offset < dst_blk.block_data.len() {
+            let mut de = Ext4DirEntry::try_from(&dst_blk.block_data[offset..]).unwrap();
+            if de.inode == 0 {
+                continue;
+            }
+            let inode = de.inode;
+            let rec_len = de.entry_len;
+
+            // 如果是有效的目录项,尝试分割它
+            if inode != 0 {
+                let used_len = de.name_len as usize;
+                let mut sz = core::mem::size_of::<Ext4FakeDirEntry>() + used_len as usize;
+
+                if used_len % 4 != 0 {
+                    sz += 4 - used_len % 4;
+                }
+
+                let free_space = rec_len as usize - sz;
+
+                // 如果有足够的空闲空间
+                if free_space >= required_len {
+                    let mut new_entry = Ext4DirEntry::default();
+
+                    de.entry_len = sz as u16;
+                    self.ext4_dir_write_entry(
+                        &mut new_entry,
+                        free_space as u16,
+                        &child,
+                        name,
+                        name_len,
+                    );
+
+                    // update parent new_de to blk_data
+                    copy_dir_entry_to_array(&de, &mut dst_blk.block_data, offset);
+                    copy_dir_entry_to_array(&new_entry, &mut dst_blk.block_data, offset + sz);
+
+                    // set tail csum
+                    let mut tail =
+                        Ext4DirEntryTail::from(&mut dst_blk.block_data, BLOCK_SIZE).unwrap();
+                    let block_device = self.block_device.clone();
+                    tail.ext4_dir_set_csum(&self.super_block, &de, &dst_blk.block_data[offset..]);
+
+                    let parent_de = Ext4DirEntry::try_from(&dst_blk.block_data[..]).unwrap();
+                    tail.ext4_dir_set_csum(&self.super_block, &parent_de, &dst_blk.block_data[..]);
+
+                    let tail_offset = BLOCK_SIZE - size_of::<Ext4DirEntryTail>();
+                    copy_diren_tail_to_array(&tail, &mut dst_blk.block_data, tail_offset);
+
+                    // sync to disk
+                    dst_blk.sync_blk_to_disk(block_device.clone());
+
+                    return EOK;
+                }
+            }
+            offset = offset + de.entry_len as usize;
+        }
+
+        ENOSPC
+    }
+
+    // 写入一个ext4目录项
+    pub fn ext4_dir_write_entry(
+        &self,
+        en: &mut Ext4DirEntry,
+        entry_len: u16,
+        child: &Ext4InodeRef,
+        name: &str,
+        name_len: u32,
+    ) {
+        let file_type = (child.inode.mode & EXT4_INODE_MODE_TYPE_MASK) as usize;
+
+        // 设置目录项的类型
+        match file_type {
+            EXT4_INODE_MODE_FILE => en.inner.inode_type = DirEntryType::EXT4_DE_REG_FILE.bits(),
+            EXT4_INODE_MODE_DIRECTORY => en.inner.inode_type = DirEntryType::EXT4_DE_DIR.bits(),
+            EXT4_INODE_MODE_CHARDEV => en.inner.inode_type = DirEntryType::EXT4_DE_CHRDEV.bits(),
+            EXT4_INODE_MODE_BLOCKDEV => en.inner.inode_type = DirEntryType::EXT4_DE_BLKDEV.bits(),
+            EXT4_INODE_MODE_FIFO => en.inner.inode_type = DirEntryType::EXT4_DE_FIFO.bits(),
+            EXT4_INODE_MODE_SOCKET => en.inner.inode_type = DirEntryType::EXT4_DE_SOCK.bits(),
+            EXT4_INODE_MODE_SOFTLINK => en.inner.inode_type = DirEntryType::EXT4_DE_SYMLINK.bits(),
+            _ => log::info!("{}: unknown type", file_type),
+        }
+
+        en.inode = child.inode_id;
+        en.entry_len = entry_len;
+        en.name_len = name_len as u8;
+
+        let en_name_ptr = en.name.as_mut_ptr();
+        unsafe {
+            en_name_ptr.copy_from_nonoverlapping(name.as_ptr(), name_len as usize);
+        }
+        let _name = get_name(en.name, en.name_len as usize).unwrap();
+        // log::info!("ext4_dir_write_entry name {:?}", name);
+    }
+
+    pub fn ext4_dir_destroy_result(
+        _inode_ref: &mut Ext4InodeRef,
+        result: &mut Ext4DirSearchResult,
+    ) {
+        result.block.logical_block_id = 0;
+        result.block.disk_block_id = 0;
+        result.dentry = Ext4DirEntry::default();
+    }
+
+    pub fn ext4_dir_find_entry(
+        &self,
+        parent: &mut Ext4InodeRef,
+        name: &str,
+        name_len: u32,
+        result: &mut Ext4DirSearchResult,
+    ) -> usize {
+        // log::info!("ext4_dir_find_entry parent {:x?} {:?}",parent.inode_num,  name);
+        let mut iblock = 0;
+        let mut fblock: Ext4FsBlockId = 0;
+
+        let inode_size: u32 = parent.inode.size;
+        let total_blocks: u32 = inode_size / BLOCK_SIZE as u32;
+
+        while iblock < total_blocks {
+            self.ext4_fs_get_inode_dblk_idx(parent, &mut iblock, &mut fblock, false);
+
+            // load_block
+            let mut data = self.block_device.read_offset(fblock as usize * BLOCK_SIZE);
+            let mut ext4_block = Ext4Block {
+                logical_block_id: iblock,
+                disk_block_id: fblock,
+                block_data: &mut data,
+                dirty: false,
+            };
+
+            let r = Self::ext4_dir_find_in_block(&mut ext4_block, name, name_len, result);
+            if r {
+                return EOK;
+            }
+
+            iblock += 1
+        }
+
+        ENOENT
+    }
+
+    pub fn ext4_dir_find_in_block(
+        block: &Ext4Block,
+        name: &str,
+        name_len: u32,
+        result: &mut Ext4DirSearchResult,
+    ) -> bool {
+        let mut offset = 0;
+    
+        while offset < block.block_data.len() {
+            let de = Ext4DirEntry::try_from(&block.block_data[offset..]).unwrap();
+    
+            offset = offset + de.entry_len as usize;
+            if de.inode == 0 {
+                continue;
+            }
+    
+            let s = get_name(de.name, de.name_len as usize);
+    
+            if let Ok(s) = s {
+                if name_len == de.name_len as u32 {
+                    if name.to_string() == s {
+                        result.dentry = de;
+                        return true;
+                    }
+                }
+            }
+        }
+    
+        false
+    }
+}

+ 312 - 0
src/ext4/extent.rs

@@ -0,0 +1,312 @@
+use super::Ext4;
+use crate::constants::*;
+use crate::ext4_defs::*;
+use crate::prelude::*;
+
+impl Ext4 {
+    pub fn find_extent(
+        inode_ref: &mut Ext4InodeRef,
+        block_id: Ext4LogicBlockId,
+        orig_path: &mut Option<Vec<Ext4ExtentPath>>,
+        _flags: u32,
+    ) -> usize {
+        let inode = &inode_ref.inode;
+        let mut _eh: &Ext4ExtentHeader;
+        let mut path = orig_path.take(); // Take the path out of the Option, which may replace it with None
+        let depth = ext4_depth(inode);
+
+        let mut ppos = 0;
+        let mut i: u16;
+
+        let eh = &inode.block as *const [u32; 15] as *mut Ext4ExtentHeader;
+
+        if let Some(ref mut p) = path {
+            if depth > p[0].maxdepth {
+                p.clear();
+            }
+        }
+        if path.is_none() {
+            let path_depth = depth + 1;
+            path = Some(vec![Ext4ExtentPath::default(); path_depth as usize + 1]);
+            path.as_mut().unwrap()[0].maxdepth = path_depth;
+        }
+
+        let path = path.as_mut().unwrap();
+        path[0].header = eh;
+
+        i = depth;
+        while i > 0 {
+            ext4_ext_binsearch_idx(&mut path[ppos], block_id);
+            path[ppos].p_block = ext4_idx_pblock(path[ppos].index);
+            path[ppos].depth = i;
+            path[ppos].extent = core::ptr::null_mut();
+
+            i -= 1;
+            ppos += 1;
+        }
+
+        path[ppos].depth = i;
+        path[ppos].extent = core::ptr::null_mut();
+        path[ppos].index = core::ptr::null_mut();
+
+        ext4_ext_binsearch(&mut path[ppos], block_id);
+        if !path[ppos].extent.is_null() {
+            path[ppos].p_block = unsafe { (*path[ppos].extent).pblock() };
+        }
+
+        *orig_path = Some(path.clone());
+
+        EOK
+    }
+
+    pub fn ext4_extent_get_blocks(
+        &self,
+        inode_ref: &mut Ext4InodeRef,
+        iblock: Ext4LogicBlockId,
+        max_blocks: u32,
+        result: &mut Ext4FsBlockId,
+        create: bool,
+        blocks_count: &mut u32,
+    ) {
+        *result = 0;
+        *blocks_count = 0;
+
+        let mut path: Option<Vec<Ext4ExtentPath>> = None;
+        let err = Self::find_extent(inode_ref, iblock, &mut path, 0);
+
+        let inode = &inode_ref.inode;
+        // 确认ext4_find_extent成功执行
+        if err != EOK {
+            return;
+        }
+
+        let depth = unsafe { *ext4_extent_hdr(inode) }.depth as usize;
+        let mut path = path.unwrap();
+
+        if !path[depth].extent.is_null() {
+            let ex = unsafe { *path[depth].extent };
+            let ee_block = ex.first_block;
+            let ee_start = ex.pblock();
+            let ee_len = ex.actual_len();
+
+            if iblock >= ee_block && iblock < ee_block + ee_len as u32 {
+                let allocated = ee_len - (iblock - ee_block) as u16;
+                *blocks_count = allocated as u32;
+
+                if !create || ex.is_unwritten() {
+                    *result = (iblock - ee_block) as u64 + ee_start;
+                    return;
+                }
+            }
+        }
+
+        // 如果没有找到对应的extent,并且create为true,则需要分配和插入新的extent
+        if create {
+            let next = EXT_MAX_BLOCKS;
+
+            let mut allocated = next - iblock;
+            if allocated > max_blocks {
+                allocated = max_blocks;
+            }
+
+            let mut newex: Ext4Extent = Ext4Extent::default();
+
+            let goal = 0;
+
+            let mut alloc_block = 0;
+            self.ext4_balloc_alloc_block(inode_ref, goal as u64, &mut alloc_block);
+
+            *result = alloc_block;
+
+            // 创建并插入新的extent
+            newex.first_block = iblock;
+            newex.start_lo = alloc_block as u32 & 0xffffffff;
+            newex.start_hi = (((alloc_block as u32) << 31) << 1) as u16;
+            newex.block_count = allocated as u16;
+
+            self.ext4_ext_insert_extent(inode_ref, &mut path[0], &newex, 0);
+        }
+    }
+
+    pub fn ext4_ext_insert_extent(
+        &self,
+        inode_ref: &mut Ext4InodeRef,
+        path: &mut Ext4ExtentPath,
+        newext: &Ext4Extent,
+        flags: i32,
+    ) {
+        let depth = ext4_depth(&inode_ref.inode);
+        let mut need_split = false;
+
+        self.ext4_ext_insert_leaf(inode_ref, path, depth, newext, flags, &mut need_split);
+
+        self.write_back_inode_without_csum(inode_ref);
+    }
+
+    pub fn ext4_ext_insert_leaf(
+        &self,
+        _inode_ref: &mut Ext4InodeRef,
+        path: &mut Ext4ExtentPath,
+        _depth: u16,
+        newext: &Ext4Extent,
+        _flags: i32,
+        need_split: &mut bool,
+    ) -> usize {
+        let eh = path.header;
+        let ex = path.extent;
+        let _last_ex = ext4_last_extent(eh);
+
+        let mut diskblock = newext.start_lo;
+        diskblock |= ((newext.start_hi as u32) << 31) << 1;
+
+        unsafe {
+            if !ex.is_null() && Ext4Extent::can_append(&*(path.extent), newext) {
+                if (*path.extent).is_unwritten() {
+                    (*path.extent).mark_unwritten();
+                }
+                (*(path.extent)).block_count = (*path.extent).actual_len() + newext.actual_len();
+                (*path).p_block = diskblock as u64;
+                return EOK;
+            }
+            if !ex.is_null() && Ext4Extent::can_append(newext, &*(path.extent)) {
+                (*(path.extent)).block_count = (*path.extent).actual_len() + newext.actual_len();
+                (*path).p_block = diskblock as u64;
+                if (*path.extent).is_unwritten() {
+                    (*path.extent).mark_unwritten();
+                }
+                return EOK;
+            }
+        }
+
+        if ex.is_null() {
+            let first_extent = ext4_first_extent_mut(eh);
+            path.extent = first_extent;
+            // log::info!("first_extent {:x?}", unsafe{*first_extent});
+            unsafe {
+                if (*eh).entries_count == (*eh).max_entries_count {
+                    *need_split = true;
+                    return EIO;
+                } else {
+                    *(path.extent) = *newext;
+                }
+            }
+        }
+
+        unsafe {
+            if (*eh).entries_count == (*eh).max_entries_count {
+                *need_split = true;
+                *(path.extent) = *newext;
+
+                (*path).p_block = diskblock as u64;
+                return EIO;
+            } else {
+                if ex.is_null() {
+                    let first_extent = ext4_first_extent_mut(eh);
+                    path.extent = first_extent;
+                    *(path.extent) = *newext;
+                } else if newext.first_block > (*(path.extent)).first_block {
+                    // insert after
+                    let next_extent = ex.add(1);
+                    path.extent = next_extent;
+                } else {
+                }
+            }
+
+            *(path.extent) = *newext;
+            (*eh).entries_count += 1;
+        }
+        unsafe {
+            *(path.extent) = *newext;
+        }
+
+        return EOK;
+    }
+
+    pub fn ext4_find_all_extent(&self, inode_ref: &Ext4InodeRef, extents: &mut Vec<Ext4Extent>) {
+        let extent_header = Ext4ExtentHeader::try_from(&inode_ref.inode.block[..2]).unwrap();
+        // log::info!("extent_header {:x?}", extent_header);
+        let data = &inode_ref.inode.block;
+        let depth = extent_header.depth;
+        self.ext4_add_extent(inode_ref, depth, data, extents, true);
+    }
+
+    pub fn ext4_add_extent(
+        &self,
+        inode_ref: &Ext4InodeRef,
+        depth: u16,
+        data: &[u32],
+        extents: &mut Vec<Ext4Extent>,
+        _first_level: bool,
+    ) {
+        let extent_header = Ext4ExtentHeader::try_from(data).unwrap();
+        let extent_entries = extent_header.entries_count;
+        // log::info!("extent_entries {:x?}", extent_entries);
+        if depth == 0 {
+            for en in 0..extent_entries {
+                let idx = (3 + en * 3) as usize;
+                let extent = Ext4Extent::try_from(&data[idx..]).unwrap();
+
+                extents.push(extent)
+            }
+            return;
+        }
+
+        for en in 0..extent_entries {
+            let idx = (3 + en * 3) as usize;
+            if idx == 12 {
+                break;
+            }
+            let extent_index = Ext4ExtentIndex::try_from(&data[idx..]).unwrap();
+            let ei_leaf_lo = extent_index.leaf_lo;
+            let ei_leaf_hi = extent_index.leaf_hi;
+            let mut block = ei_leaf_lo;
+            block |= ((ei_leaf_hi as u32) << 31) << 1;
+            let data = self.block_device.read_offset(block as usize * BLOCK_SIZE);
+            let data: Vec<u32> = unsafe { core::mem::transmute(data) };
+            self.ext4_add_extent(inode_ref, depth - 1, &data, extents, false);
+        }
+    }
+
+    pub fn ext4_fs_get_inode_dblk_idx(
+        &self,
+        inode_ref: &mut Ext4InodeRef,
+        iblock: &mut Ext4LogicBlockId,
+        fblock: &mut Ext4FsBlockId,
+        _extent_create: bool,
+    ) -> usize {
+        let current_block: Ext4FsBlockId;
+        let mut current_fsblk: Ext4FsBlockId = 0;
+        let mut blocks_count = 0;
+        self.ext4_extent_get_blocks(
+            inode_ref,
+            *iblock,
+            1,
+            &mut current_fsblk,
+            false,
+            &mut blocks_count,
+        );
+        current_block = current_fsblk;
+        *fblock = current_block;
+        EOK
+    }
+
+    pub fn ext4_fs_get_inode_dblk_idx_internal(
+        &self,
+        inode_ref: &mut Ext4InodeRef,
+        iblock: &mut Ext4LogicBlockId,
+        _fblock: &mut Ext4FsBlockId,
+        extent_create: bool,
+        _support_unwritten: bool,
+    ) {
+        let mut current_fsblk: Ext4FsBlockId = 0;
+        let mut blocks_count = 0;
+        self.ext4_extent_get_blocks(
+            inode_ref,
+            *iblock,
+            1,
+            &mut current_fsblk,
+            extent_create,
+            &mut blocks_count,
+        );
+    }
+}

+ 231 - 0
src/ext4/file.rs

@@ -0,0 +1,231 @@
+use super::utils::*;
+use super::Ext4;
+use crate::constants::*;
+use crate::ext4_defs::*;
+use crate::prelude::*;
+use crate::return_errno_with_message;
+
+impl Ext4 {
+    pub fn ext4_generic_open(
+        &self,
+        file: &mut Ext4File,
+        path: &str,
+        iflags: u32,
+        ftype: u8,
+        parent_inode: &mut Ext4InodeRef,
+    ) -> Result<usize> {
+        let mut is_goal = false;
+
+        let mut data: Vec<u8> = Vec::with_capacity(BLOCK_SIZE);
+        let ext4_blk = Ext4Block {
+            logical_block_id: 0,
+            disk_block_id: 0,
+            block_data: &mut data,
+            dirty: true,
+        };
+        let de = Ext4DirEntry::default();
+        let mut dir_search_result = Ext4DirSearchResult::new(ext4_blk, de);
+
+        file.flags = iflags;
+
+        // load root inode
+        let root_inode_ref = self.get_root_inode_ref();
+
+        // if !parent_inode.is_none() {
+        //     parent_inode.unwrap().inode_num = root_inode_ref.inode_num;
+        // }
+
+        // search dir
+        let mut search_parent = root_inode_ref;
+        let mut search_path = ext4_path_skip(&path, ".");
+        let mut len;
+        loop {
+            search_path = ext4_path_skip(search_path, "/");
+            len = ext4_path_check(search_path, &mut is_goal);
+
+            let r = self.ext4_dir_find_entry(
+                &mut search_parent,
+                &search_path[..len as usize],
+                len as u32,
+                &mut dir_search_result,
+            );
+
+            // log::info!("dir_search_result.dentry {:?} r {:?}", dir_search_result.dentry, r);
+            if r != EOK {
+                // ext4_dir_destroy_result(&mut root_inode_ref, &mut dir_search_result);
+
+                if r != ENOENT {
+                    // dir search failed with error other than ENOENT
+                    return_errno_with_message!(Errnum::ENOTSUP, "dir search failed");
+                }
+
+                if !((iflags & O_CREAT) != 0) {
+                    return_errno_with_message!(Errnum::ENOENT, "file not found");
+                }
+
+                let mut child_inode_ref = Ext4InodeRef::default();
+
+                let r = if is_goal {
+                    self.ext4_fs_alloc_inode(&mut child_inode_ref, ftype)
+                } else {
+                    self.ext4_fs_alloc_inode(&mut child_inode_ref, DirEntryType::EXT4_DE_DIR.bits())
+                };
+
+                if r != EOK {
+                    return_errno_with_message!(Errnum::EALLOCFIAL, "alloc inode fail");
+                    // break;
+                }
+
+                Self::ext4_fs_inode_blocks_init(&mut child_inode_ref);
+
+                let r = self.ext4_link(
+                    &mut search_parent,
+                    &mut child_inode_ref,
+                    &search_path[..len as usize],
+                    len as u32,
+                );
+
+                if r != EOK {
+                    /*Fail. Free new inode.*/
+                    return_errno_with_message!(Errnum::ELINKFIAL, "link fail");
+                }
+
+                self.write_back_inode(&mut search_parent);
+                self.write_back_inode(&mut child_inode_ref);
+                self.write_back_inode(parent_inode);
+
+                continue;
+            }
+
+            let _name = get_name(
+                dir_search_result.dentry.name,
+                dir_search_result.dentry.name_len as usize,
+            )
+            .unwrap();
+            // log::info!("find de name{:?} de inode {:x?}", name, dir_search_result.dentry.inode);
+
+            if is_goal {
+                file.inode = dir_search_result.dentry.inode;
+                return Ok(EOK);
+            } else {
+                search_parent = self.get_inode_ref(dir_search_result.dentry.inode);
+                search_path = &search_path[len..];
+            }
+        }
+    }
+
+    pub fn ext4_open(
+        &self,
+        file: &mut Ext4File,
+        path: &str,
+        // flags: &str,
+        iflags: u32,
+        file_expect: bool,
+    ) -> Result<usize> {
+        // get mount point
+        let mut ptr = Box::new(self.mount_point.clone());
+        file.mp = Box::as_mut(&mut ptr) as *mut Ext4MountPoint;
+
+        // get open flags
+        // let iflags = self.ext4_parse_flags(flags).unwrap();
+
+        // file for dir
+        let filetype = if file_expect {
+            DirEntryType::EXT4_DE_REG_FILE
+        } else {
+            DirEntryType::EXT4_DE_DIR
+        };
+
+        if iflags & O_CREAT != 0 {
+            self.ext4_trans_start();
+        }
+
+        let mut root_inode_ref = self.get_root_inode_ref();
+
+        let r = self.ext4_generic_open(file, path, iflags, filetype.bits(), &mut root_inode_ref);
+
+        r
+    }
+
+    pub fn ext4_file_read(&self, ext4_file: &mut Ext4File) -> Vec<u8> {
+        // 创建一个空的向量,用于存储文件的内容
+        let mut file_data: Vec<u8> = Vec::new();
+
+        // 创建一个空的向量,用于存储文件的所有extent信息
+        let mut extents: Vec<Ext4Extent> = Vec::new();
+
+        let inode_ref = self.get_inode_ref(ext4_file.inode);
+
+        self.ext4_find_all_extent(&inode_ref, &mut extents);
+
+        // 遍历extents向量,对每个extent,计算它的物理块号,然后调用read_block函数来读取数据块,并将结果追加到file_data向量中
+        for extent in extents {
+            // 获取extent的起始块号、块数和逻辑块号
+            let start_block = extent.start_lo as u64 | ((extent.start_hi as u64) << 32);
+            let block_count = extent.block_count as u64;
+            let logical_block = extent.first_block as u64;
+            // 计算extent的物理块号
+            let physical_block = start_block + logical_block;
+            // 从file中读取extent的所有数据块,并将结果追加到file_data向量中
+            for i in 0..block_count {
+                let block_num = physical_block + i;
+                let block_data = self
+                    .block_device
+                    .read_offset(block_num as usize * BLOCK_SIZE);
+                file_data.extend(block_data);
+            }
+        }
+        file_data
+    }
+
+    pub fn ext4_file_write(&self, ext4_file: &mut Ext4File, data: &[u8], size: usize) {
+        let super_block_data = self.block_device.read_offset(BASE_OFFSET);
+        let super_block = Ext4Superblock::try_from(super_block_data).unwrap();
+        let mut inode_ref = self.get_inode_ref(ext4_file.inode);
+        let block_size = super_block.block_size() as usize;
+        let iblock_last = ext4_file.fpos as usize + size / block_size;
+        let mut iblk_idx = ext4_file.fpos as usize / block_size;
+        let ifile_blocks = ext4_file.fsize as usize + block_size - 1 / block_size;
+
+        let mut fblk = 0;
+        let mut fblock_start = 0;
+        let mut fblock_count = 0;
+
+        let mut size = size;
+        while size >= block_size {
+            while iblk_idx < iblock_last {
+                if iblk_idx < ifile_blocks {
+                    self.ext4_fs_append_inode_dblk(
+                        &mut inode_ref,
+                        &mut (iblk_idx as u32),
+                        &mut fblk,
+                    );
+                }
+
+                iblk_idx += 1;
+
+                if fblock_start == 0 {
+                    fblock_start = fblk;
+                }
+                fblock_count += 1;
+            }
+            size -= block_size;
+        }
+
+        for i in 0..fblock_count {
+            let idx = i * BLOCK_SIZE as usize;
+            let offset = (fblock_start as usize + i as usize) * BLOCK_SIZE;
+            self.block_device
+                .write_offset(offset, &data[idx..(idx + BLOCK_SIZE as usize)]);
+        }
+        // inode_ref.inner.inode.size = fblock_count as u32 * BLOCK_SIZE as u32;
+        self.write_back_inode(&mut inode_ref);
+        // let mut inode_ref = Ext4InodeRef::get_inode_ref(self.self_ref.clone(), ext4_file.inode);
+        let mut root_inode_ref = self.get_root_inode_ref();
+        self.write_back_inode(&mut root_inode_ref);
+    }
+
+    pub fn ext4_file_remove(&self, _path: &str) -> Result<usize> {
+        return_errno_with_message!(Errnum::ENOTSUP, "not support");
+    }
+}

+ 46 - 0
src/ext4/link.rs

@@ -0,0 +1,46 @@
+use super::Ext4;
+use crate::constants::*;
+use crate::ext4_defs::*;
+
+impl Ext4 {
+    pub fn ext4_link(
+        &self,
+        parent: &mut Ext4InodeRef,
+        child: &mut Ext4InodeRef,
+        name: &str,
+        name_len: u32,
+    ) -> usize {
+        // log::info!("link parent inode {:x?} child inode {:x?} name {:?}", parent.inode_num, child.inode_num, name);
+        /* Add entry to parent directory */
+        let _r = self.ext4_dir_add_entry(parent, child, name, name_len);
+    
+        /* Fill new dir -> add '.' and '..' entries.
+         * Also newly allocated inode should have 0 link count.
+            */
+        let mut is_dir = false;
+        if child.inode.mode & EXT4_INODE_MODE_TYPE_MASK as u16 == EXT4_INODE_MODE_DIRECTORY as u16
+        {
+            is_dir = true;
+        }
+    
+        if is_dir {
+            // add '.' and '..' entries
+            let mut child_inode_ref = Ext4InodeRef::default();
+            child_inode_ref.inode_id = child.inode_id;
+            child_inode_ref.inode = child.inode.clone();
+    
+            let _r = self.ext4_dir_add_entry(&mut child_inode_ref, child, ".", 1);
+            child.inode.size = child_inode_ref.inode.size;
+            child.inode.block = child_inode_ref.inode.block;
+            let _r = self.ext4_dir_add_entry(&mut child_inode_ref, parent, "..", 2);
+    
+            child.inode.links_count = 2;
+            parent.inode.links_count += 1;
+    
+            return EOK;
+        }
+    
+        child.inode.links_count += 1;
+        EOK
+    }
+}

+ 114 - 0
src/ext4/mod.rs

@@ -0,0 +1,114 @@
+use crate::constants::*;
+use crate::ext4_defs::*;
+use crate::prelude::*;
+
+mod dir;
+mod file;
+mod alloc;
+mod utils;
+mod extent;
+mod link;
+
+#[derive(Debug)]
+pub struct Ext4 {
+    pub block_device: Arc<dyn BlockDevice>,
+    pub super_block: Ext4Superblock,
+    pub block_groups: Vec<Ext4BlockGroupDesc>,
+    pub inodes_per_group: u32,
+    pub blocks_per_group: u32,
+    pub inode_size: usize,
+    pub last_inode_bg_id: u32,
+    pub mount_point: Ext4MountPoint,
+}
+
+impl Ext4 {
+    /// Opens and loads an Ext4 from the `block_device`.
+    pub fn new(block_device: Arc<dyn BlockDevice>) -> Arc<Self> {
+        // Load the superblock
+        // TODO: if the main superblock is corrupted, should we load the backup?
+        let raw_data = block_device.read_offset(BASE_OFFSET);
+        let super_block = Ext4Superblock::try_from(raw_data).unwrap();
+
+        // log::info!("super_block: {:x?}", super_block);
+        let inodes_per_group = super_block.inodes_per_group();
+        let blocks_per_group = super_block.blocks_per_group();
+        let inode_size = super_block.inode_size();
+
+        // Load the block groups information
+        let load_block_groups =
+            |_fs: Weak<Ext4>, block_device: Arc<dyn BlockDevice>| -> Result<Vec<Ext4BlockGroupDesc>> {
+                let block_groups_count = super_block.block_groups_count() as usize;
+                let mut block_groups = Vec::with_capacity(block_groups_count);
+                for idx in 0..block_groups_count {
+                    let block_group =
+                        Ext4BlockGroupDesc::load(block_device.clone(), &super_block, idx).unwrap();
+                    block_groups.push(block_group);
+                }
+                Ok(block_groups)
+            };
+
+        let mount_point = Ext4MountPoint::new("/");
+
+        let ext4: Arc<Ext4> = Arc::new_cyclic(|weak_ref| Self {
+            super_block,
+            inodes_per_group,
+            blocks_per_group,
+            inode_size: inode_size as usize,
+            block_groups: load_block_groups(weak_ref.clone(), block_device.clone()).unwrap(),
+            block_device,
+            mount_point,
+            last_inode_bg_id: 0,
+        });
+
+        ext4
+    }
+
+    // start transaction
+    pub fn ext4_trans_start(&self) {}
+
+    // stop transaction
+    pub fn ext4_trans_abort(&self) {}
+
+    fn get_inode_ref(&self, inode_id: u32) -> Ext4InodeRef {
+        let super_block = self.super_block;
+
+        let inodes_per_group = super_block.inodes_per_group();
+        let inode_size = super_block.inode_size() as u64;
+        let group = (inode_id - 1) / inodes_per_group;
+        let index = (inode_id - 1) % inodes_per_group;
+        let group = self.block_groups[group as usize];
+        let inode_table_blk_num = group.get_inode_table_blk_num();
+        let offset =
+            inode_table_blk_num as usize * BLOCK_SIZE + index as usize * inode_size as usize;
+
+        let data = self.block_device.read_offset(offset);
+        let inode_data = &data[..core::mem::size_of::<Ext4Inode>()];
+        let inode = Ext4Inode::try_from(inode_data).unwrap();
+
+        Ext4InodeRef::new(inode_id, inode)
+    }
+
+    fn get_root_inode_ref(&self) -> Ext4InodeRef {
+        self.get_inode_ref(EXT4_ROOT_INO)
+    }
+
+    fn write_back_inode(&self, inode_ref: &mut Ext4InodeRef) {
+        let block_device = self.block_device.clone();
+        let super_block = self.super_block.clone();
+        let inode_id = inode_ref.inode_id;
+        inode_ref
+            .inode
+            .sync_to_disk_with_csum(block_device, &super_block, inode_id)
+            .unwrap()
+    }
+
+    fn write_back_inode_without_csum(&self, inode_ref: &mut Ext4InodeRef) {
+        let block_device = self.block_device.clone();
+        let super_block = self.super_block.clone();
+        let inode_id = inode_ref.inode_id;
+        inode_ref
+            .inode
+            .sync_to_disk(block_device, &super_block, inode_id)
+            .unwrap()
+    }
+}

+ 14 - 0
src/utils.rs → src/ext4/utils.rs

@@ -1,4 +1,5 @@
 use crate::prelude::*;
+use crate::constants::*;
 
 /// 检查位图中的某一位是否被设置
 /// 参数 bmap 位图缓冲区
@@ -98,3 +99,16 @@ pub fn get_name(
     let s = String::from_utf8(v);
     s
 }
+
+// 使用libc库定义的常量
+pub fn ext4_parse_flags(flags: &str) -> Result<u32> {
+    match flags {
+        "r" | "rb" => Ok(O_RDONLY),
+        "w" | "wb" => Ok(O_WRONLY | O_CREAT | O_TRUNC),
+        "a" | "ab" => Ok(O_WRONLY | O_CREAT | O_APPEND),
+        "r+" | "rb+" | "r+b" => Ok(O_RDWR),
+        "w+" | "wb+" | "w+b" => Ok(O_RDWR | O_CREAT | O_TRUNC),
+        "a+" | "ab+" | "a+b" => Ok(O_RDWR | O_CREAT | O_APPEND),
+        _ => Err(Ext4Error::new(Errnum::EINVAL)),
+    }
+}

+ 21 - 13
src/ext4_defs/block_group.rs

@@ -1,3 +1,12 @@
+//!# The Defination of Ext4 Block Group Description
+//! 
+//! Block Group Descriptor is the second field of Ext4 Block Group.
+//! 
+//! | Super Block | Group Descriptor | Reserved GDT Blocks | Block Bitmap |
+//! | Inode Bitmap | Inode Table | Data Blocks |
+//! 
+//! See [`super`] for more information.
+
 use crate::constants::*;
 use crate::prelude::*;
 use super::crc::*;
@@ -6,7 +15,7 @@ use super::Ext4Superblock;
 
 #[derive(Debug, Default, Clone, Copy)]
 #[repr(C, packed)]
-pub struct Ext4BlockGroup {
+pub struct Ext4BlockGroupDesc {
     block_bitmap_lo: u32,            // 块位图块
     inode_bitmap_lo: u32,            // 节点位图块
     inode_table_first_block_lo: u32, // 节点表块
@@ -33,34 +42,33 @@ pub struct Ext4BlockGroup {
     reserved: u32,                   // 填充
 }
 
-impl TryFrom<&[u8]> for Ext4BlockGroup {
+impl TryFrom<&[u8]> for Ext4BlockGroupDesc {
     type Error = u64;
     fn try_from(data: &[u8]) -> core::result::Result<Self, u64> {
-        let data = &data[..size_of::<Ext4BlockGroup>()];
+        let data = &data[..size_of::<Ext4BlockGroupDesc>()];
         Ok(unsafe { core::ptr::read(data.as_ptr() as *const _) })
     }
 }
 
-impl Ext4BlockGroup {
+impl Ext4BlockGroupDesc {
     pub fn load(
         block_device: Arc<dyn BlockDevice>,
         super_block: &Ext4Superblock,
-        block_group_idx: usize,
-        // fs: Weak<Ext4>,
+        block_group_id: usize,
     ) -> core::result::Result<Self, u64> {
         let dsc_cnt = BLOCK_SIZE / super_block.desc_size() as usize;
-        let dsc_id = block_group_idx / dsc_cnt;
+        let dsc_id = block_group_id / dsc_cnt;
         let first_data_block = super_block.first_data_block();
 
         let block_id = first_data_block as usize + dsc_id + 1;
-        let offset = (block_group_idx % dsc_cnt) * super_block.desc_size() as usize;
+        let offset = (block_group_id % dsc_cnt) * super_block.desc_size() as usize;
 
         let data = block_device.read_offset(block_id * BLOCK_SIZE);
 
         let block_group_data =
-            &data[offset as usize..offset as usize + size_of::<Ext4BlockGroup>()];
+            &data[offset as usize..offset as usize + size_of::<Ext4BlockGroupDesc>()];
 
-        let bg = Ext4BlockGroup::try_from(block_group_data);
+        let bg = Ext4BlockGroupDesc::try_from(block_group_data);
 
         bg
     }
@@ -151,7 +159,7 @@ impl Ext4BlockGroup {
         let offset = (bgid % dsc_cnt) * super_block.desc_size() as usize;
 
         let data = unsafe {
-            core::slice::from_raw_parts(self as *const _ as *const u8, size_of::<Ext4BlockGroup>())
+            core::slice::from_raw_parts(self as *const _ as *const u8, size_of::<Ext4BlockGroupDesc>())
         };
         block_device.write_offset(block_id * BLOCK_SIZE + offset, data);
     }
@@ -249,7 +257,7 @@ impl Ext4BlockGroup {
     }
 }
 
-pub fn ext4_ialloc_bitmap_csum(bitmap: &[u8], s: &Ext4Superblock) -> u32 {
+fn ext4_ialloc_bitmap_csum(bitmap: &[u8], s: &Ext4Superblock) -> u32 {
     let inodes_per_group = s.inodes_per_group();
     let uuid = s.uuid();
     let mut csum = ext4_crc32c(EXT4_CRC32_INIT, &uuid, uuid.len() as u32);
@@ -257,7 +265,7 @@ pub fn ext4_ialloc_bitmap_csum(bitmap: &[u8], s: &Ext4Superblock) -> u32 {
     csum
 }
 
-pub fn ext4_balloc_bitmap_csum(bitmap: &[u8], s: &Ext4Superblock) -> u32 {
+fn ext4_balloc_bitmap_csum(bitmap: &[u8], s: &Ext4Superblock) -> u32 {
     let blocks_per_group = s.blocks_per_group();
     let uuid = s.uuid();
     let mut csum = ext4_crc32c(EXT4_CRC32_INIT, &uuid, uuid.len() as u32);

+ 11 - 11
src/ext4_defs/dir_entry.rs

@@ -1,17 +1,17 @@
-use crate::constants::*;
-use crate::prelude::*;
 use super::crc::*;
 use super::BlockDevice;
 use super::Ext4Block;
 use super::Ext4Superblock;
+use crate::constants::*;
+use crate::prelude::*;
 
 #[repr(C)]
-pub union Ext4DirEnInternal {
+pub union Ext4DirEnInner {
     pub name_length_high: u8, // 高8位的文件名长度
     pub inode_type: u8,       // 引用的inode的类型(在rev >= 0.5中)
 }
 
-impl Debug for Ext4DirEnInternal {
+impl Debug for Ext4DirEnInner {
     fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
         unsafe {
             write!(
@@ -23,7 +23,7 @@ impl Debug for Ext4DirEnInternal {
     }
 }
 
-impl Default for Ext4DirEnInternal {
+impl Default for Ext4DirEnInner {
     fn default() -> Self {
         Self {
             name_length_high: 0,
@@ -34,11 +34,11 @@ impl Default for Ext4DirEnInternal {
 #[repr(C)]
 #[derive(Debug)]
 pub struct Ext4DirEntry {
-    pub inode: u32,               // 该目录项指向的inode的编号
-    pub entry_len: u16,           // 到下一个目录项的距离
-    pub name_len: u8,             // 低8位的文件名长度
-    pub inner: Ext4DirEnInternal, // 联合体成员
-    pub name: [u8; 255],          // 文件名
+    pub inode: u32,            // 该目录项指向的inode的编号
+    pub entry_len: u16,        // 到下一个目录项的距离
+    pub name_len: u8,          // 低8位的文件名长度
+    pub inner: Ext4DirEnInner, // 联合体成员
+    pub name: [u8; 255],       // 文件名
 }
 
 impl Default for Ext4DirEntry {
@@ -47,7 +47,7 @@ impl Default for Ext4DirEntry {
             inode: 0,
             entry_len: 0,
             name_len: 0,
-            inner: Ext4DirEnInternal::default(),
+            inner: Ext4DirEnInner::default(),
             name: [0; 255],
         }
     }

+ 100 - 63
src/ext4_defs/extent.rs

@@ -1,6 +1,6 @@
 use super::Ext4Inode;
 use crate::constants::*;
-use core::mem::size_of;
+use crate::prelude::*;
 
 #[derive(Debug, Default, Clone, Copy)]
 #[repr(C)]
@@ -161,6 +161,47 @@ impl<T> TryFrom<&[T]> for Ext4Extent {
     }
 }
 
+impl Ext4Extent {
+    pub fn pblock(&self) -> u64 {
+        self.start_lo as u64 | ((self.start_hi as u64) << 32)
+    }
+
+    pub fn is_unwritten(&self) -> bool {
+        // 返回extent是否是未写入的
+        self.block_count > EXT_INIT_MAX_LEN
+    }
+
+    pub fn actual_len(&self) -> u16 {
+        // 返回extent的实际长度
+        if self.block_count <= EXT_INIT_MAX_LEN {
+            self.block_count
+        } else {
+            self.block_count - EXT_INIT_MAX_LEN
+        }
+    }
+
+    pub fn mark_unwritten(&mut self) {
+        (*self).block_count |= EXT_INIT_MAX_LEN;
+    }
+
+    /// 检查是否可以将ex2合并到ex1的后面
+    pub fn can_append(ex1: &Ext4Extent, ex2: &Ext4Extent) -> bool {
+        if ex1.pblock() + ex1.actual_len() as u64 != ex2.pblock() {
+            return false;
+        }
+        if ex1.is_unwritten() && ex1.actual_len() + ex2.actual_len() > EXT_UNWRITTEN_MAX_LEN {
+            return false;
+        } else if ex1.actual_len() + ex2.actual_len() > EXT_INIT_MAX_LEN {
+            return false;
+        }
+        // 检查逻辑块号是否连续
+        if ex1.first_block + ex1.actual_len() as u32 != ex2.first_block {
+            return false;
+        }
+        return true;
+    }
+}
+
 #[derive(Debug, Clone, Copy)]
 pub struct Ext4ExtentPath {
     // Physical block number
@@ -225,92 +266,88 @@ impl Default for Ext4ExtentPathOld {
     }
 }
 
-#[allow(unused)]
 pub fn ext4_first_extent(hdr: *const Ext4ExtentHeader) -> *const Ext4Extent {
-    unsafe {
-        let offset = core::mem::size_of::<Ext4ExtentHeader>();
-
-        (hdr as *const u8).add(offset) as *const Ext4Extent
+    if hdr.is_null() {
+        return ptr::null_mut();
     }
+    unsafe { hdr.add(1) as *const Ext4Extent }
 }
 
 pub fn ext4_first_extent_mut(hdr: *mut Ext4ExtentHeader) -> *mut Ext4Extent {
-    unsafe {
-        let offset = core::mem::size_of::<Ext4ExtentHeader>();
+    ext4_first_extent(hdr) as *mut Ext4Extent
+}
 
-        (hdr as *mut u8).add(offset) as *mut Ext4Extent
-    }
+pub fn ext4_first_extent_index(hdr: *const Ext4ExtentHeader) -> *const Ext4ExtentIndex {
+    ext4_first_extent(hdr) as *const Ext4ExtentIndex
+}
+
+pub fn ext4_first_extent_index_mut(hdr: *mut Ext4ExtentHeader) -> *mut Ext4ExtentIndex {
+    ext4_first_extent(hdr) as *mut Ext4ExtentIndex
 }
 
 #[allow(unused)]
 pub fn ext4_last_extent(hdr: *const Ext4ExtentHeader) -> *const Ext4Extent {
-    unsafe {
-        let hdr_size = core::mem::size_of::<Ext4ExtentHeader>();
-        let ext_size = core::mem::size_of::<Ext4Extent>();
-        let hdr_ref = core::mem::transmute::<*const Ext4ExtentHeader, &Ext4ExtentHeader>(hdr);
-        let ext_count = hdr_ref.entries_count as usize;
-        (hdr as *const u8).add(hdr_size + (ext_count - 1) * ext_size) as *const Ext4Extent
-    }
+    if hdr.is_null() {
+        return ptr::null_mut();
+    }
+    // Get the number of extents from header
+    let count = unsafe { (*hdr).entries_count as usize };
+    if count == 0 {
+        return ptr::null_mut();
+    }
+    // Get the pointer to the first extent
+    let first = ext4_first_extent(hdr);
+    // Add count - 1 offset to get the last extent
+    unsafe { first.add(count - 1) }
 }
 
 pub fn ext4_last_extent_mut(hdr: *mut Ext4ExtentHeader) -> *mut Ext4Extent {
-    unsafe {
-        let hdr_size = core::mem::size_of::<Ext4ExtentHeader>();
-        let ext_size = core::mem::size_of::<Ext4Extent>();
-        let hdr_ref = core::mem::transmute::<*mut Ext4ExtentHeader, &Ext4ExtentHeader>(hdr);
-        let ext_count = hdr_ref.entries_count as usize;
-
-        (hdr as *mut u8).add(hdr_size + (ext_count - 1) * ext_size) as *mut Ext4Extent
-    }
+    ext4_last_extent(hdr) as *mut Ext4Extent
 }
 
 #[allow(unused)]
-pub fn ext4_first_extent_index(hdr: *const Ext4ExtentHeader) -> *const Ext4ExtentIndex {
-    unsafe {
-        let offset = core::mem::size_of::<Ext4ExtentHeader>();
-
-        (hdr as *const u8).add(offset) as *const Ext4ExtentIndex
-    }
+pub fn ext4_last_extent_index(hdr: *const Ext4ExtentHeader) -> *const Ext4ExtentIndex {
+    if hdr.is_null() {
+        return ptr::null_mut();
+    }
+    // Get the number of extents from header
+    let count = unsafe { (*hdr).entries_count as usize };
+    if count == 0 {
+        return ptr::null_mut();
+    }
+    // Get the pointer to the first extent_index
+    let first = ext4_first_extent_index(hdr);
+    // Add count - 1 offset to get the last extent_index
+    unsafe { first.add(count - 1) }
 }
 
-pub fn ext4_first_extent_index_mut(hdr: *mut Ext4ExtentHeader) -> *mut Ext4ExtentIndex {
-    unsafe {
-        let offset = core::mem::size_of::<Ext4ExtentHeader>();
-
-        (hdr as *mut u8).add(offset) as *mut Ext4ExtentIndex
-    }
+pub fn ext4_last_extent_index_mut(hdr: *mut Ext4ExtentHeader) -> *mut Ext4ExtentIndex {
+    ext4_last_extent_index(hdr) as *mut Ext4ExtentIndex
 }
 
-#[allow(unused)]
-pub fn ext4_last_extent_index(hdr: *const Ext4ExtentHeader) -> *const Ext4ExtentIndex {
-    unsafe {
-        let hdr_size = core::mem::size_of::<Ext4ExtentHeader>();
-        let ext_size = core::mem::size_of::<Ext4ExtentIndex>();
-        let hdr_ref = core::mem::transmute::<*const Ext4ExtentHeader, &Ext4ExtentHeader>(hdr);
-        let ext_count = hdr_ref.entries_count as usize;
-        (hdr as *const u8).add(hdr_size + (ext_count - 1) * ext_size) as *const Ext4ExtentIndex
-    }
+pub fn ext4_extent_hdr(inode: &Ext4Inode) -> *const Ext4ExtentHeader {
+    &inode.block as *const [u32; 15] as *const Ext4ExtentHeader
 }
 
-pub fn ext4_last_extent_index_mut(hdr: *mut Ext4ExtentHeader) -> *mut Ext4ExtentIndex {
-    unsafe {
-        let hdr_size = core::mem::size_of::<Ext4ExtentHeader>();
-        let ext_size = core::mem::size_of::<Ext4ExtentIndex>();
-        let hdr_ref = core::mem::transmute::<*mut Ext4ExtentHeader, &Ext4ExtentHeader>(hdr);
-        let ext_count = hdr_ref.entries_count as usize;
-        (hdr as *mut u8).add(hdr_size + (ext_count - 1) * ext_size) as *mut Ext4ExtentIndex
-    }
+pub fn ext4_extent_hdr_mut(inode: &mut Ext4Inode) -> *mut Ext4ExtentHeader {
+    ext4_extent_hdr(inode) as *mut Ext4ExtentHeader
 }
 
-pub fn ext4_inode_hdr(inode: &Ext4Inode) -> *const Ext4ExtentHeader {
-    let eh = &inode.block as *const [u32; 15] as *const Ext4ExtentHeader;
-    eh
+pub fn ext4_depth(inode: &Ext4Inode) -> u16 {
+    unsafe { (*ext4_extent_hdr(inode)).depth }
 }
 
-#[allow(unused)]
-pub fn ext4_inode_hdr_mut(inode: &mut Ext4Inode) -> *mut Ext4ExtentHeader {
-    let eh = &mut inode.block as *mut [u32; 15] as *mut Ext4ExtentHeader;
-    eh
+pub fn ext4_idx_pblock(idx: *mut Ext4ExtentIndex) -> u64 {
+    // 如果索引为空,返回0
+    if idx.is_null() {
+        return 0;
+    }
+    // 获取索引的低32位物理块号
+    let pblock_lo = unsafe { (*idx).leaf_lo } as u64;
+    // 如果支持64位物理块号,获取索引的高16位物理块号
+    let pblock_hi = unsafe { (*idx).leaf_hi } as u64;
+    // 返回索引的物理块号
+    (pblock_hi << 32) | pblock_lo
 }
 
 /// 定义ext4_ext_binsearch函数,接受一个指向ext4_extent_path的可变引用和一个逻辑块号
@@ -358,7 +395,7 @@ pub fn ext4_ext_binsearch(path: &mut Ext4ExtentPath, block: u32) -> bool {
     true
 }
 
-pub fn ext4_ext_binsearch_idx(path: &mut Ext4ExtentPath, block: ext4_lblk_t) -> bool {
+pub fn ext4_ext_binsearch_idx(path: &mut Ext4ExtentPath, block: Ext4LogicBlockId) -> bool {
     // 获取extent header的引用
     let eh = path.header;
 
@@ -394,7 +431,7 @@ pub fn ext4_ext_binsearch_idx(path: &mut Ext4ExtentPath, block: ext4_lblk_t) ->
 }
 
 #[allow(unused)]
-pub fn ext4_ext_find_extent(eh: *mut Ext4ExtentHeader, block: ext4_lblk_t) -> *mut Ext4Extent {
+pub fn ext4_ext_find_extent(eh: *mut Ext4ExtentHeader, block: Ext4LogicBlockId) -> *mut Ext4Extent {
     // 初始化一些变量
     let mut low: i32;
     let mut high: i32;

+ 81 - 65
src/ext4_defs/inode.rs

@@ -1,10 +1,18 @@
-use crate::constants::*;
+//! # The Defination of Ext4 Inode Table Entry
+//!
+//! The inode table is a linear array of struct ext4_inode. The table is sized to have
+//! enough blocks to store at least sb.s_inode_size * sb.s_inodes_per_group bytes.
+//! The number of the block group containing an inode can be calculated as
+//! (inode_number - 1) / sb.s_inodes_per_group, and the offset into the group's table is
+//! (inode_number - 1) % sb.s_inodes_per_group. There is no inode 0.
+
 use super::crc::*;
-use crate::prelude::*;
 use super::BlockDevice;
-use super::Ext4BlockGroup;
+use super::Ext4BlockGroupDesc;
 use super::Ext4ExtentHeader;
 use super::Ext4Superblock;
+use crate::constants::*;
+use crate::prelude::*;
 
 #[repr(C)]
 #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
@@ -58,80 +66,75 @@ impl TryFrom<&[u8]> for Ext4Inode {
 }
 
 impl Ext4Inode {
-    pub fn ext4_get_inode_flags(&self) -> u32 {
+    pub fn flags(&self) -> u32 {
         self.flags
     }
-    pub fn ext4_get_inode_mode(&self) -> u16 {
-        self.mode
-    }
 
-    pub fn ext4_inode_set_flags(&mut self, f: u32) {
+    pub fn set_flags(&mut self, f: u32) {
         self.flags |= f;
     }
 
-    pub fn ext4_inode_set_mode(&mut self, mode: u16) {
+    pub fn mode(&self) -> u16 {
+        self.mode
+    }
+
+    pub fn set_mode(&mut self, mode: u16) {
         self.mode |= mode;
     }
 
-    pub fn ext4_inode_set_links_cnt(&mut self, cnt: u16) {
+    pub fn links_cnt(&self) -> u16 {
+        self.links_count
+    }
+
+    pub fn set_links_cnt(&mut self, cnt: u16) {
         self.links_count = cnt;
     }
 
-    pub fn ext4_inode_set_uid(&mut self, uid: u16) {
+    pub fn set_uid(&mut self, uid: u16) {
         self.uid = uid;
     }
 
-    pub fn ext4_inode_set_gid(&mut self, gid: u16) {
+    pub fn set_gid(&mut self, gid: u16) {
         self.gid = gid;
     }
 
-    pub fn ext4_inode_set_size(&mut self, size: u64) {
-        self.size = ((size << 32) >> 32) as u32;
-        self.size_hi = (size >> 32) as u32;
+    pub fn size(&mut self) -> u64 {
+        self.size as u64 | ((self.size_hi as u64) << 32)
     }
 
-    pub fn ext4_inode_get_size(&mut self) -> u64 {
-        self.size as u64 | ((self.size_hi as u64) << 32)
+    pub fn set_size(&mut self, size: u64) {
+        self.size = ((size << 32) >> 32) as u32;
+        self.size_hi = (size >> 32) as u32;
     }
 
-    pub fn ext4_inode_set_access_time(&mut self, access_time: u32) {
+    pub fn set_access_time(&mut self, access_time: u32) {
         self.atime = access_time;
     }
 
-    pub fn ext4_inode_set_change_inode_time(&mut self, change_inode_time: u32) {
+    pub fn set_change_inode_time(&mut self, change_inode_time: u32) {
         self.ctime = change_inode_time;
     }
 
-    pub fn ext4_inode_set_modif_time(&mut self, modif_time: u32) {
+    pub fn set_modif_time(&mut self, modif_time: u32) {
         self.mtime = modif_time;
     }
 
-    pub fn ext4_inode_set_del_time(&mut self, del_time: u32) {
+    pub fn set_del_time(&mut self, del_time: u32) {
         self.dtime = del_time;
     }
 
-    pub fn ext4_inode_set_blocks_count(&mut self, blocks_count: u32) {
+    pub fn set_blocks_count(&mut self, blocks_count: u32) {
         self.blocks = blocks_count;
     }
 
-    pub fn ext4_inode_set_generation(&mut self, generation: u32) {
+    pub fn set_generation(&mut self, generation: u32) {
         self.generation = generation;
     }
 
-    pub fn ext4_inode_set_extra_isize(&mut self, extra_isize: u16) {
+    pub fn set_extra_isize(&mut self, extra_isize: u16) {
         self.i_extra_isize = extra_isize;
     }
 
-    #[allow(unused)]
-    fn get_checksum(&self, super_block: &Ext4Superblock) -> u32 {
-        let inode_size = super_block.inode_size();
-        let mut v: u32 = self.osd2.l_i_checksum_lo as u32;
-        if inode_size > 128 {
-            v |= (self.i_checksum_hi as u32) << 16;
-        }
-        v
-    }
-
     pub fn set_inode_checksum_value(
         &mut self,
         super_block: &Ext4Superblock,
@@ -146,12 +149,12 @@ impl Ext4Inode {
         }
     }
 
-    pub fn ext4_inode_get_extent_header(&mut self) -> *mut Ext4ExtentHeader {
+    pub fn extent_header(&mut self) -> *mut Ext4ExtentHeader {
         let header_ptr = (&mut self.block) as *mut [u32; 15] as *mut Ext4ExtentHeader;
         header_ptr
     }
 
-    pub fn ext4_extent_tree_init(&mut self) {
+    pub fn extent_tree_init(&mut self) {
         let mut header = Ext4ExtentHeader::default();
         header.ext4_extent_header_set_depth(0);
         header.ext4_extent_header_set_entries_count(0);
@@ -166,7 +169,7 @@ impl Ext4Inode {
         }
     }
 
-    pub fn ext4_inode_get_blocks_count(&self) -> u64 {
+    pub fn blocks_count(&self) -> u64 {
         let mut blocks = self.blocks as u64;
         if self.osd2.l_i_blocks_high != 0 {
             blocks |= (self.osd2.l_i_blocks_high as u64) << 32;
@@ -190,31 +193,24 @@ impl Ext4Inode {
         let group = (inode_id - 1) / inodes_per_group;
         let index = (inode_id - 1) % inodes_per_group;
 
-        let bg = Ext4BlockGroup::load(block_device, super_block, group as usize).unwrap();
+        let bg = Ext4BlockGroupDesc::load(block_device, super_block, group as usize).unwrap();
 
-        let inode_table_blk_num =
-            ((bg.inode_table_first_block_hi() as u64) << 32) | bg.inode_table_first_block_lo() as u64;
+        let inode_table_blk_num = ((bg.inode_table_first_block_hi() as u64) << 32)
+            | bg.inode_table_first_block_lo() as u64;
         let offset =
             inode_table_blk_num as usize * BLOCK_SIZE + (index * inode_size as u32) as usize;
         offset
     }
 
-    pub fn sync_inode_to_disk(
-        &self,
-        block_device: Arc<dyn BlockDevice>,
-        super_block: &Ext4Superblock,
-        inode_id: u32,
-    ) -> Result<()> {
-        let disk_pos = self.get_inode_disk_pos(super_block, block_device.clone(), inode_id);
-        let data = unsafe {
-            core::slice::from_raw_parts(self as *const _ as *const u8, size_of::<Ext4Inode>())
-        };
-        block_device.write_offset(disk_pos, data);
-
-        Ok(())
+    fn copy_to_byte_slice(&self, slice: &mut [u8]) {
+        unsafe {
+            let inode_ptr = self as *const Ext4Inode as *const u8;
+            let array_ptr = slice.as_ptr() as *mut u8;
+            core::ptr::copy_nonoverlapping(inode_ptr, array_ptr, 0x9c);
+        }
     }
 
-    pub fn get_inode_checksum(&mut self, inode_id: u32, super_block: &Ext4Superblock) -> u32 {
+    pub fn calc_checksum(&mut self, inode_id: u32, super_block: &Ext4Superblock) -> u32 {
         let inode_size = super_block.inode_size();
 
         let ino_index = inode_id as u32;
@@ -233,7 +229,7 @@ impl Ext4Inode {
         checksum = ext4_crc32c(checksum, &ino_gen.to_le_bytes(), 4);
 
         let mut raw_data = [0u8; 0x100];
-        copy_inode_to_array(&self, &mut raw_data);
+        self.copy_to_byte_slice(&mut raw_data);
 
         // inode checksum
         checksum = ext4_crc32c(checksum, &raw_data, inode_size as u32);
@@ -247,9 +243,9 @@ impl Ext4Inode {
         checksum
     }
 
-    pub fn set_inode_checksum(&mut self, super_block: &Ext4Superblock, inode_id: u32) {
+    pub fn set_checksum(&mut self, super_block: &Ext4Superblock, inode_id: u32) {
         let inode_size = super_block.inode_size();
-        let checksum = self.get_inode_checksum(inode_id, super_block);
+        let checksum = self.calc_checksum(inode_id, super_block);
 
         self.osd2.l_i_checksum_lo = ((checksum << 16) >> 16) as u16;
         if inode_size > 128 {
@@ -257,21 +253,41 @@ impl Ext4Inode {
         }
     }
 
-    pub fn sync_inode_to_disk_with_csum(
+    pub fn sync_to_disk(
+        &self,
+        block_device: Arc<dyn BlockDevice>,
+        super_block: &Ext4Superblock,
+        inode_id: u32,
+    ) -> Result<()> {
+        let disk_pos = self.get_inode_disk_pos(super_block, block_device.clone(), inode_id);
+        let data = unsafe {
+            core::slice::from_raw_parts(self as *const _ as *const u8, size_of::<Ext4Inode>())
+        };
+        block_device.write_offset(disk_pos, data);
+
+        Ok(())
+    }
+
+    pub fn sync_to_disk_with_csum(
         &mut self,
         block_device: Arc<dyn BlockDevice>,
         super_block: &Ext4Superblock,
         inode_id: u32,
     ) -> Result<()> {
-        self.set_inode_checksum(super_block, inode_id);
-        self.sync_inode_to_disk(block_device, super_block, inode_id)
+        self.set_checksum(super_block, inode_id);
+        self.sync_to_disk(block_device, super_block, inode_id)
     }
 }
 
-pub fn copy_inode_to_array(inode: &Ext4Inode, array: &mut [u8]) {
-    unsafe {
-        let inode_ptr = inode as *const Ext4Inode as *const u8;
-        let array_ptr = array as *mut [u8] as *mut u8;
-        core::ptr::copy_nonoverlapping(inode_ptr, array_ptr, 0x9c);
+/// A reference to an inode in the ext4 filesystem.
+#[derive(Default)]
+pub struct Ext4InodeRef {
+    pub inode_id: u32,
+    pub inode: Ext4Inode,
+}
+
+impl Ext4InodeRef {
+    pub fn new(inode_id: u32, inode: Ext4Inode) -> Self {
+        Self { inode_id, inode }
     }
 }

+ 0 - 105
src/ext4_defs/inode_ref.rs

@@ -1,105 +0,0 @@
-use super::Ext4Inode;
-use crate::Ext4;
-use crate::prelude::*;
-use crate::constants::*;
-
-pub struct Ext4InodeRef {
-    pub inode_num: u32,
-    pub inner: InodeRefInner,
-    pub fs: Weak<Ext4>,
-}
-
-impl Ext4InodeRef {
-    pub fn new(fs: Weak<Ext4>) -> Self {
-        let inner = InodeRefInner {
-            inode: Ext4Inode::default(),
-            weak_self: Weak::new(),
-        };
-        let inode = Self {
-            inode_num: 0,
-            inner,
-            fs,
-        };
-        inode
-    }
-
-    pub fn fs(&self) -> Arc<Ext4> {
-        self.fs.upgrade().unwrap()
-    }
-
-    pub fn get_inode_ref(fs: Weak<Ext4>, inode_num: u32) -> Self {
-        let fs_clone = fs.clone();
-
-        let fs = fs.upgrade().unwrap();
-        let super_block = fs.super_block;
-
-        let inodes_per_group = super_block.inodes_per_group();
-        let inode_size = super_block.inode_size() as u64;
-        let group = (inode_num - 1) / inodes_per_group;
-        let index = (inode_num - 1) % inodes_per_group;
-        let group = fs.block_groups[group as usize];
-        let inode_table_blk_num = group.get_inode_table_blk_num();
-        let offset =
-            inode_table_blk_num as usize * BLOCK_SIZE + index as usize * inode_size as usize;
-
-        let data = fs.block_device.read_offset(offset);
-        let inode_data = &data[..core::mem::size_of::<Ext4Inode>()];
-        let inode = Ext4Inode::try_from(inode_data).unwrap();
-
-        let inner = InodeRefInner {
-            inode,
-            weak_self: Weak::new(),
-        };
-        let inode = Self {
-            inode_num,
-            inner,
-            fs: fs_clone,
-        };
-
-        inode
-    }
-
-    pub fn write_back_inode(&mut self) {
-        let fs = self.fs();
-        let block_device = fs.block_device.clone();
-        let super_block = fs.super_block.clone();
-        let inode_id = self.inode_num;
-        self.inner
-            .inode
-            .sync_inode_to_disk_with_csum(block_device, &super_block, inode_id)
-            .unwrap()
-    }
-
-    pub fn write_back_inode_without_csum(&mut self) {
-        let fs = self.fs();
-        let block_device = fs.block_device.clone();
-        let super_block = fs.super_block.clone();
-        let inode_id = self.inode_num;
-        self.inner
-            .inode
-            .sync_inode_to_disk(block_device, &super_block, inode_id)
-            .unwrap()
-    }
-}
-
-pub struct InodeRefInner {
-    pub inode: Ext4Inode,
-    pub weak_self: Weak<Ext4InodeRef>,
-}
-
-impl InodeRefInner {
-    pub fn inode(&self) -> Arc<Ext4InodeRef> {
-        self.weak_self.upgrade().unwrap()
-    }
-
-    pub fn write_back_inode(&mut self) {
-        let weak_inode_ref = self.weak_self.clone().upgrade().unwrap();
-        let fs = weak_inode_ref.fs();
-        let block_device = fs.block_device.clone();
-        let super_block = fs.super_block.clone();
-        let inode_id = weak_inode_ref.inode_num;
-        self.inode
-            .sync_inode_to_disk_with_csum(block_device, &super_block, inode_id)
-            .unwrap()
-    }
-}

+ 16 - 2
src/ext4_defs/mod.rs

@@ -1,3 +1,19 @@
+//! # The Defination of Ext4 File System Data Structures
+//! 
+//! The layout of a standard block group is approximately as follows:
+//! 
+//! - Group 0 Padding: 1024 bytes
+//! - Superblock: 1 block
+//! - Group Descriptors: many blocks
+//! - Reserved GDT Blocks: many blocks
+//! - Block Bitmap: 1 block
+//! - inode Bitmap: 1 block
+//! - inode Table: many blocks
+//! - Data Blocks: many more blocks
+//! 
+//! For the special case of block group 0, the first 1024 bytes are unused.
+//! For all other block groups, there is no padding.
+
 mod block;
 mod block_device;
 mod block_group;
@@ -6,7 +22,6 @@ mod dir_entry;
 mod extent;
 mod file;
 mod inode;
-mod inode_ref;
 mod mount_point;
 mod super_block;
 
@@ -17,6 +32,5 @@ pub use dir_entry::*;
 pub use extent::*;
 pub use file::*;
 pub use inode::*;
-pub use inode_ref::*;
 pub use mount_point::*;
 pub use super_block::*;

+ 2 - 2
src/ext4_defs/mount_point.rs

@@ -6,7 +6,7 @@ pub struct Ext4MountPoint {
     /**@brief   Mount done flag.*/
     pub mounted: bool,
     /**@brief   Mount point name (@ref ext4_mount)*/
-    pub mount_name: CString,
+    pub mount_name: String,
     // pub mount_name_string: String,
 }
 
@@ -14,7 +14,7 @@ impl Ext4MountPoint {
     pub fn new(name: &str) -> Self {
         Self {
             mounted: false,
-            mount_name: CString::new(name).unwrap(),
+            mount_name: name.to_owned(),
             // mount_name_string: name.to_string(),
         }
     }

+ 41 - 63
src/ext4_defs/super_block.rs

@@ -1,7 +1,13 @@
-use crate::constants::*;
-use crate::prelude::*;
+//! # The Defination of Ext4 Super Block
+//!
+//! Super Block is the first field of Ext4 Block Group.
+//!
+//! See [`super::block_group`] for details.
+
 use super::BlockDevice;
 use super::Ext4Inode;
+use crate::constants::*;
+use crate::prelude::*;
 
 // 结构体表示超级块
 #[repr(C)]
@@ -115,33 +121,6 @@ impl TryFrom<Vec<u8>> for Ext4Superblock {
 }
 
 impl Ext4Superblock {
-    /// Returns the size of inode structure.
-    pub fn inode_size(&self) -> u16 {
-        self.inode_size
-    }
-
-    /// Returns the size of inode structure.
-    pub fn inode_size_file(&self, inode: &Ext4Inode) -> u64 {
-        let mode = inode.mode;
-
-        // 获取inode的低32位大小
-        let mut v = inode.size as u64;
-        // 如果文件系统的版本号大于0,并且inode的类型是文件
-        if self.rev_level > 0 && (mode & EXT4_INODE_MODE_TYPE_MASK) == EXT4_INODE_MODE_FILE as u16 {
-            // 获取inode的高32位大小,并左移32位
-            let hi = (inode.size_hi as u64) << 32;
-            // 用或运算符将低32位和高32位拼接为一个u64值
-            v |= hi;
-        }
-
-        // 返回inode的大小
-        v
-    }
-
-    pub fn uuid(&self) -> [u8; 16] {
-        self.uuid
-    }
-
     pub fn first_data_block(&self) -> u32 {
         self.first_data_block
     }
@@ -149,7 +128,7 @@ impl Ext4Superblock {
     pub fn free_inodes_count(&self) -> u32 {
         self.free_inodes_count
     }
-
+    
     pub fn features_read_only(&self) -> u32 {
         self.features_read_only
     }
@@ -158,7 +137,7 @@ impl Ext4Superblock {
     pub fn total_inodes(&self) -> u32 {
         self.inodes_count
     }
-
+    
     /// Returns the number of blocks in each block group.
     pub fn blocks_per_group(&self) -> u32 {
         self.blocks_per_group
@@ -168,21 +147,47 @@ impl Ext4Superblock {
     pub fn block_size(&self) -> u32 {
         1024 << self.log_block_size
     }
-
+    
     /// Returns the number of inodes in each block group.
     pub fn inodes_per_group(&self) -> u32 {
         self.inodes_per_group
     }
-
+    
     /// Returns the number of block groups.
     pub fn block_groups_count(&self) -> u32 {
         (((self.blocks_count_hi.to_le() as u64) << 32) as u32 | self.blocks_count_lo)
-            / self.blocks_per_group
+        / self.blocks_per_group
+    }
+    
+    /// Returns the size of inode structure.
+    pub fn inode_size(&self) -> u16 {
+        self.inode_size
+    }
+
+    /// Returns the size of inode structure.
+    pub fn inode_size_file(&self, inode: &Ext4Inode) -> u64 {
+        let mode = inode.mode;
+
+        // 获取inode的低32位大小
+        let mut v = inode.size as u64;
+        // 如果文件系统的版本号大于0,并且inode的类型是文件
+        if self.rev_level > 0 && (mode & EXT4_INODE_MODE_TYPE_MASK) == EXT4_INODE_MODE_FILE as u16 {
+            // 获取inode的高32位大小,并左移32位
+            let hi = (inode.size_hi as u64) << 32;
+            // 用或运算符将低32位和高32位拼接为一个u64值
+            v |= hi;
+        }
+
+        // 返回inode的大小
+        v
+    }
+
+    pub fn uuid(&self) -> [u8; 16] {
+        self.uuid
     }
 
     pub fn desc_size(&self) -> u16 {
         let size = self.desc_size;
-
         if size < EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE {
             return EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE as u16;
         } else {
@@ -218,38 +223,11 @@ impl Ext4Superblock {
         self.free_blocks_count_lo = ((free_blocks << 32) >> 32).to_le() as u32;
         self.free_blocks_count_hi = (free_blocks >> 32) as u32;
     }
-
+    
     pub fn sync_to_disk(&self, block_device: Arc<dyn BlockDevice>) {
         let data = unsafe {
             core::slice::from_raw_parts(self as *const _ as *const u8, size_of::<Ext4Superblock>())
         };
         block_device.write_offset(BASE_OFFSET, data);
     }
-
-    pub fn sync_to_disk_with_csum(&self, block_device: Arc<dyn BlockDevice>) {
-        let data = unsafe {
-            core::slice::from_raw_parts(self as *const _ as *const u8, size_of::<Ext4Superblock>())
-        };
-        block_device.write_offset(BASE_OFFSET, data);
-    }
-
-    pub fn sync_super_block_to_disk(&self, block_device: Arc<dyn BlockDevice>) {
-        let data = unsafe {
-            core::slice::from_raw_parts(self as *const _ as *const u8, size_of::<Ext4Superblock>())
-        };
-        block_device.write_offset(BASE_OFFSET, data);
-    }
 }
-
-#[allow(unused)]
-pub fn ext4_inodes_in_group_cnt(bgid: u32, s: &Ext4Superblock) -> u32 {
-    let block_group_count = s.block_groups_count();
-    let inodes_per_group = s.inodes_per_group;
-    let total_inodes = ((s.inodes_count as u64) << 32) as u32;
-
-    if bgid < block_group_count - 1 {
-        inodes_per_group
-    } else {
-        total_inodes - ((block_group_count - 1) * inodes_per_group)
-    }
-}

+ 10 - 2
src/lib.rs

@@ -11,11 +11,19 @@ mod ext4_defs;
 mod ext4_error;
 mod jbd2;
 mod prelude;
-mod utils;
 
 pub use ext4::*;
 pub use ext4_defs::*;
 pub use ext4_error::*;
-pub use utils::*;
 
 pub const BLOCK_SIZE: usize = 4096;
+
+#[cfg(test)]
+mod unit_test {
+    // use crate::Ext4;
+
+    #[test]
+    fn create_fs() {
+        // let ext4 = Ext4::new();
+    }
+}

+ 1 - 0
src/prelude.rs

@@ -15,6 +15,7 @@ pub(crate) use alloc::sync::Arc;
 pub(crate) use alloc::sync::Weak;
 pub(crate) use alloc::vec;
 pub(crate) use alloc::vec::Vec;
+pub(crate) use alloc::borrow::ToOwned;
 pub(crate) use bitflags::bitflags;
 pub(crate) use core::any::Any;
 pub(crate) use core::ffi::CStr;