summaryrefslogtreecommitdiff
path: root/ext/fs/std_fs.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ext/fs/std_fs.rs')
-rw-r--r--ext/fs/std_fs.rs36
1 files changed, 31 insertions, 5 deletions
diff --git a/ext/fs/std_fs.rs b/ext/fs/std_fs.rs
index 41a8569ba..73439d9ba 100644
--- a/ext/fs/std_fs.rs
+++ b/ext/fs/std_fs.rs
@@ -821,24 +821,46 @@ fn stat_extra(
Ok(info.dwVolumeSerialNumber as u64)
}
+ const WINDOWS_TICK: i64 = 10_000; // 100-nanosecond intervals in a millisecond
+ const SEC_TO_UNIX_EPOCH: i64 = 11_644_473_600; // Seconds between Windows epoch and Unix epoch
+
+ fn windows_time_to_unix_time_msec(windows_time: &i64) -> i64 {
+ let milliseconds_since_windows_epoch = windows_time / WINDOWS_TICK;
+ milliseconds_since_windows_epoch - SEC_TO_UNIX_EPOCH * 1000
+ }
+
use windows_sys::Wdk::Storage::FileSystem::FILE_ALL_INFORMATION;
+ use windows_sys::Win32::Foundation::NTSTATUS;
unsafe fn query_file_information(
handle: winapi::shared::ntdef::HANDLE,
- ) -> std::io::Result<FILE_ALL_INFORMATION> {
+ ) -> Result<FILE_ALL_INFORMATION, NTSTATUS> {
use windows_sys::Wdk::Storage::FileSystem::NtQueryInformationFile;
+ use windows_sys::Win32::Foundation::RtlNtStatusToDosError;
+ use windows_sys::Win32::Foundation::ERROR_MORE_DATA;
+ use windows_sys::Win32::System::IO::IO_STATUS_BLOCK;
let mut info = std::mem::MaybeUninit::<FILE_ALL_INFORMATION>::zeroed();
+ let mut io_status_block =
+ std::mem::MaybeUninit::<IO_STATUS_BLOCK>::zeroed();
let status = NtQueryInformationFile(
handle as _,
- std::ptr::null_mut(),
+ io_status_block.as_mut_ptr(),
info.as_mut_ptr() as *mut _,
std::mem::size_of::<FILE_ALL_INFORMATION>() as _,
18, /* FileAllInformation */
);
if status < 0 {
- return Err(std::io::Error::last_os_error());
+ let converted_status = RtlNtStatusToDosError(status);
+
+ // If error more data is returned, then it means that the buffer is too small to get full filename information
+ // to have that we should retry. However, since we only use BasicInformation and StandardInformation, it is fine to ignore it
+ // since struct is populated with other data anyway.
+ // https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntqueryinformationfile#remarksdd
+ if converted_status != ERROR_MORE_DATA {
+ return Err(converted_status as NTSTATUS);
+ }
}
Ok(info.assume_init())
@@ -862,10 +884,13 @@ fn stat_extra(
}
let result = get_dev(file_handle);
- CloseHandle(file_handle);
fsstat.dev = result?;
if let Ok(file_info) = query_file_information(file_handle) {
+ fsstat.ctime = Some(windows_time_to_unix_time_msec(
+ &file_info.BasicInformation.ChangeTime,
+ ) as u64);
+
if file_info.BasicInformation.FileAttributes
& winapi::um::winnt::FILE_ATTRIBUTE_REPARSE_POINT
!= 0
@@ -898,6 +923,7 @@ fn stat_extra(
}
}
+ CloseHandle(file_handle);
Ok(())
}
}
@@ -929,7 +955,7 @@ fn exists(path: &Path) -> bool {
}
fn realpath(path: &Path) -> FsResult<PathBuf> {
- Ok(deno_core::strip_unc_prefix(path.canonicalize()?))
+ Ok(deno_path_util::strip_unc_prefix(path.canonicalize()?))
}
fn read_dir(path: &Path) -> FsResult<Vec<FsDirEntry>> {