Skip to content

Commit 82f06be

Browse files
committed
Add file_id
1 parent 673b584 commit 82f06be

File tree

4 files changed

+39
-26
lines changed

4 files changed

+39
-26
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/test/test_shutil.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,6 @@ def test_copytree_simple(self):
715715
actual = read_file((dst_dir, 'test_dir', 'test.txt'))
716716
self.assertEqual(actual, '456')
717717

718-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
719718
def test_copytree_dirs_exist_ok(self):
720719
src_dir = self.mkdtemp()
721720
dst_dir = self.mkdtemp()
@@ -1558,7 +1557,6 @@ def test_copyfile_nonexistent_dir(self):
15581557
write_file(src_file, 'foo')
15591558
self.assertRaises(FileNotFoundError, shutil.copyfile, src_file, dst)
15601559

1561-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
15621560
def test_copyfile_copy_dir(self):
15631561
# Issue 45234
15641562
# test copy() and copyfile() raising proper exceptions when src and/or
@@ -2499,18 +2497,15 @@ def test_move_file(self):
24992497
# Move a file to another location on the same filesystem.
25002498
self._check_move_file(self.src_file, self.dst_file, self.dst_file)
25012499

2502-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
25032500
def test_move_file_to_dir(self):
25042501
# Move a file inside an existing dir on the same filesystem.
25052502
self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
25062503

2507-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
25082504
def test_move_file_to_dir_pathlike_src(self):
25092505
# Move a pathlike file to another location on the same filesystem.
25102506
src = pathlib.Path(self.src_file)
25112507
self._check_move_file(src, self.dst_dir, self.dst_file)
25122508

2513-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
25142509
def test_move_file_to_dir_pathlike_dst(self):
25152510
# Move a file to another pathlike location on the same filesystem.
25162511
dst = pathlib.Path(self.dst_dir)
@@ -2521,7 +2516,6 @@ def test_move_file_other_fs(self):
25212516
# Move a file to an existing dir on another filesystem.
25222517
self.test_move_file()
25232518

2524-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
25252519
@mock_rename
25262520
def test_move_file_to_dir_other_fs(self):
25272521
# Move a file to another location on another filesystem.
@@ -2540,30 +2534,25 @@ def test_move_dir_other_fs(self):
25402534
# Move a dir to another location on another filesystem.
25412535
self.test_move_dir()
25422536

