Skip to content

Commit 1548745

Browse files
committed
Add a cap-fs-ext way to get the full metadata for a DirEntry.
On Windows, `DirEntry::metadata` returns a `Metadata` value with the optional fields missing. This adds a `DirEntryExt` trait with a `full_metadata` function which computes the values of the missing fields.
1 parent e266770 commit 1548745

29 files changed

+369
-71
lines changed

build.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,20 @@ fn main() {
44
.channel
55
{
66
for feature in &[
7-
"can_vector", // https://github.com/rust-lang/rust/issues/69941
8-
"clamp", // https://github.com/rust-lang/rust/issues/44095
9-
"extend_one", // https://github.com/rust-lang/rust/issues/72631
10-
"open_options_ext_as_flags", // https://github.com/rust-lang/rust/issues/76801
11-
"pattern", // https://github.com/rust-lang/rust/issues/27721
12-
"read_initializer", // https://github.com/rust-lang/rust/issues/42788
13-
"seek_convenience", // https://github.com/rust-lang/rust/issues/59359
14-
"shrink_to", // https://github.com/rust-lang/rust/issues/56431
15-
"toowned_clone_into", // https://github.com/rust-lang/rust/issues/41263
16-
"try_reserve", // https://github.com/rust-lang/rust/issues/56431
17-
"unix_socket_peek", // https://github.com/rust-lang/rust/issues/76923
18-
"windows_by_handle", // https://github.com/rust-lang/rust/issues/63010
19-
"with_options", // https://github.com/rust-lang/rust/issues/65439
20-
"write_all_vectored", // https://github.com/rust-lang/rust/issues/70436
7+
"can_vector", // https://github.com/rust-lang/rust/issues/69941
8+
"clamp", // https://github.com/rust-lang/rust/issues/44095
9+
"extend_one", // https://github.com/rust-lang/rust/issues/72631
10+
"pattern", // https://github.com/rust-lang/rust/issues/27721
11+
"read_initializer", // https://github.com/rust-lang/rust/issues/42788
12+
"seek_convenience", // https://github.com/rust-lang/rust/issues/59359
13+
"seek_stream_len ", // https://github.com/rust-lang/rust/issues/59359
14+
"shrink_to", // https://github.com/rust-lang/rust/issues/56431
15+
"toowned_clone_into", // https://github.com/rust-lang/rust/issues/41263
16+
"try_reserve", // https://github.com/rust-lang/rust/issues/56431
17+
"unix_socket_peek", // https://github.com/rust-lang/rust/issues/76923
18+
"windows_by_handle", // https://github.com/rust-lang/rust/issues/63010
19+
"with_options", // https://github.com/rust-lang/rust/issues/65439
20+
"write_all_vectored", // https://github.com/rust-lang/rust/issues/70436
2121
// https://doc.rust-lang.org/unstable-book/library-features/windows-file-type-ext.html
2222
"windows_file_type_ext",
2323
] {

cap-async-std/src/fs/dir.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ impl Dir {
296296
pub async fn read<P: AsRef<Path>>(&self, path: P) -> io::Result<Vec<u8>> {
297297
use async_std::prelude::*;
298298
let mut file = self.open(path)?;
299-
let mut bytes = Vec::with_capacity(initial_buffer_size(&file).await);
299+
let mut bytes = Vec::with_capacity(initial_buffer_size(&file));
300300
file.read_to_end(&mut bytes).await?;
301301
Ok(bytes)
302302
}
@@ -690,14 +690,11 @@ impl IntoRawHandle for Dir {
690690
///
691691
/// Derived from the function of the same name in Rust's library/std/src/fs.rs
692692
/// at revision 108e90ca78f052c0c1c49c42a22c85620be19712.
693-
async fn initial_buffer_size(file: &File) -> usize {
693+
fn initial_buffer_size(file: &File) -> usize {
694694
// Allocate one extra byte so the buffer doesn't need to grow before the
695695
// final `read` call at the end of the file. Don't worry about `usize`
696696
// overflow because reading will fail regardless in that case.
697-
file.metadata()
698-
.await
699-
.map(|m| m.len() as usize + 1)
700-
.unwrap_or(0)
697+
file.metadata().map(|m| m.len() as usize + 1).unwrap_or(0)
701698
}
702699

703700
impl fmt::Debug for Dir {

cap-async-std/src/fs/dir_entry.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ impl DirEntry {
6767
///
6868
/// [`async_std::fs::DirEntry::metadata`]: https://docs.rs/async-std/latest/async_std/fs/struct.DirEntry.html#method.metadata
6969
#[inline]
70-
pub async fn metadata(&self) -> io::Result<Metadata> {
71-
// TODO: Make this actually async.
70+
pub fn metadata(&self) -> io::Result<Metadata> {
71+
// TODO: Make this async.
7272
self.inner.metadata()
7373
}
7474

@@ -102,6 +102,15 @@ impl DirEntryExt for DirEntry {
102102
}
103103
}
104104

105+
#[cfg(windows)]
106+
#[doc(hidden)]
107+
unsafe impl cap_primitives::fs::_WindowsDirEntryExt for DirEntry {
108+
#[inline]
109+
unsafe fn full_metadata(&self) -> io::Result<Metadata> {
110+
self.inner.full_metadata()
111+
}
112+
}
113+
105114
impl fmt::Debug for DirEntry {
106115
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107116
self.inner.fmt(f)

cap-async-std/src/fs/file.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,9 @@ impl File {
8888
///
8989
/// [`async_std::fs::File::metadata`]: https://docs.rs/async-std/latest/async_std/fs/struct.File.html#method.metadata
9090
#[inline]
91-
pub async fn metadata(&self) -> io::Result<Metadata> {
92-
self.std.metadata().await.map(metadata_from_std)
91+
pub fn metadata(&self) -> io::Result<Metadata> {
92+
let sync = self.std.as_file_view();
93+
metadata_from(&*sync)
9394
}
9495

9596
// async_std doesn't have `try_clone`.
@@ -110,14 +111,14 @@ impl File {
110111

111112
#[cfg(not(target_os = "wasi"))]
112113
#[inline]
113-
fn metadata_from_std(metadata: fs::Metadata) -> Metadata {
114-
Metadata::from_just_metadata(metadata)
114+
fn metadata_from(file: &std::fs::File) -> io::Result<Metadata> {
115+
Metadata::from_file(file)
115116
}
116117

117118
#[cfg(target_os = "wasi")]
118119
#[inline]
119-
fn metadata_from_std(metadata: fs::Metadata) -> Metadata {
120-
metadata
120+
fn metadata_from(file: &std::fs::File) -> io::Result<Metadata> {
121+
file.metadata()
121122
}
122123

123124
#[cfg(not(target_os = "wasi"))]

cap-async-std/src/fs_utf8/dir_entry.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ impl DirEntry {
7272
///
7373
/// [`async_std::fs::DirEntry::metadata`]: https://docs.rs/async-std/latest/async_std/fs/struct.DirEntry.html#method.metadata
7474
#[inline]
75-
pub async fn metadata(&self) -> io::Result<Metadata> {
76-
self.cap_std.metadata().await
75+
pub fn metadata(&self) -> io::Result<Metadata> {
76+
self.cap_std.metadata()
7777
}
7878

7979
/// Returns the file type for the file that this entry points at.
@@ -106,6 +106,15 @@ impl DirEntryExt for DirEntry {
106106
}
107107
}
108108

109+
#[cfg(windows)]
110+
#[doc(hidden)]
111+
unsafe impl cap_primitives::fs::_WindowsDirEntryExt for DirEntry {
112+
#[inline]
113+
unsafe fn full_metadata(&self) -> io::Result<Metadata> {
114+
self.cap_std.full_metadata()
115+
}
116+
}
117+
109118
impl fmt::Debug for DirEntry {
110119
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111120
self.cap_std.fmt(f)

cap-async-std/src/fs_utf8/file.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ impl File {
9292
///
9393
/// [`async_std::fs::File::metadata`]: https://docs.rs/async-std/latest/async_std/fs/struct.File.html#method.metadata
9494
#[inline]
95-
pub async fn metadata(&self) -> io::Result<Metadata> {
96-
self.cap_std.metadata().await
95+
pub fn metadata(&self) -> io::Result<Metadata> {
96+
self.cap_std.metadata()
9797
}
9898

9999
// async_std doesn't have `try_clone`.

cap-fs-ext/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ repository = "https://github.com/bytecodealliance/cap-std"
1313
edition = "2018"
1414
readme = "README.md"
1515

16+
[build-dependencies]
17+
rustc_version = "0.3.0"
18+
1619
[dependencies]
1720
arf-strings = { version = "0.3.0", optional = true }
1821
async-std = { version = "1.8.0", optional = true }

cap-fs-ext/build.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
fn main() {
2+
if let rustc_version::Channel::Nightly = rustc_version::version_meta()
3+
.expect("query rustc release channel")
4+
.channel
5+
{
6+
for feature in &[
7+
"can_vector", // https://github.com/rust-lang/rust/issues/69941
8+
"clamp", // https://github.com/rust-lang/rust/issues/44095
9+
"extend_one", // https://github.com/rust-lang/rust/issues/72631
10+
"pattern", // https://github.com/rust-lang/rust/issues/27721
11+
"read_initializer", // https://github.com/rust-lang/rust/issues/42788
12+
"seek_convenience", // https://github.com/rust-lang/rust/issues/59359
13+
"seek_stream_len ", // https://github.com/rust-lang/rust/issues/59359
14+
"shrink_to", // https://github.com/rust-lang/rust/issues/56431
15+
"toowned_clone_into", // https://github.com/rust-lang/rust/issues/41263
16+
"try_reserve", // https://github.com/rust-lang/rust/issues/56431
17+
"unix_socket_peek", // https://github.com/rust-lang/rust/issues/76923
18+
"windows_by_handle", // https://github.com/rust-lang/rust/issues/63010
19+
"with_options", // https://github.com/rust-lang/rust/issues/65439
20+
"write_all_vectored", // https://github.com/rust-lang/rust/issues/70436
21+
// https://doc.rust-lang.org/unstable-book/library-features/windows-file-type-ext.html
22+
"windows_file_type_ext",
23+
] {
24+
println!("cargo:rustc-cfg={}", feature);
25+
}
26+
}
27+
28+
// Don't rerun this on changes other than build.rs, as we only depend on
29+
// the rustc version.
30+
println!("cargo:rerun-if-changed=build.rs");
31+
}

cap-fs-ext/src/dir_entry_ext.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
use cap_primitives::fs::Metadata;
2+
#[cfg(windows)]
3+
use cap_primitives::fs::_WindowsDirEntryExt;
4+
use std::io;
5+
6+
/// Extension trait for `DirEntry`.
7+
pub trait DirEntryExt {
8+
/// Return the full metadata, which on Windows includes the optional
9+
/// values.
10+
fn full_metadata(&self) -> io::Result<Metadata>;
11+
}
12+
13+
#[cfg(not(windows))]
14+
impl DirEntryExt for std::fs::DirEntry {
15+
#[inline]
16+
fn full_metadata(&self) -> io::Result<Metadata> {
17+
self.metadata().map(Metadata::from_just_metadata)
18+
}
19+
}
20+
21+
#[cfg(all(not(windows), feature = "std"))]
22+
impl DirEntryExt for cap_std::fs::DirEntry {
23+
#[inline]
24+
fn full_metadata(&self) -> io::Result<Metadata> {
25+
self.metadata()
26+
}
27+
}
28+
29+
#[cfg(all(windows, feature = "std"))]
30+
impl DirEntryExt for cap_std::fs::DirEntry {
31+
#[inline]
32+
fn full_metadata(&self) -> io::Result<Metadata> {
33+
unsafe { _WindowsDirEntryExt::full_metadata(self) }
34+
}
35+
}
36+
37+
#[cfg(all(not(windows), feature = "async_std"))]
38+
impl DirEntryExt for cap_async_std::fs::DirEntry {
39+
#[inline]
40+
fn full_metadata(&self) -> io::Result<Metadata> {
41+
self.metadata()
42+
}
43+
}
44+
45+
#[cfg(all(windows, feature = "async_std"))]
46+
impl DirEntryExt for cap_async_std::fs::DirEntry {
47+
#[inline]
48+
fn full_metadata(&self) -> io::Result<Metadata> {
49+
unsafe { _WindowsDirEntryExt::full_metadata(self) }
50+
}
51+
}
52+
53+
#[cfg(all(not(windows), feature = "std", feature = "fs_utf8"))]
54+
impl DirEntryExt for cap_std::fs_utf8::DirEntry {
55+
#[inline]
56+
fn full_metadata(&self) -> io::Result<Metadata> {
57+
self.metadata()
58+
}
59+
}
60+
61+
#[cfg(all(windows, feature = "std", feature = "fs_utf8"))]
62+
impl DirEntryExt for cap_std::fs_utf8::DirEntry {
63+
#[inline]
64+
fn full_metadata(&self) -> io::Result<Metadata> {
65+
unsafe { _WindowsDirEntryExt::full_metadata(self) }
66+
}
67+
}
68+
69+
#[cfg(all(not(windows), feature = "async_std", feature = "fs_utf8"))]
70+
impl DirEntryExt for cap_async_std::fs_utf8::DirEntry {
71+
#[inline]
72+
fn full_metadata(&self) -> io::Result<Metadata> {
73+
self.metadata()
74+
}
75+
}
76+
77+
#[cfg(all(windows, feature = "async_std", feature = "fs_utf8"))]
78+
impl DirEntryExt for cap_async_std::fs_utf8::DirEntry {
79+
#[inline]
80+
fn full_metadata(&self) -> io::Result<Metadata> {
81+
unsafe { _WindowsDirEntryExt::full_metadata(self) }
82+
}
83+
}

cap-fs-ext/src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
html_favicon_url = "https://raw.githubusercontent.com/bytecodealliance/cap-std/main/media/cap-std.ico"
1010
)]
1111

12+
mod dir_entry_ext;
1213
mod dir_ext;
1314
mod file_type_ext;
1415
mod is_file_read_write;
@@ -17,6 +18,7 @@ mod open_options_follow_ext;
1718
mod open_options_maybe_dir_ext;
1819
mod reopen;
1920

21+
pub use dir_entry_ext::DirEntryExt;
2022
#[cfg(all(any(feature = "std", feature = "async_std"), feature = "fs_utf8"))]
2123
pub use dir_ext::DirExtUtf8;
2224
pub use dir_ext::{DirExt, SystemTimeSpec};
@@ -27,5 +29,5 @@ pub use open_options_follow_ext::OpenOptionsFollowExt;
2729
pub use open_options_maybe_dir_ext::OpenOptionsMaybeDirExt;
2830
pub use reopen::Reopen;
2931

30-
/// Re-export this to allow it to be used with `Reuse`.
31-
pub use cap_primitives::fs::{FollowSymlinks, OpenOptions};
32+
/// Re-export these to allow them to be used with `Reuse`.
33+
pub use cap_primitives::fs::{FollowSymlinks, Metadata, OpenOptions};

0 commit comments

Comments
 (0)