ref: 3bd380117136b17d8f14f3da254ff491f257bfd5
parent: a0dc0a9b1b81655ba2e9fa87f74f07a4fcea825d
author: Ori Bernstein <ori@eigenstate.org>
date: Sat Oct 18 13:40:15 EDT 2025
git/query: support expanding truncated hashes to full hashes
--- a/sys/src/cmd/git/git.h
+++ b/sys/src/cmd/git/git.h
@@ -281,6 +281,7 @@
int findtwixt(Hash *, int, Hash *, int, Object ***, int *);
Object *readobject(Hash);
Object *clearedobject(Hash, int);
+int expandprefix(Hash*, Hash, int);
void parseobject(Object *);
int indexpack(char *, char *, Hash);
int writepack(int, Hash*, int, Hash*, int, Hash*);
@@ -321,6 +322,7 @@
int showprogress(int, int);
u64int murmurhash2(void*, usize);
Qid parseqid(char*);
+int charval(int);
/* packing */
void dtinit(Dtab *, Object*);
--- a/sys/src/cmd/git/pack.c
+++ b/sys/src/cmd/git/pack.c
@@ -677,8 +677,22 @@
return -1;
}
+int
+hashcmp(uchar *a, uchar *b, uint nbit)
+{
+ int x, y, i, r;
+
+ i = nbit/8;
+ r = memcmp(a, b, i);
+ if(r != 0 || nbit % 8 == 0)
+ return r;
+ x = (a[i+1] & 0xff00>>nbit) & 0xff;
+ y = (b[i+1] & 0xff00>>nbit) & 0xff;
+ return x - y;
+}
+
vlong
-searchindex(char *idx, int nidx, Hash h)
+searchindex(char *idx, int nidx, Hash h, int npfx, Hash *hret)
{
int lo, hi, hidx, i, r, nent;
vlong o, oo;
@@ -687,6 +701,8 @@
o = 8;
if(nidx < 8 + 256*4)
return -1;
+ if(npfx < 8)
+ return -1;
/*
* Read the fanout table. The fanout table
* contains 256 entries, corresponsding to
@@ -713,12 +729,13 @@
* entry may exist in, search them
*/
r = -1;
+ s = nil;
hidx = -1;
o = 8 + 256*4;
while(lo < hi){
hidx = (hi + lo)/2;
s = idx + o + hidx*sizeof(h.h);
- r = memcmp(h.h, s, sizeof(h.h));
+ r = hashcmp(h.h, s, npfx);
if(r < 0)
hi = hidx;
else if(r > 0)
@@ -728,6 +745,8 @@
}
if(r != 0)
goto notfound;
+ if(hret != nil)
+ memcpy(hret, s, sizeof(Hash));
/*
* We found the entry. If it's 32 bits, then we
@@ -1032,7 +1051,7 @@
retried = 0;
retry:
for(i = 0; i < npackf; i++){
- o = searchindex(packf[i].idx, packf[i].nidx, h);
+ o = searchindex(packf[i].idx, packf[i].nidx, h, SHA1dlen*8, nil);
if(o != -1){
if((f = openpack(&packf[i])) == nil)
goto error;
@@ -1070,6 +1089,38 @@
error:
free(new);
return nil;
+}
+
+int
+expandprefix(Hash *rh, Hash h, int npfx)
+{
+ int i, fd, ndir;
+ char buf[128];
+ Dir *d;
+
+ refreshpacks();
+ if(npfx < 8 || npfx % 4 != 0)
+ return -1;
+ for(i = 0; i < npackf; i++)
+ if(searchindex(packf[i].idx, packf[i].nidx, h, npfx, rh) != -1)
+ return 0;
+ sprint(buf, ".git/objects/%x", h.h[0]);
+ if((fd = open(buf, OREAD)) == -1)
+ return -1;
+ ndir = dirreadall(fd, &d);
+ close(fd);
+ if(ndir == -1)
+ return -1;
+ for(i = 0; i < ndir; i++){
+ snprint(buf, sizeof(buf), "%x%s", h.h[0], d[i].name);
+ if(hparse(rh, buf) == 0 && hashcmp(h.h, rh->h, npfx) == 0){
+ free(d);
+ return 0;
+ }
+
+ }
+ free(d);
+ return -1;
}
/*
--- a/sys/src/cmd/git/ref.c
+++ b/sys/src/cmd/git/ref.c
@@ -350,6 +350,24 @@
return 0;
}
+static int
+matchpfx(Hash *h, char *ref)
+{
+ int i, c;
+ Hash pfx;
+ char *p;
+
+ memset(&pfx, 0, sizeof(Hash));
+ for(i = 0, p = ref; *p; p++, i++){
+ if((c = charval(*p)) == -1)
+ return -1;
+ pfx.h[i/2] |= c;
+ if((i & 1) == 0)
+ pfx.h[i/2] <<= 4;
+ }
+ return expandprefix(h, pfx, i*4);
+}
+
int
readref(Hash *h, char *ref)
{
@@ -357,7 +375,6 @@
char buf[256], s[256], **pfx;
int r, f, n;
- /* TODO: support hash prefixes */
if((r = hparse(h, ref)) != -1)
return r;
if(strcmp(ref, "HEAD") == 0){
@@ -383,6 +400,8 @@
close(f);
goto found;
}
+ if((r = matchpfx(h, ref)) != -1)
+ return r;
return -1;
found:
--- a/sys/src/cmd/git/util.c
+++ b/sys/src/cmd/git/util.c
@@ -85,8 +85,8 @@
return memcmp(a->h, b->h, sizeof(a->h)) == 0;
}
-static int
-charval(int c, int *err)
+int
+charval(int c)
{
if(c >= '0' && c <= '9')
return c - '0';
@@ -94,7 +94,7 @@
return c - 'a' + 10;
if(c >= 'A' && c <= 'F')
return c - 'A' + 10;
- *err = 1;
+ werrstr("invalid hex char");
return -1;
}
@@ -259,18 +259,14 @@
int
hparse(Hash *h, char *b)
{
- int i, err;
+ int i, c0, c1;
- err = 0;
- for(i = 0; i < sizeof(h->h); i++){
- err = 0;
- h->h[i] = 0;
- h->h[i] |= ((charval(b[2*i], &err) & 0xf) << 4);
- h->h[i] |= ((charval(b[2*i+1], &err)& 0xf) << 0);
- if(err){
- werrstr("invalid hash");
+ for(i = 0; i < nelem(h->h); i++){
+ if((c0 = charval(b[2*i+0])) == -1)
return -1;
- }
+ if((c1 = charval(b[2*i+1])) == -1)
+ return -1;
+ h->h[i] = (c0 << 4) | c1;
}
return 0;
}
--
⑨