sha1_file.con commit Do SHA1 hash _before_ compression. (d98b46f)
   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
 177        /* Sha1.. */
 178        SHA1_Init(&c);
 179        SHA1_Update(&c, buf, len);
 180        SHA1_Final(sha1, &c);
 181
 182        /* Set it up */
 183        memset(&stream, 0, sizeof(stream));
 184        deflateInit(&stream, Z_BEST_COMPRESSION);
 185        size = deflateBound(&stream, len);
 186        compressed = malloc(size);
 187
 188        /* Compress it */
 189        stream.next_in = buf;
 190        stream.avail_in = len;
 191        stream.next_out = compressed;
 192        stream.avail_out = size;
 193        while (deflate(&stream, Z_FINISH) == Z_OK)
 194                /* nothing */;
 195        deflateEnd(&stream);
 196        size = stream.total_out;
 197
 198        if (write_sha1_buffer(sha1, compressed, size) < 0)
 199                return -1;
 200        if (returnsha1)
 201                memcpy(returnsha1, sha1, 20);
 202        return 0;
 203}
 204
 205static inline int collision_check(char *filename, void *buf, unsigned int size)
 206{
 207#ifdef COLLISION_CHECK
 208        void *map;
 209        int fd = open(filename, O_RDONLY);
 210        struct stat st;
 211        int cmp;
 212
 213        /* Unreadable object, or object went away? Strange. */
 214        if (fd < 0)
 215                return -1;
 216
 217        if (fstat(fd, &st) < 0 || size != st.st_size)
 218                return -1;
 219
 220        map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
 221        close(fd);
 222        if (map == MAP_FAILED)
 223                return -1;
 224        cmp = memcmp(buf, map, size);
 225        munmap(map, size);
 226        if (cmp)
 227                return -1;
 228#endif
 229        return 0;
 230}
 231
 232int write_sha1_buffer(const unsigned char *sha1, void *buf, unsigned int size)
 233{
 234        char *filename = sha1_file_name(sha1);
 235        int fd;
 236
 237        fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
 238        if (fd < 0) {
 239                if (errno != EEXIST)
 240                        return -1;
 241                if (collision_check(filename, buf, size))
 242                        return error("SHA1 collision detected!"
 243                                        " This is bad, bad, BAD!\a\n");
 244                return 0;
 245        }
 246        write(fd, buf, size);
 247        close(fd);
 248        return 0;
 249}