7ccd721a4abdfec68fa9cab1f380569152fe61e9
   1#include "refs.h"
   2#include "cache.h"
   3
   4#include <errno.h>
   5
   6static int read_ref(const char *path, unsigned char *sha1)
   7{
   8        int ret = -1;
   9        int fd = open(path, O_RDONLY);
  10
  11        if (fd >= 0) {
  12                char buffer[60];
  13                if (read(fd, buffer, sizeof(buffer)) >= 40)
  14                        ret = get_sha1_hex(buffer, sha1);
  15                close(fd);
  16        }
  17        return ret;
  18}
  19
  20static int do_for_each_ref(const char *base, int (*fn)(const char *path, const unsigned char *sha1))
  21{
  22        int retval = 0;
  23        DIR *dir = opendir(base);
  24
  25        if (dir) {
  26                struct dirent *de;
  27                int baselen = strlen(base);
  28                char *path = xmalloc(baselen + 257);
  29
  30                if (!strncmp(base, "./", 2)) {
  31                        base += 2;
  32                        baselen -= 2;
  33                }
  34                memcpy(path, base, baselen);
  35                if (baselen && base[baselen-1] != '/')
  36                        path[baselen++] = '/';
  37
  38                while ((de = readdir(dir)) != NULL) {
  39                        unsigned char sha1[20];
  40                        struct stat st;
  41                        int namelen;
  42
  43                        if (de->d_name[0] == '.')
  44                                continue;
  45                        namelen = strlen(de->d_name);
  46                        if (namelen > 255)
  47                                continue;
  48                        memcpy(path + baselen, de->d_name, namelen+1);
  49                        if (lstat(path, &st) < 0)
  50                                continue;
  51                        if (S_ISDIR(st.st_mode)) {
  52                                retval = do_for_each_ref(path, fn);
  53                                if (retval)
  54                                        break;
  55                                continue;
  56                        }
  57                        if (read_ref(path, sha1) < 0)
  58                                continue;
  59                        if (!has_sha1_file(sha1))
  60                                continue;
  61                        retval = fn(path, sha1);
  62                        if (retval)
  63                                break;
  64                }
  65                free(path);
  66                closedir(dir);
  67        }
  68        return retval;
  69}
  70
  71int for_each_ref(int (*fn)(const char *path, const unsigned char *sha1))
  72{
  73        return do_for_each_ref(get_refs_directory(), fn);
  74}
  75
  76static char *ref_file_name(const char *ref)
  77{
  78        char *base = get_refs_directory();
  79        int baselen = strlen(base);
  80        int reflen = strlen(ref);
  81        char *ret = xmalloc(baselen + 2 + reflen);
  82        sprintf(ret, "%s/%s", base, ref);
  83        return ret;
  84}
  85
  86static char *ref_lock_file_name(const char *ref)
  87{
  88        char *base = get_refs_directory();
  89        int baselen = strlen(base);
  90        int reflen = strlen(ref);
  91        char *ret = xmalloc(baselen + 7 + reflen);
  92        sprintf(ret, "%s/%s.lock", base, ref);
  93        return ret;
  94}
  95
  96static int read_ref_file(const char *filename, unsigned char *sha1) {
  97        int fd = open(filename, O_RDONLY);
  98        char hex[41];
  99        if (fd < 0) {
 100                return error("Couldn't open %s\n", filename);
 101        }
 102        if ((read(fd, hex, 41) < 41) ||
 103            (hex[40] != '\n') ||
 104            get_sha1_hex(hex, sha1)) {
 105                error("Couldn't read a hash from %s\n", filename);
 106                close(fd);
 107                return -1;
 108        }
 109        close(fd);
 110        return 0;
 111}
 112
 113int get_ref_sha1(const char *ref, unsigned char *sha1)
 114{
 115        char *filename;
 116        int retval;
 117        if (check_ref_format(ref))
 118                return -1;
 119        filename = ref_file_name(ref);
 120        retval = read_ref_file(filename, sha1);
 121        free(filename);
 122        return retval;
 123}
 124
 125static int lock_ref_file(const char *filename, const char *lock_filename,
 126                         const unsigned char *old_sha1)
 127{
 128        int fd = open(lock_filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
 129        unsigned char current_sha1[20];
 130        int retval;
 131        if (fd < 0) {
 132                return error("Couldn't open lock file for %s: %s",
 133                             filename, strerror(errno));
 134        }
 135        retval = read_ref_file(filename, current_sha1);
 136        if (old_sha1) {
 137                if (retval) {
 138                        close(fd);
 139                        unlink(lock_filename);
 140                        return error("Could not read the current value of %s",
 141                                     filename);
 142                }
 143                if (memcmp(current_sha1, old_sha1, 20)) {
 144                        close(fd);
 145                        unlink(lock_filename);
 146                        error("The current value of %s is %s",
 147                              filename, sha1_to_hex(current_sha1));
 148                        return error("Expected %s",
 149                                     sha1_to_hex(old_sha1));
 150                }
 151        } else {
 152                if (!retval) {
 153                        close(fd);
 154                        unlink(lock_filename);
 155                        return error("Unexpectedly found a value of %s for %s",
 156                                     sha1_to_hex(current_sha1), filename);
 157                }
 158        }
 159        return fd;
 160}
 161
 162int lock_ref_sha1(const char *ref, const unsigned char *old_sha1)
 163{
 164        char *filename;
 165        char *lock_filename;
 166        int retval;
 167        if (check_ref_format(ref))
 168                return -1;
 169        filename = ref_file_name(ref);
 170        lock_filename = ref_lock_file_name(ref);
 171        retval = lock_ref_file(filename, lock_filename, old_sha1);
 172        free(filename);
 173        free(lock_filename);
 174        return retval;
 175}
 176
 177static int write_ref_file(const char *filename,
 178                          const char *lock_filename, int fd,
 179                          const unsigned char *sha1)
 180{
 181        char *hex = sha1_to_hex(sha1);
 182        char term = '\n';
 183        if (write(fd, hex, 40) < 40 ||
 184            write(fd, &term, 1) < 1) {
 185                error("Couldn't write %s\n", filename);
 186                close(fd);
 187                return -1;
 188        }
 189        close(fd);
 190        rename(lock_filename, filename);
 191        return 0;
 192}
 193
 194int write_ref_sha1(const char *ref, int fd, const unsigned char *sha1)
 195{
 196        char *filename;
 197        char *lock_filename;
 198        int retval;
 199        if (fd < 0)
 200                return -1;
 201        if (check_ref_format(ref))
 202                return -1;
 203        filename = ref_file_name(ref);
 204        lock_filename = ref_lock_file_name(ref);
 205        retval = write_ref_file(filename, lock_filename, fd, sha1);
 206        free(filename);
 207        free(lock_filename);
 208        return retval;
 209}
 210
 211int check_ref_format(const char *ref)
 212{
 213        char *middle;
 214        if (ref[0] == '.' || ref[0] == '/')
 215                return -1;
 216        middle = strchr(ref, '/');
 217        if (!middle || !middle[1])
 218                return -1;
 219        if (strchr(middle + 1, '/'))
 220                return -1;
 221        return 0;
 222}
 223
 224int write_ref_sha1_unlocked(const char *ref, const unsigned char *sha1)
 225{
 226        char *filename;
 227        char *lock_filename;
 228        int fd;
 229        int retval;
 230        if (check_ref_format(ref))
 231                return -1;
 232        filename = ref_file_name(ref);
 233        lock_filename = ref_lock_file_name(ref);
 234        fd = open(lock_filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
 235        if (fd < 0) {
 236                error("Writing %s", lock_filename);
 237                perror("Open");
 238        }
 239        retval = write_ref_file(filename, lock_filename, fd, sha1);
 240        free(filename);
 241        free(lock_filename);
 242        return retval;
 243}