refs.con commit Do a cross-project merge of Paul Mackerras' gitk visualizer (5569bf9)
   1#include "refs.h"
   2#include "cache.h"
   3
   4#include <errno.h>
   5
   6static char *ref_file_name(const char *ref)
   7{
   8        char *base = get_refs_directory();
   9        int baselen = strlen(base);
  10        int reflen = strlen(ref);
  11        char *ret = xmalloc(baselen + 2 + reflen);
  12        sprintf(ret, "%s/%s", base, ref);
  13        return ret;
  14}
  15
  16static char *ref_lock_file_name(const char *ref)
  17{
  18        char *base = get_refs_directory();
  19        int baselen = strlen(base);
  20        int reflen = strlen(ref);
  21        char *ret = xmalloc(baselen + 7 + reflen);
  22        sprintf(ret, "%s/%s.lock", base, ref);
  23        return ret;
  24}
  25
  26static int read_ref_file(const char *filename, unsigned char *sha1) {
  27        int fd = open(filename, O_RDONLY);
  28        char hex[41];
  29        if (fd < 0) {
  30                return error("Couldn't open %s\n", filename);
  31        }
  32        if ((read(fd, hex, 41) < 41) ||
  33            (hex[40] != '\n') ||
  34            get_sha1_hex(hex, sha1)) {
  35                error("Couldn't read a hash from %s\n", filename);
  36                close(fd);
  37                return -1;
  38        }
  39        close(fd);
  40        return 0;
  41}
  42
  43int get_ref_sha1(const char *ref, unsigned char *sha1)
  44{
  45        char *filename;
  46        int retval;
  47        if (check_ref_format(ref))
  48                return -1;
  49        filename = ref_file_name(ref);
  50        retval = read_ref_file(filename, sha1);
  51        free(filename);
  52        return retval;
  53}
  54
  55static int lock_ref_file(const char *filename, const char *lock_filename,
  56                         const unsigned char *old_sha1)
  57{
  58        int fd = open(lock_filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
  59        unsigned char current_sha1[20];
  60        int retval;
  61        if (fd < 0) {
  62                return error("Couldn't open lock file for %s: %s",
  63                             filename, strerror(errno));
  64        }
  65        retval = read_ref_file(filename, current_sha1);
  66        if (old_sha1) {
  67                if (retval) {
  68                        close(fd);
  69                        unlink(lock_filename);
  70                        return error("Could not read the current value of %s",
  71                                     filename);
  72                }
  73                if (memcmp(current_sha1, old_sha1, 20)) {
  74                        close(fd);
  75                        unlink(lock_filename);
  76                        error("The current value of %s is %s",
  77                              filename, sha1_to_hex(current_sha1));
  78                        return error("Expected %s",
  79                                     sha1_to_hex(old_sha1));
  80                }
  81        } else {
  82                if (!retval) {
  83                        close(fd);
  84                        unlink(lock_filename);
  85                        return error("Unexpectedly found a value of %s for %s",
  86                                     sha1_to_hex(current_sha1), filename);
  87                }
  88        }
  89        return fd;
  90}
  91
  92int lock_ref_sha1(const char *ref, const unsigned char *old_sha1)
  93{
  94        char *filename;
  95        char *lock_filename;
  96        int retval;
  97        if (check_ref_format(ref))
  98                return -1;
  99        filename = ref_file_name(ref);
 100        lock_filename = ref_lock_file_name(ref);
 101        retval = lock_ref_file(filename, lock_filename, old_sha1);
 102        free(filename);
 103        free(lock_filename);
 104        return retval;
 105}
 106
 107static int write_ref_file(const char *filename,
 108                          const char *lock_filename, int fd,
 109                          const unsigned char *sha1)
 110{
 111        char *hex = sha1_to_hex(sha1);
 112        char term = '\n';
 113        if (write(fd, hex, 40) < 40 ||
 114            write(fd, &term, 1) < 1) {
 115                error("Couldn't write %s\n", filename);
 116                close(fd);
 117                return -1;
 118        }
 119        close(fd);
 120        rename(lock_filename, filename);
 121        return 0;
 122}
 123
 124int write_ref_sha1(const char *ref, int fd, const unsigned char *sha1)
 125{
 126        char *filename;
 127        char *lock_filename;
 128        int retval;
 129        if (fd < 0)
 130                return -1;
 131        if (check_ref_format(ref))
 132                return -1;
 133        filename = ref_file_name(ref);
 134        lock_filename = ref_lock_file_name(ref);
 135        retval = write_ref_file(filename, lock_filename, fd, sha1);
 136        free(filename);
 137        free(lock_filename);
 138        return retval;
 139}
 140
 141int check_ref_format(const char *ref)
 142{
 143        char *middle;
 144        if (ref[0] == '.' || ref[0] == '/')
 145                return -1;
 146        middle = strchr(ref, '/');
 147        if (!middle || !middle[1])
 148                return -1;
 149        if (strchr(middle + 1, '/'))
 150                return -1;
 151        return 0;
 152}
 153
 154int write_ref_sha1_unlocked(const char *ref, const unsigned char *sha1)
 155{
 156        char *filename;
 157        char *lock_filename;
 158        int fd;
 159        int retval;
 160        if (check_ref_format(ref))
 161                return -1;
 162        filename = ref_file_name(ref);
 163        lock_filename = ref_lock_file_name(ref);
 164        fd = open(lock_filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
 165        if (fd < 0) {
 166                error("Writing %s", lock_filename);
 167                perror("Open");
 168        }
 169        retval = write_ref_file(filename, lock_filename, fd, sha1);
 170        free(filename);
 171        free(lock_filename);
 172        return retval;
 173}