diff options
author | Ćukasz Czerniawski <33061335+lczerniawski@users.noreply.github.com> | 2024-11-13 05:35:04 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-13 13:35:04 +0900 |
commit | 7becd83a3828b35331d0fcb82c64146e520f154b (patch) | |
tree | edab8904c24802a3163427d8df9b41aa3cc4c3d1 /ext/fs/std_fs.rs | |
parent | 43812ee8ff0eb2584c7beb18639da14d96d06817 (diff) |
feat(ext/fs): add ctime to Deno.stats and use it in node compat layer (#24801)
This PR fixes #24453, by introducing a ctime (using ctime for UNIX and
ChangeTime for Windows) to Deno.stats.
Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
Diffstat (limited to 'ext/fs/std_fs.rs')
-rw-r--r-- | ext/fs/std_fs.rs | 34 |
1 files changed, 30 insertions, 4 deletions
diff --git a/ext/fs/std_fs.rs b/ext/fs/std_fs.rs index 1a83c97c5..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(()) } } |