compat / mkstemps.con commit Merge branch 'maint' (e7e5548)
   1#include "../git-compat-util.h"
   2
   3/* Adapted from libiberty's mkstemp.c. */
   4
   5#undef TMP_MAX
   6#define TMP_MAX 16384
   7
   8int gitmkstemps(char *pattern, int suffix_len)
   9{
  10        static const char letters[] =
  11                "abcdefghijklmnopqrstuvwxyz"
  12                "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  13                "0123456789";
  14        static const int num_letters = 62;
  15        uint64_t value;
  16        struct timeval tv;
  17        char *template;
  18        size_t len;
  19        int fd, count;
  20
  21        len = strlen(pattern);
  22
  23        if (len < 6 + suffix_len) {
  24                errno = EINVAL;
  25                return -1;
  26        }
  27
  28        if (strncmp(&pattern[len - 6 - suffix_len], "XXXXXX", 6)) {
  29                errno = EINVAL;
  30                return -1;
  31        }
  32
  33        /*
  34         * Replace pattern's XXXXXX characters with randomness.
  35         * Try TMP_MAX different filenames.
  36         */
  37        gettimeofday(&tv, NULL);
  38        value = ((size_t)(tv.tv_usec << 16)) ^ tv.tv_sec ^ getpid();
  39        template = &pattern[len - 6 - suffix_len];
  40        for (count = 0; count < TMP_MAX; ++count) {
  41                uint64_t v = value;
  42                /* Fill in the random bits. */
  43                template[0] = letters[v % num_letters]; v /= num_letters;
  44                template[1] = letters[v % num_letters]; v /= num_letters;
  45                template[2] = letters[v % num_letters]; v /= num_letters;
  46                template[3] = letters[v % num_letters]; v /= num_letters;
  47                template[4] = letters[v % num_letters]; v /= num_letters;
  48                template[5] = letters[v % num_letters]; v /= num_letters;
  49
  50                fd = open(pattern, O_CREAT | O_EXCL | O_RDWR, 0600);
  51                if (fd > 0)
  52                        return fd;
  53                /*
  54                 * Fatal error (EPERM, ENOSPC etc).
  55                 * It doesn't make sense to loop.
  56                 */
  57                if (errno != EEXIST)
  58                        break;
  59                /*
  60                 * This is a random value.  It is only necessary that
  61                 * the next TMP_MAX values generated by adding 7777 to
  62                 * VALUE are different with (module 2^32).
  63                 */
  64                value += 7777;
  65        }
  66        /* We return the null string if we can't find a unique file name.  */
  67        pattern[0] = '\0';
  68        errno = EINVAL;
  69        return -1;
  70}