Skip to content

Commit

Permalink
feat: add support some fs operation on Windows (#336)
Browse files Browse the repository at this point in the history
* feat: add support some fs operation on Win

Signed-off-by: Lzzzt <[email protected]>

* style: make clippy happy

Signed-off-by: lzzzt <[email protected]>

* fix: make clippy happy

---------

Signed-off-by: Lzzzt <[email protected]>
Signed-off-by: lzzzt <[email protected]>
  • Loading branch information
Lzzzzzt authored Feb 28, 2025
1 parent fca9c7c commit d86d2ce
Show file tree
Hide file tree
Showing 15 changed files with 135 additions and 35 deletions.
1 change: 0 additions & 1 deletion monoio/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ impl<T> Default for RuntimeBuilder<T> {
/// [monoio::blocking::BlockingStrategy] is to execute tasks on the local thread. In other
/// words, there is no thread pool involved—all blocking I/O operations and heavy computations
/// will block the current thread.
#[must_use]
fn default() -> Self {
RuntimeBuilder::<T>::new()
}
Expand Down
6 changes: 3 additions & 3 deletions monoio/src/driver/op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ mod send;
#[cfg(unix)]
mod statx;

#[cfg(all(unix, feature = "mkdirat"))]
#[cfg(feature = "mkdirat")]
mod mkdir;

#[cfg(all(unix, feature = "unlinkat"))]
#[cfg(feature = "unlinkat")]
mod unlink;

#[cfg(all(unix, feature = "renameat"))]
#[cfg(feature = "renameat")]
mod rename;

#[cfg(all(unix, feature = "symlinkat"))]
Expand Down
31 changes: 29 additions & 2 deletions monoio/src/driver/op/mkdir.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::{ffi::CString, path::Path};

#[cfg(unix)]
use libc::mode_t;

#[cfg(any(feature = "legacy", feature = "poll-io"))]
Expand All @@ -9,14 +10,22 @@ use crate::driver::util::cstr;

pub(crate) struct MkDir {
path: CString,
#[cfg(unix)]
mode: mode_t,
}

impl Op<MkDir> {
#[cfg(unix)]
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 })
}

#[cfg(windows)]
pub(crate) fn mkdir<P: AsRef<Path>>(path: P) -> std::io::Result<Op<MkDir>> {
let path = cstr(path.as_ref())?;
Op::submit_with(MkDir { path })
}
}

