eee3598bb75e2199045b823f007e7933c0fb9cfe
   1/*
   2 * GIT - The information manager from hell
   3 *
   4 * Copyright (C) Linus Torvalds, 2005
   5 *
   6 * This handles basic git sha1 object files - packing, unpacking,
   7 * creation etc.
   8 */
   9#include <stdarg.h>
  10#include "cache.h"
  11
  12const char *sha1_file_directory = NULL;
  13
  14static unsigned hexval(char c)
  15{
  16        if (c >= '0' && c <= '9')
  17                return c - '0';
  18        if (c >= 'a' && c <= 'f')
  19                return c - 'a' + 10;
  20        if (c >= 'A' && c <= 'F')
  21                return c - 'A' + 10;
  22        return ~0;
  23}
  24
  25int get_sha1_hex(const char *hex, unsigned char *sha1)
  26{
  27        int i;
  28        for (i = 0; i < 20; i++) {
  29                unsigned int val = (hexval(hex[0]) << 4) | hexval(hex[1]);
  30                if (val & ~0xff)
  31                        return -1;
  32                *sha1++ = val;
  33                hex += 2;
  34        }
  35        return 0;
  36}
  37
  38char * sha1_to_hex(const unsigned char *sha1)
  39{
  40        static char buffer[50];
  41        static const char hex[] = "0123456789abcdef";
  42        char *buf = buffer;
  43        int i;
  44
  45        for (i = 0; i < 20; i++) {
  46                unsigned int val = *sha1++;
  47                *buf++ = hex[val >> 4];
  48                *buf++ = hex[val & 0xf];
  49        }
  50        return buffer;
  51}
  52
  53/*
  54 * NOTE! This returns a statically allocated buffer, so you have to be
  55 * careful about using it. Do a "strdup()" if you need to save the
  56 * filename.
  57 */
  58char *sha1_file_name(const unsigned char *sha1)
  59{
  60        int i;
  61        static char *name, *base;
  62
  63        if (!base) {
  64                char *sha1_file_directory = getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT;
  65                int len = strlen(sha1_file_directory);
  66                base = malloc(len + 60);
  67                memcpy(base, sha1_file_directory, len);
  68                memset(base+len, 0, 60);
  69                base[len] = '/';
  70                base[len+3] = '/';
  71                name = base + len + 1;
  72        }
  73        for (i = 0; i < 20; i++) {
  74                static char hex[] = "0123456789abcdef";
  75                unsigned int val = sha1[i];
  76                char *pos = name + i*2 + (i > 0);
  77                *pos++ = hex[val >> 4];
  78                *pos = hex[val & 0xf];
  79        }
  80        return base;
  81}
  82
  83int check_sha1_signature(unsigned char *sha1, void *map, unsigned long size, const char *type)
  84{
  85        char header[100];
  86        unsigned char real_sha1[20];
  87        SHA_CTX c;
  88
  89        SHA1_Init(&c);
  90        SHA1_Update(&c, header, 1+sprintf(header, "%s %lu", type, size));
  91        SHA1_Update(&c, map, size);
  92        SHA1_Final(real_sha1, &c);
  93        return memcmp(sha1, real_sha1, 20) ? -1 : 0;
  94}
  95
  96void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
  97{
  98        char *filename = sha1_file_name(sha1);
  99        int fd = open(filename, O_RDONLY);
 100        struct stat st;
 101        void *map;
 102
 103        if (fd < 0) {
 104                perror(filename);
 105                return NULL;
 106        }
 107        if (fstat(fd, &st) < 0) {
 108                close(fd);
 109                return NULL;
 110        }
 111        map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
 112        close(fd);
 113        if (-1 == (int)(long)map)
 114                return NULL;
 115        *size = st.st_size;
 116        return map;
 117}
 118
 119void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size)
 120{
 121        int ret, bytes;
 122        z_stream stream;
 123        char buffer[8192];
 124        char *buf;
 125
 126        /* Get the data stream */
 127        memset(&stream, 0, sizeof(stream));
 128        stream.next_in = map;
 129        stream.avail_in = mapsize;
 130        stream.next_out = buffer;
 131        stream.avail_out = sizeof(buffer);
 132
 133        inflateInit(&stream);
 134        ret = inflate(&stream, 0);
 135        if (sscanf(buffer, "%10s %lu", type, size) != 2)
 136                return NULL;
 137
 138        bytes = strlen(buffer) + 1;
 139        buf = malloc(*size);
 140        if (!buf)
 141                return NULL;
 142
 143        memcpy(buf, buffer + bytes, stream.total_out - bytes);
 144        bytes = stream.total_out - bytes;
 145        if (bytes < *size && ret == Z_OK) {
 146                stream.next_out = buf + bytes;
 147                stream.avail_out = *size - bytes;
 148                while (inflate(&stream, Z_FINISH) == Z_OK)
 149                        /* nothing */;
 150        }
 151        inflateEnd(&stream);
 152        return buf;
 153}
 154
 155void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size)
 156{
 157        unsigned long mapsize;
 158        void *map, *buf;
 159
 160        map = map_sha1_file(sha1, &mapsize);
 161        if (map) {
 162                buf = unpack_sha1_file(map, mapsize, type, size);
 163                munmap(map, mapsize);
 164                return buf;
 165        }
 166        return NULL;
 167}
 168
 169int write_sha1_file(char *buf, unsigned len, unsigned char *returnsha1)
 170{
 171        int size;
 172        char *compressed;
 173        z_stream stream;
 174        unsigned char sha1[20];
 175        SHA_CTX c;
 176        char *filename;
 177        int fd;
 178
 179        /* Sha1.. */
 180        SHA1_Init(&c);
 181        SHA1_Update(&c, buf, len);
 182        SHA1_Final(sha1, &c);
 183
 184        if (returnsha1)
 185                memcpy(returnsha1, sha1, 20);
 186
 187        filename = sha1_file_name(sha1);
 188        fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
 189        if (fd < 0) {
 190                if (errno != EEXIST)
 191                        return -1;
 192
 193                /*
 194                 * We might do collision checking here, but we'd need to
 195                 * uncompress the old file and check it. Later.
 196                 */
 197                return 0;
 198        }
 199
 200        /* Set it up */
 201        memset(&stream, 0, sizeof(stream));
 202        deflateInit(&stream, Z_BEST_COMPRESSION);
 203        size = deflateBound(&stream, len);
 204        compressed = malloc(size);
 205
 206        /* Compress it */
 207        stream.next_in = buf;
 208        stream.avail_in = len;
 209        stream.next_out = compressed;
 210        stream.avail_out = size;
 211        while (deflate(&stream, Z_FINISH) == Z_OK)
 212                /* nothing */;
 213        deflateEnd(&stream);
 214        size = stream.total_out;
 215
 216        if (write(fd, compressed, size) != size)
 217                die("unable to write file");
 218        close(fd);
 219                
 220        return 0;
 221}
 222
 223static inline int collision_check(char *filename, void *buf, unsigned int size)
 224{
 225#ifdef COLLISION_CHECK
 226        void *map;
 227        int fd = open(filename, O_RDONLY);
 228        struct stat st;
 229        int cmp;
 230
 231        /* Unreadable object, or object went away? Strange. */
 232        if (fd < 0)
 233                return -1;
 234
 235        if (fstat(fd, &st) < 0 || size != st.st_size)
 236                return -1;
 237
 238        map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
 239        close(fd);
 240        if (map == MAP_FAILED)
 241                return -1;
 242        cmp = memcmp(buf, map, size);
 243        munmap(map, size);
 244        if (cmp)
 245                return -1;
 246#endif
 247        return 0;
 248}
 249
 250int write_sha1_buffer(const unsigned char *sha1, void *buf, unsigned int size)
 251{
 252        char *filename = sha1_file_name(sha1);
 253        int fd;
 254
 255        fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
 256        if (fd < 0) {
 257                if (errno != EEXIST)
 258                        return -1;
 259                if (collision_check(filename, buf, size))
 260                        return error("SHA1 collision detected!"
 261                                        " This is bad, bad, BAD!\a\n");
 262                return 0;
 263        }
 264        write(fd, buf, size);
 265        close(fd);
 266        return 0;
 267}