7 typedef struct Buf Buf;
8 typedef struct Metavec Metavec;
9 typedef struct Meta Meta;
10 typedef struct Compout Compout;
11 typedef struct Packf Packf;
13 #define max(x, y) ((x) > (y) ? (x) : (y))
26 /* The best delta we picked */
33 /* Only used for delta window */
36 /* Only used for writing offset deltas */
62 static int readpacked(Biobuf *, Object *, int);
63 static Object *readidxobject(Biobuf *, Hash, int);
82 assert((o->flag & Ccache) == 0);
83 assert(o->flag & Cloaded);
88 free(o->commit->parent);
89 free(o->commit->author);
90 free(o->commit->committer);
108 o->flag &= ~(Cloaded|Cparsed);
136 lrutail = lrutail->prev;
137 if(!(o->flag & Cexist)){
139 o->id = objcache.nobj;
143 o->prev->next = o->next;
145 o->next->prev = o->prev;
150 }else if(lrutail == nil)
158 if(!(o->flag & Ccache)){
163 while(ncache > cachemax && lrutail != nil){
177 loadpack(Packf *pf, char *name)
183 memset(pf, 0, sizeof(Packf));
184 snprint(buf, sizeof(buf), ".git/objects/pack/%s.idx", name);
185 snprint(pf->path, sizeof(pf->path), ".git/objects/pack/%s.pack", name);
187 * if we already have the pack open, just
188 * steal the loaded info
190 for(i = 0; i < npackf; i++){
191 if(strcmp(pf->path, packf[i].path) == 0){
192 pf->pack = packf[i].pack;
193 pf->idx = packf[i].idx;
194 pf->nidx = packf[i].nidx;
199 if((ifd = open(buf, OREAD)) == -1)
201 if((d = dirfstat(ifd)) == nil)
203 pf->nidx = d->length;
204 pf->idx = emalloc(pf->nidx);
205 if(readn(ifd, pf->idx, pf->nidx) != pf->nidx){
226 if((n = slurpdir(".git/objects/pack", &d)) == -1)
229 new = eamalloc(n, sizeof(Packf));
230 for(i = 0; i < n; i++){
231 l = strlen(d[i].name);
232 if(l > 4 && strcmp(d[i].name + l - 4, ".idx") != 0)
234 d[i].name[l - 4] = 0;
235 if(loadpack(&new[nnew], d[i].name) != -1)
238 for(i = 0; i < npackf; i++){
257 if((pf->pack = Bopen(pf->path, OREAD)) == nil)
261 if(openpacks == Npackcache){
264 for(i = 0; i < npackf; i++){
265 if(packf[i].opentm < t && packf[i].refs > 0){
271 Bterm(packf[best].pack);
272 packf[best].pack = nil;
291 crc32(u32int crc, char *b, int nb)
293 static u32int crctab[256] = {
294 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535,
295 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd,
296 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d,
297 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
298 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
299 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
300 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac,
301 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
302 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab,
303 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
304 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb,
305 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
306 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea,
307 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce,
308 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
309 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
310 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409,
311 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
312 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739,
313 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
314 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268,
315 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0,
316 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8,
317 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
318 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
319 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703,
320 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7,
321 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
322 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae,
323 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
324 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6,
325 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
326 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d,
327 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5,
328 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
329 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
330 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
335 for(i = 0; i < nb; i++)
336 crc = (crc >> 8) ^ crctab[(crc ^ b[i]) & 0xFF];
337 return crc ^ 0xFFFFFFFF;
341 bappend(void *p, void *src, int len)
346 while(b->len + len >= b->sz){
347 b->sz = b->sz*2 + 64;
348 n = realloc(b->data, b->sz);
353 memmove(b->data + b->len, src, len);
365 bdecompress(Buf *d, Biobuf *b, vlong *csz)
370 if(inflatezlib(d, bappend, b, breadc) == -1 || d->data == nil){
375 *csz = Boffset(b) - o;
380 decompress(void **p, Biobuf *b, vlong *csz)
382 Buf d = {.len=0, .data=nil, .sz=0};
384 if(bdecompress(&d, b, csz) == -1){
393 readvint(char *p, char **pp)
402 n |= (c & 0x7f) << s;
404 } while (c & 0x80 && s < 63);
411 applydelta(Object *dst, Object *base, char *d, int nd)
413 char *r, *b, *ed, *er;
421 werrstr("mismatched source size");
425 nr = readvint(d, &d);
426 r = emalloc(nr + 64);
427 n = snprint(r, 64, "%T %d", base->type, nr) + 1;
429 dst->type = base->type;
442 if(d != ed && (c & 0x01)) o |= (*d++ << 0) & 0x000000ff;
443 if(d != ed && (c & 0x02)) o |= (*d++ << 8) & 0x0000ff00;
444 if(d != ed && (c & 0x04)) o |= (*d++ << 16) & 0x00ff0000;
445 if(d != ed && (c & 0x08)) o |= (*d++ << 24) & 0xff000000;
448 if(d != ed && (c & 0x10)) l |= (*d++ << 0) & 0x0000ff;
449 if(d != ed && (c & 0x20)) l |= (*d++ << 8) & 0x00ff00;
450 if(d != ed && (c & 0x40)) l |= (*d++ << 16) & 0xff0000;
451 if(l == 0) l = 0x10000;
453 if(o + l > base->size){
454 werrstr("garbled delta: out of bounds copy");
457 memmove(r, b + o, l);
462 werrstr("garbled delta: write past object");
471 werrstr("truncated delta");
479 readrdelta(Biobuf *f, Object *o, int nd, int flag)
487 if(Bread(f, h.h, sizeof(h.h)) != sizeof(h.h))
489 if(hasheq(&o->hash, &h))
491 if((n = decompress(&d, f, nil)) == -1)
493 o->len = Boffset(f) - o->off;
494 if(d == nil || n != nd)
496 if((b = readidxobject(f, h, flag|Cthin)) == nil)
498 if(applydelta(o, b, d, n) == -1)
508 readodelta(Biobuf *f, Object *o, vlong nd, vlong p, int flag)
516 if((c = Bgetc(f)) == -1)
519 while(c & 0x80 && r < (1ULL<<56)){
520 if((c = Bgetc(f)) == -1)
522 r = ((r + 1)<<7) | (c & 0x7f);
525 if(r > p || r >= (1ULL<<56)){
526 werrstr("junk offset -%lld (from %lld)", r, p);
529 if((n = decompress(&d, f, nil)) == -1)
531 o->len = Boffset(f) - o->off;
532 if(d == nil || n != nd)
534 if(Bseek(f, p - r, 0) == -1)
536 memset(&b, 0, sizeof(Object));
537 if(readpacked(f, &b, flag) == -1)
539 if(applydelta(o, &b, d, nd) == -1)
550 readpacked(Biobuf *f, Object *o, int flag)
565 werrstr("unknown type for byte %x at %lld", c, p);
569 if((c = Bgetc(f)) == -1)
571 l |= (c & 0x7f) << s;
574 if(l >= (1ULL << 32)){
575 werrstr("object too big");
580 werrstr("invalid object at %lld", Boffset(f));
587 b.data = emalloc(b.sz);
588 n = snprint(b.data, 64, "%T %lld", t, l) + 1;
590 if(bdecompress(&b, f, nil) == -1){
594 o->len = Boffset(f) - o->off;
597 o->data = b.data + n;
601 if(readodelta(f, o, l, p, flag) == -1)
605 if(readrdelta(f, o, l, flag) == -1)
609 o->flag |= Cloaded|flag;
614 readloose(Biobuf *f, Object *o, int flag)
616 struct { char *tag; int type; } *p, types[] = {
627 n = decompress(&d, f, nil);
633 for(p = types; p->tag; p++){
635 if(strncmp(s, p->tag, l) == 0){
643 if(o->type == GNone){
647 sz = strtol(s, &e, 0);
648 if(e == s || *e++ != 0){
649 werrstr("malformed object header");
652 if(sz != n - (e - d)){
653 werrstr("mismatched sizes");
659 o->flag |= Cloaded|flag;
668 searchindex(char *idx, int nidx, Hash h)
670 int lo, hi, hidx, i, r, nent;
678 * Read the fanout table. The fanout table
679 * contains 256 entries, corresponsding to
680 * the first byte of the hash. Each entry
681 * is a 4 byte big endian integer, containing
682 * the total number of entries with a leading
683 * byte <= the table index, allowing us to
684 * rapidly do a binary search on them.
688 hi = GETBE32(idx + o);
691 lo = GETBE32(idx + o);
692 hi = GETBE32(idx + o + 4);
696 nent=GETBE32(idx + 8 + 255*4);
699 * Now that we know the range of hashes that the
700 * entry may exist in, search them
707 s = idx + o + hidx*sizeof(h.h);
708 r = memcmp(h.h, s, sizeof(h.h));
720 * We found the entry. If it's 32 bits, then we
721 * can just return the oset, otherwise the 32
722 * bit entry contains the oset to the 64 bit
726 oo += 256*4; /* Fanout table */
727 oo += Hashsz*nent; /* Hashes */
728 oo += 4*nent; /* Checksums */
729 oo += 4*hidx; /* Offset offset */
730 if(oo < 0 || oo + 4 > nidx)
732 i = GETBE32(idx + oo);
733 o = i & 0xffffffffULL;
735 * Large offsets (i.e. 64-bit) are encoded as an index
736 * into the next table with the MSB bit set.
738 if(o & (1ull << 31)){
741 oo += 256*4; /* Fanout table */
742 oo += Hashsz*nent; /* Hashes */
743 oo += 4*nent; /* Checksums */
744 oo += 4*nent; /* 32-bit Offsets */
745 oo += 8*o; /* 64-bit Offset offset */
746 if(oo < 0 || oo + 8 >= nidx)
748 o = GETBE64(idx + oo);
753 werrstr("out of bounds read");
756 werrstr("not present");
761 * Scans for non-empty word, copying it into buf.
762 * Strips off word, leading, and trailing space
765 * Returns -1 on empty string or error, leaving
769 scanword(char **str, int *nstr, char *buf, int nbuf)
777 while(n && isblank(*p)){
782 for(; n && *p && !isspace(*p); p++, n--){
789 while(n && isblank(*p)){
800 nextline(char **str, int *nstr)
804 if((s = strchr(*str, '\n')) != nil){
805 *nstr -= s - *str + 1;
811 parseauthor(char **str, int *nstr, char **name, vlong *time)
818 if((p = strchr(*str, '\n')) == nil)
819 sysfatal("malformed author line");
822 sysfatal("overlong author line");
823 memset(m, 0, sizeof(m));
824 snprint(buf, n + 1, *str);
828 if(!regexec(authorpat, buf, m, nelem(m)))
829 sysfatal("invalid author line %s", buf);
830 nm = m[1].ep - m[1].sp;
831 *name = emalloc(nm + 1);
832 memcpy(*name, m[1].sp, nm);
835 nm = m[2].ep - m[2].sp;
836 memcpy(buf, m[2].sp, nm);
843 parsecommit(Object *o)
845 char *p, *t, buf[128];
850 o->commit = emalloc(sizeof(Cinfo));
852 if(scanword(&p, &np, buf, sizeof(buf)) == -1)
854 if(strcmp(buf, "tree") == 0){
855 if(scanword(&p, &np, buf, sizeof(buf)) == -1)
856 sysfatal("invalid commit: tree missing");
857 if(hparse(&o->commit->tree, buf) == -1)
858 sysfatal("invalid commit: garbled tree");
859 }else if(strcmp(buf, "parent") == 0){
860 if(scanword(&p, &np, buf, sizeof(buf)) == -1)
861 sysfatal("invalid commit: missing parent");
862 o->commit->parent = realloc(o->commit->parent, ++o->commit->nparent * sizeof(Hash));
863 if(!o->commit->parent)
864 sysfatal("unable to malloc: %r");
865 if(hparse(&o->commit->parent[o->commit->nparent - 1], buf) == -1)
866 sysfatal("invalid commit: garbled parent");
867 }else if(strcmp(buf, "author") == 0){
868 parseauthor(&p, &np, &o->commit->author, &o->commit->mtime);
869 }else if(strcmp(buf, "committer") == 0){
870 parseauthor(&p, &np, &o->commit->committer, &o->commit->ctime);
871 }else if(strcmp(buf, "gpgsig") == 0){
873 if((t = strstr(p, "-----END PGP SIGNATURE-----")) == nil)
874 sysfatal("malformed gpg signature");
880 while (np && isspace(*p)) {
885 o->commit->nmsg = np;
891 int m, a, entsz, nent;
900 ent = eamalloc(entsz, sizeof(Dirent));
901 o->tree = emalloc(sizeof(Tinfo));
905 ent = earealloc(ent, entsz, sizeof(Dirent));
908 m = strtol(p, &p, 8);
910 sysfatal("malformed tree %H: *p=(%d) %c\n", o->hash, *p, *p);
913 * only the stored permissions for the user
914 * are relevant; git fills group and world
915 * bits with whatever -- so to serve with
916 * useful permissions, replicate the mode
917 * of the git repo dir.
920 t->mode = ((a<<6)|(a<<3)|a) & gitdirmode;
926 }else if(m == 0120000){
933 p = memchr(p, 0, ep - p);
934 if(*p++ != 0 || ep - p < sizeof(t->h.h))
935 sysfatal("malformed tree %H, remaining %d (%s)", o->hash, (int)(ep - p), p);
936 memcpy(t->h.h, p, sizeof(t->h.h));
940 o->tree->nent = nent;
949 parseobject(Object *o)
951 if(o->flag & Cparsed)
954 case GTree: parsetree(o); break;
955 case GCommit: parsecommit(o); break;
956 case GTag: parsetag(o); break;
963 readidxobject(Biobuf *idx, Hash h, int flag)
965 char path[Pathmax], hbuf[41];
971 if((obj = osfind(&objcache, h)) != nil){
974 * If we're indexing, we need to be careful
975 * to only return objects within this pack,
976 * so if the objects exist outside the pack,
977 * we don't index the wrong copy.
979 if(!(obj->flag & Cidx))
981 if(obj->flag & Cloaded)
984 if(Bseek(idx, obj->off, 0) == -1)
986 if(readpacked(idx, obj, flag) == -1)
988 if(Bseek(idx, o, 0) == -1)
989 sysfatal("could not restore offset");
993 if(obj->flag & Cloaded)
1002 new = emalloc(sizeof(Object));
1003 new->id = objcache.nobj + 1;
1011 for(i = 0; i < npackf; i++){
1012 o = searchindex(packf[i].idx, packf[i].nidx, h);
1014 if((f = openpack(&packf[i])) == nil)
1016 if((r = Bseek(f, o, 0)) != -1)
1017 r = readpacked(f, obj, flag);
1018 closepack(&packf[i]);
1028 snprint(hbuf, sizeof(hbuf), "%H", h);
1029 snprint(path, sizeof(path), ".git/objects/%c%c/%s", hbuf[0], hbuf[1], hbuf + 2);
1030 if((f = Bopen(path, OREAD)) != nil){
1031 if(readloose(f, obj, flag) == -1)
1054 * Loads and returns a cached object.
1062 if(gitdirmode == -1){
1063 if((d = dirstat(".git")) == nil)
1064 sysfatal("stat .git: %r");
1065 gitdirmode = d->mode & 0777;
1068 if((o = readidxobject(nil, h, 0)) == nil)
1076 * Creates and returns a cached, cleared object
1077 * that will get loaded some other time. Useful
1078 * for performance if need to mark that a blob
1079 * exists, but we don't care about its contents.
1081 * The refcount of the returned object is 0, so
1082 * it doesn't need to be unrefed.
1085 clearedobject(Hash h, int type)
1089 if((o = osfind(&objcache, h)) != nil)
1092 o = emalloc(sizeof(Object));
1095 osadd(&objcache, o);
1096 o->id = objcache.nobj;
1102 objcmp(void *pa, void *pb)
1108 return memcmp(a->hash.h, b->hash.h, sizeof(a->hash.h));
1112 hwrite(Biobuf *b, void *buf, int len, DigestState **st)
1114 *st = sha1(buf, len, nil, *st);
1115 return Bwrite(b, buf, len);
1119 objectcrc(Biobuf *f, Object *o)
1125 Bseek(f, o->off, 0);
1126 for(n = o->len; n > 0; n -= r){
1127 r = Bread(f, buf, n > sizeof(buf) ? sizeof(buf) : n);
1132 o->crc = crc32(o->crc, buf, r);
1138 indexpack(char *pack, char *idx, Hash ph)
1140 char hdr[4*3], buf[8];
1141 int nobj, npct, nvalid, nbig;
1150 if((f = Bopen(pack, OREAD)) == nil)
1152 if(Bread(f, hdr, sizeof(hdr)) != sizeof(hdr)){
1153 werrstr("short read on header");
1156 if(memcmp(hdr, "PACK\0\0\0\2", 8) != 0){
1157 werrstr("invalid header");
1164 nobj = GETBE32(hdr + 8);
1165 obj = eamalloc(nobj, sizeof(Object*));
1166 valid = eamalloc(nobj, sizeof(char));
1168 fprint(2, "indexing %d objects: 0%%", nobj);
1169 while(nvalid != nobj){
1171 for(i = 0; i < nobj; i++){
1176 pct = showprogress((npct*100)/nobj, pct);
1178 o = emalloc(sizeof(Object));
1179 o->off = Boffset(f);
1184 * We can seek around when packing delta chains.
1185 * Be extra careful while we don't know where all
1186 * the objects start.
1188 Bseek(f, o->off, 0);
1189 if(readpacked(f, o, Cidx) == -1)
1191 sha1((uchar*)o->all, o->size + strlen(o->all) + 1, o->hash.h, nil);
1196 if(objectcrc(f, o) == -1)
1200 sysfatal("fix point reached too early: %d/%d: %r", nvalid, nobj);
1206 fprint(2, "\b\b\b\b100%%\n");
1210 qsort(obj, nobj, sizeof(Object*), objcmp);
1211 if((f = Bopen(idx, OWRITE)) == nil)
1213 if(hwrite(f, "\xfftOc\x00\x00\x00\x02", 8, &st) != 8)
1217 for(i = 0; i < 256; i++){
1218 while(c < nobj && (obj[c]->hash.h[0] & 0xff) <= i)
1221 if(hwrite(f, buf, 4, &st) == -1)
1224 for(i = 0; i < nobj; i++){
1226 if(hwrite(f, o->hash.h, sizeof(o->hash.h), &st) == -1)
1230 for(i = 0; i < nobj; i++){
1231 PUTBE32(buf, obj[i]->crc);
1232 if(hwrite(f, buf, 4, &st) == -1)
1237 for(i = 0; i < nobj; i++){
1238 if(obj[i]->off < (1ull<<31))
1239 PUTBE32(buf, obj[i]->off);
1241 PUTBE32(buf, (1ull << 31) | nbig);
1244 if(hwrite(f, buf, 4, &st) == -1)
1247 for(i = 0; i < nobj; i++){
1248 if(obj[i]->off >= (1ull<<31)){
1249 PUTBE64(buf, obj[i]->off);
1250 if(hwrite(f, buf, 8, &st) == -1)
1254 if(hwrite(f, ph.h, sizeof(ph.h), &st) == -1)
1256 sha1(nil, 0, h.h, st);
1257 Bwrite(f, h.h, sizeof(h.h));
1272 deltaordercmp(void *pa, void *pb)
1279 if(a->obj->type != b->obj->type)
1280 return a->obj->type - b->obj->type;
1281 cmp = strcmp(a->path, b->path);
1284 if(a->mtime != b->mtime)
1285 return a->mtime - b->mtime;
1286 return memcmp(a->obj->hash.h, b->obj->hash.h, sizeof(a->obj->hash.h));
1290 writeordercmp(void *pa, void *pb)
1292 Meta *a, *b, *ahd, *bhd;
1296 ahd = (a->head == nil) ? a : a->head;
1297 bhd = (b->head == nil) ? b : b->head;
1298 if(ahd->mtime != bhd->mtime)
1299 return bhd->mtime - ahd->mtime;
1301 return (uintptr)bhd - (uintptr)ahd;
1302 if(a->nchain != b->nchain)
1303 return a->nchain - b->nchain;
1304 return a->mtime - b->mtime;
1308 addmeta(Metavec *v, Objset *has, Object *o, char *path, vlong mtime)
1312 if(oshas(has, o->hash))
1317 m = emalloc(sizeof(Meta));
1319 m->path = estrdup(path);
1322 if(v->nmeta == v->metasz){
1323 v->metasz = 2*v->metasz;
1324 v->meta = earealloc(v->meta, v->metasz, sizeof(Meta*));
1326 v->meta[v->nmeta++] = m;
1338 loadtree(Metavec *v, Objset *has, Hash tree, char *dpath, vlong mtime)
1345 if(oshas(has, tree))
1347 if((t = readobject(tree)) == nil)
1349 if(t->type != GTree){
1350 fprint(2, "load: %H: not tree\n", t->hash);
1354 addmeta(v, has, t, dpath, mtime);
1355 for(i = 0; i < t->tree->nent; i++){
1356 e = &t->tree->ent[i];
1357 if(oshas(has, e->h))
1361 k = (e->mode & DMDIR) ? GTree : GBlob;
1362 o = clearedobject(e->h, k);
1363 p = smprint("%s/%s", dpath, e->name);
1365 addmeta(v, has, o, p, mtime);
1366 else if(loadtree(v, has, e->h, p, mtime) == -1){
1377 loadcommit(Metavec *v, Objset *has, Hash h)
1384 if((c = readobject(h)) == nil)
1386 if(c->type != GCommit){
1387 fprint(2, "load: %H: not commit\n", c->hash);
1391 addmeta(v, has, c, "", c->commit->ctime);
1392 r = loadtree(v, has, c->commit->tree, "", c->commit->ctime);
1398 readmeta(Hash *theirs, int ntheirs, Hash *ours, int nours, Meta ***m)
1409 v.meta = eamalloc(v.metasz, sizeof(Meta*));
1410 if(findtwixt(theirs, ntheirs, ours, nours, &obj, &nobj) == -1)
1411 sysfatal("load twixt: %r");
1415 for(i = 0; i < nours; i++)
1416 if(!hasheq(&ours[i], &Zhash))
1417 if(loadcommit(nil, &has, ours[i]) == -1)
1419 for(i = 0; i < nobj; i++)
1420 if(loadcommit(&v, &has, obj[i]->hash) == -1)
1432 deltasz(Delta *d, int nd)
1436 for(i = 0; i < nd; i++)
1437 sz += d[i].cpy ? 7 : d[i].len + 1;
1442 pickdeltas(Meta **meta, int nmeta)
1447 int i, j, nd, sz, pct, best;
1450 dprint(1, "picking deltas\n");
1451 fprint(2, "deltifying %d objects: 0%%", nmeta);
1452 qsort(meta, nmeta, sizeof(Meta*), deltaordercmp);
1453 for(i = 0; i < nmeta; i++){
1455 pct = showprogress((i*100) / nmeta, pct);
1458 if(m->obj->type == GCommit || m->obj->type == GTag)
1460 if((o = readobject(m->obj->hash)) == nil)
1461 sysfatal("readobject %H: %r", m->obj->hash);
1462 dtinit(&m->dtab, o);
1464 dtclear(&meta[i-11]->dtab);
1466 for(j = max(0, i - 10); j < i; j++){
1468 /* long chains make unpacking slow */
1469 if(p->nchain >= 128 || p->obj->type != o->type)
1471 d = deltify(o, &p->dtab, &nd);
1472 sz = deltasz(d, nd);
1475 * if we already picked a best delta,
1482 m->nchain = p->nchain + 1;
1492 for(i = max(0, nmeta - 10); i < nmeta; i++)
1493 dtclear(&meta[i]->dtab);
1494 fprint(2, "\b\b\b\b100%%\n");
1498 compread(void *p, void *dst, int n)
1503 if(n > b->sz - b->off)
1505 memcpy(dst, b->data + b->off, n);
1511 compwrite(void *p, void *buf, int n)
1513 return hwrite(((Compout *)p)->bfd, buf, n, &((Compout*)p)->st);
1517 hcompress(Biobuf *bfd, void *buf, int sz, DigestState **st)
1530 r = deflatezlib(&o, compwrite, &b, compread, 6, 0);
1536 append(char **p, int *len, int *sz, void *seg, int nseg)
1538 if(*len + nseg >= *sz){
1539 while(*len + nseg >= *sz)
1541 *p = erealloc(*p, *sz);
1543 memcpy(*p + *len, seg, nseg);
1548 encodedelta(Meta *m, Object *o, Object *b, void **pp)
1550 char *p, *bp, buf[16];
1551 int len, sz, n, i, j;
1558 /* base object size */
1559 buf[0] = b->size & 0x7f;
1561 for(i = 1; n > 0; i++){
1566 append(&p, &len, &sz, buf, i);
1568 /* target object size */
1569 buf[0] = o->size & 0x7f;
1571 for(i = 1; n > 0; i++){
1576 append(&p, &len, &sz, buf, i);
1577 for(j = 0; j < m->ndelta; j++){
1584 for(i = 0; i < sizeof(buf); i++) {
1595 for(i = 0; i < sizeof(buf)-4 && n > 0; i++){
1596 buf[0] |= 1<<(i + 4);
1601 append(&p, &len, &sz, buf, bp - buf);
1605 buf[0] = (d->len - n < 127) ? d->len - n : 127;
1606 append(&p, &len, &sz, buf, 1);
1607 append(&p, &len, &sz, o->data + d->off + n, buf[0]);
1617 packhdr(char *hdr, int ty, int len)
1622 hdr[0] |= len & 0xf;
1624 for(i = 1; len != 0; i++){
1626 hdr[i] = len & 0x7f;
1633 packoff(char *hdr, vlong off)
1638 rbuf[0] = off & 0x7f;
1639 for(i = 1; (off >>= 7) != 0; i++)
1640 rbuf[i] = (--off & 0x7f)|0x80;
1644 hdr[j++] = rbuf[--i];
1649 genpack(int fd, Meta **meta, int nmeta, Hash *h, int odelta)
1651 int i, nh, nd, res, pct, ret;
1661 dprint(1, "generating pack\n");
1662 if((fd = dup(fd, -1)) == -1)
1664 if((bfd = Bfdopen(fd, OWRITE)) == nil)
1666 if(hwrite(bfd, "PACK", 4, &st) == -1)
1669 if(hwrite(bfd, buf, 4, &st) == -1)
1671 PUTBE32(buf, nmeta);
1672 if(hwrite(bfd, buf, 4, &st) == -1)
1674 qsort(meta, nmeta, sizeof(Meta*), writeordercmp);
1676 fprint(2, "writing %d objects: 0%%", nmeta);
1677 for(i = 0; i < nmeta; i++){
1678 pct = showprogress((i*100)/nmeta, pct);
1680 if((m->off = Boffset(bfd)) == -1)
1682 if((o = readobject(m->obj->hash)) == nil)
1684 if(m->delta == nil){
1685 nh = packhdr(buf, o->type, o->size);
1686 if(hwrite(bfd, buf, nh, &st) == -1)
1688 if(hcompress(bfd, o->data, o->size, &st) == -1)
1691 if((b = readobject(m->prev->obj->hash)) == nil)
1693 nd = encodedelta(m, o, b, &p);
1695 if(odelta && m->prev->off != 0){
1697 nh += packhdr(buf, GOdelta, nd);
1698 nh += packoff(buf+nh, m->off - m->prev->off);
1699 if(hwrite(bfd, buf, nh, &st) == -1)
1702 nh = packhdr(buf, GRdelta, nd);
1704 if(hwrite(bfd, buf, nh, &st) == -1)
1706 if(hwrite(bfd, po->hash.h, sizeof(po->hash.h), &st) == -1)
1709 res = hcompress(bfd, p, nd, &st);
1717 fprint(2, "\b\b\b\b100%%\n");
1718 sha1(nil, 0, h->h, st);
1719 if(Bwrite(bfd, h->h, sizeof(h->h)) == -1)
1723 if(Bterm(bfd) == -1)
1729 writepack(int fd, Hash *theirs, int ntheirs, Hash *ours, int nours, Hash *h)
1734 if((nmeta = readmeta(theirs, ntheirs, ours, nours, &meta)) == -1)
1736 pickdeltas(meta, nmeta);
1737 r = genpack(fd, meta, nmeta, h, 0);
1738 for(i = 0; i < nmeta; i++)