|
@@ -14,16 +14,21 @@ use crate::prelude::*;
|
|
use crate::return_error;
|
|
use crate::return_error;
|
|
|
|
|
|
impl Ext4 {
|
|
impl Ext4 {
|
|
- /// Look up an object in the filesystem.
|
|
|
|
|
|
+ /// Look up an object in the filesystem recursively.
|
|
///
|
|
///
|
|
- /// ## Params
|
|
|
|
|
|
+ /// # Params
|
|
///
|
|
///
|
|
/// * `root` - The inode id of the root directory for search.
|
|
/// * `root` - The inode id of the root directory for search.
|
|
- /// * `path` - The path of the object to be opened.
|
|
|
|
|
|
+ /// * `path` - The relative path of the object to be opened.
|
|
///
|
|
///
|
|
- /// ## Return
|
|
|
|
|
|
+ /// # Return
|
|
///
|
|
///
|
|
/// `Ok(inode)` - Inode id of the object
|
|
/// `Ok(inode)` - Inode id of the object
|
|
|
|
+ ///
|
|
|
|
+ /// # Error
|
|
|
|
+ ///
|
|
|
|
+ /// * `ENOTDIR` - Any parent along `path` is not a directory.
|
|
|
|
+ /// * `ENOENT` - The object does not exist.
|
|
pub fn generic_lookup(&self, root: InodeId, path: &str) -> Result<InodeId> {
|
|
pub fn generic_lookup(&self, root: InodeId, path: &str) -> Result<InodeId> {
|
|
trace!("generic_lookup({}, {})", root, path);
|
|
trace!("generic_lookup({}, {})", root, path);
|
|
// Search from the given parent inode
|
|
// Search from the given parent inode
|
|
@@ -36,18 +41,24 @@ impl Ext4 {
|
|
Ok(cur)
|
|
Ok(cur)
|
|
}
|
|
}
|
|
|
|
|
|
- /// Open a file in the filesystem. Return error if the file does not exist.
|
|
|
|
|
|
+ /// (DEPRECATED) Open a file in the filesystem.
|
|
///
|
|
///
|
|
- /// ## Params
|
|
|
|
|
|
+ /// # Params
|
|
///
|
|
///
|
|
/// * `root` - The inode id of the root directory for search.
|
|
/// * `root` - The inode id of the root directory for search.
|
|
/// * `path` - The path of the object to be opened.
|
|
/// * `path` - The path of the object to be opened.
|
|
/// * `flags` - The open flags. Creation (O_CREAT, O_EXCL, O_NOCTTY) flags
|
|
/// * `flags` - The open flags. Creation (O_CREAT, O_EXCL, O_NOCTTY) flags
|
|
/// will be ignored.
|
|
/// will be ignored.
|
|
///
|
|
///
|
|
- /// ## Return
|
|
|
|
|
|
+ /// # Return
|
|
///
|
|
///
|
|
/// `Ok(fh)` - File handler
|
|
/// `Ok(fh)` - File handler
|
|
|
|
+ ///
|
|
|
|
+ /// # Error
|
|
|
|
+ ///
|
|
|
|
+ /// * `ENOENT` - The file does not exist.
|
|
|
|
+ /// * `EISDIR` - The file is a directory.
|
|
|
|
+ #[deprecated]
|
|
pub fn generic_open(&self, root: InodeId, path: &str, flags: OpenFlags) -> Result<FileHandler> {
|
|
pub fn generic_open(&self, root: InodeId, path: &str, flags: OpenFlags) -> Result<FileHandler> {
|
|
let inode_id = self.generic_lookup(root, path)?;
|
|
let inode_id = self.generic_lookup(root, path)?;
|
|
let inode = self.read_inode(inode_id);
|
|
let inode = self.read_inode(inode_id);
|
|
@@ -58,45 +69,51 @@ impl Ext4 {
|
|
Ok(FileHandler::new(inode.id, flags, inode.inode.size()))
|
|
Ok(FileHandler::new(inode.id, flags, inode.inode.size()))
|
|
}
|
|
}
|
|
|
|
|
|
- /// Create an object in the filesystem. Return error if the object already exists.
|
|
|
|
|
|
+ /// Create an object in the filesystem.
|
|
///
|
|
///
|
|
/// This function will perform recursive-creation i.e. if the parent
|
|
/// This function will perform recursive-creation i.e. if the parent
|
|
/// directory does not exist, it will be created as well.
|
|
/// directory does not exist, it will be created as well.
|
|
///
|
|
///
|
|
- /// ## Params
|
|
|
|
|
|
+ /// # Params
|
|
///
|
|
///
|
|
/// * `root` - The inode id of the starting directory for search.
|
|
/// * `root` - The inode id of the starting directory for search.
|
|
- /// * `path` - The path of the object to create.
|
|
|
|
|
|
+ /// * `path` - The relative path of the object to create.
|
|
/// * `mode` - file mode and type to create
|
|
/// * `mode` - file mode and type to create
|
|
///
|
|
///
|
|
- /// ## Return
|
|
|
|
|
|
+ /// # Return
|
|
///
|
|
///
|
|
/// `Ok(inode)` - Inode id of the created object
|
|
/// `Ok(inode)` - Inode id of the created object
|
|
|
|
+ ///
|
|
|
|
+ /// # Error
|
|
|
|
+ ///
|
|
|
|
+ /// * `ENOTDIR` - Any parent along `path` is not a directory.
|
|
|
|
+ /// * `EEXIST` - The object already exists.
|
|
pub fn generic_create(&self, root: InodeId, path: &str, mode: InodeMode) -> Result<InodeId> {
|
|
pub fn generic_create(&self, root: InodeId, path: &str, mode: InodeMode) -> Result<InodeId> {
|
|
// Search from the given parent inode
|
|
// Search from the given parent inode
|
|
let mut cur = self.read_inode(root);
|
|
let mut cur = self.read_inode(root);
|
|
let search_path = Self::split_path(path);
|
|
let search_path = Self::split_path(path);
|
|
-
|
|
|
|
// Search recursively
|
|
// Search recursively
|
|
for (i, path) in search_path.iter().enumerate() {
|
|
for (i, path) in search_path.iter().enumerate() {
|
|
if !cur.inode.is_dir() {
|
|
if !cur.inode.is_dir() {
|
|
return_error!(ErrCode::ENOTDIR, "Parent {} is not a directory", cur.id);
|
|
return_error!(ErrCode::ENOTDIR, "Parent {} is not a directory", cur.id);
|
|
}
|
|
}
|
|
match self.dir_find_entry(&cur, &path) {
|
|
match self.dir_find_entry(&cur, &path) {
|
|
- Ok(de) => {
|
|
|
|
- // If the object exists, check the type
|
|
|
|
- cur = self.read_inode(de);
|
|
|
|
|
|
+ Ok(id) => {
|
|
|
|
+ if i == search_path.len() - 1 {
|
|
|
|
+ // Reach the object and it already exists
|
|
|
|
+ return_error!(ErrCode::EEXIST, "Object {}/{} already exists", root, path);
|
|
|
|
+ }
|
|
|
|
+ cur = self.read_inode(id);
|
|
}
|
|
}
|
|
Err(e) => {
|
|
Err(e) => {
|
|
if e.code() != ErrCode::ENOENT {
|
|
if e.code() != ErrCode::ENOENT {
|
|
- return Err(e);
|
|
|
|
|
|
+ return_error!(e.code(), "Unexpected error: {:?}", e);
|
|
}
|
|
}
|
|
- // If the object does not exist, create it
|
|
|
|
let mut child = if i == search_path.len() - 1 {
|
|
let mut child = if i == search_path.len() - 1 {
|
|
- // Create the file
|
|
|
|
|
|
+ // Reach the object, create it
|
|
self.create_inode(mode)?
|
|
self.create_inode(mode)?
|
|
} else {
|
|
} else {
|
|
- // Create the directory
|
|
|
|
|
|
+ // Create parent directory
|
|
self.create_inode(InodeMode::DIRECTORY | InodeMode::ALL_RWX)?
|
|
self.create_inode(InodeMode::DIRECTORY | InodeMode::ALL_RWX)?
|
|
};
|
|
};
|
|
self.link_inode(&mut cur, &mut child, path)?;
|
|
self.link_inode(&mut cur, &mut child, path)?;
|
|
@@ -104,17 +121,20 @@ impl Ext4 {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
Ok(cur.id)
|
|
Ok(cur.id)
|
|
}
|
|
}
|
|
|
|
|
|
- /// Remove an object from the filesystem. Return error if the object is a
|
|
|
|
- /// directory and is not empty.
|
|
|
|
|
|
+ /// Remove an object from the filesystem.
|
|
///
|
|
///
|
|
- /// ## Params
|
|
|
|
|
|
+ /// # Params
|
|
///
|
|
///
|
|
/// * `root` - The inode id of the starting directory for search.
|
|
/// * `root` - The inode id of the starting directory for search.
|
|
/// * `path` - The path of the object to remove.
|
|
/// * `path` - The path of the object to remove.
|
|
|
|
+ ///
|
|
|
|
+ /// # Error
|
|
|
|
+ ///
|
|
|
|
+ /// * `ENOENT` - The object does not exist.
|
|
|
|
+ /// * `ENOTEMPTY` - The object is a non-empty directory.
|
|
pub fn generic_remove(&self, root: InodeId, path: &str) -> Result<()> {
|
|
pub fn generic_remove(&self, root: InodeId, path: &str) -> Result<()> {
|
|
// Get the parent directory path and the file name
|
|
// Get the parent directory path and the file name
|
|
let mut search_path = Self::split_path(path);
|
|
let mut search_path = Self::split_path(path);
|
|
@@ -126,11 +146,9 @@ impl Ext4 {
|
|
let child_id = self.generic_lookup(parent_id, &file_name)?;
|
|
let child_id = self.generic_lookup(parent_id, &file_name)?;
|
|
let mut parent = self.read_inode(parent_id);
|
|
let mut parent = self.read_inode(parent_id);
|
|
let mut child = self.read_inode(child_id);
|
|
let mut child = self.read_inode(child_id);
|
|
- if child.inode.is_dir() {
|
|
|
|
- // Check if the directory is empty
|
|
|
|
- if self.dir_list_entries(&child).len() > 2 {
|
|
|
|
- return_error!(ErrCode::ENOTEMPTY, "Directory {} not empty", path);
|
|
|
|
- }
|
|
|
|
|
|
+ // Check if child is a non-empty directory
|
|
|
|
+ if child.inode.is_dir() && self.dir_list_entries(&child).len() > 2 {
|
|
|
|
+ return_error!(ErrCode::ENOTEMPTY, "Directory {} not empty", path);
|
|
}
|
|
}
|
|
// Unlink the file
|
|
// Unlink the file
|
|
self.unlink_inode(&mut parent, &mut child, file_name, true)
|
|
self.unlink_inode(&mut parent, &mut child, file_name, true)
|