sha1_file.con commit [PATCH] show-diff.c: simplify show_diff_empty. (8f3671d)
   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)
  84{
  85        unsigned char real_sha1[20];
  86        SHA_CTX c;
  87
  88        SHA1_Init(&c);
  89        SHA1_Update(&c, map, size);
  90        SHA1_Final(real_sha1, &c);
  91        return memcmp(sha1, real_sha1, 20) ? -1 : 0;
  92}
  93
  94void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
  95{
  96        char *filename = sha1_file_name(sha1);
  97        int fd = open(filename, O_RDONLY);
  98        struct stat st;
  99        void *map;
 100
 101        if (fd < 0) {
 102                perror(filename);
 103                return NULL;
 104        }
 105        if (fstat(fd, &st) < 0) {
 106                close(fd);
 107                return NULL;
 108        }
 109        map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
 110        close(fd);
 111        if (-1 == (int)(long)map)
 112                return NULL;
 113        *size = st.st_size;
 114        return map;
 115}
 116
 117void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size)
 118{
 119        int ret, bytes;
 120        z_stream stream;
 121        char buffer[8192];
 122        char *buf;
 123
 124        /* Get the data stream */
 125        memset(&stream, 0, sizeof(stream));
 126        stream.next_in = map;
 127        stream.avail_in = mapsize;
 128        stream.next_out = buffer;
 129        stream.avail_out = sizeof(buffer);
 130
 131        inflateInit(&stream);
 132        ret = inflate(&stream, 0);
 133        if (sscanf(buffer, "%10s %lu", type, size) != 2)
 134                return NULL;
 135
 136        bytes = strlen(buffer) + 1;
 137        buf = malloc(*size);
 138        if (!buf)
 139                return NULL;
 140
 141        memcpy(buf, buffer + bytes, stream.total_out - bytes);
 142        bytes = stream.total_out - bytes;
 143        if (bytes < *size && ret == Z_OK) {
 144                stream.next_out = buf + bytes;
 145                stream.avail_out = *size - bytes;
 146                while (inflate(&stream, Z_FINISH) == Z_OK)
 147                        /* nothing */;
 148        }
 149        inflateEnd(&stream);
 150        return buf;
 151}
 152
 153void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size)
 154{
 155        unsigned long mapsize;
 156        void *map, *buf;
 157
 158        map = map_sha1_file(sha1, &mapsize);
 159        if (map) {
 160                buf = unpack_sha1_file(map, mapsize, type, size);
 161                munmap(map, mapsize);
 162                return buf;
 163        }
 164        return NULL;
 165}
 166
 167int write_sha1_file(char *buf, unsigned len, unsigned char *returnsha1)
 168{
 169        int size;
 170        char *compressed;
 171        z_stream stream;
 172        unsigned char sha1[20];
 173        SHA_CTX c;
 174
 175        /* Set it up */
 176        memset(&stream, 0, sizeof(stream));
 177        deflateInit(&stream, Z_BEST_COMPRESSION);
 178        size = deflateBound(&stream, len);
 179        compressed = malloc(size);
 180
 181        /* Compress it */
 182        stream.next_in = buf;
 183        stream.avail_in = len;
 184        stream.next_out = compressed;
 185        stream.avail_out = size;
 186        while (deflate(&stream, Z_FINISH) == Z_OK)
 187                /* nothing */;
 188        deflateEnd(&stream);
 189        size = stream.total_out;
 190
 191        /* Sha1.. */
 192        SHA1_Init(&c);
 193        SHA1_Update(&c, compressed, size);
 194        SHA1_Final(sha1, &c);
 195
 196        if (write_sha1_buffer(sha1, compressed, size) < 0)
 197                return -1;
 198        if (returnsha1)
 199                memcpy(returnsha1, sha1, 20);
 200        return 0;
 201}
 202
 203static inline int collision_check(char *filename, void *buf, unsigned int size)
 204{
 205#ifdef COLLISION_CHECK
 206        void *map;
 207        int fd = open(filename, O_RDONLY);
 208        struct stat st;
 209        int cmp;
 210
 211        /* Unreadable object, or object went away? Strange. */
 212        if (fd < 0)
 213                return -1;
 214
 215        if (fstat(fd, &st) < 0 || size != st.st_size)
 216                return -1;
 217
 218        map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
 219        close(fd);
 220        if (map == MAP_FAILED)
 221                return -1;
 222        cmp = memcmp(buf, map, size);
 223        munmap(map, size);
 224        if (cmp)
 225                return -1;
 226#endif
 227        return 0;
 228}
 229
 230int write_sha1_buffer(const unsigned char *sha1, void *buf, unsigned int size)
 231{
 232        char *filename = sha1_file_name(sha1);
 233        int fd;
 234
 235        fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
 236        if (fd < 0) {
 237                if (errno != EEXIST)
 238                        return -1;
 239                if (collision_check(filename, buf, size))
 240                        return error("SHA1 collision detected!"
 241                                        " This is bad, bad, BAD!\a\n");
 242                return 0;
 243        }
 244        write(fd, buf, size);
 245        close(fd);
 246        return 0;
 247}