xref: /inferno-os/liblogfs/wstat.c (revision 28942ead413418b56c5be78e8c4c400881fba72e)
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