|
@@ -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
|