liujingx 9 месяцев назад
Родитель
Сommit
e8fce1c961
2 измененных файлов с 44 добавлено и 10 удалено
  1. 32 4
      src/ext4/high_level.rs
  2. 12 6
      src/ext4/low_level.rs

+ 32 - 4
src/ext4/high_level.rs

@@ -53,9 +53,9 @@ impl Ext4 {
     /// # Return
     ///
     /// `Ok(fh)` - File handler
-    /// 
+    ///
     /// # Error
-    /// 
+    ///
     /// * `ENOENT` - The file does not exist.
     /// * `EISDIR` - The file is a directory.
     #[deprecated]
@@ -129,7 +129,7 @@ impl Ext4 {
     /// # Params
     ///
     /// * `root` - The inode id of the starting directory for search.
-    /// * `path` - The path of the object to remove.
+    /// * `path` - The relative path of the object to remove.
     ///
     /// # Error
     ///
@@ -143,7 +143,7 @@ impl Ext4 {
         // Get the parent directory inode
         let parent_id = self.generic_lookup(root, &parent_path)?;
         // Get the child inode
-        let child_id = self.generic_lookup(parent_id, &file_name)?;
+        let child_id = self.lookup(parent_id, &file_name)?;
         let mut parent = self.read_inode(parent_id);
         let mut child = self.read_inode(child_id);
         // Check if child is a non-empty directory
@@ -154,6 +154,34 @@ impl Ext4 {
         self.unlink_inode(&mut parent, &mut child, file_name, true)
     }
 
+    /// Move an object from one location to another.
+    ///
+    /// # Params
+    ///
+    /// * `root` - The inode id of the starting directory for search.
+    /// * `src` - The relative path of the object to move.
+    /// * `dst` - The relative path of the destination.
+    ///
+    /// # Error
+    ///
+    /// * `ENOTDIR` - Any parent in the path is not a directory. 
+    /// * `ENOENT` - The source object does not exist.
+    /// * `EEXIST` - The destination object already exists.
+    pub fn generic_rename(&self, root: InodeId, src: &str, dst: &str) -> Result<()> {
+        // Parse the directories and file names
+        let mut src_path = Self::split_path(src);
+        let src_file_name = &src_path.split_off(src_path.len() - 1)[0];
+        let src_parent_path = src_path.join("/");
+        let mut dst_path = Self::split_path(dst);
+        let dst_file_name = &dst_path.split_off(dst_path.len() - 1)[0];
+        let dst_parent_path = dst_path.join("/");
+        // Get source and des inodes
+        let src_parent_id = self.generic_lookup(root, &src_parent_path)?;
+        let dst_parent_id = self.generic_lookup(root, &dst_parent_path)?;
+        // Move the file
+        self.rename(src_parent_id, &src_file_name, dst_parent_id, &dst_file_name)
+    }
+
     /// A helper function to split a path by '/'
     fn split_path(path: &str) -> Vec<String> {
         let path = path.trim_start_matches("/");

+ 12 - 6
src/ext4/low_level.rs

@@ -313,9 +313,7 @@ impl Ext4 {
         self.unlink_inode(&mut parent, &mut child, name, true)
     }
 
-    /// Move a file. This function will not check name conflict,
-    /// call `lookup` to check beforehand. Caller should ensure
-    /// `parent/name` and `new_parent/new_name` are different.
+    /// Move a file.
     ///
     /// # Params
     ///
@@ -328,6 +326,7 @@ impl Ext4 {
     ///
     /// * `ENOTDIR` - `parent` or `new_parent` is not a directory
     /// * `ENOENT` - `name` does not exist in `parent`
+    /// * `EEXIST` - `new_parent/new_name` already exists
     /// * `ENOSPC` - no space left on device
     pub fn rename(
         &self,
@@ -336,10 +335,12 @@ impl Ext4 {
         new_parent: InodeId,
         new_name: &str,
     ) -> Result<()> {
+        // Check parent
         let mut parent = self.read_inode(parent);
         if !parent.inode.is_dir() {
             return_error!(ErrCode::ENOTDIR, "Inode {} is not a directory", parent.id);
         }
+        // Check new parent
         let mut new_parent = self.read_inode(new_parent);
         if !new_parent.inode.is_dir() {
             return_error!(
@@ -348,9 +349,14 @@ impl Ext4 {
                 new_parent.id
             );
         }
-        let child_entry = self.dir_find_entry(&parent, name)?;
-        let mut child = self.read_inode(child_entry);
-
+        // Check child existence
+        let child_id = self.dir_find_entry(&parent, name)?;
+        let mut child = self.read_inode(child_id);
+        // Check name conflict
+        if self.dir_find_entry(&new_parent, new_name).is_ok() {
+            return_error!(ErrCode::EEXIST, "Dest name {} already exists", new_name);
+        }
+        // Move
         self.unlink_inode(&mut parent, &mut child, name, false)?;
         self.link_inode(&mut new_parent, &mut child, new_name)
     }