101a344a2SDavid du Colombier #include "all.h"
201a344a2SDavid du Colombier #include "9p1.h"
301a344a2SDavid du Colombier
401a344a2SDavid du Colombier extern Nvrsafe nvr;
501a344a2SDavid du Colombier
601a344a2SDavid du Colombier typedef struct {
701a344a2SDavid du Colombier uchar chal[CHALLEN]; /* locally generated challenge */
801a344a2SDavid du Colombier uchar rchal[CHALLEN]; /* remotely generated challenge */
901a344a2SDavid du Colombier Lock idlock;
1001a344a2SDavid du Colombier ulong idoffset; /* offset of id vector */
1101a344a2SDavid du Colombier ulong idvec; /* vector of acceptable id's */
1201a344a2SDavid du Colombier } Authinfo;
1301a344a2SDavid du Colombier
1401a344a2SDavid du Colombier static void
f_nop(Chan * cp,Fcall *,Fcall *)1501a344a2SDavid du Colombier f_nop(Chan *cp, Fcall*, Fcall*)
1601a344a2SDavid du Colombier {
1701a344a2SDavid du Colombier if(CHAT(cp))
1801a344a2SDavid du Colombier print("c_nop %d\n", cp->chan);
1901a344a2SDavid du Colombier }
2001a344a2SDavid du Colombier
2101a344a2SDavid du Colombier static void
f_flush(Chan * cp,Fcall *,Fcall *)2201a344a2SDavid du Colombier f_flush(Chan *cp, Fcall*, Fcall*)
2301a344a2SDavid du Colombier {
2401a344a2SDavid du Colombier if(CHAT(cp))
2501a344a2SDavid du Colombier print("c_flush %d\n", cp->chan);
2601a344a2SDavid du Colombier runlock(&cp->reflock);
2701a344a2SDavid du Colombier wlock(&cp->reflock);
2801a344a2SDavid du Colombier wunlock(&cp->reflock);
2901a344a2SDavid du Colombier rlock(&cp->reflock);
3001a344a2SDavid du Colombier }
3101a344a2SDavid du Colombier
3201a344a2SDavid du Colombier /*
3301a344a2SDavid du Colombier * create a challenge for a fid space
3401a344a2SDavid du Colombier */
3501a344a2SDavid du Colombier static void
mkchallenge(Authinfo * aip)3601a344a2SDavid du Colombier mkchallenge(Authinfo *aip)
3701a344a2SDavid du Colombier {
3801a344a2SDavid du Colombier int i;
3901a344a2SDavid du Colombier
40*223a0358SDavid du Colombier srand((uintptr)aip + time(nil));
4101a344a2SDavid du Colombier for(i = 0; i < CHALLEN; i++)
4201a344a2SDavid du Colombier aip->chal[i] = nrand(256);
4301a344a2SDavid du Colombier
4401a344a2SDavid du Colombier aip->idoffset = 0;
4501a344a2SDavid du Colombier aip->idvec = 0;
4601a344a2SDavid du Colombier }
4701a344a2SDavid du Colombier
4801a344a2SDavid du Colombier static void
f_session(Chan * cp,Fcall * in,Fcall * ou)4901a344a2SDavid du Colombier f_session(Chan *cp, Fcall *in, Fcall *ou)
5001a344a2SDavid du Colombier {
5101a344a2SDavid du Colombier Authinfo *aip;
5201a344a2SDavid du Colombier
5301a344a2SDavid du Colombier aip = (Authinfo*)cp->authinfo;
5401a344a2SDavid du Colombier
5501a344a2SDavid du Colombier if(CHAT(cp))
5601a344a2SDavid du Colombier print("c_session %d\n", cp->chan);
5701a344a2SDavid du Colombier memmove(aip->rchal, in->chal, sizeof(aip->rchal));
5801a344a2SDavid du Colombier mkchallenge(aip);
5901a344a2SDavid du Colombier memmove(ou->chal, aip->chal, sizeof(ou->chal));
6001a344a2SDavid du Colombier if(noauth || wstatallow)
6101a344a2SDavid du Colombier memset(ou->authid, 0, sizeof(ou->authid));
6201a344a2SDavid du Colombier else
6301a344a2SDavid du Colombier memmove(ou->authid, nvr.authid, sizeof(ou->authid));
6401a344a2SDavid du Colombier
6501a344a2SDavid du Colombier sprint(ou->authdom, "%s.%s", service, nvr.authdom);
6601a344a2SDavid du Colombier fileinit(cp);
6701a344a2SDavid du Colombier }
6801a344a2SDavid du Colombier
6901a344a2SDavid du Colombier /*
7001a344a2SDavid du Colombier * match a challenge from an attach
7101a344a2SDavid du Colombier */
7201a344a2SDavid du Colombier static int
authorize(Chan * cp,Fcall * in,Fcall * ou)7301a344a2SDavid du Colombier authorize(Chan *cp, Fcall *in, Fcall *ou)
7401a344a2SDavid du Colombier {
7501a344a2SDavid du Colombier Ticket t;
7601a344a2SDavid du Colombier Authenticator a;
7701a344a2SDavid du Colombier int x;
7801a344a2SDavid du Colombier ulong bit;
7901a344a2SDavid du Colombier Authinfo *aip;
8001a344a2SDavid du Colombier
8101a344a2SDavid du Colombier if(noauth || wstatallow) /* set to allow entry during boot */
8201a344a2SDavid du Colombier return 1;
8301a344a2SDavid du Colombier
8401a344a2SDavid du Colombier if(strcmp(in->uname, "none") == 0)
8501a344a2SDavid du Colombier return 1;
8601a344a2SDavid du Colombier
8701a344a2SDavid du Colombier if(in->type == Toattach)
8801a344a2SDavid du Colombier return 0;
8901a344a2SDavid du Colombier
9001a344a2SDavid du Colombier /* decrypt and unpack ticket */
9101a344a2SDavid du Colombier convM2T9p1(in->ticket, &t, nvr.machkey);
9201a344a2SDavid du Colombier if(t.num != AuthTs){
9301a344a2SDavid du Colombier print("9p1: bad AuthTs num\n");
9401a344a2SDavid du Colombier return 0;
9501a344a2SDavid du Colombier }
9601a344a2SDavid du Colombier
9701a344a2SDavid du Colombier /* decrypt and unpack authenticator */
9801a344a2SDavid du Colombier convM2A9p1(in->auth, &a, t.key);
9901a344a2SDavid du Colombier if(a.num != AuthAc){
10001a344a2SDavid du Colombier print("9p1: bad AuthAc num\n");
10101a344a2SDavid du Colombier return 0;
10201a344a2SDavid du Colombier }
10301a344a2SDavid du Colombier
10401a344a2SDavid du Colombier /* challenges must match */
10501a344a2SDavid du Colombier aip = (Authinfo*)cp->authinfo;
10601a344a2SDavid du Colombier if(memcmp(a.chal, aip->chal, sizeof(a.chal)) != 0){
10701a344a2SDavid du Colombier print("9p1: bad challenge\n");
10801a344a2SDavid du Colombier return 0;
10901a344a2SDavid du Colombier }
11001a344a2SDavid du Colombier
11101a344a2SDavid du Colombier /*
11201a344a2SDavid du Colombier * the id must be in a valid range. the range is specified by a
11301a344a2SDavid du Colombier * lower bound (idoffset) and a bit vector (idvec) where a
11401a344a2SDavid du Colombier * bit set to 1 means unusable
11501a344a2SDavid du Colombier */
11601a344a2SDavid du Colombier lock(&aip->idlock);
11701a344a2SDavid du Colombier x = a.id - aip->idoffset;
11801a344a2SDavid du Colombier bit = 1<<x;
11901a344a2SDavid du Colombier if(x < 0 || x > 31 || (bit&aip->idvec)){
12001a344a2SDavid du Colombier unlock(&aip->idlock);
12101a344a2SDavid du Colombier print("9p1: id out of range: idoff %ld idvec %lux id %ld\n",
12201a344a2SDavid du Colombier aip->idoffset, aip->idvec, a.id);
12301a344a2SDavid du Colombier return 0;
12401a344a2SDavid du Colombier }
12501a344a2SDavid du Colombier aip->idvec |= bit;
12601a344a2SDavid du Colombier
12701a344a2SDavid du Colombier /* normalize the vector */
12801a344a2SDavid du Colombier while(aip->idvec&0xffff0001){
12901a344a2SDavid du Colombier aip->idvec >>= 1;
13001a344a2SDavid du Colombier aip->idoffset++;
13101a344a2SDavid du Colombier }
13201a344a2SDavid du Colombier unlock(&aip->idlock);
13301a344a2SDavid du Colombier
13401a344a2SDavid du Colombier /* ticket name and attach name must match */
13501a344a2SDavid du Colombier if(memcmp(in->uname, t.cuid, sizeof(in->uname)) != 0){
13601a344a2SDavid du Colombier print("9p1: names don't match\n");
13701a344a2SDavid du Colombier return 0;
13801a344a2SDavid du Colombier }
13901a344a2SDavid du Colombier
14001a344a2SDavid du Colombier /* copy translated name into input record */
14101a344a2SDavid du Colombier memmove(in->uname, t.suid, sizeof(in->uname));
14201a344a2SDavid du Colombier
14301a344a2SDavid du Colombier /* craft a reply */
14401a344a2SDavid du Colombier a.num = AuthAs;
14501a344a2SDavid du Colombier memmove(a.chal, aip->rchal, CHALLEN);
14601a344a2SDavid du Colombier convA2M9p1(&a, ou->rauth, t.key);
14701a344a2SDavid du Colombier
14801a344a2SDavid du Colombier return 1;
14901a344a2SDavid du Colombier }
15001a344a2SDavid du Colombier
15101a344a2SDavid du Colombier /*
15201a344a2SDavid du Colombier * buggery to give false qid for
15301a344a2SDavid du Colombier * the top 2 levels of the dump fs
15401a344a2SDavid du Colombier */
15501a344a2SDavid du Colombier void
mkqid(Qid * qid,Dentry * d,int buggery)15601a344a2SDavid du Colombier mkqid(Qid* qid, Dentry *d, int buggery)
15701a344a2SDavid du Colombier {
15801a344a2SDavid du Colombier int c;
15901a344a2SDavid du Colombier
16001a344a2SDavid du Colombier if(buggery && d->qid.path == (QPDIR|QPROOT)){
16101a344a2SDavid du Colombier c = d->name[0];
16201a344a2SDavid du Colombier if(isascii(c) && isdigit(c)){
16301a344a2SDavid du Colombier qid->path = 3;
16401a344a2SDavid du Colombier qid->vers = d->qid.version;
16501a344a2SDavid du Colombier qid->type = QTDIR;
16601a344a2SDavid du Colombier
16701a344a2SDavid du Colombier c = (c-'0')*10 + (d->name[1]-'0');
16801a344a2SDavid du Colombier if(c >= 1 && c <= 12)
16901a344a2SDavid du Colombier qid->path = 4;
17001a344a2SDavid du Colombier return;
17101a344a2SDavid du Colombier }
17201a344a2SDavid du Colombier }
17301a344a2SDavid du Colombier
17401a344a2SDavid du Colombier mkqid9p2(qid, &d->qid, d->mode);
17501a344a2SDavid du Colombier }
17601a344a2SDavid du Colombier
17701a344a2SDavid du Colombier int
mkqidcmp(Qid * qid,Dentry * d)17801a344a2SDavid du Colombier mkqidcmp(Qid* qid, Dentry *d)
17901a344a2SDavid du Colombier {
18001a344a2SDavid du Colombier Qid tmp;
18101a344a2SDavid du Colombier
18201a344a2SDavid du Colombier mkqid(&tmp, d, 1);
18301a344a2SDavid du Colombier if(qid->path == tmp.path && qid->type == tmp.type)
18401a344a2SDavid du Colombier return 0;
18501a344a2SDavid du Colombier return Eqid;
18601a344a2SDavid du Colombier }
18701a344a2SDavid du Colombier
18801a344a2SDavid du Colombier static void
f_attach(Chan * cp,Fcall * in,Fcall * ou)18901a344a2SDavid du Colombier f_attach(Chan *cp, Fcall *in, Fcall *ou)
19001a344a2SDavid du Colombier {
19101a344a2SDavid du Colombier Iobuf *p;
19201a344a2SDavid du Colombier Dentry *d;
19301a344a2SDavid du Colombier File *f;
19401a344a2SDavid du Colombier int u;
19501a344a2SDavid du Colombier Filsys *fs;
19601a344a2SDavid du Colombier Off raddr;
19701a344a2SDavid du Colombier
19801a344a2SDavid du Colombier if(CHAT(cp)) {
19901a344a2SDavid du Colombier print("c_attach %d\n", cp->chan);
20001a344a2SDavid du Colombier print("\tfid = %d\n", in->fid);
20101a344a2SDavid du Colombier print("\tuid = %s\n", in->uname);
20201a344a2SDavid du Colombier print("\targ = %s\n", in->aname);
20301a344a2SDavid du Colombier }
20401a344a2SDavid du Colombier
20501a344a2SDavid du Colombier ou->qid = QID9P1(0,0);
20601a344a2SDavid du Colombier ou->fid = in->fid;
20701a344a2SDavid du Colombier if(!in->aname[0]) /* default */
20801a344a2SDavid du Colombier strncpy(in->aname, "main", sizeof(in->aname));
20901a344a2SDavid du Colombier p = 0;
21001a344a2SDavid du Colombier f = filep(cp, in->fid, 1);
21101a344a2SDavid du Colombier if(!f) {
21201a344a2SDavid du Colombier ou->err = Efid;
21301a344a2SDavid du Colombier goto out;
21401a344a2SDavid du Colombier }
21501a344a2SDavid du Colombier
21601a344a2SDavid du Colombier u = -1;
21701a344a2SDavid du Colombier if(cp != cons.chan) {
21801a344a2SDavid du Colombier if(noattach && strcmp(in->uname, "none")) {
21901a344a2SDavid du Colombier ou->err = Enoattach;
22001a344a2SDavid du Colombier goto out;
22101a344a2SDavid du Colombier }
22201a344a2SDavid du Colombier if(authorize(cp, in, ou) == 0 || strcmp(in->uname, "adm") == 0) {
22301a344a2SDavid du Colombier ou->err = Eauth;
22401a344a2SDavid du Colombier goto out;
22501a344a2SDavid du Colombier }
22601a344a2SDavid du Colombier u = strtouid(in->uname);
22701a344a2SDavid du Colombier if(u < 0) {
22801a344a2SDavid du Colombier ou->err = Ebadu;
22901a344a2SDavid du Colombier goto out;
23001a344a2SDavid du Colombier }
23101a344a2SDavid du Colombier }
23201a344a2SDavid du Colombier f->uid = u;
23301a344a2SDavid du Colombier
23401a344a2SDavid du Colombier fs = fsstr(in->aname);
23501a344a2SDavid du Colombier if(fs == 0) {
23601a344a2SDavid du Colombier ou->err = Ebadspc;
23701a344a2SDavid du Colombier goto out;
23801a344a2SDavid du Colombier }
23901a344a2SDavid du Colombier raddr = getraddr(fs->dev);
24001a344a2SDavid du Colombier p = getbuf(fs->dev, raddr, Brd);
24101a344a2SDavid du Colombier d = getdir(p, 0);
24201a344a2SDavid du Colombier if(!d || checktag(p, Tdir, QPROOT) || !(d->mode & DALLOC)) {
24301a344a2SDavid du Colombier ou->err = Ealloc;
24401a344a2SDavid du Colombier goto out;
24501a344a2SDavid du Colombier }
24601a344a2SDavid du Colombier if (iaccess(f, d, DEXEC) ||
24701a344a2SDavid du Colombier f->uid == 0 && fs->dev->type == Devro) {
24801a344a2SDavid du Colombier /*
24901a344a2SDavid du Colombier * 'none' not allowed on dump
25001a344a2SDavid du Colombier */
25101a344a2SDavid du Colombier ou->err = Eaccess;
25201a344a2SDavid du Colombier goto out;
25301a344a2SDavid du Colombier }
25401a344a2SDavid du Colombier accessdir(p, d, FREAD, f->uid);
25501a344a2SDavid du Colombier mkqid(&f->qid, d, 1);
25601a344a2SDavid du Colombier f->fs = fs;
25701a344a2SDavid du Colombier f->addr = raddr;
25801a344a2SDavid du Colombier f->slot = 0;
25901a344a2SDavid du Colombier f->open = 0;
26001a344a2SDavid du Colombier freewp(f->wpath);
26101a344a2SDavid du Colombier f->wpath = 0;
26201a344a2SDavid du Colombier
26301a344a2SDavid du Colombier mkqid9p1(&ou->qid, &f->qid);
26401a344a2SDavid du Colombier
26501a344a2SDavid du Colombier strncpy(cp->whoname, in->uname, sizeof(cp->whoname));
26601a344a2SDavid du Colombier cp->whotime = time(nil);
26701a344a2SDavid du Colombier if(cons.flags & attachflag)
26801a344a2SDavid du Colombier print("9p1: attach %s %T to \"%s\" C%d\n",
26901a344a2SDavid du Colombier cp->whoname, cp->whotime, fs->name, cp->chan);
27001a344a2SDavid du Colombier
27101a344a2SDavid du Colombier out:
27201a344a2SDavid du Colombier if((cons.flags & attachflag) && ou->err)
27301a344a2SDavid du Colombier print("9p1: attach %s %T SUCK EGGS --- %s\n",
27401a344a2SDavid du Colombier in->uname, time(nil), errstr9p[ou->err]);
27501a344a2SDavid du Colombier if(p)
27601a344a2SDavid du Colombier putbuf(p);
27701a344a2SDavid du Colombier if(f) {
27801a344a2SDavid du Colombier qunlock(f);
27901a344a2SDavid du Colombier if(ou->err)
28001a344a2SDavid du Colombier freefp(f);
28101a344a2SDavid du Colombier }
28201a344a2SDavid du Colombier }
28301a344a2SDavid du Colombier
28401a344a2SDavid du Colombier static void
f_clone(Chan * cp,Fcall * in,Fcall * ou)28501a344a2SDavid du Colombier f_clone(Chan *cp, Fcall *in, Fcall *ou)
28601a344a2SDavid du Colombier {
28701a344a2SDavid du Colombier File *f1, *f2;
28801a344a2SDavid du Colombier Wpath *p;
28901a344a2SDavid du Colombier int fid, fid1;
29001a344a2SDavid du Colombier
29101a344a2SDavid du Colombier if(CHAT(cp)) {
29201a344a2SDavid du Colombier print("c_clone %d\n", cp->chan);
29301a344a2SDavid du Colombier print("\told fid = %d\n", in->fid);
29401a344a2SDavid du Colombier print("\tnew fid = %d\n", in->newfid);
29501a344a2SDavid du Colombier }
29601a344a2SDavid du Colombier
29701a344a2SDavid du Colombier fid = in->fid;
29801a344a2SDavid du Colombier fid1 = in->newfid;
29901a344a2SDavid du Colombier
30001a344a2SDavid du Colombier f1 = 0;
30101a344a2SDavid du Colombier f2 = 0;
30201a344a2SDavid du Colombier if(fid < fid1) {
30301a344a2SDavid du Colombier f1 = filep(cp, fid, 0);
30401a344a2SDavid du Colombier f2 = filep(cp, fid1, 1);
30501a344a2SDavid du Colombier } else
30601a344a2SDavid du Colombier if(fid1 < fid) {
30701a344a2SDavid du Colombier f2 = filep(cp, fid1, 1);
30801a344a2SDavid du Colombier f1 = filep(cp, fid, 0);
30901a344a2SDavid du Colombier }
31001a344a2SDavid du Colombier if(!f1 || !f2) {
31101a344a2SDavid du Colombier ou->err = Efid;
31201a344a2SDavid du Colombier goto out;
31301a344a2SDavid du Colombier }
31401a344a2SDavid du Colombier
31501a344a2SDavid du Colombier
31601a344a2SDavid du Colombier f2->fs = f1->fs;
31701a344a2SDavid du Colombier f2->addr = f1->addr;
31801a344a2SDavid du Colombier f2->open = f1->open & ~FREMOV;
31901a344a2SDavid du Colombier f2->uid = f1->uid;
32001a344a2SDavid du Colombier f2->slot = f1->slot;
32101a344a2SDavid du Colombier f2->qid = f1->qid;
32201a344a2SDavid du Colombier
32301a344a2SDavid du Colombier freewp(f2->wpath);
32401a344a2SDavid du Colombier lock(&wpathlock);
32501a344a2SDavid du Colombier f2->wpath = f1->wpath;
32601a344a2SDavid du Colombier for(p = f2->wpath; p; p = p->up)
32701a344a2SDavid du Colombier p->refs++;
32801a344a2SDavid du Colombier unlock(&wpathlock);
32901a344a2SDavid du Colombier
33001a344a2SDavid du Colombier out:
33101a344a2SDavid du Colombier ou->fid = fid;
33201a344a2SDavid du Colombier if(f1)
33301a344a2SDavid du Colombier qunlock(f1);
33401a344a2SDavid du Colombier if(f2) {
33501a344a2SDavid du Colombier qunlock(f2);
33601a344a2SDavid du Colombier if(ou->err)
33701a344a2SDavid du Colombier freefp(f2);
33801a344a2SDavid du Colombier }
33901a344a2SDavid du Colombier }
34001a344a2SDavid du Colombier
34101a344a2SDavid du Colombier static void
f_walk(Chan * cp,Fcall * in,Fcall * ou)34201a344a2SDavid du Colombier f_walk(Chan *cp, Fcall *in, Fcall *ou)
34301a344a2SDavid du Colombier {
34401a344a2SDavid du Colombier Iobuf *p, *p1;
34501a344a2SDavid du Colombier Dentry *d, *d1;
34601a344a2SDavid du Colombier File *f;
34701a344a2SDavid du Colombier Wpath *w;
34801a344a2SDavid du Colombier int slot;
34901a344a2SDavid du Colombier Off addr, qpath;
35001a344a2SDavid du Colombier
35101a344a2SDavid du Colombier if(CHAT(cp)) {
35201a344a2SDavid du Colombier print("c_walk %d\n", cp->chan);
35301a344a2SDavid du Colombier print("\tfid = %d\n", in->fid);
35401a344a2SDavid du Colombier print("\tname = %s\n", in->name);
35501a344a2SDavid du Colombier }
35601a344a2SDavid du Colombier
35701a344a2SDavid du Colombier ou->fid = in->fid;
35801a344a2SDavid du Colombier ou->qid = QID9P1(0,0);
35901a344a2SDavid du Colombier p = 0;
36001a344a2SDavid du Colombier f = filep(cp, in->fid, 0);
36101a344a2SDavid du Colombier if(!f) {
36201a344a2SDavid du Colombier ou->err = Efid;
36301a344a2SDavid du Colombier goto out;
36401a344a2SDavid du Colombier }
36501a344a2SDavid du Colombier p = getbuf(f->fs->dev, f->addr, Brd);
36601a344a2SDavid du Colombier d = getdir(p, f->slot);
36701a344a2SDavid du Colombier if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
36801a344a2SDavid du Colombier ou->err = Ealloc;
36901a344a2SDavid du Colombier goto out;
37001a344a2SDavid du Colombier }
37101a344a2SDavid du Colombier if(!(d->mode & DDIR)) {
37201a344a2SDavid du Colombier ou->err = Edir1;
37301a344a2SDavid du Colombier goto out;
37401a344a2SDavid du Colombier }
37501a344a2SDavid du Colombier if(ou->err = mkqidcmp(&f->qid, d))
37601a344a2SDavid du Colombier goto out;
37701a344a2SDavid du Colombier if(cp != cons.chan && iaccess(f, d, DEXEC)) {
37801a344a2SDavid du Colombier ou->err = Eaccess;
37901a344a2SDavid du Colombier goto out;
38001a344a2SDavid du Colombier }
38101a344a2SDavid du Colombier accessdir(p, d, FREAD, f->uid);
38201a344a2SDavid du Colombier if(strcmp(in->name, ".") == 0)
38301a344a2SDavid du Colombier goto setdot;
38401a344a2SDavid du Colombier if(strcmp(in->name, "..") == 0) {
38501a344a2SDavid du Colombier if(f->wpath == 0)
38601a344a2SDavid du Colombier goto setdot;
38701a344a2SDavid du Colombier putbuf(p);
38801a344a2SDavid du Colombier p = 0;
38901a344a2SDavid du Colombier addr = f->wpath->addr;
39001a344a2SDavid du Colombier slot = f->wpath->slot;
39101a344a2SDavid du Colombier p1 = getbuf(f->fs->dev, addr, Brd);
39201a344a2SDavid du Colombier d1 = getdir(p1, slot);
39301a344a2SDavid du Colombier if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
39401a344a2SDavid du Colombier if(p1)
39501a344a2SDavid du Colombier putbuf(p1);
39601a344a2SDavid du Colombier ou->err = Ephase;
39701a344a2SDavid du Colombier goto out;
39801a344a2SDavid du Colombier }
39901a344a2SDavid du Colombier lock(&wpathlock);
40001a344a2SDavid du Colombier f->wpath->refs--;
40101a344a2SDavid du Colombier f->wpath = f->wpath->up;
40201a344a2SDavid du Colombier unlock(&wpathlock);
40301a344a2SDavid du Colombier goto found;
40401a344a2SDavid du Colombier }
40501a344a2SDavid du Colombier for(addr=0;; addr++) {
40601a344a2SDavid du Colombier if(p == 0) {
40701a344a2SDavid du Colombier p = getbuf(f->fs->dev, f->addr, Brd);
40801a344a2SDavid du Colombier d = getdir(p, f->slot);
40901a344a2SDavid du Colombier if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
41001a344a2SDavid du Colombier ou->err = Ealloc;
41101a344a2SDavid du Colombier goto out;
41201a344a2SDavid du Colombier }
41301a344a2SDavid du Colombier }
41401a344a2SDavid du Colombier qpath = d->qid.path;
41501a344a2SDavid du Colombier p1 = dnodebuf1(p, d, addr, 0, f->uid);
41601a344a2SDavid du Colombier p = 0;
41701a344a2SDavid du Colombier if(!p1 || checktag(p1, Tdir, qpath) ) {
41801a344a2SDavid du Colombier if(p1)
41901a344a2SDavid du Colombier putbuf(p1);
42001a344a2SDavid du Colombier ou->err = Eentry;
42101a344a2SDavid du Colombier goto out;
42201a344a2SDavid du Colombier }
42301a344a2SDavid du Colombier for(slot=0; slot<DIRPERBUF; slot++) {
42401a344a2SDavid du Colombier d1 = getdir(p1, slot);
42501a344a2SDavid du Colombier if(!(d1->mode & DALLOC))
42601a344a2SDavid du Colombier continue;
42701a344a2SDavid du Colombier if(strncmp(in->name, d1->name, sizeof(in->name)) != 0)
42801a344a2SDavid du Colombier continue;
42901a344a2SDavid du Colombier /*
43001a344a2SDavid du Colombier * update walk path
43101a344a2SDavid du Colombier */
43201a344a2SDavid du Colombier w = newwp();
43301a344a2SDavid du Colombier if(!w) {
43401a344a2SDavid du Colombier ou->err = Ewalk;
43501a344a2SDavid du Colombier putbuf(p1);
43601a344a2SDavid du Colombier goto out;
43701a344a2SDavid du Colombier }
43801a344a2SDavid du Colombier w->addr = f->addr;
43901a344a2SDavid du Colombier w->slot = f->slot;
44001a344a2SDavid du Colombier w->up = f->wpath;
44101a344a2SDavid du Colombier f->wpath = w;
44201a344a2SDavid du Colombier slot += DIRPERBUF*addr;
44301a344a2SDavid du Colombier goto found;
44401a344a2SDavid du Colombier }
44501a344a2SDavid du Colombier putbuf(p1);
44601a344a2SDavid du Colombier }
44701a344a2SDavid du Colombier
44801a344a2SDavid du Colombier found:
44901a344a2SDavid du Colombier f->addr = p1->addr;
45001a344a2SDavid du Colombier mkqid(&f->qid, d1, 1);
45101a344a2SDavid du Colombier putbuf(p1);
45201a344a2SDavid du Colombier f->slot = slot;
45301a344a2SDavid du Colombier
45401a344a2SDavid du Colombier setdot:
45501a344a2SDavid du Colombier mkqid9p1(&ou->qid, &f->qid);
45601a344a2SDavid du Colombier f->open = 0;
45701a344a2SDavid du Colombier
45801a344a2SDavid du Colombier out:
45901a344a2SDavid du Colombier if(p)
46001a344a2SDavid du Colombier putbuf(p);
46101a344a2SDavid du Colombier if(f)
46201a344a2SDavid du Colombier qunlock(f);
46301a344a2SDavid du Colombier }
46401a344a2SDavid du Colombier
46501a344a2SDavid du Colombier static void
f_open(Chan * cp,Fcall * in,Fcall * ou)46601a344a2SDavid du Colombier f_open(Chan *cp, Fcall *in, Fcall *ou)
46701a344a2SDavid du Colombier {
46801a344a2SDavid du Colombier Iobuf *p;
46901a344a2SDavid du Colombier Dentry *d;
47001a344a2SDavid du Colombier File *f;
47101a344a2SDavid du Colombier Tlock *t;
47201a344a2SDavid du Colombier Qid qid;
47301a344a2SDavid du Colombier int ro, fmod, wok;
47401a344a2SDavid du Colombier
47501a344a2SDavid du Colombier if(CHAT(cp)) {
47601a344a2SDavid du Colombier print("c_open %d\n", cp->chan);
47701a344a2SDavid du Colombier print("\tfid = %d\n", in->fid);
47801a344a2SDavid du Colombier print("\tmode = %o\n", in->mode);
47901a344a2SDavid du Colombier }
48001a344a2SDavid du Colombier
48101a344a2SDavid du Colombier wok = 0;
48201a344a2SDavid du Colombier if(cp == cons.chan || writeallow)
48301a344a2SDavid du Colombier wok = 1;
48401a344a2SDavid du Colombier
48501a344a2SDavid du Colombier p = 0;
48601a344a2SDavid du Colombier f = filep(cp, in->fid, 0);
48701a344a2SDavid du Colombier if(!f) {
48801a344a2SDavid du Colombier ou->err = Efid;
48901a344a2SDavid du Colombier goto out;
49001a344a2SDavid du Colombier }
49101a344a2SDavid du Colombier
49201a344a2SDavid du Colombier /*
49301a344a2SDavid du Colombier * if remove on close, check access here
49401a344a2SDavid du Colombier */
49501a344a2SDavid du Colombier ro = f->fs->dev->type == Devro;
49601a344a2SDavid du Colombier if(in->mode & ORCLOSE) {
49701a344a2SDavid du Colombier if(ro) {
49801a344a2SDavid du Colombier ou->err = Eronly;
49901a344a2SDavid du Colombier goto out;
50001a344a2SDavid du Colombier }
50101a344a2SDavid du Colombier /*
50201a344a2SDavid du Colombier * check on parent directory of file to be deleted
50301a344a2SDavid du Colombier */
50401a344a2SDavid du Colombier if(f->wpath == 0 || f->wpath->addr == f->addr) {
50501a344a2SDavid du Colombier ou->err = Ephase;
50601a344a2SDavid du Colombier goto out;
50701a344a2SDavid du Colombier }
50801a344a2SDavid du Colombier p = getbuf(f->fs->dev, f->wpath->addr, Brd);
50901a344a2SDavid du Colombier d = getdir(p, f->wpath->slot);
51001a344a2SDavid du Colombier if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
51101a344a2SDavid du Colombier ou->err = Ephase;
51201a344a2SDavid du Colombier goto out;
51301a344a2SDavid du Colombier }
51401a344a2SDavid du Colombier if(iaccess(f, d, DWRITE)) {
51501a344a2SDavid du Colombier ou->err = Eaccess;
51601a344a2SDavid du Colombier goto out;
51701a344a2SDavid du Colombier }
51801a344a2SDavid du Colombier putbuf(p);
51901a344a2SDavid du Colombier }
52001a344a2SDavid du Colombier p = getbuf(f->fs->dev, f->addr, Brd);
52101a344a2SDavid du Colombier d = getdir(p, f->slot);
52201a344a2SDavid du Colombier if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
52301a344a2SDavid du Colombier ou->err = Ealloc;
52401a344a2SDavid du Colombier goto out;
52501a344a2SDavid du Colombier }
52601a344a2SDavid du Colombier if(ou->err = mkqidcmp(&f->qid, d))
52701a344a2SDavid du Colombier goto out;
52801a344a2SDavid du Colombier mkqid(&qid, d, 1);
52901a344a2SDavid du Colombier switch(in->mode & 7) {
53001a344a2SDavid du Colombier
53101a344a2SDavid du Colombier case OREAD:
53201a344a2SDavid du Colombier if(iaccess(f, d, DREAD) && !wok)
53301a344a2SDavid du Colombier goto badaccess;
53401a344a2SDavid du Colombier fmod = FREAD;
53501a344a2SDavid du Colombier break;
53601a344a2SDavid du Colombier
53701a344a2SDavid du Colombier case OWRITE:
53801a344a2SDavid du Colombier if((d->mode & DDIR) ||
53901a344a2SDavid du Colombier (iaccess(f, d, DWRITE) && !wok))
54001a344a2SDavid du Colombier goto badaccess;
54101a344a2SDavid du Colombier if(ro) {
54201a344a2SDavid du Colombier ou->err = Eronly;
54301a344a2SDavid du Colombier goto out;
54401a344a2SDavid du Colombier }
54501a344a2SDavid du Colombier fmod = FWRITE;
54601a344a2SDavid du Colombier break;
54701a344a2SDavid du Colombier
54801a344a2SDavid du Colombier case ORDWR:
54901a344a2SDavid du Colombier if((d->mode & DDIR) ||
55001a344a2SDavid du Colombier (iaccess(f, d, DREAD) && !wok) ||
55101a344a2SDavid du Colombier (iaccess(f, d, DWRITE) && !wok))
55201a344a2SDavid du Colombier goto badaccess;
55301a344a2SDavid du Colombier if(ro) {
55401a344a2SDavid du Colombier ou->err = Eronly;
55501a344a2SDavid du Colombier goto out;
55601a344a2SDavid du Colombier }
55701a344a2SDavid du Colombier fmod = FREAD+FWRITE;
55801a344a2SDavid du Colombier break;
55901a344a2SDavid du Colombier
56001a344a2SDavid du Colombier case OEXEC:
56101a344a2SDavid du Colombier if((d->mode & DDIR) ||
56201a344a2SDavid du Colombier (iaccess(f, d, DEXEC) && !wok))
56301a344a2SDavid du Colombier goto badaccess;
56401a344a2SDavid du Colombier fmod = FREAD;
56501a344a2SDavid du Colombier break;
56601a344a2SDavid du Colombier
56701a344a2SDavid du Colombier default:
56801a344a2SDavid du Colombier ou->err = Emode;
56901a344a2SDavid du Colombier goto out;
57001a344a2SDavid du Colombier }
57101a344a2SDavid du Colombier if(in->mode & OTRUNC) {
57201a344a2SDavid du Colombier if((d->mode & DDIR) ||
57301a344a2SDavid du Colombier (iaccess(f, d, DWRITE) && !wok))
57401a344a2SDavid du Colombier goto badaccess;
57501a344a2SDavid du Colombier if(ro) {
57601a344a2SDavid du Colombier ou->err = Eronly;
57701a344a2SDavid du Colombier goto out;
57801a344a2SDavid du Colombier }
57901a344a2SDavid du Colombier }
58001a344a2SDavid du Colombier t = 0;
58101a344a2SDavid du Colombier if(d->mode & DLOCK) {
58201a344a2SDavid du Colombier t = tlocked(p, d);
58301a344a2SDavid du Colombier if(t == nil) {
58401a344a2SDavid du Colombier ou->err = Elocked;
58501a344a2SDavid du Colombier goto out;
58601a344a2SDavid du Colombier }
58701a344a2SDavid du Colombier }
58801a344a2SDavid du Colombier if(in->mode & ORCLOSE)
58901a344a2SDavid du Colombier fmod |= FREMOV;
59001a344a2SDavid du Colombier f->open = fmod;
59101a344a2SDavid du Colombier if(in->mode & OTRUNC)
59201a344a2SDavid du Colombier if(!(d->mode & DAPND)) {
59301a344a2SDavid du Colombier dtrunc(p, d, f->uid);
59401a344a2SDavid du Colombier qid.vers = d->qid.version;
59501a344a2SDavid du Colombier }
59601a344a2SDavid du Colombier f->tlock = t;
59701a344a2SDavid du Colombier if(t)
59801a344a2SDavid du Colombier t->file = f;
59901a344a2SDavid du Colombier f->lastra = 1;
60001a344a2SDavid du Colombier mkqid9p1(&ou->qid, &qid);
60101a344a2SDavid du Colombier goto out;
60201a344a2SDavid du Colombier
60301a344a2SDavid du Colombier badaccess:
60401a344a2SDavid du Colombier ou->err = Eaccess;
60501a344a2SDavid du Colombier f->open = 0;
60601a344a2SDavid du Colombier
60701a344a2SDavid du Colombier out:
60801a344a2SDavid du Colombier if(p)
60901a344a2SDavid du Colombier putbuf(p);
61001a344a2SDavid du Colombier if(f)
61101a344a2SDavid du Colombier qunlock(f);
61201a344a2SDavid du Colombier ou->fid = in->fid;
61301a344a2SDavid du Colombier }
61401a344a2SDavid du Colombier
61501a344a2SDavid du Colombier static void
f_create(Chan * cp,Fcall * in,Fcall * ou)61601a344a2SDavid du Colombier f_create(Chan *cp, Fcall *in, Fcall *ou)
61701a344a2SDavid du Colombier {
61801a344a2SDavid du Colombier Iobuf *p, *p1;
61901a344a2SDavid du Colombier Dentry *d, *d1;
62001a344a2SDavid du Colombier File *f;
62101a344a2SDavid du Colombier int slot, slot1, fmod, wok;
62201a344a2SDavid du Colombier Off addr, addr1, path;
62301a344a2SDavid du Colombier Qid qid;
62401a344a2SDavid du Colombier Tlock *t;
62501a344a2SDavid du Colombier Wpath *w;
62601a344a2SDavid du Colombier
62701a344a2SDavid du Colombier if(CHAT(cp)) {
62801a344a2SDavid du Colombier print("c_create %d\n", cp->chan);
62901a344a2SDavid du Colombier print("\tfid = %d\n", in->fid);
63001a344a2SDavid du Colombier print("\tname = %s\n", in->name);
63101a344a2SDavid du Colombier print("\tperm = %lx+%lo\n", (in->perm>>28)&0xf,
63201a344a2SDavid du Colombier in->perm&0777);
63301a344a2SDavid du Colombier print("\tmode = %o\n", in->mode);
63401a344a2SDavid du Colombier }
63501a344a2SDavid du Colombier
63601a344a2SDavid du Colombier wok = 0;
63701a344a2SDavid du Colombier if(cp == cons.chan || writeallow)
63801a344a2SDavid du Colombier wok = 1;
63901a344a2SDavid du Colombier
64001a344a2SDavid du Colombier p = 0;
64101a344a2SDavid du Colombier f = filep(cp, in->fid, 0);
64201a344a2SDavid du Colombier if(!f) {
64301a344a2SDavid du Colombier ou->err = Efid;
64401a344a2SDavid du Colombier goto out;
64501a344a2SDavid du Colombier }
64601a344a2SDavid du Colombier if(f->fs->dev->type == Devro) {
64701a344a2SDavid du Colombier ou->err = Eronly;
64801a344a2SDavid du Colombier goto out;
64901a344a2SDavid du Colombier }
65001a344a2SDavid du Colombier
65101a344a2SDavid du Colombier p = getbuf(f->fs->dev, f->addr, Brd);
65201a344a2SDavid du Colombier d = getdir(p, f->slot);
65301a344a2SDavid du Colombier if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
65401a344a2SDavid du Colombier ou->err = Ealloc;
65501a344a2SDavid du Colombier goto out;
65601a344a2SDavid du Colombier }
65701a344a2SDavid du Colombier if(ou->err = mkqidcmp(&f->qid, d))
65801a344a2SDavid du Colombier goto out;
65901a344a2SDavid du Colombier if(!(d->mode & DDIR)) {
66001a344a2SDavid du Colombier ou->err = Edir2;
66101a344a2SDavid du Colombier goto out;
66201a344a2SDavid du Colombier }
66301a344a2SDavid du Colombier if(iaccess(f, d, DWRITE) && !wok) {
66401a344a2SDavid du Colombier ou->err = Eaccess;
66501a344a2SDavid du Colombier goto out;
66601a344a2SDavid du Colombier }
66701a344a2SDavid du Colombier accessdir(p, d, FREAD, f->uid);
66801a344a2SDavid du Colombier if(!strncmp(in->name, ".", sizeof(in->name)) ||
66901a344a2SDavid du Colombier !strncmp(in->name, "..", sizeof(in->name))) {
67001a344a2SDavid du Colombier ou->err = Edot;
67101a344a2SDavid du Colombier goto out;
67201a344a2SDavid du Colombier }
67301a344a2SDavid du Colombier if(checkname(in->name)) {
67401a344a2SDavid du Colombier ou->err = Ename;
67501a344a2SDavid du Colombier goto out;
67601a344a2SDavid du Colombier }
67701a344a2SDavid du Colombier addr1 = 0;
67801a344a2SDavid du Colombier slot1 = 0; /* set */
67901a344a2SDavid du Colombier for(addr=0;; addr++) {
68001a344a2SDavid du Colombier p1 = dnodebuf(p, d, addr, 0, f->uid);
68101a344a2SDavid du Colombier if(!p1) {
68201a344a2SDavid du Colombier if(addr1)
68301a344a2SDavid du Colombier break;
68401a344a2SDavid du Colombier p1 = dnodebuf(p, d, addr, Tdir, f->uid);
68501a344a2SDavid du Colombier }
68601a344a2SDavid du Colombier if(p1 == 0) {
68701a344a2SDavid du Colombier ou->err = Efull;
68801a344a2SDavid du Colombier goto out;
68901a344a2SDavid du Colombier }
69001a344a2SDavid du Colombier if(checktag(p1, Tdir, d->qid.path)) {
69101a344a2SDavid du Colombier putbuf(p1);
69201a344a2SDavid du Colombier goto phase;
69301a344a2SDavid du Colombier }
69401a344a2SDavid du Colombier for(slot=0; slot<DIRPERBUF; slot++) {
69501a344a2SDavid du Colombier d1 = getdir(p1, slot);
69601a344a2SDavid du Colombier if(!(d1->mode & DALLOC)) {
69701a344a2SDavid du Colombier if(!addr1) {
69801a344a2SDavid du Colombier addr1 = p1->addr;
69901a344a2SDavid du Colombier slot1 = slot + addr*DIRPERBUF;
70001a344a2SDavid du Colombier }
70101a344a2SDavid du Colombier continue;
70201a344a2SDavid du Colombier }
70301a344a2SDavid du Colombier if(!strncmp(in->name, d1->name, sizeof(in->name))) {
70401a344a2SDavid du Colombier putbuf(p1);
70501a344a2SDavid du Colombier ou->err = Eexist;
70601a344a2SDavid du Colombier goto out;
70701a344a2SDavid du Colombier }
70801a344a2SDavid du Colombier }
70901a344a2SDavid du Colombier putbuf(p1);
71001a344a2SDavid du Colombier }
71101a344a2SDavid du Colombier switch(in->mode & 7) {
71201a344a2SDavid du Colombier case OEXEC:
71301a344a2SDavid du Colombier case OREAD: /* seems only useful to make directories */
71401a344a2SDavid du Colombier fmod = FREAD;
71501a344a2SDavid du Colombier break;
71601a344a2SDavid du Colombier
71701a344a2SDavid du Colombier case OWRITE:
71801a344a2SDavid du Colombier fmod = FWRITE;
71901a344a2SDavid du Colombier break;
72001a344a2SDavid du Colombier
72101a344a2SDavid du Colombier case ORDWR:
72201a344a2SDavid du Colombier fmod = FREAD+FWRITE;
72301a344a2SDavid du Colombier break;
72401a344a2SDavid du Colombier
72501a344a2SDavid du Colombier default:
72601a344a2SDavid du Colombier ou->err = Emode;
72701a344a2SDavid du Colombier goto out;
72801a344a2SDavid du Colombier }
72901a344a2SDavid du Colombier if(in->perm & PDIR)
73001a344a2SDavid du Colombier if((in->mode & OTRUNC) || (in->perm & PAPND) || (fmod & FWRITE))
73101a344a2SDavid du Colombier goto badaccess;
73201a344a2SDavid du Colombier /*
73301a344a2SDavid du Colombier * do it
73401a344a2SDavid du Colombier */
73501a344a2SDavid du Colombier path = qidpathgen(f->fs->dev);
73601a344a2SDavid du Colombier p1 = getbuf(f->fs->dev, addr1, Brd|Bimm|Bmod);
73701a344a2SDavid du Colombier d1 = getdir(p1, slot1);
73801a344a2SDavid du Colombier if(!d1 || checktag(p1, Tdir, d->qid.path)) {
73901a344a2SDavid du Colombier if(p1)
74001a344a2SDavid du Colombier putbuf(p1);
74101a344a2SDavid du Colombier goto phase;
74201a344a2SDavid du Colombier }
74301a344a2SDavid du Colombier if(d1->mode & DALLOC) {
74401a344a2SDavid du Colombier putbuf(p1);
74501a344a2SDavid du Colombier goto phase;
74601a344a2SDavid du Colombier }
74701a344a2SDavid du Colombier
74801a344a2SDavid du Colombier strncpy(d1->name, in->name, sizeof(in->name));
74901a344a2SDavid du Colombier if(cp == cons.chan) {
75001a344a2SDavid du Colombier d1->uid = cons.uid;
75101a344a2SDavid du Colombier d1->gid = cons.gid;
75201a344a2SDavid du Colombier } else {
75301a344a2SDavid du Colombier d1->uid = f->uid;
75401a344a2SDavid du Colombier d1->gid = d->gid;
75501a344a2SDavid du Colombier in->perm &= d->mode | ~0666;
75601a344a2SDavid du Colombier if(in->perm & PDIR)
75701a344a2SDavid du Colombier in->perm &= d->mode | ~0777;
75801a344a2SDavid du Colombier }
75901a344a2SDavid du Colombier d1->qid.path = path;
76001a344a2SDavid du Colombier d1->qid.version = 0;
76101a344a2SDavid du Colombier d1->mode = DALLOC | (in->perm & 0777);
76201a344a2SDavid du Colombier if(in->perm & PDIR) {
76301a344a2SDavid du Colombier d1->mode |= DDIR;
76401a344a2SDavid du Colombier d1->qid.path |= QPDIR;
76501a344a2SDavid du Colombier }
76601a344a2SDavid du Colombier if(in->perm & PAPND)
76701a344a2SDavid du Colombier d1->mode |= DAPND;
76801a344a2SDavid du Colombier t = 0;
76901a344a2SDavid du Colombier if(in->perm & PLOCK) {
77001a344a2SDavid du Colombier d1->mode |= DLOCK;
77101a344a2SDavid du Colombier t = tlocked(p1, d1);
77201a344a2SDavid du Colombier /* if nil, out of tlock structures */
77301a344a2SDavid du Colombier }
77401a344a2SDavid du Colombier accessdir(p1, d1, FWRITE, f->uid);
77501a344a2SDavid du Colombier mkqid(&qid, d1, 0);
77601a344a2SDavid du Colombier putbuf(p1);
77701a344a2SDavid du Colombier accessdir(p, d, FWRITE, f->uid);
77801a344a2SDavid du Colombier
77901a344a2SDavid du Colombier /*
78001a344a2SDavid du Colombier * do a walk to new directory entry
78101a344a2SDavid du Colombier */
78201a344a2SDavid du Colombier w = newwp();
78301a344a2SDavid du Colombier if(!w) {
78401a344a2SDavid du Colombier ou->err = Ewalk;
78501a344a2SDavid du Colombier goto out;
78601a344a2SDavid du Colombier }
78701a344a2SDavid du Colombier w->addr = f->addr;
78801a344a2SDavid du Colombier w->slot = f->slot;
78901a344a2SDavid du Colombier w->up = f->wpath;
79001a344a2SDavid du Colombier f->wpath = w;
79101a344a2SDavid du Colombier f->qid = qid;
79201a344a2SDavid du Colombier f->tlock = t;
79301a344a2SDavid du Colombier if(t)
79401a344a2SDavid du Colombier t->file = f;
79501a344a2SDavid du Colombier f->lastra = 1;
79601a344a2SDavid du Colombier if(in->mode & ORCLOSE)
79701a344a2SDavid du Colombier fmod |= FREMOV;
79801a344a2SDavid du Colombier f->open = fmod;
79901a344a2SDavid du Colombier f->addr = addr1;
80001a344a2SDavid du Colombier f->slot = slot1;
80101a344a2SDavid du Colombier mkqid9p1(&ou->qid, &qid);
80201a344a2SDavid du Colombier goto out;
80301a344a2SDavid du Colombier
80401a344a2SDavid du Colombier badaccess:
80501a344a2SDavid du Colombier ou->err = Eaccess;
80601a344a2SDavid du Colombier goto out;
80701a344a2SDavid du Colombier
80801a344a2SDavid du Colombier phase:
80901a344a2SDavid du Colombier ou->err = Ephase;
81001a344a2SDavid du Colombier
81101a344a2SDavid du Colombier out:
81201a344a2SDavid du Colombier if(p)
81301a344a2SDavid du Colombier putbuf(p);
81401a344a2SDavid du Colombier if(f)
81501a344a2SDavid du Colombier qunlock(f);
81601a344a2SDavid du Colombier ou->fid = in->fid;
81701a344a2SDavid du Colombier }
81801a344a2SDavid du Colombier
81901a344a2SDavid du Colombier static void
f_read(Chan * cp,Fcall * in,Fcall * ou)82001a344a2SDavid du Colombier f_read(Chan *cp, Fcall *in, Fcall *ou)
82101a344a2SDavid du Colombier {
82201a344a2SDavid du Colombier Iobuf *p, *p1;
82301a344a2SDavid du Colombier File *f;
82401a344a2SDavid du Colombier Dentry *d, *d1;
82501a344a2SDavid du Colombier Tlock *t;
82601a344a2SDavid du Colombier Off addr, offset;
82701a344a2SDavid du Colombier Timet tim;
82801a344a2SDavid du Colombier int nread, count, n, o, slot;
82901a344a2SDavid du Colombier
83001a344a2SDavid du Colombier if(CHAT(cp)) {
83101a344a2SDavid du Colombier print("c_read %d\n", cp->chan);
83201a344a2SDavid du Colombier print("\tfid = %d\n", in->fid);
83301a344a2SDavid du Colombier print("\toffset = %lld\n", (Wideoff)in->offset);
83401a344a2SDavid du Colombier print("\tcount = %ld\n", in->count);
83501a344a2SDavid du Colombier }
83601a344a2SDavid du Colombier
83701a344a2SDavid du Colombier p = 0;
83801a344a2SDavid du Colombier count = in->count;
83901a344a2SDavid du Colombier offset = in->offset;
84001a344a2SDavid du Colombier nread = 0;
84101a344a2SDavid du Colombier f = filep(cp, in->fid, 0);
84201a344a2SDavid du Colombier if(!f) {
84301a344a2SDavid du Colombier ou->err = Efid;
84401a344a2SDavid du Colombier goto out;
84501a344a2SDavid du Colombier }
84601a344a2SDavid du Colombier if(!(f->open & FREAD)) {
84701a344a2SDavid du Colombier ou->err = Eopen;
84801a344a2SDavid du Colombier goto out;
84901a344a2SDavid du Colombier }
85001a344a2SDavid du Colombier if(count < 0 || count > MAXDAT) {
85101a344a2SDavid du Colombier ou->err = Ecount;
85201a344a2SDavid du Colombier goto out;
85301a344a2SDavid du Colombier }
85401a344a2SDavid du Colombier if(offset < 0) {
85501a344a2SDavid du Colombier ou->err = Eoffset;
85601a344a2SDavid du Colombier goto out;
85701a344a2SDavid du Colombier }
85801a344a2SDavid du Colombier p = getbuf(f->fs->dev, f->addr, Brd);
85901a344a2SDavid du Colombier d = getdir(p, f->slot);
86001a344a2SDavid du Colombier if(!d || !(d->mode & DALLOC)) {
86101a344a2SDavid du Colombier ou->err = Ealloc;
86201a344a2SDavid du Colombier goto out;
86301a344a2SDavid du Colombier }
86401a344a2SDavid du Colombier if(ou->err = mkqidcmp(&f->qid, d))
86501a344a2SDavid du Colombier goto out;
86601a344a2SDavid du Colombier if(t = f->tlock) {
86701a344a2SDavid du Colombier tim = toytime();
86801a344a2SDavid du Colombier if(t->time < tim || t->file != f) {
86901a344a2SDavid du Colombier ou->err = Ebroken;
87001a344a2SDavid du Colombier goto out;
87101a344a2SDavid du Colombier }
87201a344a2SDavid du Colombier /* renew the lock */
87301a344a2SDavid du Colombier t->time = tim + TLOCK;
87401a344a2SDavid du Colombier }
87501a344a2SDavid du Colombier accessdir(p, d, FREAD, f->uid);
87601a344a2SDavid du Colombier if(d->mode & DDIR) {
87701a344a2SDavid du Colombier addr = 0;
87801a344a2SDavid du Colombier goto dread;
87901a344a2SDavid du Colombier }
88001a344a2SDavid du Colombier
88101a344a2SDavid du Colombier /* XXXX terrible hack to get at raw data XXXX */
88201a344a2SDavid du Colombier if(rawreadok && strncmp(d->name, "--raw--", 7) == 0) {
88301a344a2SDavid du Colombier Device *dev;
88401a344a2SDavid du Colombier Devsize boff, bsize;
88501a344a2SDavid du Colombier
88601a344a2SDavid du Colombier dev = p->dev;
88701a344a2SDavid du Colombier putbuf(p);
88801a344a2SDavid du Colombier p = 0;
88901a344a2SDavid du Colombier
89001a344a2SDavid du Colombier boff = number(d->name + 7, 0, 10) * 100000;
89101a344a2SDavid du Colombier if(boff < 0)
89201a344a2SDavid du Colombier boff = 0;
89301a344a2SDavid du Colombier if(boff > devsize(dev))
89401a344a2SDavid du Colombier boff = devsize(dev);
89501a344a2SDavid du Colombier bsize = devsize(dev) - boff;
89601a344a2SDavid du Colombier
89701a344a2SDavid du Colombier if(offset+count >= 100000*RBUFSIZE)
89801a344a2SDavid du Colombier count = 100000*RBUFSIZE - offset;
89901a344a2SDavid du Colombier
90001a344a2SDavid du Colombier if((offset+count)/RBUFSIZE >= bsize)
90101a344a2SDavid du Colombier /* will not overflow */
90201a344a2SDavid du Colombier count = bsize*RBUFSIZE - offset;
90301a344a2SDavid du Colombier
90401a344a2SDavid du Colombier while(count > 0) {
90501a344a2SDavid du Colombier addr = offset / RBUFSIZE;
90601a344a2SDavid du Colombier addr += boff;
90701a344a2SDavid du Colombier o = offset % RBUFSIZE;
90801a344a2SDavid du Colombier n = RBUFSIZE - o;
90901a344a2SDavid du Colombier if(n > count)
91001a344a2SDavid du Colombier n = count;
91101a344a2SDavid du Colombier
91201a344a2SDavid du Colombier p1 = getbuf(dev, addr, Brd);
91301a344a2SDavid du Colombier if(p1) {
91401a344a2SDavid du Colombier memmove(ou->data+nread, p1->iobuf+o, n);
91501a344a2SDavid du Colombier putbuf(p1);
91601a344a2SDavid du Colombier } else
91701a344a2SDavid du Colombier memset(ou->data+nread, 0, n);
91801a344a2SDavid du Colombier count -= n;
91901a344a2SDavid du Colombier nread += n;
92001a344a2SDavid du Colombier offset += n;
92101a344a2SDavid du Colombier }
92201a344a2SDavid du Colombier goto out;
92301a344a2SDavid du Colombier }
92401a344a2SDavid du Colombier
92501a344a2SDavid du Colombier if(offset+count > d->size)
92601a344a2SDavid du Colombier count = d->size - offset;
92701a344a2SDavid du Colombier while(count > 0) {
92801a344a2SDavid du Colombier if(p == 0) {
92901a344a2SDavid du Colombier p = getbuf(f->fs->dev, f->addr, Brd);
93001a344a2SDavid du Colombier d = getdir(p, f->slot);
93101a344a2SDavid du Colombier if(!d || !(d->mode & DALLOC)) {
93201a344a2SDavid du Colombier ou->err = Ealloc;
93301a344a2SDavid du Colombier goto out;
93401a344a2SDavid du Colombier }
93501a344a2SDavid du Colombier }
93601a344a2SDavid du Colombier addr = offset / BUFSIZE;
93701a344a2SDavid du Colombier f->lastra = dbufread(p, d, addr, f->lastra, f->uid);
93801a344a2SDavid du Colombier o = offset % BUFSIZE;
93901a344a2SDavid du Colombier n = BUFSIZE - o;
94001a344a2SDavid du Colombier if(n > count)
94101a344a2SDavid du Colombier n = count;
94201a344a2SDavid du Colombier p1 = dnodebuf1(p, d, addr, 0, f->uid);
94301a344a2SDavid du Colombier p = 0;
94401a344a2SDavid du Colombier if(p1) {
94501a344a2SDavid du Colombier if(checktag(p1, Tfile, QPNONE)) {
94601a344a2SDavid du Colombier ou->err = Ephase;
94701a344a2SDavid du Colombier putbuf(p1);
94801a344a2SDavid du Colombier goto out;
94901a344a2SDavid du Colombier }
95001a344a2SDavid du Colombier memmove(ou->data+nread, p1->iobuf+o, n);
95101a344a2SDavid du Colombier putbuf(p1);
95201a344a2SDavid du Colombier } else
95301a344a2SDavid du Colombier memset(ou->data+nread, 0, n);
95401a344a2SDavid du Colombier count -= n;
95501a344a2SDavid du Colombier nread += n;
95601a344a2SDavid du Colombier offset += n;
95701a344a2SDavid du Colombier }
95801a344a2SDavid du Colombier goto out;
95901a344a2SDavid du Colombier
96001a344a2SDavid du Colombier dread:
96101a344a2SDavid du Colombier for (;;) {
96201a344a2SDavid du Colombier if(p == 0) {
96301a344a2SDavid du Colombier p = getbuf(f->fs->dev, f->addr, Brd);
96401a344a2SDavid du Colombier d = getdir(p, f->slot);
96501a344a2SDavid du Colombier if(!d || !(d->mode & DALLOC)) {
96601a344a2SDavid du Colombier ou->err = Ealloc;
96701a344a2SDavid du Colombier goto out;
96801a344a2SDavid du Colombier }
96901a344a2SDavid du Colombier }
97001a344a2SDavid du Colombier p1 = dnodebuf1(p, d, addr, 0, f->uid);
97101a344a2SDavid du Colombier p = 0;
97201a344a2SDavid du Colombier if(!p1)
97301a344a2SDavid du Colombier goto out;
97401a344a2SDavid du Colombier if(checktag(p1, Tdir, QPNONE)) {
97501a344a2SDavid du Colombier ou->err = Ephase;
97601a344a2SDavid du Colombier putbuf(p1);
97701a344a2SDavid du Colombier goto out;
97801a344a2SDavid du Colombier }
97901a344a2SDavid du Colombier n = DIRREC;
98001a344a2SDavid du Colombier for(slot=0; slot<DIRPERBUF; slot++) {
98101a344a2SDavid du Colombier d1 = getdir(p1, slot);
98201a344a2SDavid du Colombier if(!(d1->mode & DALLOC))
98301a344a2SDavid du Colombier continue;
98401a344a2SDavid du Colombier if(offset >= n) {
98501a344a2SDavid du Colombier offset -= n;
98601a344a2SDavid du Colombier continue;
98701a344a2SDavid du Colombier }
98801a344a2SDavid du Colombier if(count < n) {
98901a344a2SDavid du Colombier putbuf(p1);
99001a344a2SDavid du Colombier goto out;
99101a344a2SDavid du Colombier }
99201a344a2SDavid du Colombier if(convD2M9p1(d1, ou->data+nread) != n)
99301a344a2SDavid du Colombier print("9p1: dirread convD2M1990\n");
99401a344a2SDavid du Colombier nread += n;
99501a344a2SDavid du Colombier count -= n;
99601a344a2SDavid du Colombier }
99701a344a2SDavid du Colombier putbuf(p1);
99801a344a2SDavid du Colombier addr++;
99901a344a2SDavid du Colombier }
100001a344a2SDavid du Colombier out:
100101a344a2SDavid du Colombier count = in->count - nread;
100201a344a2SDavid du Colombier if(count > 0)
100301a344a2SDavid du Colombier memset(ou->data+nread, 0, count);
100401a344a2SDavid du Colombier if(p)
100501a344a2SDavid du Colombier putbuf(p);
100601a344a2SDavid du Colombier if(f)
100701a344a2SDavid du Colombier qunlock(f);
100801a344a2SDavid du Colombier ou->fid = in->fid;
100901a344a2SDavid du Colombier ou->count = nread;
101001a344a2SDavid du Colombier if(CHAT(cp))
101101a344a2SDavid du Colombier print("\tnread = %d\n", nread);
101201a344a2SDavid du Colombier }
101301a344a2SDavid du Colombier
101401a344a2SDavid du Colombier static void
f_write(Chan * cp,Fcall * in,Fcall * ou)101501a344a2SDavid du Colombier f_write(Chan *cp, Fcall *in, Fcall *ou)
101601a344a2SDavid du Colombier {
101701a344a2SDavid du Colombier Iobuf *p, *p1;
101801a344a2SDavid du Colombier Dentry *d;
101901a344a2SDavid du Colombier File *f;
102001a344a2SDavid du Colombier Tlock *t;
102101a344a2SDavid du Colombier Off offset, addr, qpath;
102201a344a2SDavid du Colombier Timet tim;
102301a344a2SDavid du Colombier int count, nwrite, o, n;
102401a344a2SDavid du Colombier
102501a344a2SDavid du Colombier if(CHAT(cp)) {
102601a344a2SDavid du Colombier print("c_write %d\n", cp->chan);
102701a344a2SDavid du Colombier print("\tfid = %d\n", in->fid);
102801a344a2SDavid du Colombier print("\toffset = %lld\n", (Wideoff)in->offset);
102901a344a2SDavid du Colombier print("\tcount = %ld\n", in->count);
103001a344a2SDavid du Colombier }
103101a344a2SDavid du Colombier
103201a344a2SDavid du Colombier offset = in->offset;
103301a344a2SDavid du Colombier count = in->count;
103401a344a2SDavid du Colombier nwrite = 0;
103501a344a2SDavid du Colombier p = 0;
103601a344a2SDavid du Colombier f = filep(cp, in->fid, 0);
103701a344a2SDavid du Colombier if(!f) {
103801a344a2SDavid du Colombier ou->err = Efid;
103901a344a2SDavid du Colombier goto out;
104001a344a2SDavid du Colombier }
104101a344a2SDavid du Colombier if(!(f->open & FWRITE)) {
104201a344a2SDavid du Colombier ou->err = Eopen;
104301a344a2SDavid du Colombier goto out;
104401a344a2SDavid du Colombier }
104501a344a2SDavid du Colombier if(f->fs->dev->type == Devro) {
104601a344a2SDavid du Colombier ou->err = Eronly;
104701a344a2SDavid du Colombier goto out;
104801a344a2SDavid du Colombier }
104901a344a2SDavid du Colombier if(count < 0 || count > MAXDAT) {
105001a344a2SDavid du Colombier ou->err = Ecount;
105101a344a2SDavid du Colombier goto out;
105201a344a2SDavid du Colombier }
105301a344a2SDavid du Colombier if(offset < 0) {
105401a344a2SDavid du Colombier ou->err = Eoffset;
105501a344a2SDavid du Colombier goto out;
105601a344a2SDavid du Colombier }
105701a344a2SDavid du Colombier p = getbuf(f->fs->dev, f->addr, Brd|Bmod);
105801a344a2SDavid du Colombier d = getdir(p, f->slot);
105901a344a2SDavid du Colombier if(!d || !(d->mode & DALLOC)) {
106001a344a2SDavid du Colombier ou->err = Ealloc;
106101a344a2SDavid du Colombier goto out;
106201a344a2SDavid du Colombier }
106301a344a2SDavid du Colombier if(ou->err = mkqidcmp(&f->qid, d))
106401a344a2SDavid du Colombier goto out;
106501a344a2SDavid du Colombier if(t = f->tlock) {
106601a344a2SDavid du Colombier tim = toytime();
106701a344a2SDavid du Colombier if(t->time < tim || t->file != f) {
106801a344a2SDavid du Colombier ou->err = Ebroken;
106901a344a2SDavid du Colombier goto out;
107001a344a2SDavid du Colombier }
107101a344a2SDavid du Colombier /* renew the lock */
107201a344a2SDavid du Colombier t->time = tim + TLOCK;
107301a344a2SDavid du Colombier }
107401a344a2SDavid du Colombier accessdir(p, d, FWRITE, f->uid);
107501a344a2SDavid du Colombier if(d->mode & DAPND)
107601a344a2SDavid du Colombier offset = d->size;
107701a344a2SDavid du Colombier if(offset+count > d->size)
107801a344a2SDavid du Colombier d->size = offset+count;
107901a344a2SDavid du Colombier while(count > 0) {
108001a344a2SDavid du Colombier if(p == 0) {
108101a344a2SDavid du Colombier p = getbuf(f->fs->dev, f->addr, Brd|Bmod);
108201a344a2SDavid du Colombier d = getdir(p, f->slot);
108301a344a2SDavid du Colombier if(!d || !(d->mode & DALLOC)) {
108401a344a2SDavid du Colombier ou->err = Ealloc;
108501a344a2SDavid du Colombier goto out;
108601a344a2SDavid du Colombier }
108701a344a2SDavid du Colombier }
108801a344a2SDavid du Colombier addr = offset / BUFSIZE;
108901a344a2SDavid du Colombier o = offset % BUFSIZE;
109001a344a2SDavid du Colombier n = BUFSIZE - o;
109101a344a2SDavid du Colombier if(n > count)
109201a344a2SDavid du Colombier n = count;
109301a344a2SDavid du Colombier qpath = d->qid.path;
109401a344a2SDavid du Colombier p1 = dnodebuf1(p, d, addr, Tfile, f->uid);
109501a344a2SDavid du Colombier p = 0;
109601a344a2SDavid du Colombier if(p1 == 0) {
109701a344a2SDavid du Colombier ou->err = Efull;
109801a344a2SDavid du Colombier goto out;
109901a344a2SDavid du Colombier }
110001a344a2SDavid du Colombier if(checktag(p1, Tfile, qpath)) {
110101a344a2SDavid du Colombier putbuf(p1);
110201a344a2SDavid du Colombier ou->err = Ephase;
110301a344a2SDavid du Colombier goto out;
110401a344a2SDavid du Colombier }
110501a344a2SDavid du Colombier memmove(p1->iobuf+o, in->data+nwrite, n);
110601a344a2SDavid du Colombier p1->flags |= Bmod;
110701a344a2SDavid du Colombier putbuf(p1);
110801a344a2SDavid du Colombier count -= n;
110901a344a2SDavid du Colombier nwrite += n;
111001a344a2SDavid du Colombier offset += n;
111101a344a2SDavid du Colombier }
111201a344a2SDavid du Colombier if(CHAT(cp))
111301a344a2SDavid du Colombier print("\tnwrite = %d\n", nwrite);
111401a344a2SDavid du Colombier
111501a344a2SDavid du Colombier out:
111601a344a2SDavid du Colombier if(p)
111701a344a2SDavid du Colombier putbuf(p);
111801a344a2SDavid du Colombier if(f)
111901a344a2SDavid du Colombier qunlock(f);
112001a344a2SDavid du Colombier ou->fid = in->fid;
112101a344a2SDavid du Colombier ou->count = nwrite;
112201a344a2SDavid du Colombier }
112301a344a2SDavid du Colombier
112401a344a2SDavid du Colombier int
doremove(File * f,int wok)112501a344a2SDavid du Colombier doremove(File *f, int wok)
112601a344a2SDavid du Colombier {
112701a344a2SDavid du Colombier Iobuf *p, *p1;
112801a344a2SDavid du Colombier Dentry *d, *d1;
112901a344a2SDavid du Colombier Off addr;
113001a344a2SDavid du Colombier int slot, err;
113101a344a2SDavid du Colombier
113201a344a2SDavid du Colombier p = 0;
113301a344a2SDavid du Colombier p1 = 0;
113401a344a2SDavid du Colombier if(f->fs->dev->type == Devro) {
113501a344a2SDavid du Colombier err = Eronly;
113601a344a2SDavid du Colombier goto out;
113701a344a2SDavid du Colombier }
113801a344a2SDavid du Colombier /*
113901a344a2SDavid du Colombier * check on parent directory of file to be deleted
114001a344a2SDavid du Colombier */
114101a344a2SDavid du Colombier if(f->wpath == 0 || f->wpath->addr == f->addr) {
114201a344a2SDavid du Colombier err = Ephase;
114301a344a2SDavid du Colombier goto out;
114401a344a2SDavid du Colombier }
114501a344a2SDavid du Colombier p1 = getbuf(f->fs->dev, f->wpath->addr, Brd);
114601a344a2SDavid du Colombier d1 = getdir(p1, f->wpath->slot);
114701a344a2SDavid du Colombier if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
114801a344a2SDavid du Colombier err = Ephase;
114901a344a2SDavid du Colombier goto out;
115001a344a2SDavid du Colombier }
115101a344a2SDavid du Colombier if(iaccess(f, d1, DWRITE) && !wok) {
115201a344a2SDavid du Colombier err = Eaccess;
115301a344a2SDavid du Colombier goto out;
115401a344a2SDavid du Colombier }
115501a344a2SDavid du Colombier accessdir(p1, d1, FWRITE, f->uid);
115601a344a2SDavid du Colombier putbuf(p1);
115701a344a2SDavid du Colombier p1 = 0;
115801a344a2SDavid du Colombier
115901a344a2SDavid du Colombier /*
116001a344a2SDavid du Colombier * check on file to be deleted
116101a344a2SDavid du Colombier */
116201a344a2SDavid du Colombier p = getbuf(f->fs->dev, f->addr, Brd);
116301a344a2SDavid du Colombier d = getdir(p, f->slot);
116401a344a2SDavid du Colombier if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
116501a344a2SDavid du Colombier err = Ealloc;
116601a344a2SDavid du Colombier goto out;
116701a344a2SDavid du Colombier }
116801a344a2SDavid du Colombier if(err = mkqidcmp(&f->qid, d))
116901a344a2SDavid du Colombier goto out;
117001a344a2SDavid du Colombier
117101a344a2SDavid du Colombier /*
117201a344a2SDavid du Colombier * if deleting a directory, make sure it is empty
117301a344a2SDavid du Colombier */
117401a344a2SDavid du Colombier if((d->mode & DDIR))
117501a344a2SDavid du Colombier for(addr=0;; addr++) {
117601a344a2SDavid du Colombier p1 = dnodebuf(p, d, addr, 0, f->uid);
117701a344a2SDavid du Colombier if(!p1)
117801a344a2SDavid du Colombier break;
117901a344a2SDavid du Colombier if(checktag(p1, Tdir, d->qid.path)) {
118001a344a2SDavid du Colombier err = Ephase;
118101a344a2SDavid du Colombier goto out;
118201a344a2SDavid du Colombier }
118301a344a2SDavid du Colombier for(slot=0; slot<DIRPERBUF; slot++) {
118401a344a2SDavid du Colombier d1 = getdir(p1, slot);
118501a344a2SDavid du Colombier if(!(d1->mode & DALLOC))
118601a344a2SDavid du Colombier continue;
118701a344a2SDavid du Colombier err = Eempty;
118801a344a2SDavid du Colombier goto out;
118901a344a2SDavid du Colombier }
119001a344a2SDavid du Colombier putbuf(p1);
119101a344a2SDavid du Colombier }
119201a344a2SDavid du Colombier
119301a344a2SDavid du Colombier /*
119401a344a2SDavid du Colombier * do it
119501a344a2SDavid du Colombier */
119601a344a2SDavid du Colombier dtrunc(p, d, f->uid);
119701a344a2SDavid du Colombier memset(d, 0, sizeof(Dentry));
119801a344a2SDavid du Colombier settag(p, Tdir, QPNONE);
119901a344a2SDavid du Colombier
120001a344a2SDavid du Colombier out:
120101a344a2SDavid du Colombier if(p1)
120201a344a2SDavid du Colombier putbuf(p1);
120301a344a2SDavid du Colombier if(p)
120401a344a2SDavid du Colombier putbuf(p);
120501a344a2SDavid du Colombier return err;
120601a344a2SDavid du Colombier }
120701a344a2SDavid du Colombier
120801a344a2SDavid du Colombier static int
doclunk(File * f,int remove,int wok)120901a344a2SDavid du Colombier doclunk(File* f, int remove, int wok)
121001a344a2SDavid du Colombier {
121101a344a2SDavid du Colombier Tlock *t;
121201a344a2SDavid du Colombier int err;
121301a344a2SDavid du Colombier
121401a344a2SDavid du Colombier err = 0;
121501a344a2SDavid du Colombier if(t = f->tlock) {
121601a344a2SDavid du Colombier if(t->file == f)
121701a344a2SDavid du Colombier t->time = 0; /* free the lock */
121801a344a2SDavid du Colombier f->tlock = 0;
121901a344a2SDavid du Colombier }
122001a344a2SDavid du Colombier if(remove)
122101a344a2SDavid du Colombier err = doremove(f, wok);
122201a344a2SDavid du Colombier f->open = 0;
122301a344a2SDavid du Colombier freewp(f->wpath);
122401a344a2SDavid du Colombier freefp(f);
122501a344a2SDavid du Colombier
122601a344a2SDavid du Colombier return err;
122701a344a2SDavid du Colombier }
122801a344a2SDavid du Colombier
122901a344a2SDavid du Colombier static void
f_clunk(Chan * cp,Fcall * in,Fcall * ou)123001a344a2SDavid du Colombier f_clunk(Chan *cp, Fcall *in, Fcall *ou)
123101a344a2SDavid du Colombier {
123201a344a2SDavid du Colombier File *f;
123301a344a2SDavid du Colombier
123401a344a2SDavid du Colombier if(CHAT(cp)) {
123501a344a2SDavid du Colombier print("c_clunk %d\n", cp->chan);
123601a344a2SDavid du Colombier print("\tfid = %d\n", in->fid);
123701a344a2SDavid du Colombier }
123801a344a2SDavid du Colombier
123901a344a2SDavid du Colombier f = filep(cp, in->fid, 0);
124001a344a2SDavid du Colombier if(!f)
124101a344a2SDavid du Colombier ou->err = Efid;
124201a344a2SDavid du Colombier else {
124301a344a2SDavid du Colombier doclunk(f, f->open & FREMOV, 0);
124401a344a2SDavid du Colombier qunlock(f);
124501a344a2SDavid du Colombier }
124601a344a2SDavid du Colombier ou->fid = in->fid;
124701a344a2SDavid du Colombier }
124801a344a2SDavid du Colombier
124901a344a2SDavid du Colombier static void
f_remove(Chan * cp,Fcall * in,Fcall * ou)125001a344a2SDavid du Colombier f_remove(Chan *cp, Fcall *in, Fcall *ou)
125101a344a2SDavid du Colombier {
125201a344a2SDavid du Colombier File *f;
125301a344a2SDavid du Colombier
125401a344a2SDavid du Colombier if(CHAT(cp)) {
125501a344a2SDavid du Colombier print("c_remove %d\n", cp->chan);
125601a344a2SDavid du Colombier print("\tfid = %d\n", in->fid);
125701a344a2SDavid du Colombier }
125801a344a2SDavid du Colombier
125901a344a2SDavid du Colombier f = filep(cp, in->fid, 0);
126001a344a2SDavid du Colombier if(!f)
126101a344a2SDavid du Colombier ou->err = Efid;
126201a344a2SDavid du Colombier else {
126301a344a2SDavid du Colombier ou->err = doclunk(f, 1, cp==cons.chan);
126401a344a2SDavid du Colombier qunlock(f);
126501a344a2SDavid du Colombier }
126601a344a2SDavid du Colombier ou->fid = in->fid;
126701a344a2SDavid du Colombier }
126801a344a2SDavid du Colombier
126901a344a2SDavid du Colombier static void
f_stat(Chan * cp,Fcall * in,Fcall * ou)127001a344a2SDavid du Colombier f_stat(Chan *cp, Fcall *in, Fcall *ou)
127101a344a2SDavid du Colombier {
127201a344a2SDavid du Colombier Iobuf *p;
127301a344a2SDavid du Colombier Dentry *d;
127401a344a2SDavid du Colombier File *f;
127501a344a2SDavid du Colombier
127601a344a2SDavid du Colombier if(CHAT(cp)) {
127701a344a2SDavid du Colombier print("c_stat %d\n", cp->chan);
127801a344a2SDavid du Colombier print("\tfid = %d\n", in->fid);
127901a344a2SDavid du Colombier }
128001a344a2SDavid du Colombier
128101a344a2SDavid du Colombier p = 0;
128201a344a2SDavid du Colombier memset(ou->stat, 0, sizeof(ou->stat));
128301a344a2SDavid du Colombier f = filep(cp, in->fid, 0);
128401a344a2SDavid du Colombier if(!f) {
128501a344a2SDavid du Colombier ou->err = Efid;
128601a344a2SDavid du Colombier goto out;
128701a344a2SDavid du Colombier }
128801a344a2SDavid du Colombier p = getbuf(f->fs->dev, f->addr, Brd);
128901a344a2SDavid du Colombier d = getdir(p, f->slot);
129001a344a2SDavid du Colombier if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
129101a344a2SDavid du Colombier ou->err = Ealloc;
129201a344a2SDavid du Colombier goto out;
129301a344a2SDavid du Colombier }
129401a344a2SDavid du Colombier if(ou->err = mkqidcmp(&f->qid, d))
129501a344a2SDavid du Colombier goto out;
129601a344a2SDavid du Colombier if(d->qid.path == QPROOT) /* stat of root gives time */
129701a344a2SDavid du Colombier d->atime = time(nil);
129801a344a2SDavid du Colombier if(convD2M9p1(d, ou->stat) != DIRREC)
129901a344a2SDavid du Colombier print("9p1: stat convD2M\n");
130001a344a2SDavid du Colombier
130101a344a2SDavid du Colombier out:
130201a344a2SDavid du Colombier if(p)
130301a344a2SDavid du Colombier putbuf(p);
130401a344a2SDavid du Colombier if(f)
130501a344a2SDavid du Colombier qunlock(f);
130601a344a2SDavid du Colombier ou->fid = in->fid;
130701a344a2SDavid du Colombier }
130801a344a2SDavid du Colombier
130901a344a2SDavid du Colombier static void
f_wstat(Chan * cp,Fcall * in,Fcall * ou)131001a344a2SDavid du Colombier f_wstat(Chan *cp, Fcall *in, Fcall *ou)
131101a344a2SDavid du Colombier {
131201a344a2SDavid du Colombier Iobuf *p, *p1;
131301a344a2SDavid du Colombier Dentry *d, *d1, xd;
131401a344a2SDavid du Colombier File *f;
131501a344a2SDavid du Colombier int slot;
131601a344a2SDavid du Colombier Off addr;
131701a344a2SDavid du Colombier
131801a344a2SDavid du Colombier if(CHAT(cp)) {
131901a344a2SDavid du Colombier print("c_wstat %d\n", cp->chan);
132001a344a2SDavid du Colombier print("\tfid = %d\n", in->fid);
132101a344a2SDavid du Colombier }
132201a344a2SDavid du Colombier
132301a344a2SDavid du Colombier p = 0;
132401a344a2SDavid du Colombier p1 = 0;
132501a344a2SDavid du Colombier d1 = 0;
132601a344a2SDavid du Colombier f = filep(cp, in->fid, 0);
132701a344a2SDavid du Colombier if(!f) {
132801a344a2SDavid du Colombier ou->err = Efid;
132901a344a2SDavid du Colombier goto out;
133001a344a2SDavid du Colombier }
133101a344a2SDavid du Colombier if(f->fs->dev->type == Devro) {
133201a344a2SDavid du Colombier ou->err = Eronly;
133301a344a2SDavid du Colombier goto out;
133401a344a2SDavid du Colombier }
133501a344a2SDavid du Colombier
133601a344a2SDavid du Colombier /*
133701a344a2SDavid du Colombier * first get parent
133801a344a2SDavid du Colombier */
133901a344a2SDavid du Colombier if(f->wpath) {
134001a344a2SDavid du Colombier p1 = getbuf(f->fs->dev, f->wpath->addr, Brd);
134101a344a2SDavid du Colombier d1 = getdir(p1, f->wpath->slot);
134201a344a2SDavid du Colombier if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
134301a344a2SDavid du Colombier ou->err = Ephase;
134401a344a2SDavid du Colombier goto out;
134501a344a2SDavid du Colombier }
134601a344a2SDavid du Colombier }
134701a344a2SDavid du Colombier
134801a344a2SDavid du Colombier p = getbuf(f->fs->dev, f->addr, Brd);
134901a344a2SDavid du Colombier d = getdir(p, f->slot);
135001a344a2SDavid du Colombier if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
135101a344a2SDavid du Colombier ou->err = Ealloc;
135201a344a2SDavid du Colombier goto out;
135301a344a2SDavid du Colombier }
135401a344a2SDavid du Colombier if(ou->err = mkqidcmp(&f->qid, d))
135501a344a2SDavid du Colombier goto out;
135601a344a2SDavid du Colombier
135701a344a2SDavid du Colombier convM2D9p1(in->stat, &xd);
135801a344a2SDavid du Colombier if(CHAT(cp)) {
135901a344a2SDavid du Colombier print("\td.name = %s\n", xd.name);
136001a344a2SDavid du Colombier print("\td.uid = %d\n", xd.uid);
136101a344a2SDavid du Colombier print("\td.gid = %d\n", xd.gid);
136201a344a2SDavid du Colombier print("\td.mode = %o\n", xd.mode);
136301a344a2SDavid du Colombier }
136401a344a2SDavid du Colombier
136501a344a2SDavid du Colombier /*
136601a344a2SDavid du Colombier * if user none,
136701a344a2SDavid du Colombier * cant do anything
136801a344a2SDavid du Colombier */
136901a344a2SDavid du Colombier if(f->uid == 0) {
137001a344a2SDavid du Colombier ou->err = Eaccess;
137101a344a2SDavid du Colombier goto out;
137201a344a2SDavid du Colombier }
137301a344a2SDavid du Colombier
137401a344a2SDavid du Colombier /*
137501a344a2SDavid du Colombier * if chown,
137601a344a2SDavid du Colombier * must be god
137701a344a2SDavid du Colombier */
137801a344a2SDavid du Colombier if(xd.uid != d->uid && !wstatallow) { /* set to allow chown during boot */
137901a344a2SDavid du Colombier ou->err = Ewstatu;
138001a344a2SDavid du Colombier goto out;
138101a344a2SDavid du Colombier }
138201a344a2SDavid du Colombier
138301a344a2SDavid du Colombier /*
138401a344a2SDavid du Colombier * if chgroup,
138501a344a2SDavid du Colombier * must be either
138601a344a2SDavid du Colombier * a) owner and in new group
138701a344a2SDavid du Colombier * b) leader of both groups
138801a344a2SDavid du Colombier */
138901a344a2SDavid du Colombier if (xd.gid != d->gid &&
139001a344a2SDavid du Colombier (!wstatallow && !writeallow && /* set to allow chgrp during boot */
139101a344a2SDavid du Colombier (d->uid != f->uid || !ingroup(f->uid, xd.gid)) &&
139201a344a2SDavid du Colombier (!leadgroup(f->uid, xd.gid) || !leadgroup(f->uid, d->gid)))) {
139301a344a2SDavid du Colombier ou->err = Ewstatg;
139401a344a2SDavid du Colombier goto out;
139501a344a2SDavid du Colombier }
139601a344a2SDavid du Colombier
139701a344a2SDavid du Colombier /*
139801a344a2SDavid du Colombier * if rename,
139901a344a2SDavid du Colombier * must have write permission in parent
140001a344a2SDavid du Colombier */
140101a344a2SDavid du Colombier if (strncmp(d->name, xd.name, sizeof(d->name)) != 0) {
140201a344a2SDavid du Colombier if (checkname(xd.name) || !d1 ||
140301a344a2SDavid du Colombier strcmp(xd.name, ".") == 0 || strcmp(xd.name, "..") == 0) {
140401a344a2SDavid du Colombier ou->err = Ename;
140501a344a2SDavid du Colombier goto out;
140601a344a2SDavid du Colombier }
140701a344a2SDavid du Colombier
140801a344a2SDavid du Colombier /*
140901a344a2SDavid du Colombier * drop entry to prevent lock, then
141001a344a2SDavid du Colombier * check that destination name is unique,
141101a344a2SDavid du Colombier */
141201a344a2SDavid du Colombier putbuf(p);
141301a344a2SDavid du Colombier for(addr=0;; addr++) {
141401a344a2SDavid du Colombier p = dnodebuf(p1, d1, addr, 0, f->uid);
141501a344a2SDavid du Colombier if(!p)
141601a344a2SDavid du Colombier break;
141701a344a2SDavid du Colombier if(checktag(p, Tdir, d1->qid.path)) {
141801a344a2SDavid du Colombier putbuf(p);
141901a344a2SDavid du Colombier continue;
142001a344a2SDavid du Colombier }
142101a344a2SDavid du Colombier for(slot=0; slot<DIRPERBUF; slot++) {
142201a344a2SDavid du Colombier d = getdir(p, slot);
142301a344a2SDavid du Colombier if(!(d->mode & DALLOC))
142401a344a2SDavid du Colombier continue;
142501a344a2SDavid du Colombier if(!strncmp(xd.name, d->name, sizeof(xd.name))) {
142601a344a2SDavid du Colombier ou->err = Eexist;
142701a344a2SDavid du Colombier goto out;
142801a344a2SDavid du Colombier }
142901a344a2SDavid du Colombier }
143001a344a2SDavid du Colombier putbuf(p);
143101a344a2SDavid du Colombier }
143201a344a2SDavid du Colombier
143301a344a2SDavid du Colombier /*
143401a344a2SDavid du Colombier * reacquire entry
143501a344a2SDavid du Colombier */
143601a344a2SDavid du Colombier p = getbuf(f->fs->dev, f->addr, Brd);
143701a344a2SDavid du Colombier d = getdir(p, f->slot);
143801a344a2SDavid du Colombier if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
143901a344a2SDavid du Colombier ou->err = Ephase;
144001a344a2SDavid du Colombier goto out;
144101a344a2SDavid du Colombier }
144201a344a2SDavid du Colombier
144301a344a2SDavid du Colombier if (!wstatallow && !writeallow && /* set to allow rename during boot */
144401a344a2SDavid du Colombier (!d1 || iaccess(f, d1, DWRITE))) {
144501a344a2SDavid du Colombier ou->err = Eaccess;
144601a344a2SDavid du Colombier goto out;
144701a344a2SDavid du Colombier }
144801a344a2SDavid du Colombier }
144901a344a2SDavid du Colombier
145001a344a2SDavid du Colombier /*
145101a344a2SDavid du Colombier * if mode/time, either
145201a344a2SDavid du Colombier * a) owner
145301a344a2SDavid du Colombier * b) leader of either group
145401a344a2SDavid du Colombier */
145501a344a2SDavid du Colombier if (d->mtime != xd.mtime ||
145601a344a2SDavid du Colombier ((d->mode^xd.mode) & (DAPND|DLOCK|0777)))
145701a344a2SDavid du Colombier if (!wstatallow && /* set to allow chmod during boot */
145801a344a2SDavid du Colombier d->uid != f->uid &&
145901a344a2SDavid du Colombier !leadgroup(f->uid, xd.gid) &&
146001a344a2SDavid du Colombier !leadgroup(f->uid, d->gid)) {
146101a344a2SDavid du Colombier ou->err = Ewstatu;
146201a344a2SDavid du Colombier goto out;
146301a344a2SDavid du Colombier }
146401a344a2SDavid du Colombier d->mtime = xd.mtime;
146501a344a2SDavid du Colombier d->uid = xd.uid;
146601a344a2SDavid du Colombier d->gid = xd.gid;
146701a344a2SDavid du Colombier d->mode = (xd.mode & (DAPND|DLOCK|0777)) | (d->mode & (DALLOC|DDIR));
146801a344a2SDavid du Colombier
146901a344a2SDavid du Colombier strncpy(d->name, xd.name, sizeof(d->name));
147001a344a2SDavid du Colombier accessdir(p, d, FREAD, f->uid);
147101a344a2SDavid du Colombier
147201a344a2SDavid du Colombier out:
147301a344a2SDavid du Colombier if(p)
147401a344a2SDavid du Colombier putbuf(p);
147501a344a2SDavid du Colombier if(p1)
147601a344a2SDavid du Colombier putbuf(p1);
147701a344a2SDavid du Colombier if(f)
147801a344a2SDavid du Colombier qunlock(f);
147901a344a2SDavid du Colombier ou->fid = in->fid;
148001a344a2SDavid du Colombier }
148101a344a2SDavid du Colombier
148201a344a2SDavid du Colombier static void
f_clwalk(Chan * cp,Fcall * in,Fcall * ou)148301a344a2SDavid du Colombier f_clwalk(Chan *cp, Fcall *in, Fcall *ou)
148401a344a2SDavid du Colombier {
148501a344a2SDavid du Colombier int er, fid;
148601a344a2SDavid du Colombier
148701a344a2SDavid du Colombier if(CHAT(cp))
148801a344a2SDavid du Colombier print("c_clwalk macro\n");
148901a344a2SDavid du Colombier
149001a344a2SDavid du Colombier f_clone(cp, in, ou); /* sets tag, fid */
149101a344a2SDavid du Colombier if(ou->err)
149201a344a2SDavid du Colombier return;
149301a344a2SDavid du Colombier fid = in->fid;
149401a344a2SDavid du Colombier in->fid = in->newfid;
149501a344a2SDavid du Colombier f_walk(cp, in, ou); /* sets tag, fid, qid */
149601a344a2SDavid du Colombier er = ou->err;
149701a344a2SDavid du Colombier if(er == Eentry) {
149801a344a2SDavid du Colombier /*
149901a344a2SDavid du Colombier * if error is "no entry"
150001a344a2SDavid du Colombier * return non error and fid
150101a344a2SDavid du Colombier */
150201a344a2SDavid du Colombier ou->err = 0;
150301a344a2SDavid du Colombier f_clunk(cp, in, ou); /* sets tag, fid */
150401a344a2SDavid du Colombier ou->err = 0;
150501a344a2SDavid du Colombier ou->fid = fid;
150601a344a2SDavid du Colombier if(CHAT(cp))
150701a344a2SDavid du Colombier print("\terror: %s\n", errstr9p[er]);
150801a344a2SDavid du Colombier } else if(er) {
150901a344a2SDavid du Colombier /*
151001a344a2SDavid du Colombier * if any other error
151101a344a2SDavid du Colombier * return an error
151201a344a2SDavid du Colombier */
151301a344a2SDavid du Colombier ou->err = 0;
151401a344a2SDavid du Colombier f_clunk(cp, in, ou); /* sets tag, fid */
151501a344a2SDavid du Colombier ou->err = er;
151601a344a2SDavid du Colombier }
151701a344a2SDavid du Colombier /*
151801a344a2SDavid du Colombier * non error
151901a344a2SDavid du Colombier * return newfid
152001a344a2SDavid du Colombier */
152101a344a2SDavid du Colombier }
152201a344a2SDavid du Colombier
152301a344a2SDavid du Colombier void (*call9p1[MAXSYSCALL])(Chan*, Fcall*, Fcall*) =
152401a344a2SDavid du Colombier {
152501a344a2SDavid du Colombier [Tnop] f_nop,
152601a344a2SDavid du Colombier [Tosession] f_session,
152701a344a2SDavid du Colombier [Tsession] f_session,
152801a344a2SDavid du Colombier [Tflush] f_flush,
152901a344a2SDavid du Colombier [Toattach] f_attach,
153001a344a2SDavid du Colombier [Tattach] f_attach,
153101a344a2SDavid du Colombier [Tclone] f_clone,
153201a344a2SDavid du Colombier [Twalk] f_walk,
153301a344a2SDavid du Colombier [Topen] f_open,
153401a344a2SDavid du Colombier [Tcreate] f_create,
153501a344a2SDavid du Colombier [Tread] f_read,
153601a344a2SDavid du Colombier [Twrite] f_write,
153701a344a2SDavid du Colombier [Tclunk] f_clunk,
153801a344a2SDavid du Colombier [Tremove] f_remove,
153901a344a2SDavid du Colombier [Tstat] f_stat,
154001a344a2SDavid du Colombier [Twstat] f_wstat,
154101a344a2SDavid du Colombier [Tclwalk] f_clwalk,
154201a344a2SDavid du Colombier };
154301a344a2SDavid du Colombier
154401a344a2SDavid du Colombier int
error9p1(Chan * cp,Msgbuf * mb)154501a344a2SDavid du Colombier error9p1(Chan* cp, Msgbuf* mb)
154601a344a2SDavid du Colombier {
154701a344a2SDavid du Colombier Msgbuf *mb1;
154801a344a2SDavid du Colombier
154901a344a2SDavid du Colombier print("type=%d count=%d\n", mb->data[0], mb->count);
155001a344a2SDavid du Colombier print(" %.2x %.2x %.2x %.2x\n",
155101a344a2SDavid du Colombier mb->data[1]&0xff, mb->data[2]&0xff,
155201a344a2SDavid du Colombier mb->data[3]&0xff, mb->data[4]&0xff);
155301a344a2SDavid du Colombier print(" %.2x %.2x %.2x %.2x\n",
155401a344a2SDavid du Colombier mb->data[5]&0xff, mb->data[6]&0xff,
155501a344a2SDavid du Colombier mb->data[7]&0xff, mb->data[8]&0xff);
155601a344a2SDavid du Colombier print(" %.2x %.2x %.2x %.2x\n",
155701a344a2SDavid du Colombier mb->data[9]&0xff, mb->data[10]&0xff,
155801a344a2SDavid du Colombier mb->data[11]&0xff, mb->data[12]&0xff);
155901a344a2SDavid du Colombier
156001a344a2SDavid du Colombier mb1 = mballoc(3, cp, Mbreply4);
156101a344a2SDavid du Colombier mb1->data[0] = Rnop; /* your nop was ok */
156201a344a2SDavid du Colombier mb1->data[1] = ~0;
156301a344a2SDavid du Colombier mb1->data[2] = ~0;
156401a344a2SDavid du Colombier mb1->count = 3;
156501a344a2SDavid du Colombier mb1->param = mb->param;
156601a344a2SDavid du Colombier fs_send(cp->reply, mb1);
156701a344a2SDavid du Colombier
156801a344a2SDavid du Colombier return 1;
156901a344a2SDavid du Colombier }
157001a344a2SDavid du Colombier
157101a344a2SDavid du Colombier int
serve9p1(Msgbuf * mb)157201a344a2SDavid du Colombier serve9p1(Msgbuf* mb)
157301a344a2SDavid du Colombier {
157401a344a2SDavid du Colombier int t, n;
157501a344a2SDavid du Colombier Chan *cp;
157601a344a2SDavid du Colombier Msgbuf *mb1;
157701a344a2SDavid du Colombier Fcall fi, fo;
157801a344a2SDavid du Colombier
157901a344a2SDavid du Colombier assert(mb != nil);
158001a344a2SDavid du Colombier cp = mb->chan;
158101a344a2SDavid du Colombier assert(mb->data != nil);
158201a344a2SDavid du Colombier if(convM2S9p1(mb->data, &fi, mb->count) == 0){
158301a344a2SDavid du Colombier assert(cp != nil);
158401a344a2SDavid du Colombier if(cp->protocol == nil)
158501a344a2SDavid du Colombier return 0;
158601a344a2SDavid du Colombier print("9p1: bad M2S conversion\n");
158701a344a2SDavid du Colombier return error9p1(cp, mb);
158801a344a2SDavid du Colombier }
158901a344a2SDavid du Colombier
159001a344a2SDavid du Colombier t = fi.type;
159101a344a2SDavid du Colombier if(t < 0 || t >= MAXSYSCALL || (t&1) || !call9p1[t]) {
159201a344a2SDavid du Colombier print("9p1: bad message type\n");
159301a344a2SDavid du Colombier return error9p1(cp, mb);
159401a344a2SDavid du Colombier }
159501a344a2SDavid du Colombier
159601a344a2SDavid du Colombier /*
159701a344a2SDavid du Colombier * allocate reply message
159801a344a2SDavid du Colombier */
159901a344a2SDavid du Colombier if(t == Tread) {
160001a344a2SDavid du Colombier mb1 = mballoc(MAXMSG+MAXDAT, cp, Mbreply2);
160101a344a2SDavid du Colombier fo.data = (char*)(mb1->data + 8);
160201a344a2SDavid du Colombier } else
160301a344a2SDavid du Colombier mb1 = mballoc(MAXMSG, cp, Mbreply3);
160401a344a2SDavid du Colombier
160501a344a2SDavid du Colombier /*
160601a344a2SDavid du Colombier * call the file system
160701a344a2SDavid du Colombier */
160801a344a2SDavid du Colombier assert(cp != nil);
160901a344a2SDavid du Colombier fo.err = 0;
161001a344a2SDavid du Colombier
161101a344a2SDavid du Colombier (*call9p1[t])(cp, &fi, &fo);
161201a344a2SDavid du Colombier
161301a344a2SDavid du Colombier fo.type = t+1;
161401a344a2SDavid du Colombier fo.tag = fi.tag;
161501a344a2SDavid du Colombier
161601a344a2SDavid du Colombier if(fo.err) {
161701a344a2SDavid du Colombier if(cons.flags&errorflag)
161801a344a2SDavid du Colombier print("\ttype %d: error: %s\n", t, errstr9p[fo.err]);
161901a344a2SDavid du Colombier if(CHAT(cp))
162001a344a2SDavid du Colombier print("\terror: %s\n", errstr9p[fo.err]);
162101a344a2SDavid du Colombier fo.type = Rerror;
162201a344a2SDavid du Colombier strncpy(fo.ename, errstr9p[fo.err], sizeof(fo.ename));
162301a344a2SDavid du Colombier }
162401a344a2SDavid du Colombier
162501a344a2SDavid du Colombier n = convS2M9p1(&fo, mb1->data);
162601a344a2SDavid du Colombier if(n == 0) {
162701a344a2SDavid du Colombier print("9p1: bad S2M conversion\n");
162801a344a2SDavid du Colombier mbfree(mb1);
162901a344a2SDavid du Colombier return error9p1(cp, mb);
163001a344a2SDavid du Colombier }
163101a344a2SDavid du Colombier mb1->count = n;
163201a344a2SDavid du Colombier mb1->param = mb->param;
163301a344a2SDavid du Colombier fs_send(cp->reply, mb1);
163401a344a2SDavid du Colombier
163501a344a2SDavid du Colombier return 1;
163601a344a2SDavid du Colombier }
1637