Skip to content

Commit 3da46ad

Browse files
Copilotyouknowone
andcommitted
refactor: extract host helpers
Agent-Logs-Url: https://github.com/RustPython/RustPython/sessions/48d1e64d-37ce-409f-b511-8e61a349665c Co-authored-by: youknowone <[email protected]>
1 parent c0b12c0 commit 3da46ad

26 files changed

Lines changed: 786 additions & 507 deletions

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/host_env/Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,24 @@ num-traits = { workspace = true }
1717
[target.'cfg(unix)'.dependencies]
1818
nix = { workspace = true }
1919

20+
[target.'cfg(all(unix, not(target_os = "ios"), not(target_os = "redox")))'.dependencies]
21+
termios = "0.3.3"
22+
2023
[target.'cfg(windows)'.dependencies]
2124
widestring = { workspace = true }
2225
windows-sys = { workspace = true, features = [
2326
"Win32_Foundation",
27+
"Win32_Globalization",
2428
"Win32_Networking_WinSock",
2529
"Win32_Storage_FileSystem",
30+
"Win32_System_Console",
31+
"Win32_System_Diagnostics_Debug",
2632
"Win32_System_Ioctl",
2733
"Win32_System_LibraryLoader",
34+
"Win32_System_SystemInformation",
2835
"Win32_System_SystemServices",
36+
"Win32_System_Threading",
37+
"Win32_System_Time",
2938
] }
3039

3140
[lints]

crates/host_env/src/fcntl.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use std::io;
2+
3+
pub fn fcntl_int(fd: i32, cmd: i32, arg: i32) -> io::Result<i32> {
4+
let ret = unsafe { libc::fcntl(fd, cmd, arg) };
5+
if ret < 0 {
6+
Err(io::Error::last_os_error())
7+
} else {
8+
Ok(ret)
9+
}
10+
}
11+
12+
pub fn fcntl_with_bytes(fd: i32, cmd: i32, arg: &mut [u8]) -> io::Result<i32> {
13+
let ret = unsafe { libc::fcntl(fd, cmd, arg.as_mut_ptr()) };
14+
if ret < 0 {
15+
Err(io::Error::last_os_error())
16+
} else {
17+
Ok(ret)
18+
}
19+
}
20+
21+
/// # Safety
22+
///
23+
/// `arg` must be a valid pointer for the `request` passed to `ioctl` and must
24+
/// satisfy the platform ABI requirements for that request.
25+
pub unsafe fn ioctl_ptr(
26+
fd: i32,
27+
request: libc::c_ulong,
28+
arg: *mut libc::c_void,
29+
) -> io::Result<i32> {
30+
let ret = unsafe { libc::ioctl(fd, request as _, arg) };
31+
if ret < 0 {
32+
Err(io::Error::last_os_error())
33+
} else {
34+
Ok(ret)
35+
}
36+
}
37+
38+
pub fn ioctl_int(fd: i32, request: libc::c_ulong, arg: i32) -> io::Result<i32> {
39+
let ret = unsafe { libc::ioctl(fd, request as _, arg) };
40+
if ret < 0 {
41+
Err(io::Error::last_os_error())
42+
} else {
43+
Ok(ret)
44+
}
45+
}
46+
47+
#[cfg(not(any(target_os = "wasi", target_os = "redox")))]
48+
pub fn flock(fd: i32, operation: i32) -> io::Result<i32> {
49+
let ret = unsafe { libc::flock(fd, operation) };
50+
if ret < 0 {
51+
Err(io::Error::last_os_error())
52+
} else {
53+
Ok(ret)
54+
}
55+
}
56+
57+
#[cfg(not(any(target_os = "wasi", target_os = "redox")))]
58+
pub fn lockf(fd: i32, cmd: i32, lock: &libc::flock) -> io::Result<i32> {
59+
let ret = unsafe {
60+
libc::fcntl(
61+
fd,
62+
if (cmd & libc::LOCK_NB) != 0 {
63+
libc::F_SETLK
64+
} else {
65+
libc::F_SETLKW
66+
},
67+
lock,
68+
)
69+
};
70+
if ret < 0 {
71+
Err(io::Error::last_os_error())
72+
} else {
73+
Ok(ret)
74+
}
75+
}

crates/host_env/src/lib.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,27 @@ pub mod fileutils;
1414

