/* rightly.c */ /* rightly converts filesystem timestamps between 'posix' format * (ie., time_t counts solar seconds, 'doesn't include leap seconds') * to/from the local format. The standard application is if * 'right' format is used locally (ie., time_t counts SI seconds, * 'includes leap seconds'). If 'posix' is already used locally, the * conversion will be effectively the identity operation. */ #include #include #define __USE_XOPEN_EXTENDED #include #include #include #include #include #include #include #include int verbose = 0; time_t posixgm(struct tm *tm) { time_t ret; char *tz; /* This can also be computed directly from the posix formula! */ tz = getenv("TZ"); setenv("TZ", "posix/UTC", 1); tzset(); ret = mktime(tm); if (tz) setenv("TZ", tz, 1); else unsetenv("TZ"); tzset(); return ret; } struct tm *gmposix(const time_t *t) { struct tm *ret; char *tz; /* This can also be computed directly from the posix formula! */ tz = getenv("TZ"); setenv("TZ", "posix/UTC", 1); tzset(); ret = gmtime(t); if (tz) setenv("TZ", tz, 1); else unsetenv("TZ"); tzset(); return ret; } time_t posix2time(time_t t) { return timegm(gmposix(&t)); } time_t time2posix(time_t t) { return posixgm(gmtime(&t)); } time_t (*convert)(time_t) = time2posix; char *cmdname; int modify(const char *file, time_t atime, time_t mtime) { struct utimbuf utb = {convert(atime), convert(mtime)}; #if 1 int result; if ((result = utime(file, &utb)) == -1) fprintf(stderr, "%s: utime failed for %s: %s\n", cmdname, file, strerror(errno)); return result; #else if (verbose) printf("%ld %ld ", mtime, atime), printf("%ld %ld ", utb.modtime, utb.actime); return 0; #endif } int apply(const char *file, const struct stat *sb, int flag, struct FTW *s) { switch (flag) { case FTW_SL: case FTW_SLN: case FTW_DP: break; case FTW_NS: fprintf(stderr, "%s: stat failed for %s.\n", cmdname, file); return 0; case FTW_DNR: fprintf(stderr, "%s: can't decend to %s.\n", cmdname, file); /* FALLTHROUGH */ default: modify(file, sb->st_atime, sb->st_mtime); break; } if (verbose) puts(file); return 0; } int main(int argc, char *argv[]) { extern char *optarg; extern int optind; struct stat st; int c, recurse = 0; int flags = FTW_PHYS; cmdname = argv[0]; while ((c = getopt(argc, argv, "rRmv")) != -1) switch (c) { case 'r': recurse = 1; break; case 'R': convert = posix2time; break; case 'v': verbose++; break; case 'm': flags |= FTW_MOUNT; break; case '?': return EXIT_FAILURE; } for (;optind < argc; optind++) { if (lstat(argv[optind], &st) == -1) { fprintf(stderr, "%s: stat failed for %s: %s\n", cmdname, argv[optind], strerror(errno)); continue; } if (S_ISDIR(st.st_mode) && recurse) { nftw(argv[optind], apply, 24, flags); continue; } if (!S_ISLNK(st.st_mode)) modify(argv[optind], st.st_atime, st.st_mtime); if (verbose) puts(argv[optind]); } return EXIT_SUCCESS; }