2023-08-21 10:49:27 +02:00
|
|
|
|
// This file is part of the uutils coreutils package.
|
|
|
|
|
|
//
|
|
|
|
|
|
// For the full copyright and license information, please view the LICENSE
|
|
|
|
|
|
// file that was distributed with this source code.
|
2026-01-06 15:06:35 -08:00
|
|
|
|
// spell-checker:ignore (formats) cymdhm cymdhms datetime mdhm mdhms mktime strtime ymdhm ymdhms
|
2022-04-23 21:32:35 +02:00
|
|
|
|
|
2025-03-24 21:04:32 +01:00
|
|
|
|
use filetime::FileTime;
|
2024-03-23 17:23:22 +08:00
|
|
|
|
#[cfg(not(target_os = "freebsd"))]
|
|
|
|
|
|
use filetime::set_symlink_file_times;
|
2026-01-06 15:06:35 -08:00
|
|
|
|
use jiff::{fmt::strtime, tz::TimeZone};
|
2021-09-09 21:48:17 +02:00
|
|
|
|
use std::fs::remove_file;
|
2021-06-12 13:28:21 +02:00
|
|
|
|
use std::path::PathBuf;
|
2025-03-28 09:51:51 +01:00
|
|
|
|
use uutests::at_and_ucmd;
|
|
|
|
|
|
use uutests::new_ucmd;
|
|
|
|
|
|
use uutests::util::{AtPath, TestScenario};
|
|
|
|
|
|
use uutests::util_name;
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2015-11-16 00:25:01 -05:00
|
|
|
|
fn get_file_times(at: &AtPath, path: &str) -> (FileTime, FileTime) {
|
|
|
|
|
|
let m = at.metadata(path);
|
2020-04-13 20:36:03 +02:00
|
|
|
|
(
|
|
|
|
|
|
FileTime::from_last_access_time(&m),
|
|
|
|
|
|
FileTime::from_last_modification_time(&m),
|
|
|
|
|
|
)
|
2015-08-11 21:38:10 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-08-28 15:06:44 +02:00
|
|
|
|
#[cfg(not(target_os = "freebsd"))]
|
2016-08-28 07:12:58 +08:00
|
|
|
|
fn get_symlink_times(at: &AtPath, path: &str) -> (FileTime, FileTime) {
|
|
|
|
|
|
let m = at.symlink_metadata(path);
|
2020-04-13 20:36:03 +02:00
|
|
|
|
(
|
|
|
|
|
|
FileTime::from_last_access_time(&m),
|
|
|
|
|
|
FileTime::from_last_modification_time(&m),
|
|
|
|
|
|
)
|
2016-08-28 07:12:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-11-16 00:25:01 -05:00
|
|
|
|
fn set_file_times(at: &AtPath, path: &str, atime: FileTime, mtime: FileTime) {
|
2022-11-15 17:57:08 +02:00
|
|
|
|
filetime::set_file_times(at.plus_as_string(path), atime, mtime).unwrap();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn str_to_filetime(format: &str, s: &str) -> FileTime {
|
2026-01-06 15:06:35 -08:00
|
|
|
|
let tm = strtime::parse(format, s).unwrap();
|
|
|
|
|
|
let dt = tm.to_datetime().unwrap();
|
|
|
|
|
|
let ts = dt.to_zoned(TimeZone::UTC).unwrap().timestamp();
|
|
|
|
|
|
FileTime::from_unix_time(ts.as_second(), ts.subsec_nanosecond() as u32)
|
2015-08-11 21:38:10 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-09-10 18:38:14 +02:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_invalid_arg() {
|
2025-03-01 15:29:11 +01:00
|
|
|
|
new_ucmd!().arg("--definitely-invalid").fails_with_code(1);
|
2022-09-10 18:38:14 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-08-11 21:38:10 -04:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_default() {
|
2016-08-23 07:52:43 -04:00
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
let file = "test_touch_default_file";
|
|
|
|
|
|
|
2016-08-13 17:59:21 -04:00
|
|
|
|
ucmd.arg(file).succeeds().no_stderr();
|
2016-08-28 07:12:58 +08:00
|
|
|
|
|
2015-11-16 00:25:01 -05:00
|
|
|
|
assert!(at.file_exists(file));
|
2015-08-11 21:38:10 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_no_create_file_absent() {
|
2016-08-23 07:52:43 -04:00
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
let file = "test_touch_no_create_file_absent";
|
|
|
|
|
|
|
2016-08-13 17:59:21 -04:00
|
|
|
|
ucmd.arg("-c").arg(file).succeeds().no_stderr();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2015-11-16 00:25:01 -05:00
|
|
|
|
assert!(!at.file_exists(file));
|
2015-08-11 21:38:10 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_no_create_file_exists() {
|
2016-08-23 07:52:43 -04:00
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
let file = "test_touch_no_create_file_exists";
|
|
|
|
|
|
|
2015-11-16 00:25:01 -05:00
|
|
|
|
at.touch(file);
|
|
|
|
|
|
assert!(at.file_exists(file));
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2016-08-13 17:59:21 -04:00
|
|
|
|
ucmd.arg("-c").arg(file).succeeds().no_stderr();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2015-11-16 00:25:01 -05:00
|
|
|
|
assert!(at.file_exists(file));
|
2015-08-11 21:38:10 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_mdhm_time() {
|
2016-08-23 07:52:43 -04:00
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
let file = "test_touch_set_mdhm_time";
|
|
|
|
|
|
|
2016-08-13 17:59:21 -04:00
|
|
|
|
ucmd.args(&["-t", "01011234", file]).succeeds().no_stderr();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2015-11-16 00:25:01 -05:00
|
|
|
|
assert!(at.file_exists(file));
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2020-04-13 20:36:03 +02:00
|
|
|
|
let start_of_year = str_to_filetime(
|
|
|
|
|
|
"%Y%m%d%H%M",
|
2023-03-26 21:47:12 +02:00
|
|
|
|
&format!("{}01010000", time::OffsetDateTime::now_utc().year()),
|
2020-04-13 20:36:03 +02:00
|
|
|
|
);
|
2015-11-16 00:25:01 -05:00
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
2015-08-11 21:38:10 -04:00
|
|
|
|
assert_eq!(atime, mtime);
|
2020-04-13 20:36:03 +02:00
|
|
|
|
assert_eq!(atime.unix_seconds() - start_of_year.unix_seconds(), 45240);
|
|
|
|
|
|
assert_eq!(mtime.unix_seconds() - start_of_year.unix_seconds(), 45240);
|
2015-08-11 21:38:10 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_mdhms_time() {
|
2016-08-23 07:52:43 -04:00
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
let file = "test_touch_set_mdhms_time";
|
|
|
|
|
|
|
2020-04-13 20:36:03 +02:00
|
|
|
|
ucmd.args(&["-t", "01011234.56", file])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2015-11-16 00:25:01 -05:00
|
|
|
|
assert!(at.file_exists(file));
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2020-04-13 20:36:03 +02:00
|
|
|
|
let start_of_year = str_to_filetime(
|
|
|
|
|
|
"%Y%m%d%H%M.%S",
|
2022-04-27 08:43:03 +02:00
|
|
|
|
&format!("{}01010000.00", time::OffsetDateTime::now_utc().year()),
|
2020-04-13 20:36:03 +02:00
|
|
|
|
);
|
2015-11-16 00:25:01 -05:00
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
2015-08-11 21:38:10 -04:00
|
|
|
|
assert_eq!(atime, mtime);
|
2020-04-13 20:36:03 +02:00
|
|
|
|
assert_eq!(atime.unix_seconds() - start_of_year.unix_seconds(), 45296);
|
|
|
|
|
|
assert_eq!(mtime.unix_seconds() - start_of_year.unix_seconds(), 45296);
|
2015-08-11 21:38:10 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-03 16:52:53 +01:00
|
|
|
|
#[test]
|
2025-03-05 13:22:23 +01:00
|
|
|
|
#[cfg(target_pointer_width = "64")]
|
2025-03-03 16:52:53 +01:00
|
|
|
|
fn test_touch_2_digit_years_68() {
|
|
|
|
|
|
// 68 and before are 20xx
|
2025-03-05 13:22:23 +01:00
|
|
|
|
// it will fail on 32 bits, because of wraparound for anything after
|
|
|
|
|
|
// 2038-01-19
|
2025-03-03 16:52:53 +01:00
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
let file = "test_touch_set_two_digit_68_time";
|
|
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["-t", "6801010000", file])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_output();
|
|
|
|
|
|
|
|
|
|
|
|
assert!(at.file_exists(file));
|
|
|
|
|
|
|
|
|
|
|
|
// January 1, 2068, 00:00:00
|
|
|
|
|
|
let expected = FileTime::from_unix_time(3_092_601_600, 0);
|
|
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
|
|
|
|
|
assert_eq!(atime, mtime);
|
|
|
|
|
|
assert_eq!(atime, expected);
|
|
|
|
|
|
assert_eq!(mtime, expected);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-05 13:22:23 +01:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_2_digit_years_2038() {
|
|
|
|
|
|
// Same as test_touch_2_digit_years_68 but for 32 bits systems
|
|
|
|
|
|
// we test a date before the y2038 bug
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
let file = "test_touch_set_two_digit_68_time";
|
|
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["-t", "3801010000", file])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_output();
|
|
|
|
|
|
|
|
|
|
|
|
assert!(at.file_exists(file));
|
|
|
|
|
|
|
|
|
|
|
|
// January 1, 2038, 00:00:00
|
|
|
|
|
|
let expected = FileTime::from_unix_time(2_145_916_800, 0);
|
|
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
|
|
|
|
|
assert_eq!(atime, mtime);
|
|
|
|
|
|
assert_eq!(atime, expected);
|
|
|
|
|
|
assert_eq!(mtime, expected);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-03 16:52:53 +01:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_2_digit_years_69() {
|
|
|
|
|
|
// 69 and after are 19xx
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
let file = "test_touch_set_two_digit_69_time";
|
|
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["-t", "6901010000", file])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_output();
|
|
|
|
|
|
|
|
|
|
|
|
assert!(at.file_exists(file));
|
|
|
|
|
|
// January 1, 1969, 00:00:00
|
|
|
|
|
|
let expected = FileTime::from_unix_time(-31_536_000, 0);
|
|
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
|
|
|
|
|
assert_eq!(atime, mtime);
|
|
|
|
|
|
assert_eq!(atime, expected);
|
|
|
|
|
|
assert_eq!(mtime, expected);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-08-11 21:38:10 -04:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_ymdhm_time() {
|
2016-08-23 07:52:43 -04:00
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
let file = "test_touch_set_ymdhm_time";
|
|
|
|
|
|
|
2020-04-13 20:36:03 +02:00
|
|
|
|
ucmd.args(&["-t", "1501011234", file])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2015-11-16 00:25:01 -05:00
|
|
|
|
assert!(at.file_exists(file));
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2022-04-27 08:43:03 +02:00
|
|
|
|
let start_of_year = str_to_filetime("%Y%m%d%H%M", "201501010000");
|
2015-11-16 00:25:01 -05:00
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
2015-08-11 21:38:10 -04:00
|
|
|
|
assert_eq!(atime, mtime);
|
2020-04-13 20:36:03 +02:00
|
|
|
|
assert_eq!(atime.unix_seconds() - start_of_year.unix_seconds(), 45240);
|
|
|
|
|
|
assert_eq!(mtime.unix_seconds() - start_of_year.unix_seconds(), 45240);
|
2015-08-11 21:38:10 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_ymdhms_time() {
|
2016-08-23 07:52:43 -04:00
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
let file = "test_touch_set_ymdhms_time";
|
|
|
|
|
|
|
2020-04-13 20:36:03 +02:00
|
|
|
|
ucmd.args(&["-t", "1501011234.56", file])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2015-11-16 00:25:01 -05:00
|
|
|
|
assert!(at.file_exists(file));
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2022-04-27 08:43:03 +02:00
|
|
|
|
let start_of_year = str_to_filetime("%Y%m%d%H%M.%S", "201501010000.00");
|
2015-11-16 00:25:01 -05:00
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
2015-08-11 21:38:10 -04:00
|
|
|
|
assert_eq!(atime, mtime);
|
2020-04-13 20:36:03 +02:00
|
|
|
|
assert_eq!(atime.unix_seconds() - start_of_year.unix_seconds(), 45296);
|
|
|
|
|
|
assert_eq!(mtime.unix_seconds() - start_of_year.unix_seconds(), 45296);
|
2015-08-11 21:38:10 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_cymdhm_time() {
|
2016-08-23 07:52:43 -04:00
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
let file = "test_touch_set_cymdhm_time";
|
|
|
|
|
|
|
2020-04-13 20:36:03 +02:00
|
|
|
|
ucmd.args(&["-t", "201501011234", file])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2015-11-16 00:25:01 -05:00
|
|
|
|
assert!(at.file_exists(file));
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
|
|
|
|
|
let start_of_year = str_to_filetime("%Y%m%d%H%M", "201501010000");
|
2015-11-16 00:25:01 -05:00
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
2015-08-11 21:38:10 -04:00
|
|
|
|
assert_eq!(atime, mtime);
|
2020-04-13 20:36:03 +02:00
|
|
|
|
assert_eq!(atime.unix_seconds() - start_of_year.unix_seconds(), 45240);
|
|
|
|
|
|
assert_eq!(mtime.unix_seconds() - start_of_year.unix_seconds(), 45240);
|
2015-08-11 21:38:10 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_cymdhms_time() {
|
2016-08-23 07:52:43 -04:00
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
let file = "test_touch_set_cymdhms_time";
|
|
|
|
|
|
|
2020-04-13 20:36:03 +02:00
|
|
|
|
ucmd.args(&["-t", "201501011234.56", file])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2015-11-16 00:25:01 -05:00
|
|
|
|
assert!(at.file_exists(file));
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
|
|
|
|
|
let start_of_year = str_to_filetime("%Y%m%d%H%M.%S", "201501010000.00");
|
2015-11-16 00:25:01 -05:00
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
2015-08-11 21:38:10 -04:00
|
|
|
|
assert_eq!(atime, mtime);
|
2020-04-13 20:36:03 +02:00
|
|
|
|
assert_eq!(atime.unix_seconds() - start_of_year.unix_seconds(), 45296);
|
|
|
|
|
|
assert_eq!(mtime.unix_seconds() - start_of_year.unix_seconds(), 45296);
|
2015-08-11 21:38:10 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_only_atime() {
|
2024-04-01 08:06:18 +02:00
|
|
|
|
let atime_args = [
|
|
|
|
|
|
"-a",
|
|
|
|
|
|
"--time=access",
|
|
|
|
|
|
"--time=atime",
|
|
|
|
|
|
"--time=atim", // spell-checker:disable-line
|
|
|
|
|
|
"--time=a",
|
|
|
|
|
|
"--time=use",
|
|
|
|
|
|
];
|
2015-08-11 21:38:10 -04:00
|
|
|
|
let file = "test_touch_set_only_atime";
|
|
|
|
|
|
|
2023-07-08 16:13:35 +02:00
|
|
|
|
for atime_arg in atime_args {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2023-07-08 16:13:35 +02:00
|
|
|
|
ucmd.args(&["-t", "201501011234", atime_arg, file])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2023-07-08 16:13:35 +02:00
|
|
|
|
assert!(at.file_exists(file));
|
|
|
|
|
|
|
|
|
|
|
|
let start_of_year = str_to_filetime("%Y%m%d%H%M", "201501010000");
|
|
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
2025-04-08 13:25:12 -04:00
|
|
|
|
assert_ne!(atime, mtime);
|
2023-07-08 16:13:35 +02:00
|
|
|
|
assert_eq!(atime.unix_seconds() - start_of_year.unix_seconds(), 45240);
|
|
|
|
|
|
}
|
2015-08-11 21:38:10 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-11-21 09:53:13 +01:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_only_mtime_failed() {
|
|
|
|
|
|
let file = "test_touch_set_only_mtime";
|
|
|
|
|
|
|
2025-09-10 11:28:23 +02:00
|
|
|
|
new_ucmd!()
|
|
|
|
|
|
.args(&["-t", "2015010112342", "-m", file])
|
|
|
|
|
|
.fails();
|
2020-11-21 09:53:13 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-03-13 17:20:39 +01:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_both_time_and_reference() {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
let ref_file = "test_touch_reference";
|
|
|
|
|
|
let file = "test_touch_set_both_time_and_reference";
|
|
|
|
|
|
|
|
|
|
|
|
let start_of_year = str_to_filetime("%Y%m%d%H%M", "201501010000");
|
|
|
|
|
|
|
|
|
|
|
|
at.touch(ref_file);
|
|
|
|
|
|
set_file_times(&at, ref_file, start_of_year, start_of_year);
|
|
|
|
|
|
assert!(at.file_exists(ref_file));
|
|
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["-t", "2015010112342", "-r", ref_file, file])
|
|
|
|
|
|
.fails();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_both_date_and_reference() {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
let ref_file = "test_touch_reference";
|
|
|
|
|
|
let file = "test_touch_set_both_date_and_reference";
|
|
|
|
|
|
|
2023-04-07 21:36:26 +02:00
|
|
|
|
let start_of_year = str_to_filetime("%Y%m%d%H%M", "201501011234");
|
2021-03-13 17:20:39 +01:00
|
|
|
|
|
|
|
|
|
|
at.touch(ref_file);
|
|
|
|
|
|
set_file_times(&at, ref_file, start_of_year, start_of_year);
|
|
|
|
|
|
assert!(at.file_exists(ref_file));
|
|
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["-d", "Thu Jan 01 12:34:00 2015", "-r", ref_file, file])
|
2023-04-07 21:36:26 +02:00
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
|
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
|
|
|
|
|
assert_eq!(atime, start_of_year);
|
|
|
|
|
|
assert_eq!(mtime, start_of_year);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_both_offset_date_and_reference() {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
let ref_file = "test_touch_reference";
|
|
|
|
|
|
let file = "test_touch_set_both_date_and_reference";
|
|
|
|
|
|
|
|
|
|
|
|
let start_of_year = str_to_filetime("%Y%m%d%H%M", "201501011234");
|
|
|
|
|
|
let five_days_later = str_to_filetime("%Y%m%d%H%M", "201501061234");
|
|
|
|
|
|
|
|
|
|
|
|
at.touch(ref_file);
|
|
|
|
|
|
set_file_times(&at, ref_file, start_of_year, start_of_year);
|
|
|
|
|
|
assert!(at.file_exists(ref_file));
|
|
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["-d", "+5 days", "-r", ref_file, file])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
|
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
|
|
|
|
|
assert_eq!(atime, five_days_later);
|
|
|
|
|
|
assert_eq!(mtime, five_days_later);
|
2021-03-13 17:20:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_both_time_and_date() {
|
|
|
|
|
|
let file = "test_touch_set_both_time_and_date";
|
|
|
|
|
|
|
2025-09-10 11:28:23 +02:00
|
|
|
|
new_ucmd!()
|
|
|
|
|
|
.args(&[
|
|
|
|
|
|
"-t",
|
|
|
|
|
|
"2015010112342",
|
|
|
|
|
|
"-d",
|
|
|
|
|
|
"Thu Jan 01 12:34:00 2015",
|
|
|
|
|
|
file,
|
|
|
|
|
|
])
|
|
|
|
|
|
.fails();
|
2021-03-13 17:20:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-08-11 21:38:10 -04:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_only_mtime() {
|
2024-04-01 08:06:18 +02:00
|
|
|
|
let mtime_args = ["-m", "--time=modify", "--time=mtime", "--time=m"];
|
2015-08-11 21:38:10 -04:00
|
|
|
|
let file = "test_touch_set_only_mtime";
|
|
|
|
|
|
|
2023-07-08 16:13:35 +02:00
|
|
|
|
for mtime_arg in mtime_args {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2023-07-08 16:13:35 +02:00
|
|
|
|
ucmd.args(&["-t", "201501011234", mtime_arg, file])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2023-07-08 16:13:35 +02:00
|
|
|
|
assert!(at.file_exists(file));
|
|
|
|
|
|
|
|
|
|
|
|
let start_of_year = str_to_filetime("%Y%m%d%H%M", "201501010000");
|
|
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
2025-04-08 13:25:12 -04:00
|
|
|
|
assert_ne!(atime, mtime);
|
2023-07-08 16:13:35 +02:00
|
|
|
|
assert_eq!(mtime.unix_seconds() - start_of_year.unix_seconds(), 45240);
|
|
|
|
|
|
}
|
2015-08-11 21:38:10 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_both() {
|
2016-08-23 07:52:43 -04:00
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
let file = "test_touch_set_both";
|
|
|
|
|
|
|
2020-04-13 20:36:03 +02:00
|
|
|
|
ucmd.args(&["-t", "201501011234", "-a", "-m", file])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2015-11-16 00:25:01 -05:00
|
|
|
|
assert!(at.file_exists(file));
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
|
|
|
|
|
let start_of_year = str_to_filetime("%Y%m%d%H%M", "201501010000");
|
2015-11-16 00:25:01 -05:00
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
2015-08-11 21:38:10 -04:00
|
|
|
|
assert_eq!(atime, mtime);
|
2020-04-13 20:36:03 +02:00
|
|
|
|
assert_eq!(atime.unix_seconds() - start_of_year.unix_seconds(), 45240);
|
|
|
|
|
|
assert_eq!(mtime.unix_seconds() - start_of_year.unix_seconds(), 45240);
|
2015-08-11 21:38:10 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-08-28 07:12:58 +08:00
|
|
|
|
#[test]
|
2021-08-24 08:53:20 +02:00
|
|
|
|
// FixME: Fails on freebsd because of a different nanos
|
|
|
|
|
|
#[cfg(not(target_os = "freebsd"))]
|
2016-08-28 07:12:58 +08:00
|
|
|
|
fn test_touch_no_dereference() {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
let file_a = "test_touch_no_dereference_a";
|
|
|
|
|
|
let file_b = "test_touch_no_dereference_b";
|
|
|
|
|
|
let start_of_year = str_to_filetime("%Y%m%d%H%M", "201501010000");
|
|
|
|
|
|
let end_of_year = str_to_filetime("%Y%m%d%H%M", "201512312359");
|
|
|
|
|
|
|
|
|
|
|
|
at.touch(file_a);
|
|
|
|
|
|
set_file_times(&at, file_a, start_of_year, start_of_year);
|
2018-11-12 22:55:25 -06:00
|
|
|
|
at.symlink_file(file_a, file_b);
|
2016-08-28 07:12:58 +08:00
|
|
|
|
assert!(at.file_exists(file_a));
|
|
|
|
|
|
assert!(at.is_symlink(file_b));
|
|
|
|
|
|
|
2020-04-13 20:36:03 +02:00
|
|
|
|
ucmd.args(&["-t", "201512312359", "-h", file_b])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
2016-08-28 07:12:58 +08:00
|
|
|
|
|
|
|
|
|
|
let (atime, mtime) = get_symlink_times(&at, file_b);
|
|
|
|
|
|
assert_eq!(atime, mtime);
|
|
|
|
|
|
assert_eq!(atime, end_of_year);
|
|
|
|
|
|
assert_eq!(mtime, end_of_year);
|
|
|
|
|
|
|
|
|
|
|
|
let (atime, mtime) = get_file_times(&at, file_a);
|
|
|
|
|
|
assert_eq!(atime, mtime);
|
|
|
|
|
|
assert_eq!(atime, start_of_year);
|
|
|
|
|
|
assert_eq!(mtime, start_of_year);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-08-11 21:38:10 -04:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_reference() {
|
2025-07-01 01:52:57 +02:00
|
|
|
|
let scenario = TestScenario::new(util_name!());
|
2021-09-09 21:48:17 +02:00
|
|
|
|
let (at, mut _ucmd) = (scenario.fixtures.clone(), scenario.ucmd());
|
2015-08-11 21:38:10 -04:00
|
|
|
|
let file_a = "test_touch_reference_a";
|
|
|
|
|
|
let file_b = "test_touch_reference_b";
|
|
|
|
|
|
let start_of_year = str_to_filetime("%Y%m%d%H%M", "201501010000");
|
|
|
|
|
|
|
2015-11-16 00:25:01 -05:00
|
|
|
|
at.touch(file_a);
|
|
|
|
|
|
set_file_times(&at, file_a, start_of_year, start_of_year);
|
|
|
|
|
|
assert!(at.file_exists(file_a));
|
2022-04-02 10:47:37 +02:00
|
|
|
|
for opt in ["-r", "--ref", "--reference"] {
|
2021-09-09 21:48:17 +02:00
|
|
|
|
scenario
|
|
|
|
|
|
.ccmd("touch")
|
|
|
|
|
|
.args(&[opt, file_a, file_b])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2021-09-09 21:48:17 +02:00
|
|
|
|
assert!(at.file_exists(file_b));
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2021-09-09 21:48:17 +02:00
|
|
|
|
let (atime, mtime) = get_file_times(&at, file_b);
|
|
|
|
|
|
assert_eq!(atime, mtime);
|
|
|
|
|
|
assert_eq!(atime, start_of_year);
|
|
|
|
|
|
assert_eq!(mtime, start_of_year);
|
|
|
|
|
|
let _ = remove_file(file_b);
|
|
|
|
|
|
}
|
2015-08-11 21:38:10 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-19 19:34:35 -08:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_reference_dangling() {
|
|
|
|
|
|
let temp_dir = tempfile::tempdir().unwrap();
|
|
|
|
|
|
let nonexistent_target = temp_dir.path().join("nonexistent_target");
|
|
|
|
|
|
let dangling_symlink = temp_dir.path().join("test_touch_reference_dangling");
|
|
|
|
|
|
|
2025-12-19 20:56:15 -08:00
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
|
|
{
|
|
|
|
|
|
std::os::unix::fs::symlink(&nonexistent_target, &dangling_symlink).unwrap();
|
|
|
|
|
|
}
|
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
|
{
|
|
|
|
|
|
std::os::windows::fs::symlink_file(&nonexistent_target, &dangling_symlink).unwrap();
|
|
|
|
|
|
}
|
2025-12-19 19:34:35 -08:00
|
|
|
|
|
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
|
.args(&[
|
|
|
|
|
|
"--reference",
|
|
|
|
|
|
dangling_symlink.to_str().unwrap(),
|
|
|
|
|
|
"some_file",
|
|
|
|
|
|
])
|
2025-12-19 20:55:46 -08:00
|
|
|
|
.fails()
|
|
|
|
|
|
.stderr_contains("touch: failed to get attributes of");
|
2025-12-19 19:34:35 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-08-11 21:38:10 -04:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_date() {
|
2016-08-23 07:52:43 -04:00
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
let file = "test_touch_set_date";
|
|
|
|
|
|
|
2020-04-13 20:36:03 +02:00
|
|
|
|
ucmd.args(&["-d", "Thu Jan 01 12:34:00 2015", file])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
2015-11-16 00:25:01 -05:00
|
|
|
|
assert!(at.file_exists(file));
|
2015-08-11 21:38:10 -04:00
|
|
|
|
|
|
|
|
|
|
let start_of_year = str_to_filetime("%Y%m%d%H%M", "201501011234");
|
2015-11-16 00:25:01 -05:00
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
2015-08-11 21:38:10 -04:00
|
|
|
|
assert_eq!(atime, mtime);
|
|
|
|
|
|
assert_eq!(atime, start_of_year);
|
|
|
|
|
|
assert_eq!(mtime, start_of_year);
|
|
|
|
|
|
}
|
2021-04-17 04:08:10 -04:00
|
|
|
|
|
2021-05-31 20:13:58 +08:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_date2() {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
let file = "test_touch_set_date";
|
|
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["-d", "2000-01-23", file])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
|
|
|
|
|
|
|
|
|
|
|
assert!(at.file_exists(file));
|
|
|
|
|
|
|
|
|
|
|
|
let start_of_year = str_to_filetime("%Y%m%d%H%M", "200001230000");
|
|
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
|
|
|
|
|
assert_eq!(atime, mtime);
|
|
|
|
|
|
assert_eq!(atime, start_of_year);
|
|
|
|
|
|
assert_eq!(mtime, start_of_year);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-06-15 21:52:47 +02:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_date3() {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
let file = "test_touch_set_date";
|
|
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["-d", "@1623786360", file])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
|
|
|
|
|
|
|
|
|
|
|
assert!(at.file_exists(file));
|
|
|
|
|
|
|
2023-03-19 15:01:59 +01:00
|
|
|
|
let expected = FileTime::from_unix_time(1_623_786_360, 0);
|
2021-06-15 21:52:47 +02:00
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
|
|
|
|
|
assert_eq!(atime, mtime);
|
|
|
|
|
|
assert_eq!(atime, expected);
|
|
|
|
|
|
assert_eq!(mtime, expected);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-04-29 10:32:28 +02:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_date4() {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
let file = "test_touch_set_date";
|
|
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["-d", "1970-01-01 18:43:33", file])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
|
|
|
|
|
|
|
|
|
|
|
assert!(at.file_exists(file));
|
|
|
|
|
|
|
2022-05-05 22:48:37 +02:00
|
|
|
|
let expected = FileTime::from_unix_time(67413, 0);
|
2022-04-29 10:32:28 +02:00
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
|
|
|
|
|
assert_eq!(atime, mtime);
|
|
|
|
|
|
assert_eq!(atime, expected);
|
|
|
|
|
|
assert_eq!(mtime, expected);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_date5() {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
let file = "test_touch_set_date";
|
|
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["-d", "1970-01-01 18:43:33.023456789", file])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
|
|
|
|
|
|
|
|
|
|
|
assert!(at.file_exists(file));
|
|
|
|
|
|
|
2022-05-05 22:48:37 +02:00
|
|
|
|
// Slightly different result on Windows for nano seconds
|
|
|
|
|
|
// TODO: investigate
|
|
|
|
|
|
#[cfg(windows)]
|
2023-03-22 16:48:53 +01:00
|
|
|
|
let expected = FileTime::from_unix_time(67413, 23_456_700);
|
2022-05-05 22:48:37 +02:00
|
|
|
|
#[cfg(not(windows))]
|
2023-03-19 15:01:59 +01:00
|
|
|
|
let expected = FileTime::from_unix_time(67413, 23_456_789);
|
2022-05-05 22:48:37 +02:00
|
|
|
|
|
2022-04-29 10:32:28 +02:00
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
|
|
|
|
|
assert_eq!(atime, mtime);
|
|
|
|
|
|
assert_eq!(atime, expected);
|
|
|
|
|
|
assert_eq!(mtime, expected);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-05-08 21:31:42 +02:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_date6() {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
let file = "test_touch_set_date";
|
|
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["-d", "2000-01-01 00:00", file])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
|
|
|
|
|
|
|
|
|
|
|
assert!(at.file_exists(file));
|
|
|
|
|
|
|
2023-03-19 15:01:59 +01:00
|
|
|
|
let expected = FileTime::from_unix_time(946_684_800, 0);
|
2022-05-08 21:31:42 +02:00
|
|
|
|
|
|
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
|
|
|
|
|
assert_eq!(atime, mtime);
|
|
|
|
|
|
assert_eq!(atime, expected);
|
|
|
|
|
|
assert_eq!(mtime, expected);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-05-08 21:52:12 +02:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_date7() {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
let file = "test_touch_set_date";
|
|
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["-d", "2004-01-16 12:00 +0000", file])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
|
|
|
|
|
|
|
|
|
|
|
assert!(at.file_exists(file));
|
|
|
|
|
|
|
2023-03-19 15:01:59 +01:00
|
|
|
|
let expected = FileTime::from_unix_time(1_074_254_400, 0);
|
2022-05-08 21:52:12 +02:00
|
|
|
|
|
|
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
|
|
|
|
|
assert_eq!(atime, mtime);
|
|
|
|
|
|
assert_eq!(atime, expected);
|
|
|
|
|
|
assert_eq!(mtime, expected);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-11-27 23:08:56 -05:00
|
|
|
|
/// Test for setting the date by a relative time unit.
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_date_relative_smoke() {
|
|
|
|
|
|
// From the GNU documentation:
|
|
|
|
|
|
//
|
|
|
|
|
|
// > The unit of time displacement may be selected by the string
|
|
|
|
|
|
// > ‘year’ or ‘month’ for moving by whole years or months. These
|
|
|
|
|
|
// > are fuzzy units, as years and months are not all of equal
|
|
|
|
|
|
// > duration. More precise units are ‘fortnight’ which is worth 14
|
|
|
|
|
|
// > days, ‘week’ worth 7 days, ‘day’ worth 24 hours, ‘hour’ worth
|
|
|
|
|
|
// > 60 minutes, ‘minute’ or ‘min’ worth 60 seconds, and ‘second’ or
|
|
|
|
|
|
// > ‘sec’ worth one second. An ‘s’ suffix on these units is
|
|
|
|
|
|
// > accepted and ignored.
|
|
|
|
|
|
//
|
|
|
|
|
|
let times = [
|
|
|
|
|
|
// "-1 year", "+1 year", "-1 years", "+1 years",
|
|
|
|
|
|
// "-1 month", "+1 month", "-1 months", "+1 months",
|
|
|
|
|
|
"-1 fortnight",
|
|
|
|
|
|
"+1 fortnight",
|
|
|
|
|
|
"-1 fortnights",
|
|
|
|
|
|
"+1 fortnights",
|
|
|
|
|
|
"fortnight",
|
|
|
|
|
|
"fortnights",
|
|
|
|
|
|
"-1 week",
|
|
|
|
|
|
"+1 week",
|
|
|
|
|
|
"-1 weeks",
|
|
|
|
|
|
"+1 weeks",
|
|
|
|
|
|
"week",
|
|
|
|
|
|
"weeks",
|
|
|
|
|
|
"-1 day",
|
|
|
|
|
|
"+1 day",
|
|
|
|
|
|
"-1 days",
|
|
|
|
|
|
"+1 days",
|
|
|
|
|
|
"day",
|
|
|
|
|
|
"days",
|
|
|
|
|
|
"-1 hour",
|
|
|
|
|
|
"+1 hour",
|
|
|
|
|
|
"-1 hours",
|
|
|
|
|
|
"+1 hours",
|
|
|
|
|
|
"hour",
|
|
|
|
|
|
"hours",
|
|
|
|
|
|
"-1 minute",
|
|
|
|
|
|
"+1 minute",
|
|
|
|
|
|
"-1 minutes",
|
|
|
|
|
|
"+1 minutes",
|
|
|
|
|
|
"minute",
|
|
|
|
|
|
"minutes",
|
|
|
|
|
|
"-1 min",
|
|
|
|
|
|
"+1 min",
|
|
|
|
|
|
"-1 mins",
|
|
|
|
|
|
"+1 mins",
|
|
|
|
|
|
"min",
|
|
|
|
|
|
"mins",
|
|
|
|
|
|
"-1 second",
|
|
|
|
|
|
"+1 second",
|
|
|
|
|
|
"-1 seconds",
|
|
|
|
|
|
"+1 seconds",
|
|
|
|
|
|
"second",
|
|
|
|
|
|
"seconds",
|
|
|
|
|
|
"-1 sec",
|
|
|
|
|
|
"+1 sec",
|
|
|
|
|
|
"-1 secs",
|
|
|
|
|
|
"+1 secs",
|
|
|
|
|
|
"sec",
|
|
|
|
|
|
"secs",
|
|
|
|
|
|
];
|
|
|
|
|
|
for time in times {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
at.touch("f");
|
|
|
|
|
|
ucmd.args(&["-d", time, "f"])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr()
|
|
|
|
|
|
.no_stdout();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// From the GNU documentation:
|
|
|
|
|
|
//
|
|
|
|
|
|
// > The string ‘tomorrow’ is worth one day in the future
|
|
|
|
|
|
// > (equivalent to ‘day’), the string ‘yesterday’ is worth one day
|
|
|
|
|
|
// > in the past (equivalent to ‘day ago’).
|
|
|
|
|
|
//
|
2023-04-23 23:15:32 +02:00
|
|
|
|
let times = [
|
|
|
|
|
|
"yesterday",
|
|
|
|
|
|
"tomorrow",
|
|
|
|
|
|
"now",
|
|
|
|
|
|
"2 seconds",
|
|
|
|
|
|
"2 years 1 week",
|
|
|
|
|
|
"2 days ago",
|
2025-08-01 10:23:30 +02:00
|
|
|
|
"2 months 1 second",
|
|
|
|
|
|
"a",
|
2023-04-23 23:15:32 +02:00
|
|
|
|
];
|
2022-11-27 23:08:56 -05:00
|
|
|
|
for time in times {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
at.touch("f");
|
|
|
|
|
|
ucmd.args(&["-d", time, "f"])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr()
|
|
|
|
|
|
.no_stdout();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-31 20:13:58 +08:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_set_date_wrong_format() {
|
|
|
|
|
|
let file = "test_touch_set_date_wrong_format";
|
|
|
|
|
|
|
2025-09-10 11:28:23 +02:00
|
|
|
|
new_ucmd!()
|
|
|
|
|
|
.args(&["-d", "2005-43-21", file])
|
2021-05-31 20:13:58 +08:00
|
|
|
|
.fails()
|
|
|
|
|
|
.stderr_contains("Unable to parse date: 2005-43-21");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-04-17 04:08:10 -04:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_mtime_dst_succeeds() {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
let file = "test_touch_set_mtime_dst_succeeds";
|
|
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["-m", "-t", "202103140300", file])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
|
|
|
|
|
|
|
|
|
|
|
assert!(at.file_exists(file));
|
|
|
|
|
|
|
|
|
|
|
|
let target_time = str_to_filetime("%Y%m%d%H%M", "202103140300");
|
|
|
|
|
|
let (_, mtime) = get_file_times(&at, file);
|
2022-03-23 08:51:09 +01:00
|
|
|
|
assert_eq!(target_time, mtime);
|
2021-04-17 04:08:10 -04:00
|
|
|
|
}
|
2021-04-18 16:36:43 -04:00
|
|
|
|
|
|
|
|
|
|
#[test]
|
2023-03-24 11:51:38 +01:00
|
|
|
|
#[cfg(unix)]
|
2021-04-18 16:36:43 -04:00
|
|
|
|
fn test_touch_mtime_dst_fails() {
|
|
|
|
|
|
let file = "test_touch_set_mtime_dst_fails";
|
|
|
|
|
|
|
2023-03-23 18:16:57 +01:00
|
|
|
|
// Some timezones use daylight savings time, this leads to problems if the
|
|
|
|
|
|
// specified time is within the jump forward. In EST (UTC-5), there is a
|
|
|
|
|
|
// jump from 1:59AM to 3:00AM on, March 8 2020, so any thing in-between is
|
|
|
|
|
|
// invalid.
|
|
|
|
|
|
// See https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
|
|
|
|
|
|
// for information on the TZ variable, which where the string is copied from.
|
2025-09-10 11:28:23 +02:00
|
|
|
|
new_ucmd!()
|
|
|
|
|
|
.env("TZ", "EST+5EDT,M3.2.0/2,M11.1.0/2")
|
2023-03-23 18:16:57 +01:00
|
|
|
|
.args(&["-m", "-t", "202003080200", file])
|
|
|
|
|
|
.fails();
|
2021-04-18 16:36:43 -04:00
|
|
|
|
}
|
2021-06-02 22:53:10 +02:00
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
#[cfg(unix)]
|
|
|
|
|
|
fn test_touch_system_fails() {
|
|
|
|
|
|
let file = "/";
|
2025-09-10 11:28:23 +02:00
|
|
|
|
new_ucmd!()
|
|
|
|
|
|
.args(&[file])
|
2021-06-02 22:53:10 +02:00
|
|
|
|
.fails()
|
|
|
|
|
|
.stderr_contains("setting times of '/'");
|
|
|
|
|
|
}
|
2021-06-02 23:43:16 +02:00
|
|
|
|
|
|
|
|
|
|
#[test]
|
2024-06-30 19:00:54 +02:00
|
|
|
|
#[cfg(not(target_os = "windows"))]
|
2021-06-02 23:43:16 +02:00
|
|
|
|
fn test_touch_trailing_slash() {
|
|
|
|
|
|
let file = "no-file/";
|
2025-09-10 11:28:23 +02:00
|
|
|
|
new_ucmd!().args(&[file]).fails().stderr_only(format!(
|
2024-06-30 19:00:54 +02:00
|
|
|
|
"touch: cannot touch '{file}': No such file or directory\n"
|
|
|
|
|
|
));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
|
|
fn test_touch_trailing_slash_windows() {
|
|
|
|
|
|
let file = "no-file/";
|
2025-09-10 11:28:23 +02:00
|
|
|
|
new_ucmd!()
|
|
|
|
|
|
.args(&[file])
|
2025-09-10 09:44:52 +02:00
|
|
|
|
.fails()
|
|
|
|
|
|
.stderr_contains(format!("touch: cannot touch '{file}'"));
|
2021-06-02 23:43:16 +02:00
|
|
|
|
}
|
2021-06-12 13:28:21 +02:00
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_no_such_file_error_msg() {
|
|
|
|
|
|
let dirname = "nonexistent";
|
|
|
|
|
|
let filename = "file";
|
|
|
|
|
|
let path = PathBuf::from(dirname).join(filename);
|
|
|
|
|
|
let path_str = path.to_str().unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
new_ucmd!().arg(&path).fails().stderr_only(format!(
|
2023-01-27 10:29:45 +01:00
|
|
|
|
"touch: cannot touch '{path_str}': No such file or directory\n"
|
2021-06-12 13:28:21 +02:00
|
|
|
|
));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-03-06 14:00:42 -08:00
|
|
|
|
#[test]
|
2024-07-06 22:29:20 +02:00
|
|
|
|
#[cfg(not(any(target_os = "freebsd", target_os = "openbsd")))]
|
2022-03-06 14:00:42 -08:00
|
|
|
|
fn test_touch_changes_time_of_file_in_stdout() {
|
|
|
|
|
|
// command like: `touch - 1< ./c`
|
|
|
|
|
|
// should change the timestamp of c
|
|
|
|
|
|
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
let file = "test_touch_changes_time_of_file_in_stdout";
|
|
|
|
|
|
|
|
|
|
|
|
at.touch(file);
|
|
|
|
|
|
assert!(at.file_exists(file));
|
|
|
|
|
|
let (_, mtime) = get_file_times(&at, file);
|
|
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["-"])
|
|
|
|
|
|
.set_stdout(at.make_file(file))
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
|
|
|
|
|
|
|
|
|
|
|
let (_, mtime_after) = get_file_times(&at, file);
|
2025-04-08 13:25:12 -04:00
|
|
|
|
assert_ne!(mtime_after, mtime);
|
2022-03-06 14:00:42 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-06-12 13:28:21 +02:00
|
|
|
|
#[test]
|
|
|
|
|
|
#[cfg(unix)]
|
|
|
|
|
|
fn test_touch_permission_denied_error_msg() {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
|
|
|
|
|
|
let dirname = "dir_with_read_only_access";
|
|
|
|
|
|
let filename = "file";
|
|
|
|
|
|
let path = PathBuf::from(dirname).join(filename);
|
|
|
|
|
|
let path_str = path.to_str().unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
// create dest without write permissions
|
|
|
|
|
|
at.mkdir(dirname);
|
|
|
|
|
|
at.set_readonly(dirname);
|
|
|
|
|
|
|
|
|
|
|
|
let full_path = at.plus_as_string(path_str);
|
|
|
|
|
|
ucmd.arg(&full_path).fails().stderr_only(format!(
|
2025-04-07 22:56:21 -04:00
|
|
|
|
"touch: cannot touch '{full_path}': Permission denied\n",
|
2021-06-12 13:28:21 +02:00
|
|
|
|
));
|
|
|
|
|
|
}
|
2022-02-03 21:14:56 +08:00
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_no_args() {
|
|
|
|
|
|
let mut ucmd = new_ucmd!();
|
2023-01-08 12:39:49 -06:00
|
|
|
|
ucmd.fails().no_stdout().usage_error("missing file operand");
|
2022-02-03 21:14:56 +08:00
|
|
|
|
}
|
2022-02-10 20:51:33 -05:00
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_no_dereference_no_file() {
|
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
|
.args(&["-h", "not-a-file"])
|
|
|
|
|
|
.fails()
|
|
|
|
|
|
.stderr_contains("setting times of 'not-a-file': No such file or directory");
|
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
|
.args(&["-h", "not-a-file-1", "not-a-file-2"])
|
|
|
|
|
|
.fails()
|
|
|
|
|
|
.stderr_contains("setting times of 'not-a-file-1': No such file or directory")
|
|
|
|
|
|
.stderr_contains("setting times of 'not-a-file-2': No such file or directory");
|
|
|
|
|
|
}
|
2022-04-29 10:28:49 +02:00
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_leap_second() {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
let file = "test_touch_leap_sec";
|
|
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["-t", "197001010000.60", file])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_stderr();
|
|
|
|
|
|
|
|
|
|
|
|
assert!(at.file_exists(file));
|
|
|
|
|
|
|
|
|
|
|
|
let epoch = str_to_filetime("%Y%m%d%H%M", "197001010000");
|
|
|
|
|
|
let (atime, mtime) = get_file_times(&at, file);
|
|
|
|
|
|
assert_eq!(atime, mtime);
|
|
|
|
|
|
assert_eq!(atime.unix_seconds() - epoch.unix_seconds(), 60);
|
|
|
|
|
|
assert_eq!(mtime.unix_seconds() - epoch.unix_seconds(), 60);
|
|
|
|
|
|
}
|
2022-08-01 10:05:31 +03:00
|
|
|
|
|
|
|
|
|
|
#[test]
|
2022-08-07 11:06:25 +03:00
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
|
|
// File::create doesn't support trailing separator in Windows
|
2022-08-01 10:05:31 +03:00
|
|
|
|
fn test_touch_trailing_slash_no_create() {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
at.touch("file");
|
2025-03-01 15:29:11 +01:00
|
|
|
|
ucmd.args(&["-c", "file/"]).fails_with_code(1);
|
2022-08-01 10:05:31 +03:00
|
|
|
|
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
ucmd.args(&["-c", "no-file/"]).succeeds();
|
|
|
|
|
|
assert!(
|
|
|
|
|
|
!at.file_exists("no-file") && !at.dir_exists("no-file") && !at.symlink_exists("no-file")
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
at.relative_symlink_file("nowhere", "dangling");
|
|
|
|
|
|
ucmd.args(&["-c", "dangling/"]).succeeds();
|
|
|
|
|
|
assert!(!at.file_exists("nowhere"));
|
|
|
|
|
|
assert!(at.symlink_exists("dangling"));
|
|
|
|
|
|
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
at.relative_symlink_file("loop", "loop");
|
2025-03-01 15:29:11 +01:00
|
|
|
|
ucmd.args(&["-c", "loop/"]).fails_with_code(1);
|
2022-08-01 10:05:31 +03:00
|
|
|
|
assert!(!at.file_exists("loop"));
|
|
|
|
|
|
|
2022-08-07 11:06:25 +03:00
|
|
|
|
#[cfg(not(target_os = "macos"))]
|
|
|
|
|
|
// MacOS supports trailing slash for symlinks to files
|
|
|
|
|
|
{
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
at.touch("file2");
|
|
|
|
|
|
at.relative_symlink_file("file2", "link1");
|
2025-03-01 15:29:11 +01:00
|
|
|
|
ucmd.args(&["-c", "link1/"]).fails_with_code(1);
|
2022-08-07 11:06:25 +03:00
|
|
|
|
assert!(at.file_exists("file2"));
|
|
|
|
|
|
assert!(at.symlink_exists("link1"));
|
|
|
|
|
|
}
|
2022-08-01 10:05:31 +03:00
|
|
|
|
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
at.mkdir("dir");
|
|
|
|
|
|
ucmd.args(&["-c", "dir/"]).succeeds();
|
|
|
|
|
|
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
at.mkdir("dir2");
|
|
|
|
|
|
at.relative_symlink_dir("dir2", "link2");
|
|
|
|
|
|
ucmd.args(&["-c", "link2/"]).succeeds();
|
|
|
|
|
|
}
|
2023-04-21 23:54:08 +02:00
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_no_dereference_ref_dangling() {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
at.touch("file");
|
|
|
|
|
|
at.relative_symlink_file("nowhere", "dangling");
|
|
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["-h", "-r", "dangling", "file"]).succeeds();
|
|
|
|
|
|
}
|
2023-04-22 08:56:01 +02:00
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_no_dereference_dangling() {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
at.relative_symlink_file("nowhere", "dangling");
|
|
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["-h", "dangling"]).succeeds();
|
|
|
|
|
|
}
|
2023-04-22 18:54:43 +02:00
|
|
|
|
|
|
|
|
|
|
#[test]
|
2024-07-06 22:29:20 +02:00
|
|
|
|
#[cfg(not(target_os = "openbsd"))]
|
2023-04-22 18:54:43 +02:00
|
|
|
|
fn test_touch_dash() {
|
2025-09-10 11:28:23 +02:00
|
|
|
|
new_ucmd!().args(&["-h", "-"]).succeeds().no_output();
|
2023-04-22 18:54:43 +02:00
|
|
|
|
}
|
2023-10-01 12:01:46 -04:00
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_invalid_date_format() {
|
|
|
|
|
|
let file = "test_touch_invalid_date_format";
|
|
|
|
|
|
|
2025-09-10 11:28:23 +02:00
|
|
|
|
new_ucmd!()
|
|
|
|
|
|
.args(&["-m", "-t", "+1000000000000 years", file])
|
2023-10-01 12:01:46 -04:00
|
|
|
|
.fails()
|
2024-02-20 04:07:32 +01:00
|
|
|
|
.stderr_contains("touch: invalid date format '+1000000000000 years'");
|
2023-10-01 12:01:46 -04:00
|
|
|
|
}
|
2024-03-10 03:05:59 -04:00
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
#[cfg(not(target_os = "freebsd"))]
|
|
|
|
|
|
fn test_touch_symlink_with_no_deref() {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
let target = "foo.txt";
|
|
|
|
|
|
let symlink = "bar.txt";
|
|
|
|
|
|
let time = FileTime::from_unix_time(123, 0);
|
|
|
|
|
|
|
|
|
|
|
|
at.touch(target);
|
|
|
|
|
|
at.relative_symlink_file(target, symlink);
|
|
|
|
|
|
set_symlink_file_times(at.plus(symlink), time, time).unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["-a", "--no-dereference", symlink]).succeeds();
|
|
|
|
|
|
// Modification time shouldn't be set to the destination's modification time
|
|
|
|
|
|
assert_eq!(time, get_symlink_times(&at, symlink).1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
#[cfg(not(target_os = "freebsd"))]
|
|
|
|
|
|
fn test_touch_reference_symlink_with_no_deref() {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
let target = "foo.txt";
|
|
|
|
|
|
let symlink = "bar.txt";
|
|
|
|
|
|
let arg = "baz.txt";
|
|
|
|
|
|
let time = FileTime::from_unix_time(123, 0);
|
|
|
|
|
|
|
|
|
|
|
|
at.touch(target);
|
|
|
|
|
|
at.relative_symlink_file(target, symlink);
|
|
|
|
|
|
set_symlink_file_times(at.plus(symlink), time, time).unwrap();
|
|
|
|
|
|
at.touch(arg);
|
|
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["--reference", symlink, "--no-dereference", arg])
|
|
|
|
|
|
.succeeds();
|
|
|
|
|
|
// Times should be taken from the symlink, not the destination
|
|
|
|
|
|
assert_eq!((time, time), get_symlink_times(&at, arg));
|
|
|
|
|
|
}
|
2025-02-03 20:24:45 -05:00
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_obsolete_posix_format() {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
ucmd.env("_POSIX2_VERSION", "199209")
|
|
|
|
|
|
.env("POSIXLY_CORRECT", "1")
|
|
|
|
|
|
.args(&["01010000", "11111111"])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_output();
|
|
|
|
|
|
assert!(at.file_exists("11111111"));
|
|
|
|
|
|
assert!(!at.file_exists("01010000"));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_obsolete_posix_format_with_year() {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
ucmd.env("_POSIX2_VERSION", "199209")
|
|
|
|
|
|
.env("POSIXLY_CORRECT", "1")
|
2025-02-06 22:02:47 -05:00
|
|
|
|
.args(&["0101000090", "11111111"])
|
2025-02-03 20:24:45 -05:00
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_output();
|
|
|
|
|
|
assert!(at.file_exists("11111111"));
|
2025-02-06 22:02:47 -05:00
|
|
|
|
assert!(!at.file_exists("0101000090"));
|
2025-02-03 20:24:45 -05:00
|
|
|
|
}
|
2025-06-29 07:26:33 -06:00
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_touch_f_option() {
|
|
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
|
|
let file = "test_f_option.txt";
|
|
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["-f", file]).succeeds().no_output();
|
|
|
|
|
|
|
|
|
|
|
|
assert!(at.file_exists(file));
|
|
|
|
|
|
at.remove(file);
|
|
|
|
|
|
}
|
2025-08-08 11:07:26 +02:00
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
|
|
fn test_touch_non_utf8_paths() {
|
|
|
|
|
|
use std::ffi::OsStr;
|
|
|
|
|
|
use std::os::unix::ffi::OsStrExt;
|
|
|
|
|
|
|
|
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
|
|
let at = &scene.fixtures;
|
2025-08-13 20:29:13 +02:00
|
|
|
|
|
2025-08-08 11:07:26 +02:00
|
|
|
|
let non_utf8_bytes = b"test_\xFF\xFE.txt";
|
|
|
|
|
|
let non_utf8_name = OsStr::from_bytes(non_utf8_bytes);
|
2025-08-13 20:29:13 +02:00
|
|
|
|
|
2025-08-12 00:18:18 +02:00
|
|
|
|
scene.ucmd().arg(non_utf8_name).succeeds().no_output();
|
2025-08-08 11:07:26 +02:00
|
|
|
|
assert!(std::fs::metadata(at.plus(non_utf8_name)).is_ok());
|
|
|
|
|
|
}
|
2025-12-31 20:09:14 +01:00
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
#[cfg(target_os = "linux")]
|
2026-01-12 20:15:22 +09:00
|
|
|
|
fn test_touch_device_files() {
|
2025-12-31 20:09:14 +01:00
|
|
|
|
let (_, mut ucmd) = at_and_ucmd!();
|
2026-01-12 20:15:22 +09:00
|
|
|
|
ucmd.args(&["/dev/null", "/dev/zero", "/dev/full", "/dev/random"])
|
|
|
|
|
|
.succeeds()
|
|
|
|
|
|
.no_output();
|
2025-12-31 20:09:14 +01:00
|
|
|
|
}
|