t / helper / test-chmtime.con commit Merge branch 'pw/add-p-recount' into maint (689204c)
   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 or
   4 * ctime (their values are explicitly preserved).
   5 *
   6 * The mtime can be changed to an absolute value:
   7 *
   8 *      test-tool chmtime =<seconds> file...
   9 *
  10 * Relative to the current time as returned by time(3):
  11 *
  12 *      test-tool chmtime =+<seconds> (or =-<seconds>) file...
  13 *
  14 * Or relative to the current mtime of the file:
  15 *
  16 *      test-tool chmtime <seconds> file...
  17 *      test-tool chmtime +<seconds> (or -<seconds>) file...
  18 *
  19 * Examples:
  20 *
  21 * To print the mtime and the file name use --verbose and set
  22 * the file mtime offset to 0:
  23 *
  24 *      test-tool chmtime -v +0 file
  25 *
  26 * To print only the mtime use --get:
  27 *
  28 *      test-tool chmtime --get file
  29 *
  30 * To set the mtime to current time:
  31 *
  32 *      test-tool chmtime =+0 file
  33 *
  34 * To set the file mtime offset to +1 and print the new value:
  35 *
  36 *      test-tool chmtime --get +1 file
  37 *
  38 */
  39#include "test-tool.h"
  40#include "git-compat-util.h"
  41#include <utime.h>
  42
  43static const char usage_str[] =
  44        "(-v|--verbose|-g|--get) (+|=|=+|=-|-)<seconds> <file>...";
  45
  46static int timespec_arg(const char *arg, long int *set_time, int *set_eq)
  47{
  48        char *test;
  49        const char *timespec = arg;
  50        *set_eq = (*timespec == '=') ? 1 : 0;
  51        if (*set_eq) {
  52                timespec++;
  53                if (*timespec == '+') {
  54                        *set_eq = 2; /* relative "in the future" */
  55                        timespec++;
  56                }
  57        }
  58        *set_time = strtol(timespec, &test, 10);
  59        if (*test) {
  60                return 0;
  61        }
  62        if ((*set_eq && *set_time < 0) || *set_eq == 2) {
  63                time_t now = time(NULL);
  64                *set_time += now;
  65        }
  66        return 1;
  67}
  68
  69int cmd__chmtime(int argc, const char **argv)
  70{
  71        static int verbose;
  72        static int get;
  73
  74        int i = 1;
  75        /* no mtime change by default */
  76        int set_eq = 0;
  77        long int set_time = 0;
  78
  79        if (argc < 3)
  80                goto usage;
  81
  82        if (strcmp(argv[i], "--get") == 0 || strcmp(argv[i], "-g") == 0) {
  83                get = 1;
  84                ++i;
  85        } else if (strcmp(argv[i], "--verbose") == 0 || strcmp(argv[i], "-v") == 0) {
  86                verbose = 1;
  87                ++i;
  88        }
  89
  90        if (i == argc) {
  91                goto usage;
  92        }
  93
  94        if (timespec_arg(argv[i], &set_time, &set_eq)) {
  95                ++i;
  96        } else {
  97                if (get == 0) {
  98                        fprintf(stderr, "Not a base-10 integer: %s\n", argv[i] + 1);
  99                        goto usage;
 100                }
 101        }
 102
 103        if (i == argc)
 104                goto usage;
 105
 106        for (; i < argc; i++) {
 107                struct stat sb;
 108                struct utimbuf utb;
 109                uintmax_t mtime;
 110
 111                if (stat(argv[i], &sb) < 0) {
 112                        fprintf(stderr, "Failed to stat %s: %s\n",
 113                                argv[i], strerror(errno));
 114                        return 1;
 115                }
 116
 117#ifdef GIT_WINDOWS_NATIVE
 118                if (!(sb.st_mode & S_IWUSR) &&
 119                                chmod(argv[i], sb.st_mode | S_IWUSR)) {
 120                        fprintf(stderr, "Could not make user-writable %s: %s",
 121                                argv[i], strerror(errno));
 122                        return 1;
 123                }
 124#endif
 125
 126                utb.actime = sb.st_atime;
 127                utb.modtime = set_eq ? set_time : sb.st_mtime + set_time;
 128
 129                mtime = utb.modtime < 0 ? 0: utb.modtime;
 130                if (get) {
 131                        printf("%"PRIuMAX"\n", mtime);
 132                } else if (verbose) {
 133                        printf("%"PRIuMAX"\t%s\n", mtime, argv[i]);
 134                }
 135
 136                if (utb.modtime != sb.st_mtime && utime(argv[i], &utb) < 0) {
 137                        fprintf(stderr, "Failed to modify time on %s: %s\n",
 138                                argv[i], strerror(errno));
 139                        return 1;
 140                }
 141        }
 142
 143        return 0;
 144
 145usage:
 146        fprintf(stderr, "usage: %s %s\n", argv[0], usage_str);
 147        return 1;
 148}