[9] | 1 | /* Touch - change file access and modification times.
|
---|
| 2 | *
|
---|
| 3 | * Usage: see end of file
|
---|
| 4 | *
|
---|
| 5 | * Conforms to P1003.2 draft 10, sec. 4.62, except that time values
|
---|
| 6 | * are not checked for validity, but passed on to mktime, so that
|
---|
| 7 | * 9301990000 will refer to Apr. 9th 1993. As a side effect, leap
|
---|
| 8 | * seconds are not handled correctly.
|
---|
| 9 | *
|
---|
| 10 | * Authors: Original author unknown. Rewritten for POSIX by
|
---|
| 11 | * Peter Holzer (hp@vmars.tuwien.ac.at).
|
---|
| 12 | *
|
---|
| 13 | * $Id: touch.c,v 1.1.1.1 2005/04/21 14:55:35 beng Exp $
|
---|
| 14 | * $Log: touch.c,v $
|
---|
| 15 | * Revision 1.1.1.1 2005/04/21 14:55:35 beng
|
---|
| 16 | * Initial import of pre-3.0.1
|
---|
| 17 | *
|
---|
| 18 | * Revision 1.1.1.1 2005/04/20 13:33:47 beng
|
---|
| 19 | * Initial import of minix 2.0.4
|
---|
| 20 | *
|
---|
| 21 | * Revision 1.8 1994/03/17 21:39:19 hjp
|
---|
| 22 | * fixed bug with 4-digit years
|
---|
| 23 | *
|
---|
| 24 | * Revision 1.7 1994/03/15 00:43:27 hjp
|
---|
| 25 | * Changes from kjb (vmd 1.6.25.1):
|
---|
| 26 | * fixed exit code
|
---|
| 27 | * nonstandard flag 0 to make file very old
|
---|
| 28 | *
|
---|
| 29 | * Revision 1.6 1994/02/12 17:26:33 hjp
|
---|
| 30 | * fixed -a and -m flags
|
---|
| 31 | *
|
---|
| 32 | * Revision 1.5 1994/02/12 16:04:13 hjp
|
---|
| 33 | * fixed bug when -t argument was not given
|
---|
| 34 | * removed debugging code
|
---|
| 35 | * run through pretty to get Minix layout
|
---|
| 36 | *
|
---|
| 37 | * Revision 1.4 1994/02/07 21:23:11 hjp
|
---|
| 38 | * POSIXified.
|
---|
| 39 | *
|
---|
| 40 | */
|
---|
| 41 |
|
---|
| 42 | #define _POSIX_C_SOURCE 2 /* getopt */
|
---|
| 43 | #include <assert.h>
|
---|
| 44 | #include <ctype.h>
|
---|
| 45 | #include <sys/types.h>
|
---|
| 46 | #include <sys/stat.h>
|
---|
| 47 | #include <errno.h>
|
---|
| 48 | #include <stdlib.h>
|
---|
| 49 | #include <stdio.h>
|
---|
| 50 | #include <string.h>
|
---|
| 51 | #include <time.h>
|
---|
| 52 | #include <fcntl.h>
|
---|
| 53 | #include <unistd.h>
|
---|
| 54 | #include <utime.h>
|
---|
| 55 |
|
---|
| 56 | #define val2(string) ((string)[0] * 10 + (string)[1] - '0' * 11)
|
---|
| 57 | #define val4(string) (val2(string) * 100 + val2(string + 2))
|
---|
| 58 |
|
---|
| 59 | typedef enum {
|
---|
| 60 | OLD, NEW
|
---|
| 61 | } formatT;
|
---|
| 62 |
|
---|
| 63 | char *cmnd;
|
---|
| 64 | int no_creat = 0;
|
---|
| 65 | unsigned int to_change = 0;
|
---|
| 66 | # define ATIME 1
|
---|
| 67 | # define MTIME 2
|
---|
| 68 |
|
---|
| 69 | _PROTOTYPE(int main, (int argc, char **argv));
|
---|
| 70 | _PROTOTYPE(int doit, (char *name, struct utimbuf tvp));
|
---|
| 71 | _PROTOTYPE(void usage, (void));
|
---|
| 72 | _PROTOTYPE(time_t parsetime, (const char *string, formatT format));
|
---|
| 73 |
|
---|
| 74 | time_t parsetime(string, format)
|
---|
| 75 | const char *string;
|
---|
| 76 | formatT format;
|
---|
| 77 | {
|
---|
| 78 | struct tm tm;
|
---|
| 79 | time_t touchtime;
|
---|
| 80 | size_t l;
|
---|
| 81 |
|
---|
| 82 | l = strspn(string, "0123456789");
|
---|
| 83 | if (l % 2 == 1) return -1;
|
---|
| 84 | if (string[l] != '\0' && (string[l] != '.' || format == OLD)) {
|
---|
| 85 | return -1;
|
---|
| 86 | }
|
---|
| 87 | if (format == OLD) {
|
---|
| 88 | if (l == 10) {
|
---|
| 89 | /* Last two digits are year */
|
---|
| 90 | tm.tm_year = val2(string + 8);
|
---|
| 91 | if (tm.tm_year <= 68) tm.tm_year += 100;
|
---|
| 92 | } else if (l == 8) {
|
---|
| 93 | time(&touchtime);
|
---|
| 94 | tm = *localtime(&touchtime);
|
---|
| 95 | } else {
|
---|
| 96 | return -1;
|
---|
| 97 | }
|
---|
| 98 | } else {
|
---|
| 99 | if (l == 12) {
|
---|
| 100 | /* First four digits are year */
|
---|
| 101 | tm.tm_year = val4(string) - 1900;
|
---|
| 102 | string += 4;
|
---|
| 103 | } else if (l == 10) {
|
---|
| 104 | /* First two digits are year */
|
---|
| 105 | tm.tm_year = val2(string);
|
---|
| 106 | if (tm.tm_year <= 68) tm.tm_year += 100;
|
---|
| 107 | string += 2;
|
---|
| 108 | } else if (l == 8) {
|
---|
| 109 | time(&touchtime);
|
---|
| 110 | tm = *localtime(&touchtime);
|
---|
| 111 | } else {
|
---|
| 112 | return -1;
|
---|
| 113 | }
|
---|
| 114 | }
|
---|
| 115 | tm.tm_mon = val2(string) - 1;
|
---|
| 116 | string += 2;
|
---|
| 117 | tm.tm_mday = val2(string);
|
---|
| 118 | string += 2;
|
---|
| 119 | tm.tm_hour = val2(string);
|
---|
| 120 | string += 2;
|
---|
| 121 | tm.tm_min = val2(string);
|
---|
| 122 | string += 2;
|
---|
| 123 | if (format == NEW && string[0] == '.') {
|
---|
| 124 | if (isdigit(string[1]) && isdigit(string[2]) &&
|
---|
| 125 | string[3] == '\0') {
|
---|
| 126 | tm.tm_sec = val2(string + 1);
|
---|
| 127 | } else {
|
---|
| 128 | return -1;
|
---|
| 129 | }
|
---|
| 130 | } else {
|
---|
| 131 | tm.tm_sec = 0;
|
---|
| 132 | }
|
---|
| 133 | tm.tm_isdst = -1;
|
---|
| 134 | touchtime = mktime(&tm);
|
---|
| 135 | return touchtime;
|
---|
| 136 | }
|
---|
| 137 |
|
---|
| 138 |
|
---|
| 139 | int main(argc, argv)
|
---|
| 140 | int argc;
|
---|
| 141 | char **argv;
|
---|
| 142 | {
|
---|
| 143 | time_t auxtime;
|
---|
| 144 | struct stat sb;
|
---|
| 145 | int c;
|
---|
| 146 | struct utimbuf touchtimes;
|
---|
| 147 | int fail = 0;
|
---|
| 148 |
|
---|
| 149 | cmnd = argv[0];
|
---|
| 150 | auxtime = time((time_t *) NULL);
|
---|
| 151 | touchtimes.modtime = auxtime;
|
---|
| 152 | touchtimes.actime = auxtime;
|
---|
| 153 |
|
---|
| 154 | while ((c = getopt(argc, argv, "r:t:acm0")) != EOF) {
|
---|
| 155 | switch (c) {
|
---|
| 156 | case 'r':
|
---|
| 157 | if (stat(optarg, &sb) == -1) {
|
---|
| 158 | fprintf(stderr, "%s: cannot stat %s: %s\n",
|
---|
| 159 | cmnd, optarg, strerror(errno));
|
---|
| 160 | exit(1);
|
---|
| 161 | }
|
---|
| 162 | touchtimes.modtime = sb.st_mtime;
|
---|
| 163 | touchtimes.actime = sb.st_atime;
|
---|
| 164 | break;
|
---|
| 165 | case 't':
|
---|
| 166 | auxtime = parsetime(optarg, NEW);
|
---|
| 167 | if (auxtime == (time_t) - 1) usage();
|
---|
| 168 | touchtimes.modtime = auxtime;
|
---|
| 169 | touchtimes.actime = auxtime;
|
---|
| 170 | break;
|
---|
| 171 | case 'a': to_change |= ATIME; break;
|
---|
| 172 | case 'm': to_change |= MTIME; break;
|
---|
| 173 | case 'c': no_creat = 1; break;
|
---|
| 174 | case '0':
|
---|
| 175 | touchtimes.modtime = touchtimes.actime = 0;
|
---|
| 176 | break;
|
---|
| 177 | case '?': usage(); break;
|
---|
| 178 | default: assert(0);
|
---|
| 179 | }
|
---|
| 180 | }
|
---|
| 181 | if (to_change == 0) {
|
---|
| 182 | to_change = ATIME | MTIME;
|
---|
| 183 | }
|
---|
| 184 | if (optind == argc) usage();
|
---|
| 185 |
|
---|
| 186 | /* Now check for old style time argument */
|
---|
| 187 | if (strcmp(argv[optind - 1], "--") != 0 &&
|
---|
| 188 | (auxtime = parsetime(argv[optind], OLD)) != (time_t) - 1) {
|
---|
| 189 | touchtimes.modtime = auxtime;
|
---|
| 190 | touchtimes.actime = auxtime;
|
---|
| 191 | optind++;
|
---|
| 192 | if (optind == argc) usage();
|
---|
| 193 | }
|
---|
| 194 | while (optind < argc) {
|
---|
| 195 | if (doit(argv[optind], touchtimes) > 0) {
|
---|
| 196 | fprintf(stderr, "%s: cannot touch %s: %s\n",
|
---|
| 197 | cmnd, argv[optind], strerror(errno));
|
---|
| 198 | fail = 1;
|
---|
| 199 | }
|
---|
| 200 | optind++;
|
---|
| 201 | }
|
---|
| 202 | return fail ? 1 : 0;
|
---|
| 203 | }
|
---|
| 204 |
|
---|
| 205 |
|
---|
| 206 | int doit(name, tvp)
|
---|
| 207 | char *name;
|
---|
| 208 | struct utimbuf tvp;
|
---|
| 209 | {
|
---|
| 210 | int fd;
|
---|
| 211 | struct stat sb;
|
---|
| 212 |
|
---|
| 213 | if (to_change != (ATIME | MTIME)) {
|
---|
| 214 |
|
---|
| 215 | if (stat(name, &sb) != -1) {
|
---|
| 216 | if (!(to_change & ATIME)) {
|
---|
| 217 | tvp.actime = sb.st_atime;
|
---|
| 218 | } else {
|
---|
| 219 | tvp.modtime = sb.st_mtime;
|
---|
| 220 | }
|
---|
| 221 | }
|
---|
| 222 | }
|
---|
| 223 | if (utime(name, &tvp) == 0) return 0;
|
---|
| 224 | if (errno != ENOENT) return 1;
|
---|
| 225 | if (no_creat == 1) return 0;
|
---|
| 226 | if ((fd = creat(name, 0666)) >= 0) {
|
---|
| 227 | if (fstat(fd, &sb) != -1) {
|
---|
| 228 | if (!(to_change & ATIME)) {
|
---|
| 229 | tvp.actime = sb.st_atime;
|
---|
| 230 | } else {
|
---|
| 231 | tvp.modtime = sb.st_mtime;
|
---|
| 232 | }
|
---|
| 233 | } else {
|
---|
| 234 | assert(0);
|
---|
| 235 | }
|
---|
| 236 | close(fd);
|
---|
| 237 | if (utime(name, &tvp) == 0) return 0;
|
---|
| 238 | }
|
---|
| 239 | return 1;
|
---|
| 240 | }
|
---|
| 241 |
|
---|
| 242 |
|
---|
| 243 | void usage()
|
---|
| 244 | {
|
---|
| 245 | fprintf(stderr, "Usage: %s [-c] [-a] [-m] [-r file] [-t [CC[YY]]MMDDhhmm[.ss]] "
|
---|
| 246 | "[MMDDhhmm[YY]] file...\n", cmnd);
|
---|
| 247 | exit(1);
|
---|
| 248 | }
|
---|