--- /dev/null
+#include "builtin.h"
+#include "cache.h"
+#include "object.h"
+#include "blob.h"
+#include "delta.h"
+#include "pack.h"
+#include "csum-file.h"
+
+static int max_depth = 10;
+static unsigned long object_count;
+static int packfd;
+static int current_depth;
+static void *lastdat;
+static unsigned long lastdatlen;
+static unsigned char lastsha1[20];
+
+static ssize_t yread(int fd, void *buffer, size_t length)
+{
+ ssize_t ret = 0;
+ while (ret < length) {
+ ssize_t size = xread(fd, (char *) buffer + ret, length - ret);
+ if (size < 0) {
+ return size;
+ }
+ if (size == 0) {
+ return ret;
+ }
+ ret += size;
+ }
+ return ret;
+}
+
+static ssize_t ywrite(int fd, void *buffer, size_t length)
+{
+ ssize_t ret = 0;
+ while (ret < length) {
+ ssize_t size = xwrite(fd, (char *) buffer + ret, length - ret);
+ if (size < 0) {
+ return size;
+ }
+ if (size == 0) {
+ return ret;
+ }
+ ret += size;
+ }
+ return ret;
+}
+
+static unsigned long encode_header(enum object_type type, unsigned long size, unsigned char *hdr)
+{
+ int n = 1;
+ unsigned char c;
+
+ if (type < OBJ_COMMIT || type > OBJ_DELTA)
+ die("bad type %d", type);
+
+ c = (type << 4) | (size & 15);
+ size >>= 4;
+ while (size) {
+ *hdr++ = c | 0x80;
+ c = size & 0x7f;
+ size >>= 7;
+ n++;
+ }
+ *hdr = c;
+ return n;
+}
+
+static void write_blob (void *dat, unsigned long datlen)
+{
+ z_stream s;
+ void *out, *delta;
+ unsigned char hdr[64];
+ unsigned long hdrlen, deltalen;
+
+ if (lastdat && current_depth < max_depth) {
+ delta = diff_delta(lastdat, lastdatlen,
+ dat, datlen,
+ &deltalen, 0);
+ } else
+ delta = 0;
+
+ memset(&s, 0, sizeof(s));
+ deflateInit(&s, zlib_compression_level);
+
+ if (delta) {
+ current_depth++;
+ s.next_in = delta;
+ s.avail_in = deltalen;
+ hdrlen = encode_header(OBJ_DELTA, deltalen, hdr);
+ if (ywrite(packfd, hdr, hdrlen) != hdrlen)
+ die("Can't write object header: %s", strerror(errno));
+ if (ywrite(packfd, lastsha1, sizeof(lastsha1)) != sizeof(lastsha1))
+ die("Can't write object base: %s", strerror(errno));
+ } else {
+ current_depth = 0;
+ s.next_in = dat;
+ s.avail_in = datlen;
+ hdrlen = encode_header(OBJ_BLOB, datlen, hdr);
+ if (ywrite(packfd, hdr, hdrlen) != hdrlen)
+ die("Can't write object header: %s", strerror(errno));
+ }
+
+ s.avail_out = deflateBound(&s, s.avail_in);
+ s.next_out = out = xmalloc(s.avail_out);
+ while (deflate(&s, Z_FINISH) == Z_OK)
+ /* nothing */;
+ deflateEnd(&s);
+
+ if (ywrite(packfd, out, s.total_out) != s.total_out)
+ die("Failed writing compressed data %s", strerror(errno));
+
+ free(out);
+ if (delta)
+ free(delta);
+}
+
+static void init_pack_header ()
+{
+ const char* magic = "PACK";
+ unsigned long version = 2;
+ unsigned long zero = 0;
+
+ version = htonl(version);
+
+ if (ywrite(packfd, (char*)magic, 4) != 4)
+ die("Can't write pack magic: %s", strerror(errno));
+ if (ywrite(packfd, &version, 4) != 4)
+ die("Can't write pack version: %s", strerror(errno));
+ if (ywrite(packfd, &zero, 4) != 4)
+ die("Can't write 0 object count: %s", strerror(errno));
+}
+
+static void fixup_header_footer ()
+{
+ SHA_CTX c;
+ char hdr[8];
+ unsigned char sha1[20];
+ unsigned long cnt;
+ char *buf;
+ size_t n;
+
+ if (lseek(packfd, 0, SEEK_SET) != 0)
+ die("Failed seeking to start: %s", strerror(errno));
+
+ SHA1_Init(&c);
+ if (yread(packfd, hdr, 8) != 8)
+ die("Failed reading header: %s", strerror(errno));
+ SHA1_Update(&c, hdr, 8);
+
+fprintf(stderr, "%lu objects\n", object_count);
+ cnt = htonl(object_count);
+ SHA1_Update(&c, &cnt, 4);
+ if (ywrite(packfd, &cnt, 4) != 4)
+ die("Failed writing object count: %s", strerror(errno));
+
+ buf = xmalloc(128 * 1024);
+ for (;;) {
+ n = xread(packfd, buf, 128 * 1024);
+ if (n <= 0)
+ break;
+ SHA1_Update(&c, buf, n);
+ }
+ free(buf);
+
+ SHA1_Final(sha1, &c);
+ if (ywrite(packfd, sha1, sizeof(sha1)) != sizeof(sha1))
+ die("Failed writing pack checksum: %s", strerror(errno));
+}
+
+int main (int argc, const char **argv)
+{
+ packfd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666);
+ if (packfd < 0)
+ die("Can't create pack file %s: %s", argv[1], strerror(errno));
+
+ init_pack_header();
+ for (;;) {
+ unsigned long datlen;
+ int hdrlen;
+ void *dat;
+ char hdr[128];
+ unsigned char sha1[20];
+ SHA_CTX c;
+
+ if (yread(0, &datlen, 4) != 4)
+ break;
+
+ dat = xmalloc(datlen);
+ if (yread(0, dat, datlen) != datlen)
+ break;
+
+ hdrlen = sprintf(hdr, "blob %lu", datlen) + 1;
+ SHA1_Init(&c);
+ SHA1_Update(&c, hdr, hdrlen);
+ SHA1_Update(&c, dat, datlen);
+ SHA1_Final(sha1, &c);
+
+ write_blob(dat, datlen);
+ object_count++;
+ printf("%s\n", sha1_to_hex(sha1));
+ fflush(stdout);
+
+ if (lastdat)
+ free(lastdat);
+ lastdat = dat;
+ lastdatlen = datlen;
+ memcpy(lastsha1, sha1, sizeof(sha1));
+ }
+ fixup_header_footer();
+ close(packfd);
+
+ return 0;
+}