Selaa lähdekoodia

feat: remove file

liujingx 11 kuukautta sitten
vanhempi
commit
d74ffe5a8e
8 muutettua tiedostoa jossa 336 lisäystä ja 143 poistoa
  1. 191 60
      src/ext4/alloc.rs
  2. 19 15
      src/ext4/dir.rs
  3. 65 33
      src/ext4/extent.rs
  4. 48 24
      src/ext4/file.rs
  5. 2 2
      src/ext4/mod.rs
  6. 9 8
      src/ext4_defs/file.rs
  7. 1 1
      src/ext4_defs/inode.rs
  8. 1 0
      src/prelude.rs

+ 191 - 60
src/ext4/alloc.rs

@@ -4,7 +4,95 @@ use crate::ext4_defs::*;
 use crate::prelude::*;
 
 impl Ext4 {
-    /// Allocate a new data block for an inode, return the physical block number
+    /// Create a new inode, returning the inode and its number
+    pub(super) fn create_inode(&mut self, filetype: FileType) -> Result<InodeRef> {
+        // Allocate an inode
+        let is_dir = filetype == FileType::Directory;
+        let id = self.alloc_inode(is_dir)?;
+
+        // Initialize the inode
+        let mut inode = Inode::default();
+        let mode = if filetype == FileType::Directory {
+            0o777 | EXT4_INODE_MODE_DIRECTORY
+        } else if filetype == FileType::SymLink {
+            0o777 | EXT4_INODE_MODE_SOFTLINK
+        } else {
+            0o666 | file_type2inode_mode(filetype)
+        };
+        inode.set_mode(mode);
+        inode.extent_init();
+        if self.super_block.inode_size() > EXT4_GOOD_OLD_INODE_SIZE {
+            inode.set_extra_isize(self.super_block.extra_size());
+        }
+        let mut inode_ref = InodeRef::new(id, inode);
+
+        // Sync the inode to disk
+        self.write_inode_with_csum(&mut inode_ref);
+
+        info!("Alloc inode {} ok", inode_ref.id);
+        Ok(inode_ref)
+    }
+
+    /// Create(initialize) the root inode of the file system
+    pub(super) fn create_root_inode(&mut self) -> Result<InodeRef> {
+        let mut inode = Inode::default();
+        inode.set_mode(0o777 | EXT4_INODE_MODE_DIRECTORY);
+        inode.extent_init();
+        if self.super_block.inode_size() > EXT4_GOOD_OLD_INODE_SIZE {
+            inode.set_extra_isize(self.super_block.extra_size());
+        }
+        let mut root = InodeRef::new(EXT4_ROOT_INO, inode);
+        let root_self = root.clone();
+
+        // Add `.` and `..` entries
+        self.dir_add_entry(&mut root, &root_self, ".")?;
+        self.dir_add_entry(&mut root, &root_self, "..")?;
+        root.inode.links_count += 2;
+
+        self.write_inode_with_csum(&mut root);
+        Ok(root)
+    }
+
+    /// Free an allocated inode and all data blocks allocated for it
+    pub(super) fn free_inode(&mut self, inode_id: InodeId) -> Result<()> {
+        let mut inode = self.read_inode(inode_id);
+        // Free the data blocks allocated for the inode
+        let pblocks = self.extent_get_all_pblocks(&inode)?;
+        for pblock in pblocks {
+            // Deallocate the block
+            self.dealloc_block(&mut inode, pblock)?;
+            // Clear the block content
+            Block::new(pblock, [0; BLOCK_SIZE]).sync_to_disk(self.block_device.clone());
+        }
+        // Deallocate the inode
+        self.dealloc_inode(&inode)?;
+        // Clear the inode content
+        inode.inode = unsafe { core::mem::zeroed() };
+        self.write_inode_without_csum(&mut inode);
+        Ok(())
+    }
+
+    /// Append a data block for an inode, return a pair of (logical block id, physical block id)
+    ///
+    /// Only data blocks allocated by `inode_append_block` will be counted in `inode.size`. Blocks
+    /// allocated by calling `alloc_block` directly will not be counted, e.g. blocks allocated
+    /// to save the inode's extent tree.
+    pub(super) fn inode_append_block(
+        &mut self,
+        inode_ref: &mut InodeRef,
+    ) -> Result<(LBlockId, PBlockId)> {
+        let inode_size = inode_ref.inode.size();
+        // The new logical block id
+        let iblock = ((inode_size + BLOCK_SIZE as u64 - 1) / BLOCK_SIZE as u64) as u32;
+        // Check the extent tree to get the physical block id
+        let fblock = self.extent_get_pblock_create(inode_ref, iblock, 1)?;
+        // Update the inode
+        inode_ref.inode.set_size(inode_size + BLOCK_SIZE as u64);
+        self.write_inode_with_csum(inode_ref);
+        Ok((iblock, fblock))
+    }
+
+    /// Allocate a new physical block for an inode, return the physical block number
     pub(super) fn alloc_block(&mut self, inode_ref: &mut InodeRef) -> Result<PBlockId> {
         // Calc block group id
         let inodes_per_group = self.super_block.inodes_per_group();
@@ -21,7 +109,8 @@ impl Ext4 {
         // Find the first free block
         let fblock = bitmap
             .find_and_set_first_clear_bit(0, 8 * BLOCK_SIZE)
-            .ok_or(Ext4Error::new(ErrCode::ENOSPC))? as PBlockId;
+            .ok_or(Ext4Error::with_message(ErrCode::ENOSPC, "No free block"))?
+            as PBlockId;
 
         // Set block group checksum
         bg.desc.set_block_bitmap_csum(&self.super_block, &bitmap);
@@ -47,73 +136,59 @@ impl Ext4 {
         Ok(fblock)
     }
 
-    /// Append a data block for an inode, return a pair of (logical block id, physical block id)
-    pub(super) fn inode_append_block(
+    /// Deallocate a physical block allocated for an inode
+    pub(super) fn dealloc_block(
         &mut self,
         inode_ref: &mut InodeRef,
-    ) -> Result<(LBlockId, PBlockId)> {
-        let inode_size = inode_ref.inode.size();
-        // The new logical block id
-        let iblock = ((inode_size + BLOCK_SIZE as u64 - 1) / BLOCK_SIZE as u64) as u32;
-        // Check the extent tree to get the physical block id
-        let fblock = self.extent_get_pblock_create(inode_ref, iblock, 1)?;
-        // Update the inode
-        inode_ref.inode.set_size(inode_size + BLOCK_SIZE as u64);
-        self.write_inode_with_csum(inode_ref);
-        Ok((iblock, fblock))
-    }
+        pblock: PBlockId,
+    ) -> Result<()> {
+        // Calc block group id
+        let inodes_per_group = self.super_block.inodes_per_group();
+        let bgid = ((inode_ref.id - 1) / inodes_per_group) as BlockGroupId;
 
-    /// Allocate(initialize) the root inode of the file system
-    pub(super) fn alloc_root_inode(&mut self) -> Result<InodeRef> {
-        let mut inode = Inode::default();
-        inode.set_mode(0o777 | EXT4_INODE_MODE_DIRECTORY);
-        inode.extent_init();
-        if self.super_block.inode_size() > EXT4_GOOD_OLD_INODE_SIZE {
-            inode.set_extra_isize(self.super_block.extra_size());
+        // Load block group descriptor
+        let mut bg = self.read_block_group(bgid);
+
+        // Load block bitmap
+        let bitmap_block_id = bg.desc.block_bitmap_block(&self.super_block);
+        let mut bitmap_block = self.block_device.read_block(bitmap_block_id);
+        let mut bitmap = Bitmap::new(&mut bitmap_block.data);
+
+        // Free the block
+        if bitmap.is_bit_clear(pblock as usize) {
+            return Err(Ext4Error::with_message(
+                ErrCode::EINVAL,
+                "Block double free",
+            ));
         }
-        let mut root = InodeRef::new(EXT4_ROOT_INO, inode);
-        let root_self = root.clone();
+        bitmap.clear_bit(pblock as usize);
 
-        // Add `.` and `..` entries
-        self.dir_add_entry(&mut root, &root_self, ".")?;
-        self.dir_add_entry(&mut root, &root_self, "..")?;
-        root.inode.links_count += 2;
+        // Set block group checksum
+        bg.desc.set_block_bitmap_csum(&self.super_block, &bitmap);
+        self.block_device.write_block(&bitmap_block);
 
-        self.write_inode_with_csum(&mut root);
-        Ok(root)
-    }
+        // Update superblock free blocks count
+        let free_blocks = self.super_block.free_blocks_count() + 1;
+        self.super_block.set_free_blocks_count(free_blocks);
+        self.super_block.sync_to_disk(self.block_device.clone());
 
-    /// Allocate a new inode in the file system, returning the inode and its number
-    pub(super) fn alloc_inode(&mut self, filetype: FileType) -> Result<InodeRef> {
-        // Allocate an inode
-        let is_dir = filetype == FileType::Directory;
-        let id = self.do_alloc_inode(is_dir)?;
+        // Update inode blocks (different block size!) count
+        let inode_blocks = inode_ref.inode.blocks_count() - (BLOCK_SIZE / INODE_BLOCK_SIZE) as u64;
+        inode_ref.inode.set_blocks_count(inode_blocks);
+        self.write_inode_with_csum(inode_ref);
 
-        // Initialize the inode
-        let mut inode = Inode::default();
-        let mode = if filetype == FileType::Directory {
-            0o777 | EXT4_INODE_MODE_DIRECTORY
-        } else if filetype == FileType::SymLink {
-            0o777 | EXT4_INODE_MODE_SOFTLINK
-        } else {
-            0o666 | file_type2inode_mode(filetype)
-        };
-        inode.set_mode(mode);
-        inode.extent_init();
-        if self.super_block.inode_size() > EXT4_GOOD_OLD_INODE_SIZE {
-            inode.set_extra_isize(self.super_block.extra_size());
-        }
-        let mut inode_ref = InodeRef::new(id, inode);
+        // Update block group free blocks count
+        let fb_cnt = bg.desc.get_free_blocks_count() + 1;
+        bg.desc.set_free_blocks_count(fb_cnt);
 
-        // Sync the inode to disk
-        self.write_inode_with_csum(&mut inode_ref);
+        self.write_block_group_with_csum(&mut bg);
 
-        info!("Alloc inode {} ok", inode_ref.id);
-        Ok(inode_ref)
+        info!("Free block {} ok", pblock);
+        Ok(())
     }
 
-    /// Allocate a new inode in the filesystem, returning its number.
-    fn do_alloc_inode(&mut self, is_dir: bool) -> Result<InodeId> {
+    /// Allocate a new inode, returning the inode number.
+    fn alloc_inode(&mut self, is_dir: bool) -> Result<InodeId> {
         let mut bgid = 0;
         let bg_count = self.super_block.block_groups_count();
 
@@ -133,7 +208,10 @@ impl Ext4 {
             let mut bitmap = Bitmap::new(&mut bitmap_block.data[..inode_count / 8]);
 
             // Find a free inode
-            let idx_in_bg = bitmap.find_and_set_first_clear_bit(0, inode_count).unwrap() as u32;
+            let idx_in_bg = bitmap
+                .find_and_set_first_clear_bit(0, inode_count)
+                .ok_or(Ext4Error::with_message(ErrCode::ENOSPC, "No free inode"))?
+                as u32;
 
             // Update bitmap in disk
             bg.desc.set_inode_bitmap_csum(&self.super_block, &bitmap);
@@ -144,9 +222,9 @@ impl Ext4 {
             bg.desc
                 .set_free_inodes_count(&self.super_block, free_inodes);
 
-            // Increment used directories counter
+            // Increase used directories counter
             if is_dir {
-                let used_dirs = bg.desc.used_dirs_count(&self.super_block) - 1;
+                let used_dirs = bg.desc.used_dirs_count(&self.super_block) + 1;
                 bg.desc.set_used_dirs_count(&self.super_block, used_dirs);
             }
 
@@ -173,4 +251,57 @@ impl Ext4 {
         log::info!("no free inode");
         Err(Ext4Error::new(ErrCode::ENOSPC))
     }
+
+    /// Free an inode
+    fn dealloc_inode(&mut self, inode_ref: &InodeRef) -> Result<()> {
+        // Calc block group id and index in block group
+        let inodes_per_group = self.super_block.inodes_per_group();
+        let bgid = ((inode_ref.id - 1) / inodes_per_group) as BlockGroupId;
+        let idx_in_bg = (inode_ref.id - 1) % inodes_per_group;
+
+        // Load block group descriptor
+        let mut bg = self.read_block_group(bgid);
+
+        // Load inode bitmap
+        let bitmap_block_id = bg.desc.inode_bitmap_block(&self.super_block);
+        let mut bitmap_block = self.block_device.read_block(bitmap_block_id);
+        let inode_count = self.super_block.inode_count_in_group(bgid) as usize;
+        let mut bitmap = Bitmap::new(&mut bitmap_block.data[..inode_count / 8]);
+
+        // Free the inode
+        if bitmap.is_bit_clear(idx_in_bg as usize) {
+            return Err(Ext4Error::with_message(
+                ErrCode::EINVAL,
+                "Inode double free",
+            ));
+        }
+        bitmap.clear_bit(idx_in_bg as usize);
+
+        // Update bitmap in disk
+        bg.desc.set_inode_bitmap_csum(&self.super_block, &bitmap);
+        self.block_device.write_block(&bitmap_block);
+
+        // Modify filesystem counters
+        let free_inodes = bg.desc.free_inodes_count() + 1;
+        bg.desc
+            .set_free_inodes_count(&self.super_block, free_inodes);
+
+        // Increase used directories counter
+        if inode_ref.inode.is_dir(&self.super_block) {
+            let used_dirs = bg.desc.used_dirs_count(&self.super_block) - 1;
+            bg.desc.set_used_dirs_count(&self.super_block, used_dirs);
+        }
+
+        // Decrease unused inodes count
+        let unused = bg.desc.itable_unused(&self.super_block) + 1;
+        bg.desc.set_itable_unused(&self.super_block, unused);
+
+        self.write_block_group_with_csum(&mut bg);
+
+        // Update superblock
+        self.super_block.decrease_free_inodes_count();
+        self.super_block.sync_to_disk(self.block_device.clone());
+
+        Ok(())
+    }
 }

+ 19 - 15
src/ext4/dir.rs

@@ -31,11 +31,11 @@ impl Ext4 {
         &mut self,
         parent: &mut InodeRef,
         child: &InodeRef,
-        path: &str,
+        name: &str,
     ) -> Result<()> {
         info!(
             "Dir add entry: parent {}, child {}, path {}",
-            parent.id, child.id, path
+            parent.id, child.id, name
         );
         let inode_size = parent.inode.size();
         let total_blocks = inode_size as u32 / BLOCK_SIZE as u32;
@@ -48,7 +48,7 @@ impl Ext4 {
             // Load the parent block from disk
             let mut block = self.block_device.read_block(fblock);
             // Try inserting the entry to parent block
-            if self.insert_entry_to_old_block(&mut block, child, path) {
+            if self.insert_entry_to_old_block(&mut block, child, name) {
                 return Ok(());
             }
             // Current block has no enough space
@@ -61,14 +61,19 @@ impl Ext4 {
         // Load new block
         let mut new_block = self.block_device.read_block(fblock);
         // Write the entry to block
-        self.insert_entry_to_new_block(&mut new_block, child, path);
+        self.insert_entry_to_new_block(&mut new_block, child, name);
 
         Ok(())
     }
 
-    /// Remove a entry from a directory
-    pub(super) fn dir_remove_entry(&mut self, parent: &mut InodeRef, path: &str) -> Result<()> {
-        info!("Dir remove entry: parent {}, path {}", parent.id, path);
+    /// Remove a entry from a directory, return the inode id that
+    /// the removed entry points to.
+    pub(super) fn dir_remove_entry(
+        &mut self,
+        parent: &mut InodeRef,
+        name: &str,
+    ) -> Result<InodeId> {
+        info!("Dir remove entry: parent {}, path {}", parent.id, name);
         let inode_size = parent.inode.size();
         let total_blocks = inode_size as u32 / BLOCK_SIZE as u32;
 
@@ -80,8 +85,8 @@ impl Ext4 {
             // Load the block from disk
             let mut block = self.block_device.read_block(fblock);
             // Try removing the entry
-            if self.remove_entry_from_block(&mut block, path) {
-                return Ok(());
+            if let Ok(inode) = self.remove_entry_from_block(&mut block, name) {
+                return Ok(inode);
             }
             // Current block has no enough space
             iblock += 1;
@@ -107,7 +112,7 @@ impl Ext4 {
     }
 
     /// Remove a directory entry that matches a given name from a given block
-    fn remove_entry_from_block(&self, block: &mut Block, name: &str) -> bool {
+    fn remove_entry_from_block(&self, block: &mut Block, name: &str) -> Result<InodeId> {
         info!("Dir remove entry {} from block {}", name, block.block_id);
         let mut offset = 0;
         while offset < BLOCK_SIZE {
@@ -116,10 +121,10 @@ impl Ext4 {
             if !de.unused() && de.compare_name(name) {
                 // Mark the target entry as unused
                 de.set_unused();
-                return true;
+                return Ok(de.inode());
             }
         }
-        false
+        Err(Ext4Error::new(ErrCode::ENOENT))
     }
 
     /// Insert a directory entry of a child inode into a new parent block.
@@ -200,9 +205,8 @@ impl Ext4 {
 
     /// Create a new directory. `path` is the absolute path of the new directory.
     pub fn mkdir(&mut self, path: &str) -> Result<()> {
-        // get open flags
-        let iflags = OpenFlags::from_str("w").unwrap();
-        self.generic_open(path, iflags, FileType::Directory, &self.read_root_inode())
+        let open_flags = OpenFlags::from_str("w").unwrap();
+        self.generic_open(EXT4_ROOT_INO, path, FileType::Directory, open_flags)
             .map(|_| {
                 info!("ext4_dir_mk: {} ok", path);
             })

+ 65 - 33
src/ext4/extent.rs

@@ -22,38 +22,6 @@ impl ExtentSearchStep {
 }
 
 impl Ext4 {
-    /// Find the given logic block id in the extent tree, return the search path
-    fn find_extent(&self, inode_ref: &InodeRef, iblock: LBlockId) -> Vec<ExtentSearchStep> {
-        let mut path: Vec<ExtentSearchStep> = Vec::new();
-        let mut ex_node = inode_ref.inode.extent_node();
-        let mut pblock = 0;
-        let mut block_data: Block;
-
-        // Go until leaf
-        while ex_node.header().depth() > 0 {
-            let index = ex_node.search_extent_index(iblock);
-            if index.is_err() {
-                // TODO: no extent index
-                panic!("Unhandled error");
-            }
-            path.push(ExtentSearchStep::new(pblock, index));
-            // Get the target extent index
-            let ex_idx = ex_node.extent_index_at(index.unwrap());
-            // Load the next extent node
-            let next = ex_idx.leaf();
-            // Note: block data cannot be released until the next assigment
-            block_data = self.block_device.read_block(next);
-            // Load the next extent header
-            ex_node = ExtentNode::from_bytes(&block_data.data);
-            pblock = next;
-        }
-        // Leaf
-        let index = ex_node.search_extent(iblock);
-        path.push(ExtentSearchStep::new(pblock, index));
-
-        path
-    }
-
     /// Given a logic block id, find the corresponding fs block id.
     /// Return 0 if not found.
     pub(super) fn extent_get_pblock(
@@ -123,6 +91,70 @@ impl Ext4 {
         }
     }
 
+    /// Get all the physical blocks that the extent tree covers, including
+    /// the blocks allocated to save the extent tree itself.
+    pub(super) fn extent_get_all_pblocks(&self, inode_ref: &InodeRef) -> Result<Vec<PBlockId>> {
+        let mut pblocks = Vec::new();
+        let ex_node = inode_ref.inode.extent_node();
+        self.get_all_pblocks_recursive(&ex_node, &mut pblocks);
+        Ok(pblocks)
+    }
+
+    /// Get all the physical blocks that an extent node covers recursively,
+    /// including the blocks allocated to save the extent tree itself.
+    fn get_all_pblocks_recursive(&self, ex_node: &ExtentNode, pblocks: &mut Vec<PBlockId>) {
+        if ex_node.header().depth() == 0 {
+            // Leaf
+            for i in 0..ex_node.header().entries_count() as usize {
+                let ex = ex_node.extent_at(i);
+                for j in 0..ex.block_count() {
+                    pblocks.push(ex.start_pblock() + j as PBlockId);
+                }
+            }
+        } else {
+            // Non-leaf
+            for i in 0..ex_node.header().entries_count() as usize {
+                let ex_idx = ex_node.extent_index_at(i);
+                pblocks.push(ex_idx.leaf());
+                let child_block = self.block_device.read_block(ex_idx.leaf());
+                let child_node = ExtentNode::from_bytes(&child_block.data);
+                self.get_all_pblocks_recursive(&child_node, pblocks);
+            }
+        }
+    }
+
+    /// Find the given logic block id in the extent tree, return the search path
+    fn find_extent(&self, inode_ref: &InodeRef, iblock: LBlockId) -> Vec<ExtentSearchStep> {
+        let mut path: Vec<ExtentSearchStep> = Vec::new();
+        let mut ex_node = inode_ref.inode.extent_node();
+        let mut pblock = 0;
+        let mut block_data: Block;
+
+        // Go until leaf
+        while ex_node.header().depth() > 0 {
+            let index = ex_node.search_extent_index(iblock);
+            if index.is_err() {
+                // TODO: no extent index
+                panic!("Unhandled error");
+            }
+            path.push(ExtentSearchStep::new(pblock, index));
+            // Get the target extent index
+            let ex_idx = ex_node.extent_index_at(index.unwrap());
+            // Load the next extent node
+            let next = ex_idx.leaf();
+            // Note: block data cannot be released until the next assigment
+            block_data = self.block_device.read_block(next);
+            // Load the next extent header
+            ex_node = ExtentNode::from_bytes(&block_data.data);
+            pblock = next;
+        }
+        // Leaf
+        let index = ex_node.search_extent(iblock);
+        path.push(ExtentSearchStep::new(pblock, index));
+
+        path
+    }
+
     /// Insert a new extent into the extent tree.
     fn insert_extent(
         &mut self,
@@ -189,7 +221,7 @@ impl Ext4 {
         let right_bid = self.alloc_block(inode_ref).unwrap();
         let mut right_block = self.block_device.read_block(right_bid);
         let mut right_node = ExtentNodeMut::from_bytes(&mut right_block.data);
-        
+
         // Insert the split half to right node
         right_node.init(0, 0);
         for (i, fake_extent) in split.iter().enumerate() {

+ 48 - 24
src/ext4/file.rs

@@ -11,37 +11,47 @@ impl Ext4 {
         path.split("/").map(|s| s.to_string()).collect()
     }
 
+    /// Open an object of any type in the filesystem. Return the inode
+    /// id of the object if found.
+    ///
+    /// ## Params
+    /// * `root` - The inode id of the starting directory for the search.
+    /// * `path` - The path of the object to open.
+    /// * `ftype` - The expect type of object to open.
+    /// * `flags` - The open flags. If the flags contains `O_CREAT`, the file
+    ///             will be created if it does not exist.
     pub(super) fn generic_open(
         &mut self,
+        root: InodeId,
         path: &str,
-        flag: OpenFlags,
         ftype: FileType,
-        root: &InodeRef,
-    ) -> Result<File> {
+        flags: OpenFlags,
+    ) -> Result<InodeId> {
         info!("generic open: {}", path);
         // Search from the given parent inode
-        let mut parent = root.clone();
+        let mut parent_id = root;
         let search_path = Self::split_path(path);
 
         for (i, path) in search_path.iter().enumerate() {
+            let mut parent = self.read_inode(parent_id);
             let res = self.dir_find_entry(&parent, path);
             match res {
                 Ok(entry) => {
-                    parent = self.read_inode(entry.inode());
+                    parent_id = entry.inode();
                 }
                 Err(e) => {
                     if e.code() != ErrCode::ENOENT {
                         // dir search failed with error other than ENOENT
                         return_errno_with_message!(ErrCode::ENOTSUP, "dir search failed");
                     }
-                    if !flag.contains(OpenFlags::O_CREAT) {
+                    if !flags.contains(OpenFlags::O_CREAT) {
                         return_errno_with_message!(ErrCode::ENOENT, "file not found");
                     }
                     // Create file/directory
                     let mut child = if i == search_path.len() - 1 {
-                        self.alloc_inode(ftype)
+                        self.create_inode(ftype)
                     } else {
-                        self.alloc_inode(FileType::Directory)
+                        self.create_inode(FileType::Directory)
                     }?;
                     // Link the new inode
                     self.link(&mut parent, &mut child, path)
@@ -50,19 +60,17 @@ impl Ext4 {
                     self.write_inode_with_csum(&mut parent);
                     self.write_inode_with_csum(&mut child);
                     // Update parent
-                    parent = child;
+                    parent_id = child.id;
                 }
             }
         }
         // `parent` is the target inode
-        let mut file = File::default();
-        file.inode = parent.id;
-        Ok(file)
+        Ok(parent_id)
     }
 
     pub fn open(&mut self, path: &str, flags: &str, file_expect: bool) -> Result<File> {
         // open flags
-        let iflags = OpenFlags::from_str(flags).unwrap();
+        let open_flags = OpenFlags::from_str(flags).unwrap();
         // file type
         let file_type = if file_expect {
             FileType::RegularFile
@@ -70,16 +78,19 @@ impl Ext4 {
             FileType::Directory
         };
         // TODO:journal
-        if iflags.contains(OpenFlags::O_CREAT) {
+        if open_flags.contains(OpenFlags::O_CREAT) {
             self.trans_start();
         }
         // open file
-        let res = self.generic_open(path, iflags, file_type, &self.read_root_inode());
-        res.map(|mut file| {
-            // set mount point
-            let mut ptr = Box::new(self.mount_point.clone());
-            file.mp = Box::as_mut(&mut ptr) as *mut MountPoint;
-            file
+        let res = self.generic_open(EXT4_ROOT_INO, path, file_type, open_flags);
+        res.map(|inode_id| {
+            let inode = self.read_inode(inode_id);
+            File::new(
+                self.mount_point.clone(),
+                inode.id,
+                open_flags.bits(),
+                inode.inode.size(),
+            )
         })
     }
 
@@ -169,9 +180,22 @@ impl Ext4 {
         Ok(())
     }
 
-    pub fn remove_file(&self, path: &str) -> Result<()> {
-        
-        
-        Ok(())
+    pub fn remove_file(&mut self, path: &str) -> Result<()> {
+        // Get the parent directory path and the file name
+        let mut search_path = Self::split_path(path);
+        let file_name = &search_path.split_off(search_path.len() - 1)[0];
+        let parent_path = search_path.join("/");
+        // Get the parent directory inode
+        let parent_id = self.generic_open(
+            EXT4_ROOT_INO,
+            &parent_path,
+            FileType::Directory,
+            OpenFlags::O_RDONLY,
+        )?;
+        let mut parent_inode = self.read_inode(parent_id);
+        // Remove the file from the parent directory
+        let child_inode_id = self.dir_remove_entry(&mut parent_inode, &file_name)?;
+        // Free the inode of the file
+        self.free_inode(child_inode_id)
     }
 }

+ 2 - 2
src/ext4/mod.rs

@@ -35,7 +35,7 @@ impl Ext4 {
             mount_point,
         };
         // Create root directory
-        ext4.alloc_root_inode()?;
+        ext4.create_root_inode()?;
         Ok(ext4)
     }
 
@@ -61,7 +61,7 @@ impl Ext4 {
     }
 
     /// Read a block group descriptor from block device, return an `BlockGroupRef`
-    /// that combines the inode and its id.
+    /// that combines the block group descriptor and its id.
     fn read_block_group(&self, block_group_id: BlockGroupId) -> BlockGroupRef {
         BlockGroupRef::load_from_disk(self.block_device.clone(), &self.super_block, block_group_id)
     }

+ 9 - 8
src/ext4_defs/file.rs

@@ -4,7 +4,7 @@ use crate::prelude::*;
 /// 文件描述符
 pub struct File {
     /// 挂载点句柄
-    pub mp: *mut MountPoint,
+    pub mp: MountPoint,
     /// 文件 inode id
     pub inode: InodeId,
     /// 打开标志
@@ -15,19 +15,20 @@ pub struct File {
     pub fpos: usize,
 }
 
-impl Default for File {
-    fn default() -> Self {
-        Self {
-            mp: ptr::null_mut(),
-            inode: 0,
-            flags: 0,
-            fsize: 0,
+impl File {
+    pub fn new(mp: MountPoint, inode: InodeId, flags: u32, fsize: u64) -> Self {
+        File {
+            mp,
+            inode,
+            flags,
+            fsize,
             fpos: 0,
         }
     }
 }
 
 bitflags! {
+    #[derive(Debug, Clone, Copy)]
     pub struct OpenFlags: u32 {
         const O_ACCMODE = 0o0003;
         const O_RDONLY = 0o00;

+ 1 - 1
src/ext4_defs/inode.rs

@@ -123,7 +123,7 @@ impl Inode {
         self.gid = gid;
     }
 
-    pub fn size(&mut self) -> u64 {
+    pub fn size(&self) -> u64 {
         self.size as u64 | ((self.size_hi as u64) << 32)
     }
 

+ 1 - 0
src/prelude.rs

@@ -16,6 +16,7 @@ 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 alloc::format;
 pub(crate) use bitflags::bitflags;
 pub(crate) use core::any::Any;
 pub(crate) use core::ffi::CStr;