Skip to content

Commit e426042

Browse files
committed
fix remove
1 parent 1ff83a7 commit e426042

File tree

2 files changed

+24
-10
lines changed

2 files changed

+24
-10
lines changed

Lib/test/test_os.py

Lines changed: 0 additions & 6 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
@@ -5230,7 +5225,6 @@ def test_fd(self):
52305225
st = os.stat(entry.name, dir_fd=fd, follow_symlinks=False)
52315226
self.assertEqual(entry.stat(follow_symlinks=False), st)
52325227

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

crates/vm/src/stdlib/os.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ pub(super) mod _os {
162162
fileutils::StatStruct,
163163
lock::{OnceCell, PyRwLock},
164164
suppress_iph,
165+
windows::ToWideString,
165166
},
166167
convert::{IntoPyException, ToPyObject},
167168
function::{ArgBytesLike, Either, FsPath, FuncArgs, OptionalArg},
@@ -292,10 +293,29 @@ pub(super) mod _os {
292293
#[pyfunction(name = "unlink")]
293294
fn remove(path: OsPath, dir_fd: DirFd<'_, 0>, vm: &VirtualMachine) -> PyResult<()> {
294295
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 {
296+
#[cfg(windows)]
297+
let is_dir_link = {
298+
// On Windows, we need to check if it's a directory symlink/junction
299+
// using GetFileAttributesW, which doesn't follow symlinks.
300+
// This is similar to CPython's Py_DeleteFileW.
301+
use windows_sys::Win32::Storage::FileSystem::{
302+
FILE_ATTRIBUTE_DIRECTORY, FILE_ATTRIBUTE_REPARSE_POINT, GetFileAttributesW,
303+
INVALID_FILE_ATTRIBUTES,
304+
};
305+
let wide_path: Vec<u16> = path.path.as_os_str().to_wide_with_nul();
306+
let attrs = unsafe { GetFileAttributesW(wide_path.as_ptr()) };
307+
if attrs != INVALID_FILE_ATTRIBUTES {
308+
let is_dir = (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0;
309+
let is_reparse = (attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
310+
is_dir && is_reparse
311+
} else {
312+
false
313+
}
314+
};
315+
#[cfg(not(windows))]
316+
let is_dir_link = false;
317+
318+
let res = if is_dir_link {
299319
fs::remove_dir(&path)
300320
} else {
301321
fs::remove_file(&path)

0 commit comments

Comments
 (0)