Skip to content

Commit 9e81462

Browse files
authored
Rollup merge of #120373 - HTGAzureX1212:HTGAzureX1212/issue-120040, r=ChrisDenton
Adjust Behaviour of `read_dir` and `ReadDir` in Windows Implementation: Check Whether Path to Search In Exists This pull request changes the `read_dir` function's and the `ReadDir` structure's internal implementations for the Windows operating system to make its behaviour more accurate. It should be noted that `ERROR_FILE_NOT_FOUND` is returned by the `FindFirstFileW` function when *no matching files can be found*, not necessarily that the path to search in does not exist in the first place. Therefore, directly returning the "The system cannot find the file specified." may not be accurate. An extra check for whether the path to search in exists is added, returning a constructed `ReadDir` iterator with its handle being an `INVALID_HANDLE_VALUE` returned by the `FindFirstFileW` function if `ERROR_FILE_NOT_FOUND` is indeed the last OS error. The `ReadDir` implementation for the Windows operating system is correspondingly updated to always return `None` if the handle it has is an `INVALID_HANDLE_VALUE` which can only be the case if and only if specifically constructed by the `read_dir` function in the aforementioned conditions. It should also be noted that `FindFirstFileW` would have returned `ERROR_PATH_NOT_FOUND` if the path to search in does not exist in the first place. Presumably fixes #120040.
2 parents 0315389 + 018bf30 commit 9e81462

File tree

1 file changed

+33
-1
lines changed
  • library/std/src/sys/pal/windows

1 file changed

+33
-1
lines changed

library/std/src/sys/pal/windows/fs.rs

+33-1
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,13 @@ impl fmt::Debug for ReadDir {
112112
impl Iterator for ReadDir {
113113
type Item = io::Result<DirEntry>;
114114
fn next(&mut self) -> Option<io::Result<DirEntry>> {
115+
if self.handle.0 == c::INVALID_HANDLE_VALUE {
116+
// This iterator was initialized with an `INVALID_HANDLE_VALUE` as its handle.
117+
// Simply return `None` because this is only the case when `FindFirstFileW` in
118+
// the construction of this iterator returns `ERROR_FILE_NOT_FOUND` which means
119+
// no matchhing files can be found.
120+
return None;
121+
}
115122
if let Some(first) = self.first.take() {
116123
if let Some(e) = DirEntry::new(&self.root, &first) {
117124
return Some(Ok(e));
@@ -1068,14 +1075,39 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
10681075
unsafe {
10691076
let mut wfd = mem::zeroed();
10701077
let find_handle = c::FindFirstFileW(path.as_ptr(), &mut wfd);
1078+
10711079
if find_handle != c::INVALID_HANDLE_VALUE {
10721080
Ok(ReadDir {
10731081
handle: FindNextFileHandle(find_handle),
10741082
root: Arc::new(root),
10751083
first: Some(wfd),
10761084
})
10771085
} else {
1078-
Err(Error::last_os_error())
1086+
// The status `ERROR_FILE_NOT_FOUND` is returned by the `FindFirstFileW` function
1087+
// if no matching files can be found, but not necessarily that the path to find the
1088+
// files in does not exist.
1089+
//
1090+
// Hence, a check for whether the path to search in exists is added when the last
1091+
// os error returned by Windows is `ERROR_FILE_NOT_FOUND` to handle this scenario.
1092+
// If that is the case, an empty `ReadDir` iterator is returned as it returns `None`
1093+
// in the initial `.next()` invocation because `ERROR_NO_MORE_FILES` would have been
1094+
// returned by the `FindNextFileW` function.
1095+
//
1096+
// See issue #120040: https://github.com/rust-lang/rust/issues/120040.
1097+
let last_error = api::get_last_error();
1098+
if last_error.code == c::ERROR_FILE_NOT_FOUND {
1099+
return Ok(ReadDir {
1100+
handle: FindNextFileHandle(find_handle),
1101+
root: Arc::new(root),
1102+
first: None,
1103+
});
1104+
}
1105+
1106+
// Just return the error constructed from the raw OS error if the above is not the case.
1107+
//
1108+
// Note: `ERROR_PATH_NOT_FOUND` would have been returned by the `FindFirstFileW` function
1109+
// when the path to search in does not exist in the first place.
1110+
Err(Error::from_raw_os_error(last_error.code as i32))
10791111
}
10801112
}
10811113
}

0 commit comments

Comments
 (0)