-
Notifications
You must be signed in to change notification settings - Fork 230
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(op): ✨ add
MkDirAt
opcode in io-uring (#270)
- Loading branch information
Showing
8 changed files
with
436 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
use std::{ffi::CString, path::Path}; | ||
|
||
use libc::mode_t; | ||
|
||
use super::{Op, OpAble}; | ||
use crate::driver::util::cstr; | ||
|
||
pub(crate) struct MkDir { | ||
path: CString, | ||
mode: mode_t, | ||
} | ||
|
||
impl Op<MkDir> { | ||
pub(crate) fn mkdir<P: AsRef<Path>>(path: P, mode: mode_t) -> std::io::Result<Op<MkDir>> { | ||
let path = cstr(path.as_ref())?; | ||
Op::submit_with(MkDir { path, mode }) | ||
} | ||
} | ||
|
||
impl OpAble for MkDir { | ||
#[cfg(all(target_os = "linux", feature = "iouring"))] | ||
fn uring_op(&mut self) -> io_uring::squeue::Entry { | ||
use io_uring::{opcode, types}; | ||
|
||
opcode::MkDirAt::new(types::Fd(libc::AT_FDCWD), self.path.as_ptr()) | ||
.mode(self.mode) | ||
.build() | ||
} | ||
|
||
#[cfg(any(feature = "legacy", feature = "poll-io"))] | ||
#[inline] | ||
fn legacy_interest(&self) -> Option<(crate::driver::ready::Direction, usize)> { | ||
None | ||
} | ||
|
||
#[cfg(all(any(feature = "legacy", feature = "poll-io"), unix))] | ||
fn legacy_call(&mut self) -> std::io::Result<u32> { | ||
use crate::syscall_u32; | ||
|
||
syscall_u32!(mkdirat(libc::AT_FDCWD, self.path.as_ptr(), self.mode)) | ||
} | ||
|
||
#[cfg(all(any(feature = "legacy", feature = "poll-io"), windows))] | ||
fn legacy_call(&mut self) -> io::Result<u32> { | ||
unimplemented!() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
use std::{io, path::Path}; | ||
|
||
use super::DirBuilder; | ||
|
||
/// Create a new directory at the target path | ||
/// | ||
/// # Note | ||
/// | ||
/// - This function require the provided path's parent are all existing. | ||
/// - To create a directory and all its missing parents at the same time, use the | ||
/// [`create_dir_all`] function. | ||
/// - Currently this function is supported on unix, windows is unimplement. | ||
/// | ||
/// # Errors | ||
/// | ||
/// This function will return an error in the following situations, but is not | ||
/// limited to just these cases: | ||
/// | ||
/// * User lacks permissions to create directory at `path`. | ||
/// * A parent of the given path doesn't exist. (To create a directory and all its missing parents | ||
/// at the same time, use the [`create_dir_all`] function.) | ||
/// * `path` already exists. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ```no_run | ||
/// use monoio::fs; | ||
/// | ||
/// #[monoio::main] | ||
/// async fn main() -> std::io::Result<()> { | ||
/// fs::create_dir("/some/dir").await?; | ||
/// Ok(()) | ||
/// } | ||
/// ``` | ||
pub async fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> { | ||
DirBuilder::new().create(path).await | ||
} | ||
|
||
/// Recursively create a directory and all of its missing components | ||
/// | ||
/// # Note | ||
/// | ||
/// - Currently this function is supported on unix, windows is unimplement. | ||
/// | ||
/// # Errors | ||
/// | ||
/// Same with [`create_dir`] | ||
/// | ||
/// # Examples | ||
/// | ||
/// ```no_run | ||
/// use monoio::fs; | ||
/// | ||
/// #[monoio::main] | ||
/// async fn main() -> std::io::Result<()> { | ||
/// fs::create_dir_all("/some/dir").await?; | ||
/// Ok(()) | ||
/// } | ||
/// ``` | ||
pub async fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> { | ||
DirBuilder::new().recursive(true).create(path).await | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
mod unix; | ||
|
||
use std::{io, os::unix::fs::DirBuilderExt, path::Path}; | ||
|
||
#[cfg(unix)] | ||
use unix as sys; | ||
|
||
/// A builder used to create directories in various manners. | ||
/// | ||
/// This builder also supports platform-specific options. | ||
pub struct DirBuilder { | ||
recursive: bool, | ||
inner: sys::BuilderInner, | ||
} | ||
|
||
impl DirBuilder { | ||
/// Creates a new set of options with default mode/security settings for all | ||
/// platforms and also non-recursive. | ||
/// | ||
/// This an async version of [`std::fs::DirBuilder::new`] | ||
/// | ||
/// # Examples | ||
/// | ||
/// ```no_run | ||
/// use monoio::fs::DirBuilder; | ||
/// | ||
/// let builder = DirBuilder::new(); | ||
/// ``` | ||
pub fn new() -> Self { | ||
Self { | ||
recursive: false, | ||
inner: sys::BuilderInner::new(), | ||
} | ||
} | ||
|
||
/// Indicates that directories should be created recursively, creating all | ||
/// parent directories. Parents that do not exist are created with the same | ||
/// security and permissions settings. | ||
/// | ||
/// This option defaults to `false`. | ||
/// | ||
/// This an async version of [`std::fs::DirBuilder::recursive`] | ||
/// | ||
/// # Examples | ||
/// | ||
/// ```no_run | ||
/// use monoio::fs::DirBuilder; | ||
/// | ||
/// let mut builder = DirBuilder::new(); | ||
/// builder.recursive(true); | ||
/// ``` | ||
pub fn recursive(&mut self, recursive: bool) -> &mut Self { | ||
self.recursive = recursive; | ||
self | ||
} | ||
|
||
/// Creates the specified directory with the options configured in this | ||
/// builder. | ||
/// | ||
/// It is considered an error if the directory already exists unless | ||
/// recursive mode is enabled. | ||
/// | ||
/// This is async version of [`std::fs::DirBuilder::create`] and use io-uring | ||
/// in support platform. | ||
/// | ||
/// # Errors | ||
/// | ||
/// An error will be returned under the following circumstances: | ||
/// | ||
/// * Path already points to an existing file. | ||
/// * Path already points to an existing directory and the mode is non-recursive. | ||
/// * The calling process doesn't have permissions to create the directory or its missing | ||
/// parents. | ||
/// * Other I/O error occurred. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ```no_run | ||
/// use monoio::fs::DirBuilder; | ||
/// | ||
/// #[monoio::main] | ||
/// async fn main() -> std::io::Result<()> { | ||
/// DirBuilder::new() | ||
/// .recursive(true) | ||
/// .create("/some/dir") | ||
/// .await?; | ||
/// | ||
/// Ok(()) | ||
/// } | ||
/// ``` | ||
pub async fn create<P: AsRef<Path>>(&self, path: P) -> io::Result<()> { | ||
if self.recursive { | ||
self.create_dir_all(path.as_ref()).await | ||
} else { | ||
self.inner.mkdir(path.as_ref()).await | ||
} | ||
} | ||
|
||
async fn create_dir_all(&self, path: &Path) -> io::Result<()> { | ||
if path == Path::new("") { | ||
return Ok(()); | ||
} | ||
|
||
let mut inexist_path = path; | ||
let mut need_create = vec![]; | ||
|
||
while match self.inner.mkdir(inexist_path).await { | ||
Ok(()) => false, | ||
Err(ref e) if e.kind() == io::ErrorKind::NotFound => true, | ||
Err(_) if is_dir(inexist_path).await => false, | ||
Err(e) => return Err(e), | ||
} { | ||
match inexist_path.parent() { | ||
Some(p) => { | ||
need_create.push(inexist_path); | ||
inexist_path = p; | ||
} | ||
None => { | ||
return Err(io::Error::new( | ||
io::ErrorKind::Other, | ||
"failed to create whole tree", | ||
)) | ||
} | ||
} | ||
} | ||
|
||
for p in need_create.into_iter().rev() { | ||
self.inner.mkdir(p).await?; | ||
} | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
impl Default for DirBuilder { | ||
fn default() -> Self { | ||
Self::new() | ||
} | ||
} | ||
|
||
impl DirBuilderExt for DirBuilder { | ||
fn mode(&mut self, mode: u32) -> &mut Self { | ||
self.inner.set_mode(mode); | ||
self | ||
} | ||
} | ||
|
||
// currently, will use the std version of metadata, will change to use the io-uring version | ||
// when the statx is merge | ||
async fn is_dir(path: &Path) -> bool { | ||
std::fs::metadata(path).is_ok_and(|metadata| metadata.is_dir()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
use std::path::Path; | ||
|
||
use libc::mode_t; | ||
|
||
use crate::driver::op::Op; | ||
|
||
pub(super) struct BuilderInner { | ||
mode: libc::mode_t, | ||
} | ||
|
||
impl BuilderInner { | ||
pub(super) fn new() -> Self { | ||
Self { mode: 0o777 } | ||
} | ||
|
||
pub(super) async fn mkdir(&self, path: &Path) -> std::io::Result<()> { | ||
Op::mkdir(path, self.mode)?.await.meta.result.map(|_| ()) | ||
} | ||
|
||
pub(super) fn set_mode(&mut self, mode: u32) { | ||
self.mode = mode as mode_t; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.