From 9e919d687d21ceaa39a7f8f5a1d33dff833d11b4 Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Fri, 20 Oct 2023 17:10:30 -0700 Subject: [PATCH 01/44] win:ReadFile,ReadFileEx --- src/async_io.rs | 51 +++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 2 files changed, 52 insertions(+) create mode 100644 src/async_io.rs diff --git a/src/async_io.rs b/src/async_io.rs new file mode 100644 index 00000000..b47cd28f --- /dev/null +++ b/src/async_io.rs @@ -0,0 +1,51 @@ +#![cfg(target_os = "windows")] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +type BOOL = i32; +type HANDLE = *mut u8; +type LPVOID = *mut u8; +type PVOID = *mut u8; +type DWORD = u32; +type LPDWORD = *mut DWORD; +type ULONG = u32; +type ULONG_PTR = *mut ULONG; +#[repr(C)] +#[derive(Copy, Clone)] +struct DUMMYSTRUCTNAME { + Offset: DWORD, + OffsetHigh: DWORD, +} +#[repr(C)] +union DUMMYUNIONNAME { + DUMMYSTRUCTNAME: DUMMYSTRUCTNAME, + Pointer: PVOID, +} +#[repr(C)] +struct OVERLAPPED { + Internal: ULONG_PTR, + InternalHigh: ULONG_PTR, + DUMMYUNIONNAME: DUMMYUNIONNAME, + hEvent: HANDLE, +} +type LPOVERLAPPED = *mut OVERLAPPED; +type LPOVERLAPPED_COMPLETION_ROUTINE = unsafe extern "C" fn( + dwErrorCode: DWORD, // [in] + dwNumberOfBytesTransfered: DWORD, // [in] + lpOverlapped: LPOVERLAPPED, // [in, out] +); +extern "C" { + fn ReadFile( + hFile: HANDLE, // [in] + lpBuffer: LPVOID, // [out] + nNumberOfBytesToRead: DWORD, // [in] + lpNumberOfBytesRead: LPDWORD, // [out, optional] + lpOverlapped: LPOVERLAPPED, // [in, out, optional] + ) -> BOOL; + fn ReadFileEx( + hFile: HANDLE, // [in] + lpBuffer: LPVOID, // [out, optional] + nNumberOfBytesToRead: DWORD, // [in] + lpOverlapped: LPOVERLAPPED, // [in, out] + lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE, // [in] + ) -> BOOL; +} diff --git a/src/lib.rs b/src/lib.rs index 5fecd35e..74b762a1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,7 @@ mod u224; mod u256; mod u32; mod u512; +mod async_io; #[cfg(test)] mod mem_table; From 2d6a6b8246e254b58190dba1777680492c6d8852 Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Sat, 21 Oct 2023 17:27:01 -0700 Subject: [PATCH 02/44] file flags --- src/async_io.rs | 254 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 236 insertions(+), 18 deletions(-) diff --git a/src/async_io.rs b/src/async_io.rs index b47cd28f..e0133425 100644 --- a/src/async_io.rs +++ b/src/async_io.rs @@ -1,39 +1,141 @@ #![cfg(target_os = "windows")] #![allow(non_camel_case_types)] #![allow(non_snake_case)] -type BOOL = i32; + +use std::{io, mem::size_of, ops::BitOr, ptr::null_mut}; +#[repr(transparent)] +struct BOOL(i32); +const FALSE: BOOL = BOOL(0); +const TRUE: BOOL = BOOL(1); +impl Into for BOOL { + fn into(self) -> bool { + self.0 != 0 + } +} type HANDLE = *mut u8; type LPVOID = *mut u8; type PVOID = *mut u8; type DWORD = u32; type LPDWORD = *mut DWORD; type ULONG = u32; -type ULONG_PTR = *mut ULONG; +// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/21eec394-630d-49ed-8b4a-ab74a1614611 +type ULONG_PTR = usize; #[repr(C)] #[derive(Copy, Clone)] -struct DUMMYSTRUCTNAME { +struct OVERLAPPED_0_0 { Offset: DWORD, OffsetHigh: DWORD, } #[repr(C)] -union DUMMYUNIONNAME { - DUMMYSTRUCTNAME: DUMMYSTRUCTNAME, +union OVERLAPPED_0 { + DUMMYSTRUCTNAME: OVERLAPPED_0_0, Pointer: PVOID, } +// https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-overlapped #[repr(C)] struct OVERLAPPED { Internal: ULONG_PTR, InternalHigh: ULONG_PTR, - DUMMYUNIONNAME: DUMMYUNIONNAME, + DUMMYUNIONNAME: OVERLAPPED_0, hEvent: HANDLE, } +type LPCSTR = *const u8; +#[repr(C)] +struct SECURITY_ATTRIBUTES { + nLength: DWORD, + lpSecurityDescriptor: LPVOID, + bInheritHandle: BOOL, +} +type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES; type LPOVERLAPPED = *mut OVERLAPPED; -type LPOVERLAPPED_COMPLETION_ROUTINE = unsafe extern "C" fn( - dwErrorCode: DWORD, // [in] - dwNumberOfBytesTransfered: DWORD, // [in] - lpOverlapped: LPOVERLAPPED, // [in, out] -); -extern "C" { +// https://learn.microsoft.com/en-us/windows/win32/secauthz/access-mask-format +#[repr(transparent)] +struct ACCESS_MASK(DWORD); +const GENERIC_READ: ACCESS_MASK = ACCESS_MASK(0x80000000); +const GENERIC_WRITE: ACCESS_MASK = ACCESS_MASK(0x40000000); +impl BitOr for ACCESS_MASK { + type Output = Self; + fn bitor(self, rhs: Self) -> Self { + ACCESS_MASK(self.0 | rhs.0) + } +} +#[derive(Default)] +#[repr(transparent)] +struct ShareMode(DWORD); +const FILE_SHARE_READ: ShareMode = ShareMode(0x00000001); +const FILE_SHARE_WRITE: ShareMode = ShareMode(0x00000002); +const FILE_SHARE_DELETE: ShareMode = ShareMode(0x00000004); +impl BitOr for ShareMode { + type Output = Self; + fn bitor(self, rhs: Self) -> Self { + ShareMode(self.0 | rhs.0) + } +} +#[repr(transparent)] +struct CreationDisposition(DWORD); +const CREATE_NEW: CreationDisposition = CreationDisposition(1); +const CREATE_ALWAYS: CreationDisposition = CreationDisposition(2); +const OPEN_EXISTING: CreationDisposition = CreationDisposition(3); +const OPEN_ALWAYS: CreationDisposition = CreationDisposition(4); +const TRUNCATE_EXISTING: CreationDisposition = CreationDisposition(5); +#[derive(Default)] +#[repr(transparent)] +struct FlagsAndAttributes(DWORD); +// +const FILE_ATTRIBUTE_READONLY: FlagsAndAttributes = FlagsAndAttributes(0x0000_0001); +const FILE_ATTRIBUTE_HIDDEN: FlagsAndAttributes = FlagsAndAttributes(0x0000_0002); +const FILE_ATTRIBUTE_SYSTEM: FlagsAndAttributes = FlagsAndAttributes(0x0000_0004); +const FILE_ATTRIBUTE_DIRECTORY: FlagsAndAttributes = FlagsAndAttributes(0x0000_0010); +const FILE_ATTRIBUTE_ARCHIVE: FlagsAndAttributes = FlagsAndAttributes(0x0000_0020); +const FILE_ATTRIBUTE_DEVICE: FlagsAndAttributes = FlagsAndAttributes(0x0000_0040); +const FILE_ATTRIBUTE_NORMAL: FlagsAndAttributes = FlagsAndAttributes(0x0000_0080); +const FILE_ATTRIBUTE_TEMPORARY: FlagsAndAttributes = FlagsAndAttributes(0x0000_0100); +const FILE_ATTRIBUTE_SPARSE_FILE: FlagsAndAttributes = FlagsAndAttributes(0x0000_0200); +const FILE_ATTRIBUTE_REPARSE_POINT: FlagsAndAttributes = FlagsAndAttributes(0x0000_0400); +const FILE_ATTRIBUTE_COMPRESSED: FlagsAndAttributes = FlagsAndAttributes(0x0000_0800); +const FILE_ATTRIBUTE_OFFLINE: FlagsAndAttributes = FlagsAndAttributes(0x0000_1000); +const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED: FlagsAndAttributes = FlagsAndAttributes(0x0000_2000); +const FILE_ATTRIBUTE_ENCRYPTED: FlagsAndAttributes = FlagsAndAttributes(0x0000_4000); +const FILE_ATTRIBUTE_INTEGRITY_STREAM: FlagsAndAttributes = FlagsAndAttributes(0x0000_8000); +const FILE_ATTRIBUTE_VIRTUAL: FlagsAndAttributes = FlagsAndAttributes(0x0001_0000); +const FILE_ATTRIBUTE_NO_SCRUB_DATA: FlagsAndAttributes = FlagsAndAttributes(0x0002_0000); +const FILE_ATTRIBUTE_EA: FlagsAndAttributes = FlagsAndAttributes(0x0004_0000); +const FILE_ATTRIBUTE_PINNED: FlagsAndAttributes = FlagsAndAttributes(0x0008_0000); +const FILE_ATTRIBUTE_UNPINNED: FlagsAndAttributes = FlagsAndAttributes(0x0010_0000); +const FILE_ATTRIBUTE_RECALL_ON_OPEN: FlagsAndAttributes = FlagsAndAttributes(0x0004_0000); // FILE_ATTRIBUTE_EA +const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS: FlagsAndAttributes = FlagsAndAttributes(0x0040_0000); +// +const FILE_FLAG_BACKUP_SEMANTICS: FlagsAndAttributes = FlagsAndAttributes(0x0200_0000); +const FILE_FLAG_DELETE_ON_CLOSE: FlagsAndAttributes = FlagsAndAttributes(0x0400_0000); +const FILE_FLAG_NO_BUFFERING: FlagsAndAttributes = FlagsAndAttributes(0x2000_0000); +const FILE_FLAG_OPEN_NO_RECALL: FlagsAndAttributes = FlagsAndAttributes(0x0010_0000); // FILE_ATTRIBUTE_UNPINNED +const FILE_FLAG_OPEN_REPARSE_POINT: FlagsAndAttributes = FlagsAndAttributes(0x0020_0000); +const FILE_FLAG_OVERLAPPED: FlagsAndAttributes = FlagsAndAttributes(0x40000000); +const FILE_FLAG_POSIX_SEMANTICS: FlagsAndAttributes = FlagsAndAttributes(0x01000000); +const FILE_FLAG_RANDOM_ACCESS: FlagsAndAttributes = FlagsAndAttributes(0x10000000); +const FILE_FLAG_SESSION_AWARE: FlagsAndAttributes = FlagsAndAttributes(0x00800000); +const FILE_FLAG_SEQUENTIAL_SCAN: FlagsAndAttributes = FlagsAndAttributes(0x08000000); +const FILE_FLAG_WRITE_THROUGH: FlagsAndAttributes = FlagsAndAttributes(0x80000000); +// +impl BitOr for FlagsAndAttributes { + type Output = Self; + fn bitor(self, rhs: Self) -> Self { + FlagsAndAttributes(self.0 | rhs.0) + } +} +extern "system" { + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea + fn CreateFileA( + lpFileName: LPCSTR, // [in] + dwDesiredAccess: ACCESS_MASK, // [in] + dwShareMode: ShareMode, // [in] + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, // [in, optional] + dwCreationDisposition: CreationDisposition, // [in] + dwFlagsAndAttributes: FlagsAndAttributes, // [in] + hTemplateFile: HANDLE, // [in, optional] + ) -> HANDLE; + fn CloseHandle(hObject: HANDLE, // [in] + ) -> BOOL; fn ReadFile( hFile: HANDLE, // [in] lpBuffer: LPVOID, // [out] @@ -41,11 +143,127 @@ extern "C" { lpNumberOfBytesRead: LPDWORD, // [out, optional] lpOverlapped: LPOVERLAPPED, // [in, out, optional] ) -> BOOL; - fn ReadFileEx( - hFile: HANDLE, // [in] - lpBuffer: LPVOID, // [out, optional] - nNumberOfBytesToRead: DWORD, // [in] - lpOverlapped: LPOVERLAPPED, // [in, out] - lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE, // [in] + fn WriteFile( + hFile: HANDLE, // [in] + lpBuffer: LPVOID, // [in] + nNumberOfBytesToWrite: DWORD, // [in] + lpNumberOfBytesWritten: LPDWORD, // [out, optional] + lpOverlapped: LPOVERLAPPED, // [in, out, optional] + ) -> BOOL; + fn GetOverlappedResult( + hFile: HANDLE, // [in] + lpOverlapped: LPOVERLAPPED, // [in] + lpNumberOfBytesTransferred: LPDWORD, // [out] + bWait: BOOL, // [in] ) -> BOOL; + fn CancelIoEx( + hFile: HANDLE, // [in] + lpOverlapped: LPOVERLAPPED, // [in, optional] + ) -> BOOL; +} + +// https://learn.microsoft.com/en-us/windows/win32/fileio/canceling-pending-i-o-operations + +struct Handle(HANDLE); + +impl Drop for Handle { + fn drop(&mut self) { + unsafe { + CloseHandle(self.0); + } + } +} + +const fn size(v: &[T]) -> DWORD { + (v.len() * size_of::()) as DWORD +} + +impl Handle { + fn create_file(file_name: &str) -> Self { + Self(unsafe { + CreateFileA( + file_name.as_bytes().as_ptr(), + GENERIC_READ | GENERIC_WRITE, + ShareMode::default(), + null_mut(), + CREATE_NEW, + FlagsAndAttributes::default(), + null_mut(), + ) + }) + } + fn read_file<'a, 'b, 'c, T>( + &'a mut self, + overlapped: &'b mut Overlapped, + buffer: &'c mut [T], + ) -> io::Result> { + to_result(unsafe { + ReadFile( + self.0, + buffer.as_mut_ptr() as LPVOID, + size(buffer), + null_mut(), + &mut overlapped.0, + ) + })?; + Ok(Operation { + handle: self, + overlapped, + _buffer: buffer, + }) + } + fn write_file<'a, 'b, 'c, T>( + &'a mut self, + overlapped: &'b mut Overlapped, + buffer: &'c [T], + ) -> io::Result> { + to_result(unsafe { + WriteFile( + self.0, + buffer.as_ptr() as LPVOID, + size(buffer), + null_mut(), + &mut overlapped.0, + ) + })?; + Ok(Operation { + handle: self, + overlapped, + _buffer: &mut [], + }) + } +} + +struct Overlapped(OVERLAPPED); + +struct Operation<'a, 'b, 'c, T> { + handle: &'a mut Handle, + overlapped: &'b mut Overlapped, + _buffer: &'c mut [T], +} + +impl Drop for Operation<'_, '_, '_, T> { + fn drop(&mut self) { + unsafe { + CancelIoEx(self.handle.0, &mut self.overlapped.0); + } + } +} + +fn to_result(v: BOOL) -> io::Result<()> { + if v.into() { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } +} + +impl<'a, 'b, 'c, T> Operation<'a, 'b, 'c, T> { + fn get_result(&mut self) -> io::Result { + let mut result: DWORD = 0; + to_result(unsafe { + GetOverlappedResult(self.handle.0, &mut self.overlapped.0, &mut result, FALSE) + })?; + Ok(result as usize) + } } From 3434b70feda8b85d2f6c7ec78b6c7dd05bd1f45b Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Sat, 21 Oct 2023 20:48:49 -0700 Subject: [PATCH 03/44] windows --- src/lib.rs | 2 +- src/{async_io.rs => windows.rs} | 27 ++++++++++++--------------- 2 files changed, 13 insertions(+), 16 deletions(-) rename src/{async_io.rs => windows.rs} (95%) diff --git a/src/lib.rs b/src/lib.rs index 74b762a1..aeb916b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ mod u224; mod u256; mod u32; mod u512; -mod async_io; +mod windows; #[cfg(test)] mod mem_table; diff --git a/src/async_io.rs b/src/windows.rs similarity index 95% rename from src/async_io.rs rename to src/windows.rs index e0133425..18a6dfdb 100644 --- a/src/async_io.rs +++ b/src/windows.rs @@ -174,10 +174,6 @@ impl Drop for Handle { } } -const fn size(v: &[T]) -> DWORD { - (v.len() * size_of::()) as DWORD -} - impl Handle { fn create_file(file_name: &str) -> Self { Self(unsafe { @@ -195,13 +191,13 @@ impl Handle { fn read_file<'a, 'b, 'c, T>( &'a mut self, overlapped: &'b mut Overlapped, - buffer: &'c mut [T], - ) -> io::Result> { + buffer: &'c mut [u8], + ) -> io::Result> { to_result(unsafe { ReadFile( self.0, buffer.as_mut_ptr() as LPVOID, - size(buffer), + buffer.len() as DWORD, null_mut(), &mut overlapped.0, ) @@ -212,16 +208,16 @@ impl Handle { _buffer: buffer, }) } - fn write_file<'a, 'b, 'c, T>( + fn write_file<'a, 'b, 'c>( &'a mut self, overlapped: &'b mut Overlapped, - buffer: &'c [T], - ) -> io::Result> { + buffer: &'c [u8], + ) -> io::Result> { to_result(unsafe { WriteFile( self.0, buffer.as_ptr() as LPVOID, - size(buffer), + buffer.len() as DWORD, null_mut(), &mut overlapped.0, ) @@ -236,17 +232,18 @@ impl Handle { struct Overlapped(OVERLAPPED); -struct Operation<'a, 'b, 'c, T> { +struct Operation<'a, 'b, 'c> { handle: &'a mut Handle, overlapped: &'b mut Overlapped, - _buffer: &'c mut [T], + _buffer: &'c mut [u8], } -impl Drop for Operation<'_, '_, '_, T> { +impl Drop for Operation<'_, '_, '_> { fn drop(&mut self) { unsafe { CancelIoEx(self.handle.0, &mut self.overlapped.0); } + let _ = self.get_result(); } } @@ -258,7 +255,7 @@ fn to_result(v: BOOL) -> io::Result<()> { } } -impl<'a, 'b, 'c, T> Operation<'a, 'b, 'c, T> { +impl<'a, 'b, 'c> Operation<'a, 'b, 'c> { fn get_result(&mut self) -> io::Result { let mut result: DWORD = 0; to_result(unsafe { From 61186bc1f8ef23143d85acf5626fe2f0864d5f1a Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Sat, 21 Oct 2023 23:56:34 -0700 Subject: [PATCH 04/44] another try --- src/lib.rs | 1 + src/windows.rs | 166 +-------------------------- src/windows_api.rs | 275 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 277 insertions(+), 165 deletions(-) create mode 100644 src/windows_api.rs diff --git a/src/lib.rs b/src/lib.rs index aeb916b4..c1ab029d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,7 @@ mod u224; mod u256; mod u32; mod u512; +mod windows_api; mod windows; #[cfg(test)] diff --git a/src/windows.rs b/src/windows.rs index 18a6dfdb..556fc451 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -1,168 +1,4 @@ -#![cfg(target_os = "windows")] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] - -use std::{io, mem::size_of, ops::BitOr, ptr::null_mut}; -#[repr(transparent)] -struct BOOL(i32); -const FALSE: BOOL = BOOL(0); -const TRUE: BOOL = BOOL(1); -impl Into for BOOL { - fn into(self) -> bool { - self.0 != 0 - } -} -type HANDLE = *mut u8; -type LPVOID = *mut u8; -type PVOID = *mut u8; -type DWORD = u32; -type LPDWORD = *mut DWORD; -type ULONG = u32; -// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/21eec394-630d-49ed-8b4a-ab74a1614611 -type ULONG_PTR = usize; -#[repr(C)] -#[derive(Copy, Clone)] -struct OVERLAPPED_0_0 { - Offset: DWORD, - OffsetHigh: DWORD, -} -#[repr(C)] -union OVERLAPPED_0 { - DUMMYSTRUCTNAME: OVERLAPPED_0_0, - Pointer: PVOID, -} -// https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-overlapped -#[repr(C)] -struct OVERLAPPED { - Internal: ULONG_PTR, - InternalHigh: ULONG_PTR, - DUMMYUNIONNAME: OVERLAPPED_0, - hEvent: HANDLE, -} -type LPCSTR = *const u8; -#[repr(C)] -struct SECURITY_ATTRIBUTES { - nLength: DWORD, - lpSecurityDescriptor: LPVOID, - bInheritHandle: BOOL, -} -type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES; -type LPOVERLAPPED = *mut OVERLAPPED; -// https://learn.microsoft.com/en-us/windows/win32/secauthz/access-mask-format -#[repr(transparent)] -struct ACCESS_MASK(DWORD); -const GENERIC_READ: ACCESS_MASK = ACCESS_MASK(0x80000000); -const GENERIC_WRITE: ACCESS_MASK = ACCESS_MASK(0x40000000); -impl BitOr for ACCESS_MASK { - type Output = Self; - fn bitor(self, rhs: Self) -> Self { - ACCESS_MASK(self.0 | rhs.0) - } -} -#[derive(Default)] -#[repr(transparent)] -struct ShareMode(DWORD); -const FILE_SHARE_READ: ShareMode = ShareMode(0x00000001); -const FILE_SHARE_WRITE: ShareMode = ShareMode(0x00000002); -const FILE_SHARE_DELETE: ShareMode = ShareMode(0x00000004); -impl BitOr for ShareMode { - type Output = Self; - fn bitor(self, rhs: Self) -> Self { - ShareMode(self.0 | rhs.0) - } -} -#[repr(transparent)] -struct CreationDisposition(DWORD); -const CREATE_NEW: CreationDisposition = CreationDisposition(1); -const CREATE_ALWAYS: CreationDisposition = CreationDisposition(2); -const OPEN_EXISTING: CreationDisposition = CreationDisposition(3); -const OPEN_ALWAYS: CreationDisposition = CreationDisposition(4); -const TRUNCATE_EXISTING: CreationDisposition = CreationDisposition(5); -#[derive(Default)] -#[repr(transparent)] -struct FlagsAndAttributes(DWORD); -// -const FILE_ATTRIBUTE_READONLY: FlagsAndAttributes = FlagsAndAttributes(0x0000_0001); -const FILE_ATTRIBUTE_HIDDEN: FlagsAndAttributes = FlagsAndAttributes(0x0000_0002); -const FILE_ATTRIBUTE_SYSTEM: FlagsAndAttributes = FlagsAndAttributes(0x0000_0004); -const FILE_ATTRIBUTE_DIRECTORY: FlagsAndAttributes = FlagsAndAttributes(0x0000_0010); -const FILE_ATTRIBUTE_ARCHIVE: FlagsAndAttributes = FlagsAndAttributes(0x0000_0020); -const FILE_ATTRIBUTE_DEVICE: FlagsAndAttributes = FlagsAndAttributes(0x0000_0040); -const FILE_ATTRIBUTE_NORMAL: FlagsAndAttributes = FlagsAndAttributes(0x0000_0080); -const FILE_ATTRIBUTE_TEMPORARY: FlagsAndAttributes = FlagsAndAttributes(0x0000_0100); -const FILE_ATTRIBUTE_SPARSE_FILE: FlagsAndAttributes = FlagsAndAttributes(0x0000_0200); -const FILE_ATTRIBUTE_REPARSE_POINT: FlagsAndAttributes = FlagsAndAttributes(0x0000_0400); -const FILE_ATTRIBUTE_COMPRESSED: FlagsAndAttributes = FlagsAndAttributes(0x0000_0800); -const FILE_ATTRIBUTE_OFFLINE: FlagsAndAttributes = FlagsAndAttributes(0x0000_1000); -const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED: FlagsAndAttributes = FlagsAndAttributes(0x0000_2000); -const FILE_ATTRIBUTE_ENCRYPTED: FlagsAndAttributes = FlagsAndAttributes(0x0000_4000); -const FILE_ATTRIBUTE_INTEGRITY_STREAM: FlagsAndAttributes = FlagsAndAttributes(0x0000_8000); -const FILE_ATTRIBUTE_VIRTUAL: FlagsAndAttributes = FlagsAndAttributes(0x0001_0000); -const FILE_ATTRIBUTE_NO_SCRUB_DATA: FlagsAndAttributes = FlagsAndAttributes(0x0002_0000); -const FILE_ATTRIBUTE_EA: FlagsAndAttributes = FlagsAndAttributes(0x0004_0000); -const FILE_ATTRIBUTE_PINNED: FlagsAndAttributes = FlagsAndAttributes(0x0008_0000); -const FILE_ATTRIBUTE_UNPINNED: FlagsAndAttributes = FlagsAndAttributes(0x0010_0000); -const FILE_ATTRIBUTE_RECALL_ON_OPEN: FlagsAndAttributes = FlagsAndAttributes(0x0004_0000); // FILE_ATTRIBUTE_EA -const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS: FlagsAndAttributes = FlagsAndAttributes(0x0040_0000); -// -const FILE_FLAG_BACKUP_SEMANTICS: FlagsAndAttributes = FlagsAndAttributes(0x0200_0000); -const FILE_FLAG_DELETE_ON_CLOSE: FlagsAndAttributes = FlagsAndAttributes(0x0400_0000); -const FILE_FLAG_NO_BUFFERING: FlagsAndAttributes = FlagsAndAttributes(0x2000_0000); -const FILE_FLAG_OPEN_NO_RECALL: FlagsAndAttributes = FlagsAndAttributes(0x0010_0000); // FILE_ATTRIBUTE_UNPINNED -const FILE_FLAG_OPEN_REPARSE_POINT: FlagsAndAttributes = FlagsAndAttributes(0x0020_0000); -const FILE_FLAG_OVERLAPPED: FlagsAndAttributes = FlagsAndAttributes(0x40000000); -const FILE_FLAG_POSIX_SEMANTICS: FlagsAndAttributes = FlagsAndAttributes(0x01000000); -const FILE_FLAG_RANDOM_ACCESS: FlagsAndAttributes = FlagsAndAttributes(0x10000000); -const FILE_FLAG_SESSION_AWARE: FlagsAndAttributes = FlagsAndAttributes(0x00800000); -const FILE_FLAG_SEQUENTIAL_SCAN: FlagsAndAttributes = FlagsAndAttributes(0x08000000); -const FILE_FLAG_WRITE_THROUGH: FlagsAndAttributes = FlagsAndAttributes(0x80000000); -// -impl BitOr for FlagsAndAttributes { - type Output = Self; - fn bitor(self, rhs: Self) -> Self { - FlagsAndAttributes(self.0 | rhs.0) - } -} -extern "system" { - // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea - fn CreateFileA( - lpFileName: LPCSTR, // [in] - dwDesiredAccess: ACCESS_MASK, // [in] - dwShareMode: ShareMode, // [in] - lpSecurityAttributes: LPSECURITY_ATTRIBUTES, // [in, optional] - dwCreationDisposition: CreationDisposition, // [in] - dwFlagsAndAttributes: FlagsAndAttributes, // [in] - hTemplateFile: HANDLE, // [in, optional] - ) -> HANDLE; - fn CloseHandle(hObject: HANDLE, // [in] - ) -> BOOL; - fn ReadFile( - hFile: HANDLE, // [in] - lpBuffer: LPVOID, // [out] - nNumberOfBytesToRead: DWORD, // [in] - lpNumberOfBytesRead: LPDWORD, // [out, optional] - lpOverlapped: LPOVERLAPPED, // [in, out, optional] - ) -> BOOL; - fn WriteFile( - hFile: HANDLE, // [in] - lpBuffer: LPVOID, // [in] - nNumberOfBytesToWrite: DWORD, // [in] - lpNumberOfBytesWritten: LPDWORD, // [out, optional] - lpOverlapped: LPOVERLAPPED, // [in, out, optional] - ) -> BOOL; - fn GetOverlappedResult( - hFile: HANDLE, // [in] - lpOverlapped: LPOVERLAPPED, // [in] - lpNumberOfBytesTransferred: LPDWORD, // [out] - bWait: BOOL, // [in] - ) -> BOOL; - fn CancelIoEx( - hFile: HANDLE, // [in] - lpOverlapped: LPOVERLAPPED, // [in, optional] - ) -> BOOL; -} - -// https://learn.microsoft.com/en-us/windows/win32/fileio/canceling-pending-i-o-operations +use std::os::windows::raw::HANDLE; struct Handle(HANDLE); diff --git a/src/windows_api.rs b/src/windows_api.rs new file mode 100644 index 00000000..3e42de87 --- /dev/null +++ b/src/windows_api.rs @@ -0,0 +1,275 @@ +#![cfg(target_os = "windows")] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + +use std::{ + ops::BitOr, + os::{raw::c_void, windows::raw::HANDLE}, +}; + +// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/3f6cc0e2-1303-4088-a26b-fb9582f29197 +type LPCSTR = *const u8; + +// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/262627d8-3418-4627-9218-4ffe110850b2 +type DWORD = u32; +type LPDWORD = *mut DWORD; + +// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/c0b7741b-f577-4eed-aff3-2e909df10a4d +type LPVOID = *mut c_void; +type PVOID = *mut c_void; + +// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/21eec394-630d-49ed-8b4a-ab74a1614611 +type ULONG_PTR = usize; + +// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/9d81be47-232e-42cf-8f0d-7a3b29bf2eb2 +#[repr(transparent)] +struct BOOL(i32); +const FALSE: BOOL = BOOL(0); +const TRUE: BOOL = BOOL(1); +impl Into for BOOL { + fn into(self) -> bool { + self.0 != 0 + } +} + +// https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-overlapped + +#[repr(C)] +#[derive(Copy, Clone)] +struct OVERLAPPED_0_0 { + Offset: DWORD, + OffsetHigh: DWORD, +} + +#[repr(C)] +union OVERLAPPED_0 { + DUMMYSTRUCTNAME: OVERLAPPED_0_0, + Pointer: PVOID, +} + +#[repr(C)] +struct OVERLAPPED { + Internal: ULONG_PTR, + InternalHigh: ULONG_PTR, + DUMMYUNIONNAME: OVERLAPPED_0, + hEvent: HANDLE, +} + +type LPOVERLAPPED = *mut OVERLAPPED; + +// https://learn.microsoft.com/en-us/windows/win32/secauthz/access-mask +#[repr(transparent)] +struct ACCESS_MASK(DWORD); +const GENERIC_READ: ACCESS_MASK = ACCESS_MASK(0x80000000); +const GENERIC_WRITE: ACCESS_MASK = ACCESS_MASK(0x40000000); +impl BitOr for ACCESS_MASK { + type Output = Self; + fn bitor(self, rhs: Self) -> Self { + ACCESS_MASK(self.0 | rhs.0) + } +} + +// https://learn.microsoft.com/en-us/windows/win32/api/wtypesbase/ns-wtypesbase-security_attributes +#[repr(C)] +struct SECURITY_ATTRIBUTES { + nLength: DWORD, + lpSecurityDescriptor: LPVOID, + bInheritHandle: BOOL, +} +type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES; + +// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea +#[link(name = "kernel32")] +extern "system" { + pub fn CreateFileA( + lpFileName: LPCSTR, // [in] + dwDesiredAccess: ACCESS_MASK, // [in] + dwShareMode: DWORD, // [in] + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, // [in, optional] + dwCreationDisposition: DWORD, // [in] + dwFlagsAndAttributes: DWORD, // [in] + hTemplateFile: HANDLE, // [in, optional] + ) -> HANDLE; +} + +// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile +#[link(name = "kernel32")] +extern "system" { + pub fn ReadFile( + hFile: HANDLE, // [in] + lpBuffer: LPVOID, // [out] + nNumberOfBytesToRead: DWORD, // [in] + lpNumberOfBytesRead: LPDWORD, // [out, optional] + lpOverlapped: LPOVERLAPPED, // [in, out, optional] + ) -> BOOL; +} + +// https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle +#[link(name = "kernel32")] +extern "system" { + pub fn CloseHandle(hObject: HANDLE, // [in] + ) -> BOOL; +} + +/* +use std::ops::BitOr; + +#[repr(transparent)] +struct BOOL(i32); +const FALSE: BOOL = BOOL(0); +const TRUE: BOOL = BOOL(1); +impl Into for BOOL { + fn into(self) -> bool { + self.0 != 0 + } +} +type HANDLE = *mut u8; +type LPVOID = *mut u8; +type PVOID = *mut u8; +type DWORD = u32; +type LPDWORD = *mut DWORD; +type ULONG = u32; +// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/21eec394-630d-49ed-8b4a-ab74a1614611 +type ULONG_PTR = usize; +#[repr(C)] +#[derive(Copy, Clone)] +struct OVERLAPPED_0_0 { + Offset: DWORD, + OffsetHigh: DWORD, +} +#[repr(C)] +union OVERLAPPED_0 { + DUMMYSTRUCTNAME: OVERLAPPED_0_0, + Pointer: PVOID, +} +// https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-overlapped +#[repr(C)] +struct OVERLAPPED { + Internal: ULONG_PTR, + InternalHigh: ULONG_PTR, + DUMMYUNIONNAME: OVERLAPPED_0, + hEvent: HANDLE, +} +type LPCSTR = *const u8; +#[repr(C)] +struct SECURITY_ATTRIBUTES { + nLength: DWORD, + lpSecurityDescriptor: LPVOID, + bInheritHandle: BOOL, +} +type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES; +type LPOVERLAPPED = *mut OVERLAPPED; +// https://learn.microsoft.com/en-us/windows/win32/secauthz/access-mask-format +#[repr(transparent)] +struct ACCESS_MASK(DWORD); +const GENERIC_READ: ACCESS_MASK = ACCESS_MASK(0x80000000); +const GENERIC_WRITE: ACCESS_MASK = ACCESS_MASK(0x40000000); +impl BitOr for ACCESS_MASK { + type Output = Self; + fn bitor(self, rhs: Self) -> Self { + ACCESS_MASK(self.0 | rhs.0) + } +} +#[derive(Default)] +#[repr(transparent)] +struct ShareMode(DWORD); +const FILE_SHARE_READ: ShareMode = ShareMode(0x00000001); +const FILE_SHARE_WRITE: ShareMode = ShareMode(0x00000002); +const FILE_SHARE_DELETE: ShareMode = ShareMode(0x00000004); +impl BitOr for ShareMode { + type Output = Self; + fn bitor(self, rhs: Self) -> Self { + ShareMode(self.0 | rhs.0) + } +} +#[repr(transparent)] +struct CreationDisposition(DWORD); +const CREATE_NEW: CreationDisposition = CreationDisposition(1); +const CREATE_ALWAYS: CreationDisposition = CreationDisposition(2); +const OPEN_EXISTING: CreationDisposition = CreationDisposition(3); +const OPEN_ALWAYS: CreationDisposition = CreationDisposition(4); +const TRUNCATE_EXISTING: CreationDisposition = CreationDisposition(5); +#[derive(Default)] +#[repr(transparent)] +struct FlagsAndAttributes(DWORD); +// +const FILE_ATTRIBUTE_READONLY: FlagsAndAttributes = FlagsAndAttributes(0x0000_0001); +const FILE_ATTRIBUTE_HIDDEN: FlagsAndAttributes = FlagsAndAttributes(0x0000_0002); +const FILE_ATTRIBUTE_SYSTEM: FlagsAndAttributes = FlagsAndAttributes(0x0000_0004); +const FILE_ATTRIBUTE_DIRECTORY: FlagsAndAttributes = FlagsAndAttributes(0x0000_0010); +const FILE_ATTRIBUTE_ARCHIVE: FlagsAndAttributes = FlagsAndAttributes(0x0000_0020); +const FILE_ATTRIBUTE_DEVICE: FlagsAndAttributes = FlagsAndAttributes(0x0000_0040); +const FILE_ATTRIBUTE_NORMAL: FlagsAndAttributes = FlagsAndAttributes(0x0000_0080); +const FILE_ATTRIBUTE_TEMPORARY: FlagsAndAttributes = FlagsAndAttributes(0x0000_0100); +const FILE_ATTRIBUTE_SPARSE_FILE: FlagsAndAttributes = FlagsAndAttributes(0x0000_0200); +const FILE_ATTRIBUTE_REPARSE_POINT: FlagsAndAttributes = FlagsAndAttributes(0x0000_0400); +const FILE_ATTRIBUTE_COMPRESSED: FlagsAndAttributes = FlagsAndAttributes(0x0000_0800); +const FILE_ATTRIBUTE_OFFLINE: FlagsAndAttributes = FlagsAndAttributes(0x0000_1000); +const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED: FlagsAndAttributes = FlagsAndAttributes(0x0000_2000); +const FILE_ATTRIBUTE_ENCRYPTED: FlagsAndAttributes = FlagsAndAttributes(0x0000_4000); +const FILE_ATTRIBUTE_INTEGRITY_STREAM: FlagsAndAttributes = FlagsAndAttributes(0x0000_8000); +const FILE_ATTRIBUTE_VIRTUAL: FlagsAndAttributes = FlagsAndAttributes(0x0001_0000); +const FILE_ATTRIBUTE_NO_SCRUB_DATA: FlagsAndAttributes = FlagsAndAttributes(0x0002_0000); +const FILE_ATTRIBUTE_EA: FlagsAndAttributes = FlagsAndAttributes(0x0004_0000); +const FILE_ATTRIBUTE_PINNED: FlagsAndAttributes = FlagsAndAttributes(0x0008_0000); +const FILE_ATTRIBUTE_UNPINNED: FlagsAndAttributes = FlagsAndAttributes(0x0010_0000); +const FILE_ATTRIBUTE_RECALL_ON_OPEN: FlagsAndAttributes = FlagsAndAttributes(0x0004_0000); // FILE_ATTRIBUTE_EA +const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS: FlagsAndAttributes = FlagsAndAttributes(0x0040_0000); +// +const FILE_FLAG_BACKUP_SEMANTICS: FlagsAndAttributes = FlagsAndAttributes(0x0200_0000); +const FILE_FLAG_DELETE_ON_CLOSE: FlagsAndAttributes = FlagsAndAttributes(0x0400_0000); +const FILE_FLAG_NO_BUFFERING: FlagsAndAttributes = FlagsAndAttributes(0x2000_0000); +const FILE_FLAG_OPEN_NO_RECALL: FlagsAndAttributes = FlagsAndAttributes(0x0010_0000); // FILE_ATTRIBUTE_UNPINNED +const FILE_FLAG_OPEN_REPARSE_POINT: FlagsAndAttributes = FlagsAndAttributes(0x0020_0000); +const FILE_FLAG_OVERLAPPED: FlagsAndAttributes = FlagsAndAttributes(0x40000000); +const FILE_FLAG_POSIX_SEMANTICS: FlagsAndAttributes = FlagsAndAttributes(0x01000000); +const FILE_FLAG_RANDOM_ACCESS: FlagsAndAttributes = FlagsAndAttributes(0x10000000); +const FILE_FLAG_SESSION_AWARE: FlagsAndAttributes = FlagsAndAttributes(0x00800000); +const FILE_FLAG_SEQUENTIAL_SCAN: FlagsAndAttributes = FlagsAndAttributes(0x08000000); +const FILE_FLAG_WRITE_THROUGH: FlagsAndAttributes = FlagsAndAttributes(0x80000000); +// +impl BitOr for FlagsAndAttributes { + type Output = Self; + fn bitor(self, rhs: Self) -> Self { + FlagsAndAttributes(self.0 | rhs.0) + } +} +extern "system" { + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea + fn CreateFileA( + lpFileName: LPCSTR, // [in] + dwDesiredAccess: ACCESS_MASK, // [in] + dwShareMode: ShareMode, // [in] + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, // [in, optional] + dwCreationDisposition: CreationDisposition, // [in] + dwFlagsAndAttributes: FlagsAndAttributes, // [in] + hTemplateFile: HANDLE, // [in, optional] + ) -> HANDLE; + fn CloseHandle(hObject: HANDLE, // [in] + ) -> BOOL; + fn ReadFile( + hFile: HANDLE, // [in] + lpBuffer: LPVOID, // [out] + nNumberOfBytesToRead: DWORD, // [in] + lpNumberOfBytesRead: LPDWORD, // [out, optional] + lpOverlapped: LPOVERLAPPED, // [in, out, optional] + ) -> BOOL; + fn WriteFile( + hFile: HANDLE, // [in] + lpBuffer: LPVOID, // [in] + nNumberOfBytesToWrite: DWORD, // [in] + lpNumberOfBytesWritten: LPDWORD, // [out, optional] + lpOverlapped: LPOVERLAPPED, // [in, out, optional] + ) -> BOOL; + fn GetOverlappedResult( + hFile: HANDLE, // [in] + lpOverlapped: LPOVERLAPPED, // [in] + lpNumberOfBytesTransferred: LPDWORD, // [out] + bWait: BOOL, // [in] + ) -> BOOL; + fn CancelIoEx( + hFile: HANDLE, // [in] + lpOverlapped: LPOVERLAPPED, // [in, optional] + ) -> BOOL; +} +*/ From 8b177f944e3f436e27a59c0deda9876daa142572 Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Sun, 22 Oct 2023 14:48:31 -0700 Subject: [PATCH 05/44] read and write with non-blocking API --- src/windows.rs | 160 ++++++++++++++++++-------- src/windows_api.rs | 273 +++++++++++++++++---------------------------- test.txt | 1 + 3 files changed, 217 insertions(+), 217 deletions(-) create mode 100644 test.txt diff --git a/src/windows.rs b/src/windows.rs index 556fc451..c9c05616 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -1,4 +1,10 @@ -use std::os::windows::raw::HANDLE; +use std::{io, os::windows::raw::HANDLE, ptr::null_mut, ffi::CStr}; + +use crate::windows_api::{ + CancelIoEx, CloseHandle, CreateFileA, CreationDisposition, GetOverlappedResult, ReadFile, + WriteFile, ACCESS_MASK, CREATE_ALWAYS, DWORD, FILE_ATTRIBUTE_NORMAL, FILE_FLAG_OVERLAPPED, + GENERIC_READ, GENERIC_WRITE, INVALID_HANDLE_VALUE, LPCVOID, LPVOID, OPEN_ALWAYS, OVERLAPPED, GetLastError, ERROR_IO_PENDING, BOOL, to_bool, +}; struct Handle(HANDLE); @@ -11,25 +17,56 @@ impl Drop for Handle { } impl Handle { - fn create_file(file_name: &str) -> Self { - Self(unsafe { + fn create_file( + file_name: &CStr, + desired_access: ACCESS_MASK, + creation_disposition: CreationDisposition, + ) -> io::Result { + let result = unsafe { CreateFileA( - file_name.as_bytes().as_ptr(), - GENERIC_READ | GENERIC_WRITE, - ShareMode::default(), + file_name.as_ptr(), + desired_access, + 0, null_mut(), - CREATE_NEW, - FlagsAndAttributes::default(), + creation_disposition, + FILE_FLAG_OVERLAPPED, null_mut(), ) - }) + }; + if result == INVALID_HANDLE_VALUE { + let e = io::Error::last_os_error(); + println!("{}", e); + Err(io::Error::last_os_error()) + } else { + Ok(Self(result)) + } + } + pub fn create(file_name: &CStr) -> io::Result { + Self::create_file(file_name, GENERIC_WRITE, CREATE_ALWAYS) } - fn read_file<'a, 'b, 'c, T>( + pub fn open(file_name: &CStr) -> io::Result { + Self::create_file(file_name, GENERIC_READ, OPEN_ALWAYS) + } + + fn to_operation<'a>(&'a mut self, overlapped: &'a mut Overlapped, result: BOOL) -> io::Result> { + assert!(!to_bool(result)); + let e = unsafe { GetLastError() }; + if e == ERROR_IO_PENDING { + Ok(Operation { + handle: self, + overlapped, + }) + } else { + Err(e.to_error()) + } + } + + pub fn read<'a>( &'a mut self, - overlapped: &'b mut Overlapped, - buffer: &'c mut [u8], - ) -> io::Result> { - to_result(unsafe { + overlapped: &'a mut Overlapped, + buffer: &'a mut [u8], // it's important that the buffer has the same life time as the overlapped! + ) -> io::Result> { + let result = unsafe { ReadFile( self.0, buffer.as_mut_ptr() as LPVOID, @@ -37,66 +74,91 @@ impl Handle { null_mut(), &mut overlapped.0, ) - })?; - Ok(Operation { - handle: self, - overlapped, - _buffer: buffer, - }) + }; + self.to_operation(overlapped, result) } - fn write_file<'a, 'b, 'c>( + + pub fn write<'a>( &'a mut self, - overlapped: &'b mut Overlapped, - buffer: &'c [u8], - ) -> io::Result> { - to_result(unsafe { + overlapped: &'a mut Overlapped, + buffer: &'a [u8], // it's important that the buffer has the same life time as the overlapped! + ) -> io::Result> { + let result = unsafe { WriteFile( self.0, - buffer.as_ptr() as LPVOID, + buffer.as_ptr() as LPCVOID, buffer.len() as DWORD, null_mut(), &mut overlapped.0, ) - })?; - Ok(Operation { - handle: self, - overlapped, - _buffer: &mut [], - }) + }; + self.to_operation(overlapped, result) } } +#[derive(Default)] struct Overlapped(OVERLAPPED); -struct Operation<'a, 'b, 'c> { +struct Operation<'a> { handle: &'a mut Handle, - overlapped: &'b mut Overlapped, - _buffer: &'c mut [u8], + overlapped: &'a mut Overlapped, } -impl Drop for Operation<'_, '_, '_> { +impl Drop for Operation<'_> { fn drop(&mut self) { unsafe { CancelIoEx(self.handle.0, &mut self.overlapped.0); } - let _ = self.get_result(); + let _ = self.get_result(true); } } -fn to_result(v: BOOL) -> io::Result<()> { - if v.into() { - Ok(()) - } else { - Err(io::Error::last_os_error()) +impl Operation<'_> { + fn get_result(&mut self, wait: bool) -> io::Result { + let mut result: DWORD = 0; + let r = unsafe { + GetOverlappedResult( + self.handle.0, + &mut self.overlapped.0, + &mut result, + wait.into(), + ) + }; + if r.into() { + Ok(result as usize) + } else { + Err(io::Error::last_os_error()) + } } } -impl<'a, 'b, 'c> Operation<'a, 'b, 'c> { - fn get_result(&mut self) -> io::Result { - let mut result: DWORD = 0; - to_result(unsafe { - GetOverlappedResult(self.handle.0, &mut self.overlapped.0, &mut result, FALSE) - })?; - Ok(result as usize) +#[cfg(test)] +mod test { + use std::ffi::CString; + + #[test] + fn test() { + use super::{Handle, Overlapped}; + // + let x: CString = CString::new("test.txt").unwrap(); + { + + let mut handle = Handle::create(&x).unwrap(); + let mut overlapped = Overlapped(Default::default()); + let mut operation = handle.write(&mut overlapped, b"Hello World!").unwrap(); + let result = operation.get_result(true).unwrap(); + assert_eq!(result, 12); + } + { + let mut handle = Handle::open(&x).unwrap(); + let mut overlapped = Overlapped(Default::default()); + let mut buffer = [0u8; 1024]; + { + let mut operation = handle.read(&mut overlapped, &mut buffer).unwrap(); + let result = operation.get_result(true).unwrap(); + assert_eq!(result, 12); + } + assert_eq!(&buffer[..12], b"Hello World!"); + } } } diff --git a/src/windows_api.rs b/src/windows_api.rs index 3e42de87..60e18a75 100644 --- a/src/windows_api.rs +++ b/src/windows_api.rs @@ -4,18 +4,21 @@ use std::{ ops::BitOr, - os::{raw::c_void, windows::raw::HANDLE}, + os::{raw::c_void, windows::raw::HANDLE}, ptr::null_mut, io, }; +pub const INVALID_HANDLE_VALUE: HANDLE = -1isize as HANDLE; + // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/3f6cc0e2-1303-4088-a26b-fb9582f29197 -type LPCSTR = *const u8; +type LPCSTR = *const i8; // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/262627d8-3418-4627-9218-4ffe110850b2 -type DWORD = u32; +pub type DWORD = u32; type LPDWORD = *mut DWORD; // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/c0b7741b-f577-4eed-aff3-2e909df10a4d -type LPVOID = *mut c_void; +pub type LPVOID = *mut c_void; +pub type LPCVOID = *const c_void; type PVOID = *mut c_void; // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/21eec394-630d-49ed-8b4a-ab74a1614611 @@ -23,12 +26,24 @@ type ULONG_PTR = usize; // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/9d81be47-232e-42cf-8f0d-7a3b29bf2eb2 #[repr(transparent)] -struct BOOL(i32); +pub struct BOOL(i32); const FALSE: BOOL = BOOL(0); const TRUE: BOOL = BOOL(1); +pub const fn to_bool(x: BOOL) -> bool { + x.0 != FALSE.0 +} impl Into for BOOL { fn into(self) -> bool { - self.0 != 0 + to_bool(self) + } +} +impl From for BOOL { + fn from(x: bool) -> Self { + if x { + TRUE + } else { + FALSE + } } } @@ -47,21 +62,38 @@ union OVERLAPPED_0 { Pointer: PVOID, } +impl Default for OVERLAPPED_0 { + fn default() -> Self { + unsafe { std::mem::zeroed() } + } +} + #[repr(C)] -struct OVERLAPPED { +pub struct OVERLAPPED { Internal: ULONG_PTR, InternalHigh: ULONG_PTR, DUMMYUNIONNAME: OVERLAPPED_0, hEvent: HANDLE, } +impl Default for OVERLAPPED { + fn default() -> Self { + OVERLAPPED { + Internal: 0, + InternalHigh: 0, + DUMMYUNIONNAME: OVERLAPPED_0::default(), + hEvent: null_mut(), + } + } +} + type LPOVERLAPPED = *mut OVERLAPPED; // https://learn.microsoft.com/en-us/windows/win32/secauthz/access-mask #[repr(transparent)] -struct ACCESS_MASK(DWORD); -const GENERIC_READ: ACCESS_MASK = ACCESS_MASK(0x80000000); -const GENERIC_WRITE: ACCESS_MASK = ACCESS_MASK(0x40000000); +pub struct ACCESS_MASK(DWORD); +pub const GENERIC_READ: ACCESS_MASK = ACCESS_MASK(0x80000000); +pub const GENERIC_WRITE: ACCESS_MASK = ACCESS_MASK(0x40000000); impl BitOr for ACCESS_MASK { type Output = Self; fn bitor(self, rhs: Self) -> Self { @@ -71,13 +103,43 @@ impl BitOr for ACCESS_MASK { // https://learn.microsoft.com/en-us/windows/win32/api/wtypesbase/ns-wtypesbase-security_attributes #[repr(C)] -struct SECURITY_ATTRIBUTES { +pub struct SECURITY_ATTRIBUTES { nLength: DWORD, lpSecurityDescriptor: LPVOID, bInheritHandle: BOOL, } type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES; +#[repr(transparent)] +pub struct CreationDisposition(DWORD); +pub const CREATE_NEW: CreationDisposition = CreationDisposition(1); +pub const CREATE_ALWAYS: CreationDisposition = CreationDisposition(2); +pub const OPEN_EXISTING: CreationDisposition = CreationDisposition(3); +pub const OPEN_ALWAYS: CreationDisposition = CreationDisposition(4); +pub const TRUNCATE_EXISTING: CreationDisposition = CreationDisposition(5); + +#[repr(transparent)] +pub struct FlagsAndAttributes(DWORD); +pub const FILE_FLAG_OVERLAPPED: FlagsAndAttributes = FlagsAndAttributes(0x40000000); +pub const FILE_ATTRIBUTE_NORMAL: FlagsAndAttributes = FlagsAndAttributes(0x00000080); +impl BitOr for FlagsAndAttributes { + type Output = Self; + fn bitor(self, rhs: Self) -> Self { + FlagsAndAttributes(self.0 | rhs.0) + } +} + +// https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--500-999- +#[derive(PartialEq)] +#[repr(transparent)] +pub struct Error(DWORD); +pub const ERROR_IO_PENDING: Error = Error(997); +impl Error { + pub fn to_error(self) -> io::Error { + io::Error::from_raw_os_error(self.0 as i32) + } +} + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea #[link(name = "kernel32")] extern "system" { @@ -86,8 +148,8 @@ extern "system" { dwDesiredAccess: ACCESS_MASK, // [in] dwShareMode: DWORD, // [in] lpSecurityAttributes: LPSECURITY_ATTRIBUTES, // [in, optional] - dwCreationDisposition: DWORD, // [in] - dwFlagsAndAttributes: DWORD, // [in] + dwCreationDisposition: CreationDisposition, // [in] + dwFlagsAndAttributes: FlagsAndAttributes, // [in] hTemplateFile: HANDLE, // [in, optional] ) -> HANDLE; } @@ -104,6 +166,18 @@ extern "system" { ) -> BOOL; } +// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefile +#[link(name = "kernel32")] +extern "system" { + pub fn WriteFile( + hFile: HANDLE, // [in] + lpBuffer: LPCVOID, // [in] + nNumberOfBytesToWrite: DWORD, // [in] + lpNumberOfBytesWritten: LPDWORD, // [out, optional] + lpOverlapped: LPOVERLAPPED, // [in, out, optional] + ) -> BOOL; +} + // https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle #[link(name = "kernel32")] extern "system" { @@ -111,165 +185,28 @@ extern "system" { ) -> BOOL; } -/* -use std::ops::BitOr; - -#[repr(transparent)] -struct BOOL(i32); -const FALSE: BOOL = BOOL(0); -const TRUE: BOOL = BOOL(1); -impl Into for BOOL { - fn into(self) -> bool { - self.0 != 0 - } -} -type HANDLE = *mut u8; -type LPVOID = *mut u8; -type PVOID = *mut u8; -type DWORD = u32; -type LPDWORD = *mut DWORD; -type ULONG = u32; -// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/21eec394-630d-49ed-8b4a-ab74a1614611 -type ULONG_PTR = usize; -#[repr(C)] -#[derive(Copy, Clone)] -struct OVERLAPPED_0_0 { - Offset: DWORD, - OffsetHigh: DWORD, -} -#[repr(C)] -union OVERLAPPED_0 { - DUMMYSTRUCTNAME: OVERLAPPED_0_0, - Pointer: PVOID, -} -// https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-overlapped -#[repr(C)] -struct OVERLAPPED { - Internal: ULONG_PTR, - InternalHigh: ULONG_PTR, - DUMMYUNIONNAME: OVERLAPPED_0, - hEvent: HANDLE, -} -type LPCSTR = *const u8; -#[repr(C)] -struct SECURITY_ATTRIBUTES { - nLength: DWORD, - lpSecurityDescriptor: LPVOID, - bInheritHandle: BOOL, -} -type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES; -type LPOVERLAPPED = *mut OVERLAPPED; -// https://learn.microsoft.com/en-us/windows/win32/secauthz/access-mask-format -#[repr(transparent)] -struct ACCESS_MASK(DWORD); -const GENERIC_READ: ACCESS_MASK = ACCESS_MASK(0x80000000); -const GENERIC_WRITE: ACCESS_MASK = ACCESS_MASK(0x40000000); -impl BitOr for ACCESS_MASK { - type Output = Self; - fn bitor(self, rhs: Self) -> Self { - ACCESS_MASK(self.0 | rhs.0) - } -} -#[derive(Default)] -#[repr(transparent)] -struct ShareMode(DWORD); -const FILE_SHARE_READ: ShareMode = ShareMode(0x00000001); -const FILE_SHARE_WRITE: ShareMode = ShareMode(0x00000002); -const FILE_SHARE_DELETE: ShareMode = ShareMode(0x00000004); -impl BitOr for ShareMode { - type Output = Self; - fn bitor(self, rhs: Self) -> Self { - ShareMode(self.0 | rhs.0) - } -} -#[repr(transparent)] -struct CreationDisposition(DWORD); -const CREATE_NEW: CreationDisposition = CreationDisposition(1); -const CREATE_ALWAYS: CreationDisposition = CreationDisposition(2); -const OPEN_EXISTING: CreationDisposition = CreationDisposition(3); -const OPEN_ALWAYS: CreationDisposition = CreationDisposition(4); -const TRUNCATE_EXISTING: CreationDisposition = CreationDisposition(5); -#[derive(Default)] -#[repr(transparent)] -struct FlagsAndAttributes(DWORD); -// -const FILE_ATTRIBUTE_READONLY: FlagsAndAttributes = FlagsAndAttributes(0x0000_0001); -const FILE_ATTRIBUTE_HIDDEN: FlagsAndAttributes = FlagsAndAttributes(0x0000_0002); -const FILE_ATTRIBUTE_SYSTEM: FlagsAndAttributes = FlagsAndAttributes(0x0000_0004); -const FILE_ATTRIBUTE_DIRECTORY: FlagsAndAttributes = FlagsAndAttributes(0x0000_0010); -const FILE_ATTRIBUTE_ARCHIVE: FlagsAndAttributes = FlagsAndAttributes(0x0000_0020); -const FILE_ATTRIBUTE_DEVICE: FlagsAndAttributes = FlagsAndAttributes(0x0000_0040); -const FILE_ATTRIBUTE_NORMAL: FlagsAndAttributes = FlagsAndAttributes(0x0000_0080); -const FILE_ATTRIBUTE_TEMPORARY: FlagsAndAttributes = FlagsAndAttributes(0x0000_0100); -const FILE_ATTRIBUTE_SPARSE_FILE: FlagsAndAttributes = FlagsAndAttributes(0x0000_0200); -const FILE_ATTRIBUTE_REPARSE_POINT: FlagsAndAttributes = FlagsAndAttributes(0x0000_0400); -const FILE_ATTRIBUTE_COMPRESSED: FlagsAndAttributes = FlagsAndAttributes(0x0000_0800); -const FILE_ATTRIBUTE_OFFLINE: FlagsAndAttributes = FlagsAndAttributes(0x0000_1000); -const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED: FlagsAndAttributes = FlagsAndAttributes(0x0000_2000); -const FILE_ATTRIBUTE_ENCRYPTED: FlagsAndAttributes = FlagsAndAttributes(0x0000_4000); -const FILE_ATTRIBUTE_INTEGRITY_STREAM: FlagsAndAttributes = FlagsAndAttributes(0x0000_8000); -const FILE_ATTRIBUTE_VIRTUAL: FlagsAndAttributes = FlagsAndAttributes(0x0001_0000); -const FILE_ATTRIBUTE_NO_SCRUB_DATA: FlagsAndAttributes = FlagsAndAttributes(0x0002_0000); -const FILE_ATTRIBUTE_EA: FlagsAndAttributes = FlagsAndAttributes(0x0004_0000); -const FILE_ATTRIBUTE_PINNED: FlagsAndAttributes = FlagsAndAttributes(0x0008_0000); -const FILE_ATTRIBUTE_UNPINNED: FlagsAndAttributes = FlagsAndAttributes(0x0010_0000); -const FILE_ATTRIBUTE_RECALL_ON_OPEN: FlagsAndAttributes = FlagsAndAttributes(0x0004_0000); // FILE_ATTRIBUTE_EA -const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS: FlagsAndAttributes = FlagsAndAttributes(0x0040_0000); -// -const FILE_FLAG_BACKUP_SEMANTICS: FlagsAndAttributes = FlagsAndAttributes(0x0200_0000); -const FILE_FLAG_DELETE_ON_CLOSE: FlagsAndAttributes = FlagsAndAttributes(0x0400_0000); -const FILE_FLAG_NO_BUFFERING: FlagsAndAttributes = FlagsAndAttributes(0x2000_0000); -const FILE_FLAG_OPEN_NO_RECALL: FlagsAndAttributes = FlagsAndAttributes(0x0010_0000); // FILE_ATTRIBUTE_UNPINNED -const FILE_FLAG_OPEN_REPARSE_POINT: FlagsAndAttributes = FlagsAndAttributes(0x0020_0000); -const FILE_FLAG_OVERLAPPED: FlagsAndAttributes = FlagsAndAttributes(0x40000000); -const FILE_FLAG_POSIX_SEMANTICS: FlagsAndAttributes = FlagsAndAttributes(0x01000000); -const FILE_FLAG_RANDOM_ACCESS: FlagsAndAttributes = FlagsAndAttributes(0x10000000); -const FILE_FLAG_SESSION_AWARE: FlagsAndAttributes = FlagsAndAttributes(0x00800000); -const FILE_FLAG_SEQUENTIAL_SCAN: FlagsAndAttributes = FlagsAndAttributes(0x08000000); -const FILE_FLAG_WRITE_THROUGH: FlagsAndAttributes = FlagsAndAttributes(0x80000000); -// -impl BitOr for FlagsAndAttributes { - type Output = Self; - fn bitor(self, rhs: Self) -> Self { - FlagsAndAttributes(self.0 | rhs.0) - } -} +// https://learn.microsoft.com/en-us/windows/win32/fileio/cancelioex-func +#[link(name = "kernel32")] extern "system" { - // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea - fn CreateFileA( - lpFileName: LPCSTR, // [in] - dwDesiredAccess: ACCESS_MASK, // [in] - dwShareMode: ShareMode, // [in] - lpSecurityAttributes: LPSECURITY_ATTRIBUTES, // [in, optional] - dwCreationDisposition: CreationDisposition, // [in] - dwFlagsAndAttributes: FlagsAndAttributes, // [in] - hTemplateFile: HANDLE, // [in, optional] - ) -> HANDLE; - fn CloseHandle(hObject: HANDLE, // [in] - ) -> BOOL; - fn ReadFile( - hFile: HANDLE, // [in] - lpBuffer: LPVOID, // [out] - nNumberOfBytesToRead: DWORD, // [in] - lpNumberOfBytesRead: LPDWORD, // [out, optional] - lpOverlapped: LPOVERLAPPED, // [in, out, optional] - ) -> BOOL; - fn WriteFile( - hFile: HANDLE, // [in] - lpBuffer: LPVOID, // [in] - nNumberOfBytesToWrite: DWORD, // [in] - lpNumberOfBytesWritten: LPDWORD, // [out, optional] - lpOverlapped: LPOVERLAPPED, // [in, out, optional] + pub fn CancelIoEx( + hFile: HANDLE, // [in] + lpOverlapped: LPOVERLAPPED, // [in, optional] ) -> BOOL; - fn GetOverlappedResult( +} + +// https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-getoverlappedresult +#[link(name = "kernel32")] +extern "system" { + pub fn GetOverlappedResult( hFile: HANDLE, // [in] lpOverlapped: LPOVERLAPPED, // [in] - lpNumberOfBytesTransferred: LPDWORD, // [out] + lpNumberOfBytesTransferred: LPDWORD, // [out, optional] bWait: BOOL, // [in] ) -> BOOL; - fn CancelIoEx( - hFile: HANDLE, // [in] - lpOverlapped: LPOVERLAPPED, // [in, optional] - ) -> BOOL; } -*/ + +// https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror +#[link(name = "kernel32")] +extern "system" { + pub fn GetLastError() -> Error; +} \ No newline at end of file diff --git a/test.txt b/test.txt new file mode 100644 index 00000000..c57eff55 --- /dev/null +++ b/test.txt @@ -0,0 +1 @@ +Hello World! \ No newline at end of file From 27ba1b86a19b83c37167331e8545b341b16d79f1 Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Sun, 22 Oct 2023 14:55:28 -0700 Subject: [PATCH 06/44] test.txt --- .gitignore | 1 + src/windows.rs | 2 +- test.txt | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 test.txt diff --git a/.gitignore b/.gitignore index 66a23c94..ec1abf6d 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ Cargo.lock tarpaulin-report.html cdt0 .DS_Store +_* diff --git a/src/windows.rs b/src/windows.rs index c9c05616..8ba2260a 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -140,7 +140,7 @@ mod test { fn test() { use super::{Handle, Overlapped}; // - let x: CString = CString::new("test.txt").unwrap(); + let x: CString = CString::new("_test.txt").unwrap(); { let mut handle = Handle::create(&x).unwrap(); diff --git a/test.txt b/test.txt deleted file mode 100644 index c57eff55..00000000 --- a/test.txt +++ /dev/null @@ -1 +0,0 @@ -Hello World! \ No newline at end of file From 745dfee05cedc52e126dee609949abb44d823323 Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Sun, 22 Oct 2023 15:02:32 -0700 Subject: [PATCH 07/44] fmt --- src/lib.rs | 2 +- src/windows.rs | 20 ++++++++++++-------- src/windows_api.rs | 24 +++++++++++++----------- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c1ab029d..9d08f162 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,8 +20,8 @@ mod u224; mod u256; mod u32; mod u512; -mod windows_api; mod windows; +mod windows_api; #[cfg(test)] mod mem_table; diff --git a/src/windows.rs b/src/windows.rs index 8ba2260a..0730f77f 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -1,9 +1,10 @@ -use std::{io, os::windows::raw::HANDLE, ptr::null_mut, ffi::CStr}; +use std::{ffi::CStr, io, os::windows::raw::HANDLE, ptr::null_mut}; use crate::windows_api::{ - CancelIoEx, CloseHandle, CreateFileA, CreationDisposition, GetOverlappedResult, ReadFile, - WriteFile, ACCESS_MASK, CREATE_ALWAYS, DWORD, FILE_ATTRIBUTE_NORMAL, FILE_FLAG_OVERLAPPED, - GENERIC_READ, GENERIC_WRITE, INVALID_HANDLE_VALUE, LPCVOID, LPVOID, OPEN_ALWAYS, OVERLAPPED, GetLastError, ERROR_IO_PENDING, BOOL, to_bool, + to_bool, CancelIoEx, CloseHandle, CreateFileA, CreationDisposition, GetLastError, + GetOverlappedResult, ReadFile, WriteFile, ACCESS_MASK, BOOL, CREATE_ALWAYS, DWORD, + ERROR_IO_PENDING, FILE_FLAG_OVERLAPPED, GENERIC_READ, GENERIC_WRITE, INVALID_HANDLE_VALUE, + LPCVOID, LPVOID, OPEN_ALWAYS, OVERLAPPED, }; struct Handle(HANDLE); @@ -48,7 +49,11 @@ impl Handle { Self::create_file(file_name, GENERIC_READ, OPEN_ALWAYS) } - fn to_operation<'a>(&'a mut self, overlapped: &'a mut Overlapped, result: BOOL) -> io::Result> { + fn create_operation<'a>( + &'a mut self, + overlapped: &'a mut Overlapped, + result: BOOL, + ) -> io::Result> { assert!(!to_bool(result)); let e = unsafe { GetLastError() }; if e == ERROR_IO_PENDING { @@ -75,7 +80,7 @@ impl Handle { &mut overlapped.0, ) }; - self.to_operation(overlapped, result) + self.create_operation(overlapped, result) } pub fn write<'a>( @@ -92,7 +97,7 @@ impl Handle { &mut overlapped.0, ) }; - self.to_operation(overlapped, result) + self.create_operation(overlapped, result) } } @@ -142,7 +147,6 @@ mod test { // let x: CString = CString::new("_test.txt").unwrap(); { - let mut handle = Handle::create(&x).unwrap(); let mut overlapped = Overlapped(Default::default()); let mut operation = handle.write(&mut overlapped, b"Hello World!").unwrap(); diff --git a/src/windows_api.rs b/src/windows_api.rs index 60e18a75..8cdba6b7 100644 --- a/src/windows_api.rs +++ b/src/windows_api.rs @@ -1,10 +1,13 @@ #![cfg(target_os = "windows")] #![allow(non_camel_case_types)] #![allow(non_snake_case)] +#![allow(clippy::upper_case_acronyms)] use std::{ + io, ops::BitOr, - os::{raw::c_void, windows::raw::HANDLE}, ptr::null_mut, io, + os::{raw::c_void, windows::raw::HANDLE}, + ptr::null_mut, }; pub const INVALID_HANDLE_VALUE: HANDLE = -1isize as HANDLE; @@ -32,9 +35,9 @@ const TRUE: BOOL = BOOL(1); pub const fn to_bool(x: BOOL) -> bool { x.0 != FALSE.0 } -impl Into for BOOL { - fn into(self) -> bool { - to_bool(self) +impl From for bool { + fn from(val: BOOL) -> Self { + to_bool(val) } } impl From for BOOL { @@ -121,7 +124,6 @@ pub const TRUNCATE_EXISTING: CreationDisposition = CreationDisposition(5); #[repr(transparent)] pub struct FlagsAndAttributes(DWORD); pub const FILE_FLAG_OVERLAPPED: FlagsAndAttributes = FlagsAndAttributes(0x40000000); -pub const FILE_ATTRIBUTE_NORMAL: FlagsAndAttributes = FlagsAndAttributes(0x00000080); impl BitOr for FlagsAndAttributes { type Output = Self; fn bitor(self, rhs: Self) -> Self { @@ -130,7 +132,7 @@ impl BitOr for FlagsAndAttributes { } // https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--500-999- -#[derive(PartialEq)] +#[derive(PartialEq, Clone, Copy)] #[repr(transparent)] pub struct Error(DWORD); pub const ERROR_IO_PENDING: Error = Error(997); @@ -170,11 +172,11 @@ extern "system" { #[link(name = "kernel32")] extern "system" { pub fn WriteFile( - hFile: HANDLE, // [in] - lpBuffer: LPCVOID, // [in] - nNumberOfBytesToWrite: DWORD, // [in] + hFile: HANDLE, // [in] + lpBuffer: LPCVOID, // [in] + nNumberOfBytesToWrite: DWORD, // [in] lpNumberOfBytesWritten: LPDWORD, // [out, optional] - lpOverlapped: LPOVERLAPPED, // [in, out, optional] + lpOverlapped: LPOVERLAPPED, // [in, out, optional] ) -> BOOL; } @@ -209,4 +211,4 @@ extern "system" { #[link(name = "kernel32")] extern "system" { pub fn GetLastError() -> Error; -} \ No newline at end of file +} From 13ca7ade25bd0bd45a477d5a42e1f8cd854f3a5a Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Sun, 22 Oct 2023 15:04:16 -0700 Subject: [PATCH 08/44] windows only --- src/windows.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/windows.rs b/src/windows.rs index 0730f77f..21612130 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -1,3 +1,4 @@ +#![cfg(target_os = "windows")] use std::{ffi::CStr, io, os::windows::raw::HANDLE, ptr::null_mut}; use crate::windows_api::{ From 19cfec0de241413b94cd6b93be79e29c8e295ee5 Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Sun, 22 Oct 2023 15:17:54 -0700 Subject: [PATCH 09/44] operation --- src/windows.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/windows.rs b/src/windows.rs index 21612130..4039cf1a 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -55,15 +55,21 @@ impl Handle { overlapped: &'a mut Overlapped, result: BOOL, ) -> io::Result> { - assert!(!to_bool(result)); - let e = unsafe { GetLastError() }; - if e == ERROR_IO_PENDING { - Ok(Operation { + if result.into() { + return Ok(Operation { handle: self, overlapped, - }) + }); } else { - Err(e.to_error()) + let e = unsafe { GetLastError() }; + if e == ERROR_IO_PENDING { + Ok(Operation { + handle: self, + overlapped, + }) + } else { + Err(e.to_error()) + } } } @@ -72,6 +78,7 @@ impl Handle { overlapped: &'a mut Overlapped, buffer: &'a mut [u8], // it's important that the buffer has the same life time as the overlapped! ) -> io::Result> { + *overlapped = Default::default(); let result = unsafe { ReadFile( self.0, @@ -89,6 +96,7 @@ impl Handle { overlapped: &'a mut Overlapped, buffer: &'a [u8], // it's important that the buffer has the same life time as the overlapped! ) -> io::Result> { + *overlapped = Default::default(); let result = unsafe { WriteFile( self.0, From 4c4f1051baa619b4742f8632ce4d8fea419fee4c Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Sun, 22 Oct 2023 15:41:13 -0700 Subject: [PATCH 10/44] Overlapped::default() --- src/windows.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/windows.rs b/src/windows.rs index 4039cf1a..67a44c66 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -157,14 +157,14 @@ mod test { let x: CString = CString::new("_test.txt").unwrap(); { let mut handle = Handle::create(&x).unwrap(); - let mut overlapped = Overlapped(Default::default()); + let mut overlapped = Overlapped::default(); let mut operation = handle.write(&mut overlapped, b"Hello World!").unwrap(); let result = operation.get_result(true).unwrap(); assert_eq!(result, 12); } { let mut handle = Handle::open(&x).unwrap(); - let mut overlapped = Overlapped(Default::default()); + let mut overlapped = Overlapped::default(); let mut buffer = [0u8; 1024]; { let mut operation = handle.read(&mut overlapped, &mut buffer).unwrap(); From 423fa25cb3ca08100d9ee50ecb56fa360f275d05 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Sun, 22 Oct 2023 17:43:56 -0700 Subject: [PATCH 11/44] posix --- Cargo.toml | 1 + src/lib.rs | 1 + src/posix.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ src/windows.rs | 1 + 4 files changed, 46 insertions(+) create mode 100644 src/posix.rs diff --git a/Cargo.toml b/Cargo.toml index 8032cd41..51aef1b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ authors = ["Sergey Shandar"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +libc = "0.2.149" [dev-dependencies] wasm-bindgen-test = "0.3.37" diff --git a/src/lib.rs b/src/lib.rs index 9d08f162..437706bc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,7 @@ mod u32; mod u512; mod windows; mod windows_api; +mod posix; #[cfg(test)] mod mem_table; diff --git a/src/posix.rs b/src/posix.rs new file mode 100644 index 00000000..587b47c4 --- /dev/null +++ b/src/posix.rs @@ -0,0 +1,43 @@ +#[cfg(test)] +mod test { + use std::{ffi::CString, mem::zeroed, time::Duration, thread::sleep}; + + use libc::{open, aiocb, O_WRONLY, O_CREAT, O_TRUNC, aio_error, aio_return, }; + + #[test] + fn test() { + let x: CString = CString::new("_test_posix.txt").unwrap(); + let fd = unsafe { open(x.as_ptr(), O_WRONLY|O_CREAT|O_TRUNC) }; + if fd == -1 { + panic!(); + } + let buffer = "Hello, world!"; + let mut aiocb: aiocb = unsafe { zeroed() }; + aiocb.aio_fildes = fd; + aiocb.aio_buf = buffer.as_ptr() as *mut _; + aiocb.aio_nbytes = buffer.len(); + + let r = unsafe { libc::aio_write(&mut aiocb) }; + if r == -1 { + panic!(); + } + + loop { + match unsafe { aio_error(&mut aiocb) } { + libc::EINPROGRESS => { + sleep(Duration::from_millis(100)); + }, + 0 => { + let bytes_written = unsafe { aio_return(&mut aiocb) }; + if bytes_written != buffer.len() as isize { + panic!(); + } + break + }, + _ => panic!(), + } + } + + unsafe { libc::close(fd) }; + } +} \ No newline at end of file diff --git a/src/windows.rs b/src/windows.rs index 67a44c66..ef730fbb 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -1,4 +1,5 @@ #![cfg(target_os = "windows")] +#![cfg(not(tarpaulin_include))] use std::{ffi::CStr, io, os::windows::raw::HANDLE, ptr::null_mut}; use crate::windows_api::{ From ee41fb6788ef7235b86c0857d1a6dd998ad781e8 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Sun, 22 Oct 2023 17:59:05 -0700 Subject: [PATCH 12/44] but coverage fails --- src/posix.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/posix.rs b/src/posix.rs index 587b47c4..9e84f972 100644 --- a/src/posix.rs +++ b/src/posix.rs @@ -1,3 +1,5 @@ +#![cfg(not(target_os = "windows"))] + #[cfg(test)] mod test { use std::{ffi::CString, mem::zeroed, time::Duration, thread::sleep}; @@ -7,7 +9,7 @@ mod test { #[test] fn test() { let x: CString = CString::new("_test_posix.txt").unwrap(); - let fd = unsafe { open(x.as_ptr(), O_WRONLY|O_CREAT|O_TRUNC) }; + let fd = unsafe { open(x.as_ptr(), O_WRONLY|O_CREAT|O_TRUNC, 0o644) }; if fd == -1 { panic!(); } From 5994f4439b8a4a04713f31db28196cea688ed761 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Sun, 22 Oct 2023 17:59:48 -0700 Subject: [PATCH 13/44] fmt --- src/lib.rs | 2 +- src/posix.rs | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 437706bc..74387642 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ mod digest; mod file_table; mod io; mod level_storage; +mod posix; mod real_io; mod sha224; mod sigma32; @@ -22,7 +23,6 @@ mod u32; mod u512; mod windows; mod windows_api; -mod posix; #[cfg(test)] mod mem_table; diff --git a/src/posix.rs b/src/posix.rs index 9e84f972..f2117272 100644 --- a/src/posix.rs +++ b/src/posix.rs @@ -2,14 +2,14 @@ #[cfg(test)] mod test { - use std::{ffi::CString, mem::zeroed, time::Duration, thread::sleep}; + use std::{ffi::CString, mem::zeroed, thread::sleep, time::Duration}; - use libc::{open, aiocb, O_WRONLY, O_CREAT, O_TRUNC, aio_error, aio_return, }; + use libc::{aio_error, aio_return, aiocb, open, O_CREAT, O_TRUNC, O_WRONLY}; #[test] fn test() { let x: CString = CString::new("_test_posix.txt").unwrap(); - let fd = unsafe { open(x.as_ptr(), O_WRONLY|O_CREAT|O_TRUNC, 0o644) }; + let fd = unsafe { open(x.as_ptr(), O_WRONLY | O_CREAT | O_TRUNC, 0o644) }; if fd == -1 { panic!(); } @@ -28,18 +28,18 @@ mod test { match unsafe { aio_error(&mut aiocb) } { libc::EINPROGRESS => { sleep(Duration::from_millis(100)); - }, + } 0 => { let bytes_written = unsafe { aio_return(&mut aiocb) }; if bytes_written != buffer.len() as isize { panic!(); } - break - }, + break; + } _ => panic!(), } } unsafe { libc::close(fd) }; } -} \ No newline at end of file +} From 6e3c14317ec55672a1d2abd345f1f4268d7df240 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Sun, 22 Oct 2023 18:17:09 -0700 Subject: [PATCH 14/44] os --- src/posix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/posix.rs b/src/posix.rs index f2117272..64fdd7fa 100644 --- a/src/posix.rs +++ b/src/posix.rs @@ -9,7 +9,7 @@ mod test { #[test] fn test() { let x: CString = CString::new("_test_posix.txt").unwrap(); - let fd = unsafe { open(x.as_ptr(), O_WRONLY | O_CREAT | O_TRUNC, 0o644) }; + let fd = unsafe { open(x.as_ptr(), O_WRONLY | O_CREAT | O_TRUNC) }; if fd == -1 { panic!(); } From 63ceb370837a872a48e396b55107753563a96f61 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Sun, 22 Oct 2023 23:14:52 -0700 Subject: [PATCH 15/44] family --- src/posix.rs | 65 +++++++++++++++++++++++++++++++++++++++++++++++++- src/windows.rs | 2 +- 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/posix.rs b/src/posix.rs index 64fdd7fa..926c4397 100644 --- a/src/posix.rs +++ b/src/posix.rs @@ -1,4 +1,67 @@ -#![cfg(not(target_os = "windows"))] +#![cfg(target_family = "unix")] + +use std::{ffi::CStr, io, mem::zeroed, thread::yield_now}; + +use libc::{close, open, aiocb, aio_cancel, aio_error, aio_return, AIO_NOTCANCELED}; + +struct File(i32); + +impl Drop for File { + fn drop(&mut self) { + unsafe { + close(self.0); + } + } +} + +struct Overlapped(aiocb); + +impl Default for Overlapped { + fn default() -> Self { + Self(unsafe { zeroed() }) + } +} + +struct Operation<'a> { + file: &'a mut File, + overlapped: &'a mut Overlapped, +} + +impl Drop for Operation<'_> { + fn drop(&mut self) { + let mut e = unsafe { aio_cancel(self.file.0, &mut self.overlapped.0) }; + while e == AIO_NOTCANCELED { + yield_now(); + e = unsafe { aio_error(&mut self.overlapped.0) }; + } + } +} + +impl Operation<'_> { + fn get_result(&mut self, wait: bool) -> io::Result { + match unsafe { aio_error(&mut self.overlapped.0) } { + 0 => Ok(unsafe { aio_return(&mut self.overlapped.0) } as usize), + _ => Err(io::Error::last_os_error()), + } + } +} + +impl File { + fn internal_open(path: &CStr, oflag: i32) -> io::Result { + let fd = unsafe { open(path.as_ptr(), oflag) }; + if fd == -1 { + Err(io::Error::last_os_error()) + } else { + Ok(Self(fd)) + } + } + pub fn create(path: &CStr) -> io::Result { + File::internal_open(path, libc::O_WRONLY | libc::O_CREAT | libc::O_TRUNC) + } + pub fn open(path: &CStr) -> io::Result { + File::internal_open(path, libc::O_RDONLY) + } +} #[cfg(test)] mod test { diff --git a/src/windows.rs b/src/windows.rs index ef730fbb..ee14b0cc 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -1,4 +1,4 @@ -#![cfg(target_os = "windows")] +#![cfg(target_family = "windows")] #![cfg(not(tarpaulin_include))] use std::{ffi::CStr, io, os::windows::raw::HANDLE, ptr::null_mut}; From 97c9f2db96017e5cca47d4cbe313f2756e83fa23 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Sun, 22 Oct 2023 23:18:35 -0700 Subject: [PATCH 16/44] posix --- src/posix.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/posix.rs b/src/posix.rs index 926c4397..d4cd9ca2 100644 --- a/src/posix.rs +++ b/src/posix.rs @@ -2,7 +2,7 @@ use std::{ffi::CStr, io, mem::zeroed, thread::yield_now}; -use libc::{close, open, aiocb, aio_cancel, aio_error, aio_return, AIO_NOTCANCELED}; +use libc::{aio_cancel, aio_error, aio_return, aiocb, close, open, AIO_NOTCANCELED}; struct File(i32); @@ -32,14 +32,14 @@ impl Drop for Operation<'_> { let mut e = unsafe { aio_cancel(self.file.0, &mut self.overlapped.0) }; while e == AIO_NOTCANCELED { yield_now(); - e = unsafe { aio_error(&mut self.overlapped.0) }; + e = unsafe { aio_error(&self.overlapped.0) }; } } } impl Operation<'_> { - fn get_result(&mut self, wait: bool) -> io::Result { - match unsafe { aio_error(&mut self.overlapped.0) } { + fn get_result(&mut self) -> io::Result { + match unsafe { aio_error(&self.overlapped.0) } { 0 => Ok(unsafe { aio_return(&mut self.overlapped.0) } as usize), _ => Err(io::Error::last_os_error()), } From 7839587803aa1a743da57f40b58864ba328a514f Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Mon, 23 Oct 2023 00:18:06 -0700 Subject: [PATCH 17/44] posix --- src/posix.rs | 119 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 87 insertions(+), 32 deletions(-) diff --git a/src/posix.rs b/src/posix.rs index d4cd9ca2..2633a3a7 100644 --- a/src/posix.rs +++ b/src/posix.rs @@ -37,11 +37,22 @@ impl Drop for Operation<'_> { } } +enum OperationResult { + Ok(usize), + Pending, + Err(io::Error), +} + impl Operation<'_> { - fn get_result(&mut self) -> io::Result { + fn get_result(&mut self) -> OperationResult { match unsafe { aio_error(&self.overlapped.0) } { - 0 => Ok(unsafe { aio_return(&mut self.overlapped.0) } as usize), - _ => Err(io::Error::last_os_error()), + 0 => OperationResult::Ok(unsafe { aio_return(&mut self.overlapped.0) } as usize), + e => { + if e == libc::EINPROGRESS { + return OperationResult::Pending; + } + OperationResult::Err(io::Error::from_raw_os_error(e)) + }, } } } @@ -61,48 +72,92 @@ impl File { pub fn open(path: &CStr) -> io::Result { File::internal_open(path, libc::O_RDONLY) } + pub fn write<'a>(&'a mut self, overlapped: &'a mut Overlapped, buffer: &'a[u8]) -> io::Result> { + *overlapped = Default::default(); + overlapped.0.aio_fildes = self.0; + overlapped.0.aio_buf = buffer.as_ptr() as *mut _; + overlapped.0.aio_nbytes = buffer.len(); + let r = unsafe { libc::aio_write(&mut overlapped.0) }; + if r == -1 { + Err(io::Error::last_os_error()) + } else { + Ok(Operation { + file: self, + overlapped, + }) + } + } + pub fn read<'a>(&'a mut self, overlapped: &'a mut Overlapped, buffer: &'a mut[u8]) -> io::Result> { + *overlapped = Default::default(); + overlapped.0.aio_fildes = self.0; + overlapped.0.aio_buf = buffer.as_ptr() as *mut _; + overlapped.0.aio_nbytes = buffer.len(); + let r = unsafe { libc::aio_read(&mut overlapped.0) }; + if r == -1 { + Err(io::Error::last_os_error()) + } else { + Ok(Operation { + file: self, + overlapped, + }) + } + } } #[cfg(test)] mod test { - use std::{ffi::CString, mem::zeroed, thread::sleep, time::Duration}; + use std::{ffi::CString, thread::yield_now}; - use libc::{aio_error, aio_return, aiocb, open, O_CREAT, O_TRUNC, O_WRONLY}; + use super::{File, Overlapped, OperationResult}; #[test] fn test() { let x: CString = CString::new("_test_posix.txt").unwrap(); - let fd = unsafe { open(x.as_ptr(), O_WRONLY | O_CREAT | O_TRUNC) }; - if fd == -1 { - panic!(); - } - let buffer = "Hello, world!"; - let mut aiocb: aiocb = unsafe { zeroed() }; - aiocb.aio_fildes = fd; - aiocb.aio_buf = buffer.as_ptr() as *mut _; - aiocb.aio_nbytes = buffer.len(); - - let r = unsafe { libc::aio_write(&mut aiocb) }; - if r == -1 { - panic!(); - } - - loop { - match unsafe { aio_error(&mut aiocb) } { - libc::EINPROGRESS => { - sleep(Duration::from_millis(100)); + let origin = "Hello, world!"; + { + let mut file = File::create(&x).unwrap(); + let mut overlapped: Overlapped = Overlapped::default(); + let mut operation = file.write(&mut overlapped, origin.as_bytes()).unwrap(); + loop { + match operation.get_result() { + OperationResult::Ok(bytes_written) => { + if bytes_written != origin.len() { + panic!(); + } + break; + } + OperationResult::Pending => { + yield_now(); + } + OperationResult::Err(e) => { + panic!("e: {}", e); + } } - 0 => { - let bytes_written = unsafe { aio_return(&mut aiocb) }; - if bytes_written != buffer.len() as isize { - panic!(); + } + } + { + let mut file = File::open(&x).unwrap(); + let mut overlapped: Overlapped = Overlapped::default(); + let mut buffer = [0u8; 1024]; + let mut len = 0; + { + let mut operation = file.read(&mut overlapped, &mut buffer).unwrap(); + loop { + match operation.get_result() { + OperationResult::Ok(bytes_read) => { + len = bytes_read; + break; + } + OperationResult::Pending => { + yield_now(); + } + OperationResult::Err(e) => { + panic!("e: {}", e); + } } - break; } - _ => panic!(), } + assert_eq!(&buffer[..len], origin.as_bytes()); } - - unsafe { libc::close(fd) }; } } From 6948c4719fad9ae3af2857532e4fca6a92547ed4 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Mon, 23 Oct 2023 00:44:06 -0700 Subject: [PATCH 18/44] fmt --- src/posix.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/posix.rs b/src/posix.rs index 2633a3a7..81df92f9 100644 --- a/src/posix.rs +++ b/src/posix.rs @@ -52,7 +52,7 @@ impl Operation<'_> { return OperationResult::Pending; } OperationResult::Err(io::Error::from_raw_os_error(e)) - }, + } } } } @@ -72,7 +72,11 @@ impl File { pub fn open(path: &CStr) -> io::Result { File::internal_open(path, libc::O_RDONLY) } - pub fn write<'a>(&'a mut self, overlapped: &'a mut Overlapped, buffer: &'a[u8]) -> io::Result> { + pub fn write<'a>( + &'a mut self, + overlapped: &'a mut Overlapped, + buffer: &'a [u8], + ) -> io::Result> { *overlapped = Default::default(); overlapped.0.aio_fildes = self.0; overlapped.0.aio_buf = buffer.as_ptr() as *mut _; @@ -87,7 +91,11 @@ impl File { }) } } - pub fn read<'a>(&'a mut self, overlapped: &'a mut Overlapped, buffer: &'a mut[u8]) -> io::Result> { + pub fn read<'a>( + &'a mut self, + overlapped: &'a mut Overlapped, + buffer: &'a mut [u8], + ) -> io::Result> { *overlapped = Default::default(); overlapped.0.aio_fildes = self.0; overlapped.0.aio_buf = buffer.as_ptr() as *mut _; @@ -106,9 +114,9 @@ impl File { #[cfg(test)] mod test { - use std::{ffi::CString, thread::yield_now}; + use std::{ffi::CString, thread::yield_now}; - use super::{File, Overlapped, OperationResult}; + use super::{File, OperationResult, Overlapped}; #[test] fn test() { From 0c519c4cfd0418a37765cdf758b6a5d6883c67c6 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Mon, 23 Oct 2023 00:46:46 -0700 Subject: [PATCH 19/44] 644 --- src/posix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/posix.rs b/src/posix.rs index 81df92f9..c4e433c1 100644 --- a/src/posix.rs +++ b/src/posix.rs @@ -59,7 +59,7 @@ impl Operation<'_> { impl File { fn internal_open(path: &CStr, oflag: i32) -> io::Result { - let fd = unsafe { open(path.as_ptr(), oflag) }; + let fd = unsafe { open(path.as_ptr(), oflag, 0o644) }; if fd == -1 { Err(io::Error::last_os_error()) } else { From f8867455bdf62fe988863bfad5e539c74bea873c Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Mon, 23 Oct 2023 01:00:48 -0700 Subject: [PATCH 20/44] common function --- src/posix.rs | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/posix.rs b/src/posix.rs index c4e433c1..a84667d5 100644 --- a/src/posix.rs +++ b/src/posix.rs @@ -2,7 +2,9 @@ use std::{ffi::CStr, io, mem::zeroed, thread::yield_now}; -use libc::{aio_cancel, aio_error, aio_return, aiocb, close, open, AIO_NOTCANCELED}; +use libc::{ + aio_cancel, aio_error, aio_read, aio_return, aio_write, aiocb, close, open, AIO_NOTCANCELED, +}; struct File(i32); @@ -72,16 +74,17 @@ impl File { pub fn open(path: &CStr) -> io::Result { File::internal_open(path, libc::O_RDONLY) } - pub fn write<'a>( + fn create_operation<'a>( &'a mut self, overlapped: &'a mut Overlapped, buffer: &'a [u8], + f: unsafe extern "C" fn(*mut aiocb) -> i32, ) -> io::Result> { *overlapped = Default::default(); overlapped.0.aio_fildes = self.0; overlapped.0.aio_buf = buffer.as_ptr() as *mut _; overlapped.0.aio_nbytes = buffer.len(); - let r = unsafe { libc::aio_write(&mut overlapped.0) }; + let r = unsafe { f(&mut overlapped.0) }; if r == -1 { Err(io::Error::last_os_error()) } else { @@ -91,24 +94,19 @@ impl File { }) } } + pub fn write<'a>( + &'a mut self, + overlapped: &'a mut Overlapped, + buffer: &'a [u8], + ) -> io::Result> { + self.create_operation(overlapped, buffer, aio_write) + } pub fn read<'a>( &'a mut self, overlapped: &'a mut Overlapped, buffer: &'a mut [u8], ) -> io::Result> { - *overlapped = Default::default(); - overlapped.0.aio_fildes = self.0; - overlapped.0.aio_buf = buffer.as_ptr() as *mut _; - overlapped.0.aio_nbytes = buffer.len(); - let r = unsafe { libc::aio_read(&mut overlapped.0) }; - if r == -1 { - Err(io::Error::last_os_error()) - } else { - Ok(Operation { - file: self, - overlapped, - }) - } + self.create_operation(overlapped, buffer, aio_read) } } From 43dde280e05ab46b352efe33420dd26b59ef511d Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Mon, 23 Oct 2023 01:02:40 -0700 Subject: [PATCH 21/44] no r --- src/posix.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/posix.rs b/src/posix.rs index a84667d5..1bb58b7f 100644 --- a/src/posix.rs +++ b/src/posix.rs @@ -84,8 +84,7 @@ impl File { overlapped.0.aio_fildes = self.0; overlapped.0.aio_buf = buffer.as_ptr() as *mut _; overlapped.0.aio_nbytes = buffer.len(); - let r = unsafe { f(&mut overlapped.0) }; - if r == -1 { + if unsafe { f(&mut overlapped.0) } == -1 { Err(io::Error::last_os_error()) } else { Ok(Operation { From 4db1afcaec332daade488841ce5aa6a0b11c74de Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Mon, 23 Oct 2023 21:56:58 -0700 Subject: [PATCH 22/44] Operation --- src/io.rs | 24 ++++++++++++++++++++++++ src/posix.rs | 8 ++------ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/io.rs b/src/io.rs index 37f41be0..80f9bba8 100644 --- a/src/io.rs +++ b/src/io.rs @@ -78,6 +78,30 @@ pub trait Io { } } +pub enum OperationResult { + Ok(usize), + Pending, + Err(io::Error), +} + +trait Operation { + fn get_result(&mut self) -> OperationResult; +} + +trait AsyncFile { + type Operation<'a>: Operation + where + Self: 'a; + fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> io::Result>; + fn write<'a>(&'a mut self, buffer: &'a [u8]) -> io::Result>; +} + +trait AsyncIo { + type File: AsyncFile; + fn create(&self, path: &str) -> io::Result; + fn open(&self, path: &str) -> io::Result; +} + #[cfg(test)] mod test { use wasm_bindgen_test::wasm_bindgen_test; diff --git a/src/posix.rs b/src/posix.rs index 1bb58b7f..74308437 100644 --- a/src/posix.rs +++ b/src/posix.rs @@ -6,6 +6,8 @@ use libc::{ aio_cancel, aio_error, aio_read, aio_return, aio_write, aiocb, close, open, AIO_NOTCANCELED, }; +use crate::io::OperationResult; + struct File(i32); impl Drop for File { @@ -39,12 +41,6 @@ impl Drop for Operation<'_> { } } -enum OperationResult { - Ok(usize), - Pending, - Err(io::Error), -} - impl Operation<'_> { fn get_result(&mut self) -> OperationResult { match unsafe { aio_error(&self.overlapped.0) } { From c0ad081abb112c7b76a88ea0bad1aff280c11bf4 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Tue, 24 Oct 2023 06:27:51 -0700 Subject: [PATCH 23/44] CStr --- src/io.rs | 13 +++++++------ src/posix.rs | 45 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/io.rs b/src/io.rs index 80f9bba8..26b91cf2 100644 --- a/src/io.rs +++ b/src/io.rs @@ -1,4 +1,5 @@ use std::{ + ffi::CStr, fmt, io::{self, Read, Write}, }; @@ -84,22 +85,22 @@ pub enum OperationResult { Err(io::Error), } -trait Operation { +pub trait AsyncOperation { fn get_result(&mut self) -> OperationResult; } -trait AsyncFile { - type Operation<'a>: Operation +pub trait AsyncFile { + type Operation<'a>: AsyncOperation where Self: 'a; fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> io::Result>; fn write<'a>(&'a mut self, buffer: &'a [u8]) -> io::Result>; } -trait AsyncIo { +pub trait AsyncIo { type File: AsyncFile; - fn create(&self, path: &str) -> io::Result; - fn open(&self, path: &str) -> io::Result; + fn create(&self, path: &CStr) -> io::Result; + fn open(&self, path: &CStr) -> io::Result; } #[cfg(test)] diff --git a/src/posix.rs b/src/posix.rs index 74308437..1f172e3f 100644 --- a/src/posix.rs +++ b/src/posix.rs @@ -6,7 +6,7 @@ use libc::{ aio_cancel, aio_error, aio_read, aio_return, aio_write, aiocb, close, open, AIO_NOTCANCELED, }; -use crate::io::OperationResult; +use crate::io::{AsyncFile, AsyncIo, AsyncOperation, OperationResult}; struct File(i32); @@ -105,6 +105,49 @@ impl File { } } +impl AsyncOperation for Operation<'_> { + fn get_result(&mut self) -> OperationResult { + self.get_result() + } +} + +struct AFile { + file: File, + overlapped: Overlapped, +} + +impl AsyncFile for AFile { + type Operation<'a> = Operation<'a>; + + fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> io::Result> { + self.file.read(&mut self.overlapped, buffer) + } + + fn write<'a>(&'a mut self, buffer: &'a [u8]) -> io::Result> { + self.file.write(&mut self.overlapped, buffer) + } +} + +struct AIo(); + +impl AsyncIo for AIo { + type File = AFile; + + fn create(&self, path: &CStr) -> io::Result { + Ok(AFile { + file: File::create(path)?, + overlapped: Default::default(), + }) + } + + fn open(&self, path: &CStr) -> io::Result { + Ok(AFile { + file: File::open(path)?, + overlapped: Default::default(), + }) + } +} + #[cfg(test)] mod test { use std::{ffi::CString, thread::yield_now}; From cb3d5b54bc18245f502217db63e08bc656b9747e Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Tue, 24 Oct 2023 06:49:04 -0700 Subject: [PATCH 24/44] Windows with OperationResult --- src/windows.rs | 147 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 118 insertions(+), 29 deletions(-) diff --git a/src/windows.rs b/src/windows.rs index ee14b0cc..51aa434b 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -2,11 +2,14 @@ #![cfg(not(tarpaulin_include))] use std::{ffi::CStr, io, os::windows::raw::HANDLE, ptr::null_mut}; -use crate::windows_api::{ - to_bool, CancelIoEx, CloseHandle, CreateFileA, CreationDisposition, GetLastError, - GetOverlappedResult, ReadFile, WriteFile, ACCESS_MASK, BOOL, CREATE_ALWAYS, DWORD, - ERROR_IO_PENDING, FILE_FLAG_OVERLAPPED, GENERIC_READ, GENERIC_WRITE, INVALID_HANDLE_VALUE, - LPCVOID, LPVOID, OPEN_ALWAYS, OVERLAPPED, +use crate::{ + io::{AsyncFile, AsyncIo, AsyncOperation, OperationResult}, + windows_api::{ + to_bool, CancelIoEx, CloseHandle, CreateFileA, CreationDisposition, GetLastError, + GetOverlappedResult, ReadFile, WriteFile, ACCESS_MASK, BOOL, CREATE_ALWAYS, DWORD, + ERROR_IO_PENDING, FILE_FLAG_OVERLAPPED, GENERIC_READ, GENERIC_WRITE, INVALID_HANDLE_VALUE, + LPCVOID, LPVOID, OPEN_ALWAYS, OVERLAPPED, + }, }; struct Handle(HANDLE); @@ -19,6 +22,19 @@ impl Drop for Handle { } } +fn to_operation_result(v: BOOL) -> OperationResult { + if to_bool(v) { + OperationResult::Ok(0) + } else { + let e = unsafe { GetLastError() }; + if e == ERROR_IO_PENDING { + OperationResult::Pending + } else { + OperationResult::Err(e.to_error()) + } + } +} + impl Handle { fn create_file( file_name: &CStr, @@ -37,8 +53,6 @@ impl Handle { ) }; if result == INVALID_HANDLE_VALUE { - let e = io::Error::last_os_error(); - println!("{}", e); Err(io::Error::last_os_error()) } else { Ok(Self(result)) @@ -56,21 +70,13 @@ impl Handle { overlapped: &'a mut Overlapped, result: BOOL, ) -> io::Result> { - if result.into() { - return Ok(Operation { + if let OperationResult::Err(e) = to_operation_result(result) { + Err(e) + } else { + Ok(Operation { handle: self, overlapped, - }); - } else { - let e = unsafe { GetLastError() }; - if e == ERROR_IO_PENDING { - Ok(Operation { - handle: self, - overlapped, - }) - } else { - Err(e.to_error()) - } + }) } } @@ -129,7 +135,7 @@ impl Drop for Operation<'_> { } impl Operation<'_> { - fn get_result(&mut self, wait: bool) -> io::Result { + fn get_result(&mut self, wait: bool) -> OperationResult { let mut result: DWORD = 0; let r = unsafe { GetOverlappedResult( @@ -140,28 +146,95 @@ impl Operation<'_> { ) }; if r.into() { - Ok(result as usize) + OperationResult::Ok(result as usize) } else { - Err(io::Error::last_os_error()) + let e = unsafe { GetLastError() }; + if e == ERROR_IO_PENDING { + OperationResult::Pending + } else { + OperationResult::Err(e.to_error()) + } } } } +impl AsyncOperation for Operation<'_> { + fn get_result(&mut self) -> OperationResult { + self.get_result(false) + } +} + +struct AFile { + file: Handle, + overlapped: Overlapped, +} + +impl AsyncFile for AFile { + type Operation<'a> = Operation<'a>; + + fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> io::Result> { + self.file.read(&mut self.overlapped, buffer) + } + + fn write<'a>(&'a mut self, buffer: &'a [u8]) -> io::Result> { + self.file.write(&mut self.overlapped, buffer) + } +} + +struct AIo(); + +impl AsyncIo for AIo { + type File = AFile; + + fn create(&self, path: &CStr) -> io::Result { + Ok(AFile { + file: Handle::create(path)?, + overlapped: Default::default(), + }) + } + + fn open(&self, path: &CStr) -> io::Result { + Ok(AFile { + file: Handle::open(path)?, + overlapped: Default::default(), + }) + } +} + #[cfg(test)] mod test { - use std::ffi::CString; + use std::{ffi::CString, thread::yield_now}; + + use crate::io::OperationResult; #[test] fn test() { use super::{Handle, Overlapped}; // let x: CString = CString::new("_test.txt").unwrap(); + let origin = b"Hello World!"; { let mut handle = Handle::create(&x).unwrap(); let mut overlapped = Overlapped::default(); - let mut operation = handle.write(&mut overlapped, b"Hello World!").unwrap(); - let result = operation.get_result(true).unwrap(); - assert_eq!(result, 12); + let mut operation = handle.write(&mut overlapped, origin).unwrap(); + loop { + match operation.get_result(false) { + OperationResult::Ok(bytes_written) => { + if bytes_written != origin.len() { + panic!(); + } + break; + } + OperationResult::Pending => { + yield_now(); + } + OperationResult::Err(e) => { + panic!("e: {}", e); + } + } + } + // let result = operation.get_result(true).unwrap(); + // assert_eq!(result, 12); } { let mut handle = Handle::open(&x).unwrap(); @@ -169,8 +242,24 @@ mod test { let mut buffer = [0u8; 1024]; { let mut operation = handle.read(&mut overlapped, &mut buffer).unwrap(); - let result = operation.get_result(true).unwrap(); - assert_eq!(result, 12); + loop { + match operation.get_result(false) { + OperationResult::Ok(bytes_written) => { + if bytes_written != origin.len() { + panic!(); + } + break; + } + OperationResult::Pending => { + yield_now(); + } + OperationResult::Err(e) => { + panic!("e: {}", e); + } + } + } + // let result = operation.get_result(true).unwrap(); + // assert_eq!(result, 12); } assert_eq!(&buffer[..12], b"Hello World!"); } From bd3805288d37f370f37d206f7fd2239c1b3d0906 Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Thu, 26 Oct 2023 19:10:38 -0700 Subject: [PATCH 25/44] fmt --- src/async_io.rs | 25 +++++++++++++++++++++++++ src/io.rs | 24 ------------------------ src/lib.rs | 1 + src/windows.rs | 4 ++-- 4 files changed, 28 insertions(+), 26 deletions(-) create mode 100644 src/async_io.rs diff --git a/src/async_io.rs b/src/async_io.rs new file mode 100644 index 00000000..d852db2b --- /dev/null +++ b/src/async_io.rs @@ -0,0 +1,25 @@ +use std::{ffi::CStr, io}; + +pub enum OperationResult { + Ok(usize), + Pending, + Err(io::Error), +} + +pub trait AsyncOperation { + fn get_result(&mut self) -> OperationResult; +} + +pub trait AsyncFile { + type Operation<'a>: AsyncOperation + where + Self: 'a; + fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> io::Result>; + fn write<'a>(&'a mut self, buffer: &'a [u8]) -> io::Result>; +} + +pub trait AsyncIo { + type File: AsyncFile; + fn create(&self, path: &CStr) -> io::Result; + fn open(&self, path: &CStr) -> io::Result; +} diff --git a/src/io.rs b/src/io.rs index 26b91cf2..5fdcb3b8 100644 --- a/src/io.rs +++ b/src/io.rs @@ -79,30 +79,6 @@ pub trait Io { } } -pub enum OperationResult { - Ok(usize), - Pending, - Err(io::Error), -} - -pub trait AsyncOperation { - fn get_result(&mut self) -> OperationResult; -} - -pub trait AsyncFile { - type Operation<'a>: AsyncOperation - where - Self: 'a; - fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> io::Result>; - fn write<'a>(&'a mut self, buffer: &'a [u8]) -> io::Result>; -} - -pub trait AsyncIo { - type File: AsyncFile; - fn create(&self, path: &CStr) -> io::Result; - fn open(&self, path: &CStr) -> io::Result; -} - #[cfg(test)] mod test { use wasm_bindgen_test::wasm_bindgen_test; diff --git a/src/lib.rs b/src/lib.rs index 74387642..977e316d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ mod app; mod array; mod ascii; +mod async_io; mod base32; mod bit_vec; mod digest; diff --git a/src/windows.rs b/src/windows.rs index 51aa434b..e394ec1e 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -3,7 +3,7 @@ use std::{ffi::CStr, io, os::windows::raw::HANDLE, ptr::null_mut}; use crate::{ - io::{AsyncFile, AsyncIo, AsyncOperation, OperationResult}, + async_io::{AsyncFile, AsyncIo, AsyncOperation, OperationResult}, windows_api::{ to_bool, CancelIoEx, CloseHandle, CreateFileA, CreationDisposition, GetLastError, GetOverlappedResult, ReadFile, WriteFile, ACCESS_MASK, BOOL, CREATE_ALWAYS, DWORD, @@ -205,7 +205,7 @@ impl AsyncIo for AIo { mod test { use std::{ffi::CString, thread::yield_now}; - use crate::io::OperationResult; + use crate::async_io::OperationResult; #[test] fn test() { From f97375f231960a600c88301c8cea869a4ce14795 Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Thu, 26 Oct 2023 19:15:45 -0700 Subject: [PATCH 26/44] async_io fpr posix --- src/posix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/posix.rs b/src/posix.rs index 1f172e3f..84245eaf 100644 --- a/src/posix.rs +++ b/src/posix.rs @@ -6,7 +6,7 @@ use libc::{ aio_cancel, aio_error, aio_read, aio_return, aio_write, aiocb, close, open, AIO_NOTCANCELED, }; -use crate::io::{AsyncFile, AsyncIo, AsyncOperation, OperationResult}; +use crate::async_io::{AsyncFile, AsyncIo, AsyncOperation, OperationResult}; struct File(i32); From 8c2c5bd97c03da67166903e54e5c13831b852203 Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Thu, 26 Oct 2023 19:23:06 -0700 Subject: [PATCH 27/44] real_async_io --- src/lib.rs | 1 + src/real_async_io.rs | 5 +++++ src/windows.rs | 20 ++++++++++---------- 3 files changed, 16 insertions(+), 10 deletions(-) create mode 100644 src/real_async_io.rs diff --git a/src/lib.rs b/src/lib.rs index 977e316d..d02c9119 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,7 @@ mod file_table; mod io; mod level_storage; mod posix; +mod real_async_io; mod real_io; mod sha224; mod sigma32; diff --git a/src/real_async_io.rs b/src/real_async_io.rs new file mode 100644 index 00000000..2ba5b9a8 --- /dev/null +++ b/src/real_async_io.rs @@ -0,0 +1,5 @@ +#[cfg(target_family = "windows")] +use crate::windows::*; + +#[cfg(target_family = "unix")] +use crate::posix::*; diff --git a/src/windows.rs b/src/windows.rs index e394ec1e..a4f5e004 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -12,9 +12,9 @@ use crate::{ }, }; -struct Handle(HANDLE); +struct File(HANDLE); -impl Drop for Handle { +impl Drop for File { fn drop(&mut self) { unsafe { CloseHandle(self.0); @@ -35,7 +35,7 @@ fn to_operation_result(v: BOOL) -> OperationResult { } } -impl Handle { +impl File { fn create_file( file_name: &CStr, desired_access: ACCESS_MASK, @@ -121,7 +121,7 @@ impl Handle { struct Overlapped(OVERLAPPED); struct Operation<'a> { - handle: &'a mut Handle, + handle: &'a mut File, overlapped: &'a mut Overlapped, } @@ -165,7 +165,7 @@ impl AsyncOperation for Operation<'_> { } struct AFile { - file: Handle, + file: File, overlapped: Overlapped, } @@ -188,14 +188,14 @@ impl AsyncIo for AIo { fn create(&self, path: &CStr) -> io::Result { Ok(AFile { - file: Handle::create(path)?, + file: File::create(path)?, overlapped: Default::default(), }) } fn open(&self, path: &CStr) -> io::Result { Ok(AFile { - file: Handle::open(path)?, + file: File::open(path)?, overlapped: Default::default(), }) } @@ -209,12 +209,12 @@ mod test { #[test] fn test() { - use super::{Handle, Overlapped}; + use super::{File, Overlapped}; // let x: CString = CString::new("_test.txt").unwrap(); let origin = b"Hello World!"; { - let mut handle = Handle::create(&x).unwrap(); + let mut handle = File::create(&x).unwrap(); let mut overlapped = Overlapped::default(); let mut operation = handle.write(&mut overlapped, origin).unwrap(); loop { @@ -237,7 +237,7 @@ mod test { // assert_eq!(result, 12); } { - let mut handle = Handle::open(&x).unwrap(); + let mut handle = File::open(&x).unwrap(); let mut overlapped = Overlapped::default(); let mut buffer = [0u8; 1024]; { From cd02bcdbe3d9d71a5b9479f8a50e4db47dc579cb Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Thu, 26 Oct 2023 19:45:20 -0700 Subject: [PATCH 28/44] real_async_io with Windows --- src/real_async_io.rs | 106 +++++++++++++++++++++++++++++++++++++++++++ src/windows.rs | 6 +-- 2 files changed, 109 insertions(+), 3 deletions(-) diff --git a/src/real_async_io.rs b/src/real_async_io.rs index 2ba5b9a8..db70af55 100644 --- a/src/real_async_io.rs +++ b/src/real_async_io.rs @@ -1,5 +1,111 @@ +use std::{io, ffi::CStr}; + +use crate::async_io::{AsyncFile, AsyncIo}; + #[cfg(target_family = "windows")] use crate::windows::*; #[cfg(target_family = "unix")] use crate::posix::*; + +struct AFile { + file: File, + overlapped: Overlapped, +} + +impl AsyncFile for AFile { + type Operation<'a> = Operation<'a>; + + fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> io::Result> { + self.file.read(&mut self.overlapped, buffer) + } + + fn write<'a>(&'a mut self, buffer: &'a [u8]) -> io::Result> { + self.file.write(&mut self.overlapped, buffer) + } +} + +struct AIo(); + +impl AsyncIo for AIo { + type File = AFile; + + fn create(&self, path: &CStr) -> io::Result { + Ok(AFile { + file: File::create(path)?, + overlapped: Default::default(), + }) + } + + fn open(&self, path: &CStr) -> io::Result { + Ok(AFile { + file: File::open(path)?, + overlapped: Default::default(), + }) + } +} + +#[cfg(test)] +mod test { + use std::{ffi::CString, thread::yield_now}; + + use crate::async_io::{OperationResult, AsyncOperation}; + + #[test] + fn test() { + use super::{File, Overlapped}; + // + let x: CString = CString::new("_test.txt").unwrap(); + let origin = b"Hello World!"; + { + let mut handle = File::create(&x).unwrap(); + let mut overlapped = Overlapped::default(); + let mut operation = handle.write(&mut overlapped, origin).unwrap(); + loop { + match operation.get_result() { + OperationResult::Ok(bytes_written) => { + if bytes_written != origin.len() { + panic!(); + } + break; + } + OperationResult::Pending => { + yield_now(); + } + OperationResult::Err(e) => { + panic!("e: {}", e); + } + } + } + // let result = operation.get_result(true).unwrap(); + // assert_eq!(result, 12); + } + { + let mut handle = File::open(&x).unwrap(); + let mut overlapped = Overlapped::default(); + let mut buffer = [0u8; 1024]; + { + let mut operation = handle.read(&mut overlapped, &mut buffer).unwrap(); + loop { + match operation.get_result() { + OperationResult::Ok(bytes_written) => { + if bytes_written != origin.len() { + panic!(); + } + break; + } + OperationResult::Pending => { + yield_now(); + } + OperationResult::Err(e) => { + panic!("e: {}", e); + } + } + } + // let result = operation.get_result(true).unwrap(); + // assert_eq!(result, 12); + } + assert_eq!(&buffer[..12], b"Hello World!"); + } + } +} diff --git a/src/windows.rs b/src/windows.rs index a4f5e004..dd2178af 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -12,7 +12,7 @@ use crate::{ }, }; -struct File(HANDLE); +pub struct File(HANDLE); impl Drop for File { fn drop(&mut self) { @@ -118,9 +118,9 @@ impl File { } #[derive(Default)] -struct Overlapped(OVERLAPPED); +pub struct Overlapped(OVERLAPPED); -struct Operation<'a> { +pub struct Operation<'a> { handle: &'a mut File, overlapped: &'a mut Overlapped, } From b2d0e92a0db175eaeeee60f4a8c73f51d15995db Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Thu, 26 Oct 2023 19:47:03 -0700 Subject: [PATCH 29/44] with Posix --- src/posix.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/posix.rs b/src/posix.rs index 84245eaf..f0a8826e 100644 --- a/src/posix.rs +++ b/src/posix.rs @@ -8,7 +8,7 @@ use libc::{ use crate::async_io::{AsyncFile, AsyncIo, AsyncOperation, OperationResult}; -struct File(i32); +pub struct File(i32); impl Drop for File { fn drop(&mut self) { @@ -18,7 +18,7 @@ impl Drop for File { } } -struct Overlapped(aiocb); +pub struct Overlapped(aiocb); impl Default for Overlapped { fn default() -> Self { @@ -26,7 +26,7 @@ impl Default for Overlapped { } } -struct Operation<'a> { +pub struct Operation<'a> { file: &'a mut File, overlapped: &'a mut Overlapped, } From 14c931c2e9ee6c73130ff385323ecb6d907da0f6 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Thu, 26 Oct 2023 19:47:28 -0700 Subject: [PATCH 30/44] unix --- src/lib.rs | 2 +- src/real_async_io.rs | 2 +- src/{posix.rs => unix.rs} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/{posix.rs => unix.rs} (100%) diff --git a/src/lib.rs b/src/lib.rs index d02c9119..a3134ed2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ mod digest; mod file_table; mod io; mod level_storage; -mod posix; +mod unix; mod real_async_io; mod real_io; mod sha224; diff --git a/src/real_async_io.rs b/src/real_async_io.rs index db70af55..76224bd8 100644 --- a/src/real_async_io.rs +++ b/src/real_async_io.rs @@ -6,7 +6,7 @@ use crate::async_io::{AsyncFile, AsyncIo}; use crate::windows::*; #[cfg(target_family = "unix")] -use crate::posix::*; +use crate::unix::*; struct AFile { file: File, diff --git a/src/posix.rs b/src/unix.rs similarity index 100% rename from src/posix.rs rename to src/unix.rs From c800e01947e2e693b9193a70c86c47dcbf69612f Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Thu, 26 Oct 2023 19:48:12 -0700 Subject: [PATCH 31/44] fmt --- src/lib.rs | 2 +- src/real_async_io.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a3134ed2..06e19017 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,6 @@ mod digest; mod file_table; mod io; mod level_storage; -mod unix; mod real_async_io; mod real_io; mod sha224; @@ -23,6 +22,7 @@ mod u224; mod u256; mod u32; mod u512; +mod unix; mod windows; mod windows_api; diff --git a/src/real_async_io.rs b/src/real_async_io.rs index 76224bd8..b0813e8b 100644 --- a/src/real_async_io.rs +++ b/src/real_async_io.rs @@ -1,4 +1,4 @@ -use std::{io, ffi::CStr}; +use std::{ffi::CStr, io}; use crate::async_io::{AsyncFile, AsyncIo}; @@ -49,7 +49,7 @@ impl AsyncIo for AIo { mod test { use std::{ffi::CString, thread::yield_now}; - use crate::async_io::{OperationResult, AsyncOperation}; + use crate::async_io::{AsyncOperation, OperationResult}; #[test] fn test() { From df3e1ee829b11dbca09b866806f5fa8bda3df5a9 Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Thu, 26 Oct 2023 19:55:43 -0700 Subject: [PATCH 32/44] remove duplicate tests --- src/real_async_io.rs | 53 +++++++++++++++++++++++++++++++++++- src/unix.rs | 58 --------------------------------------- src/windows.rs | 65 -------------------------------------------- 3 files changed, 52 insertions(+), 124 deletions(-) diff --git a/src/real_async_io.rs b/src/real_async_io.rs index b0813e8b..575b6826 100644 --- a/src/real_async_io.rs +++ b/src/real_async_io.rs @@ -49,11 +49,11 @@ impl AsyncIo for AIo { mod test { use std::{ffi::CString, thread::yield_now}; + use super::{File, Overlapped}; use crate::async_io::{AsyncOperation, OperationResult}; #[test] fn test() { - use super::{File, Overlapped}; // let x: CString = CString::new("_test.txt").unwrap(); let origin = b"Hello World!"; @@ -108,4 +108,55 @@ mod test { assert_eq!(&buffer[..12], b"Hello World!"); } } + + #[test] + fn test2() { + let x: CString = CString::new("_test_posix.txt").unwrap(); + let origin = "Hello, world!"; + { + let mut file = File::create(&x).unwrap(); + let mut overlapped: Overlapped = Overlapped::default(); + let mut operation = file.write(&mut overlapped, origin.as_bytes()).unwrap(); + loop { + match operation.get_result() { + OperationResult::Ok(bytes_written) => { + if bytes_written != origin.len() { + panic!(); + } + break; + } + OperationResult::Pending => { + yield_now(); + } + OperationResult::Err(e) => { + panic!("e: {}", e); + } + } + } + } + { + let mut file = File::open(&x).unwrap(); + let mut overlapped: Overlapped = Overlapped::default(); + let mut buffer = [0u8; 1024]; + let mut len = 0; + { + let mut operation = file.read(&mut overlapped, &mut buffer).unwrap(); + loop { + match operation.get_result() { + OperationResult::Ok(bytes_read) => { + len = bytes_read; + break; + } + OperationResult::Pending => { + yield_now(); + } + OperationResult::Err(e) => { + panic!("e: {}", e); + } + } + } + } + assert_eq!(&buffer[..len], origin.as_bytes()); + } + } } diff --git a/src/unix.rs b/src/unix.rs index f0a8826e..c0a61b56 100644 --- a/src/unix.rs +++ b/src/unix.rs @@ -147,61 +147,3 @@ impl AsyncIo for AIo { }) } } - -#[cfg(test)] -mod test { - use std::{ffi::CString, thread::yield_now}; - - use super::{File, OperationResult, Overlapped}; - - #[test] - fn test() { - let x: CString = CString::new("_test_posix.txt").unwrap(); - let origin = "Hello, world!"; - { - let mut file = File::create(&x).unwrap(); - let mut overlapped: Overlapped = Overlapped::default(); - let mut operation = file.write(&mut overlapped, origin.as_bytes()).unwrap(); - loop { - match operation.get_result() { - OperationResult::Ok(bytes_written) => { - if bytes_written != origin.len() { - panic!(); - } - break; - } - OperationResult::Pending => { - yield_now(); - } - OperationResult::Err(e) => { - panic!("e: {}", e); - } - } - } - } - { - let mut file = File::open(&x).unwrap(); - let mut overlapped: Overlapped = Overlapped::default(); - let mut buffer = [0u8; 1024]; - let mut len = 0; - { - let mut operation = file.read(&mut overlapped, &mut buffer).unwrap(); - loop { - match operation.get_result() { - OperationResult::Ok(bytes_read) => { - len = bytes_read; - break; - } - OperationResult::Pending => { - yield_now(); - } - OperationResult::Err(e) => { - panic!("e: {}", e); - } - } - } - } - assert_eq!(&buffer[..len], origin.as_bytes()); - } - } -} diff --git a/src/windows.rs b/src/windows.rs index dd2178af..a44631d5 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -200,68 +200,3 @@ impl AsyncIo for AIo { }) } } - -#[cfg(test)] -mod test { - use std::{ffi::CString, thread::yield_now}; - - use crate::async_io::OperationResult; - - #[test] - fn test() { - use super::{File, Overlapped}; - // - let x: CString = CString::new("_test.txt").unwrap(); - let origin = b"Hello World!"; - { - let mut handle = File::create(&x).unwrap(); - let mut overlapped = Overlapped::default(); - let mut operation = handle.write(&mut overlapped, origin).unwrap(); - loop { - match operation.get_result(false) { - OperationResult::Ok(bytes_written) => { - if bytes_written != origin.len() { - panic!(); - } - break; - } - OperationResult::Pending => { - yield_now(); - } - OperationResult::Err(e) => { - panic!("e: {}", e); - } - } - } - // let result = operation.get_result(true).unwrap(); - // assert_eq!(result, 12); - } - { - let mut handle = File::open(&x).unwrap(); - let mut overlapped = Overlapped::default(); - let mut buffer = [0u8; 1024]; - { - let mut operation = handle.read(&mut overlapped, &mut buffer).unwrap(); - loop { - match operation.get_result(false) { - OperationResult::Ok(bytes_written) => { - if bytes_written != origin.len() { - panic!(); - } - break; - } - OperationResult::Pending => { - yield_now(); - } - OperationResult::Err(e) => { - panic!("e: {}", e); - } - } - } - // let result = operation.get_result(true).unwrap(); - // assert_eq!(result, 12); - } - assert_eq!(&buffer[..12], b"Hello World!"); - } - } -} From 6886a92f9b1b4c45c01d1d34f6ff76669f2c9e3a Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Thu, 26 Oct 2023 20:04:05 -0700 Subject: [PATCH 33/44] get_result --- src/real_async_io.rs | 2 +- src/windows.rs | 37 ------------------------------------- 2 files changed, 1 insertion(+), 38 deletions(-) diff --git a/src/real_async_io.rs b/src/real_async_io.rs index 575b6826..2bc9b90e 100644 --- a/src/real_async_io.rs +++ b/src/real_async_io.rs @@ -111,7 +111,7 @@ mod test { #[test] fn test2() { - let x: CString = CString::new("_test_posix.txt").unwrap(); + let x: CString = CString::new("_test2.txt").unwrap(); let origin = "Hello, world!"; { let mut file = File::create(&x).unwrap(); diff --git a/src/windows.rs b/src/windows.rs index a44631d5..008fca7f 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -163,40 +163,3 @@ impl AsyncOperation for Operation<'_> { self.get_result(false) } } - -struct AFile { - file: File, - overlapped: Overlapped, -} - -impl AsyncFile for AFile { - type Operation<'a> = Operation<'a>; - - fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> io::Result> { - self.file.read(&mut self.overlapped, buffer) - } - - fn write<'a>(&'a mut self, buffer: &'a [u8]) -> io::Result> { - self.file.write(&mut self.overlapped, buffer) - } -} - -struct AIo(); - -impl AsyncIo for AIo { - type File = AFile; - - fn create(&self, path: &CStr) -> io::Result { - Ok(AFile { - file: File::create(path)?, - overlapped: Default::default(), - }) - } - - fn open(&self, path: &CStr) -> io::Result { - Ok(AFile { - file: File::open(path)?, - overlapped: Default::default(), - }) - } -} From ec7c077b32ce77f5748749cd192f0d162fb92054 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Thu, 26 Oct 2023 20:27:43 -0700 Subject: [PATCH 34/44] cargo n --- src/unix.rs | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/src/unix.rs b/src/unix.rs index c0a61b56..88a3dfff 100644 --- a/src/unix.rs +++ b/src/unix.rs @@ -110,40 +110,3 @@ impl AsyncOperation for Operation<'_> { self.get_result() } } - -struct AFile { - file: File, - overlapped: Overlapped, -} - -impl AsyncFile for AFile { - type Operation<'a> = Operation<'a>; - - fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> io::Result> { - self.file.read(&mut self.overlapped, buffer) - } - - fn write<'a>(&'a mut self, buffer: &'a [u8]) -> io::Result> { - self.file.write(&mut self.overlapped, buffer) - } -} - -struct AIo(); - -impl AsyncIo for AIo { - type File = AFile; - - fn create(&self, path: &CStr) -> io::Result { - Ok(AFile { - file: File::create(path)?, - overlapped: Default::default(), - }) - } - - fn open(&self, path: &CStr) -> io::Result { - Ok(AFile { - file: File::open(path)?, - overlapped: Default::default(), - }) - } -} From 9fbfc26e1e50a50a54b495f88f0482ede0ac1075 Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Thu, 26 Oct 2023 21:58:54 -0700 Subject: [PATCH 35/44] io-trait --- Cargo.toml | 1 + src/app.rs | 6 ++-- src/file_table.rs | 3 +- src/io.rs | 84 +---------------------------------------------- src/lib.rs | 1 - src/real_io.rs | 21 +----------- src/virtual_io.rs | 6 ++-- 7 files changed, 11 insertions(+), 111 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 51aef1b7..1ab47fe7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ authors = ["Sergey Shandar"] [dependencies] libc = "0.2.149" +io-trait = "0.1.1" [dev-dependencies] wasm-bindgen-test = "0.3.37" diff --git a/src/app.rs b/src/app.rs index 3a045928..f0a3b08b 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,16 +1,16 @@ use std::io::{self, Read, Write}; +use io_trait::{DirEntry, Io, Metadata}; + use crate::{ base32::{StrEx, ToBase32}, file_table::{FileTable, CDT0, PARTS, ROOTS}, - io::{DirEntry, Io}, level_storage::LevelStorage, state::{mb, progress, State}, storage::{Null, Storage}, table::{Table, Type}, tree::Tree, u224::U224, - Metadata, }; trait ResultEx { @@ -153,6 +153,7 @@ pub fn run(io: &impl Io) -> Result<(), String> { #[cfg(test)] mod test { + use io_trait::Io; use wasm_bindgen_test::wasm_bindgen_test; use crate::{ @@ -161,7 +162,6 @@ mod test { sha224::{compress, compress_one}, u256::{to_u224, U256}, virtual_io::VirtualIo, - Io, }; #[wasm_bindgen_test] diff --git a/src/file_table.rs b/src/file_table.rs index 242ebf5b..0421e7b4 100644 --- a/src/file_table.rs +++ b/src/file_table.rs @@ -1,10 +1,11 @@ use std::io; +use io_trait::Io; + use crate::{ base32::ToBase32, table::{Table, Type}, u224::U224, - Io, }; pub struct FileTable<'a, T: Io>(pub &'a T); diff --git a/src/io.rs b/src/io.rs index 5fdcb3b8..59cd5cb8 100644 --- a/src/io.rs +++ b/src/io.rs @@ -1,92 +1,10 @@ -use std::{ - ffi::CStr, - fmt, - io::{self, Read, Write}, -}; - -#[allow(clippy::len_without_is_empty)] -pub trait Metadata { - fn len(&self) -> u64; - fn is_dir(&self) -> bool; -} - -pub trait DirEntry { - type Metadata: Metadata; - fn path(&self) -> String; - fn metadata(&self) -> io::Result; -} - -pub trait Io { - type Args: Iterator; - type File: Read + Write + fmt::Debug; - type Stdout: Write; - type Metadata: Metadata; - type DirEntry: DirEntry; - fn args(&self) -> Self::Args; - fn stdout(&self) -> Self::Stdout; - fn metadata(&self, path: &str) -> io::Result; - fn create_dir(&self, path: &str) -> io::Result<()>; - fn create(&self, path: &str) -> io::Result; - fn open(&self, path: &str) -> io::Result; - fn read(&self, path: &str) -> io::Result> { - let mut file = self.open(path)?; - let mut result = Vec::default(); - file.read_to_end(&mut result)?; - Ok(result) - } - fn read_dir(&self, path: &str) -> io::Result>; - fn read_to_string(&self, path: &str) -> io::Result { - let mut file = self.open(path)?; - let mut result = String::default(); - file.read_to_string(&mut result)?; - Ok(result) - } - fn write(&self, path: &str, data: &[u8]) -> io::Result<()> { - let mut file = self.create(path)?; - file.write_all(data)?; - Ok(()) - } - fn create_dir_recursively(&self, path: &str) -> io::Result<()> { - let mut x = String::default(); - let mut e = Ok(()); - for i in path.split('/') { - x += i; - e = self.create_dir(&x); - x += "/"; - } - e - } - fn write_recursively(&self, path: &str, data: &[u8]) -> io::Result<()> { - let e = self.write(path, data); - if let Err(er) = e { - return if let Some((p, _)) = path.rsplit_once('/') { - self.create_dir_recursively(p)?; - self.write(path, data) - } else { - Err(er) - }; - } - Ok(()) - } - fn read_dir_type(&self, path: &str, is_dir: bool) -> io::Result> { - let mut result = Vec::default(); - for i in self.read_dir(path)? { - if i.metadata()?.is_dir() == is_dir { - result.push(i); - } - } - Ok(result) - } -} - #[cfg(test)] mod test { + use io_trait::Io; use wasm_bindgen_test::wasm_bindgen_test; use crate::virtual_io::VirtualIo; - use super::Io; - #[wasm_bindgen_test] #[test] fn test() { diff --git a/src/lib.rs b/src/lib.rs index 06e19017..225dbecc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,5 +34,4 @@ mod static_assert; mod virtual_io; pub use app::run; -pub use io::{Io, Metadata}; pub use real_io::RealIo; diff --git a/src/real_io.rs b/src/real_io.rs index 5313efdc..45af1068 100644 --- a/src/real_io.rs +++ b/src/real_io.rs @@ -6,26 +6,7 @@ use std::{ io::{self, Stdout}, }; -use crate::{io::DirEntry, Io, Metadata}; - -impl Metadata for fs::Metadata { - fn len(&self) -> u64 { - self.len() - } - fn is_dir(&self) -> bool { - self.is_dir() - } -} - -impl DirEntry for fs::DirEntry { - type Metadata = fs::Metadata; - fn path(&self) -> String { - self.path().to_str().unwrap().to_string() - } - fn metadata(&self) -> io::Result { - self.metadata() - } -} +use io_trait::Io; #[derive(Default)] pub struct RealIo(); diff --git a/src/virtual_io.rs b/src/virtual_io.rs index 18a9744f..c21bca43 100644 --- a/src/virtual_io.rs +++ b/src/virtual_io.rs @@ -7,7 +7,7 @@ use std::{ vec, }; -use crate::io::Io; +use io_trait::Io; #[derive(Debug, Clone)] pub struct Metadata { @@ -15,7 +15,7 @@ pub struct Metadata { is_dir: bool, } -impl crate::io::Metadata for Metadata { +impl io_trait::Metadata for Metadata { fn len(&self) -> u64 { self.len } @@ -100,7 +100,7 @@ pub struct DirEntry { metadata: Metadata, } -impl crate::io::DirEntry for DirEntry { +impl io_trait::DirEntry for DirEntry { type Metadata = Metadata; fn path(&self) -> String { self.path.clone() From 78afc62bf90513015f5b5dd8974b31bd62df208e Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Thu, 26 Oct 2023 22:14:22 -0700 Subject: [PATCH 36/44] io_impl --- Cargo.toml | 1 + src/lib.rs | 2 -- src/main.rs | 3 ++- src/real_io.rs | 49 ------------------------------------------------- 4 files changed, 3 insertions(+), 52 deletions(-) delete mode 100644 src/real_io.rs diff --git a/Cargo.toml b/Cargo.toml index 1ab47fe7..fcaffd3e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ authors = ["Sergey Shandar"] [dependencies] libc = "0.2.149" io-trait = "0.1.1" +io-impl = "0.1.0" [dev-dependencies] wasm-bindgen-test = "0.3.37" diff --git a/src/lib.rs b/src/lib.rs index 225dbecc..812effee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,6 @@ mod file_table; mod io; mod level_storage; mod real_async_io; -mod real_io; mod sha224; mod sigma32; mod state; @@ -34,4 +33,3 @@ mod static_assert; mod virtual_io; pub use app::run; -pub use real_io::RealIo; diff --git a/src/main.rs b/src/main.rs index 4fcf57d5..ecdfa2cc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ -use blockset::{run, RealIo}; +use blockset::run; +use io_impl::RealIo; fn main() -> Result<(), String> { run(&RealIo::default()) diff --git a/src/real_io.rs b/src/real_io.rs deleted file mode 100644 index 45af1068..00000000 --- a/src/real_io.rs +++ /dev/null @@ -1,49 +0,0 @@ -#![cfg(not(tarpaulin_include))] - -use std::{ - env::{args, Args}, - fs::{self, create_dir, File}, - io::{self, Stdout}, -}; - -use io_trait::Io; - -#[derive(Default)] -pub struct RealIo(); - -impl Io for RealIo { - type Args = Args; - - type Stdout = Stdout; - type File = File; - type Metadata = fs::Metadata; - type DirEntry = fs::DirEntry; - - fn args(&self) -> Self::Args { - args() - } - - fn create(&self, path: &str) -> io::Result { - File::create(path) - } - - fn open(&self, path: &str) -> io::Result { - File::open(path) - } - - fn metadata(&self, path: &str) -> io::Result { - fs::metadata(path) - } - - fn read_dir(&self, path: &str) -> io::Result> { - fs::read_dir(path)?.collect() - } - - fn create_dir(&self, path: &str) -> io::Result<()> { - create_dir(path) - } - - fn stdout(&self) -> Self::Stdout { - io::stdout() - } -} From 4dd582a400f39fc6da8abae209989427280b8074 Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Thu, 26 Oct 2023 22:47:00 -0700 Subject: [PATCH 37/44] no IO and Virtual IO --- Cargo.toml | 3 +- src/app.rs | 2 +- src/io.rs | 53 ---------- src/lib.rs | 3 - src/virtual_io.rs | 247 ---------------------------------------------- 5 files changed, 3 insertions(+), 305 deletions(-) delete mode 100644 src/io.rs delete mode 100644 src/virtual_io.rs diff --git a/Cargo.toml b/Cargo.toml index fcaffd3e..fa6c8c90 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,8 @@ authors = ["Sergey Shandar"] [dependencies] libc = "0.2.149" io-trait = "0.1.1" -io-impl = "0.1.0" +io-impl = "0.1.2" [dev-dependencies] +io-test = "0.1.3" wasm-bindgen-test = "0.3.37" diff --git a/src/app.rs b/src/app.rs index f0a3b08b..942a3ba6 100644 --- a/src/app.rs +++ b/src/app.rs @@ -153,6 +153,7 @@ pub fn run(io: &impl Io) -> Result<(), String> { #[cfg(test)] mod test { + use io_test::VirtualIo; use io_trait::Io; use wasm_bindgen_test::wasm_bindgen_test; @@ -161,7 +162,6 @@ mod test { run, sha224::{compress, compress_one}, u256::{to_u224, U256}, - virtual_io::VirtualIo, }; #[wasm_bindgen_test] diff --git a/src/io.rs b/src/io.rs deleted file mode 100644 index 59cd5cb8..00000000 --- a/src/io.rs +++ /dev/null @@ -1,53 +0,0 @@ -#[cfg(test)] -mod test { - use io_trait::Io; - use wasm_bindgen_test::wasm_bindgen_test; - - use crate::virtual_io::VirtualIo; - - #[wasm_bindgen_test] - #[test] - fn test() { - let io = VirtualIo::new(&[]); - io.write("test.txt", "Hello, world!".as_bytes()).unwrap(); - let result = io.read_to_string("test.txt").unwrap(); - assert_eq!(result, "Hello, world!"); - } - - #[wasm_bindgen_test] - #[test] - fn test_dir_fail() { - let io = VirtualIo::new(&[]); - assert!(io.write("a/test.txt", "Hello, world!".as_bytes()).is_err()); - } - - #[wasm_bindgen_test] - #[test] - fn test_write_recursively() { - let io = VirtualIo::new(&[]); - assert!(io - .write_recursively("a/test.txt", "Hello, world!".as_bytes()) - .is_ok()); - assert!(io - .write_recursively("a/test2.txt", "Hello, world!".as_bytes()) - .is_ok()); - } - - #[wasm_bindgen_test] - #[test] - fn test_dir_rec() { - let io = VirtualIo::new(&[]); - assert!(io - .write_recursively("a/b/test.txt", "Hello, world!".as_bytes()) - .is_ok()); - } - - #[wasm_bindgen_test] - #[test] - fn test_err() { - let io = VirtualIo::new(&[]); - assert!(io - .write_recursively("?", "Hello, world!".as_bytes()) - .is_err()); - } -} diff --git a/src/lib.rs b/src/lib.rs index 812effee..145a368d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,6 @@ mod base32; mod bit_vec; mod digest; mod file_table; -mod io; mod level_storage; mod real_async_io; mod sha224; @@ -29,7 +28,5 @@ mod windows_api; mod mem_table; #[cfg(test)] mod static_assert; -#[cfg(test)] -mod virtual_io; pub use app::run; diff --git a/src/virtual_io.rs b/src/virtual_io.rs deleted file mode 100644 index c21bca43..00000000 --- a/src/virtual_io.rs +++ /dev/null @@ -1,247 +0,0 @@ -use std::{ - cell::RefCell, - collections::HashMap, - io::{self, Read, Write}, - iter::once, - rc::Rc, - vec, -}; - -use io_trait::Io; - -#[derive(Debug, Clone)] -pub struct Metadata { - len: u64, - is_dir: bool, -} - -impl io_trait::Metadata for Metadata { - fn len(&self) -> u64 { - self.len - } - fn is_dir(&self) -> bool { - self.is_dir - } -} - -#[derive(Debug, Default, Clone)] -pub struct VecRef(Rc>>); - -impl VecRef { - pub fn to_string(&self) -> String { - let mut result = String::default(); - for &c in self.0.borrow().iter() { - if c == 8 { - result.pop(); - } else { - result.push(c as char); - } - } - result - } -} - -impl Write for VecRef { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.borrow_mut().extend_from_slice(buf); - Ok(buf.len()) - } - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -#[derive(Debug, Default)] -enum Entity { - #[default] - Dir, - File(VecRef), -} - -impl Entity { - fn metadata(&self) -> Metadata { - match self { - Entity::Dir => Metadata { - len: 0, - is_dir: true, - }, - Entity::File(x) => Metadata { - len: x.0.borrow().len() as u64, - is_dir: false, - }, - } - } -} - -#[derive(Debug, Default)] -pub struct FileSystem { - entity_map: HashMap, -} - -impl FileSystem { - pub fn check_dir(&self, path: &str) -> io::Result<()> { - if let Some(Entity::Dir) = self.entity_map.get(path) { - Ok(()) - } else { - Err(not_found()) - } - } - pub fn check_parent(&self, path: &str) -> io::Result<()> { - if let Some(d) = path.rfind('/').map(|i| &path[..i]) { - self.check_dir(d) - } else { - Ok(()) - } - } -} - -pub struct DirEntry { - path: String, - metadata: Metadata, -} - -impl io_trait::DirEntry for DirEntry { - type Metadata = Metadata; - fn path(&self) -> String { - self.path.clone() - } - fn metadata(&self) -> io::Result { - Ok(self.metadata.clone()) - } -} - -pub struct VirtualIo { - pub args: Vec, - pub fs: RefCell, - pub stdout: VecRef, -} - -impl VirtualIo { - pub fn new(args: &[&str]) -> Self { - Self { - args: once("blockset".to_string()) - .chain(args.iter().map(|v| v.to_string())) - .collect(), - fs: Default::default(), - stdout: VecRef::default(), - } - } -} - -#[derive(Debug)] -pub struct MemFile { - vec_ref: VecRef, - pos: usize, -} - -impl MemFile { - fn new(vec_ref: VecRef) -> Self { - Self { vec_ref, pos: 0 } - } -} - -impl Read for MemFile { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let sorce = &self.vec_ref.0.borrow()[self.pos..]; - let len = sorce.len().min(buf.len()); - buf[..len].copy_from_slice(&sorce[..len]); - self.pos += len; - Ok(len) - } -} - -impl Write for MemFile { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.vec_ref.write(buf) - } - fn flush(&mut self) -> io::Result<()> { - self.vec_ref.flush() - } -} - -fn not_found() -> io::Error { - io::Error::new(io::ErrorKind::NotFound, "file not found") -} - -fn check_path(a: &str) -> io::Result<()> { - if a.chars() - .all(|c| c.is_ascii_alphanumeric() || c == '/' || c == '_' || c == '.') - { - Ok(()) - } else { - Err(io::Error::new( - io::ErrorKind::InvalidInput, - "invalid file name", - )) - } -} - -impl Io for VirtualIo { - type File = MemFile; - type Stdout = VecRef; - type Args = vec::IntoIter; - type Metadata = Metadata; - type DirEntry = DirEntry; - fn args(&self) -> Self::Args { - self.args.clone().into_iter() - } - fn metadata(&self, path: &str) -> io::Result { - let fs = self.fs.borrow(); - fs.entity_map - .get(path) - .map(Entity::metadata) - .ok_or_else(not_found) - } - fn create(&self, path: &str) -> io::Result { - let mut fs = self.fs.borrow_mut(); - fs.check_parent(path)?; - let vec_ref = VecRef::default(); - check_path(path)?; - fs.entity_map - .insert(path.to_string(), Entity::File(vec_ref.clone())); - Ok(MemFile::new(vec_ref)) - } - fn create_dir(&self, path: &str) -> io::Result<()> { - let mut fs = self.fs.borrow_mut(); - fs.entity_map.insert(path.to_string(), Entity::Dir); - Ok(()) - } - fn open(&self, path: &str) -> io::Result { - let fs = self.fs.borrow(); - fs.check_parent(path)?; - check_path(path)?; - fs.entity_map - .get(path) - .map(|v| { - if let Entity::File(x) = v { - Some(MemFile::new(x.to_owned())) - } else { - None - } - }) - .flatten() - .ok_or_else(not_found) - } - fn stdout(&self) -> VecRef { - self.stdout.clone() - } - - fn read_dir(&self, path: &str) -> io::Result> { - let fs = self.fs.borrow(); - fs.check_dir(path)?; - let i = fs.entity_map.iter().map(|(p, e)| DirEntry { - path: p.to_owned(), - metadata: e.metadata(), - }); - let x = i - .filter(|p| { - if let Some((a, _)) = p.path.rsplit_once('/') { - a == path - } else { - false - } - }) - .collect(); - Ok(x) - } -} From f5faf1e8f3e5542e7045f604188939335bde8275 Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Thu, 26 Oct 2023 23:07:33 -0700 Subject: [PATCH 38/44] async in io-trait --- Cargo.toml | 6 +++--- src/async_io.rs | 25 ------------------------- src/lib.rs | 1 - src/real_async_io.rs | 4 ++-- src/windows.rs | 15 +++++++-------- 5 files changed, 12 insertions(+), 39 deletions(-) delete mode 100644 src/async_io.rs diff --git a/Cargo.toml b/Cargo.toml index fa6c8c90..0d129c36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,9 +10,9 @@ authors = ["Sergey Shandar"] [dependencies] libc = "0.2.149" -io-trait = "0.1.1" -io-impl = "0.1.2" +io-trait = "0.1.3" +io-impl = "0.1.4" [dev-dependencies] -io-test = "0.1.3" +io-test = "0.1.5" wasm-bindgen-test = "0.3.37" diff --git a/src/async_io.rs b/src/async_io.rs deleted file mode 100644 index d852db2b..00000000 --- a/src/async_io.rs +++ /dev/null @@ -1,25 +0,0 @@ -use std::{ffi::CStr, io}; - -pub enum OperationResult { - Ok(usize), - Pending, - Err(io::Error), -} - -pub trait AsyncOperation { - fn get_result(&mut self) -> OperationResult; -} - -pub trait AsyncFile { - type Operation<'a>: AsyncOperation - where - Self: 'a; - fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> io::Result>; - fn write<'a>(&'a mut self, buffer: &'a [u8]) -> io::Result>; -} - -pub trait AsyncIo { - type File: AsyncFile; - fn create(&self, path: &CStr) -> io::Result; - fn open(&self, path: &CStr) -> io::Result; -} diff --git a/src/lib.rs b/src/lib.rs index 145a368d..5d949042 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,6 @@ mod app; mod array; mod ascii; -mod async_io; mod base32; mod bit_vec; mod digest; diff --git a/src/real_async_io.rs b/src/real_async_io.rs index 2bc9b90e..ec91e20e 100644 --- a/src/real_async_io.rs +++ b/src/real_async_io.rs @@ -1,6 +1,6 @@ use std::{ffi::CStr, io}; -use crate::async_io::{AsyncFile, AsyncIo}; +use io_trait::{AsyncFile, AsyncIo}; #[cfg(target_family = "windows")] use crate::windows::*; @@ -50,7 +50,7 @@ mod test { use std::{ffi::CString, thread::yield_now}; use super::{File, Overlapped}; - use crate::async_io::{AsyncOperation, OperationResult}; + use io_trait::{AsyncOperation, OperationResult}; #[test] fn test() { diff --git a/src/windows.rs b/src/windows.rs index 008fca7f..a97ce15f 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -2,14 +2,13 @@ #![cfg(not(tarpaulin_include))] use std::{ffi::CStr, io, os::windows::raw::HANDLE, ptr::null_mut}; -use crate::{ - async_io::{AsyncFile, AsyncIo, AsyncOperation, OperationResult}, - windows_api::{ - to_bool, CancelIoEx, CloseHandle, CreateFileA, CreationDisposition, GetLastError, - GetOverlappedResult, ReadFile, WriteFile, ACCESS_MASK, BOOL, CREATE_ALWAYS, DWORD, - ERROR_IO_PENDING, FILE_FLAG_OVERLAPPED, GENERIC_READ, GENERIC_WRITE, INVALID_HANDLE_VALUE, - LPCVOID, LPVOID, OPEN_ALWAYS, OVERLAPPED, - }, +use io_trait::{OperationResult, AsyncOperation}; + +use crate::windows_api::{ + to_bool, CancelIoEx, CloseHandle, CreateFileA, CreationDisposition, GetLastError, + GetOverlappedResult, ReadFile, WriteFile, ACCESS_MASK, BOOL, CREATE_ALWAYS, DWORD, + ERROR_IO_PENDING, FILE_FLAG_OVERLAPPED, GENERIC_READ, GENERIC_WRITE, INVALID_HANDLE_VALUE, + LPCVOID, LPVOID, OPEN_ALWAYS, OVERLAPPED, }; pub struct File(HANDLE); From 3dfedfa4d9dd3049a574056f5615a3f5aae9ddb2 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Thu, 26 Oct 2023 23:09:05 -0700 Subject: [PATCH 39/44] Async --- src/unix.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/unix.rs b/src/unix.rs index 88a3dfff..4447a219 100644 --- a/src/unix.rs +++ b/src/unix.rs @@ -2,12 +2,11 @@ use std::{ffi::CStr, io, mem::zeroed, thread::yield_now}; +use io_trait::{OperationResult, AsyncOperation}; use libc::{ aio_cancel, aio_error, aio_read, aio_return, aio_write, aiocb, close, open, AIO_NOTCANCELED, }; -use crate::async_io::{AsyncFile, AsyncIo, AsyncOperation, OperationResult}; - pub struct File(i32); impl Drop for File { From cf661bda91bec5e9466a31f7061667711923e13b Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Thu, 26 Oct 2023 23:10:27 -0700 Subject: [PATCH 40/44] fmt --- src/windows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/windows.rs b/src/windows.rs index a97ce15f..569af174 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -2,7 +2,7 @@ #![cfg(not(tarpaulin_include))] use std::{ffi::CStr, io, os::windows::raw::HANDLE, ptr::null_mut}; -use io_trait::{OperationResult, AsyncOperation}; +use io_trait::{AsyncOperation, OperationResult}; use crate::windows_api::{ to_bool, CancelIoEx, CloseHandle, CreateFileA, CreationDisposition, GetLastError, From ac0a155fdfc623d4d26bc144a7c3506be2697468 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Thu, 26 Oct 2023 23:10:55 -0700 Subject: [PATCH 41/44] unix --- src/unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix.rs b/src/unix.rs index 4447a219..e6dbfe6a 100644 --- a/src/unix.rs +++ b/src/unix.rs @@ -2,7 +2,7 @@ use std::{ffi::CStr, io, mem::zeroed, thread::yield_now}; -use io_trait::{OperationResult, AsyncOperation}; +use io_trait::{AsyncOperation, OperationResult}; use libc::{ aio_cancel, aio_error, aio_read, aio_return, aio_write, aiocb, close, open, AIO_NOTCANCELED, }; From a50ca3a4c4f7301df36e5f8350c34148e76125a8 Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Fri, 27 Oct 2023 00:57:57 -0700 Subject: [PATCH 42/44] io_test 0.2.0 --- Cargo.toml | 6 +++--- src/app.rs | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0d129c36..639a82c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,9 +10,9 @@ authors = ["Sergey Shandar"] [dependencies] libc = "0.2.149" -io-trait = "0.1.3" -io-impl = "0.1.4" +io-trait = "0.1.4" +io-impl = "0.1.5" [dev-dependencies] -io-test = "0.1.5" +io-test = "0.2.0" wasm-bindgen-test = "0.3.37" diff --git a/src/app.rs b/src/app.rs index 942a3ba6..22d3a350 100644 --- a/src/app.rs +++ b/src/app.rs @@ -216,7 +216,7 @@ mod test { 0x68000000_00000000_00000000_00000000, ]; let s = to_u224(&compress([d, [0, 0]])).unwrap().to_base32(); - assert_eq!(io.stdout.to_string(), s + "\n"); + assert_eq!(io.stdout.to_stdout(), s + "\n"); } #[wasm_bindgen_test] @@ -231,7 +231,7 @@ mod test { 0x68000000_00000000_00000000_00000000, ]; let s = compress_one(&d).to_base32(); - assert_eq!(io.stdout.to_string(), s.clone() + "\n"); + assert_eq!(io.stdout.to_stdout(), s.clone() + "\n"); let v = io .read(&("cdt0/roots/".to_owned() + &s[..2] + "/" + &s[2..4] + "/" + &s[4..])) .unwrap(); @@ -287,7 +287,7 @@ mod test { assert_eq!(e, Ok(())); let d: U256 = [0, 0]; let s = compress_one(&d).to_base32(); - assert_eq!(io.stdout.to_string(), s.clone() + "\n"); + assert_eq!(io.stdout.to_stdout(), s.clone() + "\n"); } #[wasm_bindgen_test] @@ -305,7 +305,7 @@ mod test { io.write("a.txt", src.as_bytes()).unwrap(); let e = run(&mut io); assert_eq!(e, Ok(())); - let x = &io.stdout.to_string()[..45]; + let x = &io.stdout.to_stdout()[..45]; io.args = ["blockset", "get", x, "b.txt"] .iter() .map(|s| s.to_string()) From 7096b0468abf6f19c8d1459613cf44f5a1357511 Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Fri, 27 Oct 2023 01:54:42 -0700 Subject: [PATCH 43/44] cargo n --- src/lib.rs | 4 - src/real_async_io.rs | 162 -------------------------------- src/unix.rs | 111 ---------------------- src/windows.rs | 164 --------------------------------- src/windows_api.rs | 214 ------------------------------------------- 5 files changed, 655 deletions(-) delete mode 100644 src/real_async_io.rs delete mode 100644 src/unix.rs delete mode 100644 src/windows.rs delete mode 100644 src/windows_api.rs diff --git a/src/lib.rs b/src/lib.rs index 5d949042..9c45d303 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,6 @@ mod bit_vec; mod digest; mod file_table; mod level_storage; -mod real_async_io; mod sha224; mod sigma32; mod state; @@ -19,9 +18,6 @@ mod u224; mod u256; mod u32; mod u512; -mod unix; -mod windows; -mod windows_api; #[cfg(test)] mod mem_table; diff --git a/src/real_async_io.rs b/src/real_async_io.rs deleted file mode 100644 index ec91e20e..00000000 --- a/src/real_async_io.rs +++ /dev/null @@ -1,162 +0,0 @@ -use std::{ffi::CStr, io}; - -use io_trait::{AsyncFile, AsyncIo}; - -#[cfg(target_family = "windows")] -use crate::windows::*; - -#[cfg(target_family = "unix")] -use crate::unix::*; - -struct AFile { - file: File, - overlapped: Overlapped, -} - -impl AsyncFile for AFile { - type Operation<'a> = Operation<'a>; - - fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> io::Result> { - self.file.read(&mut self.overlapped, buffer) - } - - fn write<'a>(&'a mut self, buffer: &'a [u8]) -> io::Result> { - self.file.write(&mut self.overlapped, buffer) - } -} - -struct AIo(); - -impl AsyncIo for AIo { - type File = AFile; - - fn create(&self, path: &CStr) -> io::Result { - Ok(AFile { - file: File::create(path)?, - overlapped: Default::default(), - }) - } - - fn open(&self, path: &CStr) -> io::Result { - Ok(AFile { - file: File::open(path)?, - overlapped: Default::default(), - }) - } -} - -#[cfg(test)] -mod test { - use std::{ffi::CString, thread::yield_now}; - - use super::{File, Overlapped}; - use io_trait::{AsyncOperation, OperationResult}; - - #[test] - fn test() { - // - let x: CString = CString::new("_test.txt").unwrap(); - let origin = b"Hello World!"; - { - let mut handle = File::create(&x).unwrap(); - let mut overlapped = Overlapped::default(); - let mut operation = handle.write(&mut overlapped, origin).unwrap(); - loop { - match operation.get_result() { - OperationResult::Ok(bytes_written) => { - if bytes_written != origin.len() { - panic!(); - } - break; - } - OperationResult::Pending => { - yield_now(); - } - OperationResult::Err(e) => { - panic!("e: {}", e); - } - } - } - // let result = operation.get_result(true).unwrap(); - // assert_eq!(result, 12); - } - { - let mut handle = File::open(&x).unwrap(); - let mut overlapped = Overlapped::default(); - let mut buffer = [0u8; 1024]; - { - let mut operation = handle.read(&mut overlapped, &mut buffer).unwrap(); - loop { - match operation.get_result() { - OperationResult::Ok(bytes_written) => { - if bytes_written != origin.len() { - panic!(); - } - break; - } - OperationResult::Pending => { - yield_now(); - } - OperationResult::Err(e) => { - panic!("e: {}", e); - } - } - } - // let result = operation.get_result(true).unwrap(); - // assert_eq!(result, 12); - } - assert_eq!(&buffer[..12], b"Hello World!"); - } - } - - #[test] - fn test2() { - let x: CString = CString::new("_test2.txt").unwrap(); - let origin = "Hello, world!"; - { - let mut file = File::create(&x).unwrap(); - let mut overlapped: Overlapped = Overlapped::default(); - let mut operation = file.write(&mut overlapped, origin.as_bytes()).unwrap(); - loop { - match operation.get_result() { - OperationResult::Ok(bytes_written) => { - if bytes_written != origin.len() { - panic!(); - } - break; - } - OperationResult::Pending => { - yield_now(); - } - OperationResult::Err(e) => { - panic!("e: {}", e); - } - } - } - } - { - let mut file = File::open(&x).unwrap(); - let mut overlapped: Overlapped = Overlapped::default(); - let mut buffer = [0u8; 1024]; - let mut len = 0; - { - let mut operation = file.read(&mut overlapped, &mut buffer).unwrap(); - loop { - match operation.get_result() { - OperationResult::Ok(bytes_read) => { - len = bytes_read; - break; - } - OperationResult::Pending => { - yield_now(); - } - OperationResult::Err(e) => { - panic!("e: {}", e); - } - } - } - } - assert_eq!(&buffer[..len], origin.as_bytes()); - } - } -} diff --git a/src/unix.rs b/src/unix.rs deleted file mode 100644 index e6dbfe6a..00000000 --- a/src/unix.rs +++ /dev/null @@ -1,111 +0,0 @@ -#![cfg(target_family = "unix")] - -use std::{ffi::CStr, io, mem::zeroed, thread::yield_now}; - -use io_trait::{AsyncOperation, OperationResult}; -use libc::{ - aio_cancel, aio_error, aio_read, aio_return, aio_write, aiocb, close, open, AIO_NOTCANCELED, -}; - -pub struct File(i32); - -impl Drop for File { - fn drop(&mut self) { - unsafe { - close(self.0); - } - } -} - -pub struct Overlapped(aiocb); - -impl Default for Overlapped { - fn default() -> Self { - Self(unsafe { zeroed() }) - } -} - -pub struct Operation<'a> { - file: &'a mut File, - overlapped: &'a mut Overlapped, -} - -impl Drop for Operation<'_> { - fn drop(&mut self) { - let mut e = unsafe { aio_cancel(self.file.0, &mut self.overlapped.0) }; - while e == AIO_NOTCANCELED { - yield_now(); - e = unsafe { aio_error(&self.overlapped.0) }; - } - } -} - -impl Operation<'_> { - fn get_result(&mut self) -> OperationResult { - match unsafe { aio_error(&self.overlapped.0) } { - 0 => OperationResult::Ok(unsafe { aio_return(&mut self.overlapped.0) } as usize), - e => { - if e == libc::EINPROGRESS { - return OperationResult::Pending; - } - OperationResult::Err(io::Error::from_raw_os_error(e)) - } - } - } -} - -impl File { - fn internal_open(path: &CStr, oflag: i32) -> io::Result { - let fd = unsafe { open(path.as_ptr(), oflag, 0o644) }; - if fd == -1 { - Err(io::Error::last_os_error()) - } else { - Ok(Self(fd)) - } - } - pub fn create(path: &CStr) -> io::Result { - File::internal_open(path, libc::O_WRONLY | libc::O_CREAT | libc::O_TRUNC) - } - pub fn open(path: &CStr) -> io::Result { - File::internal_open(path, libc::O_RDONLY) - } - fn create_operation<'a>( - &'a mut self, - overlapped: &'a mut Overlapped, - buffer: &'a [u8], - f: unsafe extern "C" fn(*mut aiocb) -> i32, - ) -> io::Result> { - *overlapped = Default::default(); - overlapped.0.aio_fildes = self.0; - overlapped.0.aio_buf = buffer.as_ptr() as *mut _; - overlapped.0.aio_nbytes = buffer.len(); - if unsafe { f(&mut overlapped.0) } == -1 { - Err(io::Error::last_os_error()) - } else { - Ok(Operation { - file: self, - overlapped, - }) - } - } - pub fn write<'a>( - &'a mut self, - overlapped: &'a mut Overlapped, - buffer: &'a [u8], - ) -> io::Result> { - self.create_operation(overlapped, buffer, aio_write) - } - pub fn read<'a>( - &'a mut self, - overlapped: &'a mut Overlapped, - buffer: &'a mut [u8], - ) -> io::Result> { - self.create_operation(overlapped, buffer, aio_read) - } -} - -impl AsyncOperation for Operation<'_> { - fn get_result(&mut self) -> OperationResult { - self.get_result() - } -} diff --git a/src/windows.rs b/src/windows.rs deleted file mode 100644 index 569af174..00000000 --- a/src/windows.rs +++ /dev/null @@ -1,164 +0,0 @@ -#![cfg(target_family = "windows")] -#![cfg(not(tarpaulin_include))] -use std::{ffi::CStr, io, os::windows::raw::HANDLE, ptr::null_mut}; - -use io_trait::{AsyncOperation, OperationResult}; - -use crate::windows_api::{ - to_bool, CancelIoEx, CloseHandle, CreateFileA, CreationDisposition, GetLastError, - GetOverlappedResult, ReadFile, WriteFile, ACCESS_MASK, BOOL, CREATE_ALWAYS, DWORD, - ERROR_IO_PENDING, FILE_FLAG_OVERLAPPED, GENERIC_READ, GENERIC_WRITE, INVALID_HANDLE_VALUE, - LPCVOID, LPVOID, OPEN_ALWAYS, OVERLAPPED, -}; - -pub struct File(HANDLE); - -impl Drop for File { - fn drop(&mut self) { - unsafe { - CloseHandle(self.0); - } - } -} - -fn to_operation_result(v: BOOL) -> OperationResult { - if to_bool(v) { - OperationResult::Ok(0) - } else { - let e = unsafe { GetLastError() }; - if e == ERROR_IO_PENDING { - OperationResult::Pending - } else { - OperationResult::Err(e.to_error()) - } - } -} - -impl File { - fn create_file( - file_name: &CStr, - desired_access: ACCESS_MASK, - creation_disposition: CreationDisposition, - ) -> io::Result { - let result = unsafe { - CreateFileA( - file_name.as_ptr(), - desired_access, - 0, - null_mut(), - creation_disposition, - FILE_FLAG_OVERLAPPED, - null_mut(), - ) - }; - if result == INVALID_HANDLE_VALUE { - Err(io::Error::last_os_error()) - } else { - Ok(Self(result)) - } - } - pub fn create(file_name: &CStr) -> io::Result { - Self::create_file(file_name, GENERIC_WRITE, CREATE_ALWAYS) - } - pub fn open(file_name: &CStr) -> io::Result { - Self::create_file(file_name, GENERIC_READ, OPEN_ALWAYS) - } - - fn create_operation<'a>( - &'a mut self, - overlapped: &'a mut Overlapped, - result: BOOL, - ) -> io::Result> { - if let OperationResult::Err(e) = to_operation_result(result) { - Err(e) - } else { - Ok(Operation { - handle: self, - overlapped, - }) - } - } - - pub fn read<'a>( - &'a mut self, - overlapped: &'a mut Overlapped, - buffer: &'a mut [u8], // it's important that the buffer has the same life time as the overlapped! - ) -> io::Result> { - *overlapped = Default::default(); - let result = unsafe { - ReadFile( - self.0, - buffer.as_mut_ptr() as LPVOID, - buffer.len() as DWORD, - null_mut(), - &mut overlapped.0, - ) - }; - self.create_operation(overlapped, result) - } - - pub fn write<'a>( - &'a mut self, - overlapped: &'a mut Overlapped, - buffer: &'a [u8], // it's important that the buffer has the same life time as the overlapped! - ) -> io::Result> { - *overlapped = Default::default(); - let result = unsafe { - WriteFile( - self.0, - buffer.as_ptr() as LPCVOID, - buffer.len() as DWORD, - null_mut(), - &mut overlapped.0, - ) - }; - self.create_operation(overlapped, result) - } -} - -#[derive(Default)] -pub struct Overlapped(OVERLAPPED); - -pub struct Operation<'a> { - handle: &'a mut File, - overlapped: &'a mut Overlapped, -} - -impl Drop for Operation<'_> { - fn drop(&mut self) { - unsafe { - CancelIoEx(self.handle.0, &mut self.overlapped.0); - } - let _ = self.get_result(true); - } -} - -impl Operation<'_> { - fn get_result(&mut self, wait: bool) -> OperationResult { - let mut result: DWORD = 0; - let r = unsafe { - GetOverlappedResult( - self.handle.0, - &mut self.overlapped.0, - &mut result, - wait.into(), - ) - }; - if r.into() { - OperationResult::Ok(result as usize) - } else { - let e = unsafe { GetLastError() }; - if e == ERROR_IO_PENDING { - OperationResult::Pending - } else { - OperationResult::Err(e.to_error()) - } - } - } -} - -impl AsyncOperation for Operation<'_> { - fn get_result(&mut self) -> OperationResult { - self.get_result(false) - } -} diff --git a/src/windows_api.rs b/src/windows_api.rs deleted file mode 100644 index 8cdba6b7..00000000 --- a/src/windows_api.rs +++ /dev/null @@ -1,214 +0,0 @@ -#![cfg(target_os = "windows")] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] -#![allow(clippy::upper_case_acronyms)] - -use std::{ - io, - ops::BitOr, - os::{raw::c_void, windows::raw::HANDLE}, - ptr::null_mut, -}; - -pub const INVALID_HANDLE_VALUE: HANDLE = -1isize as HANDLE; - -// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/3f6cc0e2-1303-4088-a26b-fb9582f29197 -type LPCSTR = *const i8; - -// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/262627d8-3418-4627-9218-4ffe110850b2 -pub type DWORD = u32; -type LPDWORD = *mut DWORD; - -// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/c0b7741b-f577-4eed-aff3-2e909df10a4d -pub type LPVOID = *mut c_void; -pub type LPCVOID = *const c_void; -type PVOID = *mut c_void; - -// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/21eec394-630d-49ed-8b4a-ab74a1614611 -type ULONG_PTR = usize; - -// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/9d81be47-232e-42cf-8f0d-7a3b29bf2eb2 -#[repr(transparent)] -pub struct BOOL(i32); -const FALSE: BOOL = BOOL(0); -const TRUE: BOOL = BOOL(1); -pub const fn to_bool(x: BOOL) -> bool { - x.0 != FALSE.0 -} -impl From for bool { - fn from(val: BOOL) -> Self { - to_bool(val) - } -} -impl From for BOOL { - fn from(x: bool) -> Self { - if x { - TRUE - } else { - FALSE - } - } -} - -// https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-overlapped - -#[repr(C)] -#[derive(Copy, Clone)] -struct OVERLAPPED_0_0 { - Offset: DWORD, - OffsetHigh: DWORD, -} - -#[repr(C)] -union OVERLAPPED_0 { - DUMMYSTRUCTNAME: OVERLAPPED_0_0, - Pointer: PVOID, -} - -impl Default for OVERLAPPED_0 { - fn default() -> Self { - unsafe { std::mem::zeroed() } - } -} - -#[repr(C)] -pub struct OVERLAPPED { - Internal: ULONG_PTR, - InternalHigh: ULONG_PTR, - DUMMYUNIONNAME: OVERLAPPED_0, - hEvent: HANDLE, -} - -impl Default for OVERLAPPED { - fn default() -> Self { - OVERLAPPED { - Internal: 0, - InternalHigh: 0, - DUMMYUNIONNAME: OVERLAPPED_0::default(), - hEvent: null_mut(), - } - } -} - -type LPOVERLAPPED = *mut OVERLAPPED; - -// https://learn.microsoft.com/en-us/windows/win32/secauthz/access-mask -#[repr(transparent)] -pub struct ACCESS_MASK(DWORD); -pub const GENERIC_READ: ACCESS_MASK = ACCESS_MASK(0x80000000); -pub const GENERIC_WRITE: ACCESS_MASK = ACCESS_MASK(0x40000000); -impl BitOr for ACCESS_MASK { - type Output = Self; - fn bitor(self, rhs: Self) -> Self { - ACCESS_MASK(self.0 | rhs.0) - } -} - -// https://learn.microsoft.com/en-us/windows/win32/api/wtypesbase/ns-wtypesbase-security_attributes -#[repr(C)] -pub struct SECURITY_ATTRIBUTES { - nLength: DWORD, - lpSecurityDescriptor: LPVOID, - bInheritHandle: BOOL, -} -type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES; - -#[repr(transparent)] -pub struct CreationDisposition(DWORD); -pub const CREATE_NEW: CreationDisposition = CreationDisposition(1); -pub const CREATE_ALWAYS: CreationDisposition = CreationDisposition(2); -pub const OPEN_EXISTING: CreationDisposition = CreationDisposition(3); -pub const OPEN_ALWAYS: CreationDisposition = CreationDisposition(4); -pub const TRUNCATE_EXISTING: CreationDisposition = CreationDisposition(5); - -#[repr(transparent)] -pub struct FlagsAndAttributes(DWORD); -pub const FILE_FLAG_OVERLAPPED: FlagsAndAttributes = FlagsAndAttributes(0x40000000); -impl BitOr for FlagsAndAttributes { - type Output = Self; - fn bitor(self, rhs: Self) -> Self { - FlagsAndAttributes(self.0 | rhs.0) - } -} - -// https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--500-999- -#[derive(PartialEq, Clone, Copy)] -#[repr(transparent)] -pub struct Error(DWORD); -pub const ERROR_IO_PENDING: Error = Error(997); -impl Error { - pub fn to_error(self) -> io::Error { - io::Error::from_raw_os_error(self.0 as i32) - } -} - -// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea -#[link(name = "kernel32")] -extern "system" { - pub fn CreateFileA( - lpFileName: LPCSTR, // [in] - dwDesiredAccess: ACCESS_MASK, // [in] - dwShareMode: DWORD, // [in] - lpSecurityAttributes: LPSECURITY_ATTRIBUTES, // [in, optional] - dwCreationDisposition: CreationDisposition, // [in] - dwFlagsAndAttributes: FlagsAndAttributes, // [in] - hTemplateFile: HANDLE, // [in, optional] - ) -> HANDLE; -} - -// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile -#[link(name = "kernel32")] -extern "system" { - pub fn ReadFile( - hFile: HANDLE, // [in] - lpBuffer: LPVOID, // [out] - nNumberOfBytesToRead: DWORD, // [in] - lpNumberOfBytesRead: LPDWORD, // [out, optional] - lpOverlapped: LPOVERLAPPED, // [in, out, optional] - ) -> BOOL; -} - -// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefile -#[link(name = "kernel32")] -extern "system" { - pub fn WriteFile( - hFile: HANDLE, // [in] - lpBuffer: LPCVOID, // [in] - nNumberOfBytesToWrite: DWORD, // [in] - lpNumberOfBytesWritten: LPDWORD, // [out, optional] - lpOverlapped: LPOVERLAPPED, // [in, out, optional] - ) -> BOOL; -} - -// https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle -#[link(name = "kernel32")] -extern "system" { - pub fn CloseHandle(hObject: HANDLE, // [in] - ) -> BOOL; -} - -// https://learn.microsoft.com/en-us/windows/win32/fileio/cancelioex-func -#[link(name = "kernel32")] -extern "system" { - pub fn CancelIoEx( - hFile: HANDLE, // [in] - lpOverlapped: LPOVERLAPPED, // [in, optional] - ) -> BOOL; -} - -// https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-getoverlappedresult -#[link(name = "kernel32")] -extern "system" { - pub fn GetOverlappedResult( - hFile: HANDLE, // [in] - lpOverlapped: LPOVERLAPPED, // [in] - lpNumberOfBytesTransferred: LPDWORD, // [out, optional] - bWait: BOOL, // [in] - ) -> BOOL; -} - -// https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror -#[link(name = "kernel32")] -extern "system" { - pub fn GetLastError() -> Error; -} From 9a058a605662403901b7dea548d4ef1f828a10d0 Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Fri, 27 Oct 2023 01:58:05 -0700 Subject: [PATCH 44/44] remove libc --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 639a82c8..720b0ebc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,6 @@ authors = ["Sergey Shandar"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -libc = "0.2.149" io-trait = "0.1.4" io-impl = "0.1.5"