Skip to content

Commit

Permalink
git/serve: support better error reports
Browse files Browse the repository at this point in the history
  • Loading branch information
oridb committed Jun 4, 2023
1 parent e333684 commit 8da1ef1
Showing 1 changed file with 84 additions and 34 deletions.
118 changes: 84 additions & 34 deletions serve.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -28,7 +44,14 @@ showrefs(Conn *c)
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)
Expand All @@ -45,8 +68,8 @@ showrefs(Conn *c)
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;

Expand All @@ -62,14 +85,22 @@ servnegotiate(Conn *c, Hash **head, int *nhead, Hash **tail, int *ntail)
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;
Expand Down Expand Up @@ -151,7 +182,7 @@ recvnegotiate(Conn *c, Hash **cur, Hash **upd, char ***ref, int *nupd)
{
char pkt[Pktmax], *sp[4];
Hash old, new;
int n, i;
int l, n, i;

if(showrefs(c) == -1)
return -1;
Expand All @@ -164,6 +195,11 @@ recvnegotiate(Conn *c, Hash **cur, Hash **upd, char ***ref, int *nupd)
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;
Expand Down Expand Up @@ -314,21 +350,26 @@ updatepack(Conn *c)
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;
}

Expand All @@ -348,12 +389,13 @@ lockrepo(void)
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];
int i, j, newidx, hadref, fd, ret, lockfd;
vlong newtm;
Object *o;
Hash h;

i = 0;
ret = -1;
hadref = 0;
newidx = -1;
Expand All @@ -364,46 +406,46 @@ updaterefs(Conn *c, Hash *cur, Hash *upd, char **ref, int nupd)
*/
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);
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;
newidx = i;
}
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);
}
Expand All @@ -420,22 +462,30 @@ updaterefs(Conn *c, Hash *cur, Hash *upd, char **ref, int nupd)
* 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(report){
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]);
}
}
if(lockfd != -1)
close(lockfd);
return ret;
}

Expand Down

0 comments on commit 8da1ef1

Please sign in to comment.