Skip to content

Commit 42d0a58

Browse files
committed
fix remove
1 parent 649606f commit 42d0a58

File tree

4 files changed

+26
-14
lines changed

4 files changed

+26
-14
lines changed

Lib/test/test_os.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -736,7 +736,6 @@ def test_file_attributes(self):
736736
result.st_file_attributes & stat.FILE_ATTRIBUTE_DIRECTORY,
737737
stat.FILE_ATTRIBUTE_DIRECTORY)
738738

739-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; os.stat (PermissionError: [Errno 5] Access is denied.)')
740739
@unittest.skipUnless(sys.platform == "win32", "Win32 specific tests")
741740
def test_access_denied(self):
742741
# Default to FindFirstFile WIN32_FIND_DATA when access is
@@ -759,7 +758,6 @@ def test_access_denied(self):
759758
self.assertNotEqual(result.st_size, 0)
760759
self.assertTrue(os.path.isfile(fname))
761760

762-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; os.stat (PermissionError: [Errno 1] Incorrect function.)')
763761
@unittest.skipUnless(sys.platform == "win32", "Win32 specific tests")
764762
def test_stat_block_device(self):
765763
# bpo-38030: os.stat fails for block devices
@@ -1796,7 +1794,6 @@ def test_mode(self):
17961794
self.assertEqual(os.stat(path).st_mode & 0o777, 0o555)
17971795
self.assertEqual(os.stat(parent).st_mode & 0o777, 0o775)
17981796

1799-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; os.umask not implemented yet for all platforms')
18001797
@unittest.skipIf(
18011798
support.is_emscripten or support.is_wasi,
18021799
"Emscripten's/WASI's umask is a stub."
@@ -2116,7 +2113,6 @@ def test_urandom_fd_closed(self):
21162113
"""
21172114
rc, out, err = assert_python_ok('-Sc', code)
21182115

2119-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; (ModuleNotFoundError: No module named 'os'")
21202116
def test_urandom_fd_reopened(self):
21212117
# Issue #21207: urandom() should detect its fd to /dev/urandom
21222118
# changed to something else, and reopen it.
@@ -3221,7 +3217,6 @@ def test_getfinalpathname_handles(self):
32213217

32223218
self.assertEqual(0, handle_delta)
32233219

3224-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; os.stat (PermissionError: [Errno 5] Access is denied.)')
32253220
@support.requires_subprocess()
32263221
def test_stat_unlink_race(self):
32273222
# bpo-46785: the implementation of os.stat() falls back to reading
@@ -4927,7 +4922,6 @@ def setUp(self):
49274922
self.addCleanup(os_helper.rmtree, self.path)
49284923
os.mkdir(self.path)
49294924

4930-
@unittest.expectedFailure # TODO: RUSTPYTHON; (AssertionError: TypeError not raised by DirEntry)
49314925
def test_uninstantiable(self):
49324926
self.assertRaises(TypeError, os.DirEntry)
49334927

@@ -4976,7 +4970,6 @@ def assert_stat_equal(self, stat1, stat2, skip_fields):
49764970
else:
49774971
self.assertEqual(stat1, stat2)
49784972

4979-
@unittest.expectedFailure # TODO: RUSTPYTHON; (AssertionError: TypeError not raised by ScandirIter)
49804973
def test_uninstantiable(self):
49814974
scandir_iter = os.scandir(self.path)
49824975
self.assertRaises(TypeError, type(scandir_iter))
@@ -5230,7 +5223,6 @@ def test_fd(self):
52305223
st = os.stat(entry.name, dir_fd=fd, follow_symlinks=False)
52315224
self.assertEqual(entry.stat(follow_symlinks=False), st)
52325225

5233-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; (AssertionError: FileNotFoundError not raised by scandir)')
52345226
@unittest.skipIf(support.is_wasi, "WASI maps '' to cwd")
52355227
def test_empty_path(self):
52365228
self.assertRaises(FileNotFoundError, os.scandir, '')

Lib/test/test_shutil.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,6 @@ def onexc(*args):
235235
self.assertEqual(errors[0][1], link)
236236
self.assertIsInstance(errors[0][2], OSError)
237237

238-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
239238
@os_helper.skip_unless_symlink
240239
def test_rmtree_works_on_symlinks(self):
241240
tmp = self.mkdtemp()

crates/vm/src/stdlib/os.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ impl ToPyObject for crt_fd::Borrowed<'_> {
152152
#[pymodule(sub)]
153153
pub(super) mod _os {
154154
use super::{DirFd, FollowSymlinks, SupportFunc, errno_err};
155+
#[cfg(windows)]
156+
use crate::common::windows::ToWideString;
155157
use crate::{
156158
AsObject, Py, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
157159
builtins::{
@@ -292,10 +294,29 @@ pub(super) mod _os {
292294
#[pyfunction(name = "unlink")]
293295
fn remove(path: OsPath, dir_fd: DirFd<'_, 0>, vm: &VirtualMachine) -> PyResult<()> {
294296
let [] = dir_fd.0;
295-
let is_junction = cfg!(windows)
296-
&& fs::metadata(&path).is_ok_and(|meta| meta.file_type().is_dir())
297-
&& fs::symlink_metadata(&path).is_ok_and(|meta| meta.file_type().is_symlink());
298-
let res = if is_junction {
297+
#[cfg(windows)]
298+
let is_dir_link = {
299+
// On Windows, we need to check if it's a directory symlink/junction
300+
// using GetFileAttributesW, which doesn't follow symlinks.
301+
// This is similar to CPython's Py_DeleteFileW.
302+
use windows_sys::Win32::Storage::FileSystem::{
303+
FILE_ATTRIBUTE_DIRECTORY, FILE_ATTRIBUTE_REPARSE_POINT, GetFileAttributesW,
304+
INVALID_FILE_ATTRIBUTES,
305+
};
306+
let wide_path: Vec<u16> = path.path.as_os_str().to_wide_with_nul();
307+
let attrs = unsafe { GetFileAttributesW(wide_path.as_ptr()) };
308+
if attrs != INVALID_FILE_ATTRIBUTES {
309+
let is_dir = (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0;
310+
let is_reparse = (attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
311+
is_dir && is_reparse
312+
} else {
313+
false
314+
}
315+
};
316+
#[cfg(not(windows))]
317+
let is_dir_link = false;
318+
319+
let res = if is_dir_link {
299320
fs::remove_dir(&path)
300321
} else {
301322
fs::remove_file(&path)

crates/vm/src/stdlib/sys.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ mod sys {
1212
common::{
1313
ascii,
1414
hash::{PyHash, PyUHash},
15-
windows::ToWideString,
1615
},
1716
convert::ToPyObject,
1817
frame::FrameRef,
@@ -550,6 +549,7 @@ mod sys {
550549

551550
#[cfg(windows)]
552551
fn get_kernel32_version() -> std::io::Result<(u32, u32, u32)> {
552+
use crate::common::windows::ToWideString;
553553
unsafe {
554554
// Create a wide string for "kernel32.dll"
555555
let module_name: Vec<u16> = std::ffi::OsStr::new("kernel32.dll").to_wide_with_nul();

0 commit comments

Comments
 (0)