1 /* touch.c : change timestamp of a file 2 * 3 * Copyright 2012 Choubey Ji <warior.linux (at) gmail.com> 4 * 5 * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/touch.html 6 7 USE_TOUCH(NEWTOY(touch, "<1acd:mr:t:h[!dtr]", TOYFLAG_BIN)) 8 9 config TOUCH 10 bool "touch" 11 default y 12 help 13 usage: touch [-amch] [-d DATE] [-t TIME] [-r FILE] FILE... 14 15 Update the access and modification times of each FILE to the current time. 16 17 -a change access time 18 -m change modification time 19 -c don't create file 20 -h change symlink 21 -d set time to DATE (in YYYY-MM-DDThh:mm:SS[.frac][tz] format) 22 -t set time to TIME (in [[CC]YY]MMDDhhmm[.ss][frac] format) 23 -r set time same as reference FILE 24 */ 25 26 #define FOR_touch 27 #include "toys.h" 28 29 GLOBALS( 30 char *time; 31 char *file; 32 char *date; 33 ) 34 35 void touch_main(void) 36 { 37 struct timespec ts[2]; 38 char **ss; 39 int fd, i; 40 41 // use current time if no -t or -d 42 ts[0].tv_nsec = UTIME_NOW; 43 if (toys.optflags & (FLAG_t|FLAG_d)) { 44 char *s, *date, **format; 45 struct tm tm; 46 int len = 0; 47 48 // Initialize default values for time fields 49 ts->tv_sec = time(0); 50 ts->tv_nsec = 0; 51 52 // List of search types 53 if (toys.optflags & FLAG_d) { 54 format = (char *[]){"%Y-%m-%dT%T", "%Y-%m-%d %T", 0}; 55 date = TT.date; 56 } else { 57 format = (char *[]){"%m%d%H%M", "%y%m%d%H%M", "%C%y%m%d%H%M", 0}; 58 date = TT.time; 59 } 60 61 // Trailing Z means UTC timezone, don't expect libc to know this. 62 i = strlen(s = date); 63 if (i && toupper(date[i-1])=='Z') { 64 date[i-1] = 0; 65 setenv("TZ", "UTC0", 1); 66 } 67 68 while (*format) { 69 if (toys.optflags&FLAG_t) { 70 s = strchr(date, '.'); 71 if ((s ? s-date : strlen(date)) != strlen(*format)) { 72 format++; 73 continue; 74 } 75 } 76 localtime_r(&(ts->tv_sec), &tm); 77 // Adjusting for daylight savings time gives the wrong answer. 78 tm.tm_isdst = 0; 79 tm.tm_sec = 0; 80 s = strptime(date, *format++, &tm); 81 82 // parse nanoseconds 83 if (s && *s=='.' && isdigit(s[1])) { 84 s++; 85 if (toys.optflags&FLAG_t) 86 if (1 == sscanf(s, "%2u%n", &(tm.tm_sec), &len)) s += len; 87 if (1 == sscanf(s, "%lu%n", &ts->tv_nsec, &len)) { 88 s += len; 89 if (ts->tv_nsec > 999999999) s = 0; 90 else while (len++ < 9) ts->tv_nsec *= 10; 91 } 92 } 93 if (s && !*s) break; 94 } 95 96 errno = 0; 97 ts->tv_sec = mktime(&tm); 98 if (!s || *s || ts->tv_sec == -1) perror_exit("bad '%s'", date); 99 } 100 ts[1]=ts[0]; 101 102 // Set time from -r? 103 104 if (TT.file) { 105 struct stat st; 106 107 xstat(TT.file, &st); 108 ts[0] = st.st_atim; 109 ts[1] = st.st_mtim; 110 } 111 112 // Which time(s) should we actually change? 113 i = toys.optflags & (FLAG_a|FLAG_m); 114 if (i && i!=(FLAG_a|FLAG_m)) ts[i!=FLAG_m].tv_nsec = UTIME_OMIT; 115 116 // Loop through files on command line 117 for (ss = toys.optargs; *ss;) { 118 char *s = *ss++; 119 120 if (!strcmp(s, "-")) { 121 if (!futimens(1, ts)) continue; 122 } else { 123 // cheat: FLAG_h is rightmost flag, so its value is 1 124 if (!utimensat(AT_FDCWD, s, ts, 125 (toys.optflags & FLAG_h)*AT_SYMLINK_NOFOLLOW)) continue; 126 if (toys.optflags & FLAG_c) continue; 127 if (access(s, F_OK) && (-1!=(fd = open(s, O_CREAT, 0666)))) { 128 close(fd); 129 if (toys.optflags) ss--; 130 continue; 131 } 132 } 133 perror_msg("'%s'", s); 134 } 135 } 136