shithub: git9

Download patch

ref: 0b6837301afe104a582f67cd701b90fb7ccf84aa
parent: 8fec5d15308b5b99b246e521f6db16422adea3e9
author: Ori Bernstein <ori@eigenstate.org>
date: Tue Jul 2 20:20:06 EDT 2019

Improve and simplify our breadcrumb trail when walking the file tree.

--- a/fs.c
+++ b/fs.c
@@ -34,15 +34,22 @@
 };
 
 typedef struct Gitaux Gitaux;
-struct Gitaux {
-	int	 npath;
-	Qid	 path[Npath];
-	Object  *opath[Npath];
-	char 	*refpath;
-	int	 qdir;
-	vlong	 mtime;
+typedef struct Crumb Crumb;
+
+struct Crumb {
+	char	*name;
 	Object	*obj;
+	Qid	qid;
+	int	mode;
+	vlong	mtime;
+};
 
+struct Gitaux {
+	int	ncrumb;
+	Crumb	*crumb;
+	char	*refpath;
+	int	qdir;
+
 	/* For listing object dir */
 	Ols	*ols;
 	Object	*olslast;
@@ -59,6 +66,12 @@
 char *mtpt = "/mnt/git";
 char **branches = nil;
 
+static Crumb*
+curcrumb(Gitaux *aux)
+{
+	return &aux->crumb[aux->ncrumb - 1];
+}
+
 static vlong
 findbranch(Gitaux *aux, char *path)
 {
@@ -78,23 +91,20 @@
 }
 
 static void
-obj2dir(Dir *d, Object *o, long qdir, vlong mtime)
+obj2dir(Dir *d, Object *o, Crumb *c, char *name, long qdir)
 {
-	char name[64];
-
-	snprint(name, sizeof(name), "%H", o->hash);
-	d->name = estrdup9p(name);
 	d->qid.type = QTDIR;
 	d->qid.path = QPATH(o->id, qdir);
-	d->atime = mtime;
-	d->mtime = mtime;
+	d->atime = c->mtime;
+	d->mtime = c->mtime;
+	d->mode = c->mode;
+	d->name = estrdup9p(name);
 	d->uid = estrdup9p(username);
 	d->gid = estrdup9p(username);
 	d->muid = estrdup9p(username);
-	d->mode = 0755 | DMDIR;
 	if(o->type == GBlob || o->type == GTag){
 		d->qid.type = 0;
-		d->mode = 0644;
+		d->mode &= 0777;
 		d->length = o->size;
 	}
 
@@ -103,9 +113,9 @@
 static int
 rootgen(int i, Dir *d, void *p)
 {
-	Gitaux *aux;
+	Crumb *c;
 
-	aux = p;
+	c = curcrumb(p);
 	if (i >= nelem(qroot))
 		return -1;
 	d->mode = 0555 | DMDIR;
@@ -116,7 +126,7 @@
 	d->uid = estrdup9p(username);
 	d->gid = estrdup9p(username);
 	d->muid = estrdup9p(username);
-	d->mtime = aux->mtime;
+	d->mtime = c->mtime;
 	return 0;
 }
 
@@ -125,9 +135,11 @@
 {
 	Gitaux *aux;
 	Dir *refs;
+	Crumb *c;
 	int n;
 
 	aux = p;
+	c = curcrumb(aux);
 	refs = nil;
 	d->qid.vers = 0;
 	d->qid.type = QTDIR;
@@ -136,8 +148,8 @@
 	d->uid = estrdup9p(username);
 	d->gid = estrdup9p(username);
 	d->muid = estrdup9p(username);
-	d->mtime = aux->mtime;
-	d->atime = aux->mtime;
+	d->mtime = c->mtime;
+	d->atime = c->mtime;
 	if((n = slurpdir(aux->refpath, &refs)) < 0)
 		return -1;
 	if(i < n){
@@ -172,11 +184,13 @@
 static int
 gtreegen(int i, Dir *d, void *p)
 {
-	Gitaux *aux;
 	Object *o, *e;
+	Gitaux *aux;
+	Crumb *c;
 
 	aux = p;
-	e = aux->obj;
+	c = curcrumb(aux);
+	e = c->obj;
 	if(i >= e->tree->nent)
 		return -1;
 	if((o = readobject(e->tree->ent[i].h)) == nil)
@@ -188,8 +202,8 @@
 	d->qid.type = o->type == GTree ? QTDIR : 0;
 	d->qid.path = QPATH(o->id, aux->qdir);
 	d->mode = e->tree->ent[i].mode;
-	d->atime = aux->mtime;
-	d->mtime = aux->mtime;
+	d->atime = c->mtime;
+	d->mtime = c->mtime;
 	d->uid = estrdup9p(username);
 	d->gid = estrdup9p(username);
 	d->muid = estrdup9p(username);
@@ -203,7 +217,7 @@
 {
 	Object *o;
 
-	o = ((Gitaux*)p)->obj;
+	o = curcrumb(p)->obj;
 	d->uid = estrdup9p(username);
 	d->gid = estrdup9p(username);
 	d->muid = estrdup9p(username);
@@ -248,10 +262,13 @@
 {
 	Gitaux *aux;
 	Object *o;
+	Crumb *c;
+	char name[64];
 	Ols *ols;
 	Hash h;
 
 	aux = p;
+	c = curcrumb(aux);
 	if(!aux->ols)
 		aux->ols = mkols();
 	ols = aux->ols;
@@ -258,7 +275,8 @@
 	o = nil;
 	/* We tried to sent it, but it didn't fit */
 	if(aux->olslast && ols->idx == i + 1){
-		obj2dir(d, aux->olslast, Qobject, aux->mtime);
+		snprint(name, sizeof(name), "%H", aux->olslast->hash);
+		obj2dir(d, aux->olslast, c, name, Qobject);
 		return 0;
 	}
 	while(ols->idx <= i){
@@ -268,7 +286,8 @@
 			return -1;
 	}
 	if(o != nil){
-		obj2dir(d, o, Qobject, aux->mtime);
+		snprint(name, sizeof(name), "%H", o->hash);
+		obj2dir(d, o, c, name, Qobject);
 		unref(aux->olslast);
 		aux->olslast = ref(o);
 		return 0;
@@ -281,7 +300,7 @@
 {
 	Object *o;
 
-	o = aux->obj;
+	o = curcrumb(aux)->obj;
 	switch(o->type){
 	case GBlob:
 		readbuf(r, o->data, o->size);
@@ -325,10 +344,13 @@
 	if((d = dirstat(".git")) == nil)
 		sysfatal("git/fs: %r");
 	aux = emalloc(sizeof(Gitaux));
-	aux->path[0] = (Qid){Qroot, 0, QTDIR};
-	aux->opath[0] = nil;
-	aux->npath = 1;
-	aux->mtime = d->mtime;
+	aux->crumb = emalloc(sizeof(Crumb));
+	aux->crumb[0].qid = (Qid){Qroot, 0, QTDIR};
+	aux->crumb[0].obj = nil;
+	aux->crumb[0].mode = DMDIR | 0555;
+	aux->crumb[0].mtime = d->mtime;
+	aux->crumb[0].name = estrdup("/");
+	aux->ncrumb = 1;
 	r->ofcall.qid = (Qid){Qroot, 0, QTDIR};
 	r->fid->qid = r->ofcall.qid;
 	r->fid->aux = aux;
@@ -336,15 +358,14 @@
 }
 
 static char *
-objwalk1(Qid *q, Gitaux *aux, char *name, vlong qdir)
+objwalk1(Qid *q, Object *o, Crumb *c, char *name, vlong qdir)
 {
-	Object *o, *w;
+	Object *w;
 	char *e;
 	int i;
 
 	w = nil;
 	e = nil;
-	o = aux->obj;
 	if(!o)
 		return Eexist;
 	if(o->type == GTree){
@@ -359,13 +380,15 @@
 				die("could not read object for %s", name);
 			q->type = (w->type == GTree) ? QTDIR : 0;
 			q->path = QPATH(w->id, qdir);
-			aux->obj = w;
+			c->mode = o->tree->ent[i].mode;
+			c->obj = w;
 		}
 		if(!w)
 			e = Eexist;
 	}else if(o->type == GCommit){
 		q->type = 0;
-		aux->mtime = o->commit->mtime;
+		c->mtime = o->commit->mtime;
+		c->mode = 0444;
 		assert(qdir == Qcommit || qdir == Qobject || qdir == Qcommittree || qdir == Qhead);
 		if(strcmp(name, "msg") == 0)
 			q->path = QPATH(o->id, Qcommitmsg);
@@ -378,7 +401,9 @@
 		else if(strcmp(name, "tree") == 0){
 			q->type = QTDIR;
 			q->path = QPATH(o->id, Qcommittree);
-			aux->obj = readobject(o->commit->tree);
+			unref(c->obj);
+			c->obj = readobject(o->commit->tree);
+			c->mode = DMDIR | 0555;
 		}
 		else
 			e = Eexist;
@@ -427,7 +452,7 @@
 {
 	char path[128];
 	Gitaux *aux;
-	Object *o;
+	Crumb *c, *o;
 	char *e;
 	Dir *d;
 	Hash h;
@@ -434,33 +459,48 @@
 
 	e = nil;
 	aux = fid->aux;
+	
 	q->vers = 0;
 
 	if(strcmp(name, "..") == 0){
-		if(aux->npath > 1)
-			aux->npath--;
-		*q = aux->path[aux->npath - 1];
-		o = ref(aux->opath[aux->npath - 1]);
-		if(aux->obj)
-			unref(aux->obj);
-		aux->obj = o;
+		if(aux->ncrumb > 1){
+			c = &aux->crumb[aux->ncrumb - 1];
+			free(c->name);
+			unref(c->obj);
+			aux->ncrumb--;
+		}
+		c = &aux->crumb[aux->ncrumb - 1];
+		*q = c->qid;
 		fid->qid = *q;
 		return nil;
 	}
 	
-
+	aux->crumb = realloc(aux->crumb, (aux->ncrumb + 1) * sizeof(Crumb));
+	c = &aux->crumb[aux->ncrumb];
+	o = &aux->crumb[aux->ncrumb - 1];
+	memset(c, 0, sizeof(Crumb));
+	c->mode = o->mode;
+	c->mtime = o->mtime;
+	if(o->obj)
+		c->obj = ref(o->obj);
+	aux->ncrumb++;
+	
 	switch(QDIR(&fid->qid)){
 	case Qroot:
 		if(strcmp(name, "HEAD") == 0){
 			*q = (Qid){Qhead, 0, QTDIR};
-			aux->obj = readref(".git/HEAD");
+			c->mode = DMDIR | 0555;
+			c->obj = readref(".git/HEAD");
 		}else if(strcmp(name, "object") == 0){
 			*q = (Qid){Qobject, 0, QTDIR};
+			c->mode = DMDIR | 0555;
 		}else if(strcmp(name, "branch") == 0){
 			*q = (Qid){Qbranch, 0, QTDIR};
 			aux->refpath = estrdup(".git/refs/");
+			c->mode = DMDIR | 0555;
 		}else if(strcmp(name, "ctl") == 0){
 			*q = (Qid){Qctl, 0, 0};
+			c->mode = 0644;
 		}else{
 			e = Eexist;
 		}
@@ -474,33 +514,34 @@
 		d = dirstat(path);
 		if(d && d->qid.type == QTDIR)
 			q->path = QPATH(findbranch(aux, path), Qbranch);
-		else if(d && (aux->obj = readref(path)) != nil)
-			q->path = QPATH(aux->obj->id, Qcommit);
+		else if(d && (c->obj = readref(path)) != nil)
+			q->path = QPATH(c->obj->id, Qcommit);
 		else
 			e = Eexist;
 		free(d);
 		break;
 	case Qobject:
-		if(aux->obj){
-			e = objwalk1(q, aux, name, Qobject);
+		if(c->obj){
+			e = objwalk1(q, o->obj, c, name, Qobject);
 		}else{
 			if(hparse(&h, name) == -1)
 				return "invalid object name";
-			if((aux->obj = readobject(h)) == nil)
+			if((c->obj = readobject(h)) == nil)
 				return "could not read object";
-			q->path = QPATH(aux->obj->id, Qobject);
-			q->type = (aux->obj->type == GBlob) ? 0 : QTDIR;
+			c->mode = (c->obj->type == GBlob) ? 0444 : QTDIR | 0555;
+			q->path = QPATH(c->obj->id, Qobject);
+			q->type = (c->obj->type == GBlob) ? 0 : QTDIR;
 			q->vers = 0;
 		}
 		break;
 	case Qhead:
-		e = objwalk1(q, aux, name, Qhead);
+		e = objwalk1(q, o->obj, c, name, Qhead);
 		break;
 	case Qcommit:
-		e = objwalk1(q, aux, name, Qcommit);
+		e = objwalk1(q, o->obj, c, name, Qcommit);
 		break;
 	case Qcommittree:
-		e = objwalk1(q, aux, name, Qcommittree);
+		e = objwalk1(q, o->obj, c, name, Qcommittree);
 		break;
 	case Qcommitparent:
 	case Qcommitmsg:
@@ -510,24 +551,11 @@
 	case Qctl:
 		return Enodir;
 	default:
-		die("walk: bad qid %Q", *q);
+		return Egreg;
 	}
-	if(aux->npath >= Npath)
-		e = E2long;
-	if(!e && QDIR(q) >= Qmax){
-		print("npath: %d\n", aux->npath);
-		print("walking to %llx (name: %s)\n", q->path, name);
-		print("walking from %llx\n", fid->qid.path);
-		print("QDIR=%d\n", QDIR(&fid->qid));
-		if(aux->obj)
-			print("obj=%O\n", aux->obj);
-		abort();
-	}
 
-	aux->path[aux->npath] = *q;
-	if(aux->obj)
-		aux->opath[aux->npath] = ref(aux->obj);
-	aux->npath++;
+	c->name = estrdup(name);
+	c->qid = *q;
 	fid->qid = *q;
 	return e;
 }
@@ -540,19 +568,17 @@
 
 	oaux = o->aux;
 	aux = emalloc(sizeof(Gitaux));
-	aux->npath = oaux->npath;
-	for(i = 0; i < aux->npath; i++){
-		aux->path[i] = oaux->path[i];
-		aux->opath[i] = oaux->opath[i];
-		if(aux->opath[i])
-			ref(aux->opath[i]);
+	aux->ncrumb = oaux->ncrumb;
+	aux->crumb = emalloc(oaux->ncrumb * sizeof(Crumb));
+	for(i = 0; i < aux->ncrumb; i++){
+		aux->crumb[i] = oaux->crumb[i];
+		aux->crumb[i].name = estrdup(oaux->crumb[i].name);
+		if(aux->crumb[i].obj)
+			aux->crumb[i].obj = ref(oaux->crumb[i].obj);
 	}
 	if(oaux->refpath)
 		aux->refpath = strdup(oaux->refpath);
-	if(oaux->obj)
-		aux->obj = ref(oaux->obj);
 	aux->qdir = oaux->qdir;
-	aux->mtime = oaux->mtime;
 	n->aux = aux;
 	return nil;
 }
@@ -565,11 +591,14 @@
 
 	if((aux = f->aux) == nil)
 		return;
-	for(i = 0; i < aux->npath; i++)
-		unref(aux->opath[i]);
-	free(aux->refpath);
+	for(i = 0; i < aux->ncrumb; i++){
+		if(aux->crumb[i].obj)
+			unref(aux->crumb[i].obj);
+		free(aux->crumb[i].name);
+	}
 	olsfree(aux->ols);
-	unref(aux->obj);
+	free(aux->refpath);
+	free(aux->crumb);
 	free(aux);
 }
 
@@ -603,11 +632,10 @@
 	Object *o;
 	Qid *q;
 
+	aux = r->fid->aux;
 	q = &r->fid->qid;
-	o = nil;
+	o = curcrumb(aux)->obj;
 	e = nil;
-	if(aux = r->fid->aux)
-		o = aux->obj;
 
 	switch(QDIR(q)){
 	case Qroot:
@@ -643,7 +671,7 @@
 		break;
 	case Qhead:
 		/* Empty repositories have no HEAD */
-		if(aux->obj == nil)
+		if(o == nil)
 			r->ofcall.count = 0;
 		else
 			objread(r, aux);
@@ -654,7 +682,7 @@
 		objread(r, aux);
 		break;
 	default:
-		die("read: bad qid %Q", *q);
+		e = Egreg;
 	}
 	respond(r, e);
 }
@@ -663,60 +691,23 @@
 gitstat(Req *r)
 {
 	Gitaux *aux;
+	Crumb *c;
 	Qid *q;
 
-	q = &r->fid->qid;
 	aux = r->fid->aux;
+	q = &r->fid->qid;
+	c = curcrumb(aux);
 	r->d.uid = estrdup9p(username);
 	r->d.gid = estrdup9p(username);
 	r->d.muid = estrdup9p(username);
-	r->d.mtime = aux->mtime;
-	r->d.atime = r->d.mtime;
 	r->d.qid = r->fid->qid;
-	r->d.mode = 0755 | DMDIR;
-	if(aux->obj){
-		obj2dir(&r->d, aux->obj, QDIR(q), aux->mtime);
-	} else {
-		switch(QDIR(q)){
-		case Qroot:
-			r->d.name = estrdup9p("/");
-			break;
-		case Qhead:
-			r->d.name = estrdup9p("HEAD");
-			break;
-		case Qbranch:
-			r->d.name = estrdup9p("branch");
-			break;
-		case Qobject:
-			r->d.name = estrdup9p("object");
-			break;
-		case Qctl:
-			r->d.name = estrdup9p("ctl");
-			r->d.mode = 0666;
-			break;
-		case Qcommit:
-			r->d.name = smprint("%H", aux->obj->hash);
-			break;
-		case Qcommitmsg:
-			r->d.name = estrdup9p("msg");
-			r->d.mode = 0644;
-			break;
-		case Qcommittree:
-			r->d.name = estrdup9p("tree");
-			break;
-		case Qcommitparent:
-			r->d.name = estrdup9p("info");
-			r->d.mode = 0644;
-			break;
-		case Qcommithash:
-			r->d.name = estrdup9p("hash");
-			r->d.mode = 0644;
-			break;
-		default:
-			die("stat: bad qid %Q", *q);
-		}
-	}
-
+	r->d.mtime = c->mtime;
+	r->d.atime = c->mtime;
+	r->d.mode = c->mode;
+	if(c->obj)
+		obj2dir(&r->d, c->obj, c, c->name, QDIR(q));
+	else
+		r->d.name = estrdup9p(c->name);
 	respond(r, nil);
 }