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.
This commit is contained in:
Ori Bernstein 2021-06-22 23:55:54 +00:00
parent 5770332282
commit b904edadd8
3 changed files with 50 additions and 15 deletions

View file

@ -74,6 +74,15 @@ hierarchy are the same as the date of the commit.
.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 @@ The global configuration for git tools.
.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.

View file

@ -79,6 +79,7 @@ char *qroot[] = {
char gitdir[512];
char *username;
char *groupname;
char *mntpt = ".git/fs";
char **branches = nil;
Cache uqidcache[512];
@ -164,7 +165,7 @@ obj2dir(Dir *d, Crumb *c, Object *o, char *name)
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 @@ rootgen(int i, Dir *d, void *p)
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 @@ branchgen(int i, Dir *d, void *p)
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 @@ gtreegen(int i, Dir *d, void *p)
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 @@ gcommitgen(int i, Dir *d, void *p)
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 @@ objwalk1(Qid *q, Object *o, Crumb *p, Crumb *c, char *name, vlong qdir, Gitaux *
}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 @@ gitstat(Req *r)
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 @@ usage(void)
void
main(int argc, char **argv)
{
Dir *d;
gitinit();
ARGBEGIN{
case 'd':
@ -852,7 +854,12 @@ main(int argc, char **argv)
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);

View file

@ -70,6 +70,7 @@ int cachemax = 4096;
Packf *packf;
int npackf;
int openpacks;
int gitdirmode = -1;
static void
clear(Object *o)
@ -887,7 +888,7 @@ parsecommit(Object *o)
static void
parsetree(Object *o)
{
int m, entsz, nent;
int m, a, entsz, nent;
Dirent *t, *ent;
char *p, *ep;
@ -908,7 +909,15 @@ parsetree(Object *o)
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 @@ Object*
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);