Skip to content

Commit

Permalink
Rollup merge of rust-lang#120373 - HTGAzureX1212:HTGAzureX1212/issue-…
Browse files Browse the repository at this point in the history
…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 rust-lang#120040.
  • Loading branch information
matthiaskrgr authored Jan 27, 2024
2 parents 68b39be + 018bf30 commit 34f0710
Showing 1 changed file with 33 additions and 1 deletion.
34 changes: 33 additions & 1 deletion library/std/src/sys/pal/windows/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ impl fmt::Debug for ReadDir {
impl Iterator for ReadDir {
type Item = io::Result<DirEntry>;
fn next(&mut self) -> Option<io::Result<DirEntry>> {
if self.handle.0 == c::INVALID_HANDLE_VALUE {
// This iterator was initialized with an `INVALID_HANDLE_VALUE` as its handle.
// Simply return `None` because this is only the case when `FindFirstFileW` in
// the construction of this iterator returns `ERROR_FILE_NOT_FOUND` which means
// no matchhing files can be found.
return None;
}
if let Some(first) = self.first.take() {
if let Some(e) = DirEntry::new(&self.root, &first) {
return Some(Ok(e));
Expand Down Expand Up @@ -1068,14 +1075,39 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
unsafe {
let mut wfd = mem::zeroed();
let find_handle = c::FindFirstFileW(path.as_ptr(), &mut wfd);

if find_handle != c::INVALID_HANDLE_VALUE {
Ok(ReadDir {
handle: FindNextFileHandle(find_handle),
root: Arc::new(root),
first: Some(wfd),
})
} else {
Err(Error::last_os_error())
// The status `ERROR_FILE_NOT_FOUND` is returned by the `FindFirstFileW` function
// if no matching files can be found, but not necessarily that the path to find the
// files in does not exist.
//
// Hence, a check for whether the path to search in exists is added when the last
// os error returned by Windows is `ERROR_FILE_NOT_FOUND` to handle this scenario.
// If that is the case, an empty `ReadDir` iterator is returned as it returns `None`
// in the initial `.next()` invocation because `ERROR_NO_MORE_FILES` would have been
// returned by the `FindNextFileW` function.
//
// See issue #120040: https://github.com/rust-lang/rust/issues/120040.
let last_error = api::get_last_error();
if last_error.code == c::ERROR_FILE_NOT_FOUND {
return Ok(ReadDir {
handle: FindNextFileHandle(find_handle),
root: Arc::new(root),
first: None,
});
}

// Just return the error constructed from the raw OS error if the above is not the case.
//
// Note: `ERROR_PATH_NOT_FOUND` would have been returned by the `FindFirstFileW` function
// when the path to search in does not exist in the first place.
Err(Error::from_raw_os_error(last_error.code as i32))
}
}
}
Expand Down

0 comments on commit 34f0710

Please sign in to comment.