From 1c93a793e95658eab54e1754ce39d9b5d1240519 Mon Sep 17 00:00:00 2001 From: kwantam Date: Thu, 30 Apr 2015 01:46:10 -0400 Subject: [PATCH] fix `touch` --- src/touch/touch.rs | 89 ++++++++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 31 deletions(-) diff --git a/src/touch/touch.rs b/src/touch/touch.rs index 8119f6114..48687828a 100644 --- a/src/touch/touch.rs +++ b/src/touch/touch.rs @@ -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) -> 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) -> 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) -> 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) -> 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 {