diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index 74354227d84a6..8e57d1cc94899 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -67,7 +67,10 @@ pub use imp::{ pub fn read_dir(path: &Path) -> io::Result { // FIXME: use with_native_path on all platforms - imp::readdir(path) + #[cfg(not(windows))] + return imp::readdir(path); + #[cfg(windows)] + 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..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}; @@ -1182,18 +1183,25 @@ impl DirBuilder { } } -pub fn readdir(p: &Path) -> io::Result { +pub fn readdir(p: &WCStr) -> io::Result { + 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.as_os_str().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(); @@ -1205,7 +1213,7 @@ pub fn readdir(p: &Path) -> 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, diff --git a/library/std/src/sys/path/windows.rs b/library/std/src/sys/path/windows.rs index f124e1e5a71c7..0b416f744935a 100644 --- a/library/std/src/sys/path/windows.rs +++ b/library/std/src/sys/path/windows.rs @@ -29,6 +29,10 @@ impl WCStr { unsafe { &*(s as *const [u16] as *const Self) } } + pub const fn to_wchars_with_null_unchecked(&self) -> &[u16] { + &self.0 + } + pub fn as_ptr(&self) -> *const u16 { self.0.as_ptr() }