mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
more hostenv isolation (#7886)
* Convert host_env Windows path/argv params from raw *const u16 to &WideCStr * Migrate remaining winapi raw u16 pointer signatures to typed references * Migrate winreg pub unsafe fn string parameters to typed references * Add ToPyException impls for host_env error types (PyPy wrap_oserror analog) * Add CheckLibcResult helper and apply to socket/fcntl/shm/posix_wasi * Add Win32 BOOL/HANDLE check helpers; apply check helpers across host_env * Apply Win32/libc check helpers to overlapped/testconsole/os.rs * Apply Win32 check helpers to winapi.rs (partial) * Apply Win32 check helpers across more winapi.rs functions * Apply Win32 check helpers to nt.rs (partial) * Add CheckWin32Sentinel helper; apply to nt.rs INVALID_HANDLE_VALUE/INVALID_FILE_ATTRIBUTES patterns * Add OwnedHandle / HandleToOwned helper; apply to mmap create_named_mapping leak path * Use OwnedHandle RAII in nt::pipe to eliminate manual cleanup on error path * Use OwnedHandle in nt::chmod_follow; hoist HandleToOwned import * Drop rustix dependency from vm crate Remove unused IntoPyException impl for rustix::io::Errno and the rustix entry in crates/vm/Cargo.toml. rustix is now only depended on by host_env. * Fix CI failures: cross-platform regressions - winapi.rs: pass None to create_event_w; the recent Option<&WideCStr> migration left one call site still passing a raw null pointer. - exceptions.rs: gate ToPyException for LockfError with cfg(any(unix, target_os = "wasi")), matching host_env::fcntl's own cfg. The previous cfg let it compile on wasm32-unknown-unknown where host_env::fcntl does not exist. - io_unsupported.rs: derive Eq on FileMode alongside PartialEq to satisfy clippy::derive_partial_eq_without_eq. * Fix CI failures: cfg gates and unused imports - exceptions.rs: gate ToPyException for LockfError with cfg(all(unix, not(target_os = "redox"))) to match the type's own cfg in host_env/src/fcntl.rs (LockfError is not built on wasi). - signal.rs: CheckLibcResult is only used in unix-gated functions; split import so it is not pulled in for windows. - mmap.rs: remove CheckWin32Handle from imports; no longer used after switching to HandleToOwned-based RAII. - overlapped.rs: remove INVALID_HANDLE_VALUE from connect_pipe import; the call now uses .check_valid(). * Fix CI failures: rustfmt and windows unused import - signal.rs: reorder cfg-gated imports per rustfmt. - socket.rs: gate ToPyException import to cfg(all(unix, not(target_os = "redox"))); it is only used inside sendmsg which has the same gate, so it was unused on windows. * Push remaining libc/extern callsites from vm into host_env Add host_env wrappers and replace the corresponding vm call sites: - host_env::errno::strerror_string for libc::strerror - host_env::io::write_stderr_raw for libc::write(STDERR_FILENO,...) - host_env::locale::localeconv_data reused from vm::format - host_env::os::abort for the inline abort extern - host_env::os::urandom wraps getrandom; getrandom moves from vm to host_env - host_env::posix::lchmod for the macOS/BSD lchmod extern - host_env::posix::fcopyfile for the macOS fcopyfile extern - host_env::nt::wputenv for the Windows _wputenv extern vm/format.rs's get_locale_info now uses host_env on both unix and windows instead of the unix-only libc::localeconv path. * Move time tz state and winsound FFI into host_env - host_env::time::tz: wraps the libc tzset/timezone/daylight/tzname globals on non-msvc, non-wasm32 targets. vm::stdlib::time now reads these via the typed wrappers instead of declaring its own externs. - host_env::winsound (windows): exposes PlaySoundW (via a typed PlaySoundSource enum), Beep, and MessageBeep. vm::stdlib::winsound drops its inline FFI block and routes through host_env. * Migrate unsetenv to host_env::nt::wputenv; rustfmt - vm::stdlib::os::unsetenv had a second _wputenv call site that still referenced the removed inline extern. Route it through host_env::nt::wputenv like putenv. - rustfmt fixups in exceptions.rs (boolean chain layout) and the two winsound files. * Address PR review comments - host_env::winapi::create_process: assert that the command_line buffer is NUL-terminated and that the env block ends with a double-NUL, matching the Win32 CreateProcessW contract. - stdlib::overlapped CreateEvent: replace WideCString::from_str_truncate with the fallible from_str(), so embedded NULs in the event name surface as ValueError instead of being silently truncated. - vm::exceptions::ReadlinkError::NotSymbolicLink now maps to OSError (matches Win32 ERROR_NOT_A_REPARSE_POINT semantics) rather than ValueError. - winreg::ConnectRegistry: route the non-zero return through the existing os_error_from_windows_code helper so the resulting exception carries the real winerror/message instead of a generic OSError. * Fix CI failures and address review follow-ups CI failures: - rustfmt cleanup in exceptions.rs after the ReadlinkError change. - vm/stdlib/os.rs: drop unused ToWideString import that the wputenv migration left behind. - vm/stdlib/winsound.rs: replace explicit `&*buf` with `&buf` to satisfy clippy::explicit_auto_deref. - Lib/test/test_format.py, Lib/test/test_types.py: drop the now-stale expectedFailureIfWindows decorators on the locale-format tests; the Windows path now reads real `localeconv` data via host_env so these tests pass. Review follow-ups: - host_env::winapi::create_process: switch the new buffer terminator checks from `assert!` to fallible validators returning `io::ErrorKind::InvalidInput`, so bad inputs stay recoverable at the API boundary. - host_env::winsound::play_sound: reject `Memory(_)` together with `SND_ASYNC` (lifetime-unsafe) and `SND_MEMORY` without a `Memory(_)` source. Expand `PlaySoundError` into a variant enum. - vm::stdlib::_winapi::CreateProcess: route the Win32 path/argv strings through `as_wtf8().to_wide_cstring()` like the rest of the Windows API surface; `expect_str()` could panic on Python strings containing lone surrogates.
This commit is contained in:
1 parent
0e947907c2
commit
40b2da6037
45 files changed
+1170
-1216
No files matched your search
Generated
+1
-2
@@ -3352,6 +3352,7 @@ name = "rustpython-host_env"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"bitflags 2.11.1",
|
||||
"getrandom 0.3.4",
|
||||
"junction",
|
||||
"libc",
|
||||
"libffi",
|
||||
@@ -3596,7 +3597,6 @@ dependencies = [
|
||||
"exitcode",
|
||||
"flame",
|
||||
"flamer",
|
||||
"getrandom 0.3.4",
|
||||
"glob",
|
||||
"half",
|
||||
"hex",
|
||||
@@ -3619,7 +3619,6 @@ dependencies = [
|
||||
"paste",
|
||||
"psm",
|
||||
"result-like",
|
||||
"rustix",
|
||||
"rustpython-codegen",
|
||||
"rustpython-common",
|
||||
"rustpython-compiler",
|
||||
|
||||
Vendored
-1
@@ -423,7 +423,6 @@ class FormatTest(unittest.TestCase):
|
||||
self.assertEqual(format(1+2j, "\u2007^8"), "\u2007(1+2j)\u2007")
|
||||
self.assertEqual(format(0j, "\u2007^4"), "\u20070j\u2007")
|
||||
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; AssertionError: ',' not found in '123456789'")
|
||||
def test_locale(self):
|
||||
try:
|
||||
oldloc = locale.setlocale(locale.LC_ALL)
|
||||
|
||||
Vendored
-2
@@ -431,7 +431,6 @@ class TypesTests(unittest.TestCase):
|
||||
test(123456, "1=20", '11111111111111123456')
|
||||
test(123456, "*=20", '**************123456')
|
||||
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; AssertionError: '1,234.57' != '1234.57'")
|
||||
@run_with_locale('LC_NUMERIC', 'en_US.UTF8', '')
|
||||
def test_float__format__locale(self):
|
||||
# test locale support for __format__ code 'n'
|
||||
@@ -441,7 +440,6 @@ class TypesTests(unittest.TestCase):
|
||||
self.assertEqual(locale.format_string('%g', x, grouping=True), format(x, 'n'))
|
||||
self.assertEqual(locale.format_string('%.10g', x, grouping=True), format(x, '.10n'))
|
||||
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; AssertionError: '123,456,789,012,345,678,901,234,567,890' != '123456789012345678901234567890'")
|
||||
@run_with_locale('LC_NUMERIC', 'en_US.UTF8', '')
|
||||
def test_int__format__locale(self):
|
||||
# test locale support for __format__ code 'n' for integers
|
||||
|
||||
@@ -12,6 +12,7 @@ license.workspace = true
|
||||
rustpython-wtf8 = { workspace = true }
|
||||
|
||||
bitflags = { workspace = true }
|
||||
getrandom = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
num-traits = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
// spell-checker:disable
|
||||
|
||||
/// Return the platform `strerror(errno)` message as an owned `String`.
|
||||
/// Returns `None` when the runtime gives no description for `errno`.
|
||||
#[cfg(any(unix, windows))]
|
||||
#[must_use]
|
||||
pub fn strerror_string(errno: i32) -> Option<String> {
|
||||
let ptr = unsafe { libc::strerror(errno) };
|
||||
if ptr.is_null() {
|
||||
return None;
|
||||
}
|
||||
let s = unsafe { core::ffi::CStr::from_ptr(ptr) }.to_string_lossy();
|
||||
Some(s.into_owned())
|
||||
}
|
||||
|
||||
#[cfg(any(unix, windows, target_os = "wasi"))]
|
||||
pub mod errors {
|
||||
pub use libc::*;
|
||||
|
||||
@@ -3,17 +3,14 @@ use std::io;
|
||||
#[cfg(unix)]
|
||||
use std::os::fd::BorrowedFd;
|
||||
|
||||
use crate::os::CheckLibcResult;
|
||||
|
||||
pub fn normalize_ioctl_request(request: i64) -> libc::c_ulong {
|
||||
(request as u32) as libc::c_ulong
|
||||
}
|
||||
|
||||
pub fn fcntl_int(fd: i32, cmd: i32, arg: i32) -> io::Result<i32> {
|
||||
let ret = unsafe { libc::fcntl(fd, cmd, arg) };
|
||||
if ret < 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(ret)
|
||||
}
|
||||
unsafe { libc::fcntl(fd, cmd, arg) }.check_libc_neg()
|
||||
}
|
||||
|
||||
pub fn validate_fd(fd: i32) -> io::Result<()> {
|
||||
@@ -56,12 +53,7 @@ pub fn set_blocking(fd: BorrowedFd<'_>, blocking: bool) -> io::Result<()> {
|
||||
}
|
||||
|
||||
pub fn fcntl_with_bytes(fd: i32, cmd: i32, arg: &mut [u8]) -> io::Result<i32> {
|
||||
let ret = unsafe { libc::fcntl(fd, cmd, arg.as_mut_ptr()) };
|
||||
if ret < 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(ret)
|
||||
}
|
||||
unsafe { libc::fcntl(fd, cmd, arg.as_mut_ptr()) }.check_libc_neg()
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
@@ -73,31 +65,16 @@ pub unsafe fn ioctl_ptr(
|
||||
request: libc::c_ulong,
|
||||
arg: *mut libc::c_void,
|
||||
) -> io::Result<i32> {
|
||||
let ret = unsafe { libc::ioctl(fd, request as _, arg) };
|
||||
if ret < 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(ret)
|
||||
}
|
||||
unsafe { libc::ioctl(fd, request as _, arg) }.check_libc_neg()
|
||||
}
|
||||
|
||||
pub fn ioctl_int(fd: i32, request: libc::c_ulong, arg: i32) -> io::Result<i32> {
|
||||
let ret = unsafe { libc::ioctl(fd, request as _, arg) };
|
||||
if ret < 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(ret)
|
||||
}
|
||||
unsafe { libc::ioctl(fd, request as _, arg) }.check_libc_neg()
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "wasi", target_os = "redox")))]
|
||||
pub fn flock(fd: i32, operation: i32) -> io::Result<i32> {
|
||||
let ret = unsafe { libc::flock(fd, operation) };
|
||||
if ret < 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(ret)
|
||||
}
|
||||
unsafe { libc::flock(fd, operation) }.check_libc_neg()
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "wasi", target_os = "redox")))]
|
||||
@@ -137,7 +114,7 @@ pub fn lockf(fd: i32, cmd: i32, len: i64, start: i64, whence: i32) -> Result<i32
|
||||
..unsafe { core::mem::zeroed() }
|
||||
};
|
||||
|
||||
let ret = unsafe {
|
||||
unsafe {
|
||||
libc::fcntl(
|
||||
fd,
|
||||
if (cmd & libc::LOCK_NB) != 0 {
|
||||
@@ -147,10 +124,7 @@ pub fn lockf(fd: i32, cmd: i32, len: i64, start: i64, whence: i32) -> Result<i32
|
||||
},
|
||||
&lock,
|
||||
)
|
||||
};
|
||||
if ret < 0 {
|
||||
Err(LockfError::Io(io::Error::last_os_error()))
|
||||
} else {
|
||||
Ok(ret)
|
||||
}
|
||||
.check_libc_neg()
|
||||
.map_err(LockfError::Io)
|
||||
}
|
||||
@@ -252,3 +252,13 @@ pub fn write_once(fd: crt_fd::Borrowed<'_>, buf: &[u8]) -> io::Result<usize> {
|
||||
pub fn close_owned_fd(fd: crt_fd::Owned) -> io::Result<()> {
|
||||
crt_fd::close(fd)
|
||||
}
|
||||
|
||||
/// Async-signal-safe raw write to the platform stderr file descriptor.
|
||||
/// Avoids `std::io::stderr()` locking so it is safe to call from fork
|
||||
/// children and signal handlers.
|
||||
#[cfg(unix)]
|
||||
pub fn write_stderr_raw(buf: &[u8]) {
|
||||
unsafe {
|
||||
let _ = libc::write(libc::STDERR_FILENO, buf.as_ptr().cast(), buf.len());
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ const O_TRUNC: i32 = 0x0400;
|
||||
const O_EXCL: i32 = 0x0800;
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct FileMode: u8 {
|
||||
const CREATED = 0b0001;
|
||||
const READABLE = 0b0010;
|
||||
|
||||
@@ -83,4 +83,6 @@ pub mod winapi;
|
||||
#[cfg(windows)]
|
||||
pub mod winreg;
|
||||
#[cfg(windows)]
|
||||
pub mod winsound;
|
||||
#[cfg(windows)]
|
||||
pub mod wmi;
|
||||
+24
-24
@@ -5,10 +5,14 @@
|
||||
|
||||
use std::io;
|
||||
|
||||
#[cfg(windows)]
|
||||
use crate::windows::{CheckWin32Bool, HandleToOwned};
|
||||
#[cfg(unix)]
|
||||
use crate::{crt_fd, fileutils, posix};
|
||||
use memmap2::{Mmap, MmapMut, MmapOptions};
|
||||
#[cfg(windows)]
|
||||
use std::os::windows::io::{AsRawHandle, IntoRawHandle};
|
||||
#[cfg(windows)]
|
||||
use windows_sys::Win32::{
|
||||
Foundation::{
|
||||
CloseHandle, DUPLICATE_SAME_ACCESS, DuplicateHandle, GetLastError, HANDLE,
|
||||
@@ -131,7 +135,7 @@ impl Drop for NamedMmap {
|
||||
#[cfg(windows)]
|
||||
pub fn duplicate_handle(handle: Handle) -> io::Result<Handle> {
|
||||
let mut new_handle: Handle = INVALID_HANDLE;
|
||||
let result = unsafe {
|
||||
unsafe {
|
||||
DuplicateHandle(
|
||||
GetCurrentProcess(),
|
||||
handle,
|
||||
@@ -141,12 +145,9 @@ pub fn duplicate_handle(handle: Handle) -> io::Result<Handle> {
|
||||
0,
|
||||
DUPLICATE_SAME_ACCESS,
|
||||
)
|
||||
};
|
||||
if result == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(new_handle)
|
||||
}
|
||||
.check_win32_bool()?;
|
||||
Ok(new_handle)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
@@ -187,13 +188,9 @@ pub fn is_invalid_handle_value(handle: isize) -> bool {
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn extend_file(handle: Handle, size: i64) -> io::Result<()> {
|
||||
if unsafe { SetFilePointerEx(handle, size, core::ptr::null_mut(), FILE_BEGIN) } == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
if unsafe { SetEndOfFile(handle) } == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
Ok(())
|
||||
unsafe { SetFilePointerEx(handle, size, core::ptr::null_mut(), FILE_BEGIN) }
|
||||
.check_win32_bool()?;
|
||||
unsafe { SetEndOfFile(handle) }.check_win32_bool()
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -210,11 +207,7 @@ pub fn close_handle(handle: Handle) {
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn flush_view(ptr: *const core::ffi::c_void, size: usize) -> io::Result<()> {
|
||||
if unsafe { FlushViewOfFile(ptr, size) } == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
unsafe { FlushViewOfFile(ptr, size) }.check_win32_bool()
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
@@ -252,21 +245,28 @@ pub fn create_named_mapping(
|
||||
size_lo,
|
||||
tag_wide.as_ptr(),
|
||||
)
|
||||
};
|
||||
if map_handle.is_null() {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
.into_owned()
|
||||
.ok_or_else(io::Error::last_os_error)?;
|
||||
|
||||
let off_hi = (offset as u64 >> 32) as u32;
|
||||
let off_lo = offset as u32;
|
||||
let view = unsafe { MapViewOfFile(map_handle, desired_access, off_hi, off_lo, map_size) };
|
||||
let view = unsafe {
|
||||
MapViewOfFile(
|
||||
map_handle.as_raw_handle() as Handle,
|
||||
desired_access,
|
||||
off_hi,
|
||||
off_lo,
|
||||
map_size,
|
||||
)
|
||||
};
|
||||
if view.Value.is_null() {
|
||||
unsafe { CloseHandle(map_handle) };
|
||||
// `map_handle` is closed automatically when dropped on this error path.
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(NamedMmap {
|
||||
map_handle,
|
||||
map_handle: map_handle.into_raw_handle() as Handle,
|
||||
view_ptr: view.Value as *mut u8,
|
||||
len: map_size,
|
||||
})
|
||||
|
||||
@@ -2,6 +2,7 @@ use alloc::{string::String, vec::Vec};
|
||||
use std::io;
|
||||
|
||||
use crate::crt_fd;
|
||||
use crate::os::CheckLibcResult;
|
||||
use windows_sys::Win32::System::Diagnostics::Debug;
|
||||
|
||||
pub type ErrorMode = u32;
|
||||
@@ -89,39 +90,21 @@ pub fn kbhit() -> i32 {
|
||||
}
|
||||
|
||||
pub fn locking(fd: i32, mode: i32, nbytes: i64) -> io::Result<()> {
|
||||
let ret = unsafe { suppress_iph!(_locking(fd, mode, nbytes)) };
|
||||
if ret == -1 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
unsafe { suppress_iph!(_locking(fd, mode, nbytes)) }.check_libc_neg()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn heapmin() -> io::Result<()> {
|
||||
let ret = unsafe { suppress_iph!(_heapmin()) };
|
||||
if ret == -1 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
unsafe { suppress_iph!(_heapmin()) }.check_libc_neg()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn setmode(fd: crt_fd::Borrowed<'_>, flags: i32) -> io::Result<i32> {
|
||||
let ret = unsafe { suppress_iph!(_setmode(fd, flags)) };
|
||||
if ret == -1 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(ret)
|
||||
}
|
||||
unsafe { suppress_iph!(_setmode(fd, flags)) }.check_libc_neg()
|
||||
}
|
||||
|
||||
pub fn open_osfhandle(handle: isize, flags: i32) -> io::Result<i32> {
|
||||
let ret = unsafe { suppress_iph!(libc::open_osfhandle(handle, flags)) };
|
||||
if ret == -1 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(ret)
|
||||
}
|
||||
unsafe { suppress_iph!(libc::open_osfhandle(handle, flags)) }.check_libc_neg()
|
||||
}
|
||||
|
||||
pub fn get_error_mode() -> u32 {
|
||||
|
||||
@@ -159,13 +159,11 @@ impl SemHandle {
|
||||
#[cfg(windows)]
|
||||
impl SemHandle {
|
||||
pub fn create(value: i32, maxvalue: i32) -> io::Result<Self> {
|
||||
use crate::windows::CheckWin32Handle;
|
||||
let handle =
|
||||
unsafe { CreateSemaphoreW(core::ptr::null(), value, maxvalue, core::ptr::null()) };
|
||||
if handle == 0 as HANDLE {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(Self { raw: handle })
|
||||
}
|
||||
unsafe { CreateSemaphoreW(core::ptr::null(), value, maxvalue, core::ptr::null()) }
|
||||
.check_nonnull()?;
|
||||
Ok(Self { raw: handle })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
+117
-120
@@ -19,7 +19,7 @@ use crate::{
|
||||
StatStruct,
|
||||
windows::{FILE_INFO_BY_NAME_CLASS, get_file_information_by_name, stat_basic_info_to_stat},
|
||||
},
|
||||
windows::ToWideString,
|
||||
windows::{CheckWin32Bool, CheckWin32Handle, CheckWin32Sentinel, HandleToOwned, ToWideString},
|
||||
};
|
||||
use libc::intptr_t;
|
||||
use windows_sys::Win32::{
|
||||
@@ -257,16 +257,12 @@ pub fn remove(path: &Path) -> io::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
let ok = if is_directory && is_link {
|
||||
if is_directory && is_link {
|
||||
unsafe { RemoveDirectoryW(wide_path.as_ptr()) }
|
||||
} else {
|
||||
unsafe { DeleteFileW(wide_path.as_ptr()) }
|
||||
};
|
||||
if ok == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
.check_win32_bool()
|
||||
}
|
||||
|
||||
pub fn supports_virtual_terminal() -> bool {
|
||||
@@ -351,17 +347,15 @@ pub fn symlink(
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
pub fn win32_hchmod(handle: HANDLE, mode: u32, write_bit: u32) -> io::Result<()> {
|
||||
let mut info: FILE_BASIC_INFO = unsafe { core::mem::zeroed() };
|
||||
let ret = unsafe {
|
||||
unsafe {
|
||||
GetFileInformationByHandleEx(
|
||||
handle,
|
||||
FileBasicInfo,
|
||||
(&mut info as *mut FILE_BASIC_INFO).cast(),
|
||||
core::mem::size_of::<FILE_BASIC_INFO>() as u32,
|
||||
)
|
||||
};
|
||||
if ret == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
.check_win32_bool()?;
|
||||
|
||||
if mode & write_bit != 0 {
|
||||
info.FileAttributes &= !FILE_ATTRIBUTE_READONLY;
|
||||
@@ -369,19 +363,15 @@ pub fn win32_hchmod(handle: HANDLE, mode: u32, write_bit: u32) -> io::Result<()>
|
||||
info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
|
||||
}
|
||||
|
||||
let ret = unsafe {
|
||||
unsafe {
|
||||
SetFileInformationByHandle(
|
||||
handle,
|
||||
FileBasicInfo,
|
||||
(&info as *const FILE_BASIC_INFO).cast(),
|
||||
core::mem::size_of::<FILE_BASIC_INFO>() as u32,
|
||||
)
|
||||
};
|
||||
if ret == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
.check_win32_bool()
|
||||
}
|
||||
|
||||
pub fn fchmod(fd: i32, mode: u32, write_bit: u32) -> io::Result<()> {
|
||||
@@ -392,21 +382,13 @@ pub fn fchmod(fd: i32, mode: u32, write_bit: u32) -> io::Result<()> {
|
||||
|
||||
pub fn win32_lchmod(path: &OsStr, mode: u32, write_bit: u32) -> io::Result<()> {
|
||||
let wide = path.to_wide_with_nul();
|
||||
let attr = unsafe { GetFileAttributesW(wide.as_ptr()) };
|
||||
if attr == INVALID_FILE_ATTRIBUTES {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
let attr = unsafe { GetFileAttributesW(wide.as_ptr()) }.check_ne(INVALID_FILE_ATTRIBUTES)?;
|
||||
let new_attr = if mode & write_bit != 0 {
|
||||
attr & !FILE_ATTRIBUTE_READONLY
|
||||
} else {
|
||||
attr | FILE_ATTRIBUTE_READONLY
|
||||
};
|
||||
let ret = unsafe { SetFileAttributesW(wide.as_ptr(), new_attr) };
|
||||
if ret == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
unsafe { SetFileAttributesW(wide.as_ptr(), new_attr) }.check_win32_bool()
|
||||
}
|
||||
|
||||
pub fn chmod_follow(path: &widestring::WideCStr, mode: u32, write_bit: u32) -> io::Result<()> {
|
||||
@@ -426,22 +408,16 @@ pub fn chmod_follow(path: &widestring::WideCStr, mode: u32, write_bit: u32) -> i
|
||||
core::ptr::null_mut(),
|
||||
)
|
||||
};
|
||||
if handle == INVALID_HANDLE_VALUE {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
let result = win32_hchmod(handle, mode, write_bit);
|
||||
unsafe { CloseHandle(handle) };
|
||||
result
|
||||
use std::os::windows::io::AsRawHandle;
|
||||
let handle = handle.into_owned().ok_or_else(io::Error::last_os_error)?;
|
||||
win32_hchmod(handle.as_raw_handle() as HANDLE, mode, write_bit)
|
||||
}
|
||||
|
||||
pub fn find_first_file_name(path: &Path) -> io::Result<OsString> {
|
||||
let wide_path = path.as_os_str().to_wide_with_nul();
|
||||
let mut find_data: WIN32_FIND_DATAW = unsafe { core::mem::zeroed() };
|
||||
|
||||
let handle = unsafe { FindFirstFileW(wide_path.as_ptr(), &mut find_data) };
|
||||
if handle == INVALID_HANDLE_VALUE {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
let handle = unsafe { FindFirstFileW(wide_path.as_ptr(), &mut find_data) }.check_valid()?;
|
||||
unsafe { FindClose(handle) };
|
||||
|
||||
let len = find_data
|
||||
@@ -472,11 +448,8 @@ pub fn path_isdevdrive(path: &Path) -> io::Result<bool> {
|
||||
|
||||
let wide_path = path.as_os_str().to_wide_with_nul();
|
||||
let mut volume = [0u16; MAX_PATH as usize];
|
||||
let ok =
|
||||
unsafe { GetVolumePathNameW(wide_path.as_ptr(), volume.as_mut_ptr(), volume.len() as _) };
|
||||
if ok == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
unsafe { GetVolumePathNameW(wide_path.as_ptr(), volume.as_mut_ptr(), volume.len() as _) }
|
||||
.check_win32_bool()?;
|
||||
if unsafe { GetDriveTypeW(volume.as_ptr()) } != DRIVE_FIXED {
|
||||
return Ok(false);
|
||||
}
|
||||
@@ -491,10 +464,8 @@ pub fn path_isdevdrive(path: &Path) -> io::Result<bool> {
|
||||
FILE_FLAG_BACKUP_SEMANTICS,
|
||||
core::ptr::null_mut(),
|
||||
)
|
||||
};
|
||||
if handle == INVALID_HANDLE_VALUE {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
.check_valid()?;
|
||||
|
||||
let mut volume_state = FileFsPersistentVolumeInformation {
|
||||
volume_flags: 0,
|
||||
@@ -645,10 +616,7 @@ fn win32_xstat_attributes_from_dir(
|
||||
let wide: Vec<u16> = path.to_wide_with_nul();
|
||||
let mut find_data: WIN32_FIND_DATAW = unsafe { core::mem::zeroed() };
|
||||
|
||||
let handle = unsafe { FindFirstFileW(wide.as_ptr(), &mut find_data) };
|
||||
if handle == INVALID_HANDLE_VALUE {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
let handle = unsafe { FindFirstFileW(wide.as_ptr(), &mut find_data) }.check_valid()?;
|
||||
unsafe { FindClose(handle) };
|
||||
|
||||
let mut info: BY_HANDLE_FILE_INFORMATION = unsafe { core::mem::zeroed() };
|
||||
@@ -1138,6 +1106,7 @@ pub fn fd_exists(fd: crate::crt_fd::Borrowed<'_>) -> bool {
|
||||
}
|
||||
|
||||
pub fn pipe() -> io::Result<(i32, i32)> {
|
||||
use std::os::windows::io::{AsRawHandle, IntoRawHandle};
|
||||
use windows_sys::Win32::Security::SECURITY_ATTRIBUTES;
|
||||
use windows_sys::Win32::System::Pipes::CreatePipe;
|
||||
|
||||
@@ -1150,34 +1119,39 @@ pub fn pipe() -> io::Result<(i32, i32)> {
|
||||
let (read_handle, write_handle) = unsafe {
|
||||
let mut read = core::mem::MaybeUninit::<isize>::uninit();
|
||||
let mut write = core::mem::MaybeUninit::<isize>::uninit();
|
||||
let ok = CreatePipe(
|
||||
CreatePipe(
|
||||
read.as_mut_ptr() as *mut _,
|
||||
write.as_mut_ptr() as *mut _,
|
||||
&mut attr as *mut _,
|
||||
0,
|
||||
);
|
||||
if ok == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
(read.assume_init(), write.assume_init())
|
||||
)
|
||||
.check_win32_bool()?;
|
||||
(read.assume_init() as HANDLE, write.assume_init() as HANDLE)
|
||||
};
|
||||
// RAII wrappers: both handles are auto-closed on any early return below.
|
||||
let read_handle = read_handle
|
||||
.into_owned()
|
||||
.expect("CreatePipe returned valid read handle");
|
||||
let write_handle = write_handle
|
||||
.into_owned()
|
||||
.expect("CreatePipe returned valid write handle");
|
||||
|
||||
const O_NOINHERIT: i32 = 0x80;
|
||||
let read_fd = match crate::msvcrt::open_osfhandle(read_handle, O_NOINHERIT) {
|
||||
Ok(fd) => fd,
|
||||
Err(err) => {
|
||||
unsafe {
|
||||
CloseHandle(read_handle as _);
|
||||
CloseHandle(write_handle as _);
|
||||
}
|
||||
return Err(err);
|
||||
let read_fd = crate::msvcrt::open_osfhandle(read_handle.as_raw_handle() as isize, O_NOINHERIT)?;
|
||||
// Ownership of the read handle now belongs to the CRT fd.
|
||||
let _ = read_handle.into_raw_handle();
|
||||
|
||||
let write_fd = match crate::msvcrt::open_osfhandle(
|
||||
write_handle.as_raw_handle() as isize,
|
||||
libc::O_WRONLY | O_NOINHERIT,
|
||||
) {
|
||||
Ok(fd) => {
|
||||
let _ = write_handle.into_raw_handle();
|
||||
fd
|
||||
}
|
||||
};
|
||||
let write_fd = match crate::msvcrt::open_osfhandle(write_handle, libc::O_WRONLY | O_NOINHERIT) {
|
||||
Ok(fd) => fd,
|
||||
Err(err) => {
|
||||
// Close the CRT fd we already created; `write_handle` auto-closes via Drop.
|
||||
let _ = unsafe { crt_fd::Owned::from_raw(read_fd) };
|
||||
unsafe { CloseHandle(write_handle as _) };
|
||||
return Err(err);
|
||||
}
|
||||
};
|
||||
@@ -1201,17 +1175,15 @@ pub fn mkdir(path: &widestring::WideCStr, mode: i32) -> io::Result<()> {
|
||||
let sddl: Vec<u16> = "D:P(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;FA;;;OW)\0"
|
||||
.encode_utf16()
|
||||
.collect();
|
||||
let convert_ok = unsafe {
|
||||
unsafe {
|
||||
ConvertStringSecurityDescriptorToSecurityDescriptorW(
|
||||
sddl.as_ptr(),
|
||||
SDDL_REVISION_1,
|
||||
&mut sec_attr.lpSecurityDescriptor,
|
||||
core::ptr::null_mut(),
|
||||
)
|
||||
};
|
||||
if convert_ok == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
.check_win32_bool()?;
|
||||
let ok = unsafe {
|
||||
windows_sys::Win32::Storage::FileSystem::CreateDirectoryW(
|
||||
path.as_ptr(),
|
||||
@@ -1229,15 +1201,12 @@ pub fn mkdir(path: &widestring::WideCStr, mode: i32) -> io::Result<()> {
|
||||
}
|
||||
};
|
||||
|
||||
if ok == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
ok.check_win32_bool()
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
fn _umask(mask: i32) -> i32;
|
||||
fn _wputenv(envstring: *const u16) -> libc::c_int;
|
||||
}
|
||||
|
||||
pub fn umask(mask: i32) -> io::Result<i32> {
|
||||
@@ -1249,6 +1218,17 @@ pub fn umask(mask: i32) -> io::Result<i32> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Update the CRT environment via `_wputenv`.
|
||||
/// `envstring` must point to a nul-terminated wide string of the form `KEY=value`.
|
||||
pub fn wputenv(envstring: &widestring::WideCStr) -> io::Result<()> {
|
||||
let result = unsafe { crate::suppress_iph!(_wputenv(envstring.as_ptr())) };
|
||||
if result != 0 {
|
||||
Err(crate::os::errno_io_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn set_fd_inheritable(fd: i32, inheritable: bool) -> io::Result<()> {
|
||||
let borrowed = unsafe { crt_fd::Borrowed::borrow_raw(fd) };
|
||||
let handle = crt_fd::as_handle(borrowed)?;
|
||||
@@ -1378,18 +1358,11 @@ pub fn kill(pid: u32, sig: u32) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
let handle = unsafe { Threading::OpenProcess(Threading::PROCESS_ALL_ACCESS, 0, pid) };
|
||||
if handle.is_null() {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
let ok = unsafe { Threading::TerminateProcess(handle, sig) };
|
||||
let err = if ok == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
};
|
||||
let handle = unsafe { Threading::OpenProcess(Threading::PROCESS_ALL_ACCESS, 0, pid) }
|
||||
.check_nonnull()?;
|
||||
let result = unsafe { Threading::TerminateProcess(handle, sig) }.check_win32_bool();
|
||||
unsafe { CloseHandle(handle) };
|
||||
err
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1407,10 +1380,8 @@ pub fn getfinalpathname(path: &Path) -> io::Result<OsString> {
|
||||
FILE_FLAG_BACKUP_SEMANTICS,
|
||||
core::ptr::null_mut(),
|
||||
)
|
||||
};
|
||||
if handle == INVALID_HANDLE_VALUE {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
.check_valid()?;
|
||||
|
||||
let mut buffer = vec![0u16; MAX_PATH as usize];
|
||||
let result = loop {
|
||||
@@ -1445,10 +1416,8 @@ pub fn getfullpathname(path: &Path) -> io::Result<OsString> {
|
||||
buffer.as_mut_ptr(),
|
||||
core::ptr::null_mut(),
|
||||
)
|
||||
};
|
||||
if ret == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
.check_ne(0)?;
|
||||
if ret as usize > buffer.len() {
|
||||
buffer.resize(ret as usize, 0);
|
||||
ret = unsafe {
|
||||
@@ -1458,11 +1427,10 @@ pub fn getfullpathname(path: &Path) -> io::Result<OsString> {
|
||||
buffer.as_mut_ptr(),
|
||||
core::ptr::null_mut(),
|
||||
)
|
||||
};
|
||||
if ret == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
.check_ne(0)?;
|
||||
}
|
||||
let _ = ret;
|
||||
Ok(widestring::WideCString::from_vec_truncate(buffer).to_os_string())
|
||||
}
|
||||
|
||||
@@ -1470,18 +1438,15 @@ pub fn getvolumepathname(path: &Path) -> io::Result<OsString> {
|
||||
let wide = path.as_os_str().to_wide_with_nul();
|
||||
let buflen = core::cmp::max(wide.len(), MAX_PATH as usize);
|
||||
let mut buffer = vec![0u16; buflen];
|
||||
let ok = unsafe {
|
||||
unsafe {
|
||||
windows_sys::Win32::Storage::FileSystem::GetVolumePathNameW(
|
||||
wide.as_ptr(),
|
||||
buffer.as_mut_ptr(),
|
||||
buflen as u32,
|
||||
)
|
||||
};
|
||||
if ok == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(widestring::WideCString::from_vec_truncate(buffer).to_os_string())
|
||||
}
|
||||
.check_win32_bool()?;
|
||||
Ok(widestring::WideCString::from_vec_truncate(buffer).to_os_string())
|
||||
}
|
||||
|
||||
pub fn getdiskusage(path: &Path) -> io::Result<(u64, u64)> {
|
||||
@@ -1709,13 +1674,13 @@ pub fn getppid() -> u32 {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn path_skip_root(path: *const u16) -> Option<usize> {
|
||||
pub fn path_skip_root(path: &widestring::WideCStr) -> Option<usize> {
|
||||
let mut end: *const u16 = core::ptr::null();
|
||||
let hr = unsafe { windows_sys::Win32::UI::Shell::PathCchSkipRoot(path, &mut end) };
|
||||
let hr = unsafe { windows_sys::Win32::UI::Shell::PathCchSkipRoot(path.as_ptr(), &mut end) };
|
||||
if hr >= 0 {
|
||||
assert!(!end.is_null());
|
||||
Some(
|
||||
unsafe { end.offset_from(path) }
|
||||
unsafe { end.offset_from(path.as_ptr()) }
|
||||
.try_into()
|
||||
.expect("len must be non-negative"),
|
||||
)
|
||||
@@ -2150,7 +2115,7 @@ pub fn write_console_utf8(handle: HANDLE, data: &[u8], max_bytes: usize) -> io::
|
||||
Ok(len)
|
||||
}
|
||||
|
||||
pub fn open_console_path_fd(path: *const u16, writable: bool) -> io::Result<i32> {
|
||||
pub fn open_console_path_fd(path: &widestring::WideCStr, writable: bool) -> io::Result<i32> {
|
||||
use windows_sys::Win32::{
|
||||
Foundation::{GENERIC_READ, GENERIC_WRITE},
|
||||
Storage::FileSystem::{FILE_SHARE_READ, FILE_SHARE_WRITE},
|
||||
@@ -2164,7 +2129,7 @@ pub fn open_console_path_fd(path: *const u16, writable: bool) -> io::Result<i32>
|
||||
|
||||
let mut handle = unsafe {
|
||||
CreateFileW(
|
||||
path,
|
||||
path.as_ptr(),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
core::ptr::null(),
|
||||
@@ -2176,7 +2141,7 @@ pub fn open_console_path_fd(path: *const u16, writable: bool) -> io::Result<i32>
|
||||
if handle == INVALID_HANDLE_VALUE {
|
||||
handle = unsafe {
|
||||
CreateFileW(
|
||||
path,
|
||||
path.as_ptr(),
|
||||
access,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
core::ptr::null(),
|
||||
@@ -2216,8 +2181,22 @@ pub fn cwait(pid: intptr_t, opt: i32) -> io::Result<(intptr_t, i32)> {
|
||||
}
|
||||
|
||||
#[cfg(target_env = "msvc")]
|
||||
pub fn spawnv(mode: i32, path: *const u16, argv: *const *const u16) -> io::Result<intptr_t> {
|
||||
let result = unsafe { crate::suppress_iph!(_wspawnv(mode, path, argv)) };
|
||||
fn null_terminated_ptrs(strings: &[&widestring::WideCStr]) -> Vec<*const u16> {
|
||||
strings
|
||||
.iter()
|
||||
.map(|s| s.as_ptr())
|
||||
.chain(core::iter::once(core::ptr::null()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(target_env = "msvc")]
|
||||
pub fn spawnv(
|
||||
mode: i32,
|
||||
path: &widestring::WideCStr,
|
||||
argv: &[&widestring::WideCStr],
|
||||
) -> io::Result<intptr_t> {
|
||||
let argv_ptrs = null_terminated_ptrs(argv);
|
||||
let result = unsafe { crate::suppress_iph!(_wspawnv(mode, path.as_ptr(), argv_ptrs.as_ptr())) };
|
||||
if result == -1 {
|
||||
Err(crate::os::errno_io_error())
|
||||
} else {
|
||||
@@ -2228,11 +2207,20 @@ pub fn spawnv(mode: i32, path: *const u16, argv: *const *const u16) -> io::Resul
|
||||
#[cfg(target_env = "msvc")]
|
||||
pub fn spawnve(
|
||||
mode: i32,
|
||||
path: *const u16,
|
||||
argv: *const *const u16,
|
||||
envp: *const *const u16,
|
||||
path: &widestring::WideCStr,
|
||||
argv: &[&widestring::WideCStr],
|
||||
envp: &[&widestring::WideCStr],
|
||||
) -> io::Result<intptr_t> {
|
||||
let result = unsafe { crate::suppress_iph!(_wspawnve(mode, path, argv, envp)) };
|
||||
let argv_ptrs = null_terminated_ptrs(argv);
|
||||
let envp_ptrs = null_terminated_ptrs(envp);
|
||||
let result = unsafe {
|
||||
crate::suppress_iph!(_wspawnve(
|
||||
mode,
|
||||
path.as_ptr(),
|
||||
argv_ptrs.as_ptr(),
|
||||
envp_ptrs.as_ptr()
|
||||
))
|
||||
};
|
||||
if result == -1 {
|
||||
Err(crate::os::errno_io_error())
|
||||
} else {
|
||||
@@ -2241,8 +2229,9 @@ pub fn spawnve(
|
||||
}
|
||||
|
||||
#[cfg(target_env = "msvc")]
|
||||
pub fn execv(path: *const u16, argv: *const *const u16) -> io::Result<()> {
|
||||
let result = unsafe { crate::suppress_iph!(_wexecv(path, argv)) };
|
||||
pub fn execv(path: &widestring::WideCStr, argv: &[&widestring::WideCStr]) -> io::Result<()> {
|
||||
let argv_ptrs = null_terminated_ptrs(argv);
|
||||
let result = unsafe { crate::suppress_iph!(_wexecv(path.as_ptr(), argv_ptrs.as_ptr())) };
|
||||
if result == -1 {
|
||||
Err(crate::os::errno_io_error())
|
||||
} else {
|
||||
@@ -2252,11 +2241,19 @@ pub fn execv(path: *const u16, argv: *const *const u16) -> io::Result<()> {
|
||||
|
||||
#[cfg(target_env = "msvc")]
|
||||
pub fn execve(
|
||||
path: *const u16,
|
||||
argv: *const *const u16,
|
||||
envp: *const *const u16,
|
||||
path: &widestring::WideCStr,
|
||||
argv: &[&widestring::WideCStr],
|
||||
envp: &[&widestring::WideCStr],
|
||||
) -> io::Result<()> {
|
||||
let result = unsafe { crate::suppress_iph!(_wexecve(path, argv, envp)) };
|
||||
let argv_ptrs = null_terminated_ptrs(argv);
|
||||
let envp_ptrs = null_terminated_ptrs(envp);
|
||||
let result = unsafe {
|
||||
crate::suppress_iph!(_wexecve(
|
||||
path.as_ptr(),
|
||||
argv_ptrs.as_ptr(),
|
||||
envp_ptrs.as_ptr()
|
||||
))
|
||||
};
|
||||
if result == -1 {
|
||||
Err(crate::os::errno_io_error())
|
||||
} else {
|
||||
|
||||
+65
-12
@@ -223,6 +223,21 @@ pub fn exit(code: i32) -> ! {
|
||||
std::process::exit(code)
|
||||
}
|
||||
|
||||
/// Wrapper around the C `abort()` call: terminates the process abnormally.
|
||||
pub fn abort() -> ! {
|
||||
unsafe extern "C" {
|
||||
fn abort() -> !;
|
||||
}
|
||||
unsafe { abort() }
|
||||
}
|
||||
|
||||
/// Read `size` cryptographically random bytes from the OS.
|
||||
pub fn urandom(size: usize) -> io::Result<Vec<u8>> {
|
||||
let mut buf = vec![0u8; size];
|
||||
getrandom::fill(&mut buf).map_err(io::Error::from)?;
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
#[cfg(any(unix, windows, target_os = "wasi"))]
|
||||
pub fn isatty(fd: i32) -> bool {
|
||||
unsafe { suppress_iph!(libc::isatty(fd)) != 0 }
|
||||
@@ -304,12 +319,7 @@ pub fn seek_fd(
|
||||
position: crt_fd::Offset,
|
||||
how: i32,
|
||||
) -> io::Result<crt_fd::Offset> {
|
||||
let ret = unsafe { suppress_iph!(libc::lseek(fd.as_raw(), position, how)) };
|
||||
if ret < 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(ret)
|
||||
}
|
||||
unsafe { suppress_iph!(libc::lseek(fd.as_raw(), position, how)) }.check_libc_neg()
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
@@ -328,22 +338,19 @@ pub fn set_file_times(
|
||||
access: Duration,
|
||||
modified: Duration,
|
||||
) -> io::Result<()> {
|
||||
use crate::windows::CheckWin32Bool;
|
||||
let access = filetime_from_duration(access);
|
||||
let modified = filetime_from_duration(modified);
|
||||
let file = fs::open_write_with_custom_flags(path, FILE_FLAG_BACKUP_SEMANTICS)?;
|
||||
let ret = unsafe {
|
||||
unsafe {
|
||||
SetFileTime(
|
||||
file.as_raw_handle() as _,
|
||||
core::ptr::null(),
|
||||
&access,
|
||||
&modified,
|
||||
)
|
||||
};
|
||||
if ret == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
.check_win32_bool()
|
||||
}
|
||||
|
||||
pub trait ErrorExt {
|
||||
@@ -378,6 +385,52 @@ pub fn errno_io_error() -> io::Error {
|
||||
std::io::Error::last_os_error()
|
||||
}
|
||||
|
||||
/// Convert a libc-style return value into an `io::Result`.
|
||||
///
|
||||
/// Negative values are treated as errors; errno is read via [`errno_io_error`].
|
||||
/// Modeled after PyPy's `rposix.handle_posix_error`.
|
||||
pub trait CheckLibcResult: Sized {
|
||||
/// Returns `Ok(self)` if non-negative, otherwise `Err` with the current errno.
|
||||
fn check_libc_neg(self) -> io::Result<Self>;
|
||||
}
|
||||
|
||||
macro_rules! impl_check_libc_result {
|
||||
($($ty:ty),* $(,)?) => {
|
||||
$(
|
||||
impl CheckLibcResult for $ty {
|
||||
#[inline]
|
||||
fn check_libc_neg(self) -> io::Result<Self> {
|
||||
if self < 0 { Err(errno_io_error()) } else { Ok(self) }
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
impl_check_libc_result!(i16, i32, i64, isize);
|
||||
|
||||
/// libc convention where `0` means success and any non-zero value indicates failure
|
||||
/// (with errno set). Used by APIs like `sigemptyset`, `sigaction`, `pthread_*`, etc.
|
||||
pub trait CheckLibcZero {
|
||||
/// Returns `Ok(())` if `self == 0`, otherwise the current errno as an `io::Error`.
|
||||
fn check_libc_zero(self) -> io::Result<()>;
|
||||
}
|
||||
|
||||
macro_rules! impl_check_libc_zero {
|
||||
($($ty:ty),* $(,)?) => {
|
||||
$(
|
||||
impl CheckLibcZero for $ty {
|
||||
#[inline]
|
||||
fn check_libc_zero(self) -> io::Result<()> {
|
||||
if self == 0 { Ok(()) } else { Err(errno_io_error()) }
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
impl_check_libc_zero!(i32, i64, isize);
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn get_errno() -> i32 {
|
||||
unsafe extern "C" {
|
||||
|
||||
@@ -14,6 +14,8 @@ use std::{
|
||||
io,
|
||||
sync::{Mutex, OnceLock},
|
||||
};
|
||||
|
||||
use crate::windows::{CheckWin32Bool, CheckWin32Handle};
|
||||
use windows_sys::Win32::{
|
||||
Foundation::{CloseHandle, ERROR_IO_PENDING, ERROR_MORE_DATA, ERROR_SUCCESS, HANDLE},
|
||||
Networking::WinSock::{AF_INET, AF_INET6, SOCKADDR, SOCKADDR_IN, SOCKADDR_IN6},
|
||||
@@ -76,10 +78,8 @@ unsafe impl Send for Operation {}
|
||||
|
||||
impl Operation {
|
||||
pub fn new(handle: HANDLE) -> io::Result<Self> {
|
||||
let event = unsafe { CreateEventW(core::ptr::null(), 1, 0, core::ptr::null()) };
|
||||
if event.is_null() {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
let event =
|
||||
unsafe { CreateEventW(core::ptr::null(), 1, 0, core::ptr::null()) }.check_nonnull()?;
|
||||
|
||||
let mut overlapped: OVERLAPPED = unsafe { core::mem::zeroed() };
|
||||
overlapped.hEvent = event;
|
||||
@@ -177,9 +177,7 @@ impl Operation {
|
||||
self.pending = true;
|
||||
}
|
||||
ERROR_PIPE_CONNECTED => {
|
||||
if unsafe { SetEvent(self.overlapped.hEvent) } == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
unsafe { SetEvent(self.overlapped.hEvent) }.check_win32_bool()?;
|
||||
}
|
||||
_ => return Err(io::Error::from_raw_os_error(err as i32)),
|
||||
}
|
||||
@@ -792,7 +790,7 @@ pub fn start_wsa_recv_from(
|
||||
|
||||
pub fn connect_pipe(address: &str) -> io::Result<isize> {
|
||||
use windows_sys::Win32::{
|
||||
Foundation::{GENERIC_READ, GENERIC_WRITE, INVALID_HANDLE_VALUE},
|
||||
Foundation::{GENERIC_READ, GENERIC_WRITE},
|
||||
Storage::FileSystem::{CreateFileW, FILE_FLAG_OVERLAPPED, OPEN_EXISTING},
|
||||
};
|
||||
|
||||
@@ -808,11 +806,8 @@ pub fn connect_pipe(address: &str) -> io::Result<isize> {
|
||||
core::ptr::null_mut(),
|
||||
)
|
||||
};
|
||||
if handle == INVALID_HANDLE_VALUE {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(handle as isize)
|
||||
}
|
||||
let handle = handle.check_valid()?;
|
||||
Ok(handle as isize)
|
||||
}
|
||||
|
||||
pub fn create_io_completion_port(
|
||||
@@ -827,13 +822,10 @@ pub fn create_io_completion_port(
|
||||
port as HANDLE,
|
||||
key,
|
||||
concurrency,
|
||||
) as isize
|
||||
};
|
||||
if r == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(r)
|
||||
)
|
||||
}
|
||||
.check_nonnull()?;
|
||||
Ok(r as isize)
|
||||
}
|
||||
|
||||
pub fn get_queued_completion_status(port: isize, msecs: u32) -> io::Result<WaitResult> {
|
||||
@@ -876,19 +868,15 @@ pub fn post_queued_completion_status(
|
||||
key: usize,
|
||||
address: usize,
|
||||
) -> io::Result<()> {
|
||||
let ret = unsafe {
|
||||
unsafe {
|
||||
windows_sys::Win32::System::IO::PostQueuedCompletionStatus(
|
||||
port as HANDLE,
|
||||
bytes,
|
||||
key,
|
||||
address as *mut OVERLAPPED,
|
||||
)
|
||||
};
|
||||
if ret == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
.check_win32_bool()
|
||||
}
|
||||
|
||||
unsafe impl Send for WaitCallbackData {}
|
||||
@@ -974,11 +962,7 @@ pub fn unregister_wait(wait_handle: isize) -> io::Result<()> {
|
||||
let ret =
|
||||
unsafe { windows_sys::Win32::System::Threading::UnregisterWait(wait_handle as HANDLE) };
|
||||
cleanup_wait_callback_data(wait_handle);
|
||||
if ret == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
ret.check_win32_bool()
|
||||
}
|
||||
|
||||
pub fn unregister_wait_ex(wait_handle: isize, event: isize) -> io::Result<()> {
|
||||
@@ -989,11 +973,7 @@ pub fn unregister_wait_ex(wait_handle: isize, event: isize) -> io::Result<()> {
|
||||
)
|
||||
};
|
||||
cleanup_wait_callback_data(wait_handle);
|
||||
if ret == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
ret.check_win32_bool()
|
||||
}
|
||||
|
||||
pub fn bind_local(socket: isize, family: i32) -> io::Result<()> {
|
||||
|
||||
@@ -144,6 +144,36 @@ pub fn unlinkat(dir_fd: i32, path: &CStr) -> std::io::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "netbsd"))]
|
||||
pub fn lchmod(path: &CStr, mode: libc::mode_t) -> std::io::Result<()> {
|
||||
unsafe extern "C" {
|
||||
fn lchmod(path: *const libc::c_char, mode: libc::mode_t) -> libc::c_int;
|
||||
}
|
||||
if unsafe { lchmod(path.as_ptr(), mode) } == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(std::io::Error::last_os_error())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn fcopyfile(in_fd: i32, out_fd: i32, flags: u32) -> std::io::Result<()> {
|
||||
unsafe extern "C" {
|
||||
fn fcopyfile(
|
||||
in_fd: libc::c_int,
|
||||
out_fd: libc::c_int,
|
||||
state: *mut libc::c_void,
|
||||
flags: u32,
|
||||
) -> libc::c_int;
|
||||
}
|
||||
let ret = unsafe { fcopyfile(in_fd, out_fd, core::ptr::null_mut(), flags) };
|
||||
if ret < 0 {
|
||||
Err(std::io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
pub fn make_dir(path: &CStr, mode: u32) -> std::io::Result<()> {
|
||||
let ret = unsafe { libc::mkdir(path.as_ptr(), mode as _) };
|
||||
|
||||
@@ -2,31 +2,21 @@ use alloc::ffi::CString;
|
||||
use core::{ffi::CStr, time::Duration};
|
||||
use std::{ffi::OsStr, io};
|
||||
|
||||
use crate::os::CheckLibcResult;
|
||||
|
||||
pub fn make_dir(path: &CStr, mode: u32) -> io::Result<()> {
|
||||
let ret = unsafe { libc::mkdir(path.as_ptr(), mode as _) };
|
||||
if ret < 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
unsafe { libc::mkdir(path.as_ptr(), mode as _) }.check_libc_neg()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn make_dir_at(dir_fd: i32, path: &CStr, mode: u32) -> io::Result<()> {
|
||||
let ret = unsafe { libc::mkdirat(dir_fd, path.as_ptr(), mode as _) };
|
||||
if ret < 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
unsafe { libc::mkdirat(dir_fd, path.as_ptr(), mode as _) }.check_libc_neg()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_dir_at(dir_fd: i32, path: &CStr) -> io::Result<()> {
|
||||
let ret = unsafe { libc::unlinkat(dir_fd, path.as_ptr(), libc::AT_REMOVEDIR) };
|
||||
if ret < 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
unsafe { libc::unlinkat(dir_fd, path.as_ptr(), libc::AT_REMOVEDIR) }.check_libc_neg()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn stat_path(
|
||||
@@ -48,10 +38,8 @@ pub fn stat_path(
|
||||
} else {
|
||||
libc::AT_SYMLINK_NOFOLLOW
|
||||
};
|
||||
let ret = unsafe { libc::fstatat(dir_fd, path.as_ptr(), stat.as_mut_ptr(), flags) };
|
||||
if ret < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
unsafe { libc::fstatat(dir_fd, path.as_ptr(), stat.as_mut_ptr(), flags) }
|
||||
.check_libc_neg()?;
|
||||
return Ok(Some(unsafe { stat.assume_init() }));
|
||||
}
|
||||
|
||||
@@ -60,11 +48,8 @@ pub fn stat_path(
|
||||
} else {
|
||||
unsafe { libc::lstat(path.as_ptr(), stat.as_mut_ptr()) }
|
||||
};
|
||||
if ret < 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(Some(unsafe { stat.assume_init() }))
|
||||
}
|
||||
ret.check_libc_neg()?;
|
||||
Ok(Some(unsafe { stat.assume_init() }))
|
||||
}
|
||||
|
||||
pub fn stat_fd(fd: crate::crt_fd::Borrowed<'_>) -> io::Result<crate::fileutils::StatStruct> {
|
||||
@@ -83,7 +68,7 @@ pub fn set_file_times_at(
|
||||
tv_nsec: d.subsec_nanos() as _,
|
||||
};
|
||||
let times = [ts(access), ts(modified)];
|
||||
let ret = unsafe {
|
||||
unsafe {
|
||||
libc::utimensat(
|
||||
dir_fd,
|
||||
path.as_ptr(),
|
||||
@@ -94,10 +79,7 @@ pub fn set_file_times_at(
|
||||
libc::AT_SYMLINK_NOFOLLOW
|
||||
},
|
||||
)
|
||||
};
|
||||
if ret < 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
.check_libc_neg()?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
use std::io;
|
||||
|
||||
use crate::os::CheckLibcResult;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct RUsage {
|
||||
pub ru_utime: libc::timeval,
|
||||
@@ -44,35 +46,20 @@ impl From<libc::rusage> for RUsage {
|
||||
}
|
||||
|
||||
pub fn getrusage(who: i32) -> io::Result<RUsage> {
|
||||
unsafe {
|
||||
let mut rusage = core::mem::MaybeUninit::<libc::rusage>::uninit();
|
||||
if libc::getrusage(who, rusage.as_mut_ptr()) == -1 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(rusage.assume_init().into())
|
||||
}
|
||||
}
|
||||
let mut rusage = core::mem::MaybeUninit::<libc::rusage>::uninit();
|
||||
unsafe { libc::getrusage(who, rusage.as_mut_ptr()) }.check_libc_neg()?;
|
||||
Ok(unsafe { rusage.assume_init() }.into())
|
||||
}
|
||||
|
||||
pub fn getrlimit(resource: libc::rlim_t) -> io::Result<libc::rlimit> {
|
||||
unsafe {
|
||||
let mut rlimit = core::mem::MaybeUninit::<libc::rlimit>::uninit();
|
||||
if libc::getrlimit(resource as _, rlimit.as_mut_ptr()) == -1 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(rlimit.assume_init())
|
||||
}
|
||||
}
|
||||
let mut rlimit = core::mem::MaybeUninit::<libc::rlimit>::uninit();
|
||||
unsafe { libc::getrlimit(resource as _, rlimit.as_mut_ptr()) }.check_libc_neg()?;
|
||||
Ok(unsafe { rlimit.assume_init() })
|
||||
}
|
||||
|
||||
pub fn setrlimit(resource: libc::rlim_t, limits: libc::rlimit) -> io::Result<()> {
|
||||
unsafe {
|
||||
if libc::setrlimit(resource as _, &limits) == -1 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
unsafe { libc::setrlimit(resource as _, &limits) }.check_libc_neg()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
|
||||
|
||||
@@ -1,23 +1,16 @@
|
||||
use core::ffi::CStr;
|
||||
use std::io;
|
||||
|
||||
use crate::os::CheckLibcResult;
|
||||
|
||||
pub fn shm_open(name: &CStr, flags: libc::c_int, mode: libc::c_uint) -> io::Result<libc::c_int> {
|
||||
#[cfg(target_os = "freebsd")]
|
||||
let mode = mode.try_into().unwrap();
|
||||
|
||||
let fd = unsafe { libc::shm_open(name.as_ptr(), flags, mode) };
|
||||
if fd == -1 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(fd)
|
||||
}
|
||||
unsafe { libc::shm_open(name.as_ptr(), flags, mode) }.check_libc_neg()
|
||||
}
|
||||
|
||||
pub fn shm_unlink(name: &CStr) -> io::Result<()> {
|
||||
let ret = unsafe { libc::shm_unlink(name.as_ptr()) };
|
||||
if ret == -1 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
unsafe { libc::shm_unlink(name.as_ptr()) }.check_libc_neg()?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -2,6 +2,11 @@ use std::io;
|
||||
#[cfg(windows)]
|
||||
use std::sync::Once;
|
||||
|
||||
#[cfg(unix)]
|
||||
use crate::os::CheckLibcResult;
|
||||
#[cfg(any(unix, windows))]
|
||||
use crate::os::CheckLibcZero;
|
||||
|
||||
#[cfg(any(unix, windows))]
|
||||
pub use libc::sighandler_t;
|
||||
|
||||
@@ -81,12 +86,7 @@ pub unsafe fn install_handler(signalnum: i32, handler: sighandler_t) -> io::Resu
|
||||
|
||||
#[cfg(any(unix, windows))]
|
||||
pub fn raise_signal(signalnum: i32) -> io::Result<()> {
|
||||
let res = unsafe { libc::raise(signalnum) };
|
||||
if res != 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
unsafe { libc::raise(signalnum) }.check_libc_zero()
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -104,21 +104,13 @@ pub fn set_sigint_default_onstack() -> io::Result<()> {
|
||||
let mut action: libc::sigaction = unsafe { core::mem::zeroed() };
|
||||
action.sa_sigaction = libc::SIG_DFL;
|
||||
action.sa_flags = libc::SA_ONSTACK;
|
||||
if unsafe { libc::sigemptyset(&mut action.sa_mask) } != 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
if unsafe { libc::sigaction(libc::SIGINT, &action, core::ptr::null_mut()) } != 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
Ok(())
|
||||
unsafe { libc::sigemptyset(&mut action.sa_mask) }.check_libc_zero()?;
|
||||
unsafe { libc::sigaction(libc::SIGINT, &action, core::ptr::null_mut()) }.check_libc_zero()
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn send_sigint_to_self() -> io::Result<()> {
|
||||
if unsafe { libc::kill(libc::getpid(), libc::SIGINT) } != 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
Ok(())
|
||||
unsafe { libc::kill(libc::getpid(), libc::SIGINT) }.check_libc_zero()
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -128,11 +120,8 @@ pub fn setitimer(which: i32, new: &libc::itimerval) -> io::Result<libc::itimerva
|
||||
let ret = unsafe { ffi::setitimer(which, new, old.as_mut_ptr()) };
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
let ret = unsafe { libc::setitimer(which, new, old.as_mut_ptr()) };
|
||||
if ret != 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(unsafe { old.assume_init() })
|
||||
}
|
||||
ret.check_libc_zero()?;
|
||||
Ok(unsafe { old.assume_init() })
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -142,30 +131,20 @@ pub fn getitimer(which: i32) -> io::Result<libc::itimerval> {
|
||||
let ret = unsafe { ffi::getitimer(which, old.as_mut_ptr()) };
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
let ret = unsafe { libc::getitimer(which, old.as_mut_ptr()) };
|
||||
if ret != 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(unsafe { old.assume_init() })
|
||||
}
|
||||
ret.check_libc_zero()?;
|
||||
Ok(unsafe { old.assume_init() })
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn sigemptyset() -> io::Result<libc::sigset_t> {
|
||||
let mut set: libc::sigset_t = unsafe { core::mem::zeroed() };
|
||||
if unsafe { libc::sigemptyset(&mut set) } != 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(set)
|
||||
}
|
||||
unsafe { libc::sigemptyset(&mut set) }.check_libc_zero()?;
|
||||
Ok(set)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn sigaddset(set: &mut libc::sigset_t, signum: i32) -> io::Result<()> {
|
||||
if unsafe { libc::sigaddset(set, signum) } != 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
unsafe { libc::sigaddset(set, signum) }.check_libc_zero()
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -190,21 +169,14 @@ pub fn pidfd_send_signal(pidfd: i32, sig: i32, flags: u32) -> io::Result<()> {
|
||||
flags,
|
||||
) as libc::c_long
|
||||
};
|
||||
if ret == -1 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
ret.check_libc_neg()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(target_os = "redox")))]
|
||||
pub fn siginterrupt(signalnum: i32, flag: i32) -> io::Result<()> {
|
||||
let res = unsafe { c_siginterrupt(signalnum, flag) };
|
||||
if res < 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
unsafe { c_siginterrupt(signalnum, flag) }.check_libc_neg()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
@@ -349,9 +321,7 @@ pub fn strsignal(signalnum: i32) -> Option<String> {
|
||||
#[cfg(unix)]
|
||||
pub fn valid_signals(max_signum: usize) -> io::Result<Vec<i32>> {
|
||||
let mut mask: libc::sigset_t = unsafe { core::mem::zeroed() };
|
||||
if unsafe { libc::sigfillset(&mut mask) } != 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
unsafe { libc::sigfillset(&mut mask) }.check_libc_zero()?;
|
||||
let mut signals = Vec::new();
|
||||
for signum in 1..max_signum {
|
||||
if unsafe { libc::sigismember(&mask, signum as i32) } == 1 {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#[cfg(unix)]
|
||||
use crate::os::CheckLibcResult;
|
||||
#[cfg(unix)]
|
||||
use core::ffi::CStr;
|
||||
#[cfg(unix)]
|
||||
use core::time::Duration;
|
||||
@@ -36,7 +38,7 @@ pub fn close_socket_ignore_connreset(socket: libc::c_int) -> io::Result<()> {
|
||||
pub fn getsockopt_int(fd: libc::c_int, level: i32, name: i32) -> io::Result<i32> {
|
||||
let mut flag: libc::c_int = 0;
|
||||
let mut flagsize = core::mem::size_of::<libc::c_int>() as libc::socklen_t;
|
||||
let ret = unsafe {
|
||||
unsafe {
|
||||
libc::getsockopt(
|
||||
fd,
|
||||
level,
|
||||
@@ -44,12 +46,9 @@ pub fn getsockopt_int(fd: libc::c_int, level: i32, name: i32) -> io::Result<i32>
|
||||
&mut flag as *mut libc::c_int as *mut _,
|
||||
&mut flagsize,
|
||||
)
|
||||
};
|
||||
if ret < 0 {
|
||||
Err(crate::os::errno_io_error())
|
||||
} else {
|
||||
Ok(flag)
|
||||
}
|
||||
.check_libc_neg()?;
|
||||
Ok(flag)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -61,18 +60,15 @@ pub fn getsockopt_bytes(
|
||||
) -> io::Result<Vec<u8>> {
|
||||
let mut buf = vec![0u8; buflen];
|
||||
let mut optlen = buflen as libc::socklen_t;
|
||||
let ret = unsafe { libc::getsockopt(fd, level, name, buf.as_mut_ptr() as *mut _, &mut optlen) };
|
||||
if ret < 0 {
|
||||
Err(crate::os::errno_io_error())
|
||||
} else {
|
||||
buf.truncate(optlen as usize);
|
||||
Ok(buf)
|
||||
}
|
||||
unsafe { libc::getsockopt(fd, level, name, buf.as_mut_ptr() as *mut _, &mut optlen) }
|
||||
.check_libc_neg()?;
|
||||
buf.truncate(optlen as usize);
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn setsockopt_bytes(fd: libc::c_int, level: i32, name: i32, value: &[u8]) -> io::Result<()> {
|
||||
let ret = unsafe {
|
||||
unsafe {
|
||||
libc::setsockopt(
|
||||
fd,
|
||||
level,
|
||||
@@ -80,17 +76,14 @@ pub fn setsockopt_bytes(fd: libc::c_int, level: i32, name: i32, value: &[u8]) ->
|
||||
value.as_ptr() as *const _,
|
||||
value.len() as libc::socklen_t,
|
||||
)
|
||||
};
|
||||
if ret < 0 {
|
||||
Err(crate::os::errno_io_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
.check_libc_neg()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn setsockopt_int(fd: libc::c_int, level: i32, name: i32, value: i32) -> io::Result<()> {
|
||||
let ret = unsafe {
|
||||
unsafe {
|
||||
libc::setsockopt(
|
||||
fd,
|
||||
level,
|
||||
@@ -98,17 +91,14 @@ pub fn setsockopt_int(fd: libc::c_int, level: i32, name: i32, value: i32) -> io:
|
||||
&value as *const i32 as *const _,
|
||||
core::mem::size_of::<i32>() as libc::socklen_t,
|
||||
)
|
||||
};
|
||||
if ret < 0 {
|
||||
Err(crate::os::errno_io_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
.check_libc_neg()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn setsockopt_none(fd: libc::c_int, level: i32, name: i32, optlen: u32) -> io::Result<()> {
|
||||
let ret = unsafe {
|
||||
unsafe {
|
||||
libc::setsockopt(
|
||||
fd,
|
||||
level,
|
||||
@@ -116,12 +106,9 @@ pub fn setsockopt_none(fd: libc::c_int, level: i32, name: i32, optlen: u32) -> i
|
||||
core::ptr::null(),
|
||||
optlen as libc::socklen_t,
|
||||
)
|
||||
};
|
||||
if ret < 0 {
|
||||
Err(crate::os::errno_io_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
.check_libc_neg()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -367,10 +354,7 @@ pub fn recvmsg(
|
||||
msg.msg_controllen = ancbufsize as _;
|
||||
}
|
||||
|
||||
let ret = unsafe { libc::recvmsg(fd.as_raw_fd(), &mut msg, flags) };
|
||||
if ret < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
let ret = unsafe { libc::recvmsg(fd.as_raw_fd(), &mut msg, flags) }.check_libc_neg()?;
|
||||
|
||||
let data = unsafe {
|
||||
data_buf.set_len(ret as usize);
|
||||
@@ -477,12 +461,8 @@ pub fn sendmsg_afalg(
|
||||
msghdr.msg_controllen = control_buf.len() as _;
|
||||
}
|
||||
|
||||
let ret = unsafe { libc::sendmsg(fd.as_raw_fd(), &msghdr, flags) };
|
||||
if ret < 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(ret as usize)
|
||||
}
|
||||
let ret = unsafe { libc::sendmsg(fd.as_raw_fd(), &msghdr, flags) }.check_libc_neg()?;
|
||||
Ok(ret as usize)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
use std::io;
|
||||
use windows_sys::Win32::{
|
||||
Foundation::{HANDLE, INVALID_HANDLE_VALUE},
|
||||
Foundation::HANDLE,
|
||||
System::Console::{INPUT_RECORD, KEY_EVENT, WriteConsoleInputW},
|
||||
};
|
||||
|
||||
use crate::windows::{CheckWin32Bool, CheckWin32Handle};
|
||||
|
||||
pub fn write_console_input(fd: i32, data: &[u16]) -> io::Result<()> {
|
||||
let handle = unsafe { libc::get_osfhandle(fd) } as HANDLE;
|
||||
if handle == INVALID_HANDLE_VALUE {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
let handle = (unsafe { libc::get_osfhandle(fd) } as HANDLE).check_valid()?;
|
||||
|
||||
let size = data.len() as u32;
|
||||
let mut records: Vec<INPUT_RECORD> = Vec::with_capacity(data.len());
|
||||
@@ -24,17 +23,15 @@ pub fn write_console_input(fd: i32, data: &[u16]) -> io::Result<()> {
|
||||
let mut total: u32 = 0;
|
||||
while total < size {
|
||||
let mut wrote: u32 = 0;
|
||||
let res = unsafe {
|
||||
unsafe {
|
||||
WriteConsoleInputW(
|
||||
handle,
|
||||
records[total as usize..].as_ptr(),
|
||||
size - total,
|
||||
&mut wrote,
|
||||
)
|
||||
};
|
||||
if res == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
.check_win32_bool()?;
|
||||
if wrote == 0 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::WriteZero,
|
||||
|
||||
@@ -15,6 +15,54 @@ pub const SEC_TO_NS: i64 = SEC_TO_MS * MS_TO_NS;
|
||||
pub const NS_TO_MS: i64 = 1000 * 1000;
|
||||
pub const NS_TO_US: i64 = 1000;
|
||||
|
||||
/// Access to the C runtime's `tzset` / `timezone` / `daylight` / `tzname`
|
||||
/// globals used by Python's `time` module.
|
||||
///
|
||||
/// Not available under MSVC (which exposes these only via the
|
||||
/// `_get_tzname`-style helpers) or on `wasm32` (no libc tz state).
|
||||
#[cfg(all(not(target_env = "msvc"), not(target_arch = "wasm32")))]
|
||||
pub mod tz {
|
||||
unsafe extern "C" {
|
||||
#[cfg(not(target_os = "freebsd"))]
|
||||
#[link_name = "daylight"]
|
||||
static c_daylight: core::ffi::c_int;
|
||||
#[link_name = "timezone"]
|
||||
static c_timezone: core::ffi::c_long;
|
||||
#[link_name = "tzname"]
|
||||
static c_tzname: [*const core::ffi::c_char; 2];
|
||||
#[link_name = "tzset"]
|
||||
fn c_tzset();
|
||||
}
|
||||
|
||||
pub fn tzset() {
|
||||
unsafe { c_tzset() }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn timezone() -> core::ffi::c_long {
|
||||
unsafe { c_timezone }
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "freebsd"))]
|
||||
#[must_use]
|
||||
pub fn daylight() -> core::ffi::c_int {
|
||||
unsafe { c_daylight }
|
||||
}
|
||||
|
||||
/// Snapshot of `tzname[0]` / `tzname[1]` as owned `String`s.
|
||||
/// Reads the C globals once and copies the bytes out so callers don't
|
||||
/// have to handle the raw pointers themselves.
|
||||
#[must_use]
|
||||
pub fn tzname_strings() -> (String, String) {
|
||||
unsafe fn to_str(s: *const core::ffi::c_char) -> String {
|
||||
unsafe { core::ffi::CStr::from_ptr(s) }
|
||||
.to_string_lossy()
|
||||
.into_owned()
|
||||
}
|
||||
unsafe { (to_str(c_tzname[0]), to_str(c_tzname[1])) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn duration_since_system_now() -> Result<Duration, SystemTimeError> {
|
||||
SystemTime::now().duration_since(UNIX_EPOCH)
|
||||
}
|
||||
|
||||
+155
-196
@@ -9,6 +9,8 @@ use windows_sys::Win32::{
|
||||
System::Threading::PROCESS_INFORMATION,
|
||||
};
|
||||
|
||||
use crate::windows::{CheckWin32Bool, CheckWin32Handle};
|
||||
|
||||
pub use windows_sys::Win32::{
|
||||
Foundation::{
|
||||
DUPLICATE_CLOSE_SOURCE, DUPLICATE_SAME_ACCESS, ERROR_ACCESS_DENIED, ERROR_ALREADY_EXISTS,
|
||||
@@ -163,7 +165,7 @@ impl Drop for AttrList {
|
||||
}
|
||||
|
||||
pub fn create_file_w(
|
||||
file_name: *const u16,
|
||||
file_name: &widestring::WideCStr,
|
||||
desired_access: u32,
|
||||
share_mode: u32,
|
||||
creation_disposition: u32,
|
||||
@@ -171,7 +173,7 @@ pub fn create_file_w(
|
||||
) -> io::Result<HANDLE> {
|
||||
let handle = unsafe {
|
||||
windows_sys::Win32::Storage::FileSystem::CreateFileW(
|
||||
file_name,
|
||||
file_name.as_ptr(),
|
||||
desired_access,
|
||||
share_mode,
|
||||
core::ptr::null(),
|
||||
@@ -180,43 +182,67 @@ pub fn create_file_w(
|
||||
core::ptr::null_mut(),
|
||||
)
|
||||
};
|
||||
if handle == windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(handle)
|
||||
}
|
||||
handle.check_valid()
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// The pointer arguments must follow the Win32 `CreateProcessW` contract.
|
||||
pub unsafe fn create_process_w(
|
||||
app_name: *const u16,
|
||||
command_line: *mut u16,
|
||||
/// `startup_info` must point to a valid `STARTUPINFOW` (or extended).
|
||||
unsafe fn create_process_w_raw(
|
||||
app_name: Option<&widestring::WideCStr>,
|
||||
command_line: Option<&mut [u16]>,
|
||||
inherit_handles: i32,
|
||||
creation_flags: u32,
|
||||
env: *mut u16,
|
||||
current_dir: *mut u16,
|
||||
env: Option<&[u16]>,
|
||||
current_dir: Option<&widestring::WideCStr>,
|
||||
startup_info: *mut windows_sys::Win32::System::Threading::STARTUPINFOW,
|
||||
) -> io::Result<PROCESS_INFORMATION> {
|
||||
let mut procinfo = core::mem::MaybeUninit::<PROCESS_INFORMATION>::uninit();
|
||||
let ok = unsafe {
|
||||
unsafe {
|
||||
windows_sys::Win32::System::Threading::CreateProcessW(
|
||||
app_name,
|
||||
command_line,
|
||||
app_name.map_or(core::ptr::null(), |s| s.as_ptr()),
|
||||
command_line.map_or(core::ptr::null_mut(), |s| s.as_mut_ptr()),
|
||||
core::ptr::null(),
|
||||
core::ptr::null(),
|
||||
inherit_handles,
|
||||
creation_flags,
|
||||
env.cast(),
|
||||
current_dir,
|
||||
env.map_or(core::ptr::null(), |s| s.as_ptr().cast()),
|
||||
current_dir.map_or(core::ptr::null(), |s| s.as_ptr()),
|
||||
startup_info,
|
||||
procinfo.as_mut_ptr(),
|
||||
)
|
||||
};
|
||||
if ok == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
}
|
||||
.check_win32_bool()?;
|
||||
Ok(unsafe { procinfo.assume_init() })
|
||||
}
|
||||
|
||||
/// Win32 `CreateProcessW` requires `lpCommandLine` to be NUL-terminated.
|
||||
/// The buffer is passed `&mut [u16]` because `CreateProcessW` may modify it
|
||||
/// in place.
|
||||
#[inline]
|
||||
fn validate_command_line_terminated(buf: &[u16]) -> io::Result<()> {
|
||||
if buf.last() == Some(&0) {
|
||||
Ok(())
|
||||
} else {
|
||||
Ok(unsafe { procinfo.assume_init() })
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"command_line buffer passed to create_process must be NUL-terminated",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Win32 `CreateProcessW` with `CREATE_UNICODE_ENVIRONMENT` requires
|
||||
/// `lpEnvironment` to be a sequence of `KEY=value\0` strings followed by a
|
||||
/// final terminating `\0` — i.e. the block ends with two consecutive zero
|
||||
/// `u16`s.
|
||||
#[inline]
|
||||
fn validate_environment_block_terminated(buf: &[u16]) -> io::Result<()> {
|
||||
if buf.len() >= 2 && buf[buf.len() - 2..] == [0, 0] {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"env block passed to create_process must end with a double NUL terminator",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,15 +251,22 @@ pub unsafe fn create_process_w(
|
||||
reason = "This is the semantic host wrapper for Win32 CreateProcess parameters."
|
||||
)]
|
||||
pub fn create_process(
|
||||
app_name: *const u16,
|
||||
command_line: *mut u16,
|
||||
app_name: Option<&widestring::WideCStr>,
|
||||
command_line: Option<&mut [u16]>,
|
||||
inherit_handles: i32,
|
||||
creation_flags: u32,
|
||||
env: *mut u16,
|
||||
current_dir: *mut u16,
|
||||
env: Option<&[u16]>,
|
||||
current_dir: Option<&widestring::WideCStr>,
|
||||
startup_info: StartupInfoData,
|
||||
handle_list: Option<Vec<usize>>,
|
||||
) -> io::Result<ProcessInfo> {
|
||||
if let Some(cmd) = command_line.as_deref() {
|
||||
validate_command_line_terminated(cmd)?;
|
||||
}
|
||||
if let Some(env_block) = env {
|
||||
validate_environment_block_terminated(env_block)?;
|
||||
}
|
||||
|
||||
let mut si: windows_sys::Win32::System::Threading::STARTUPINFOEXW =
|
||||
unsafe { core::mem::zeroed() };
|
||||
si.StartupInfo.cb = core::mem::size_of_val(&si) as _;
|
||||
@@ -249,7 +282,7 @@ pub fn create_process(
|
||||
.map_or_else(core::ptr::null_mut, |l| l.as_mut_ptr() as _);
|
||||
|
||||
let procinfo = unsafe {
|
||||
create_process_w(
|
||||
create_process_w_raw(
|
||||
app_name,
|
||||
command_line,
|
||||
inherit_handles,
|
||||
@@ -335,19 +368,17 @@ pub fn create_handle_list_attribute_list(
|
||||
handlelist,
|
||||
attrlist: vec![0u8; size],
|
||||
};
|
||||
let ok = unsafe {
|
||||
unsafe {
|
||||
windows_sys::Win32::System::Threading::InitializeProcThreadAttributeList(
|
||||
attrs.attrlist.as_mut_ptr().cast(),
|
||||
1,
|
||||
0,
|
||||
&mut size,
|
||||
)
|
||||
};
|
||||
if ok == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
.check_win32_bool()?;
|
||||
|
||||
let ok = unsafe {
|
||||
unsafe {
|
||||
windows_sys::Win32::System::Threading::UpdateProcThreadAttribute(
|
||||
attrs.attrlist.as_mut_ptr().cast(),
|
||||
0,
|
||||
@@ -357,10 +388,8 @@ pub fn create_handle_list_attribute_list(
|
||||
core::ptr::null_mut(),
|
||||
core::ptr::null(),
|
||||
)
|
||||
};
|
||||
if ok == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
.check_win32_bool()?;
|
||||
|
||||
Ok(Some(attrs))
|
||||
}
|
||||
@@ -381,74 +410,54 @@ pub fn open_process(
|
||||
inherit_handle: bool,
|
||||
process_id: u32,
|
||||
) -> io::Result<HANDLE> {
|
||||
let handle = unsafe {
|
||||
unsafe {
|
||||
windows_sys::Win32::System::Threading::OpenProcess(
|
||||
desired_access,
|
||||
i32::from(inherit_handle),
|
||||
process_id,
|
||||
)
|
||||
};
|
||||
if handle.is_null() {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(handle)
|
||||
}
|
||||
.check_nonnull()
|
||||
}
|
||||
|
||||
pub fn create_pipe(size: u32) -> io::Result<(HANDLE, HANDLE)> {
|
||||
let (read, write) = unsafe {
|
||||
unsafe {
|
||||
let mut read = core::mem::MaybeUninit::<HANDLE>::uninit();
|
||||
let mut write = core::mem::MaybeUninit::<HANDLE>::uninit();
|
||||
let ok = windows_sys::Win32::System::Pipes::CreatePipe(
|
||||
windows_sys::Win32::System::Pipes::CreatePipe(
|
||||
read.as_mut_ptr(),
|
||||
write.as_mut_ptr(),
|
||||
core::ptr::null(),
|
||||
size,
|
||||
);
|
||||
if ok == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
(read.assume_init(), write.assume_init())
|
||||
};
|
||||
Ok((read, write))
|
||||
)
|
||||
.check_win32_bool()?;
|
||||
Ok((read.assume_init(), write.assume_init()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_event_w(
|
||||
manual_reset: bool,
|
||||
initial_state: bool,
|
||||
name: *const u16,
|
||||
name: Option<&widestring::WideCStr>,
|
||||
) -> io::Result<HANDLE> {
|
||||
let handle = unsafe {
|
||||
let name_ptr = name.map_or(core::ptr::null(), |n| n.as_ptr());
|
||||
unsafe {
|
||||
windows_sys::Win32::System::Threading::CreateEventW(
|
||||
core::ptr::null(),
|
||||
i32::from(manual_reset),
|
||||
i32::from(initial_state),
|
||||
name,
|
||||
name_ptr,
|
||||
)
|
||||
};
|
||||
if handle.is_null() {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(handle)
|
||||
}
|
||||
.check_nonnull()
|
||||
}
|
||||
|
||||
pub fn set_event(handle: HANDLE) -> io::Result<()> {
|
||||
let ok = unsafe { windows_sys::Win32::System::Threading::SetEvent(handle) };
|
||||
if ok == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
unsafe { windows_sys::Win32::System::Threading::SetEvent(handle) }.check_win32_bool()
|
||||
}
|
||||
|
||||
pub fn reset_event(handle: HANDLE) -> io::Result<()> {
|
||||
let ok = unsafe { windows_sys::Win32::System::Threading::ResetEvent(handle) };
|
||||
if ok == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
unsafe { windows_sys::Win32::System::Threading::ResetEvent(handle) }.check_win32_bool()
|
||||
}
|
||||
|
||||
pub fn wait_for_single_object(handle: HANDLE, milliseconds: u32) -> io::Result<u32> {
|
||||
@@ -566,7 +575,7 @@ pub fn batched_wait_for_multiple_objects(
|
||||
};
|
||||
}
|
||||
|
||||
let cancel_event = create_event_w(true, false, core::ptr::null())
|
||||
let cancel_event = create_event_w(true, false, None)
|
||||
.map_err(|err| BatchedWaitError::Os(err.raw_os_error().unwrap_or_default() as u32))?;
|
||||
|
||||
struct BatchData {
|
||||
@@ -761,14 +770,11 @@ pub fn get_current_process() -> HANDLE {
|
||||
|
||||
pub fn get_exit_code_process(handle: HANDLE) -> io::Result<u32> {
|
||||
let mut exit_code = core::mem::MaybeUninit::<u32>::uninit();
|
||||
let ok = unsafe {
|
||||
unsafe {
|
||||
windows_sys::Win32::System::Threading::GetExitCodeProcess(handle, exit_code.as_mut_ptr())
|
||||
};
|
||||
if ok == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(unsafe { exit_code.assume_init() })
|
||||
}
|
||||
.check_win32_bool()?;
|
||||
Ok(unsafe { exit_code.assume_init() })
|
||||
}
|
||||
|
||||
pub fn get_file_type(handle: HANDLE) -> io::Result<FileType> {
|
||||
@@ -798,34 +804,20 @@ pub fn get_version() -> u32 {
|
||||
unsafe { windows_sys::Win32::System::SystemInformation::GetVersion() }
|
||||
}
|
||||
|
||||
pub fn create_job_object_w(name: *const u16) -> io::Result<HANDLE> {
|
||||
let handle = unsafe {
|
||||
windows_sys::Win32::System::JobObjects::CreateJobObjectW(core::ptr::null(), name)
|
||||
};
|
||||
if handle.is_null() {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(handle)
|
||||
}
|
||||
pub fn create_job_object_w(name: Option<&widestring::WideCStr>) -> io::Result<HANDLE> {
|
||||
let name_ptr = name.map_or(core::ptr::null(), |n| n.as_ptr());
|
||||
unsafe { windows_sys::Win32::System::JobObjects::CreateJobObjectW(core::ptr::null(), name_ptr) }
|
||||
.check_nonnull()
|
||||
}
|
||||
|
||||
pub fn assign_process_to_job_object(job: HANDLE, process: HANDLE) -> io::Result<()> {
|
||||
let ok =
|
||||
unsafe { windows_sys::Win32::System::JobObjects::AssignProcessToJobObject(job, process) };
|
||||
if ok == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
unsafe { windows_sys::Win32::System::JobObjects::AssignProcessToJobObject(job, process) }
|
||||
.check_win32_bool()
|
||||
}
|
||||
|
||||
pub fn terminate_job_object(job: HANDLE, exit_code: u32) -> io::Result<()> {
|
||||
let ok = unsafe { windows_sys::Win32::System::JobObjects::TerminateJobObject(job, exit_code) };
|
||||
if ok == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
unsafe { windows_sys::Win32::System::JobObjects::TerminateJobObject(job, exit_code) }
|
||||
.check_win32_bool()
|
||||
}
|
||||
|
||||
pub fn set_job_object_kill_on_close(job: HANDLE) -> io::Result<()> {
|
||||
@@ -836,19 +828,15 @@ pub fn set_job_object_kill_on_close(job: HANDLE) -> io::Result<()> {
|
||||
|
||||
let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION = unsafe { core::mem::zeroed() };
|
||||
info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
|
||||
let ok = unsafe {
|
||||
unsafe {
|
||||
SetInformationJobObject(
|
||||
job,
|
||||
JobObjectExtendedLimitInformation,
|
||||
(&info as *const JOBOBJECT_EXTENDED_LIMIT_INFORMATION).cast(),
|
||||
core::mem::size_of::<JOBOBJECT_EXTENDED_LIMIT_INFORMATION>() as u32,
|
||||
)
|
||||
};
|
||||
if ok == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
.check_win32_bool()
|
||||
}
|
||||
|
||||
pub fn get_module_file_name(module: HMODULE, buffer: &mut [u16]) -> u32 {
|
||||
@@ -861,14 +849,14 @@ pub fn get_module_file_name(module: HMODULE, buffer: &mut [u16]) -> u32 {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_short_path_name_w(path: *const u16) -> io::Result<Vec<u16>> {
|
||||
pub fn get_short_path_name_w(path: &widestring::WideCStr) -> io::Result<Vec<u16>> {
|
||||
get_path_name_impl(
|
||||
path,
|
||||
windows_sys::Win32::Storage::FileSystem::GetShortPathNameW,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_long_path_name_w(path: *const u16) -> io::Result<Vec<u16>> {
|
||||
pub fn get_long_path_name_w(path: &widestring::WideCStr) -> io::Result<Vec<u16>> {
|
||||
get_path_name_impl(
|
||||
path,
|
||||
windows_sys::Win32::Storage::FileSystem::GetLongPathNameW,
|
||||
@@ -876,16 +864,16 @@ pub fn get_long_path_name_w(path: *const u16) -> io::Result<Vec<u16>> {
|
||||
}
|
||||
|
||||
fn get_path_name_impl(
|
||||
path: *const u16,
|
||||
path: &widestring::WideCStr,
|
||||
api_fn: unsafe extern "system" fn(*const u16, *mut u16, u32) -> u32,
|
||||
) -> io::Result<Vec<u16>> {
|
||||
let size = unsafe { api_fn(path, core::ptr::null_mut(), 0) };
|
||||
let size = unsafe { api_fn(path.as_ptr(), core::ptr::null_mut(), 0) };
|
||||
if size == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
let mut buffer = vec![0u16; size as usize];
|
||||
let result = unsafe { api_fn(path, buffer.as_mut_ptr(), buffer.len() as u32) };
|
||||
let result = unsafe { api_fn(path.as_ptr(), buffer.as_mut_ptr(), buffer.len() as u32) };
|
||||
if result == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
@@ -896,20 +884,16 @@ fn get_path_name_impl(
|
||||
pub fn open_mutex_w(
|
||||
desired_access: u32,
|
||||
inherit_handle: bool,
|
||||
name: *const u16,
|
||||
name: &widestring::WideCStr,
|
||||
) -> io::Result<HANDLE> {
|
||||
let handle = unsafe {
|
||||
unsafe {
|
||||
windows_sys::Win32::System::Threading::OpenMutexW(
|
||||
desired_access,
|
||||
i32::from(inherit_handle),
|
||||
name,
|
||||
name.as_ptr(),
|
||||
)
|
||||
};
|
||||
if handle.is_null() {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(handle)
|
||||
}
|
||||
.check_nonnull()
|
||||
}
|
||||
|
||||
pub fn release_mutex(handle: HANDLE) -> i32 {
|
||||
@@ -917,7 +901,7 @@ pub fn release_mutex(handle: HANDLE) -> i32 {
|
||||
}
|
||||
|
||||
pub fn create_named_pipe_w(
|
||||
name: *const u16,
|
||||
name: &widestring::WideCStr,
|
||||
open_mode: u32,
|
||||
pipe_mode: u32,
|
||||
max_instances: u32,
|
||||
@@ -925,9 +909,9 @@ pub fn create_named_pipe_w(
|
||||
in_buffer_size: u32,
|
||||
default_timeout: u32,
|
||||
) -> io::Result<HANDLE> {
|
||||
let handle = unsafe {
|
||||
unsafe {
|
||||
windows_sys::Win32::System::Pipes::CreateNamedPipeW(
|
||||
name,
|
||||
name.as_ptr(),
|
||||
open_mode,
|
||||
pipe_mode,
|
||||
max_instances,
|
||||
@@ -936,12 +920,8 @@ pub fn create_named_pipe_w(
|
||||
default_timeout,
|
||||
core::ptr::null(),
|
||||
)
|
||||
};
|
||||
if handle == windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(handle)
|
||||
}
|
||||
.check_valid()
|
||||
}
|
||||
|
||||
pub fn create_file_mapping_w(
|
||||
@@ -949,42 +929,35 @@ pub fn create_file_mapping_w(
|
||||
protect: u32,
|
||||
max_size_high: u32,
|
||||
max_size_low: u32,
|
||||
name: *const u16,
|
||||
name: Option<&widestring::WideCStr>,
|
||||
) -> io::Result<HANDLE> {
|
||||
let handle = unsafe {
|
||||
let name_ptr = name.map_or(core::ptr::null(), |n| n.as_ptr());
|
||||
unsafe {
|
||||
windows_sys::Win32::System::Memory::CreateFileMappingW(
|
||||
file_handle,
|
||||
core::ptr::null(),
|
||||
protect,
|
||||
max_size_high,
|
||||
max_size_low,
|
||||
name,
|
||||
name_ptr,
|
||||
)
|
||||
};
|
||||
if handle.is_null() {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(handle)
|
||||
}
|
||||
.check_nonnull()
|
||||
}
|
||||
|
||||
pub fn open_file_mapping_w(
|
||||
desired_access: u32,
|
||||
inherit_handle: bool,
|
||||
name: *const u16,
|
||||
name: &widestring::WideCStr,
|
||||
) -> io::Result<HANDLE> {
|
||||
let handle = unsafe {
|
||||
unsafe {
|
||||
windows_sys::Win32::System::Memory::OpenFileMappingW(
|
||||
desired_access,
|
||||
i32::from(inherit_handle),
|
||||
name,
|
||||
name.as_ptr(),
|
||||
)
|
||||
};
|
||||
if handle.is_null() {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(handle)
|
||||
}
|
||||
.check_nonnull()
|
||||
}
|
||||
|
||||
pub fn map_view_of_file(
|
||||
@@ -1015,12 +988,7 @@ pub fn unmap_view_of_file(address: isize) -> io::Result<()> {
|
||||
let view = windows_sys::Win32::System::Memory::MEMORY_MAPPED_VIEW_ADDRESS {
|
||||
Value: address as *mut core::ffi::c_void,
|
||||
};
|
||||
let ok = unsafe { windows_sys::Win32::System::Memory::UnmapViewOfFile(view) };
|
||||
if ok == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
unsafe { windows_sys::Win32::System::Memory::UnmapViewOfFile(view) }.check_win32_bool()
|
||||
}
|
||||
|
||||
pub fn virtual_query_size(address: isize) -> io::Result<usize> {
|
||||
@@ -1040,13 +1008,19 @@ pub fn virtual_query_size(address: isize) -> io::Result<usize> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn copy_file2(src: *const u16, dst: *const u16, flags: u32) -> io::Result<()> {
|
||||
pub fn copy_file2(
|
||||
src: &widestring::WideCStr,
|
||||
dst: &widestring::WideCStr,
|
||||
flags: u32,
|
||||
) -> io::Result<()> {
|
||||
let mut params: windows_sys::Win32::Storage::FileSystem::COPYFILE2_EXTENDED_PARAMETERS =
|
||||
unsafe { core::mem::zeroed() };
|
||||
params.dwSize = core::mem::size_of_val(¶ms) as u32;
|
||||
params.dwCopyFlags = flags;
|
||||
|
||||
let hr = unsafe { windows_sys::Win32::Storage::FileSystem::CopyFile2(src, dst, ¶ms) };
|
||||
let hr = unsafe {
|
||||
windows_sys::Win32::Storage::FileSystem::CopyFile2(src.as_ptr(), dst.as_ptr(), ¶ms)
|
||||
};
|
||||
if hr < 0 {
|
||||
let err = if (hr as u32 >> 16) == 0x8007 {
|
||||
(hr as u32) & 0xFFFF
|
||||
@@ -1161,16 +1135,16 @@ where
|
||||
}
|
||||
|
||||
pub fn lc_map_string_ex(
|
||||
locale: *const u16,
|
||||
locale: &widestring::WideCStr,
|
||||
flags: u32,
|
||||
src: *const u16,
|
||||
src_len: i32,
|
||||
src: &[u16],
|
||||
) -> io::Result<Vec<u16>> {
|
||||
let src_len = src.len() as i32;
|
||||
let dest_size = unsafe {
|
||||
windows_sys::Win32::Globalization::LCMapStringEx(
|
||||
locale,
|
||||
locale.as_ptr(),
|
||||
flags,
|
||||
src,
|
||||
src.as_ptr(),
|
||||
src_len,
|
||||
core::ptr::null_mut(),
|
||||
0,
|
||||
@@ -1186,9 +1160,9 @@ pub fn lc_map_string_ex(
|
||||
let mut dest = vec![0u16; dest_size as usize];
|
||||
let nmapped = unsafe {
|
||||
windows_sys::Win32::Globalization::LCMapStringEx(
|
||||
locale,
|
||||
locale.as_ptr(),
|
||||
flags,
|
||||
src,
|
||||
src.as_ptr(),
|
||||
src_len,
|
||||
dest.as_mut_ptr(),
|
||||
dest_size,
|
||||
@@ -1217,13 +1191,9 @@ pub fn connect_named_pipe(handle: HANDLE) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn wait_named_pipe_w(name: *const u16, timeout: u32) -> io::Result<()> {
|
||||
let ok = unsafe { windows_sys::Win32::System::Pipes::WaitNamedPipeW(name, timeout) };
|
||||
if ok == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
pub fn wait_named_pipe_w(name: &widestring::WideCStr, timeout: u32) -> io::Result<()> {
|
||||
unsafe { windows_sys::Win32::System::Pipes::WaitNamedPipeW(name.as_ptr(), timeout) }
|
||||
.check_win32_bool()
|
||||
}
|
||||
|
||||
pub fn peek_named_pipe(handle: HANDLE, size: Option<u32>) -> io::Result<PeekNamedPipeResult> {
|
||||
@@ -1233,7 +1203,7 @@ pub fn peek_named_pipe(handle: HANDLE, size: Option<u32>) -> io::Result<PeekName
|
||||
Some(size) => {
|
||||
let mut data = vec![0u8; size as usize];
|
||||
let mut read = 0;
|
||||
let ok = unsafe {
|
||||
unsafe {
|
||||
windows_sys::Win32::System::Pipes::PeekNamedPipe(
|
||||
handle,
|
||||
data.as_mut_ptr().cast(),
|
||||
@@ -1242,10 +1212,8 @@ pub fn peek_named_pipe(handle: HANDLE, size: Option<u32>) -> io::Result<PeekName
|
||||
&mut available,
|
||||
&mut left_this_message,
|
||||
)
|
||||
};
|
||||
if ok == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
.check_win32_bool()?;
|
||||
data.truncate(read as usize);
|
||||
Ok(PeekNamedPipeResult {
|
||||
data: Some(data),
|
||||
@@ -1254,7 +1222,7 @@ pub fn peek_named_pipe(handle: HANDLE, size: Option<u32>) -> io::Result<PeekName
|
||||
})
|
||||
}
|
||||
None => {
|
||||
let ok = unsafe {
|
||||
unsafe {
|
||||
windows_sys::Win32::System::Pipes::PeekNamedPipe(
|
||||
handle,
|
||||
core::ptr::null_mut(),
|
||||
@@ -1263,10 +1231,8 @@ pub fn peek_named_pipe(handle: HANDLE, size: Option<u32>) -> io::Result<PeekName
|
||||
&mut available,
|
||||
&mut left_this_message,
|
||||
)
|
||||
};
|
||||
if ok == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
.check_win32_bool()?;
|
||||
Ok(PeekNamedPipeResult {
|
||||
data: None,
|
||||
available,
|
||||
@@ -1347,54 +1313,47 @@ pub fn set_named_pipe_handle_state(
|
||||
p_args[index] = &mut dw_args[index];
|
||||
}
|
||||
}
|
||||
let ok = unsafe {
|
||||
unsafe {
|
||||
windows_sys::Win32::System::Pipes::SetNamedPipeHandleState(
|
||||
handle, p_args[0], p_args[1], p_args[2],
|
||||
)
|
||||
};
|
||||
if ok == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
.check_win32_bool()
|
||||
}
|
||||
|
||||
pub fn create_mutex_w(initial_owner: bool, name: *const u16) -> io::Result<HANDLE> {
|
||||
let handle = unsafe {
|
||||
pub fn create_mutex_w(
|
||||
initial_owner: bool,
|
||||
name: Option<&widestring::WideCStr>,
|
||||
) -> io::Result<HANDLE> {
|
||||
let name_ptr = name.map_or(core::ptr::null(), |n| n.as_ptr());
|
||||
unsafe {
|
||||
windows_sys::Win32::System::Threading::CreateMutexW(
|
||||
core::ptr::null(),
|
||||
i32::from(initial_owner),
|
||||
name,
|
||||
name_ptr,
|
||||
)
|
||||
};
|
||||
if handle.is_null() {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(handle)
|
||||
}
|
||||
.check_nonnull()
|
||||
}
|
||||
|
||||
pub fn open_event_w(
|
||||
desired_access: u32,
|
||||
inherit_handle: bool,
|
||||
name: *const u16,
|
||||
name: &widestring::WideCStr,
|
||||
) -> io::Result<HANDLE> {
|
||||
let handle = unsafe {
|
||||
unsafe {
|
||||
windows_sys::Win32::System::Threading::OpenEventW(
|
||||
desired_access,
|
||||
i32::from(inherit_handle),
|
||||
name,
|
||||
name.as_ptr(),
|
||||
)
|
||||
};
|
||||
if handle.is_null() {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(handle)
|
||||
}
|
||||
.check_nonnull()
|
||||
}
|
||||
|
||||
pub fn need_current_directory_for_exe_path_w(exe_name: *const u16) -> bool {
|
||||
pub fn need_current_directory_for_exe_path_w(exe_name: &widestring::WideCStr) -> bool {
|
||||
unsafe {
|
||||
windows_sys::Win32::System::Environment::NeedCurrentDirectoryForExePathW(exe_name) != 0
|
||||
windows_sys::Win32::System::Environment::NeedCurrentDirectoryForExePathW(exe_name.as_ptr())
|
||||
!= 0
|
||||
}
|
||||
}
|
||||
+105
-18
@@ -47,6 +47,98 @@ pub fn init_winsock() {
|
||||
})
|
||||
}
|
||||
|
||||
/// Win32 BOOL convention: 0 = failure, nonzero = success.
|
||||
/// Reads error via `GetLastError()` through [`io::Error::last_os_error`].
|
||||
pub trait CheckWin32Bool {
|
||||
fn check_win32_bool(self) -> io::Result<()>;
|
||||
}
|
||||
|
||||
impl CheckWin32Bool for i32 {
|
||||
#[inline]
|
||||
fn check_win32_bool(self) -> io::Result<()> {
|
||||
if self == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience checks for Win32 `HANDLE` return values.
|
||||
pub trait CheckWin32Handle: Sized {
|
||||
/// Returns `Ok(self)` if the handle is non-NULL, otherwise the last OS error.
|
||||
/// Use for APIs whose failure sentinel is NULL (Create*Event, Create*Mutex,
|
||||
/// CreateFileMapping, GetModuleHandle, etc.).
|
||||
fn check_nonnull(self) -> io::Result<Self>;
|
||||
|
||||
/// Returns `Ok(self)` unless the handle equals `INVALID_HANDLE_VALUE`.
|
||||
/// Use for APIs whose failure sentinel is `INVALID_HANDLE_VALUE`
|
||||
/// (CreateFileW, CreateNamedPipeW, etc.).
|
||||
fn check_valid(self) -> io::Result<Self>;
|
||||
}
|
||||
|
||||
impl CheckWin32Handle for windows_sys::Win32::Foundation::HANDLE {
|
||||
#[inline]
|
||||
fn check_nonnull(self) -> io::Result<Self> {
|
||||
if self.is_null() {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn check_valid(self) -> io::Result<Self> {
|
||||
if self == windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generic sentinel check for Win32 return values not covered by [`CheckWin32Bool`] or
|
||||
/// [`CheckWin32Handle`]. Use for APIs that signal failure with a specific value
|
||||
/// (`INVALID_FILE_ATTRIBUTES`, `WAIT_FAILED`, `GetFileVersionInfoSizeW` returning `0`, etc.).
|
||||
pub trait CheckWin32Sentinel: Sized + Copy + PartialEq {
|
||||
/// Returns `Ok(self)` if `self != fail`, otherwise the last OS error.
|
||||
#[inline]
|
||||
fn check_ne(self, fail: Self) -> io::Result<Self> {
|
||||
if self == fail {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckWin32Sentinel for u32 {}
|
||||
impl CheckWin32Sentinel for i32 {}
|
||||
impl CheckWin32Sentinel for u64 {}
|
||||
|
||||
use std::os::windows::io::FromRawHandle;
|
||||
pub use std::os::windows::io::{BorrowedHandle, OwnedHandle};
|
||||
|
||||
/// Conversion of raw Win32 `HANDLE` into an [`OwnedHandle`] (RAII auto-close).
|
||||
pub trait HandleToOwned: Sized {
|
||||
/// Wraps the handle in an [`OwnedHandle`] that calls `CloseHandle` on drop.
|
||||
/// Returns `None` if the handle is NULL or `INVALID_HANDLE_VALUE`.
|
||||
fn into_owned(self) -> Option<OwnedHandle>;
|
||||
}
|
||||
|
||||
impl HandleToOwned for windows_sys::Win32::Foundation::HANDLE {
|
||||
#[inline]
|
||||
fn into_owned(self) -> Option<OwnedHandle> {
|
||||
if self.is_null() || self == windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE {
|
||||
None
|
||||
} else {
|
||||
// SAFETY: caller is asserting via the public `Create*`/`Open*` paths
|
||||
// that this handle is owned and unaliased.
|
||||
Some(unsafe { OwnedHandle::from_raw_handle(self.cast()) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct WindowsVersionInfo {
|
||||
pub major: u32,
|
||||
@@ -63,10 +155,7 @@ pub struct WindowsVersionInfo {
|
||||
fn get_kernel32_version() -> io::Result<(u32, u32, u32)> {
|
||||
unsafe {
|
||||
let module_name: Vec<u16> = OsStr::new("kernel32.dll").to_wide_with_nul();
|
||||
let h_kernel32 = GetModuleHandleW(module_name.as_ptr());
|
||||
if h_kernel32.is_null() {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
let h_kernel32 = GetModuleHandleW(module_name.as_ptr()).check_nonnull()?;
|
||||
|
||||
let mut kernel32_path = [0u16; MAX_PATH as usize];
|
||||
let len = GetModuleFileNameW(
|
||||
@@ -84,28 +173,26 @@ fn get_kernel32_version() -> io::Result<(u32, u32, u32)> {
|
||||
}
|
||||
|
||||
let mut ver_block = vec![0u8; ver_block_size as usize];
|
||||
if GetFileVersionInfoW(
|
||||
GetFileVersionInfoW(
|
||||
kernel32_path.as_ptr(),
|
||||
0,
|
||||
ver_block_size,
|
||||
ver_block.as_mut_ptr() as *mut _,
|
||||
) == 0
|
||||
{
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
)
|
||||
.check_win32_bool()?;
|
||||
|
||||
let sub_block: Vec<u16> = OsStr::new("").to_wide_with_nul();
|
||||
|
||||
let mut ffi_ptr: *mut VS_FIXEDFILEINFO = core::ptr::null_mut();
|
||||
let mut ffi_len: u32 = 0;
|
||||
if VerQueryValueW(
|
||||
VerQueryValueW(
|
||||
ver_block.as_ptr() as *const _,
|
||||
sub_block.as_ptr(),
|
||||
&mut ffi_ptr as *mut *mut VS_FIXEDFILEINFO as *mut *mut _,
|
||||
&mut ffi_len as *mut u32,
|
||||
) == 0
|
||||
|| ffi_ptr.is_null()
|
||||
{
|
||||
)
|
||||
.check_win32_bool()?;
|
||||
if ffi_ptr.is_null() {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
@@ -121,14 +208,11 @@ fn get_kernel32_version() -> io::Result<(u32, u32, u32)> {
|
||||
pub fn get_windows_version() -> io::Result<WindowsVersionInfo> {
|
||||
let mut version: OSVERSIONINFOEXW = unsafe { core::mem::zeroed() };
|
||||
version.dwOSVersionInfoSize = core::mem::size_of::<OSVERSIONINFOEXW>() as u32;
|
||||
let result = unsafe {
|
||||
unsafe {
|
||||
let os_vi = &mut version as *mut OSVERSIONINFOEXW as *mut OSVERSIONINFOW;
|
||||
GetVersionExW(os_vi)
|
||||
};
|
||||
|
||||
if result == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
.check_win32_bool()?;
|
||||
|
||||
let service_pack = {
|
||||
let (last, _) = version
|
||||
@@ -313,6 +397,9 @@ pub fn multi_byte_to_wide(
|
||||
pub trait ToWideString {
|
||||
fn to_wide(&self) -> Vec<u16>;
|
||||
fn to_wide_with_nul(&self) -> Vec<u16>;
|
||||
fn to_wide_cstring(&self) -> widestring::WideCString {
|
||||
widestring::WideCString::from_vec_truncate(self.to_wide())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ToWideString for T
|
||||
|
||||
@@ -101,24 +101,25 @@ pub fn close_key(hkey: Registry::HKEY) -> u32 {
|
||||
}
|
||||
|
||||
pub unsafe fn connect_registry(
|
||||
computer_name: *const u16,
|
||||
computer_name: Option<&widestring::WideCStr>,
|
||||
key: Registry::HKEY,
|
||||
out_key: *mut Registry::HKEY,
|
||||
) -> u32 {
|
||||
unsafe { Registry::RegConnectRegistryW(computer_name, key, out_key) }
|
||||
let name_ptr = computer_name.map_or(core::ptr::null(), |n| n.as_ptr());
|
||||
unsafe { Registry::RegConnectRegistryW(name_ptr, key, out_key) }
|
||||
}
|
||||
|
||||
pub unsafe fn create_key(
|
||||
key: Registry::HKEY,
|
||||
sub_key: *const u16,
|
||||
sub_key: &widestring::WideCStr,
|
||||
out_key: *mut Registry::HKEY,
|
||||
) -> u32 {
|
||||
unsafe { Registry::RegCreateKeyW(key, sub_key, out_key) }
|
||||
unsafe { Registry::RegCreateKeyW(key, sub_key.as_ptr(), out_key) }
|
||||
}
|
||||
|
||||
pub unsafe fn create_key_ex(
|
||||
key: Registry::HKEY,
|
||||
sub_key: *const u16,
|
||||
sub_key: &widestring::WideCStr,
|
||||
reserved: u32,
|
||||
class: *mut u16,
|
||||
options: u32,
|
||||
@@ -130,7 +131,7 @@ pub unsafe fn create_key_ex(
|
||||
unsafe {
|
||||
Registry::RegCreateKeyExW(
|
||||
key,
|
||||
sub_key,
|
||||
sub_key.as_ptr(),
|
||||
reserved,
|
||||
class,
|
||||
options,
|
||||
@@ -142,21 +143,22 @@ pub unsafe fn create_key_ex(
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn delete_key(key: Registry::HKEY, sub_key: *const u16) -> u32 {
|
||||
unsafe { Registry::RegDeleteKeyW(key, sub_key) }
|
||||
pub unsafe fn delete_key(key: Registry::HKEY, sub_key: &widestring::WideCStr) -> u32 {
|
||||
unsafe { Registry::RegDeleteKeyW(key, sub_key.as_ptr()) }
|
||||
}
|
||||
|
||||
pub unsafe fn delete_key_ex(
|
||||
key: Registry::HKEY,
|
||||
sub_key: *const u16,
|
||||
sub_key: &widestring::WideCStr,
|
||||
sam: u32,
|
||||
reserved: u32,
|
||||
) -> u32 {
|
||||
unsafe { Registry::RegDeleteKeyExW(key, sub_key, sam, reserved) }
|
||||
unsafe { Registry::RegDeleteKeyExW(key, sub_key.as_ptr(), sam, reserved) }
|
||||
}
|
||||
|
||||
pub unsafe fn delete_value(key: Registry::HKEY, value_name: *const u16) -> u32 {
|
||||
unsafe { Registry::RegDeleteValueW(key, value_name) }
|
||||
pub unsafe fn delete_value(key: Registry::HKEY, value_name: Option<&widestring::WideCStr>) -> u32 {
|
||||
let name_ptr = value_name.map_or(core::ptr::null(), |n| n.as_ptr());
|
||||
unsafe { Registry::RegDeleteValueW(key, name_ptr) }
|
||||
}
|
||||
|
||||
pub unsafe fn enum_key_ex(
|
||||
@@ -268,31 +270,36 @@ pub fn flush_key(key: Registry::HKEY) -> u32 {
|
||||
unsafe { Registry::RegFlushKey(key) }
|
||||
}
|
||||
|
||||
pub unsafe fn load_key(key: Registry::HKEY, sub_key: *const u16, file_name: *const u16) -> u32 {
|
||||
unsafe { Registry::RegLoadKeyW(key, sub_key, file_name) }
|
||||
pub unsafe fn load_key(
|
||||
key: Registry::HKEY,
|
||||
sub_key: &widestring::WideCStr,
|
||||
file_name: &widestring::WideCStr,
|
||||
) -> u32 {
|
||||
unsafe { Registry::RegLoadKeyW(key, sub_key.as_ptr(), file_name.as_ptr()) }
|
||||
}
|
||||
|
||||
pub unsafe fn open_key_ex(
|
||||
key: Registry::HKEY,
|
||||
sub_key: *const u16,
|
||||
sub_key: &widestring::WideCStr,
|
||||
options: u32,
|
||||
sam: u32,
|
||||
out_key: *mut Registry::HKEY,
|
||||
) -> u32 {
|
||||
unsafe { Registry::RegOpenKeyExW(key, sub_key, options, sam, out_key) }
|
||||
unsafe { Registry::RegOpenKeyExW(key, sub_key.as_ptr(), options, sam, out_key) }
|
||||
}
|
||||
|
||||
pub unsafe fn query_value_ex(
|
||||
key: Registry::HKEY,
|
||||
value_name: *const u16,
|
||||
value_name: Option<&widestring::WideCStr>,
|
||||
value_type: *mut u32,
|
||||
data: *mut u8,
|
||||
data_len: *mut u32,
|
||||
) -> u32 {
|
||||
let name_ptr = value_name.map_or(core::ptr::null(), |n| n.as_ptr());
|
||||
unsafe {
|
||||
Registry::RegQueryValueExW(
|
||||
key,
|
||||
value_name,
|
||||
name_ptr,
|
||||
core::ptr::null_mut(),
|
||||
value_type,
|
||||
data,
|
||||
@@ -301,18 +308,19 @@ pub unsafe fn query_value_ex(
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn save_key(key: Registry::HKEY, file_name: *const u16) -> u32 {
|
||||
unsafe { Registry::RegSaveKeyW(key, file_name, core::ptr::null_mut()) }
|
||||
pub unsafe fn save_key(key: Registry::HKEY, file_name: &widestring::WideCStr) -> u32 {
|
||||
unsafe { Registry::RegSaveKeyW(key, file_name.as_ptr(), core::ptr::null_mut()) }
|
||||
}
|
||||
|
||||
pub unsafe fn set_value_ex(
|
||||
key: Registry::HKEY,
|
||||
value_name: *const u16,
|
||||
value_name: Option<&widestring::WideCStr>,
|
||||
typ: u32,
|
||||
ptr: *const u8,
|
||||
len: u32,
|
||||
) -> u32 {
|
||||
unsafe { Registry::RegSetValueExW(key, value_name, 0, typ, ptr, len) }
|
||||
let name_ptr = value_name.map_or(core::ptr::null(), |n| n.as_ptr());
|
||||
unsafe { Registry::RegSetValueExW(key, name_ptr, 0, typ, ptr, len) }
|
||||
}
|
||||
|
||||
pub fn disable_reflection_key(key: Registry::HKEY) -> u32 {
|
||||
@@ -342,12 +350,12 @@ pub fn query_default_value(
|
||||
sub_key: Option<&OsStr>,
|
||||
) -> Result<String, QueryStringError> {
|
||||
let child_key = if let Some(sub_key) = sub_key.filter(|s| !s.is_empty()) {
|
||||
let wide_sub_key = sub_key.to_wide_with_nul();
|
||||
let wide_sub_key = sub_key.to_wide_cstring();
|
||||
let mut out_key = core::ptr::null_mut();
|
||||
let res = unsafe {
|
||||
open_key_ex(
|
||||
hkey,
|
||||
wide_sub_key.as_ptr(),
|
||||
&wide_sub_key,
|
||||
0,
|
||||
Registry::KEY_QUERY_VALUE,
|
||||
&mut out_key,
|
||||
@@ -371,7 +379,7 @@ pub fn query_default_value(
|
||||
let res = unsafe {
|
||||
query_value_ex(
|
||||
target_key,
|
||||
core::ptr::null(),
|
||||
None,
|
||||
&mut reg_type,
|
||||
buffer.as_mut_ptr(),
|
||||
&mut size,
|
||||
@@ -408,12 +416,12 @@ pub fn query_default_value(
|
||||
}
|
||||
|
||||
pub fn query_value_bytes(hkey: Registry::HKEY, value_name: &OsStr) -> Result<(Vec<u8>, u32), u32> {
|
||||
let wide_name = value_name.to_wide_with_nul();
|
||||
let wide_name = value_name.to_wide_cstring();
|
||||
let mut buf_size: u32 = 0;
|
||||
let res = unsafe {
|
||||
query_value_ex(
|
||||
hkey,
|
||||
wide_name.as_ptr(),
|
||||
Some(&wide_name),
|
||||
core::ptr::null_mut(),
|
||||
core::ptr::null_mut(),
|
||||
&mut buf_size,
|
||||
@@ -433,7 +441,7 @@ pub fn query_value_bytes(hkey: Registry::HKEY, value_name: &OsStr) -> Result<(Ve
|
||||
let res = unsafe {
|
||||
query_value_ex(
|
||||
hkey,
|
||||
wide_name.as_ptr(),
|
||||
Some(&wide_name),
|
||||
&mut typ,
|
||||
ret_buf.as_mut_ptr(),
|
||||
&mut ret_size,
|
||||
@@ -453,12 +461,12 @@ pub fn query_value_bytes(hkey: Registry::HKEY, value_name: &OsStr) -> Result<(Ve
|
||||
|
||||
pub fn set_default_value(hkey: Registry::HKEY, sub_key: &OsStr, typ: u32, value: &OsStr) -> u32 {
|
||||
let child_key = if !sub_key.is_empty() {
|
||||
let wide_sub_key = sub_key.to_wide_with_nul();
|
||||
let wide_sub_key = sub_key.to_wide_cstring();
|
||||
let mut out_key = core::ptr::null_mut();
|
||||
let res = unsafe {
|
||||
create_key_ex(
|
||||
hkey,
|
||||
wide_sub_key.as_ptr(),
|
||||
&wide_sub_key,
|
||||
0,
|
||||
core::ptr::null_mut(),
|
||||
0,
|
||||
@@ -481,7 +489,7 @@ pub fn set_default_value(hkey: Registry::HKEY, sub_key: &OsStr, typ: u32, value:
|
||||
let res = unsafe {
|
||||
set_value_ex(
|
||||
target_key,
|
||||
core::ptr::null(),
|
||||
None,
|
||||
typ,
|
||||
wide_value.as_ptr() as *const u8,
|
||||
(wide_value.len() * 2) as u32,
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
// spell-checker:ignore pszSound fdwSound winmm
|
||||
|
||||
use std::io;
|
||||
|
||||
#[link(name = "winmm")]
|
||||
unsafe extern "system" {
|
||||
fn PlaySoundW(pszSound: *const u16, hmod: isize, fdwSound: u32) -> i32;
|
||||
}
|
||||
|
||||
unsafe extern "system" {
|
||||
fn Beep(dwFreq: u32, dwDuration: u32) -> i32;
|
||||
fn MessageBeep(uType: u32) -> i32;
|
||||
}
|
||||
|
||||
/// `SND_ASYNC` flag value from `mmsystem.h`.
|
||||
const SND_ASYNC: u32 = 0x0001;
|
||||
/// `SND_MEMORY` flag value from `mmsystem.h`.
|
||||
const SND_MEMORY: u32 = 0x0004;
|
||||
|
||||
/// Source for a `PlaySound` call.
|
||||
pub enum PlaySoundSource<'a> {
|
||||
/// Stop currently playing sound (NULL `pszSound`).
|
||||
Stop,
|
||||
/// Play sound data from memory; pass with `SND_MEMORY` set in `flags`.
|
||||
Memory(&'a [u8]),
|
||||
/// Play sound by filename or system alias.
|
||||
Name(&'a widestring::WideCStr),
|
||||
}
|
||||
|
||||
/// Returns `Ok(())` when `PlaySoundW` returns non-zero, an error otherwise.
|
||||
///
|
||||
/// Rejects `Memory(_)` together with `SND_ASYNC` because async playback
|
||||
/// requires the buffer to outlive the call; combining them with a borrowed
|
||||
/// slice would let WinMM read freed memory.
|
||||
pub fn play_sound(source: PlaySoundSource<'_>, flags: u32) -> Result<(), PlaySoundError> {
|
||||
if matches!(source, PlaySoundSource::Memory(_)) && flags & SND_ASYNC != 0 {
|
||||
return Err(PlaySoundError::MemoryAsyncRejected);
|
||||
}
|
||||
// `SND_MEMORY` requires a `Memory(_)` source; an empty pointer would
|
||||
// dereference garbage.
|
||||
if !matches!(source, PlaySoundSource::Memory(_)) && flags & SND_MEMORY != 0 {
|
||||
return Err(PlaySoundError::MemoryFlagWithoutBuffer);
|
||||
}
|
||||
let ptr: *const u16 = match source {
|
||||
PlaySoundSource::Stop => core::ptr::null(),
|
||||
PlaySoundSource::Memory(buf) => buf.as_ptr().cast(),
|
||||
PlaySoundSource::Name(s) => s.as_ptr(),
|
||||
};
|
||||
let ok = unsafe { PlaySoundW(ptr, 0, flags) };
|
||||
if ok == 0 {
|
||||
Err(PlaySoundError::CallFailed)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum PlaySoundError {
|
||||
/// `PlaySoundW` returned 0; there is no documented errno for this path.
|
||||
CallFailed,
|
||||
/// `Memory(_)` source cannot be combined with `SND_ASYNC` in the safe API.
|
||||
MemoryAsyncRejected,
|
||||
/// `SND_MEMORY` set in `flags` but no `Memory(_)` buffer supplied.
|
||||
MemoryFlagWithoutBuffer,
|
||||
}
|
||||
|
||||
/// `Beep(freq, duration)`. `false` on failure.
|
||||
#[must_use]
|
||||
pub fn beep(frequency: u32, duration_ms: u32) -> bool {
|
||||
unsafe { Beep(frequency, duration_ms) != 0 }
|
||||
}
|
||||
|
||||
/// `MessageBeep(type)`. On failure returns `Err` populated from `GetLastError`.
|
||||
pub fn message_beep(beep_type: u32) -> io::Result<()> {
|
||||
let ok = unsafe { MessageBeep(beep_type) };
|
||||
if ok == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ use windows_sys::Win32::System::Threading::{
|
||||
CreateEventW, CreateThread, GetExitCodeThread, SetEvent, WaitForSingleObject,
|
||||
};
|
||||
|
||||
const BUFFER_SIZE: usize = 8192;
|
||||
pub const BUFFER_SIZE: usize = 8192;
|
||||
|
||||
pub enum ExecQueryError {
|
||||
MoreData,
|
||||
|
||||
@@ -9,6 +9,7 @@ mod fcntl {
|
||||
use crate::vm::{
|
||||
PyResult, VirtualMachine,
|
||||
builtins::PyIntRef,
|
||||
convert::ToPyException,
|
||||
function::{ArgMemoryBuffer, ArgStrOrBytesLike, Either, OptionalArg},
|
||||
stdlib::_io,
|
||||
};
|
||||
@@ -167,11 +168,8 @@ mod fcntl {
|
||||
OptionalArg::Present(w) => w,
|
||||
OptionalArg::Missing => 0,
|
||||
};
|
||||
let ret = host_fcntl::lockf(fd, cmd, len, start, whence).map_err(|err| match err {
|
||||
host_fcntl::LockfError::InvalidCmd => vm.new_value_error("unrecognized lockf argument"),
|
||||
host_fcntl::LockfError::Overflow(e) => vm.new_overflow_error(e),
|
||||
host_fcntl::LockfError::Io(_) => vm.new_last_errno_error(),
|
||||
})?;
|
||||
let ret =
|
||||
host_fcntl::lockf(fd, cmd, len, start, whence).map_err(|err| err.to_pyexception(vm))?;
|
||||
Ok(vm.ctx.new_int(ret).into())
|
||||
}
|
||||
}
|
||||
@@ -350,6 +350,7 @@ mod _multiprocessing {
|
||||
use crate::vm::{
|
||||
Context, FromArgs, Py, PyPayload, PyRef, PyResult, VirtualMachine,
|
||||
builtins::{PyBaseExceptionRef, PyDict, PyType, PyTypeRef},
|
||||
convert::ToPyException,
|
||||
function::{FuncArgs, KwArgs},
|
||||
types::Constructor,
|
||||
};
|
||||
@@ -872,14 +873,7 @@ mod _multiprocessing {
|
||||
}
|
||||
|
||||
fn os_error(vm: &VirtualMachine, err: SemError) -> PyBaseExceptionRef {
|
||||
// _PyMp_SetError maps to PyErr_SetFromErrno
|
||||
let exc_type = match err {
|
||||
SemError::AlreadyExists => vm.ctx.exceptions.file_exists_error.to_owned(),
|
||||
SemError::NotFound => vm.ctx.exceptions.file_not_found_error.to_owned(),
|
||||
_ => vm.ctx.exceptions.os_error.to_owned(),
|
||||
};
|
||||
vm.new_os_subtype_error(exc_type, Some(err.raw_os_error()), err.description())
|
||||
.upcast()
|
||||
err.to_pyexception(vm)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ mod _overlapped {
|
||||
AsObject, Py, PyObjectRef, PyPayload, PyResult, VirtualMachine,
|
||||
builtins::{PyBaseExceptionRef, PyBytesRef, PyModule, PyStrRef, PyTupleRef, PyType},
|
||||
common::lock::PyMutex,
|
||||
convert::ToPyObject,
|
||||
convert::{ToPyException, ToPyObject},
|
||||
function::OptionalArg,
|
||||
object::{Traverse, TraverseFn},
|
||||
protocol::PyBuffer,
|
||||
@@ -1077,7 +1077,7 @@ mod _overlapped {
|
||||
let mut event = event.unwrap_or(INVALID_HANDLE_VALUE);
|
||||
|
||||
if event == INVALID_HANDLE_VALUE {
|
||||
event = host_winapi::create_event_w(true, false, core::ptr::null())
|
||||
event = host_winapi::create_event_w(true, false, None)
|
||||
.map(|handle| handle as isize)
|
||||
.map_err(|err| {
|
||||
set_from_windows_err(err.raw_os_error().unwrap_or(0) as u32, vm)
|
||||
@@ -1251,15 +1251,12 @@ mod _overlapped {
|
||||
return Err(vm.new_value_error("EventAttributes must be None"));
|
||||
}
|
||||
|
||||
let name_wide: Option<Vec<u16>> =
|
||||
name.map(|n| n.encode_utf16().chain(core::iter::once(0)).collect());
|
||||
host_winapi::create_event_w(
|
||||
manual_reset,
|
||||
initial_state,
|
||||
name_wide.as_ref().map_or(core::ptr::null(), |n| n.as_ptr()),
|
||||
)
|
||||
.map(|h| h as isize)
|
||||
.map_err(|err| set_from_windows_err(err.raw_os_error().unwrap_or(0) as u32, vm))
|
||||
let name_wide: Option<widestring::WideCString> = name
|
||||
.map(|n| widestring::WideCString::from_str(&n).map_err(|err| err.to_pyexception(vm)))
|
||||
.transpose()?;
|
||||
host_winapi::create_event_w(manual_reset, initial_state, name_wide.as_deref())
|
||||
.map(|h| h as isize)
|
||||
.map_err(|err| set_from_windows_err(err.raw_os_error().unwrap_or(0) as u32, vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
|
||||
@@ -8,6 +8,8 @@ pub(super) use _socket::{PySocket, SelectKind, sock_select, timeout_error_msg};
|
||||
#[pymodule]
|
||||
mod _socket {
|
||||
use crate::common::lock::{PyMappedRwLockReadGuard, PyRwLock, PyRwLockReadGuard};
|
||||
#[cfg(all(unix, not(target_os = "redox")))]
|
||||
use crate::vm::convert::ToPyException;
|
||||
use crate::vm::{
|
||||
AsObject, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
|
||||
builtins::{
|
||||
@@ -1947,17 +1949,7 @@ mod _socket {
|
||||
.map(|(lvl, typ, data)| (*lvl, *typ, data.as_slice()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
host_socket::pack_ancillary_messages(&data_refs).map_err(|err| match err {
|
||||
host_socket::AncillaryPackError::ItemTooLarge => {
|
||||
vm.new_os_error("ancillary data item too large".to_owned())
|
||||
}
|
||||
host_socket::AncillaryPackError::TooMuchData => {
|
||||
vm.new_os_error("too much ancillary data".to_owned())
|
||||
}
|
||||
host_socket::AncillaryPackError::UnexpectedNullHeader => {
|
||||
vm.new_runtime_error("unexpected NULL result from CMSG_FIRSTHDR/CMSG_NXTHDR")
|
||||
}
|
||||
})
|
||||
host_socket::pack_ancillary_messages(&data_refs).map_err(|err| err.to_pyexception(vm))
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
|
||||
@@ -51,7 +51,6 @@ crossbeam-utils = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
constant_time_eq = { workspace = true }
|
||||
flame = { workspace = true, optional = true }
|
||||
getrandom = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
@@ -87,7 +86,6 @@ icu_properties = { workspace = true }
|
||||
writeable = { workspace = true }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
rustix = { workspace = true }
|
||||
exitcode = { workspace = true }
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
|
||||
+161
-21
@@ -1385,28 +1385,18 @@ impl ToOSErrorBuilder for std::io::Error {
|
||||
// Use C runtime's strerror for POSIX errno values.
|
||||
// For Windows-specific error codes, fall back to FormatMessage.
|
||||
const MAX_POSIX_ERRNO: i32 = 127;
|
||||
if errno > 0 && errno <= MAX_POSIX_ERRNO {
|
||||
let ptr = unsafe { libc::strerror(errno) };
|
||||
if !ptr.is_null() {
|
||||
let s = unsafe { core::ffi::CStr::from_ptr(ptr) }.to_string_lossy();
|
||||
if !s.starts_with("Unknown error") {
|
||||
break 'msg s.into_owned();
|
||||
}
|
||||
}
|
||||
if errno > 0
|
||||
&& errno <= MAX_POSIX_ERRNO
|
||||
&& let Some(s) = crate::host_env::errno::strerror_string(errno)
|
||||
&& !s.starts_with("Unknown error")
|
||||
{
|
||||
break 'msg s;
|
||||
}
|
||||
self.to_string()
|
||||
};
|
||||
#[cfg(unix)]
|
||||
let msg = {
|
||||
let ptr = unsafe { libc::strerror(errno) };
|
||||
if !ptr.is_null() {
|
||||
unsafe { core::ffi::CStr::from_ptr(ptr) }
|
||||
.to_string_lossy()
|
||||
.into_owned()
|
||||
} else {
|
||||
self.to_string()
|
||||
}
|
||||
};
|
||||
let msg =
|
||||
crate::host_env::errno::strerror_string(errno).unwrap_or_else(|| self.to_string());
|
||||
#[cfg(not(any(windows, unix)))]
|
||||
let msg = self.to_string();
|
||||
|
||||
@@ -1433,10 +1423,160 @@ impl IntoPyException for std::io::Error {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(target_os = "redox")))]
|
||||
impl ToPyException for rustpython_host_env::fcntl::LockfError {
|
||||
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
|
||||
match self {
|
||||
Self::InvalidCmd => vm.new_value_error("unrecognized lockf argument"),
|
||||
Self::Overflow(e) => vm.new_overflow_error(e.clone()),
|
||||
Self::Io(err) => err.to_pyexception(vm),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl IntoPyException for rustix::io::Errno {
|
||||
fn into_pyexception(self, vm: &VirtualMachine) -> PyBaseExceptionRef {
|
||||
std::io::Error::from(self).into_pyexception(vm)
|
||||
impl ToPyException for rustpython_host_env::posix::AccessError {
|
||||
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
|
||||
match self {
|
||||
Self::InvalidMode => vm.new_value_error(
|
||||
"One of the flags is wrong, there are only 4 possibilities F_OK, R_OK, W_OK and X_OK",
|
||||
),
|
||||
Self::Os(errno) => std::io::Error::from_raw_os_error(*errno).to_pyexception(vm),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(target_os = "redox")))]
|
||||
impl ToPyException for rustpython_host_env::socket::AncillaryPackError {
|
||||
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
|
||||
match self {
|
||||
Self::ItemTooLarge => vm.new_os_error("ancillary data item too large"),
|
||||
Self::TooMuchData => vm.new_os_error("too much ancillary data"),
|
||||
Self::UnexpectedNullHeader => {
|
||||
vm.new_runtime_error("unexpected NULL result from CMSG_FIRSTHDR/CMSG_NXTHDR")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(unix, windows))]
|
||||
impl ToPyException for rustpython_host_env::time::CheckedTmError {
|
||||
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
|
||||
match self {
|
||||
Self::YearOutOfRange => vm.new_overflow_error("year out of range"),
|
||||
Self::MonthOutOfRange => vm.new_value_error("month out of range"),
|
||||
Self::DayOfMonthOutOfRange => vm.new_value_error("day of month out of range"),
|
||||
Self::HourOutOfRange => vm.new_value_error("hour out of range"),
|
||||
Self::MinuteOutOfRange => vm.new_value_error("minute out of range"),
|
||||
Self::SecondsOutOfRange => vm.new_value_error("seconds out of range"),
|
||||
Self::DayOfWeekOutOfRange => vm.new_value_error("day of week out of range"),
|
||||
Self::DayOfYearOutOfRange => vm.new_value_error("day of year out of range"),
|
||||
Self::EmbeddedNul => vm.new_value_error("embedded null character"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl ToPyException for rustpython_host_env::winapi::BuildEnvironmentBlockError {
|
||||
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
|
||||
match self {
|
||||
Self::ContainsNul => vm.new_value_error("embedded null character"),
|
||||
Self::IllegalName => vm.new_value_error("illegal environment variable name"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl ToPyException for rustpython_host_env::winapi::BatchedWaitError {
|
||||
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
|
||||
match self {
|
||||
Self::Timeout => vm
|
||||
.new_os_subtype_error(
|
||||
vm.ctx.exceptions.timeout_error.to_owned(),
|
||||
None,
|
||||
"timed out",
|
||||
)
|
||||
.upcast(),
|
||||
Self::Interrupted => vm
|
||||
.new_errno_error(libc::EINTR, "Interrupted system call")
|
||||
.upcast(),
|
||||
Self::Os(err) => vm.new_os_error(*err as i32),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl ToPyException for rustpython_host_env::nt::ReadlinkError {
|
||||
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
|
||||
match self {
|
||||
Self::Io(err) => err.to_pyexception(vm),
|
||||
Self::NotSymbolicLink => {
|
||||
vm.new_os_error("The file or directory is not a reparse point")
|
||||
}
|
||||
Self::InvalidReparseData => vm.new_os_error("Invalid reparse data"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl ToPyException for rustpython_host_env::nt::ReadConsoleError {
|
||||
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
|
||||
match self {
|
||||
Self::Io(err) => err.to_pyexception(vm),
|
||||
Self::BufferTooSmall {
|
||||
available,
|
||||
required,
|
||||
} => vm.new_system_error(format!(
|
||||
"Buffer had room for {available} bytes but {required} bytes required",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl ToPyException for rustpython_host_env::winreg::ExpandEnvironmentStringsError {
|
||||
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
|
||||
match self {
|
||||
Self::Os => vm.new_os_error("ExpandEnvironmentStringsW failed"),
|
||||
Self::Utf16(e) => vm.new_value_error(format!("UTF16 error: {e}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl ToPyException for rustpython_host_env::winreg::QueryStringError {
|
||||
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
|
||||
match self {
|
||||
Self::Code(err) => std::io::Error::from_raw_os_error(*err as i32).to_pyexception(vm),
|
||||
Self::Utf16(e) => vm.new_value_error(format!("UTF16 error: {e}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl ToPyException for rustpython_host_env::wmi::ExecQueryError {
|
||||
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
|
||||
match self {
|
||||
Self::MoreData => vm.new_os_error(format!(
|
||||
"Query returns more than {} characters",
|
||||
rustpython_host_env::wmi::BUFFER_SIZE
|
||||
)),
|
||||
Self::Code(err) => std::io::Error::from_raw_os_error(*err as i32).to_pyexception(vm),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl ToPyException for rustpython_host_env::multiprocessing::SemError {
|
||||
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
|
||||
let excs = &vm.ctx.exceptions;
|
||||
let exc_type = match self {
|
||||
Self::AlreadyExists => excs.file_exists_error.to_owned(),
|
||||
Self::NotFound => excs.file_not_found_error.to_owned(),
|
||||
_ => excs.os_error.to_owned(),
|
||||
};
|
||||
vm.new_os_subtype_error(exc_type, Some(self.raw_os_error()), self.description())
|
||||
.upcast()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-48
@@ -10,34 +10,25 @@ use crate::common::format::*;
|
||||
use crate::common::wtf8::{Wtf8, Wtf8Buf};
|
||||
|
||||
/// Get locale information from C `localeconv()` for the 'n' format specifier.
|
||||
#[cfg(unix)]
|
||||
#[cfg(any(unix, windows))]
|
||||
pub(crate) fn get_locale_info() -> LocaleInfo {
|
||||
use core::ffi::CStr;
|
||||
unsafe {
|
||||
let lc = libc::localeconv();
|
||||
if lc.is_null() {
|
||||
return LocaleInfo {
|
||||
thousands_sep: String::new(),
|
||||
decimal_point: ".".to_string(),
|
||||
grouping: vec![],
|
||||
};
|
||||
}
|
||||
let thousands_sep = CStr::from_ptr((*lc).thousands_sep)
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
let decimal_point = CStr::from_ptr((*lc).decimal_point)
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
let grouping = parse_grouping((*lc).grouping);
|
||||
LocaleInfo {
|
||||
thousands_sep,
|
||||
decimal_point,
|
||||
grouping,
|
||||
}
|
||||
let lc = crate::host_env::locale::localeconv_data();
|
||||
let mut grouping: Vec<u8> = lc.grouping.iter().map(|&c| c as u8).collect();
|
||||
if !grouping.is_empty() {
|
||||
grouping.push(0);
|
||||
}
|
||||
LocaleInfo {
|
||||
thousands_sep: String::from_utf8_lossy(&lc.thousands_sep).into_owned(),
|
||||
decimal_point: if lc.decimal_point.is_empty() {
|
||||
".".to_string()
|
||||
} else {
|
||||
String::from_utf8_lossy(&lc.decimal_point).into_owned()
|
||||
},
|
||||
grouping,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
#[cfg(not(any(unix, windows)))]
|
||||
pub(crate) fn get_locale_info() -> LocaleInfo {
|
||||
LocaleInfo {
|
||||
thousands_sep: String::new(),
|
||||
@@ -46,30 +37,6 @@ pub(crate) fn get_locale_info() -> LocaleInfo {
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse C `lconv.grouping` into a `Vec<u8>`.
|
||||
/// Reads bytes until 0 or CHAR_MAX, then appends 0 (meaning "repeat last group").
|
||||
#[cfg(unix)]
|
||||
unsafe fn parse_grouping(grouping: *const libc::c_char) -> Vec<u8> {
|
||||
let mut result = Vec::new();
|
||||
if grouping.is_null() {
|
||||
return result;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let mut ptr = grouping;
|
||||
while ![0, libc::c_char::MAX].contains(&*ptr) {
|
||||
result.push(*ptr as _);
|
||||
ptr = ptr.add(1);
|
||||
}
|
||||
}
|
||||
|
||||
if !result.is_empty() {
|
||||
result.push(0);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
impl IntoPyException for FormatSpecError {
|
||||
fn into_pyexception(self, vm: &VirtualMachine) -> PyBaseExceptionRef {
|
||||
match self {
|
||||
|
||||
@@ -5843,6 +5843,7 @@ mod winconsoleio {
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use rustpython_host_env::io as host_io;
|
||||
use rustpython_host_env::nt as host_nt;
|
||||
use rustpython_host_env::windows::ToWideString;
|
||||
type HANDLE = host_nt::Handle;
|
||||
|
||||
const SMALLBUF: usize = 4;
|
||||
@@ -6013,13 +6014,9 @@ mod winconsoleio {
|
||||
}
|
||||
|
||||
let name_str = nameobj.str(vm)?;
|
||||
let wide = name_str
|
||||
.as_wtf8()
|
||||
.encode_wide()
|
||||
.chain(core::iter::once(0))
|
||||
.collect::<Vec<u16>>();
|
||||
let wide = name_str.as_wtf8().to_wide_cstring();
|
||||
|
||||
fd = host_nt::open_console_path_fd(wide.as_ptr(), writable)
|
||||
fd = host_nt::open_console_path_fd(&wide, writable)
|
||||
.map_err(|err| err.to_pyexception(vm))?;
|
||||
} else {
|
||||
// When opened by fd, never close the fd (user owns it)
|
||||
@@ -6242,16 +6239,8 @@ mod winconsoleio {
|
||||
|
||||
let dest = &mut *buf_ref;
|
||||
let mut smallbuf = self.buf.lock();
|
||||
match host_nt::read_console_into(handle, dest, &mut smallbuf) {
|
||||
Ok(read_len) => Ok(read_len),
|
||||
Err(host_nt::ReadConsoleError::BufferTooSmall {
|
||||
available,
|
||||
required,
|
||||
}) => Err(vm.new_system_error(format!(
|
||||
"Buffer had room for {available} bytes but {required} bytes required",
|
||||
))),
|
||||
Err(host_nt::ReadConsoleError::Io(err)) => Err(err.into_pyexception(vm)),
|
||||
}
|
||||
host_nt::read_console_into(handle, dest, &mut smallbuf)
|
||||
.map_err(|err| err.to_pyexception(vm))
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
@@ -6305,20 +6294,9 @@ mod winconsoleio {
|
||||
}
|
||||
{
|
||||
let mut ibuf = self.buf.lock();
|
||||
match host_nt::read_console_into(handle, &mut buf[read_len..], &mut ibuf) {
|
||||
Ok(n) => read_len += n,
|
||||
Err(host_nt::ReadConsoleError::BufferTooSmall {
|
||||
available,
|
||||
required,
|
||||
}) => {
|
||||
return Err(vm.new_system_error(format!(
|
||||
"Buffer had room for {available} bytes but {required} bytes required",
|
||||
)));
|
||||
}
|
||||
Err(host_nt::ReadConsoleError::Io(err)) => {
|
||||
return Err(err.into_pyexception(vm));
|
||||
}
|
||||
}
|
||||
let n = host_nt::read_console_into(handle, &mut buf[read_len..], &mut ibuf)
|
||||
.map_err(|err| err.to_pyexception(vm))?;
|
||||
read_len += n;
|
||||
}
|
||||
|
||||
buf.truncate(read_len);
|
||||
|
||||
@@ -14,7 +14,7 @@ mod _winapi {
|
||||
types::Constructor,
|
||||
windows::{WinHandle, WindowsSysResult},
|
||||
};
|
||||
use core::ptr::{null, null_mut};
|
||||
use core::ptr::null_mut;
|
||||
use rustpython_common::wtf8::Wtf8Buf;
|
||||
use rustpython_host_env::overlapped as host_overlapped;
|
||||
use rustpython_host_env::winapi as host_winapi;
|
||||
@@ -92,9 +92,9 @@ mod _winapi {
|
||||
_template_file: PyObjectRef, // Always NULL (0)
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<WinHandle> {
|
||||
let file_name_wide = file_name.as_wtf8().to_wide_with_nul();
|
||||
let file_name_wide = file_name.as_wtf8().to_wide_cstring();
|
||||
host_winapi::create_file_w(
|
||||
file_name_wide.as_ptr(),
|
||||
&file_name_wide,
|
||||
desired_access,
|
||||
share_mode,
|
||||
creation_disposition,
|
||||
@@ -223,21 +223,15 @@ mod _winapi {
|
||||
std_error: si_attr!(hStdError, isize),
|
||||
};
|
||||
|
||||
let mut env = args
|
||||
let env = args
|
||||
.env_mapping
|
||||
.map(|m| getenvironment(m, vm))
|
||||
.transpose()?;
|
||||
let env = env.as_mut().map_or_else(null_mut, |v| v.as_mut_ptr());
|
||||
|
||||
let handle_list = get_handle_list(args.startup_info.get_attr("lpAttributeList", vm)?, vm)?;
|
||||
|
||||
let wstr = |s: PyStrRef| {
|
||||
let ws = widestring::WideCString::from_str(s.expect_str())
|
||||
.map_err(|err| err.to_pyexception(vm))?;
|
||||
Ok(ws.into_vec_with_nul())
|
||||
};
|
||||
|
||||
// Validate no embedded null bytes in command name and command line
|
||||
// before handing the strings off; to_wide_cstring truncates at NUL.
|
||||
if let Some(ref name) = args.name
|
||||
&& name.as_bytes().contains(&0)
|
||||
{
|
||||
@@ -249,26 +243,21 @@ mod _winapi {
|
||||
return Err(crate::exceptions::cstring_error(vm));
|
||||
}
|
||||
|
||||
let app_name = args.name.map(wstr).transpose()?;
|
||||
let app_name = app_name.as_ref().map_or_else(null, |w| w.as_ptr());
|
||||
|
||||
let mut command_line = args.command_line.map(wstr).transpose()?;
|
||||
let command_line = command_line
|
||||
.as_mut()
|
||||
.map_or_else(null_mut, |w| w.as_mut_ptr());
|
||||
|
||||
let mut current_dir = args.current_dir.map(wstr).transpose()?;
|
||||
let current_dir = current_dir
|
||||
.as_mut()
|
||||
.map_or_else(null_mut, |w| w.as_mut_ptr());
|
||||
let wcstring = |s: PyStrRef| s.as_wtf8().to_wide_cstring();
|
||||
let app_name = args.name.as_ref().map(|s| wcstring(s.clone()));
|
||||
let current_dir = args.current_dir.as_ref().map(|s| wcstring(s.clone()));
|
||||
let mut command_line = args
|
||||
.command_line
|
||||
.as_ref()
|
||||
.map(|s| wcstring(s.clone()).into_vec_with_nul());
|
||||
|
||||
let procinfo = host_winapi::create_process(
|
||||
app_name,
|
||||
command_line,
|
||||
app_name.as_deref(),
|
||||
command_line.as_deref_mut(),
|
||||
args.inherit_handles,
|
||||
args.creation_flags,
|
||||
env,
|
||||
current_dir,
|
||||
env.as_deref(),
|
||||
current_dir.as_deref(),
|
||||
startup_info,
|
||||
handle_list,
|
||||
)
|
||||
@@ -301,8 +290,8 @@ mod _winapi {
|
||||
|
||||
#[pyfunction]
|
||||
fn NeedCurrentDirectoryForExePath(exe_name: PyStrRef) -> bool {
|
||||
let exe_name = exe_name.as_wtf8().to_wide_with_nul();
|
||||
host_winapi::need_current_directory_for_exe_path_w(exe_name.as_ptr())
|
||||
let exe_name = exe_name.as_wtf8().to_wide_cstring();
|
||||
host_winapi::need_current_directory_for_exe_path_w(&exe_name)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
@@ -336,14 +325,7 @@ mod _winapi {
|
||||
entries.push((k, v));
|
||||
}
|
||||
|
||||
host_winapi::build_environment_block(entries).map_err(|err| match err {
|
||||
host_winapi::BuildEnvironmentBlockError::ContainsNul => {
|
||||
crate::exceptions::cstring_error(vm)
|
||||
}
|
||||
host_winapi::BuildEnvironmentBlockError::IllegalName => {
|
||||
vm.new_value_error("illegal environment variable name")
|
||||
}
|
||||
})
|
||||
host_winapi::build_environment_block(entries).map_err(|err| err.to_pyexception(vm))
|
||||
}
|
||||
|
||||
fn get_handle_list(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<Option<Vec<usize>>> {
|
||||
@@ -419,8 +401,8 @@ mod _winapi {
|
||||
name: OptionalArg<Option<PyStrRef>>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<WinHandle> {
|
||||
let name = name.flatten().map(|name| name.as_wtf8().to_wide_with_nul());
|
||||
host_winapi::create_job_object_w(name.as_ref().map_or(null(), |name| name.as_ptr()))
|
||||
let name = name.flatten().map(|name| name.as_wtf8().to_wide_cstring());
|
||||
host_winapi::create_job_object_w(name.as_deref())
|
||||
.map(WinHandle)
|
||||
.map_err(|e| e.to_pyexception(vm))
|
||||
}
|
||||
@@ -465,8 +447,8 @@ mod _winapi {
|
||||
name: PyStrRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<WinHandle> {
|
||||
let name_wide = name.as_wtf8().to_wide_with_nul();
|
||||
host_winapi::open_mutex_w(desired_access, inherit_handle, name_wide.as_ptr())
|
||||
let name_wide = name.as_wtf8().to_wide_cstring();
|
||||
host_winapi::open_mutex_w(desired_access, inherit_handle, &name_wide)
|
||||
.map(WinHandle)
|
||||
.map_err(|e| e.to_pyexception(vm))
|
||||
}
|
||||
@@ -509,20 +491,15 @@ mod _winapi {
|
||||
}
|
||||
|
||||
// Use ToWideString which properly handles WTF-8 (including surrogates)
|
||||
let locale_wide = locale.as_wtf8().to_wide_with_nul();
|
||||
let locale_wide = locale.as_wtf8().to_wide_cstring();
|
||||
let src_wide = src.as_wtf8().to_wide();
|
||||
|
||||
if src_wide.len() > i32::MAX as usize {
|
||||
return Err(vm.new_overflow_error("input string is too long"));
|
||||
}
|
||||
|
||||
let dest = host_winapi::lc_map_string_ex(
|
||||
locale_wide.as_ptr(),
|
||||
flags,
|
||||
src_wide.as_ptr(),
|
||||
src_wide.len() as i32,
|
||||
)
|
||||
.map_err(|e| e.to_pyexception(vm))?;
|
||||
let dest = host_winapi::lc_map_string_ex(&locale_wide, flags, &src_wide)
|
||||
.map_err(|e| e.to_pyexception(vm))?;
|
||||
|
||||
// Convert UTF-16 back to WTF-8 (handles surrogates properly)
|
||||
let result = Wtf8Buf::from_wide(&dest);
|
||||
@@ -552,9 +529,9 @@ mod _winapi {
|
||||
/// CreateNamedPipe - Create a named pipe
|
||||
#[pyfunction]
|
||||
fn CreateNamedPipe(args: CreateNamedPipeArgs, vm: &VirtualMachine) -> PyResult<WinHandle> {
|
||||
let name_wide = args.name.as_wtf8().to_wide_with_nul();
|
||||
let name_wide = args.name.as_wtf8().to_wide_cstring();
|
||||
host_winapi::create_named_pipe_w(
|
||||
name_wide.as_ptr(),
|
||||
&name_wide,
|
||||
args.open_mode,
|
||||
args.pipe_mode,
|
||||
args.max_instances,
|
||||
@@ -672,27 +649,26 @@ mod _winapi {
|
||||
/// GetShortPathName - Return the short version of the provided path.
|
||||
#[pyfunction]
|
||||
fn GetShortPathName(path: PyStrRef, vm: &VirtualMachine) -> PyResult<PyStrRef> {
|
||||
let path_wide = path.as_wtf8().to_wide_with_nul();
|
||||
let wide = host_winapi::get_short_path_name_w(path_wide.as_ptr())
|
||||
.map_err(|e| e.to_pyexception(vm))?;
|
||||
let path_wide = path.as_wtf8().to_wide_cstring();
|
||||
let wide =
|
||||
host_winapi::get_short_path_name_w(&path_wide).map_err(|e| e.to_pyexception(vm))?;
|
||||
Ok(path_name_result_to_pystr(wide, vm))
|
||||
}
|
||||
|
||||
/// GetLongPathName - Return the long version of the provided path.
|
||||
#[pyfunction]
|
||||
fn GetLongPathName(path: PyStrRef, vm: &VirtualMachine) -> PyResult<PyStrRef> {
|
||||
let path_wide = path.as_wtf8().to_wide_with_nul();
|
||||
let wide = host_winapi::get_long_path_name_w(path_wide.as_ptr())
|
||||
.map_err(|e| e.to_pyexception(vm))?;
|
||||
let path_wide = path.as_wtf8().to_wide_cstring();
|
||||
let wide =
|
||||
host_winapi::get_long_path_name_w(&path_wide).map_err(|e| e.to_pyexception(vm))?;
|
||||
Ok(path_name_result_to_pystr(wide, vm))
|
||||
}
|
||||
|
||||
/// WaitNamedPipe - Wait for an instance of a named pipe to become available.
|
||||
#[pyfunction]
|
||||
fn WaitNamedPipe(name: PyStrRef, timeout: u32, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let name_wide = name.as_wtf8().to_wide_with_nul();
|
||||
host_winapi::wait_named_pipe_w(name_wide.as_ptr(), timeout)
|
||||
.map_err(|e| e.to_pyexception(vm))
|
||||
let name_wide = name.as_wtf8().to_wide_cstring();
|
||||
host_winapi::wait_named_pipe_w(&name_wide, timeout).map_err(|e| e.to_pyexception(vm))
|
||||
}
|
||||
|
||||
/// PeekNamedPipe - Peek at data in a named pipe without removing it.
|
||||
@@ -745,9 +721,8 @@ mod _winapi {
|
||||
) -> PyResult<WinHandle> {
|
||||
let _ = security_attributes; // Ignored, always NULL
|
||||
|
||||
let name_wide = name.map(|n| n.as_wtf8().to_wide_with_nul());
|
||||
let name_ptr = name_wide.as_ref().map_or(null(), |n| n.as_ptr());
|
||||
host_winapi::create_event_w(manual_reset, initial_state, name_ptr)
|
||||
let name_wide = name.map(|n| n.as_wtf8().to_wide_cstring());
|
||||
host_winapi::create_event_w(manual_reset, initial_state, name_wide.as_deref())
|
||||
.map(WinHandle)
|
||||
.map_err(|e| e.to_pyexception(vm))
|
||||
}
|
||||
@@ -872,9 +847,8 @@ mod _winapi {
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<WinHandle> {
|
||||
let _ = security_attributes;
|
||||
let name_wide = name.map(|n| n.as_wtf8().to_wide_with_nul());
|
||||
let name_ptr = name_wide.as_ref().map_or(null(), |n| n.as_ptr());
|
||||
host_winapi::create_mutex_w(initial_owner, name_ptr)
|
||||
let name_wide = name.map(|n| n.as_wtf8().to_wide_cstring());
|
||||
host_winapi::create_mutex_w(initial_owner, name_wide.as_deref())
|
||||
.map(WinHandle)
|
||||
.map_err(|e| e.to_pyexception(vm))
|
||||
}
|
||||
@@ -887,8 +861,8 @@ mod _winapi {
|
||||
name: PyStrRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<WinHandle> {
|
||||
let name_wide = name.as_wtf8().to_wide_with_nul();
|
||||
host_winapi::open_event_w(desired_access, inherit_handle, name_wide.as_ptr())
|
||||
let name_wide = name.as_wtf8().to_wide_cstring();
|
||||
host_winapi::open_event_w(desired_access, inherit_handle, &name_wide)
|
||||
.map(WinHandle)
|
||||
.map_err(|e| e.to_pyexception(vm))
|
||||
}
|
||||
@@ -935,7 +909,7 @@ mod _winapi {
|
||||
if is_main {
|
||||
let handle = crate::signal::get_sigint_event().map_or_else(
|
||||
|| {
|
||||
let handle = host_winapi::create_event_w(true, false, null())
|
||||
let handle = host_winapi::create_event_w(true, false, None)
|
||||
.unwrap_or(core::ptr::null_mut());
|
||||
if !handle.is_null() {
|
||||
crate::signal::set_sigint_event(handle as isize);
|
||||
@@ -968,17 +942,7 @@ mod _winapi {
|
||||
.collect(),
|
||||
)
|
||||
.into()),
|
||||
Err(host_winapi::BatchedWaitError::Timeout) => Err(vm
|
||||
.new_os_subtype_error(
|
||||
vm.ctx.exceptions.timeout_error.to_owned(),
|
||||
None,
|
||||
"timed out",
|
||||
)
|
||||
.upcast()),
|
||||
Err(host_winapi::BatchedWaitError::Interrupted) => Err(vm
|
||||
.new_errno_error(libc::EINTR, "Interrupted system call")
|
||||
.upcast()),
|
||||
Err(host_winapi::BatchedWaitError::Os(err)) => Err(vm.new_os_error(err as i32)),
|
||||
Err(err) => Err(err.to_pyexception(vm)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1000,14 +964,13 @@ mod _winapi {
|
||||
vm.new_value_error("CreateFileMapping: name must not contain null characters")
|
||||
);
|
||||
}
|
||||
let name_wide = name.as_ref().map(|n| n.as_wtf8().to_wide_with_nul());
|
||||
let name_ptr = name_wide.as_ref().map_or(null(), |n| n.as_ptr());
|
||||
let name_wide = name.as_ref().map(|n| n.as_wtf8().to_wide_cstring());
|
||||
host_winapi::create_file_mapping_w(
|
||||
file_handle.0,
|
||||
protect,
|
||||
max_size_high,
|
||||
max_size_low,
|
||||
name_ptr,
|
||||
name_wide.as_deref(),
|
||||
)
|
||||
.map(WinHandle)
|
||||
.map_err(|e| e.to_pyexception(vm))
|
||||
@@ -1026,8 +989,8 @@ mod _winapi {
|
||||
vm.new_value_error("OpenFileMapping: name must not contain null characters")
|
||||
);
|
||||
}
|
||||
let name_wide = name.as_wtf8().to_wide_with_nul();
|
||||
host_winapi::open_file_mapping_w(desired_access, inherit_handle, name_wide.as_ptr())
|
||||
let name_wide = name.as_wtf8().to_wide_cstring();
|
||||
host_winapi::open_file_mapping_w(desired_access, inherit_handle, &name_wide)
|
||||
.map(WinHandle)
|
||||
.map_err(|e| e.to_pyexception(vm))
|
||||
}
|
||||
@@ -1073,10 +1036,9 @@ mod _winapi {
|
||||
_progress_routine: OptionalArg<PyObjectRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
let src_wide = existing_file_name.as_wtf8().to_wide_with_nul();
|
||||
let dst_wide = new_file_name.as_wtf8().to_wide_with_nul();
|
||||
host_winapi::copy_file2(src_wide.as_ptr(), dst_wide.as_ptr(), flags)
|
||||
.map_err(|e| e.to_pyexception(vm))
|
||||
let src_wide = existing_file_name.as_wtf8().to_wide_cstring();
|
||||
let dst_wide = new_file_name.as_wtf8().to_wide_cstring();
|
||||
host_winapi::copy_file2(&src_wide, &dst_wide, flags).map_err(|e| e.to_pyexception(vm))
|
||||
}
|
||||
|
||||
/// _mimetypes_read_windows_registry - Read MIME type associations from registry.
|
||||
|
||||
@@ -10,8 +10,6 @@ mod _wmi {
|
||||
use crate::{PyResult, VirtualMachine};
|
||||
use rustpython_host_env::wmi as host_wmi;
|
||||
|
||||
const BUFFER_SIZE: usize = 8192;
|
||||
|
||||
#[pyfunction]
|
||||
fn exec_query(query: PyStrRef, vm: &VirtualMachine) -> PyResult<String> {
|
||||
let query_str = query.expect_str();
|
||||
@@ -23,14 +21,6 @@ mod _wmi {
|
||||
return Err(vm.new_value_error("only SELECT queries are supported"));
|
||||
}
|
||||
|
||||
match host_wmi::exec_query(query_str) {
|
||||
Ok(result) => Ok(result),
|
||||
Err(host_wmi::ExecQueryError::MoreData) => {
|
||||
Err(vm.new_os_error(format!("Query returns more than {BUFFER_SIZE} characters")))
|
||||
}
|
||||
Err(host_wmi::ExecQueryError::Code(err)) => {
|
||||
Err(std::io::Error::from_raw_os_error(err as i32).to_pyexception(vm))
|
||||
}
|
||||
}
|
||||
host_wmi::exec_query(query_str).map_err(|err| err.to_pyexception(vm))
|
||||
}
|
||||
}
|
||||
+16
-56
@@ -412,7 +412,6 @@ pub(crate) mod module {
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<intptr_t> {
|
||||
use crate::function::FsPath;
|
||||
use core::iter::once;
|
||||
|
||||
let path = path.to_wide_cstring(vm)?;
|
||||
|
||||
@@ -429,14 +428,8 @@ pub(crate) mod module {
|
||||
return Err(vm.new_value_error("spawnv() arg 3 first element cannot be empty"));
|
||||
}
|
||||
|
||||
let argv_spawn: Vec<*const u16> = argv
|
||||
.iter()
|
||||
.map(|v| v.as_ptr())
|
||||
.chain(once(core::ptr::null()))
|
||||
.collect();
|
||||
|
||||
host_nt::spawnv(mode, path.as_ptr(), argv_spawn.as_ptr())
|
||||
.map_err(|_| vm.new_last_errno_error())
|
||||
let argv_refs: Vec<&widestring::WideCStr> = argv.iter().map(|s| s.as_ref()).collect();
|
||||
host_nt::spawnv(mode, &path, &argv_refs).map_err(|_| vm.new_last_errno_error())
|
||||
}
|
||||
|
||||
#[cfg(target_env = "msvc")]
|
||||
@@ -449,7 +442,6 @@ pub(crate) mod module {
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<intptr_t> {
|
||||
use crate::function::FsPath;
|
||||
use core::iter::once;
|
||||
|
||||
let path = path.to_wide_cstring(vm)?;
|
||||
|
||||
@@ -466,12 +458,6 @@ pub(crate) mod module {
|
||||
return Err(vm.new_value_error("spawnve() arg 2 first element cannot be empty"));
|
||||
}
|
||||
|
||||
let argv_spawn: Vec<*const u16> = argv
|
||||
.iter()
|
||||
.map(|v| v.as_ptr())
|
||||
.chain(once(core::ptr::null()))
|
||||
.collect();
|
||||
|
||||
// Build environment strings as "KEY=VALUE\0" wide strings
|
||||
let mut env_strings: Vec<widestring::WideCString> = Vec::new();
|
||||
for (key, value) in env {
|
||||
@@ -494,14 +480,10 @@ pub(crate) mod module {
|
||||
);
|
||||
}
|
||||
|
||||
let envp: Vec<*const u16> = env_strings
|
||||
.iter()
|
||||
.map(|s| s.as_ptr())
|
||||
.chain(once(core::ptr::null()))
|
||||
.collect();
|
||||
|
||||
host_nt::spawnve(mode, path.as_ptr(), argv_spawn.as_ptr(), envp.as_ptr())
|
||||
.map_err(|_| vm.new_last_errno_error())
|
||||
let argv_refs: Vec<&widestring::WideCStr> = argv.iter().map(|s| s.as_ref()).collect();
|
||||
let envp_refs: Vec<&widestring::WideCStr> =
|
||||
env_strings.iter().map(|s| s.as_ref()).collect();
|
||||
host_nt::spawnve(mode, &path, &argv_refs, &envp_refs).map_err(|_| vm.new_last_errno_error())
|
||||
}
|
||||
|
||||
#[cfg(target_env = "msvc")]
|
||||
@@ -511,8 +493,6 @@ pub(crate) mod module {
|
||||
argv: Either<PyListRef, PyTupleRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
use core::iter::once;
|
||||
|
||||
let make_widestring =
|
||||
|s: &str| widestring::WideCString::from_os_str(s).map_err(|err| err.to_pyexception(vm));
|
||||
|
||||
@@ -531,13 +511,8 @@ pub(crate) mod module {
|
||||
return Err(vm.new_value_error("execv() arg 2 first element cannot be empty"));
|
||||
}
|
||||
|
||||
let argv_execv: Vec<*const u16> = argv
|
||||
.iter()
|
||||
.map(|v| v.as_ptr())
|
||||
.chain(once(core::ptr::null()))
|
||||
.collect();
|
||||
|
||||
host_nt::execv(path.as_ptr(), argv_execv.as_ptr()).map_err(|_| vm.new_last_errno_error())
|
||||
let argv_refs: Vec<&widestring::WideCStr> = argv.iter().map(|s| s.as_ref()).collect();
|
||||
host_nt::execv(&path, &argv_refs).map_err(|_| vm.new_last_errno_error())
|
||||
}
|
||||
|
||||
#[cfg(target_env = "msvc")]
|
||||
@@ -548,8 +523,6 @@ pub(crate) mod module {
|
||||
env: ArgMapping,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
use core::iter::once;
|
||||
|
||||
let make_widestring =
|
||||
|s: &str| widestring::WideCString::from_os_str(s).map_err(|err| err.to_pyexception(vm));
|
||||
|
||||
@@ -568,12 +541,6 @@ pub(crate) mod module {
|
||||
return Err(vm.new_value_error("execve: argv first element cannot be empty"));
|
||||
}
|
||||
|
||||
let argv_execve: Vec<*const u16> = argv
|
||||
.iter()
|
||||
.map(|v| v.as_ptr())
|
||||
.chain(once(core::ptr::null()))
|
||||
.collect();
|
||||
|
||||
let env = crate::stdlib::os::envobj_to_dict(env, vm)?;
|
||||
// Build environment strings as "KEY=VALUE\0" wide strings
|
||||
let mut env_strings: Vec<widestring::WideCString> = Vec::new();
|
||||
@@ -598,14 +565,10 @@ pub(crate) mod module {
|
||||
env_strings.push(make_widestring(&env_str)?);
|
||||
}
|
||||
|
||||
let envp: Vec<*const u16> = env_strings
|
||||
.iter()
|
||||
.map(|s| s.as_ptr())
|
||||
.chain(once(core::ptr::null()))
|
||||
.collect();
|
||||
|
||||
host_nt::execve(path.as_ptr(), argv_execve.as_ptr(), envp.as_ptr())
|
||||
.map_err(|_| vm.new_last_errno_error())
|
||||
let argv_refs: Vec<&widestring::WideCStr> = argv.iter().map(|s| s.as_ref()).collect();
|
||||
let envp_refs: Vec<&widestring::WideCStr> =
|
||||
env_strings.iter().map(|s| s.as_ref()).collect();
|
||||
host_nt::execve(&path, &argv_refs, &envp_refs).map_err(|_| vm.new_last_errno_error())
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
@@ -792,7 +755,9 @@ pub(crate) mod module {
|
||||
.chain(core::iter::once(0)) // null-terminated
|
||||
.collect();
|
||||
|
||||
if let Some(len) = host_nt::path_skip_root(backslashed.as_ptr()) {
|
||||
let backslashed_wide = widestring::WideCStr::from_slice_truncate(&backslashed)
|
||||
.expect("backslashed is null-terminated");
|
||||
if let Some(len) = host_nt::path_skip_root(backslashed_wide) {
|
||||
assert!(
|
||||
len < backslashed.len(), // backslashed is null-terminated
|
||||
"path: {:?} {} < {}",
|
||||
@@ -1107,12 +1072,7 @@ pub(crate) mod module {
|
||||
Err(host_nt::ReadlinkError::Io(err)) => {
|
||||
Err(OSErrorBuilder::with_filename(&err, path.clone(), vm))
|
||||
}
|
||||
Err(host_nt::ReadlinkError::NotSymbolicLink) => {
|
||||
Err(vm.new_value_error("not a symbolic link"))
|
||||
}
|
||||
Err(host_nt::ReadlinkError::InvalidReparseData) => {
|
||||
Err(vm.new_os_error("Invalid reparse data".to_owned()))
|
||||
}
|
||||
Err(err) => Err(err.to_pyexception(vm)),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
-30
@@ -156,8 +156,6 @@ impl ToPyObject for crt_fd::Borrowed<'_> {
|
||||
pub(super) mod _os {
|
||||
use super::{DirFd, FollowSymlinks, SupportFunc};
|
||||
use crate::host_env::fileutils::StatStruct;
|
||||
#[cfg(windows)]
|
||||
use crate::host_env::windows::ToWideString;
|
||||
#[cfg(any(unix, windows))]
|
||||
use crate::utils::ToCString;
|
||||
use crate::{
|
||||
@@ -466,11 +464,6 @@ pub(super) mod _os {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
unsafe extern "C" {
|
||||
fn _wputenv(envstring: *const u16) -> libc::c_int;
|
||||
}
|
||||
|
||||
/// Check if wide string length exceeds Windows environment variable limit.
|
||||
#[cfg(windows)]
|
||||
fn check_env_var_len(wide_len: usize, vm: &VirtualMachine) -> PyResult<()> {
|
||||
@@ -498,15 +491,13 @@ pub(super) mod _os {
|
||||
return Err(vm.new_value_error("illegal environment variable name"));
|
||||
}
|
||||
let env_str = format!("{key_str}={value_str}");
|
||||
let wide = env_str.to_wide_with_nul();
|
||||
check_env_var_len(wide.len(), vm)?;
|
||||
// env_str is guaranteed nul-free by the checks above.
|
||||
let wide = widestring::WideCString::from_str(&env_str)
|
||||
.expect("env_str validated to contain no NUL");
|
||||
check_env_var_len(wide.len() + 1, vm)?;
|
||||
|
||||
// Use _wputenv like CPython (not SetEnvironmentVariableW) to update CRT environ
|
||||
let result = unsafe { rustpython_host_env::suppress_iph!(_wputenv(wide.as_ptr())) };
|
||||
if result != 0 {
|
||||
return Err(vm.new_last_errno_error());
|
||||
}
|
||||
Ok(())
|
||||
// Use _wputenv (not SetEnvironmentVariableW) to update CRT environ.
|
||||
rustpython_host_env::nt::wputenv(&wide).map_err(|e| e.into_pyexception(vm))
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
@@ -545,15 +536,13 @@ pub(super) mod _os {
|
||||
}
|
||||
// "key=" to unset (empty value removes the variable)
|
||||
let env_str = format!("{key_str}=");
|
||||
let wide = env_str.to_wide_with_nul();
|
||||
check_env_var_len(wide.len(), vm)?;
|
||||
// env_str is guaranteed nul-free by the checks above.
|
||||
let wide = widestring::WideCString::from_str(&env_str)
|
||||
.expect("env_str validated to contain no NUL");
|
||||
check_env_var_len(wide.len() + 1, vm)?;
|
||||
|
||||
// Use _wputenv like CPython (not SetEnvironmentVariableW) to update CRT environ
|
||||
let result = unsafe { rustpython_host_env::suppress_iph!(_wputenv(wide.as_ptr())) };
|
||||
if result != 0 {
|
||||
return Err(vm.new_last_errno_error());
|
||||
}
|
||||
Ok(())
|
||||
// Use _wputenv (not SetEnvironmentVariableW) to update CRT environ.
|
||||
rustpython_host_env::nt::wputenv(&wide).map_err(|e| e.into_pyexception(vm))
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
@@ -1434,10 +1423,7 @@ pub(super) mod _os {
|
||||
|
||||
#[pyfunction]
|
||||
fn abort() {
|
||||
unsafe extern "C" {
|
||||
fn abort();
|
||||
}
|
||||
unsafe { abort() }
|
||||
crate::host_env::os::abort()
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
@@ -1445,9 +1431,7 @@ pub(super) mod _os {
|
||||
if size < 0 {
|
||||
return Err(vm.new_value_error("negative argument not allowed"));
|
||||
}
|
||||
let mut buf = vec![0u8; size as usize];
|
||||
getrandom::fill(&mut buf).map_err(|e| io::Error::from(e).into_pyexception(vm))?;
|
||||
Ok(buf)
|
||||
crate::host_env::os::urandom(size as usize).map_err(|e| e.into_pyexception(vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
|
||||
@@ -18,7 +18,7 @@ pub mod module {
|
||||
use crate::{
|
||||
AsObject, Py, PyObjectRef, PyResult, VirtualMachine,
|
||||
builtins::{PyDictRef, PyInt, PyListRef, PyTupleRef, PyUtf8Str},
|
||||
convert::{IntoPyException, ToPyObject, TryFromObject},
|
||||
convert::{IntoPyException, ToPyException, ToPyObject, TryFromObject},
|
||||
exceptions::OSErrorBuilder,
|
||||
function::{ArgMapping, Either, KwArgs, OptionalArg},
|
||||
ospath::{OsPath, OsPathOrFd},
|
||||
@@ -380,15 +380,8 @@ pub mod module {
|
||||
|
||||
#[pyfunction]
|
||||
pub(super) fn access(path: OsPath, mode: u8, vm: &VirtualMachine) -> PyResult<bool> {
|
||||
match rustpython_host_env::posix::check_access(path.as_ref(), mode) {
|
||||
Ok(ok) => Ok(ok),
|
||||
Err(rustpython_host_env::posix::AccessError::InvalidMode) => Err(vm.new_value_error(
|
||||
"One of the flags is wrong, there are only 4 possibilities F_OK, R_OK, W_OK and X_OK",
|
||||
)),
|
||||
Err(rustpython_host_env::posix::AccessError::Os(err)) => {
|
||||
Err(io::Error::from_raw_os_error(err).into_pyexception(vm))
|
||||
}
|
||||
}
|
||||
rustpython_host_env::posix::check_access(path.as_ref(), mode)
|
||||
.map_err(|err| err.to_pyexception(vm))
|
||||
}
|
||||
|
||||
#[pyattr]
|
||||
@@ -1006,16 +999,9 @@ pub mod module {
|
||||
#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "netbsd",))]
|
||||
#[pyfunction]
|
||||
fn lchmod(path: OsPath, mode: u32, vm: &VirtualMachine) -> PyResult<()> {
|
||||
unsafe extern "C" {
|
||||
fn lchmod(path: *const libc::c_char, mode: libc::mode_t) -> libc::c_int;
|
||||
}
|
||||
let c_path = path.clone().into_cstring(vm)?;
|
||||
if unsafe { lchmod(c_path.as_ptr(), mode as libc::mode_t) } == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
let err = std::io::Error::last_os_error();
|
||||
Err(OSErrorBuilder::with_filename(&err, path, vm))
|
||||
}
|
||||
rustpython_host_env::posix::lchmod(&c_path, mode as libc::mode_t)
|
||||
.map_err(|err| OSErrorBuilder::with_filename(&err, path, vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
@@ -1667,27 +1653,11 @@ pub mod module {
|
||||
Ok(_os::TerminalSizeData { columns, lines })
|
||||
}
|
||||
|
||||
// from libstd:
|
||||
// https://github.com/rust-lang/rust/blob/daecab3a784f28082df90cebb204998051f3557d/src/libstd/sys/unix/fs.rs#L1251
|
||||
#[cfg(target_os = "macos")]
|
||||
unsafe extern "C" {
|
||||
fn fcopyfile(
|
||||
in_fd: libc::c_int,
|
||||
out_fd: libc::c_int,
|
||||
state: *mut libc::c_void, // copyfile_state_t (unused)
|
||||
flags: u32, // copyfile_flags_t
|
||||
) -> libc::c_int;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[pyfunction]
|
||||
fn _fcopyfile(in_fd: i32, out_fd: i32, flags: i32, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let ret = unsafe { fcopyfile(in_fd, out_fd, core::ptr::null_mut(), flags as u32) };
|
||||
if ret < 0 {
|
||||
Err(vm.new_last_errno_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
rustpython_host_env::posix::fcopyfile(in_fd, out_fd, flags as u32)
|
||||
.map_err(|err| err.into_pyexception(vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
|
||||
@@ -8,21 +8,6 @@ pub use decl::time;
|
||||
|
||||
pub(crate) use decl::module_def;
|
||||
|
||||
#[cfg(not(target_env = "msvc"))]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
unsafe extern "C" {
|
||||
#[cfg(not(target_os = "freebsd"))]
|
||||
#[link_name = "daylight"]
|
||||
static c_daylight: core::ffi::c_int;
|
||||
// pub static dstbias: std::ffi::c_int;
|
||||
#[link_name = "timezone"]
|
||||
static c_timezone: core::ffi::c_long;
|
||||
#[link_name = "tzname"]
|
||||
static c_tzname: [*const core::ffi::c_char; 2];
|
||||
#[link_name = "tzset"]
|
||||
fn c_tzset();
|
||||
}
|
||||
|
||||
#[pymodule(name = "time", with(#[cfg(any(unix, windows))] platform))]
|
||||
mod decl {
|
||||
#![allow(unreachable_pub)]
|
||||
@@ -36,7 +21,10 @@ mod decl {
|
||||
types::{PyStructSequence, struct_sequence_new},
|
||||
};
|
||||
#[cfg(any(unix, windows))]
|
||||
use crate::{common::wtf8::Wtf8Buf, convert::ToPyObject};
|
||||
use crate::{
|
||||
common::wtf8::Wtf8Buf,
|
||||
convert::{ToPyException, ToPyObject},
|
||||
};
|
||||
#[cfg(not(any(unix, windows)))]
|
||||
use chrono::{
|
||||
DateTime, Datelike, TimeZone, Timelike,
|
||||
@@ -219,7 +207,7 @@ mod decl {
|
||||
#[pyattr]
|
||||
fn altzone(_vm: &VirtualMachine) -> core::ffi::c_long {
|
||||
// TODO: RUSTPYTHON; Add support for using the C altzone
|
||||
unsafe { super::c_timezone - 3600 }
|
||||
crate::host_env::time::tz::timezone() - 3600
|
||||
}
|
||||
|
||||
#[cfg(target_env = "msvc")]
|
||||
@@ -235,7 +223,7 @@ mod decl {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[pyattr]
|
||||
fn timezone(_vm: &VirtualMachine) -> core::ffi::c_long {
|
||||
unsafe { super::c_timezone }
|
||||
crate::host_env::time::tz::timezone()
|
||||
}
|
||||
|
||||
#[cfg(target_env = "msvc")]
|
||||
@@ -252,7 +240,7 @@ mod decl {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[pyattr]
|
||||
fn daylight(_vm: &VirtualMachine) -> core::ffi::c_int {
|
||||
unsafe { super::c_daylight }
|
||||
crate::host_env::time::tz::daylight()
|
||||
}
|
||||
|
||||
#[cfg(target_env = "msvc")]
|
||||
@@ -269,13 +257,7 @@ mod decl {
|
||||
#[pyattr]
|
||||
fn tzname(vm: &VirtualMachine) -> crate::builtins::PyTupleRef {
|
||||
use crate::builtins::tuple::IntoPyTuple;
|
||||
|
||||
unsafe fn to_str(s: *const core::ffi::c_char) -> String {
|
||||
unsafe { core::ffi::CStr::from_ptr(s) }
|
||||
.to_string_lossy()
|
||||
.into_owned()
|
||||
}
|
||||
unsafe { (to_str(super::c_tzname[0]), to_str(super::c_tzname[1])) }.into_pytuple(vm)
|
||||
crate::host_env::time::tz::tzname_strings().into_pytuple(vm)
|
||||
}
|
||||
|
||||
#[cfg(target_env = "msvc")]
|
||||
@@ -411,7 +393,7 @@ mod decl {
|
||||
zone,
|
||||
gmtoff,
|
||||
})
|
||||
.map_err(|err| map_checked_tm_error(vm, err))
|
||||
.map_err(|err| err.to_pyexception(vm))
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
@@ -426,35 +408,7 @@ mod decl {
|
||||
tm_yday,
|
||||
tm_isdst,
|
||||
})
|
||||
.map_err(|err| map_checked_tm_error(vm, err))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(unix, windows))]
|
||||
fn map_checked_tm_error(
|
||||
vm: &VirtualMachine,
|
||||
err: host_time::CheckedTmError,
|
||||
) -> PyBaseExceptionRef {
|
||||
match err {
|
||||
host_time::CheckedTmError::YearOutOfRange => vm.new_overflow_error("year out of range"),
|
||||
host_time::CheckedTmError::MonthOutOfRange => vm.new_value_error("month out of range"),
|
||||
host_time::CheckedTmError::DayOfMonthOutOfRange => {
|
||||
vm.new_value_error("day of month out of range")
|
||||
}
|
||||
host_time::CheckedTmError::HourOutOfRange => vm.new_value_error("hour out of range"),
|
||||
host_time::CheckedTmError::MinuteOutOfRange => {
|
||||
vm.new_value_error("minute out of range")
|
||||
}
|
||||
host_time::CheckedTmError::SecondsOutOfRange => {
|
||||
vm.new_value_error("seconds out of range")
|
||||
}
|
||||
host_time::CheckedTmError::DayOfWeekOutOfRange => {
|
||||
vm.new_value_error("day of week out of range")
|
||||
}
|
||||
host_time::CheckedTmError::DayOfYearOutOfRange => {
|
||||
vm.new_value_error("day of year out of range")
|
||||
}
|
||||
host_time::CheckedTmError::EmbeddedNul => vm.new_value_error("embedded null character"),
|
||||
.map_err(|err| err.to_pyexception(vm))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -942,9 +896,7 @@ mod decl {
|
||||
) -> PyResult<()> {
|
||||
#[cfg(not(target_env = "msvc"))]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
unsafe {
|
||||
super::c_tzset()
|
||||
};
|
||||
crate::host_env::time::tz::tzset();
|
||||
|
||||
__module_exec(vm, module);
|
||||
Ok(())
|
||||
|
||||
@@ -7,7 +7,7 @@ pub(crate) use winreg::module_def;
|
||||
mod winreg {
|
||||
use crate::builtins::{PyInt, PyStr, PyTuple, PyTypeRef};
|
||||
use crate::common::hash::PyHash;
|
||||
use crate::convert::TryFromObject;
|
||||
use crate::convert::{ToPyException, TryFromObject};
|
||||
use crate::function::FuncArgs;
|
||||
use crate::host_env::windows::ToWideString;
|
||||
use crate::object::AsObject;
|
||||
@@ -27,7 +27,6 @@ mod winreg {
|
||||
vm: &VirtualMachine,
|
||||
code: i32,
|
||||
) -> crate::PyRef<crate::builtins::PyBaseException> {
|
||||
use crate::convert::ToPyException;
|
||||
std::io::Error::from_raw_os_error(code).to_pyexception(vm)
|
||||
}
|
||||
|
||||
@@ -256,45 +255,31 @@ mod winreg {
|
||||
key: PyRef<PyHkey>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyHkey> {
|
||||
if let Some(computer_name) = computer_name {
|
||||
let mut ret_key = core::ptr::null_mut();
|
||||
let wide_computer_name = computer_name.to_wide_with_nul();
|
||||
let res = unsafe {
|
||||
host_winreg::connect_registry(
|
||||
wide_computer_name.as_ptr(),
|
||||
key.hkey.load(),
|
||||
&mut ret_key,
|
||||
)
|
||||
};
|
||||
if res == 0 {
|
||||
Ok(PyHkey::new(ret_key))
|
||||
} else {
|
||||
Err(vm.new_os_error(format!("error code: {res}")))
|
||||
}
|
||||
let wide_computer_name = computer_name.map(|n| n.to_wide_cstring());
|
||||
let mut ret_key = core::ptr::null_mut();
|
||||
let res = unsafe {
|
||||
host_winreg::connect_registry(
|
||||
wide_computer_name.as_deref(),
|
||||
key.hkey.load(),
|
||||
&mut ret_key,
|
||||
)
|
||||
};
|
||||
if res == 0 {
|
||||
Ok(PyHkey::new(ret_key))
|
||||
} else {
|
||||
let mut ret_key = core::ptr::null_mut();
|
||||
let res = unsafe {
|
||||
host_winreg::connect_registry(core::ptr::null_mut(), key.hkey.load(), &mut ret_key)
|
||||
};
|
||||
if res == 0 {
|
||||
Ok(PyHkey::new(ret_key))
|
||||
} else {
|
||||
Err(vm.new_os_error(format!("error code: {res}")))
|
||||
}
|
||||
Err(os_error_from_windows_code(vm, res as i32))
|
||||
}
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn CreateKey(key: PyRef<PyHkey>, sub_key: String, vm: &VirtualMachine) -> PyResult<PyHkey> {
|
||||
let wide_sub_key = sub_key.to_wide_with_nul();
|
||||
let wide_sub_key = sub_key.to_wide_cstring();
|
||||
let mut out_key = core::ptr::null_mut();
|
||||
let res = unsafe {
|
||||
host_winreg::create_key(key.hkey.load(), wide_sub_key.as_ptr(), &mut out_key)
|
||||
};
|
||||
let res = unsafe { host_winreg::create_key(key.hkey.load(), &wide_sub_key, &mut out_key) };
|
||||
if res == 0 {
|
||||
Ok(PyHkey::new(out_key))
|
||||
} else {
|
||||
Err(vm.new_os_error(format!("error code: {res}")))
|
||||
Err(os_error_from_windows_code(vm, res as i32))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,13 +297,13 @@ mod winreg {
|
||||
|
||||
#[pyfunction]
|
||||
fn CreateKeyEx(args: CreateKeyExArgs, vm: &VirtualMachine) -> PyResult<PyHkey> {
|
||||
let wide_sub_key = args.sub_key.to_wide_with_nul();
|
||||
let wide_sub_key = args.sub_key.to_wide_cstring();
|
||||
let mut res: host_winreg::HKEY = core::ptr::null_mut();
|
||||
let err = unsafe {
|
||||
let key = args.key.hkey.load();
|
||||
host_winreg::create_key_ex(
|
||||
key,
|
||||
wide_sub_key.as_ptr(),
|
||||
&wide_sub_key,
|
||||
args.reserved,
|
||||
core::ptr::null_mut(),
|
||||
host_winreg::REG_OPTION_NON_VOLATILE,
|
||||
@@ -345,8 +330,8 @@ mod winreg {
|
||||
|
||||
#[pyfunction]
|
||||
fn DeleteKey(key: PyRef<PyHkey>, sub_key: String, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let wide_sub_key = sub_key.to_wide_with_nul();
|
||||
let res = unsafe { host_winreg::delete_key(key.hkey.load(), wide_sub_key.as_ptr()) };
|
||||
let wide_sub_key = sub_key.to_wide_cstring();
|
||||
let res = unsafe { host_winreg::delete_key(key.hkey.load(), &wide_sub_key) };
|
||||
if res == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
@@ -356,11 +341,8 @@ mod winreg {
|
||||
|
||||
#[pyfunction]
|
||||
fn DeleteValue(key: PyRef<PyHkey>, value: Option<String>, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let wide_value = value.map(|v| v.to_wide_with_nul());
|
||||
let value_ptr = wide_value
|
||||
.as_ref()
|
||||
.map_or(core::ptr::null(), |v| v.as_ptr());
|
||||
let res = unsafe { host_winreg::delete_value(key.hkey.load(), value_ptr) };
|
||||
let wide_value = value.map(|v| v.to_wide_cstring());
|
||||
let res = unsafe { host_winreg::delete_value(key.hkey.load(), wide_value.as_deref()) };
|
||||
if res == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
@@ -382,11 +364,11 @@ mod winreg {
|
||||
|
||||
#[pyfunction]
|
||||
fn DeleteKeyEx(args: DeleteKeyExArgs, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let wide_sub_key = args.sub_key.to_wide_with_nul();
|
||||
let wide_sub_key = args.sub_key.to_wide_cstring();
|
||||
let res = unsafe {
|
||||
host_winreg::delete_key_ex(
|
||||
args.key.hkey.load(),
|
||||
wide_sub_key.as_ptr(),
|
||||
&wide_sub_key,
|
||||
args.access,
|
||||
args.reserved,
|
||||
)
|
||||
@@ -519,10 +501,9 @@ mod winreg {
|
||||
file_name: String,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
let sub_key = sub_key.to_wide_with_nul();
|
||||
let file_name = file_name.to_wide_with_nul();
|
||||
let res =
|
||||
unsafe { host_winreg::load_key(key.hkey.load(), sub_key.as_ptr(), file_name.as_ptr()) };
|
||||
let sub_key = sub_key.to_wide_cstring();
|
||||
let file_name = file_name.to_wide_cstring();
|
||||
let res = unsafe { host_winreg::load_key(key.hkey.load(), &sub_key, &file_name) };
|
||||
if res == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
@@ -545,17 +526,11 @@ mod winreg {
|
||||
#[pyfunction]
|
||||
#[pyfunction(name = "OpenKeyEx")]
|
||||
fn OpenKey(args: OpenKeyArgs, vm: &VirtualMachine) -> PyResult<PyHkey> {
|
||||
let wide_sub_key = args.sub_key.to_wide_with_nul();
|
||||
let wide_sub_key = args.sub_key.to_wide_cstring();
|
||||
let mut res: host_winreg::HKEY = core::ptr::null_mut();
|
||||
let err = unsafe {
|
||||
let key = args.key.hkey.load();
|
||||
host_winreg::open_key_ex(
|
||||
key,
|
||||
wide_sub_key.as_ptr(),
|
||||
args.reserved,
|
||||
args.access,
|
||||
&mut res,
|
||||
)
|
||||
host_winreg::open_key_ex(key, &wide_sub_key, args.reserved, args.access, &mut res)
|
||||
};
|
||||
if err == 0 {
|
||||
Ok(PyHkey {
|
||||
@@ -592,14 +567,7 @@ mod winreg {
|
||||
}
|
||||
|
||||
host_winreg::query_default_value(hkey, sub_key.as_deref().map(std::ffi::OsStr::new))
|
||||
.map_err(|err| match err {
|
||||
host_winreg::QueryStringError::Code(err) => {
|
||||
os_error_from_windows_code(vm, err as i32)
|
||||
}
|
||||
host_winreg::QueryStringError::Utf16(e) => {
|
||||
vm.new_value_error(format!("UTF16 error: {e}"))
|
||||
}
|
||||
})
|
||||
.map_err(|err| err.to_pyexception(vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
@@ -614,8 +582,8 @@ mod winreg {
|
||||
|
||||
#[pyfunction]
|
||||
fn SaveKey(key: PyRef<PyHkey>, file_name: String, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let file_name = file_name.to_wide_with_nul();
|
||||
let res = unsafe { host_winreg::save_key(key.hkey.load(), file_name.as_ptr()) };
|
||||
let file_name = file_name.to_wide_cstring();
|
||||
let res = unsafe { host_winreg::save_key(key.hkey.load(), &file_name) };
|
||||
if res == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
@@ -825,17 +793,15 @@ mod winreg {
|
||||
value: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
let wide_value_name = value_name.as_deref().map(|s| s.to_wide_with_nul());
|
||||
let value_name_ptr = wide_value_name
|
||||
.as_deref()
|
||||
.map_or(core::ptr::null(), |s| s.as_ptr());
|
||||
let wide_value_name = value_name.as_deref().map(|s| s.to_wide_cstring());
|
||||
let reg_value = py2reg(value, typ, vm)?;
|
||||
let (ptr, len) = match ®_value {
|
||||
Some(v) => (v.as_ptr(), v.len() as u32),
|
||||
None => (core::ptr::null(), 0),
|
||||
};
|
||||
let res =
|
||||
unsafe { host_winreg::set_value_ex(key.hkey.load(), value_name_ptr, typ, ptr, len) };
|
||||
let res = unsafe {
|
||||
host_winreg::set_value_ex(key.hkey.load(), wide_value_name.as_deref(), typ, ptr, len)
|
||||
};
|
||||
if res != 0 {
|
||||
return Err(os_error_from_windows_code(vm, res as i32));
|
||||
}
|
||||
@@ -875,13 +841,7 @@ mod winreg {
|
||||
|
||||
#[pyfunction]
|
||||
fn ExpandEnvironmentStrings(i: String, vm: &VirtualMachine) -> PyResult<String> {
|
||||
host_winreg::expand_environment_strings(std::ffi::OsStr::new(&i)).map_err(|err| match err {
|
||||
host_winreg::ExpandEnvironmentStringsError::Os => {
|
||||
vm.new_os_error("ExpandEnvironmentStringsW failed".to_string())
|
||||
}
|
||||
host_winreg::ExpandEnvironmentStringsError::Utf16(e) => {
|
||||
vm.new_value_error(format!("UTF16 error: {e}"))
|
||||
}
|
||||
})
|
||||
host_winreg::expand_environment_strings(std::ffi::OsStr::new(&i))
|
||||
.map_err(|err| err.to_pyexception(vm))
|
||||
}
|
||||
}
|
||||
@@ -3,18 +3,6 @@
|
||||
|
||||
pub(crate) use winsound::module_def;
|
||||
|
||||
mod win32 {
|
||||
#[link(name = "winmm")]
|
||||
unsafe extern "system" {
|
||||
pub(super) fn PlaySoundW(pszSound: *const u16, hmod: isize, fdwSound: u32) -> i32;
|
||||
}
|
||||
|
||||
unsafe extern "system" {
|
||||
pub(super) fn Beep(dwFreq: u32, dwDuration: u32) -> i32;
|
||||
pub(super) fn MessageBeep(uType: u32) -> i32;
|
||||
}
|
||||
}
|
||||
|
||||
#[pymodule]
|
||||
mod winsound {
|
||||
use crate::builtins::{PyBytes, PyStr};
|
||||
@@ -22,6 +10,7 @@ mod winsound {
|
||||
use crate::host_env::windows::ToWideString;
|
||||
use crate::protocol::PyBuffer;
|
||||
use crate::{AsObject, PyObjectRef, PyResult, VirtualMachine};
|
||||
use rustpython_host_env::winsound::{PlaySoundSource, play_sound};
|
||||
|
||||
// PlaySound flags
|
||||
#[pyattr]
|
||||
@@ -79,32 +68,34 @@ mod winsound {
|
||||
flags: i32,
|
||||
}
|
||||
|
||||
fn map_play_err(
|
||||
vm: &VirtualMachine,
|
||||
) -> impl FnOnce(
|
||||
rustpython_host_env::winsound::PlaySoundError,
|
||||
) -> crate::builtins::PyBaseExceptionRef
|
||||
+ '_ {
|
||||
use rustpython_host_env::winsound::PlaySoundError::*;
|
||||
|err| match err {
|
||||
MemoryAsyncRejected => vm.new_runtime_error("Cannot play asynchronously from memory"),
|
||||
MemoryFlagWithoutBuffer | CallFailed => vm.new_runtime_error("Failed to play sound"),
|
||||
}
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn PlaySound(args: PlaySoundArgs, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let sound = args.sound;
|
||||
let flags = args.flags as u32;
|
||||
|
||||
if vm.is_none(&sound) {
|
||||
let ok = unsafe { super::win32::PlaySoundW(core::ptr::null(), 0, flags) };
|
||||
if ok == 0 {
|
||||
return Err(vm.new_runtime_error("Failed to play sound"));
|
||||
}
|
||||
return Ok(());
|
||||
return play_sound(PlaySoundSource::Stop, flags).map_err(map_play_err(vm));
|
||||
}
|
||||
|
||||
if flags & SND_MEMORY != 0 {
|
||||
if flags & SND_ASYNC != 0 {
|
||||
return Err(vm.new_runtime_error("Cannot play asynchronously from memory"));
|
||||
}
|
||||
let buffer = PyBuffer::try_from_borrowed_object(vm, &sound)?;
|
||||
let buf = buffer
|
||||
.as_contiguous()
|
||||
.ok_or_else(|| vm.new_type_error("a bytes-like object is required, not 'str'"))?;
|
||||
let ok = unsafe { super::win32::PlaySoundW(buf.as_ptr() as *const u16, 0, flags) };
|
||||
if ok == 0 {
|
||||
return Err(vm.new_runtime_error("Failed to play sound"));
|
||||
}
|
||||
return Ok(());
|
||||
return play_sound(PlaySoundSource::Memory(&buf), flags).map_err(map_play_err(vm));
|
||||
}
|
||||
|
||||
if sound.downcastable::<PyBytes>() {
|
||||
@@ -157,11 +148,9 @@ mod winsound {
|
||||
}
|
||||
|
||||
let wide = path.to_wide_with_nul();
|
||||
let ok = unsafe { super::win32::PlaySoundW(wide.as_ptr(), 0, flags) };
|
||||
if ok == 0 {
|
||||
return Err(vm.new_runtime_error("Failed to play sound"));
|
||||
}
|
||||
Ok(())
|
||||
let wide_cstr = widestring::WideCStr::from_slice_truncate(&wide)
|
||||
.map_err(|_| vm.new_value_error("embedded null character"))?;
|
||||
play_sound(PlaySoundSource::Name(wide_cstr), flags).map_err(map_play_err(vm))
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
@@ -178,11 +167,11 @@ mod winsound {
|
||||
return Err(vm.new_value_error("frequency must be in 37 thru 32767"));
|
||||
}
|
||||
|
||||
let ok = unsafe { super::win32::Beep(args.frequency as u32, args.duration as u32) };
|
||||
if ok == 0 {
|
||||
return Err(vm.new_runtime_error("Failed to beep"));
|
||||
if rustpython_host_env::winsound::beep(args.frequency as u32, args.duration as u32) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(vm.new_runtime_error("Failed to beep"))
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
@@ -193,10 +182,6 @@ mod winsound {
|
||||
|
||||
#[pyfunction]
|
||||
fn MessageBeep(args: MessageBeepArgs, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let ok = unsafe { super::win32::MessageBeep(args.r#type) };
|
||||
if ok == 0 {
|
||||
return Err(std::io::Error::last_os_error().into_pyexception(vm));
|
||||
}
|
||||
Ok(())
|
||||
rustpython_host_env::winsound::message_beep(args.r#type).map_err(|e| e.into_pyexception(vm))
|
||||
}
|
||||
}
|
||||
@@ -572,9 +572,7 @@ pub(super) fn stw_trace(msg: core::fmt::Arguments<'_>) {
|
||||
crate::stdlib::_thread::get_ident(),
|
||||
msg
|
||||
);
|
||||
unsafe {
|
||||
let _ = libc::write(libc::STDERR_FILENO, out.buf.as_ptr().cast(), out.len);
|
||||
}
|
||||
crate::host_env::io::write_stderr_raw(&out.buf[..out.len]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user