Skip to content

Commit

Permalink
perf(fs/windows): stat - only open file once (#27487)
Browse files Browse the repository at this point in the history
  • Loading branch information
dsherret authored Dec 31, 2024
1 parent 4638caa commit 88bd5f0
Showing 1 changed file with 22 additions and 42 deletions.
64 changes: 22 additions & 42 deletions ext/fs/std_fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl FileSystem for RealFs {
umask(Mode::from_bits_truncate(mask as mode_t))
} else {
// If no mask provided, we query the current. Requires two syscalls.
let prev = umask(Mode::from_bits_truncate(0o777));
let prev = umask(Mode::from_bits_truncate(0));
let _ = umask(prev);
prev
};
Expand Down Expand Up @@ -761,11 +761,16 @@ fn stat(path: &Path) -> FsResult<FsStat> {

#[cfg(windows)]
fn stat(path: &Path) -> FsResult<FsStat> {
let metadata = fs::metadata(path)?;
let mut fsstat = FsStat::from_std(metadata);
use std::os::windows::fs::OpenOptionsExt;
use winapi::um::winbase::FILE_FLAG_BACKUP_SEMANTICS;
let path = path.canonicalize()?;
stat_extra(&mut fsstat, &path, FILE_FLAG_BACKUP_SEMANTICS)?;

let mut opts = fs::OpenOptions::new();
opts.access_mode(0); // no read or write
opts.custom_flags(FILE_FLAG_BACKUP_SEMANTICS);
let file = opts.open(path)?;
let metadata = file.metadata()?;
let mut fsstat = FsStat::from_std(metadata);
stat_extra(&file, &mut fsstat)?;
Ok(fsstat)
}

Expand All @@ -777,34 +782,24 @@ fn lstat(path: &Path) -> FsResult<FsStat> {

#[cfg(windows)]
fn lstat(path: &Path) -> FsResult<FsStat> {
use std::os::windows::fs::OpenOptionsExt;

use winapi::um::winbase::FILE_FLAG_BACKUP_SEMANTICS;
use winapi::um::winbase::FILE_FLAG_OPEN_REPARSE_POINT;

let metadata = fs::symlink_metadata(path)?;
let mut opts = fs::OpenOptions::new();
opts.access_mode(0); // no read or write
opts.custom_flags(FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT);
let file = opts.open(path)?;
let metadata = file.metadata()?;
let mut fsstat = FsStat::from_std(metadata);
stat_extra(
&mut fsstat,
path,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
)?;
stat_extra(&file, &mut fsstat)?;
Ok(fsstat)
}

#[cfg(windows)]
fn stat_extra(
fsstat: &mut FsStat,
path: &Path,
file_flags: winapi::shared::minwindef::DWORD,
) -> FsResult<()> {
use std::os::windows::prelude::OsStrExt;

use winapi::um::fileapi::CreateFileW;
use winapi::um::fileapi::OPEN_EXISTING;
use winapi::um::handleapi::CloseHandle;
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::winnt::FILE_SHARE_DELETE;
use winapi::um::winnt::FILE_SHARE_READ;
use winapi::um::winnt::FILE_SHARE_WRITE;
fn stat_extra(file: &std::fs::File, fsstat: &mut FsStat) -> FsResult<()> {
use std::os::windows::io::AsRawHandle;

unsafe fn get_dev(
handle: winapi::shared::ntdef::HANDLE,
Expand Down Expand Up @@ -873,23 +868,9 @@ fn stat_extra(

// SAFETY: winapi calls
unsafe {
let mut path: Vec<_> = path.as_os_str().encode_wide().collect();
path.push(0);
let file_handle = CreateFileW(
path.as_ptr(),
0,
FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE,
std::ptr::null_mut(),
OPEN_EXISTING,
file_flags,
std::ptr::null_mut(),
);
if file_handle == INVALID_HANDLE_VALUE {
return Err(std::io::Error::last_os_error().into());
}
let file_handle = file.as_raw_handle();

let result = get_dev(file_handle);
fsstat.dev = result?;
fsstat.dev = get_dev(file_handle)?;

if let Ok(file_info) = query_file_information(file_handle) {
fsstat.ctime = Some(windows_time_to_unix_time_msec(
Expand Down Expand Up @@ -928,7 +909,6 @@ fn stat_extra(
}
}

CloseHandle(file_handle);
Ok(())
}
}
Expand Down

0 comments on commit 88bd5f0

Please sign in to comment.