Skip to content

Commit ac9e861

Browse files
committed
vm::windows
1 parent 7d276da commit ac9e861

File tree

5 files changed

+114
-4
lines changed

5 files changed

+114
-4
lines changed

stdlib/src/select.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::{io, mem};
66

77
pub(crate) fn make_module(vm: &VirtualMachine) -> PyRef<PyModule> {
88
#[cfg(windows)]
9-
crate::vm::stdlib::nt::init_winsock();
9+
crate::vm::windows::init_winsock();
1010

1111
#[cfg(unix)]
1212
{

stdlib/src/socket.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pub(super) use _socket::{sock_select, timeout_error_msg, PySocket, SelectKind};
44

55
pub fn make_module(vm: &VirtualMachine) -> PyRef<PyModule> {
66
#[cfg(windows)]
7-
crate::vm::stdlib::nt::init_winsock();
7+
crate::vm::windows::init_winsock();
88
_socket::make_module(vm)
99
}
1010

vm/src/stdlib/os.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::{
77
};
88
use std::{ffi, fs, io, path::Path};
99

10-
pub(super) fn fs_metadata<P: AsRef<Path>>(
10+
pub(crate) fn fs_metadata<P: AsRef<Path>>(
1111
path: P,
1212
follow_symlink: bool,
1313
) -> io::Result<fs::Metadata> {

vm/src/stdlib/signal.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ pub(crate) mod _signal {
201201
let is_socket = if fd != INVALID_WAKEUP {
202202
use windows_sys::Win32::Networking::WinSock;
203203

204-
crate::stdlib::nt::init_winsock();
204+
crate::windows::init_winsock();
205205
let mut res = 0i32;
206206
let mut res_size = std::mem::size_of::<i32>() as i32;
207207
let res = unsafe {

vm/src/windows.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
use crate::common::fileutils::StatStruct;
12
use crate::{
23
convert::{ToPyObject, ToPyResult},
34
stdlib::os::errno_err,
45
PyObjectRef, PyResult, TryFromObject, VirtualMachine,
56
};
7+
use std::{ffi::OsStr, time::SystemTime};
68
use windows::Win32::Foundation::HANDLE;
79
use windows_sys::Win32::Foundation::{BOOL, HANDLE as RAW_HANDLE, INVALID_HANDLE_VALUE};
810

@@ -66,3 +68,111 @@ impl ToPyObject for HANDLE {
6668
(self.0 as HandleInt).to_pyobject(vm)
6769
}
6870
}
71+
72+
pub fn init_winsock() {
73+
static WSA_INIT: parking_lot::Once = parking_lot::Once::new();
74+
WSA_INIT.call_once(|| unsafe {
75+
let mut wsa_data = std::mem::MaybeUninit::uninit();
76+
let _ = windows_sys::Win32::Networking::WinSock::WSAStartup(0x0101, wsa_data.as_mut_ptr());
77+
})
78+
}
79+
80+
// win32_xstat in cpython
81+
pub fn win32_xstat(path: &OsStr, traverse: bool) -> std::io::Result<StatStruct> {
82+
let mut result = match win32_xstat_impl(path, traverse) {
83+
Ok(r) => r,
84+
Err(e) => {
85+
// TODO: cpython comments say GetLastError must be called here.
86+
return Err(e);
87+
}
88+
};
89+
// ctime is only deprecated from 3.12, so we copy birthtime across
90+
result.st_ctime = result.st_birthtime;
91+
result.st_ctime_nsec = result.st_birthtime_nsec;
92+
return Ok(result);
93+
}
94+
95+
fn is_reparse_tag_name_surrogate(tag: u32) -> bool {
96+
(tag & 0x20000000) > 0
97+
}
98+
99+
fn win32_xstat_impl(path: &OsStr, traverse: bool) -> std::io::Result<StatStruct> {
100+
use crate::common::fileutils::windows::{
101+
get_file_information_by_name, FILE_INFO_BY_NAME_CLASS,
102+
};
103+
use windows_sys::Win32::{Foundation, Storage::FileSystem::FILE_ATTRIBUTE_REPARSE_POINT};
104+
105+
let stat_info =
106+
get_file_information_by_name(&path, FILE_INFO_BY_NAME_CLASS::FileStatBasicByNameInfo);
107+
match stat_info {
108+
Ok(stat_info) => {
109+
if !(stat_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT != 0)
110+
|| (!traverse && is_reparse_tag_name_surrogate(stat_info.ReparseTag))
111+
{
112+
let mut result =
113+
crate::common::fileutils::windows::stat_basic_info_to_stat(&stat_info);
114+
result.update_st_mode_from_path(&path, stat_info.FileAttributes);
115+
return Ok(result);
116+
}
117+
}
118+
Err(e) => {
119+
if let Some(errno) = e.raw_os_error() {
120+
if matches!(
121+
errno as u32,
122+
Foundation::ERROR_FILE_NOT_FOUND
123+
| Foundation::ERROR_PATH_NOT_FOUND
124+
| Foundation::ERROR_NOT_READY
125+
| Foundation::ERROR_BAD_NET_NAME
126+
) {
127+
return Err(e);
128+
}
129+
}
130+
}
131+
}
132+
133+
// TODO: win32_xstat_slow_impl(&path, result, traverse)
134+
meta_to_stat(&crate::stdlib::os::fs_metadata(path, traverse)?)
135+
}
136+
137+
fn meta_to_stat(meta: &std::fs::Metadata) -> std::io::Result<StatStruct> {
138+
let st_mode = {
139+
// Based on CPython fileutils.c' attributes_to_mode
140+
let mut m = 0;
141+
if meta.is_dir() {
142+
m |= libc::S_IFDIR | 0o111; /* IFEXEC for user,group,other */
143+
} else {
144+
m |= libc::S_IFREG;
145+
}
146+
if meta.permissions().readonly() {
147+
m |= 0o444;
148+
} else {
149+
m |= 0o666;
150+
}
151+
m as _
152+
};
153+
let (atime, mtime, ctime) = (meta.accessed()?, meta.modified()?, meta.created()?);
154+
let sec = |systime: SystemTime| match systime.duration_since(SystemTime::UNIX_EPOCH) {
155+
Ok(d) => d.as_secs() as libc::time_t,
156+
Err(e) => -(e.duration().as_secs() as libc::time_t),
157+
};
158+
let nsec = |systime: SystemTime| match systime.duration_since(SystemTime::UNIX_EPOCH) {
159+
Ok(d) => d.subsec_nanos() as i32,
160+
Err(e) => -(e.duration().subsec_nanos() as i32),
161+
};
162+
Ok(StatStruct {
163+
st_dev: 0,
164+
st_ino: 0,
165+
st_mode,
166+
st_nlink: 0,
167+
st_uid: 0,
168+
st_gid: 0,
169+
st_size: meta.len(),
170+
st_atime: sec(atime),
171+
st_mtime: sec(mtime),
172+
st_ctime: sec(ctime),
173+
st_atime_nsec: nsec(atime),
174+
st_mtime_nsec: nsec(mtime),
175+
st_ctime_nsec: nsec(ctime),
176+
..Default::default()
177+
})
178+
}

0 commit comments

Comments
 (0)