1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 12:07:46 +00:00

Replace unstable set_file_times w/ external crate.

This commit is contained in:
Joseph Crail 2015-08-11 19:13:22 -04:00
parent 9d84890c89
commit e455ba5de1
5 changed files with 49 additions and 47 deletions

1
deps/Cargo.toml vendored
View file

@ -22,3 +22,4 @@ winapi = "0.2"
advapi32-sys = "0.1" advapi32-sys = "0.1"
kernel32-sys = "0.1" kernel32-sys = "0.1"
walker = "^1.0.0" walker = "^1.0.0"
filetime = "0.1"

View file

@ -1 +1 @@
DEPLIBS += time DEPLIBS += kernel32 winapi filetime time

View file

@ -1 +1 @@
DEPLIBS += time DEPLIBS += kernel32 winapi filetime time

View file

@ -1,5 +1,4 @@
#![crate_name = "touch"] #![crate_name = "touch"]
#![feature(fs_time)]
/* /*
* This file is part of the uutils coreutils package. * This file is part of the uutils coreutils package.
@ -13,14 +12,11 @@
extern crate getopts; extern crate getopts;
extern crate libc; extern crate libc;
extern crate time; extern crate time;
extern crate filetime;
use libc::types::os::arch::c95::c_char; use filetime::*;
use libc::types::os::arch::posix01::stat as stat_t; use std::fs::{self, File};
use libc::funcs::posix88::stat_::stat as c_stat;
use libc::funcs::posix01::stat_::lstat as c_lstat;
use std::fs::{set_file_times, File};
use std::io::{Error, Write}; use std::io::{Error, Write};
use std::mem::uninitialized;
use std::path::Path; use std::path::Path;
#[path = "../common/util.rs"] #[path = "../common/util.rs"]
@ -35,6 +31,24 @@ use filesystem::UUPathExt;
static NAME: &'static str = "touch"; static NAME: &'static str = "touch";
static VERSION: &'static str = "1.0.0"; static VERSION: &'static str = "1.0.0";
// Since touch's date/timestamp parsing doesn't account for timezone, the
// returned value from time::strptime() is UTC. We get system's timezone to
// localize the time.
macro_rules! to_local(
($exp:expr) => ({
let mut tm = $exp;
tm.tm_utcoff = time::now().tm_utcoff;
tm
})
);
macro_rules! local_tm_to_filetime(
($exp:expr) => ({
let ts = $exp.to_timespec();
FileTime::from_seconds_since_1970(ts.sec as u64, ts.nsec as u32)
})
);
pub fn uumain(args: Vec<String>) -> i32 { pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = getopts::Options::new(); let mut opts = getopts::Options::new();
@ -92,8 +106,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
}; };
(timestamp, timestamp) (timestamp, timestamp)
} else { } else {
// FIXME: Should use Timespec. https://github.com/mozilla/rust/issues/10301 let now = local_tm_to_filetime!(time::now());
let now = (time::get_time().sec * 1000) as u64;
(now, now) (now, now)
}; };
@ -142,7 +155,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
// this follows symlinks and thus does not work correctly for the -h flag // this follows symlinks and thus does not work correctly for the -h flag
// need to use lutimes() c function on supported platforms // need to use lutimes() c function on supported platforms
match set_file_times(path, atime, mtime) { match filetime::set_file_times(path, atime, mtime) {
Err(e) => show_warning!("cannot touch '{}': {}", path, e), Err(e) => show_warning!("cannot touch '{}': {}", path, e),
_ => (), _ => (),
}; };
@ -151,48 +164,34 @@ pub fn uumain(args: Vec<String>) -> i32 {
0 0
} }
fn stat(path: &str, follow: bool) -> (u64, u64) { fn stat(path: &str, follow: bool) -> (FileTime, FileTime) {
let stat_fn = if follow { let metadata = if follow {
c_stat fs::symlink_metadata(path)
} else { } else {
c_lstat fs::metadata(path)
}; };
let mut st: stat_t = unsafe { uninitialized() };
let result = unsafe { stat_fn(path.as_ptr() as *const c_char, &mut st as *mut stat_t) };
if result < 0 { match metadata {
crash!(1, "failed to get attributes of '{}': {}", path, Error::last_os_error()); Ok(m) => (
FileTime::from_last_access_time(&m),
FileTime::from_last_modification_time(&m)
),
Err(_) => crash!(1, "failed to get attributes of '{}': {}", path, Error::last_os_error())
}
} }
// set_file_times expects milliseconds fn parse_date(str: &str) -> FileTime {
let atime = if st.st_atime_nsec == 0 {
st.st_atime * 1000
} else {
st.st_atime_nsec / 1000
} as u64;
// set_file_times expects milliseconds
let mtime = if st.st_mtime_nsec == 0 {
st.st_mtime * 1000
} else {
st.st_mtime_nsec / 1000
} as u64;
(atime, mtime)
}
fn parse_date(str: &str) -> u64 {
// This isn't actually compatible with GNU touch, but there doesn't seem to // This isn't actually compatible with GNU touch, but there doesn't seem to
// be any simple specification for what format this parameter allows and I'm // be any simple specification for what format this parameter allows and I'm
// not about to implement GNU parse_datetime. // not about to implement GNU parse_datetime.
// http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=lib/parse-datetime.y // http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=lib/parse-datetime.y
match time::strptime(str, "%c") { match time::strptime(str, "%c") {
Ok(tm) => (tm.to_timespec().sec * 1000) as u64, Ok(tm) => local_tm_to_filetime!(to_local!(tm)),
Err(e) => panic!("Unable to parse date\n{}", e) Err(e) => panic!("Unable to parse date\n{}", e)
} }
} }
fn parse_timestamp(str: &str) -> u64 { fn parse_timestamp(str: &str) -> FileTime {
let format = match str.chars().count() { let format = match str.chars().count() {
15 => "%Y%m%d%H%M.%S", 15 => "%Y%m%d%H%M.%S",
12 => "%Y%m%d%H%M", 12 => "%Y%m%d%H%M",
@ -204,7 +203,7 @@ fn parse_timestamp(str: &str) -> u64 {
}; };
match time::strptime(str, format) { match time::strptime(str, format) {
Ok(tm) => (tm.to_timespec().sec * 1000) as u64, Ok(tm) => local_tm_to_filetime!(to_local!(tm)),
Err(e) => panic!("Unable to parse timestamp\n{}", e) Err(e) => panic!("Unable to parse timestamp\n{}", e)
} }
} }

View file

@ -1,10 +1,10 @@
#![feature(fs_time)]
extern crate libc; extern crate libc;
extern crate time; extern crate time;
extern crate kernel32;
extern crate winapi;
extern crate filetime;
use std::fs; use filetime::*;
use std::path::Path;
use std::process::Command; use std::process::Command;
use util::*; use util::*;
@ -272,9 +272,11 @@ fn test_mv_update_option() {
touch(file_a); touch(file_a);
touch(file_b); touch(file_b);
let now = (time::get_time().sec * 1000) as u64; let ts = time::now().to_timespec();
fs::set_file_times(Path::new(file_a), now, now).unwrap(); let now = FileTime::from_seconds_since_1970(ts.sec as u64, ts.nsec as u32);
fs::set_file_times(Path::new(file_b), now, now+3600).unwrap(); let later = FileTime::from_seconds_since_1970(ts.sec as u64 + 3600, ts.nsec as u32);
filetime::set_file_times(file_a, now, now).unwrap();
filetime::set_file_times(file_b, now, later).unwrap();
let result1 = run(Command::new(PROGNAME).arg("--update").arg(file_a).arg(file_b)); let result1 = run(Command::new(PROGNAME).arg("--update").arg(file_a).arg(file_b));