247 lines
5.4 KiB
C
247 lines
5.4 KiB
C
/* Touch - change file access and modification times.
|
|
*
|
|
* Usage: see end of file
|
|
*
|
|
* Conforms to P1003.2 draft 10, sec. 4.62, except that time values
|
|
* are not checked for validity, but passed on to mktime, so that
|
|
* 9301990000 will refer to Apr. 9th 1993. As a side effect, leap
|
|
* seconds are not handled correctly.
|
|
*
|
|
* Authors: Original author unknown. Rewritten for POSIX by
|
|
* Peter Holzer (hp@vmars.tuwien.ac.at).
|
|
*
|
|
* $Log$
|
|
* Revision 1.1 2005/04/21 14:55:35 beng
|
|
* Initial revision
|
|
*
|
|
* Revision 1.1.1.1 2005/04/20 13:33:47 beng
|
|
* Initial import of minix 2.0.4
|
|
*
|
|
* Revision 1.8 1994/03/17 21:39:19 hjp
|
|
* fixed bug with 4-digit years
|
|
*
|
|
* Revision 1.7 1994/03/15 00:43:27 hjp
|
|
* Changes from kjb (vmd 1.6.25.1):
|
|
* fixed exit code
|
|
* nonstandard flag 0 to make file very old
|
|
*
|
|
* Revision 1.6 1994/02/12 17:26:33 hjp
|
|
* fixed -a and -m flags
|
|
*
|
|
* Revision 1.5 1994/02/12 16:04:13 hjp
|
|
* fixed bug when -t argument was not given
|
|
* removed debugging code
|
|
* run through pretty to get Minix layout
|
|
*
|
|
* Revision 1.4 1994/02/07 21:23:11 hjp
|
|
* POSIXified.
|
|
*
|
|
*/
|
|
|
|
#define _POSIX_C_SOURCE 2 /* getopt */
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <utime.h>
|
|
|
|
#define val2(string) ((string)[0] * 10 + (string)[1] - '0' * 11)
|
|
#define val4(string) (val2(string) * 100 + val2(string + 2))
|
|
|
|
typedef enum {
|
|
OLD, NEW
|
|
} formatT;
|
|
|
|
char *cmnd;
|
|
int no_creat = 0;
|
|
unsigned int to_change = 0;
|
|
# define ATIME 1
|
|
# define MTIME 2
|
|
|
|
_PROTOTYPE(int main, (int argc, char **argv));
|
|
_PROTOTYPE(int doit, (char *name, struct utimbuf tvp));
|
|
_PROTOTYPE(void usage, (void));
|
|
_PROTOTYPE(time_t parsetime, (const char *string, formatT format));
|
|
|
|
time_t parsetime(string, format)
|
|
const char *string;
|
|
formatT format;
|
|
{
|
|
struct tm tm;
|
|
time_t touchtime;
|
|
size_t l;
|
|
|
|
l = strspn(string, "0123456789");
|
|
if (l % 2 == 1) return -1;
|
|
if (string[l] != '\0' && (string[l] != '.' || format == OLD)) {
|
|
return -1;
|
|
}
|
|
if (format == OLD) {
|
|
if (l == 10) {
|
|
/* Last two digits are year */
|
|
tm.tm_year = val2(string + 8);
|
|
if (tm.tm_year <= 68) tm.tm_year += 100;
|
|
} else if (l == 8) {
|
|
time(&touchtime);
|
|
tm = *localtime(&touchtime);
|
|
} else {
|
|
return -1;
|
|
}
|
|
} else {
|
|
if (l == 12) {
|
|
/* First four digits are year */
|
|
tm.tm_year = val4(string) - 1900;
|
|
string += 4;
|
|
} else if (l == 10) {
|
|
/* First two digits are year */
|
|
tm.tm_year = val2(string);
|
|
if (tm.tm_year <= 68) tm.tm_year += 100;
|
|
string += 2;
|
|
} else if (l == 8) {
|
|
time(&touchtime);
|
|
tm = *localtime(&touchtime);
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
tm.tm_mon = val2(string) - 1;
|
|
string += 2;
|
|
tm.tm_mday = val2(string);
|
|
string += 2;
|
|
tm.tm_hour = val2(string);
|
|
string += 2;
|
|
tm.tm_min = val2(string);
|
|
string += 2;
|
|
if (format == NEW && string[0] == '.') {
|
|
if (isdigit(string[1]) && isdigit(string[2]) &&
|
|
string[3] == '\0') {
|
|
tm.tm_sec = val2(string + 1);
|
|
} else {
|
|
return -1;
|
|
}
|
|
} else {
|
|
tm.tm_sec = 0;
|
|
}
|
|
tm.tm_isdst = -1;
|
|
touchtime = mktime(&tm);
|
|
return touchtime;
|
|
}
|
|
|
|
|
|
int main(argc, argv)
|
|
int argc;
|
|
char **argv;
|
|
{
|
|
time_t auxtime;
|
|
struct stat sb;
|
|
int c;
|
|
struct utimbuf touchtimes;
|
|
int fail = 0;
|
|
|
|
cmnd = argv[0];
|
|
auxtime = time((time_t *) NULL);
|
|
touchtimes.modtime = auxtime;
|
|
touchtimes.actime = auxtime;
|
|
|
|
while ((c = getopt(argc, argv, "r:t:acm0")) != EOF) {
|
|
switch (c) {
|
|
case 'r':
|
|
if (stat(optarg, &sb) == -1) {
|
|
fprintf(stderr, "%s: cannot stat %s: %s\n",
|
|
cmnd, optarg, strerror(errno));
|
|
exit(1);
|
|
}
|
|
touchtimes.modtime = sb.st_mtime;
|
|
touchtimes.actime = sb.st_atime;
|
|
break;
|
|
case 't':
|
|
auxtime = parsetime(optarg, NEW);
|
|
if (auxtime == (time_t) - 1) usage();
|
|
touchtimes.modtime = auxtime;
|
|
touchtimes.actime = auxtime;
|
|
break;
|
|
case 'a': to_change |= ATIME; break;
|
|
case 'm': to_change |= MTIME; break;
|
|
case 'c': no_creat = 1; break;
|
|
case '0':
|
|
touchtimes.modtime = touchtimes.actime = 0;
|
|
break;
|
|
case '?': usage(); break;
|
|
default: assert(0);
|
|
}
|
|
}
|
|
if (to_change == 0) {
|
|
to_change = ATIME | MTIME;
|
|
}
|
|
if (optind == argc) usage();
|
|
|
|
/* Now check for old style time argument */
|
|
if (strcmp(argv[optind - 1], "--") != 0 &&
|
|
(auxtime = parsetime(argv[optind], OLD)) != (time_t) - 1) {
|
|
touchtimes.modtime = auxtime;
|
|
touchtimes.actime = auxtime;
|
|
optind++;
|
|
if (optind == argc) usage();
|
|
}
|
|
while (optind < argc) {
|
|
if (doit(argv[optind], touchtimes) > 0) {
|
|
fprintf(stderr, "%s: cannot touch %s: %s\n",
|
|
cmnd, argv[optind], strerror(errno));
|
|
fail = 1;
|
|
}
|
|
optind++;
|
|
}
|
|
return fail ? 1 : 0;
|
|
}
|
|
|
|
|
|
int doit(name, tvp)
|
|
char *name;
|
|
struct utimbuf tvp;
|
|
{
|
|
int fd;
|
|
struct stat sb;
|
|
|
|
if (to_change != (ATIME | MTIME)) {
|
|
|
|
if (stat(name, &sb) != -1) {
|
|
if (!(to_change & ATIME)) {
|
|
tvp.actime = sb.st_atime;
|
|
} else {
|
|
tvp.modtime = sb.st_mtime;
|
|
}
|
|
}
|
|
}
|
|
if (utime(name, &tvp) == 0) return 0;
|
|
if (errno != ENOENT) return 1;
|
|
if (no_creat == 1) return 0;
|
|
if ((fd = creat(name, 0666)) >= 0) {
|
|
if (fstat(fd, &sb) != -1) {
|
|
if (!(to_change & ATIME)) {
|
|
tvp.actime = sb.st_atime;
|
|
} else {
|
|
tvp.modtime = sb.st_mtime;
|
|
}
|
|
} else {
|
|
assert(0);
|
|
}
|
|
close(fd);
|
|
if (utime(name, &tvp) == 0) return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
void usage()
|
|
{
|
|
fprintf(stderr, "Usage: %s [-c] [-a] [-m] [-r file] [-t [CC[YY]]MMDDhhmm[.ss]] "
|
|
"[MMDDhhmm[YY]] file...\n", cmnd);
|
|
exit(1);
|
|
}
|