fix(fs): 修复 sys_rename 逻辑并支持 RENAME_NOREPLACE (#1393)
逻辑修复: · 修正覆盖现有文件/目录时的逻辑,确保目标被正确截断和删除。 · 增加文件类型检查,禁止文件与目录之间的非法覆盖。 · 增加祖先关系检查,防止将目录移动到其子目录下。 · 修复同名重命名及非空目录覆盖的边界情况。 · 拦截源或目标路径以 . 或 .. 结尾的非法操作。 功能增强: 引入RenameFlags支持,实现了 RENAME_NOREPLACE 语义。 相关 Commits: · 添加 RenameFlags 支持 (NOREPLACE) · 完善路径拦截 (. / ..) ·修复覆盖 截断及类型检查逻辑 · 增加祖先关系判断 --------- Signed-off-by: kaleidoscope416 <2448956191@qq.com>
This commit is contained in:
parent
1e6ccecc17
commit
54c2a45d36
|
|
@ -1,8 +1,7 @@
|
|||
#![allow(dead_code)]
|
||||
use core::{cmp::min, intrinsics::unlikely};
|
||||
use log::{debug, warn};
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::filesystem::fat::fs::LockedFATInode;
|
||||
use crate::filesystem::vfs::IndexNode;
|
||||
use crate::mm::truncate::truncate_inode_pages;
|
||||
use crate::{
|
||||
driver::base::block::{block_device::LBA_SIZE, SeekFrom},
|
||||
libs::vec_cursor::VecCursor,
|
||||
|
|
@ -12,6 +11,9 @@ use alloc::{
|
|||
sync::Arc,
|
||||
vec::Vec,
|
||||
};
|
||||
use core::{cmp::min, intrinsics::unlikely};
|
||||
use log::{debug, warn};
|
||||
use system_error::SystemError;
|
||||
|
||||
use super::{
|
||||
fs::{Cluster, FATFileSystem, MAX_FILE_SIZE},
|
||||
|
|
@ -789,7 +791,8 @@ impl FATDir {
|
|||
let e: FATDirEntry = self.find_entry(name, None, None, fs.clone())?;
|
||||
|
||||
// 判断文件夹是否为空,如果空,则不删除,报错。
|
||||
if e.is_dir() && !(e.to_dir().unwrap().is_empty(fs.clone())) {
|
||||
// remove_clusters 为 false 时(即重命名/移动操作),不再检查目录是否为空,从而允许非空目录被“搬运”到新位置。
|
||||
if e.is_dir() && remove_clusters && !(e.to_dir().unwrap().is_empty(fs.clone())) {
|
||||
return Err(SystemError::ENOTEMPTY);
|
||||
}
|
||||
|
||||
|
|
@ -852,6 +855,7 @@ impl FATDir {
|
|||
fs: Arc<FATFileSystem>,
|
||||
old_name: &str,
|
||||
new_name: &str,
|
||||
new_inode: Option<Arc<LockedFATInode>>,
|
||||
) -> Result<FATDirEntry, SystemError> {
|
||||
// 判断源目录项是否存在
|
||||
let old_dentry = if let FATDirEntryOrShortName::DirEntry(dentry) =
|
||||
|
|
@ -862,25 +866,26 @@ impl FATDir {
|
|||
// 如果目标目录项不存在,则返回错误
|
||||
return Err(SystemError::ENOENT);
|
||||
};
|
||||
|
||||
let short_name = match self.check_existence(new_name, None, fs.clone())? {
|
||||
FATDirEntryOrShortName::ShortName(s) => s,
|
||||
// If newpath already exists, it will be atomically replaced, so that
|
||||
// there is no point at which another process attempting to access
|
||||
// newpath will find it missing.
|
||||
// TODO: support other flags like RENAME_EXCHANGE
|
||||
// 目标已存在:根据类型关系决定是否允许覆盖
|
||||
FATDirEntryOrShortName::DirEntry(e) => {
|
||||
// remove the existing entry
|
||||
validate_rename_target(&old_dentry, &e, fs.clone())?;
|
||||
|
||||
if let Some(new_inode) = new_inode {
|
||||
if let Some(page_cache) = new_inode.page_cache().clone() {
|
||||
truncate_inode_pages(page_cache, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// 允许覆盖:若为非空目录,remove 会返回 ENOTEMPTY(这里只处理空目录或文件)
|
||||
self.remove(fs.clone(), new_name, true)?;
|
||||
e.short_name_raw()
|
||||
}
|
||||
};
|
||||
|
||||
let old_short_dentry = old_dentry.short_dir_entry();
|
||||
if let Some(se) = old_short_dentry {
|
||||
// 删除原来的目录项
|
||||
self.remove(fs.clone(), old_dentry.name().as_str(), false)?;
|
||||
|
||||
// 创建新的目录项
|
||||
let new_dentry = self.create_dir_entries(
|
||||
new_name,
|
||||
|
|
@ -889,7 +894,6 @@ impl FATDir {
|
|||
se.attributes,
|
||||
fs.clone(),
|
||||
)?;
|
||||
|
||||
return Ok(new_dentry);
|
||||
} else {
|
||||
// 不允许对根目录项进行重命名
|
||||
|
|
@ -905,6 +909,7 @@ impl FATDir {
|
|||
target: &FATDir,
|
||||
old_name: &str,
|
||||
new_name: &str,
|
||||
new_inode: Result<Arc<LockedFATInode>, SystemError>,
|
||||
) -> Result<FATDirEntry, SystemError> {
|
||||
// 判断源目录项是否存在
|
||||
let old_dentry: FATDirEntry = if let FATDirEntryOrShortName::DirEntry(dentry) =
|
||||
|
|
@ -916,20 +921,24 @@ impl FATDir {
|
|||
return Err(SystemError::ENOENT);
|
||||
};
|
||||
|
||||
let short_name = if let FATDirEntryOrShortName::ShortName(s) =
|
||||
target.check_existence(new_name, None, fs.clone())?
|
||||
{
|
||||
s
|
||||
} else {
|
||||
// 如果目标目录项存在,那么就返回错误
|
||||
return Err(SystemError::EEXIST);
|
||||
let short_name = match target.check_existence(new_name, None, fs.clone())? {
|
||||
FATDirEntryOrShortName::ShortName(s) => s,
|
||||
// 目标已存在:根据类型关系决定是否允许覆盖
|
||||
FATDirEntryOrShortName::DirEntry(e) => {
|
||||
validate_rename_target(&old_dentry, &e, fs.clone())?;
|
||||
|
||||
if let Some(page_cache) = new_inode.unwrap().page_cache().clone() {
|
||||
truncate_inode_pages(page_cache, 0);
|
||||
}
|
||||
// 覆盖前删除目标目录项(空目录或文件),不截断源内容
|
||||
target.remove(fs.clone(), new_name, true)?;
|
||||
e.short_name_raw()
|
||||
}
|
||||
};
|
||||
|
||||
let old_short_dentry: Option<ShortDirEntry> = old_dentry.short_dir_entry();
|
||||
if let Some(se) = old_short_dentry {
|
||||
// 删除原来的目录项
|
||||
self.remove(fs.clone(), old_dentry.name().as_str(), false)?;
|
||||
|
||||
// 创建新的目录项
|
||||
let new_dentry: FATDirEntry = target.create_dir_entries(
|
||||
new_name,
|
||||
|
|
@ -1025,7 +1034,6 @@ pub struct LongDirEntry {
|
|||
/// 长文件名的12-13个字符,每个字符占2bytes
|
||||
name3: [u16; 2],
|
||||
}
|
||||
|
||||
impl LongDirEntry {
|
||||
/// 长目录项的字符串长度(单位:word)
|
||||
pub const LONG_NAME_STR_LEN: usize = 13;
|
||||
|
|
@ -2464,3 +2472,24 @@ pub fn get_raw_dir_entry(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate_rename_target(
|
||||
old_entry: &FATDirEntry,
|
||||
new_entry: &FATDirEntry,
|
||||
fs: Arc<FATFileSystem>,
|
||||
) -> Result<(), SystemError> {
|
||||
let old_is_dir = old_entry.is_dir();
|
||||
let new_is_dir = new_entry.is_dir();
|
||||
|
||||
if old_is_dir && !new_is_dir {
|
||||
return Err(SystemError::ENOTDIR);
|
||||
}
|
||||
if !old_is_dir && new_is_dir {
|
||||
return Err(SystemError::EISDIR);
|
||||
}
|
||||
// new_entry是目录,直接unwrap
|
||||
if new_entry.is_dir() && !(new_entry.to_dir().unwrap().is_empty(fs)) {
|
||||
return Err(SystemError::ENOTEMPTY);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
use crate::filesystem::vfs::syscall::RenameFlags;
|
||||
use alloc::string::ToString;
|
||||
use alloc::{
|
||||
string::String,
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
};
|
||||
use core::cmp::Ordering;
|
||||
use core::intrinsics::unlikely;
|
||||
use core::{any::Any, fmt::Debug};
|
||||
|
|
@ -6,12 +12,6 @@ use hashbrown::HashMap;
|
|||
use log::error;
|
||||
use system_error::SystemError;
|
||||
|
||||
use alloc::{
|
||||
string::String,
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
use crate::driver::base::block::gendisk::GenDisk;
|
||||
use crate::driver::base::device::device_number::DeviceNumber;
|
||||
use crate::filesystem::page_cache::PageCache;
|
||||
|
|
@ -265,13 +265,29 @@ impl LockedFATInode {
|
|||
&self,
|
||||
old_name: &str,
|
||||
new_name: &str,
|
||||
flags: RenameFlags,
|
||||
) -> Result<(), SystemError> {
|
||||
if old_name == new_name {
|
||||
return Ok(());
|
||||
}
|
||||
let mut guard = self.0.lock();
|
||||
let old_inode = guard.find(old_name)?;
|
||||
// 对目标inode上锁,以防更改
|
||||
let old_inode_guard = old_inode.0.lock();
|
||||
let fs = old_inode_guard.fs.upgrade().unwrap();
|
||||
let new_inode = guard.find(new_name).ok();
|
||||
if flags.contains(RenameFlags::NOREPLACE) && new_inode.is_some() {
|
||||
return Err(SystemError::EEXIST);
|
||||
}
|
||||
|
||||
if flags.contains(RenameFlags::EXCHANGE) {
|
||||
if new_inode.is_none() {
|
||||
return Err(SystemError::ENOENT);
|
||||
}
|
||||
// TODO: Implement EXCHANGE logic
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
// 对目标inode上锁,以防更改
|
||||
let mut old_inode_guard = old_inode.0.lock();
|
||||
let fs = old_inode_guard.fs.upgrade().unwrap();
|
||||
let old_dir = match &guard.inode_type {
|
||||
FATDirEntry::File(_) | FATDirEntry::VolId(_) => {
|
||||
return Err(SystemError::ENOTDIR);
|
||||
|
|
@ -282,10 +298,8 @@ impl LockedFATInode {
|
|||
return Err(SystemError::EROFS);
|
||||
}
|
||||
};
|
||||
|
||||
// remove entries
|
||||
old_dir.rename(fs, old_name, new_name)?;
|
||||
|
||||
old_inode_guard.inode_type = old_dir.rename(fs, old_name, new_name, new_inode)?;
|
||||
let old_inode = guard.children.remove(&to_search_name(old_name)).unwrap();
|
||||
// the new_name should refer to old_inode
|
||||
guard.children.insert(to_search_name(new_name), old_inode);
|
||||
|
|
@ -299,18 +313,33 @@ impl LockedFATInode {
|
|||
old_name: &str,
|
||||
new_name: &str,
|
||||
target: &Arc<dyn IndexNode>,
|
||||
flags: RenameFlags,
|
||||
) -> Result<(), SystemError> {
|
||||
let mut old_guard = self.0.lock();
|
||||
let other: &LockedFATInode = target
|
||||
.downcast_ref::<LockedFATInode>()
|
||||
.ok_or(SystemError::EPERM)?;
|
||||
|
||||
let new_guard = other.0.lock();
|
||||
let mut new_guard = other.0.lock();
|
||||
let old_inode: Arc<LockedFATInode> = old_guard.find(old_name)?;
|
||||
// 对目标inode上锁,以防更改
|
||||
let old_inode_guard: SpinLockGuard<FATInode> = old_inode.0.lock();
|
||||
let fs = old_inode_guard.fs.upgrade().unwrap();
|
||||
let new_inode = new_guard.find(new_name);
|
||||
|
||||
if flags.contains(RenameFlags::NOREPLACE) && new_inode.is_ok() {
|
||||
return Err(SystemError::EEXIST);
|
||||
}
|
||||
|
||||
if flags.contains(RenameFlags::EXCHANGE) {
|
||||
if new_inode.is_err() {
|
||||
return Err(SystemError::ENOENT);
|
||||
}
|
||||
// TODO: Implement EXCHANGE logic
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
// 对目标inode上锁,以防更改
|
||||
let mut old_inode_guard: SpinLockGuard<FATInode> = old_inode.0.lock();
|
||||
// let new_inode_guard = new_inode.0.lock();
|
||||
let fs = old_inode_guard.fs.upgrade().unwrap();
|
||||
let old_dir = match &old_guard.inode_type {
|
||||
FATDirEntry::File(_) | FATDirEntry::VolId(_) => {
|
||||
return Err(SystemError::ENOTDIR);
|
||||
|
|
@ -331,12 +360,17 @@ impl LockedFATInode {
|
|||
return Err(SystemError::EROFS);
|
||||
}
|
||||
};
|
||||
// 检查文件是否存在
|
||||
old_dir.check_existence(old_name, Some(false), old_guard.fs.upgrade().unwrap())?;
|
||||
old_dir.rename_across(fs, new_dir, old_name, new_name)?;
|
||||
// 从缓存删除
|
||||
let _nod = old_guard.children.remove(&to_search_name(old_name));
|
||||
|
||||
old_inode_guard.inode_type =
|
||||
old_dir.rename_across(fs, new_dir, old_name, new_name, new_inode)?;
|
||||
// 将源节点从父目录中删除
|
||||
let old_inode = old_guard
|
||||
.children
|
||||
.remove(&to_search_name(old_name))
|
||||
.unwrap();
|
||||
new_guard
|
||||
.children
|
||||
.insert(to_search_name(new_name), old_inode);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -1900,14 +1934,15 @@ impl IndexNode for LockedFATInode {
|
|||
old_name: &str,
|
||||
target: &Arc<dyn IndexNode>,
|
||||
new_name: &str,
|
||||
flags: RenameFlags,
|
||||
) -> Result<(), SystemError> {
|
||||
let old_id = self.metadata().unwrap().inode_id;
|
||||
let new_id = target.metadata().unwrap().inode_id;
|
||||
// 若在同一父目录下
|
||||
if old_id == new_id {
|
||||
self.rename_file_in_current_dir(old_name, new_name)?;
|
||||
self.rename_file_in_current_dir(old_name, new_name, flags)?;
|
||||
} else {
|
||||
self.move_to_another_dir(old_name, new_name, target)?;
|
||||
self.move_to_another_dir(old_name, new_name, target, flags)?;
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use system_error::SystemError;
|
|||
|
||||
use crate::{
|
||||
driver::base::device::device_number::DeviceNumber,
|
||||
filesystem::vfs::syscall::RenameFlags,
|
||||
libs::{
|
||||
casting::DowncastArc,
|
||||
rwlock::RwLock,
|
||||
|
|
@ -227,6 +228,7 @@ impl IndexNode for KernFSInode {
|
|||
_old_name: &str,
|
||||
_target: &Arc<dyn IndexNode>,
|
||||
_new_name: &str,
|
||||
_flags: RenameFlags,
|
||||
) -> Result<(), SystemError> {
|
||||
// 应当通过kernfs的其它方法来操作文件,而不能从用户态直接调用此方法。
|
||||
return Err(SystemError::ENOSYS);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use crate::{
|
|||
driver::base::device::device_number::DeviceNumber,
|
||||
filesystem::vfs::{
|
||||
mount::{MountFlags, MountPath},
|
||||
syscall::RenameFlags,
|
||||
vcore::generate_inode_id,
|
||||
FileType,
|
||||
},
|
||||
|
|
@ -1078,6 +1079,7 @@ impl IndexNode for LockedProcFSInode {
|
|||
_old_name: &str,
|
||||
_target: &Arc<dyn IndexNode>,
|
||||
_new_name: &str,
|
||||
_flag: RenameFlags,
|
||||
) -> Result<(), SystemError> {
|
||||
return Err(SystemError::ENOSYS);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use core::any::Any;
|
||||
use core::intrinsics::unlikely;
|
||||
|
||||
use crate::filesystem::vfs::syscall::RenameFlags;
|
||||
use crate::filesystem::vfs::{FileSystemMakerData, FSMAKER};
|
||||
use crate::libs::rwlock::RwLock;
|
||||
use crate::register_mountable_fs;
|
||||
|
|
@ -440,6 +441,7 @@ impl IndexNode for LockedRamFSInode {
|
|||
old_name: &str,
|
||||
target: &Arc<dyn IndexNode>,
|
||||
new_name: &str,
|
||||
flags: RenameFlags,
|
||||
) -> Result<(), SystemError> {
|
||||
let inode_to_move = self
|
||||
.find(old_name)?
|
||||
|
|
@ -455,6 +457,10 @@ impl IndexNode for LockedRamFSInode {
|
|||
let mut self_inode = self.0.lock();
|
||||
// 判断是否在同一目录下, 是则进行重命名
|
||||
if target_id == self_inode.metadata.inode_id {
|
||||
if flags.contains(RenameFlags::NOREPLACE) && self_inode.children.contains_key(&new_name)
|
||||
{
|
||||
return Err(SystemError::EEXIST);
|
||||
}
|
||||
self_inode.children.remove(&DName::from(old_name));
|
||||
self_inode.children.insert(new_name, inode_to_move);
|
||||
return Ok(());
|
||||
|
|
|
|||
|
|
@ -20,7 +20,10 @@ use crate::{
|
|||
driver::base::{
|
||||
block::block_device::BlockDevice, char::CharDevice, device::device_number::DeviceNumber,
|
||||
},
|
||||
filesystem::{epoll::EPollItem, vfs::permission::PermissionMask},
|
||||
filesystem::{
|
||||
epoll::EPollItem,
|
||||
vfs::{permission::PermissionMask, syscall::RenameFlags},
|
||||
},
|
||||
ipc::pipe::LockedPipeInode,
|
||||
libs::{
|
||||
casting::DowncastArc,
|
||||
|
|
@ -407,6 +410,7 @@ pub trait IndexNode: Any + Sync + Send + Debug + CastFromSync {
|
|||
_old_name: &str,
|
||||
_target: &Arc<dyn IndexNode>,
|
||||
_new_name: &str,
|
||||
_flag: RenameFlags,
|
||||
) -> Result<(), SystemError> {
|
||||
// 若文件系统没有实现此方法,则返回“不支持”
|
||||
return Err(SystemError::ENOSYS);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use crate::{
|
|||
driver::base::device::device_number::DeviceNumber,
|
||||
filesystem::{
|
||||
page_cache::PageCache,
|
||||
vfs::{fcntl::AtFlags, vcore::do_mkdir_at},
|
||||
vfs::{fcntl::AtFlags, syscall::RenameFlags, vcore::do_mkdir_at},
|
||||
},
|
||||
libs::{
|
||||
casting::DowncastArc,
|
||||
|
|
@ -729,8 +729,9 @@ impl IndexNode for MountFSInode {
|
|||
old_name: &str,
|
||||
target: &Arc<dyn IndexNode>,
|
||||
new_name: &str,
|
||||
flags: RenameFlags,
|
||||
) -> Result<(), SystemError> {
|
||||
return self.inner_inode.move_to(old_name, target, new_name);
|
||||
return self.inner_inode.move_to(old_name, target, new_name, flags);
|
||||
}
|
||||
|
||||
fn find(&self, name: &str) -> Result<Arc<dyn IndexNode>, SystemError> {
|
||||
|
|
|
|||
|
|
@ -175,6 +175,19 @@ bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Flags used in the `renameat2` system call.
|
||||
///
|
||||
/// Reference: <https://elixir.bootlin.com/linux/v6.16.3/source/include/uapi/linux/fcntl.h#L140-L143>.
|
||||
///
|
||||
/// Reference: <https://man7.org/linux/man-pages/man2/renameat.2.html>.
|
||||
pub struct RenameFlags: u32 {
|
||||
const NOREPLACE = 1 << 0;
|
||||
const EXCHANGE = 1 << 1;
|
||||
const WHITEOUT = 1 << 2;
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
/// # 文件信息结构体X
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use crate::filesystem::vfs::syscall::RenameFlags;
|
||||
use crate::filesystem::vfs::utils::is_ancestor;
|
||||
use crate::filesystem::vfs::utils::rsplit_path;
|
||||
use crate::filesystem::vfs::utils::user_path_at;
|
||||
use crate::filesystem::vfs::SystemError;
|
||||
|
|
@ -21,6 +23,7 @@ use crate::syscall::user_access::check_and_clone_cstr;
|
|||
/// - Ok(返回值类型): 返回值的说明
|
||||
/// - Err(错误值类型): 错误的说明
|
||||
///
|
||||
/// references: https://code.dragonos.org.cn/xref/linux-6.6.21/fs/namei.c#4913
|
||||
pub fn do_renameat2(
|
||||
oldfd: i32,
|
||||
filename_from: *const u8,
|
||||
|
|
@ -41,10 +44,8 @@ pub fn do_renameat2(
|
|||
return Err(SystemError::ENAMETOOLONG);
|
||||
}
|
||||
|
||||
let flags = Flags::from_bits_truncate(flags);
|
||||
if !flags.is_empty() {
|
||||
log::warn!("renameat2 flags {flags:?} not supported yet");
|
||||
return Err(SystemError::EINVAL);
|
||||
if filename_from == "/" || filename_to == "/" {
|
||||
return Err(SystemError::EBUSY);
|
||||
}
|
||||
|
||||
//获取pcb,文件节点
|
||||
|
|
@ -59,19 +60,28 @@ pub fn do_renameat2(
|
|||
let (new_filename, new_parent_path) = rsplit_path(&new_remain_path);
|
||||
let new_parent_inode = root_inode
|
||||
.lookup_follow_symlink(new_parent_path.unwrap_or("/"), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
|
||||
old_parent_inode.move_to(old_filename, &new_parent_inode, new_filename)?;
|
||||
|
||||
let flags = RenameFlags::from_bits_truncate(flags);
|
||||
if flags.contains(RenameFlags::NOREPLACE) && (new_filename == "." || new_filename == "..") {
|
||||
return Err(SystemError::EEXIST);
|
||||
}
|
||||
|
||||
if old_filename == "." || old_filename == ".." || new_filename == "." || new_filename == ".." {
|
||||
return Err(SystemError::EBUSY);
|
||||
}
|
||||
|
||||
let old_inode = old_parent_inode.lookup(old_filename)?;
|
||||
if old_inode.metadata()?.file_type == crate::filesystem::vfs::FileType::Dir {
|
||||
// 仅当把目录移动到其自身或其子树下时拦截
|
||||
if is_ancestor(&old_inode, &new_parent_inode) {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
// 不要在这里检查 new_parent 是否是 old 的祖先:
|
||||
// 这会把同目录/向上移动的合法情况误判为 ENOTEMPTY。
|
||||
// 非空目录覆盖应由具体文件系统在 move_to/rename 实现中返回 ENOTEMPTY。
|
||||
|
||||
old_parent_inode.move_to(old_filename, &new_parent_inode, new_filename, flags)?;
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Flags used in the `renameat2` system call.
|
||||
///
|
||||
/// Reference: <https://elixir.bootlin.com/linux/v6.16.3/source/include/uapi/linux/fcntl.h#L140-L143>.
|
||||
///
|
||||
/// Reference: <https://man7.org/linux/man-pages/man2/renameat.2.html>.
|
||||
struct Flags: u32 {
|
||||
const NOREPLACE = 1 << 0;
|
||||
const EXCHANGE = 1 << 1;
|
||||
const WHITEOUT = 1 << 2;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,6 +78,42 @@ pub fn user_path_at(
|
|||
return Ok((inode, ret_path));
|
||||
}
|
||||
|
||||
pub fn is_ancestor(ancestor: &Arc<dyn IndexNode>, node: &Arc<dyn IndexNode>) -> bool {
|
||||
let ancestor_id = match ancestor.metadata() {
|
||||
Ok(m) => m.inode_id,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
let mut next_node: Option<Arc<dyn IndexNode>> = Some(node.clone());
|
||||
while let Some(current) = next_node {
|
||||
let cur_id = match current.metadata() {
|
||||
Ok(m) => m.inode_id,
|
||||
Err(_) => break,
|
||||
};
|
||||
|
||||
if cur_id == ancestor_id {
|
||||
return true;
|
||||
}
|
||||
|
||||
let parent = match current.parent() {
|
||||
Ok(p) => p,
|
||||
Err(_) => break, // 没有父节点,到达根或错误,停止循环
|
||||
};
|
||||
|
||||
let parent_id = match parent.metadata() {
|
||||
Ok(m) => m.inode_id,
|
||||
Err(_) => break,
|
||||
};
|
||||
|
||||
if parent_id == cur_id {
|
||||
break;
|
||||
}
|
||||
next_node = Some(parent);
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Directory Name
|
||||
/// 可以用来作为原地提取目录名及比较的
|
||||
/// Dentry的对标(x
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
RenameTest.DirectoryOverwritesDirectoryLinkCount
|
||||
# 权限相关未实现
|
||||
RenameTest.FailsWhenOldParentNotWritable
|
||||
RenameTest.FailsWhenNewParentNotWritable
|
||||
RenameTest.OverwriteFailsWhenNewParentNotWritable
|
||||
RenameTest.FileDoesNotExistWhenNewParentNotExecutable
|
||||
# 相关系统调用未实现
|
||||
RenameTest.SysfsFileToSelf
|
||||
RenameTest.SysfsDirectoryToSelf
|
||||
|
|
@ -23,6 +23,7 @@ sync_test
|
|||
#chown_test
|
||||
chdir_test
|
||||
fchdir_test
|
||||
rename_test
|
||||
getdents_test
|
||||
|
||||
# 进程相关测试
|
||||
|
|
|
|||
Loading…
Reference in New Issue