1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-30 04:27:45 +00:00

fix touch

This commit is contained in:
kwantam 2015-04-30 01:46:10 -04:00
parent 6c4e967fc6
commit 1c93a793e9

View file

@ -1,5 +1,5 @@
#![crate_name = "touch"]
#![feature(collections, core, old_io, old_path, rustc_private)]
#![feature(rustc_private, path_ext, fs_time)]
/*
* This file is part of the uutils coreutils package.
@ -10,11 +10,19 @@
* that was distributed with this source code.
*/
extern crate libc;
extern crate getopts;
extern crate time;
use std::old_io::File;
use std::old_io::fs::PathExtensions;
use libc::types::os::arch::c95::c_char;
use libc::types::os::arch::posix01::stat as stat_t;
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, PathExt};
use std::io::{Error, Write};
use std::mem::uninitialized;
use std::path::Path;
#[path = "../common/util.rs"]
#[macro_use]
@ -40,7 +48,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
getopts::optflag("V", "version", "output version information and exit"),
];
let matches = match getopts::getopts(args.tail(), &opts) {
let matches = match getopts::getopts(&args[1..], &opts) {
Ok(m) => m,
Err(e) => panic!("Invalid options\n{}", e)
};
@ -71,14 +79,12 @@ pub fn uumain(args: Vec<String>) -> i32 {
let (mut atime, mut mtime) =
if matches.opt_present("reference") {
let path = Path::new(matches.opt_str("reference").unwrap().to_string());
let stat = stat(&path, !matches.opt_present("no-dereference"));
(stat.accessed, stat.modified)
stat(&matches.opt_str("reference").unwrap()[..], !matches.opt_present("no-dereference"))
} else if matches.opts_present(&["date".to_string(), "t".to_string()]) {
let timestamp = if matches.opt_present("date") {
parse_date(matches.opt_str("date").unwrap().as_slice())
parse_date(matches.opt_str("date").unwrap().as_ref())
} else {
parse_timestamp(matches.opt_str("t").unwrap().as_slice())
parse_timestamp(matches.opt_str("t").unwrap().as_ref())
};
(timestamp, timestamp)
} else {
@ -88,17 +94,20 @@ pub fn uumain(args: Vec<String>) -> i32 {
};
for filename in matches.free.iter() {
let path = Path::new(filename.to_string());
let path = &filename[..];
if !path.exists() {
if ! Path::new(path).exists() {
// no-dereference included here for compatibility
if matches.opts_present(&["no-create".to_string(), "no-dereference".to_string()]) {
continue;
}
match File::create(&path) {
Ok(fd) => fd,
Err(e) => panic!("Unable to create file: {}\n{}", filename, e.desc)
match File::create(path) {
Err(e) => {
show_warning!("cannot touch '{}': {}", path, e);
continue;
},
_ => (),
};
// Minor optimization: if no reference time was specified, we're done.
@ -110,44 +119,62 @@ pub fn uumain(args: Vec<String>) -> i32 {
// If changing "only" atime or mtime, grab the existing value of the other.
// Note that "-a" and "-m" may be passed together; this is not an xor.
if matches.opts_present(&["a".to_string(), "m".to_string(), "time".to_string()]) {
let stat = stat(&path, !matches.opt_present("no-dereference"));
let st = stat(path, !matches.opt_present("no-dereference"));
let time = matches.opt_strs("time");
if !(matches.opt_present("a") ||
time.contains(&"access".to_string()) ||
time.contains(&"atime".to_string()) ||
time.contains(&"use".to_string())) {
atime = stat.accessed;
atime = st.0;
}
if !(matches.opt_present("m") ||
time.contains(&"modify".to_string()) ||
time.contains(&"mtime".to_string())) {
mtime = stat.modified;
mtime = st.1;
}
}
match std::old_io::fs::change_file_times(&path, atime, mtime) {
Ok(t) => t,
Err(e) => panic!("Unable to modify times\n{}", e.desc)
}
// this follows symlinks and thus does not work correctly for the -h flag
// need to use lutimes() c function on supported platforms
match set_file_times(path, atime, mtime) {
Err(e) => show_warning!("cannot touch '{}': {}", path, e),
_ => (),
};
}
0
}
fn stat(path: &Path, follow: bool) -> std::old_io::FileStat {
if follow {
match std::old_io::fs::stat(path) {
Ok(stat) => stat,
Err(e) => panic!("Unable to open file\n{}", e.desc)
}
fn stat(path: &str, follow: bool) -> (u64, u64) {
let stat_fn = if follow {
c_stat
} else {
match std::old_io::fs::lstat(path) {
Ok(stat) => stat,
Err(e) => panic!("Unable to open file\n{}", e.desc)
}
c_lstat
};
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 {
crash!(1, "failed to get attributes of '{}': {}", path, Error::last_os_error());
}
// set_file_times expects milliseconds
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 {