Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(op, fs): ✨ Intergated statx into monoio #268

Merged
merged 17 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions monoio/src/driver/op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ mod recv;
mod send;
mod write;

#[cfg(target_os = "linux")]
mod statx;

#[cfg(all(target_os = "linux", feature = "splice"))]
mod splice;

Expand Down
145 changes: 145 additions & 0 deletions monoio/src/driver/op/statx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#[cfg(target_os = "linux")]
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<T> {
inner: T,
flags: i32,
statx_buf: Box<MaybeUninit<statx>>,
}

type FdStatx = Statx<SharedFd>;

impl Op<FdStatx> {
/// submit a statx operation
pub(crate) fn statx_using_fd(fd: &SharedFd, flags: i32) -> std::io::Result<Self> {
Op::submit_with(Statx {
inner: fd.clone(),
flags,
statx_buf: Box::new(MaybeUninit::uninit()),
})
}

pub(crate) async fn statx_result(self) -> std::io::Result<statx> {
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<u32> {
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<u32> {
unimplemented!()
}

#[cfg(all(any(feature = "legacy", feature = "poll-io"), target_os = "macos"))]
fn legacy_call(&mut self) -> std::io::Result<u32> {
unimplemented!()
}
}

type PathStatx = Statx<CString>;

impl Op<PathStatx> {
/// submit a statx operation
pub(crate) fn statx_using_path<P: AsRef<Path>>(path: P, flags: i32) -> std::io::Result<Self> {
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<statx> {
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<u32> {
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<u32> {
unimplemented!()
}

#[cfg(all(any(feature = "legacy", feature = "poll-io"), target_os = "macos"))]
fn legacy_call(&mut self) -> std::io::Result<u32> {
unimplemented!()
}
}
25 changes: 25 additions & 0 deletions monoio/src/fs/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use std::{
};
use std::{io, path::Path};

#[cfg(target_os = "linux")]
use super::{metadata::FileAttr, Metadata};
use crate::{
buf::{IoBuf, IoBufMut},
driver::{op::Op, shared_fd::SharedFd},
Expand Down Expand Up @@ -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<Metadata> {
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)]
Expand Down
63 changes: 63 additions & 0 deletions monoio/src/fs/file_type.rs
Original file line number Diff line number Diff line change
@@ -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()
}
}
Loading
Loading