|  | @@ -0,0 +1,1405 @@
 | 
	
		
			
				|  |  | +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);
 | 
	
		
			
				|  |  | +}
 |