about summary refs log tree commit diff
path: root/library/std/src/sys
diff options
context:
space:
mode:
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>2024-01-29 12:56:52 +0000
committerGitHub <noreply@github.com>2024-01-29 12:56:52 +0000
commitd04bede047171967736d6237299e3aee8374b858 (patch)
treece588759e579ead1086d1530c8d30201c2584185 /library/std/src/sys
parent4528b371963276ed32dd261da04b6c714e6768f6 (diff)
parent018bf305cdcc2d478998642bc2d9a5613ec902f3 (diff)
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.
Diffstat (limited to 'library/std/src/sys')
-rw-r--r--library/std/src/sys/pal/windows/fs.rs34
1 files changed, 33 insertions, 1 deletions
diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs
index 42484543686..2bdd3d96fa4 100644
--- a/library/std/src/sys/pal/windows/fs.rs
+++ b/library/std/src/sys/pal/windows/fs.rs
@@ -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));
@@ -1068,6 +1075,7 @@ 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),
@@ -1075,7 +1083,31 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
                 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))
         }
     }
 }