liujingx пре 10 месеци
родитељ
комит
5a37d97273
3 измењених фајлова са 29 додато и 13 уклоњено
  1. 2 1
      src/ext4/alloc.rs
  2. 2 2
      src/ext4/dir.rs
  3. 25 10
      src/ext4/link.rs

+ 2 - 1
src/ext4/alloc.rs

@@ -30,7 +30,7 @@ impl Ext4 {
         let mut inode = Inode::default();
         inode.set_mode(InodeMode::from_type_and_perm(
             FileType::Directory,
-            InodeMode::ALL_RWX,
+            InodeMode::from_bits_retain(0o755),
         ));
         inode.extent_init();
 
@@ -40,6 +40,7 @@ impl Ext4 {
         // Add `.` and `..` entries
         self.dir_add_entry(&mut root, &root_self, ".")?;
         self.dir_add_entry(&mut root, &root_self, "..")?;
+        root.inode.set_link_count(2);
 
         self.write_inode_with_csum(&mut root);
         Ok(root)

+ 2 - 2
src/ext4/dir.rs

@@ -24,7 +24,7 @@ impl Ext4 {
         Err(Ext4Error::new(ErrCode::ENOENT))
     }
 
-    /// Add an entry to a directory
+    /// Add an entry to a directory, memory consistency guaranteed
     pub(super) fn dir_add_entry(
         &self,
         dir: &mut InodeRef,
@@ -66,7 +66,7 @@ impl Ext4 {
     }
 
     /// Remove a entry from a directory
-    pub(super) fn dir_remove_entry(&self, dir: &mut InodeRef, name: &str) -> Result<()> {
+    pub(super) fn dir_remove_entry(&self, dir: &InodeRef, name: &str) -> Result<()> {
         info!("Dir remove entry: dir {}, path {}", dir.id, name);
         let total_blocks: u32 = dir.inode.block_count() as u32;
 

+ 25 - 10
src/ext4/link.rs

@@ -12,14 +12,21 @@ impl Ext4 {
     ) -> Result<()> {
         // Add entry to parent directory
         self.dir_add_entry(parent, child, name)?;
-        // Update link count of child
-        let link_cnt = child.inode.link_count() + 1;
-        child.inode.set_link_count(link_cnt);
-        // Add '.' and '..' entries if child is a newly created directory
-        if link_cnt == 1 && child.inode.is_dir() {
+
+        let child_link_count = child.inode.link_count();
+        if child.inode.is_dir() && child_link_count == 0 {
+            // Add '.' and '..' entries if child is a newly created directory
             let child_self = child.clone();
             self.dir_add_entry(child, &child_self, ".")?;
             self.dir_add_entry(child, parent, "..")?;
+            // Link child/".."
+            parent.inode.set_link_count(parent.inode.link_count() + 1);
+            self.write_inode_with_csum(parent);
+            // Link parent/child + child/"."
+            child.inode.set_link_count(child_link_count + 2);
+        } else {
+            // Link parent/child
+            child.inode.set_link_count(child_link_count + 1);
         }
         self.write_inode_with_csum(child);
         Ok(())
@@ -35,13 +42,21 @@ impl Ext4 {
     ) -> Result<()> {
         // Remove entry from parent directory
         self.dir_remove_entry(parent, name)?;
-        // Update link count of child
-        let link_cnt = child.inode.link_count() - 1;
-        if link_cnt == 0 {
-            // Free the inode if link count is 0
+
+        let child_link_cnt = child.inode.link_count();
+        if child.inode.is_dir() && child_link_cnt == 2 {
+            // If child is an empty directory
+            // Unlink "child/.."
+            parent.inode.set_link_count(parent.inode.link_count() - 1);
+            self.write_inode_with_csum(parent);
+            // Remove directory
+            return self.free_inode(child);
+        } else if child_link_cnt == 1 {
+            // Remove file
             return self.free_inode(child);
         }
-        child.inode.set_link_count(link_cnt);
+        // Not remove
+        child.inode.set_link_count(child_link_cnt - 1);
         self.write_inode_with_csum(child);
         Ok(())
     }