From f891b7058158e2687a4c827e89fc6fda71d57793 Mon Sep 17 00:00:00 2001 From: Jin Wei Tan <48111396+CarrotzRule123@users.noreply.github.com> Date: Tue, 11 Jul 2023 11:03:33 +0800 Subject: [PATCH] implement open op on windows (#189) --- monoio/src/driver/op/open.rs | 42 +++++++++++++++- monoio/src/fs/file.rs | 2 - monoio/src/fs/open_options.rs | 94 ++++++++++++++++++++++++++++++++++- 3 files changed, 132 insertions(+), 6 deletions(-) diff --git a/monoio/src/driver/op/open.rs b/monoio/src/driver/op/open.rs index a1046781..a9b158b7 100644 --- a/monoio/src/driver/op/open.rs +++ b/monoio/src/driver/op/open.rs @@ -2,18 +2,27 @@ use std::{ffi::CString, io, path::Path}; #[cfg(all(target_os = "linux", feature = "iouring"))] use io_uring::{opcode, types}; +#[cfg(windows)] +use windows_sys::Win32::{Foundation::INVALID_HANDLE_VALUE, Storage::FileSystem::CreateFileW}; use super::{Op, OpAble}; +#[cfg(feature = "legacy")] +use crate::driver::legacy::ready::Direction; +#[cfg(windows)] +use crate::syscall; #[cfg(all(unix, feature = "legacy"))] -use crate::{driver::legacy::ready::Direction, syscall_u32}; +use crate::syscall_u32; use crate::{driver::util::cstr, fs::OpenOptions}; /// Open a file pub(crate) struct Open { pub(crate) path: CString, + #[cfg(unix)] flags: i32, #[cfg(unix)] mode: libc::mode_t, + #[cfg(windows)] + opts: OpenOptions, } impl Op { @@ -30,6 +39,18 @@ impl Op { Op::submit_with(Open { path, flags, mode }) } + + #[cfg(windows)] + /// Submit a request to open a file. + pub(crate) fn open>(path: P, options: &OpenOptions) -> io::Result> { + // Here the path will be copied, so its safe. + let path = cstr(path.as_ref())?; + + Op::submit_with(Open { + path, + opts: options.clone(), + }) + } } impl OpAble for Open { @@ -41,7 +62,7 @@ impl OpAble for Open { .build() } - #[cfg(all(unix, feature = "legacy"))] + #[cfg(feature = "legacy")] fn legacy_interest(&self) -> Option<(Direction, usize)> { None } @@ -54,4 +75,21 @@ impl OpAble for Open { self.mode as libc::c_int )) } + + #[cfg(windows)] + fn legacy_call(&mut self) -> io::Result { + syscall!( + CreateFileW( + self.path.as_c_str().as_ptr(), + self.opts.access_mode()?, + self.opts.share_mode, + self.opts.security_attributes, + self.opts.creation_mode()?, + self.opts.get_flags_and_attributes(), + std::ptr::null_mut(), + ), + PartialEq::eq, + INVALID_HANDLE_VALUE + ) + } } diff --git a/monoio/src/fs/file.rs b/monoio/src/fs/file.rs index 3fe9942b..f7fa13c0 100644 --- a/monoio/src/fs/file.rs +++ b/monoio/src/fs/file.rs @@ -59,7 +59,6 @@ pub struct File { } impl File { - #[cfg(unix)] /// Attempts to open a file in read-only mode. /// /// See the [`OpenOptions::open`] method for more details. @@ -87,7 +86,6 @@ impl File { OpenOptions::new().read(true).open(path).await } - #[cfg(unix)] /// Opens a file in write-only mode. /// /// This function will create a file if it does not exist, diff --git a/monoio/src/fs/open_options.rs b/monoio/src/fs/open_options.rs index 913e88c0..cabd3a8d 100644 --- a/monoio/src/fs/open_options.rs +++ b/monoio/src/fs/open_options.rs @@ -1,4 +1,17 @@ -use std::{io, os::unix::prelude::OpenOptionsExt, path::Path}; +#[cfg(unix)] +use std::os::unix::prelude::OpenOptionsExt; +use std::{io, path::Path}; + +#[cfg(windows)] +use windows_sys::Win32::{ + Foundation::{ERROR_INVALID_PARAMETER, GENERIC_READ, GENERIC_WRITE}, + Security::SECURITY_ATTRIBUTES, + Storage::FileSystem::{ + CREATE_ALWAYS, CREATE_NEW, FILE_FLAG_OPEN_REPARSE_POINT, FILE_GENERIC_WRITE, + FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_WRITE_DATA, OPEN_ALWAYS, + OPEN_EXISTING, TRUNCATE_EXISTING, + }, +}; use crate::{ driver::{op::Op, shared_fd::SharedFd}, @@ -61,6 +74,18 @@ pub struct OpenOptions { pub(crate) mode: libc::mode_t, #[cfg(unix)] pub(crate) custom_flags: libc::c_int, + #[cfg(windows)] + pub(crate) custom_flags: u32, + #[cfg(windows)] + pub(crate) access_mode: Option, + #[cfg(windows)] + pub(crate) attributes: u32, + #[cfg(windows)] + pub(crate) share_mode: u32, + #[cfg(windows)] + pub(crate) security_qos_flags: u32, + #[cfg(windows)] + pub(crate) security_attributes: *mut SECURITY_ATTRIBUTES, } impl OpenOptions { @@ -93,6 +118,18 @@ impl OpenOptions { mode: 0o666, #[cfg(unix)] custom_flags: 0, + #[cfg(windows)] + custom_flags: 0, + #[cfg(windows)] + access_mode: None, + #[cfg(windows)] + share_mode: FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + #[cfg(windows)] + attributes: 0, + #[cfg(windows)] + security_qos_flags: 0, + #[cfg(windows)] + security_attributes: std::ptr::null_mut(), } } @@ -264,7 +301,6 @@ impl OpenOptions { self } - #[cfg(unix)] /// Opens a file at `path` with the options specified by `self`. /// /// # Errors @@ -320,6 +356,7 @@ impl OpenOptions { ))) } + #[cfg(unix)] pub(crate) fn access_mode(&self) -> io::Result { match (self.read, self.write, self.append) { (true, false, false) => Ok(libc::O_RDONLY), @@ -331,6 +368,22 @@ impl OpenOptions { } } + #[cfg(windows)] + pub(crate) fn access_mode(&self) -> io::Result { + match (self.read, self.write, self.append, self.access_mode) { + (.., Some(mode)) => Ok(mode), + (true, false, false, None) => Ok(GENERIC_READ), + (false, true, false, None) => Ok(GENERIC_WRITE), + (true, true, false, None) => Ok(GENERIC_READ | GENERIC_WRITE), + (false, _, true, None) => Ok(FILE_GENERIC_WRITE & !FILE_WRITE_DATA), + (true, _, true, None) => Ok(GENERIC_READ | (FILE_GENERIC_WRITE & !FILE_WRITE_DATA)), + (false, false, false, None) => { + Err(io::Error::from_raw_os_error(ERROR_INVALID_PARAMETER)) + } + } + } + + #[cfg(unix)] pub(crate) fn creation_mode(&self) -> io::Result { match (self.write, self.append) { (true, false) => {} @@ -354,6 +407,43 @@ impl OpenOptions { (_, _, true) => libc::O_CREAT | libc::O_EXCL, }) } + + #[cfg(windows)] + pub(crate) fn creation_mode(&self) -> io::Result { + match (self.write, self.append) { + (true, false) => {} + (false, false) => { + if self.truncate || self.create || self.create_new { + return Err(io::Error::from_raw_os_error(ERROR_INVALID_PARAMETER)); + } + } + (_, true) => { + if self.truncate && !self.create_new { + return Err(io::Error::from_raw_os_error(ERROR_INVALID_PARAMETER)); + } + } + } + + Ok(match (self.create, self.truncate, self.create_new) { + (false, false, false) => OPEN_EXISTING, + (true, false, false) => OPEN_ALWAYS, + (false, true, false) => TRUNCATE_EXISTING, + (true, true, false) => CREATE_ALWAYS, + (_, _, true) => CREATE_NEW, + }) + } + + #[cfg(windows)] + pub(crate) fn get_flags_and_attributes(&self) -> u32 { + self.custom_flags + | self.attributes + | self.security_qos_flags + | if self.create_new { + FILE_FLAG_OPEN_REPARSE_POINT + } else { + 0 + } + } } #[cfg(unix)]