From ec5d8016f7c657dee1c1cc1e2715783e74709461 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 7 May 2021 06:52:54 -0700 Subject: [PATCH] On Windows, ignore files for which `full_metadata` fails. On Windows, `metadata` computes only partial metadata results, which don't include what WASI needs for the `inode` field in `readdir` results. cap-std has a `full_metadata` function which is able to include this extra information, however it has more strict access requirements, so it sometimes fails even when plain `metadata` would succeed. Make WASI's `readdir` silently skip over files that can't be accessed by `full_metadata`. These files wouldn't be openable in any other way by WASI programs, so the only benefit of listing them would be to let applications know that they exist. This allows it to avoid failing and avoid returning bogus results. This is part of a fix for bytecodealliance/cap-std#169. --- crates/wasi-common/cap-std-sync/src/dir.rs | 27 ++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/crates/wasi-common/cap-std-sync/src/dir.rs b/crates/wasi-common/cap-std-sync/src/dir.rs index 2552787900..91126f8638 100644 --- a/crates/wasi-common/cap-std-sync/src/dir.rs +++ b/crates/wasi-common/cap-std-sync/src/dir.rs @@ -116,9 +116,9 @@ impl WasiDir for Dir { }, ] .into_iter() - .chain( + .chain({ // Now process the `DirEntry`s: - self.0.entries()?.map(|entry| { + let entries = self.0.entries()?.map(|entry| { let entry = entry?; let meta = entry.full_metadata()?; let inode = meta.ino(); @@ -128,8 +128,27 @@ impl WasiDir for Dir { .into_string() .map_err(|_| Error::illegal_byte_sequence().context("filename"))?; Ok((filetype, inode, name)) - }), - ) + }); + + // On Windows, filter out files like `C:\DumpStack.log.tmp` which we + // can't get a full metadata for. + #[cfg(windows)] + let entries = entries.filter(|entry: &Result<_, wasi_common::Error>| { + use winapi::shared::winerror::{ERROR_ACCESS_DENIED, ERROR_SHARING_VIOLATION}; + if let Err(err) = entry { + if let Some(err) = err.downcast_ref::() { + if err.raw_os_error() == Some(ERROR_SHARING_VIOLATION as i32) + || err.raw_os_error() == Some(ERROR_ACCESS_DENIED as i32) + { + return false; + } + } + } + true + }); + + entries + }) // Enumeration of the iterator makes it possible to define the ReaddirCursor .enumerate() .map(|(ix, r)| match r {