minix/commands/simple/touch.c
2005-04-21 14:53:53 +00:00

248 lines
5.4 KiB
C
Executable file

/* 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).
*
* $Id$
* $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);
}