ref: b904edadd8869787b4419ce93c1c29b5beee3556
parent: 577033228209f28350dc3f75ef9d4ce88dfdf190
author: Ori Bernstein <[email protected]>
date: Tue Jun 22 19:55:54 EDT 2021
git/fs: use a better heuristic for permissions. Since we now store /dist/plan9front in git, the initial assumption that the owner of the repo is the person touching it is not always true. This change gives us a better heuristic for the file permissions we should have in the files we copy around, basing it off of the permissions of the .git directory.
--- a/sys/man/4/gitfs
+++ b/sys/man/4/gitfs
@@ -74,6 +74,15 @@
.PP
Trees are presented as directory listings, and blobs
as files.
+The repository controls the user permissions.
+The group and world permissions are derived by masking
+the user permissions with the permissions of the
+.I .git
+directory.
+The user and group presented is the same as the user and
+group of the
+.I .git
+directory.
.SH FILES
.TP
@@ -100,11 +109,14 @@
.SH BUGS
Symlinks are only partially supported.
-Symlinks are treated as regular files when reading.
-Modifying symlinks is unsupported.
+They will be followed when reading, but a commit that
+modifies a symlink is an error.
.PP
-There is no way to inspect the raw objects. This is
-a feature that would be useful for debugging.
+For efficiency, git/fs only loads repo permissions at startup
+
+.PP
+There is no way to inspect the raw objects.
+Inspecting raw objects would be useful for debugging.
--- a/sys/src/cmd/git/fs.c
+++ b/sys/src/cmd/git/fs.c
@@ -79,6 +79,7 @@
char gitdir[512];
char *username;
+char *groupname;
char *mntpt = ".git/fs";
char **branches = nil;
Cache uqidcache[512];
@@ -164,7 +165,7 @@
d->mode = c->mode;
d->name = estrdup9p(name);
d->uid = estrdup9p(username);
- d->gid = estrdup9p(username);
+ d->gid = estrdup9p(groupname);
d->muid = estrdup9p(username);
if(o->type == GBlob || o->type == GTag){
d->qid.type = 0;
@@ -188,7 +189,7 @@
d->qid.type = strcmp(qroot[i], "ctl") == 0 ? 0 : QTDIR;
d->qid.path = qpath(nil, i, i, Qroot);
d->uid = estrdup9p(username);
- d->gid = estrdup9p(username);
+ d->gid = estrdup9p(groupname);
d->muid = estrdup9p(username);
d->mtime = c->mtime;
return 0;
@@ -210,7 +211,7 @@
d->qid.path = qpath(c, i, branchid(aux, aux->refpath), Qbranch | Internal);
d->mode = 0555 | DMDIR;
d->uid = estrdup9p(username);
- d->gid = estrdup9p(username);
+ d->gid = estrdup9p(groupname);
d->muid = estrdup9p(username);
d->mtime = c->mtime;
d->atime = c->mtime;
@@ -251,11 +252,10 @@
d->qid.type = o->type == GTree ? QTDIR : 0;
d->qid.path = qpath(c, i, o->id, aux->qdir);
d->mode = m;
- d->mode |= (o->type == GTree) ? 0755 : 0644;
d->atime = c->mtime;
d->mtime = c->mtime;
d->uid = estrdup9p(username);
- d->gid = estrdup9p(username);
+ d->gid = estrdup9p(groupname);
d->muid = estrdup9p(username);
d->name = estrdup9p(e->tree->ent[i].name);
d->length = o->size;
@@ -271,7 +271,7 @@
c = crumb(p, 0);
o = c->obj;
d->uid = estrdup9p(username);
- d->gid = estrdup9p(username);
+ d->gid = estrdup9p(groupname);
d->muid = estrdup9p(username);
d->mode = 0444;
d->atime = o->commit->ctime;
@@ -490,7 +490,7 @@
}else if(o->type == GCommit){
q->type = 0;
c->mtime = o->commit->mtime;
- c->mode = 0444;
+ c->mode = 0644;
assert(qdir == Qcommit || qdir == Qobject || qdir == Qcommittree || qdir == Qhead);
if(strcmp(name, "msg") == 0)
q->path = qpath(p, 0, o->id, Qcommitmsg);
@@ -804,7 +804,7 @@
aux = r->fid->aux;
c = crumb(aux, 0);
r->d.uid = estrdup9p(username);
- r->d.gid = estrdup9p(username);
+ r->d.gid = estrdup9p(groupname);
r->d.muid = estrdup9p(username);
r->d.qid = r->fid->qid;
r->d.mtime = c->mtime;
@@ -837,6 +837,8 @@
void
main(int argc, char **argv)
{
+ Dir *d;
+
gitinit();
ARGBEGIN{
case 'd':
@@ -852,7 +854,12 @@
if(argc != 0)
usage();
- username = getuser();
+ if((d = dirstat(".git")) == nil)
+ sysfatal("dirstat .git: %r");
+ username = strdup(d->uid);
+ groupname = strdup(d->gid);
+ free(d);
+
branches = emalloc(sizeof(char*));
branches[0] = nil;
postmountsrv(&gitsrv, nil, mntpt, MCREATE);
--- a/sys/src/cmd/git/pack.c
+++ b/sys/src/cmd/git/pack.c
@@ -70,6 +70,7 @@
Packf *packf;
int npackf;
int openpacks;
+int gitdirmode = -1;
static void
clear(Object *o)
@@ -887,7 +888,7 @@
static void
parsetree(Object *o)
{
- int m, entsz, nent;
+ int m, a, entsz, nent;
Dirent *t, *ent;
char *p, *ep;
@@ -908,7 +909,15 @@
if(*p != ' ')
sysfatal("malformed tree %H: *p=(%d) %c\n", o->hash, *p, *p);
p++;
- t->mode = m & 0777;
+ /*
+ * only the stored permissions for the user
+ * are relevant; git fills group and world
+ * bits with whatever -- so to serve with
+ * useful permissions, replicate the mode
+ * of the git repo dir.
+ */
+ a = (m & 0777)>>6;
+ t->mode = ((a<<6)|(a<<3)|a) & gitdirmode;
t->ismod = 0;
t->islink = 0;
if(m == 0160000){
@@ -1048,7 +1057,14 @@
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);