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.
This commit is contained in:
Dan Gohman
2021-05-07 06:52:54 -07:00
parent 002b0744eb
commit ec5d8016f7

View File

@@ -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::<std::io::Error>() {
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 {