commit: 2b7c2e96b970a727f4d3a5956dc6175a54af1c80
parent 7388639c77f0a4760932fcef994bf8aa7ff73aaf
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Sat, 3 Jun 2023 11:18:59 +0200
cmd/touch: Use utimensat on directories
Diffstat:
3 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/cmd/touch.1 b/cmd/touch.1
@@ -78,9 +78,7 @@ is mostly compliant with the
.St -p1003.1-2008
specification.
.Fl t
-is intentionally missing and
-.Xr futimens 3
-is always used.
+is intentionally missing.
.Fl h
is an extension.
.Sh AUTHORS
diff --git a/cmd/touch.c b/cmd/touch.c
@@ -12,7 +12,7 @@
#include <stdio.h> /* perror, sscanf */
#include <stdlib.h> /* exit */
#include <string.h> /* memset */
-#include <sys/stat.h> /* futimens, stat */
+#include <sys/stat.h> /* futimens, stat, utimensat */
#include <time.h> /* strptime, tm */
#include <unistd.h> /* access */
@@ -83,6 +83,7 @@ main(int argc, char *argv[])
};
struct timespec target = {0, UTIME_NOW};
int open_flags = O_WRONLY | O_CREAT | O_NOCTTY;
+ int utimensat_flags = 0;
int c = 0;
while((c = getopt(argc, argv, ":achmr:t:d:")) != -1)
@@ -97,6 +98,7 @@ main(int argc, char *argv[])
break;
case 'h':
open_flags |= O_NOFOLLOW;
+ utimensat_flags |= AT_SYMLINK_NOFOLLOW;
break;
case 'm':
ch_mtime = true;
@@ -161,7 +163,18 @@ main(int argc, char *argv[])
int fd = open(argv[i], open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if(fd == -1)
{
+ if(errno == EISDIR)
+ {
+ if(utimensat(AT_FDCWD, argv[i], times, utimensat_flags) != 0)
+ {
+ perror("touch: utimensat");
+ return 1;
+ }
+
+ return 0;
+ }
if(errno != ENOENT) perror("touch: open");
+
return 1;
}
diff --git a/test-cmd/touch b/test-cmd/touch
@@ -122,6 +122,18 @@ ref_amtime_body() {
atf_check -o "inline:$(./stat_mtime ../cmd/touch)\n" ./stat_mtime ./foo
}
+atf_test_case dir
+dir_body() {
+ mkdir -p ./foo.d
+ atime="$(./stat_atime ./foo.d)"
+ mtime="$(./stat_mtime ./foo.d)"
+
+ maybe_sleep
+ atf_check ../cmd/touch ./foo.d
+ atf_check -o "not-inline:${atime}\n" ./stat_atime ./foo.d
+ atf_check -o "not-inline:${mtime}\n" ./stat_mtime ./foo.d
+}
+
atf_test_case optd
optd_body() {
atf_check touch -a ./foo
@@ -171,6 +183,8 @@ atf_init_test_cases() {
atf_add_test_case ref_mtime
atf_add_test_case ref_amtime
+ atf_add_test_case dir
+
atf_add_test_case optd
# No support for displaying fractional seconds on FreeBSD stat(1)