system_extensions/metadata/
time.rs1#[cfg(windows)]
2extern crate winapi;
3
4use std::ffi::OsStr;
5use std::iter::once;
6use std::path::Path;
7use std::process::Command;
8
9
10#[cfg(windows)]
14macro_rules! windows_imports {
15 () => {
16 use winapi::um::winnt;
17 use self::winapi::um::handleapi::CloseHandle;
18 use winapi::um::sysinfoapi;
19 use self::winapi::um::fileapi::{OPEN_EXISTING};
20 use self::winapi::shared::minwindef::{FILETIME};
21 use self::winapi::_core::ptr::{null_mut};
22 use self::winapi::um::winnt::{FILE_WRITE_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_WRITE};
23 use self::winapi::um::minwinbase::SYSTEMTIME;
24 use self::winapi::um::timezoneapi::SystemTimeToFileTime;
25 use winapi::um::fileapi::SetFileTime;
26 use std::os::windows::ffi::OsStrExt;
27 };
28}
29
30#[derive(Debug)]
34pub struct FileTime {
35 pub day: i16,
36 pub month: i16,
37 pub year: i16,
38 pub hour: i16,
39 pub minute: i16,
40 pub second: i16,
41 pub milliseconds: i16,
42}
43
44impl FileTime {
45 pub fn new(day: i16, month: i16, year: i16) -> FileTime {
49 FileTime {
50 day,
51 month,
52 year,
53 hour: -1,
54 minute: -1,
55 second: -1,
56 milliseconds: -1,
57 }
58 }
59}
60
61#[cfg(windows)]
62unsafe fn filetime_to_systime(system_time: *mut winapi::um::minwinbase::SYSTEMTIME, time: &FileTime) {
63 if time.day != -1 {
64 (*system_time).wDay = time.day as u16;
65 }
66 if time.month != -1 {
67 (*system_time).wMonth = time.month as u16;
68 }
69 if time.year != -1 {
70 (*system_time).wYear = time.year as u16;
71 }
72 if time.hour != -1 {
73 (*system_time).wHour = time.hour as u16;
74 }
75 if time.minute != -1 {
76 (*system_time).wMinute = time.minute as u16;
77 }
78 if time.second != -1 {
79 (*system_time).wSecond = time.second as u16;
80 }
81 if time.milliseconds != -1 {
82 (*system_time).wMilliseconds = time.milliseconds as u16;
83 }
84}
85
86#[cfg(windows)]
107pub fn set_creation_date(file: &Path, create: &FileTime) -> bool {
108 windows_imports!();
109 unsafe {
110 let mut file_handle: winnt::HANDLE = std::mem::zeroed();
111
112 let wide: Vec<u16> = OsStr::new(file.to_str().unwrap()).encode_wide().chain(once(0)).collect();
113 file_handle = winapi::um::fileapi::CreateFileW(wide.as_ptr(), GENERIC_WRITE,
114 FILE_SHARE_READ | FILE_SHARE_WRITE, null_mut(), OPEN_EXISTING,
115 FILE_ATTRIBUTE_NORMAL | FILE_WRITE_ATTRIBUTES, null_mut());
116 if file_handle == winapi::um::handleapi::INVALID_HANDLE_VALUE {
117 return false;
118 }
119
120 let system_time: *mut SYSTEMTIME = &mut SYSTEMTIME {
121 wYear: 0,
122 wMonth: 0,
123 wDayOfWeek: 0,
124 wDay: 0,
125 wHour: 0,
126 wMinute: 0,
127 wSecond: 0,
128 wMilliseconds: 0,
129 };
130
131 sysinfoapi::GetSystemTime(system_time);
132
133 filetime_to_systime(system_time, create);
135
136 let file_time: *mut FILETIME = &mut FILETIME { dwLowDateTime: 0, dwHighDateTime: 0 };
137 SystemTimeToFileTime(system_time, file_time);
138
139 SetFileTime(file_handle, file_time as *const FILETIME, null_mut(), null_mut());
140 CloseHandle(file_handle);
141 }
142
143 true
144}
145
146
147#[cfg(windows)]
168pub fn set_accessed_date(file: &Path, accessed: &FileTime) -> bool {
169 unsafe {
170 windows_imports!();
171 let mut file_handle: winnt::HANDLE = std::mem::zeroed();
172
173 let wide: Vec<u16> = OsStr::new(file.to_str().unwrap()).encode_wide().chain(once(0)).collect();
174 file_handle = winapi::um::fileapi::CreateFileW(wide.as_ptr(), GENERIC_WRITE,
175 FILE_SHARE_READ | FILE_SHARE_WRITE, null_mut(), OPEN_EXISTING,
176 FILE_ATTRIBUTE_NORMAL | FILE_WRITE_ATTRIBUTES, null_mut());
177
178 if file_handle == winapi::um::handleapi::INVALID_HANDLE_VALUE {
179 return false;
180 }
181
182 let system_time: *mut SYSTEMTIME = &mut SYSTEMTIME {
183 wYear: 0,
184 wMonth: 0,
185 wDayOfWeek: 0,
186 wDay: 0,
187 wHour: 0,
188 wMinute: 0,
189 wSecond: 0,
190 wMilliseconds: 0,
191 };
192
193 sysinfoapi::GetSystemTime(system_time);
194
195 filetime_to_systime(system_time, accessed);
197
198 let file_time: *mut FILETIME = &mut FILETIME { dwLowDateTime: 0, dwHighDateTime: 0 };
199 SystemTimeToFileTime(system_time, file_time);
200
201 SetFileTime(file_handle, null_mut(), file_time as *const FILETIME, null_mut());
202 CloseHandle(file_handle);
203 }
204 true
205}
206
207#[cfg(windows)]
228pub fn set_changed_date(file: &Path, changed: &FileTime) -> bool{
229 unsafe {
230 windows_imports!();
231 let mut file_handle: winnt::HANDLE = std::mem::zeroed();
232
233 let wide: Vec<u16> = OsStr::new(file.to_str().unwrap()).encode_wide().chain(once(0)).collect();
234 file_handle = winapi::um::fileapi::CreateFileW(wide.as_ptr(), GENERIC_WRITE,
235 FILE_SHARE_READ | FILE_SHARE_WRITE, null_mut(), OPEN_EXISTING,
236 FILE_ATTRIBUTE_NORMAL | FILE_WRITE_ATTRIBUTES, null_mut());
237
238 if file_handle == winapi::um::handleapi::INVALID_HANDLE_VALUE {
239 return false;
240 }
241
242 let system_time: *mut SYSTEMTIME = &mut SYSTEMTIME {
243 wYear: 0,
244 wMonth: 0,
245 wDayOfWeek: 0,
246 wDay: 0,
247 wHour: 0,
248 wMinute: 0,
249 wSecond: 0,
250 wMilliseconds: 0,
251 };
252
253 sysinfoapi::GetSystemTime(system_time);
254
255 filetime_to_systime(system_time, changed);
257
258 let file_time: *mut FILETIME = &mut FILETIME { dwLowDateTime: 0, dwHighDateTime: 0 };
259 SystemTimeToFileTime(system_time, file_time);
260
261 SetFileTime(file_handle, null_mut(), null_mut(), file_time as *const FILETIME);
262 CloseHandle(file_handle);
263 }
264
265 true
266}
267
268#[cfg(all(unix, not(target_os = "macos")))]
297pub fn set_creation_date(file: &Path, create: &FileTime) -> bool {
298 true
300}
301
302#[cfg(unix)]
323pub fn set_accessed_date(file: &Path, create: &FileTime) -> bool {
324 Command::new("touch").arg("-a").arg("-t").arg(filetime_to_systime(&create)).arg(file.to_str().unwrap()).spawn().is_ok()
325
326}
327
328#[cfg(unix)]
349pub fn set_changed_date(file: &Path, create: &FileTime) -> bool {
350 Command::new("touch").arg("-m").arg("-t").arg(filetime_to_systime(&create)).arg(file.to_str().unwrap()).spawn().is_ok()
351}
352
353#[cfg(unix)]
377pub fn filetime_to_systime(time: &FileTime) -> String{
378 use chrono::{Local, Timelike, Datelike};
379
380 let now = Local::now();
381
382 let mut year:String;
383 if time.year!=-1{
384 year = time.year.to_string();
385 }else{
386 year = now.year().to_string();
387 }
388 if year.len()!=2{
389 year = format!("{}", year);
390 }
391
392 let mut month:String;
393 if time.month!=-1{
394 month = time.month.to_string();
395 }else{
396 month = now.month().to_string();
397 }
398 if month.len()!=2{
399 month = format!("0{}", month);
400 }
401
402 let mut day:String;
403 if time.day!=-1{
404 day = time.day.to_string();
405 }else{
406 day = (now.day()).to_string();
407 }
408 if day.len()!=2{
409 day = format!("0{}", day);
410 }
411
412 let mut hour:String;
413 if time.hour!=-1{
414 hour = time.hour.to_string();
415 }else{
416 hour = (now.hour()+1).to_string();
417 }
418 if hour.len()!=2{
419 hour = format!("0{}", hour);
420 }
421
422 let mut minute:String;
423 if time.minute!=-1{
424 minute = time.minute.to_string();
425 }else{
426 minute = (now.minute()+1).to_string();
427 }
428 if minute.len()!=2{
429 minute = format!("0{}", minute);
430 }
431
432 let mut second:String;
433 if time.second!=-1{
434 second = time.second.to_string();
435 }else{
436 second = (now.second()+1).to_string();
437 }
438 if second.len()!=2{
439 second = format!("0{}", second);
440 }
441
442 format!("{}{}{}{}{}.{}", year, month, day, hour, minute, second)
443}
444
445#[cfg(target_os = "macos")]
473pub fn set_creation_date(file: &Path, create: &FileTime) -> bool {
474 let mut time = "AM";
475 if create.hour >= 12 {
476 time = "PM";
477 }
478
479 Command::new("SetFile")
480 .arg("-d")
481 .arg(format!("'{}/{}/{} {}:{}:{} {}'", create.month, create.day, (create.year + 1), create.hour,
482 create.minute, create.second, time))
483 .arg(file.to_str().unwrap())
484 .spawn().is_ok()
485}