|
| 1 | +use crate::common::fileutils::{ |
| 2 | + StatStruct, |
| 3 | + windows::{get_file_information_by_name, FILE_INFO_BY_NAME_CLASS}, |
| 4 | +}; |
1 | 5 | use crate::{ |
2 | 6 | convert::{ToPyObject, ToPyResult}, |
3 | 7 | stdlib::os::errno_err, |
4 | 8 | PyObjectRef, PyResult, TryFromObject, VirtualMachine, |
5 | 9 | }; |
| 10 | +use std::{ffi::OsStr, time::SystemTime}; |
6 | 11 | use windows::Win32::Foundation::HANDLE; |
7 | 12 | use windows_sys::Win32::Foundation::{BOOL, HANDLE as RAW_HANDLE, INVALID_HANDLE_VALUE}; |
8 | 13 |
|
@@ -66,3 +71,108 @@ impl ToPyObject for HANDLE { |
66 | 71 | (self.0 as HandleInt).to_pyobject(vm) |
67 | 72 | } |
68 | 73 | } |
| 74 | + |
| 75 | +pub fn init_winsock() { |
| 76 | + static WSA_INIT: parking_lot::Once = parking_lot::Once::new(); |
| 77 | + WSA_INIT.call_once(|| unsafe { |
| 78 | + let mut wsa_data = std::mem::MaybeUninit::uninit(); |
| 79 | + let _ = windows_sys::Win32::Networking::WinSock::WSAStartup(0x0101, wsa_data.as_mut_ptr()); |
| 80 | + }) |
| 81 | +} |
| 82 | + |
| 83 | +// win32_xstat in cpython |
| 84 | +pub fn win32_xstat(path: &OsStr, traverse: bool) -> std::io::Result<StatStruct> { |
| 85 | + let mut result = match win32_xstat_impl(path, traverse) { |
| 86 | + Ok(r) => r, |
| 87 | + Err(e) => { |
| 88 | + // TODO: cpython comments say GetLastError must be called here. |
| 89 | + return Err(e); |
| 90 | + } |
| 91 | + }; |
| 92 | + // ctime is only deprecated from 3.12, so we copy birthtime across |
| 93 | + result.st_ctime = result.st_birthtime; |
| 94 | + result.st_ctime_nsec = result.st_birthtime_nsec; |
| 95 | + Ok(result) |
| 96 | +} |
| 97 | + |
| 98 | +fn is_reparse_tag_name_surrogate(tag: u32) -> bool { |
| 99 | + (tag & 0x20000000) > 0 |
| 100 | +} |
| 101 | + |
| 102 | +fn win32_xstat_impl(path: &OsStr, traverse: bool) -> std::io::Result<StatStruct> { |
| 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: replace it with 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_birthtime: sec(ctime), |
| 173 | + st_atime_nsec: nsec(atime), |
| 174 | + st_mtime_nsec: nsec(mtime), |
| 175 | + st_birthtime_nsec: nsec(ctime), |
| 176 | + ..Default::default() |
| 177 | + }) |
| 178 | +} |
0 commit comments