diff --git a/crates/vm/src/stdlib/os.rs b/crates/vm/src/stdlib/os.rs index e9e133723..6d4a0836a 100644 --- a/crates/vm/src/stdlib/os.rs +++ b/crates/vm/src/stdlib/os.rs @@ -510,7 +510,9 @@ pub(super) mod _os { lstat: OnceCell, #[cfg(unix)] ino: AtomicCell, - #[cfg(not(unix))] + #[cfg(windows)] + ino: AtomicCell>, + #[cfg(not(any(unix, windows)))] ino: AtomicCell>, } @@ -608,9 +610,9 @@ pub(super) mod _os { Ok(stat.clone()) } - #[cfg(not(unix))] + #[cfg(windows)] #[pymethod] - fn inode(&self, vm: &VirtualMachine) -> PyResult { + fn inode(&self, vm: &VirtualMachine) -> PyResult { match self.ino.load() { Some(ino) => Ok(ino), None => { @@ -625,9 +627,14 @@ pub(super) mod _os { ) .map_err(|e| e.into_pyexception(vm))? .ok_or_else(|| crate::exceptions::cstring_error(vm))?; + // On Windows, combine st_ino and st_ino_high into 128-bit value + #[cfg(windows)] + let ino: u128 = stat.st_ino as u128 | ((stat.st_ino_high as u128) << 64); + #[cfg(not(windows))] + let ino: u128 = stat.st_ino as u128; // Err(T) means other thread set `ino` at the mean time which is safe to ignore - let _ = self.ino.compare_exchange(None, Some(stat.st_ino)); - Ok(stat.st_ino) + let _ = self.ino.compare_exchange(None, Some(ino)); + Ok(ino) } } } @@ -638,6 +645,12 @@ pub(super) mod _os { Ok(self.ino.load()) } + #[cfg(not(any(unix, windows)))] + #[pymethod] + fn inode(&self, _vm: &VirtualMachine) -> PyResult> { + Ok(self.ino.load()) + } + #[cfg(not(windows))] #[pymethod] const fn is_junction(&self, _vm: &VirtualMachine) -> PyResult { @@ -737,6 +750,12 @@ pub(super) mod _os { use std::os::unix::fs::DirEntryExt; entry.ino() }; + // TODO: wasi is nightly + // #[cfg(target_os = "wasi")] + // let ino = { + // use std::os::wasi::fs::DirEntryExt; + // entry.ino() + // }; #[cfg(not(unix))] let ino = None; @@ -882,9 +901,16 @@ pub(super) mod _os { #[cfg(not(windows))] let st_file_attributes = 0; + // On Windows, combine st_ino and st_ino_high into a 128-bit value + // like _pystat_l128_from_l64_l64 + #[cfg(windows)] + let st_ino: u128 = stat.st_ino as u128 | ((stat.st_ino_high as u128) << 64); + #[cfg(not(windows))] + let st_ino = stat.st_ino; + Self { st_mode: vm.ctx.new_pyref(stat.st_mode), - st_ino: vm.ctx.new_pyref(stat.st_ino), + st_ino: vm.ctx.new_pyref(st_ino), st_dev: vm.ctx.new_pyref(stat.st_dev), st_nlink: vm.ctx.new_pyref(stat.st_nlink), st_uid: vm.ctx.new_pyref(stat.st_uid), diff --git a/crates/vm/src/windows.rs b/crates/vm/src/windows.rs index 9b48e54e1..394714be9 100644 --- a/crates/vm/src/windows.rs +++ b/crates/vm/src/windows.rs @@ -515,8 +515,11 @@ fn win32_xstat_impl(path: &OsStr, traverse: bool) -> std::io::Result { 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); + // 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); + return Ok(result); + } } } Err(e) => {