shithub: git9

Download patch

ref: 45426d65b7b9f83a0adaf30acbec47611438f93c
parent: 22a4ca0f360a36a4a0927844e4d41e0845614826
author: Ori Bernstein <ori@eigenstate.org>
date: Fri Feb 7 18:25:16 EST 2020

add support for symlinks.

--- a/fs.c
+++ b/fs.c
@@ -84,6 +84,8 @@
 Cache	uqidcache[512];
 vlong	nextqid = Qmax;
 
+static char*	gitwalk1(Fid *fid, char *name, Qid *q);
+
 vlong
 qpath(Crumb *p, int idx, vlong id, vlong t)
 {
@@ -411,8 +413,29 @@
 	respond(r, nil);
 }
 
+static char*
+walklink(Fid *fid, char *_path, int npath, Qid *q)
+{
+	char *p, *e, *err, *path;
+
+	err = nil;
+	path = emalloc(npath + 1);
+	memcpy(path, _path, npath);
+	cleanname(path);
+	for(p = path; *p; p = e){
+		e = p + strcspn(p, "/");
+		if(*e == '/')
+			*e++ = '\0';
+		err = gitwalk1(fid, p, q);
+		if(err != nil)
+			break;
+	}
+	free(path);
+	return err;
+}
+
 static char *
-objwalk1(Qid *q, Object *o, Crumb *p, Crumb *c, char *name, vlong qdir)
+objwalk1(Fid *fid, Qid *q, Object *o, Crumb *p, Crumb *c, char *name, vlong qdir)
 {
 	Object *w;
 	char *e;
@@ -432,6 +455,8 @@
 				w = modrefobj(&o->tree->ent[i]);
 			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);
 			q->type = (w->type == GTree) ? QTDIR : 0;
 			q->path = qpath(c, i, w->id, qdir);
 			c->mode = o->tree->ent[i].mode;
@@ -577,7 +602,7 @@
 		break;
 	case Qobject:
 		if(c->obj){
-			e = objwalk1(q, o->obj, o, c, name, Qobject);
+			e = objwalk1(fid, q, o->obj, o, c, name, Qobject);
 		}else{
 			if(hparse(&h, name) == -1)
 				return "invalid object name";
@@ -590,13 +615,13 @@
 		}
 		break;
 	case Qhead:
-		e = objwalk1(q, o->obj, o, c, name, Qhead);
+		e = objwalk1(fid, q, o->obj, o, c, name, Qhead);
 		break;
 	case Qcommit:
-		e = objwalk1(q, o->obj, o, c, name, Qcommit);
+		e = objwalk1(fid, q, o->obj, o, c, name, Qcommit);
 		break;
 	case Qcommittree:
-		e = objwalk1(q, o->obj, o, c, name, Qcommittree);
+		e = objwalk1(fid, q, o->obj, o, c, name, Qcommittree);
 		break;
 	case Qcommitparent:
 	case Qcommitmsg:
--- a/save.c
+++ b/save.c
@@ -27,13 +27,14 @@
 int
 gitmode(int m)
 {
-	int b;
-
-	if((m & 0111) || (m & DMDIR))
-		b = 0755;
-	else
-		b = 0644;
-	return b | ((m & DMDIR) ? 0040000 : 0100000);
+	if(m & DMDIR)		/* directory */
+		return 0040755;
+	else if(m & 0111)	/* executable */
+		return 0100755;
+	else if(m != 0)		/* regular */
+		return 0100644;
+	else			/* symlink */
+		return 0120000;
 }
 
 int
@@ -167,6 +168,8 @@
 
 	if((d->mode & DMDIR) != 0)
 		sysfatal("not file: %s", path);
+	if(*mode == 0)
+		sysfatal("symlinks may not be modified: %s", path);
 	*mode = d->mode;
 	nh = snprint(h, sizeof(h), "%T %lld", GBlob, d->length) + 1;
 	if((f = open(path, OREAD)) == -1)