From c4fab37a376dca243d6f7b9cd1909da7c3d01a1d Mon Sep 17 00:00:00 2001 From: Anna Date: Sun, 20 Jun 2021 18:21:15 -0400 Subject: [PATCH] refactor: begin no_std conversion --- .gitignore | 1 + Cargo.toml | 7 +- src/lib.rs | 29 +- src/system.rs | 260 ++++++++++++++ src/win_c.rs | 933 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1226 insertions(+), 4 deletions(-) create mode 100644 src/system.rs create mode 100644 src/win_c.rs diff --git a/.gitignore b/.gitignore index 96ef6c0..2de3917 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target Cargo.lock +/.idea diff --git a/Cargo.toml b/Cargo.toml index 2d4883d..cd68e51 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ name = "xivchat-native-tools" version = "1.0.0" authors = ["Anna Clemenes "] edition = "2018" +resolver = "2" [lib] name = "xivchat_native_tools" @@ -11,10 +12,14 @@ crate-type = ["cdylib"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -libc = "0.2" +cstr_core = "0.2" unicode-linebreak = "0.1" unicode-segmentation = "1" +[dependencies.libc] +version = "0.2" +default-features = false + # build with # cargo +nightly build --release -Z build-std --target x86_64-pc-windows-msvc [profile.release] diff --git a/src/lib.rs b/src/lib.rs index f6d7eaa..c7169b3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,29 @@ +#![no_std] +#![feature(default_alloc_error_handler, lang_items)] #![feature(vec_into_raw_parts)] #![allow(clippy::not_unsafe_ptr_arg_deref)] #[cfg(test)] mod test; +mod system; +mod win_c; + +extern crate core; +extern crate alloc; use libc::c_char; -use std::ffi::{CStr, CString}; +use alloc::{ + borrow::ToOwned, + boxed::Box, + string::String, + vec::Vec, +}; +use cstr_core::{CStr, CString}; use unicode_segmentation::UnicodeSegmentation; +use crate::system::System; + +#[global_allocator] +static ALLOC: System = System; #[repr(C)] pub struct RawVec { @@ -18,7 +35,7 @@ pub struct RawVec { #[no_mangle] pub extern "C" fn wrap(raw_input: *const c_char, width: u32) -> *mut RawVec { if raw_input.is_null() { - return std::ptr::null::() as *mut _; + return core::ptr::null::() as *mut _; } let c_input = unsafe { @@ -27,7 +44,7 @@ pub extern "C" fn wrap(raw_input: *const c_char, width: u32) -> *mut RawVec { let input = match c_input.to_str() { Ok(x) => x, - Err(_) => return std::ptr::null::() as *mut _, + Err(_) => return core::ptr::null::() as *mut _, }; let lines = inner_wrap(input, width); @@ -115,3 +132,9 @@ fn hard_break(lines: &mut Vec, segment: &str, width: usize) { lines.push(string); } } + +#[lang = "eh_personality"] extern fn rust_eh_personality() {} +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/src/system.rs b/src/system.rs new file mode 100644 index 0000000..47a28f9 --- /dev/null +++ b/src/system.rs @@ -0,0 +1,260 @@ +use crate::win_c as c; +use libc::c_void; +use alloc::alloc::{GlobalAlloc, Layout}; +use core::ptr; +use core::sync::atomic::{AtomicPtr, Ordering}; + +pub struct System; + +// Heap memory management on Windows is done by using the system Heap API (heapapi.h) +// See https://docs.microsoft.com/windows/win32/api/heapapi/ + +// Flag to indicate that the memory returned by `HeapAlloc` should be zeroed. +const HEAP_ZERO_MEMORY: c::DWORD = 0x00000008; +const MIN_ALIGN: usize = 16; + +extern "system" { + // Get a handle to the default heap of the current process, or null if the operation fails. + // + // SAFETY: Successful calls to this function within the same process are assumed to + // always return the same handle, which remains valid for the entire lifetime of the process. + // + // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-getprocessheap + fn GetProcessHeap() -> c::HANDLE; + + // Allocate a block of `dwBytes` bytes of memory from a given heap `hHeap`. + // The allocated memory may be uninitialized, or zeroed if `dwFlags` is + // set to `HEAP_ZERO_MEMORY`. + // + // Returns a pointer to the newly-allocated memory or null if the operation fails. + // The returned pointer will be aligned to at least `MIN_ALIGN`. + // + // SAFETY: + // - `hHeap` must be a non-null handle returned by `GetProcessHeap`. + // - `dwFlags` must be set to either zero or `HEAP_ZERO_MEMORY`. + // + // Note that `dwBytes` is allowed to be zero, contrary to some other allocators. + // + // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapalloc + fn HeapAlloc(hHeap: c::HANDLE, dwFlags: c::DWORD, dwBytes: c::SIZE_T) -> c::LPVOID; + + // Reallocate a block of memory behind a given pointer `lpMem` from a given heap `hHeap`, + // to a block of at least `dwBytes` bytes, either shrinking the block in place, + // or allocating at a new location, copying memory, and freeing the original location. + // + // Returns a pointer to the reallocated memory or null if the operation fails. + // The returned pointer will be aligned to at least `MIN_ALIGN`. + // If the operation fails the given block will never have been freed. + // + // SAFETY: + // - `hHeap` must be a non-null handle returned by `GetProcessHeap`. + // - `dwFlags` must be set to zero. + // - `lpMem` must be a non-null pointer to an allocated block returned by `HeapAlloc` or + // `HeapReAlloc`, that has not already been freed. + // If the block was successfully reallocated at a new location, pointers pointing to + // the freed memory, such as `lpMem`, must not be dereferenced ever again. + // + // Note that `dwBytes` is allowed to be zero, contrary to some other allocators. + // + // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heaprealloc + fn HeapReAlloc( + hHeap: c::HANDLE, + dwFlags: c::DWORD, + lpMem: c::LPVOID, + dwBytes: c::SIZE_T, + ) -> c::LPVOID; + + // Free a block of memory behind a given pointer `lpMem` from a given heap `hHeap`. + // Returns a nonzero value if the operation is successful, and zero if the operation fails. + // + // SAFETY: + // - `hHeap` must be a non-null handle returned by `GetProcessHeap`. + // - `dwFlags` must be set to zero. + // - `lpMem` must be a pointer to an allocated block returned by `HeapAlloc` or `HeapReAlloc`, + // that has not already been freed. + // If the block was successfully freed, pointers pointing to the freed memory, such as `lpMem`, + // must not be dereferenced ever again. + // + // Note that `lpMem` is allowed to be null, which will not cause the operation to fail. + // + // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapfree + fn HeapFree(hHeap: c::HANDLE, dwFlags: c::DWORD, lpMem: c::LPVOID) -> c::BOOL; +} + +// Cached handle to the default heap of the current process. +// Either a non-null handle returned by `GetProcessHeap`, or null when not yet initialized or `GetProcessHeap` failed. +static HEAP: AtomicPtr = AtomicPtr::new(ptr::null_mut()); + +// Get a handle to the default heap of the current process, or null if the operation fails. +// If this operation is successful, `HEAP` will be successfully initialized and contain +// a non-null handle returned by `GetProcessHeap`. +#[inline] +fn init_or_get_process_heap() -> c::HANDLE { + let heap = HEAP.load(Ordering::Relaxed); + if heap.is_null() { + // `HEAP` has not yet been successfully initialized + let heap = unsafe { GetProcessHeap() }; + if !heap.is_null() { + // SAFETY: No locking is needed because within the same process, + // successful calls to `GetProcessHeap` will always return the same value, even on different threads. + HEAP.store(heap, Ordering::Release); + + // SAFETY: `HEAP` contains a non-null handle returned by `GetProcessHeap` + heap + } else { + // Could not get the current process heap. + ptr::null_mut() + } + } else { + // SAFETY: `HEAP` contains a non-null handle returned by `GetProcessHeap` + heap + } +} + +// Get a non-null handle to the default heap of the current process. +// SAFETY: `HEAP` must have been successfully initialized. +#[inline] +unsafe fn get_process_heap() -> c::HANDLE { + HEAP.load(Ordering::Acquire) +} + +// Header containing a pointer to the start of an allocated block. +// SAFETY: Size and alignment must be <= `MIN_ALIGN`. +#[repr(C)] +struct Header(*mut u8); + +// Allocate a block of optionally zeroed memory for a given `layout`. +// SAFETY: Returns a pointer satisfying the guarantees of `System` about allocated pointers, +// or null if the operation fails. If this returns non-null `HEAP` will have been successfully +// initialized. +#[inline] +unsafe fn allocate(layout: Layout, zeroed: bool) -> *mut u8 { + let heap = init_or_get_process_heap(); + if heap.is_null() { + // Allocation has failed, could not get the current process heap. + return ptr::null_mut(); + } + + // Allocated memory will be either zeroed or uninitialized. + let flags = if zeroed { HEAP_ZERO_MEMORY } else { 0 }; + + if layout.align() <= MIN_ALIGN { + // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`. + // The returned pointer points to the start of an allocated block. + unsafe { HeapAlloc(heap, flags, layout.size()) as *mut u8 } + } else { + // Allocate extra padding in order to be able to satisfy the alignment. + let total = layout.align() + layout.size(); + + // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`. + let ptr = unsafe { HeapAlloc(heap, flags, total) as *mut u8 }; + if ptr.is_null() { + // Allocation has failed. + return ptr::null_mut(); + } + + // Create a correctly aligned pointer offset from the start of the allocated block, + // and write a header before it. + + let offset = layout.align() - (ptr as usize & (layout.align() - 1)); + // SAFETY: `MIN_ALIGN` <= `offset` <= `layout.align()` and the size of the allocated + // block is `layout.align() + layout.size()`. `aligned` will thus be a correctly aligned + // pointer inside the allocated block with at least `layout.size()` bytes after it and at + // least `MIN_ALIGN` bytes of padding before it. + let aligned = unsafe { ptr.add(offset) }; + // SAFETY: Because the size and alignment of a header is <= `MIN_ALIGN` and `aligned` + // is aligned to at least `MIN_ALIGN` and has at least `MIN_ALIGN` bytes of padding before + // it, it is safe to write a header directly before it. + unsafe { ptr::write((aligned as *mut Header).offset(-1), Header(ptr)) }; + + // SAFETY: The returned pointer does not point to the to the start of an allocated block, + // but there is a header readable directly before it containing the location of the start + // of the block. + aligned + } +} + +// All pointers returned by this allocator have, in addition to the guarantees of `GlobalAlloc`, the +// following properties: +// +// If the pointer was allocated or reallocated with a `layout` specifying an alignment <= `MIN_ALIGN` +// the pointer will be aligned to at least `MIN_ALIGN` and point to the start of the allocated block. +// +// If the pointer was allocated or reallocated with a `layout` specifying an alignment > `MIN_ALIGN` +// the pointer will be aligned to the specified alignment and not point to the start of the allocated block. +// Instead there will be a header readable directly before the returned pointer, containing the actual +// location of the start of the block. +unsafe impl GlobalAlloc for System { + #[inline] + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + // SAFETY: Pointers returned by `allocate` satisfy the guarantees of `System` + let zeroed = false; + unsafe { allocate(layout, zeroed) } + } + + #[inline] + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + let block = { + if layout.align() <= MIN_ALIGN { + ptr + } else { + // The location of the start of the block is stored in the padding before `ptr`. + + // SAFETY: Because of the contract of `System`, `ptr` is guaranteed to be non-null + // and have a header readable directly before it. + unsafe { ptr::read((ptr as *mut Header).offset(-1)).0 } + } + }; + + // SAFETY: because `ptr` has been successfully allocated with this allocator, + // `HEAP` must have been successfully initialized. + let heap = unsafe { get_process_heap() }; + + // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`, + // `block` is a pointer to the start of an allocated block. + unsafe { HeapFree(heap, 0, block as c::LPVOID) }; + } + + #[inline] + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + // SAFETY: Pointers returned by `allocate` satisfy the guarantees of `System` + let zeroed = true; + unsafe { allocate(layout, zeroed) } + } + + #[inline] + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + if layout.align() <= MIN_ALIGN { + // SAFETY: because `ptr` has been successfully allocated with this allocator, + // `HEAP` must have been successfully initialized. + let heap = unsafe { get_process_heap() }; + + // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`, + // `ptr` is a pointer to the start of an allocated block. + // The returned pointer points to the start of an allocated block. + unsafe { HeapReAlloc(heap, 0, ptr as c::LPVOID, new_size) as *mut u8 } + } else { + // SAFETY: `realloc_fallback` is implemented using `dealloc` and `alloc`, which will + // correctly handle `ptr` and return a pointer satisfying the guarantees of `System` + unsafe { realloc_fallback(self, ptr, layout, new_size) } + } + } +} + +pub unsafe fn realloc_fallback( + alloc: &System, + ptr: *mut u8, + old_layout: Layout, + new_size: usize, +) -> *mut u8 { + // Docs for GlobalAlloc::realloc require this to be valid: + let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); + + let new_ptr = GlobalAlloc::alloc(alloc, new_layout); + if !new_ptr.is_null() { + let size = core::cmp::min(old_layout.size(), new_size); + ptr::copy_nonoverlapping(ptr, new_ptr, size); + GlobalAlloc::dealloc(alloc, ptr, old_layout); + } + new_ptr +} diff --git a/src/win_c.rs b/src/win_c.rs new file mode 100644 index 0000000..8294420 --- /dev/null +++ b/src/win_c.rs @@ -0,0 +1,933 @@ +//! C definitions used by libnative that don't belong in liblibc + +#![allow(nonstandard_style)] +#![cfg_attr(test, allow(dead_code))] + +use libc::{c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ushort}; +use core::ptr; + +use libc::{c_void, size_t, wchar_t}; + +pub use self::EXCEPTION_DISPOSITION::*; +pub use self::FILE_INFO_BY_HANDLE_CLASS::*; + +pub type DWORD = c_ulong; +pub type NonZeroDWORD = c_ulong; +pub type HANDLE = LPVOID; +pub type HINSTANCE = HANDLE; +pub type HMODULE = HINSTANCE; +pub type HRESULT = LONG; +pub type BOOL = c_int; +pub type BYTE = u8; +pub type BOOLEAN = BYTE; +pub type GROUP = c_uint; +pub type LARGE_INTEGER = c_longlong; +pub type LONG = c_long; +pub type UINT = c_uint; +pub type WCHAR = u16; +pub type USHORT = c_ushort; +pub type SIZE_T = usize; +pub type WORD = u16; +pub type CHAR = c_char; +pub type ULONG_PTR = usize; +pub type ULONG = c_ulong; +pub type NTSTATUS = LONG; +pub type ACCESS_MASK = DWORD; + +pub type LPBOOL = *mut BOOL; +pub type LPBYTE = *mut BYTE; +pub type LPCSTR = *const CHAR; +pub type LPCWSTR = *const WCHAR; +pub type LPDWORD = *mut DWORD; +pub type LPHANDLE = *mut HANDLE; +pub type LPOVERLAPPED = *mut OVERLAPPED; +pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION; +pub type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES; +pub type LPSTARTUPINFO = *mut STARTUPINFO; +pub type LPVOID = *mut c_void; +pub type LPWCH = *mut WCHAR; +pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW; +pub type LPWSADATA = *mut WSADATA; +pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO; +pub type LPWSTR = *mut WCHAR; +pub type LPFILETIME = *mut FILETIME; +pub type LPWSABUF = *mut WSABUF; +pub type LPWSAOVERLAPPED = *mut c_void; +pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE = *mut c_void; + +pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE; +pub type PLARGE_INTEGER = *mut c_longlong; +pub type PSRWLOCK = *mut SRWLOCK; + +pub type SOCKET = libc::SOCKET; +pub type socklen_t = c_int; +pub type ADDRESS_FAMILY = USHORT; + +pub const TRUE: BOOL = 1; +pub const FALSE: BOOL = 0; + +pub const FILE_ATTRIBUTE_READONLY: DWORD = 0x1; +pub const FILE_ATTRIBUTE_DIRECTORY: DWORD = 0x10; +pub const FILE_ATTRIBUTE_REPARSE_POINT: DWORD = 0x400; + +pub const FILE_SHARE_DELETE: DWORD = 0x4; +pub const FILE_SHARE_READ: DWORD = 0x1; +pub const FILE_SHARE_WRITE: DWORD = 0x2; + +pub const CREATE_ALWAYS: DWORD = 2; +pub const CREATE_NEW: DWORD = 1; +pub const OPEN_ALWAYS: DWORD = 4; +pub const OPEN_EXISTING: DWORD = 3; +pub const TRUNCATE_EXISTING: DWORD = 5; + +pub const FILE_WRITE_DATA: DWORD = 0x00000002; +pub const FILE_APPEND_DATA: DWORD = 0x00000004; +pub const FILE_WRITE_EA: DWORD = 0x00000010; +pub const FILE_WRITE_ATTRIBUTES: DWORD = 0x00000100; +pub const READ_CONTROL: DWORD = 0x00020000; +pub const SYNCHRONIZE: DWORD = 0x00100000; +pub const GENERIC_READ: DWORD = 0x80000000; +pub const GENERIC_WRITE: DWORD = 0x40000000; +pub const STANDARD_RIGHTS_WRITE: DWORD = READ_CONTROL; +pub const FILE_GENERIC_WRITE: DWORD = STANDARD_RIGHTS_WRITE + | FILE_WRITE_DATA + | FILE_WRITE_ATTRIBUTES + | FILE_WRITE_EA + | FILE_APPEND_DATA + | SYNCHRONIZE; + +pub const FILE_FLAG_OPEN_REPARSE_POINT: DWORD = 0x00200000; +pub const FILE_FLAG_BACKUP_SEMANTICS: DWORD = 0x02000000; +pub const SECURITY_SQOS_PRESENT: DWORD = 0x00100000; + +pub const FIONBIO: c_ulong = 0x8004667e; + +#[repr(C)] +#[derive(Copy)] +pub struct WIN32_FIND_DATAW { + pub dwFileAttributes: DWORD, + pub ftCreationTime: FILETIME, + pub ftLastAccessTime: FILETIME, + pub ftLastWriteTime: FILETIME, + pub nFileSizeHigh: DWORD, + pub nFileSizeLow: DWORD, + pub dwReserved0: DWORD, + pub dwReserved1: DWORD, + pub cFileName: [wchar_t; 260], // #define MAX_PATH 260 + pub cAlternateFileName: [wchar_t; 14], +} +impl Clone for WIN32_FIND_DATAW { + fn clone(&self) -> Self { + *self + } +} + +pub const WSA_FLAG_OVERLAPPED: DWORD = 0x01; +pub const WSA_FLAG_NO_HANDLE_INHERIT: DWORD = 0x80; + +pub const WSADESCRIPTION_LEN: usize = 256; +pub const WSASYS_STATUS_LEN: usize = 128; +pub const WSAPROTOCOL_LEN: DWORD = 255; +pub const INVALID_SOCKET: SOCKET = !0; + +pub const WSAEACCES: c_int = 10013; +pub const WSAEINVAL: c_int = 10022; +pub const WSAEWOULDBLOCK: c_int = 10035; +pub const WSAEPROTOTYPE: c_int = 10041; +pub const WSAEADDRINUSE: c_int = 10048; +pub const WSAEADDRNOTAVAIL: c_int = 10049; +pub const WSAECONNABORTED: c_int = 10053; +pub const WSAECONNRESET: c_int = 10054; +pub const WSAENOTCONN: c_int = 10057; +pub const WSAESHUTDOWN: c_int = 10058; +pub const WSAETIMEDOUT: c_int = 10060; +pub const WSAECONNREFUSED: c_int = 10061; + +pub const MAX_PROTOCOL_CHAIN: DWORD = 7; + +pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024; +pub const FSCTL_GET_REPARSE_POINT: DWORD = 0x900a8; +pub const IO_REPARSE_TAG_SYMLINK: DWORD = 0xa000000c; +pub const IO_REPARSE_TAG_MOUNT_POINT: DWORD = 0xa0000003; +pub const SYMLINK_FLAG_RELATIVE: DWORD = 0x00000001; +pub const FSCTL_SET_REPARSE_POINT: DWORD = 0x900a4; + +pub const SYMBOLIC_LINK_FLAG_DIRECTORY: DWORD = 0x1; +pub const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE: DWORD = 0x2; + +// Note that these are not actually HANDLEs, just values to pass to GetStdHandle +pub const STD_INPUT_HANDLE: DWORD = -10i32 as DWORD; +pub const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD; +pub const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD; + +pub const PROGRESS_CONTINUE: DWORD = 0; + +// List of Windows system error codes with descriptions: +// https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes#system-error-codes +pub const ERROR_FILE_NOT_FOUND: DWORD = 2; +pub const ERROR_PATH_NOT_FOUND: DWORD = 3; +pub const ERROR_ACCESS_DENIED: DWORD = 5; +pub const ERROR_INVALID_HANDLE: DWORD = 6; +pub const ERROR_NOT_ENOUGH_MEMORY: DWORD = 8; +pub const ERROR_OUTOFMEMORY: DWORD = 14; +pub const ERROR_NO_MORE_FILES: DWORD = 18; +pub const ERROR_SHARING_VIOLATION: u32 = 32; +pub const ERROR_HANDLE_EOF: DWORD = 38; +pub const ERROR_FILE_EXISTS: DWORD = 80; +pub const ERROR_INVALID_PARAMETER: DWORD = 87; +pub const ERROR_BROKEN_PIPE: DWORD = 109; +pub const ERROR_CALL_NOT_IMPLEMENTED: DWORD = 120; +pub const ERROR_SEM_TIMEOUT: DWORD = 121; +pub const ERROR_INSUFFICIENT_BUFFER: DWORD = 122; +pub const ERROR_ALREADY_EXISTS: DWORD = 183; +pub const ERROR_ENVVAR_NOT_FOUND: DWORD = 203; +pub const ERROR_NO_DATA: DWORD = 232; +pub const ERROR_DRIVER_CANCEL_TIMEOUT: DWORD = 594; +pub const ERROR_OPERATION_ABORTED: DWORD = 995; +pub const ERROR_IO_PENDING: DWORD = 997; +pub const ERROR_SERVICE_REQUEST_TIMEOUT: DWORD = 1053; +pub const ERROR_COUNTER_TIMEOUT: DWORD = 1121; +pub const ERROR_TIMEOUT: DWORD = 1460; +pub const ERROR_RESOURCE_CALL_TIMED_OUT: DWORD = 5910; +pub const ERROR_CTX_MODEM_RESPONSE_TIMEOUT: DWORD = 7012; +pub const ERROR_CTX_CLIENT_QUERY_TIMEOUT: DWORD = 7040; +pub const FRS_ERR_SYSVOL_POPULATE_TIMEOUT: DWORD = 8014; +pub const ERROR_DS_TIMELIMIT_EXCEEDED: DWORD = 8226; +pub const DNS_ERROR_RECORD_TIMED_OUT: DWORD = 9705; +pub const ERROR_IPSEC_IKE_TIMED_OUT: DWORD = 13805; +pub const ERROR_RUNLEVEL_SWITCH_TIMEOUT: DWORD = 15402; +pub const ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT: DWORD = 15403; + +pub const E_NOTIMPL: HRESULT = 0x80004001u32 as HRESULT; + +pub const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE; + +pub const FACILITY_NT_BIT: DWORD = 0x1000_0000; + +pub const FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000; +pub const FORMAT_MESSAGE_FROM_HMODULE: DWORD = 0x00000800; +pub const FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200; + +pub const TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF; + +pub const DLL_THREAD_DETACH: DWORD = 3; +pub const DLL_PROCESS_DETACH: DWORD = 0; + +pub const INFINITE: DWORD = !0; + +pub const DUPLICATE_SAME_ACCESS: DWORD = 0x00000002; + +pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = CONDITION_VARIABLE { ptr: ptr::null_mut() }; +pub const SRWLOCK_INIT: SRWLOCK = SRWLOCK { ptr: ptr::null_mut() }; + +pub const DETACHED_PROCESS: DWORD = 0x00000008; +pub const CREATE_NEW_PROCESS_GROUP: DWORD = 0x00000200; +pub const CREATE_UNICODE_ENVIRONMENT: DWORD = 0x00000400; +pub const STARTF_USESTDHANDLES: DWORD = 0x00000100; + +pub const AF_INET: c_int = 2; +pub const AF_INET6: c_int = 23; +pub const SD_BOTH: c_int = 2; +pub const SD_RECEIVE: c_int = 0; +pub const SD_SEND: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; +pub const SOCK_STREAM: c_int = 1; +pub const SOCKET_ERROR: c_int = -1; +pub const SOL_SOCKET: c_int = 0xffff; +pub const SO_RCVTIMEO: c_int = 0x1006; +pub const SO_SNDTIMEO: c_int = 0x1005; +pub const IPPROTO_IP: c_int = 0; +pub const IPPROTO_TCP: c_int = 6; +pub const IPPROTO_IPV6: c_int = 41; +pub const TCP_NODELAY: c_int = 0x0001; +pub const IP_TTL: c_int = 4; +pub const IPV6_V6ONLY: c_int = 27; +pub const SO_ERROR: c_int = 0x1007; +pub const SO_BROADCAST: c_int = 0x0020; +pub const IP_MULTICAST_LOOP: c_int = 11; +pub const IPV6_MULTICAST_LOOP: c_int = 11; +pub const IP_MULTICAST_TTL: c_int = 10; +pub const IP_ADD_MEMBERSHIP: c_int = 12; +pub const IP_DROP_MEMBERSHIP: c_int = 13; +pub const IPV6_ADD_MEMBERSHIP: c_int = 12; +pub const IPV6_DROP_MEMBERSHIP: c_int = 13; +pub const MSG_PEEK: c_int = 0x2; + +#[repr(C)] +pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, +} + +#[repr(C)] +pub struct ipv6_mreq { + pub ipv6mr_multiaddr: in6_addr, + pub ipv6mr_interface: c_uint, +} + +pub const VOLUME_NAME_DOS: DWORD = 0x0; +pub const MOVEFILE_REPLACE_EXISTING: DWORD = 1; + +pub const FILE_BEGIN: DWORD = 0; +pub const FILE_CURRENT: DWORD = 1; +pub const FILE_END: DWORD = 2; + +pub const WAIT_OBJECT_0: DWORD = 0x00000000; +pub const WAIT_TIMEOUT: DWORD = 258; +pub const WAIT_FAILED: DWORD = 0xFFFFFFFF; + +pub const PIPE_ACCESS_INBOUND: DWORD = 0x00000001; +pub const PIPE_ACCESS_OUTBOUND: DWORD = 0x00000002; +pub const FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD = 0x00080000; +pub const FILE_FLAG_OVERLAPPED: DWORD = 0x40000000; +pub const PIPE_WAIT: DWORD = 0x00000000; +pub const PIPE_TYPE_BYTE: DWORD = 0x00000000; +pub const PIPE_REJECT_REMOTE_CLIENTS: DWORD = 0x00000008; +pub const PIPE_READMODE_BYTE: DWORD = 0x00000000; + +pub const FD_SETSIZE: usize = 64; + +pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000; + +pub const STATUS_SUCCESS: NTSTATUS = 0x00000000; + +#[repr(C)] +#[cfg(not(target_pointer_width = "64"))] +pub struct WSADATA { + pub wVersion: WORD, + pub wHighVersion: WORD, + pub szDescription: [u8; WSADESCRIPTION_LEN + 1], + pub szSystemStatus: [u8; WSASYS_STATUS_LEN + 1], + pub iMaxSockets: u16, + pub iMaxUdpDg: u16, + pub lpVendorInfo: *mut u8, +} +#[repr(C)] +#[cfg(target_pointer_width = "64")] +pub struct WSADATA { + pub wVersion: WORD, + pub wHighVersion: WORD, + pub iMaxSockets: u16, + pub iMaxUdpDg: u16, + pub lpVendorInfo: *mut u8, + pub szDescription: [u8; WSADESCRIPTION_LEN + 1], + pub szSystemStatus: [u8; WSASYS_STATUS_LEN + 1], +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct WSABUF { + pub len: ULONG, + pub buf: *mut CHAR, +} + +#[repr(C)] +pub struct WSAPROTOCOL_INFO { + pub dwServiceFlags1: DWORD, + pub dwServiceFlags2: DWORD, + pub dwServiceFlags3: DWORD, + pub dwServiceFlags4: DWORD, + pub dwProviderFlags: DWORD, + pub ProviderId: GUID, + pub dwCatalogEntryId: DWORD, + pub ProtocolChain: WSAPROTOCOLCHAIN, + pub iVersion: c_int, + pub iAddressFamily: c_int, + pub iMaxSockAddr: c_int, + pub iMinSockAddr: c_int, + pub iSocketType: c_int, + pub iProtocol: c_int, + pub iProtocolMaxOffset: c_int, + pub iNetworkByteOrder: c_int, + pub iSecurityScheme: c_int, + pub dwMessageSize: DWORD, + pub dwProviderReserved: DWORD, + pub szProtocol: [u16; (WSAPROTOCOL_LEN as usize) + 1], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct WIN32_FILE_ATTRIBUTE_DATA { + pub dwFileAttributes: DWORD, + pub ftCreationTime: FILETIME, + pub ftLastAccessTime: FILETIME, + pub ftLastWriteTime: FILETIME, + pub nFileSizeHigh: DWORD, + pub nFileSizeLow: DWORD, +} + +#[repr(C)] +#[allow(dead_code)] // we only use some variants +pub enum FILE_INFO_BY_HANDLE_CLASS { + FileBasicInfo = 0, + FileStandardInfo = 1, + FileNameInfo = 2, + FileRenameInfo = 3, + FileDispositionInfo = 4, + FileAllocationInfo = 5, + FileEndOfFileInfo = 6, + FileStreamInfo = 7, + FileCompressionInfo = 8, + FileAttributeTagInfo = 9, + FileIdBothDirectoryInfo = 10, // 0xA + FileIdBothDirectoryRestartInfo = 11, // 0xB + FileIoPriorityHintInfo = 12, // 0xC + FileRemoteProtocolInfo = 13, // 0xD + FileFullDirectoryInfo = 14, // 0xE + FileFullDirectoryRestartInfo = 15, // 0xF + FileStorageInfo = 16, // 0x10 + FileAlignmentInfo = 17, // 0x11 + FileIdInfo = 18, // 0x12 + FileIdExtdDirectoryInfo = 19, // 0x13 + FileIdExtdDirectoryRestartInfo = 20, // 0x14 + MaximumFileInfoByHandlesClass, +} + +#[repr(C)] +pub struct FILE_BASIC_INFO { + pub CreationTime: LARGE_INTEGER, + pub LastAccessTime: LARGE_INTEGER, + pub LastWriteTime: LARGE_INTEGER, + pub ChangeTime: LARGE_INTEGER, + pub FileAttributes: DWORD, +} + +#[repr(C)] +pub struct FILE_END_OF_FILE_INFO { + pub EndOfFile: LARGE_INTEGER, +} + +#[repr(C)] +pub struct REPARSE_DATA_BUFFER { + pub ReparseTag: c_uint, + pub ReparseDataLength: c_ushort, + pub Reserved: c_ushort, + pub rest: (), +} + +#[repr(C)] +pub struct SYMBOLIC_LINK_REPARSE_BUFFER { + pub SubstituteNameOffset: c_ushort, + pub SubstituteNameLength: c_ushort, + pub PrintNameOffset: c_ushort, + pub PrintNameLength: c_ushort, + pub Flags: c_ulong, + pub PathBuffer: WCHAR, +} + +#[repr(C)] +pub struct MOUNT_POINT_REPARSE_BUFFER { + pub SubstituteNameOffset: c_ushort, + pub SubstituteNameLength: c_ushort, + pub PrintNameOffset: c_ushort, + pub PrintNameLength: c_ushort, + pub PathBuffer: WCHAR, +} + +pub type LPPROGRESS_ROUTINE = core::option::Option< + unsafe extern "system" fn( + TotalFileSize: LARGE_INTEGER, + TotalBytesTransferred: LARGE_INTEGER, + StreamSize: LARGE_INTEGER, + StreamBytesTransferred: LARGE_INTEGER, + dwStreamNumber: DWORD, + dwCallbackReason: DWORD, + hSourceFile: HANDLE, + hDestinationFile: HANDLE, + lpData: LPVOID, + ) -> DWORD, +>; + +#[repr(C)] +pub struct CONDITION_VARIABLE { + pub ptr: LPVOID, +} +#[repr(C)] +pub struct SRWLOCK { + pub ptr: LPVOID, +} +#[repr(C)] +pub struct CRITICAL_SECTION { + CriticalSectionDebug: LPVOID, + LockCount: LONG, + RecursionCount: LONG, + OwningThread: HANDLE, + LockSemaphore: HANDLE, + SpinCount: ULONG_PTR, +} + +#[repr(C)] +pub struct REPARSE_MOUNTPOINT_DATA_BUFFER { + pub ReparseTag: DWORD, + pub ReparseDataLength: DWORD, + pub Reserved: WORD, + pub ReparseTargetLength: WORD, + pub ReparseTargetMaximumLength: WORD, + pub Reserved1: WORD, + pub ReparseTarget: WCHAR, +} + +#[repr(C)] +pub struct GUID { + pub Data1: DWORD, + pub Data2: WORD, + pub Data3: WORD, + pub Data4: [BYTE; 8], +} + +#[repr(C)] +pub struct WSAPROTOCOLCHAIN { + pub ChainLen: c_int, + pub ChainEntries: [DWORD; MAX_PROTOCOL_CHAIN as usize], +} + +#[repr(C)] +pub struct SECURITY_ATTRIBUTES { + pub nLength: DWORD, + pub lpSecurityDescriptor: LPVOID, + pub bInheritHandle: BOOL, +} + +#[repr(C)] +pub struct PROCESS_INFORMATION { + pub hProcess: HANDLE, + pub hThread: HANDLE, + pub dwProcessId: DWORD, + pub dwThreadId: DWORD, +} + +#[repr(C)] +pub struct STARTUPINFO { + pub cb: DWORD, + pub lpReserved: LPWSTR, + pub lpDesktop: LPWSTR, + pub lpTitle: LPWSTR, + pub dwX: DWORD, + pub dwY: DWORD, + pub dwXSize: DWORD, + pub dwYSize: DWORD, + pub dwXCountChars: DWORD, + pub dwYCountCharts: DWORD, + pub dwFillAttribute: DWORD, + pub dwFlags: DWORD, + pub wShowWindow: WORD, + pub cbReserved2: WORD, + pub lpReserved2: LPBYTE, + pub hStdInput: HANDLE, + pub hStdOutput: HANDLE, + pub hStdError: HANDLE, +} + +#[repr(C)] +pub struct SOCKADDR { + pub sa_family: ADDRESS_FAMILY, + pub sa_data: [CHAR; 14], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct FILETIME { + pub dwLowDateTime: DWORD, + pub dwHighDateTime: DWORD, +} + +#[repr(C)] +pub struct OVERLAPPED { + pub Internal: *mut c_ulong, + pub InternalHigh: *mut c_ulong, + pub Offset: DWORD, + pub OffsetHigh: DWORD, + pub hEvent: HANDLE, +} + +#[repr(C)] +#[allow(dead_code)] // we only use some variants +pub enum ADDRESS_MODE { + AddrMode1616, + AddrMode1632, + AddrModeReal, + AddrModeFlat, +} + +#[repr(C)] +pub struct SOCKADDR_STORAGE_LH { + pub ss_family: ADDRESS_FAMILY, + pub __ss_pad1: [CHAR; 6], + pub __ss_align: i64, + pub __ss_pad2: [CHAR; 112], +} + +#[repr(C)] +pub struct ADDRINFOA { + pub ai_flags: c_int, + pub ai_family: c_int, + pub ai_socktype: c_int, + pub ai_protocol: c_int, + pub ai_addrlen: size_t, + pub ai_canonname: *mut c_char, + pub ai_addr: *mut SOCKADDR, + pub ai_next: *mut ADDRINFOA, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct sockaddr_in { + pub sin_family: ADDRESS_FAMILY, + pub sin_port: USHORT, + pub sin_addr: in_addr, + pub sin_zero: [CHAR; 8], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct sockaddr_in6 { + pub sin6_family: ADDRESS_FAMILY, + pub sin6_port: USHORT, + pub sin6_flowinfo: c_ulong, + pub sin6_addr: in6_addr, + pub sin6_scope_id: c_ulong, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct in_addr { + pub s_addr: u32, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct in6_addr { + pub s6_addr: [u8; 16], +} + +#[repr(C)] +#[derive(Copy, Clone)] +#[allow(dead_code)] // we only use some variants +pub enum EXCEPTION_DISPOSITION { + ExceptionContinueExecution, + ExceptionContinueSearch, + ExceptionNestedException, + ExceptionCollidedUnwind, +} + +#[repr(C)] +#[derive(Copy)] +pub struct fd_set { + pub fd_count: c_uint, + pub fd_array: [SOCKET; FD_SETSIZE], +} + +impl Clone for fd_set { + fn clone(&self) -> fd_set { + *self + } +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct timeval { + pub tv_sec: c_long, + pub tv_usec: c_long, +} + +// Shared between Desktop & UWP + +#[link(name = "kernel32")] +extern "system" { + pub fn GetCurrentProcessId() -> DWORD; + pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION); + pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION); + pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOL; + pub fn LeaveCriticalSection(CriticalSection: *mut CRITICAL_SECTION); + pub fn DeleteCriticalSection(CriticalSection: *mut CRITICAL_SECTION); + + pub fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL; + pub fn SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: DWORD) -> BOOL; + pub fn SetLastError(dwErrCode: DWORD); + pub fn GetCommandLineW() -> *mut LPCWSTR; + pub fn GetTempPathW(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD; + pub fn GetCurrentProcess() -> HANDLE; + pub fn GetCurrentThread() -> HANDLE; + pub fn GetStdHandle(which: DWORD) -> HANDLE; + pub fn ExitProcess(uExitCode: c_uint) -> !; + pub fn DeviceIoControl( + hDevice: HANDLE, + dwIoControlCode: DWORD, + lpInBuffer: LPVOID, + nInBufferSize: DWORD, + lpOutBuffer: LPVOID, + nOutBufferSize: DWORD, + lpBytesReturned: LPDWORD, + lpOverlapped: LPOVERLAPPED, + ) -> BOOL; + pub fn CreateThread( + lpThreadAttributes: LPSECURITY_ATTRIBUTES, + dwStackSize: SIZE_T, + lpStartAddress: extern "system" fn(*mut c_void) -> DWORD, + lpParameter: LPVOID, + dwCreationFlags: DWORD, + lpThreadId: LPDWORD, + ) -> HANDLE; + pub fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD; + pub fn SwitchToThread() -> BOOL; + pub fn Sleep(dwMilliseconds: DWORD); + pub fn GetProcessId(handle: HANDLE) -> DWORD; + pub fn CopyFileExW( + lpExistingFileName: LPCWSTR, + lpNewFileName: LPCWSTR, + lpProgressRoutine: LPPROGRESS_ROUTINE, + lpData: LPVOID, + pbCancel: LPBOOL, + dwCopyFlags: DWORD, + ) -> BOOL; + pub fn FormatMessageW( + flags: DWORD, + lpSrc: LPVOID, + msgId: DWORD, + langId: DWORD, + buf: LPWSTR, + nsize: DWORD, + args: *const c_void, + ) -> DWORD; + pub fn TlsAlloc() -> DWORD; + pub fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID; + pub fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL; + pub fn GetLastError() -> DWORD; + pub fn QueryPerformanceFrequency(lpFrequency: *mut LARGE_INTEGER) -> BOOL; + pub fn QueryPerformanceCounter(lpPerformanceCount: *mut LARGE_INTEGER) -> BOOL; + pub fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: LPDWORD) -> BOOL; + pub fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) -> BOOL; + pub fn CreateProcessW( + lpApplicationName: LPCWSTR, + lpCommandLine: LPWSTR, + lpProcessAttributes: LPSECURITY_ATTRIBUTES, + lpThreadAttributes: LPSECURITY_ATTRIBUTES, + bInheritHandles: BOOL, + dwCreationFlags: DWORD, + lpEnvironment: LPVOID, + lpCurrentDirectory: LPCWSTR, + lpStartupInfo: LPSTARTUPINFO, + lpProcessInformation: LPPROCESS_INFORMATION, + ) -> BOOL; + pub fn GetEnvironmentVariableW(n: LPCWSTR, v: LPWSTR, nsize: DWORD) -> DWORD; + pub fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR) -> BOOL; + pub fn GetEnvironmentStringsW() -> LPWCH; + pub fn FreeEnvironmentStringsW(env_ptr: LPWCH) -> BOOL; + pub fn GetModuleFileNameW(hModule: HMODULE, lpFilename: LPWSTR, nSize: DWORD) -> DWORD; + pub fn CreateDirectoryW( + lpPathName: LPCWSTR, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + ) -> BOOL; + pub fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL; + pub fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: LPWSTR) -> DWORD; + pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL; + pub fn DuplicateHandle( + hSourceProcessHandle: HANDLE, + hSourceHandle: HANDLE, + hTargetProcessHandle: HANDLE, + lpTargetHandle: LPHANDLE, + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + dwOptions: DWORD, + ) -> BOOL; + pub fn ReadFile( + hFile: HANDLE, + lpBuffer: LPVOID, + nNumberOfBytesToRead: DWORD, + lpNumberOfBytesRead: LPDWORD, + lpOverlapped: LPOVERLAPPED, + ) -> BOOL; + pub fn WriteFile( + hFile: HANDLE, + lpBuffer: LPVOID, + nNumberOfBytesToWrite: DWORD, + lpNumberOfBytesWritten: LPDWORD, + lpOverlapped: LPOVERLAPPED, + ) -> BOOL; + pub fn CloseHandle(hObject: HANDLE) -> BOOL; + pub fn MoveFileExW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, dwFlags: DWORD) + -> BOOL; + pub fn SetFilePointerEx( + hFile: HANDLE, + liDistanceToMove: LARGE_INTEGER, + lpNewFilePointer: PLARGE_INTEGER, + dwMoveMethod: DWORD, + ) -> BOOL; + pub fn FlushFileBuffers(hFile: HANDLE) -> BOOL; + pub fn CreateFileW( + lpFileName: LPCWSTR, + dwDesiredAccess: DWORD, + dwShareMode: DWORD, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + dwCreationDisposition: DWORD, + dwFlagsAndAttributes: DWORD, + hTemplateFile: HANDLE, + ) -> HANDLE; + + pub fn FindFirstFileW(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW) -> HANDLE; + pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL; + pub fn FindClose(findFile: HANDLE) -> BOOL; + + pub fn GetProcAddress(handle: HMODULE, name: LPCSTR) -> *mut c_void; + pub fn GetModuleHandleA(lpModuleName: LPCSTR) -> HMODULE; + pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; + + pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME); + + pub fn CreateEventW( + lpEventAttributes: LPSECURITY_ATTRIBUTES, + bManualReset: BOOL, + bInitialState: BOOL, + lpName: LPCWSTR, + ) -> HANDLE; + pub fn WaitForMultipleObjects( + nCount: DWORD, + lpHandles: *const HANDLE, + bWaitAll: BOOL, + dwMilliseconds: DWORD, + ) -> DWORD; + pub fn CreateNamedPipeW( + lpName: LPCWSTR, + dwOpenMode: DWORD, + dwPipeMode: DWORD, + nMaxInstances: DWORD, + nOutBufferSize: DWORD, + nInBufferSize: DWORD, + nDefaultTimeOut: DWORD, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + ) -> HANDLE; + pub fn CancelIo(handle: HANDLE) -> BOOL; + pub fn GetOverlappedResult( + hFile: HANDLE, + lpOverlapped: LPOVERLAPPED, + lpNumberOfBytesTransferred: LPDWORD, + bWait: BOOL, + ) -> BOOL; + pub fn CreateSymbolicLinkW( + lpSymlinkFileName: LPCWSTR, + lpTargetFileName: LPCWSTR, + dwFlags: DWORD, + ) -> BOOLEAN; + pub fn GetFinalPathNameByHandleW( + hFile: HANDLE, + lpszFilePath: LPCWSTR, + cchFilePath: DWORD, + dwFlags: DWORD, + ) -> DWORD; + pub fn SetFileInformationByHandle( + hFile: HANDLE, + FileInformationClass: FILE_INFO_BY_HANDLE_CLASS, + lpFileInformation: LPVOID, + dwBufferSize: DWORD, + ) -> BOOL; + pub fn SleepConditionVariableSRW( + ConditionVariable: PCONDITION_VARIABLE, + SRWLock: PSRWLOCK, + dwMilliseconds: DWORD, + Flags: ULONG, + ) -> BOOL; + + pub fn WakeConditionVariable(ConditionVariable: PCONDITION_VARIABLE); + pub fn WakeAllConditionVariable(ConditionVariable: PCONDITION_VARIABLE); + + pub fn AcquireSRWLockExclusive(SRWLock: PSRWLOCK); + pub fn AcquireSRWLockShared(SRWLock: PSRWLOCK); + pub fn ReleaseSRWLockExclusive(SRWLock: PSRWLOCK); + pub fn ReleaseSRWLockShared(SRWLock: PSRWLOCK); + pub fn TryAcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> BOOLEAN; + pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN; +} + +#[link(name = "ws2_32")] +extern "system" { + pub fn WSAStartup(wVersionRequested: WORD, lpWSAData: LPWSADATA) -> c_int; + pub fn WSACleanup() -> c_int; + pub fn WSAGetLastError() -> c_int; + pub fn WSADuplicateSocketW( + s: SOCKET, + dwProcessId: DWORD, + lpProtocolInfo: LPWSAPROTOCOL_INFO, + ) -> c_int; + pub fn WSASend( + s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, + lpNumberOfBytesSent: LPDWORD, + dwFlags: DWORD, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int; + pub fn WSARecv( + s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, + lpNumberOfBytesRecvd: LPDWORD, + lpFlags: LPDWORD, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int; + pub fn WSASocketW( + af: c_int, + kind: c_int, + protocol: c_int, + lpProtocolInfo: LPWSAPROTOCOL_INFO, + g: GROUP, + dwFlags: DWORD, + ) -> SOCKET; + pub fn ioctlsocket(s: SOCKET, cmd: c_long, argp: *mut c_ulong) -> c_int; + pub fn closesocket(socket: SOCKET) -> c_int; + pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int; + pub fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int; + pub fn recvfrom( + socket: SOCKET, + buf: *mut c_void, + len: c_int, + flags: c_int, + addr: *mut SOCKADDR, + addrlen: *mut c_int, + ) -> c_int; + pub fn sendto( + socket: SOCKET, + buf: *const c_void, + len: c_int, + flags: c_int, + addr: *const SOCKADDR, + addrlen: c_int, + ) -> c_int; + pub fn shutdown(socket: SOCKET, how: c_int) -> c_int; + pub fn accept(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET; + pub fn getsockopt( + s: SOCKET, + level: c_int, + optname: c_int, + optval: *mut c_char, + optlen: *mut c_int, + ) -> c_int; + pub fn setsockopt( + s: SOCKET, + level: c_int, + optname: c_int, + optval: *const c_void, + optlen: c_int, + ) -> c_int; + pub fn getsockname(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int; + pub fn getpeername(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int; + pub fn bind(socket: SOCKET, address: *const SOCKADDR, address_len: socklen_t) -> c_int; + pub fn listen(socket: SOCKET, backlog: c_int) -> c_int; + pub fn connect(socket: SOCKET, address: *const SOCKADDR, len: c_int) -> c_int; + pub fn getaddrinfo( + node: *const c_char, + service: *const c_char, + hints: *const ADDRINFOA, + res: *mut *mut ADDRINFOA, + ) -> c_int; + pub fn freeaddrinfo(res: *mut ADDRINFOA); + pub fn select( + nfds: c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + exceptfds: *mut fd_set, + timeout: *const timeval, + ) -> c_int; +} +