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 | ✅ |
|
| 131 | sigaltstack | ✅ |
|
||||||
| 132 | utime | ✅ |
|
| 132 | utime | ✅ |
|
||||||
| 133 | mknod | ✅ |
|
| 133 | mknod | ✅ |
|
||||||
| 132 | utime | ❌ |
|
|
||||||
| 133 | mknod | ✅ |
|
|
||||||
| 134 | uselib | ❌ |
|
| 134 | uselib | ❌ |
|
||||||
| 135 | personality | ❌ |
|
| 135 | personality | ❌ |
|
||||||
| 136 | ustat | ❌ |
|
| 136 | ustat | ❌ |
|
||||||
|
@ -48,12 +48,18 @@ pub fn init() -> Result<()> {
|
|||||||
Ok(())
|
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>> {
|
pub fn get_device(dev: usize) -> Result<Arc<dyn Device>> {
|
||||||
if dev == 0 {
|
if dev == 0 {
|
||||||
return_errno_with_message!(Errno::EPERM, "whiteout device")
|
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) {
|
match (major, minor) {
|
||||||
(1, 3) => Ok(Arc::new(null::Null)),
|
(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.
|
/// Add a device node to FS for the device.
|
||||||
///
|
///
|
||||||
/// If the parent path is not existing, `mkdir -p` the parent path.
|
/// If the parent path is not existing, `mkdir -p` the parent path.
|
||||||
|
@ -318,6 +318,31 @@ impl FsResolver {
|
|||||||
|
|
||||||
Ok((dir_dentry, base_name))
|
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;
|
pub const AT_FDCWD: FileDesc = -100;
|
||||||
|
@ -37,8 +37,8 @@ pub fn sys_linkat(
|
|||||||
return_errno_with_message!(Errno::ENOENT, "oldpath is empty");
|
return_errno_with_message!(Errno::ENOENT, "oldpath is empty");
|
||||||
}
|
}
|
||||||
let new_path = new_path.to_string_lossy();
|
let new_path = new_path.to_string_lossy();
|
||||||
if new_path.ends_with('/') || new_path.is_empty() {
|
if new_path.is_empty() {
|
||||||
return_errno_with_message!(Errno::ENOENT, "newpath is dir or is empty");
|
return_errno_with_message!(Errno::ENOENT, "newpath is empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
let old_fs_path = FsPath::new(old_dirfd, old_path.as_ref())?;
|
let old_fs_path = FsPath::new(old_dirfd, old_path.as_ref())?;
|
||||||
@ -49,7 +49,7 @@ pub fn sys_linkat(
|
|||||||
} else {
|
} else {
|
||||||
fs.lookup_no_follow(&old_fs_path)?
|
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)
|
(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");
|
return_errno_with_message!(Errno::ENOENT, "path is empty");
|
||||||
}
|
}
|
||||||
let fs_path = FsPath::new(dirfd, path.as_ref())?;
|
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 = {
|
let inode_mode = {
|
||||||
|
@ -9,7 +9,7 @@ use crate::{
|
|||||||
utils::{InodeMode, InodeType},
|
utils::{InodeMode, InodeType},
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
syscall::{constants::MAX_FILENAME_LEN, stat::FileTypeFlags},
|
syscall::{constants::MAX_FILENAME_LEN, stat::FileType},
|
||||||
util::read_cstring_from_user,
|
util::read_cstring_from_user,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ pub fn sys_mknodat(
|
|||||||
let mask_mode = mode & !current.umask().read().get();
|
let mask_mode = mode & !current.umask().read().get();
|
||||||
InodeMode::from_bits_truncate(mask_mode)
|
InodeMode::from_bits_truncate(mask_mode)
|
||||||
};
|
};
|
||||||
let file_type = FileTypeFlags::from_bits_truncate(mode);
|
let file_type = FileType::from_mode(mode);
|
||||||
debug!(
|
debug!(
|
||||||
"dirfd = {}, path = {:?}, inode_mode = {:?}, file_type = {:?}, dev = {}",
|
"dirfd = {}, path = {:?}, inode_mode = {:?}, file_type = {:?}, dev = {}",
|
||||||
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");
|
return_errno_with_message!(Errno::ENOENT, "path is empty");
|
||||||
}
|
}
|
||||||
let fs_path = FsPath::new(dirfd, path.as_ref())?;
|
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() {
|
match file_type {
|
||||||
let _ = dir_dentry.new_fs_child(name.trim_end_matches('/'), InodeType::File, inode_mode)?;
|
FileType::RegularFile => {
|
||||||
} else if file_type.contains(FileTypeFlags::S_IFCHR)
|
let _ = dir_dentry.new_fs_child(&name, InodeType::File, inode_mode)?;
|
||||||
|| file_type.contains(FileTypeFlags::S_IFBLK)
|
}
|
||||||
{
|
FileType::CharacterDevice | FileType::BlockDevice => {
|
||||||
let _ = dir_dentry.mknod(name.trim_end_matches('/'), inode_mode, get_device(dev)?)?;
|
let device_inode = get_device(dev)?;
|
||||||
} else if file_type.contains(FileTypeFlags::S_IFIFO)
|
let _ = dir_dentry.mknod(&name, inode_mode, device_inode)?;
|
||||||
|| file_type.contains(FileTypeFlags::S_IFSOCK)
|
}
|
||||||
{
|
FileType::Fifo | FileType::Socket => {
|
||||||
return_errno_with_message!(Errno::EINVAL, "unsupported file type flag");
|
return_errno_with_message!(Errno::EINVAL, "unsupported file types")
|
||||||
} else {
|
}
|
||||||
return_errno_with_message!(Errno::EPERM, "unimplemented types");
|
_ => return_errno_with_message!(Errno::EPERM, "unimplemented file types"),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(SyscallReturn::Return(0))
|
Ok(SyscallReturn::Return(0))
|
||||||
|
@ -165,14 +165,14 @@ fn get_fs(fs_type: CString, devname: CString) -> Result<Arc<dyn FileSystem>> {
|
|||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
struct MountFlags: u32 {
|
struct MountFlags: u32 {
|
||||||
const MS_RDONLY = 1 << 0; // Mount read-only */
|
const MS_RDONLY = 1 << 0; // Mount read-only.
|
||||||
const MS_NOSUID = 1 << 1; // Ignore suid and sgid bits */
|
const MS_NOSUID = 1 << 1; // Ignore suid and sgid bits.
|
||||||
const MS_NODEV = 1 << 2; // Disallow access to device special files */
|
const MS_NODEV = 1 << 2; // Disallow access to device special files.
|
||||||
const MS_NOEXEC = 1 << 3; // Disallow program execution */
|
const MS_NOEXEC = 1 << 3; // Disallow program execution.
|
||||||
const MS_SYNCHRONOUS = 1 << 4; // Writes are synced at once
|
const MS_SYNCHRONOUS = 1 << 4; // Writes are synced at once.
|
||||||
const MS_REMOUNT = 1 << 5; // Alter flags of a mounted FS.
|
const MS_REMOUNT = 1 << 5; // Alter flags of a mounted FS.
|
||||||
const MS_MANDLOCK = 1 << 6; // Allow mandatory locks on an 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_NOSYMFOLLOW = 1 << 8; // Do not follow symlinks.
|
||||||
const MS_NOATIME = 1 << 10; // Do not update access times.
|
const MS_NOATIME = 1 << 10; // Do not update access times.
|
||||||
const MS_NODIRATIME = 1 << 11; // Do not update directory 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))
|
Ok(SyscallReturn::Return(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
/// File type mask.
|
||||||
/// File type.
|
const S_IFMT: u16 = 0o170000;
|
||||||
pub struct FileTypeFlags: u16 {
|
|
||||||
const S_IFMT = 0o170000; // File type mask.
|
/// Enum representing different file types.
|
||||||
const S_IFSOCK = 0o140000; // Socket.
|
#[derive(Debug, PartialEq)]
|
||||||
const S_IFCHR = 0o020000; // Character device.
|
pub enum FileType {
|
||||||
const S_IFBLK = 0o060000; // Block device.
|
Socket,
|
||||||
const S_IFDIR = 0o040000; // Directory.
|
CharacterDevice,
|
||||||
const S_IFIFO = 0o010000; // FIFO (named pipe).
|
BlockDevice,
|
||||||
const S_IFREG = 0o100000; // Regular file.
|
Directory,
|
||||||
const S_IFLNK = 0o120000; // Symbolic link.
|
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() {
|
if linkpath.is_empty() {
|
||||||
return_errno_with_message!(Errno::ENOENT, "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())?;
|
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(
|
let new_dentry = dir_dentry.new_fs_child(
|
||||||
|
Reference in New Issue
Block a user