Repository: denoland/deno
Pull request: perf(fs/windows): stat - only open file once

Even debug is way faster:

```
> cat main.cts
for (let i = 0; i < 100_000; i++) {
  Deno.statSync("b.txt");
}
> Measure-Command { deno run -A main.cts } | Select-Object -Property TotalMilliseconds    
          2684.68
> Measure-Command { ../deno/target/debug/deno run -A main.cts } | Select-Object -Property TotalMilliseconds
           988.55
```

Changed files:
filename: ext/fs/std_fs.rs
patch: @@ -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
     };
@@ -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)
 }
 
@@ -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,
@@ -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(
@@ -928,7 +909,6 @@ fn stat_extra(
       }
     }
 
-    CloseHandle(file_handle);
     Ok(())
   }
 }