From e84ba9278b8593d6852b1dcbb8f4c51f2d90ca08 Mon Sep 17 00:00:00 2001 From: Dean Li Date: Sun, 2 May 2021 17:45:47 +0800 Subject: [PATCH] os: Implement `inode()` for class `DirEntry` Use `std::os::unix::fs::DirEntryExt` on unix to get inode and use `stat_inner` for other platfrom to get stat and cache inode into `AtomicCell>`. Currently on windows platform in `stat_inner` inode will only contains default value (0). --- Lib/test/test_os.py | 2 -- vm/src/stdlib/os.rs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 4fa31e38c..fa8398ba1 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -3785,8 +3785,6 @@ class TestScandir(unittest.TestCase): entry_lstat, os.name == 'nt') - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_attributes(self): link = hasattr(os, 'link') symlink = support.can_symlink() diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index 9589ca7a8..2b41b4b9d 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -1,6 +1,8 @@ use std::ffi; use std::fs::OpenOptions; use std::io::{self, ErrorKind, Read, Write}; +#[cfg(unix)] +use std::os::unix::fs::DirEntryExt; use std::path::{Path, PathBuf}; use std::time::{Duration, SystemTime}; use std::{env, fs}; @@ -717,6 +719,8 @@ mod _os { struct DirEntry { entry: fs::DirEntry, mode: OutputMode, + #[cfg(not(unix))] + ino: AtomicCell>, } impl PyValue for DirEntry { @@ -793,6 +797,35 @@ mod _os { ) } + #[cfg(not(unix))] + #[pymethod] + fn inode(&self, vm: &VirtualMachine) -> PyResult { + match self.ino.load() { + Some(ino) => Ok(ino), + None => { + let stat = stat_inner( + PathOrFd::Path(PyPathLike { + path: self.entry.path(), + mode: OutputMode::String, + }), + DirFd::default(), + FollowSymlinks(false), + ) + .map_err(|e| e.into_pyexception(vm))? + .ok_or_else(|| vm.new_value_error("embedded null character".to_owned()))?; + // 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) + } + } + } + + #[cfg(unix)] + #[pymethod] + fn inode(&self, _vm: &VirtualMachine) -> PyResult { + Ok(self.entry.ino()) + } + #[pymethod(magic)] fn fspath(&self, vm: &VirtualMachine) -> PyResult { self.path(vm) @@ -842,6 +875,8 @@ mod _os { Ok(entry) => Ok(DirEntry { entry, mode: zelf.mode, + #[cfg(not(unix))] + ino: AtomicCell::new(None), } .into_ref(vm) .into_object()),