aboutsummaryrefslogtreecommitdiff
path: root/coreutils/touch.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2021-04-11 06:41:31 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2021-04-13 11:31:46 +0200
commit79c92dbd7028a9782b85fcbbbe123e1c44cbaec1 (patch)
tree9c87d3495efdbf9c407f6519659b23644ea48724 /coreutils/touch.c
parent1a181264d51bc3f3a3c66f756da84ab61b6823d4 (diff)
downloadbusybox-w32-79c92dbd7028a9782b85fcbbbe123e1c44cbaec1.tar.gz
busybox-w32-79c92dbd7028a9782b85fcbbbe123e1c44cbaec1.tar.bz2
busybox-w32-79c92dbd7028a9782b85fcbbbe123e1c44cbaec1.zip
touch: switch to using utimensat() and futimens()
This patch changes the functions used to update timestamps in touch. Before, utimes() and lutimes() were used, which had certain disadvantages. They are unable to handle nanosecond timestamps, and implementations of certain features like -a and -m require running stat() in a loop. Almost all implementations of utimes() and lutimes() are wrappers for utimensat(), this is the case for glibc, ulibc and musl libc. function old new delta __futimens_time64 - 24 +24 __lutimes_time64 80 - -80 touch_main 539 456 -83 ------------------------------------------------------------------------------ (add/remove: 2/2 grow/shrink: 0/1 up/down: 24/-163) Total: -139 bytes Signed-off-by: urmum-69 <urmum69@snopyta.org> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'coreutils/touch.c')
-rw-r--r--coreutils/touch.c57
1 files changed, 16 insertions, 41 deletions
diff --git a/coreutils/touch.c b/coreutils/touch.c
index 690517e66..8d3f8dbbe 100644
--- a/coreutils/touch.c
+++ b/coreutils/touch.c
@@ -25,7 +25,6 @@
25//config: depends on TOUCH 25//config: depends on TOUCH
26//config: help 26//config: help
27//config: Enable touch to have the -h option. 27//config: Enable touch to have the -h option.
28//config: This requires libc support for lutimes() function.
29//config: 28//config:
30//config:config FEATURE_TOUCH_SUSV3 29//config:config FEATURE_TOUCH_SUSV3
31//config: bool "Add support for SUSV3 features (-a -d -m -t -r)" 30//config: bool "Add support for SUSV3 features (-a -d -m -t -r)"
@@ -97,8 +96,6 @@ int touch_main(int argc UNUSED_PARAM, char **argv)
97 OPT_a = (1 << (4+ENABLE_FEATURE_TOUCH_NODEREF)) * ENABLE_FEATURE_TOUCH_SUSV3, 96 OPT_a = (1 << (4+ENABLE_FEATURE_TOUCH_NODEREF)) * ENABLE_FEATURE_TOUCH_SUSV3,
98 OPT_m = (1 << (5+ENABLE_FEATURE_TOUCH_NODEREF)) * ENABLE_FEATURE_TOUCH_SUSV3, 97 OPT_m = (1 << (5+ENABLE_FEATURE_TOUCH_NODEREF)) * ENABLE_FEATURE_TOUCH_SUSV3,
99 }; 98 };
100 /* NULL = use current time */
101 const struct timeval *newtime = NULL;
102#if ENABLE_LONG_OPTS 99#if ENABLE_LONG_OPTS
103 static const char touch_longopts[] ALIGN1 = 100 static const char touch_longopts[] ALIGN1 =
104 /* name, has_arg, val */ 101 /* name, has_arg, val */
@@ -112,12 +109,11 @@ int touch_main(int argc UNUSED_PARAM, char **argv)
112 char *reference_file = NULL; 109 char *reference_file = NULL;
113 char *date_str = NULL; 110 char *date_str = NULL;
114 /* timebuf[0] is atime, timebuf[1] is mtime */ 111 /* timebuf[0] is atime, timebuf[1] is mtime */
115 struct timeval timebuf[2]; 112 struct timespec timebuf[2];
116 timebuf[1].tv_usec = timebuf[0].tv_usec = 0;
117#else 113#else
118# define reference_file NULL 114# define reference_file NULL
119# define date_str NULL 115# define date_str NULL
120# define timebuf ((struct timeval*)NULL) 116# define timebuf ((struct timespec*)NULL)
121#endif 117#endif
122 118
123 /* -d and -t both set time. In coreutils, 119 /* -d and -t both set time. In coreutils,
@@ -140,16 +136,15 @@ int touch_main(int argc UNUSED_PARAM, char **argv)
140 bb_show_usage(); 136 bb_show_usage();
141 } 137 }
142 138
139 timebuf[0].tv_nsec = timebuf[1].tv_nsec = UTIME_NOW;
140
143 if (reference_file) { 141 if (reference_file) {
144 struct stat stbuf; 142 struct stat stbuf;
145 xstat(reference_file, &stbuf); 143 xstat(reference_file, &stbuf);
146 timebuf[0].tv_sec = stbuf.st_atime; 144 timebuf[0].tv_sec = stbuf.st_atime;
147 timebuf[1].tv_sec = stbuf.st_mtime; 145 timebuf[1].tv_sec = stbuf.st_mtime;
148 /* Can use .st_mtim.tv_nsec 146 timebuf[0].tv_nsec = stbuf.st_atim.tv_nsec;
149 * (or is it .st_mtimensec?? see date.c) 147 timebuf[1].tv_nsec = stbuf.st_mtim.tv_nsec;
150 * to set microseconds too.
151 */
152 newtime = timebuf;
153 } 148 }
154 149
155 if (date_str) { 150 if (date_str) {
@@ -167,39 +162,19 @@ int touch_main(int argc UNUSED_PARAM, char **argv)
167 t = validate_tm_time(date_str, &tm_time); 162 t = validate_tm_time(date_str, &tm_time);
168 163
169 timebuf[1].tv_sec = timebuf[0].tv_sec = t; 164 timebuf[1].tv_sec = timebuf[0].tv_sec = t;
170 newtime = timebuf; 165 timebuf[1].tv_nsec = timebuf[0].tv_nsec = 0;
171 } 166 }
172 167
173 if ((opts & (OPT_a | OPT_m)) && !newtime) { 168 if (opts & OPT_a) {
174 time(&timebuf[0].tv_sec); 169 timebuf[1].tv_nsec = UTIME_OMIT;
175 timebuf[1].tv_sec = timebuf[0].tv_sec; 170 }
176 newtime = timebuf; 171 if (opts & OPT_m) {
172 timebuf[0].tv_nsec = UTIME_OMIT;
177 } 173 }
178 174
179 do { 175 do {
180 int result; 176 int result = utimensat(AT_FDCWD, *argv, timebuf,
181 177 (opts & OPT_h) ? AT_SYMLINK_NOFOLLOW : 0);
182 if (opts & (OPT_a | OPT_m)) {
183 /* Save original times */
184 struct stat stbuf;
185 if (stat(*argv, &stbuf) == 0) {
186 /* As we must set both times, we lose original
187 * file time microseconds.
188 * Can use .st_mtim.tv_nsec
189 * (or is it .st_mtimensec?? see date.c)
190 * to set microseconds too.
191 * Also, utimensat(2) allows to omit one of the
192 * times to be set. But it is SUSv4.
193 */
194 if (!(opts & OPT_a))
195 timebuf[0].tv_sec = stbuf.st_atime;
196 if (!(opts & OPT_m))
197 timebuf[1].tv_sec = stbuf.st_mtime;
198 }
199 }
200
201 result = (ENABLE_FEATURE_TOUCH_NODEREF && (opts & OPT_h) ? lutimes : utimes)(*argv, newtime);
202
203 if (result != 0) { 178 if (result != 0) {
204 if (errno == ENOENT) { /* no such file? */ 179 if (errno == ENOENT) { /* no such file? */
205 if (opts & OPT_c) { 180 if (opts & OPT_c) {
@@ -209,9 +184,9 @@ int touch_main(int argc UNUSED_PARAM, char **argv)
209 /* Try to create the file */ 184 /* Try to create the file */
210 fd = open(*argv, O_RDWR | O_CREAT, 0666); 185 fd = open(*argv, O_RDWR | O_CREAT, 0666);
211 if (fd >= 0) { 186 if (fd >= 0) {
212 xclose(fd);
213 if (reference_file || date_str) 187 if (reference_file || date_str)
214 utimes(*argv, newtime); 188 futimens(fd, timebuf);
189 xclose(fd);
215 continue; 190 continue;
216 } 191 }
217 } 192 }