Alex Riesen | 0ea9ca0 | 2008-10-30 10:00:29 +0100 | [diff] [blame] | 1 | /* |
| 2 | * This program can either change modification time of the given |
| 3 | * file(s) or just print it. The program does not change atime nor |
Junio C Hamano | 9517e6b | 2010-02-03 21:23:18 -0800 | [diff] [blame] | 4 | * ctime (their values are explicitly preserved). |
Alex Riesen | 0ea9ca0 | 2008-10-30 10:00:29 +0100 | [diff] [blame] | 5 | * |
| 6 | * The mtime can be changed to an absolute value: |
| 7 | * |
| 8 | * test-chmtime =<seconds> file... |
| 9 | * |
| 10 | * Relative to the current time as returned by time(3): |
| 11 | * |
| 12 | * test-chmtime =+<seconds> (or =-<seconds>) file... |
| 13 | * |
| 14 | * Or relative to the current mtime of the file: |
| 15 | * |
| 16 | * test-chmtime <seconds> file... |
| 17 | * test-chmtime +<seconds> (or -<seconds>) file... |
| 18 | * |
| 19 | * Examples: |
| 20 | * |
| 21 | * To just print the mtime use --verbose and set the file mtime offset to 0: |
| 22 | * |
| 23 | * test-chmtime -v +0 file |
| 24 | * |
| 25 | * To set the mtime to current time: |
| 26 | * |
| 27 | * test-chmtime =+0 file |
| 28 | * |
| 29 | */ |
Eric Wong | 17e4836 | 2007-02-24 18:18:22 -0800 | [diff] [blame] | 30 | #include "git-compat-util.h" |
| 31 | #include <utime.h> |
| 32 | |
Alex Riesen | 0ea9ca0 | 2008-10-30 10:00:29 +0100 | [diff] [blame] | 33 | static const char usage_str[] = "-v|--verbose (+|=|=+|=-|-)<seconds> <file>..."; |
| 34 | |
| 35 | static int timespec_arg(const char *arg, long int *set_time, int *set_eq) |
| 36 | { |
| 37 | char *test; |
| 38 | const char *timespec = arg; |
| 39 | *set_eq = (*timespec == '=') ? 1 : 0; |
| 40 | if (*set_eq) { |
| 41 | timespec++; |
| 42 | if (*timespec == '+') { |
| 43 | *set_eq = 2; /* relative "in the future" */ |
| 44 | timespec++; |
| 45 | } |
| 46 | } |
| 47 | *set_time = strtol(timespec, &test, 10); |
| 48 | if (*test) { |
| 49 | fprintf(stderr, "Not a base-10 integer: %s\n", arg + 1); |
| 50 | return 0; |
| 51 | } |
| 52 | if ((*set_eq && *set_time < 0) || *set_eq == 2) { |
| 53 | time_t now = time(NULL); |
| 54 | *set_time += now; |
| 55 | } |
| 56 | return 1; |
| 57 | } |
Eric Wong | 17e4836 | 2007-02-24 18:18:22 -0800 | [diff] [blame] | 58 | |
| 59 | int main(int argc, const char *argv[]) |
| 60 | { |
Alex Riesen | 0ea9ca0 | 2008-10-30 10:00:29 +0100 | [diff] [blame] | 61 | static int verbose; |
| 62 | |
| 63 | int i = 1; |
| 64 | /* no mtime change by default */ |
| 65 | int set_eq = 0; |
| 66 | long int set_time = 0; |
Eric Wong | 17e4836 | 2007-02-24 18:18:22 -0800 | [diff] [blame] | 67 | |
| 68 | if (argc < 3) |
| 69 | goto usage; |
| 70 | |
Alex Riesen | 0ea9ca0 | 2008-10-30 10:00:29 +0100 | [diff] [blame] | 71 | if (strcmp(argv[i], "--verbose") == 0 || strcmp(argv[i], "-v") == 0) { |
| 72 | verbose = 1; |
| 73 | ++i; |
Eric Wong | 17e4836 | 2007-02-24 18:18:22 -0800 | [diff] [blame] | 74 | } |
Alex Riesen | 0ea9ca0 | 2008-10-30 10:00:29 +0100 | [diff] [blame] | 75 | if (timespec_arg(argv[i], &set_time, &set_eq)) |
| 76 | ++i; |
| 77 | else |
Eric Wong | 17e4836 | 2007-02-24 18:18:22 -0800 | [diff] [blame] | 78 | goto usage; |
Eric Wong | 17e4836 | 2007-02-24 18:18:22 -0800 | [diff] [blame] | 79 | |
Alex Riesen | 0ea9ca0 | 2008-10-30 10:00:29 +0100 | [diff] [blame] | 80 | for (; i < argc; i++) { |
Eric Wong | 17e4836 | 2007-02-24 18:18:22 -0800 | [diff] [blame] | 81 | struct stat sb; |
| 82 | struct utimbuf utb; |
| 83 | |
| 84 | if (stat(argv[i], &sb) < 0) { |
| 85 | fprintf(stderr, "Failed to stat %s: %s\n", |
| 86 | argv[i], strerror(errno)); |
| 87 | return -1; |
| 88 | } |
| 89 | |
Johannes Schindelin | d9b2633 | 2009-05-31 18:15:18 +0200 | [diff] [blame] | 90 | #ifdef WIN32 |
| 91 | if (!(sb.st_mode & S_IWUSR) && |
| 92 | chmod(argv[i], sb.st_mode | S_IWUSR)) { |
| 93 | fprintf(stderr, "Could not make user-writable %s: %s", |
| 94 | argv[i], strerror(errno)); |
| 95 | return -1; |
| 96 | } |
| 97 | #endif |
| 98 | |
Eric Wong | 17e4836 | 2007-02-24 18:18:22 -0800 | [diff] [blame] | 99 | utb.actime = sb.st_atime; |
| 100 | utb.modtime = set_eq ? set_time : sb.st_mtime + set_time; |
| 101 | |
Alex Riesen | 0ea9ca0 | 2008-10-30 10:00:29 +0100 | [diff] [blame] | 102 | if (verbose) { |
| 103 | uintmax_t mtime = utb.modtime < 0 ? 0: utb.modtime; |
| 104 | printf("%"PRIuMAX"\t%s\n", mtime, argv[i]); |
| 105 | } |
| 106 | |
| 107 | if (utb.modtime != sb.st_mtime && utime(argv[i], &utb) < 0) { |
Eric Wong | 17e4836 | 2007-02-24 18:18:22 -0800 | [diff] [blame] | 108 | fprintf(stderr, "Failed to modify time on %s: %s\n", |
| 109 | argv[i], strerror(errno)); |
| 110 | return -1; |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | return 0; |
| 115 | |
| 116 | usage: |
| 117 | fprintf(stderr, "Usage: %s %s\n", argv[0], usage_str); |
| 118 | return -1; |
| 119 | } |