1*28942eadSforsyth #include "logfsos.h"
237da2899SCharles.Forsyth #include "logfs.h"
337da2899SCharles.Forsyth #include "fcall.h"
437da2899SCharles.Forsyth #include "local.h"
537da2899SCharles.Forsyth
637da2899SCharles.Forsyth char *
logfsserverwstat(LogfsServer * server,u32int fid,uchar * stat,ushort nstat)737da2899SCharles.Forsyth logfsserverwstat(LogfsServer *server, u32int fid, uchar *stat, ushort nstat)
837da2899SCharles.Forsyth {
937da2899SCharles.Forsyth Fid *f;
1037da2899SCharles.Forsyth uchar *p;
1137da2899SCharles.Forsyth ushort len;
1237da2899SCharles.Forsyth uchar *mep;
1337da2899SCharles.Forsyth Qid qid;
1437da2899SCharles.Forsyth u32int perm, mtime;
1537da2899SCharles.Forsyth uvlong length;
1637da2899SCharles.Forsyth char *name, *uname, *gname, *muname;
1737da2899SCharles.Forsyth int qiddonttouch, permdonttouch, mtimedonttouch, lengthdonttouch;
1837da2899SCharles.Forsyth Entry *e, *parent;
1937da2899SCharles.Forsyth LogMessage s;
2037da2899SCharles.Forsyth char *cuid, *ngid;
2137da2899SCharles.Forsyth Group *eg, *ng;
2237da2899SCharles.Forsyth char *cname;
2337da2899SCharles.Forsyth char *errmsg;
2437da2899SCharles.Forsyth char *nuid;
2537da2899SCharles.Forsyth
2637da2899SCharles.Forsyth if(server->trace > 1)
2737da2899SCharles.Forsyth print("logfsserverwstat(%ud, %ud)\n", fid, nstat);
2837da2899SCharles.Forsyth if(nstat < 49)
29*28942eadSforsyth return Eshortstat;
3037da2899SCharles.Forsyth p = stat;
3137da2899SCharles.Forsyth len = GBIT16(p); p += BIT16SZ;
3237da2899SCharles.Forsyth if(len + BIT16SZ != nstat)
33*28942eadSforsyth return Eshortstat;
3437da2899SCharles.Forsyth mep = p + len;
3537da2899SCharles.Forsyth p += BIT16SZ + BIT32SZ; /* skip type and dev */
3637da2899SCharles.Forsyth qid.type = *p++;
3737da2899SCharles.Forsyth qid.vers = GBIT32(p); p += BIT32SZ;
3837da2899SCharles.Forsyth qid.path = GBIT64(p); p += BIT64SZ;
3937da2899SCharles.Forsyth perm = GBIT32(p); p += BIT32SZ;
4037da2899SCharles.Forsyth p += BIT32SZ; /* skip atime */
4137da2899SCharles.Forsyth mtime = GBIT32(p); p += BIT32SZ;
4237da2899SCharles.Forsyth length = GBIT64(p); p+= BIT64SZ;
4337da2899SCharles.Forsyth if(!logfsgn(&p, mep, &name) || !logfsgn(&p, mep, &uname)
4437da2899SCharles.Forsyth || !logfsgn(&p, mep, &gname) || !logfsgn(&p, mep, &muname))
45*28942eadSforsyth return Eshortstat;
4637da2899SCharles.Forsyth if(p != mep)
47*28942eadSforsyth return Eshortstat;
4837da2899SCharles.Forsyth qiddonttouch = qid.type == (uchar)~0 && qid.vers == ~0 && qid.path == ~(uvlong)0;
4937da2899SCharles.Forsyth permdonttouch = perm == ~0;
5037da2899SCharles.Forsyth mtimedonttouch = mtime == ~0;
5137da2899SCharles.Forsyth lengthdonttouch = length == ~(uvlong)0;
5237da2899SCharles.Forsyth if(server->trace > 1) {
5337da2899SCharles.Forsyth int comma = 0;
5437da2899SCharles.Forsyth print("logfsserverwstat(");
5537da2899SCharles.Forsyth if(!qiddonttouch) {
5637da2899SCharles.Forsyth comma = 1;
5737da2899SCharles.Forsyth print("qid=0x%.2ux/%lud/%llud", qid.type, qid.vers, qid.path);
5837da2899SCharles.Forsyth }
5937da2899SCharles.Forsyth if(!permdonttouch) {
6037da2899SCharles.Forsyth if(comma)
6137da2899SCharles.Forsyth print(", ");
6237da2899SCharles.Forsyth print("perm=0%uo", perm);
6337da2899SCharles.Forsyth comma = 1;
6437da2899SCharles.Forsyth }
6537da2899SCharles.Forsyth if(!mtimedonttouch) {
6637da2899SCharles.Forsyth if(comma)
6737da2899SCharles.Forsyth print(", ");
6837da2899SCharles.Forsyth print("mtime=%ud", mtime);
6937da2899SCharles.Forsyth comma = 1;
7037da2899SCharles.Forsyth }
7137da2899SCharles.Forsyth if(!lengthdonttouch) {
7237da2899SCharles.Forsyth if(comma)
7337da2899SCharles.Forsyth print(", ");
7437da2899SCharles.Forsyth print("length=%llud", length);
7537da2899SCharles.Forsyth comma = 1;
7637da2899SCharles.Forsyth }
7737da2899SCharles.Forsyth if(name != nil) {
7837da2899SCharles.Forsyth if(comma)
7937da2899SCharles.Forsyth print(", ");
8037da2899SCharles.Forsyth print("name=%s", name);
8137da2899SCharles.Forsyth comma = 1;
8237da2899SCharles.Forsyth }
8337da2899SCharles.Forsyth if(uname != nil) {
8437da2899SCharles.Forsyth if(comma)
8537da2899SCharles.Forsyth print(", ");
8637da2899SCharles.Forsyth print("uid=%s", uname);
8737da2899SCharles.Forsyth comma = 1;
8837da2899SCharles.Forsyth }
8937da2899SCharles.Forsyth if(gname != nil) {
9037da2899SCharles.Forsyth if(comma)
9137da2899SCharles.Forsyth print(", ");
9237da2899SCharles.Forsyth print("gid=%s", gname);
9337da2899SCharles.Forsyth comma = 1;
9437da2899SCharles.Forsyth }
9537da2899SCharles.Forsyth if(muname != nil) {
9637da2899SCharles.Forsyth if(comma)
9737da2899SCharles.Forsyth print(", ");
9837da2899SCharles.Forsyth print("muname=%s", muname);
9937da2899SCharles.Forsyth comma = 1;
10037da2899SCharles.Forsyth }
10137da2899SCharles.Forsyth USED(comma);
10237da2899SCharles.Forsyth print(")\n");
10337da2899SCharles.Forsyth }
10437da2899SCharles.Forsyth f = logfsfidmapfindentry(server->fidmap, fid);
10537da2899SCharles.Forsyth if(f == nil)
10637da2899SCharles.Forsyth return logfsebadfid;
10737da2899SCharles.Forsyth e = f->entry;
10837da2899SCharles.Forsyth if(e->deadandgone)
10937da2899SCharles.Forsyth return Eio;
11037da2899SCharles.Forsyth parent = e->parent;
11137da2899SCharles.Forsyth if(name) {
11237da2899SCharles.Forsyth Entry *oe;
11337da2899SCharles.Forsyth if(parent == e)
11437da2899SCharles.Forsyth return Eperm;
11537da2899SCharles.Forsyth if(!logfsuserpermcheck(server, e->parent, f, DMWRITE))
11637da2899SCharles.Forsyth return Eperm;
11737da2899SCharles.Forsyth for(oe = parent->u.dir.list; oe; oe = oe->next) {
11837da2899SCharles.Forsyth if(oe == e)
11937da2899SCharles.Forsyth continue;
12037da2899SCharles.Forsyth if(strcmp(oe->name, name) == 0)
12137da2899SCharles.Forsyth return Eexist;
12237da2899SCharles.Forsyth }
12337da2899SCharles.Forsyth }
12437da2899SCharles.Forsyth if(!lengthdonttouch) {
12537da2899SCharles.Forsyth if(!logfsuserpermcheck(server, e, f, DMWRITE))
12637da2899SCharles.Forsyth return Eperm;
12737da2899SCharles.Forsyth if(e->qid.type & QTDIR) {
12837da2899SCharles.Forsyth if(length != 0)
12937da2899SCharles.Forsyth return Eperm;
13037da2899SCharles.Forsyth }else if(length != e->u.file.length){
13137da2899SCharles.Forsyth /*
13237da2899SCharles.Forsyth * TODO - truncate directory
13337da2899SCharles.Forsyth * TODO - truncate file
13437da2899SCharles.Forsyth */
13537da2899SCharles.Forsyth return "wstat -- can't change length";
13637da2899SCharles.Forsyth }
13737da2899SCharles.Forsyth }
13837da2899SCharles.Forsyth cuid = logfsisfindidfromname(server->is, f->uname);
13937da2899SCharles.Forsyth /* TODO - change entries to have a group pointer */
14037da2899SCharles.Forsyth eg = logfsisfindgroupfromid(server->is, e->uid);
14137da2899SCharles.Forsyth if(gname) {
14237da2899SCharles.Forsyth gname = logfsisustadd(server->is, gname);
14337da2899SCharles.Forsyth if(gname == nil)
14437da2899SCharles.Forsyth return Enomem;
14537da2899SCharles.Forsyth ngid = logfsisfindidfromname(server->is, gname);
14637da2899SCharles.Forsyth if(ngid == nil)
14737da2899SCharles.Forsyth return Eunknown;
14837da2899SCharles.Forsyth }
14937da2899SCharles.Forsyth else
15037da2899SCharles.Forsyth ngid = nil;
15137da2899SCharles.Forsyth if(uname) {
15237da2899SCharles.Forsyth uname = logfsisustadd(server->is, uname);
15337da2899SCharles.Forsyth if(uname == nil)
15437da2899SCharles.Forsyth return Enomem;
15537da2899SCharles.Forsyth nuid = logfsisfindidfromname(server->is, uname);
15637da2899SCharles.Forsyth if(nuid == nil)
15737da2899SCharles.Forsyth return Eunknown;
15837da2899SCharles.Forsyth }
15937da2899SCharles.Forsyth else
16037da2899SCharles.Forsyth nuid = nil;
16137da2899SCharles.Forsyth if(!permdonttouch || !mtimedonttouch) {
16237da2899SCharles.Forsyth /*
16337da2899SCharles.Forsyth * same permissions rules - change by owner, or by group leader
16437da2899SCharles.Forsyth */
16537da2899SCharles.Forsyth if((server->openflags & LogfsOpenFlagWstatAllow) == 0 &&
16637da2899SCharles.Forsyth e->uid != cuid && (eg == nil || !logfsisgroupuidisleader(server->is, eg, cuid)))
16737da2899SCharles.Forsyth return Eperm;
16837da2899SCharles.Forsyth }
16937da2899SCharles.Forsyth if(!permdonttouch){
17037da2899SCharles.Forsyth if((perm^e->perm) & DMDIR)
17137da2899SCharles.Forsyth return "wstat -- attempt to change directory";
17237da2899SCharles.Forsyth if(perm & ~(DMDIR|DMAPPEND|DMEXCL|0777))
17337da2899SCharles.Forsyth return Eperm;
17437da2899SCharles.Forsyth }
17537da2899SCharles.Forsyth if(gname) {
17637da2899SCharles.Forsyth int ok;
17737da2899SCharles.Forsyth ng = logfsisfindgroupfromid(server->is, ngid);
17837da2899SCharles.Forsyth ok = 0;
17937da2899SCharles.Forsyth if(e->uid == cuid && logfsisgroupuidismember(server->is, ng, e->uid))
18037da2899SCharles.Forsyth ok = 1;
18137da2899SCharles.Forsyth if(!ok && eg && logfsisgroupuidisleader(server->is, eg, cuid)
18237da2899SCharles.Forsyth && logfsisgroupuidisleader(server->is, ng, cuid))
18337da2899SCharles.Forsyth ok = 1;
18437da2899SCharles.Forsyth if(!ok && (server->openflags & LogfsOpenFlagWstatAllow) == 0)
18537da2899SCharles.Forsyth return Eperm;
18637da2899SCharles.Forsyth }
18737da2899SCharles.Forsyth if(!qiddonttouch)
18837da2899SCharles.Forsyth return Eperm;
18937da2899SCharles.Forsyth if(uname){
19037da2899SCharles.Forsyth if((server->openflags & LogfsOpenFlagWstatAllow) == 0)
19137da2899SCharles.Forsyth return Eperm;
19237da2899SCharles.Forsyth }
19337da2899SCharles.Forsyth if(muname)
19437da2899SCharles.Forsyth return Eperm;
19537da2899SCharles.Forsyth /*
19637da2899SCharles.Forsyth * we can do this
19737da2899SCharles.Forsyth */
19837da2899SCharles.Forsyth if(mtimedonttouch && permdonttouch && lengthdonttouch
19937da2899SCharles.Forsyth && name == nil && uname == nil && gname == nil) {
20037da2899SCharles.Forsyth /*
20137da2899SCharles.Forsyth * but we aren't doing anything - this is a wstat flush
20237da2899SCharles.Forsyth */
20337da2899SCharles.Forsyth return logfsserverflush(server);
20437da2899SCharles.Forsyth }
20537da2899SCharles.Forsyth if(name) {
20637da2899SCharles.Forsyth cname = logfsstrdup(name);
20737da2899SCharles.Forsyth if(cname == nil)
20837da2899SCharles.Forsyth return Enomem;
20937da2899SCharles.Forsyth }
21037da2899SCharles.Forsyth else
21137da2899SCharles.Forsyth cname = nil;
21237da2899SCharles.Forsyth /*
21337da2899SCharles.Forsyth * send the log message
21437da2899SCharles.Forsyth */
21537da2899SCharles.Forsyth s.type = LogfsLogTwstat;
21637da2899SCharles.Forsyth s.path = e->qid.path;
21737da2899SCharles.Forsyth s.u.wstat.name = cname;
21837da2899SCharles.Forsyth s.u.wstat.perm = perm;
21937da2899SCharles.Forsyth s.u.wstat.uid = nuid;
22037da2899SCharles.Forsyth s.u.wstat.gid = ngid;
22137da2899SCharles.Forsyth s.u.wstat.mtime = mtime;
22237da2899SCharles.Forsyth s.u.wstat.muid = cuid;
22337da2899SCharles.Forsyth errmsg = logfslog(server, 1, &s);
22437da2899SCharles.Forsyth if(errmsg) {
22537da2899SCharles.Forsyth logfsfreemem(cname);
22637da2899SCharles.Forsyth return errmsg;
22737da2899SCharles.Forsyth }
22837da2899SCharles.Forsyth if(!mtimedonttouch)
22937da2899SCharles.Forsyth e->mtime = mtime;
23037da2899SCharles.Forsyth if(!permdonttouch)
23137da2899SCharles.Forsyth e->perm = (e->perm & DMDIR) | perm;
23237da2899SCharles.Forsyth if(!lengthdonttouch) {
23337da2899SCharles.Forsyth /* TODO */
23437da2899SCharles.Forsyth }
23537da2899SCharles.Forsyth if(name) {
23637da2899SCharles.Forsyth logfsfreemem(e->name);
23737da2899SCharles.Forsyth e->name = cname;
23837da2899SCharles.Forsyth }
23937da2899SCharles.Forsyth if(uname)
24037da2899SCharles.Forsyth e->uid = nuid;
24137da2899SCharles.Forsyth if(ngid)
24237da2899SCharles.Forsyth e->gid = ngid;
24337da2899SCharles.Forsyth return nil;
24437da2899SCharles.Forsyth }
24537da2899SCharles.Forsyth
246