From 42cf17838294e317fb9bdd791026da610245fe31 Mon Sep 17 00:00:00 2001 From: Lzzzt Date: Thu, 6 Jun 2024 11:03:28 +0800 Subject: [PATCH 01/14] feat(op, fs): :sparkles: Intergated `statx` into monoio --- monoio/src/driver/op.rs | 1 + monoio/src/driver/op/statx.rs | 145 +++++++++++ monoio/src/fs/file.rs | 25 ++ monoio/src/fs/file_type.rs | 63 +++++ monoio/src/fs/metadata.rs | 457 ++++++++++++++++++++++++++++++++++ monoio/src/fs/mod.rs | 9 + monoio/src/fs/permissions.rs | 69 +++++ monoio/tests/fs_metadata.rs | 80 ++++++ 8 files changed, 849 insertions(+) create mode 100644 monoio/src/driver/op/statx.rs create mode 100644 monoio/src/fs/file_type.rs create mode 100644 monoio/src/fs/metadata.rs create mode 100644 monoio/src/fs/permissions.rs create mode 100644 monoio/tests/fs_metadata.rs diff --git a/monoio/src/driver/op.rs b/monoio/src/driver/op.rs index 3a1e60ef..aa82e479 100644 --- a/monoio/src/driver/op.rs +++ b/monoio/src/driver/op.rs @@ -17,6 +17,7 @@ mod poll; mod read; mod recv; mod send; +mod statx; mod write; #[cfg(all(target_os = "linux", feature = "splice"))] diff --git a/monoio/src/driver/op/statx.rs b/monoio/src/driver/op/statx.rs new file mode 100644 index 00000000..a0b8a4c8 --- /dev/null +++ b/monoio/src/driver/op/statx.rs @@ -0,0 +1,145 @@ +#[cfg(unix)] +use std::os::fd::AsRawFd; +use std::{ffi::CString, mem::MaybeUninit, path::Path}; + +#[cfg(all(target_os = "linux", feature = "iouring"))] +use io_uring::{opcode, types}; +#[cfg(target_os = "linux")] +use libc::statx; + +use super::{Op, OpAble}; +#[cfg(any(feature = "legacy", feature = "poll-io"))] +use crate::driver::ready::Direction; +use crate::driver::{shared_fd::SharedFd, util::cstr}; + +#[derive(Debug)] +pub(crate) struct Statx { + inner: T, + flags: i32, + statx_buf: Box>, +} + +type FdStatx = Statx; + +impl Op { + /// submit a statx operation + pub(crate) fn statx_using_fd(fd: &SharedFd, flags: i32) -> std::io::Result { + Op::submit_with(Statx { + inner: fd.clone(), + flags, + statx_buf: Box::new(MaybeUninit::uninit()), + }) + } + + pub(crate) async fn statx_result(self) -> std::io::Result { + let complete = self.await; + complete.meta.result?; + + Ok(unsafe { MaybeUninit::assume_init(*complete.data.statx_buf) }) + } +} + +impl OpAble for FdStatx { + #[cfg(all(target_os = "linux", feature = "iouring"))] + fn uring_op(&mut self) -> io_uring::squeue::Entry { + let statxbuf = self.statx_buf.as_mut_ptr() as *mut _; + + opcode::Statx::new(types::Fd(self.inner.as_raw_fd()), c"".as_ptr(), statxbuf) + .flags(libc::AT_EMPTY_PATH | libc::AT_STATX_SYNC_AS_STAT) + .mask(libc::STATX_ALL) + .build() + } + + #[cfg(any(feature = "legacy", feature = "poll-io"))] + fn legacy_interest(&self) -> Option<(crate::driver::ready::Direction, usize)> { + self.inner + .registered_index() + .map(|idx| (Direction::Read, idx)) + } + + #[cfg(all(any(feature = "legacy", feature = "poll-io"), target_os = "linux"))] + fn legacy_call(&mut self) -> std::io::Result { + use std::os::fd::AsRawFd; + + use crate::syscall_u32; + + syscall_u32!(statx( + self.inner.as_raw_fd(), + c"".as_ptr(), + libc::AT_EMPTY_PATH, + libc::STATX_ALL, + self.statx_buf.as_mut_ptr() as *mut _ + )) + } + + #[cfg(all(any(feature = "legacy", feature = "poll-io"), windows))] + fn legacy_call(&mut self) -> std::io::Result { + unimplemented!() + } + + #[cfg(all(any(feature = "legacy", feature = "poll-io"), target_os = "macos"))] + fn legacy_call(&mut self) -> std::io::Result { + unimplemented!() + } +} + +type PathStatx = Statx; + +impl Op { + /// submit a statx operation + pub(crate) fn statx_using_path>(path: P, flags: i32) -> std::io::Result { + let path = cstr(path.as_ref())?; + Op::submit_with(Statx { + inner: path, + flags, + statx_buf: Box::new(MaybeUninit::uninit()), + }) + } + + pub(crate) async fn statx_result(self) -> std::io::Result { + let complete = self.await; + complete.meta.result?; + + Ok(unsafe { MaybeUninit::assume_init(*complete.data.statx_buf) }) + } +} + +impl OpAble for PathStatx { + #[cfg(all(target_os = "linux", feature = "iouring"))] + fn uring_op(&mut self) -> io_uring::squeue::Entry { + let statxbuf = self.statx_buf.as_mut_ptr() as *mut _; + + opcode::Statx::new(types::Fd(libc::AT_FDCWD), self.inner.as_ptr(), statxbuf) + .flags(self.flags) + .mask(libc::STATX_ALL) + .build() + } + + #[cfg(any(feature = "legacy", feature = "poll-io"))] + fn legacy_interest(&self) -> Option<(crate::driver::ready::Direction, usize)> { + None + } + + #[cfg(all(any(feature = "legacy", feature = "poll-io"), target_os = "linux"))] + fn legacy_call(&mut self) -> std::io::Result { + use crate::syscall_u32; + + syscall_u32!(statx( + libc::AT_FDCWD, + self.inner.as_ptr(), + self.flags, + libc::STATX_ALL, + self.statx_buf.as_mut_ptr() as *mut _ + )) + } + + #[cfg(all(any(feature = "legacy", feature = "poll-io"), windows))] + fn legacy_call(&mut self) -> std::io::Result { + unimplemented!() + } + + #[cfg(all(any(feature = "legacy", feature = "poll-io"), target_os = "macos"))] + fn legacy_call(&mut self) -> std::io::Result { + unimplemented!() + } +} diff --git a/monoio/src/fs/file.rs b/monoio/src/fs/file.rs index a354eb93..697d07a0 100644 --- a/monoio/src/fs/file.rs +++ b/monoio/src/fs/file.rs @@ -10,6 +10,8 @@ use std::{ }; use std::{io, path::Path}; +#[cfg(unix)] +use super::{metadata::FileAttr, Metadata}; use crate::{ buf::{IoBuf, IoBufMut}, driver::{op::Op, shared_fd::SharedFd}, @@ -498,6 +500,29 @@ impl File { self.fd.close().await; Ok(()) } + + /// Queries metadata about the underlying file. + /// + /// # Examples + /// + /// ```no_run + /// use monoio::fs::File; + /// + /// #[monoio::main] + /// async fn main() -> std::io::Result<()> { + /// let mut f = File::open("foo.txt").await?; + /// let metadata = f.metadata().await?; + /// Ok(()) + /// } + /// ``` + #[cfg(target_os = "linux")] + pub async fn metadata(&self) -> io::Result { + let flags = libc::AT_STATX_SYNC_AS_STAT | libc::AT_EMPTY_PATH; + + let op = Op::statx_using_fd(&self.fd, flags).unwrap(); + + op.statx_result().await.map(FileAttr::from).map(Metadata) + } } #[cfg(unix)] diff --git a/monoio/src/fs/file_type.rs b/monoio/src/fs/file_type.rs new file mode 100644 index 00000000..a5a8884c --- /dev/null +++ b/monoio/src/fs/file_type.rs @@ -0,0 +1,63 @@ +use std::{fmt::Debug, os::unix::fs::FileTypeExt}; + +use libc::mode_t; + +/// A structure representing a type of file with accessors for each file type. +#[derive(PartialEq, Eq, Clone, Copy, Hash)] +pub struct FileType { + pub(crate) mode: mode_t, +} + +#[cfg(unix)] +impl FileType { + /// Returns `true` if this file type is a directory. + pub fn is_dir(&self) -> bool { + self.is(libc::S_IFDIR) + } + + /// Returns `true` if this file type is a regular file. + pub fn is_file(&self) -> bool { + self.is(libc::S_IFREG) + } + + /// Returns `true` if this file type is a symbolic link. + pub fn is_symlink(&self) -> bool { + self.is(libc::S_IFLNK) + } + + pub(crate) fn is(&self, mode: mode_t) -> bool { + self.masked() == mode + } + + fn masked(&self) -> mode_t { + self.mode & libc::S_IFMT + } +} + +impl FileTypeExt for FileType { + fn is_block_device(&self) -> bool { + self.is(libc::S_IFBLK) + } + + fn is_char_device(&self) -> bool { + self.is(libc::S_IFCHR) + } + + fn is_fifo(&self) -> bool { + self.is(libc::S_IFIFO) + } + + fn is_socket(&self) -> bool { + self.is(libc::S_IFSOCK) + } +} + +impl Debug for FileType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("FileType") + .field("is_file", &self.is_file()) + .field("is_dir", &self.is_dir()) + .field("is_symlink", &self.is_symlink()) + .finish_non_exhaustive() + } +} diff --git a/monoio/src/fs/metadata.rs b/monoio/src/fs/metadata.rs new file mode 100644 index 00000000..a6b02cb3 --- /dev/null +++ b/monoio/src/fs/metadata.rs @@ -0,0 +1,457 @@ +#[cfg(unix)] +use std::os::unix::fs::MetadataExt; +use std::{path::Path, time::SystemTime}; + +#[cfg(target_os = "linux")] +use libc::statx; +#[cfg(unix)] +use libc::{mode_t, stat64}; + +use super::{ + file_type::FileType, + permissions::{FilePermissions, Permissions}, +}; +use crate::driver::op::Op; + +/// File attributes, not platform-specific. +/// Current implementation is only for unix. +#[cfg(unix)] +pub(crate) struct FileAttr { + stat: stat64, + #[cfg(target_os = "linux")] + statx_extra_fields: Option, +} + +#[cfg(unix)] +impl FileAttr { + fn size(&self) -> u64 { + self.stat.st_size as u64 + } + + fn perm(&self) -> FilePermissions { + FilePermissions { + mode: (self.stat.st_mode as mode_t), + } + } + + fn file_type(&self) -> FileType { + FileType { + mode: self.stat.st_mode as mode_t, + } + } +} + +/// Extra fields that are available in `statx` struct. +#[cfg(target_os = "linux")] +pub(crate) struct StatxExtraFields { + stx_mask: u32, + stx_btime: libc::statx_timestamp, +} + +/// Convert a `statx` struct to not platform-specific `FileAttr`. +/// Current implementation is only for Linux. +#[cfg(target_os = "linux")] +impl From for FileAttr { + fn from(buf: statx) -> Self { + let mut stat: stat64 = unsafe { std::mem::zeroed() }; + + stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor) as _; + stat.st_ino = buf.stx_ino as libc::ino64_t; + stat.st_nlink = buf.stx_nlink as libc::nlink_t; + stat.st_mode = buf.stx_mode as libc::mode_t; + stat.st_uid = buf.stx_uid as libc::uid_t; + stat.st_gid = buf.stx_gid as libc::gid_t; + stat.st_rdev = libc::makedev(buf.stx_rdev_major, buf.stx_rdev_minor) as _; + stat.st_size = buf.stx_size as libc::off64_t; + stat.st_blksize = buf.stx_blksize as libc::blksize_t; + stat.st_blocks = buf.stx_blocks as libc::blkcnt64_t; + stat.st_atime = buf.stx_atime.tv_sec as libc::time_t; + // `i64` on gnu-x86_64-x32, `c_ulong` otherwise. + stat.st_atime_nsec = buf.stx_atime.tv_nsec as _; + stat.st_mtime = buf.stx_mtime.tv_sec as libc::time_t; + stat.st_mtime_nsec = buf.stx_mtime.tv_nsec as _; + stat.st_ctime = buf.stx_ctime.tv_sec as libc::time_t; + stat.st_ctime_nsec = buf.stx_ctime.tv_nsec as _; + + let extra = StatxExtraFields { + stx_mask: buf.stx_mask, + stx_btime: buf.stx_btime, + }; + + Self { + stat, + statx_extra_fields: Some(extra), + } + } +} + +/// Metadata information about a file. +/// +/// This structure is returned from the [`metadata`] or +/// [`symlink_metadata`] function or method and represents known +/// metadata about a file such as its permissions, size, modification +/// times, etc. +#[cfg(unix)] +pub struct Metadata(pub(crate) FileAttr); + +impl Metadata { + /// Returns `true` if this metadata is for a directory. + /// + /// # Examples + /// + /// ```no_run + /// use monoio::fs; + /// + /// #[monoio::main] + /// async fn main() -> std::io::Result<()> { + /// let metadata = fs::metadata("path/to/dir").await?; + /// + /// println!("{:?}", metadata.is_dir()); + /// Ok(()) + /// } + /// ``` + pub fn is_dir(&self) -> bool { + self.0.stat.st_mode & libc::S_IFMT == libc::S_IFDIR + } + + /// Returns `true` if this metadata is for a regular file. + /// + /// # Examples + /// + /// ```no_run + /// use monoio::fs; + /// + /// #[monoio::main] + /// async fn main() -> std::io::Result<()> { + /// let metadata = fs::metadata("foo.txt").await?; + /// + /// println!("{:?}", metadata.is_file()); + /// Ok(()) + /// } + /// ``` + pub fn is_file(&self) -> bool { + self.0.stat.st_mode & libc::S_IFMT == libc::S_IFREG + } + + /// Returns `true` if this metadata is for a symbolic link. + /// + /// # Examples + /// + /// ```no_run + /// use monoio::fs; + /// + /// #[monoio::main] + /// async fn main() -> std::io::Result<()> { + /// let metadata = fs::metadata("foo.txt").await?; + /// + /// println!("{:?}", metadata.is_symlink()); + /// Ok(()) + /// } + /// ``` + pub fn is_symlink(&self) -> bool { + self.0.stat.st_mode & libc::S_IFMT == libc::S_IFLNK + } + + /// Returns the size of the file, in bytes, this metadata is for. + /// + /// # Examples + /// + /// ```no_run + /// use monoio::fs; + /// + /// #[monoio::main] + /// async fn main() -> std::io::Result<()> { + /// let metadata = fs::metadata("foo.txt").await?; + /// + /// println!("{:?}", metadata.len()); + /// Ok(()) + /// } + /// ``` + #[allow(clippy::len_without_is_empty)] + pub fn len(&self) -> u64 { + self.0.size() + } + + /// Returns the last modification time listed in this metadata. + /// + /// # Examples + /// + /// ```no_run + /// use monoio::fs; + /// + /// #[monoio::main] + /// async fn main() -> std::io::Result<()> { + /// let metadata = fs::metadata("foo.txt").await?; + /// + /// println!("{:?}", metadata.modified()); + /// Ok(()) + /// } + pub fn modified(&self) -> std::io::Result { + let mtime = self.0.stat.st_mtime; + let mtime_nsec = self.0.stat.st_mtime_nsec as u32; + + Ok(SystemTime::UNIX_EPOCH + std::time::Duration::new(mtime as u64, mtime_nsec)) + } + + /// Returns the last access time listed in this metadata. + /// + /// # Examples + /// + /// ```no_run + /// use monoio::fs; + /// + /// #[monoio::main] + /// async fn main() -> std::io::Result<()> { + /// let metadata = fs::metadata("foo.txt").await?; + /// + /// println!("{:?}", metadata.accessed()); + /// Ok(()) + /// } + /// ``` + pub fn accessed(&self) -> std::io::Result { + let atime = self.0.stat.st_atime; + let atime_nsec = self.0.stat.st_atime_nsec as u32; + + Ok(SystemTime::UNIX_EPOCH + std::time::Duration::new(atime as u64, atime_nsec)) + } + + /// Returns the creation time listed in this metadata. + /// + /// # Examples + /// + /// ```no_run + /// use monoio::fs; + /// + /// #[monoio::main] + /// async fn main() -> std::io::Result<()> { + /// let metadata = fs::metadata("foo.txt").await?; + /// + /// println!("{:?}", metadata.created()); + /// Ok(()) + /// } + /// ``` + #[cfg(target_os = "linux")] + pub fn created(&self) -> std::io::Result { + if let Some(extra) = self.0.statx_extra_fields.as_ref() { + return if extra.stx_mask & libc::STATX_BTIME != 0 { + let btime = extra.stx_btime.tv_sec; + let btime_nsec = extra.stx_btime.tv_nsec; + + Ok(SystemTime::UNIX_EPOCH + std::time::Duration::new(btime as u64, btime_nsec)) + } else { + Err(std::io::Error::new( + std::io::ErrorKind::Other, + "Creation time is not available", + )) + }; + } + + Err(std::io::Error::new( + std::io::ErrorKind::Other, + "Creation time is not available", + )) + } + + /// Returns the permissions of the file this metadata is for. + /// + /// # Examples + /// + /// ```no_run + /// use monoio::fs; + /// + /// #[monoio::main] + /// async fn main() -> std::io::Result<()> { + /// let metadata = fs::metadata("foo.txt").await?; + /// + /// println!("{:?}", metadata.permissions()); + /// Ok(()) + /// } + /// ``` + #[cfg(unix)] + pub fn permissions(&self) -> Permissions { + Permissions(self.0.perm()) + } + + /// Returns the file type for this metadata. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// + /// #[monoio::main] + /// fn main() -> std::io::Result<()> { + /// let metadata = fs::metadata("foo.txt").await?; + /// + /// println!("{:?}", metadata.file_type()); + /// Ok(()) + /// } + /// ``` + #[cfg(unix)] + pub fn file_type(&self) -> FileType { + self.0.file_type() + } +} + +impl std::fmt::Debug for Metadata { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut debug = f.debug_struct("Metadata"); + // debug.field("file_type", &self.file_type()); + debug.field("permissions", &self.permissions()); + debug.field("len", &self.len()); + if let Ok(modified) = self.modified() { + debug.field("modified", &modified); + } + if let Ok(accessed) = self.accessed() { + debug.field("accessed", &accessed); + } + if let Ok(created) = self.created() { + debug.field("created", &created); + } + debug.finish_non_exhaustive() + } +} + +#[cfg(unix)] +impl MetadataExt for Metadata { + fn dev(&self) -> u64 { + self.0.stat.st_dev + } + + fn ino(&self) -> u64 { + self.0.stat.st_ino + } + + fn mode(&self) -> u32 { + self.0.stat.st_mode + } + + fn nlink(&self) -> u64 { + self.0.stat.st_nlink + } + + fn uid(&self) -> u32 { + self.0.stat.st_uid + } + + fn gid(&self) -> u32 { + self.0.stat.st_gid + } + + fn rdev(&self) -> u64 { + self.0.stat.st_rdev + } + + fn size(&self) -> u64 { + self.0.stat.st_size as u64 + } + + fn atime(&self) -> i64 { + self.0.stat.st_atime + } + + fn atime_nsec(&self) -> i64 { + self.0.stat.st_atime_nsec + } + + fn mtime(&self) -> i64 { + self.0.stat.st_mtime + } + + fn mtime_nsec(&self) -> i64 { + self.0.stat.st_mtime_nsec + } + + fn ctime(&self) -> i64 { + self.0.stat.st_ctime + } + + fn ctime_nsec(&self) -> i64 { + self.0.stat.st_ctime_nsec + } + + fn blksize(&self) -> u64 { + self.0.stat.st_blksize as u64 + } + + fn blocks(&self) -> u64 { + self.0.stat.st_blocks as u64 + } +} + +/// Given a path, query the file system to get information about a file, +/// directory, etc. +/// +/// This function will traverse symbolic links to query information about the +/// destination file. +/// +/// # Platform-specific behavior +/// +/// current implementation is only for Linux. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not +/// limited to just these cases: +/// +/// * The user lacks permissions to perform `metadata` call on `path`. +/// * execute(search) permission is required on all of the directories in path that lead to the +/// file. +/// * `path` does not exist. +/// +/// # Examples +/// +/// ```rust,no_run +/// use monoio::fs; +/// +/// #[monoio::main] +/// async fn main() -> std::io::Result<()> { +/// let attr = fs::metadata("/some/file/path.txt").await?; +/// // inspect attr ... +/// Ok(()) +/// } +/// ``` +#[cfg(target_os = "linux")] +pub async fn metadata>(path: P) -> std::io::Result { + let flags = libc::AT_STATX_SYNC_AS_STAT; + + let op = Op::statx_using_path(path, flags).unwrap(); + + op.statx_result().await.map(FileAttr::from).map(Metadata) +} + +/// Query the metadata about a file without following symlinks. +/// +/// # Platform-specific behavior +/// +/// This function currently corresponds to the `lstat` function on linux +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not +/// limited to just these cases: +/// +/// * The user lacks permissions to perform `metadata` call on `path`. +/// * execute(search) permission is required on all of the directories in path that lead to the +/// file. +/// * `path` does not exist. +/// +/// # Examples +/// ```rust,no_run +/// use monoio::fs; +/// +/// #[monoio::main] +/// async fn main() -> std::io::Result<()> { +/// let attr = fs::symlink_metadata("/some/file/path.txt").await?; +/// // inspect attr ... +/// Ok(()) +/// } +/// ``` +#[cfg(target_os = "linux")] +pub async fn symlink_metadata>(path: P) -> std::io::Result { + let flags = libc::AT_STATX_SYNC_AS_STAT | libc::AT_SYMLINK_NOFOLLOW; + + let op = Op::statx_using_path(path, flags).unwrap(); + + op.statx_result().await.map(FileAttr::from).map(Metadata) +} diff --git a/monoio/src/fs/mod.rs b/monoio/src/fs/mod.rs index e4ec774d..a6700e29 100644 --- a/monoio/src/fs/mod.rs +++ b/monoio/src/fs/mod.rs @@ -8,6 +8,15 @@ pub use file::File; mod open_options; pub use open_options::OpenOptions; +mod metadata; +pub use metadata::{metadata, symlink_metadata, Metadata}; + +mod file_type; +pub use file_type::FileType; + +mod permissions; +pub use permissions::Permissions; + use crate::buf::IoBuf; /// Read the entire contents of a file into a bytes vector. diff --git a/monoio/src/fs/permissions.rs b/monoio/src/fs/permissions.rs new file mode 100644 index 00000000..f664d51f --- /dev/null +++ b/monoio/src/fs/permissions.rs @@ -0,0 +1,69 @@ +use std::{fmt::Debug, os::unix::fs::PermissionsExt}; + +#[cfg(unix)] +use libc::mode_t; + +#[cfg(unix)] +#[derive(Clone, PartialEq, Eq)] +pub(crate) struct FilePermissions { + pub(crate) mode: mode_t, +} + +impl FilePermissions { + fn readonly(&self) -> bool { + self.mode & 0o222 == 0 + } + + fn mode(&self) -> u32 { + self.mode + } +} + +/// Representation of the various permissions on a file. +#[cfg(unix)] +pub struct Permissions(pub(crate) FilePermissions); + +impl Permissions { + /// Returns `true` if these permissions describe a readonly (unwritable) file. + pub fn readonly(&self) -> bool { + self.0.readonly() + } + + /// Set the readonly flag for this set of permissions. + /// + /// # NOTE + /// this function is unimplemented because current don't know how to sync the + /// mode bits to the file. So currently, it will not expose to the user. + #[allow(unused)] + pub(crate) fn set_readonly(&self, _read_only: bool) { + unimplemented!() + } +} + +impl PermissionsExt for Permissions { + /// Returns the underlying raw `mode_t` bits that are used by the OS. + fn mode(&self) -> u32 { + self.0.mode() + } + + /// Set the mode bits for this set of permissions. + /// + /// this function is unimplemented because current don't know how to sync the + /// mode bits to the file. + fn set_mode(&mut self, _mode: u32) { + unimplemented!() + } + + /// Create a new instance of `Permissions` from the given mode bits. + fn from_mode(mode: u32) -> Self { + Self(FilePermissions { mode }) + } +} + +impl Debug for Permissions { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Permissions") + .field("readonly", &self.readonly()) + .finish() + } +} diff --git a/monoio/tests/fs_metadata.rs b/monoio/tests/fs_metadata.rs new file mode 100644 index 00000000..b5a70393 --- /dev/null +++ b/monoio/tests/fs_metadata.rs @@ -0,0 +1,80 @@ +use std::io::Write; + +#[monoio::test_all] +async fn basic_file_metadata() { + let mut file = tempfile::NamedTempFile::new().unwrap(); + + assert_eq!(file.write(b"foo bar").unwrap(), 7); + + let m_file = monoio::fs::File::open(file.path()).await.unwrap(); + + let m_meta = monoio::fs::metadata(file.path()).await.unwrap(); + let mf_meta = m_file.metadata().await.unwrap(); + let std_meta = std::fs::metadata(file.path()).unwrap(); + + assert_eq!(m_meta.len(), std_meta.len()); + assert_eq!(mf_meta.len(), std_meta.len()); + + assert_eq!(m_meta.modified().unwrap(), std_meta.modified().unwrap()); + assert_eq!(mf_meta.modified().unwrap(), std_meta.modified().unwrap()); + + assert_eq!(m_meta.accessed().unwrap(), std_meta.accessed().unwrap()); + assert_eq!(mf_meta.accessed().unwrap(), std_meta.accessed().unwrap()); + + #[cfg(target_os = "linux")] + assert_eq!(m_meta.created().unwrap(), std_meta.created().unwrap()); + #[cfg(target_os = "linux")] + assert_eq!(mf_meta.created().unwrap(), std_meta.created().unwrap()); + + assert_eq!(m_meta.is_file(), std_meta.is_file()); + assert_eq!(mf_meta.is_file(), std_meta.is_file()); + + assert_eq!(m_meta.is_dir(), std_meta.is_dir()); + assert_eq!(mf_meta.is_dir(), std_meta.is_dir()); +} + +#[monoio::test_all] +async fn dir_metadata() { + let dir = tempfile::tempdir().unwrap(); + + let m_meta = monoio::fs::metadata(dir.path()).await.unwrap(); + let std_meta = std::fs::metadata(dir.path()).unwrap(); + + assert_eq!(m_meta.len(), std_meta.len()); + + assert_eq!(m_meta.modified().unwrap(), std_meta.modified().unwrap()); + + assert_eq!(m_meta.accessed().unwrap(), std_meta.accessed().unwrap()); + + #[cfg(target_os = "linux")] + assert_eq!(m_meta.created().unwrap(), std_meta.created().unwrap()); + + assert_eq!(m_meta.is_file(), std_meta.is_file()); + + assert_eq!(m_meta.is_dir(), std_meta.is_dir()); +} + +#[monoio::test_all] +async fn symlink_metadata() { + let dir = tempfile::tempdir().unwrap(); + let link = dir.path().join("link"); + std::os::unix::fs::symlink(dir.path(), &link).unwrap(); + + let m_meta = monoio::fs::symlink_metadata(&link).await.unwrap(); + let std_meta = std::fs::symlink_metadata(&link).unwrap(); + + assert_eq!(m_meta.len(), std_meta.len()); + + assert_eq!(m_meta.modified().unwrap(), std_meta.modified().unwrap()); + + assert_eq!(m_meta.accessed().unwrap(), std_meta.accessed().unwrap()); + + #[cfg(target_os = "linux")] + assert_eq!(m_meta.created().unwrap(), std_meta.created().unwrap()); + + assert_eq!(m_meta.is_file(), std_meta.is_file()); + + assert_eq!(m_meta.is_dir(), std_meta.is_dir()); + + assert_eq!(m_meta.is_symlink(), std_meta.is_symlink()); +} From 80653449e400d498fd6d4e159e2b752b556d97e1 Mon Sep 17 00:00:00 2001 From: Lzzzt Date: Thu, 6 Jun 2024 11:57:48 +0800 Subject: [PATCH 02/14] feat(op, fs): :sparkles: Intergated `statx` into monoio --- monoio/src/driver/op.rs | 4 +++- monoio/src/fs/file.rs | 2 +- monoio/src/fs/metadata.rs | 11 +++++------ monoio/src/fs/mod.rs | 6 ++++++ monoio/src/fs/permissions.rs | 10 +++++++++- monoio/tests/fs_metadata.rs | 4 ++++ 6 files changed, 28 insertions(+), 9 deletions(-) diff --git a/monoio/src/driver/op.rs b/monoio/src/driver/op.rs index aa82e479..90fd505a 100644 --- a/monoio/src/driver/op.rs +++ b/monoio/src/driver/op.rs @@ -17,9 +17,11 @@ mod poll; mod read; mod recv; mod send; -mod statx; mod write; +#[cfg(target_os = "linux")] +mod statx; + #[cfg(all(target_os = "linux", feature = "splice"))] mod splice; diff --git a/monoio/src/fs/file.rs b/monoio/src/fs/file.rs index 697d07a0..ebfa3ada 100644 --- a/monoio/src/fs/file.rs +++ b/monoio/src/fs/file.rs @@ -10,7 +10,7 @@ use std::{ }; use std::{io, path::Path}; -#[cfg(unix)] +#[cfg(target_os = "linux")] use super::{metadata::FileAttr, Metadata}; use crate::{ buf::{IoBuf, IoBufMut}, diff --git a/monoio/src/fs/metadata.rs b/monoio/src/fs/metadata.rs index a6b02cb3..00748d15 100644 --- a/monoio/src/fs/metadata.rs +++ b/monoio/src/fs/metadata.rs @@ -2,10 +2,9 @@ use std::os::unix::fs::MetadataExt; use std::{path::Path, time::SystemTime}; -#[cfg(target_os = "linux")] -use libc::statx; #[cfg(unix)] -use libc::{mode_t, stat64}; +use libc::mode_t; +use libc::{stat64, statx}; use super::{ file_type::FileType, @@ -86,7 +85,7 @@ impl From for FileAttr { } /// Metadata information about a file. -/// +/// /// This structure is returned from the [`metadata`] or /// [`symlink_metadata`] function or method and represents known /// metadata about a file such as its permissions, size, modification @@ -411,7 +410,7 @@ impl MetadataExt for Metadata { /// Ok(()) /// } /// ``` -#[cfg(target_os = "linux")] + pub async fn metadata>(path: P) -> std::io::Result { let flags = libc::AT_STATX_SYNC_AS_STAT; @@ -447,7 +446,7 @@ pub async fn metadata>(path: P) -> std::io::Result { /// Ok(()) /// } /// ``` -#[cfg(target_os = "linux")] + pub async fn symlink_metadata>(path: P) -> std::io::Result { let flags = libc::AT_STATX_SYNC_AS_STAT | libc::AT_SYMLINK_NOFOLLOW; diff --git a/monoio/src/fs/mod.rs b/monoio/src/fs/mod.rs index a6700e29..9bc3be6f 100644 --- a/monoio/src/fs/mod.rs +++ b/monoio/src/fs/mod.rs @@ -8,13 +8,19 @@ pub use file::File; mod open_options; pub use open_options::OpenOptions; +#[cfg(target_os = "linux")] mod metadata; +#[cfg(target_os = "linux")] pub use metadata::{metadata, symlink_metadata, Metadata}; +#[cfg(target_os = "linux")] mod file_type; +#[cfg(target_os = "linux")] pub use file_type::FileType; +#[cfg(target_os = "linux")] mod permissions; +#[cfg(target_os = "linux")] pub use permissions::Permissions; use crate::buf::IoBuf; diff --git a/monoio/src/fs/permissions.rs b/monoio/src/fs/permissions.rs index f664d51f..c5200205 100644 --- a/monoio/src/fs/permissions.rs +++ b/monoio/src/fs/permissions.rs @@ -14,9 +14,15 @@ impl FilePermissions { self.mode & 0o222 == 0 } + #[cfg(target_os = "linux")] fn mode(&self) -> u32 { self.mode } + + #[cfg(not(target_os = "linux"))] + fn mode(&self) -> u32 { + unimplemented!() + } } /// Representation of the various permissions on a file. @@ -56,7 +62,9 @@ impl PermissionsExt for Permissions { /// Create a new instance of `Permissions` from the given mode bits. fn from_mode(mode: u32) -> Self { - Self(FilePermissions { mode }) + Self(FilePermissions { + mode: mode as mode_t, + }) } } diff --git a/monoio/tests/fs_metadata.rs b/monoio/tests/fs_metadata.rs index b5a70393..46d8df20 100644 --- a/monoio/tests/fs_metadata.rs +++ b/monoio/tests/fs_metadata.rs @@ -1,6 +1,8 @@ +#[allow(unused)] use std::io::Write; #[monoio::test_all] +#[cfg(target_os = "linux")] async fn basic_file_metadata() { let mut file = tempfile::NamedTempFile::new().unwrap(); @@ -34,6 +36,7 @@ async fn basic_file_metadata() { } #[monoio::test_all] +#[cfg(target_os = "linux")] async fn dir_metadata() { let dir = tempfile::tempdir().unwrap(); @@ -55,6 +58,7 @@ async fn dir_metadata() { } #[monoio::test_all] +#[cfg(target_os = "linux")] async fn symlink_metadata() { let dir = tempfile::tempdir().unwrap(); let link = dir.path().join("link"); From 30c9ddcfd071886166044bec679db6130ed74bb0 Mon Sep 17 00:00:00 2001 From: Lzzzt Date: Thu, 6 Jun 2024 15:11:21 +0800 Subject: [PATCH 03/14] fix(op, fs): :bug: fix some platform-specific bug --- monoio/src/driver/op/statx.rs | 2 +- monoio/src/fs/metadata.rs | 81 +++++++++++++++++++++++++++++++++-- 2 files changed, 79 insertions(+), 4 deletions(-) diff --git a/monoio/src/driver/op/statx.rs b/monoio/src/driver/op/statx.rs index a0b8a4c8..84a49309 100644 --- a/monoio/src/driver/op/statx.rs +++ b/monoio/src/driver/op/statx.rs @@ -1,4 +1,4 @@ -#[cfg(unix)] +#[cfg(target_os = "linux")] use std::os::fd::AsRawFd; use std::{ffi::CString, mem::MaybeUninit, path::Path}; diff --git a/monoio/src/fs/metadata.rs b/monoio/src/fs/metadata.rs index 00748d15..ecbc7419 100644 --- a/monoio/src/fs/metadata.rs +++ b/monoio/src/fs/metadata.rs @@ -276,10 +276,10 @@ impl Metadata { /// # Examples /// /// ```no_run - /// use std::fs; + /// use monoio::fs; /// /// #[monoio::main] - /// fn main() -> std::io::Result<()> { + /// async fn main() -> std::io::Result<()> { /// let metadata = fs::metadata("foo.txt").await?; /// /// println!("{:?}", metadata.file_type()); @@ -311,7 +311,7 @@ impl std::fmt::Debug for Metadata { } } -#[cfg(unix)] +#[cfg(all(unix, not(target_pointer_width = "32")))] impl MetadataExt for Metadata { fn dev(&self) -> u64 { self.0.stat.st_dev @@ -325,6 +325,14 @@ impl MetadataExt for Metadata { self.0.stat.st_mode } + #[cfg(all( + target_os = "linux", + any(target_arch = "aarch64", target_arch = "riscv64") + ))] + fn nlink(&self) -> u64 { + self.0.stat.st_nlink.into() + } + fn nlink(&self) -> u64 { self.0.stat.st_nlink } @@ -378,6 +386,73 @@ impl MetadataExt for Metadata { } } +#[cfg(all(unix, target_pointer_width = "32"))] +impl MetadataExt for Metadata { + fn dev(&self) -> u64 { + self.0.stat.st_dev.into() + } + + fn ino(&self) -> u64 { + self.0.stat.st_ino.into() + } + + fn mode(&self) -> u32 { + self.0.stat.st_mode + } + + fn nlink(&self) -> u64 { + self.0.stat.st_nlink.into() + } + + fn uid(&self) -> u32 { + self.0.stat.st_uid + } + + fn gid(&self) -> u32 { + self.0.stat.st_gid + } + + fn rdev(&self) -> u64 { + self.0.stat.st_rdev.into() + } + + fn size(&self) -> u64 { + self.0.stat.st_size as u64 + } + + fn atime(&self) -> i64 { + self.0.stat.st_atime.into() + } + + fn atime_nsec(&self) -> i64 { + self.0.stat.st_atime_nsec.into() + } + + fn mtime(&self) -> i64 { + self.0.stat.st_mtime.into() + } + + fn mtime_nsec(&self) -> i64 { + self.0.stat.st_mtime_nsec.into() + } + + fn ctime(&self) -> i64 { + self.0.stat.st_ctime.into() + } + + fn ctime_nsec(&self) -> i64 { + self.0.stat.st_ctime_nsec.into() + } + + fn blksize(&self) -> u64 { + self.0.stat.st_blksize as u64 + } + + fn blocks(&self) -> u64 { + self.0.stat.st_blocks as u64 + } +} + /// Given a path, query the file system to get information about a file, /// directory, etc. /// From 3318f3759b612bea5b6d53add885f317752739b3 Mon Sep 17 00:00:00 2001 From: Lzzzt Date: Thu, 6 Jun 2024 15:54:24 +0800 Subject: [PATCH 04/14] fix(op, fs): :bug: fix some platform-specific bug --- monoio/src/fs/metadata.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/monoio/src/fs/metadata.rs b/monoio/src/fs/metadata.rs index ecbc7419..1583ba6d 100644 --- a/monoio/src/fs/metadata.rs +++ b/monoio/src/fs/metadata.rs @@ -325,10 +325,7 @@ impl MetadataExt for Metadata { self.0.stat.st_mode } - #[cfg(all( - target_os = "linux", - any(target_arch = "aarch64", target_arch = "riscv64") - ))] + #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] fn nlink(&self) -> u64 { self.0.stat.st_nlink.into() } From 38643ca131419afc1e084831483d0fd456c8161a Mon Sep 17 00:00:00 2001 From: Lzzzt Date: Thu, 6 Jun 2024 20:04:14 +0800 Subject: [PATCH 05/14] docs(fs): update permissions doc --- monoio/src/fs/permissions.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/monoio/src/fs/permissions.rs b/monoio/src/fs/permissions.rs index c5200205..43fee21c 100644 --- a/monoio/src/fs/permissions.rs +++ b/monoio/src/fs/permissions.rs @@ -19,6 +19,14 @@ impl FilePermissions { self.mode } + fn set_readonly(&mut self, readonly: bool) { + if readonly { + self.mode &= !0o222; + } else { + self.mode |= 0o222; + } + } + #[cfg(not(target_os = "linux"))] fn mode(&self) -> u32 { unimplemented!() @@ -37,12 +45,12 @@ impl Permissions { /// Set the readonly flag for this set of permissions. /// - /// # NOTE - /// this function is unimplemented because current don't know how to sync the - /// mode bits to the file. So currently, it will not expose to the user. + /// This will not change the file's permissions, only the in-memory representation. + /// Same with the `std::fs`, if you want to change the file's permissions, you should use + /// `monoio::fs::set_permissions`(currently not support) or `std::fs::set_permissions`. #[allow(unused)] - pub(crate) fn set_readonly(&self, _read_only: bool) { - unimplemented!() + pub fn set_readonly(&mut self, readonly: bool) { + self.0.set_readonly(readonly) } } @@ -54,10 +62,11 @@ impl PermissionsExt for Permissions { /// Set the mode bits for this set of permissions. /// - /// this function is unimplemented because current don't know how to sync the - /// mode bits to the file. - fn set_mode(&mut self, _mode: u32) { - unimplemented!() + /// This will not change the file's permissions, only the in-memory representation. + /// Same with the `std::fs`, if you want to change the file's permissions, you should use + /// `monoio::fs::set_permissions`(currently not support) or `std::fs::set_permissions`. + fn set_mode(&mut self, mode: u32) { + *self = Self::from_mode(mode); } /// Create a new instance of `Permissions` from the given mode bits. From 9f630e7e99e0ddf0dd1d3eb89b81d7e0e0b85024 Mon Sep 17 00:00:00 2001 From: Lzzzt Date: Fri, 7 Jun 2024 13:15:24 +0800 Subject: [PATCH 06/14] fix(op, fs): :bug: fix some platform-specific bug --- monoio/src/fs/metadata.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monoio/src/fs/metadata.rs b/monoio/src/fs/metadata.rs index 1583ba6d..e492a9c6 100644 --- a/monoio/src/fs/metadata.rs +++ b/monoio/src/fs/metadata.rs @@ -330,6 +330,7 @@ impl MetadataExt for Metadata { self.0.stat.st_nlink.into() } + #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] fn nlink(&self) -> u64 { self.0.stat.st_nlink } @@ -518,7 +519,6 @@ pub async fn metadata>(path: P) -> std::io::Result { /// Ok(()) /// } /// ``` - pub async fn symlink_metadata>(path: P) -> std::io::Result { let flags = libc::AT_STATX_SYNC_AS_STAT | libc::AT_SYMLINK_NOFOLLOW; From 8224167bce933fc9788fc86db300ed84b33322b6 Mon Sep 17 00:00:00 2001 From: Lzzzt Date: Sat, 8 Jun 2024 23:35:37 +0800 Subject: [PATCH 07/14] fix(fs): :bug: remove `unwrap` call that will cause panic --- monoio/src/fs/file.rs | 2 +- monoio/src/fs/metadata.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/monoio/src/fs/file.rs b/monoio/src/fs/file.rs index ebfa3ada..abf75b9d 100644 --- a/monoio/src/fs/file.rs +++ b/monoio/src/fs/file.rs @@ -519,7 +519,7 @@ impl File { pub async fn metadata(&self) -> io::Result { let flags = libc::AT_STATX_SYNC_AS_STAT | libc::AT_EMPTY_PATH; - let op = Op::statx_using_fd(&self.fd, flags).unwrap(); + let op = Op::statx_using_fd(&self.fd, flags)?; op.statx_result().await.map(FileAttr::from).map(Metadata) } diff --git a/monoio/src/fs/metadata.rs b/monoio/src/fs/metadata.rs index e492a9c6..c8d9f6a7 100644 --- a/monoio/src/fs/metadata.rs +++ b/monoio/src/fs/metadata.rs @@ -487,7 +487,7 @@ impl MetadataExt for Metadata { pub async fn metadata>(path: P) -> std::io::Result { let flags = libc::AT_STATX_SYNC_AS_STAT; - let op = Op::statx_using_path(path, flags).unwrap(); + let op = Op::statx_using_path(path, flags)?; op.statx_result().await.map(FileAttr::from).map(Metadata) } @@ -522,7 +522,7 @@ pub async fn metadata>(path: P) -> std::io::Result { pub async fn symlink_metadata>(path: P) -> std::io::Result { let flags = libc::AT_STATX_SYNC_AS_STAT | libc::AT_SYMLINK_NOFOLLOW; - let op = Op::statx_using_path(path, flags).unwrap(); + let op = Op::statx_using_path(path, flags)?; op.statx_result().await.map(FileAttr::from).map(Metadata) } From 1dc3c7e49b06992b0eeb0ee626860970b9c8fac1 Mon Sep 17 00:00:00 2001 From: Lzzzt Date: Sun, 9 Jun 2024 00:32:40 +0800 Subject: [PATCH 08/14] feat: :sparkles: make `Statx`(actually is stat) support macos --- monoio/src/driver/op.rs | 2 +- monoio/src/driver/op/statx.rs | 71 ++++++++++++++++++++++++- monoio/src/fs/file.rs | 9 ++-- monoio/src/fs/metadata.rs | 97 ++++++++++++++++++++++++++++++++++- monoio/src/fs/mod.rs | 8 +-- monoio/tests/fs_metadata.rs | 6 +-- 6 files changed, 179 insertions(+), 14 deletions(-) diff --git a/monoio/src/driver/op.rs b/monoio/src/driver/op.rs index 90fd505a..6576933f 100644 --- a/monoio/src/driver/op.rs +++ b/monoio/src/driver/op.rs @@ -19,7 +19,7 @@ mod recv; mod send; mod write; -#[cfg(target_os = "linux")] +#[cfg(unix)] mod statx; #[cfg(all(target_os = "linux", feature = "splice"))] diff --git a/monoio/src/driver/op/statx.rs b/monoio/src/driver/op/statx.rs index 84a49309..2c784cf8 100644 --- a/monoio/src/driver/op/statx.rs +++ b/monoio/src/driver/op/statx.rs @@ -15,14 +15,21 @@ use crate::driver::{shared_fd::SharedFd, util::cstr}; #[derive(Debug)] pub(crate) struct Statx { inner: T, + #[cfg(target_os = "linux")] flags: i32, + #[cfg(target_os = "linux")] statx_buf: Box>, + #[cfg(target_os = "macos")] + stat_buf: Box>, + #[cfg(target_os = "macos")] + follow_symlinks: bool, } type FdStatx = Statx; impl Op { /// submit a statx operation + #[cfg(target_os = "linux")] pub(crate) fn statx_using_fd(fd: &SharedFd, flags: i32) -> std::io::Result { Op::submit_with(Statx { inner: fd.clone(), @@ -31,12 +38,30 @@ impl Op { }) } + #[cfg(target_os = "linux")] pub(crate) async fn statx_result(self) -> std::io::Result { let complete = self.await; complete.meta.result?; Ok(unsafe { MaybeUninit::assume_init(*complete.data.statx_buf) }) } + + #[cfg(target_os = "macos")] + pub(crate) fn statx_using_fd(fd: &SharedFd, follow_symlinks: bool) -> std::io::Result { + Op::submit_with(Statx { + inner: fd.clone(), + follow_symlinks, + stat_buf: Box::new(MaybeUninit::uninit()), + }) + } + + #[cfg(target_os = "macos")] + pub(crate) async fn statx_result(self) -> std::io::Result { + let complete = self.await; + complete.meta.result?; + + Ok(unsafe { MaybeUninit::assume_init(*complete.data.stat_buf) }) + } } impl OpAble for FdStatx { @@ -79,7 +104,14 @@ impl OpAble for FdStatx { #[cfg(all(any(feature = "legacy", feature = "poll-io"), target_os = "macos"))] fn legacy_call(&mut self) -> std::io::Result { - unimplemented!() + use std::os::fd::AsRawFd; + + use crate::syscall_u32; + + syscall_u32!(fstat( + self.inner.as_raw_fd(), + self.stat_buf.as_mut_ptr() as *mut _ + )) } } @@ -87,6 +119,7 @@ type PathStatx = Statx; impl Op { /// submit a statx operation + #[cfg(target_os = "linux")] pub(crate) fn statx_using_path>(path: P, flags: i32) -> std::io::Result { let path = cstr(path.as_ref())?; Op::submit_with(Statx { @@ -96,12 +129,34 @@ impl Op { }) } + #[cfg(target_os = "linux")] pub(crate) async fn statx_result(self) -> std::io::Result { let complete = self.await; complete.meta.result?; Ok(unsafe { MaybeUninit::assume_init(*complete.data.statx_buf) }) } + + #[cfg(target_os = "macos")] + pub(crate) fn statx_using_path>( + path: P, + follow_symlinks: bool, + ) -> std::io::Result { + let path = cstr(path.as_ref())?; + Op::submit_with(Statx { + inner: path, + follow_symlinks, + stat_buf: Box::new(MaybeUninit::uninit()), + }) + } + + #[cfg(target_os = "macos")] + pub(crate) async fn statx_result(self) -> std::io::Result { + let complete = self.await; + complete.meta.result?; + + Ok(unsafe { MaybeUninit::assume_init(*complete.data.stat_buf) }) + } } impl OpAble for PathStatx { @@ -140,6 +195,18 @@ impl OpAble for PathStatx { #[cfg(all(any(feature = "legacy", feature = "poll-io"), target_os = "macos"))] fn legacy_call(&mut self) -> std::io::Result { - unimplemented!() + use crate::syscall_u32; + + if self.follow_symlinks { + syscall_u32!(stat( + self.inner.as_ptr(), + self.stat_buf.as_mut_ptr() as *mut _ + )) + } else { + syscall_u32!(lstat( + self.inner.as_ptr(), + self.stat_buf.as_mut_ptr() as *mut _ + )) + } } } diff --git a/monoio/src/fs/file.rs b/monoio/src/fs/file.rs index abf75b9d..05366750 100644 --- a/monoio/src/fs/file.rs +++ b/monoio/src/fs/file.rs @@ -10,7 +10,7 @@ use std::{ }; use std::{io, path::Path}; -#[cfg(target_os = "linux")] +#[cfg(unix)] use super::{metadata::FileAttr, Metadata}; use crate::{ buf::{IoBuf, IoBufMut}, @@ -515,11 +515,14 @@ impl File { /// Ok(()) /// } /// ``` - #[cfg(target_os = "linux")] + #[cfg(unix)] pub async fn metadata(&self) -> io::Result { + #[cfg(target_os = "linux")] let flags = libc::AT_STATX_SYNC_AS_STAT | libc::AT_EMPTY_PATH; - + #[cfg(target_os = "linux")] let op = Op::statx_using_fd(&self.fd, flags)?; + #[cfg(target_os = "macos")] + let op = Op::statx_using_fd(&self.fd, true)?; op.statx_result().await.map(FileAttr::from).map(Metadata) } diff --git a/monoio/src/fs/metadata.rs b/monoio/src/fs/metadata.rs index c8d9f6a7..ee15989f 100644 --- a/monoio/src/fs/metadata.rs +++ b/monoio/src/fs/metadata.rs @@ -4,6 +4,7 @@ use std::{path::Path, time::SystemTime}; #[cfg(unix)] use libc::mode_t; +#[cfg(target_os = "linux")] use libc::{stat64, statx}; use super::{ @@ -16,7 +17,10 @@ use crate::driver::op::Op; /// Current implementation is only for unix. #[cfg(unix)] pub(crate) struct FileAttr { + #[cfg(target_os = "linux")] stat: stat64, + #[cfg(target_os = "macos")] + stat: libc::stat, #[cfg(target_os = "linux")] statx_extra_fields: Option, } @@ -84,6 +88,13 @@ impl From for FileAttr { } } +#[cfg(target_os = "macos")] +impl From for FileAttr { + fn from(stat: libc::stat) -> Self { + Self { stat } + } +} + /// Metadata information about a file. /// /// This structure is returned from the [`metadata`] or @@ -304,6 +315,7 @@ impl std::fmt::Debug for Metadata { if let Ok(accessed) = self.accessed() { debug.field("accessed", &accessed); } + #[cfg(target_os = "linux")] if let Ok(created) = self.created() { debug.field("created", &created); } @@ -311,7 +323,7 @@ impl std::fmt::Debug for Metadata { } } -#[cfg(all(unix, not(target_pointer_width = "32")))] +#[cfg(all(target_os = "linux", not(target_pointer_width = "32")))] impl MetadataExt for Metadata { fn dev(&self) -> u64 { self.0.stat.st_dev @@ -384,6 +396,79 @@ impl MetadataExt for Metadata { } } +#[cfg(all(target_os = "macos", not(target_pointer_width = "32")))] +impl MetadataExt for Metadata { + fn dev(&self) -> u64 { + self.0.stat.st_dev as u64 + } + + fn ino(&self) -> u64 { + self.0.stat.st_ino + } + + fn mode(&self) -> u32 { + self.0.stat.st_mode as u32 + } + + #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + fn nlink(&self) -> u64 { + self.0.stat.st_nlink.into() + } + + #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] + fn nlink(&self) -> u64 { + self.0.stat.st_nlink + } + + fn uid(&self) -> u32 { + self.0.stat.st_uid + } + + fn gid(&self) -> u32 { + self.0.stat.st_gid + } + + fn rdev(&self) -> u64 { + self.0.stat.st_rdev as u64 + } + + fn size(&self) -> u64 { + self.0.stat.st_size as u64 + } + + fn atime(&self) -> i64 { + self.0.stat.st_atime + } + + fn atime_nsec(&self) -> i64 { + self.0.stat.st_atime_nsec + } + + fn mtime(&self) -> i64 { + self.0.stat.st_mtime + } + + fn mtime_nsec(&self) -> i64 { + self.0.stat.st_mtime_nsec + } + + fn ctime(&self) -> i64 { + self.0.stat.st_ctime + } + + fn ctime_nsec(&self) -> i64 { + self.0.stat.st_ctime_nsec + } + + fn blksize(&self) -> u64 { + self.0.stat.st_blksize as u64 + } + + fn blocks(&self) -> u64 { + self.0.stat.st_blocks as u64 + } +} + #[cfg(all(unix, target_pointer_width = "32"))] impl MetadataExt for Metadata { fn dev(&self) -> u64 { @@ -485,10 +570,15 @@ impl MetadataExt for Metadata { /// ``` pub async fn metadata>(path: P) -> std::io::Result { + #[cfg(target_os = "linux")] let flags = libc::AT_STATX_SYNC_AS_STAT; + #[cfg(target_os = "linux")] let op = Op::statx_using_path(path, flags)?; + #[cfg(target_os = "macos")] + let op = Op::statx_using_path(path, true)?; + op.statx_result().await.map(FileAttr::from).map(Metadata) } @@ -520,9 +610,14 @@ pub async fn metadata>(path: P) -> std::io::Result { /// } /// ``` pub async fn symlink_metadata>(path: P) -> std::io::Result { + #[cfg(target_os = "linux")] let flags = libc::AT_STATX_SYNC_AS_STAT | libc::AT_SYMLINK_NOFOLLOW; + #[cfg(target_os = "linux")] let op = Op::statx_using_path(path, flags)?; + #[cfg(target_os = "macos")] + let op = Op::statx_using_path(path, false)?; + op.statx_result().await.map(FileAttr::from).map(Metadata) } diff --git a/monoio/src/fs/mod.rs b/monoio/src/fs/mod.rs index 9bc3be6f..0147bdc0 100644 --- a/monoio/src/fs/mod.rs +++ b/monoio/src/fs/mod.rs @@ -8,17 +8,17 @@ pub use file::File; mod open_options; pub use open_options::OpenOptions; -#[cfg(target_os = "linux")] +#[cfg(unix)] mod metadata; -#[cfg(target_os = "linux")] +#[cfg(unix)] pub use metadata::{metadata, symlink_metadata, Metadata}; -#[cfg(target_os = "linux")] +#[cfg(unix)] mod file_type; #[cfg(target_os = "linux")] pub use file_type::FileType; -#[cfg(target_os = "linux")] +#[cfg(unix)] mod permissions; #[cfg(target_os = "linux")] pub use permissions::Permissions; diff --git a/monoio/tests/fs_metadata.rs b/monoio/tests/fs_metadata.rs index 46d8df20..11f419e1 100644 --- a/monoio/tests/fs_metadata.rs +++ b/monoio/tests/fs_metadata.rs @@ -2,7 +2,7 @@ use std::io::Write; #[monoio::test_all] -#[cfg(target_os = "linux")] +#[cfg(unix)] async fn basic_file_metadata() { let mut file = tempfile::NamedTempFile::new().unwrap(); @@ -36,7 +36,7 @@ async fn basic_file_metadata() { } #[monoio::test_all] -#[cfg(target_os = "linux")] +#[cfg(unix)] async fn dir_metadata() { let dir = tempfile::tempdir().unwrap(); @@ -58,7 +58,7 @@ async fn dir_metadata() { } #[monoio::test_all] -#[cfg(target_os = "linux")] +#[cfg(unix)] async fn symlink_metadata() { let dir = tempfile::tempdir().unwrap(); let link = dir.path().join("link"); From 4acdea13034b03bb24d7f7b1028fa9bb5eea9b30 Mon Sep 17 00:00:00 2001 From: Lzzzt Date: Sun, 9 Jun 2024 00:37:07 +0800 Subject: [PATCH 09/14] feat: :sparkles: make `Statx`(actually is stat) support macos --- monoio/src/fs/metadata.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/monoio/src/fs/metadata.rs b/monoio/src/fs/metadata.rs index ee15989f..b1f638a1 100644 --- a/monoio/src/fs/metadata.rs +++ b/monoio/src/fs/metadata.rs @@ -410,16 +410,10 @@ impl MetadataExt for Metadata { self.0.stat.st_mode as u32 } - #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] fn nlink(&self) -> u64 { self.0.stat.st_nlink.into() } - #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] - fn nlink(&self) -> u64 { - self.0.stat.st_nlink - } - fn uid(&self) -> u32 { self.0.stat.st_uid } From 49282ddbf90ae098b777670eb9e4ae75806b090f Mon Sep 17 00:00:00 2001 From: Lzzzt Date: Sun, 9 Jun 2024 14:09:08 +0800 Subject: [PATCH 10/14] fix(tests): :bug: disable tests on windows --- monoio/tests/fs_metadata.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/monoio/tests/fs_metadata.rs b/monoio/tests/fs_metadata.rs index 11f419e1..0f1c40c1 100644 --- a/monoio/tests/fs_metadata.rs +++ b/monoio/tests/fs_metadata.rs @@ -1,8 +1,8 @@ -#[allow(unused)] +#![cfg(unix)] + use std::io::Write; #[monoio::test_all] -#[cfg(unix)] async fn basic_file_metadata() { let mut file = tempfile::NamedTempFile::new().unwrap(); @@ -36,7 +36,6 @@ async fn basic_file_metadata() { } #[monoio::test_all] -#[cfg(unix)] async fn dir_metadata() { let dir = tempfile::tempdir().unwrap(); @@ -58,7 +57,6 @@ async fn dir_metadata() { } #[monoio::test_all] -#[cfg(unix)] async fn symlink_metadata() { let dir = tempfile::tempdir().unwrap(); let link = dir.path().join("link"); From db58247cc0e4ff9df4b7ab4e70ad1b03b6b618fd Mon Sep 17 00:00:00 2001 From: Lzzzt Date: Sun, 9 Jun 2024 15:21:44 +0800 Subject: [PATCH 11/14] ci: :pushpin: upgrade the cross version with latest git branch upgrade the cross version with latest git branch, to fix some linker error when CI --- .github/workflows/ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.sh b/.github/workflows/ci.sh index 3224093f..00d943b6 100755 --- a/.github/workflows/ci.sh +++ b/.github/workflows/ci.sh @@ -9,7 +9,7 @@ if [ "${NO_RUN}" != "1" ] && [ "${NO_RUN}" != "true" ]; then export CARGO_NET_RETRY=5 export CARGO_NET_TIMEOUT=10 - cargo install cross + cargo install cross --git "https://github.com/cross-rs/cross#19be83481fd3e50ea103d800d72e0f8eddb1c90c" CARGO=cross fi From 40ab63a312138924eade83e6fdfeeebcbfe35acb Mon Sep 17 00:00:00 2001 From: Lzzzt Date: Mon, 24 Jun 2024 16:02:41 +0800 Subject: [PATCH 12/14] refactor: refact the impl structure for different os --- .../src/fs/{metadata.rs => metadata/mod.rs} | 258 ++++++------------ monoio/src/fs/metadata/unix.rs | 82 ++++++ monoio/src/fs/metadata/windows.rs | 0 monoio/src/fs/permissions.rs | 2 +- 4 files changed, 171 insertions(+), 171 deletions(-) rename monoio/src/fs/{metadata.rs => metadata/mod.rs} (82%) create mode 100644 monoio/src/fs/metadata/unix.rs create mode 100644 monoio/src/fs/metadata/windows.rs diff --git a/monoio/src/fs/metadata.rs b/monoio/src/fs/metadata/mod.rs similarity index 82% rename from monoio/src/fs/metadata.rs rename to monoio/src/fs/metadata/mod.rs index b1f638a1..ae0fc755 100644 --- a/monoio/src/fs/metadata.rs +++ b/monoio/src/fs/metadata/mod.rs @@ -1,100 +1,102 @@ -#[cfg(unix)] -use std::os::unix::fs::MetadataExt; -use std::{path::Path, time::SystemTime}; +mod unix; +mod windows; -#[cfg(unix)] -use libc::mode_t; -#[cfg(target_os = "linux")] -use libc::{stat64, statx}; - -use super::{ - file_type::FileType, - permissions::{FilePermissions, Permissions}, -}; use crate::driver::op::Op; -/// File attributes, not platform-specific. -/// Current implementation is only for unix. -#[cfg(unix)] -pub(crate) struct FileAttr { - #[cfg(target_os = "linux")] - stat: stat64, - #[cfg(target_os = "macos")] - stat: libc::stat, +use super::file_type::FileType; +use super::permissions::Permissions; +use std::os::unix::fs::MetadataExt; +use std::path::Path; +use std::time::SystemTime; + +/// Given a path, query the file system to get information about a file, +/// directory, etc. +/// +/// This function will traverse symbolic links to query information about the +/// destination file. +/// +/// # Platform-specific behavior +/// +/// current implementation is only for Linux. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not +/// limited to just these cases: +/// +/// * The user lacks permissions to perform `metadata` call on `path`. +/// * execute(search) permission is required on all of the directories in path that lead to the +/// file. +/// * `path` does not exist. +/// +/// # Examples +/// +/// ```rust,no_run +/// use monoio::fs; +/// +/// #[monoio::main] +/// async fn main() -> std::io::Result<()> { +/// let attr = fs::metadata("/some/file/path.txt").await?; +/// // inspect attr ... +/// Ok(()) +/// } +/// ``` +pub async fn metadata>(path: P) -> std::io::Result { #[cfg(target_os = "linux")] - statx_extra_fields: Option, -} + let flags = libc::AT_STATX_SYNC_AS_STAT; -#[cfg(unix)] -impl FileAttr { - fn size(&self) -> u64 { - self.stat.st_size as u64 - } + #[cfg(target_os = "linux")] + let op = Op::statx_using_path(path, flags)?; - fn perm(&self) -> FilePermissions { - FilePermissions { - mode: (self.stat.st_mode as mode_t), - } - } + #[cfg(target_os = "macos")] + let op = Op::statx_using_path(path, true)?; - fn file_type(&self) -> FileType { - FileType { - mode: self.stat.st_mode as mode_t, - } - } + op.statx_result().await.map(FileAttr::from).map(Metadata) } -/// Extra fields that are available in `statx` struct. -#[cfg(target_os = "linux")] -pub(crate) struct StatxExtraFields { - stx_mask: u32, - stx_btime: libc::statx_timestamp, -} +/// Query the metadata about a file without following symlinks. +/// +/// # Platform-specific behavior +/// +/// This function currently corresponds to the `lstat` function on linux +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not +/// limited to just these cases: +/// +/// * The user lacks permissions to perform `metadata` call on `path`. +/// * execute(search) permission is required on all of the directories in path that lead to the +/// file. +/// * `path` does not exist. +/// +/// # Examples +/// ```rust,no_run +/// use monoio::fs; +/// +/// #[monoio::main] +/// async fn main() -> std::io::Result<()> { +/// let attr = fs::symlink_metadata("/some/file/path.txt").await?; +/// // inspect attr ... +/// Ok(()) +/// } +/// ``` +pub async fn symlink_metadata>(path: P) -> std::io::Result { + #[cfg(target_os = "linux")] + let flags = libc::AT_STATX_SYNC_AS_STAT | libc::AT_SYMLINK_NOFOLLOW; -/// Convert a `statx` struct to not platform-specific `FileAttr`. -/// Current implementation is only for Linux. -#[cfg(target_os = "linux")] -impl From for FileAttr { - fn from(buf: statx) -> Self { - let mut stat: stat64 = unsafe { std::mem::zeroed() }; - - stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor) as _; - stat.st_ino = buf.stx_ino as libc::ino64_t; - stat.st_nlink = buf.stx_nlink as libc::nlink_t; - stat.st_mode = buf.stx_mode as libc::mode_t; - stat.st_uid = buf.stx_uid as libc::uid_t; - stat.st_gid = buf.stx_gid as libc::gid_t; - stat.st_rdev = libc::makedev(buf.stx_rdev_major, buf.stx_rdev_minor) as _; - stat.st_size = buf.stx_size as libc::off64_t; - stat.st_blksize = buf.stx_blksize as libc::blksize_t; - stat.st_blocks = buf.stx_blocks as libc::blkcnt64_t; - stat.st_atime = buf.stx_atime.tv_sec as libc::time_t; - // `i64` on gnu-x86_64-x32, `c_ulong` otherwise. - stat.st_atime_nsec = buf.stx_atime.tv_nsec as _; - stat.st_mtime = buf.stx_mtime.tv_sec as libc::time_t; - stat.st_mtime_nsec = buf.stx_mtime.tv_nsec as _; - stat.st_ctime = buf.stx_ctime.tv_sec as libc::time_t; - stat.st_ctime_nsec = buf.stx_ctime.tv_nsec as _; - - let extra = StatxExtraFields { - stx_mask: buf.stx_mask, - stx_btime: buf.stx_btime, - }; - - Self { - stat, - statx_extra_fields: Some(extra), - } - } -} + #[cfg(target_os = "linux")] + let op = Op::statx_using_path(path, flags)?; -#[cfg(target_os = "macos")] -impl From for FileAttr { - fn from(stat: libc::stat) -> Self { - Self { stat } - } + #[cfg(target_os = "macos")] + let op = Op::statx_using_path(path, false)?; + + op.statx_result().await.map(FileAttr::from).map(Metadata) } +#[cfg(unix)] +pub(crate) use unix::FileAttr; + /// Metadata information about a file. /// /// This structure is returned from the [`metadata`] or @@ -279,6 +281,8 @@ impl Metadata { /// ``` #[cfg(unix)] pub fn permissions(&self) -> Permissions { + use super::permissions::Permissions; + Permissions(self.0.perm()) } @@ -529,89 +533,3 @@ impl MetadataExt for Metadata { self.0.stat.st_blocks as u64 } } - -/// Given a path, query the file system to get information about a file, -/// directory, etc. -/// -/// This function will traverse symbolic links to query information about the -/// destination file. -/// -/// # Platform-specific behavior -/// -/// current implementation is only for Linux. -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * The user lacks permissions to perform `metadata` call on `path`. -/// * execute(search) permission is required on all of the directories in path that lead to the -/// file. -/// * `path` does not exist. -/// -/// # Examples -/// -/// ```rust,no_run -/// use monoio::fs; -/// -/// #[monoio::main] -/// async fn main() -> std::io::Result<()> { -/// let attr = fs::metadata("/some/file/path.txt").await?; -/// // inspect attr ... -/// Ok(()) -/// } -/// ``` - -pub async fn metadata>(path: P) -> std::io::Result { - #[cfg(target_os = "linux")] - let flags = libc::AT_STATX_SYNC_AS_STAT; - - #[cfg(target_os = "linux")] - let op = Op::statx_using_path(path, flags)?; - - #[cfg(target_os = "macos")] - let op = Op::statx_using_path(path, true)?; - - op.statx_result().await.map(FileAttr::from).map(Metadata) -} - -/// Query the metadata about a file without following symlinks. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `lstat` function on linux -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * The user lacks permissions to perform `metadata` call on `path`. -/// * execute(search) permission is required on all of the directories in path that lead to the -/// file. -/// * `path` does not exist. -/// -/// # Examples -/// ```rust,no_run -/// use monoio::fs; -/// -/// #[monoio::main] -/// async fn main() -> std::io::Result<()> { -/// let attr = fs::symlink_metadata("/some/file/path.txt").await?; -/// // inspect attr ... -/// Ok(()) -/// } -/// ``` -pub async fn symlink_metadata>(path: P) -> std::io::Result { - #[cfg(target_os = "linux")] - let flags = libc::AT_STATX_SYNC_AS_STAT | libc::AT_SYMLINK_NOFOLLOW; - - #[cfg(target_os = "linux")] - let op = Op::statx_using_path(path, flags)?; - - #[cfg(target_os = "macos")] - let op = Op::statx_using_path(path, false)?; - - op.statx_result().await.map(FileAttr::from).map(Metadata) -} diff --git a/monoio/src/fs/metadata/unix.rs b/monoio/src/fs/metadata/unix.rs new file mode 100644 index 00000000..876296a9 --- /dev/null +++ b/monoio/src/fs/metadata/unix.rs @@ -0,0 +1,82 @@ +use libc::mode_t; + +use crate::fs::{file_type::FileType, permissions::FilePermissions}; + +pub(crate) struct FileAttr { + #[cfg(target_os = "linux")] + pub(crate) stat: stat64, + #[cfg(target_os = "macos")] + pub(crate) stat: libc::stat, + #[cfg(target_os = "linux")] + pub(crate) statx_extra_fields: Option, +} + +#[cfg(unix)] +impl FileAttr { + pub(crate) fn size(&self) -> u64 { + self.stat.st_size as u64 + } + + pub(crate) fn perm(&self) -> FilePermissions { + FilePermissions { + mode: (self.stat.st_mode as mode_t), + } + } + + pub(crate) fn file_type(&self) -> FileType { + FileType { + mode: self.stat.st_mode as mode_t, + } + } +} + +/// Extra fields that are available in `statx` struct. +#[cfg(target_os = "linux")] +pub(crate) struct StatxExtraFields { + stx_mask: u32, + stx_btime: libc::statx_timestamp, +} + +/// Convert a `statx` struct to not platform-specific `FileAttr`. +/// Current implementation is only for Linux. +#[cfg(target_os = "linux")] +impl From for FileAttr { + fn from(buf: statx) -> Self { + let mut stat: stat64 = unsafe { std::mem::zeroed() }; + + stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor) as _; + stat.st_ino = buf.stx_ino as libc::ino64_t; + stat.st_nlink = buf.stx_nlink as libc::nlink_t; + stat.st_mode = buf.stx_mode as libc::mode_t; + stat.st_uid = buf.stx_uid as libc::uid_t; + stat.st_gid = buf.stx_gid as libc::gid_t; + stat.st_rdev = libc::makedev(buf.stx_rdev_major, buf.stx_rdev_minor) as _; + stat.st_size = buf.stx_size as libc::off64_t; + stat.st_blksize = buf.stx_blksize as libc::blksize_t; + stat.st_blocks = buf.stx_blocks as libc::blkcnt64_t; + stat.st_atime = buf.stx_atime.tv_sec as libc::time_t; + // `i64` on gnu-x86_64-x32, `c_ulong` otherwise. + stat.st_atime_nsec = buf.stx_atime.tv_nsec as _; + stat.st_mtime = buf.stx_mtime.tv_sec as libc::time_t; + stat.st_mtime_nsec = buf.stx_mtime.tv_nsec as _; + stat.st_ctime = buf.stx_ctime.tv_sec as libc::time_t; + stat.st_ctime_nsec = buf.stx_ctime.tv_nsec as _; + + let extra = StatxExtraFields { + stx_mask: buf.stx_mask, + stx_btime: buf.stx_btime, + }; + + Self { + stat, + statx_extra_fields: Some(extra), + } + } +} + +#[cfg(target_os = "macos")] +impl From for FileAttr { + fn from(stat: libc::stat) -> Self { + Self { stat } + } +} diff --git a/monoio/src/fs/metadata/windows.rs b/monoio/src/fs/metadata/windows.rs new file mode 100644 index 00000000..e69de29b diff --git a/monoio/src/fs/permissions.rs b/monoio/src/fs/permissions.rs index 43fee21c..5b69ea5f 100644 --- a/monoio/src/fs/permissions.rs +++ b/monoio/src/fs/permissions.rs @@ -81,6 +81,6 @@ impl Debug for Permissions { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Permissions") .field("readonly", &self.readonly()) - .finish() + .finish_non_exhaustive() } } From 5c2f0f842a6735f2e2ed326553eb3d5fe8c0a4d2 Mon Sep 17 00:00:00 2001 From: Lzzzt Date: Mon, 24 Jun 2024 16:09:12 +0800 Subject: [PATCH 13/14] cross --- .github/workflows/ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.sh b/.github/workflows/ci.sh index 00d943b6..3224093f 100755 --- a/.github/workflows/ci.sh +++ b/.github/workflows/ci.sh @@ -9,7 +9,7 @@ if [ "${NO_RUN}" != "1" ] && [ "${NO_RUN}" != "true" ]; then export CARGO_NET_RETRY=5 export CARGO_NET_TIMEOUT=10 - cargo install cross --git "https://github.com/cross-rs/cross#19be83481fd3e50ea103d800d72e0f8eddb1c90c" + cargo install cross CARGO=cross fi From 6660b7ef072c0075c4efebc9e50641ac4352670d Mon Sep 17 00:00:00 2001 From: Lzzzt Date: Mon, 24 Jun 2024 19:24:38 +0800 Subject: [PATCH 14/14] refactor: refact the impl structure for different os --- monoio/src/driver/op/statx.rs | 4 ++-- monoio/src/fs/metadata/unix.rs | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/monoio/src/driver/op/statx.rs b/monoio/src/driver/op/statx.rs index 2c784cf8..97a365fc 100644 --- a/monoio/src/driver/op/statx.rs +++ b/monoio/src/driver/op/statx.rs @@ -1,5 +1,3 @@ -#[cfg(target_os = "linux")] -use std::os::fd::AsRawFd; use std::{ffi::CString, mem::MaybeUninit, path::Path}; #[cfg(all(target_os = "linux", feature = "iouring"))] @@ -67,6 +65,8 @@ impl Op { impl OpAble for FdStatx { #[cfg(all(target_os = "linux", feature = "iouring"))] fn uring_op(&mut self) -> io_uring::squeue::Entry { + use std::os::fd::AsRawFd; + let statxbuf = self.statx_buf.as_mut_ptr() as *mut _; opcode::Statx::new(types::Fd(self.inner.as_raw_fd()), c"".as_ptr(), statxbuf) diff --git a/monoio/src/fs/metadata/unix.rs b/monoio/src/fs/metadata/unix.rs index 876296a9..352c8f78 100644 --- a/monoio/src/fs/metadata/unix.rs +++ b/monoio/src/fs/metadata/unix.rs @@ -4,7 +4,7 @@ use crate::fs::{file_type::FileType, permissions::FilePermissions}; pub(crate) struct FileAttr { #[cfg(target_os = "linux")] - pub(crate) stat: stat64, + pub(crate) stat: libc::stat64, #[cfg(target_os = "macos")] pub(crate) stat: libc::stat, #[cfg(target_os = "linux")] @@ -33,16 +33,16 @@ impl FileAttr { /// Extra fields that are available in `statx` struct. #[cfg(target_os = "linux")] pub(crate) struct StatxExtraFields { - stx_mask: u32, - stx_btime: libc::statx_timestamp, + pub(crate) stx_mask: u32, + pub(crate) stx_btime: libc::statx_timestamp, } /// Convert a `statx` struct to not platform-specific `FileAttr`. /// Current implementation is only for Linux. #[cfg(target_os = "linux")] -impl From for FileAttr { - fn from(buf: statx) -> Self { - let mut stat: stat64 = unsafe { std::mem::zeroed() }; +impl From for FileAttr { + fn from(buf: libc::statx) -> Self { + let mut stat: libc::stat64 = unsafe { std::mem::zeroed() }; stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor) as _; stat.st_ino = buf.stx_ino as libc::ino64_t;