mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 10:44:36 +08:00
Create rustpython-host-env (#7582)
* Create rustpython-host-env crate; move host abstractions out of common
Move os, crt_fd, fileutils, windows, macros modules from
rustpython-common into the new rustpython-host-env crate.
This isolates host OS API wrappers behind a crate boundary
with zero Python runtime dependency.
- Add crates/host_env to workspace
- Drop nix, windows-sys, widestring deps from common
- Wire vm and stdlib to depend on rustpython-host-env
- Migrate all imports from common::{os,crt_fd,fileutils,windows}
to rustpython_host_env::
* refactor: extract host helpers
Agent-Logs-Url: https://github.com/RustPython/RustPython/sessions/48d1e64d-37ce-409f-b511-8e61a349665c
Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com>
* lint: enforce direct host API boundaries
Agent-Logs-Url: https://github.com/RustPython/RustPython/sessions/97225fb7-7b3d-4197-a77c-eb44aead5b13
Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com>
* refactor: extract remaining host env helpers
Agent-Logs-Url: https://github.com/RustPython/RustPython/sessions/d96f57e1-b196-4460-9983-97d5ff118835
Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com>
* fix: clean extracted host env follow-up
Agent-Logs-Url: https://github.com/RustPython/RustPython/sessions/d96f57e1-b196-4460-9983-97d5ff118835
Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com>
* fix: document env mutation safety
Agent-Logs-Url: https://github.com/RustPython/RustPython/sessions/d96f57e1-b196-4460-9983-97d5ff118835
Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com>
* refactor: split host fs helpers from fileutils
Agent-Logs-Url: https://github.com/RustPython/RustPython/sessions/c57424c5-0e1d-490a-82b3-2d2f6c8cf2cd
Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com>
* fix: resolve latest host env ci regressions
Agent-Logs-Url: https://github.com/RustPython/RustPython/sessions/899eb717-ebc6-4a4a-870c-2a15c5f33e02
Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com>
* fix: resolve remaining windows clippy host fs calls
Agent-Logs-Url: https://github.com/RustPython/RustPython/sessions/12f32740-8173-4b10-a1d6-00b29e90a8ec
Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com>
* host_env
---------
Co-authored-by: Jeong, YunWon <jeong@youknowone.org>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com>
This commit is contained in:
77 files changed
+1373
-777
No files matched your search
Generated
+15
-3
@@ -3143,7 +3143,6 @@ dependencies = [
|
||||
"malachite-base",
|
||||
"malachite-bigint",
|
||||
"malachite-q",
|
||||
"nix 0.30.1",
|
||||
"num-complex",
|
||||
"num-traits",
|
||||
"parking_lot",
|
||||
@@ -3152,8 +3151,6 @@ dependencies = [
|
||||
"rustpython-wtf8",
|
||||
"siphasher",
|
||||
"unicode_names2 2.0.0",
|
||||
"widestring",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3222,6 +3219,19 @@ dependencies = [
|
||||
"phf 0.13.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustpython-host_env"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"nix 0.30.1",
|
||||
"num-traits",
|
||||
"rustpython-wtf8",
|
||||
"termios",
|
||||
"widestring",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustpython-jit"
|
||||
version = "0.5.0"
|
||||
@@ -3409,6 +3419,7 @@ dependencies = [
|
||||
"rustls-platform-verifier",
|
||||
"rustpython-common",
|
||||
"rustpython-derive",
|
||||
"rustpython-host_env",
|
||||
"rustpython-ruff_python_ast",
|
||||
"rustpython-ruff_python_parser",
|
||||
"rustpython-ruff_source_file",
|
||||
@@ -3488,6 +3499,7 @@ dependencies = [
|
||||
"rustpython-compiler",
|
||||
"rustpython-compiler-core",
|
||||
"rustpython-derive",
|
||||
"rustpython-host_env",
|
||||
"rustpython-jit",
|
||||
"rustpython-literal",
|
||||
"rustpython-ruff_python_ast",
|
||||
|
||||
@@ -145,6 +145,7 @@ rustpython-compiler-core = { path = "crates/compiler-core", version = "0.5.0" }
|
||||
rustpython-compiler = { path = "crates/compiler", version = "0.5.0" }
|
||||
rustpython-codegen = { path = "crates/codegen", version = "0.5.0" }
|
||||
rustpython-common = { path = "crates/common", version = "0.5.0" }
|
||||
rustpython-host_env = { path = "crates/host_env", version = "0.5.0" }
|
||||
rustpython-derive = { path = "crates/derive", version = "0.5.0" }
|
||||
rustpython-derive-impl = { path = "crates/derive-impl", version = "0.5.0" }
|
||||
rustpython-jit = { path = "crates/jit", version = "0.5.0" }
|
||||
|
||||
@@ -36,19 +36,5 @@ lock_api = "0.4"
|
||||
siphasher = "1"
|
||||
num-complex.workspace = true
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
nix = { workspace = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
widestring = { workspace = true }
|
||||
windows-sys = { workspace = true, features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_Networking_WinSock",
|
||||
"Win32_Storage_FileSystem",
|
||||
"Win32_System_Ioctl",
|
||||
"Win32_System_LibraryLoader",
|
||||
"Win32_System_SystemServices",
|
||||
] }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -0,0 +1,32 @@
|
||||
disallowed-methods = [
|
||||
{ path = "std::fs::read", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::write", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::read_to_string", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::read_dir", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::create_dir", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::create_dir_all", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::remove_file", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::remove_dir", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::metadata", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::symlink_metadata", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::canonicalize", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::File::open", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::File::create", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::OpenOptions::open", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::env::var", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::var_os", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::set_var", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::remove_var", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::vars", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::vars_os", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::current_dir", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::set_current_dir", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::temp_dir", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::process::Command::new", reason = "use rustpython_host_env for host process access" },
|
||||
{ path = "std::process::exit", reason = "use rustpython_host_env for host process access" },
|
||||
{ path = "std::process::abort", reason = "use rustpython_host_env for host process access" },
|
||||
{ path = "std::process::id", reason = "use rustpython_host_env for host process access" },
|
||||
{ path = "std::net::TcpStream::connect", reason = "use rustpython_host_env for host network access" },
|
||||
{ path = "std::net::TcpListener::bind", reason = "use rustpython_host_env for host network access" },
|
||||
{ path = "std::net::UdpSocket::bind", reason = "use rustpython_host_env for host network access" },
|
||||
]
|
||||
@@ -1,37 +1,26 @@
|
||||
//! A crate to hold types and functions common to all rustpython components.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![deny(clippy::disallowed_methods)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
pub use macros::*;
|
||||
|
||||
pub mod atomic;
|
||||
pub mod borrow;
|
||||
pub mod boxvec;
|
||||
pub mod cformat;
|
||||
#[cfg(all(feature = "std", any(unix, windows, target_os = "wasi")))]
|
||||
pub mod crt_fd;
|
||||
pub mod encodings;
|
||||
#[cfg(all(feature = "std", any(not(target_arch = "wasm32"), target_os = "wasi")))]
|
||||
pub mod fileutils;
|
||||
pub mod float_ops;
|
||||
pub mod format;
|
||||
pub mod hash;
|
||||
pub mod int;
|
||||
pub mod linked_list;
|
||||
pub mod lock;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod os;
|
||||
pub mod rand;
|
||||
pub mod rc;
|
||||
pub mod refcount;
|
||||
pub mod static_cell;
|
||||
pub mod str;
|
||||
#[cfg(all(feature = "std", windows))]
|
||||
pub mod windows;
|
||||
|
||||
pub use rustpython_wtf8 as wtf8;
|
||||
|
||||
|
||||
@@ -15,6 +15,10 @@ const WEAK_COUNT: usize = 1 << STRONG_WIDTH;
|
||||
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
#[allow(
|
||||
clippy::disallowed_methods,
|
||||
reason = "refcount overflow must preserve upstream abort semantics"
|
||||
)]
|
||||
fn refcount_overflow() -> ! {
|
||||
#[cfg(feature = "std")]
|
||||
std::process::abort();
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
[package]
|
||||
name = "rustpython-host_env"
|
||||
description = "Host OS API abstractions for RustPython"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
repository.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
rustpython-wtf8 = { workspace = true }
|
||||
|
||||
libc = { workspace = true }
|
||||
num-traits = { workspace = true }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
nix = { workspace = true }
|
||||
|
||||
[target.'cfg(all(unix, not(target_os = "ios"), not(target_os = "redox")))'.dependencies]
|
||||
termios = "0.3.3"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
widestring = { workspace = true }
|
||||
windows-sys = { workspace = true, features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_Globalization",
|
||||
"Win32_Networking_WinSock",
|
||||
"Win32_Storage_FileSystem",
|
||||
"Win32_System_Console",
|
||||
"Win32_System_Diagnostics_Debug",
|
||||
"Win32_System_Ioctl",
|
||||
"Win32_System_LibraryLoader",
|
||||
"Win32_System_SystemInformation",
|
||||
"Win32_System_SystemServices",
|
||||
"Win32_System_Threading",
|
||||
"Win32_System_Time",
|
||||
] }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -0,0 +1 @@
|
||||
disallowed-methods = []
|
||||
File renamed without changes.
@@ -0,0 +1,75 @@
|
||||
use std::io;
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// `arg` must be a valid pointer for the `request` passed to `ioctl` and must
|
||||
/// satisfy the platform ABI requirements for that request.
|
||||
pub unsafe fn ioctl_ptr(
|
||||
fd: i32,
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "wasi", target_os = "redox")))]
|
||||
pub fn lockf(fd: i32, cmd: i32, lock: &libc::flock) -> io::Result<i32> {
|
||||
let ret = unsafe {
|
||||
libc::fcntl(
|
||||
fd,
|
||||
if (cmd & libc::LOCK_NB) != 0 {
|
||||
libc::F_SETLK
|
||||
} else {
|
||||
libc::F_SETLKW
|
||||
},
|
||||
lock,
|
||||
)
|
||||
};
|
||||
if ret < 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
File renamed without changes.
@@ -0,0 +1,59 @@
|
||||
use std::{
|
||||
fs::{self, File, Metadata, ReadDir},
|
||||
io,
|
||||
path::Path,
|
||||
};
|
||||
|
||||
pub fn open(path: impl AsRef<Path>) -> io::Result<File> {
|
||||
File::open(path)
|
||||
}
|
||||
|
||||
pub fn read(path: impl AsRef<Path>) -> io::Result<Vec<u8>> {
|
||||
fs::read(path)
|
||||
}
|
||||
|
||||
pub fn read_to_string(path: impl AsRef<Path>) -> io::Result<String> {
|
||||
fs::read_to_string(path)
|
||||
}
|
||||
|
||||
pub fn read_dir(path: impl AsRef<Path>) -> io::Result<ReadDir> {
|
||||
fs::read_dir(path)
|
||||
}
|
||||
|
||||
pub fn create_dir_all(path: impl AsRef<Path>) -> io::Result<()> {
|
||||
fs::create_dir_all(path)
|
||||
}
|
||||
|
||||
pub fn remove_dir(path: impl AsRef<Path>) -> io::Result<()> {
|
||||
fs::remove_dir(path)
|
||||
}
|
||||
|
||||
pub fn remove_file(path: impl AsRef<Path>) -> io::Result<()> {
|
||||
fs::remove_file(path)
|
||||
}
|
||||
|
||||
pub fn metadata(path: impl AsRef<Path>) -> io::Result<Metadata> {
|
||||
fs::metadata(path)
|
||||
}
|
||||
|
||||
pub fn symlink_metadata(path: impl AsRef<Path>) -> io::Result<Metadata> {
|
||||
fs::symlink_metadata(path)
|
||||
}
|
||||
|
||||
pub fn open_write(path: impl AsRef<Path>) -> io::Result<File> {
|
||||
fs::OpenOptions::new().write(true).open(path)
|
||||
}
|
||||
|
||||
pub fn canonicalize(path: impl AsRef<Path>) -> io::Result<std::path::PathBuf> {
|
||||
fs::canonicalize(path)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn open_write_with_custom_flags(path: impl AsRef<Path>, flags: u32) -> io::Result<File> {
|
||||
use std::os::windows::fs::OpenOptionsExt;
|
||||
|
||||
fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.custom_flags(flags)
|
||||
.open(path)
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
extern crate alloc;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
pub use macros::*;
|
||||
|
||||
pub mod os;
|
||||
|
||||
#[cfg(any(unix, windows, target_os = "wasi"))]
|
||||
pub mod crt_fd;
|
||||
|
||||
#[cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))]
|
||||
pub mod fileutils;
|
||||
#[cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))]
|
||||
pub mod fs;
|
||||
|
||||
#[cfg(windows)]
|
||||
pub mod windows;
|
||||
|
||||
#[cfg(any(unix, target_os = "wasi"))]
|
||||
pub mod fcntl;
|
||||
#[cfg(any(unix, windows, target_os = "wasi"))]
|
||||
pub mod select;
|
||||
#[cfg(unix)]
|
||||
pub mod syslog;
|
||||
#[cfg(all(unix, not(target_os = "redox"), not(target_os = "ios")))]
|
||||
pub mod termios;
|
||||
|
||||
#[cfg(unix)]
|
||||
pub mod posix;
|
||||
#[cfg(all(unix, not(target_os = "redox"), not(target_os = "android")))]
|
||||
pub mod shm;
|
||||
#[cfg(unix)]
|
||||
pub mod signal;
|
||||
pub mod time;
|
||||
|
||||
#[cfg(windows)]
|
||||
pub mod msvcrt;
|
||||
#[cfg(windows)]
|
||||
pub mod nt;
|
||||
#[cfg(windows)]
|
||||
pub mod winapi;
|
||||
File renamed without changes.
@@ -0,0 +1,126 @@
|
||||
use alloc::{string::String, vec::Vec};
|
||||
use std::io;
|
||||
|
||||
use crate::crt_fd;
|
||||
use windows_sys::Win32::System::Diagnostics::Debug;
|
||||
|
||||
pub const LK_UNLCK: i32 = 0;
|
||||
pub const LK_LOCK: i32 = 1;
|
||||
pub const LK_NBLCK: i32 = 2;
|
||||
pub const LK_RLCK: i32 = 3;
|
||||
pub const LK_NBRLCK: i32 = 4;
|
||||
|
||||
unsafe extern "C" {
|
||||
fn _getch() -> i32;
|
||||
fn _getwch() -> u32;
|
||||
fn _getche() -> i32;
|
||||
fn _getwche() -> u32;
|
||||
fn _putch(c: u32) -> i32;
|
||||
fn _putwch(c: u16) -> u32;
|
||||
fn _ungetch(c: i32) -> i32;
|
||||
fn _ungetwch(c: u32) -> u32;
|
||||
fn _locking(fd: i32, mode: i32, nbytes: i64) -> i32;
|
||||
fn _heapmin() -> i32;
|
||||
fn _kbhit() -> i32;
|
||||
fn _setmode(fd: crt_fd::Borrowed<'_>, flags: i32) -> i32;
|
||||
}
|
||||
|
||||
pub fn setmode_binary(fd: crt_fd::Borrowed<'_>) {
|
||||
unsafe { suppress_iph!(_setmode(fd, libc::O_BINARY)) };
|
||||
}
|
||||
|
||||
pub fn getch() -> Vec<u8> {
|
||||
vec![unsafe { _getch() } as u8]
|
||||
}
|
||||
|
||||
pub fn getwch() -> String {
|
||||
let value = unsafe { _getwch() };
|
||||
char::from_u32(value)
|
||||
.unwrap_or_else(|| panic!("invalid unicode {value:#x} from _getwch"))
|
||||
.to_string()
|
||||
}
|
||||
|
||||
pub fn getche() -> Vec<u8> {
|
||||
vec![unsafe { _getche() } as u8]
|
||||
}
|
||||
|
||||
pub fn getwche() -> String {
|
||||
let value = unsafe { _getwche() };
|
||||
char::from_u32(value)
|
||||
.unwrap_or_else(|| panic!("invalid unicode {value:#x} from _getwche"))
|
||||
.to_string()
|
||||
}
|
||||
|
||||
pub fn putch(c: u8) {
|
||||
unsafe { suppress_iph!(_putch(c.into())) };
|
||||
}
|
||||
|
||||
pub fn putwch(c: char) {
|
||||
unsafe { suppress_iph!(_putwch(c as u16)) };
|
||||
}
|
||||
|
||||
pub fn ungetch(c: u8) -> io::Result<()> {
|
||||
let ret = unsafe { suppress_iph!(_ungetch(c as i32)) };
|
||||
if ret == -1 {
|
||||
Err(io::Error::from_raw_os_error(libc::ENOSPC))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ungetwch(c: char) -> io::Result<()> {
|
||||
let ret = unsafe { suppress_iph!(_ungetwch(c as u32)) };
|
||||
if ret == 0xFFFF {
|
||||
Err(io::Error::from_raw_os_error(libc::ENOSPC))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kbhit() -> i32 {
|
||||
unsafe { _kbhit() }
|
||||
}
|
||||
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn heapmin() -> io::Result<()> {
|
||||
let ret = unsafe { suppress_iph!(_heapmin()) };
|
||||
if ret == -1 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_error_mode() -> u32 {
|
||||
unsafe { suppress_iph!(Debug::GetErrorMode()) }
|
||||
}
|
||||
|
||||
pub fn set_error_mode(mode: Debug::THREAD_ERROR_MODE) -> u32 {
|
||||
unsafe { suppress_iph!(Debug::SetErrorMode(mode)) }
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// cspell:ignore hchmod
|
||||
use std::{ffi::OsStr, io, os::windows::io::AsRawHandle};
|
||||
|
||||
use crate::{crt_fd, windows::ToWideString};
|
||||
use windows_sys::Win32::{
|
||||
Foundation::HANDLE,
|
||||
Storage::FileSystem::{
|
||||
FILE_ATTRIBUTE_READONLY, FILE_BASIC_INFO, FileBasicInfo, GetFileAttributesW,
|
||||
GetFileInformationByHandleEx, INVALID_FILE_ATTRIBUTES, SetFileAttributesW,
|
||||
SetFileInformationByHandle,
|
||||
},
|
||||
};
|
||||
|
||||
#[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 {
|
||||
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());
|
||||
}
|
||||
|
||||
if mode & write_bit != 0 {
|
||||
info.FileAttributes &= !FILE_ATTRIBUTE_READONLY;
|
||||
} else {
|
||||
info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
|
||||
}
|
||||
|
||||
let ret = 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(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fchmod(fd: i32, mode: u32, write_bit: u32) -> io::Result<()> {
|
||||
let borrowed = unsafe { crt_fd::Borrowed::borrow_raw(fd) };
|
||||
let handle = crt_fd::as_handle(borrowed)?;
|
||||
win32_hchmod(handle.as_raw_handle() as HANDLE, mode, write_bit)
|
||||
}
|
||||
|
||||
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 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(())
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,13 @@
|
||||
// TODO: we can move more os-specific bindings/interfaces from stdlib::{os, posix, nt} to here
|
||||
|
||||
use core::str::Utf8Error;
|
||||
use std::{io, process::ExitCode};
|
||||
use std::{
|
||||
env,
|
||||
ffi::{OsStr, OsString},
|
||||
io,
|
||||
path::PathBuf,
|
||||
process::ExitCode,
|
||||
};
|
||||
|
||||
/// Convert exit code to std::process::ExitCode
|
||||
///
|
||||
@@ -22,6 +28,56 @@ pub fn exit_code(code: u32) -> ExitCode {
|
||||
ExitCode::from(code as u8)
|
||||
}
|
||||
|
||||
pub fn current_dir() -> io::Result<PathBuf> {
|
||||
env::current_dir()
|
||||
}
|
||||
|
||||
pub fn temp_dir() -> PathBuf {
|
||||
env::temp_dir()
|
||||
}
|
||||
|
||||
pub fn var(key: &str) -> Result<String, env::VarError> {
|
||||
env::var(key)
|
||||
}
|
||||
|
||||
pub fn var_os(key: impl AsRef<OsStr>) -> Option<OsString> {
|
||||
env::var_os(key)
|
||||
}
|
||||
|
||||
pub fn vars_os() -> env::VarsOs {
|
||||
env::vars_os()
|
||||
}
|
||||
|
||||
pub fn vars() -> env::Vars {
|
||||
env::vars()
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// The caller must ensure no other threads can concurrently read or write
|
||||
/// the process environment while this mutation is performed.
|
||||
pub unsafe fn set_var(key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) {
|
||||
unsafe { env::set_var(key, value) };
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// The caller must ensure no other threads can concurrently read or write
|
||||
/// the process environment while this mutation is performed.
|
||||
pub unsafe fn remove_var(key: impl AsRef<OsStr>) {
|
||||
unsafe { env::remove_var(key) };
|
||||
}
|
||||
|
||||
pub fn set_current_dir(path: impl AsRef<std::path::Path>) -> io::Result<()> {
|
||||
env::set_current_dir(path)
|
||||
}
|
||||
|
||||
pub fn process_id() -> u32 {
|
||||
std::process::id()
|
||||
}
|
||||
|
||||
pub fn exit(code: i32) -> ! {
|
||||
std::process::exit(code)
|
||||
}
|
||||
|
||||
pub trait ErrorExt {
|
||||
fn posix_errno(&self) -> i32;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
use std::os::fd::BorrowedFd;
|
||||
|
||||
pub fn set_inheritable(fd: BorrowedFd<'_>, inheritable: bool) -> nix::Result<()> {
|
||||
use nix::fcntl;
|
||||
|
||||
let flags = fcntl::FdFlag::from_bits_truncate(fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFD)?);
|
||||
let mut new_flags = flags;
|
||||
new_flags.set(fcntl::FdFlag::FD_CLOEXEC, !inheritable);
|
||||
if flags != new_flags {
|
||||
fcntl::fcntl(fd, fcntl::FcntlArg::F_SETFD(new_flags))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn get_number_of_os_threads() -> isize {
|
||||
type MachPortT = libc::c_uint;
|
||||
type KernReturnT = libc::c_int;
|
||||
type MachMsgTypeNumberT = libc::c_uint;
|
||||
type ThreadActArrayT = *mut MachPortT;
|
||||
const KERN_SUCCESS: KernReturnT = 0;
|
||||
unsafe extern "C" {
|
||||
fn mach_task_self() -> MachPortT;
|
||||
fn task_for_pid(
|
||||
task: MachPortT,
|
||||
pid: libc::c_int,
|
||||
target_task: *mut MachPortT,
|
||||
) -> KernReturnT;
|
||||
fn task_threads(
|
||||
target_task: MachPortT,
|
||||
act_list: *mut ThreadActArrayT,
|
||||
act_list_cnt: *mut MachMsgTypeNumberT,
|
||||
) -> KernReturnT;
|
||||
fn vm_deallocate(
|
||||
target_task: MachPortT,
|
||||
address: libc::uintptr_t,
|
||||
size: libc::uintptr_t,
|
||||
) -> KernReturnT;
|
||||
}
|
||||
|
||||
let self_task = unsafe { mach_task_self() };
|
||||
let mut proc_task: MachPortT = 0;
|
||||
if unsafe { task_for_pid(self_task, libc::getpid(), &mut proc_task) } == KERN_SUCCESS {
|
||||
let mut threads: ThreadActArrayT = core::ptr::null_mut();
|
||||
let mut n_threads: MachMsgTypeNumberT = 0;
|
||||
if unsafe { task_threads(proc_task, &mut threads, &mut n_threads) } == KERN_SUCCESS {
|
||||
if !threads.is_null() {
|
||||
let _ = unsafe {
|
||||
vm_deallocate(
|
||||
self_task,
|
||||
threads as libc::uintptr_t,
|
||||
(n_threads as usize * core::mem::size_of::<MachPortT>()) as libc::uintptr_t,
|
||||
)
|
||||
};
|
||||
}
|
||||
return n_threads as isize;
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn get_number_of_os_threads() -> isize {
|
||||
use std::io::Read as _;
|
||||
|
||||
let mut file = match crate::fs::open("/proc/self/stat") {
|
||||
Ok(f) => f,
|
||||
Err(_) => return 0,
|
||||
};
|
||||
let mut buf = [0u8; 160];
|
||||
let n = match file.read(&mut buf) {
|
||||
Ok(n) => n,
|
||||
Err(_) => return 0,
|
||||
};
|
||||
let line = match core::str::from_utf8(&buf[..n]) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return 0,
|
||||
};
|
||||
if let Some(field) = line.split_whitespace().nth(19) {
|
||||
return field.parse::<isize>().unwrap_or(0);
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
|
||||
pub fn get_number_of_os_threads() -> isize {
|
||||
0
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
use core::mem::MaybeUninit;
|
||||
use std::io;
|
||||
|
||||
#[cfg(unix)]
|
||||
mod platform {
|
||||
pub use libc::{FD_ISSET, FD_SET, FD_SETSIZE, FD_ZERO, fd_set, select, timeval};
|
||||
pub use std::os::unix::io::RawFd;
|
||||
|
||||
pub const fn check_err(x: i32) -> bool {
|
||||
x < 0
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[cfg(windows)]
|
||||
mod platform {
|
||||
pub use WinSock::{FD_SET as fd_set, FD_SETSIZE, SOCKET as RawFd, TIMEVAL as timeval, select};
|
||||
use windows_sys::Win32::Networking::WinSock;
|
||||
|
||||
pub unsafe fn FD_SET(fd: RawFd, set: *mut fd_set) {
|
||||
let mut slot = unsafe { (&raw mut (*set).fd_array).cast::<RawFd>() };
|
||||
let fd_count = unsafe { (*set).fd_count };
|
||||
for _ in 0..fd_count {
|
||||
if unsafe { *slot } == fd {
|
||||
return;
|
||||
}
|
||||
slot = unsafe { slot.add(1) };
|
||||
}
|
||||
if fd_count < FD_SETSIZE {
|
||||
unsafe {
|
||||
*slot = fd as RawFd;
|
||||
(*set).fd_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn FD_ZERO(set: *mut fd_set) {
|
||||
unsafe { (*set).fd_count = 0 };
|
||||
}
|
||||
|
||||
pub unsafe fn FD_ISSET(fd: RawFd, set: *mut fd_set) -> bool {
|
||||
use WinSock::__WSAFDIsSet;
|
||||
unsafe { __WSAFDIsSet(fd as _, set) != 0 }
|
||||
}
|
||||
|
||||
pub fn check_err(x: i32) -> bool {
|
||||
x == WinSock::SOCKET_ERROR
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "wasi")]
|
||||
mod platform {
|
||||
pub use libc::{FD_SETSIZE, timeval};
|
||||
pub use std::os::fd::RawFd;
|
||||
|
||||
pub const fn check_err(x: i32) -> bool {
|
||||
x < 0
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct fd_set {
|
||||
__nfds: usize,
|
||||
__fds: [libc::c_int; FD_SETSIZE],
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn FD_ISSET(fd: RawFd, set: *const fd_set) -> bool {
|
||||
let set = unsafe { &*set };
|
||||
for p in &set.__fds[..set.__nfds] {
|
||||
if *p == fd {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn FD_SET(fd: RawFd, set: *mut fd_set) {
|
||||
let set = unsafe { &mut *set };
|
||||
for p in &set.__fds[..set.__nfds] {
|
||||
if *p == fd {
|
||||
return;
|
||||
}
|
||||
}
|
||||
let n = set.__nfds;
|
||||
assert!(n < set.__fds.len(), "fd_set full");
|
||||
set.__fds[n] = fd;
|
||||
set.__nfds = n + 1;
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn FD_ZERO(set: *mut fd_set) {
|
||||
unsafe { (*set).__nfds = 0 };
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
pub fn select(
|
||||
nfds: libc::c_int,
|
||||
readfds: *mut fd_set,
|
||||
writefds: *mut fd_set,
|
||||
errorfds: *mut fd_set,
|
||||
timeout: *const timeval,
|
||||
) -> libc::c_int;
|
||||
}
|
||||
}
|
||||
|
||||
pub use platform::{RawFd, timeval};
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct FdSet(MaybeUninit<platform::fd_set>);
|
||||
|
||||
impl FdSet {
|
||||
pub fn new() -> Self {
|
||||
let mut fdset = MaybeUninit::zeroed();
|
||||
unsafe { platform::FD_ZERO(fdset.as_mut_ptr()) };
|
||||
Self(fdset)
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, fd: RawFd) {
|
||||
unsafe { platform::FD_SET(fd, self.0.as_mut_ptr()) };
|
||||
}
|
||||
|
||||
pub fn contains(&mut self, fd: RawFd) -> bool {
|
||||
unsafe { platform::FD_ISSET(fd, self.0.as_mut_ptr()) }
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
unsafe { platform::FD_ZERO(self.0.as_mut_ptr()) };
|
||||
}
|
||||
|
||||
pub fn highest(&mut self) -> Option<RawFd> {
|
||||
(0..platform::FD_SETSIZE as RawFd)
|
||||
.rev()
|
||||
.find(|&fd| self.contains(fd))
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FdSet {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select(
|
||||
nfds: libc::c_int,
|
||||
readfds: &mut FdSet,
|
||||
writefds: &mut FdSet,
|
||||
errfds: &mut FdSet,
|
||||
timeout: Option<&mut timeval>,
|
||||
) -> io::Result<i32> {
|
||||
let timeout = match timeout {
|
||||
Some(tv) => tv as *mut timeval,
|
||||
None => core::ptr::null_mut(),
|
||||
};
|
||||
let ret = unsafe {
|
||||
platform::select(
|
||||
nfds,
|
||||
readfds.0.as_mut_ptr(),
|
||||
writefds.0.as_mut_ptr(),
|
||||
errfds.0.as_mut_ptr(),
|
||||
timeout,
|
||||
)
|
||||
};
|
||||
if platform::check_err(ret) {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sec_to_timeval(sec: f64) -> timeval {
|
||||
timeval {
|
||||
tv_sec: sec.trunc() as _,
|
||||
tv_usec: (sec.fract() * 1e6) as _,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
use core::ffi::CStr;
|
||||
use std::io;
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
pub fn timeval_to_double(tv: &libc::timeval) -> f64 {
|
||||
tv.tv_sec as f64 + (tv.tv_usec as f64 / 1_000_000.0)
|
||||
}
|
||||
|
||||
pub fn double_to_timeval(val: f64) -> libc::timeval {
|
||||
libc::timeval {
|
||||
tv_sec: val.trunc() as _,
|
||||
tv_usec: (val.fract() * 1_000_000.0) as _,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn itimerval_to_tuple(it: &libc::itimerval) -> (f64, f64) {
|
||||
(
|
||||
timeval_to_double(&it.it_value),
|
||||
timeval_to_double(&it.it_interval),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
use alloc::boxed::Box;
|
||||
use core::ffi::CStr;
|
||||
use std::{
|
||||
os::raw::c_char,
|
||||
sync::{OnceLock, RwLock},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
enum GlobalIdent {
|
||||
Explicit(Box<CStr>),
|
||||
Implicit,
|
||||
}
|
||||
|
||||
impl GlobalIdent {
|
||||
fn as_ptr(&self) -> *const c_char {
|
||||
match self {
|
||||
Self::Explicit(cstr) => cstr.as_ptr(),
|
||||
Self::Implicit => core::ptr::null(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn global_ident() -> &'static RwLock<Option<GlobalIdent>> {
|
||||
static IDENT: OnceLock<RwLock<Option<GlobalIdent>>> = OnceLock::new();
|
||||
IDENT.get_or_init(|| RwLock::new(None))
|
||||
}
|
||||
|
||||
pub fn is_open() -> bool {
|
||||
global_ident()
|
||||
.read()
|
||||
.expect("syslog lock poisoned")
|
||||
.is_some()
|
||||
}
|
||||
|
||||
pub fn openlog(ident: Option<Box<CStr>>, logoption: i32, facility: i32) {
|
||||
let ident = match ident {
|
||||
Some(ident) => GlobalIdent::Explicit(ident),
|
||||
None => GlobalIdent::Implicit,
|
||||
};
|
||||
let mut locked_ident = global_ident().write().expect("syslog lock poisoned");
|
||||
unsafe { libc::openlog(ident.as_ptr(), logoption, facility) };
|
||||
*locked_ident = Some(ident);
|
||||
}
|
||||
|
||||
pub fn syslog(priority: i32, msg: &CStr) {
|
||||
let cformat = c"%s";
|
||||
unsafe { libc::syslog(priority, cformat.as_ptr(), msg.as_ptr()) };
|
||||
}
|
||||
|
||||
pub fn closelog() {
|
||||
if is_open() {
|
||||
let mut locked_ident = global_ident().write().expect("syslog lock poisoned");
|
||||
unsafe { libc::closelog() };
|
||||
*locked_ident = None;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setlogmask(maskpri: i32) -> i32 {
|
||||
unsafe { libc::setlogmask(maskpri) }
|
||||
}
|
||||
|
||||
pub const fn log_mask(pri: i32) -> i32 {
|
||||
pri << 1
|
||||
}
|
||||
|
||||
pub const fn log_upto(pri: i32) -> i32 {
|
||||
(1 << (pri + 1)) - 1
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
pub fn tcgetattr(fd: i32) -> std::io::Result<::termios::Termios> {
|
||||
::termios::Termios::from_fd(fd)
|
||||
}
|
||||
|
||||
pub fn tcsetattr(fd: i32, when: i32, termios: &::termios::Termios) -> std::io::Result<()> {
|
||||
::termios::tcsetattr(fd, when, termios)
|
||||
}
|
||||
|
||||
pub fn tcsendbreak(fd: i32, duration: i32) -> std::io::Result<()> {
|
||||
::termios::tcsendbreak(fd, duration)
|
||||
}
|
||||
|
||||
pub fn tcdrain(fd: i32) -> std::io::Result<()> {
|
||||
::termios::tcdrain(fd)
|
||||
}
|
||||
|
||||
pub fn tcflush(fd: i32, queue: i32) -> std::io::Result<()> {
|
||||
::termios::tcflush(fd, queue)
|
||||
}
|
||||
|
||||
pub fn tcflow(fd: i32, action: i32) -> std::io::Result<()> {
|
||||
::termios::tcflow(fd, action)
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
use core::time::Duration;
|
||||
use std::time::{SystemTime, SystemTimeError, UNIX_EPOCH};
|
||||
|
||||
pub const SEC_TO_MS: i64 = 1000;
|
||||
pub const MS_TO_US: i64 = 1000;
|
||||
pub const SEC_TO_US: i64 = SEC_TO_MS * MS_TO_US;
|
||||
pub const US_TO_NS: i64 = 1000;
|
||||
pub const MS_TO_NS: i64 = MS_TO_US * US_TO_NS;
|
||||
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;
|
||||
|
||||
pub fn duration_since_system_now() -> Result<Duration, SystemTimeError> {
|
||||
SystemTime::now().duration_since(UNIX_EPOCH)
|
||||
}
|
||||
|
||||
#[cfg(target_env = "msvc")]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub fn get_tz_info() -> windows_sys::Win32::System::Time::TIME_ZONE_INFORMATION {
|
||||
let mut info = unsafe { core::mem::zeroed() };
|
||||
unsafe { windows_sys::Win32::System::Time::GetTimeZoneInformation(&mut info) };
|
||||
info
|
||||
}
|
||||
|
||||
#[cfg(any(unix, windows))]
|
||||
pub fn asctime_from_tm(tm: &libc::tm) -> String {
|
||||
const WDAY_NAME: [&str; 7] = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
||||
const MON_NAME: [&str; 12] = [
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
|
||||
];
|
||||
format!(
|
||||
"{} {}{:>3} {:02}:{:02}:{:02} {}",
|
||||
WDAY_NAME[tm.tm_wday as usize],
|
||||
MON_NAME[tm.tm_mon as usize],
|
||||
tm.tm_mday,
|
||||
tm.tm_hour,
|
||||
tm.tm_min,
|
||||
tm.tm_sec,
|
||||
tm.tm_year + 1900
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use windows_sys::Win32::Foundation::HANDLE;
|
||||
|
||||
pub fn get_acp() -> u32 {
|
||||
unsafe { windows_sys::Win32::Globalization::GetACP() }
|
||||
}
|
||||
|
||||
pub fn get_current_process() -> HANDLE {
|
||||
unsafe { windows_sys::Win32::System::Threading::GetCurrentProcess() }
|
||||
}
|
||||
|
||||
pub fn get_last_error() -> u32 {
|
||||
unsafe { windows_sys::Win32::Foundation::GetLastError() }
|
||||
}
|
||||
|
||||
pub fn get_version() -> u32 {
|
||||
unsafe { windows_sys::Win32::System::SystemInformation::GetVersion() }
|
||||
}
|
||||
File renamed without changes.
@@ -30,6 +30,7 @@ flame-it = ["flame"]
|
||||
rustpython-derive = { workspace = true }
|
||||
rustpython-vm = { workspace = true, default-features = false, features = ["compiler"]}
|
||||
rustpython-common = { workspace = true }
|
||||
rustpython-host_env = { workspace = true }
|
||||
|
||||
ruff_python_parser = { workspace = true }
|
||||
ruff_python_ast = { workspace = true }
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
#![allow(
|
||||
clippy::disallowed_methods,
|
||||
reason = "build scripts cannot use rustpython-host_env"
|
||||
)]
|
||||
|
||||
// spell-checker:ignore ossl osslconf
|
||||
|
||||
fn main() {
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
disallowed-methods = [
|
||||
{ path = "std::fs::read", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::write", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::read_to_string", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::read_dir", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::create_dir", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::create_dir_all", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::remove_file", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::remove_dir", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::metadata", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::symlink_metadata", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::canonicalize", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::File::open", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::File::create", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::OpenOptions::open", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::env::var", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::var_os", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::set_var", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::remove_var", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::vars", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::vars_os", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::current_dir", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::set_current_dir", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::temp_dir", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::process::Command::new", reason = "use rustpython_host_env for host process access" },
|
||||
{ path = "std::process::exit", reason = "use rustpython_host_env for host process access" },
|
||||
{ path = "std::process::abort", reason = "use rustpython_host_env for host process access" },
|
||||
{ path = "std::process::id", reason = "use rustpython_host_env for host process access" },
|
||||
{ path = "std::net::TcpStream::connect", reason = "use rustpython_host_env for host network access" },
|
||||
{ path = "std::net::TcpListener::bind", reason = "use rustpython_host_env for host network access" },
|
||||
{ path = "std::net::UdpSocket::bind", reason = "use rustpython_host_env for host network access" },
|
||||
]
|
||||
@@ -13,7 +13,7 @@ mod decl {
|
||||
use core::time::Duration;
|
||||
use parking_lot::{Condvar, Mutex};
|
||||
#[cfg(any(unix, windows))]
|
||||
use rustpython_common::os::{get_errno, set_errno};
|
||||
use rustpython_host_env::os::{get_errno, set_errno};
|
||||
use std::thread;
|
||||
|
||||
/// fault_handler_t
|
||||
@@ -587,7 +587,7 @@ mod decl {
|
||||
}
|
||||
|
||||
// Fallback
|
||||
std::process::exit(1);
|
||||
rustpython_host_env::os::exit(1);
|
||||
}
|
||||
|
||||
// Windows vectored exception handler (faulthandler.c:417-480)
|
||||
@@ -880,7 +880,7 @@ mod decl {
|
||||
}
|
||||
|
||||
if exit {
|
||||
std::process::exit(1);
|
||||
rustpython_host_env::os::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-39
@@ -4,6 +4,8 @@ pub(crate) use fcntl::module_def;
|
||||
|
||||
#[pymodule]
|
||||
mod fcntl {
|
||||
use rustpython_host_env::fcntl as host_fcntl;
|
||||
|
||||
use crate::vm::{
|
||||
PyResult, VirtualMachine,
|
||||
builtins::PyIntRef,
|
||||
@@ -73,19 +75,15 @@ mod fcntl {
|
||||
.ok_or_else(|| vm.new_value_error("fcntl string arg too long"))?
|
||||
.copy_from_slice(&s)
|
||||
}
|
||||
let ret = unsafe { libc::fcntl(fd, cmd, buf.as_mut_ptr()) };
|
||||
if ret < 0 {
|
||||
return Err(vm.new_last_errno_error());
|
||||
}
|
||||
host_fcntl::fcntl_with_bytes(fd, cmd, &mut buf[..arg_len])
|
||||
.map_err(|_| vm.new_last_errno_error())?;
|
||||
return Ok(vm.ctx.new_bytes(buf[..arg_len].to_vec()).into());
|
||||
}
|
||||
OptionalArg::Present(Either::B(i)) => i.as_u32_mask(),
|
||||
OptionalArg::Missing => 0,
|
||||
};
|
||||
let ret = unsafe { libc::fcntl(fd, cmd, int as i32) };
|
||||
if ret < 0 {
|
||||
return Err(vm.new_last_errno_error());
|
||||
}
|
||||
let ret =
|
||||
host_fcntl::fcntl_int(fd, cmd, int as i32).map_err(|_| vm.new_last_errno_error())?;
|
||||
Ok(vm.new_pyobj(ret))
|
||||
}
|
||||
|
||||
@@ -118,11 +116,10 @@ mod fcntl {
|
||||
let mutate_flag = mutate_flag.unwrap_or(true);
|
||||
let mut arg_buf = rw_arg.borrow_buf_mut();
|
||||
if mutate_flag {
|
||||
let ret =
|
||||
unsafe { libc::ioctl(fd, request as _, arg_buf.as_mut_ptr()) };
|
||||
if ret < 0 {
|
||||
return Err(vm.new_last_errno_error());
|
||||
let ret = unsafe {
|
||||
host_fcntl::ioctl_ptr(fd, request, arg_buf.as_mut_ptr().cast())
|
||||
}
|
||||
.map_err(|_| vm.new_last_errno_error())?;
|
||||
return Ok(vm.ctx.new_int(ret).into());
|
||||
}
|
||||
// treat like an immutable buffer
|
||||
@@ -130,17 +127,13 @@ mod fcntl {
|
||||
}
|
||||
Either::B(ro_buf) => fill_buf(&ro_buf.borrow_bytes())?,
|
||||
};
|
||||
let ret = unsafe { libc::ioctl(fd, request as _, buf.as_mut_ptr()) };
|
||||
if ret < 0 {
|
||||
return Err(vm.new_last_errno_error());
|
||||
}
|
||||
unsafe { host_fcntl::ioctl_ptr(fd, request, buf.as_mut_ptr().cast()) }
|
||||
.map_err(|_| vm.new_last_errno_error())?;
|
||||
Ok(vm.ctx.new_bytes(buf[..buf_len].to_vec()).into())
|
||||
}
|
||||
Either::B(i) => {
|
||||
let ret = unsafe { libc::ioctl(fd, request as _, i) };
|
||||
if ret < 0 {
|
||||
return Err(vm.new_last_errno_error());
|
||||
}
|
||||
let ret =
|
||||
host_fcntl::ioctl_int(fd, request, i).map_err(|_| vm.new_last_errno_error())?;
|
||||
Ok(vm.ctx.new_int(ret).into())
|
||||
}
|
||||
}
|
||||
@@ -150,11 +143,7 @@ mod fcntl {
|
||||
#[cfg(not(any(target_os = "wasi", target_os = "redox")))]
|
||||
#[pyfunction]
|
||||
fn flock(_io::Fildes(fd): _io::Fildes, operation: i32, vm: &VirtualMachine) -> PyResult {
|
||||
let ret = unsafe { libc::flock(fd, operation) };
|
||||
// TODO: add support for platforms that don't have a builtin `flock` syscall
|
||||
if ret < 0 {
|
||||
return Err(vm.new_last_errno_error());
|
||||
}
|
||||
let ret = host_fcntl::flock(fd, operation).map_err(|_| vm.new_last_errno_error())?;
|
||||
Ok(vm.ctx.new_int(ret).into())
|
||||
}
|
||||
|
||||
@@ -201,20 +190,7 @@ mod fcntl {
|
||||
.map_err(|e| vm.new_overflow_error(format!("{e}")))?,
|
||||
OptionalArg::Missing => 0,
|
||||
};
|
||||
let ret = unsafe {
|
||||
libc::fcntl(
|
||||
fd,
|
||||
if (cmd & libc::LOCK_NB) != 0 {
|
||||
libc::F_SETLK
|
||||
} else {
|
||||
libc::F_SETLKW
|
||||
},
|
||||
&l,
|
||||
)
|
||||
};
|
||||
if ret < 0 {
|
||||
return Err(vm.new_last_errno_error());
|
||||
}
|
||||
let ret = host_fcntl::lockf(fd, cmd, &l).map_err(|_| vm.new_last_errno_error())?;
|
||||
Ok(vm.ctx.new_int(ret).into())
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// to allow `mod foo {}` in foo.rs; clippy thinks this is a mistake/misunderstanding of
|
||||
// how `mod` works, but we want this sometimes for pymodule declarations
|
||||
|
||||
#![deny(clippy::disallowed_methods)]
|
||||
#![allow(clippy::module_inception)]
|
||||
|
||||
#[macro_use]
|
||||
|
||||
@@ -30,10 +30,10 @@ mod mmap {
|
||||
#[cfg(unix)]
|
||||
use nix::{sys::stat::fstat, unistd};
|
||||
#[cfg(unix)]
|
||||
use rustpython_common::crt_fd;
|
||||
use rustpython_host_env::crt_fd;
|
||||
|
||||
#[cfg(windows)]
|
||||
use rustpython_common::suppress_iph;
|
||||
use rustpython_host_env::suppress_iph;
|
||||
#[cfg(windows)]
|
||||
use std::os::windows::io::{AsRawHandle, FromRawHandle, OwnedHandle, RawHandle};
|
||||
#[cfg(windows)]
|
||||
|
||||
@@ -1671,17 +1671,17 @@ mod _ssl {
|
||||
|
||||
// Open the file using fopen (cross-platform)
|
||||
let fp =
|
||||
rustpython_common::fileutils::fopen(path.as_path(), "rb").map_err(|e| {
|
||||
match e.kind() {
|
||||
std::io::ErrorKind::NotFound => vm
|
||||
.new_os_subtype_error(
|
||||
vm.ctx.exceptions.file_not_found_error.to_owned(),
|
||||
Some(libc::ENOENT),
|
||||
e.to_string(),
|
||||
)
|
||||
.upcast(),
|
||||
_ => vm.new_os_error(e.to_string()),
|
||||
}
|
||||
rustpython_host_env::fileutils::fopen(path.as_path(), "rb").map_err(|e| match e
|
||||
.kind()
|
||||
{
|
||||
std::io::ErrorKind::NotFound => vm
|
||||
.new_os_subtype_error(
|
||||
vm.ctx.exceptions.file_not_found_error.to_owned(),
|
||||
Some(libc::ENOENT),
|
||||
e.to_string(),
|
||||
)
|
||||
.upcast(),
|
||||
_ => vm.new_os_error(e.to_string()),
|
||||
})?;
|
||||
|
||||
// Read DH parameters
|
||||
@@ -1880,7 +1880,7 @@ mod _ssl {
|
||||
const PEM_BUFSIZE: usize = 1024;
|
||||
|
||||
// Read key file data
|
||||
let key_data = std::fs::read(key_file_path)
|
||||
let key_data = rustpython_host_env::fs::read(key_file_path)
|
||||
.map_err(|e| crate::vm::convert::ToPyException::to_pyexception(&e, vm))?;
|
||||
|
||||
let pkey = if let Some(ref pw_obj) = password {
|
||||
|
||||
@@ -359,7 +359,7 @@ pub(crate) mod ssl_cert {
|
||||
#[pyfunction]
|
||||
pub(crate) fn _test_decode_cert(path: FsPath, vm: &VirtualMachine) -> PyResult {
|
||||
let path = path.to_path_buf(vm)?;
|
||||
let pem = std::fs::read(path).map_err(|e| e.to_pyexception(vm))?;
|
||||
let pem = rustpython_host_env::fs::read(path).map_err(|e| e.to_pyexception(vm))?;
|
||||
let x509 = X509::from_pem(&pem).map_err(|e| convert_openssl_error(vm, e))?;
|
||||
cert_to_py(vm, &x509, false)
|
||||
}
|
||||
|
||||
@@ -283,7 +283,7 @@ mod _overlapped {
|
||||
} else {
|
||||
err
|
||||
};
|
||||
let errno = crate::vm::common::os::winerror_to_errno(err as i32);
|
||||
let errno = rustpython_host_env::os::winerror_to_errno(err as i32);
|
||||
let message = std::io::Error::from_raw_os_error(err as i32).to_string();
|
||||
let exc = vm.new_errno_error(errno, message);
|
||||
let _ = exc
|
||||
|
||||
@@ -6,12 +6,10 @@ pub(crate) use _posixshmem::module_def;
|
||||
mod _posixshmem {
|
||||
use alloc::ffi::CString;
|
||||
|
||||
use crate::{
|
||||
common::os::errno_io_error,
|
||||
vm::{
|
||||
FromArgs, PyResult, VirtualMachine, builtins::PyUtf8StrRef, convert::IntoPyException,
|
||||
},
|
||||
use crate::vm::{
|
||||
FromArgs, PyResult, VirtualMachine, builtins::PyUtf8StrRef, convert::IntoPyException,
|
||||
};
|
||||
use rustpython_host_env::shm;
|
||||
|
||||
#[derive(FromArgs)]
|
||||
struct ShmOpenArgs {
|
||||
@@ -27,26 +25,12 @@ mod _posixshmem {
|
||||
fn shm_open(args: ShmOpenArgs, vm: &VirtualMachine) -> PyResult<libc::c_int> {
|
||||
let name = CString::new(args.name.as_str()).map_err(|e| e.into_pyexception(vm))?;
|
||||
let mode: libc::c_uint = args.mode as _;
|
||||
#[cfg(target_os = "freebsd")]
|
||||
let mode = mode.try_into().unwrap();
|
||||
// SAFETY: `name` is a NUL-terminated string and `shm_open` does not write through it.
|
||||
let fd = unsafe { libc::shm_open(name.as_ptr(), args.flags, mode) };
|
||||
if fd == -1 {
|
||||
Err(errno_io_error().into_pyexception(vm))
|
||||
} else {
|
||||
Ok(fd)
|
||||
}
|
||||
shm::shm_open(name.as_c_str(), args.flags, mode).map_err(|e| e.into_pyexception(vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn shm_unlink(name: PyUtf8StrRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let name = CString::new(name.as_str()).map_err(|e| e.into_pyexception(vm))?;
|
||||
// SAFETY: `name` is a valid NUL-terminated string and `shm_unlink` only reads it.
|
||||
let ret = unsafe { libc::shm_unlink(name.as_ptr()) };
|
||||
if ret == -1 {
|
||||
Err(errno_io_error().into_pyexception(vm))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
shm::shm_unlink(name.as_c_str()).map_err(|e| e.into_pyexception(vm))
|
||||
}
|
||||
}
|
||||
@@ -248,7 +248,7 @@ fn exec(args: &ForkExecArgs<'_>, procargs: ProcArgs<'_>, vm: &VirtualMachine) ->
|
||||
// errno is written in hex format
|
||||
let _ = write!(pipe, "OSError:{:x}:{}", e as i32, ctx.as_msg());
|
||||
}
|
||||
std::process::exit(255)
|
||||
rustpython_host_env::os::exit(255)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-179
@@ -5,119 +5,9 @@ pub(crate) use decl::module_def;
|
||||
use crate::vm::{
|
||||
PyObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine, builtins::PyListRef,
|
||||
};
|
||||
use core::mem;
|
||||
use rustpython_host_env::select::{self as host_select, FdSet, RawFd};
|
||||
use std::io;
|
||||
|
||||
#[cfg(unix)]
|
||||
mod platform {
|
||||
pub use libc::{FD_ISSET, FD_SET, FD_SETSIZE, FD_ZERO, fd_set, select, timeval};
|
||||
pub use std::os::unix::io::RawFd;
|
||||
|
||||
pub const fn check_err(x: i32) -> bool {
|
||||
x < 0
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[cfg(windows)]
|
||||
mod platform {
|
||||
pub use WinSock::{FD_SET as fd_set, FD_SETSIZE, SOCKET as RawFd, TIMEVAL as timeval, select};
|
||||
use windows_sys::Win32::Networking::WinSock;
|
||||
|
||||
// based off winsock2.h: https://gist.github.com/piscisaureus/906386#file-winsock2-h-L128-L141
|
||||
|
||||
pub unsafe fn FD_SET(fd: RawFd, set: *mut fd_set) {
|
||||
unsafe {
|
||||
let mut slot = (&raw mut (*set).fd_array).cast::<RawFd>();
|
||||
let fd_count = (*set).fd_count;
|
||||
for _ in 0..fd_count {
|
||||
if *slot == fd {
|
||||
return;
|
||||
}
|
||||
slot = slot.add(1);
|
||||
}
|
||||
// slot == &fd_array[fd_count] at this point
|
||||
if fd_count < FD_SETSIZE {
|
||||
*slot = fd as RawFd;
|
||||
(*set).fd_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn FD_ZERO(set: *mut fd_set) {
|
||||
unsafe { (*set).fd_count = 0 };
|
||||
}
|
||||
|
||||
pub unsafe fn FD_ISSET(fd: RawFd, set: *mut fd_set) -> bool {
|
||||
use WinSock::__WSAFDIsSet;
|
||||
unsafe { __WSAFDIsSet(fd as _, set) != 0 }
|
||||
}
|
||||
|
||||
pub fn check_err(x: i32) -> bool {
|
||||
x == WinSock::SOCKET_ERROR
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "wasi")]
|
||||
mod platform {
|
||||
pub use libc::{FD_SETSIZE, timeval};
|
||||
pub use std::os::fd::RawFd;
|
||||
|
||||
pub fn check_err(x: i32) -> bool {
|
||||
x < 0
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct fd_set {
|
||||
__nfds: usize,
|
||||
__fds: [libc::c_int; FD_SETSIZE],
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn FD_ISSET(fd: RawFd, set: *const fd_set) -> bool {
|
||||
let set = unsafe { &*set };
|
||||
let n = set.__nfds;
|
||||
for p in &set.__fds[..n] {
|
||||
if *p == fd {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn FD_SET(fd: RawFd, set: *mut fd_set) {
|
||||
let set = unsafe { &mut *set };
|
||||
let n = set.__nfds;
|
||||
for p in &set.__fds[..n] {
|
||||
if *p == fd {
|
||||
return;
|
||||
}
|
||||
}
|
||||
set.__nfds = n + 1;
|
||||
set.__fds[n] = fd;
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn FD_ZERO(set: *mut fd_set) {
|
||||
let set = unsafe { &mut *set };
|
||||
set.__nfds = 0;
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
pub fn select(
|
||||
nfds: libc::c_int,
|
||||
readfds: *mut fd_set,
|
||||
writefds: *mut fd_set,
|
||||
errorfds: *mut fd_set,
|
||||
timeout: *const timeval,
|
||||
) -> libc::c_int;
|
||||
}
|
||||
}
|
||||
|
||||
use platform::RawFd;
|
||||
pub use platform::timeval;
|
||||
|
||||
#[derive(Traverse)]
|
||||
struct Selectable {
|
||||
obj: PyObjectRef,
|
||||
@@ -139,72 +29,6 @@ impl TryFromObject for Selectable {
|
||||
}
|
||||
}
|
||||
|
||||
// Keep it in a MaybeUninit, since on windows FD_ZERO doesn't actually zero the whole thing
|
||||
#[repr(transparent)]
|
||||
pub struct FdSet(mem::MaybeUninit<platform::fd_set>);
|
||||
|
||||
impl FdSet {
|
||||
pub fn new() -> Self {
|
||||
// it's just ints, and all the code that's actually
|
||||
// interacting with it is in C, so it's safe to zero
|
||||
let mut fdset = core::mem::MaybeUninit::zeroed();
|
||||
unsafe { platform::FD_ZERO(fdset.as_mut_ptr()) };
|
||||
Self(fdset)
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, fd: RawFd) {
|
||||
unsafe { platform::FD_SET(fd, self.0.as_mut_ptr()) };
|
||||
}
|
||||
|
||||
pub fn contains(&mut self, fd: RawFd) -> bool {
|
||||
unsafe { platform::FD_ISSET(fd, self.0.as_mut_ptr()) }
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
unsafe { platform::FD_ZERO(self.0.as_mut_ptr()) };
|
||||
}
|
||||
|
||||
pub fn highest(&mut self) -> Option<RawFd> {
|
||||
(0..platform::FD_SETSIZE as RawFd)
|
||||
.rev()
|
||||
.find(|&i| self.contains(i))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select(
|
||||
nfds: libc::c_int,
|
||||
readfds: &mut FdSet,
|
||||
writefds: &mut FdSet,
|
||||
errfds: &mut FdSet,
|
||||
timeout: Option<&mut timeval>,
|
||||
) -> io::Result<i32> {
|
||||
let timeout = match timeout {
|
||||
Some(tv) => tv as *mut timeval,
|
||||
None => core::ptr::null_mut(),
|
||||
};
|
||||
let ret = unsafe {
|
||||
platform::select(
|
||||
nfds,
|
||||
readfds.0.as_mut_ptr(),
|
||||
writefds.0.as_mut_ptr(),
|
||||
errfds.0.as_mut_ptr(),
|
||||
timeout,
|
||||
)
|
||||
};
|
||||
if platform::check_err(ret) {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
|
||||
fn sec_to_timeval(sec: f64) -> timeval {
|
||||
timeval {
|
||||
tv_sec: sec.trunc() as _,
|
||||
tv_usec: (sec.fract() * 1e6) as _,
|
||||
}
|
||||
}
|
||||
|
||||
#[pymodule(name = "select")]
|
||||
mod decl {
|
||||
use super::*;
|
||||
@@ -279,8 +103,9 @@ mod decl {
|
||||
.map_or(0, |n| n + 1) as _;
|
||||
|
||||
loop {
|
||||
let mut tv = timeout.map(sec_to_timeval);
|
||||
let res = vm.allow_threads(|| super::select(nfds, &mut r, &mut w, &mut x, tv.as_mut()));
|
||||
let mut tv = timeout.map(host_select::sec_to_timeval);
|
||||
let res =
|
||||
vm.allow_threads(|| host_select::select(nfds, &mut r, &mut w, &mut x, tv.as_mut()));
|
||||
|
||||
match res {
|
||||
Ok(_) => break,
|
||||
|
||||
+12
-12
@@ -14,7 +14,6 @@ mod _socket {
|
||||
PyBaseExceptionRef, PyListRef, PyModule, PyOSError, PyStrRef, PyTupleRef, PyTypeRef,
|
||||
PyUtf8StrRef,
|
||||
},
|
||||
common::os::ErrorExt,
|
||||
convert::{IntoPyException, ToPyObject, TryFromBorrowedObject, TryFromObject},
|
||||
function::{
|
||||
ArgBytesLike, ArgIntoFloat, ArgMemoryBuffer, ArgStrOrBytesLike, Either, FsPath,
|
||||
@@ -23,6 +22,7 @@ mod _socket {
|
||||
types::{Constructor, DefaultConstructor, Destructor, Initializer, Representable},
|
||||
utils::ToCString,
|
||||
};
|
||||
use rustpython_host_env::os::ErrorExt;
|
||||
|
||||
pub(crate) fn module_exec(vm: &VirtualMachine, module: &Py<PyModule>) -> PyResult<()> {
|
||||
#[cfg(windows)]
|
||||
@@ -2270,7 +2270,7 @@ mod _socket {
|
||||
)
|
||||
};
|
||||
if ret < 0 {
|
||||
return Err(crate::common::os::errno_io_error().into());
|
||||
return Err(rustpython_host_env::os::errno_io_error().into());
|
||||
}
|
||||
Ok(vm.ctx.new_int(flag).into())
|
||||
} else {
|
||||
@@ -2291,7 +2291,7 @@ mod _socket {
|
||||
)
|
||||
};
|
||||
if ret < 0 {
|
||||
return Err(crate::common::os::errno_io_error().into());
|
||||
return Err(rustpython_host_env::os::errno_io_error().into());
|
||||
}
|
||||
buf.truncate(buflen as usize);
|
||||
Ok(vm.ctx.new_bytes(buf).into())
|
||||
@@ -2332,7 +2332,7 @@ mod _socket {
|
||||
}
|
||||
};
|
||||
if ret < 0 {
|
||||
Err(crate::common::os::errno_io_error().into())
|
||||
Err(rustpython_host_env::os::errno_io_error().into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
@@ -2787,13 +2787,13 @@ mod _socket {
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use crate::select;
|
||||
use rustpython_host_env::select as host_select;
|
||||
|
||||
let fd = sock_fileno(sock);
|
||||
|
||||
let mut reads = select::FdSet::new();
|
||||
let mut writes = select::FdSet::new();
|
||||
let mut errs = select::FdSet::new();
|
||||
let mut reads = host_select::FdSet::new();
|
||||
let mut writes = host_select::FdSet::new();
|
||||
let mut errs = host_select::FdSet::new();
|
||||
|
||||
let fd = fd as usize;
|
||||
match kind {
|
||||
@@ -2805,12 +2805,12 @@ mod _socket {
|
||||
}
|
||||
}
|
||||
|
||||
let mut interval = interval.map(|dur| select::timeval {
|
||||
let mut interval = interval.map(|dur| host_select::timeval {
|
||||
tv_sec: dur.as_secs() as _,
|
||||
tv_usec: dur.subsec_micros() as _,
|
||||
});
|
||||
|
||||
select::select(
|
||||
host_select::select(
|
||||
fd as i32 + 1,
|
||||
&mut reads,
|
||||
&mut writes,
|
||||
@@ -3084,7 +3084,7 @@ mod _socket {
|
||||
fn if_nametoindex(name: FsPath, vm: &VirtualMachine) -> PyResult<IfIndex> {
|
||||
let name = name.to_cstring(vm)?;
|
||||
// in case 'if_nametoindex' does not set errno
|
||||
crate::common::os::set_errno(libc::ENODEV);
|
||||
rustpython_host_env::os::set_errno(libc::ENODEV);
|
||||
let ret = unsafe { c::if_nametoindex(name.as_ptr() as _) };
|
||||
if ret == 0 {
|
||||
Err(vm.new_last_errno_error())
|
||||
@@ -3098,7 +3098,7 @@ mod _socket {
|
||||
fn if_indextoname(index: IfIndex, vm: &VirtualMachine) -> PyResult<String> {
|
||||
let mut buf = [0; c::IF_NAMESIZE + 1];
|
||||
// in case 'if_indextoname' does not set errno
|
||||
crate::common::os::set_errno(libc::ENXIO);
|
||||
rustpython_host_env::os::set_errno(libc::ENXIO);
|
||||
let ret = unsafe { c::if_indextoname(index, buf.as_mut_ptr()) };
|
||||
if ret.is_null() {
|
||||
Err(vm.new_last_errno_error())
|
||||
|
||||
@@ -1766,8 +1766,8 @@ mod _ssl {
|
||||
|
||||
// Validate that the file contains DH parameters
|
||||
// Read the file and check for DH PARAMETERS header
|
||||
let contents =
|
||||
std::fs::read_to_string(&path_str).map_err(|e| vm.new_os_error(e.to_string()))?;
|
||||
let contents = rustpython_host_env::fs::read_to_string(&path_str)
|
||||
.map_err(|e| vm.new_os_error(e.to_string()))?;
|
||||
|
||||
if !contents.contains("BEGIN DH PARAMETERS")
|
||||
&& !contents.contains("BEGIN X9.42 DH PARAMETERS")
|
||||
@@ -2154,7 +2154,7 @@ mod _ssl {
|
||||
path: &str,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<Option<CertificateRevocationListDer<'static>>> {
|
||||
let data = std::fs::read(path).map_err(|e| match e.kind() {
|
||||
let data = rustpython_host_env::fs::read(path).map_err(|e| match e.kind() {
|
||||
std::io::ErrorKind::NotFound | std::io::ErrorKind::PermissionDenied => {
|
||||
e.into_pyexception(vm)
|
||||
}
|
||||
@@ -4913,7 +4913,7 @@ mod _ssl {
|
||||
fn _test_decode_cert(path: PyUtf8StrRef, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
|
||||
// Read certificate file
|
||||
let path_str = path.as_str();
|
||||
let cert_data = std::fs::read(path_str).map_err(|e| {
|
||||
let cert_data = rustpython_host_env::fs::read(path_str).map_err(|e| {
|
||||
vm.new_os_error(format!(
|
||||
"Failed to read certificate file {}: {}",
|
||||
path_str, e
|
||||
|
||||
@@ -639,7 +639,7 @@ impl<'a> CertLoader<'a> {
|
||||
///
|
||||
/// Returns statistics about loaded certificates
|
||||
pub fn load_from_file(&mut self, path: &str) -> Result<CertStats, std::io::Error> {
|
||||
let contents = std::fs::read(path)?;
|
||||
let contents = rustpython_host_env::fs::read(path)?;
|
||||
self.load_from_bytes(&contents)
|
||||
}
|
||||
|
||||
@@ -648,7 +648,7 @@ impl<'a> CertLoader<'a> {
|
||||
/// Reads all files in the directory and attempts to parse them as certificates.
|
||||
/// Invalid files are silently skipped (matches OpenSSL capath behavior).
|
||||
pub fn load_from_dir(&mut self, dir_path: &str) -> Result<CertStats, std::io::Error> {
|
||||
let entries = std::fs::read_dir(dir_path)?;
|
||||
let entries = rustpython_host_env::fs::read_dir(dir_path)?;
|
||||
let mut stats = CertStats::default();
|
||||
|
||||
for entry in entries {
|
||||
@@ -658,7 +658,7 @@ impl<'a> CertLoader<'a> {
|
||||
// Skip directories and process all files
|
||||
// OpenSSL capath uses hash-based naming like "4e1295a3.0"
|
||||
if path.is_file()
|
||||
&& let Ok(contents) = std::fs::read(&path)
|
||||
&& let Ok(contents) = rustpython_host_env::fs::read(&path)
|
||||
{
|
||||
// Ignore errors for individual files (some may not be certs)
|
||||
if let Ok(file_stats) = self.load_from_bytes(&contents) {
|
||||
@@ -1129,7 +1129,7 @@ pub(super) fn load_cert_chain_from_file(
|
||||
password: Option<&str>,
|
||||
) -> Result<(Vec<CertificateDer<'static>>, PrivateKeyDer<'static>), Box<dyn core::error::Error>> {
|
||||
// Load certificate file - preserve io::Error for errno
|
||||
let cert_contents = std::fs::read(cert_path)?;
|
||||
let cert_contents = rustpython_host_env::fs::read(cert_path)?;
|
||||
|
||||
// Parse certificates (PEM format)
|
||||
let mut cert_cursor = std::io::Cursor::new(&cert_contents);
|
||||
@@ -1142,7 +1142,7 @@ pub(super) fn load_cert_chain_from_file(
|
||||
}
|
||||
|
||||
// Load private key file - preserve io::Error for errno
|
||||
let key_contents = std::fs::read(key_path)?;
|
||||
let key_contents = rustpython_host_env::fs::read(key_path)?;
|
||||
|
||||
// Parse private key (supports PKCS8, RSA, EC formats)
|
||||
let private_key = if let Some(pwd) = password {
|
||||
|
||||
@@ -4,15 +4,13 @@ pub(crate) use syslog::module_def;
|
||||
|
||||
#[pymodule(name = "syslog")]
|
||||
mod syslog {
|
||||
use crate::common::lock::PyRwLock;
|
||||
use crate::vm::{
|
||||
PyObjectRef, PyPayload, PyResult, VirtualMachine,
|
||||
builtins::{PyStr, PyStrRef},
|
||||
function::{OptionalArg, OptionalOption},
|
||||
utils::ToCString,
|
||||
};
|
||||
use core::ffi::CStr;
|
||||
use std::os::raw::c_char;
|
||||
use rustpython_host_env::syslog as host_syslog;
|
||||
|
||||
#[pyattr]
|
||||
use libc::{
|
||||
@@ -41,28 +39,6 @@ mod syslog {
|
||||
None
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum GlobalIdent {
|
||||
Explicit(Box<CStr>),
|
||||
Implicit,
|
||||
}
|
||||
|
||||
impl GlobalIdent {
|
||||
fn as_ptr(&self) -> *const c_char {
|
||||
match self {
|
||||
Self::Explicit(cstr) => cstr.as_ptr(),
|
||||
Self::Implicit => core::ptr::null(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn global_ident() -> &'static PyRwLock<Option<GlobalIdent>> {
|
||||
rustpython_common::static_cell! {
|
||||
static IDENT: PyRwLock<Option<GlobalIdent>>;
|
||||
};
|
||||
IDENT.get_or_init(|| PyRwLock::new(None))
|
||||
}
|
||||
|
||||
#[derive(Default, FromArgs)]
|
||||
struct OpenLogArgs {
|
||||
#[pyarg(any, optional)]
|
||||
@@ -83,16 +59,7 @@ mod syslog {
|
||||
}
|
||||
.map(|ident| ident.into_boxed_c_str());
|
||||
|
||||
let ident = match ident {
|
||||
Some(ident) => GlobalIdent::Explicit(ident),
|
||||
None => GlobalIdent::Implicit,
|
||||
};
|
||||
|
||||
{
|
||||
let mut locked_ident = global_ident().write();
|
||||
unsafe { libc::openlog(ident.as_ptr(), logoption, facility) };
|
||||
*locked_ident = Some(ident);
|
||||
}
|
||||
host_syslog::openlog(ident, logoption, facility);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -111,38 +78,34 @@ mod syslog {
|
||||
None => (LOG_INFO, args.priority.try_into_value(vm)?),
|
||||
};
|
||||
|
||||
if global_ident().read().is_none() {
|
||||
if !host_syslog::is_open() {
|
||||
openlog(OpenLogArgs::default(), vm)?;
|
||||
}
|
||||
|
||||
let (cformat, cmsg) = ("%s".to_cstring(vm)?, msg.to_cstring(vm)?);
|
||||
unsafe { libc::syslog(priority, cformat.as_ptr(), cmsg.as_ptr()) };
|
||||
let cmsg = msg.to_cstring(vm)?;
|
||||
host_syslog::syslog(priority, cmsg.as_c_str());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn closelog() {
|
||||
if global_ident().read().is_some() {
|
||||
let mut locked_ident = global_ident().write();
|
||||
unsafe { libc::closelog() };
|
||||
*locked_ident = None;
|
||||
}
|
||||
host_syslog::closelog();
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn setlogmask(maskpri: i32) -> i32 {
|
||||
unsafe { libc::setlogmask(maskpri) }
|
||||
host_syslog::setlogmask(maskpri)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[pyfunction(name = "LOG_MASK")]
|
||||
const fn log_mask(pri: i32) -> i32 {
|
||||
pri << 1
|
||||
host_syslog::log_mask(pri)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[pyfunction(name = "LOG_UPTO")]
|
||||
const fn log_upto(pri: i32) -> i32 {
|
||||
(1 << (pri + 1)) - 1
|
||||
host_syslog::log_upto(pri)
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,9 @@ mod termios {
|
||||
use crate::vm::{
|
||||
PyObjectRef, PyResult, TryFromObject, VirtualMachine,
|
||||
builtins::{PyBaseExceptionRef, PyBytes, PyInt, PyListRef, PyTypeRef},
|
||||
common::os::ErrorExt,
|
||||
convert::ToPyObject,
|
||||
};
|
||||
use termios::Termios;
|
||||
use rustpython_host_env::{os::ErrorExt, termios as host_termios};
|
||||
|
||||
// TODO: more ioctl numbers
|
||||
// NOTE: B2500000, B3000000, B3500000, B4000000, and CIBAUD
|
||||
@@ -171,7 +170,7 @@ mod termios {
|
||||
|
||||
#[pyfunction]
|
||||
fn tcgetattr(fd: i32, vm: &VirtualMachine) -> PyResult<Vec<PyObjectRef>> {
|
||||
let termios = Termios::from_fd(fd).map_err(|e| termios_error(e, vm))?;
|
||||
let termios = host_termios::tcgetattr(fd).map_err(|e| termios_error(e, vm))?;
|
||||
let noncanon = (termios.c_lflag & termios::ICANON) == 0;
|
||||
let cc = termios
|
||||
.c_cc
|
||||
@@ -200,7 +199,7 @@ mod termios {
|
||||
<&[PyObjectRef; 7]>::try_from(&*attributes.borrow_vec())
|
||||
.map_err(|_| vm.new_type_error("tcsetattr, arg 3: must be 7 element list"))?
|
||||
.clone();
|
||||
let mut termios = Termios::from_fd(fd).map_err(|e| termios_error(e, vm))?;
|
||||
let mut termios = host_termios::tcgetattr(fd).map_err(|e| termios_error(e, vm))?;
|
||||
termios.c_iflag = iflag.try_into_value(vm)?;
|
||||
termios.c_oflag = oflag.try_into_value(vm)?;
|
||||
termios.c_cflag = cflag.try_into_value(vm)?;
|
||||
@@ -231,32 +230,32 @@ mod termios {
|
||||
};
|
||||
}
|
||||
|
||||
termios::tcsetattr(fd, when, &termios).map_err(|e| termios_error(e, vm))?;
|
||||
host_termios::tcsetattr(fd, when, &termios).map_err(|e| termios_error(e, vm))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn tcsendbreak(fd: i32, duration: i32, vm: &VirtualMachine) -> PyResult<()> {
|
||||
termios::tcsendbreak(fd, duration).map_err(|e| termios_error(e, vm))?;
|
||||
host_termios::tcsendbreak(fd, duration).map_err(|e| termios_error(e, vm))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn tcdrain(fd: i32, vm: &VirtualMachine) -> PyResult<()> {
|
||||
termios::tcdrain(fd).map_err(|e| termios_error(e, vm))?;
|
||||
host_termios::tcdrain(fd).map_err(|e| termios_error(e, vm))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn tcflush(fd: i32, queue: i32, vm: &VirtualMachine) -> PyResult<()> {
|
||||
termios::tcflush(fd, queue).map_err(|e| termios_error(e, vm))?;
|
||||
host_termios::tcflush(fd, queue).map_err(|e| termios_error(e, vm))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn tcflow(fd: i32, action: i32, vm: &VirtualMachine) -> PyResult<()> {
|
||||
termios::tcflow(fd, action).map_err(|e| termios_error(e, vm))?;
|
||||
host_termios::tcflow(fd, action).map_err(|e| termios_error(e, vm))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
#![allow(
|
||||
clippy::disallowed_methods,
|
||||
reason = "tkinter environment setup still uses direct host APIs until later extraction"
|
||||
)]
|
||||
|
||||
// spell-checker:ignore createcommand
|
||||
|
||||
pub(crate) use self::_tkinter::module_def;
|
||||
|
||||
@@ -33,6 +33,7 @@ rustpython-compiler = { workspace = true, optional = true }
|
||||
rustpython-codegen = { workspace = true, optional = true }
|
||||
rustpython-common = { workspace = true }
|
||||
rustpython-derive = { workspace = true }
|
||||
rustpython-host_env = { workspace = true }
|
||||
rustpython-jit = { workspace = true, optional = true }
|
||||
|
||||
ruff_python_ast = { workspace = true, optional = true }
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
#![allow(
|
||||
clippy::disallowed_methods,
|
||||
reason = "build scripts cannot use rustpython-host_env"
|
||||
)]
|
||||
|
||||
use itertools::Itertools;
|
||||
use std::{env, io::prelude::*, path::PathBuf, process::Command};
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
disallowed-methods = [
|
||||
{ path = "std::fs::read", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::write", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::read_to_string", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::read_dir", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::create_dir", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::create_dir_all", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::remove_file", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::remove_dir", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::metadata", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::symlink_metadata", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::canonicalize", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::File::open", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::File::create", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::fs::OpenOptions::open", reason = "use rustpython_host_env for host filesystem access" },
|
||||
{ path = "std::env::var", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::var_os", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::set_var", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::remove_var", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::vars", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::vars_os", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::current_dir", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::set_current_dir", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::env::temp_dir", reason = "use rustpython_host_env for host environment access" },
|
||||
{ path = "std::process::Command::new", reason = "use rustpython_host_env for host process access" },
|
||||
{ path = "std::process::exit", reason = "use rustpython_host_env for host process access" },
|
||||
{ path = "std::process::abort", reason = "use rustpython_host_env for host process access" },
|
||||
{ path = "std::process::id", reason = "use rustpython_host_env for host process access" },
|
||||
{ path = "std::net::TcpStream::connect", reason = "use rustpython_host_env for host network access" },
|
||||
{ path = "std::net::TcpListener::bind", reason = "use rustpython_host_env for host network access" },
|
||||
{ path = "std::net::UdpSocket::bind", reason = "use rustpython_host_env for host network access" },
|
||||
]
|
||||
@@ -2,12 +2,14 @@
|
||||
|
||||
use super::{PyBytesRef, PyStrRef, PyTupleRef, PyType, set::PyFrozenSet};
|
||||
use crate::common::lock::PyMutex;
|
||||
#[cfg(feature = "host_env")]
|
||||
use crate::convert::ToPyException;
|
||||
use crate::{
|
||||
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
|
||||
builtins::PyStrInterned,
|
||||
bytecode::{self, AsBag, BorrowedConstant, CodeFlags, Constant, ConstantBag, Instruction},
|
||||
class::{PyClassImpl, StaticType},
|
||||
convert::{ToPyException, ToPyObject},
|
||||
convert::ToPyObject,
|
||||
frozen,
|
||||
function::OptionalArg,
|
||||
types::{Comparable, Constructor, Hashable, Representable},
|
||||
@@ -517,12 +519,13 @@ impl PyCode {
|
||||
Self::new_ref_with_bag(vm, code.decode(PyVmBag(vm)))
|
||||
}
|
||||
|
||||
#[cfg(feature = "host_env")]
|
||||
pub fn from_pyc_path(path: &std::path::Path, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
let name = match path.file_stem() {
|
||||
Some(stem) => stem.display().to_string(),
|
||||
None => "".to_owned(),
|
||||
};
|
||||
let content = std::fs::read(path).map_err(|e| e.to_pyexception(vm))?;
|
||||
let content = crate::host_env::fs::read(path).map_err(|e| e.to_pyexception(vm))?;
|
||||
Self::from_pyc(
|
||||
&content,
|
||||
Some(&name),
|
||||
@@ -531,6 +534,10 @@ impl PyCode {
|
||||
vm,
|
||||
)
|
||||
}
|
||||
#[cfg(not(feature = "host_env"))]
|
||||
pub fn from_pyc_path(_path: &std::path::Path, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
Err(vm.new_runtime_error("loading a pyc file requires the `host_env` feature".to_owned()))
|
||||
}
|
||||
pub fn from_pyc(
|
||||
pyc_bytes: &[u8],
|
||||
name: Option<&str>,
|
||||
|
||||
@@ -17,10 +17,9 @@ use crate::{
|
||||
};
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use itertools::Itertools;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
io::{self, BufRead, BufReader},
|
||||
};
|
||||
#[cfg(feature = "host_env")]
|
||||
use std::io::{BufRead, BufReader};
|
||||
use std::{collections::HashSet, io};
|
||||
|
||||
pub use super::exception_group::exception_group;
|
||||
|
||||
@@ -366,6 +365,7 @@ impl VirtualMachine {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "host_env")]
|
||||
fn print_source_line<W: Write>(
|
||||
output: &mut W,
|
||||
filename: &str,
|
||||
@@ -373,7 +373,7 @@ fn print_source_line<W: Write>(
|
||||
) -> Result<(), W::Error> {
|
||||
// TODO: use io.open() method instead, when available, according to https://github.com/python/cpython/blob/main/Python/traceback.c#L393
|
||||
// TODO: support different encodings
|
||||
let file = match std::fs::File::open(filename) {
|
||||
let file = match crate::host_env::fs::open(filename) {
|
||||
Ok(file) => file,
|
||||
Err(_) => return Ok(()),
|
||||
};
|
||||
@@ -392,6 +392,15 @@ fn print_source_line<W: Write>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "host_env"))]
|
||||
fn print_source_line<W: Write>(
|
||||
_output: &mut W,
|
||||
_filename: &str,
|
||||
_lineno: usize,
|
||||
) -> Result<(), W::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Print exception occurrence location from traceback element
|
||||
fn write_traceback_entry<W: Write>(
|
||||
output: &mut W,
|
||||
@@ -1380,7 +1389,7 @@ impl IntoPyException for OSErrorBuilder {
|
||||
|
||||
impl ToOSErrorBuilder for std::io::Error {
|
||||
fn to_os_error_builder(&self, vm: &VirtualMachine) -> OSErrorBuilder {
|
||||
use crate::common::os::ErrorExt;
|
||||
use crate::host_env::os::ErrorExt;
|
||||
|
||||
let errno = self.posix_errno();
|
||||
#[cfg(windows)]
|
||||
@@ -1937,7 +1946,7 @@ pub(super) mod types {
|
||||
.as_ref()
|
||||
.and_then(|w| w.downcast_ref::<crate::builtins::PyInt>())
|
||||
.and_then(|w| w.try_to_primitive::<i32>(vm).ok())
|
||||
.map(crate::common::os::winerror_to_errno)
|
||||
.map(crate::host_env::os::winerror_to_errno)
|
||||
{
|
||||
let errno_obj = vm.new_pyobj(errno);
|
||||
let _ = unsafe { exc.errno.swap(Some(errno_obj.clone())) };
|
||||
|
||||
@@ -123,7 +123,7 @@ impl FsPath {
|
||||
}
|
||||
|
||||
pub fn bytes_as_os_str<'a>(b: &'a [u8], vm: &VirtualMachine) -> PyResult<&'a std::ffi::OsStr> {
|
||||
rustpython_common::os::bytes_as_os_str(b)
|
||||
rustpython_host_env::os::bytes_as_os_str(b)
|
||||
.map_err(|_| vm.new_unicode_decode_error("can't decode path for utf-8"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ pub fn init_path_config(settings: &Settings) -> Paths {
|
||||
// In this case:
|
||||
// - sys.executable should be the launcher path (where user invoked Python)
|
||||
// - sys._base_executable should be the real Python executable
|
||||
let exe_dir = if let Ok(launcher) = env::var("__PYVENV_LAUNCHER__") {
|
||||
let exe_dir = if let Ok(launcher) = crate::host_env::os::var("__PYVENV_LAUNCHER__") {
|
||||
paths.executable = launcher.clone();
|
||||
paths.base_executable = real_executable;
|
||||
PathBuf::from(&launcher).parent().map(PathBuf::from)
|
||||
@@ -370,8 +370,9 @@ fn get_executable_path() -> Option<PathBuf> {
|
||||
}
|
||||
|
||||
/// Parse pyvenv.cfg and extract the 'home' key value
|
||||
#[cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))]
|
||||
fn parse_pyvenv_home(pyvenv_cfg: &Path) -> Option<String> {
|
||||
let content = std::fs::read_to_string(pyvenv_cfg).ok()?;
|
||||
let content = crate::host_env::fs::read_to_string(pyvenv_cfg).ok()?;
|
||||
|
||||
for line in content.lines() {
|
||||
if let Some((key, value)) = line.split_once('=')
|
||||
@@ -384,6 +385,11 @@ fn parse_pyvenv_home(pyvenv_cfg: &Path) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
|
||||
fn parse_pyvenv_home(_pyvenv_cfg: &Path) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -399,7 +405,10 @@ mod tests {
|
||||
#[test]
|
||||
fn test_search_up() {
|
||||
// Test with a path that doesn't have any landmarks
|
||||
let result = search_up_file(std::env::temp_dir(), &["nonexistent_landmark_xyz"]);
|
||||
let result = search_up_file(
|
||||
crate::host_env::os::temp_dir(),
|
||||
&["nonexistent_landmark_xyz"],
|
||||
);
|
||||
assert!(result.is_none());
|
||||
}
|
||||
|
||||
|
||||
@@ -340,7 +340,7 @@ pub(crate) fn is_possibly_shadowing_path(origin: &str, vm: &VirtualMachine) -> b
|
||||
};
|
||||
|
||||
let cmp_path = if sys_path_0.is_empty() {
|
||||
match std::env::current_dir() {
|
||||
match crate::host_env::os::current_dir() {
|
||||
Ok(d) => d.to_string_lossy().to_string(),
|
||||
Err(_) => return false,
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
// to allow `mod foo {}` in foo.rs; clippy thinks this is a mistake/misunderstanding of
|
||||
// how `mod` works, but we want this sometimes for pymodule declarations
|
||||
#![deny(clippy::disallowed_methods)]
|
||||
#![allow(clippy::module_inception)]
|
||||
// we want to mirror python naming conventions when defining python structs, so that does mean
|
||||
// uppercase acronyms, e.g. TextIOWrapper instead of TextIoWrapper
|
||||
@@ -105,6 +106,7 @@ pub use self::vm::{Context, Interpreter, InterpreterBuilder, Settings, VirtualMa
|
||||
|
||||
pub use rustpython_common as common;
|
||||
pub use rustpython_compiler_core::{bytecode, frozen};
|
||||
pub use rustpython_host_env as host_env;
|
||||
pub use rustpython_literal as literal;
|
||||
|
||||
#[doc(hidden)]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use rustpython_common::crt_fd;
|
||||
use rustpython_host_env::crt_fd;
|
||||
|
||||
use crate::{
|
||||
AsObject, PyObjectRef, PyResult, VirtualMachine,
|
||||
|
||||
@@ -105,18 +105,34 @@ mod rustyline_readline {
|
||||
}
|
||||
|
||||
pub fn load_history(&mut self, path: &Path) -> OtherResult<()> {
|
||||
self.repl.load_history(path)?;
|
||||
Ok(())
|
||||
#[cfg(not(feature = "host_env"))]
|
||||
{
|
||||
let _ = path;
|
||||
Err(io::Error::other("history requires the `host_env` feature").into())
|
||||
}
|
||||
#[cfg(feature = "host_env")]
|
||||
{
|
||||
self.repl.load_history(path)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn save_history(&mut self, path: &Path) -> OtherResult<()> {
|
||||
if !path.exists()
|
||||
&& let Some(parent) = path.parent()
|
||||
#[cfg(not(feature = "host_env"))]
|
||||
{
|
||||
std::fs::create_dir_all(parent)?;
|
||||
let _ = path;
|
||||
Err(io::Error::other("history requires the `host_env` feature").into())
|
||||
}
|
||||
#[cfg(feature = "host_env")]
|
||||
{
|
||||
if !path.exists()
|
||||
&& let Some(parent) = path.parent()
|
||||
{
|
||||
crate::host_env::fs::create_dir_all(parent)?;
|
||||
}
|
||||
self.repl.save_history(path)?;
|
||||
Ok(())
|
||||
}
|
||||
self.repl.save_history(path)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_history_entry(&mut self, entry: &str) -> OtherResult<()> {
|
||||
|
||||
@@ -387,7 +387,7 @@ mod _codecs_windows {
|
||||
|
||||
#[pyfunction]
|
||||
fn mbcs_encode(args: MbcsEncodeArgs, vm: &VirtualMachine) -> PyResult<(Vec<u8>, usize)> {
|
||||
use crate::common::windows::ToWideString;
|
||||
use crate::host_env::windows::ToWideString;
|
||||
use windows_sys::Win32::Globalization::{
|
||||
CP_ACP, WC_NO_BEST_FIT_CHARS, WideCharToMultiByte,
|
||||
};
|
||||
@@ -573,7 +573,7 @@ mod _codecs_windows {
|
||||
|
||||
#[pyfunction]
|
||||
fn oem_encode(args: OemEncodeArgs, vm: &VirtualMachine) -> PyResult<(Vec<u8>, usize)> {
|
||||
use crate::common::windows::ToWideString;
|
||||
use crate::host_env::windows::ToWideString;
|
||||
use windows_sys::Win32::Globalization::{
|
||||
CP_OEMCP, WC_NO_BEST_FIT_CHARS, WideCharToMultiByte,
|
||||
};
|
||||
@@ -1049,7 +1049,7 @@ mod _codecs_windows {
|
||||
args: CodePageEncodeArgs,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<(Vec<u8>, usize)> {
|
||||
use crate::common::windows::ToWideString;
|
||||
use crate::host_env::windows::ToWideString;
|
||||
|
||||
if args.code_page < 0 {
|
||||
return Err(vm.new_value_error("invalid code page number"));
|
||||
|
||||
@@ -2154,7 +2154,7 @@ unsafe extern "C" fn thunk_callback(
|
||||
// Swap errno before call if FUNCFLAG_USE_ERRNO is set
|
||||
let use_errno = userdata.flags & StgInfoFlags::FUNCFLAG_USE_ERRNO.bits() != 0;
|
||||
let saved_errno = if use_errno {
|
||||
let current = rustpython_common::os::get_errno();
|
||||
let current = rustpython_host_env::os::get_errno();
|
||||
// TODO: swap with ctypes stored errno (thread-local)
|
||||
Some(current)
|
||||
} else {
|
||||
@@ -2175,10 +2175,10 @@ unsafe extern "C" fn thunk_callback(
|
||||
|
||||
// Swap errno back after call
|
||||
if use_errno {
|
||||
let _current = rustpython_common::os::get_errno();
|
||||
let _current = rustpython_host_env::os::get_errno();
|
||||
// TODO: store current errno to ctypes storage
|
||||
if let Some(saved) = saved_errno {
|
||||
rustpython_common::os::set_errno(saved);
|
||||
rustpython_host_env::os::set_errno(saved);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ pub(crate) use _io::reinit_std_streams_after_fork;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))] {
|
||||
use crate::common::crt_fd::Offset;
|
||||
use rustpython_host_env::crt_fd::Offset;
|
||||
} else {
|
||||
type Offset = i64;
|
||||
}
|
||||
@@ -5323,11 +5323,12 @@ mod _io {
|
||||
#[pymodule]
|
||||
mod fileio {
|
||||
use super::{_io::*, Offset, iobase_finalize};
|
||||
use crate::host_env::crt_fd;
|
||||
use crate::{
|
||||
AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
|
||||
VirtualMachine,
|
||||
builtins::{PyBaseExceptionRef, PyUtf8Str, PyUtf8StrRef},
|
||||
common::{crt_fd, wtf8::Wtf8Buf},
|
||||
common::wtf8::Wtf8Buf,
|
||||
convert::{IntoPyException, ToPyException},
|
||||
exceptions::OSErrorBuilder,
|
||||
function::{ArgBytesLike, ArgMemoryBuffer, OptionalArg, OptionalOption},
|
||||
@@ -5554,7 +5555,7 @@ mod fileio {
|
||||
|
||||
// TODO: _Py_set_inheritable
|
||||
|
||||
let fd_fstat = crate::common::fileutils::fstat(fd);
|
||||
let fd_fstat = rustpython_host_env::fileutils::fstat(fd);
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
@@ -6017,7 +6018,7 @@ mod winconsoleio {
|
||||
const BUFMAX: usize = 32 * 1024 * 1024;
|
||||
|
||||
fn handle_from_fd(fd: i32) -> HANDLE {
|
||||
unsafe { rustpython_common::suppress_iph!(libc::get_osfhandle(fd)) as HANDLE }
|
||||
unsafe { rustpython_host_env::suppress_iph!(libc::get_osfhandle(fd)) as HANDLE }
|
||||
}
|
||||
|
||||
fn is_invalid_handle(handle: HANDLE) -> bool {
|
||||
|
||||
@@ -13,6 +13,8 @@ pub(crate) mod _signal {
|
||||
function::{ArgIntoFloat, OptionalArg},
|
||||
};
|
||||
use core::sync::atomic::{self, Ordering};
|
||||
#[cfg(unix)]
|
||||
use rustpython_host_env::signal::{double_to_timeval, itimerval_to_tuple};
|
||||
|
||||
#[cfg(any(unix, windows))]
|
||||
use libc::sighandler_t;
|
||||
@@ -280,27 +282,6 @@ pub(crate) mod _signal {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn timeval_to_double(tv: &libc::timeval) -> f64 {
|
||||
tv.tv_sec as f64 + (tv.tv_usec as f64 / 1_000_000.0)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn double_to_timeval(val: f64) -> libc::timeval {
|
||||
libc::timeval {
|
||||
tv_sec: val.trunc() as _,
|
||||
tv_usec: ((val.fract()) * 1_000_000.0) as _,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn itimerval_to_tuple(it: &libc::itimerval) -> (f64, f64) {
|
||||
(
|
||||
timeval_to_double(&it.it_value),
|
||||
timeval_to_double(&it.it_interval),
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[pyfunction]
|
||||
fn setitimer(
|
||||
@@ -404,16 +385,17 @@ pub(crate) mod _signal {
|
||||
let fd_i32 = i32::try_from(fd).map_err(|_| vm.new_value_error("invalid fd"))?;
|
||||
// Verify the fd is valid by trying to fstat it
|
||||
let borrowed_fd =
|
||||
unsafe { crate::common::crt_fd::Borrowed::try_borrow_raw(fd_i32) }
|
||||
unsafe { rustpython_host_env::crt_fd::Borrowed::try_borrow_raw(fd_i32) }
|
||||
.map_err(|e| e.into_pyexception(vm))?;
|
||||
crate::common::fileutils::fstat(borrowed_fd).map_err(|e| e.into_pyexception(vm))?;
|
||||
rustpython_host_env::fileutils::fstat(borrowed_fd)
|
||||
.map_err(|e| e.into_pyexception(vm))?;
|
||||
}
|
||||
is_socket
|
||||
} else {
|
||||
false
|
||||
};
|
||||
#[cfg(unix)]
|
||||
if let Ok(fd) = unsafe { crate::common::crt_fd::Borrowed::try_borrow_raw(fd) } {
|
||||
if let Ok(fd) = unsafe { rustpython_host_env::crt_fd::Borrowed::try_borrow_raw(fd) } {
|
||||
use nix::fcntl;
|
||||
let oflags = fcntl::fcntl(fd, fcntl::F_GETFL).map_err(|e| e.into_pyexception(vm))?;
|
||||
let nonblock =
|
||||
|
||||
@@ -8,7 +8,7 @@ mod _winapi {
|
||||
use crate::{
|
||||
Py, PyObjectRef, PyPayload, PyResult, TryFromObject, VirtualMachine,
|
||||
builtins::PyStrRef,
|
||||
common::{lock::PyMutex, windows::ToWideString},
|
||||
common::lock::PyMutex,
|
||||
convert::{ToPyException, ToPyResult},
|
||||
function::{ArgMapping, ArgSequence, OptionalArg},
|
||||
types::Constructor,
|
||||
@@ -16,6 +16,8 @@ mod _winapi {
|
||||
};
|
||||
use core::ptr::{null, null_mut};
|
||||
use rustpython_common::wtf8::Wtf8Buf;
|
||||
use rustpython_host_env::winapi as host_winapi;
|
||||
use rustpython_host_env::windows::ToWideString;
|
||||
use windows_sys::Win32::Foundation::{HANDLE, MAX_PATH};
|
||||
|
||||
#[pyattr]
|
||||
@@ -200,12 +202,12 @@ mod _winapi {
|
||||
|
||||
#[pyfunction]
|
||||
fn GetACP() -> u32 {
|
||||
unsafe { windows_sys::Win32::Globalization::GetACP() }
|
||||
host_winapi::get_acp()
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn GetCurrentProcess() -> WinHandle {
|
||||
WinHandle(unsafe { windows_sys::Win32::System::Threading::GetCurrentProcess() })
|
||||
WinHandle(host_winapi::get_current_process())
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
@@ -223,12 +225,12 @@ mod _winapi {
|
||||
|
||||
#[pyfunction]
|
||||
fn GetLastError() -> u32 {
|
||||
unsafe { windows_sys::Win32::Foundation::GetLastError() }
|
||||
host_winapi::get_last_error()
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn GetVersion() -> u32 {
|
||||
unsafe { windows_sys::Win32::System::SystemInformation::GetVersion() }
|
||||
host_winapi::get_version()
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
|
||||
@@ -7,10 +7,11 @@ mod msvcrt {
|
||||
use crate::{
|
||||
PyRef, PyResult, VirtualMachine,
|
||||
builtins::{PyBytes, PyStrRef},
|
||||
common::{crt_fd, suppress_iph},
|
||||
convert::IntoPyException,
|
||||
host_env::crt_fd,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use rustpython_host_env::msvcrt as host_msvcrt;
|
||||
use std::os::windows::io::AsRawHandle;
|
||||
use windows_sys::Win32::System::Diagnostics::Debug;
|
||||
|
||||
@@ -21,54 +22,36 @@ mod msvcrt {
|
||||
};
|
||||
|
||||
pub fn setmode_binary(fd: crt_fd::Borrowed<'_>) {
|
||||
unsafe { suppress_iph!(_setmode(fd, libc::O_BINARY)) };
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
fn _getch() -> i32;
|
||||
fn _getwch() -> u32;
|
||||
fn _getche() -> i32;
|
||||
fn _getwche() -> u32;
|
||||
fn _putch(c: u32) -> i32;
|
||||
fn _putwch(c: u16) -> u32;
|
||||
fn _ungetch(c: i32) -> i32;
|
||||
fn _ungetwch(c: u32) -> u32;
|
||||
fn _locking(fd: i32, mode: i32, nbytes: i64) -> i32;
|
||||
fn _heapmin() -> i32;
|
||||
fn _kbhit() -> i32;
|
||||
host_msvcrt::setmode_binary(fd);
|
||||
}
|
||||
|
||||
// Locking mode constants
|
||||
#[pyattr]
|
||||
const LK_UNLCK: i32 = 0; // Unlock
|
||||
const LK_UNLCK: i32 = host_msvcrt::LK_UNLCK; // Unlock
|
||||
#[pyattr]
|
||||
const LK_LOCK: i32 = 1; // Lock (blocking)
|
||||
const LK_LOCK: i32 = host_msvcrt::LK_LOCK; // Lock (blocking)
|
||||
#[pyattr]
|
||||
const LK_NBLCK: i32 = 2; // Non-blocking lock
|
||||
const LK_NBLCK: i32 = host_msvcrt::LK_NBLCK; // Non-blocking lock
|
||||
#[pyattr]
|
||||
const LK_RLCK: i32 = 3; // Lock for reading (same as LK_LOCK)
|
||||
const LK_RLCK: i32 = host_msvcrt::LK_RLCK; // Lock for reading (same as LK_LOCK)
|
||||
#[pyattr]
|
||||
const LK_NBRLCK: i32 = 4; // Non-blocking lock for reading (same as LK_NBLCK)
|
||||
const LK_NBRLCK: i32 = host_msvcrt::LK_NBRLCK; // Non-blocking lock for reading (same as LK_NBLCK)
|
||||
|
||||
#[pyfunction]
|
||||
fn getch() -> Vec<u8> {
|
||||
let c = unsafe { _getch() };
|
||||
vec![c as u8]
|
||||
host_msvcrt::getch()
|
||||
}
|
||||
#[pyfunction]
|
||||
fn getwch() -> String {
|
||||
let c = unsafe { _getwch() };
|
||||
char::from_u32(c).unwrap().to_string()
|
||||
host_msvcrt::getwch()
|
||||
}
|
||||
#[pyfunction]
|
||||
fn getche() -> Vec<u8> {
|
||||
let c = unsafe { _getche() };
|
||||
vec![c as u8]
|
||||
host_msvcrt::getche()
|
||||
}
|
||||
#[pyfunction]
|
||||
fn getwche() -> String {
|
||||
let c = unsafe { _getwche() };
|
||||
char::from_u32(c).unwrap().to_string()
|
||||
host_msvcrt::getwche()
|
||||
}
|
||||
#[pyfunction]
|
||||
fn putch(b: PyRef<PyBytes>, vm: &VirtualMachine) -> PyResult<()> {
|
||||
@@ -76,7 +59,7 @@ mod msvcrt {
|
||||
b.as_bytes().iter().exactly_one().map_err(|_| {
|
||||
vm.new_type_error("putch() argument must be a byte string of length 1")
|
||||
})?;
|
||||
unsafe { suppress_iph!(_putch(c.into())) };
|
||||
host_msvcrt::putch(c);
|
||||
Ok(())
|
||||
}
|
||||
#[pyfunction]
|
||||
@@ -86,7 +69,7 @@ mod msvcrt {
|
||||
.chars()
|
||||
.exactly_one()
|
||||
.map_err(|_| vm.new_type_error("putch() argument must be a string of length 1"))?;
|
||||
unsafe { suppress_iph!(_putwch(c as u16)) };
|
||||
host_msvcrt::putwch(c);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -95,13 +78,7 @@ mod msvcrt {
|
||||
let &c = b.as_bytes().iter().exactly_one().map_err(|_| {
|
||||
vm.new_type_error("ungetch() argument must be a byte string of length 1")
|
||||
})?;
|
||||
let ret = unsafe { suppress_iph!(_ungetch(c as i32)) };
|
||||
if ret == -1 {
|
||||
// EOF returned means the buffer is full
|
||||
Err(vm.new_os_error(libc::ENOSPC))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
host_msvcrt::ungetch(c).map_err(|e| e.into_pyexception(vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
@@ -110,62 +87,32 @@ mod msvcrt {
|
||||
s.expect_str().chars().exactly_one().map_err(|_| {
|
||||
vm.new_type_error("ungetwch() argument must be a string of length 1")
|
||||
})?;
|
||||
let ret = unsafe { suppress_iph!(_ungetwch(c as u32)) };
|
||||
if ret == 0xFFFF {
|
||||
// WEOF returned means the buffer is full
|
||||
Err(vm.new_os_error(libc::ENOSPC))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
host_msvcrt::ungetwch(c).map_err(|e| e.into_pyexception(vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn kbhit() -> i32 {
|
||||
unsafe { _kbhit() }
|
||||
host_msvcrt::kbhit()
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn locking(fd: i32, mode: i32, nbytes: i64, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let ret = unsafe { suppress_iph!(_locking(fd, mode, nbytes)) };
|
||||
if ret == -1 {
|
||||
Err(vm.new_last_errno_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
host_msvcrt::locking(fd, mode, nbytes).map_err(|e| e.into_pyexception(vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn heapmin(vm: &VirtualMachine) -> PyResult<()> {
|
||||
let ret = unsafe { suppress_iph!(_heapmin()) };
|
||||
if ret == -1 {
|
||||
Err(vm.new_last_errno_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
fn _setmode(fd: crt_fd::Borrowed<'_>, flags: i32) -> i32;
|
||||
host_msvcrt::heapmin().map_err(|e| e.into_pyexception(vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn setmode(fd: crt_fd::Borrowed<'_>, flags: i32, vm: &VirtualMachine) -> PyResult<i32> {
|
||||
let flags = unsafe { suppress_iph!(_setmode(fd, flags)) };
|
||||
if flags == -1 {
|
||||
Err(vm.new_last_errno_error())
|
||||
} else {
|
||||
Ok(flags)
|
||||
}
|
||||
host_msvcrt::setmode(fd, flags).map_err(|e| e.into_pyexception(vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn open_osfhandle(handle: isize, flags: i32, vm: &VirtualMachine) -> PyResult<i32> {
|
||||
let ret = unsafe { suppress_iph!(libc::open_osfhandle(handle, flags)) };
|
||||
if ret == -1 {
|
||||
Err(vm.new_last_errno_error())
|
||||
} else {
|
||||
Ok(ret)
|
||||
}
|
||||
host_msvcrt::open_osfhandle(handle, flags).map_err(|e| e.into_pyexception(vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
@@ -178,12 +125,12 @@ mod msvcrt {
|
||||
#[allow(non_snake_case)]
|
||||
#[pyfunction]
|
||||
fn GetErrorMode() -> u32 {
|
||||
unsafe { suppress_iph!(Debug::GetErrorMode()) }
|
||||
host_msvcrt::get_error_mode()
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[pyfunction]
|
||||
fn SetErrorMode(mode: Debug::THREAD_ERROR_MODE, _: &VirtualMachine) -> u32 {
|
||||
unsafe { suppress_iph!(Debug::SetErrorMode(mode)) }
|
||||
host_msvcrt::set_error_mode(mode)
|
||||
}
|
||||
}
|
||||
+17
-76
@@ -10,18 +10,19 @@ pub(crate) mod module {
|
||||
builtins::{
|
||||
PyBaseExceptionRef, PyBytes, PyDictRef, PyListRef, PyStr, PyStrRef, PyTupleRef,
|
||||
},
|
||||
common::{crt_fd, suppress_iph, windows::ToWideString},
|
||||
convert::ToPyException,
|
||||
exceptions::OSErrorBuilder,
|
||||
function::{ArgMapping, Either, OptionalArg},
|
||||
host_env::{crt_fd, suppress_iph, windows::ToWideString},
|
||||
ospath::{OsPath, OsPathOrFd},
|
||||
stdlib::os::{_os, DirFd, SupportFunc, TargetIsDirectory},
|
||||
};
|
||||
use core::mem::MaybeUninit;
|
||||
use libc::intptr_t;
|
||||
use rustpython_common::wtf8::Wtf8Buf;
|
||||
use rustpython_host_env::nt as host_nt;
|
||||
use std::os::windows::io::AsRawHandle;
|
||||
use std::{env, io, os::windows::ffi::OsStringExt};
|
||||
use std::{io, os::windows::ffi::OsStringExt};
|
||||
use windows_sys::Win32::{
|
||||
Foundation::{self, INVALID_HANDLE_VALUE},
|
||||
Storage::FileSystem,
|
||||
@@ -235,7 +236,7 @@ pub(crate) mod module {
|
||||
fn environ(vm: &VirtualMachine) -> PyDictRef {
|
||||
let environ = vm.ctx.new_dict();
|
||||
|
||||
for (key, value) in env::vars() {
|
||||
for (key, value) in crate::host_env::os::vars() {
|
||||
// Skip hidden Windows environment variables (e.g., =C:, =D:, =ExitCode)
|
||||
// These are internal cmd.exe bookkeeping variables that store per-drive
|
||||
// current directories and cannot be reliably modified via _wputenv().
|
||||
@@ -250,7 +251,7 @@ pub(crate) mod module {
|
||||
#[pyfunction]
|
||||
fn _create_environ(vm: &VirtualMachine) -> PyDictRef {
|
||||
let environ = vm.ctx.new_dict();
|
||||
for (key, value) in env::vars() {
|
||||
for (key, value) in crate::host_env::os::vars() {
|
||||
if key.starts_with('=') {
|
||||
continue;
|
||||
}
|
||||
@@ -274,76 +275,16 @@ pub(crate) mod module {
|
||||
const S_IWRITE: u32 = 128;
|
||||
|
||||
fn win32_hchmod(handle: Foundation::HANDLE, mode: u32, vm: &VirtualMachine) -> PyResult<()> {
|
||||
use windows_sys::Win32::Storage::FileSystem::{
|
||||
FILE_BASIC_INFO, FileBasicInfo, GetFileInformationByHandleEx,
|
||||
SetFileInformationByHandle,
|
||||
};
|
||||
|
||||
// Get current file info
|
||||
let mut info: FILE_BASIC_INFO = unsafe { core::mem::zeroed() };
|
||||
let ret = unsafe {
|
||||
GetFileInformationByHandleEx(
|
||||
handle,
|
||||
FileBasicInfo,
|
||||
&mut info as *mut _ as *mut _,
|
||||
core::mem::size_of::<FILE_BASIC_INFO>() as u32,
|
||||
)
|
||||
};
|
||||
if ret == 0 {
|
||||
return Err(vm.new_last_os_error());
|
||||
}
|
||||
|
||||
// Modify readonly attribute based on S_IWRITE bit
|
||||
if mode & S_IWRITE != 0 {
|
||||
info.FileAttributes &= !FileSystem::FILE_ATTRIBUTE_READONLY;
|
||||
} else {
|
||||
info.FileAttributes |= FileSystem::FILE_ATTRIBUTE_READONLY;
|
||||
}
|
||||
|
||||
// Set the new attributes
|
||||
let ret = unsafe {
|
||||
SetFileInformationByHandle(
|
||||
handle,
|
||||
FileBasicInfo,
|
||||
&info as *const _ as *const _,
|
||||
core::mem::size_of::<FILE_BASIC_INFO>() as u32,
|
||||
)
|
||||
};
|
||||
if ret == 0 {
|
||||
return Err(vm.new_last_os_error());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
host_nt::win32_hchmod(handle, mode, S_IWRITE).map_err(|e| e.to_pyexception(vm))
|
||||
}
|
||||
|
||||
fn fchmod_impl(fd: i32, mode: u32, vm: &VirtualMachine) -> PyResult<()> {
|
||||
// Get Windows HANDLE from fd
|
||||
let borrowed = unsafe { crt_fd::Borrowed::borrow_raw(fd) };
|
||||
let handle = crt_fd::as_handle(borrowed).map_err(|e| e.to_pyexception(vm))?;
|
||||
let hfile = handle.as_raw_handle() as Foundation::HANDLE;
|
||||
win32_hchmod(hfile, mode, vm)
|
||||
host_nt::fchmod(fd, mode, S_IWRITE).map_err(|e| e.to_pyexception(vm))
|
||||
}
|
||||
|
||||
fn win32_lchmod(path: &OsPath, mode: u32, vm: &VirtualMachine) -> PyResult<()> {
|
||||
use windows_sys::Win32::Storage::FileSystem::{GetFileAttributesW, SetFileAttributesW};
|
||||
|
||||
let wide = path.to_wide_cstring(vm)?;
|
||||
let attr = unsafe { GetFileAttributesW(wide.as_ptr()) };
|
||||
if attr == FileSystem::INVALID_FILE_ATTRIBUTES {
|
||||
let err = io::Error::last_os_error();
|
||||
return Err(OSErrorBuilder::with_filename(&err, path.clone(), vm));
|
||||
}
|
||||
let new_attr = if mode & S_IWRITE != 0 {
|
||||
attr & !FileSystem::FILE_ATTRIBUTE_READONLY
|
||||
} else {
|
||||
attr | FileSystem::FILE_ATTRIBUTE_READONLY
|
||||
};
|
||||
let ret = unsafe { SetFileAttributesW(wide.as_ptr(), new_attr) };
|
||||
if ret == 0 {
|
||||
let err = io::Error::last_os_error();
|
||||
return Err(OSErrorBuilder::with_filename(&err, path.clone(), vm));
|
||||
}
|
||||
Ok(())
|
||||
host_nt::win32_lchmod(path.path.as_os_str(), mode, S_IWRITE)
|
||||
.map_err(|err| OSErrorBuilder::with_filename(&err, path.clone(), vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
@@ -411,7 +352,7 @@ pub(crate) mod module {
|
||||
/// Uses FindFirstFileW to get the name as stored on the filesystem.
|
||||
#[pyfunction]
|
||||
fn _findfirstfile(path: OsPath, vm: &VirtualMachine) -> PyResult<PyStrRef> {
|
||||
use crate::common::windows::ToWideString;
|
||||
use crate::host_env::windows::ToWideString;
|
||||
use std::os::windows::ffi::OsStringExt;
|
||||
use windows_sys::Win32::Storage::FileSystem::{
|
||||
FindClose, FindFirstFileW, WIN32_FIND_DATAW,
|
||||
@@ -575,10 +516,10 @@ pub(crate) mod module {
|
||||
|
||||
/// _testFileTypeByName - test file type by path name
|
||||
fn _test_file_type_by_name(path: &std::path::Path, tested_type: u32) -> bool {
|
||||
use crate::common::fileutils::windows::{
|
||||
use crate::host_env::fileutils::windows::{
|
||||
FILE_INFO_BY_NAME_CLASS, get_file_information_by_name,
|
||||
};
|
||||
use crate::common::windows::ToWideString;
|
||||
use crate::host_env::windows::ToWideString;
|
||||
use windows_sys::Win32::Foundation::{CloseHandle, INVALID_HANDLE_VALUE};
|
||||
use windows_sys::Win32::Storage::FileSystem::{
|
||||
CreateFileW, FILE_ATTRIBUTE_REPARSE_POINT, FILE_FLAG_BACKUP_SEMANTICS,
|
||||
@@ -670,10 +611,10 @@ pub(crate) mod module {
|
||||
|
||||
/// _testFileExistsByName - test if path exists
|
||||
fn _test_file_exists_by_name(path: &std::path::Path, follow_links: bool) -> bool {
|
||||
use crate::common::fileutils::windows::{
|
||||
use crate::host_env::fileutils::windows::{
|
||||
FILE_INFO_BY_NAME_CLASS, get_file_information_by_name,
|
||||
};
|
||||
use crate::common::windows::ToWideString;
|
||||
use crate::host_env::windows::ToWideString;
|
||||
use windows_sys::Win32::Foundation::{CloseHandle, INVALID_HANDLE_VALUE};
|
||||
use windows_sys::Win32::Storage::FileSystem::{
|
||||
CreateFileW, FILE_ATTRIBUTE_REPARSE_POINT, FILE_FLAG_BACKUP_SEMANTICS,
|
||||
@@ -761,7 +702,7 @@ pub(crate) mod module {
|
||||
fn _test_file_type(path_or_fd: &OsPathOrFd<'_>, tested_type: u32) -> bool {
|
||||
match path_or_fd {
|
||||
OsPathOrFd::Fd(fd) => {
|
||||
if let Ok(handle) = crate::common::crt_fd::as_handle(*fd) {
|
||||
if let Ok(handle) = crate::host_env::crt_fd::as_handle(*fd) {
|
||||
use std::os::windows::io::AsRawHandle;
|
||||
_test_file_type_by_handle(handle.as_raw_handle() as _, tested_type, true)
|
||||
} else {
|
||||
@@ -778,7 +719,7 @@ pub(crate) mod module {
|
||||
|
||||
match path_or_fd {
|
||||
OsPathOrFd::Fd(fd) => {
|
||||
if let Ok(handle) = crate::common::crt_fd::as_handle(*fd) {
|
||||
if let Ok(handle) = crate::host_env::crt_fd::as_handle(*fd) {
|
||||
use std::os::windows::io::AsRawHandle;
|
||||
let file_type = unsafe { GetFileType(handle.as_raw_handle() as _) };
|
||||
// GetFileType(hfile) != FILE_TYPE_UNKNOWN || !GetLastError()
|
||||
@@ -2156,7 +2097,7 @@ pub(crate) mod module {
|
||||
/// returns the substitute name from reparse data which includes the prefix
|
||||
#[pyfunction]
|
||||
fn readlink(path: OsPath, vm: &VirtualMachine) -> PyResult {
|
||||
use crate::common::windows::ToWideString;
|
||||
use crate::host_env::windows::ToWideString;
|
||||
use windows_sys::Win32::Foundation::CloseHandle;
|
||||
use windows_sys::Win32::Storage::FileSystem::{
|
||||
CreateFileW, FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT,
|
||||
|
||||
+43
-42
@@ -3,20 +3,20 @@
|
||||
use crate::{
|
||||
AsObject, Py, PyObjectRef, PyPayload, PyResult, TryFromObject, VirtualMachine,
|
||||
builtins::{PyModule, PySet},
|
||||
common::crt_fd,
|
||||
convert::{IntoPyException, ToPyException, ToPyObject},
|
||||
function::{ArgumentError, FromArgs, FuncArgs},
|
||||
host_env::crt_fd,
|
||||
};
|
||||
use std::{fs, io, path::Path};
|
||||
use std::{io, path::Path};
|
||||
|
||||
pub(crate) fn fs_metadata<P: AsRef<Path>>(
|
||||
path: P,
|
||||
follow_symlink: bool,
|
||||
) -> io::Result<fs::Metadata> {
|
||||
) -> io::Result<std::fs::Metadata> {
|
||||
if follow_symlink {
|
||||
fs::metadata(path.as_ref())
|
||||
crate::host_env::fs::metadata(path.as_ref())
|
||||
} else {
|
||||
fs::symlink_metadata(path.as_ref())
|
||||
crate::host_env::fs::symlink_metadata(path.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ pub(super) struct FollowSymlinks(
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn bytes_as_os_str<'a>(b: &'a [u8], vm: &VirtualMachine) -> PyResult<&'a std::ffi::OsStr> {
|
||||
rustpython_common::os::bytes_as_os_str(b)
|
||||
rustpython_host_env::os::bytes_as_os_str(b)
|
||||
.map_err(|_| vm.new_unicode_decode_error("can't decode path for utf-8"))
|
||||
}
|
||||
|
||||
@@ -152,8 +152,9 @@ impl ToPyObject for crt_fd::Borrowed<'_> {
|
||||
#[pymodule(sub)]
|
||||
pub(super) mod _os {
|
||||
use super::{DirFd, FollowSymlinks, SupportFunc};
|
||||
use crate::host_env::fileutils::StatStruct;
|
||||
#[cfg(windows)]
|
||||
use crate::common::windows::ToWideString;
|
||||
use crate::host_env::windows::ToWideString;
|
||||
#[cfg(any(unix, windows))]
|
||||
use crate::utils::ToCString;
|
||||
use crate::{
|
||||
@@ -161,15 +162,11 @@ pub(super) mod _os {
|
||||
builtins::{
|
||||
PyBytesRef, PyGenericAlias, PyIntRef, PyStrRef, PyTuple, PyTupleRef, PyTypeRef,
|
||||
},
|
||||
common::{
|
||||
crt_fd,
|
||||
fileutils::StatStruct,
|
||||
lock::{OnceCell, PyRwLock},
|
||||
suppress_iph,
|
||||
},
|
||||
common::lock::{OnceCell, PyRwLock},
|
||||
convert::{IntoPyException, ToPyObject},
|
||||
exceptions::{OSErrorBuilder, ToOSErrorBuilder},
|
||||
function::{ArgBytesLike, ArgMemoryBuffer, FsPath, FuncArgs, OptionalArg},
|
||||
host_env::crt_fd,
|
||||
ospath::{OsPath, OsPathOrFd, OutputMode, PathConverter},
|
||||
protocol::PyIterReturn,
|
||||
recursion::ReprGuard,
|
||||
@@ -179,7 +176,8 @@ pub(super) mod _os {
|
||||
use core::time::Duration;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use rustpython_common::wtf8::Wtf8Buf;
|
||||
use std::{env, fs, fs::OpenOptions, io, path::PathBuf, time::SystemTime};
|
||||
use rustpython_host_env::suppress_iph;
|
||||
use std::{fs, io, path::PathBuf, time::SystemTime};
|
||||
|
||||
const OPEN_DIR_FD: bool = cfg!(not(any(windows, target_os = "redox")));
|
||||
pub(crate) const MKDIR_DIR_FD: bool = cfg!(not(any(windows, target_os = "redox")));
|
||||
@@ -349,7 +347,7 @@ pub(super) mod _os {
|
||||
if let Some(fd) = dir_fd.raw_opt() {
|
||||
let res = unsafe { libc::mkdirat(fd, c_path.as_ptr(), mode as _) };
|
||||
return if res < 0 {
|
||||
let err = crate::common::os::errno_io_error();
|
||||
let err = crate::host_env::os::errno_io_error();
|
||||
Err(OSErrorBuilder::with_filename(&err, path, vm))
|
||||
} else {
|
||||
Ok(())
|
||||
@@ -359,7 +357,7 @@ pub(super) mod _os {
|
||||
let [] = dir_fd.0;
|
||||
let res = unsafe { libc::mkdir(c_path.as_ptr(), mode as _) };
|
||||
if res < 0 {
|
||||
let err = crate::common::os::errno_io_error();
|
||||
let err = crate::host_env::os::errno_io_error();
|
||||
return Err(OSErrorBuilder::with_filename(&err, path, vm));
|
||||
}
|
||||
Ok(())
|
||||
@@ -368,7 +366,7 @@ pub(super) mod _os {
|
||||
#[pyfunction]
|
||||
fn mkdirs(path: PyStrRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let os_path = vm.fsencode(&path)?;
|
||||
fs::create_dir_all(&*os_path).map_err(|err| err.into_pyexception(vm))
|
||||
crate::host_env::fs::create_dir_all(&*os_path).map_err(|err| err.into_pyexception(vm))
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
@@ -383,7 +381,7 @@ pub(super) mod _os {
|
||||
let c_path = path.clone().into_cstring(vm)?;
|
||||
let res = unsafe { libc::unlinkat(fd, c_path.as_ptr(), libc::AT_REMOVEDIR) };
|
||||
return if res < 0 {
|
||||
let err = crate::common::os::errno_io_error();
|
||||
let err = crate::host_env::os::errno_io_error();
|
||||
Err(OSErrorBuilder::with_filename(&err, path, vm))
|
||||
} else {
|
||||
Ok(())
|
||||
@@ -391,14 +389,16 @@ pub(super) mod _os {
|
||||
}
|
||||
#[cfg(target_os = "redox")]
|
||||
let [] = dir_fd.0;
|
||||
fs::remove_dir(&path).map_err(|err| OSErrorBuilder::with_filename(&err, path, vm))
|
||||
crate::host_env::fs::remove_dir(&path)
|
||||
.map_err(|err| OSErrorBuilder::with_filename(&err, path, vm))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[pyfunction]
|
||||
fn rmdir(path: OsPath, dir_fd: DirFd<'_, 0>, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let [] = dir_fd.0;
|
||||
fs::remove_dir(&path).map_err(|err| OSErrorBuilder::with_filename(&err, path, vm))
|
||||
crate::host_env::fs::remove_dir(&path)
|
||||
.map_err(|err| OSErrorBuilder::with_filename(&err, path, vm))
|
||||
}
|
||||
|
||||
const LISTDIR_FD: bool = cfg!(all(unix, not(target_os = "redox")));
|
||||
@@ -413,7 +413,7 @@ pub(super) mod _os {
|
||||
.unwrap_or_else(|| OsPathOrFd::Path(OsPath::new_str(".")));
|
||||
let list = match path {
|
||||
OsPathOrFd::Path(path) => {
|
||||
let dir_iter = match fs::read_dir(&path) {
|
||||
let dir_iter = match crate::host_env::fs::read_dir(&path) {
|
||||
Ok(iter) => iter,
|
||||
Err(err) => {
|
||||
return Err(OSErrorBuilder::with_filename(&err, path, vm));
|
||||
@@ -437,7 +437,7 @@ pub(super) mod _os {
|
||||
}
|
||||
#[cfg(all(unix, not(target_os = "redox")))]
|
||||
{
|
||||
use rustpython_common::os::ffi::OsStrExt;
|
||||
use rustpython_host_env::os::ffi::OsStrExt;
|
||||
use std::os::unix::io::IntoRawFd;
|
||||
let new_fd = nix::unistd::dup(fno).map_err(|e| e.into_pyexception(vm))?;
|
||||
let raw_fd = new_fd.into_raw_fd();
|
||||
@@ -490,7 +490,7 @@ pub(super) mod _os {
|
||||
/// Check if wide string length exceeds Windows environment variable limit.
|
||||
#[cfg(windows)]
|
||||
fn check_env_var_len(wide_len: usize, vm: &VirtualMachine) -> PyResult<()> {
|
||||
use crate::common::windows::_MAX_ENV;
|
||||
use crate::host_env::windows::_MAX_ENV;
|
||||
if wide_len > _MAX_ENV + 1 {
|
||||
return Err(vm.new_value_error(format!(
|
||||
"the environment variable is longer than {_MAX_ENV} characters",
|
||||
@@ -543,7 +543,7 @@ pub(super) mod _os {
|
||||
let key = super::bytes_as_os_str(key, vm)?;
|
||||
let value = super::bytes_as_os_str(value, vm)?;
|
||||
// SAFETY: requirements forwarded from the caller
|
||||
unsafe { env::set_var(key, value) };
|
||||
unsafe { crate::host_env::os::set_var(key, value) };
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -595,7 +595,7 @@ pub(super) mod _os {
|
||||
}
|
||||
let key = super::bytes_as_os_str(key, vm)?;
|
||||
// SAFETY: requirements forwarded from the caller
|
||||
unsafe { env::remove_var(key) };
|
||||
unsafe { crate::host_env::os::remove_var(key) };
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1124,7 +1124,7 @@ pub(super) mod _os {
|
||||
#[cfg(all(unix, not(target_os = "redox")))]
|
||||
impl IterNext for ScandirIteratorFd {
|
||||
fn next(zelf: &crate::Py<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
|
||||
use rustpython_common::os::ffi::OsStrExt;
|
||||
use rustpython_host_env::os::ffi::OsStrExt;
|
||||
let mut guard = zelf.dir.lock();
|
||||
let dir = match guard.as_mut() {
|
||||
None => return Ok(PyIterReturn::StopIteration(None)),
|
||||
@@ -1187,7 +1187,7 @@ pub(super) mod _os {
|
||||
.unwrap_or_else(|| OsPathOrFd::Path(OsPath::new_str(".")));
|
||||
match path {
|
||||
OsPathOrFd::Path(path) => {
|
||||
let entries = fs::read_dir(&path.path)
|
||||
let entries = crate::host_env::fs::read_dir(&path.path)
|
||||
.map_err(|err| OSErrorBuilder::with_filename(&err, path.clone(), vm))?;
|
||||
Ok(ScandirIterator {
|
||||
entries: PyRwLock::new(Some(entries)),
|
||||
@@ -1400,7 +1400,7 @@ pub(super) mod _os {
|
||||
let [] = dir_fd.0;
|
||||
match file {
|
||||
OsPathOrFd::Path(path) => crate::windows::win32_xstat(&path.path, follow_symlinks.0),
|
||||
OsPathOrFd::Fd(fd) => crate::common::fileutils::fstat(fd),
|
||||
OsPathOrFd::Fd(fd) => crate::host_env::fileutils::fstat(fd),
|
||||
}
|
||||
.map(Some)
|
||||
}
|
||||
@@ -1414,7 +1414,7 @@ pub(super) mod _os {
|
||||
let mut stat = core::mem::MaybeUninit::uninit();
|
||||
let ret = match file {
|
||||
OsPathOrFd::Path(path) => {
|
||||
use rustpython_common::os::ffi::OsStrExt;
|
||||
use rustpython_host_env::os::ffi::OsStrExt;
|
||||
let path = path.as_ref().as_os_str().as_bytes();
|
||||
let path = match alloc::ffi::CString::new(path) {
|
||||
Ok(x) => x,
|
||||
@@ -1473,7 +1473,7 @@ pub(super) mod _os {
|
||||
}
|
||||
|
||||
fn curdir_inner(vm: &VirtualMachine) -> PyResult<PathBuf> {
|
||||
env::current_dir().map_err(|err| err.into_pyexception(vm))
|
||||
crate::host_env::os::current_dir().map_err(|err| err.into_pyexception(vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
@@ -1488,7 +1488,7 @@ pub(super) mod _os {
|
||||
|
||||
#[pyfunction]
|
||||
fn chdir(path: OsPath, vm: &VirtualMachine) -> PyResult<()> {
|
||||
env::set_current_dir(&path.path)
|
||||
crate::host_env::os::set_current_dir(&path.path)
|
||||
.map_err(|err| OSErrorBuilder::with_filename(&err, path, vm))?;
|
||||
|
||||
#[cfg(windows)]
|
||||
@@ -1501,7 +1501,7 @@ pub(super) mod _os {
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
use windows_sys::Win32::System::Environment::SetEnvironmentVariableW;
|
||||
|
||||
if let Ok(cwd) = env::current_dir() {
|
||||
if let Ok(cwd) = crate::host_env::os::current_dir() {
|
||||
let cwd_str = cwd.as_os_str();
|
||||
let mut cwd_wide: Vec<u16> = cwd_str.encode_wide().collect();
|
||||
|
||||
@@ -1558,7 +1558,7 @@ pub(super) mod _os {
|
||||
// https://github.com/WebAssembly/wasi-libc/blob/wasi-sdk-21/libc-bottom-half/getpid/getpid.c
|
||||
42
|
||||
} else {
|
||||
std::process::id()
|
||||
crate::host_env::os::process_id()
|
||||
};
|
||||
vm.ctx.new_int(pid).into()
|
||||
}
|
||||
@@ -1571,7 +1571,7 @@ pub(super) mod _os {
|
||||
|
||||
#[pyfunction]
|
||||
fn _exit(code: i32) {
|
||||
std::process::exit(code)
|
||||
crate::host_env::os::exit(code)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
@@ -1687,7 +1687,8 @@ pub(super) mod _os {
|
||||
let src_path = match follow_symlinks.into_option() {
|
||||
Some(true) => {
|
||||
// Explicit follow_symlinks=True: resolve symlinks
|
||||
fs::canonicalize(&src.path).unwrap_or_else(|_| PathBuf::from(src.path.clone()))
|
||||
crate::host_env::fs::canonicalize(&src.path)
|
||||
.unwrap_or_else(|_| PathBuf::from(src.path.clone()))
|
||||
}
|
||||
Some(false) | None => {
|
||||
// Default or explicit no-follow: native hard_link behavior
|
||||
@@ -1835,7 +1836,7 @@ pub(super) mod _os {
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use std::{fs::OpenOptions, os::windows::prelude::*};
|
||||
use std::os::windows::prelude::*;
|
||||
type DWORD = u32;
|
||||
use windows_sys::Win32::{Foundation::FILETIME, Storage::FileSystem};
|
||||
|
||||
@@ -1859,11 +1860,11 @@ pub(super) mod _os {
|
||||
let acc = ft(acc);
|
||||
let modif = ft(modif);
|
||||
|
||||
let f = OpenOptions::new()
|
||||
.write(true)
|
||||
.custom_flags(windows_sys::Win32::Storage::FileSystem::FILE_FLAG_BACKUP_SEMANTICS)
|
||||
.open(&path)
|
||||
.map_err(|err| OSErrorBuilder::with_filename(&err, path.clone(), vm))?;
|
||||
let f = crate::host_env::fs::open_write_with_custom_flags(
|
||||
&path,
|
||||
windows_sys::Win32::Storage::FileSystem::FILE_FLAG_BACKUP_SEMANTICS,
|
||||
)
|
||||
.map_err(|err| OSErrorBuilder::with_filename(&err, path.clone(), vm))?;
|
||||
|
||||
let ret = unsafe {
|
||||
FileSystem::SetFileTime(f.as_raw_handle() as _, core::ptr::null(), &acc, &modif)
|
||||
@@ -2050,7 +2051,7 @@ pub(super) mod _os {
|
||||
|
||||
let path = OsPath::try_from_object(vm, path)?;
|
||||
// TODO: just call libc::truncate() on POSIX
|
||||
let f = match OpenOptions::new().write(true).open(&path) {
|
||||
let f = match crate::host_env::fs::open_write(&path) {
|
||||
Ok(f) => f,
|
||||
Err(e) => return Err(error(vm, e, path)),
|
||||
};
|
||||
|
||||
@@ -1,19 +1,8 @@
|
||||
// spell-checker:disable
|
||||
|
||||
use std::os::fd::BorrowedFd;
|
||||
|
||||
pub(crate) use module::module_def;
|
||||
|
||||
pub fn set_inheritable(fd: BorrowedFd<'_>, inheritable: bool) -> nix::Result<()> {
|
||||
use nix::fcntl;
|
||||
let flags = fcntl::FdFlag::from_bits_truncate(fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFD)?);
|
||||
let mut new_flags = flags;
|
||||
new_flags.set(fcntl::FdFlag::FD_CLOEXEC, !inheritable);
|
||||
if flags != new_flags {
|
||||
fcntl::fcntl(fd, fcntl::FcntlArg::F_SETFD(new_flags))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub use rustpython_host_env::posix::set_inheritable;
|
||||
|
||||
#[pymodule(name = "posix", with(
|
||||
super::os::_os,
|
||||
@@ -53,9 +42,9 @@ pub mod module {
|
||||
fcntl,
|
||||
unistd::{self, Gid, Pid, Uid},
|
||||
};
|
||||
use rustpython_common::os::ffi::OsStringExt;
|
||||
use rustpython_host_env::os::ffi::OsStringExt;
|
||||
use std::{
|
||||
env, fs, io,
|
||||
fs, io,
|
||||
os::fd::{AsFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd},
|
||||
};
|
||||
use strum::IntoEnumIterator;
|
||||
@@ -483,7 +472,7 @@ pub mod module {
|
||||
)
|
||||
})?;
|
||||
|
||||
let metadata = match fs::metadata(&path.path) {
|
||||
let metadata = match crate::host_env::fs::metadata(&path.path) {
|
||||
Ok(m) => m,
|
||||
// If the file doesn't exist, return False for any access check
|
||||
Err(_) => return Ok(false),
|
||||
@@ -511,7 +500,7 @@ pub mod module {
|
||||
#[pyattr]
|
||||
fn environ(vm: &VirtualMachine) -> PyDictRef {
|
||||
let environ = vm.ctx.new_dict();
|
||||
for (key, value) in env::vars_os() {
|
||||
for (key, value) in crate::host_env::os::vars_os() {
|
||||
let key: PyObjectRef = vm.ctx.new_bytes(key.into_vec()).into();
|
||||
let value: PyObjectRef = vm.ctx.new_bytes(value.into_vec()).into();
|
||||
environ.set_item(&*key, value, vm).unwrap();
|
||||
@@ -523,7 +512,7 @@ pub mod module {
|
||||
#[pyfunction]
|
||||
fn _create_environ(vm: &VirtualMachine) -> PyDictRef {
|
||||
let environ = vm.ctx.new_dict();
|
||||
for (key, value) in env::vars_os() {
|
||||
for (key, value) in crate::host_env::os::vars_os() {
|
||||
let key: PyObjectRef = vm.ctx.new_bytes(key.into_vec()).into();
|
||||
let value: PyObjectRef = vm.ctx.new_bytes(value.into_vec()).into();
|
||||
environ.set_item(&*key, value, vm).unwrap();
|
||||
@@ -574,7 +563,7 @@ pub mod module {
|
||||
let c_path = path.clone().into_cstring(vm)?;
|
||||
let res = unsafe { libc::unlinkat(fd, c_path.as_ptr(), 0) };
|
||||
return if res < 0 {
|
||||
let err = crate::common::os::errno_io_error();
|
||||
let err = crate::host_env::os::errno_io_error();
|
||||
Err(OSErrorBuilder::with_filename(&err, path, vm))
|
||||
} else {
|
||||
Ok(())
|
||||
@@ -582,7 +571,8 @@ pub mod module {
|
||||
}
|
||||
#[cfg(target_os = "redox")]
|
||||
let [] = dir_fd.0;
|
||||
fs::remove_file(&path).map_err(|err| OSErrorBuilder::with_filename(&err, path, vm))
|
||||
crate::host_env::fs::remove_file(&path)
|
||||
.map_err(|err| OSErrorBuilder::with_filename(&err, path, vm))
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
@@ -876,79 +866,7 @@ pub mod module {
|
||||
/// Best-effort number of OS threads in this process.
|
||||
/// Returns <= 0 when unavailable.
|
||||
fn get_number_of_os_threads() -> isize {
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
type MachPortT = libc::c_uint;
|
||||
type KernReturnT = libc::c_int;
|
||||
type MachMsgTypeNumberT = libc::c_uint;
|
||||
type ThreadActArrayT = *mut MachPortT;
|
||||
const KERN_SUCCESS: KernReturnT = 0;
|
||||
unsafe extern "C" {
|
||||
fn mach_task_self() -> MachPortT;
|
||||
fn task_for_pid(
|
||||
task: MachPortT,
|
||||
pid: libc::c_int,
|
||||
target_task: *mut MachPortT,
|
||||
) -> KernReturnT;
|
||||
fn task_threads(
|
||||
target_task: MachPortT,
|
||||
act_list: *mut ThreadActArrayT,
|
||||
act_list_cnt: *mut MachMsgTypeNumberT,
|
||||
) -> KernReturnT;
|
||||
fn vm_deallocate(
|
||||
target_task: MachPortT,
|
||||
address: libc::uintptr_t,
|
||||
size: libc::uintptr_t,
|
||||
) -> KernReturnT;
|
||||
}
|
||||
|
||||
let self_task = unsafe { mach_task_self() };
|
||||
let mut proc_task: MachPortT = 0;
|
||||
if unsafe { task_for_pid(self_task, libc::getpid(), &mut proc_task) } == KERN_SUCCESS {
|
||||
let mut threads: ThreadActArrayT = core::ptr::null_mut();
|
||||
let mut n_threads: MachMsgTypeNumberT = 0;
|
||||
if unsafe { task_threads(proc_task, &mut threads, &mut n_threads) } == KERN_SUCCESS
|
||||
{
|
||||
if !threads.is_null() {
|
||||
let _ = unsafe {
|
||||
vm_deallocate(
|
||||
self_task,
|
||||
threads as libc::uintptr_t,
|
||||
(n_threads as usize * core::mem::size_of::<MachPortT>())
|
||||
as libc::uintptr_t,
|
||||
)
|
||||
};
|
||||
}
|
||||
return n_threads as isize;
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
use std::io::Read as _;
|
||||
let mut file = match std::fs::File::open("/proc/self/stat") {
|
||||
Ok(f) => f,
|
||||
Err(_) => return 0,
|
||||
};
|
||||
let mut buf = [0u8; 160];
|
||||
let n = match file.read(&mut buf) {
|
||||
Ok(n) => n,
|
||||
Err(_) => return 0,
|
||||
};
|
||||
let line = match core::str::from_utf8(&buf[..n]) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return 0,
|
||||
};
|
||||
if let Some(field) = line.split_whitespace().nth(19) {
|
||||
return field.parse::<isize>().unwrap_or(0);
|
||||
}
|
||||
0
|
||||
}
|
||||
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
|
||||
{
|
||||
0
|
||||
}
|
||||
rustpython_host_env::posix::get_number_of_os_threads()
|
||||
}
|
||||
|
||||
/// Warn if forking from a multi-threaded process.
|
||||
@@ -1859,7 +1777,7 @@ pub mod module {
|
||||
} else {
|
||||
// env=None means use the current environment
|
||||
|
||||
env::vars_os()
|
||||
crate::host_env::os::vars_os()
|
||||
.map(|(k, v)| {
|
||||
let mut entry = k.into_vec();
|
||||
entry.push(b'=');
|
||||
@@ -2598,9 +2516,9 @@ pub mod module {
|
||||
|
||||
#[pyfunction]
|
||||
fn sysconf(name: SysconfName, vm: &VirtualMachine) -> PyResult<libc::c_long> {
|
||||
crate::common::os::set_errno(0);
|
||||
crate::host_env::os::set_errno(0);
|
||||
let r = unsafe { libc::sysconf(name.0) };
|
||||
if r == -1 && crate::common::os::get_errno() != 0 {
|
||||
if r == -1 && crate::host_env::os::get_errno() != 0 {
|
||||
return Err(vm.new_last_errno_error());
|
||||
}
|
||||
Ok(r)
|
||||
@@ -2626,7 +2544,7 @@ pub mod module {
|
||||
struct SendFileArgs<'fd> {
|
||||
out_fd: BorrowedFd<'fd>,
|
||||
in_fd: BorrowedFd<'fd>,
|
||||
offset: crate::common::crt_fd::Offset,
|
||||
offset: rustpython_host_env::crt_fd::Offset,
|
||||
count: i64,
|
||||
#[cfg(target_os = "macos")]
|
||||
#[pyarg(any, optional)]
|
||||
|
||||
@@ -13,7 +13,7 @@ pub(crate) mod module {
|
||||
ospath::OsPath,
|
||||
stdlib::os::{_os, DirFd, SupportFunc, TargetIsDirectory},
|
||||
};
|
||||
use std::{env, fs};
|
||||
use std::fs;
|
||||
|
||||
#[pyfunction]
|
||||
pub(super) fn access(_path: PyStrRef, _mode: u8, vm: &VirtualMachine) -> PyResult<bool> {
|
||||
@@ -46,10 +46,10 @@ pub(crate) mod module {
|
||||
#[cfg(target_os = "wasi")]
|
||||
#[pyattr]
|
||||
fn environ(vm: &VirtualMachine) -> crate::builtins::PyDictRef {
|
||||
use rustpython_common::os::ffi::OsStringExt;
|
||||
use rustpython_host_env::os::ffi::OsStringExt;
|
||||
|
||||
let environ = vm.ctx.new_dict();
|
||||
for (key, value) in env::vars_os() {
|
||||
for (key, value) in crate::host_env::os::vars_os() {
|
||||
let key: PyObjectRef = vm.ctx.new_bytes(key.into_vec()).into();
|
||||
let value: PyObjectRef = vm.ctx.new_bytes(value.into_vec()).into();
|
||||
environ.set_item(&*key, value, vm).unwrap();
|
||||
|
||||
@@ -53,7 +53,7 @@ mod sys {
|
||||
use core::sync::atomic::Ordering;
|
||||
use num_traits::ToPrimitive;
|
||||
use std::{
|
||||
env::{self, VarError},
|
||||
env,
|
||||
io::{IsTerminal, Read, Write},
|
||||
};
|
||||
|
||||
@@ -871,15 +871,18 @@ mod sys {
|
||||
#[pyfunction(name = "__breakpointhook__")]
|
||||
#[pyfunction]
|
||||
pub fn breakpointhook(args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
let env_var = std::env::var("PYTHONBREAKPOINT")
|
||||
#[cfg(feature = "host_env")]
|
||||
let env_var = crate::host_env::os::var("PYTHONBREAKPOINT")
|
||||
.and_then(|env_var| {
|
||||
if env_var.is_empty() {
|
||||
Err(VarError::NotPresent)
|
||||
Err(std::env::VarError::NotPresent)
|
||||
} else {
|
||||
Ok(env_var)
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|_| "pdb.set_trace".to_owned());
|
||||
#[cfg(not(feature = "host_env"))]
|
||||
let env_var = "pdb.set_trace".to_owned();
|
||||
|
||||
if env_var.eq("0") {
|
||||
return Ok(vm.ctx.none());
|
||||
@@ -1091,7 +1094,7 @@ mod sys {
|
||||
|
||||
#[cfg(windows)]
|
||||
fn get_kernel32_version() -> std::io::Result<(u32, u32, u32)> {
|
||||
use crate::common::windows::ToWideString;
|
||||
use crate::host_env::windows::ToWideString;
|
||||
unsafe {
|
||||
// Create a wide string for "kernel32.dll"
|
||||
let module_name: Vec<u16> = std::ffi::OsStr::new("kernel32.dll").to_wide_with_nul();
|
||||
|
||||
@@ -41,9 +41,12 @@ mod decl {
|
||||
naive::{NaiveDate, NaiveDateTime, NaiveTime},
|
||||
};
|
||||
use core::time::Duration;
|
||||
#[cfg(any(unix, windows))]
|
||||
use rustpython_host_env::time::asctime_from_tm;
|
||||
use rustpython_host_env::time::{self as host_time};
|
||||
#[cfg(target_env = "msvc")]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use windows_sys::Win32::System::Time::{GetTimeZoneInformation, TIME_ZONE_INFORMATION};
|
||||
use windows_sys::Win32::System::Time::TIME_ZONE_INFORMATION;
|
||||
|
||||
#[cfg(windows)]
|
||||
unsafe extern "C" {
|
||||
@@ -56,27 +59,24 @@ mod decl {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(super) const SEC_TO_MS: i64 = 1000;
|
||||
pub(super) const SEC_TO_MS: i64 = host_time::SEC_TO_MS;
|
||||
#[allow(dead_code)]
|
||||
pub(super) const MS_TO_US: i64 = 1000;
|
||||
pub(super) const MS_TO_US: i64 = host_time::MS_TO_US;
|
||||
#[allow(dead_code)]
|
||||
pub(super) const SEC_TO_US: i64 = SEC_TO_MS * MS_TO_US;
|
||||
pub(super) const SEC_TO_US: i64 = host_time::SEC_TO_US;
|
||||
#[allow(dead_code)]
|
||||
pub(super) const US_TO_NS: i64 = 1000;
|
||||
pub(super) const US_TO_NS: i64 = host_time::US_TO_NS;
|
||||
#[allow(dead_code)]
|
||||
pub(super) const MS_TO_NS: i64 = MS_TO_US * US_TO_NS;
|
||||
pub(super) const MS_TO_NS: i64 = host_time::MS_TO_NS;
|
||||
#[allow(dead_code)]
|
||||
pub(super) const SEC_TO_NS: i64 = SEC_TO_MS * MS_TO_NS;
|
||||
pub(super) const SEC_TO_NS: i64 = host_time::SEC_TO_NS;
|
||||
#[allow(dead_code)]
|
||||
pub(super) const NS_TO_MS: i64 = 1000 * 1000;
|
||||
pub(super) const NS_TO_MS: i64 = host_time::NS_TO_MS;
|
||||
#[allow(dead_code)]
|
||||
pub(super) const NS_TO_US: i64 = 1000;
|
||||
pub(super) const NS_TO_US: i64 = host_time::NS_TO_US;
|
||||
|
||||
fn duration_since_system_now(vm: &VirtualMachine) -> PyResult<Duration> {
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
host_time::duration_since_system_now()
|
||||
.map_err(|e| vm.new_value_error(format!("Time error: {e:?}")))
|
||||
}
|
||||
|
||||
@@ -218,9 +218,7 @@ mod decl {
|
||||
#[cfg(target_env = "msvc")]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub(super) fn get_tz_info() -> TIME_ZONE_INFORMATION {
|
||||
let mut info: TIME_ZONE_INFORMATION = unsafe { core::mem::zeroed() };
|
||||
unsafe { GetTimeZoneInformation(&mut info) };
|
||||
info
|
||||
host_time::get_tz_info()
|
||||
}
|
||||
|
||||
// #[pyfunction]
|
||||
@@ -477,24 +475,6 @@ mod decl {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(unix, windows))]
|
||||
fn asctime_from_tm(tm: &libc::tm) -> String {
|
||||
const WDAY_NAME: [&str; 7] = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
||||
const MON_NAME: [&str; 12] = [
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
|
||||
];
|
||||
format!(
|
||||
"{} {}{:>3} {:02}:{:02}:{:02} {}",
|
||||
WDAY_NAME[tm.tm_wday as usize],
|
||||
MON_NAME[tm.tm_mon as usize],
|
||||
tm.tm_mday,
|
||||
tm.tm_hour,
|
||||
tm.tm_min,
|
||||
tm.tm_sec,
|
||||
tm.tm_year + 1900
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(not(any(unix, windows)))]
|
||||
impl OptionalArg<StructTimeData> {
|
||||
fn naive_or_local(self, vm: &VirtualMachine) -> PyResult<NaiveDateTime> {
|
||||
@@ -678,7 +658,7 @@ mod decl {
|
||||
loop {
|
||||
let mut out = vec![0u16; size];
|
||||
let written = unsafe {
|
||||
rustpython_common::suppress_iph!(wcsftime(
|
||||
rustpython_host_env::suppress_iph!(wcsftime(
|
||||
out.as_mut_ptr(),
|
||||
out.len(),
|
||||
fmt_wide.as_ptr(),
|
||||
@@ -1428,7 +1408,7 @@ mod platform {
|
||||
|
||||
pub(super) fn win_mktime(t: &StructTimeData, vm: &VirtualMachine) -> PyResult<f64> {
|
||||
let mut tm = super::decl::tm_from_struct_time(t, vm)?;
|
||||
let timestamp = unsafe { rustpython_common::suppress_iph!(c_mktime(&mut tm)) };
|
||||
let timestamp = unsafe { rustpython_host_env::suppress_iph!(c_mktime(&mut tm)) };
|
||||
if timestamp == -1 && tm.tm_wday == -1 {
|
||||
return Err(vm.new_overflow_error("mktime argument out of range"));
|
||||
}
|
||||
|
||||
@@ -7,9 +7,9 @@ pub(crate) use winreg::module_def;
|
||||
mod winreg {
|
||||
use crate::builtins::{PyInt, PyStr, PyTuple, PyTypeRef};
|
||||
use crate::common::hash::PyHash;
|
||||
use crate::common::windows::ToWideString;
|
||||
use crate::convert::TryFromObject;
|
||||
use crate::function::FuncArgs;
|
||||
use crate::host_env::windows::ToWideString;
|
||||
use crate::object::AsObject;
|
||||
use crate::protocol::PyNumberMethods;
|
||||
use crate::types::{AsNumber, Hashable};
|
||||
|
||||
@@ -18,8 +18,8 @@ mod win32 {
|
||||
#[pymodule]
|
||||
mod winsound {
|
||||
use crate::builtins::{PyBytes, PyStr};
|
||||
use crate::common::windows::ToWideString;
|
||||
use crate::convert::{IntoPyException, TryFromBorrowedObject};
|
||||
use crate::host_env::windows::ToWideString;
|
||||
use crate::protocol::PyBuffer;
|
||||
use crate::{AsObject, PyObjectRef, PyResult, VirtualMachine};
|
||||
|
||||
|
||||
@@ -536,7 +536,7 @@ impl StopTheWorldState {
|
||||
#[cfg(all(unix, feature = "threading"))]
|
||||
pub(super) fn stw_trace_enabled() -> bool {
|
||||
static ENABLED: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
|
||||
*ENABLED.get_or_init(|| std::env::var_os("RUSTPYTHON_STW_TRACE").is_some())
|
||||
*ENABLED.get_or_init(|| crate::host_env::os::var_os("RUSTPYTHON_STW_TRACE").is_some())
|
||||
}
|
||||
|
||||
#[cfg(all(unix, feature = "threading"))]
|
||||
@@ -788,8 +788,8 @@ impl VirtualMachine {
|
||||
#[cfg(feature = "encodings")]
|
||||
fn import_encodings(&mut self) -> PyResult<()> {
|
||||
self.import("encodings", 0).map_err(|import_err| {
|
||||
let rustpythonpath_env = std::env::var("RUSTPYTHONPATH").ok();
|
||||
let pythonpath_env = std::env::var("PYTHONPATH").ok();
|
||||
let rustpythonpath_env = crate::host_env::os::var("RUSTPYTHONPATH").ok();
|
||||
let pythonpath_env = crate::host_env::os::var("PYTHONPATH").ok();
|
||||
let env_set = rustpythonpath_env.as_ref().is_some() || pythonpath_env.as_ref().is_some();
|
||||
let path_contains_env = self.state.config.paths.module_search_paths.iter().any(|s| {
|
||||
Some(s.as_str()) == rustpythonpath_env.as_deref() || Some(s.as_str()) == pythonpath_env.as_deref()
|
||||
|
||||
@@ -105,7 +105,7 @@ mod file_run {
|
||||
if path != "<stdin>" {
|
||||
set_main_loader(module_dict, path, "SourceFileLoader", self)?;
|
||||
}
|
||||
match std::fs::read_to_string(path) {
|
||||
match crate::host_env::fs::read_to_string(path) {
|
||||
Ok(source) => {
|
||||
let code_obj = self
|
||||
.compile(&source, compiler::Mode::Exec, path.to_owned())
|
||||
@@ -160,7 +160,7 @@ mod file_run {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let mut file = std::fs::File::open(path)?;
|
||||
let mut file = crate::host_env::fs::open(path)?;
|
||||
let mut buf = [0u8; 2];
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
@@ -249,7 +249,7 @@ impl VirtualMachine {
|
||||
/// On windows, CRT errno are expected to be handled by this function.
|
||||
/// This is identical to `new_last_os_error` on non-Windows platforms.
|
||||
pub fn new_last_errno_error(&self) -> PyBaseExceptionRef {
|
||||
let err = crate::common::os::errno_io_error();
|
||||
let err = crate::host_env::os::errno_io_error();
|
||||
err.to_pyexception(self)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::common::fileutils::{
|
||||
use crate::host_env::fileutils::{
|
||||
StatStruct,
|
||||
windows::{FILE_INFO_BY_NAME_CLASS, get_file_information_by_name},
|
||||
};
|
||||
@@ -6,7 +6,7 @@ use crate::{
|
||||
PyObjectRef, PyResult, TryFromObject, VirtualMachine,
|
||||
convert::{ToPyObject, ToPyResult},
|
||||
};
|
||||
use rustpython_common::windows::ToWideString;
|
||||
use rustpython_host_env::windows::ToWideString;
|
||||
use std::ffi::OsStr;
|
||||
use windows_sys::Win32::Foundation::{HANDLE, INVALID_HANDLE_VALUE};
|
||||
|
||||
@@ -103,8 +103,8 @@ const S_IFMT: u16 = libc::S_IFMT as u16;
|
||||
const S_IFDIR: u16 = libc::S_IFDIR as u16;
|
||||
const S_IFREG: u16 = libc::S_IFREG as u16;
|
||||
const S_IFCHR: u16 = libc::S_IFCHR as u16;
|
||||
const S_IFLNK: u16 = crate::common::fileutils::windows::S_IFLNK as u16;
|
||||
const S_IFIFO: u16 = crate::common::fileutils::windows::S_IFIFO as u16;
|
||||
const S_IFLNK: u16 = crate::host_env::fileutils::windows::S_IFLNK as u16;
|
||||
const S_IFIFO: u16 = crate::host_env::fileutils::windows::S_IFIFO as u16;
|
||||
|
||||
/// FILE_ATTRIBUTE_TAG_INFO structure for GetFileInformationByHandleEx
|
||||
#[repr(C)]
|
||||
@@ -141,7 +141,7 @@ fn attribute_data_to_stat(
|
||||
basic_info: Option<&windows_sys::Win32::Storage::FileSystem::FILE_BASIC_INFO>,
|
||||
id_info: Option<&windows_sys::Win32::Storage::FileSystem::FILE_ID_INFO>,
|
||||
) -> StatStruct {
|
||||
use crate::common::fileutils::windows::SECS_BETWEEN_EPOCHS;
|
||||
use crate::host_env::fileutils::windows::SECS_BETWEEN_EPOCHS;
|
||||
use windows_sys::Win32::Storage::FileSystem::FILE_ATTRIBUTE_REPARSE_POINT;
|
||||
|
||||
let mut st_mode = attributes_to_mode(info.dwFileAttributes);
|
||||
@@ -513,7 +513,7 @@ fn win32_xstat_impl(path: &OsStr, traverse: bool) -> std::io::Result<StatStruct>
|
||||
|| (!traverse && is_reparse_tag_name_surrogate(stat_info.ReparseTag))
|
||||
{
|
||||
let mut result =
|
||||
crate::common::fileutils::windows::stat_basic_info_to_stat(&stat_info);
|
||||
crate::host_env::fileutils::windows::stat_basic_info_to_stat(&stat_info);
|
||||
// If st_ino is 0, fall through to slow path to get proper file ID
|
||||
if result.st_ino != 0 || result.st_ino_high != 0 {
|
||||
result.update_st_mode_from_path(path, stat_info.FileAttributes);
|
||||
|
||||
@@ -46,5 +46,5 @@ fn main() -> ExitCode {
|
||||
let defs = rustpython_stdlib::stdlib_module_defs(&builder.ctx);
|
||||
let interp = builder.add_native_modules(&defs).build();
|
||||
let result = py_main(&interp);
|
||||
vm::common::os::exit_code(interp.run(|_vm| result))
|
||||
vm::host_env::os::exit_code(interp.run(|_vm| result))
|
||||
}
|
||||
@@ -26,5 +26,5 @@ fn main() -> ExitCode {
|
||||
let result = result.map(|result| {
|
||||
println!("name: {result}");
|
||||
});
|
||||
vm::common::os::exit_code(interp.run(|_vm| result))
|
||||
vm::host_env::os::exit_code(interp.run(|_vm| result))
|
||||
}
|
||||
+1
-1
@@ -120,7 +120,7 @@ pub fn run(mut builder: InterpreterBuilder) -> ExitCode {
|
||||
let interp = builder.interpreter();
|
||||
let exitcode = interp.run(move |vm| run_rustpython(vm, run_mode));
|
||||
|
||||
rustpython_vm::common::os::exit_code(exitcode)
|
||||
rustpython_vm::host_env::os::exit_code(exitcode)
|
||||
}
|
||||
|
||||
fn get_pip(scope: Scope, vm: &VirtualMachine) -> PyResult<()> {
|
||||
|
||||
Reference in new issue
Block a user