Ver Fonte

feat: rename

liujingx há 11 meses atrás
pai
commit
1623d0ca97
4 ficheiros alterados com 107 adições e 28 exclusões
  1. 13 13
      src/ext4/dir.rs
  2. 1 2
      src/ext4/extent.rs
  3. 1 1
      src/ext4/high_level.rs
  4. 92 12
      src/ext4/low_level.rs

+ 13 - 13
src/ext4/dir.rs

@@ -18,7 +18,7 @@ impl Ext4 {
             let block = self.read_block(fblock);
             // Find the entry in block
             let res = Self::find_entry_in_block(&block, name);
-            if let Ok(r) = res {
+            if let Some(r) = res {
                 return Ok(r);
             }
             iblock += 1;
@@ -44,7 +44,7 @@ impl Ext4 {
         let mut iblock: LBlockId = 0;
         while iblock < total_blocks {
             // Get the parent physical block id
-            let fblock = self.extent_get_pblock(dir, iblock)?;
+            let fblock = self.extent_get_pblock(dir, iblock).unwrap();
             // Load the parent block from disk
             let mut block = self.read_block(fblock);
             // Try inserting the entry to parent block
@@ -76,11 +76,11 @@ impl Ext4 {
         let mut iblock: LBlockId = 0;
         while iblock < total_blocks {
             // Get the parent physical block id
-            let fblock = self.extent_get_pblock(dir, iblock)?;
+            let fblock = self.extent_get_pblock(dir, iblock).unwrap();
             // Load the block from disk
             let mut block = self.read_block(fblock);
             // Try removing the entry
-            if let Ok(()) = Self::remove_entry_from_block(&mut block, name) {
+            if Self::remove_entry_from_block(&mut block, name) {
                 self.write_block(&block);
                 return Ok(());
             }
@@ -93,7 +93,7 @@ impl Ext4 {
     }
 
     /// Get all entries under a directory
-    pub(super) fn dir_get_all_entries(&self, dir: &InodeRef) -> Result<Vec<DirEntry>> {
+    pub(super) fn dir_get_all_entries(&self, dir: &InodeRef) -> Vec<DirEntry> {
         info!("Dir get all entries: dir {}", dir.id);
         let inode_size: u32 = dir.inode.size;
         let total_blocks: u32 = inode_size / BLOCK_SIZE as u32;
@@ -102,32 +102,32 @@ impl Ext4 {
         let mut iblock: LBlockId = 0;
         while iblock < total_blocks {
             // Get the fs block id
-            let fblock = self.extent_get_pblock(dir, iblock)?;
+            let fblock = self.extent_get_pblock(dir, iblock).unwrap();
             // Load block from disk
             let block = self.read_block(fblock);
             // Get all entries from block
             Self::get_all_entries_from_block(&block, &mut entries);
             iblock += 1;
         }
-        Ok(entries)
+        entries
     }
 
     /// Find a directory entry that matches a given name in a given block
-    fn find_entry_in_block(block: &Block, name: &str) -> Result<DirEntry> {
+    fn find_entry_in_block(block: &Block, name: &str) -> Option<DirEntry> {
         info!("Dir find entry {} in block {}", name, block.block_id);
         let mut offset = 0;
         while offset < BLOCK_SIZE {
             let de: DirEntry = block.read_offset_as(offset);
             if !de.unused() && de.compare_name(name) {
-                return Ok(de);
+                return Some(de);
             }
             offset += de.rec_len() as usize;
         }
-        Err(Ext4Error::new(ErrCode::ENOENT))
+        None
     }
 
     /// Remove a directory entry that matches a given name from a given block
-    fn remove_entry_from_block(block: &mut Block, name: &str) -> Result<()> {
+    fn remove_entry_from_block(block: &mut Block, name: &str) -> bool {
         info!("Dir remove entry {} from block {}", name, block.block_id);
         let mut offset = 0;
         while offset < BLOCK_SIZE {
@@ -136,11 +136,11 @@ impl Ext4 {
                 // Mark the target entry as unused
                 de.set_unused();
                 block.write_offset_as(offset, &de);
-                return Ok(());
+                return true;
             }
             offset += de.rec_len() as usize;
         }
-        Err(Ext4Error::new(ErrCode::ENOENT))
+        false
     }
 
     /// Get all directory entries from a given block

+ 1 - 2
src/ext4/extent.rs

@@ -23,7 +23,6 @@ impl ExtentSearchStep {
 
 impl Ext4 {
     /// Given a logic block id, find the corresponding fs block id.
-    /// Return 0 if not found.
     pub(super) fn extent_get_pblock(
         &self,
         inode_ref: &InodeRef,
@@ -47,7 +46,7 @@ impl Ext4 {
             let ex = ex_node.extent_at(index);
             Ok(ex.start_pblock() + (iblock - ex.start_lblock()) as PBlockId)
         } else {
-            Err(Ext4Error::new(ErrCode::ENOENT))
+            Err(Ext4Error::with_msg_str(ErrCode::ENOENT, "Extent not found"))
         }
     }
 

+ 1 - 1
src/ext4/high_level.rs

@@ -138,7 +138,7 @@ impl Ext4 {
         let mut child = self.read_inode(child_id);
         if child.inode.is_dir() {
             // Check if the directory is empty
-            if self.dir_get_all_entries(&child)?.len() > 2 {
+            if self.dir_get_all_entries(&child).len() > 2 {
                 return_err_with_msg_str!(ErrCode::ENOTEMPTY, "Directory not empty");
             }
         }

+ 92 - 12
src/ext4/low_level.rs

@@ -37,6 +37,11 @@ impl Ext4 {
     /// # Return
     ///
     /// `Ok(inode)` - Inode id of the new file
+    ///
+    /// # Error
+    ///
+    /// * `ENOTDIR` - `parent` is not a directory
+    /// * `ENOSPC` - No space left on device
     pub fn create(&mut self, parent: InodeId, name: &str, mode: InodeMode) -> Result<InodeId> {
         let mut parent = self.read_inode(parent);
         // Can only create a file in a directory
@@ -45,8 +50,7 @@ impl Ext4 {
         }
         // Create child inode and link it to parent directory
         let mut child = self.create_inode(mode)?;
-        self.link_inode(&mut parent, &mut child, name)
-            .map_err(|_| Ext4Error::with_msg_str(ErrCode::ELINKFAIL, "link fail"))?;
+        self.link_inode(&mut parent, &mut child, name)?;
         // Create file handler
         Ok(child.id)
     }
@@ -64,6 +68,10 @@ impl Ext4 {
     ///
     /// `Ok(usize)` - the actual number of bytes read
     ///
+    /// # Error
+    ///
+    /// * `EISDIR` - `file` is not a regular file
+    ///
     /// TODO: handle EOF
     pub fn read(&mut self, file: InodeId, offset: usize, buf: &mut [u8]) -> Result<usize> {
         // Get the inode of the file
@@ -91,7 +99,9 @@ impl Ext4 {
         // Read first block
         if misaligned > 0 {
             let read_len = min(BLOCK_SIZE - misaligned, size_to_read);
-            let fblock = self.extent_get_pblock(&mut inode_ref, start_iblock)?;
+            let fblock = self
+                .extent_get_pblock(&mut inode_ref, start_iblock)
+                .unwrap();
             let block = self.read_block(fblock);
             // Copy data from block to the user buffer
             buf[cursor..cursor + read_len].copy_from_slice(block.read_offset(misaligned, read_len));
@@ -101,7 +111,7 @@ impl Ext4 {
         // Continue with full block reads
         while cursor < size_to_read {
             let read_len = min(BLOCK_SIZE, size_to_read - cursor);
-            let fblock = self.extent_get_pblock(&mut inode_ref, iblock)?;
+            let fblock = self.extent_get_pblock(&mut inode_ref, iblock).unwrap();
             let block = self.read_block(fblock);
             // Copy data from block to the user buffer
             buf[cursor..cursor + read_len].copy_from_slice(block.read_offset(0, read_len));
@@ -124,6 +134,11 @@ impl Ext4 {
     ///
     /// `Ok(usize)` - the actual number of bytes written
     ///
+    /// # Error
+    ///
+    /// * `EISDIR` - `file` is not a regular file
+    /// `ENOSPC` - no space left on device
+    ///
     /// TODO: handle EOF
     pub fn write(&mut self, file: InodeId, offset: usize, data: &[u8]) -> Result<usize> {
         // Get the inode of the file
@@ -175,6 +190,11 @@ impl Ext4 {
     /// # Return
     ///
     /// `Ok(child)` - An inode reference to the child inode.
+    ///
+    /// # Error
+    ///
+    /// * `ENOTDIR` - `parent` is not a directory
+    /// * `ENOSPC` - no space left on device
     pub fn link(&mut self, child: InodeId, parent: InodeId, name: &str) -> Result<InodeRef> {
         let mut parent = self.read_inode(parent);
         // Can only link to a directory
@@ -186,13 +206,17 @@ impl Ext4 {
         Ok(child)
     }
 
-    /// Unlink a file. This function will not check the existence of the file.
-    /// Call `lookup` to check beforehand.
+    /// Unlink a file.
     ///
     /// # Params
     ///
     /// * `parent` - the inode of the directory to unlink from
     /// * `name` - the name of the file to unlink
+    ///
+    /// # Error
+    ///
+    /// * `ENOTDIR` - `parent` is not a directory
+    /// * `ENOENT` - `name` does not exist in `parent`
     pub fn unlink(&mut self, parent: InodeId, name: &str) -> Result<()> {
         let mut parent = self.read_inode(parent);
         // Can only unlink from a directory
@@ -204,6 +228,44 @@ impl Ext4 {
         self.unlink_inode(&mut parent, &mut child, name)
     }
 
+    /// Move a file. This function will not check name conflict.
+    /// Call `lookup` to check beforehand.
+    ///
+    /// # Params
+    ///
+    /// * `parent` - the inode of the directory to move from
+    /// * `name` - the name of the file to move
+    /// * `new_parent` - the inode of the directory to move to
+    /// * `new_name` - the new name of the file
+    ///
+    /// # Error
+    ///
+    /// * `ENOTDIR` - `parent` or `new_parent` is not a directory
+    /// * `ENOENT` - `name` does not exist in `parent`
+    /// * `ENOSPC` - no space left on device
+    pub fn rename(
+        &mut self,
+        parent: InodeId,
+        name: &str,
+        new_parent: InodeId,
+        new_name: &str,
+    ) -> Result<()> {
+        let mut parent = self.read_inode(parent);
+        if !parent.inode.is_dir() {
+            return_err_with_msg_str!(ErrCode::ENOTDIR, "Not a directory");
+        }
+        let mut new_parent = self.read_inode(new_parent);
+        if !new_parent.inode.is_dir() {
+            return_err_with_msg_str!(ErrCode::ENOTDIR, "Not a directory");
+        }
+
+        let child_id = self.dir_find_entry(&parent, name)?;
+        let mut child = self.read_inode(child_id.inode());
+
+        self.link_inode(&mut new_parent, &mut child, new_name)?;
+        self.unlink_inode(&mut parent, &mut child, name)
+    }
+
     /// Create a directory. This function will not check name conflict.
     /// Call `lookup` to check beforehand.
     ///
@@ -216,6 +278,11 @@ impl Ext4 {
     /// # Return
     ///
     /// `Ok(child)` - An inode reference to the new directory.
+    ///
+    /// # Error
+    ///
+    /// * `ENOTDIR` - `parent` is not a directory
+    /// * `ENOSPC` - no space left on device
     pub fn mkdir(&mut self, parent: InodeId, name: &str, mode: InodeMode) -> Result<InodeRef> {
         let mut parent = self.read_inode(parent);
         // Can only create a directory in a directory
@@ -226,8 +293,7 @@ impl Ext4 {
         let mode = mode & InodeMode::PERM_MASK | InodeMode::DIRECTORY;
         let mut child = self.create_inode(mode)?;
         // Link the new inode
-        self.link_inode(&mut parent, &mut child, name)
-            .map_err(|_| Ext4Error::with_msg_str(ErrCode::ELINKFAIL, "link fail"))?;
+        self.link_inode(&mut parent, &mut child, name)?;
 
         Ok(child)
     }
@@ -242,6 +308,11 @@ impl Ext4 {
     /// # Return
     ///
     /// `Ok(child)`: The inode id to which the directory entry points.
+    ///
+    /// # Error
+    ///
+    /// * `ENOTDIR` - `parent` is not a directory
+    /// * `ENOENT` - `name` does not exist in `parent`
     pub fn lookup(&mut self, parent: InodeId, name: &str) -> Result<InodeId> {
         let parent = self.read_inode(parent);
         // Can only lookup in a directory
@@ -261,22 +332,31 @@ impl Ext4 {
     /// # Return
     ///
     /// `Ok(entries)` - A vector of directory entries in the directory.
+    ///
+    /// # Error
+    ///
+    /// `ENOTDIR` - `inode` is not a directory
     pub fn list(&self, inode: InodeId) -> Result<Vec<DirEntry>> {
         let inode_ref = self.read_inode(inode);
         // Can only list a directory
         if inode_ref.inode.file_type() != FileType::Directory {
             return_err_with_msg_str!(ErrCode::ENOTDIR, "Not a directory");
         }
-        self.dir_get_all_entries(&inode_ref)
+        Ok(self.dir_get_all_entries(&inode_ref))
     }
 
-    /// Remove an empty directory. Return `ENOTEMPTY` if the child directory
-    /// is not empty.
+    /// Remove an empty directory.
     ///
     /// # Params
     ///
     /// * `parent` - the parent directory where the directory is located
     /// * `name` - the name of the directory to remove
+    ///
+    /// # Error
+    ///
+    /// * `ENOTDIR` - `parent` or `child` is not a directory
+    /// * `ENOENT` - `name` does not exist in `parent`
+    /// * `ENOTEMPTY` - `child` is not empty
     pub fn rmdir(&mut self, parent: InodeId, name: &str) -> Result<()> {
         let mut parent = self.read_inode(parent);
         // Can only remove a directory in a directory
@@ -289,7 +369,7 @@ impl Ext4 {
             return_err_with_msg_str!(ErrCode::ENOTDIR, "Child not a directory");
         }
         // Child must be empty
-        if self.dir_get_all_entries(&child)?.len() > 2 {
+        if self.dir_get_all_entries(&child).len() > 2 {
             return_err_with_msg_str!(ErrCode::ENOTEMPTY, "Directory not empty");
         }
         // Remove directory entry