mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-31 04:57: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"]
|
#![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.
|
* This file is part of the uutils coreutils package.
|
||||||
|
@ -10,11 +10,19 @@
|
||||||
* that was distributed with this source code.
|
* that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
extern crate libc;
|
||||||
extern crate getopts;
|
extern crate getopts;
|
||||||
extern crate time;
|
extern crate time;
|
||||||
|
|
||||||
use std::old_io::File;
|
use libc::types::os::arch::c95::c_char;
|
||||||
use std::old_io::fs::PathExtensions;
|
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"]
|
#[path = "../common/util.rs"]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -40,7 +48,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
getopts::optflag("V", "version", "output version information and exit"),
|
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,
|
Ok(m) => m,
|
||||||
Err(e) => panic!("Invalid options\n{}", e)
|
Err(e) => panic!("Invalid options\n{}", e)
|
||||||
};
|
};
|
||||||
|
@ -71,14 +79,12 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
|
|
||||||
let (mut atime, mut mtime) =
|
let (mut atime, mut mtime) =
|
||||||
if matches.opt_present("reference") {
|
if matches.opt_present("reference") {
|
||||||
let path = Path::new(matches.opt_str("reference").unwrap().to_string());
|
stat(&matches.opt_str("reference").unwrap()[..], !matches.opt_present("no-dereference"))
|
||||||
let stat = stat(&path, !matches.opt_present("no-dereference"));
|
|
||||||
(stat.accessed, stat.modified)
|
|
||||||
} else if matches.opts_present(&["date".to_string(), "t".to_string()]) {
|
} else if matches.opts_present(&["date".to_string(), "t".to_string()]) {
|
||||||
let timestamp = if matches.opt_present("date") {
|
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 {
|
} else {
|
||||||
parse_timestamp(matches.opt_str("t").unwrap().as_slice())
|
parse_timestamp(matches.opt_str("t").unwrap().as_ref())
|
||||||
};
|
};
|
||||||
(timestamp, timestamp)
|
(timestamp, timestamp)
|
||||||
} else {
|
} else {
|
||||||
|
@ -88,17 +94,20 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
};
|
};
|
||||||
|
|
||||||
for filename in matches.free.iter() {
|
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
|
// no-dereference included here for compatibility
|
||||||
if matches.opts_present(&["no-create".to_string(), "no-dereference".to_string()]) {
|
if matches.opts_present(&["no-create".to_string(), "no-dereference".to_string()]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
match File::create(&path) {
|
match File::create(path) {
|
||||||
Ok(fd) => fd,
|
Err(e) => {
|
||||||
Err(e) => panic!("Unable to create file: {}\n{}", filename, e.desc)
|
show_warning!("cannot touch '{}': {}", path, e);
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Minor optimization: if no reference time was specified, we're done.
|
// 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.
|
// 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.
|
// 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()]) {
|
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");
|
let time = matches.opt_strs("time");
|
||||||
|
|
||||||
if !(matches.opt_present("a") ||
|
if !(matches.opt_present("a") ||
|
||||||
time.contains(&"access".to_string()) ||
|
time.contains(&"access".to_string()) ||
|
||||||
time.contains(&"atime".to_string()) ||
|
time.contains(&"atime".to_string()) ||
|
||||||
time.contains(&"use".to_string())) {
|
time.contains(&"use".to_string())) {
|
||||||
atime = stat.accessed;
|
atime = st.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(matches.opt_present("m") ||
|
if !(matches.opt_present("m") ||
|
||||||
time.contains(&"modify".to_string()) ||
|
time.contains(&"modify".to_string()) ||
|
||||||
time.contains(&"mtime".to_string())) {
|
time.contains(&"mtime".to_string())) {
|
||||||
mtime = stat.modified;
|
mtime = st.1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match std::old_io::fs::change_file_times(&path, atime, mtime) {
|
// this follows symlinks and thus does not work correctly for the -h flag
|
||||||
Ok(t) => t,
|
// need to use lutimes() c function on supported platforms
|
||||||
Err(e) => panic!("Unable to modify times\n{}", e.desc)
|
match set_file_times(path, atime, mtime) {
|
||||||
}
|
Err(e) => show_warning!("cannot touch '{}': {}", path, e),
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stat(path: &Path, follow: bool) -> std::old_io::FileStat {
|
fn stat(path: &str, follow: bool) -> (u64, u64) {
|
||||||
if follow {
|
let stat_fn = if follow {
|
||||||
match std::old_io::fs::stat(path) {
|
c_stat
|
||||||
Ok(stat) => stat,
|
|
||||||
Err(e) => panic!("Unable to open file\n{}", e.desc)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
match std::old_io::fs::lstat(path) {
|
c_lstat
|
||||||
Ok(stat) => stat,
|
};
|
||||||
Err(e) => panic!("Unable to open file\n{}", e.desc)
|
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 {
|
fn parse_date(str: &str) -> u64 {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue