use std::io::{Error, ErrorKind};
use thiserror::Error;
use windows::Win32::Foundation::{
ERROR_ACCESS_DENIED, ERROR_ALREADY_EXISTS, ERROR_FILE_NOT_FOUND, ERROR_INVALID_PARAMETER,
};
use windows::Win32::Foundation::{
ERROR_DIRECTORY, ERROR_DIRECTORY_NOT_SUPPORTED, ERROR_FILENAME_EXCED_RANGE,
};
use winfsp_sys::FspNtStatusFromWin32;
#[non_exhaustive]
#[derive(Error, Debug)]
pub enum FspError {
#[error("HRESULT")]
HRESULT(i32),
#[error("WIN32_ERROR")]
WIN32(u32),
#[error("NTRESULT")]
NTSTATUS(i32),
#[error("IO")]
IO(ErrorKind),
}
impl FspError {
#[inline(always)]
pub fn to_ntstatus(&self) -> winfsp_sys::NTSTATUS {
match self {
&FspError::HRESULT(h) => unsafe { FspNtStatusFromWin32(h as u32) },
&FspError::WIN32(e) => {
unsafe { FspNtStatusFromWin32(e) }
}
FspError::IO(e) => {
let win32_equiv = match e {
ErrorKind::NotFound => ERROR_FILE_NOT_FOUND,
ErrorKind::PermissionDenied => ERROR_ACCESS_DENIED,
ErrorKind::AlreadyExists => ERROR_ALREADY_EXISTS,
ErrorKind::InvalidInput => ERROR_INVALID_PARAMETER,
ErrorKind::IsADirectory => ERROR_DIRECTORY_NOT_SUPPORTED,
ErrorKind::NotADirectory => ERROR_DIRECTORY,
ErrorKind::InvalidFilename => ERROR_FILENAME_EXCED_RANGE,
_ => return 0xC00000E9u32 as i32, };
unsafe { FspNtStatusFromWin32(win32_equiv.0) }
}
&FspError::NTSTATUS(e) => e,
}
}
}
pub type Result<T> = std::result::Result<T, FspError>;
impl From<std::io::Error> for FspError {
fn from(e: Error) -> Self {
if let Some(e) = e.raw_os_error() {
FspError::WIN32(e as u32)
} else {
FspError::IO(e.kind())
}
}
}
macro_rules! windows_rs_error {
($windows_crate:ident, $module_name:ident) => {
mod $module_name {
use $windows_crate as windows;
impl From<windows::Win32::Foundation::WIN32_ERROR> for $crate::FspError {
fn from(h: windows::Win32::Foundation::WIN32_ERROR) -> Self {
$crate::FspError::WIN32(h.0)
}
}
impl From<windows::Win32::Foundation::NTSTATUS> for $crate::FspError {
fn from(h: windows::Win32::Foundation::NTSTATUS) -> Self {
$crate::FspError::NTSTATUS(h.0)
}
}
}
};
}
macro_rules! windows_core_rs_error {
($windows_crate:ident, $module_name:ident) => {
mod $module_name {
use $windows_crate as windows;
impl From<windows::core::HRESULT> for $crate::FspError {
fn from(h: windows::core::HRESULT) -> Self {
$crate::FspError::HRESULT(h.0)
}
}
impl From<windows::core::Error> for $crate::FspError {
fn from(e: windows::core::Error) -> Self {
let code = e.code().0 as u32;
if (code & 0x1000_0000) >> 28 == 1 {
let nt_status = code & !(1 << 28);
return $crate::FspError::NTSTATUS(nt_status as i32);
}
match windows::Win32::Foundation::WIN32_ERROR::from_error(&e) {
None => $crate::FspError::HRESULT(e.code().0),
Some(w) => $crate::FspError::WIN32(w.0),
}
}
}
}
};
}
windows_core_rs_error!(windows, windows_rs_error);
windows_rs_error!(windows, windows_core_rs_error);
#[cfg(feature = "windows-60")]
windows_rs_error!(windows_60, windows_60_rs_error);
#[cfg(feature = "windows-56")]
windows_rs_error!(windows_56, windows_56_rs_error);
#[cfg(feature = "windows-56")]
windows_core_rs_error!(windows_56, windows_core_56_rs_error);
#[cfg(feature = "windows-62")]
windows_rs_error!(windows_62, windows_62_rs_error);
#[cfg(feature = "windows-62")]
windows_core_rs_error!(windows_62, windows_62_core_rs_error);