416ba5c7c6bacfbb62236326ffe02769cdee0199
   1#include "builtin.h"
   2#include "cache.h"
   3#include "object.h"
   4#include "blob.h"
   5#include "delta.h"
   6#include "pack.h"
   7#include "csum-file.h"
   8
   9static int max_depth = 10;
  10static unsigned long object_count;
  11static int packfd;
  12static int current_depth;
  13static void *lastdat;
  14static unsigned long lastdatlen;
  15static unsigned char lastsha1[20];
  16
  17static ssize_t yread(int fd, void *buffer, size_t length)
  18{
  19        ssize_t ret = 0;
  20        while (ret < length) {
  21                ssize_t size = xread(fd, (char *) buffer + ret, length - ret);
  22                if (size < 0) {
  23                        return size;
  24                }
  25                if (size == 0) {
  26                        return ret;
  27                }
  28                ret += size;
  29        }
  30        return ret;
  31}
  32
  33static ssize_t ywrite(int fd, void *buffer, size_t length)
  34{
  35        ssize_t ret = 0;
  36        while (ret < length) {
  37                ssize_t size = xwrite(fd, (char *) buffer + ret, length - ret);
  38                if (size < 0) {
  39                        return size;
  40                }
  41                if (size == 0) {
  42                        return ret;
  43                }
  44                ret += size;
  45        }
  46        return ret;
  47}
  48
  49static unsigned long encode_header(enum object_type type, unsigned long size, unsigned char *hdr)
  50{
  51        int n = 1;
  52        unsigned char c;
  53
  54        if (type < OBJ_COMMIT || type > OBJ_DELTA)
  55                die("bad type %d", type);
  56
  57        c = (type << 4) | (size & 15);
  58        size >>= 4;
  59        while (size) {
  60                *hdr++ = c | 0x80;
  61                c = size & 0x7f;
  62                size >>= 7;
  63                n++;
  64        }
  65        *hdr = c;
  66        return n;
  67}
  68
  69static void write_blob (void *dat, unsigned long datlen)
  70{
  71        z_stream s;
  72        void *out, *delta;
  73        unsigned char hdr[64];
  74        unsigned long hdrlen, deltalen;
  75
  76        if (lastdat && current_depth < max_depth) {
  77                delta = diff_delta(lastdat, lastdatlen,
  78                        dat, datlen,
  79                        &deltalen, 0);
  80        } else
  81                delta = 0;
  82
  83        memset(&s, 0, sizeof(s));
  84        deflateInit(&s, zlib_compression_level);
  85
  86        if (delta) {
  87                current_depth++;
  88                s.next_in = delta;
  89                s.avail_in = deltalen;
  90                hdrlen = encode_header(OBJ_DELTA, deltalen, hdr);
  91                if (ywrite(packfd, hdr, hdrlen) != hdrlen)
  92                        die("Can't write object header: %s", strerror(errno));
  93                if (ywrite(packfd, lastsha1, sizeof(lastsha1)) != sizeof(lastsha1))
  94                        die("Can't write object base: %s", strerror(errno));
  95        } else {
  96                current_depth = 0;
  97                s.next_in = dat;
  98                s.avail_in = datlen;
  99                hdrlen = encode_header(OBJ_BLOB, datlen, hdr);
 100                if (ywrite(packfd, hdr, hdrlen) != hdrlen)
 101                        die("Can't write object header: %s", strerror(errno));
 102        }
 103
 104        s.avail_out = deflateBound(&s, s.avail_in);
 105        s.next_out = out = xmalloc(s.avail_out);
 106        while (deflate(&s, Z_FINISH) == Z_OK)
 107                /* nothing */;
 108        deflateEnd(&s);
 109
 110        if (ywrite(packfd, out, s.total_out) != s.total_out)
 111                die("Failed writing compressed data %s", strerror(errno));
 112
 113        free(out);
 114        if (delta)
 115                free(delta);
 116}
 117
 118static void init_pack_header ()
 119{
 120        const char* magic = "PACK";
 121        unsigned long version = 2;
 122        unsigned long zero = 0;
 123
 124        version = htonl(version);
 125
 126        if (ywrite(packfd, (char*)magic, 4) != 4)
 127                die("Can't write pack magic: %s", strerror(errno));
 128        if (ywrite(packfd, &version, 4) != 4)
 129                die("Can't write pack version: %s", strerror(errno));
 130        if (ywrite(packfd, &zero, 4) != 4)
 131                die("Can't write 0 object count: %s", strerror(errno));
 132}
 133
 134static void fixup_header_footer ()
 135{
 136        SHA_CTX c;
 137        char hdr[8];
 138        unsigned char sha1[20];
 139        unsigned long cnt;
 140        char *buf;
 141        size_t n;
 142
 143        if (lseek(packfd, 0, SEEK_SET) != 0)
 144                die("Failed seeking to start: %s", strerror(errno));
 145
 146        SHA1_Init(&c);
 147        if (yread(packfd, hdr, 8) != 8)
 148                die("Failed reading header: %s", strerror(errno));
 149        SHA1_Update(&c, hdr, 8);
 150
 151fprintf(stderr, "%lu objects\n", object_count);
 152        cnt = htonl(object_count);
 153        SHA1_Update(&c, &cnt, 4);
 154        if (ywrite(packfd, &cnt, 4) != 4)
 155                die("Failed writing object count: %s", strerror(errno));
 156
 157        buf = xmalloc(128 * 1024);
 158        for (;;) {
 159                n = xread(packfd, buf, 128 * 1024);
 160                if (n <= 0)
 161                        break;
 162                SHA1_Update(&c, buf, n);
 163        }
 164        free(buf);
 165
 166        SHA1_Final(sha1, &c);
 167        if (ywrite(packfd, sha1, sizeof(sha1)) != sizeof(sha1))
 168                die("Failed writing pack checksum: %s", strerror(errno));
 169}
 170
 171int main (int argc, const char **argv)
 172{
 173        packfd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666);
 174        if (packfd < 0)
 175                die("Can't create pack file %s: %s", argv[1], strerror(errno));
 176
 177        init_pack_header();
 178        for (;;) {
 179                unsigned long datlen;
 180                int hdrlen;
 181                void *dat;
 182                char hdr[128];
 183                unsigned char sha1[20];
 184                SHA_CTX c;
 185
 186                if (yread(0, &datlen, 4) != 4)
 187                        break;
 188
 189                dat = xmalloc(datlen);
 190                if (yread(0, dat, datlen) != datlen)
 191                        break;
 192
 193                hdrlen = sprintf(hdr, "blob %lu", datlen) + 1;
 194                SHA1_Init(&c);
 195                SHA1_Update(&c, hdr, hdrlen);
 196                SHA1_Update(&c, dat, datlen);
 197                SHA1_Final(sha1, &c);
 198
 199                write_blob(dat, datlen);
 200                object_count++;
 201                printf("%s\n", sha1_to_hex(sha1));
 202                fflush(stdout);
 203
 204                if (lastdat)
 205                        free(lastdat);
 206                lastdat = dat;
 207                lastdatlen = datlen;
 208                memcpy(lastsha1, sha1, sizeof(sha1));
 209        }
 210        fixup_header_footer();
 211        close(packfd);
 212
 213        return 0;
 214}