mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-30 04:27:45 +00:00
fix touch
This commit is contained in:
parent
6c4e967fc6
commit
1c93a793e9
1 changed files with 58 additions and 31 deletions
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue