Skip to content

Commit 593b164

Browse files
committed
Add file_id
1 parent 2c2d914 commit 593b164

File tree

7 files changed

+40
-79
lines changed

7 files changed

+40
-79
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_genericpath.py

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,6 @@ def _test_samefile_on_link_func(self, func):
242242
create_file(test_fn2)
243243
self.assertFalse(self.pathmodule.samefile(test_fn1, test_fn2))
244244

245-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; properly implement stat st_dev/st_ino")
246245
@os_helper.skip_unless_symlink
247246
def test_samefile_on_symlink(self):
248247
self._test_samefile_on_link_func(os.symlink)
@@ -285,7 +284,6 @@ def _test_samestat_on_link_func(self, func):
285284
self.assertFalse(self.pathmodule.samestat(os.stat(test_fn1),
286285
os.stat(test_fn2)))
287286

288-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; properly implement stat st_dev/st_ino")
289287
@os_helper.skip_unless_symlink
290288
def test_samestat_on_symlink(self):
291289
self._test_samestat_on_link_func(os.symlink)
@@ -314,30 +312,6 @@ class TestGenericTest(GenericTest, unittest.TestCase):
314312
# and is only meant to be inherited by others.
315313
pathmodule = genericpath
316314

317-
# TODO: RUSTPYTHON
318-
if sys.platform == "win32":
319-
@unittest.expectedFailure
320-
def test_samefile(self):
321-
super().test_samefile()
322-
323-
# TODO: RUSTPYTHON
324-
if sys.platform == "win32":
325-
@unittest.expectedFailure
326-
def test_samefile_on_link(self):
327-
super().test_samefile_on_link()
328-
329-
# TODO: RUSTPYTHON
330-
if sys.platform == "win32":
331-
@unittest.expectedFailure
332-
def test_samestat(self):
333-
super().test_samestat()
334-
335-
# TODO: RUSTPYTHON
336-
if sys.platform == "win32":
337-
@unittest.expectedFailure
338-
def test_samestat_on_link(self):
339-
super().test_samestat_on_link()
340-
341315
def test_invalid_paths(self):
342316
for attr in GenericTest.common_attributes:
343317
# os.path.commonprefix doesn't raise ValueError

Lib/test/test_ntpath.py

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -912,26 +912,6 @@ def test_expandvars(self): # TODO: RUSTPYTHON; remove when done
912912
def test_expandvars_nonascii(self): # TODO: RUSTPYTHON; remove when done
913913
super().test_expandvars_nonascii()
914914

915-
# TODO: RUSTPYTHON
916-
@unittest.expectedFailure
917-
def test_samefile(self): # TODO: RUSTPYTHON; remove when done
918-
super().test_samefile()
919-
920-
# TODO: RUSTPYTHON
921-
@unittest.expectedFailure
922-
def test_samefile_on_link(self): # TODO: RUSTPYTHON; remove when done
923-
super().test_samefile_on_link()
924-
925-
# TODO: RUSTPYTHON
926-
@unittest.expectedFailure
927-
def test_samestat(self): # TODO: RUSTPYTHON; remove when done
928-
super().test_samestat()
929-
930-
# TODO: RUSTPYTHON
931-
@unittest.expectedFailure
932-
def test_samestat_on_link(self): # TODO: RUSTPYTHON; remove when done
933-
super().test_samestat_on_link()
934-
935915

936916
class PathLikeTests(NtpathTestCase):
937917

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()
@@ -1557,7 +1556,6 @@ def test_copyfile_nonexistent_dir(self):
15571556
write_file(src_file, 'foo')
15581557
self.assertRaises(FileNotFoundError, shutil.copyfile, src_file, dst)
15591558

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

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

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

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

2523-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
25242518
@mock_rename
25252519
def test_move_file_to_dir_other_fs(self):
25262520
# Move a file to another location on another filesystem.
@@ -2539,30 +2533,25 @@ def test_move_dir_other_fs(self):
25392533
# Move a dir to another location on another filesystem.
25402534
self.test_move_dir()
25412535

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

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

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

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

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

2648-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
26492637
def test_move_return_value(self):
26502638
rv = shutil.move(self.src_file, self.dst_dir)
26512639
self.assertEqual(rv,
@@ -2655,7 +2643,6 @@ def test_move_as_rename_return_value(self):
26552643
rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
26562644
self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
26572645

2658-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
26592646
@mock_rename
26602647
def test_move_file_special_function(self):
26612648
moved = []
@@ -2664,7 +2651,6 @@ def _copy(src, dst):
26642651
shutil.move(self.src_file, self.dst_dir, copy_function=_copy)
26652652
self.assertEqual(len(moved), 1)
26662653

2667-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
26682654
@mock_rename
26692655
def test_move_dir_special_function(self):
26702656
moved = []
@@ -2693,7 +2679,6 @@ def test_move_dir_caseinsensitive(self):
26932679

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

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

Lib/test/test_tarfile.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,6 +1299,7 @@ def test_link_size(self):
12991299
os_helper.unlink(target)
13001300
os_helper.unlink(link)
13011301

1302+
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
13021303
@os_helper.skip_unless_symlink
13031304
def test_symlink_size(self):
13041305
path = os.path.join(TEMPDIR, "symlink")
@@ -1496,13 +1497,6 @@ def expectedSuccess(test_item):
14961497
def test_cwd(self):
14971498
super().test_cwd()
14981499

1499-
# TODO: RUSTPYTHON
1500-
if sys.platform == "win32":
1501-
@expectedSuccess
1502-
def test_symlink_size(self):
1503-
super().test_symlink_size()
1504-
pass
1505-
15061500

15071501
class Bz2WriteTest(Bz2Test, WriteTest):
15081502
pass

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},
@@ -124,11 +124,42 @@ fn win32_xstat_impl(path: &OsStr, traverse: bool) -> std::io::Result<StatStruct>
124124
}
125125
}
126126

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

131-
fn meta_to_stat(meta: &std::fs::Metadata) -> std::io::Result<StatStruct> {
162+
fn meta_to_stat(meta: &std::fs::Metadata, file_id: u64) -> std::io::Result<StatStruct> {
132163
let st_mode = {
133164
// Based on CPython fileutils.c' attributes_to_mode
134165
let mut m = 0;
@@ -155,7 +186,7 @@ fn meta_to_stat(meta: &std::fs::Metadata) -> std::io::Result<StatStruct> {
155186
};
156187
Ok(StatStruct {
157188
st_dev: 0,
158-
st_ino: 0,
189+
st_ino: file_id,
159190
st_mode,
160191
st_nlink: 0,
161192
st_uid: 0,

0 commit comments

Comments
 (0)