2543-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
25442537
def test_move_dir_to_dir(self):
25452538
# Move a dir inside an existing dir on the same filesystem.
25462539
self._check_move_dir(self.src_dir, self.dst_dir,
25472540
os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
25482541

2549-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
25502542
@mock_rename
25512543
def test_move_dir_to_dir_other_fs(self):
25522544
# Move a dir inside an existing dir on another filesystem.
25532545
self.test_move_dir_to_dir()
25542546

2555-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
25562547
def test_move_dir_sep_to_dir(self):
25572548
self._check_move_dir(self.src_dir + os.path.sep, self.dst_dir,
25582549
os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
25592550

2560-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
25612551
@unittest.skipUnless(os.path.altsep, 'requires os.path.altsep')
25622552
def test_move_dir_altsep_to_dir(self):
25632553
self._check_move_dir(self.src_dir + os.path.altsep, self.dst_dir,
25642554
os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
25652555

2566-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
25672556
def test_existing_file_inside_dest_dir(self):
25682557
# A file with the same name inside the destination dir already exists.
25692558
with open(self.dst_file, "wb"):
@@ -2646,7 +2635,6 @@ def test_move_dir_symlink(self):
26462635
self.assertTrue(os.path.islink(dst_link))
26472636
self.assertTrue(os.path.samefile(src, dst_link))
26482637

2649-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
26502638
def test_move_return_value(self):
26512639
rv = shutil.move(self.src_file, self.dst_dir)
26522640
self.assertEqual(rv,
@@ -2656,7 +2644,6 @@ def test_move_as_rename_return_value(self):
26562644
rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
26572645
self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
26582646

2659-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
26602647
@mock_rename
26612648
def test_move_file_special_function(self):
26622649
moved = []
@@ -2665,7 +2652,6 @@ def _copy(src, dst):
26652652
shutil.move(self.src_file, self.dst_dir, copy_function=_copy)
26662653
self.assertEqual(len(moved), 1)
26672654

2668-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
26692655
@mock_rename
26702656
def test_move_dir_special_function(self):
26712657
moved = []
@@ -2694,7 +2680,6 @@ def test_move_dir_caseinsensitive(self):
26942680

26952681
# bpo-26791: Check that a symlink to a directory can
26962682
# be moved into that directory.
2697-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
26982683
@mock_rename
26992684
def _test_move_symlink_to_dir_into_dir(self, dst):
27002685
src = os.path.join(self.src_dir, 'linktodir')
@@ -2895,7 +2880,6 @@ def test_file_offset(self):
28952880
self.assertEqual(src.tell(), self.FILESIZE)
28962881
self.assertEqual(dst.tell(), self.FILESIZE)
28972882

2898-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
28992883
@unittest.skipIf(os.name != 'nt', "Windows only")
29002884
def test_win_impl(self):
29012885
# Make sure alternate Windows implementation is called.

vm/Cargo.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,11 @@ which = "4.2.5"
102102
num_cpus = "1.13.1"
103103

104104
[target.'cfg(windows)'.dependencies]
105+
junction = { workspace = true }
105106
schannel = { workspace = true }
106107
widestring = { workspace = true }
107108
winreg = "0.10.1"
108109

109-
[target.'cfg(windows)'.dependencies.junction]
110-
workspace = true
111-
112110
[target.'cfg(windows)'.dependencies.windows]
113111
version = "0.52.0"
114112
features = [

vm/src/windows.rs

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::common::fileutils::{
2-
StatStruct,
32
windows::{get_file_information_by_name, FILE_INFO_BY_NAME_CLASS},
3+
StatStruct,
44
};
55
use crate::{
66
convert::{ToPyObject, ToPyResult},
@@ -130,11 +130,42 @@ fn win32_xstat_impl(path: &OsStr, traverse: bool) -> std::io::Result<StatStruct>
130130
}
131131
}
132132

133-
// TODO: replace it with win32_xstat_slow_impl(&path, result, traverse)
134-
meta_to_stat(&crate::stdlib::os::fs_metadata(path, traverse)?)
133+
// TODO: check if win32_xstat_slow_impl(&path, result, traverse) is required
134+
meta_to_stat(
135+
&crate::stdlib::os::fs_metadata(path, traverse)?,
136+
file_id(path)?,
137+
)
138+
}
139+
140+
// Ported from zed: https://github.com/zed-industries/zed/blob/v0.131.6/crates/fs/src/fs.rs#L1532-L1562
141+
// can we get file id not open the file twice?
142+
// https://github.com/rust-lang/rust/issues/63010
143+
fn file_id(path: &OsStr) -> std::io::Result<u64> {
144+
use std::os::windows::{fs::OpenOptionsExt, io::AsRawHandle};
145+
use windows_sys::Win32::{
146+
Foundation::HANDLE,
147+
Storage::FileSystem::{
148+
GetFileInformationByHandle, BY_HANDLE_FILE_INFORMATION, FILE_FLAG_BACKUP_SEMANTICS,
149+
},
150+
};
151+
152+
let file = std::fs::OpenOptions::new()
153+
.read(true)
154+
.custom_flags(FILE_FLAG_BACKUP_SEMANTICS)
155+
.open(path)?;
156+
157+
let mut info: BY_HANDLE_FILE_INFORMATION = unsafe { std::mem::zeroed() };
158+
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileinformationbyhandle
159+
// This function supports Windows XP+
160+
let ret = unsafe { GetFileInformationByHandle(file.as_raw_handle() as HANDLE, &mut info) };
161+
if ret == 0 {
162+
return Err(std::io::Error::last_os_error());
163+
};
164+
165+
Ok(((info.nFileIndexHigh as u64) << 32) | (info.nFileIndexLow as u64))
135166
}
136167

137-
fn meta_to_stat(meta: &std::fs::Metadata) -> std::io::Result<StatStruct> {
168+
fn meta_to_stat(meta: &std::fs::Metadata, file_id: u64) -> std::io::Result<StatStruct> {
138169
let st_mode = {
139170
// Based on CPython fileutils.c' attributes_to_mode
140171
let mut m = 0;
@@ -161,7 +192,7 @@ fn meta_to_stat(meta: &std::fs::Metadata) -> std::io::Result<StatStruct> {
161192
};
162193
Ok(StatStruct {
163194
st_dev: 0,
164-
st_ino: 0,
195+
st_ino: file_id,
165196
st_mode,
166197
st_nlink: 0,
167198
st_uid: 0,

0 commit comments

Comments
 (0)