impl OpAble for MkDir {
Expand Down Expand Up @@ -45,7 +54,25 @@ impl OpAble for MkDir {
}

#[cfg(all(any(feature = "legacy", feature = "poll-io"), windows))]
fn legacy_call(&mut self) -> io::Result<MaybeFd> {
unimplemented!()
fn legacy_call(&mut self) -> std::io::Result<MaybeFd> {
use std::io::{Error, ErrorKind};

use windows_sys::Win32::Storage::FileSystem::CreateDirectoryW;

use crate::driver::util::to_wide_string;

let path = to_wide_string(
self.path
.to_str()
.map_err(|e| Error::new(ErrorKind::InvalidData, e))?,
);

// Currently, we don't check the validness of the path.
// Should we port the Rust std lib to check the validness?
crate::syscall!(
CreateDirectoryW@NON_FD(path.as_ptr(), std::ptr::null()),
PartialEq::eq,
0
)
}
}
26 changes: 24 additions & 2 deletions monoio/src/driver/op/rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,29 @@ impl OpAble for Rename {
}

#[cfg(all(any(feature = "legacy", feature = "poll-io"), windows))]
fn legacy_call(&mut self) -> io::Result<MaybeFd> {
unimplemented!()
fn legacy_call(&mut self) -> std::io::Result<MaybeFd> {
use std::io::{Error, ErrorKind};

use windows_sys::Win32::Storage::FileSystem::{MoveFileExW, MOVEFILE_REPLACE_EXISTING};

use crate::driver::util::to_wide_string;

let from = to_wide_string(
self.from
.to_str()
.map_err(|e| Error::new(ErrorKind::InvalidData, e))?,
);

let to = to_wide_string(
self.to
.to_str()
.map_err(|e| Error::new(ErrorKind::InvalidData, e))?,
);

crate::syscall!(
MoveFileExW@NON_FD(from.as_ptr(), to.as_ptr(), MOVEFILE_REPLACE_EXISTING),
PartialEq::eq,
0
)
}
}
9 changes: 4 additions & 5 deletions monoio/src/driver/op/send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,11 +259,10 @@ impl<T: IoBuf> Op<SendMsgUnix<T>> {
buf: T,
socket_addr: Option<UnixSocketAddr>,
) -> io::Result<Self> {
let mut info: Box<(Option<UnixSocketAddr>, IoVecMeta, libc::msghdr)> = Box::new((
socket_addr.map(Into::into),
IoVecMeta::from(&buf),
unsafe { std::mem::zeroed() },
));
let mut info: Box<(Option<UnixSocketAddr>, IoVecMeta, libc::msghdr)> =
Box::new((socket_addr, IoVecMeta::from(&buf), unsafe {
std::mem::zeroed()
}));

info.2.msg_iov = info.1.write_iovec_ptr();
info.2.msg_iovlen = info.1.write_iovec_len() as _;
Expand Down
29 changes: 25 additions & 4 deletions monoio/src/driver/op/unlink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ use io_uring::{opcode, squeue::Entry, types::Fd};
#[cfg(all(target_os = "linux", feature = "iouring"))]
use libc::{AT_FDCWD, AT_REMOVEDIR};

use super::{Op, OpAble};
use crate::driver::util::cstr;
use super::{MaybeFd, Op, OpAble};
#[cfg(any(feature = "legacy", feature = "poll-io"))]
use crate::driver::{op::MaybeFd, ready::Direction};
use crate::driver::ready::Direction;
use crate::driver::util::cstr;

pub(crate) struct Unlink {
path: CString,
Expand Down Expand Up @@ -46,12 +46,33 @@ impl OpAble for Unlink {
None
}

#[cfg(any(feature = "legacy", feature = "poll-io"))]
#[cfg(all(unix, any(feature = "legacy", feature = "poll-io")))]
fn legacy_call(&mut self) -> io::Result<MaybeFd> {
if self.remove_dir {
crate::syscall!(rmdir@NON_FD(self.path.as_c_str().as_ptr()))
} else {
crate::syscall!(unlink@NON_FD(self.path.as_c_str().as_ptr()))
}
}

#[cfg(all(windows, any(feature = "legacy", feature = "poll-io")))]
fn legacy_call(&mut self) -> std::io::Result<MaybeFd> {
use std::io::{Error, ErrorKind};

use windows_sys::Win32::Storage::FileSystem::{DeleteFileW, RemoveDirectoryW};

use crate::driver::util::to_wide_string;

let path = to_wide_string(
self.path
.to_str()
.map_err(|e| Error::new(ErrorKind::InvalidData, e))?,
);

if self.remove_dir {
crate::syscall!(RemoveDirectoryW@NON_FD(path.as_ptr()), PartialEq::eq, 0)
} else {
crate::syscall!(DeleteFileW@NON_FD(path.as_ptr()), PartialEq::eq, 0)
}
}
}
7 changes: 7 additions & 0 deletions monoio/src/driver/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,10 @@ macro_rules! syscall {
pub(crate) fn feature_panic() -> ! {
panic!("one of iouring and legacy features must be enabled");
}

#[cfg(all(windows, feature = "renameat"))]
pub(crate) fn to_wide_string(str: &str) -> Vec<u16> {
use std::{ffi::OsStr, iter::once, os::windows::ffi::OsStrExt};

OsStr::new(str).encode_wide().chain(once(0)).collect()
}
10 changes: 9 additions & 1 deletion monoio/src/fs/dir_builder/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
#[cfg(unix)]
mod unix;
#[cfg(windows)]
mod windows;

use std::{io, os::unix::fs::DirBuilderExt, path::Path};
#[cfg(unix)]
use std::os::unix::fs::DirBuilderExt;
use std::{io, path::Path};

#[cfg(unix)]
use unix as sys;
#[cfg(windows)]
use windows as sys;

/// A builder used to create directories in various manners.
///
Expand Down Expand Up @@ -138,6 +145,7 @@ impl Default for DirBuilder {
}
}

#[cfg(unix)]
impl DirBuilderExt for DirBuilder {
fn mode(&mut self, mode: u32) -> &mut Self {
self.inner.set_mode(mode);
Expand Down
15 changes: 15 additions & 0 deletions monoio/src/fs/dir_builder/windows.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use std::path::Path;

use crate::driver::op::Op;

pub(super) struct BuilderInner;

impl BuilderInner {
pub(super) fn new() -> Self {
Self
}

pub(super) async fn mkdir(&self, path: &Path) -> std::io::Result<()> {
Op::mkdir(path)?.await.meta.result.map(|_| ())
}
}
16 changes: 7 additions & 9 deletions monoio/src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ use std::{io, path::Path};

pub use file::File;

#[cfg(all(unix, feature = "mkdirat"))]
#[cfg(feature = "mkdirat")]
mod dir_builder;
#[cfg(all(unix, feature = "mkdirat"))]
#[cfg(feature = "mkdirat")]
pub use dir_builder::DirBuilder;

#[cfg(all(unix, feature = "mkdirat"))]
#[cfg(feature = "mkdirat")]
mod create_dir;
#[cfg(all(unix, feature = "mkdirat"))]
#[cfg(feature = "mkdirat")]
pub use create_dir::*;

#[cfg(all(unix, feature = "symlinkat"))]
Expand Down Expand Up @@ -42,8 +42,6 @@ use std::os::windows::io::{AsRawHandle, FromRawHandle};
pub use permissions::Permissions;

use crate::buf::IoBuf;
#[cfg(all(unix, feature = "unlinkat"))]
use crate::driver::op::Op;

/// Executes a blocking operation asynchronously on a separate thread.
///
Expand Down Expand Up @@ -219,7 +217,7 @@ pub async fn write<P: AsRef<Path>, C: IoBuf>(path: P, contents: C) -> (io::Resul
/// Ok(())
/// }
/// ```
#[cfg(all(unix, feature = "unlinkat"))]
#[cfg(feature = "unlinkat")]
pub async fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
Op::unlink(path)?.await.meta.result?;
Ok(())
Expand Down Expand Up @@ -250,7 +248,7 @@ pub async fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
/// Ok(())
/// }
/// ```
#[cfg(all(unix, feature = "unlinkat"))]
#[cfg(feature = "unlinkat")]
pub async fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
Op::rmdir(path)?.await.meta.result?;
Ok(())
Expand Down Expand Up @@ -281,7 +279,7 @@ pub async fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
/// Ok(())
/// }
/// ```
#[cfg(all(unix, feature = "renameat"))]
#[cfg(feature = "renameat")]
pub async fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
Op::rename(from.as_ref(), to.as_ref())?.await.meta.result?;
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion monoio/src/utils/rand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ impl FastRand {
let s0 = self.two.get();

s1 ^= s1 << 17;
s1 = s1 ^ s0 ^ s1 >> 7 ^ s0 >> 16;
s1 = s1 ^ s0 ^ (s1 >> 7) ^ (s0 >> 16);

self.one.set(s0);
self.two.set(s1);
Expand Down
7 changes: 6 additions & 1 deletion monoio/tests/fs_create_dir.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg(all(unix, feature = "mkdirat"))]
#![cfg(feature = "mkdirat")]

use monoio::fs;
use tempfile::tempdir;
Expand Down Expand Up @@ -86,14 +86,18 @@ async fn create_directory_with_symlink() {
let link = temp_dir.path().join("bar");
let to_create = link.join("nested");

#[cfg(unix)]
std::os::unix::fs::symlink(&target, &link).unwrap();
#[cfg(windows)]
std::os::windows::fs::symlink_dir(&target, &link).unwrap();

fs::create_dir_all(&to_create).await.unwrap();

assert!(to_create.exists());
assert!(target.join("nested").exists());
}

#[cfg(unix)]
#[monoio::test_all]
async fn create_very_long_path() {
let temp_dir = tempdir().unwrap();
Expand All @@ -108,6 +112,7 @@ async fn create_very_long_path() {
assert!(path.exists());
}

#[cfg(unix)]
#[monoio::test_all]
async fn create_directory_with_permission_issue() {
use std::os::unix::fs::PermissionsExt;
Expand Down
2 changes: 0 additions & 2 deletions monoio/tests/fs_file_asyncify.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#![cfg(feature = "sync")]
use std::io::prelude::*;
#[cfg(windows)]
use std::os::windows::io::{AsRawHandle, FromRawHandle, RawHandle as RawFd};

use monoio::{
blocking::DefaultThreadPool, buf::VecBuf, fs::File, io::AsyncReadRent, LegacyDriver, Runtime,
Expand Down
7 changes: 4 additions & 3 deletions monoio/tests/fs_rename.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
#![cfg(all(unix, feature = "renameat"))]

use std::{fs::Permissions, os::unix::fs::PermissionsExt};
#![cfg(feature = "renameat")]

#[monoio::test_all]
async fn rename_file_in_the_same_directory() {
Expand Down Expand Up @@ -62,8 +60,11 @@ async fn rename_nonexistent_file() {
assert!(result.is_err());
}

#[cfg(unix)]
#[monoio::test_all]
async fn rename_file_without_permission() {
use std::{fs::Permissions, os::unix::fs::PermissionsExt};

let temp_dir = tempfile::tempdir().unwrap();
let temp_file = tempfile::NamedTempFile::new_in(&temp_dir).unwrap();

Expand Down
2 changes: 1 addition & 1 deletion monoio/tests/fs_unlink.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg(all(unix, feature = "unlinkat", feature = "mkdirat"))]
#![cfg(all(feature = "unlinkat", feature = "mkdirat"))]

use std::{io, path::PathBuf};

Expand Down

0 comments on commit d86d2ce

Please sign in to comment.