diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /liblogfs/wstat.c | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'liblogfs/wstat.c')
| -rw-r--r-- | liblogfs/wstat.c | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/liblogfs/wstat.c b/liblogfs/wstat.c new file mode 100644 index 00000000..85f112da --- /dev/null +++ b/liblogfs/wstat.c @@ -0,0 +1,245 @@ +#include "lib9.h" +#include "logfs.h" +#include "fcall.h" +#include "local.h" + +char * +logfsserverwstat(LogfsServer *server, u32int fid, uchar *stat, ushort nstat) +{ + Fid *f; + uchar *p; + ushort len; + uchar *mep; + Qid qid; + u32int perm, mtime; + uvlong length; + char *name, *uname, *gname, *muname; + int qiddonttouch, permdonttouch, mtimedonttouch, lengthdonttouch; + Entry *e, *parent; + LogMessage s; + char *cuid, *ngid; + Group *eg, *ng; + char *cname; + char *errmsg; + char *nuid; + + if(server->trace > 1) + print("logfsserverwstat(%ud, %ud)\n", fid, nstat); + if(nstat < 49) + return Emsgsize; + p = stat; + len = GBIT16(p); p += BIT16SZ; + if(len + BIT16SZ != nstat) + return Emsgsize; + mep = p + len; + p += BIT16SZ + BIT32SZ; /* skip type and dev */ + qid.type = *p++; + qid.vers = GBIT32(p); p += BIT32SZ; + qid.path = GBIT64(p); p += BIT64SZ; + perm = GBIT32(p); p += BIT32SZ; + p += BIT32SZ; /* skip atime */ + mtime = GBIT32(p); p += BIT32SZ; + length = GBIT64(p); p+= BIT64SZ; + if(!logfsgn(&p, mep, &name) || !logfsgn(&p, mep, &uname) + || !logfsgn(&p, mep, &gname) || !logfsgn(&p, mep, &muname)) + return Emsgsize; + if(p != mep) + return Emsgsize; + qiddonttouch = qid.type == (uchar)~0 && qid.vers == ~0 && qid.path == ~(uvlong)0; + permdonttouch = perm == ~0; + mtimedonttouch = mtime == ~0; + lengthdonttouch = length == ~(uvlong)0; + if(server->trace > 1) { + int comma = 0; + print("logfsserverwstat("); + if(!qiddonttouch) { + comma = 1; + print("qid=0x%.2ux/%lud/%llud", qid.type, qid.vers, qid.path); + } + if(!permdonttouch) { + if(comma) + print(", "); + print("perm=0%uo", perm); + comma = 1; + } + if(!mtimedonttouch) { + if(comma) + print(", "); + print("mtime=%ud", mtime); + comma = 1; + } + if(!lengthdonttouch) { + if(comma) + print(", "); + print("length=%llud", length); + comma = 1; + } + if(name != nil) { + if(comma) + print(", "); + print("name=%s", name); + comma = 1; + } + if(uname != nil) { + if(comma) + print(", "); + print("uid=%s", uname); + comma = 1; + } + if(gname != nil) { + if(comma) + print(", "); + print("gid=%s", gname); + comma = 1; + } + if(muname != nil) { + if(comma) + print(", "); + print("muname=%s", muname); + comma = 1; + } + USED(comma); + print(")\n"); + } + f = logfsfidmapfindentry(server->fidmap, fid); + if(f == nil) + return logfsebadfid; + e = f->entry; + if(e->deadandgone) + return Eio; + parent = e->parent; + if(name) { + Entry *oe; + if(parent == e) + return Eperm; + if(!logfsuserpermcheck(server, e->parent, f, DMWRITE)) + return Eperm; + for(oe = parent->u.dir.list; oe; oe = oe->next) { + if(oe == e) + continue; + if(strcmp(oe->name, name) == 0) + return Eexist; + } + } + if(!lengthdonttouch) { + if(!logfsuserpermcheck(server, e, f, DMWRITE)) + return Eperm; + if(e->qid.type & QTDIR) { + if(length != 0) + return Eperm; + }else if(length != e->u.file.length){ + /* + * TODO - truncate directory + * TODO - truncate file + */ + return "wstat -- can't change length"; + } + } + cuid = logfsisfindidfromname(server->is, f->uname); + /* TODO - change entries to have a group pointer */ + eg = logfsisfindgroupfromid(server->is, e->uid); + if(gname) { + gname = logfsisustadd(server->is, gname); + if(gname == nil) + return Enomem; + ngid = logfsisfindidfromname(server->is, gname); + if(ngid == nil) + return Eunknown; + } + else + ngid = nil; + if(uname) { + uname = logfsisustadd(server->is, uname); + if(uname == nil) + return Enomem; + nuid = logfsisfindidfromname(server->is, uname); + if(nuid == nil) + return Eunknown; + } + else + nuid = nil; + if(!permdonttouch || !mtimedonttouch) { + /* + * same permissions rules - change by owner, or by group leader + */ + if((server->openflags & LogfsOpenFlagWstatAllow) == 0 && + e->uid != cuid && (eg == nil || !logfsisgroupuidisleader(server->is, eg, cuid))) + return Eperm; + } + if(!permdonttouch){ + if((perm^e->perm) & DMDIR) + return "wstat -- attempt to change directory"; + if(perm & ~(DMDIR|DMAPPEND|DMEXCL|0777)) + return Eperm; + } + if(gname) { + int ok; + ng = logfsisfindgroupfromid(server->is, ngid); + ok = 0; + if(e->uid == cuid && logfsisgroupuidismember(server->is, ng, e->uid)) + ok = 1; + if(!ok && eg && logfsisgroupuidisleader(server->is, eg, cuid) + && logfsisgroupuidisleader(server->is, ng, cuid)) + ok = 1; + if(!ok && (server->openflags & LogfsOpenFlagWstatAllow) == 0) + return Eperm; + } + if(!qiddonttouch) + return Eperm; + if(uname){ + if((server->openflags & LogfsOpenFlagWstatAllow) == 0) + return Eperm; + } + if(muname) + return Eperm; + /* + * we can do this + */ + if(mtimedonttouch && permdonttouch && lengthdonttouch + && name == nil && uname == nil && gname == nil) { + /* + * but we aren't doing anything - this is a wstat flush + */ + return logfsserverflush(server); + } + if(name) { + cname = logfsstrdup(name); + if(cname == nil) + return Enomem; + } + else + cname = nil; + /* + * send the log message + */ + s.type = LogfsLogTwstat; + s.path = e->qid.path; + s.u.wstat.name = cname; + s.u.wstat.perm = perm; + s.u.wstat.uid = nuid; + s.u.wstat.gid = ngid; + s.u.wstat.mtime = mtime; + s.u.wstat.muid = cuid; + errmsg = logfslog(server, 1, &s); + if(errmsg) { + logfsfreemem(cname); + return errmsg; + } + if(!mtimedonttouch) + e->mtime = mtime; + if(!permdonttouch) + e->perm = (e->perm & DMDIR) | perm; + if(!lengthdonttouch) { + /* TODO */ + } + if(name) { + logfsfreemem(e->name); + e->name = cname; + } + if(uname) + e->uid = nuid; + if(ngid) + e->gid = ngid; + return nil; +} + |
