use crate::FileTime; use std::fs::{self, File, OpenOptions}; use std::io; use std::os::windows::prelude::*; use std::path::Path; use std::ptr; use windows_sys::Win32::Foundation::{FILETIME, HANDLE}; use windows_sys::Win32::Storage::FileSystem::*; pub fn set_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { let f = OpenOptions::new() .write(true) .custom_flags(FILE_FLAG_BACKUP_SEMANTICS) .open(p)?; set_file_handle_times(&f, Some(atime), Some(mtime)) } pub fn set_file_mtime(p: &Path, mtime: FileTime) -> io::Result<()> { let f = OpenOptions::new() .write(true) .custom_flags(FILE_FLAG_BACKUP_SEMANTICS) .open(p)?; set_file_handle_times(&f, None, Some(mtime)) } pub fn set_file_atime(p: &Path, atime: FileTime) -> io::Result<()> { let f = OpenOptions::new() .write(true) .custom_flags(FILE_FLAG_BACKUP_SEMANTICS) .open(p)?; set_file_handle_times(&f, Some(atime), None) } pub fn set_file_handle_times( f: &File, atime: Option, mtime: Option, ) -> io::Result<()> { let atime = atime.map(to_filetime); let mtime = mtime.map(to_filetime); return unsafe { let ret = SetFileTime( f.as_raw_handle() as HANDLE, ptr::null(), atime .as_ref() .map(|p| p as *const FILETIME) .unwrap_or(ptr::null()), mtime .as_ref() .map(|p| p as *const FILETIME) .unwrap_or(ptr::null()), ); if ret != 0 { Ok(()) } else { Err(io::Error::last_os_error()) } }; fn to_filetime(ft: FileTime) -> FILETIME { let intervals = ft.seconds() * (1_000_000_000 / 100) + ((ft.nanoseconds() as i64) / 100); FILETIME { dwLowDateTime: intervals as u32, dwHighDateTime: (intervals >> 32) as u32, } } } pub fn set_symlink_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { use std::os::windows::fs::OpenOptionsExt; let f = OpenOptions::new() .write(true) .custom_flags(FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS) .open(p)?; set_file_handle_times(&f, Some(atime), Some(mtime)) } pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime { from_intervals(meta.last_write_time()) } pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime { from_intervals(meta.last_access_time()) } pub fn from_creation_time(meta: &fs::Metadata) -> Option { Some(from_intervals(meta.creation_time())) } fn from_intervals(ticks: u64) -> FileTime { // Windows write times are in 100ns intervals, so do a little math to // get it into the right representation. FileTime { seconds: (ticks / (1_000_000_000 / 100)) as i64, nanos: ((ticks % (1_000_000_000 / 100)) * 100) as u32, } }