Skip to content

Commit 684a62f

Browse files
authored
Use the NtCreateFile path for implementing stat on Windows. (#295)
Always use `open_unchecked` with no access for implementing `stat` on Windows, as that now uses the new `NtCreateFile` path.
1 parent 808667d commit 684a62f

File tree

3 files changed

+30
-35
lines changed

3 files changed

+30
-35
lines changed

cap-primitives/src/windows/fs/create_file_at_w.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ const FILE_ATTRIBUTE_VALID_FLAGS: FILE_FLAGS_AND_ATTRIBUTES = FILE_ATTRIBUTE_EA
6666

6767
/// Like Windows' `CreateFileW`, but takes a `dir` argument to use as the
6868
/// root directory.
69+
///
70+
/// Also, the `lpfilename` is a Rust slice instead of a C-style NUL-terminated
71+
/// array, because that's what our callers have and it's closer to what
72+
/// `NtCreatePath` takes.
6973
#[allow(non_snake_case)]
7074
pub unsafe fn CreateFileAtW(
7175
dir: HANDLE,

cap-primitives/src/windows/fs/open_unchecked.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,10 @@ fn open_at(start: &fs::File, path: &Path, opts: &OpenOptions) -> io::Result<fs::
9595
// own `CreateFileAtW` so that it does the requisite magic for absolute
9696
// paths.
9797
if dir == 0 {
98+
// We're calling the windows-sys `CreateFileW` which expects a
99+
// NUL-terminated filename, so add a NUL terminator.
98100
wide.push(0);
101+
99102
let handle = unsafe {
100103
CreateFileW(
101104
wide.as_ptr(),
@@ -113,6 +116,9 @@ fn open_at(start: &fs::File, path: &Path, opts: &OpenOptions) -> io::Result<fs::
113116
Err(io::Error::last_os_error())
114117
}
115118
} else {
119+
// Our own `CreateFileAtW` is similar to `CreateFileW` except it
120+
// takes the filename as a Rust slice directly, so we can skip
121+
// the NUL terminator.
116122
let handle = unsafe {
117123
CreateFileAtW(
118124
dir,
Lines changed: 20 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
1-
#[cfg(windows_by_handle)]
2-
use super::get_path::concatenate;
31
use crate::fs::{FollowSymlinks, Metadata};
42
use std::path::Path;
53
use std::{fs, io};
6-
#[cfg(not(windows_by_handle))]
7-
use windows_sys::Win32::Storage::FileSystem::{
8-
FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT,
9-
};
10-
#[cfg(not(windows_by_handle))]
114
use {
125
crate::fs::{open_unchecked, OpenOptions},
136
std::os::windows::fs::OpenOptionsExt,
7+
windows_sys::Win32::Storage::FileSystem::{
8+
FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT,
9+
},
1410
};
1511

1612
/// *Unsandboxed* function similar to `stat`, but which does not perform
@@ -20,35 +16,24 @@ pub(crate) fn stat_unchecked(
2016
path: &Path,
2117
follow: FollowSymlinks,
2218
) -> io::Result<Metadata> {
23-
// When we have `windows_by_handle`, we just call `fs::metadata` etc. and it
24-
// has everything.
25-
#[cfg(windows_by_handle)]
26-
{
27-
let full_path = concatenate(start, path)?;
28-
match follow {
29-
FollowSymlinks::Yes => fs::metadata(full_path),
30-
FollowSymlinks::No => fs::symlink_metadata(full_path),
31-
}
32-
.map(Metadata::from_just_metadata)
33-
}
19+
// Attempt to open the file to get the metadata that way, as that gives
20+
// us all the info.
21+
let mut opts = OpenOptions::new();
3422

35-
// Otherwise, attempt to open the file to get the metadata that way, as
36-
// that gives us all the info.
37-
#[cfg(not(windows_by_handle))]
38-
{
39-
let mut opts = OpenOptions::new();
40-
opts.access_mode(0);
41-
match follow {
42-
FollowSymlinks::Yes => {
43-
opts.custom_flags(FILE_FLAG_BACKUP_SEMANTICS);
44-
opts.follow(FollowSymlinks::Yes);
45-
}
46-
FollowSymlinks::No => {
47-
opts.custom_flags(FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS);
48-
opts.follow(FollowSymlinks::No);
49-
}
23+
// Explicitly request no access, because we're just querying metadata.
24+
opts.access_mode(0);
25+
26+
match follow {
27+
FollowSymlinks::Yes => {
28+
opts.custom_flags(FILE_FLAG_BACKUP_SEMANTICS);
29+
opts.follow(FollowSymlinks::Yes);
30+
}
31+
FollowSymlinks::No => {
32+
opts.custom_flags(FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS);
33+
opts.follow(FollowSymlinks::No);
5034
}
51-
let file = open_unchecked(start, path, &opts)?;
52-
Metadata::from_file(&file)
5335
}
36+
37+
let file = open_unchecked(start, path, &opts)?;
38+
Metadata::from_file(&file)
5439
}

0 commit comments

Comments
 (0)