From 3eddb099687bd389e81d01bcf0164dc3e2c376f1 Mon Sep 17 00:00:00 2001 From: Evan Martin Date: Sun, 22 Sep 2024 20:45:38 -0700 Subject: [PATCH] ERROR enum for win32 errors --- cli/src/host.rs | 53 +++---- cli/src/main.rs | 3 +- web/glue/src/host.rs | 22 +-- win32/src/host.rs | 21 +-- win32/src/winapi/error.rs | 36 +++++ win32/src/winapi/kernel32/dll.rs | 2 +- win32/src/winapi/kernel32/file.rs | 229 +++++++++++++----------------- win32/src/winapi/kernel32/misc.rs | 20 +-- win32/src/winapi/kernel32/time.rs | 9 +- win32/src/winapi/mod.rs | 3 + win32/src/winapi/types.rs | 39 ----- 11 files changed, 204 insertions(+), 233 deletions(-) create mode 100644 win32/src/winapi/error.rs diff --git a/cli/src/host.rs b/cli/src/host.rs index 41f18aeba..99926bcd8 100644 --- a/cli/src/host.rs +++ b/cli/src/host.rs @@ -6,23 +6,22 @@ use std::path::{Path, PathBuf}; use std::time::{SystemTime, UNIX_EPOCH}; use std::{cell::RefCell, io::Write, rc::Rc}; use typed_path::{UnixPath, WindowsPath, WindowsPathBuf}; -use win32::winapi::types::io_error_to_win32; -use win32::{FileOptions, ReadDir, Stat}; +use win32::{FileOptions, ReadDir, Stat, ERROR}; struct File { f: std::fs::File, } impl win32::File for File { - fn stat(&self) -> Result { + fn stat(&self) -> Result { match self.f.metadata() { Ok(ref meta) => Ok(metadata_to_stat(meta)), - Err(ref e) => Err(io_error_to_win32(e)), + Err(ref e) => Err(ERROR::from_io_error(e)), } } - fn set_len(&self, len: u64) -> Result<(), u32> { - self.f.set_len(len).map_err(|e| io_error_to_win32(&e)) + fn set_len(&self, len: u64) -> Result<(), ERROR> { + self.f.set_len(len).map_err(|e| ERROR::from_io_error(&e)) } } @@ -53,7 +52,7 @@ struct ReadDirIter { } impl ReadDir for ReadDirIter { - fn next(&mut self) -> Result, u32> { + fn next(&mut self) -> Result, ERROR> { match self.iter.next() { Some(Ok(entry)) => { let name = entry @@ -68,7 +67,7 @@ impl ReadDir for ReadDirIter { stat: metadata_to_stat(&meta), })) } - Some(Err(ref e)) => Err(io_error_to_win32(e)), + Some(Err(ref e)) => Err(ERROR::from_io_error(e)), None => Ok(None), } } @@ -80,7 +79,7 @@ struct ReadDirFile { } impl ReadDir for ReadDirFile { - fn next(&mut self) -> Result, u32> { + fn next(&mut self) -> Result, ERROR> { if self.consumed { Ok(None) } else { @@ -145,12 +144,16 @@ impl win32::Host for EnvRef { gui.block(wait) } - fn current_dir(&self) -> Result { - let path = std::env::current_dir().map_err(|e| io_error_to_win32(&e))?; + fn current_dir(&self) -> Result { + let path = std::env::current_dir().map_err(|e| ERROR::from_io_error(&e))?; Ok(host_to_windows_path(&path)) } - fn open(&self, path: &WindowsPath, options: FileOptions) -> Result, u32> { + fn open( + &self, + path: &WindowsPath, + options: FileOptions, + ) -> Result, ERROR> { let path = windows_to_host_path(path); let result = std::fs::File::options() .read(options.read) @@ -161,30 +164,30 @@ impl win32::Host for EnvRef { .open(path); match result { Ok(f) => Ok(Box::new(File { f })), - Err(ref e) => Err(io_error_to_win32(e)), + Err(ref e) => Err(ERROR::from_io_error(e)), } } - fn stat(&self, path: &WindowsPath) -> Result { + fn stat(&self, path: &WindowsPath) -> Result { let path = windows_to_host_path(path); match std::fs::metadata(path) { Ok(ref meta) => Ok(metadata_to_stat(meta)), - Err(ref e) => Err(io_error_to_win32(e)), + Err(ref e) => Err(ERROR::from_io_error(e)), } } - fn read_dir(&self, path: &WindowsPath) -> Result, u32> { + fn read_dir(&self, path: &WindowsPath) -> Result, ERROR> { let path = windows_to_host_path(path); let full_path = match std::fs::canonicalize(path) { Ok(p) => p, - Err(ref e) => return Err(io_error_to_win32(e)), + Err(ref e) => return Err(ERROR::from_io_error(e)), }; match std::fs::metadata(&full_path) { Ok(meta) => { if meta.is_dir() { let iter = match std::fs::read_dir(&full_path) { Ok(iter) => iter, - Err(ref e) => return Err(io_error_to_win32(e)), + Err(ref e) => return Err(ERROR::from_io_error(e)), }; Ok(Box::new(ReadDirIter { iter })) } else { @@ -203,23 +206,23 @@ impl win32::Host for EnvRef { })) } } - Err(ref e) => Err(io_error_to_win32(e)), + Err(ref e) => Err(ERROR::from_io_error(e)), } } - fn create_dir(&self, path: &WindowsPath) -> Result<(), u32> { + fn create_dir(&self, path: &WindowsPath) -> Result<(), ERROR> { let path = windows_to_host_path(path); - std::fs::create_dir(path).map_err(|e| io_error_to_win32(&e)) + std::fs::create_dir(path).map_err(|e| ERROR::from_io_error(&e)) } - fn remove_file(&self, path: &WindowsPath) -> Result<(), u32> { + fn remove_file(&self, path: &WindowsPath) -> Result<(), ERROR> { let path = windows_to_host_path(path); - std::fs::remove_file(path).map_err(|e| io_error_to_win32(&e)) + std::fs::remove_file(path).map_err(|e| ERROR::from_io_error(&e)) } - fn remove_dir(&self, path: &WindowsPath) -> Result<(), u32> { + fn remove_dir(&self, path: &WindowsPath) -> Result<(), ERROR> { let path = windows_to_host_path(path); - std::fs::remove_dir(path).map_err(|e| io_error_to_win32(&e)) + std::fs::remove_dir(path).map_err(|e| ERROR::from_io_error(&e)) } fn log(&self, buf: &[u8]) { diff --git a/cli/src/main.rs b/cli/src/main.rs index 51627288c..c815ab815 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -12,7 +12,6 @@ mod resv32; use anyhow::anyhow; use std::borrow::Cow; use std::process::ExitCode; -use win32::winapi::types::win32_error_str; use win32::Host; #[derive(argh::FromArgs)] @@ -125,7 +124,7 @@ fn main() -> anyhow::Result { let mut cmdline = args.cmdline.clone(); let cwd = host .current_dir() - .map_err(|e| anyhow!("failed to get current dir: {}", win32_error_str(e)))?; + .map_err(|e| anyhow!("failed to get current dir: {e:?}"))?; cmdline[0] = cwd .join(&cmdline[0]) .normalize() diff --git a/web/glue/src/host.rs b/web/glue/src/host.rs index 8bb437d5b..271f6ca87 100644 --- a/web/glue/src/host.rs +++ b/web/glue/src/host.rs @@ -2,7 +2,7 @@ use anyhow::bail; use wasm_bindgen::prelude::*; -use win32::{ReadDir, Stat, StatKind, WindowsPath}; +use win32::{ReadDir, Stat, StatKind, WindowsPath, ERROR}; struct WebSurface { _hwnd: u32, @@ -145,7 +145,7 @@ extern "C" { } impl win32::File for JsFile { - fn stat(&self) -> Result { + fn stat(&self) -> Result { Ok(Stat { kind: StatKind::File, size: JsFile::info(self), @@ -155,7 +155,7 @@ impl win32::File for JsFile { }) } - fn set_len(&self, len: u64) -> Result<(), u32> { + fn set_len(&self, len: u64) -> Result<(), ERROR> { todo!("set_len {len}") } } @@ -313,18 +313,18 @@ impl win32::Host for JsHost { &self, path: &WindowsPath, options: win32::FileOptions, - ) -> Result, u32> { + ) -> Result, ERROR> { match JsHost::open(self, &path.to_string_lossy(), options) { Some(file) => Ok(Box::new(file)), - None => Err(win32::winapi::types::ERROR_FILE_NOT_FOUND), + None => Err(ERROR::FILE_NOT_FOUND), } } - fn stat(&self, path: &WindowsPath) -> Result { + fn stat(&self, path: &WindowsPath) -> Result { todo!("stat {path}") } - fn read_dir(&self, path: &WindowsPath) -> Result, u32> { + fn read_dir(&self, path: &WindowsPath) -> Result, ERROR> { todo!("read_dir {path}") } @@ -345,19 +345,19 @@ impl win32::Host for JsHost { Box::new(WebSurface::new(hwnd, opts, JsHost::screen(self))) } - fn current_dir(&self) -> Result { + fn current_dir(&self) -> Result { todo!() } - fn create_dir(&self, path: &WindowsPath) -> Result<(), u32> { + fn create_dir(&self, path: &WindowsPath) -> Result<(), ERROR> { todo!("create_dir {path}") } - fn remove_file(&self, path: &WindowsPath) -> Result<(), u32> { + fn remove_file(&self, path: &WindowsPath) -> Result<(), ERROR> { todo!("remove_file {path}") } - fn remove_dir(&self, path: &WindowsPath) -> Result<(), u32> { + fn remove_dir(&self, path: &WindowsPath) -> Result<(), ERROR> { todo!("remove_dir {path}") } } diff --git a/win32/src/host.rs b/win32/src/host.rs index a1d9d1c39..0afce5d5c 100644 --- a/win32/src/host.rs +++ b/win32/src/host.rs @@ -1,5 +1,6 @@ //! Interfaces expected of the x86 host. +pub use crate::winapi::ERROR; pub use typed_path::{WindowsPath, WindowsPathBuf}; /// DirectDraw surface. @@ -65,12 +66,12 @@ impl FileOptions { } pub trait File: std::io::Read + std::io::Write + std::io::Seek { - fn stat(&self) -> Result; - fn set_len(&self, len: u64) -> Result<(), u32>; + fn stat(&self) -> Result; + fn set_len(&self, len: u64) -> Result<(), ERROR>; } pub trait ReadDir { - fn next(&mut self) -> Result, u32>; + fn next(&mut self) -> Result, ERROR>; } #[derive(Debug, Clone)] @@ -141,19 +142,19 @@ pub trait Host { fn block(&self, wait: Option) -> bool; /// Retrieves the absolute (Windows-style) path of the current working directory. - fn current_dir(&self) -> Result; + fn current_dir(&self) -> Result; /// Open a file at the given (Windows-style) path. - fn open(&self, path: &WindowsPath, options: FileOptions) -> Result, u32>; + fn open(&self, path: &WindowsPath, options: FileOptions) -> Result, ERROR>; /// Retrieve file or directory metadata at the given (Windows-style) path. - fn stat(&self, path: &WindowsPath) -> Result; + fn stat(&self, path: &WindowsPath) -> Result; /// Iterate the contents of a directory at the given (Windows-style) path. - fn read_dir(&self, path: &WindowsPath) -> Result, u32>; + fn read_dir(&self, path: &WindowsPath) -> Result, ERROR>; /// Create a new directory at the given (Windows-style) path. - fn create_dir(&self, path: &WindowsPath) -> Result<(), u32>; + fn create_dir(&self, path: &WindowsPath) -> Result<(), ERROR>; /// Remove a file at the given (Windows-style) path. - fn remove_file(&self, path: &WindowsPath) -> Result<(), u32>; + fn remove_file(&self, path: &WindowsPath) -> Result<(), ERROR>; /// Remove a directory at the given (Windows-style) path. - fn remove_dir(&self, path: &WindowsPath) -> Result<(), u32>; + fn remove_dir(&self, path: &WindowsPath) -> Result<(), ERROR>; fn log(&self, buf: &[u8]); fn create_window(&mut self, hwnd: u32) -> Box; diff --git a/win32/src/winapi/error.rs b/win32/src/winapi/error.rs new file mode 100644 index 000000000..def5fbb28 --- /dev/null +++ b/win32/src/winapi/error.rs @@ -0,0 +1,36 @@ +// https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499- + +/// Windows error codes. +#[allow(non_camel_case_types)] +#[derive(Debug, win32_derive::TryFromEnum)] +pub enum ERROR { + SUCCESS = 0, + FILE_NOT_FOUND = 2, + ACCESS_DENIED = 5, + INVALID_HANDLE = 6, + INVALID_ACCESS = 12, + INVALID_DATA = 13, + FILE_EXISTS = 80, + OPEN_FAILED = 110, + MOD_NOT_FOUND = 126, + ALREADY_EXISTS = 183, +} + +impl ERROR { + pub fn from_io_error(err: &std::io::Error) -> ERROR { + match err.kind() { + std::io::ErrorKind::NotFound => ERROR::FILE_NOT_FOUND, + std::io::ErrorKind::PermissionDenied => ERROR::ACCESS_DENIED, + std::io::ErrorKind::InvalidData => ERROR::INVALID_DATA, + std::io::ErrorKind::AlreadyExists => ERROR::FILE_EXISTS, + std::io::ErrorKind::InvalidInput => ERROR::INVALID_ACCESS, + _ => ERROR::OPEN_FAILED, + } + } +} + +impl From for u32 { + fn from(err: ERROR) -> u32 { + err as u32 + } +} diff --git a/win32/src/winapi/kernel32/dll.rs b/win32/src/winapi/kernel32/dll.rs index da6e2bb15..e7fb0f5f7 100644 --- a/win32/src/winapi/kernel32/dll.rs +++ b/win32/src/winapi/kernel32/dll.rs @@ -66,7 +66,7 @@ pub fn GetModuleHandleA(machine: &mut Machine, lpModuleName: Option<&str>) -> HM return *hmodule; } - set_last_error(machine, ERROR_MOD_NOT_FOUND); + set_last_error(machine, winapi::ERROR::MOD_NOT_FOUND); return HMODULE::null(); } diff --git a/win32/src/winapi/kernel32/file.rs b/win32/src/winapi/kernel32/file.rs index 79e7b8a12..82d25ff89 100644 --- a/win32/src/winapi/kernel32/file.rs +++ b/win32/src/winapi/kernel32/file.rs @@ -1,10 +1,8 @@ use crate::str16::String16; use crate::winapi::kernel32::set_last_error; use crate::winapi::stack_args::ToX86; -use crate::winapi::types::{ - io_error_to_win32, win32_error_str, DWORD, ERROR_FILE_NOT_FOUND, ERROR_INVALID_DATA, - ERROR_INVALID_HANDLE, ERROR_SUCCESS, HFIND, MAX_PATH, -}; +use crate::winapi::types::{DWORD, HFIND, MAX_PATH}; +use crate::winapi::ERROR; use crate::{ machine::Machine, winapi::{ @@ -155,7 +153,7 @@ pub fn CreateFileA( ) -> HFILE { let Some(file_name) = lpFileName else { log::debug!("CreateFileA failed: null lpFileName"); - set_last_error(machine, ERROR_INVALID_DATA); + set_last_error(machine, ERROR::INVALID_DATA); return HFILE::invalid(); }; @@ -165,7 +163,7 @@ pub fn CreateFileA( Ok(value) => value, Err(value) => { log::debug!("CreateFileA({file_name:?}) failed: invalid dwCreationDisposition {value}"); - set_last_error(machine, ERROR_INVALID_DATA); + set_last_error(machine, ERROR::INVALID_DATA); return HFILE::invalid(); } }; @@ -197,15 +195,12 @@ pub fn CreateFileA( let path = WindowsPath::new(file_name); match machine.host.open(path, file_options) { Ok(file) => { - set_last_error(machine, ERROR_SUCCESS); + set_last_error(machine, ERROR::SUCCESS); machine.state.kernel32.files.add(file) } - Err(code) => { - log::debug!( - "CreateFileA({file_name:?}) failed: {}", - win32_error_str(code) - ); - set_last_error(machine, code); + Err(err) => { + log::debug!("CreateFileA({file_name:?}) failed: {err:?}",); + set_last_error(machine, err); HFILE::invalid() } } @@ -337,19 +332,16 @@ pub fn GetFileInformationByHandle( Some(f) => f, None => { log::debug!("GetFileInformationByHandle({hFile:?}) unknown handle"); - set_last_error(machine, ERROR_INVALID_DATA); + set_last_error(machine, ERROR::INVALID_DATA); return false; } }; let stat = match file.stat() { Ok(stat) => stat, - Err(code) => { - log::debug!( - "GetFileInformationByHandle({hFile:?}) failed: {}", - win32_error_str(code) - ); - set_last_error(machine, code); + Err(err) => { + log::debug!("GetFileInformationByHandle({hFile:?}) failed: {err:?}",); + set_last_error(machine, err); return false; } }; @@ -358,7 +350,7 @@ pub fn GetFileInformationByHandle( *info = BY_HANDLE_FILE_INFORMATION::from(&stat); } - set_last_error(machine, ERROR_SUCCESS); + set_last_error(machine, ERROR::SUCCESS); true } @@ -383,7 +375,7 @@ pub fn SetFilePointer( } let Some(file) = machine.state.kernel32.files.get_mut(hFile) else { log::debug!("SetFilePointer({hFile:?}) unknown handle"); - set_last_error(machine, ERROR_INVALID_HANDLE); + set_last_error(machine, ERROR::INVALID_HANDLE); return u32::MAX; }; let seek = match dwMoveMethod.unwrap() { @@ -395,7 +387,7 @@ pub fn SetFilePointer( Ok(pos) => pos, Err(err) => { log::debug!("SetFilePointer({hFile:?}) failed: {:?}", err); - set_last_error(machine, io_error_to_win32(&err)); + set_last_error(machine, ERROR::from_io_error(&err)); return u32::MAX; } }; @@ -403,10 +395,10 @@ pub fn SetFilePointer( *high = (pos >> 32) as i32; } else if pos >> 32 != 0 { log::debug!("SetFilePointer({hFile:?}) overflow"); - set_last_error(machine, ERROR_INVALID_DATA); + set_last_error(machine, ERROR::INVALID_DATA); return u32::MAX; } - set_last_error(machine, ERROR_SUCCESS); + set_last_error(machine, ERROR::SUCCESS); pos as u32 } @@ -427,7 +419,7 @@ pub fn ReadFile( _ => machine.state.kernel32.files.get_mut(hFile), }) else { log::debug!("ReadFile({hFile:?}) unknown handle"); - set_last_error(machine, ERROR_INVALID_HANDLE); + set_last_error(machine, ERROR::INVALID_HANDLE); return false; }; if lpOverlapped != 0 { @@ -435,7 +427,7 @@ pub fn ReadFile( } let Some(mut buf) = lpBuffer.to_option() else { log::debug!("ReadFile({hFile:?}) failed: null lpBuffer"); - set_last_error(machine, ERROR_INVALID_DATA); + set_last_error(machine, ERROR::INVALID_DATA); return false; }; @@ -449,13 +441,13 @@ pub fn ReadFile( } Err(err) => { log::debug!("ReadFile({hFile:?}) failed: {:?}", err); - set_last_error(machine, io_error_to_win32(&err)); + set_last_error(machine, ERROR::from_io_error(&err)); return false; } } } - set_last_error(machine, ERROR_SUCCESS); + set_last_error(machine, ERROR::SUCCESS); if let Some(bytes) = lpNumberOfBytesRead { *bytes = read as u32; } @@ -479,7 +471,7 @@ pub fn WriteFile( } let Some(mut buf) = lpBuffer else { log::debug!("WriteFile({hFile:?}) failed: null lpBuffer"); - set_last_error(machine, ERROR_INVALID_DATA); + set_last_error(machine, ERROR::INVALID_DATA); return false; }; @@ -491,7 +483,7 @@ pub fn WriteFile( _ => { let Some(file) = machine.state.kernel32.files.get_mut(hFile) else { log::debug!("WriteFile({hFile:?}) unknown handle"); - set_last_error(machine, ERROR_INVALID_HANDLE); + set_last_error(machine, ERROR::INVALID_HANDLE); return false; }; let mut written = 0; @@ -504,7 +496,7 @@ pub fn WriteFile( } Err(err) => { log::debug!("WriteFile({hFile:?}) failed: {:?}", err); - set_last_error(machine, io_error_to_win32(&err)); + set_last_error(machine, ERROR::from_io_error(&err)); return false; } } @@ -513,7 +505,7 @@ pub fn WriteFile( } }; - set_last_error(machine, ERROR_SUCCESS); + set_last_error(machine, ERROR::SUCCESS); if let Some(written) = lpNumberOfBytesWritten { *written = n as u32; } @@ -540,25 +532,22 @@ pub fn GetFullPathNameA( ) -> u32 { let Some(file_name) = lpFileName else { log::debug!("GetFullPathNameA failed: null lpFileName"); - set_last_error(machine, ERROR_INVALID_DATA); + set_last_error(machine, ERROR::INVALID_DATA); return 0; }; let cwd = match machine.host.current_dir() { Ok(value) => value, - Err(code) => { - log::debug!( - "GetFullPathNameA({file_name:?}) failed: {}", - win32_error_str(code) - ); - set_last_error(machine, code); + Err(err) => { + log::debug!("GetFullPathNameA({file_name:?}) failed: {err:?}",); + set_last_error(machine, err); return 0; } }; let out_path = cwd.join(file_name).normalize(); let out_bytes = out_path.as_bytes(); - set_last_error(machine, ERROR_SUCCESS); + set_last_error(machine, ERROR::SUCCESS); let buf = machine.mem().sub32_mut(lpBuffer, nBufferLength); if let Some(part) = lpFilePart { @@ -598,26 +587,23 @@ pub fn GetFullPathNameW( ) -> u32 { let Some(file_name) = lpFileName else { log::debug!("GetFullPathNameW failed: null lpFileName"); - set_last_error(machine, ERROR_INVALID_DATA); + set_last_error(machine, ERROR::INVALID_DATA); return 0; }; let file_name = file_name.to_string(); let cwd = match machine.host.current_dir() { Ok(value) => value, - Err(code) => { - log::debug!( - "GetFullPathNameW({file_name:?}) failed: {}", - win32_error_str(code) - ); - set_last_error(machine, code); + Err(err) => { + log::debug!("GetFullPathNameW({file_name:?}) failed: {err:?}",); + set_last_error(machine, err); return 0; } }; let out_path = cwd.join(&file_name).normalize(); let out_bytes = String16::from(out_path.to_string_lossy().as_ref()).0; - set_last_error(machine, ERROR_SUCCESS); + set_last_error(machine, ERROR::SUCCESS); let buf = Str16::from_bytes_mut(machine.mem().sub32_mut(lpBuffer, nBufferLength * 2)); if let Some(part) = lpFilePart { @@ -651,22 +637,19 @@ pub fn GetFullPathNameW( pub fn DeleteFileA(machine: &mut Machine, lpFileName: Option<&str>) -> bool { let Some(file_name) = lpFileName else { log::debug!("DeleteFileA failed: null lpFileName"); - set_last_error(machine, ERROR_INVALID_DATA); + set_last_error(machine, ERROR::INVALID_DATA); return false; }; let path = WindowsPath::new(file_name); match machine.host.remove_file(path) { Ok(()) => { - set_last_error(machine, ERROR_SUCCESS); + set_last_error(machine, ERROR::SUCCESS); true } - Err(code) => { - log::debug!( - "DeleteFileA({file_name:?}) failed: {}", - win32_error_str(code) - ); - set_last_error(machine, code); + Err(err) => { + log::debug!("DeleteFileA({file_name:?}) failed: {err:?}",); + set_last_error(machine, err); false } } @@ -676,22 +659,19 @@ pub fn DeleteFileA(machine: &mut Machine, lpFileName: Option<&str>) -> bool { pub fn RemoveDirectoryA(machine: &mut Machine, lpPathName: Option<&str>) -> bool { let Some(path_name) = lpPathName else { log::debug!("RemoveDirectoryA failed: null lpPathName"); - set_last_error(machine, ERROR_INVALID_DATA); + set_last_error(machine, ERROR::INVALID_DATA); return false; }; let path = WindowsPath::new(path_name); match machine.host.remove_dir(path) { Ok(()) => { - set_last_error(machine, ERROR_SUCCESS); + set_last_error(machine, ERROR::SUCCESS); true } - Err(code) => { - log::debug!( - "RemoveDirectoryA({path_name:?}) failed: {}", - win32_error_str(code) - ); - set_last_error(machine, code); + Err(err) => { + log::debug!("RemoveDirectoryA({path_name:?}) failed: {err:?}",); + set_last_error(machine, err); false } } @@ -701,24 +681,21 @@ pub fn RemoveDirectoryA(machine: &mut Machine, lpPathName: Option<&str>) -> bool pub fn GetFileAttributesA(machine: &mut Machine, lpFileName: Option<&str>) -> FileAttribute { let Some(file_name) = lpFileName else { log::debug!("CreateFileA failed: null lpFileName"); - set_last_error(machine, ERROR_INVALID_DATA); + set_last_error(machine, ERROR::INVALID_DATA); return FileAttribute::INVALID; }; let path = WindowsPath::new(file_name); let stat = match machine.host.stat(path) { Ok(stat) => stat, - Err(code) => { - log::debug!( - "GetFileAttributesA({file_name:?}) failed: {}", - win32_error_str(code) - ); - set_last_error(machine, code); + Err(err) => { + log::debug!("GetFileAttributesA({file_name:?}) failed: {err:?}",); + set_last_error(machine, err); return FileAttribute::INVALID; } }; - set_last_error(machine, ERROR_SUCCESS); + set_last_error(machine, ERROR::SUCCESS); match stat.kind { StatKind::File => FileAttribute::NORMAL, @@ -731,9 +708,9 @@ pub fn GetFileAttributesA(machine: &mut Machine, lpFileName: Option<&str>) -> Fi pub fn GetCurrentDirectoryA(machine: &mut Machine, nBufferLength: u32, lpBuffer: u32) -> u32 { let cwd = match machine.host.current_dir() { Ok(value) => value, - Err(code) => { - log::debug!("GetCurrentDirectoryA failed: {}", win32_error_str(code)); - set_last_error(machine, code); + Err(err) => { + log::debug!("GetCurrentDirectoryA failed: {err:?}"); + set_last_error(machine, err); return 0; } }; @@ -750,7 +727,7 @@ pub fn GetCurrentDirectoryA(machine: &mut Machine, nBufferLength: u32, lpBuffer: buf[..out_bytes.len()].copy_from_slice(out_bytes); buf[out_bytes.len()] = 0; - set_last_error(machine, ERROR_SUCCESS); + set_last_error(machine, ERROR::SUCCESS); out_bytes.len() as u32 } @@ -812,7 +789,7 @@ pub fn FindFirstFileA( ) -> HFIND { let Some(file_name) = lpFileName else { log::debug!("FindFirstFileA failed: null lpFileName"); - set_last_error(machine, ERROR_INVALID_DATA); + set_last_error(machine, ERROR::INVALID_DATA); return HFIND::invalid(); }; @@ -820,14 +797,14 @@ pub fn FindFirstFileA( let parent = path.parent().unwrap_or(WindowsPath::new(".")); let Some(pattern) = path.file_name() else { log::debug!("FindFirstFileA({file_name:?}) no file name"); - set_last_error(machine, ERROR_INVALID_DATA); + set_last_error(machine, ERROR::INVALID_DATA); return HFIND::invalid(); }; let mut pattern = match String::from_utf8(pattern.to_vec()) { Ok(value) => value, Err(e) => { log::debug!("FindFirstFileA({file_name:?}) invalid file name: {:?}", e); - set_last_error(machine, ERROR_INVALID_DATA); + set_last_error(machine, ERROR::INVALID_DATA); return HFIND::invalid(); } }; @@ -837,12 +814,9 @@ pub fn FindFirstFileA( let mut read_dir = match machine.host.read_dir(parent) { Ok(handle) => handle, - Err(code) => { - log::debug!( - "FindFirstFileA({file_name:?}) failed: {}", - win32_error_str(code) - ); - set_last_error(machine, code); + Err(err) => { + log::debug!("FindFirstFileA({file_name:?}) failed: {err:?}",); + set_last_error(machine, err); return HFIND::invalid(); } }; @@ -856,15 +830,12 @@ pub fn FindFirstFileA( } Ok(None) => { log::debug!("FindFirstFileA({file_name:?}) not found"); - set_last_error(machine, ERROR_FILE_NOT_FOUND); + set_last_error(machine, ERROR::FILE_NOT_FOUND); return HFIND::invalid(); } - Err(code) => { - log::debug!( - "FindFirstFileA({file_name:?}) failed: {}", - win32_error_str(code) - ); - set_last_error(machine, code); + Err(err) => { + log::debug!("FindFirstFileA({file_name:?}) failed: {err:?}",); + set_last_error(machine, err); return HFIND::invalid(); } } @@ -874,7 +845,7 @@ pub fn FindFirstFileA( *data = WIN32_FIND_DATAA::from(&next); } - set_last_error(machine, ERROR_SUCCESS); + set_last_error(machine, ERROR::SUCCESS); machine .state .kernel32 @@ -892,7 +863,7 @@ pub fn FindNextFileA( Some(handle) => handle, None => { log::debug!("FindNextFileA({hFindFile:?}) unknown handle"); - set_last_error(machine, ERROR_INVALID_HANDLE); + set_last_error(machine, ERROR::INVALID_HANDLE); return false; } }; @@ -905,15 +876,12 @@ pub fn FindNextFileA( } } Ok(None) => { - set_last_error(machine, ERROR_FILE_NOT_FOUND); + set_last_error(machine, ERROR::FILE_NOT_FOUND); return false; } - Err(code) => { - log::debug!( - "FindNextFileA({hFindFile:?}) failed: {}", - win32_error_str(code) - ); - set_last_error(machine, code); + Err(err) => { + log::debug!("FindNextFileA({hFindFile:?}) failed: {err:?}",); + set_last_error(machine, err); return false; } }; @@ -923,7 +891,7 @@ pub fn FindNextFileA( *data = WIN32_FIND_DATAA::from(&next); } - set_last_error(machine, ERROR_SUCCESS); + set_last_error(machine, ERROR::SUCCESS); true } @@ -937,11 +905,11 @@ pub fn FindClose(machine: &mut Machine, hFindFile: HFIND) -> bool { .is_none() { log::debug!("FindClose({hFindFile:?}): unknown handle"); - set_last_error(machine, ERROR_INVALID_HANDLE); + set_last_error(machine, ERROR::INVALID_HANDLE); return false; } - set_last_error(machine, ERROR_SUCCESS); + set_last_error(machine, ERROR::SUCCESS); true } @@ -951,21 +919,21 @@ pub fn GetFileSize(machine: &mut Machine, hFile: HFILE, lpFileSizeHigh: Option<& Some(f) => f, None => { log::debug!("GetFileSize({hFile:?}) unknown handle"); - set_last_error(machine, ERROR_INVALID_HANDLE); + set_last_error(machine, ERROR::INVALID_HANDLE); return u32::MAX; } }; let stat = match file.stat() { Ok(stat) => stat, - Err(code) => { - log::debug!("GetFileSize({hFile:?}) failed: {}", win32_error_str(code)); - set_last_error(machine, code); + Err(err) => { + log::debug!("GetFileSize({hFile:?}) failed: {err:?}"); + set_last_error(machine, err); return u32::MAX; } }; - set_last_error(machine, ERROR_SUCCESS); + set_last_error(machine, ERROR::SUCCESS); if let Some(high) = lpFileSizeHigh { *high = (stat.size >> 32) as u32; @@ -988,16 +956,16 @@ pub fn GetFileTime( Some(f) => f, None => { log::debug!("GetFileTime({hFile:?}) unknown handle"); - set_last_error(machine, ERROR_INVALID_HANDLE); + set_last_error(machine, ERROR::INVALID_HANDLE); return false; } }; let stat = match file.stat() { Ok(stat) => stat, - Err(code) => { - log::debug!("GetFileTime({hFile:?}) failed: {}", win32_error_str(code)); - set_last_error(machine, code); + Err(error) => { + log::debug!("GetFileTime({hFile:?}) failed: {error:?}"); + set_last_error(machine, error); return false; } }; @@ -1012,7 +980,7 @@ pub fn GetFileTime( *time = FILETIME::from_unix_nanos(stat.mtime); } - set_last_error(machine, ERROR_SUCCESS); + set_last_error(machine, ERROR::SUCCESS); true } @@ -1022,7 +990,7 @@ pub fn SetEndOfFile(machine: &mut Machine, hFile: HFILE) -> bool { Some(f) => f, None => { log::debug!("SetEndOfFile({hFile:?}) unknown handle"); - set_last_error(machine, ERROR_INVALID_HANDLE); + set_last_error(machine, ERROR::INVALID_HANDLE); return false; } }; @@ -1031,17 +999,17 @@ pub fn SetEndOfFile(machine: &mut Machine, hFile: HFILE) -> bool { Ok(pos) => pos, Err(err) => { log::debug!("SetEndOfFile({hFile:?}) failed: {:?}", err); - set_last_error(machine, io_error_to_win32(&err)); + set_last_error(machine, ERROR::from_io_error(&err)); return false; } }; match file.set_len(len) { Ok(()) => { - set_last_error(machine, ERROR_SUCCESS); + set_last_error(machine, ERROR::SUCCESS); true } Err(err) => { - log::debug!("SetEndOfFile({hFile:?}) failed: {:?}", win32_error_str(err)); + log::debug!("SetEndOfFile({hFile:?}) failed: {err:?}",); set_last_error(machine, err); false } @@ -1056,22 +1024,19 @@ pub fn CreateDirectoryA( ) -> bool { let Some(path_name) = lpPathName else { log::debug!("CreateDirectoryA failed: null lpPathName"); - set_last_error(machine, ERROR_INVALID_DATA); + set_last_error(machine, ERROR::INVALID_DATA); return false; }; let path = WindowsPath::new(path_name); match machine.host.create_dir(path) { Ok(()) => { - set_last_error(machine, ERROR_SUCCESS); + set_last_error(machine, ERROR::SUCCESS); true } - Err(code) => { - log::debug!( - "CreateDirectoryA({path_name:?}) failed: {}", - win32_error_str(code) - ); - set_last_error(machine, code); + Err(error) => { + log::debug!("CreateDirectoryA({path_name:?}) failed: {error:?}",); + set_last_error(machine, error); false } } @@ -1085,7 +1050,7 @@ pub fn SetFileAttributesA( ) -> bool { let Some(file_name) = lpFileName else { log::debug!("SetFileAttributesA failed: null lpFileName"); - set_last_error(machine, ERROR_INVALID_DATA); + set_last_error(machine, ERROR::INVALID_DATA); return false; }; dwFileAttributes.unwrap(); @@ -1107,16 +1072,16 @@ pub fn SetFileTime( Some(f) => f, None => { log::debug!("SetFileTime({hFile:?}) unknown handle"); - set_last_error(machine, ERROR_INVALID_HANDLE); + set_last_error(machine, ERROR::INVALID_HANDLE); return false; } }; let mut stat = match file.stat() { Ok(stat) => stat, - Err(code) => { - log::debug!("SetFileTime({hFile:?}) failed: {}", win32_error_str(code)); - set_last_error(machine, code); + Err(error) => { + log::debug!("SetFileTime({hFile:?}) failed: {error:?}"); + set_last_error(machine, error); return false; } }; diff --git a/win32/src/winapi/kernel32/misc.rs b/win32/src/winapi/kernel32/misc.rs index d6d064724..dd236b9e8 100644 --- a/win32/src/winapi/kernel32/misc.rs +++ b/win32/src/winapi/kernel32/misc.rs @@ -1,20 +1,24 @@ //! kernel32 API without a better home. use super::teb_mut; -use crate::{winapi::types::*, Machine}; +use crate::{ + winapi::{types::*, ERROR}, + Machine, +}; use ::memory::Pod; use bitflags::bitflags; use memory::ExtensionsMut; const TRACE_CONTEXT: &'static str = "kernel32/misc"; -pub fn set_last_error(machine: &mut Machine, err: u32) { - teb_mut(machine).LastErrorValue = err; +pub fn set_last_error(machine: &mut Machine, err: ERROR) { + teb_mut(machine).LastErrorValue = err.into(); } #[win32_derive::dllexport] pub fn SetLastError(machine: &mut Machine, dwErrCode: u32) -> u32 { - set_last_error(machine, dwErrCode); + // Avoid set_last_error to allow for unknown error codes. + teb_mut(machine).LastErrorValue = dwErrCode; 0 // unused } @@ -281,11 +285,11 @@ pub fn FormatMessageW( pub fn CloseHandle(machine: &mut Machine, hObject: HFILE) -> bool { if machine.state.kernel32.files.remove(hObject).is_none() { log::debug!("CloseHandle({hObject:?}): unknown handle"); - set_last_error(machine, ERROR_INVALID_HANDLE); + set_last_error(machine, ERROR::INVALID_HANDLE); return false; } - set_last_error(machine, ERROR_SUCCESS); + set_last_error(machine, ERROR::SUCCESS); true } @@ -296,7 +300,7 @@ pub fn GetSystemDirectoryA(machine: &mut Machine, lpBuffer: u32, uSize: u32) -> if uSize < path_bytes.len() as u32 + 1 { return path_bytes.len() as u32 + 1; } - set_last_error(machine, ERROR_SUCCESS); + set_last_error(machine, ERROR::SUCCESS); if lpBuffer != 0 { let buf = machine.mem().sub32_mut(lpBuffer, uSize); buf[..path_bytes.len()].copy_from_slice(path_bytes); @@ -309,7 +313,7 @@ pub fn GetSystemDirectoryA(machine: &mut Machine, lpBuffer: u32, uSize: u32) -> pub fn GetWindowsDirectoryA(machine: &mut Machine, lpBuffer: u32, uSize: u32) -> u32 { let path = "C:\\Windows"; let path_bytes = path.as_bytes(); - set_last_error(machine, ERROR_SUCCESS); + set_last_error(machine, ERROR::SUCCESS); if uSize < path_bytes.len() as u32 + 1 { return path_bytes.len() as u32 + 1; } diff --git a/win32/src/winapi/kernel32/time.rs b/win32/src/winapi/kernel32/time.rs index 0627c0c57..5b539c930 100644 --- a/win32/src/winapi/kernel32/time.rs +++ b/win32/src/winapi/kernel32/time.rs @@ -1,6 +1,5 @@ use super::{set_last_error, FILETIME}; -use crate::winapi::types::ERROR_INVALID_DATA; -use crate::Machine; +use crate::{winapi::ERROR, Machine}; use chrono::{Datelike, Timelike}; use memory::{ExtensionsMut, Pod}; @@ -93,7 +92,7 @@ pub fn SystemTimeToFileTime( ) -> bool { let Some(lpSystemTime) = lpSystemTime else { log::warn!("SystemTimeToFileTime: lpSystemTime is null"); - set_last_error(machine, ERROR_INVALID_DATA); + set_last_error(machine, ERROR::INVALID_DATA); return false; }; let date_time = match chrono::NaiveDate::from_ymd_opt( @@ -112,7 +111,7 @@ pub fn SystemTimeToFileTime( Some(dt) => dt.and_utc(), None => { log::warn!("SystemTimeToFileTime: invalid SYSTEMTIME"); - set_last_error(machine, ERROR_INVALID_DATA); + set_last_error(machine, ERROR::INVALID_DATA); return false; } }; @@ -135,7 +134,7 @@ pub fn FileTimeToSystemTime( ) -> bool { let Some(lpFileTime) = lpFileTime else { log::warn!("FileTimeToSystemTime: lpFileTime is null"); - set_last_error(machine, ERROR_INVALID_DATA); + set_last_error(machine, ERROR::INVALID_DATA); return false; }; let nanos = lpFileTime.to_unix_nanos(); diff --git a/win32/src/winapi/mod.rs b/win32/src/winapi/mod.rs index 66931ea42..1bde58a7d 100644 --- a/win32/src/winapi/mod.rs +++ b/win32/src/winapi/mod.rs @@ -8,6 +8,7 @@ mod builtin; mod com; pub mod ddraw; pub mod dsound; +mod error; pub mod gdi32; mod handle; mod heap; @@ -25,6 +26,8 @@ mod version; mod wininet; mod winmm; +pub use error::ERROR; + #[derive(Debug)] pub enum ImportSymbol<'a> { Name(&'a str), diff --git a/win32/src/winapi/types.rs b/win32/src/winapi/types.rs index 552dabed5..2d1405735 100644 --- a/win32/src/winapi/types.rs +++ b/win32/src/winapi/types.rs @@ -53,43 +53,4 @@ impl<'a> super::stack_args::FromStack<'a> for POINT { } } -// https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499- -pub const ERROR_SUCCESS: u32 = 0; -pub const ERROR_FILE_NOT_FOUND: u32 = 2; -pub const ERROR_ACCESS_DENIED: u32 = 5; -pub const ERROR_INVALID_HANDLE: u32 = 6; -pub const ERROR_INVALID_ACCESS: u32 = 12; -pub const ERROR_INVALID_DATA: u32 = 13; -pub const ERROR_FILE_EXISTS: u32 = 80; -pub const ERROR_OPEN_FAILED: u32 = 110; -pub const ERROR_MOD_NOT_FOUND: u32 = 126; -pub const ERROR_ALREADY_EXISTS: u32 = 183; - -pub fn win32_error_str(code: u32) -> &'static str { - match code { - ERROR_SUCCESS => "ERROR_SUCCESS", - ERROR_FILE_NOT_FOUND => "ERROR_FILE_NOT_FOUND", - ERROR_ACCESS_DENIED => "ERROR_ACCESS_DENIED", - ERROR_INVALID_HANDLE => "ERROR_INVALID_HANDLE", - ERROR_INVALID_ACCESS => "ERROR_INVALID_ACCESS", - ERROR_INVALID_DATA => "ERROR_INVALID_DATA", - ERROR_FILE_EXISTS => "ERROR_FILE_EXISTS", - ERROR_OPEN_FAILED => "ERROR_OPEN_FAILED", - ERROR_MOD_NOT_FOUND => "ERROR_MOD_NOT_FOUND", - ERROR_ALREADY_EXISTS => "ERROR_ALREADY_EXISTS", - _ => "ERROR_UNKNOWN", - } -} - -pub fn io_error_to_win32(err: &std::io::Error) -> u32 { - match err.kind() { - std::io::ErrorKind::NotFound => ERROR_FILE_NOT_FOUND, - std::io::ErrorKind::PermissionDenied => ERROR_ACCESS_DENIED, - std::io::ErrorKind::InvalidData => ERROR_INVALID_DATA, - std::io::ErrorKind::AlreadyExists => ERROR_FILE_EXISTS, - std::io::ErrorKind::InvalidInput => ERROR_INVALID_ACCESS, - _ => ERROR_OPEN_FAILED, - } -} - pub const MAX_PATH: usize = 260;