1515
#[cfg(windows)]
1616
pub mod windows;
17+
18+
#[cfg(any(unix, target_os = "wasi"))]
19+
pub mod fcntl;
20+
#[cfg(any(unix, windows, target_os = "wasi"))]
21+
pub mod select;
22+
#[cfg(unix)]
23+
pub mod syslog;
24+
#[cfg(all(unix, not(target_os = "redox"), not(target_os = "ios")))]
25+
pub mod termios;
26+
27+
#[cfg(unix)]
28+
pub mod posix;
29+
#[cfg(all(unix, not(target_os = "redox"), not(target_os = "android")))]
30+
pub mod shm;
31+
#[cfg(unix)]
32+
pub mod signal;
33+
pub mod time;
34+
35+
#[cfg(windows)]
36+
pub mod msvcrt;
37+
#[cfg(windows)]
38+
pub mod nt;
39+
#[cfg(windows)]
40+
pub mod winapi;

crates/host_env/src/msvcrt.rs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
use alloc::{string::String, vec::Vec};
2+
use std::io;
3+
4+
use crate::crt_fd;
5+
use windows_sys::Win32::System::Diagnostics::Debug;
6+
7+
pub const LK_UNLCK: i32 = 0;
8+
pub const LK_LOCK: i32 = 1;
9+
pub const LK_NBLCK: i32 = 2;
10+
pub const LK_RLCK: i32 = 3;
11+
pub const LK_NBRLCK: i32 = 4;
12+
13+
unsafe extern "C" {
14+
fn _getch() -> i32;
15+
fn _getwch() -> u32;
16+
fn _getche() -> i32;
17+
fn _getwche() -> u32;
18+
fn _putch(c: u32) -> i32;
19+
fn _putwch(c: u16) -> u32;
20+
fn _ungetch(c: i32) -> i32;
21+
fn _ungetwch(c: u32) -> u32;
22+
fn _locking(fd: i32, mode: i32, nbytes: i64) -> i32;
23+
fn _heapmin() -> i32;
24+
fn _kbhit() -> i32;
25+
fn _setmode(fd: crt_fd::Borrowed<'_>, flags: i32) -> i32;
26+
}
27+
28+
pub fn setmode_binary(fd: crt_fd::Borrowed<'_>) {
29+
unsafe { suppress_iph!(_setmode(fd, libc::O_BINARY)) };
30+
}
31+
32+
pub fn getch() -> Vec<u8> {
33+
vec![unsafe { _getch() } as u8]
34+
}
35+
36+
pub fn getwch() -> String {
37+
let value = unsafe { _getwch() };
38+
char::from_u32(value)
39+
.unwrap_or_else(|| panic!("invalid unicode {value:#x} from _getwch"))
40+
.to_string()
41+
}
42+
43+
pub fn getche() -> Vec<u8> {
44+
vec![unsafe { _getche() } as u8]
45+
}
46+
47+
pub fn getwche() -> String {
48+
let value = unsafe { _getwche() };
49+
char::from_u32(value)
50+
.unwrap_or_else(|| panic!("invalid unicode {value:#x} from _getwche"))
51+
.to_string()
52+
}
53+
54+
pub fn putch(c: u8) {
55+
unsafe { suppress_iph!(_putch(c.into())) };
56+
}
57+
58+
pub fn putwch(c: char) {
59+
unsafe { suppress_iph!(_putwch(c as u16)) };
60+
}
61+
62+
pub fn ungetch(c: u8) -> io::Result<()> {
63+
let ret = unsafe { suppress_iph!(_ungetch(c as i32)) };
64+
if ret == -1 {
65+
Err(io::Error::from_raw_os_error(libc::ENOSPC))
66+
} else {
67+
Ok(())
68+
}
69+
}
70+
71+
pub fn ungetwch(c: char) -> io::Result<()> {
72+
let ret = unsafe { suppress_iph!(_ungetwch(c as u32)) };
73+
if ret == 0xFFFF {
74+
Err(io::Error::from_raw_os_error(libc::ENOSPC))
75+
} else {
76+
Ok(())
77+
}
78+
}
79+
80+
pub fn kbhit() -> i32 {
81+
unsafe { _kbhit() }
82+
}
83+
84+
pub fn locking(fd: i32, mode: i32, nbytes: i64) -> io::Result<()> {
85+
let ret = unsafe { suppress_iph!(_locking(fd, mode, nbytes)) };
86+
if ret == -1 {
87+
Err(io::Error::last_os_error())
88+
} else {
89+
Ok(())
90+
}
91+
}
92+
93+
pub fn heapmin() -> io::Result<()> {
94+
let ret = unsafe { suppress_iph!(_heapmin()) };
95+
if ret == -1 {
96+
Err(io::Error::last_os_error())
97+
} else {
98+
Ok(())
99+
}
100+
}
101+
102+
pub fn setmode(fd: crt_fd::Borrowed<'_>, flags: i32) -> io::Result<i32> {
103+
let ret = unsafe { suppress_iph!(_setmode(fd, flags)) };
104+
if ret == -1 {
105+
Err(io::Error::last_os_error())
106+
} else {
107+
Ok(ret)
108+
}
109+
}
110+
111+
pub fn open_osfhandle(handle: isize, flags: i32) -> io::Result<i32> {
112+
let ret = unsafe { suppress_iph!(libc::open_osfhandle(handle, flags)) };
113+
if ret == -1 {
114+
Err(io::Error::last_os_error())
115+
} else {
116+
Ok(ret)
117+
}
118+
}
119+
120+
pub fn get_error_mode() -> u32 {
121+
unsafe { suppress_iph!(Debug::GetErrorMode()) }
122+
}
123+
124+
pub fn set_error_mode(mode: Debug::THREAD_ERROR_MODE) -> u32 {
125+
unsafe { suppress_iph!(Debug::SetErrorMode(mode)) }
126+
}

crates/host_env/src/nt.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// cspell:ignore hchmod
2+
use std::{ffi::OsStr, io, os::windows::io::AsRawHandle};
3+
4+
use crate::{crt_fd, windows::ToWideString};
5+
use windows_sys::Win32::{
6+
Foundation::HANDLE,
7+
Storage::FileSystem::{
8+
FILE_ATTRIBUTE_READONLY, FILE_BASIC_INFO, FileBasicInfo, GetFileAttributesW,
9+
GetFileInformationByHandleEx, INVALID_FILE_ATTRIBUTES, SetFileAttributesW,
10+
SetFileInformationByHandle,
11+
},
12+
};
13+
14+
#[allow(clippy::not_unsafe_ptr_arg_deref)]
15+
pub fn win32_hchmod(handle: HANDLE, mode: u32, write_bit: u32) -> io::Result<()> {
16+
let mut info: FILE_BASIC_INFO = unsafe { core::mem::zeroed() };
17+
let ret = unsafe {
18+
GetFileInformationByHandleEx(
19+
handle,
20+
FileBasicInfo,
21+
(&mut info as *mut FILE_BASIC_INFO).cast(),
22+
core::mem::size_of::<FILE_BASIC_INFO>() as u32,
23+
)
24+
};
25+
if ret == 0 {
26+
return Err(io::Error::last_os_error());
27+
}
28+
29+
if mode & write_bit != 0 {
30+
info.FileAttributes &= !FILE_ATTRIBUTE_READONLY;
31+
} else {
32+
info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
33+
}
34+
35+
let ret = unsafe {
36+
SetFileInformationByHandle(
37+
handle,
38+
FileBasicInfo,
39+
(&info as *const FILE_BASIC_INFO).cast(),
40+
core::mem::size_of::<FILE_BASIC_INFO>() as u32,
41+
)
42+
};
43+
if ret == 0 {
44+
Err(io::Error::last_os_error())
45+
} else {
46+
Ok(())
47+
}
48+
}
49+
50+
pub fn fchmod(fd: i32, mode: u32, write_bit: u32) -> io::Result<()> {
51+
let borrowed = unsafe { crt_fd::Borrowed::borrow_raw(fd) };
52+
let handle = crt_fd::as_handle(borrowed)?;
53+
win32_hchmod(handle.as_raw_handle() as HANDLE, mode, write_bit)
54+
}
55+
56+
pub fn win32_lchmod(path: &OsStr, mode: u32, write_bit: u32) -> io::Result<()> {
57+
let wide = path.to_wide_with_nul();
58+
let attr = unsafe { GetFileAttributesW(wide.as_ptr()) };
59+
if attr == INVALID_FILE_ATTRIBUTES {
60+
return Err(io::Error::last_os_error());
61+
}
62+
let new_attr = if mode & write_bit != 0 {
63+
attr & !FILE_ATTRIBUTE_READONLY
64+
} else {
65+
attr | FILE_ATTRIBUTE_READONLY
66+
};
67+
let ret = unsafe { SetFileAttributesW(wide.as_ptr(), new_attr) };
68+
if ret == 0 {
69+
Err(io::Error::last_os_error())
70+
} else {
71+
Ok(())
72+
}
73+
}

crates/host_env/src/posix.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use std::os::fd::BorrowedFd;
2+
3+
pub fn set_inheritable(fd: BorrowedFd<'_>, inheritable: bool) -> nix::Result<()> {
4+
use nix::fcntl;
5+
6+
let flags = fcntl::FdFlag::from_bits_truncate(fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFD)?);
7+
let mut new_flags = flags;
8+
new_flags.set(fcntl::FdFlag::FD_CLOEXEC, !inheritable);
9+
if flags != new_flags {
10+
fcntl::fcntl(fd, fcntl::FcntlArg::F_SETFD(new_flags))?;
11+
}
12+
Ok(())
13+
}

0 commit comments

Comments
 (0)