git: 9front

Download patch

ref: 7a9a9e674e8d963444abc8b5474cfa98ae4cf810
parent: 744de082b50aaffea83f16ca74997879a5d72b9e
author: Ori Bernstein <ori@eigenstate.org>
date: Sat Mar 21 23:08:18 EDT 2026

git: correctly inherit permissions from the .git dir for directories

git defaults to storing permission bits as 0o40000 for dirs by default,
so when reconstruct permissons we need to put back the perms for the dir
correctly, taking it from /.git.

--- a/sys/src/cmd/git/fs.c
+++ b/sys/src/cmd/git/fs.c
@@ -284,7 +284,7 @@
 
 	switch(i){
 	case 0:
-		d->mode = 0755 | DMDIR;
+		d->mode = DMDIR | gitdirmode;
 		d->name = estrdup9p("tree");
 		d->qid.type = QTDIR;
 		d->qid.path = qpath(c, i, o->id, Qtree);
@@ -495,7 +495,7 @@
 			q->type = (w->type == GTree) ? QTDIR : 0;
 			q->path = qpath(p, i, w->id, qdir);
 			c->mode = m;
-			c->mode |= (w->type == GTree) ? DMDIR|0755 : 0644;
+			c->mode |= (w->type == GTree) ? (DMDIR|0755) : 0644;
 			c->obj = w;
 			break;
 		}
@@ -521,7 +521,7 @@
 			q->type = QTDIR;
 			q->path = qpath(p, 4, o->id, Qtree);
 			unref(c->obj);
-			c->mode = DMDIR | 0755;
+			c->mode = DMDIR | gitdirmode;
 			c->obj = readobject(o->commit->tree);
 			if(c->obj == nil)
 				sysfatal("could not read object %H: %r", o->commit->tree);
--- a/sys/src/cmd/git/git.h
+++ b/sys/src/cmd/git/git.h
@@ -261,6 +261,7 @@
 extern Hash	Zhash;
 extern int	chattygit;
 extern int	interactive;
+extern int	gitdirmode;
 
 #pragma varargck type "H" Hash
 #pragma varargck type "T" int
--- a/sys/src/cmd/git/pack.c
+++ b/sys/src/cmd/git/pack.c
@@ -70,7 +70,6 @@
 Packf	*packf;
 int	npackf;
 int	openpacks;
-int	gitdirmode = -1;
 
 static void
 clear(Object *o)
@@ -958,18 +957,21 @@
 		 * useful permissions, replicate the mode
 		 * of the git repo dir.
 		 */
-		a = (m & 0777)>>6;
-		t->mode = ((a<<6)|(a<<3)|a) & gitdirmode;
+		t->mode = gitdirmode;
 		t->ismod = 0;
 		t->islink = 0;
-		if(m == 0160000){
+		if(m & 0777){
+			a = (m & 0777)>>6;
+			t->mode &= ((a<<6)|(a<<3)|a);
+		}
+		if(m == 0160000){ /* module */
 			t->mode |= DMDIR;
 			t->ismod = 1;
-		}else if(m == 0120000){
+		}else if(m == 0120000){ /* symlink */
 			t->mode = 0;
 			t->islink = 1;
 		}
-		if(m & 0040000)
+		if(m & 0040000) /* dir */
 			t->mode |= DMDIR;
 		t->name = p;
 		p = memchr(p, 0, ep - p);
@@ -1130,14 +1132,7 @@
 readobject(Hash h)
 {
 	Object *o;
-	Dir *d;
 
-	if(gitdirmode == -1){
-		if((d = dirstat(".git")) == nil)
-			sysfatal("stat .git: %r");
-		gitdirmode = d->mode & 0777;
-		free(d);
-	}
 	if((o = readidxobject(nil, h, 0)) == nil)
 		return nil;
 	parseobject(o);
--- a/sys/src/cmd/git/util.c
+++ b/sys/src/cmd/git/util.c
@@ -4,12 +4,12 @@
 
 #include "git.h"
 
-Reprog *authorpat;
-Hash Zhash;
+Reprog	*authorpat;
+Hash	Zhash;
+int	chattygit;
+int	interactive = 1;
+int	gitdirmode = -1;
 
-int chattygit;
-int interactive = 1;
-
 enum {
 	Seed		= 2928213749ULL
 };
@@ -246,6 +246,8 @@
 void
 gitinit(void)
 {
+	Dir *d;
+
 	fmtinstall('H', Hfmt);
 	fmtinstall('T', Tfmt);
 	fmtinstall('O', Ofmt);
@@ -254,6 +256,12 @@
 	deflateinit();
 	authorpat = regcomp("[\t ]*(.*)[\t ]+([0-9]+)[\t ]*([\\-+]?[0-9]+)?");
 	osinit(&objcache);
+	if(gitdirmode == -1){
+		if((d = dirstat(".git")) == nil)
+			sysfatal("stat .git: %r");
+		gitdirmode = d->mode & 0777;
+		free(d);
+	}
 }
 
 int
--