Skip to content

Commit 54c2a45

Browse files
fix(fs): 修复 sys_rename 逻辑并支持 RENAME_NOREPLACE (#1393)
逻辑修复: · 修正覆盖现有文件/目录时的逻辑,确保目标被正确截断和删除。 · 增加文件类型检查,禁止文件与目录之间的非法覆盖。 · 增加祖先关系检查,防止将目录移动到其子目录下。 · 修复同名重命名及非空目录覆盖的边界情况。 · 拦截源或目标路径以 . 或 .. 结尾的非法操作。 功能增强: 引入RenameFlags支持,实现了 RENAME_NOREPLACE 语义。 相关 Commits: · 添加 RenameFlags 支持 (NOREPLACE) · 完善路径拦截 (. / ..) ·修复覆盖 截断及类型检查逻辑 · 增加祖先关系判断 --------- Signed-off-by: kaleidoscope416 <[email protected]>
1 parent 1e6ccec commit 54c2a45

File tree

12 files changed

+214
-66
lines changed

12 files changed

+214
-66
lines changed

kernel/src/filesystem/fat/entry.rs

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
#![allow(dead_code)]
2-
use core::{cmp::min, intrinsics::unlikely};
3-
use log::{debug, warn};
4-
use system_error::SystemError;
5-
2+
use crate::filesystem::fat::fs::LockedFATInode;
3+
use crate::filesystem::vfs::IndexNode;
4+
use crate::mm::truncate::truncate_inode_pages;
65
use crate::{
76
driver::base::block::{block_device::LBA_SIZE, SeekFrom},
87
libs::vec_cursor::VecCursor,
@@ -12,6 +11,9 @@ use alloc::{
1211
sync::Arc,
1312
vec::Vec,
1413
};
14+
use core::{cmp::min, intrinsics::unlikely};
15+
use log::{debug, warn};
16+
use system_error::SystemError;
1517

1618
use super::{
1719
fs::{Cluster, FATFileSystem, MAX_FILE_SIZE},
@@ -789,7 +791,8 @@ impl FATDir {
789791
let e: FATDirEntry = self.find_entry(name, None, None, fs.clone())?;
790792

791793
// 判断文件夹是否为空,如果空,则不删除,报错。
792-
if e.is_dir() && !(e.to_dir().unwrap().is_empty(fs.clone())) {
794+
// remove_clusters 为 false 时(即重命名/移动操作),不再检查目录是否为空,从而允许非空目录被“搬运”到新位置。
795+
if e.is_dir() && remove_clusters && !(e.to_dir().unwrap().is_empty(fs.clone())) {
793796
return Err(SystemError::ENOTEMPTY);
794797
}
795798

@@ -852,6 +855,7 @@ impl FATDir {
852855
fs: Arc<FATFileSystem>,
853856
old_name: &str,
854857
new_name: &str,
858+
new_inode: Option<Arc<LockedFATInode>>,
855859
) -> Result<FATDirEntry, SystemError> {
856860
// 判断源目录项是否存在
857861
let old_dentry = if let FATDirEntryOrShortName::DirEntry(dentry) =
@@ -862,25 +866,26 @@ impl FATDir {
862866
// 如果目标目录项不存在,则返回错误
863867
return Err(SystemError::ENOENT);
864868
};
865-
866869
let short_name = match self.check_existence(new_name, None, fs.clone())? {
867870
FATDirEntryOrShortName::ShortName(s) => s,
868-
// If newpath already exists, it will be atomically replaced, so that
869-
// there is no point at which another process attempting to access
870-
// newpath will find it missing.
871-
// TODO: support other flags like RENAME_EXCHANGE
871+
// 目标已存在:根据类型关系决定是否允许覆盖
872872
FATDirEntryOrShortName::DirEntry(e) => {
873-
// remove the existing entry
873+
validate_rename_target(&old_dentry, &e, fs.clone())?;
874+
875+
if let Some(new_inode) = new_inode {
876+
if let Some(page_cache) = new_inode.page_cache().clone() {
877+
truncate_inode_pages(page_cache, 0);
878+
}
879+
}
880+
881+
// 允许覆盖:若为非空目录,remove 会返回 ENOTEMPTY(这里只处理空目录或文件)
874882
self.remove(fs.clone(), new_name, true)?;
875883
e.short_name_raw()
876884
}
877885
};
878-
879886
let old_short_dentry = old_dentry.short_dir_entry();
880887
if let Some(se) = old_short_dentry {
881-
// 删除原来的目录项
882888
self.remove(fs.clone(), old_dentry.name().as_str(), false)?;
883-
884889
// 创建新的目录项
885890
let new_dentry = self.create_dir_entries(
886891
new_name,
@@ -889,7 +894,6 @@ impl FATDir {
889894
se.attributes,
890895
fs.clone(),
891896
)?;
892-
893897
return Ok(new_dentry);
894898
} else {
895899
// 不允许对根目录项进行重命名
@@ -905,6 +909,7 @@ impl FATDir {
905909
target: &FATDir,
906910
old_name: &str,
907911
new_name: &str,
912+
new_inode: Result<Arc<LockedFATInode>, SystemError>,
908913
) -> Result<FATDirEntry, SystemError> {
909914
// 判断源目录项是否存在
910915
let old_dentry: FATDirEntry = if let FATDirEntryOrShortName::DirEntry(dentry) =
@@ -916,20 +921,24 @@ impl FATDir {
916921
return Err(SystemError::ENOENT);
917922
};
918923

919-
let short_name = if let FATDirEntryOrShortName::ShortName(s) =
920-
target.check_existence(new_name, None, fs.clone())?
921-
{
922-
s
923-
} else {
924-
// 如果目标目录项存在,那么就返回错误
925-
return Err(SystemError::EEXIST);
924+
let short_name = match target.check_existence(new_name, None, fs.clone())? {
925+
FATDirEntryOrShortName::ShortName(s) => s,
926+
// 目标已存在:根据类型关系决定是否允许覆盖
927+
FATDirEntryOrShortName::DirEntry(e) => {
928+
validate_rename_target(&old_dentry, &e, fs.clone())?;
929+
930+
if let Some(page_cache) = new_inode.unwrap().page_cache().clone() {
931+
truncate_inode_pages(page_cache, 0);
932+
}
933+
// 覆盖前删除目标目录项(空目录或文件),不截断源内容
934+
target.remove(fs.clone(), new_name, true)?;
935+
e.short_name_raw()
936+
}
926937
};
927938

928939
let old_short_dentry: Option<ShortDirEntry> = old_dentry.short_dir_entry();
929940
if let Some(se) = old_short_dentry {
930-
// 删除原来的目录项
931941
self.remove(fs.clone(), old_dentry.name().as_str(), false)?;
932-
933942
// 创建新的目录项
934943
let new_dentry: FATDirEntry = target.create_dir_entries(
935944
new_name,
@@ -1025,7 +1034,6 @@ pub struct LongDirEntry {
10251034
/// 长文件名的12-13个字符,每个字符占2bytes
10261035
name3: [u16; 2],
10271036
}
1028-
10291037
impl LongDirEntry {
10301038
/// 长目录项的字符串长度(单位:word)
10311039
pub const LONG_NAME_STR_LEN: usize = 13;
@@ -2464,3 +2472,24 @@ pub fn get_raw_dir_entry(
24642472
}
24652473
}
24662474
}
2475+
2476+
pub fn validate_rename_target(
2477+
old_entry: &FATDirEntry,
2478+
new_entry: &FATDirEntry,
2479+
fs: Arc<FATFileSystem>,
2480+
) -> Result<(), SystemError> {
2481+
let old_is_dir = old_entry.is_dir();
2482+
let new_is_dir = new_entry.is_dir();
2483+
2484+
if old_is_dir && !new_is_dir {
2485+
return Err(SystemError::ENOTDIR);
2486+
}
2487+
if !old_is_dir && new_is_dir {
2488+
return Err(SystemError::EISDIR);
2489+
}
2490+
// new_entry是目录,直接unwrap
2491+
if new_entry.is_dir() && !(new_entry.to_dir().unwrap().is_empty(fs)) {
2492+
return Err(SystemError::ENOTEMPTY);
2493+
}
2494+
Ok(())
2495+
}

kernel/src/filesystem/fat/fs.rs

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1+
use crate::filesystem::vfs::syscall::RenameFlags;
12
use alloc::string::ToString;
3+
use alloc::{
4+
string::String,
5+
sync::{Arc, Weak},
6+
vec::Vec,
7+
};
28
use core::cmp::Ordering;
39
use core::intrinsics::unlikely;
410
use core::{any::Any, fmt::Debug};
511
use hashbrown::HashMap;
612
use log::error;
713
use system_error::SystemError;
814

9-
use alloc::{
10-
string::String,
11-
sync::{Arc, Weak},
12-
vec::Vec,
13-
};
14-
1515
use crate::driver::base::block::gendisk::GenDisk;
1616
use crate::driver::base::device::device_number::DeviceNumber;
1717
use crate::filesystem::page_cache::PageCache;
@@ -265,13 +265,29 @@ impl LockedFATInode {
265265
&self,
266266
old_name: &str,
267267
new_name: &str,
268+
flags: RenameFlags,
268269
) -> Result<(), SystemError> {
270+
if old_name == new_name {
271+
return Ok(());
272+
}
269273
let mut guard = self.0.lock();
270274
let old_inode = guard.find(old_name)?;
275+
let new_inode = guard.find(new_name).ok();
276+
if flags.contains(RenameFlags::NOREPLACE) && new_inode.is_some() {
277+
return Err(SystemError::EEXIST);
278+
}
279+
280+
if flags.contains(RenameFlags::EXCHANGE) {
281+
if new_inode.is_none() {
282+
return Err(SystemError::ENOENT);
283+
}
284+
// TODO: Implement EXCHANGE logic
285+
return Err(SystemError::EINVAL);
286+
}
287+
271288
// 对目标inode上锁,以防更改
272-
let old_inode_guard = old_inode.0.lock();
289+
let mut old_inode_guard = old_inode.0.lock();
273290
let fs = old_inode_guard.fs.upgrade().unwrap();
274-
275291
let old_dir = match &guard.inode_type {
276292
FATDirEntry::File(_) | FATDirEntry::VolId(_) => {
277293
return Err(SystemError::ENOTDIR);
@@ -282,10 +298,8 @@ impl LockedFATInode {
282298
return Err(SystemError::EROFS);
283299
}
284300
};
285-
286301
// remove entries
287-
old_dir.rename(fs, old_name, new_name)?;
288-
302+
old_inode_guard.inode_type = old_dir.rename(fs, old_name, new_name, new_inode)?;
289303
let old_inode = guard.children.remove(&to_search_name(old_name)).unwrap();
290304
// the new_name should refer to old_inode
291305
guard.children.insert(to_search_name(new_name), old_inode);
@@ -299,18 +313,33 @@ impl LockedFATInode {
299313
old_name: &str,
300314
new_name: &str,
301315
target: &Arc<dyn IndexNode>,
316+
flags: RenameFlags,
302317
) -> Result<(), SystemError> {
303318
let mut old_guard = self.0.lock();
304319
let other: &LockedFATInode = target
305320
.downcast_ref::<LockedFATInode>()
306321
.ok_or(SystemError::EPERM)?;
307322

308-
let new_guard = other.0.lock();
323+
let mut new_guard = other.0.lock();
309324
let old_inode: Arc<LockedFATInode> = old_guard.find(old_name)?;
325+
let new_inode = new_guard.find(new_name);
326+
327+
if flags.contains(RenameFlags::NOREPLACE) && new_inode.is_ok() {
328+
return Err(SystemError::EEXIST);
329+
}
330+
331+
if flags.contains(RenameFlags::EXCHANGE) {
332+
if new_inode.is_err() {
333+
return Err(SystemError::ENOENT);
334+
}
335+
// TODO: Implement EXCHANGE logic
336+
return Err(SystemError::EINVAL);
337+
}
338+
310339
// 对目标inode上锁,以防更改
311-
let old_inode_guard: SpinLockGuard<FATInode> = old_inode.0.lock();
340+
let mut old_inode_guard: SpinLockGuard<FATInode> = old_inode.0.lock();
341+
// let new_inode_guard = new_inode.0.lock();
312342
let fs = old_inode_guard.fs.upgrade().unwrap();
313-
314343
let old_dir = match &old_guard.inode_type {
315344
FATDirEntry::File(_) | FATDirEntry::VolId(_) => {
316345
return Err(SystemError::ENOTDIR);
@@ -331,12 +360,17 @@ impl LockedFATInode {
331360
return Err(SystemError::EROFS);
332361
}
333362
};
334-
// 检查文件是否存在
335-
old_dir.check_existence(old_name, Some(false), old_guard.fs.upgrade().unwrap())?;
336-
old_dir.rename_across(fs, new_dir, old_name, new_name)?;
337-
// 从缓存删除
338-
let _nod = old_guard.children.remove(&to_search_name(old_name));
339363

364+
old_inode_guard.inode_type =
365+
old_dir.rename_across(fs, new_dir, old_name, new_name, new_inode)?;
366+
// 将源节点从父目录中删除
367+
let old_inode = old_guard
368+
.children
369+
.remove(&to_search_name(old_name))
370+
.unwrap();
371+
new_guard
372+
.children
373+
.insert(to_search_name(new_name), old_inode);
340374
Ok(())
341375
}
342376
}
@@ -1900,14 +1934,15 @@ impl IndexNode for LockedFATInode {
19001934
old_name: &str,
19011935
target: &Arc<dyn IndexNode>,
19021936
new_name: &str,
1937+
flags: RenameFlags,
19031938
) -> Result<(), SystemError> {
19041939
let old_id = self.metadata().unwrap().inode_id;
19051940
let new_id = target.metadata().unwrap().inode_id;
19061941
// 若在同一父目录下
19071942
if old_id == new_id {
1908-
self.rename_file_in_current_dir(old_name, new_name)?;
1943+
self.rename_file_in_current_dir(old_name, new_name, flags)?;
19091944
} else {
1910-
self.move_to_another_dir(old_name, new_name, target)?;
1945+
self.move_to_another_dir(old_name, new_name, target, flags)?;
19111946
}
19121947

19131948
return Ok(());

kernel/src/filesystem/kernfs/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use system_error::SystemError;
1212

1313
use crate::{
1414
driver::base::device::device_number::DeviceNumber,
15+
filesystem::vfs::syscall::RenameFlags,
1516
libs::{
1617
casting::DowncastArc,
1718
rwlock::RwLock,
@@ -227,6 +228,7 @@ impl IndexNode for KernFSInode {
227228
_old_name: &str,
228229
_target: &Arc<dyn IndexNode>,
229230
_new_name: &str,
231+
_flags: RenameFlags,
230232
) -> Result<(), SystemError> {
231233
// 应当通过kernfs的其它方法来操作文件,而不能从用户态直接调用此方法。
232234
return Err(SystemError::ENOSYS);

kernel/src/filesystem/procfs/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::{
1616
driver::base::device::device_number::DeviceNumber,
1717
filesystem::vfs::{
1818
mount::{MountFlags, MountPath},
19+
syscall::RenameFlags,
1920
vcore::generate_inode_id,
2021
FileType,
2122
},
@@ -1078,6 +1079,7 @@ impl IndexNode for LockedProcFSInode {
10781079
_old_name: &str,
10791080
_target: &Arc<dyn IndexNode>,
10801081
_new_name: &str,
1082+
_flag: RenameFlags,
10811083
) -> Result<(), SystemError> {
10821084
return Err(SystemError::ENOSYS);
10831085
}

kernel/src/filesystem/ramfs/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use core::any::Any;
22
use core::intrinsics::unlikely;
33

4+
use crate::filesystem::vfs::syscall::RenameFlags;
45
use crate::filesystem::vfs::{FileSystemMakerData, FSMAKER};
56
use crate::libs::rwlock::RwLock;
67
use crate::register_mountable_fs;
@@ -440,6 +441,7 @@ impl IndexNode for LockedRamFSInode {
440441
old_name: &str,
441442
target: &Arc<dyn IndexNode>,
442443
new_name: &str,
444+
flags: RenameFlags,
443445
) -> Result<(), SystemError> {
444446
let inode_to_move = self
445447
.find(old_name)?
@@ -455,6 +457,10 @@ impl IndexNode for LockedRamFSInode {
455457
let mut self_inode = self.0.lock();
456458
// 判断是否在同一目录下, 是则进行重命名
457459
if target_id == self_inode.metadata.inode_id {
460+
if flags.contains(RenameFlags::NOREPLACE) && self_inode.children.contains_key(&new_name)
461+
{
462+
return Err(SystemError::EEXIST);
463+
}
458464
self_inode.children.remove(&DName::from(old_name));
459465
self_inode.children.insert(new_name, inode_to_move);
460466
return Ok(());

kernel/src/filesystem/vfs/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ use crate::{
2020
driver::base::{
2121
block::block_device::BlockDevice, char::CharDevice, device::device_number::DeviceNumber,
2222
},
23-
filesystem::{epoll::EPollItem, vfs::permission::PermissionMask},
23+
filesystem::{
24+
epoll::EPollItem,
25+
vfs::{permission::PermissionMask, syscall::RenameFlags},
26+
},
2427
ipc::pipe::LockedPipeInode,
2528
libs::{
2629
casting::DowncastArc,
@@ -407,6 +410,7 @@ pub trait IndexNode: Any + Sync + Send + Debug + CastFromSync {
407410
_old_name: &str,
408411
_target: &Arc<dyn IndexNode>,
409412
_new_name: &str,
413+
_flag: RenameFlags,
410414
) -> Result<(), SystemError> {
411415
// 若文件系统没有实现此方法,则返回“不支持”
412416
return Err(SystemError::ENOSYS);

0 commit comments

Comments
 (0)