Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 54 additions & 25 deletions kernel/src/filesystem/fat/entry.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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},
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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) =
Expand All @@ -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,
Expand All @@ -889,7 +894,6 @@ impl FATDir {
se.attributes,
fs.clone(),
)?;

return Ok(new_dentry);
} else {
// 不允许对根目录项进行重命名
Expand All @@ -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) =
Expand All @@ -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);
Comment on lines +930 to +931
Copy link

Copilot AI Nov 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling .unwrap() on new_inode will panic if it contains an Err value. The parameter type is Result<Arc<LockedFATInode>, SystemError>, so when the target doesn't exist, this will be an Err.

Use pattern matching or safe handling:

if let Ok(inode) = &new_inode {
    if let Some(page_cache) = inode.page_cache().clone() {
        truncate_inode_pages(page_cache, 0);
    }
}
Suggested change
if let Some(page_cache) = new_inode.unwrap().page_cache().clone() {
truncate_inode_pages(page_cache, 0);
if let Ok(inode) = &new_inode {
if let Some(page_cache) = inode.page_cache().clone() {
truncate_inode_pages(page_cache, 0);
}

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

和上面一样

}
// 覆盖前删除目标目录项(空目录或文件),不截断源内容
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,
Expand Down Expand Up @@ -1025,7 +1034,6 @@ pub struct LongDirEntry {
/// 长文件名的12-13个字符,每个字符占2bytes
name3: [u16; 2],
}

impl LongDirEntry {
/// 长目录项的字符串长度(单位:word)
pub const LONG_NAME_STR_LEN: usize = 13;
Expand Down Expand Up @@ -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(())
}
77 changes: 56 additions & 21 deletions kernel/src/filesystem/fat/fs.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
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};
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;
Expand Down Expand Up @@ -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)?;
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 old_inode_guard = old_inode.0.lock();
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);
Expand All @@ -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);
Expand All @@ -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)?;
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 old_inode_guard: SpinLockGuard<FATInode> = old_inode.0.lock();
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);
Expand All @@ -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(())
}
}
Expand Down Expand Up @@ -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(());
Expand Down
2 changes: 2 additions & 0 deletions kernel/src/filesystem/kernfs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions kernel/src/filesystem/procfs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::{
driver::base::device::device_number::DeviceNumber,
filesystem::vfs::{
mount::{MountFlags, MountPath},
syscall::RenameFlags,
vcore::generate_inode_id,
FileType,
},
Expand Down Expand Up @@ -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);
}
Expand Down
6 changes: 6 additions & 0 deletions kernel/src/filesystem/ramfs/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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)?
Expand All @@ -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(());
Expand Down
6 changes: 5 additions & 1 deletion kernel/src/filesystem/vfs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down
Loading
Loading