use std::ffi::c_void;
use std::os::windows::io::{FromRawHandle, OwnedHandle};
use std::ptr;
use windows_sys::Win32::Storage::FileSystem::{
CreateFileW, FILE_CREATION_DISPOSITION, FILE_FLAGS_AND_ATTRIBUTES, FILE_SHARE_MODE,
};
use crate::handle::{CapturedHandle, HandleCaptureError};
use crate::outcome::{Outcome, perform_handle};
use crate::path::PreparedPath;
use crate::security::SecurityAttributes;
#[derive(Debug)]
#[must_use = "an unperformed request opens nothing"]
pub struct OpenFile {
path: PreparedPath,
desired_access: u32,
share_mode: FILE_SHARE_MODE,
security: Option<SecurityAttributes>,
creation_disposition: FILE_CREATION_DISPOSITION,
flags_and_attributes: FILE_FLAGS_AND_ATTRIBUTES,
template: Option<CapturedHandle>,
}
impl OpenFile {
pub fn new(path: PreparedPath) -> Self {
Self {
path,
desired_access: 0,
share_mode: 0,
security: None,
creation_disposition: 0,
flags_and_attributes: 0,
template: None,
}
}
pub fn with_desired_access(mut self, desired_access: u32) -> Self {
self.desired_access = desired_access;
self
}
pub fn with_share_mode(mut self, share_mode: FILE_SHARE_MODE) -> Self {
self.share_mode = share_mode;
self
}
pub fn with_security(mut self, security: Option<SecurityAttributes>) -> Self {
self.security = security;
self
}
pub fn with_creation_disposition(
mut self,
creation_disposition: FILE_CREATION_DISPOSITION,
) -> Self {
self.creation_disposition = creation_disposition;
self
}
pub fn with_flags_and_attributes(
mut self,
flags_and_attributes: FILE_FLAGS_AND_ATTRIBUTES,
) -> Self {
self.flags_and_attributes = flags_and_attributes;
self
}
pub fn with_template(mut self, template: Option<CapturedHandle>) -> Self {
self.template = template;
self
}
#[must_use]
pub fn path(&self) -> &PreparedPath {
&self.path
}
#[must_use]
pub fn desired_access(&self) -> u32 {
self.desired_access
}
#[must_use]
pub fn share_mode(&self) -> FILE_SHARE_MODE {
self.share_mode
}
#[must_use]
pub fn security(&self) -> Option<&SecurityAttributes> {
self.security.as_ref()
}
#[must_use]
pub fn creation_disposition(&self) -> FILE_CREATION_DISPOSITION {
self.creation_disposition
}
#[must_use]
pub fn flags_and_attributes(&self) -> FILE_FLAGS_AND_ATTRIBUTES {
self.flags_and_attributes
}
#[must_use]
pub fn template(&self) -> Option<&CapturedHandle> {
self.template.as_ref()
}
pub fn try_clone(&self) -> Result<Self, HandleCaptureError> {
let template = self
.template
.as_ref()
.map(CapturedHandle::try_clone)
.transpose()?;
Ok(Self {
path: self.path.clone(),
desired_access: self.desired_access,
share_mode: self.share_mode,
security: self.security.clone(),
creation_disposition: self.creation_disposition,
flags_and_attributes: self.flags_and_attributes,
template,
})
}
pub fn perform(&self) -> Outcome<OwnedHandle> {
let attributes = self.security.as_ref().map(SecurityAttributes::to_raw);
let attributes_ptr = attributes.as_ref().map_or(ptr::null(), ptr::from_ref);
let template = self
.template
.as_ref()
.map_or(ptr::null_mut(), |handle| handle.raw());
let raw = perform_handle(|| {
unsafe {
CreateFileW(
self.path.as_wtf16_terminated(),
self.desired_access,
self.share_mode,
attributes_ptr,
self.creation_disposition,
self.flags_and_attributes,
template,
)
}
})?;
Ok(unsafe { OwnedHandle::from_raw_handle(raw.cast::<c_void>()) })
}
}
impl crate::request::Request for OpenFile {
type Error = crate::Win32Error;
type Output = OwnedHandle;
fn perform(&self) -> Outcome<OwnedHandle> {
Self::perform(self)
}
}
#[cfg(test)]
mod tests;