diff 25319382697878e01b9949afb33fcc6f4c4e6e1d uncommitted --- a/sys/src/cmd/git/serve.c +++ b/sys/src/cmd/git/serve.c @@ -7,12 +7,28 @@ char *pathpfx = nil; int allowwrite; +int report; int +parsecaps(char *caps) +{ + char *p, *n; + + for(p = caps; p != nil; p = n){ + if((n = strchr(p, ' ')) != nil) + *n++ = 0; + if(strcmp(p, "report-status") == 0) + report = 1; + } + return 0; +} + +int showrefs(Conn *c) { int i, ret, nrefs; Hash head, *refs; + char *p, *e, pkt[Pktmax]; char **names; ret = -1; @@ -28,7 +44,14 @@ for(i = 0; i < nrefs; i++){ if(strncmp(names[i], "heads/", strlen("heads/")) != 0) continue; - if(fmtpkt(c, "%H refs/%s\n", refs[i], names[i]) == -1) + p = pkt; + e = pkt+sizeof(pkt); + p = seprint(p, e, "%H refs/%s\n", refs[i], names[i]); + if(i == 0){ + *p++ = 0; + p = seprint(p, e, "report-status"); + } + if(writepkt(c, pkt, p-pkt) == -1) goto error; } if(flushpkt(c) == -1) @@ -45,8 +68,8 @@ int servnegotiate(Conn *c, Hash **head, int *nhead, Hash **tail, int *ntail) { - char pkt[Pktmax]; - int n, acked; + char *sp[3], pkt[Pktmax]; + int n, nsp, acked; Object *o; Hash h; @@ -62,14 +85,22 @@ goto error; if(n == 0) break; - if(strncmp(pkt, "want ", 5) != 0){ + if((nsp = getfields(pkt, sp, nelem(sp), 1, " \t")) < 2){ + werrstr("protocol garble %s", pkt); + goto error; + } + if(strcmp(sp[0], "want") != 0){ werrstr(" protocol garble %s", pkt); goto error; } - if(hparse(&h, &pkt[5]) == -1){ + if(hparse(&h, sp[1]) == -1){ werrstr(" garbled want"); goto error; } + if(nsp > 2 && parsecaps(sp[2]) == -1){ + werrstr("garbled caps %s", sp[2]); + goto error; + } if((o = readobject(h)) == nil){ werrstr("requested nonexistent object"); goto error; @@ -151,7 +182,7 @@ { char pkt[Pktmax], *sp[4]; Hash old, new; - int n, i; + int l, n, i; if(showrefs(c) == -1) return -1; @@ -164,6 +195,11 @@ goto error; if(n == 0) break; + l = strlen(pkt); + if(n > l+1 && parsecaps(pkt+l+1) == -1){ + fmtpkt(c, "ERR protocol garble %s\n", pkt); + goto error; + } if(getfields(pkt, sp, nelem(sp), 1, " \t\n\r") != 3){ fmtpkt(c, "ERR protocol garble %s\n", pkt); goto error; @@ -314,21 +350,26 @@ packsz += n; } if(checkhash(pfd, packsz, &h) == -1){ - dprint(1, "hash mismatch\n"); + werrstr("hash mismatch\n"); goto error1; } if(indexpack(packtmp, idxtmp, h) == -1){ - dprint(1, "indexing failed: %r\n"); + werrstr("indexing failed: %r\n"); goto error1; } if(rename(packtmp, idxtmp, h) == -1){ - dprint(1, "rename failed: %r\n"); + werrstr("rename failed: %r\n"); goto error2; } + if(report) + fmtpkt(c, "unpack ok"); return 0; error2: remove(idxtmp); error1: remove(packtmp); + dprint(1, "update pack: %r"); + if(report) + fmtpkt(c, "unpack %r"); return -1; } @@ -348,12 +389,13 @@ int updaterefs(Conn *c, Hash *cur, Hash *upd, char **ref, int nupd) { - char refpath[512], buf[128]; - int i, newidx, hadref, fd, ret, lockfd; + char refpath[512];//, buf[128]; + int i, j, newidx, hadref, fd, ret, lockfd; vlong newtm; Object *o; Hash h; + i = 0; ret = -1; hadref = 0; newidx = -1; @@ -364,20 +406,20 @@ */ newtm = -23811206400; if((lockfd = lockrepo()) == -1){ - snprint(buf, sizeof(buf), "repo locked\n"); - return -1; + werrstr("repo locked\n"); + goto out; } for(i = 0; i < nupd; i++){ if(resolveref(&h, ref[i]) == 0){ hadref = 1; if(!hasheq(&h, &cur[i])){ - snprint(buf, sizeof(buf), "old ref changed: %s", ref[i]); - goto error; + werrstr("old ref changed: %s", ref[i]); + goto out; } } if(snprint(refpath, sizeof(refpath), ".git/%s", ref[i]) == sizeof(refpath)){ - snprint(buf, sizeof(buf), "ref path too long: %s", ref[i]); - goto error; + werrstr("ref path too long: %s", ref[i]); + goto out; } if(hasheq(&upd[i], &Zhash)){ remove(refpath); @@ -384,12 +426,12 @@ continue; } if((o = readobject(upd[i])) == nil){ - snprint(buf, sizeof(buf), "update to nonexistent hash %H", upd[i]); - goto error; + werrstr("update to nonexistent hash %H", upd[i]); + goto out; } if(o->type != GCommit){ - snprint(buf, sizeof(buf), "not commit: %H", upd[i]); - goto error; + werrstr("not commit: %H", upd[i]); + goto out; } if(o->commit->mtime > newtm){ newtm = o->commit->mtime; @@ -397,13 +439,13 @@ } unref(o); if((fd = create(refpath, OWRITE|OTRUNC, 0644)) == -1){ - snprint(buf, sizeof(buf), "open ref: %r"); - goto error; + werrstr("open ref: %r"); + goto out; } if(fprint(fd, "%H", upd[i]) == -1){ - snprint(buf, sizeof(buf), "upate ref: %r"); + werrstr("upate ref: %r"); close(fd); - goto error; + goto out; } close(fd); } @@ -420,22 +462,30 @@ * use. This should make us pick a useful default in * those cases, instead of silently failing. */ + i = 0; if(resolveref(&h, "HEAD") == -1 && hadref == 0 && newidx != -1){ if((fd = create(".git/HEAD", OWRITE|OTRUNC, 0644)) == -1){ - snprint(buf, sizeof(buf), "open HEAD: %r"); - goto error; + werrstr("open HEAD: %r"); + goto out; } - if(fprint(fd, "ref: %s", ref[0]) == -1){ - snprint(buf, sizeof(buf), "write HEAD ref: %r"); - goto error; + if(fprint(fd, "ref: %s", ref[i]) == -1){ + werrstr("write HEAD ref: %r"); + goto out; } close(fd); } ret = 0; -error: - fmtpkt(c, "ERR %s", buf); - close(lockfd); - werrstr(buf); +out: + if(lockfd != -1) + close(lockfd); + if(!report) + return ret; + for(j = 0; j < nupd; j++){ + if(i != j || ret == 0) + fmtpkt(c, "ok %s", ref[i]); + else + fmtpkt(c, "ng %s %r\n", ref[i]); + } return ret; }