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){
205 pf->nidx = d->length;
206 pf->idx = emalloc(pf->nidx);
207 if(readn(ifd, pf->idx, pf->nidx) != pf->nidx){
225 if((n = slurpdir(".git/objects/pack", &d)) == -1)
228 new = eamalloc(n, sizeof(Packf));
229 for(i = 0; i < n; i++){
230 l = strlen(d[i].name);
231 if(l > 4 && strcmp(d[i].name + l - 4, ".idx") != 0)
233 d[i].name[l - 4] = 0;
234 if(loadpack(&new[nnew], d[i].name) != -1)
237 for(i = 0; i < npackf; i++){
256 if((pf->pack = Bopen(pf->path, OREAD)) == nil)
260 if(openpacks == Npackcache){
263 for(i = 0; i < npackf; i++){
264 if(packf[i].opentm < t && packf[i].refs > 0){
270 Bterm(packf[best].pack);
271 packf[best].pack = nil;
290 crc32(u32int crc, char *b, int nb)
292 static u32int crctab[256] = {
293 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535,
294 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd,
295 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d,
296 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
297 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
298 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
299 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac,
300 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
301 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab,
302 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
303 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb,
304 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
305 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea,
306 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce,
307 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
308 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
309 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409,
310 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
311 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739,
312 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
313 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268,
314 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0,
315 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8,
316 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
317 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
318 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703,
319 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7,
320 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
321 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae,
322 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
323 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6,
324 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
325 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d,
326 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5,
327 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
328 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
329 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
334 for(i = 0; i < nb; i++)
335 crc = (crc >> 8) ^ crctab[(crc ^ b[i]) & 0xFF];
336 return crc ^ 0xFFFFFFFF;
340 bappend(void *p, void *src, int len)
345 while(b->len + len >= b->sz){
346 b->sz = b->sz*2 + 64;
347 n = realloc(b->data, b->sz);
352 memmove(b->data + b->len, src, len);
364 bdecompress(Buf *d, Biobuf *b, vlong *csz)
369 if(inflatezlib(d, bappend, b, breadc) == -1 || d->data == nil){
374 *csz = Boffset(b) - o;
379 decompress(void **p, Biobuf *b, vlong *csz)
381 Buf d = {.len=0, .data=nil, .sz=0};
383 if(bdecompress(&d, b, csz) == -1){
392 readvint(char *p, char **pp)
401 n |= (c & 0x7f) << s;
403 } while (c & 0x80 && s < 63);
410 applydelta(Object *dst, Object *base, char *d, int nd)
412 char *r, *b, *ed, *er;
420 werrstr("mismatched source size");
424 nr = readvint(d, &d);
425 r = emalloc(nr + 64);
426 n = snprint(r, 64, "%T %d", base->type, nr) + 1;
428 dst->type = base->type;
441 if(d != ed && (c & 0x01)) o |= (*d++ << 0) & 0x000000ff;
442 if(d != ed && (c & 0x02)) o |= (*d++ << 8) & 0x0000ff00;
443 if(d != ed && (c & 0x04)) o |= (*d++ << 16) & 0x00ff0000;
444 if(d != ed && (c & 0x08)) o |= (*d++ << 24) & 0xff000000;
447 if(d != ed && (c & 0x10)) l |= (*d++ << 0) & 0x0000ff;
448 if(d != ed && (c & 0x20)) l |= (*d++ << 8) & 0x00ff00;
449 if(d != ed && (c & 0x40)) l |= (*d++ << 16) & 0xff0000;
450 if(l == 0) l = 0x10000;
452 if(o + l > base->size){
453 werrstr("garbled delta: out of bounds copy");
456 memmove(r, b + o, l);
461 werrstr("garbled delta: write past object");
470 werrstr("truncated delta");
478 readrdelta(Biobuf *f, Object *o, int nd, int flag)
486 if(Bread(f, h.h, sizeof(h.h)) != sizeof(h.h))
488 if(hasheq(&o->hash, &h))
490 if((n = decompress(&d, f, nil)) == -1)
492 o->len = Boffset(f) - o->off;
493 if(d == nil || n != nd)
495 if((b = readidxobject(f, h, flag|Cthin)) == nil)
497 if(applydelta(o, b, d, n) == -1)
507 readodelta(Biobuf *f, Object *o, vlong nd, vlong p, int flag)
515 if((c = Bgetc(f)) == -1)
518 while(c & 0x80 && r < (1ULL<<56)){
519 if((c = Bgetc(f)) == -1)
521 r = ((r + 1)<<7) | (c & 0x7f);
524 if(r > p || r >= (1ULL<<56)){
525 werrstr("junk offset -%lld (from %lld)", r, p);
528 if((n = decompress(&d, f, nil)) == -1)
530 o->len = Boffset(f) - o->off;
531 if(d == nil || n != nd)
533 if(Bseek(f, p - r, 0) == -1)
535 memset(&b, 0, sizeof(Object));
536 if(readpacked(f, &b, flag) == -1)
538 if(applydelta(o, &b, d, nd) == -1)
549 readpacked(Biobuf *f, Object *o, int flag)
564 werrstr("unknown type for byte %x at %lld", c, p);
568 if((c = Bgetc(f)) == -1)
570 l |= (c & 0x7f) << s;
573 if(l >= (1ULL << 32)){
574 werrstr("object too big");
579 werrstr("invalid object at %lld", Boffset(f));
586 b.data = emalloc(b.sz);
587 n = snprint(b.data, 64, "%T %lld", t, l) + 1;
589 if(bdecompress(&b, f, nil) == -1){
593 o->len = Boffset(f) - o->off;
596 o->data = b.data + n;
600 if(readodelta(f, o, l, p, flag) == -1)
604 if(readrdelta(f, o, l, flag) == -1)
608 o->flag |= Cloaded|flag;
613 readloose(Biobuf *f, Object *o, int flag)
615 struct { char *tag; int type; } *p, types[] = {
626 n = decompress(&d, f, nil);
632 for(p = types; p->tag; p++){
634 if(strncmp(s, p->tag, l) == 0){
642 if(o->type == GNone){
646 sz = strtol(s, &e, 0);
647 if(e == s || *e++ != 0){
648 werrstr("malformed object header");
651 if(sz != n - (e - d)){
652 werrstr("mismatched sizes");
658 o->flag |= Cloaded|flag;
667 searchindex(char *idx, int nidx, Hash h)
669 int lo, hi, hidx, i, r, nent;
677 * Read the fanout table. The fanout table
678 * contains 256 entries, corresponsding to
679 * the first byte of the hash. Each entry
680 * is a 4 byte big endian integer, containing
681 * the total number of entries with a leading
682 * byte <= the table index, allowing us to
683 * rapidly do a binary search on them.
687 hi = GETBE32(idx + o);
690 lo = GETBE32(idx + o);
691 hi = GETBE32(idx + o + 4);
695 nent=GETBE32(idx + 8 + 255*4);
698 * Now that we know the range of hashes that the
699 * entry may exist in, search them
706 s = idx + o + hidx*sizeof(h.h);
707 r = memcmp(h.h, s, sizeof(h.h));
719 * We found the entry. If it's 32 bits, then we
720 * can just return the oset, otherwise the 32
721 * bit entry contains the oset to the 64 bit
725 oo += 256*4; /* Fanout table */
726 oo += Hashsz*nent; /* Hashes */
727 oo += 4*nent; /* Checksums */
728 oo += 4*hidx; /* Offset offset */
729 if(oo < 0 || oo + 4 > nidx)
731 i = GETBE32(idx + oo);
732 o = i & 0xffffffffULL;
734 * Large offsets (i.e. 64-bit) are encoded as an index
735 * into the next table with the MSB bit set.
737 if(o & (1ull << 31)){
740 oo += 256*4; /* Fanout table */
741 oo += Hashsz*nent; /* Hashes */
742 oo += 4*nent; /* Checksums */
743 oo += 4*nent; /* 32-bit Offsets */
744 oo += 8*o; /* 64-bit Offset offset */
745 if(oo < 0 || oo + 8 >= nidx)
747 o = GETBE64(idx + oo);
752 werrstr("out of bounds read");
755 werrstr("not present");
760 * Scans for non-empty word, copying it into buf.
761 * Strips off word, leading, and trailing space
764 * Returns -1 on empty string or error, leaving
768 scanword(char **str, int *nstr, char *buf, int nbuf)
776 while(n && isblank(*p)){
781 for(; n && *p && !isspace(*p); p++, n--){
788 while(n && isblank(*p)){
799 nextline(char **str, int *nstr)
803 if((s = strchr(*str, '\n')) != nil){
804 *nstr -= s - *str + 1;
810 parseauthor(char **str, int *nstr, char **name, vlong *time)
817 if((p = strchr(*str, '\n')) == nil)
818 sysfatal("malformed author line");
821 sysfatal("overlong author line");
822 memset(m, 0, sizeof(m));
823 snprint(buf, n + 1, *str);
827 if(!regexec(authorpat, buf, m, nelem(m)))
828 sysfatal("invalid author line %s", buf);
829 nm = m[1].ep - m[1].sp;
830 *name = emalloc(nm + 1);
831 memcpy(*name, m[1].sp, nm);
834 nm = m[2].ep - m[2].sp;
835 memcpy(buf, m[2].sp, nm);
842 parsecommit(Object *o)
844 char *p, *t, buf[128];
849 o->commit = emalloc(sizeof(Cinfo));
851 if(scanword(&p, &np, buf, sizeof(buf)) == -1)
853 if(strcmp(buf, "tree") == 0){
854 if(scanword(&p, &np, buf, sizeof(buf)) == -1)
855 sysfatal("invalid commit: tree missing");
856 if(hparse(&o->commit->tree, buf) == -1)
857 sysfatal("invalid commit: garbled tree");
858 }else if(strcmp(buf, "parent") == 0){
859 if(scanword(&p, &np, buf, sizeof(buf)) == -1)
860 sysfatal("invalid commit: missing parent");
861 o->commit->parent = realloc(o->commit->parent, ++o->commit->nparent * sizeof(Hash));
862 if(!o->commit->parent)
863 sysfatal("unable to malloc: %r");
864 if(hparse(&o->commit->parent[o->commit->nparent - 1], buf) == -1)
865 sysfatal("invalid commit: garbled parent");
866 }else if(strcmp(buf, "author") == 0){
867 parseauthor(&p, &np, &o->commit->author, &o->commit->mtime);
868 }else if(strcmp(buf, "committer") == 0){
869 parseauthor(&p, &np, &o->commit->committer, &o->commit->ctime);
870 }else if(strcmp(buf, "gpgsig") == 0){
872 if((t = strstr(p, "-----END PGP SIGNATURE-----")) == nil)
873 sysfatal("malformed gpg signature");
879 while (np && isspace(*p)) {
884 o->commit->nmsg = np;
890 int m, a, entsz, nent;
899 ent = eamalloc(entsz, sizeof(Dirent));
900 o->tree = emalloc(sizeof(Tinfo));
904 ent = earealloc(ent, entsz, sizeof(Dirent));
907 m = strtol(p, &p, 8);
909 sysfatal("malformed tree %H: *p=(%d) %c\n", o->hash, *p, *p);
912 * only the stored permissions for the user
913 * are relevant; git fills group and world
914 * bits with whatever -- so to serve with
915 * useful permissions, replicate the mode
916 * of the git repo dir.
919 t->mode = ((a<<6)|(a<<3)|a) & gitdirmode;
925 }else if(m == 0120000){
932 p = memchr(p, 0, ep - p);
933 if(*p++ != 0 || ep - p < sizeof(t->h.h))
934 sysfatal("malformed tree %H, remaining %d (%s)", o->hash, (int)(ep - p), p);
935 memcpy(t->h.h, p, sizeof(t->h.h));
939 o->tree->nent = nent;
948 parseobject(Object *o)
950 if(o->flag & Cparsed)
953 case GTree: parsetree(o); break;
954 case GCommit: parsecommit(o); break;
955 case GTag: parsetag(o); break;
962 readidxobject(Biobuf *idx, Hash h, int flag)
964 char path[Pathmax], hbuf[41];
970 if((obj = osfind(&objcache, h)) != nil){
973 * If we're indexing, we need to be careful
974 * to only return objects within this pack,
975 * so if the objects exist outside the pack,
976 * we don't index the wrong copy.
978 if(!(obj->flag & Cidx))
980 if(obj->flag & Cloaded)
983 if(Bseek(idx, obj->off, 0) == -1)
985 if(readpacked(idx, obj, flag) == -1)
987 if(Bseek(idx, o, 0) == -1)
988 sysfatal("could not restore offset");
992 if(obj->flag & Cloaded)
1001 new = emalloc(sizeof(Object));
1002 new->id = objcache.nobj + 1;
1010 for(i = 0; i < npackf; i++){
1011 o = searchindex(packf[i].idx, packf[i].nidx, h);
1013 if((f = openpack(&packf[i])) == nil)
1015 if((r = Bseek(f, o, 0)) != -1)
1016 r = readpacked(f, obj, flag);
1017 closepack(&packf[i]);
1027 snprint(hbuf, sizeof(hbuf), "%H", h);
1028 snprint(path, sizeof(path), ".git/objects/%c%c/%s", hbuf[0], hbuf[1], hbuf + 2);
1029 if((f = Bopen(path, OREAD)) != nil){
1030 if(readloose(f, obj, flag) == -1)
1053 * Loads and returns a cached object.
1061 if(gitdirmode == -1){
1062 if((d = dirstat(".git")) == nil)
1063 sysfatal("stat .git: %r");
1064 gitdirmode = d->mode & 0777;
1067 if((o = readidxobject(nil, h, 0)) == nil)
1075 * Creates and returns a cached, cleared object
1076 * that will get loaded some other time. Useful
1077 * for performance if need to mark that a blob
1078 * exists, but we don't care about its contents.
1080 * The refcount of the returned object is 0, so
1081 * it doesn't need to be unrefed.
1084 clearedobject(Hash h, int type)
1088 if((o = osfind(&objcache, h)) != nil)
1091 o = emalloc(sizeof(Object));
1094 osadd(&objcache, o);
1095 o->id = objcache.nobj;
1101 objcmp(void *pa, void *pb)
1107 return memcmp(a->hash.h, b->hash.h, sizeof(a->hash.h));
1111 hwrite(Biobuf *b, void *buf, int len, DigestState **st)
1113 *st = sha1(buf, len, nil, *st);
1114 return Bwrite(b, buf, len);
1118 objectcrc(Biobuf *f, Object *o)
1124 Bseek(f, o->off, 0);
1125 for(n = o->len; n > 0; n -= r){
1126 r = Bread(f, buf, n > sizeof(buf) ? sizeof(buf) : n);
1131 o->crc = crc32(o->crc, buf, r);
1137 indexpack(char *pack, char *idx, Hash ph)
1139 char hdr[4*3], buf[8];
1140 int nobj, npct, nvalid, nbig;
1149 if((f = Bopen(pack, OREAD)) == nil)
1151 if(Bread(f, hdr, sizeof(hdr)) != sizeof(hdr)){
1152 werrstr("short read on header");
1155 if(memcmp(hdr, "PACK\0\0\0\2", 8) != 0){
1156 werrstr("invalid header");
1163 nobj = GETBE32(hdr + 8);
1164 obj = eamalloc(nobj, sizeof(Object*));
1165 valid = eamalloc(nobj, sizeof(char));
1167 fprint(2, "indexing %d objects: 0%%", nobj);
1168 while(nvalid != nobj){
1170 for(i = 0; i < nobj; i++){
1175 pct = showprogress((npct*100)/nobj, pct);
1177 o = emalloc(sizeof(Object));
1178 o->off = Boffset(f);
1183 * We can seek around when packing delta chains.
1184 * Be extra careful while we don't know where all
1185 * the objects start.
1187 Bseek(f, o->off, 0);
1188 if(readpacked(f, o, Cidx) == -1)
1190 sha1((uchar*)o->all, o->size + strlen(o->all) + 1, o->hash.h, nil);
1195 if(objectcrc(f, o) == -1)
1199 sysfatal("fix point reached too early: %d/%d: %r", nvalid, nobj);
1205 fprint(2, "\b\b\b\b100%%\n");
1209 qsort(obj, nobj, sizeof(Object*), objcmp);
1210 if((f = Bopen(idx, OWRITE)) == nil)
1212 if(hwrite(f, "\xfftOc\x00\x00\x00\x02", 8, &st) != 8)
1216 for(i = 0; i < 256; i++){
1217 while(c < nobj && (obj[c]->hash.h[0] & 0xff) <= i)
1220 if(hwrite(f, buf, 4, &st) == -1)
1223 for(i = 0; i < nobj; i++){
1225 if(hwrite(f, o->hash.h, sizeof(o->hash.h), &st) == -1)
1229 for(i = 0; i < nobj; i++){
1230 PUTBE32(buf, obj[i]->crc);
1231 if(hwrite(f, buf, 4, &st) == -1)
1236 for(i = 0; i < nobj; i++){
1237 if(obj[i]->off < (1ull<<31))
1238 PUTBE32(buf, obj[i]->off);
1240 PUTBE32(buf, (1ull << 31) | nbig);
1243 if(hwrite(f, buf, 4, &st) == -1)
1246 for(i = 0; i < nobj; i++){
1247 if(obj[i]->off >= (1ull<<31)){
1248 PUTBE64(buf, obj[i]->off);
1249 if(hwrite(f, buf, 8, &st) == -1)
1253 if(hwrite(f, ph.h, sizeof(ph.h), &st) == -1)
1255 sha1(nil, 0, h.h, st);
1256 Bwrite(f, h.h, sizeof(h.h));
1271 deltaordercmp(void *pa, void *pb)
1278 if(a->obj->type != b->obj->type)
1279 return a->obj->type - b->obj->type;
1280 cmp = strcmp(a->path, b->path);
1283 if(a->mtime != b->mtime)
1284 return a->mtime - b->mtime;
1285 return memcmp(a->obj->hash.h, b->obj->hash.h, sizeof(a->obj->hash.h));
1289 writeordercmp(void *pa, void *pb)
1291 Meta *a, *b, *ahd, *bhd;
1295 ahd = (a->head == nil) ? a : a->head;
1296 bhd = (b->head == nil) ? b : b->head;
1297 if(ahd->mtime != bhd->mtime)
1298 return bhd->mtime - ahd->mtime;
1300 return (uintptr)bhd - (uintptr)ahd;
1301 if(a->nchain != b->nchain)
1302 return a->nchain - b->nchain;
1303 return a->mtime - b->mtime;
1307 addmeta(Metavec *v, Objset *has, Object *o, char *path, vlong mtime)
1311 if(oshas(has, o->hash))
1316 m = emalloc(sizeof(Meta));
1318 m->path = estrdup(path);
1321 if(v->nmeta == v->metasz){
1322 v->metasz = 2*v->metasz;
1323 v->meta = earealloc(v->meta, v->metasz, sizeof(Meta*));
1325 v->meta[v->nmeta++] = m;
1337 loadtree(Metavec *v, Objset *has, Hash tree, char *dpath, vlong mtime)
1344 if(oshas(has, tree))
1346 if((t = readobject(tree)) == nil)
1348 if(t->type != GTree){
1349 fprint(2, "load: %H: not tree\n", t->hash);
1353 addmeta(v, has, t, dpath, mtime);
1354 for(i = 0; i < t->tree->nent; i++){
1355 e = &t->tree->ent[i];
1356 if(oshas(has, e->h))
1360 k = (e->mode & DMDIR) ? GTree : GBlob;
1361 o = clearedobject(e->h, k);
1362 p = smprint("%s/%s", dpath, e->name);
1364 addmeta(v, has, o, p, mtime);
1365 else if(loadtree(v, has, e->h, p, mtime) == -1){
1376 loadcommit(Metavec *v, Objset *has, Hash h)
1383 if((c = readobject(h)) == nil)
1385 if(c->type != GCommit){
1386 fprint(2, "load: %H: not commit\n", c->hash);
1390 addmeta(v, has, c, "", c->commit->ctime);
1391 r = loadtree(v, has, c->commit->tree, "", c->commit->ctime);
1397 readmeta(Hash *theirs, int ntheirs, Hash *ours, int nours, Meta ***m)
1408 v.meta = eamalloc(v.metasz, sizeof(Meta*));
1409 if(findtwixt(theirs, ntheirs, ours, nours, &obj, &nobj) == -1)
1410 sysfatal("load twixt: %r");
1414 for(i = 0; i < nours; i++)
1415 if(!hasheq(&ours[i], &Zhash))
1416 if(loadcommit(nil, &has, ours[i]) == -1)
1418 for(i = 0; i < nobj; i++)
1419 if(loadcommit(&v, &has, obj[i]->hash) == -1)
1431 deltasz(Delta *d, int nd)
1435 for(i = 0; i < nd; i++)
1436 sz += d[i].cpy ? 7 : d[i].len + 1;
1441 pickdeltas(Meta **meta, int nmeta)
1446 int i, j, nd, sz, pct, best;
1449 dprint(1, "picking deltas\n");
1450 fprint(2, "deltifying %d objects: 0%%", nmeta);
1451 qsort(meta, nmeta, sizeof(Meta*), deltaordercmp);
1452 for(i = 0; i < nmeta; i++){
1454 pct = showprogress((i*100) / nmeta, pct);
1457 if(m->obj->type == GCommit || m->obj->type == GTag)
1459 if((o = readobject(m->obj->hash)) == nil)
1460 sysfatal("readobject %H: %r", m->obj->hash);
1461 dtinit(&m->dtab, o);
1463 dtclear(&meta[i-11]->dtab);
1465 for(j = max(0, i - 10); j < i; j++){
1467 /* long chains make unpacking slow */
1468 if(p->nchain >= 128 || p->obj->type != o->type)
1470 d = deltify(o, &p->dtab, &nd);
1471 sz = deltasz(d, nd);
1474 * if we already picked a best delta,
1481 m->nchain = p->nchain + 1;
1491 for(i = max(0, nmeta - 10); i < nmeta; i++)
1492 dtclear(&meta[i]->dtab);
1493 fprint(2, "\b\b\b\b100%%\n");
1497 compread(void *p, void *dst, int n)
1502 if(n > b->sz - b->off)
1504 memcpy(dst, b->data + b->off, n);
1510 compwrite(void *p, void *buf, int n)
1512 return hwrite(((Compout *)p)->bfd, buf, n, &((Compout*)p)->st);
1516 hcompress(Biobuf *bfd, void *buf, int sz, DigestState **st)
1529 r = deflatezlib(&o, compwrite, &b, compread, 6, 0);
1535 append(char **p, int *len, int *sz, void *seg, int nseg)
1537 if(*len + nseg >= *sz){
1538 while(*len + nseg >= *sz)
1540 *p = erealloc(*p, *sz);
1542 memcpy(*p + *len, seg, nseg);
1547 encodedelta(Meta *m, Object *o, Object *b, void **pp)
1549 char *p, *bp, buf[16];
1550 int len, sz, n, i, j;
1557 /* base object size */
1558 buf[0] = b->size & 0x7f;
1560 for(i = 1; n > 0; i++){
1565 append(&p, &len, &sz, buf, i);
1567 /* target object size */
1568 buf[0] = o->size & 0x7f;
1570 for(i = 1; n > 0; i++){
1575 append(&p, &len, &sz, buf, i);
1576 for(j = 0; j < m->ndelta; j++){
1583 for(i = 0; i < sizeof(buf); i++) {
1594 for(i = 0; i < sizeof(buf)-4 && n > 0; i++){
1595 buf[0] |= 1<<(i + 4);
1600 append(&p, &len, &sz, buf, bp - buf);
1604 buf[0] = (d->len - n < 127) ? d->len - n : 127;
1605 append(&p, &len, &sz, buf, 1);
1606 append(&p, &len, &sz, o->data + d->off + n, buf[0]);
1616 packhdr(char *hdr, int ty, int len)
1621 hdr[0] |= len & 0xf;
1623 for(i = 1; len != 0; i++){
1625 hdr[i] = len & 0x7f;
1632 packoff(char *hdr, vlong off)
1637 rbuf[0] = off & 0x7f;
1638 for(i = 1; (off >>= 7) != 0; i++)
1639 rbuf[i] = (--off & 0x7f)|0x80;
1643 hdr[j++] = rbuf[--i];
1648 genpack(int fd, Meta **meta, int nmeta, Hash *h, int odelta)
1650 int i, nh, nd, res, pct, ret;
1660 dprint(1, "generating pack\n");
1661 if((fd = dup(fd, -1)) == -1)
1663 if((bfd = Bfdopen(fd, OWRITE)) == nil)
1665 if(hwrite(bfd, "PACK", 4, &st) == -1)
1668 if(hwrite(bfd, buf, 4, &st) == -1)
1670 PUTBE32(buf, nmeta);
1671 if(hwrite(bfd, buf, 4, &st) == -1)
1673 qsort(meta, nmeta, sizeof(Meta*), writeordercmp);
1675 fprint(2, "writing %d objects: 0%%", nmeta);
1676 for(i = 0; i < nmeta; i++){
1677 pct = showprogress((i*100)/nmeta, pct);
1679 m->off = Boffset(bfd);
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++)