Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
vm::windows
  • Loading branch information
youknowone committed Apr 21, 2024
commit 2c2d91400f074182ce23f20812144c4ed09a520c
2 changes: 1 addition & 1 deletion stdlib/src/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::{io, mem};

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

#[cfg(unix)]
{
Expand Down
2 changes: 1 addition & 1 deletion stdlib/src/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pub(super) use _socket::{sock_select, timeout_error_msg, PySocket, SelectKind};

pub fn make_module(vm: &VirtualMachine) -> PyRef<PyModule> {
#[cfg(windows)]
crate::vm::stdlib::nt::init_winsock();
crate::vm::windows::init_winsock();
_socket::make_module(vm)
}

Expand Down
111 changes: 0 additions & 111 deletions vm/src/stdlib/nt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,114 +420,3 @@ pub(crate) mod module {
Vec::new()
}
}

pub fn init_winsock() {
static WSA_INIT: parking_lot::Once = parking_lot::Once::new();
WSA_INIT.call_once(|| unsafe {
let mut wsa_data = std::mem::MaybeUninit::uninit();
let _ = windows_sys::Win32::Networking::WinSock::WSAStartup(0x0101, wsa_data.as_mut_ptr());
})
}

// win32_xstat in cpython
pub fn win32_xstat(path: &OsStr, traverse: bool) -> std::io::Result<StatStruct> {
let mut result = match win32_xstat_impl(path, traverse) {
Ok(r) => r,
Err(e) => {
// TODO: cpython comments say GetLastError must be called here.
return Err(e);
}
};
// ctime is only deprecated from 3.12, so we copy birthtime across
result.st_ctime = result.st_birthtime;
result.st_ctime_nsec = result.st_birthtime_nsec;
return Ok(result);
}

fn is_reparse_tag_name_surrogate(tag: u32) -> bool {
(tag & 0x20000000) > 0
}

use crate::common::fileutils::StatStruct;
use std::{ffi::OsStr, time::SystemTime};

fn win32_xstat_impl(path: &OsStr, traverse: bool) -> std::io::Result<StatStruct> {
use crate::common::fileutils::windows::{
get_file_information_by_name, FILE_INFO_BY_NAME_CLASS,
};
use windows_sys::Win32::{Foundation, Storage::FileSystem::FILE_ATTRIBUTE_REPARSE_POINT};

let stat_info =
get_file_information_by_name(&path, FILE_INFO_BY_NAME_CLASS::FileStatBasicByNameInfo);
match stat_info {
Ok(stat_info) => {
if !(stat_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT != 0)
|| (!traverse && is_reparse_tag_name_surrogate(stat_info.ReparseTag))
{
let mut result =
crate::common::fileutils::windows::stat_basic_info_to_stat(&stat_info);
result.update_st_mode_from_path(&path, stat_info.FileAttributes);
return Ok(result);
}
}
Err(e) => {
if let Some(errno) = e.raw_os_error() {
if matches!(
errno as u32,
Foundation::ERROR_FILE_NOT_FOUND
| Foundation::ERROR_PATH_NOT_FOUND
| Foundation::ERROR_NOT_READY
| Foundation::ERROR_BAD_NET_NAME
) {
return Err(e);
}
}
}
}

// TODO: win32_xstat_slow_impl(&path, result, traverse)
meta_to_stat(&crate::stdlib::os::fs_metadata(path, traverse)?)
}

fn meta_to_stat(meta: &std::fs::Metadata) -> std::io::Result<StatStruct> {
let st_mode = {
// Based on CPython fileutils.c' attributes_to_mode
let mut m = 0;
if meta.is_dir() {
m |= libc::S_IFDIR | 0o111; /* IFEXEC for user,group,other */
} else {
m |= libc::S_IFREG;
}
if meta.permissions().readonly() {
m |= 0o444;
} else {
m |= 0o666;
}
m as _
};
let (atime, mtime, ctime) = (meta.accessed()?, meta.modified()?, meta.created()?);
let sec = |systime: SystemTime| match systime.duration_since(SystemTime::UNIX_EPOCH) {
Ok(d) => d.as_secs() as libc::time_t,
Err(e) => -(e.duration().as_secs() as libc::time_t),
};
let nsec = |systime: SystemTime| match systime.duration_since(SystemTime::UNIX_EPOCH) {
Ok(d) => d.subsec_nanos() as i32,
Err(e) => -(e.duration().subsec_nanos() as i32),
};
Ok(StatStruct {
st_dev: 0,
st_ino: 0,
st_mode,
st_nlink: 0,
st_uid: 0,
st_gid: 0,
st_size: meta.len(),
st_atime: sec(atime),
st_mtime: sec(mtime),
st_ctime: sec(ctime),
st_atime_nsec: nsec(atime),
st_mtime_nsec: nsec(mtime),
st_ctime_nsec: nsec(ctime),
..Default::default()
})
}
4 changes: 2 additions & 2 deletions vm/src/stdlib/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
};
use std::{ffi, fs, io, path::Path};

