From 4fa8174f38c89a233e471d71db123616241549f8 Mon Sep 17 00:00:00 2001 From: WrldEngine Date: Thu, 23 Oct 2025 20:27:31 +0500 Subject: [PATCH 1/8] fix: std::sys::fs use_with_native_path for read_dir for windows --- library/std/src/sys/fs/mod.rs | 3 +-- library/std/src/sys/fs/windows.rs | 16 ++++++++++++++-- library/std/src/sys/path/windows.rs | 5 +++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index 74354227d84a6..807f8b2d7e809 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -66,8 +66,7 @@ pub use imp::{ }; pub fn read_dir(path: &Path) -> io::Result { - // FIXME: use with_native_path on all platforms - imp::readdir(path) + with_native_path(path, &imp::readdir) } pub fn remove_file(path: &Path) -> io::Result<()> { diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index f2d325da35c7d..388ff791c86ba 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -1182,11 +1182,23 @@ impl DirBuilder { } } -pub fn readdir(p: &Path) -> io::Result { +pub fn readdir(p: &WCStr) -> io::Result { + let mut p = unsafe { p.to_wchars_with_null_unchecked() }.to_vec(); + + // `p` already contains NUL, because before reading directory function, + // it already passes `maybe_verbatim` that appending zero at the end, it + // should be refactored. + if let Some(pos) = p.iter().position(|x| *x == 0) { + p.remove(pos); + } + + let p_os_string = OsString::from_wide(&p); + let p = Path::new(&p_os_string); + // We push a `*` to the end of the path which cause the empty path to be // treated as the current directory. So, for consistency with other platforms, // we explicitly error on the empty path. - if p.as_os_str().is_empty() { + if p_os_string.is_empty() { // Return an error code consistent with other ways of opening files. // E.g. fs::metadata or File::open. return Err(io::Error::from_raw_os_error(c::ERROR_PATH_NOT_FOUND as i32)); diff --git a/library/std/src/sys/path/windows.rs b/library/std/src/sys/path/windows.rs index f124e1e5a71c7..10bdea771c901 100644 --- a/library/std/src/sys/path/windows.rs +++ b/library/std/src/sys/path/windows.rs @@ -1,3 +1,4 @@ +use crate::alloc_crate::slice; use crate::ffi::{OsStr, OsString}; use crate::path::{Path, PathBuf}; use crate::sys::api::utf16; @@ -29,6 +30,10 @@ impl WCStr { unsafe { &*(s as *const [u16] as *const Self) } } + pub unsafe fn to_wchars_with_null_unchecked(&self) -> &[u16] { + unsafe { slice::from_raw_parts(self.as_ptr(), self.0.len()) } + } + pub fn as_ptr(&self) -> *const u16 { self.0.as_ptr() } From fbdf6e84283ba9c73dfcb28e1dbabb463b16cded Mon Sep 17 00:00:00 2001 From: WrldEngine Date: Thu, 23 Oct 2025 21:18:50 +0500 Subject: [PATCH 2/8] chore: add windows cfg in read_dir, for use_native_path --- library/std/src/sys/fs/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index 807f8b2d7e809..c58644b0f4f35 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -66,6 +66,9 @@ pub use imp::{ }; pub fn read_dir(path: &Path) -> io::Result { + #[cfg(not(windows))] + return imp::remove_dir_all(path); + #[cfg(windows)] with_native_path(path, &imp::readdir) } From 0527ec1f01ea460ad87ddc03583823d562942b54 Mon Sep 17 00:00:00 2001 From: WrldEngine Date: Thu, 23 Oct 2025 21:37:33 +0500 Subject: [PATCH 3/8] chore: add windows cfg in read_dir, for use_native_path --- library/std/src/sys/fs/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index c58644b0f4f35..2ab38bcba5235 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -67,7 +67,7 @@ pub use imp::{ pub fn read_dir(path: &Path) -> io::Result { #[cfg(not(windows))] - return imp::remove_dir_all(path); + return imp::readdir(path); #[cfg(windows)] with_native_path(path, &imp::readdir) } From bdafbe25aa7b5e382c2b54d070092cfbad006a95 Mon Sep 17 00:00:00 2001 From: WrldEngine Date: Fri, 24 Oct 2025 20:03:55 +0500 Subject: [PATCH 4/8] edit: return FIXME comment --- library/std/src/sys/fs/mod.rs | 1 + library/std/src/sys/path/windows.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index 2ab38bcba5235..8e57d1cc94899 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -66,6 +66,7 @@ pub use imp::{ }; pub fn read_dir(path: &Path) -> io::Result { + // FIXME: use with_native_path on all platforms #[cfg(not(windows))] return imp::readdir(path); #[cfg(windows)] diff --git a/library/std/src/sys/path/windows.rs b/library/std/src/sys/path/windows.rs index 10bdea771c901..e9333d5aa7bc2 100644 --- a/library/std/src/sys/path/windows.rs +++ b/library/std/src/sys/path/windows.rs @@ -31,7 +31,7 @@ impl WCStr { } pub unsafe fn to_wchars_with_null_unchecked(&self) -> &[u16] { - unsafe { slice::from_raw_parts(self.as_ptr(), self.0.len()) } + unsafe { slice::from_raw_parts(self.0.as_ptr(), self.0.len()) } } pub fn as_ptr(&self) -> *const u16 { From b9aba0c81bcdb45ef2ede8e8d50d36918ea1e6f5 Mon Sep 17 00:00:00 2001 From: WrldEngine Date: Fri, 24 Oct 2025 21:15:43 +0500 Subject: [PATCH 5/8] chore: remove non-essential steps --- library/std/src/sys/fs/windows.rs | 2 +- library/std/src/sys/path/windows.rs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index 388ff791c86ba..9a8c23610aacb 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -1183,7 +1183,7 @@ impl DirBuilder { } pub fn readdir(p: &WCStr) -> io::Result { - let mut p = unsafe { p.to_wchars_with_null_unchecked() }.to_vec(); + let mut p = p.to_wchars_with_null_unchecked().to_vec(); // `p` already contains NUL, because before reading directory function, // it already passes `maybe_verbatim` that appending zero at the end, it diff --git a/library/std/src/sys/path/windows.rs b/library/std/src/sys/path/windows.rs index e9333d5aa7bc2..0b416f744935a 100644 --- a/library/std/src/sys/path/windows.rs +++ b/library/std/src/sys/path/windows.rs @@ -1,4 +1,3 @@ -use crate::alloc_crate::slice; use crate::ffi::{OsStr, OsString}; use crate::path::{Path, PathBuf}; use crate::sys::api::utf16; @@ -30,8 +29,8 @@ impl WCStr { unsafe { &*(s as *const [u16] as *const Self) } } - pub unsafe fn to_wchars_with_null_unchecked(&self) -> &[u16] { - unsafe { slice::from_raw_parts(self.0.as_ptr(), self.0.len()) } + pub const fn to_wchars_with_null_unchecked(&self) -> &[u16] { + &self.0 } pub fn as_ptr(&self) -> *const u16 { From 7f9747be786738831c316f2dafa81dd156948dbd Mon Sep 17 00:00:00 2001 From: WrldEngine Date: Fri, 24 Oct 2025 22:16:56 +0500 Subject: [PATCH 6/8] chore: remove non-essential steps --- library/std/src/sys/fs/windows.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index 9a8c23610aacb..90a39552db59e 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -1183,16 +1183,12 @@ impl DirBuilder { } pub fn readdir(p: &WCStr) -> io::Result { - let mut p = p.to_wchars_with_null_unchecked().to_vec(); + let p = p.to_wchars_with_null_unchecked().to_vec(); // `p` already contains NUL, because before reading directory function, // it already passes `maybe_verbatim` that appending zero at the end, it // should be refactored. - if let Some(pos) = p.iter().position(|x| *x == 0) { - p.remove(pos); - } - - let p_os_string = OsString::from_wide(&p); + let p_os_string = OsString::from_wide(&p[..p.len() - 1]); let p = Path::new(&p_os_string); // We push a `*` to the end of the path which cause the empty path to be From 8aab8458f37daa75469878d4e1347e6c7b8ad8e4 Mon Sep 17 00:00:00 2001 From: WrldEngine Date: Sat, 8 Nov 2025 23:19:29 +0500 Subject: [PATCH 7/8] chore: remove Path, replaced with WCStr main part --- library/std/src/sys/fs/windows.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index 90a39552db59e..4c1606de17a10 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -18,6 +18,7 @@ use crate::sys::time::SystemTime; use crate::sys::{Align8, c, cvt}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::{fmt, ptr, slice}; +use crate::os::windows::ffi::OsStringExt; mod remove_dir_all; use remove_dir_all::remove_dir_all_iterative; @@ -1183,25 +1184,24 @@ impl DirBuilder { } pub fn readdir(p: &WCStr) -> io::Result { - let p = p.to_wchars_with_null_unchecked().to_vec(); - - // `p` already contains NUL, because before reading directory function, - // it already passes `maybe_verbatim` that appending zero at the end, it - // should be refactored. - let p_os_string = OsString::from_wide(&p[..p.len() - 1]); - let p = Path::new(&p_os_string); + let p = p.to_wchars_with_null_unchecked(); + let mut p = p[..p.len() - 1].to_vec(); // We push a `*` to the end of the path which cause the empty path to be // treated as the current directory. So, for consistency with other platforms, // we explicitly error on the empty path. - if p_os_string.is_empty() { + if p.is_empty() { // Return an error code consistent with other ways of opening files. // E.g. fs::metadata or File::open. return Err(io::Error::from_raw_os_error(c::ERROR_PATH_NOT_FOUND as i32)); } - let root = p.to_path_buf(); - let star = p.join("*"); - let path = maybe_verbatim(&star)?; + + let root = PathBuf::from(OsString::from_wide(&p)); + + // Pushing `*` and NUL at the end + p.push(0x005C); + p.push(0x002A); + p.push(0); unsafe { let mut wfd: c::WIN32_FIND_DATAW = mem::zeroed(); @@ -1213,7 +1213,7 @@ pub fn readdir(p: &WCStr) -> io::Result { // We can pass FIND_FIRST_EX_LARGE_FETCH to dwAdditionalFlags to speed up things more, // but as we don't know user's use profile of this function, lets be conservative. let find_handle = c::FindFirstFileExW( - path.as_ptr(), + p.as_ptr(), c::FindExInfoBasic, &mut wfd as *mut _ as _, c::FindExSearchNameMatch, From bb270fe573f1b521087866ab2f67bdafa28fe15a Mon Sep 17 00:00:00 2001 From: WrldEngine Date: Sat, 8 Nov 2025 23:20:48 +0500 Subject: [PATCH 8/8] chore: remove Path, replaced with WCStr main part --- library/std/src/sys/fs/windows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index 4c1606de17a10..0a5defe620e76 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -6,6 +6,7 @@ use crate::ffi::{OsStr, OsString, c_void}; use crate::fs::TryLockError; use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom}; use crate::mem::{self, MaybeUninit, offset_of}; +use crate::os::windows::ffi::OsStringExt; use crate::os::windows::io::{AsHandle, BorrowedHandle}; use crate::os::windows::prelude::*; use crate::path::{Path, PathBuf}; @@ -18,7 +19,6 @@ use crate::sys::time::SystemTime; use crate::sys::{Align8, c, cvt}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::{fmt, ptr, slice}; -use crate::os::windows::ffi::OsStringExt; mod remove_dir_all; use remove_dir_all::remove_dir_all_iterative;