shithub: git9

Download patch

ref: 2856dd8f8c8cf799212163fe79ba9752f1bcd797
parent: 0e48e4b5ea80db83fb6bff5c3cfc51593a27dd7f
author: Ori Bernstein <[email protected]>
date: Fri Feb 7 23:40:29 EST 2020

fix symlink walks with '..'s

--- a/fs.c
+++ b/fs.c
@@ -121,6 +121,19 @@
 	return nil;
 }
 
+static void
+popcrumb(Gitaux *aux)
+{
+	Crumb *c;
+
+	if(aux->ncrumb > 1){
+		c = crumb(aux, 0);
+		free(c->name);
+		unref(c->obj);
+		aux->ncrumb--;
+	}
+}
+
 static vlong
 branchid(Gitaux *aux, char *path)
 {
@@ -414,20 +427,20 @@
 }
 
 static char*
-walklink(Fid *fid, char *_path, int npath, Qid *q)
+walklink(Fid *fid, Qid *q, char *link, int nlink)
 {
 	char *p, *e, *err, *path;
 
 	err = nil;
-	path = emalloc(npath + 1);
-	memcpy(path, _path, npath);
+	path = emalloc(nlink + 1);
+	memcpy(path, link, nlink);
 	cleanname(path);
+	popcrumb(fid->aux);
 	for(p = path; *p; p = e){
 		e = p + strcspn(p, "/");
 		if(*e == '/')
 			*e++ = '\0';
-		err = gitwalk1(fid, p, q);
-		if(err != nil)
+		if((err = gitwalk1(fid, p, q)) != nil)
 			break;
 	}
 	free(path);
@@ -456,7 +469,7 @@
 			if(!w)
 				die("could not read object for %s: %r", name);
 			if(o->tree->ent[i].mode == 0)
-				return walklink(fid, w->data, w->size, q);
+				return walklink(fid, q, w->data, w->size);
 			q->type = (w->type == GTree) ? QTDIR : 0;
 			q->path = qpath(c, i, w->id, qdir);
 			c->mode = o->tree->ent[i].mode;
@@ -541,15 +554,9 @@
 	aux = fid->aux;
 	
 	q->vers = 0;
-
 	if(strcmp(name, "..") == 0){
-		if(aux->ncrumb > 1){
-			c = &aux->crumb[aux->ncrumb - 1];
-			free(c->name);
-			unref(c->obj);
-			aux->ncrumb--;
-		}
-		c = &aux->crumb[aux->ncrumb - 1];
+		popcrumb(aux);
+		c = crumb(aux, 0);
 		*q = c->qid;
 		fid->qid = *q;
 		return nil;
@@ -556,14 +563,13 @@
 	}
 	
 	aux->crumb = realloc(aux->crumb, (aux->ncrumb + 1) * sizeof(Crumb));
-	c = &aux->crumb[aux->ncrumb];
-	o = &aux->crumb[aux->ncrumb - 1];
+	aux->ncrumb++;
+	c = crumb(aux, 0);
+	o = crumb(aux, 1);
 	memset(c, 0, sizeof(Crumb));
 	c->mode = o->mode;
 	c->mtime = o->mtime;
-	if(o->obj)
-		c->obj = ref(o->obj);
-	aux->ncrumb++;
+		c->obj = o->obj ? ref(o->obj) : nil;
 	
 	switch(QDIR(&fid->qid)){
 	case Qroot:
@@ -634,6 +640,12 @@
 		return Egreg;
 	}
 
+	/* 
+	 * if we get called recursively from
+	 * objwalk1, we realloc the crumb array;
+	 * get a valid crumb again.
+	 */
+	c = crumb(aux, 0);
 	c->name = estrdup(name);
 	c->qid = *q;
 	fid->qid = *q;