mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
feat:添加symlink系统调用 (#984)
* 添加symlink系统调用 * 修改FATInode的dname的获取逻辑 * 修改fat对Dname的处理,分离dname和inode缓存的key --------- Co-authored-by: sparkzky <sparkhhhhhhhhh@outlook.com> Co-authored-by: longjin <longjin@DragonOS.org>
This commit is contained in:
parent
cae6182257
commit
01c18c64b1
@ -2,11 +2,11 @@ use alloc::string::ToString;
|
|||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
use core::intrinsics::unlikely;
|
use core::intrinsics::unlikely;
|
||||||
use core::{any::Any, fmt::Debug};
|
use core::{any::Any, fmt::Debug};
|
||||||
|
use hashbrown::HashMap;
|
||||||
use log::error;
|
use log::error;
|
||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
use alloc::{
|
use alloc::{
|
||||||
collections::BTreeMap,
|
|
||||||
string::String,
|
string::String,
|
||||||
sync::{Arc, Weak},
|
sync::{Arc, Weak},
|
||||||
vec::Vec,
|
vec::Vec,
|
||||||
@ -36,6 +36,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::entry::FATFile;
|
use super::entry::FATFile;
|
||||||
|
use super::utils::{to_search_name, to_search_name_string};
|
||||||
use super::{
|
use super::{
|
||||||
bpb::{BiosParameterBlock, FATType},
|
bpb::{BiosParameterBlock, FATType},
|
||||||
entry::{FATDir, FATDirEntry, FATDirIter, FATEntry},
|
entry::{FATDir, FATDirEntry, FATDirIter, FATEntry},
|
||||||
@ -106,9 +107,9 @@ pub struct FATInode {
|
|||||||
parent: Weak<LockedFATInode>,
|
parent: Weak<LockedFATInode>,
|
||||||
/// 指向自身的弱引用
|
/// 指向自身的弱引用
|
||||||
self_ref: Weak<LockedFATInode>,
|
self_ref: Weak<LockedFATInode>,
|
||||||
/// 子Inode的B树. 该数据结构用作缓存区。其中,它的key表示inode的名称。
|
/// 子Inode的map. 该数据结构用作缓存区。其中,它的key表示inode的名称。
|
||||||
/// 请注意,由于FAT的查询过程对大小写不敏感,因此我们选择让key全部是大写的,方便统一操作。
|
/// 请注意,由于FAT的查询过程对大小写不敏感,因此我们选择让key全部是大写的,方便统一操作。
|
||||||
children: BTreeMap<DName, Arc<LockedFATInode>>,
|
children: HashMap<String, Arc<LockedFATInode>>,
|
||||||
/// 当前inode的元数据
|
/// 当前inode的元数据
|
||||||
metadata: Metadata,
|
metadata: Metadata,
|
||||||
/// 指向inode所在的文件系统对象的指针
|
/// 指向inode所在的文件系统对象的指针
|
||||||
@ -148,24 +149,25 @@ impl FATInode {
|
|||||||
fn find(&mut self, name: &str) -> Result<Arc<LockedFATInode>, SystemError> {
|
fn find(&mut self, name: &str) -> Result<Arc<LockedFATInode>, SystemError> {
|
||||||
match &self.inode_type {
|
match &self.inode_type {
|
||||||
FATDirEntry::Dir(d) => {
|
FATDirEntry::Dir(d) => {
|
||||||
let dname = DName::from(name.to_uppercase());
|
let search_name = to_search_name(name);
|
||||||
// 尝试在缓存区查找
|
// 尝试在缓存区查找
|
||||||
if let Some(entry) = self.children.get(&dname) {
|
if let Some(entry) = self.children.get(&search_name) {
|
||||||
return Ok(entry.clone());
|
return Ok(entry.clone());
|
||||||
}
|
}
|
||||||
// 在缓存区找不到
|
// 在缓存区找不到
|
||||||
// 在磁盘查找
|
// 在磁盘查找
|
||||||
let fat_entry: FATDirEntry =
|
let fat_entry: FATDirEntry =
|
||||||
d.find_entry(name, None, None, self.fs.upgrade().unwrap())?;
|
d.find_entry(name, None, None, self.fs.upgrade().unwrap())?;
|
||||||
|
let dname = DName::from(name);
|
||||||
// 创建新的inode
|
// 创建新的inode
|
||||||
let entry_inode: Arc<LockedFATInode> = LockedFATInode::new(
|
let entry_inode: Arc<LockedFATInode> = LockedFATInode::new(
|
||||||
dname.clone(),
|
dname,
|
||||||
self.fs.upgrade().unwrap(),
|
self.fs.upgrade().unwrap(),
|
||||||
self.self_ref.clone(),
|
self.self_ref.clone(),
|
||||||
fat_entry,
|
fat_entry,
|
||||||
);
|
);
|
||||||
// 加入缓存区, 由于FAT文件系统的大小写不敏感问题,因此存入缓存区的key应当是全大写的
|
// 加入缓存区, 由于FAT文件系统的大小写不敏感问题,因此存入缓存区的key应当是全大写的
|
||||||
self.children.insert(dname, entry_inode.clone());
|
self.children.insert(search_name, entry_inode.clone());
|
||||||
return Ok(entry_inode);
|
return Ok(entry_inode);
|
||||||
}
|
}
|
||||||
FATDirEntry::UnInit => {
|
FATDirEntry::UnInit => {
|
||||||
@ -197,7 +199,7 @@ impl LockedFATInode {
|
|||||||
let inode: Arc<LockedFATInode> = Arc::new(LockedFATInode(SpinLock::new(FATInode {
|
let inode: Arc<LockedFATInode> = Arc::new(LockedFATInode(SpinLock::new(FATInode {
|
||||||
parent,
|
parent,
|
||||||
self_ref: Weak::default(),
|
self_ref: Weak::default(),
|
||||||
children: BTreeMap::new(),
|
children: HashMap::new(),
|
||||||
fs: Arc::downgrade(&fs),
|
fs: Arc::downgrade(&fs),
|
||||||
inode_type,
|
inode_type,
|
||||||
metadata: Metadata {
|
metadata: Metadata {
|
||||||
@ -348,7 +350,7 @@ impl FATFileSystem {
|
|||||||
let root_inode: Arc<LockedFATInode> = Arc::new(LockedFATInode(SpinLock::new(FATInode {
|
let root_inode: Arc<LockedFATInode> = Arc::new(LockedFATInode(SpinLock::new(FATInode {
|
||||||
parent: Weak::default(),
|
parent: Weak::default(),
|
||||||
self_ref: Weak::default(),
|
self_ref: Weak::default(),
|
||||||
children: BTreeMap::new(),
|
children: HashMap::new(),
|
||||||
fs: Weak::default(),
|
fs: Weak::default(),
|
||||||
inode_type: FATDirEntry::UnInit,
|
inode_type: FATDirEntry::UnInit,
|
||||||
metadata: Metadata {
|
metadata: Metadata {
|
||||||
@ -1559,14 +1561,15 @@ impl IndexNode for LockedFATInode {
|
|||||||
for ent in dir_iter {
|
for ent in dir_iter {
|
||||||
ret.push(ent.name());
|
ret.push(ent.name());
|
||||||
|
|
||||||
// ====== 生成inode缓存,存入B树
|
// ====== 生成inode缓存
|
||||||
let name = DName::from(ent.name().to_uppercase());
|
let search_name = to_search_name_string(ent.name());
|
||||||
// debug!("name={name}");
|
// debug!("name={name}");
|
||||||
|
|
||||||
if !guard.children.contains_key(&name)
|
if !guard.children.contains_key(&search_name)
|
||||||
&& name.as_ref() != "."
|
&& search_name != "."
|
||||||
&& name.as_ref() != ".."
|
&& search_name != ".."
|
||||||
{
|
{
|
||||||
|
let name = DName::from(ent.name());
|
||||||
// 创建新的inode
|
// 创建新的inode
|
||||||
let entry_inode: Arc<LockedFATInode> = LockedFATInode::new(
|
let entry_inode: Arc<LockedFATInode> = LockedFATInode::new(
|
||||||
name.clone(),
|
name.clone(),
|
||||||
@ -1575,7 +1578,7 @@ impl IndexNode for LockedFATInode {
|
|||||||
ent,
|
ent,
|
||||||
);
|
);
|
||||||
// 加入缓存区, 由于FAT文件系统的大小写不敏感问题,因此存入缓存区的key应当是全大写的
|
// 加入缓存区, 由于FAT文件系统的大小写不敏感问题,因此存入缓存区的key应当是全大写的
|
||||||
guard.children.insert(name, entry_inode.clone());
|
guard.children.insert(search_name, entry_inode.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Ok(ret);
|
return Ok(ret);
|
||||||
@ -1611,7 +1614,7 @@ impl IndexNode for LockedFATInode {
|
|||||||
// 对目标inode上锁,以防更改
|
// 对目标inode上锁,以防更改
|
||||||
let target_guard: SpinLockGuard<FATInode> = target.0.lock();
|
let target_guard: SpinLockGuard<FATInode> = target.0.lock();
|
||||||
// 先从缓存删除
|
// 先从缓存删除
|
||||||
let nod = guard.children.remove(&DName::from(name.to_uppercase()));
|
let nod = guard.children.remove(&to_search_name(name));
|
||||||
|
|
||||||
// 若删除缓存中为管道的文件,则不需要再到磁盘删除
|
// 若删除缓存中为管道的文件,则不需要再到磁盘删除
|
||||||
if nod.is_some() {
|
if nod.is_some() {
|
||||||
@ -1646,7 +1649,7 @@ impl IndexNode for LockedFATInode {
|
|||||||
// 对目标inode上锁,以防更改
|
// 对目标inode上锁,以防更改
|
||||||
let target_guard: SpinLockGuard<FATInode> = target.0.lock();
|
let target_guard: SpinLockGuard<FATInode> = target.0.lock();
|
||||||
// 先从缓存删除
|
// 先从缓存删除
|
||||||
guard.children.remove(&DName::from(name.to_uppercase()));
|
guard.children.remove(&to_search_name(name));
|
||||||
|
|
||||||
let dir = match &guard.inode_type {
|
let dir = match &guard.inode_type {
|
||||||
FATDirEntry::File(_) | FATDirEntry::VolId(_) => {
|
FATDirEntry::File(_) | FATDirEntry::VolId(_) => {
|
||||||
@ -1669,9 +1672,7 @@ impl IndexNode for LockedFATInode {
|
|||||||
Err(r) => {
|
Err(r) => {
|
||||||
if r == SystemError::ENOTEMPTY {
|
if r == SystemError::ENOTEMPTY {
|
||||||
// 如果要删除的是目录,且不为空,则删除动作未发生,重新加入缓存
|
// 如果要删除的是目录,且不为空,则删除动作未发生,重新加入缓存
|
||||||
guard
|
guard.children.insert(to_search_name(name), target.clone());
|
||||||
.children
|
|
||||||
.insert(DName::from(name.to_uppercase()), target.clone());
|
|
||||||
drop(target_guard);
|
drop(target_guard);
|
||||||
}
|
}
|
||||||
return Err(r);
|
return Err(r);
|
||||||
@ -1695,7 +1696,6 @@ impl IndexNode for LockedFATInode {
|
|||||||
let old_inode_guard: SpinLockGuard<FATInode> = old_inode.0.lock();
|
let old_inode_guard: SpinLockGuard<FATInode> = old_inode.0.lock();
|
||||||
let fs = old_inode_guard.fs.upgrade().unwrap();
|
let fs = old_inode_guard.fs.upgrade().unwrap();
|
||||||
// 从缓存删除
|
// 从缓存删除
|
||||||
let _nod = guard.children.remove(&DName::from(old_name.to_uppercase()));
|
|
||||||
let old_dir = match &guard.inode_type {
|
let old_dir = match &guard.inode_type {
|
||||||
FATDirEntry::File(_) | FATDirEntry::VolId(_) => {
|
FATDirEntry::File(_) | FATDirEntry::VolId(_) => {
|
||||||
return Err(SystemError::ENOTDIR);
|
return Err(SystemError::ENOTDIR);
|
||||||
@ -1710,6 +1710,7 @@ impl IndexNode for LockedFATInode {
|
|||||||
// old_dir.check_existence(old_name, Some(false), guard.fs.upgrade().unwrap())?;
|
// old_dir.check_existence(old_name, Some(false), guard.fs.upgrade().unwrap())?;
|
||||||
|
|
||||||
old_dir.rename(fs, old_name, new_name)?;
|
old_dir.rename(fs, old_name, new_name)?;
|
||||||
|
let _nod = guard.children.remove(&to_search_name(old_name));
|
||||||
} else {
|
} else {
|
||||||
let mut old_guard = self.0.lock();
|
let mut old_guard = self.0.lock();
|
||||||
let other: &LockedFATInode = target
|
let other: &LockedFATInode = target
|
||||||
@ -1721,10 +1722,7 @@ impl IndexNode for LockedFATInode {
|
|||||||
// 对目标inode上锁,以防更改
|
// 对目标inode上锁,以防更改
|
||||||
let old_inode_guard: SpinLockGuard<FATInode> = old_inode.0.lock();
|
let old_inode_guard: SpinLockGuard<FATInode> = old_inode.0.lock();
|
||||||
let fs = old_inode_guard.fs.upgrade().unwrap();
|
let fs = old_inode_guard.fs.upgrade().unwrap();
|
||||||
// 从缓存删除
|
|
||||||
let _nod = old_guard
|
|
||||||
.children
|
|
||||||
.remove(&DName::from(old_name.to_uppercase()));
|
|
||||||
let old_dir = match &old_guard.inode_type {
|
let old_dir = match &old_guard.inode_type {
|
||||||
FATDirEntry::File(_) | FATDirEntry::VolId(_) => {
|
FATDirEntry::File(_) | FATDirEntry::VolId(_) => {
|
||||||
return Err(SystemError::ENOTDIR);
|
return Err(SystemError::ENOTDIR);
|
||||||
@ -1748,6 +1746,8 @@ impl IndexNode for LockedFATInode {
|
|||||||
// 检查文件是否存在
|
// 检查文件是否存在
|
||||||
old_dir.check_existence(old_name, Some(false), old_guard.fs.upgrade().unwrap())?;
|
old_dir.check_existence(old_name, Some(false), old_guard.fs.upgrade().unwrap())?;
|
||||||
old_dir.rename_across(fs, new_dir, old_name, new_name)?;
|
old_dir.rename_across(fs, new_dir, old_name, new_name)?;
|
||||||
|
// 从缓存删除
|
||||||
|
let _nod = old_guard.children.remove(&to_search_name(old_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -1806,9 +1806,9 @@ impl IndexNode for LockedFATInode {
|
|||||||
return self.create(filename, FileType::File, mode);
|
return self.create(filename, FileType::File, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
let filename = DName::from(filename.to_uppercase());
|
let dname = DName::from(filename);
|
||||||
let nod = LockedFATInode::new(
|
let nod = LockedFATInode::new(
|
||||||
filename.clone(),
|
dname,
|
||||||
inode.fs.upgrade().unwrap(),
|
inode.fs.upgrade().unwrap(),
|
||||||
inode.self_ref.clone(),
|
inode.self_ref.clone(),
|
||||||
FATDirEntry::File(FATFile::default()),
|
FATDirEntry::File(FATFile::default()),
|
||||||
@ -1830,7 +1830,7 @@ impl IndexNode for LockedFATInode {
|
|||||||
return Err(SystemError::EINVAL);
|
return Err(SystemError::EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
inode.children.insert(filename, nod.clone());
|
inode.children.insert(to_search_name(filename), nod.clone());
|
||||||
Ok(nod)
|
Ok(nod)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use alloc::string::String;
|
||||||
use core::char::REPLACEMENT_CHARACTER;
|
use core::char::REPLACEMENT_CHARACTER;
|
||||||
|
|
||||||
/// FAT文件系统保留开头的2个簇
|
/// FAT文件系统保留开头的2个簇
|
||||||
@ -5,7 +6,7 @@ pub const RESERVED_CLUSTERS: u32 = 2;
|
|||||||
|
|
||||||
/// @brief 将u8转为ascii字符。
|
/// @brief 将u8转为ascii字符。
|
||||||
/// 当转码成功时,返回对应的ascii字符,否则返回Unicode占位符
|
/// 当转码成功时,返回对应的ascii字符,否则返回Unicode占位符
|
||||||
pub fn decode_u8_ascii(value: u8) -> char {
|
pub(super) fn decode_u8_ascii(value: u8) -> char {
|
||||||
if value <= 0x7f {
|
if value <= 0x7f {
|
||||||
return value as char;
|
return value as char;
|
||||||
} else {
|
} else {
|
||||||
@ -13,3 +14,16 @@ pub fn decode_u8_ascii(value: u8) -> char {
|
|||||||
return REPLACEMENT_CHARACTER;
|
return REPLACEMENT_CHARACTER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 把名称转为inode缓存里面的key
|
||||||
|
#[inline(always)]
|
||||||
|
pub(super) fn to_search_name(name: &str) -> String {
|
||||||
|
name.to_ascii_uppercase()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 把名称转为inode缓存里面的key(输入为string,原地替换)
|
||||||
|
#[inline(always)]
|
||||||
|
pub(super) fn to_search_name_string(mut name: String) -> String {
|
||||||
|
name.make_ascii_uppercase();
|
||||||
|
name
|
||||||
|
}
|
||||||
|
@ -12,9 +12,13 @@ use crate::{
|
|||||||
procfs::procfs_init,
|
procfs::procfs_init,
|
||||||
ramfs::RamFS,
|
ramfs::RamFS,
|
||||||
sysfs::sysfs_init,
|
sysfs::sysfs_init,
|
||||||
vfs::{mount::MountFS, syscall::ModeType, AtomicInodeId, FileSystem, FileType},
|
vfs::{
|
||||||
|
mount::MountFS, syscall::ModeType, AtomicInodeId, FileSystem, FileType, MAX_PATHLEN,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
libs::spinlock::SpinLock,
|
||||||
process::ProcessManager,
|
process::ProcessManager,
|
||||||
|
syscall::user_access::check_and_clone_cstr,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
@ -23,7 +27,7 @@ use super::{
|
|||||||
mount::{init_mountlist, MOUNT_LIST},
|
mount::{init_mountlist, MOUNT_LIST},
|
||||||
syscall::UmountFlag,
|
syscall::UmountFlag,
|
||||||
utils::{rsplit_path, user_path_at},
|
utils::{rsplit_path, user_path_at},
|
||||||
IndexNode, InodeId, VFS_MAX_FOLLOW_SYMLINK_TIMES,
|
FilePrivateData, IndexNode, InodeId, VFS_MAX_FOLLOW_SYMLINK_TIMES,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// 当没有指定根文件系统时,尝试的根文件系统列表
|
/// 当没有指定根文件系统时,尝试的根文件系统列表
|
||||||
@ -248,6 +252,48 @@ pub fn do_unlink_at(dirfd: i32, path: &str) -> Result<u64, SystemError> {
|
|||||||
return Ok(0);
|
return Ok(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn do_symlinkat(from: *const u8, newdfd: i32, to: *const u8) -> Result<usize, SystemError> {
|
||||||
|
let oldname = check_and_clone_cstr(from, Some(MAX_PATHLEN))?
|
||||||
|
.into_string()
|
||||||
|
.map_err(|_| SystemError::EINVAL)?;
|
||||||
|
let newname = check_and_clone_cstr(to, Some(MAX_PATHLEN))?
|
||||||
|
.into_string()
|
||||||
|
.map_err(|_| SystemError::EINVAL)?;
|
||||||
|
let from = oldname.as_str().trim();
|
||||||
|
let to = newname.as_str().trim();
|
||||||
|
|
||||||
|
// TODO: 添加权限检查,确保进程拥有目标路径的权限
|
||||||
|
|
||||||
|
let pcb = ProcessManager::current_pcb();
|
||||||
|
let (old_begin_inode, old_remain_path) = user_path_at(&pcb, AtFlags::AT_FDCWD.bits(), from)?;
|
||||||
|
// info!("old_begin_inode={:?}", old_begin_inode.metadata());
|
||||||
|
let _ =
|
||||||
|
old_begin_inode.lookup_follow_symlink(&old_remain_path, VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
|
||||||
|
|
||||||
|
// 得到新创建节点的父节点
|
||||||
|
let (new_begin_inode, new_remain_path) = user_path_at(&pcb, newdfd, to)?;
|
||||||
|
let (new_name, new_parent_path) = rsplit_path(&new_remain_path);
|
||||||
|
let new_parent = new_begin_inode
|
||||||
|
.lookup_follow_symlink(new_parent_path.unwrap_or("/"), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
|
||||||
|
// info!("new_parent={:?}", new_parent.metadata());
|
||||||
|
|
||||||
|
if new_parent.metadata()?.file_type != FileType::Dir {
|
||||||
|
return Err(SystemError::ENOTDIR);
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_inode = new_parent.create_with_data(
|
||||||
|
new_name,
|
||||||
|
FileType::SymLink,
|
||||||
|
ModeType::from_bits_truncate(0o777),
|
||||||
|
0,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let buf = old_remain_path.as_bytes();
|
||||||
|
let len = buf.len();
|
||||||
|
new_inode.write_at(0, len, buf, SpinLock::new(FilePrivateData::Unused).lock())?;
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
|
||||||
/// # do_mount - 挂载文件系统
|
/// # do_mount - 挂载文件系统
|
||||||
///
|
///
|
||||||
/// 将给定的文件系统挂载到指定的挂载点。
|
/// 将给定的文件系统挂载到指定的挂载点。
|
||||||
|
@ -8,6 +8,7 @@ use alloc::{
|
|||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
sync::{Arc, Weak},
|
sync::{Arc, Weak},
|
||||||
|
vec::Vec,
|
||||||
};
|
};
|
||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
@ -215,12 +216,29 @@ impl MountFSInode {
|
|||||||
.ok_or(SystemError::ENOENT);
|
.ok_or(SystemError::ENOENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_absolute_path(&self, len: usize) -> Result<String, SystemError> {
|
fn do_absolute_path(&self) -> Result<String, SystemError> {
|
||||||
if self.metadata()?.inode_id == ROOT_INODE().metadata()?.inode_id {
|
let mut path_parts = Vec::new();
|
||||||
return Ok(String::with_capacity(len));
|
let mut current = self.self_ref.upgrade().unwrap();
|
||||||
|
|
||||||
|
while current.metadata()?.inode_id != ROOT_INODE().metadata()?.inode_id {
|
||||||
|
let name = current.dname()?;
|
||||||
|
path_parts.push(name.0);
|
||||||
|
current = current.do_parent()?;
|
||||||
}
|
}
|
||||||
let name = self.dname()?;
|
|
||||||
return Ok(self.do_parent()?.do_absolute_path(len + name.0.len() + 1)? + "/" + &name.0);
|
// 由于我们从叶子节点向上遍历到根节点,所以需要反转路径部分
|
||||||
|
path_parts.reverse();
|
||||||
|
|
||||||
|
// 构建最终的绝对路径字符串
|
||||||
|
let mut absolute_path = String::with_capacity(
|
||||||
|
path_parts.iter().map(|s| s.len()).sum::<usize>() + path_parts.len(),
|
||||||
|
);
|
||||||
|
for part in path_parts {
|
||||||
|
absolute_path.push('/');
|
||||||
|
absolute_path.push_str(&part);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(absolute_path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -469,7 +487,7 @@ impl IndexNode for MountFSInode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn absolute_path(&self) -> Result<String, SystemError> {
|
fn absolute_path(&self) -> Result<String, SystemError> {
|
||||||
self.do_absolute_path(0)
|
self.do_absolute_path()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -20,6 +20,7 @@ use crate::{
|
|||||||
time::{syscall::PosixTimeval, PosixTimeSpec},
|
time::{syscall::PosixTimeval, PosixTimeSpec},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::core::do_symlinkat;
|
||||||
use super::{
|
use super::{
|
||||||
core::{do_mkdir_at, do_remove_dir, do_unlink_at},
|
core::{do_mkdir_at, do_remove_dir, do_unlink_at},
|
||||||
fcntl::{AtFlags, FcntlCommand, FD_CLOEXEC},
|
fcntl::{AtFlags, FcntlCommand, FD_CLOEXEC},
|
||||||
@ -980,6 +981,18 @@ impl Syscall {
|
|||||||
return do_unlink_at(AtFlags::AT_FDCWD.bits(), &path).map(|v| v as usize);
|
return do_unlink_at(AtFlags::AT_FDCWD.bits(), &path).map(|v| v as usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn symlink(oldname: *const u8, newname: *const u8) -> Result<usize, SystemError> {
|
||||||
|
return do_symlinkat(oldname, AtFlags::AT_FDCWD.bits(), newname);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn symlinkat(
|
||||||
|
oldname: *const u8,
|
||||||
|
newdfd: i32,
|
||||||
|
newname: *const u8,
|
||||||
|
) -> Result<usize, SystemError> {
|
||||||
|
return do_symlinkat(oldname, newdfd, newname);
|
||||||
|
}
|
||||||
|
|
||||||
/// # 修改文件名
|
/// # 修改文件名
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
|
@ -346,6 +346,20 @@ impl Syscall {
|
|||||||
Self::unlinkat(dirfd, path, flags)
|
Self::unlinkat(dirfd, path, flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
SYS_SYMLINK => {
|
||||||
|
let oldname = args[0] as *const u8;
|
||||||
|
let newname = args[1] as *const u8;
|
||||||
|
Self::symlink(oldname, newname)
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_SYMLINKAT => {
|
||||||
|
let oldname = args[0] as *const u8;
|
||||||
|
let newdfd = args[1] as i32;
|
||||||
|
let newname = args[2] as *const u8;
|
||||||
|
Self::symlinkat(oldname, newdfd, newname)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
SYS_RMDIR => {
|
SYS_RMDIR => {
|
||||||
let path = args[0] as *const u8;
|
let path = args[0] as *const u8;
|
||||||
|
@ -8,4 +8,5 @@ authors = [ "xiaolin2004 <1553367438@qq.com>" ]
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libc="0.2"
|
errno = "0.3.9"
|
||||||
|
libc="0.2"
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
use core::ffi::{c_char, c_void};
|
use core::ffi::{c_char, c_void};
|
||||||
|
use errno::errno;
|
||||||
use libc::{mount, MS_BIND};
|
use libc::{mount, MS_BIND};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::time;
|
use std::time;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let path = Path::new("mnt/tmp");
|
let path = Path::new("mnt/tmp");
|
||||||
let dir = fs::create_dir_all(path);
|
let dir = fs::create_dir_all(path);
|
||||||
@ -26,7 +28,8 @@ fn main() {
|
|||||||
if result == 0 {
|
if result == 0 {
|
||||||
println!("Mount successful");
|
println!("Mount successful");
|
||||||
} else {
|
} else {
|
||||||
println!("Mount failed");
|
let err = errno();
|
||||||
|
println!("Mount failed with error code: {}", err.0);
|
||||||
}
|
}
|
||||||
let dur = clock.elapsed();
|
let dur = clock.elapsed();
|
||||||
println!("mount costing time: {} ns", dur.as_nanos());
|
println!("mount costing time: {} ns", dur.as_nanos());
|
||||||
|
3
user/apps/test-symlink/.gitignore
vendored
Normal file
3
user/apps/test-symlink/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/target
|
||||||
|
Cargo.lock
|
||||||
|
/install/
|
13
user/apps/test-symlink/Cargo.toml
Normal file
13
user/apps/test-symlink/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "test-symlink"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
description = "测试symlink系统调用"
|
||||||
|
authors = [ "sparkzky <sparkhhhhhhhhh@outlook.com>" ]
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
errno = "0.3.9"
|
||||||
|
libc="0.2"
|
||||||
|
nix = "0.23"
|
56
user/apps/test-symlink/Makefile
Normal file
56
user/apps/test-symlink/Makefile
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
TOOLCHAIN=
|
||||||
|
RUSTFLAGS=
|
||||||
|
|
||||||
|
ifdef DADK_CURRENT_BUILD_DIR
|
||||||
|
# 如果是在dadk中编译,那么安装到dadk的安装目录中
|
||||||
|
INSTALL_DIR = $(DADK_CURRENT_BUILD_DIR)
|
||||||
|
else
|
||||||
|
# 如果是在本地编译,那么安装到当前目录下的install目录中
|
||||||
|
INSTALL_DIR = ./install
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(ARCH), x86_64)
|
||||||
|
export RUST_TARGET=x86_64-unknown-linux-musl
|
||||||
|
else ifeq ($(ARCH), riscv64)
|
||||||
|
export RUST_TARGET=riscv64gc-unknown-linux-gnu
|
||||||
|
else
|
||||||
|
# 默认为x86_86,用于本地编译
|
||||||
|
export RUST_TARGET=x86_64-unknown-linux-musl
|
||||||
|
endif
|
||||||
|
|
||||||
|
run:
|
||||||
|
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET)
|
||||||
|
|
||||||
|
build:
|
||||||
|
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET)
|
||||||
|
|
||||||
|
test:
|
||||||
|
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET)
|
||||||
|
|
||||||
|
doc:
|
||||||
|
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) doc --target $(RUST_TARGET)
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt
|
||||||
|
|
||||||
|
fmt-check:
|
||||||
|
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt --check
|
||||||
|
|
||||||
|
run-release:
|
||||||
|
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET) --release
|
||||||
|
|
||||||
|
build-release:
|
||||||
|
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET) --release
|
||||||
|
|
||||||
|
clean-release:
|
||||||
|
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET) --release
|
||||||
|
|
||||||
|
test-release:
|
||||||
|
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET) --release
|
||||||
|
|
||||||
|
.PHONY: install
|
||||||
|
install:
|
||||||
|
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) install --target $(RUST_TARGET) --path . --no-track --root $(INSTALL_DIR) --force
|
1
user/apps/test-symlink/README.md
Normal file
1
user/apps/test-symlink/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# 测试Symlink系统调用的程序
|
78
user/apps/test-symlink/src/main.rs
Normal file
78
user/apps/test-symlink/src/main.rs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
extern crate libc;
|
||||||
|
use core::ffi::{c_char, c_void};
|
||||||
|
use libc::{mount, umount};
|
||||||
|
use nix::errno::Errno;
|
||||||
|
use std::fs;
|
||||||
|
use std::os::unix::fs::symlink;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
mount_test_ramfs();
|
||||||
|
|
||||||
|
let target = "/mnt/myramfs/target_file.txt";
|
||||||
|
let symlink_path = "/mnt/myramfs/another/symlink_file.txt";
|
||||||
|
let dir = "/mnt/myramfs/another";
|
||||||
|
|
||||||
|
fs::write(target, "This is the content of the target file.")
|
||||||
|
.expect("Failed to create target file");
|
||||||
|
fs::create_dir(dir).expect("Failed to create target dir");
|
||||||
|
|
||||||
|
assert!(Path::new(target).exists(), "Target file was not created");
|
||||||
|
assert!(Path::new(dir).exists(), "Target dir was not created");
|
||||||
|
|
||||||
|
symlink(target, symlink_path).expect("Failed to create symlink");
|
||||||
|
|
||||||
|
assert!(Path::new(symlink_path).exists(), "Symlink was not created");
|
||||||
|
|
||||||
|
let symlink_content = fs::read_link(symlink_path).expect("Failed to read symlink");
|
||||||
|
assert_eq!(
|
||||||
|
symlink_content.display().to_string(),
|
||||||
|
target,
|
||||||
|
"Symlink points to the wrong target"
|
||||||
|
);
|
||||||
|
|
||||||
|
fs::remove_file(symlink_path).expect("Failed to remove symlink");
|
||||||
|
fs::remove_file(target).expect("Failed to remove target file");
|
||||||
|
fs::remove_dir(dir).expect("Failed to remove test_dir");
|
||||||
|
|
||||||
|
assert!(!Path::new(symlink_path).exists(), "Symlink was not deleted");
|
||||||
|
assert!(!Path::new(target).exists(), "Target file was not deleted");
|
||||||
|
assert!(!Path::new(dir).exists(), "Directory was not deleted");
|
||||||
|
|
||||||
|
umount_test_ramfs();
|
||||||
|
|
||||||
|
println!("All tests passed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mount_test_ramfs() {
|
||||||
|
let path = Path::new("mnt/myramfs");
|
||||||
|
let dir = fs::create_dir_all(path);
|
||||||
|
assert!(dir.is_ok(), "mkdir /mnt/myramfs failed");
|
||||||
|
|
||||||
|
let source = b"\0".as_ptr() as *const c_char;
|
||||||
|
let target = b"/mnt/myramfs\0".as_ptr() as *const c_char;
|
||||||
|
let fstype = b"ramfs\0".as_ptr() as *const c_char;
|
||||||
|
// let flags = MS_BIND;
|
||||||
|
let flags = 0;
|
||||||
|
let data = std::ptr::null() as *const c_void;
|
||||||
|
let result = unsafe { mount(source, target, fstype, flags, data) };
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
result,
|
||||||
|
0,
|
||||||
|
"Mount myramfs failed, errno: {}",
|
||||||
|
Errno::last().desc()
|
||||||
|
);
|
||||||
|
println!("Mount myramfs success!");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn umount_test_ramfs() {
|
||||||
|
let path = b"/mnt/myramfs\0".as_ptr() as *const c_char;
|
||||||
|
let result = unsafe { umount(path) };
|
||||||
|
if result != 0 {
|
||||||
|
let err = Errno::last();
|
||||||
|
println!("Errno: {}", err);
|
||||||
|
println!("Infomation: {}", err.desc());
|
||||||
|
}
|
||||||
|
assert_eq!(result, 0, "Umount myramfs failed");
|
||||||
|
}
|
29
user/dadk/config/test_symlink_0_1_0.dadk
Normal file
29
user/dadk/config/test_symlink_0_1_0.dadk
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"name": "test-symlink",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "测试symlink系统调用",
|
||||||
|
"rust_target": "x86_64-unknown-dragonos",
|
||||||
|
"task_type": {
|
||||||
|
"BuildFromSource": {
|
||||||
|
"Local": {
|
||||||
|
"path": "apps/test-symlink"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"depends": [],
|
||||||
|
"build": {
|
||||||
|
"build_command": "make install"
|
||||||
|
},
|
||||||
|
"install": {
|
||||||
|
"in_dragonos_path": "/"
|
||||||
|
},
|
||||||
|
"clean": {
|
||||||
|
"clean_command": "make clean"
|
||||||
|
},
|
||||||
|
"envs": [],
|
||||||
|
"build_once": false,
|
||||||
|
"install_once": false,
|
||||||
|
"target_arch": [
|
||||||
|
"x86_64"
|
||||||
|
]
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user