mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 00:43:24 +00:00
Fix issue about pathname and redefine the Filetype.
Signed-off-by: Zhenchen Wang <m202372036@hust.edu.cn>
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
d8389da797
commit
12b355b701
@ -154,8 +154,6 @@ provided by Linux on x86-64 architecture.
|
||||
| 131 | sigaltstack | ✅ |
|
||||
| 132 | utime | ✅ |
|
||||
| 133 | mknod | ✅ |
|
||||
| 132 | utime | ❌ |
|
||||
| 133 | mknod | ✅ |
|
||||
| 134 | uselib | ❌ |
|
||||
| 135 | personality | ❌ |
|
||||
| 136 | ustat | ❌ |
|
||||
|
@ -48,12 +48,18 @@ pub fn init() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: Implement a more scalable solution for ID-to-device mapping.
|
||||
// Instead of hardcoding every device numbers in this function,
|
||||
// a registration mechanism should be used to allow each driver to
|
||||
// allocate device IDs either statically or dynamically.
|
||||
pub fn get_device(dev: usize) -> Result<Arc<dyn Device>> {
|
||||
if dev == 0 {
|
||||
return_errno_with_message!(Errno::EPERM, "whiteout device")
|
||||
}
|
||||
let major = ((dev >> 32) & 0xffff_f000 | (dev >> 8) & 0x0000_0fff) as u32;
|
||||
let minor = ((dev >> 12) & 0xffff_ff00 | dev & 0x0000_00ff) as u32;
|
||||
|
||||
let devid = DeviceId::from(dev as u64);
|
||||
let major = devid.major();
|
||||
let minor = devid.minor();
|
||||
|
||||
match (major, minor) {
|
||||
(1, 3) => Ok(Arc::new(null::Null)),
|
||||
|
@ -81,6 +81,12 @@ impl From<DeviceId> for u64 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for DeviceId {
|
||||
fn from(raw: u64) -> Self {
|
||||
Self(raw)
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a device node to FS for the device.
|
||||
///
|
||||
/// If the parent path is not existing, `mkdir -p` the parent path.
|
||||
|
@ -318,6 +318,31 @@ impl FsResolver {
|
||||
|
||||
Ok((dir_dentry, base_name))
|
||||
}
|
||||
|
||||
/// The method used to create a new file using pathname.
|
||||
///
|
||||
/// For example, mkdir, mknod, link, and symlink all need to create
|
||||
/// new file and all need to perform unique processing on the last
|
||||
/// component of the path name. It is used to provide a unified
|
||||
/// method for pathname lookup and error handling.
|
||||
///
|
||||
/// is_dir is used to determine whether a directory needs to be created.
|
||||
pub fn lookup_dir_and_new_basename(
|
||||
&self,
|
||||
path: &FsPath,
|
||||
is_dir: bool,
|
||||
) -> Result<(Arc<Dentry>, String)> {
|
||||
let (dir_dentry, filename) = self.lookup_dir_and_base_name_inner(path, false)?;
|
||||
if dir_dentry.lookup(filename.trim_end_matches('/')).is_ok() {
|
||||
return_errno_with_message!(Errno::EEXIST, "file exists");
|
||||
}
|
||||
|
||||
if !is_dir && filename.ends_with('/') {
|
||||
return_errno_with_message!(Errno::ENOENT, "No such file or directory");
|
||||
}
|
||||
|
||||
Ok((dir_dentry, filename))
|
||||
}
|
||||
}
|
||||
|
||||
pub const AT_FDCWD: FileDesc = -100;
|
||||
|
@ -37,8 +37,8 @@ pub fn sys_linkat(
|
||||
return_errno_with_message!(Errno::ENOENT, "oldpath is empty");
|
||||
}
|
||||
let new_path = new_path.to_string_lossy();
|
||||
if new_path.ends_with('/') || new_path.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "newpath is dir or is empty");
|
||||
if new_path.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "newpath is empty");
|
||||
}
|
||||
|
||||
let old_fs_path = FsPath::new(old_dirfd, old_path.as_ref())?;
|
||||
@ -49,7 +49,7 @@ pub fn sys_linkat(
|
||||
} else {
|
||||
fs.lookup_no_follow(&old_fs_path)?
|
||||
};
|
||||
let (new_dir_dentry, new_name) = fs.lookup_dir_and_base_name(&new_fs_path)?;
|
||||
let (new_dir_dentry, new_name) = fs.lookup_dir_and_new_basename(&new_fs_path, false)?;
|
||||
(old_dentry, new_dir_dentry, new_name)
|
||||
};
|
||||
|
||||
|
@ -23,7 +23,10 @@ pub fn sys_mkdirat(dirfd: FileDesc, path_addr: Vaddr, mode: u16) -> Result<Sysca
|
||||
return_errno_with_message!(Errno::ENOENT, "path is empty");
|
||||
}
|
||||
let fs_path = FsPath::new(dirfd, path.as_ref())?;
|
||||
current.fs().read().lookup_dir_and_base_name(&fs_path)?
|
||||
current
|
||||
.fs()
|
||||
.read()
|
||||
.lookup_dir_and_new_basename(&fs_path, true)?
|
||||
};
|
||||
|
||||
let inode_mode = {
|
||||
|
@ -9,7 +9,7 @@ use crate::{
|
||||
utils::{InodeMode, InodeType},
|
||||
},
|
||||
prelude::*,
|
||||
syscall::{constants::MAX_FILENAME_LEN, stat::FileTypeFlags},
|
||||
syscall::{constants::MAX_FILENAME_LEN, stat::FileType},
|
||||
util::read_cstring_from_user,
|
||||
};
|
||||
|
||||
@ -25,7 +25,7 @@ pub fn sys_mknodat(
|
||||
let mask_mode = mode & !current.umask().read().get();
|
||||
InodeMode::from_bits_truncate(mask_mode)
|
||||
};
|
||||
let file_type = FileTypeFlags::from_bits_truncate(mode);
|
||||
let file_type = FileType::from_mode(mode);
|
||||
debug!(
|
||||
"dirfd = {}, path = {:?}, inode_mode = {:?}, file_type = {:?}, dev = {}",
|
||||
dirfd, path, inode_mode, file_type, dev
|
||||
@ -37,21 +37,24 @@ pub fn sys_mknodat(
|
||||
return_errno_with_message!(Errno::ENOENT, "path is empty");
|
||||
}
|
||||
let fs_path = FsPath::new(dirfd, path.as_ref())?;
|
||||
current.fs().read().lookup_dir_and_base_name(&fs_path)?
|
||||
current
|
||||
.fs()
|
||||
.read()
|
||||
.lookup_dir_and_new_basename(&fs_path, false)?
|
||||
};
|
||||
|
||||
if file_type.contains(FileTypeFlags::S_IFREG) || file_type.is_empty() {
|
||||
let _ = dir_dentry.new_fs_child(name.trim_end_matches('/'), InodeType::File, inode_mode)?;
|
||||
} else if file_type.contains(FileTypeFlags::S_IFCHR)
|
||||
|| file_type.contains(FileTypeFlags::S_IFBLK)
|
||||
{
|
||||
let _ = dir_dentry.mknod(name.trim_end_matches('/'), inode_mode, get_device(dev)?)?;
|
||||
} else if file_type.contains(FileTypeFlags::S_IFIFO)
|
||||
|| file_type.contains(FileTypeFlags::S_IFSOCK)
|
||||
{
|
||||
return_errno_with_message!(Errno::EINVAL, "unsupported file type flag");
|
||||
} else {
|
||||
return_errno_with_message!(Errno::EPERM, "unimplemented types");
|
||||
match file_type {
|
||||
FileType::RegularFile => {
|
||||
let _ = dir_dentry.new_fs_child(&name, InodeType::File, inode_mode)?;
|
||||
}
|
||||
FileType::CharacterDevice | FileType::BlockDevice => {
|
||||
let device_inode = get_device(dev)?;
|
||||
let _ = dir_dentry.mknod(&name, inode_mode, device_inode)?;
|
||||
}
|
||||
FileType::Fifo | FileType::Socket => {
|
||||
return_errno_with_message!(Errno::EINVAL, "unsupported file types")
|
||||
}
|
||||
_ => return_errno_with_message!(Errno::EPERM, "unimplemented file types"),
|
||||
}
|
||||
|
||||
Ok(SyscallReturn::Return(0))
|
||||
|
@ -165,14 +165,14 @@ fn get_fs(fs_type: CString, devname: CString) -> Result<Arc<dyn FileSystem>> {
|
||||
|
||||
bitflags! {
|
||||
struct MountFlags: u32 {
|
||||
const MS_RDONLY = 1 << 0; // Mount read-only */
|
||||
const MS_NOSUID = 1 << 1; // Ignore suid and sgid bits */
|
||||
const MS_NODEV = 1 << 2; // Disallow access to device special files */
|
||||
const MS_NOEXEC = 1 << 3; // Disallow program execution */
|
||||
const MS_SYNCHRONOUS = 1 << 4; // Writes are synced at once
|
||||
const MS_RDONLY = 1 << 0; // Mount read-only.
|
||||
const MS_NOSUID = 1 << 1; // Ignore suid and sgid bits.
|
||||
const MS_NODEV = 1 << 2; // Disallow access to device special files.
|
||||
const MS_NOEXEC = 1 << 3; // Disallow program execution.
|
||||
const MS_SYNCHRONOUS = 1 << 4; // Writes are synced at once.
|
||||
const MS_REMOUNT = 1 << 5; // Alter flags of a mounted FS.
|
||||
const MS_MANDLOCK = 1 << 6; // Allow mandatory locks on an FS.
|
||||
const MS_DIRSYNC = 1 << 7; // Directory modifications are synchronous
|
||||
const MS_DIRSYNC = 1 << 7; // Directory modifications are synchronous.
|
||||
const MS_NOSYMFOLLOW = 1 << 8; // Do not follow symlinks.
|
||||
const MS_NOATIME = 1 << 10; // Do not update access times.
|
||||
const MS_NODIRATIME = 1 << 11; // Do not update directory access times.
|
||||
|
@ -77,17 +77,35 @@ pub fn sys_fstatat(
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// File type.
|
||||
pub struct FileTypeFlags: u16 {
|
||||
const S_IFMT = 0o170000; // File type mask.
|
||||
const S_IFSOCK = 0o140000; // Socket.
|
||||
const S_IFCHR = 0o020000; // Character device.
|
||||
const S_IFBLK = 0o060000; // Block device.
|
||||
const S_IFDIR = 0o040000; // Directory.
|
||||
const S_IFIFO = 0o010000; // FIFO (named pipe).
|
||||
const S_IFREG = 0o100000; // Regular file.
|
||||
const S_IFLNK = 0o120000; // Symbolic link.
|
||||
/// File type mask.
|
||||
const S_IFMT: u16 = 0o170000;
|
||||
|
||||
/// Enum representing different file types.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum FileType {
|
||||
Socket,
|
||||
CharacterDevice,
|
||||
BlockDevice,
|
||||
Directory,
|
||||
Fifo,
|
||||
RegularFile,
|
||||
Symlink,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl FileType {
|
||||
/// Extract the file type from the mode.
|
||||
pub fn from_mode(mode: u16) -> FileType {
|
||||
match mode & S_IFMT {
|
||||
0o140000 => FileType::Socket, // Socket.
|
||||
0o020000 => FileType::CharacterDevice, // Character device.
|
||||
0o060000 => FileType::BlockDevice, // Block device.
|
||||
0o040000 => FileType::Directory, // Directory.
|
||||
0o010000 => FileType::Fifo, // FIFO (named pipe).
|
||||
0 | 0o100000 => FileType::RegularFile, // Regular file.
|
||||
0o120000 => FileType::Symlink, // Symbolic link.
|
||||
_ => FileType::Unknown, // Unkonwn file type.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,11 +34,11 @@ pub fn sys_symlinkat(
|
||||
if linkpath.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "linkpath is empty");
|
||||
}
|
||||
if linkpath.ends_with('/') {
|
||||
return_errno_with_message!(Errno::EISDIR, "linkpath is dir");
|
||||
}
|
||||
let fs_path = FsPath::new(dirfd, linkpath.as_ref())?;
|
||||
current.fs().read().lookup_dir_and_base_name(&fs_path)?
|
||||
current
|
||||
.fs()
|
||||
.read()
|
||||
.lookup_dir_and_new_basename(&fs_path, false)?
|
||||
};
|
||||
|
||||
let new_dentry = dir_dentry.new_fs_child(
|
||||
|
Reference in New Issue
Block a user