use crate::U16CStr;
use crate::error::Result;
use crate::filesystem::{DirInfo, DirMarker, FileInfo, OpenFileInfo, VolumeInfo};
use std::ffi::c_void;
use windows::Win32::Foundation::STATUS_INVALID_DEVICE_REQUEST;
use winfsp_sys::{
FILE_ACCESS_RIGHTS, FILE_FLAGS_AND_ATTRIBUTES, FSP_FSCTL_TRANSACT_REQ, FSP_FSCTL_TRANSACT_RSP,
PSECURITY_DESCRIPTOR,
};
#[repr(transparent)]
pub struct ModificationDescriptor(pub(crate) PSECURITY_DESCRIPTOR);
impl ModificationDescriptor {
pub fn as_mut_ptr(&self) -> PSECURITY_DESCRIPTOR {
self.0
}
}
#[derive(Debug)]
pub struct FileSecurity {
pub reparse: bool,
pub sz_security_descriptor: u64,
pub attributes: u32,
}
#[allow(unused_variables)]
pub trait FileSystemContext: Sized {
type FileContext: Sized;
fn get_security_by_name(
&self,
file_name: &U16CStr,
security_descriptor: Option<&mut [c_void]>,
reparse_point_resolver: impl FnOnce(&U16CStr) -> Option<FileSecurity>,
) -> Result<FileSecurity>;
fn open(
&self,
file_name: &U16CStr,
create_options: u32,
granted_access: FILE_ACCESS_RIGHTS,
file_info: &mut OpenFileInfo,
) -> Result<Self::FileContext>;
fn close(&self, context: Self::FileContext);
#[allow(clippy::too_many_arguments)]
fn create(
&self,
file_name: &U16CStr,
create_options: u32,
granted_access: FILE_ACCESS_RIGHTS,
file_attributes: FILE_FLAGS_AND_ATTRIBUTES,
security_descriptor: Option<&[c_void]>,
allocation_size: u64,
extra_buffer: Option<&[u8]>,
extra_buffer_is_reparse_point: bool,
file_info: &mut OpenFileInfo,
) -> Result<Self::FileContext> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn cleanup(&self, context: &Self::FileContext, file_name: Option<&U16CStr>, flags: u32) {}
fn flush(&self, context: Option<&Self::FileContext>, file_info: &mut FileInfo) -> Result<()> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn get_file_info(&self, context: &Self::FileContext, file_info: &mut FileInfo) -> Result<()> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn get_security(
&self,
context: &Self::FileContext,
security_descriptor: Option<&mut [c_void]>,
) -> Result<u64> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn set_security(
&self,
context: &Self::FileContext,
security_information: u32,
modification_descriptor: ModificationDescriptor,
) -> Result<()> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn overwrite(
&self,
context: &Self::FileContext,
file_attributes: FILE_FLAGS_AND_ATTRIBUTES,
replace_file_attributes: bool,
allocation_size: u64,
extra_buffer: Option<&[u8]>,
file_info: &mut FileInfo,
) -> Result<()> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn read_directory(
&self,
context: &Self::FileContext,
pattern: Option<&U16CStr>,
marker: DirMarker,
buffer: &mut [u8],
) -> Result<u32> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn rename(
&self,
context: &Self::FileContext,
file_name: &U16CStr,
new_file_name: &U16CStr,
replace_if_exists: bool,
) -> Result<()> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
#[allow(clippy::too_many_arguments)]
fn set_basic_info(
&self,
context: &Self::FileContext,
file_attributes: u32,
creation_time: u64,
last_access_time: u64,
last_write_time: u64,
last_change_time: u64,
file_info: &mut FileInfo,
) -> Result<()> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn set_delete(
&self,
context: &Self::FileContext,
file_name: &U16CStr,
delete_file: bool,
) -> Result<()> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn set_file_size(
&self,
context: &Self::FileContext,
new_size: u64,
set_allocation_size: bool,
file_info: &mut FileInfo,
) -> Result<()> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn read(&self, context: &Self::FileContext, buffer: &mut [u8], offset: u64) -> Result<u32> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn write(
&self,
context: &Self::FileContext,
buffer: &[u8],
offset: u64,
write_to_eof: bool,
constrained_io: bool,
file_info: &mut FileInfo,
) -> Result<u32> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn get_dir_info_by_name(
&self,
context: &Self::FileContext,
file_name: &U16CStr,
out_dir_info: &mut DirInfo,
) -> Result<()> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn get_volume_info(&self, out_volume_info: &mut VolumeInfo) -> Result<()> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn set_volume_label(&self, volume_label: &U16CStr, volume_info: &mut VolumeInfo) -> Result<()> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn get_stream_info(&self, context: &Self::FileContext, buffer: &mut [u8]) -> Result<u32> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn get_reparse_point_by_name(
&self,
file_name: &U16CStr,
is_directory: bool,
buffer: &mut [u8],
) -> Result<u64> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn get_reparse_point(
&self,
context: &Self::FileContext,
file_name: &U16CStr,
buffer: &mut [u8],
) -> Result<u64> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn set_reparse_point(
&self,
context: &Self::FileContext,
file_name: &U16CStr,
buffer: &[u8],
) -> Result<()> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn delete_reparse_point(
&self,
context: &Self::FileContext,
file_name: &U16CStr,
buffer: &[u8],
) -> Result<()> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn get_extended_attributes(
&self,
context: &Self::FileContext,
buffer: &mut [u8],
) -> Result<u32> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn set_extended_attributes(
&self,
context: &Self::FileContext,
buffer: &[u8],
file_info: &mut FileInfo,
) -> Result<()> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn control(
&self,
context: &Self::FileContext,
control_code: u32,
input: &[u8],
output: &mut [u8],
) -> Result<u32> {
Err(STATUS_INVALID_DEVICE_REQUEST.into())
}
fn dispatcher_stopped(&self, normally: bool) {}
unsafe fn with_operation_response<T, F>(&self, f: F) -> Option<T>
where
F: FnOnce(&mut FSP_FSCTL_TRANSACT_RSP) -> T,
{
unsafe {
if let Some(context) = winfsp_sys::FspFileSystemGetOperationContext().as_ref() {
if let Some(response) = context.Response.as_mut() {
return Some(f(response));
}
}
}
None
}
unsafe fn with_operation_request<T, F>(&self, f: F) -> Option<T>
where
F: FnOnce(&FSP_FSCTL_TRANSACT_REQ) -> T,
{
unsafe {
if let Some(context) = winfsp_sys::FspFileSystemGetOperationContext().as_ref() {
if let Some(request) = context.Request.as_ref() {
return Some(f(request));
}
}
}
None
}
}
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "async-io")))]
#[cfg(feature = "async-io")]
#[allow(unused_variables)]
pub trait AsyncFileSystemContext: FileSystemContext + 'static + Sync
where
<Self as FileSystemContext>::FileContext: Sync,
{
fn read_async(
&self,
context: &Self::FileContext,
buffer: &mut [u8],
offset: u64,
) -> impl std::future::Future<Output = Result<u32>> + Send {
async move { Self::read(self, context, buffer, offset) }
}
fn write_async(
&self,
context: &Self::FileContext,
buffer: &[u8],
offset: u64,
write_to_eof: bool,
constrained_io: bool,
file_info: &mut FileInfo,
) -> impl std::future::Future<Output = Result<u32>> + Send {
async move {
Self::write(
self,
context,
buffer,
offset,
write_to_eof,
constrained_io,
file_info,
)
}
}
fn read_directory_async(
&self,
context: &Self::FileContext,
pattern: Option<&U16CStr>,
marker: DirMarker<'_>,
buffer: &mut [u8],
) -> impl std::future::Future<Output = Result<u32>> + Send {
async move { Self::read_directory(self, context, pattern, marker, buffer) }
}
fn spawn_task(&self, future: impl std::future::Future<Output = ()> + Send + 'static);
}