pub(super) fn fs_metadata<P: AsRef<Path>>(
pub(crate) fn fs_metadata<P: AsRef<Path>>(
path: P,
follow_symlink: bool,
) -> io::Result<fs::Metadata> {
Expand Down Expand Up @@ -821,7 +821,7 @@ pub(super) mod _os {
// TODO: replicate CPython's win32_xstat
let [] = dir_fd.0;
match file {
OsPathOrFd::Path(path) => crate::stdlib::nt::win32_xstat(&path.path, follow_symlinks.0),
OsPathOrFd::Path(path) => crate::windows::win32_xstat(&path.path, follow_symlinks.0),
OsPathOrFd::Fd(fd) => crate::common::fileutils::fstat(fd),
}
.map(Some)
Expand Down
2 changes: 1 addition & 1 deletion vm/src/stdlib/signal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ pub(crate) mod _signal {
let is_socket = if fd != INVALID_WAKEUP {
use windows_sys::Win32::Networking::WinSock;

crate::stdlib::nt::init_winsock();
crate::windows::init_winsock();
let mut res = 0i32;
let mut res_size = std::mem::size_of::<i32>() as i32;
let res = unsafe {
Expand Down
104 changes: 104 additions & 0 deletions vm/src/windows.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
use crate::common::fileutils::{
StatStruct,
windows::{get_file_information_by_name, FILE_INFO_BY_NAME_CLASS},
};
use crate::{
convert::{ToPyObject, ToPyResult},
stdlib::os::errno_err,
PyObjectRef, PyResult, TryFromObject, VirtualMachine,
};
use std::{ffi::OsStr, time::SystemTime};
use windows::Win32::Foundation::HANDLE;
use windows_sys::Win32::Foundation::{BOOL, HANDLE as RAW_HANDLE, INVALID_HANDLE_VALUE};

Expand Down Expand Up @@ -66,3 +71,102 @@ impl ToPyObject for HANDLE {
(self.0 as HandleInt).to_pyobject(vm)
}
}

pub fn init_winsock() {
static WSA_INIT: parking_lot::Once = parking_lot::Once::new();
WSA_INIT.call_once(|| unsafe {
let mut wsa_data = std::mem::MaybeUninit::uninit();
let _ = windows_sys::Win32::Networking::WinSock::WSAStartup(0x0101, wsa_data.as_mut_ptr());
})
}

// win32_xstat in cpython
pub fn win32_xstat(path: &OsStr, traverse: bool) -> std::io::Result<StatStruct> {
let mut result = win32_xstat_impl(path, traverse)?;
// ctime is only deprecated from 3.12, so we copy birthtime across
result.st_ctime = result.st_birthtime;
result.st_ctime_nsec = result.st_birthtime_nsec;
Ok(result)
}

fn is_reparse_tag_name_surrogate(tag: u32) -> bool {
(tag & 0x20000000) > 0
}

fn win32_xstat_impl(path: &OsStr, traverse: bool) -> std::io::Result<StatStruct> {
use windows_sys::Win32::{Foundation, Storage::FileSystem::FILE_ATTRIBUTE_REPARSE_POINT};

let stat_info =
get_file_information_by_name(path, FILE_INFO_BY_NAME_CLASS::FileStatBasicByNameInfo);
match stat_info {
Ok(stat_info) => {
if (stat_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT == 0)
|| (!traverse && is_reparse_tag_name_surrogate(stat_info.ReparseTag))
{
let mut result =
crate::common::fileutils::windows::stat_basic_info_to_stat(&stat_info);
result.update_st_mode_from_path(path, stat_info.FileAttributes);
return Ok(result);
}
}
Err(e) => {
if let Some(errno) = e.raw_os_error() {
if matches!(
errno as u32,
Foundation::ERROR_FILE_NOT_FOUND
| Foundation::ERROR_PATH_NOT_FOUND
| Foundation::ERROR_NOT_READY
| Foundation::ERROR_BAD_NET_NAME
) {
return Err(e);
}
}
}
}

// TODO: replace it with win32_xstat_slow_impl(&path, result, traverse)
meta_to_stat(&crate::stdlib::os::fs_metadata(path, traverse)?)
}

fn meta_to_stat(meta: &std::fs::Metadata) -> std::io::Result<StatStruct> {
let st_mode = {
// Based on CPython fileutils.c' attributes_to_mode
let mut m = 0;
if meta.is_dir() {
m |= libc::S_IFDIR | 0o111; /* IFEXEC for user,group,other */
} else {
m |= libc::S_IFREG;
}
if meta.permissions().readonly() {
m |= 0o444;
} else {
m |= 0o666;
}
m as _
};
let (atime, mtime, ctime) = (meta.accessed()?, meta.modified()?, meta.created()?);
let sec = |systime: SystemTime| match systime.duration_since(SystemTime::UNIX_EPOCH) {
Ok(d) => d.as_secs() as libc::time_t,
Err(e) => -(e.duration().as_secs() as libc::time_t),
};
let nsec = |systime: SystemTime| match systime.duration_since(SystemTime::UNIX_EPOCH) {
Ok(d) => d.subsec_nanos() as i32,
Err(e) => -(e.duration().subsec_nanos() as i32),
};
Ok(StatStruct {
st_dev: 0,
st_ino: 0,
st_mode,
st_nlink: 0,
st_uid: 0,
st_gid: 0,
st_size: meta.len(),
st_atime: sec(atime),
st_mtime: sec(mtime),
st_birthtime: sec(ctime),
st_atime_nsec: nsec(atime),
st_mtime_nsec: nsec(mtime),
st_birthtime_nsec: nsec(ctime),
..Default::default()
})
}