19a747e4fSDavid du Colombier #include "all.h"
29a747e4fSDavid du Colombier
39a747e4fSDavid du Colombier #define MSIZE (MAXDAT+128)
49a747e4fSDavid du Colombier
59a747e4fSDavid du Colombier static void
seterror(Fcall * ou,int err)69a747e4fSDavid du Colombier seterror(Fcall *ou, int err)
79a747e4fSDavid du Colombier {
89a747e4fSDavid du Colombier
99a747e4fSDavid du Colombier if(0 <= err && err < MAXERR)
109a747e4fSDavid du Colombier ou->ename = errstring[err];
119a747e4fSDavid du Colombier else
129a747e4fSDavid du Colombier ou->ename = "unknown error";
139a747e4fSDavid du Colombier }
149a747e4fSDavid du Colombier
159a747e4fSDavid du Colombier static int
fsversion(Chan * chan,Fcall * f,Fcall * r)169a747e4fSDavid du Colombier fsversion(Chan* chan, Fcall* f, Fcall* r)
179a747e4fSDavid du Colombier {
189a747e4fSDavid du Colombier if(f->msize < MSIZE)
199a747e4fSDavid du Colombier r->msize = f->msize;
209a747e4fSDavid du Colombier else
219a747e4fSDavid du Colombier r->msize = MSIZE;
229a747e4fSDavid du Colombier /*
239a747e4fSDavid du Colombier * Should check the '.' stuff here.
249a747e4fSDavid du Colombier * What happens if Tversion has already been seen?
259a747e4fSDavid du Colombier */
269a747e4fSDavid du Colombier if(strcmp(f->version, VERSION9P) == 0){
279a747e4fSDavid du Colombier r->version = VERSION9P;
289a747e4fSDavid du Colombier chan->msize = r->msize;
299a747e4fSDavid du Colombier }else
309a747e4fSDavid du Colombier r->version = "unknown";
319a747e4fSDavid du Colombier
329a747e4fSDavid du Colombier fileinit(chan);
339a747e4fSDavid du Colombier return 0;
349a747e4fSDavid du Colombier }
359a747e4fSDavid du Colombier
36b7b24591SDavid du Colombier char *keyspec = "proto=p9any role=server";
37b7b24591SDavid du Colombier
389a747e4fSDavid du Colombier static int
fsauth(Chan * chan,Fcall * f,Fcall * r)399a747e4fSDavid du Colombier fsauth(Chan *chan, Fcall *f, Fcall *r)
409a747e4fSDavid du Colombier {
419a747e4fSDavid du Colombier int err, fd;
429a747e4fSDavid du Colombier char *aname;
439a747e4fSDavid du Colombier File *file;
44b7b24591SDavid du Colombier int afd;
45b7b24591SDavid du Colombier AuthRpc *rpc;
469a747e4fSDavid du Colombier
479a747e4fSDavid du Colombier err = 0;
489a747e4fSDavid du Colombier if(chan == cons.srvchan)
499a747e4fSDavid du Colombier return Eauthmsg;
509a747e4fSDavid du Colombier file = filep(chan, f->afid, 1);
519a747e4fSDavid du Colombier if(file == nil)
529a747e4fSDavid du Colombier return Efidinuse;
535d459b5aSDavid du Colombier
545d459b5aSDavid du Colombier /* forget any previous authentication */
555d459b5aSDavid du Colombier file->cuid = 0;
56b7b24591SDavid du Colombier
579a747e4fSDavid du Colombier if(access("/mnt/factotum", 0) < 0)
589a747e4fSDavid du Colombier if((fd = open("/srv/factotum", ORDWR)) >= 0)
599a747e4fSDavid du Colombier mount(fd, -1, "/mnt", MBEFORE, "");
60b7b24591SDavid du Colombier
61b7b24591SDavid du Colombier afd = open("/mnt/factotum/rpc", ORDWR);
62b7b24591SDavid du Colombier if(afd < 0){
639a747e4fSDavid du Colombier err = Esystem;
649a747e4fSDavid du Colombier goto out;
659a747e4fSDavid du Colombier }
66b7b24591SDavid du Colombier rpc = auth_allocrpc(afd);
67b7b24591SDavid du Colombier if(rpc == nil){
68b7b24591SDavid du Colombier close(afd);
69b7b24591SDavid du Colombier err = Esystem;
70b7b24591SDavid du Colombier goto out;
71b7b24591SDavid du Colombier }
72b7b24591SDavid du Colombier file->rpc = rpc;
73b7b24591SDavid du Colombier if(auth_rpc(rpc, "start", keyspec, strlen(keyspec)) != ARok){
74b7b24591SDavid du Colombier err = Esystem;
75b7b24591SDavid du Colombier goto out;
76b7b24591SDavid du Colombier }
77b7b24591SDavid du Colombier
789a747e4fSDavid du Colombier aname = f->aname;
799a747e4fSDavid du Colombier if(!aname[0])
809a747e4fSDavid du Colombier aname = "main";
819a747e4fSDavid du Colombier file->fs = fsstr(aname);
829a747e4fSDavid du Colombier if(file->fs == nil){
839a747e4fSDavid du Colombier err = Ebadspc;
849a747e4fSDavid du Colombier goto out;
859a747e4fSDavid du Colombier }
869a747e4fSDavid du Colombier file->uid = strtouid(f->uname);
879a747e4fSDavid du Colombier if(file->uid < 0){
889a747e4fSDavid du Colombier err = Ebadu;
899a747e4fSDavid du Colombier goto out;
909a747e4fSDavid du Colombier }
919a747e4fSDavid du Colombier file->qid.path = 0;
929a747e4fSDavid du Colombier file->qid.vers = 0;
939a747e4fSDavid du Colombier file->qid.type = QTAUTH;
949a747e4fSDavid du Colombier r->qid = file->qid;
959a747e4fSDavid du Colombier
969a747e4fSDavid du Colombier out:
979a747e4fSDavid du Colombier if(file != nil){
989a747e4fSDavid du Colombier qunlock(file);
999a747e4fSDavid du Colombier if(err != 0)
1009a747e4fSDavid du Colombier freefp(file);
1019a747e4fSDavid du Colombier }
1029a747e4fSDavid du Colombier return err;
1039a747e4fSDavid du Colombier }
1049a747e4fSDavid du Colombier
105b7b24591SDavid du Colombier int
authread(File * file,uchar * data,int count)106b7b24591SDavid du Colombier authread(File *file, uchar *data, int count)
107b7b24591SDavid du Colombier {
108b7b24591SDavid du Colombier AuthInfo *ai;
109b7b24591SDavid du Colombier AuthRpc *rpc;
110b7b24591SDavid du Colombier int rv;
111b7b24591SDavid du Colombier
112b7b24591SDavid du Colombier rpc = file->rpc;
1135d459b5aSDavid du Colombier if(rpc == nil)
1145d459b5aSDavid du Colombier return -1;
1155d459b5aSDavid du Colombier
116b7b24591SDavid du Colombier rv = auth_rpc(rpc, "read", nil, 0);
117b7b24591SDavid du Colombier switch(rv){
118b7b24591SDavid du Colombier case ARdone:
119b7b24591SDavid du Colombier ai = auth_getinfo(rpc);
120b7b24591SDavid du Colombier if(ai == nil)
121b7b24591SDavid du Colombier return -1;
122b7b24591SDavid du Colombier if(chat)
123b7b24591SDavid du Colombier print("authread identifies user as %s\n", ai->cuid);
124b7b24591SDavid du Colombier file->cuid = strtouid(ai->cuid);
1255d459b5aSDavid du Colombier auth_freeAI(ai);
126b7b24591SDavid du Colombier if(file->cuid == 0)
127b7b24591SDavid du Colombier return -1;
128b7b24591SDavid du Colombier if(chat)
129b7b24591SDavid du Colombier print("%s is a known user\n", ai->cuid);
130b7b24591SDavid du Colombier return 0;
131b7b24591SDavid du Colombier case ARok:
132b7b24591SDavid du Colombier if(count < rpc->narg)
133b7b24591SDavid du Colombier return -1;
134b7b24591SDavid du Colombier memmove(data, rpc->arg, rpc->narg);
135b7b24591SDavid du Colombier return rpc->narg;
136b7b24591SDavid du Colombier case ARphase:
137b7b24591SDavid du Colombier return -1;
138b7b24591SDavid du Colombier default:
139b7b24591SDavid du Colombier return -1;
140b7b24591SDavid du Colombier }
141b7b24591SDavid du Colombier }
142b7b24591SDavid du Colombier
143b7b24591SDavid du Colombier int
authwrite(File * file,uchar * data,int count)144b7b24591SDavid du Colombier authwrite(File *file, uchar *data, int count)
145b7b24591SDavid du Colombier {
146b7b24591SDavid du Colombier int ret;
147b7b24591SDavid du Colombier
148b7b24591SDavid du Colombier ret = auth_rpc(file->rpc, "write", data, count);
149b7b24591SDavid du Colombier if(ret != ARok)
150b7b24591SDavid du Colombier return -1;
151b7b24591SDavid du Colombier return count;
152b7b24591SDavid du Colombier }
153b7b24591SDavid du Colombier
1549a747e4fSDavid du Colombier void
mkqid9p1(Qid9p1 * qid9p1,Qid * qid)1559a747e4fSDavid du Colombier mkqid9p1(Qid9p1* qid9p1, Qid* qid)
1569a747e4fSDavid du Colombier {
1579a747e4fSDavid du Colombier if(qid->path & 0xFFFFFFFF00000000LL)
1589a747e4fSDavid du Colombier panic("mkqid9p1: path %lluX\n", qid->path);
1599a747e4fSDavid du Colombier qid9p1->path = qid->path & 0xFFFFFFFF;
1609a747e4fSDavid du Colombier if(qid->type & QTDIR)
1619a747e4fSDavid du Colombier qid9p1->path |= QPDIR;
1629a747e4fSDavid du Colombier qid9p1->version = qid->vers;
1639a747e4fSDavid du Colombier }
1649a747e4fSDavid du Colombier
1659a747e4fSDavid du Colombier void
authfree(File * fp)166b7b24591SDavid du Colombier authfree(File *fp)
167b7b24591SDavid du Colombier {
168b7b24591SDavid du Colombier if(fp->rpc != nil){
169b7b24591SDavid du Colombier close(fp->rpc->afd);
170b7b24591SDavid du Colombier free(fp->rpc);
171b7b24591SDavid du Colombier fp->rpc = nil;
172b7b24591SDavid du Colombier }
173b7b24591SDavid du Colombier }
174b7b24591SDavid du Colombier
175b7b24591SDavid du Colombier void
mkqid9p2(Qid * qid,Qid9p1 * qid9p1,int mode)1769a747e4fSDavid du Colombier mkqid9p2(Qid* qid, Qid9p1* qid9p1, int mode)
1779a747e4fSDavid du Colombier {
1789a747e4fSDavid du Colombier qid->path = (ulong)(qid9p1->path & ~QPDIR);
1799a747e4fSDavid du Colombier qid->vers = qid9p1->version;
1809a747e4fSDavid du Colombier qid->type = 0;
1819a747e4fSDavid du Colombier if(mode & DDIR)
1829a747e4fSDavid du Colombier qid->type |= QTDIR;
1839a747e4fSDavid du Colombier if(mode & DAPND)
1849a747e4fSDavid du Colombier qid->type |= QTAPPEND;
1859a747e4fSDavid du Colombier if(mode & DLOCK)
1869a747e4fSDavid du Colombier qid->type |= QTEXCL;
1879a747e4fSDavid du Colombier }
1889a747e4fSDavid du Colombier
1899a747e4fSDavid du Colombier static int
checkattach(Chan * chan,File * afile,File * file,Filsys * fs)1909a747e4fSDavid du Colombier checkattach(Chan *chan, File *afile, File *file, Filsys *fs)
1919a747e4fSDavid du Colombier {
192b7b24591SDavid du Colombier uchar buf[1];
1939a747e4fSDavid du Colombier
1949a747e4fSDavid du Colombier if(chan == cons.srvchan || chan == cons.chan)
1959a747e4fSDavid du Colombier return 0;
196b7b24591SDavid du Colombier
197b7b24591SDavid du Colombier /* if no afile, this had better be none */
198b7b24591SDavid du Colombier if(afile == nil){
1999a747e4fSDavid du Colombier if(file->uid == 0){
2009a747e4fSDavid du Colombier if(!allownone && !chan->authed)
2019a747e4fSDavid du Colombier return Eauth;
2029a747e4fSDavid du Colombier return 0;
2039a747e4fSDavid du Colombier }
2049a747e4fSDavid du Colombier return Eauth;
205b7b24591SDavid du Colombier }
206b7b24591SDavid du Colombier
207b7b24591SDavid du Colombier /* otherwise, we'ld better have a usable cuid */
2089a747e4fSDavid du Colombier if(!(afile->qid.type&QTAUTH))
2099a747e4fSDavid du Colombier return Eauth;
2109a747e4fSDavid du Colombier if(afile->uid != file->uid || afile->fs != fs)
2119a747e4fSDavid du Colombier return Eauth;
212b7b24591SDavid du Colombier if(afile->cuid <= 0){
213b7b24591SDavid du Colombier if(authread(afile, buf, 0) != 0)
2149a747e4fSDavid du Colombier return Eauth;
215b7b24591SDavid du Colombier if(afile->cuid <= 0)
216b7b24591SDavid du Colombier return Eauth;
217b7b24591SDavid du Colombier }
218b7b24591SDavid du Colombier file->uid = afile->cuid;
2195d459b5aSDavid du Colombier
2205d459b5aSDavid du Colombier /* once someone has authenticated on the channel, others can become none */
2219a747e4fSDavid du Colombier chan->authed = 1;
222b7b24591SDavid du Colombier
2239a747e4fSDavid du Colombier return 0;
2249a747e4fSDavid du Colombier }
2259a747e4fSDavid du Colombier
2269a747e4fSDavid du Colombier static int
fsattach(Chan * chan,Fcall * f,Fcall * r)2279a747e4fSDavid du Colombier fsattach(Chan* chan, Fcall* f, Fcall* r)
2289a747e4fSDavid du Colombier {
2299a747e4fSDavid du Colombier char *aname;
2309a747e4fSDavid du Colombier Iobuf *p;
2319a747e4fSDavid du Colombier Dentry *d;
2329a747e4fSDavid du Colombier File *file;
2339a747e4fSDavid du Colombier File *afile;
2349a747e4fSDavid du Colombier Filsys *fs;
2359a747e4fSDavid du Colombier long raddr;
2369a747e4fSDavid du Colombier int error, u;
2379a747e4fSDavid du Colombier
2389a747e4fSDavid du Colombier aname = f->aname;
2399a747e4fSDavid du Colombier if(!aname[0]) /* default */
2409a747e4fSDavid du Colombier aname = "main";
2419a747e4fSDavid du Colombier p = nil;
2429a747e4fSDavid du Colombier afile = filep(chan, f->afid, 0);
2439a747e4fSDavid du Colombier file = filep(chan, f->fid, 1);
2449a747e4fSDavid du Colombier if(file == nil){
2459a747e4fSDavid du Colombier error = Efidinuse;
2469a747e4fSDavid du Colombier goto out;
2479a747e4fSDavid du Colombier }
2489a747e4fSDavid du Colombier
2499a747e4fSDavid du Colombier u = -1;
2509a747e4fSDavid du Colombier if(chan != cons.chan){
2519a747e4fSDavid du Colombier if(strcmp(f->uname, "adm") == 0){
2529a747e4fSDavid du Colombier error = Eauth;
2539a747e4fSDavid du Colombier goto out;
2549a747e4fSDavid du Colombier }
2559a747e4fSDavid du Colombier u = strtouid(f->uname);
2569a747e4fSDavid du Colombier if(u < 0){
2579a747e4fSDavid du Colombier error = Ebadu;
2589a747e4fSDavid du Colombier goto out;
2599a747e4fSDavid du Colombier }
2609a747e4fSDavid du Colombier }
2619a747e4fSDavid du Colombier file->uid = u;
2629a747e4fSDavid du Colombier
2639a747e4fSDavid du Colombier fs = fsstr(aname);
2649a747e4fSDavid du Colombier if(fs == nil){
2659a747e4fSDavid du Colombier error = Ebadspc;
2669a747e4fSDavid du Colombier goto out;
2679a747e4fSDavid du Colombier }
2689a747e4fSDavid du Colombier
2699a747e4fSDavid du Colombier if(error = checkattach(chan, afile, file, fs))
2709a747e4fSDavid du Colombier goto out;
2719a747e4fSDavid du Colombier
2729a747e4fSDavid du Colombier raddr = getraddr(fs->dev);
2739a747e4fSDavid du Colombier p = getbuf(fs->dev, raddr, Bread);
2749a747e4fSDavid du Colombier d = getdir(p, 0);
2759a747e4fSDavid du Colombier if(d == nil || checktag(p, Tdir, QPROOT) || !(d->mode & DALLOC)){
2769a747e4fSDavid du Colombier error = Ealloc;
2779a747e4fSDavid du Colombier goto out;
2789a747e4fSDavid du Colombier }
2799a747e4fSDavid du Colombier if(iaccess(file, d, DEXEC)){
2809a747e4fSDavid du Colombier error = Eaccess;
2819a747e4fSDavid du Colombier goto out;
2829a747e4fSDavid du Colombier }
2839a747e4fSDavid du Colombier if(file->uid == 0 && isro(fs->dev)) {
2849a747e4fSDavid du Colombier /*
2859a747e4fSDavid du Colombier * 'none' not allowed on dump
2869a747e4fSDavid du Colombier */
2879a747e4fSDavid du Colombier error = Eaccess;
2889a747e4fSDavid du Colombier goto out;
2899a747e4fSDavid du Colombier }
2909a747e4fSDavid du Colombier accessdir(p, d, FREAD);
2919a747e4fSDavid du Colombier mkqid(&file->qid, d, 1);
2929a747e4fSDavid du Colombier file->fs = fs;
2939a747e4fSDavid du Colombier file->addr = raddr;
2949a747e4fSDavid du Colombier file->slot = 0;
2959a747e4fSDavid du Colombier file->open = 0;
2969a747e4fSDavid du Colombier freewp(file->wpath);
2979a747e4fSDavid du Colombier file->wpath = 0;
2989a747e4fSDavid du Colombier
2999a747e4fSDavid du Colombier r->qid = file->qid;
3009a747e4fSDavid du Colombier
3019a747e4fSDavid du Colombier // if(cons.flags & attachflag)
3029a747e4fSDavid du Colombier // print("9p2: attach %s %T to \"%s\" C%d\n",
3039a747e4fSDavid du Colombier // chan->whoname, chan->whotime, fs->name, chan->chan);
3049a747e4fSDavid du Colombier
3059a747e4fSDavid du Colombier out:
3069a747e4fSDavid du Colombier // if((cons.flags & attachflag) && error)
3079a747e4fSDavid du Colombier // print("9p2: attach %s %T SUCK EGGS --- %s\n",
3089a747e4fSDavid du Colombier // f->uname, time(), errstr[error]);
3099a747e4fSDavid du Colombier if(p != nil)
3109a747e4fSDavid du Colombier putbuf(p);
3119a747e4fSDavid du Colombier if(afile != nil)
3129a747e4fSDavid du Colombier qunlock(afile);
3139a747e4fSDavid du Colombier if(file != nil){
3149a747e4fSDavid du Colombier qunlock(file);
3159a747e4fSDavid du Colombier if(error)
3169a747e4fSDavid du Colombier freefp(file);
3179a747e4fSDavid du Colombier }
3189a747e4fSDavid du Colombier
3199a747e4fSDavid du Colombier return error;
3209a747e4fSDavid du Colombier }
3219a747e4fSDavid du Colombier
3229a747e4fSDavid du Colombier static int
fsflush(Chan * chan,Fcall *,Fcall *)3239a747e4fSDavid du Colombier fsflush(Chan* chan, Fcall*, Fcall*)
3249a747e4fSDavid du Colombier {
3259a747e4fSDavid du Colombier runlock(&chan->reflock);
3269a747e4fSDavid du Colombier wlock(&chan->reflock);
3279a747e4fSDavid du Colombier wunlock(&chan->reflock);
3289a747e4fSDavid du Colombier rlock(&chan->reflock);
3299a747e4fSDavid du Colombier
3309a747e4fSDavid du Colombier return 0;
3319a747e4fSDavid du Colombier }
3329a747e4fSDavid du Colombier
3339a747e4fSDavid du Colombier static void
clone(File * nfile,File * file)3349a747e4fSDavid du Colombier clone(File* nfile, File* file)
3359a747e4fSDavid du Colombier {
3369a747e4fSDavid du Colombier Wpath *wpath;
3379a747e4fSDavid du Colombier
3389a747e4fSDavid du Colombier nfile->qid = file->qid;
3399a747e4fSDavid du Colombier
3409a747e4fSDavid du Colombier lock(&wpathlock);
3419a747e4fSDavid du Colombier nfile->wpath = file->wpath;
3429a747e4fSDavid du Colombier for(wpath = nfile->wpath; wpath != nil; wpath = wpath->up)
3439a747e4fSDavid du Colombier wpath->refs++;
3449a747e4fSDavid du Colombier unlock(&wpathlock);
3459a747e4fSDavid du Colombier
3469a747e4fSDavid du Colombier nfile->fs = file->fs;
3479a747e4fSDavid du Colombier nfile->addr = file->addr;
3489a747e4fSDavid du Colombier nfile->slot = file->slot;
3499a747e4fSDavid du Colombier nfile->uid = file->uid;
3505d459b5aSDavid du Colombier nfile->cuid = 0;
3519a747e4fSDavid du Colombier nfile->open = file->open & ~FREMOV;
3529a747e4fSDavid du Colombier }
3539a747e4fSDavid du Colombier
3549a747e4fSDavid du Colombier static int
walkname(File * file,char * wname,Qid * wqid)3559a747e4fSDavid du Colombier walkname(File* file, char* wname, Qid* wqid)
3569a747e4fSDavid du Colombier {
3579a747e4fSDavid du Colombier Wpath *w;
3589a747e4fSDavid du Colombier Iobuf *p, *p1;
3599a747e4fSDavid du Colombier Dentry *d, *d1;
3609a747e4fSDavid du Colombier int error, slot;
3619a747e4fSDavid du Colombier long addr, qpath;
3629a747e4fSDavid du Colombier
3639a747e4fSDavid du Colombier p = p1 = nil;
3649a747e4fSDavid du Colombier
3659a747e4fSDavid du Colombier /*
3669a747e4fSDavid du Colombier * File must not have been opened for I/O by an open
3679a747e4fSDavid du Colombier * or create message and must represent a directory.
3689a747e4fSDavid du Colombier */
3699a747e4fSDavid du Colombier if(file->open != 0){
3709a747e4fSDavid du Colombier error = Emode;
3719a747e4fSDavid du Colombier goto out;
3729a747e4fSDavid du Colombier }
3739a747e4fSDavid du Colombier
3749a747e4fSDavid du Colombier p = getbuf(file->fs->dev, file->addr, Bread);
3759a747e4fSDavid du Colombier if(p == nil || checktag(p, Tdir, QPNONE)){
3769a747e4fSDavid du Colombier error = Edir1;
3779a747e4fSDavid du Colombier goto out;
3789a747e4fSDavid du Colombier }
3799a747e4fSDavid du Colombier if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){
3809a747e4fSDavid du Colombier error = Ealloc;
3819a747e4fSDavid du Colombier goto out;
3829a747e4fSDavid du Colombier }
3839a747e4fSDavid du Colombier if(!(d->mode & DDIR)){
3849a747e4fSDavid du Colombier error = Edir1;
3859a747e4fSDavid du Colombier goto out;
3869a747e4fSDavid du Colombier }
3879a747e4fSDavid du Colombier if(error = mkqidcmp(&file->qid, d))
3889a747e4fSDavid du Colombier goto out;
3899a747e4fSDavid du Colombier
3909a747e4fSDavid du Colombier /*
3919a747e4fSDavid du Colombier * For walked elements the implied user must
3929a747e4fSDavid du Colombier * have permission to search the directory.
3939a747e4fSDavid du Colombier */
3949a747e4fSDavid du Colombier if(file->cp != cons.chan && iaccess(file, d, DEXEC)){
3959a747e4fSDavid du Colombier error = Eaccess;
3969a747e4fSDavid du Colombier goto out;
3979a747e4fSDavid du Colombier }
3989a747e4fSDavid du Colombier accessdir(p, d, FREAD);
3999a747e4fSDavid du Colombier
4009a747e4fSDavid du Colombier if(strcmp(wname, ".") == 0){
4019a747e4fSDavid du Colombier setdot:
4029a747e4fSDavid du Colombier if(wqid != nil)
4039a747e4fSDavid du Colombier *wqid = file->qid;
4049a747e4fSDavid du Colombier goto out;
4059a747e4fSDavid du Colombier }
4069a747e4fSDavid du Colombier if(strcmp(wname, "..") == 0){
4079a747e4fSDavid du Colombier if(file->wpath == 0)
4089a747e4fSDavid du Colombier goto setdot;
4099a747e4fSDavid du Colombier putbuf(p);
4109a747e4fSDavid du Colombier p = nil;
4119a747e4fSDavid du Colombier addr = file->wpath->addr;
4129a747e4fSDavid du Colombier slot = file->wpath->slot;
4139a747e4fSDavid du Colombier p1 = getbuf(file->fs->dev, addr, Bread);
4149a747e4fSDavid du Colombier if(p1 == nil || checktag(p1, Tdir, QPNONE)){
4159a747e4fSDavid du Colombier error = Edir1;
4169a747e4fSDavid du Colombier goto out;
4179a747e4fSDavid du Colombier }
4189a747e4fSDavid du Colombier if((d1 = getdir(p1, slot)) == nil || !(d1->mode & DALLOC)){
4199a747e4fSDavid du Colombier error = Ephase;
4209a747e4fSDavid du Colombier goto out;
4219a747e4fSDavid du Colombier }
4229a747e4fSDavid du Colombier lock(&wpathlock);
4239a747e4fSDavid du Colombier file->wpath->refs--;
4249a747e4fSDavid du Colombier file->wpath = file->wpath->up;
4259a747e4fSDavid du Colombier unlock(&wpathlock);
4269a747e4fSDavid du Colombier goto found;
4279a747e4fSDavid du Colombier }
4289a747e4fSDavid du Colombier
4299a747e4fSDavid du Colombier for(addr = 0; ; addr++){
4309a747e4fSDavid du Colombier if(p == nil){
4319a747e4fSDavid du Colombier p = getbuf(file->fs->dev, file->addr, Bread);
4329a747e4fSDavid du Colombier if(p == nil || checktag(p, Tdir, QPNONE)){
4339a747e4fSDavid du Colombier error = Ealloc;
4349a747e4fSDavid du Colombier goto out;
4359a747e4fSDavid du Colombier }
4369a747e4fSDavid du Colombier d = getdir(p, file->slot);
4379a747e4fSDavid du Colombier if(d == nil || !(d->mode & DALLOC)){
4389a747e4fSDavid du Colombier error = Ealloc;
4399a747e4fSDavid du Colombier goto out;
4409a747e4fSDavid du Colombier }
4419a747e4fSDavid du Colombier }
4429a747e4fSDavid du Colombier qpath = d->qid.path;
4439a747e4fSDavid du Colombier p1 = dnodebuf1(p, d, addr, 0);
4449a747e4fSDavid du Colombier p = nil;
4459a747e4fSDavid du Colombier if(p1 == nil || checktag(p1, Tdir, qpath)){
4469a747e4fSDavid du Colombier error = Eentry;
4479a747e4fSDavid du Colombier goto out;
4489a747e4fSDavid du Colombier }
4499a747e4fSDavid du Colombier for(slot = 0; slot < DIRPERBUF; slot++){
4509a747e4fSDavid du Colombier d1 = getdir(p1, slot);
4519a747e4fSDavid du Colombier if(!(d1->mode & DALLOC))
4529a747e4fSDavid du Colombier continue;
4539a747e4fSDavid du Colombier if(strncmp(wname, d1->name, NAMELEN) != 0)
4549a747e4fSDavid du Colombier continue;
4559a747e4fSDavid du Colombier /*
4569a747e4fSDavid du Colombier * update walk path
4579a747e4fSDavid du Colombier */
4589a747e4fSDavid du Colombier if((w = newwp()) == nil){
4599a747e4fSDavid du Colombier error = Ewalk;
4609a747e4fSDavid du Colombier goto out;
4619a747e4fSDavid du Colombier }
4629a747e4fSDavid du Colombier w->addr = file->addr;
4639a747e4fSDavid du Colombier w->slot = file->slot;
4649a747e4fSDavid du Colombier w->up = file->wpath;
4659a747e4fSDavid du Colombier file->wpath = w;
4669a747e4fSDavid du Colombier slot += DIRPERBUF*addr;
4679a747e4fSDavid du Colombier goto found;
4689a747e4fSDavid du Colombier }
4699a747e4fSDavid du Colombier putbuf(p1);
4709a747e4fSDavid du Colombier p1 = nil;
4719a747e4fSDavid du Colombier }
4729a747e4fSDavid du Colombier
4739a747e4fSDavid du Colombier found:
4749a747e4fSDavid du Colombier file->addr = p1->addr;
4759a747e4fSDavid du Colombier mkqid(&file->qid, d1, 1);
4769a747e4fSDavid du Colombier putbuf(p1);
4779a747e4fSDavid du Colombier p1 = nil;
4789a747e4fSDavid du Colombier file->slot = slot;
4799a747e4fSDavid du Colombier if(wqid != nil)
4809a747e4fSDavid du Colombier *wqid = file->qid;
4819a747e4fSDavid du Colombier
4829a747e4fSDavid du Colombier out:
4839a747e4fSDavid du Colombier if(p1 != nil)
4849a747e4fSDavid du Colombier putbuf(p1);
4859a747e4fSDavid du Colombier if(p != nil)
4869a747e4fSDavid du Colombier putbuf(p);
4879a747e4fSDavid du Colombier
4889a747e4fSDavid du Colombier return error;
4899a747e4fSDavid du Colombier }
4909a747e4fSDavid du Colombier
4919a747e4fSDavid du Colombier static int
fswalk(Chan * chan,Fcall * f,Fcall * r)4929a747e4fSDavid du Colombier fswalk(Chan* chan, Fcall* f, Fcall* r)
4939a747e4fSDavid du Colombier {
4949a747e4fSDavid du Colombier int error, nwname;
4959a747e4fSDavid du Colombier File *file, *nfile, tfile;
4969a747e4fSDavid du Colombier
4979a747e4fSDavid du Colombier /*
4989a747e4fSDavid du Colombier * The file identified by f->fid must be valid in the
4999a747e4fSDavid du Colombier * current session and must not have been opened for I/O
5009a747e4fSDavid du Colombier * by an open or create message.
5019a747e4fSDavid du Colombier */
5029a747e4fSDavid du Colombier if((file = filep(chan, f->fid, 0)) == nil)
5039a747e4fSDavid du Colombier return Efid;
5049a747e4fSDavid du Colombier if(file->open != 0){
5059a747e4fSDavid du Colombier qunlock(file);
5069a747e4fSDavid du Colombier return Emode;
5079a747e4fSDavid du Colombier }
5089a747e4fSDavid du Colombier
5099a747e4fSDavid du Colombier /*
5109a747e4fSDavid du Colombier * If newfid is not the same as fid, allocate a new file;
5119a747e4fSDavid du Colombier * a side effect is checking newfid is not already in use (error);
5129a747e4fSDavid du Colombier * if there are no names to walk this will be equivalent to a
5139a747e4fSDavid du Colombier * simple 'clone' operation.
5149a747e4fSDavid du Colombier * Otherwise, fid and newfid are the same and if there are names
5159a747e4fSDavid du Colombier * to walk make a copy of 'file' to be used during the walk as
5169a747e4fSDavid du Colombier * 'file' must only be updated on success.
5179a747e4fSDavid du Colombier * Finally, it's a no-op if newfid is the same as fid and f->nwname
5189a747e4fSDavid du Colombier * is 0.
5199a747e4fSDavid du Colombier */
5209a747e4fSDavid du Colombier r->nwqid = 0;
5219a747e4fSDavid du Colombier if(f->newfid != f->fid){
5229a747e4fSDavid du Colombier if((nfile = filep(chan, f->newfid, 1)) == nil){
5239a747e4fSDavid du Colombier qunlock(file);
5249a747e4fSDavid du Colombier return Efidinuse;
5259a747e4fSDavid du Colombier }
5269a747e4fSDavid du Colombier }
5279a747e4fSDavid du Colombier else if(f->nwname != 0){
5289a747e4fSDavid du Colombier nfile = &tfile;
5299a747e4fSDavid du Colombier memset(nfile, 0, sizeof(File));
5309a747e4fSDavid du Colombier nfile->cp = chan;
5319a747e4fSDavid du Colombier nfile->fid = ~0;
5329a747e4fSDavid du Colombier }
5339a747e4fSDavid du Colombier else{
5349a747e4fSDavid du Colombier qunlock(file);
5359a747e4fSDavid du Colombier return 0;
5369a747e4fSDavid du Colombier }
5379a747e4fSDavid du Colombier clone(nfile, file);
5389a747e4fSDavid du Colombier
5399a747e4fSDavid du Colombier /*
5409a747e4fSDavid du Colombier * Should check name is not too long.
5419a747e4fSDavid du Colombier */
5429a747e4fSDavid du Colombier error = 0;
5439a747e4fSDavid du Colombier for(nwname = 0; nwname < f->nwname; nwname++){
5449a747e4fSDavid du Colombier error = walkname(nfile, f->wname[nwname], &r->wqid[r->nwqid]);
5459a747e4fSDavid du Colombier if(error != 0 || ++r->nwqid >= MAXDAT/sizeof(Qid))
5469a747e4fSDavid du Colombier break;
5479a747e4fSDavid du Colombier }
5489a747e4fSDavid du Colombier
5499a747e4fSDavid du Colombier if(f->nwname == 0){
5509a747e4fSDavid du Colombier /*
5519a747e4fSDavid du Colombier * Newfid must be different to fid (see above)
5529a747e4fSDavid du Colombier * so this is a simple 'clone' operation - there's
5539a747e4fSDavid du Colombier * nothing to do except unlock unless there's
5549a747e4fSDavid du Colombier * an error.
5559a747e4fSDavid du Colombier */
5569a747e4fSDavid du Colombier if(error){
5579a747e4fSDavid du Colombier freewp(nfile->wpath);
5589a747e4fSDavid du Colombier qunlock(nfile);
5599a747e4fSDavid du Colombier freefp(nfile);
5609a747e4fSDavid du Colombier }
5619a747e4fSDavid du Colombier else
5629a747e4fSDavid du Colombier qunlock(nfile);
5639a747e4fSDavid du Colombier }
5649a747e4fSDavid du Colombier else if(r->nwqid < f->nwname){
5659a747e4fSDavid du Colombier /*
5669a747e4fSDavid du Colombier * Didn't walk all elements, 'clunk' nfile
5679a747e4fSDavid du Colombier * and leave 'file' alone.
5689a747e4fSDavid du Colombier * Clear error if some of the elements were
5699a747e4fSDavid du Colombier * walked OK.
5709a747e4fSDavid du Colombier */
5719a747e4fSDavid du Colombier freewp(nfile->wpath);
5729a747e4fSDavid du Colombier if(nfile != &tfile){
5739a747e4fSDavid du Colombier qunlock(nfile);
5749a747e4fSDavid du Colombier freefp(nfile);
5759a747e4fSDavid du Colombier }
5769a747e4fSDavid du Colombier if(r->nwqid != 0)
5779a747e4fSDavid du Colombier error = 0;
5789a747e4fSDavid du Colombier }
5799a747e4fSDavid du Colombier else{
5809a747e4fSDavid du Colombier /*
5819a747e4fSDavid du Colombier * Walked all elements. If newfid is the same
5829a747e4fSDavid du Colombier * as fid must update 'file' from the temporary
5839a747e4fSDavid du Colombier * copy used during the walk.
5849a747e4fSDavid du Colombier * Otherwise just unlock (when using tfile there's
5859a747e4fSDavid du Colombier * no need to unlock as it's a local).
5869a747e4fSDavid du Colombier */
5879a747e4fSDavid du Colombier if(nfile == &tfile){
5889a747e4fSDavid du Colombier file->qid = nfile->qid;
5899a747e4fSDavid du Colombier freewp(file->wpath);
5909a747e4fSDavid du Colombier file->wpath = nfile->wpath;
5919a747e4fSDavid du Colombier file->addr = nfile->addr;
5929a747e4fSDavid du Colombier file->slot = nfile->slot;
5939a747e4fSDavid du Colombier }
5949a747e4fSDavid du Colombier else
5959a747e4fSDavid du Colombier qunlock(nfile);
5969a747e4fSDavid du Colombier }
5979a747e4fSDavid du Colombier qunlock(file);
5989a747e4fSDavid du Colombier
5999a747e4fSDavid du Colombier return error;
6009a747e4fSDavid du Colombier }
6019a747e4fSDavid du Colombier
6029a747e4fSDavid du Colombier static int
fsopen(Chan * chan,Fcall * f,Fcall * r)6039a747e4fSDavid du Colombier fsopen(Chan* chan, Fcall* f, Fcall* r)
6049a747e4fSDavid du Colombier {
6059a747e4fSDavid du Colombier Iobuf *p;
6069a747e4fSDavid du Colombier Dentry *d;
6079a747e4fSDavid du Colombier File *file;
6089a747e4fSDavid du Colombier Tlock *t;
6099a747e4fSDavid du Colombier Qid qid;
6109a747e4fSDavid du Colombier int error, ro, fmod, wok;
6119a747e4fSDavid du Colombier
6129a747e4fSDavid du Colombier wok = 0;
6139a747e4fSDavid du Colombier p = nil;
6149a747e4fSDavid du Colombier
6159a747e4fSDavid du Colombier if(chan == cons.chan || writeallow)
6169a747e4fSDavid du Colombier wok = 1;
6179a747e4fSDavid du Colombier
6189a747e4fSDavid du Colombier if((file = filep(chan, f->fid, 0)) == nil){
6199a747e4fSDavid du Colombier error = Efid;
6209a747e4fSDavid du Colombier goto out;
6219a747e4fSDavid du Colombier }
6229a747e4fSDavid du Colombier
6239a747e4fSDavid du Colombier /*
6249a747e4fSDavid du Colombier * if remove on close, check access here
6259a747e4fSDavid du Colombier */
6265d459b5aSDavid du Colombier ro = isro(file->fs->dev) || (writegroup && !ingroup(file->uid, writegroup));
6279a747e4fSDavid du Colombier if(f->mode & ORCLOSE){
6289a747e4fSDavid du Colombier if(ro){
6299a747e4fSDavid du Colombier error = Eronly;
6309a747e4fSDavid du Colombier goto out;
6319a747e4fSDavid du Colombier }
6329a747e4fSDavid du Colombier /*
6339a747e4fSDavid du Colombier * check on parent directory of file to be deleted
6349a747e4fSDavid du Colombier */
6359a747e4fSDavid du Colombier if(file->wpath == 0 || file->wpath->addr == file->addr){
6369a747e4fSDavid du Colombier error = Ephase;
6379a747e4fSDavid du Colombier goto out;
6389a747e4fSDavid du Colombier }
6399a747e4fSDavid du Colombier p = getbuf(file->fs->dev, file->wpath->addr, Bread);
6409a747e4fSDavid du Colombier if(p == nil || checktag(p, Tdir, QPNONE)){
6419a747e4fSDavid du Colombier error = Ephase;
6429a747e4fSDavid du Colombier goto out;
6439a747e4fSDavid du Colombier }
6449a747e4fSDavid du Colombier if((d = getdir(p, file->wpath->slot)) == nil || !(d->mode & DALLOC)){
6459a747e4fSDavid du Colombier error = Ephase;
6469a747e4fSDavid du Colombier goto out;
6479a747e4fSDavid du Colombier }
6489a747e4fSDavid du Colombier if(iaccess(file, d, DWRITE)){
6499a747e4fSDavid du Colombier error = Eaccess;
6509a747e4fSDavid du Colombier goto out;
6519a747e4fSDavid du Colombier }
6529a747e4fSDavid du Colombier putbuf(p);
6539a747e4fSDavid du Colombier }
6549a747e4fSDavid du Colombier p = getbuf(file->fs->dev, file->addr, Bread);
6559a747e4fSDavid du Colombier if(p == nil || checktag(p, Tdir, QPNONE)){
6569a747e4fSDavid du Colombier error = Ealloc;
6579a747e4fSDavid du Colombier goto out;
6589a747e4fSDavid du Colombier }
6599a747e4fSDavid du Colombier if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){
6609a747e4fSDavid du Colombier error = Ealloc;
6619a747e4fSDavid du Colombier goto out;
6629a747e4fSDavid du Colombier }
6639a747e4fSDavid du Colombier if(error = mkqidcmp(&file->qid, d))
6649a747e4fSDavid du Colombier goto out;
6659a747e4fSDavid du Colombier mkqid(&qid, d, 1);
6669a747e4fSDavid du Colombier switch(f->mode & 7){
6679a747e4fSDavid du Colombier
6689a747e4fSDavid du Colombier case OREAD:
6699a747e4fSDavid du Colombier if(iaccess(file, d, DREAD) && !wok)
6709a747e4fSDavid du Colombier goto badaccess;
6719a747e4fSDavid du Colombier fmod = FREAD;
6729a747e4fSDavid du Colombier break;
6739a747e4fSDavid du Colombier
6749a747e4fSDavid du Colombier case OWRITE:
6759a747e4fSDavid du Colombier if((d->mode & DDIR) || (iaccess(file, d, DWRITE) && !wok))
6769a747e4fSDavid du Colombier goto badaccess;
6779a747e4fSDavid du Colombier if(ro){
6789a747e4fSDavid du Colombier error = Eronly;
6799a747e4fSDavid du Colombier goto out;
6809a747e4fSDavid du Colombier }
6819a747e4fSDavid du Colombier fmod = FWRITE;
6829a747e4fSDavid du Colombier break;
6839a747e4fSDavid du Colombier
6849a747e4fSDavid du Colombier case ORDWR:
6859a747e4fSDavid du Colombier if((d->mode & DDIR)
6869a747e4fSDavid du Colombier || (iaccess(file, d, DREAD) && !wok)
6879a747e4fSDavid du Colombier || (iaccess(file, d, DWRITE) && !wok))
6889a747e4fSDavid du Colombier goto badaccess;
6899a747e4fSDavid du Colombier if(ro){
6909a747e4fSDavid du Colombier error = Eronly;
6919a747e4fSDavid du Colombier goto out;
6929a747e4fSDavid du Colombier }
6939a747e4fSDavid du Colombier fmod = FREAD+FWRITE;
6949a747e4fSDavid du Colombier break;
6959a747e4fSDavid du Colombier
6969a747e4fSDavid du Colombier case OEXEC:
6979a747e4fSDavid du Colombier if((d->mode & DDIR) || (iaccess(file, d, DEXEC) && !wok))
6989a747e4fSDavid du Colombier goto badaccess;
6999a747e4fSDavid du Colombier fmod = FREAD;
7009a747e4fSDavid du Colombier break;
7019a747e4fSDavid du Colombier
7029a747e4fSDavid du Colombier default:
7039a747e4fSDavid du Colombier error = Emode;
7049a747e4fSDavid du Colombier goto out;
7059a747e4fSDavid du Colombier }
7069a747e4fSDavid du Colombier if(f->mode & OTRUNC){
7079a747e4fSDavid du Colombier if((d->mode & DDIR) || (iaccess(file, d, DWRITE) && !wok))
7089a747e4fSDavid du Colombier goto badaccess;
7099a747e4fSDavid du Colombier if(ro){
7109a747e4fSDavid du Colombier error = Eronly;
7119a747e4fSDavid du Colombier goto out;
7129a747e4fSDavid du Colombier }
7139a747e4fSDavid du Colombier }
7149a747e4fSDavid du Colombier t = 0;
7159a747e4fSDavid du Colombier if(d->mode & DLOCK){
7169a747e4fSDavid du Colombier if((t = tlocked(p, d)) == nil){
7179a747e4fSDavid du Colombier error = Elocked;
7189a747e4fSDavid du Colombier goto out;
7199a747e4fSDavid du Colombier }
7209a747e4fSDavid du Colombier }
7219a747e4fSDavid du Colombier if(f->mode & ORCLOSE)
7229a747e4fSDavid du Colombier fmod |= FREMOV;
7239a747e4fSDavid du Colombier file->open = fmod;
7249a747e4fSDavid du Colombier if((f->mode & OTRUNC) && !(d->mode & DAPND)){
7259a747e4fSDavid du Colombier dtrunc(p, d);
7269a747e4fSDavid du Colombier qid.vers = d->qid.version;
7279a747e4fSDavid du Colombier }
7289a747e4fSDavid du Colombier r->qid = qid;
7299a747e4fSDavid du Colombier file->tlock = t;
7309a747e4fSDavid du Colombier if(t != nil)
7319a747e4fSDavid du Colombier t->file = file;
7329a747e4fSDavid du Colombier file->lastra = 1;
7339a747e4fSDavid du Colombier goto out;
7349a747e4fSDavid du Colombier
7359a747e4fSDavid du Colombier badaccess:
7369a747e4fSDavid du Colombier error = Eaccess;
7379a747e4fSDavid du Colombier file->open = 0;
7389a747e4fSDavid du Colombier
7399a747e4fSDavid du Colombier out:
7409a747e4fSDavid du Colombier if(p != nil)
7419a747e4fSDavid du Colombier putbuf(p);
7429a747e4fSDavid du Colombier if(file != nil)
7439a747e4fSDavid du Colombier qunlock(file);
7449a747e4fSDavid du Colombier
7459a747e4fSDavid du Colombier r->iounit = chan->msize-IOHDRSZ;
7469a747e4fSDavid du Colombier
7479a747e4fSDavid du Colombier return error;
7489a747e4fSDavid du Colombier }
7499a747e4fSDavid du Colombier
7509a747e4fSDavid du Colombier static int
dir9p2(Dir * dir,Dentry * dentry,void * strs)7519a747e4fSDavid du Colombier dir9p2(Dir* dir, Dentry* dentry, void* strs)
7529a747e4fSDavid du Colombier {
7539a747e4fSDavid du Colombier char *op, *p;
7549a747e4fSDavid du Colombier
7559a747e4fSDavid du Colombier memset(dir, 0, sizeof(Dir));
7569a747e4fSDavid du Colombier mkqid(&dir->qid, dentry, 1);
7579a747e4fSDavid du Colombier dir->mode = (dir->qid.type<<24)|(dentry->mode & 0777);
7589a747e4fSDavid du Colombier dir->atime = dentry->atime;
7599a747e4fSDavid du Colombier dir->mtime = dentry->mtime;
7609a747e4fSDavid du Colombier dir->length = dentry->size;
7619a747e4fSDavid du Colombier
7629a747e4fSDavid du Colombier op = p = strs;
7639a747e4fSDavid du Colombier dir->name = p;
7649a747e4fSDavid du Colombier p += sprint(p, "%s", dentry->name)+1;
7659a747e4fSDavid du Colombier
7669a747e4fSDavid du Colombier dir->uid = p;
7679a747e4fSDavid du Colombier uidtostr(p, dentry->uid);
7689a747e4fSDavid du Colombier p += strlen(p)+1;
7699a747e4fSDavid du Colombier
7709a747e4fSDavid du Colombier dir->gid = p;
7719a747e4fSDavid du Colombier uidtostr(p, dentry->gid);
7729a747e4fSDavid du Colombier p += strlen(p)+1;
7739a747e4fSDavid du Colombier
7749a747e4fSDavid du Colombier dir->muid = p;
7759a747e4fSDavid du Colombier strcpy(p, "");
7769a747e4fSDavid du Colombier p += strlen(p)+1;
7779a747e4fSDavid du Colombier
7789a747e4fSDavid du Colombier return p-op;
7799a747e4fSDavid du Colombier }
7809a747e4fSDavid du Colombier
7819a747e4fSDavid du Colombier static int
checkname9p2(char * name)7829a747e4fSDavid du Colombier checkname9p2(char* name)
7839a747e4fSDavid du Colombier {
7849a747e4fSDavid du Colombier char *p;
7859a747e4fSDavid du Colombier
7869a747e4fSDavid du Colombier /*
7879a747e4fSDavid du Colombier * Return length of string if valid, 0 if not.
7889a747e4fSDavid du Colombier */
7899a747e4fSDavid du Colombier if(name == nil)
7909a747e4fSDavid du Colombier return 0;
7919a747e4fSDavid du Colombier
7929a747e4fSDavid du Colombier for(p = name; *p != 0; p++){
7939a747e4fSDavid du Colombier if((*p & 0xFF) <= 040)
7949a747e4fSDavid du Colombier return 0;
7959a747e4fSDavid du Colombier }
7969a747e4fSDavid du Colombier
7979a747e4fSDavid du Colombier return p-name;
7989a747e4fSDavid du Colombier }
7999a747e4fSDavid du Colombier
8009a747e4fSDavid du Colombier static int
fscreate(Chan * chan,Fcall * f,Fcall * r)8019a747e4fSDavid du Colombier fscreate(Chan* chan, Fcall* f, Fcall* r)
8029a747e4fSDavid du Colombier {
8039a747e4fSDavid du Colombier Iobuf *p, *p1;
8049a747e4fSDavid du Colombier Dentry *d, *d1;
8059a747e4fSDavid du Colombier File *file;
8069a747e4fSDavid du Colombier int error, slot, slot1, fmod, wok, l;
8079a747e4fSDavid du Colombier long addr, addr1, path;
8089a747e4fSDavid du Colombier Tlock *t;
8099a747e4fSDavid du Colombier Wpath *w;
8109a747e4fSDavid du Colombier
8119a747e4fSDavid du Colombier wok = 0;
8129a747e4fSDavid du Colombier p = nil;
8139a747e4fSDavid du Colombier
8149a747e4fSDavid du Colombier if(chan == cons.chan || writeallow)
8159a747e4fSDavid du Colombier wok = 1;
8169a747e4fSDavid du Colombier
8179a747e4fSDavid du Colombier if((file = filep(chan, f->fid, 0)) == nil){
8189a747e4fSDavid du Colombier error = Efid;
8199a747e4fSDavid du Colombier goto out;
8209a747e4fSDavid du Colombier }
8215d459b5aSDavid du Colombier if(isro(file->fs->dev) || (writegroup && !ingroup(file->uid, writegroup))){
8229a747e4fSDavid du Colombier error = Eronly;
8239a747e4fSDavid du Colombier goto out;
8249a747e4fSDavid du Colombier }
8259a747e4fSDavid du Colombier
8269a747e4fSDavid du Colombier p = getbuf(file->fs->dev, file->addr, Bread);
8279a747e4fSDavid du Colombier if(p == nil || checktag(p, Tdir, QPNONE)){
8289a747e4fSDavid du Colombier error = Ealloc;
8299a747e4fSDavid du Colombier goto out;
8309a747e4fSDavid du Colombier }
8319a747e4fSDavid du Colombier if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){
8329a747e4fSDavid du Colombier error = Ealloc;
8339a747e4fSDavid du Colombier goto out;
8349a747e4fSDavid du Colombier }
8359a747e4fSDavid du Colombier if(error = mkqidcmp(&file->qid, d))
8369a747e4fSDavid du Colombier goto out;
8379a747e4fSDavid du Colombier if(!(d->mode & DDIR)){
8389a747e4fSDavid du Colombier error = Edir2;
8399a747e4fSDavid du Colombier goto out;
8409a747e4fSDavid du Colombier }
8419a747e4fSDavid du Colombier if(iaccess(file, d, DWRITE) && !wok) {
8429a747e4fSDavid du Colombier error = Eaccess;
8439a747e4fSDavid du Colombier goto out;
8449a747e4fSDavid du Colombier }
8459a747e4fSDavid du Colombier accessdir(p, d, FREAD);
8469a747e4fSDavid du Colombier
8479a747e4fSDavid du Colombier /*
8489a747e4fSDavid du Colombier * Check the name is valid and will fit in an old
8499a747e4fSDavid du Colombier * directory entry.
8509a747e4fSDavid du Colombier */
8519a747e4fSDavid du Colombier if((l = checkname9p2(f->name)) == 0){
8529a747e4fSDavid du Colombier error = Ename;
8539a747e4fSDavid du Colombier goto out;
8549a747e4fSDavid du Colombier }
8559a747e4fSDavid du Colombier if(l+1 > NAMELEN){
8569a747e4fSDavid du Colombier error = Etoolong;
8579a747e4fSDavid du Colombier goto out;
8589a747e4fSDavid du Colombier }
8599a747e4fSDavid du Colombier if(strcmp(f->name, ".") == 0 || strcmp(f->name, "..") == 0){
8609a747e4fSDavid du Colombier error = Edot;
8619a747e4fSDavid du Colombier goto out;
8629a747e4fSDavid du Colombier }
8639a747e4fSDavid du Colombier
8649a747e4fSDavid du Colombier addr1 = 0;
8659a747e4fSDavid du Colombier slot1 = 0; /* set */
8669a747e4fSDavid du Colombier for(addr = 0; ; addr++){
8679a747e4fSDavid du Colombier if((p1 = dnodebuf(p, d, addr, 0)) == nil){
8689a747e4fSDavid du Colombier if(addr1 != 0)
8699a747e4fSDavid du Colombier break;
8709a747e4fSDavid du Colombier p1 = dnodebuf(p, d, addr, Tdir);
8719a747e4fSDavid du Colombier }
8729a747e4fSDavid du Colombier if(p1 == nil){
8739a747e4fSDavid du Colombier error = Efull;
8749a747e4fSDavid du Colombier goto out;
8759a747e4fSDavid du Colombier }
8769a747e4fSDavid du Colombier if(checktag(p1, Tdir, d->qid.path)){
8779a747e4fSDavid du Colombier putbuf(p1);
8789a747e4fSDavid du Colombier goto phase;
8799a747e4fSDavid du Colombier }
8809a747e4fSDavid du Colombier for(slot = 0; slot < DIRPERBUF; slot++){
8819a747e4fSDavid du Colombier d1 = getdir(p1, slot);
8829a747e4fSDavid du Colombier if(!(d1->mode & DALLOC)){
8839a747e4fSDavid du Colombier if(addr1 == 0){
8849a747e4fSDavid du Colombier addr1 = p1->addr;
8859a747e4fSDavid du Colombier slot1 = slot + addr*DIRPERBUF;
8869a747e4fSDavid du Colombier }
8879a747e4fSDavid du Colombier continue;
8889a747e4fSDavid du Colombier }
8899a747e4fSDavid du Colombier if(strncmp(f->name, d1->name, sizeof(d1->name)) == 0){
8909a747e4fSDavid du Colombier putbuf(p1);
8919a747e4fSDavid du Colombier error = Eexist;
8929a747e4fSDavid du Colombier goto out;
8939a747e4fSDavid du Colombier }
8949a747e4fSDavid du Colombier }
8959a747e4fSDavid du Colombier putbuf(p1);
8969a747e4fSDavid du Colombier }
8979a747e4fSDavid du Colombier
8989a747e4fSDavid du Colombier switch(f->mode & 7){
8999a747e4fSDavid du Colombier case OEXEC:
9009a747e4fSDavid du Colombier case OREAD: /* seems only useful to make directories */
9019a747e4fSDavid du Colombier fmod = FREAD;
9029a747e4fSDavid du Colombier break;
9039a747e4fSDavid du Colombier
9049a747e4fSDavid du Colombier case OWRITE:
9059a747e4fSDavid du Colombier fmod = FWRITE;
9069a747e4fSDavid du Colombier break;
9079a747e4fSDavid du Colombier
9089a747e4fSDavid du Colombier case ORDWR:
9099a747e4fSDavid du Colombier fmod = FREAD+FWRITE;
9109a747e4fSDavid du Colombier break;
9119a747e4fSDavid du Colombier
9129a747e4fSDavid du Colombier default:
9139a747e4fSDavid du Colombier error = Emode;
9149a747e4fSDavid du Colombier goto out;
9159a747e4fSDavid du Colombier }
9169a747e4fSDavid du Colombier if(f->perm & PDIR)
9179a747e4fSDavid du Colombier if((f->mode & OTRUNC) || (f->perm & PAPND) || (fmod & FWRITE))
9189a747e4fSDavid du Colombier goto badaccess;
9199a747e4fSDavid du Colombier /*
9209a747e4fSDavid du Colombier * do it
9219a747e4fSDavid du Colombier */
9229a747e4fSDavid du Colombier path = qidpathgen(&file->fs->dev);
9239a747e4fSDavid du Colombier if((p1 = getbuf(file->fs->dev, addr1, Bread|Bimm|Bmod)) == nil)
9249a747e4fSDavid du Colombier goto phase;
9259a747e4fSDavid du Colombier d1 = getdir(p1, slot1);
9269a747e4fSDavid du Colombier if(d1 == nil || checktag(p1, Tdir, d->qid.path)) {
9279a747e4fSDavid du Colombier putbuf(p1);
9289a747e4fSDavid du Colombier goto phase;
9299a747e4fSDavid du Colombier }
9309a747e4fSDavid du Colombier if(d1->mode & DALLOC){
9319a747e4fSDavid du Colombier putbuf(p1);
9329a747e4fSDavid du Colombier goto phase;
9339a747e4fSDavid du Colombier }
9349a747e4fSDavid du Colombier
9359a747e4fSDavid du Colombier strncpy(d1->name, f->name, sizeof(d1->name));
9369a747e4fSDavid du Colombier if(chan == cons.chan){
9379a747e4fSDavid du Colombier d1->uid = cons.uid;
9389a747e4fSDavid du Colombier d1->gid = cons.gid;
9399a747e4fSDavid du Colombier }
9409a747e4fSDavid du Colombier else{
9419a747e4fSDavid du Colombier d1->uid = file->uid;
9429a747e4fSDavid du Colombier d1->gid = d->gid;
9439a747e4fSDavid du Colombier f->perm &= d->mode | ~0666;
9449a747e4fSDavid du Colombier if(f->perm & PDIR)
9459a747e4fSDavid du Colombier f->perm &= d->mode | ~0777;
9469a747e4fSDavid du Colombier }
9479a747e4fSDavid du Colombier d1->qid.path = path;
9489a747e4fSDavid du Colombier d1->qid.version = 0;
9499a747e4fSDavid du Colombier d1->mode = DALLOC | (f->perm & 0777);
9509a747e4fSDavid du Colombier if(f->perm & PDIR) {
9519a747e4fSDavid du Colombier d1->mode |= DDIR;
9529a747e4fSDavid du Colombier d1->qid.path |= QPDIR;
9539a747e4fSDavid du Colombier }
9549a747e4fSDavid du Colombier if(f->perm & PAPND)
9559a747e4fSDavid du Colombier d1->mode |= DAPND;
9569a747e4fSDavid du Colombier t = nil;
9579a747e4fSDavid du Colombier if(f->perm & PLOCK){
9589a747e4fSDavid du Colombier d1->mode |= DLOCK;
9599a747e4fSDavid du Colombier t = tlocked(p1, d1);
9609a747e4fSDavid du Colombier /* if nil, out of tlock structures */
9619a747e4fSDavid du Colombier }
9629a747e4fSDavid du Colombier accessdir(p1, d1, FWRITE);
9639a747e4fSDavid du Colombier mkqid(&r->qid, d1, 0);
9649a747e4fSDavid du Colombier putbuf(p1);
9659a747e4fSDavid du Colombier accessdir(p, d, FWRITE);
9669a747e4fSDavid du Colombier
9679a747e4fSDavid du Colombier /*
9689a747e4fSDavid du Colombier * do a walk to new directory entry
9699a747e4fSDavid du Colombier */
9709a747e4fSDavid du Colombier if((w = newwp()) == nil){
9719a747e4fSDavid du Colombier error = Ewalk;
9729a747e4fSDavid du Colombier goto out;
9739a747e4fSDavid du Colombier }
9749a747e4fSDavid du Colombier w->addr = file->addr;
9759a747e4fSDavid du Colombier w->slot = file->slot;
9769a747e4fSDavid du Colombier w->up = file->wpath;
9779a747e4fSDavid du Colombier file->wpath = w;
9789a747e4fSDavid du Colombier file->qid = r->qid;
9799a747e4fSDavid du Colombier file->tlock = t;
9809a747e4fSDavid du Colombier if(t != nil)
9819a747e4fSDavid du Colombier t->file = file;
9829a747e4fSDavid du Colombier file->lastra = 1;
9839a747e4fSDavid du Colombier if(f->mode & ORCLOSE)
9849a747e4fSDavid du Colombier fmod |= FREMOV;
9859a747e4fSDavid du Colombier file->open = fmod;
9869a747e4fSDavid du Colombier file->addr = addr1;
9879a747e4fSDavid du Colombier file->slot = slot1;
9889a747e4fSDavid du Colombier goto out;
9899a747e4fSDavid du Colombier
9909a747e4fSDavid du Colombier badaccess:
9919a747e4fSDavid du Colombier error = Eaccess;
9929a747e4fSDavid du Colombier goto out;
9939a747e4fSDavid du Colombier
9949a747e4fSDavid du Colombier phase:
9959a747e4fSDavid du Colombier error = Ephase;
9969a747e4fSDavid du Colombier
9979a747e4fSDavid du Colombier out:
9989a747e4fSDavid du Colombier if(p != nil)
9999a747e4fSDavid du Colombier putbuf(p);
10009a747e4fSDavid du Colombier if(file != nil)
10019a747e4fSDavid du Colombier qunlock(file);
10029a747e4fSDavid du Colombier
10039a747e4fSDavid du Colombier r->iounit = chan->msize-IOHDRSZ;
10049a747e4fSDavid du Colombier
10059a747e4fSDavid du Colombier return error;
10069a747e4fSDavid du Colombier }
10079a747e4fSDavid du Colombier
10089a747e4fSDavid du Colombier static int
fsread(Chan * chan,Fcall * f,Fcall * r)10099a747e4fSDavid du Colombier fsread(Chan* chan, Fcall* f, Fcall* r)
10109a747e4fSDavid du Colombier {
10119a747e4fSDavid du Colombier uchar *data;
10129a747e4fSDavid du Colombier Iobuf *p, *p1;
10139a747e4fSDavid du Colombier File *file;
10149a747e4fSDavid du Colombier Dentry *d, *d1;
10159a747e4fSDavid du Colombier Tlock *t;
10169a747e4fSDavid du Colombier long addr, offset, start, tim;
10179a747e4fSDavid du Colombier int error, iounit, nread, count, n, o, slot;
10189a747e4fSDavid du Colombier Dir dir;
10199a747e4fSDavid du Colombier char strdata[28*10];
10209a747e4fSDavid du Colombier
10219a747e4fSDavid du Colombier p = nil;
10229a747e4fSDavid du Colombier data = (uchar*)r->data;
10239a747e4fSDavid du Colombier count = f->count;
10249a747e4fSDavid du Colombier offset = f->offset;
10259a747e4fSDavid du Colombier nread = 0;
10269a747e4fSDavid du Colombier if((file = filep(chan, f->fid, 0)) == nil){
10279a747e4fSDavid du Colombier error = Efid;
10289a747e4fSDavid du Colombier goto out;
10299a747e4fSDavid du Colombier }
10309a747e4fSDavid du Colombier if(file->qid.type & QTAUTH){
1031b7b24591SDavid du Colombier nread = authread(file, data, count);
10329a747e4fSDavid du Colombier if(nread < 0)
10339a747e4fSDavid du Colombier error = Esystem;
1034b7b24591SDavid du Colombier else
1035b7b24591SDavid du Colombier error = 0;
10369a747e4fSDavid du Colombier goto out;
10379a747e4fSDavid du Colombier }
10389a747e4fSDavid du Colombier if(!(file->open & FREAD)){
10399a747e4fSDavid du Colombier error = Eopen;
10409a747e4fSDavid du Colombier goto out;
10419a747e4fSDavid du Colombier }
10429a747e4fSDavid du Colombier iounit = chan->msize-IOHDRSZ;
10439a747e4fSDavid du Colombier if(count < 0 || count > iounit){
10449a747e4fSDavid du Colombier error = Ecount;
10459a747e4fSDavid du Colombier goto out;
10469a747e4fSDavid du Colombier }
10479a747e4fSDavid du Colombier if(offset < 0){
10489a747e4fSDavid du Colombier error = Eoffset;
10499a747e4fSDavid du Colombier goto out;
10509a747e4fSDavid du Colombier }
10519a747e4fSDavid du Colombier p = getbuf(file->fs->dev, file->addr, Bread);
10529a747e4fSDavid du Colombier if(p == nil || checktag(p, Tdir, QPNONE)){
10539a747e4fSDavid du Colombier error = Ealloc;
10549a747e4fSDavid du Colombier goto out;
10559a747e4fSDavid du Colombier }
10569a747e4fSDavid du Colombier if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){
10579a747e4fSDavid du Colombier error = Ealloc;
10589a747e4fSDavid du Colombier goto out;
10599a747e4fSDavid du Colombier }
10609a747e4fSDavid du Colombier if(error = mkqidcmp(&file->qid, d))
10619a747e4fSDavid du Colombier goto out;
10629a747e4fSDavid du Colombier if(t = file->tlock){
10639a747e4fSDavid du Colombier tim = time(0);
10649a747e4fSDavid du Colombier if(t->time < tim || t->file != file){
10659a747e4fSDavid du Colombier error = Ebroken;
10669a747e4fSDavid du Colombier goto out;
10679a747e4fSDavid du Colombier }
10689a747e4fSDavid du Colombier /* renew the lock */
10699a747e4fSDavid du Colombier t->time = tim + TLOCK;
10709a747e4fSDavid du Colombier }
10719a747e4fSDavid du Colombier accessdir(p, d, FREAD);
10729a747e4fSDavid du Colombier if(d->mode & DDIR)
10739a747e4fSDavid du Colombier goto dread;
10749a747e4fSDavid du Colombier if(offset+count > d->size)
10759a747e4fSDavid du Colombier count = d->size - offset;
10769a747e4fSDavid du Colombier while(count > 0){
10779a747e4fSDavid du Colombier if(p == nil){
10789a747e4fSDavid du Colombier p = getbuf(file->fs->dev, file->addr, Bread);
10799a747e4fSDavid du Colombier if(p == nil || checktag(p, Tdir, QPNONE)){
10809a747e4fSDavid du Colombier error = Ealloc;
10819a747e4fSDavid du Colombier goto out;
10829a747e4fSDavid du Colombier }
10839a747e4fSDavid du Colombier if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){
10849a747e4fSDavid du Colombier error = Ealloc;
10859a747e4fSDavid du Colombier goto out;
10869a747e4fSDavid du Colombier }
10879a747e4fSDavid du Colombier }
10889a747e4fSDavid du Colombier addr = offset / BUFSIZE;
10899a747e4fSDavid du Colombier o = offset % BUFSIZE;
10909a747e4fSDavid du Colombier n = BUFSIZE - o;
10919a747e4fSDavid du Colombier if(n > count)
10929a747e4fSDavid du Colombier n = count;
10939a747e4fSDavid du Colombier p1 = dnodebuf1(p, d, addr, 0);
10949a747e4fSDavid du Colombier p = nil;
10959a747e4fSDavid du Colombier if(p1 != nil){
10969a747e4fSDavid du Colombier if(checktag(p1, Tfile, QPNONE)){
10979a747e4fSDavid du Colombier error = Ephase;
10989a747e4fSDavid du Colombier putbuf(p1);
10999a747e4fSDavid du Colombier goto out;
11009a747e4fSDavid du Colombier }
11019a747e4fSDavid du Colombier memmove(data+nread, p1->iobuf+o, n);
11029a747e4fSDavid du Colombier putbuf(p1);
11039a747e4fSDavid du Colombier }
11049a747e4fSDavid du Colombier else
11059a747e4fSDavid du Colombier memset(data+nread, 0, n);
11069a747e4fSDavid du Colombier count -= n;
11079a747e4fSDavid du Colombier nread += n;
11089a747e4fSDavid du Colombier offset += n;
11099a747e4fSDavid du Colombier }
11109a747e4fSDavid du Colombier goto out;
11119a747e4fSDavid du Colombier
11129a747e4fSDavid du Colombier dread:
11139a747e4fSDavid du Colombier /*
11149a747e4fSDavid du Colombier * Pick up where we left off last time if nothing has changed,
11159a747e4fSDavid du Colombier * otherwise must scan from the beginning.
11169a747e4fSDavid du Colombier */
11179a747e4fSDavid du Colombier if(offset == file->doffset /*&& file->qid.vers == file->dvers*/){
11189a747e4fSDavid du Colombier addr = file->dslot/DIRPERBUF;
11199a747e4fSDavid du Colombier slot = file->dslot%DIRPERBUF;
11209a747e4fSDavid du Colombier start = offset;
11219a747e4fSDavid du Colombier }
11229a747e4fSDavid du Colombier else{
11239a747e4fSDavid du Colombier addr = 0;
11249a747e4fSDavid du Colombier slot = 0;
11259a747e4fSDavid du Colombier start = 0;
11269a747e4fSDavid du Colombier }
11279a747e4fSDavid du Colombier
11289a747e4fSDavid du Colombier dread1:
11299a747e4fSDavid du Colombier if(p == nil){
11309a747e4fSDavid du Colombier /*
11319a747e4fSDavid du Colombier * This is just a check to ensure the entry hasn't
11329a747e4fSDavid du Colombier * gone away during the read of each directory block.
11339a747e4fSDavid du Colombier */
11349a747e4fSDavid du Colombier p = getbuf(file->fs->dev, file->addr, Bread);
11359a747e4fSDavid du Colombier if(p == nil || checktag(p, Tdir, QPNONE)){
11369a747e4fSDavid du Colombier error = Ealloc;
11379a747e4fSDavid du Colombier goto out1;
11389a747e4fSDavid du Colombier }
11399a747e4fSDavid du Colombier if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){
11409a747e4fSDavid du Colombier error = Ealloc;
11419a747e4fSDavid du Colombier goto out1;
11429a747e4fSDavid du Colombier }
11439a747e4fSDavid du Colombier }
11449a747e4fSDavid du Colombier p1 = dnodebuf1(p, d, addr, 0);
11459a747e4fSDavid du Colombier p = nil;
11469a747e4fSDavid du Colombier if(p1 == nil)
11479a747e4fSDavid du Colombier goto out1;
11489a747e4fSDavid du Colombier if(checktag(p1, Tdir, QPNONE)){
11499a747e4fSDavid du Colombier error = Ephase;
11509a747e4fSDavid du Colombier putbuf(p1);
11519a747e4fSDavid du Colombier goto out1;
11529a747e4fSDavid du Colombier }
11539a747e4fSDavid du Colombier
11549a747e4fSDavid du Colombier for(; slot < DIRPERBUF; slot++){
11559a747e4fSDavid du Colombier d1 = getdir(p1, slot);
11569a747e4fSDavid du Colombier if(!(d1->mode & DALLOC))
11579a747e4fSDavid du Colombier continue;
11589a747e4fSDavid du Colombier dir9p2(&dir, d1, strdata);
11599a747e4fSDavid du Colombier if((n = convD2M(&dir, data+nread, iounit - nread)) <= BIT16SZ){
11609a747e4fSDavid du Colombier putbuf(p1);
11619a747e4fSDavid du Colombier goto out1;
11629a747e4fSDavid du Colombier }
11639a747e4fSDavid du Colombier start += n;
11649a747e4fSDavid du Colombier if(start < offset)
11659a747e4fSDavid du Colombier continue;
11669a747e4fSDavid du Colombier if(count < n){
11679a747e4fSDavid du Colombier putbuf(p1);
11689a747e4fSDavid du Colombier goto out1;
11699a747e4fSDavid du Colombier }
11709a747e4fSDavid du Colombier count -= n;
11719a747e4fSDavid du Colombier nread += n;
11729a747e4fSDavid du Colombier offset += n;
11739a747e4fSDavid du Colombier }
11749a747e4fSDavid du Colombier putbuf(p1);
11759a747e4fSDavid du Colombier slot = 0;
11769a747e4fSDavid du Colombier addr++;
11779a747e4fSDavid du Colombier goto dread1;
11789a747e4fSDavid du Colombier
11799a747e4fSDavid du Colombier out1:
11809a747e4fSDavid du Colombier if(error == 0){
11819a747e4fSDavid du Colombier file->doffset = offset;
11829a747e4fSDavid du Colombier file->dvers = file->qid.vers;
11839a747e4fSDavid du Colombier file->dslot = slot+DIRPERBUF*addr;
11849a747e4fSDavid du Colombier }
11859a747e4fSDavid du Colombier
11869a747e4fSDavid du Colombier out:
11879a747e4fSDavid du Colombier /*
11889a747e4fSDavid du Colombier * Do we need this any more?
11899a747e4fSDavid du Colombier count = f->count - nread;
11909a747e4fSDavid du Colombier if(count > 0)
11919a747e4fSDavid du Colombier memset(data+nread, 0, count);
11929a747e4fSDavid du Colombier */
11939a747e4fSDavid du Colombier if(p != nil)
11949a747e4fSDavid du Colombier putbuf(p);
11959a747e4fSDavid du Colombier if(file != nil)
11969a747e4fSDavid du Colombier qunlock(file);
11979a747e4fSDavid du Colombier r->count = nread;
11989a747e4fSDavid du Colombier r->data = (char*)data;
11999a747e4fSDavid du Colombier
12009a747e4fSDavid du Colombier return error;
12019a747e4fSDavid du Colombier }
12029a747e4fSDavid du Colombier
12039a747e4fSDavid du Colombier static int
fswrite(Chan * chan,Fcall * f,Fcall * r)12049a747e4fSDavid du Colombier fswrite(Chan* chan, Fcall* f, Fcall* r)
12059a747e4fSDavid du Colombier {
12069a747e4fSDavid du Colombier Iobuf *p, *p1;
12079a747e4fSDavid du Colombier Dentry *d;
12089a747e4fSDavid du Colombier File *file;
12099a747e4fSDavid du Colombier Tlock *t;
12109a747e4fSDavid du Colombier long offset, addr, tim, qpath;
12119a747e4fSDavid du Colombier int count, error, nwrite, o, n;
12129a747e4fSDavid du Colombier
12139a747e4fSDavid du Colombier offset = f->offset;
12149a747e4fSDavid du Colombier count = f->count;
12159a747e4fSDavid du Colombier
12169a747e4fSDavid du Colombier nwrite = 0;
12179a747e4fSDavid du Colombier p = nil;
12189a747e4fSDavid du Colombier
12199a747e4fSDavid du Colombier if((file = filep(chan, f->fid, 0)) == nil){
12209a747e4fSDavid du Colombier error = Efid;
12219a747e4fSDavid du Colombier goto out;
12229a747e4fSDavid du Colombier }
12239a747e4fSDavid du Colombier if(file->qid.type & QTAUTH){
1224b7b24591SDavid du Colombier nwrite = authwrite(file, (uchar*)f->data, count);
12259a747e4fSDavid du Colombier if(nwrite < 0)
12269a747e4fSDavid du Colombier error = Esystem;
1227b7b24591SDavid du Colombier else
1228b7b24591SDavid du Colombier error = 0;
12299a747e4fSDavid du Colombier goto out;
12309a747e4fSDavid du Colombier }
12319a747e4fSDavid du Colombier if(!(file->open & FWRITE)){
12329a747e4fSDavid du Colombier error = Eopen;
12339a747e4fSDavid du Colombier goto out;
12349a747e4fSDavid du Colombier }
12355d459b5aSDavid du Colombier if(isro(file->fs->dev) || (writegroup && !ingroup(file->uid, writegroup))){
12369a747e4fSDavid du Colombier error = Eronly;
12379a747e4fSDavid du Colombier goto out;
12389a747e4fSDavid du Colombier }
12399a747e4fSDavid du Colombier if(count < 0 || count > chan->msize-IOHDRSZ){
12409a747e4fSDavid du Colombier error = Ecount;
12419a747e4fSDavid du Colombier goto out;
12429a747e4fSDavid du Colombier }
12439a747e4fSDavid du Colombier if(offset < 0) {
12449a747e4fSDavid du Colombier error = Eoffset;
12459a747e4fSDavid du Colombier goto out;
12469a747e4fSDavid du Colombier }
12479a747e4fSDavid du Colombier if((p = getbuf(file->fs->dev, file->addr, Bread|Bmod)) == nil){
12489a747e4fSDavid du Colombier error = Ealloc;
12499a747e4fSDavid du Colombier goto out;
12509a747e4fSDavid du Colombier }
12519a747e4fSDavid du Colombier if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){
12529a747e4fSDavid du Colombier error = Ealloc;
12539a747e4fSDavid du Colombier goto out;
12549a747e4fSDavid du Colombier }
12559a747e4fSDavid du Colombier if(error = mkqidcmp(&file->qid, d))
12569a747e4fSDavid du Colombier goto out;
12579a747e4fSDavid du Colombier if(t = file->tlock) {
12589a747e4fSDavid du Colombier tim = time(0);
12599a747e4fSDavid du Colombier if(t->time < tim || t->file != file){
12609a747e4fSDavid du Colombier error = Ebroken;
12619a747e4fSDavid du Colombier goto out;
12629a747e4fSDavid du Colombier }
12639a747e4fSDavid du Colombier /* renew the lock */
12649a747e4fSDavid du Colombier t->time = tim + TLOCK;
12659a747e4fSDavid du Colombier }
12669a747e4fSDavid du Colombier accessdir(p, d, FWRITE);
12679a747e4fSDavid du Colombier if(d->mode & DAPND)
12689a747e4fSDavid du Colombier offset = d->size;
12699a747e4fSDavid du Colombier if(offset+count > d->size)
12709a747e4fSDavid du Colombier d->size = offset+count;
12719a747e4fSDavid du Colombier while(count > 0){
12729a747e4fSDavid du Colombier if(p == nil){
12739a747e4fSDavid du Colombier p = getbuf(file->fs->dev, file->addr, Bread|Bmod);
12749a747e4fSDavid du Colombier if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){
12759a747e4fSDavid du Colombier error = Ealloc;
12769a747e4fSDavid du Colombier goto out;
12779a747e4fSDavid du Colombier }
12789a747e4fSDavid du Colombier }
12799a747e4fSDavid du Colombier addr = offset / BUFSIZE;
12809a747e4fSDavid du Colombier o = offset % BUFSIZE;
12819a747e4fSDavid du Colombier n = BUFSIZE - o;
12829a747e4fSDavid du Colombier if(n > count)
12839a747e4fSDavid du Colombier n = count;
12849a747e4fSDavid du Colombier qpath = d->qid.path;
12859a747e4fSDavid du Colombier p1 = dnodebuf1(p, d, addr, Tfile);
12869a747e4fSDavid du Colombier p = nil;
12879a747e4fSDavid du Colombier if(p1 == nil) {
12889a747e4fSDavid du Colombier error = Efull;
12899a747e4fSDavid du Colombier goto out;
12909a747e4fSDavid du Colombier }
12919a747e4fSDavid du Colombier if(checktag(p1, Tfile, qpath)){
12929a747e4fSDavid du Colombier putbuf(p1);
12939a747e4fSDavid du Colombier error = Ephase;
12949a747e4fSDavid du Colombier goto out;
12959a747e4fSDavid du Colombier }
12969a747e4fSDavid du Colombier memmove(p1->iobuf+o, f->data+nwrite, n);
12979a747e4fSDavid du Colombier p1->flags |= Bmod;
12989a747e4fSDavid du Colombier putbuf(p1);
12999a747e4fSDavid du Colombier count -= n;
13009a747e4fSDavid du Colombier nwrite += n;
13019a747e4fSDavid du Colombier offset += n;
13029a747e4fSDavid du Colombier }
13039a747e4fSDavid du Colombier
13049a747e4fSDavid du Colombier out:
13059a747e4fSDavid du Colombier if(p != nil)
13069a747e4fSDavid du Colombier putbuf(p);
13079a747e4fSDavid du Colombier if(file != nil)
13089a747e4fSDavid du Colombier qunlock(file);
13099a747e4fSDavid du Colombier r->count = nwrite;
13109a747e4fSDavid du Colombier
13119a747e4fSDavid du Colombier return error;
13129a747e4fSDavid du Colombier }
13139a747e4fSDavid du Colombier
13149a747e4fSDavid du Colombier static int
_clunk(File * file,int remove,int wok)13159a747e4fSDavid du Colombier _clunk(File* file, int remove, int wok)
13169a747e4fSDavid du Colombier {
13179a747e4fSDavid du Colombier Tlock *t;
13189a747e4fSDavid du Colombier int error;
13199a747e4fSDavid du Colombier
13209a747e4fSDavid du Colombier error = 0;
13219a747e4fSDavid du Colombier if(t = file->tlock){
13229a747e4fSDavid du Colombier if(t->file == file)
13239a747e4fSDavid du Colombier t->time = 0; /* free the lock */
13249a747e4fSDavid du Colombier file->tlock = 0;
13259a747e4fSDavid du Colombier }
13269a747e4fSDavid du Colombier if(remove)
13279a747e4fSDavid du Colombier error = doremove(file, wok);
13289a747e4fSDavid du Colombier file->open = 0;
13299a747e4fSDavid du Colombier freewp(file->wpath);
13309a747e4fSDavid du Colombier freefp(file);
13319a747e4fSDavid du Colombier qunlock(file);
13329a747e4fSDavid du Colombier
13339a747e4fSDavid du Colombier return error;
13349a747e4fSDavid du Colombier }
13359a747e4fSDavid du Colombier
13369a747e4fSDavid du Colombier static int
fsclunk(Chan * chan,Fcall * f,Fcall *)13379a747e4fSDavid du Colombier fsclunk(Chan* chan, Fcall* f, Fcall*)
13389a747e4fSDavid du Colombier {
13399a747e4fSDavid du Colombier File *file;
13409a747e4fSDavid du Colombier
13419a747e4fSDavid du Colombier if((file = filep(chan, f->fid, 0)) == nil)
13429a747e4fSDavid du Colombier return Efid;
13439a747e4fSDavid du Colombier
13449a747e4fSDavid du Colombier _clunk(file, file->open & FREMOV, 0);
13459a747e4fSDavid du Colombier return 0;
13469a747e4fSDavid du Colombier }
13479a747e4fSDavid du Colombier
13489a747e4fSDavid du Colombier static int
fsremove(Chan * chan,Fcall * f,Fcall *)13499a747e4fSDavid du Colombier fsremove(Chan* chan, Fcall* f, Fcall*)
13509a747e4fSDavid du Colombier {
13519a747e4fSDavid du Colombier File *file;
13529a747e4fSDavid du Colombier
13539a747e4fSDavid du Colombier if((file = filep(chan, f->fid, 0)) == nil)
13549a747e4fSDavid du Colombier return Efid;
13559a747e4fSDavid du Colombier
13569a747e4fSDavid du Colombier return _clunk(file, 1, chan == cons.chan);
13579a747e4fSDavid du Colombier }
13589a747e4fSDavid du Colombier
13599a747e4fSDavid du Colombier static int
fsstat(Chan * chan,Fcall * f,Fcall * r,uchar * data)13609a747e4fSDavid du Colombier fsstat(Chan* chan, Fcall* f, Fcall* r, uchar* data)
13619a747e4fSDavid du Colombier {
13629a747e4fSDavid du Colombier Dir dir;
13639a747e4fSDavid du Colombier Iobuf *p;
13649a747e4fSDavid du Colombier Dentry *d;
13659a747e4fSDavid du Colombier File *file;
13669a747e4fSDavid du Colombier int error, len;
13679a747e4fSDavid du Colombier
13689a747e4fSDavid du Colombier if((file = filep(chan, f->fid, 0)) == nil)
13699a747e4fSDavid du Colombier return Efid;
13709a747e4fSDavid du Colombier
13719a747e4fSDavid du Colombier p = getbuf(file->fs->dev, file->addr, Bread);
13729a747e4fSDavid du Colombier if(p == nil || checktag(p, Tdir, QPNONE)){
13739a747e4fSDavid du Colombier error = Edir1;
13749a747e4fSDavid du Colombier goto out;
13759a747e4fSDavid du Colombier }
13769a747e4fSDavid du Colombier if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){
13779a747e4fSDavid du Colombier error = Ealloc;
13789a747e4fSDavid du Colombier goto out;
13799a747e4fSDavid du Colombier }
13809a747e4fSDavid du Colombier if(error = mkqidcmp(&file->qid, d))
13819a747e4fSDavid du Colombier goto out;
13829a747e4fSDavid du Colombier
13839a747e4fSDavid du Colombier if(d->qid.path == QPROOT) /* stat of root gives time */
13849a747e4fSDavid du Colombier d->atime = time(0);
13859a747e4fSDavid du Colombier
13869a747e4fSDavid du Colombier len = dir9p2(&dir, d, data);
13879a747e4fSDavid du Colombier data += len;
13889a747e4fSDavid du Colombier if((r->nstat = convD2M(&dir, data, chan->msize - len)) == 0)
13899a747e4fSDavid du Colombier error = Ersc;
13909a747e4fSDavid du Colombier else
13919a747e4fSDavid du Colombier r->stat = data;
13929a747e4fSDavid du Colombier
13939a747e4fSDavid du Colombier out:
13949a747e4fSDavid du Colombier if(p != nil)
13959a747e4fSDavid du Colombier putbuf(p);
13969a747e4fSDavid du Colombier if(file != nil)
13979a747e4fSDavid du Colombier qunlock(file);
13989a747e4fSDavid du Colombier
13999a747e4fSDavid du Colombier return error;
14009a747e4fSDavid du Colombier }
14019a747e4fSDavid du Colombier
14029a747e4fSDavid du Colombier static int
fswstat(Chan * chan,Fcall * f,Fcall *,char * strs)14039a747e4fSDavid du Colombier fswstat(Chan* chan, Fcall* f, Fcall*, char *strs)
14049a747e4fSDavid du Colombier {
14059a747e4fSDavid du Colombier Iobuf *p, *p1;
14069a747e4fSDavid du Colombier Dentry *d, *d1, xd;
14079a747e4fSDavid du Colombier File *file;
14089a747e4fSDavid du Colombier int error, slot, uid, gid, l;
14099a747e4fSDavid du Colombier long addr;
14109a747e4fSDavid du Colombier Dir dir;
14119a747e4fSDavid du Colombier ulong mode;
14129a747e4fSDavid du Colombier
14139a747e4fSDavid du Colombier p = p1 = nil;
14149a747e4fSDavid du Colombier d1 = nil;
14159a747e4fSDavid du Colombier
14169a747e4fSDavid du Colombier if((file = filep(chan, f->fid, 0)) == nil){
14179a747e4fSDavid du Colombier error = Efid;
14189a747e4fSDavid du Colombier goto out;
14199a747e4fSDavid du Colombier }
14209a747e4fSDavid du Colombier
14219a747e4fSDavid du Colombier /*
14229a747e4fSDavid du Colombier * if user none,
14239a747e4fSDavid du Colombier * can't do anything
14249a747e4fSDavid du Colombier * unless allow.
14259a747e4fSDavid du Colombier */
14269a747e4fSDavid du Colombier if(file->uid == 0 && !wstatallow){
14279a747e4fSDavid du Colombier error = Eaccess;
14289a747e4fSDavid du Colombier goto out;
14299a747e4fSDavid du Colombier }
14309a747e4fSDavid du Colombier
14315d459b5aSDavid du Colombier if(isro(file->fs->dev) || (writegroup && !ingroup(file->uid, writegroup))){
14329a747e4fSDavid du Colombier error = Eronly;
14339a747e4fSDavid du Colombier goto out;
14349a747e4fSDavid du Colombier }
14359a747e4fSDavid du Colombier
14369a747e4fSDavid du Colombier /*
14379a747e4fSDavid du Colombier * first get parent
14389a747e4fSDavid du Colombier */
14399a747e4fSDavid du Colombier if(file->wpath){
14409a747e4fSDavid du Colombier p1 = getbuf(file->fs->dev, file->wpath->addr, Bread);
14419a747e4fSDavid du Colombier if(p1 == nil){
14429a747e4fSDavid du Colombier error = Ephase;
14439a747e4fSDavid du Colombier goto out;
14449a747e4fSDavid du Colombier }
14459a747e4fSDavid du Colombier d1 = getdir(p1, file->wpath->slot);
14469a747e4fSDavid du Colombier if(d1 == nil || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)){
14479a747e4fSDavid du Colombier error = Ephase;
14489a747e4fSDavid du Colombier goto out;
14499a747e4fSDavid du Colombier }
14509a747e4fSDavid du Colombier }
14519a747e4fSDavid du Colombier
14529a747e4fSDavid du Colombier if((p = getbuf(file->fs->dev, file->addr, Bread)) == nil){
14539a747e4fSDavid du Colombier error = Ealloc;
14549a747e4fSDavid du Colombier goto out;
14559a747e4fSDavid du Colombier }
14569a747e4fSDavid du Colombier d = getdir(p, file->slot);
14579a747e4fSDavid du Colombier if(d == nil || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)){
14589a747e4fSDavid du Colombier error = Ealloc;
14599a747e4fSDavid du Colombier goto out;
14609a747e4fSDavid du Colombier }
14619a747e4fSDavid du Colombier if(error = mkqidcmp(&file->qid, d))
14629a747e4fSDavid du Colombier goto out;
14639a747e4fSDavid du Colombier
14649a747e4fSDavid du Colombier /*
14659a747e4fSDavid du Colombier * Convert the message and fix up
14669a747e4fSDavid du Colombier * fields not to be changed.
14679a747e4fSDavid du Colombier */
14689a747e4fSDavid du Colombier if(convM2D(f->stat, f->nstat, &dir, strs) == 0){
14699a747e4fSDavid du Colombier print("9p2: convM2D returns 0\n");
14709a747e4fSDavid du Colombier error = Econvert;
14719a747e4fSDavid du Colombier goto out;
14729a747e4fSDavid du Colombier }
14739a747e4fSDavid du Colombier if(dir.uid == nil || strlen(dir.uid) == 0)
14749a747e4fSDavid du Colombier uid = d->uid;
14759a747e4fSDavid du Colombier else
14769a747e4fSDavid du Colombier uid = strtouid(dir.uid);
14779a747e4fSDavid du Colombier if(dir.gid == nil || strlen(dir.gid) == 0)
14789a747e4fSDavid du Colombier gid = d->gid;
14799a747e4fSDavid du Colombier else
14809a747e4fSDavid du Colombier gid = strtouid(dir.gid);
14819a747e4fSDavid du Colombier if(dir.name == nil || strlen(dir.name) == 0)
14829a747e4fSDavid du Colombier dir.name = d->name;
14839a747e4fSDavid du Colombier else{
14849a747e4fSDavid du Colombier if((l = checkname9p2(dir.name)) == 0){
14859a747e4fSDavid du Colombier error = Ename;
14869a747e4fSDavid du Colombier goto out;
14879a747e4fSDavid du Colombier }
14889a747e4fSDavid du Colombier if(l > NAMELEN){
14899a747e4fSDavid du Colombier error = Etoolong;
14909a747e4fSDavid du Colombier goto out;
14919a747e4fSDavid du Colombier }
14929a747e4fSDavid du Colombier }
14939a747e4fSDavid du Colombier
14949a747e4fSDavid du Colombier /*
14959a747e4fSDavid du Colombier * Before doing sanity checks, find out what the
14969a747e4fSDavid du Colombier * new 'mode' should be:
14979a747e4fSDavid du Colombier * if 'type' and 'mode' are both defaults, take the
14989a747e4fSDavid du Colombier * new mode from the old directory entry;
14999a747e4fSDavid du Colombier * else if 'type' is the default, use the new mode entry;
15009a747e4fSDavid du Colombier * else if 'mode' is the default, create the new mode from
15019a747e4fSDavid du Colombier * 'type' or'ed with the old directory mode;
15029a747e4fSDavid du Colombier * else neither are defaults, use the new mode but check
15039a747e4fSDavid du Colombier * it agrees with 'type'.
15049a747e4fSDavid du Colombier */
15059a747e4fSDavid du Colombier if(dir.qid.type == 0xFF && dir.mode == ~0){
15069a747e4fSDavid du Colombier dir.mode = d->mode & 0777;
15079a747e4fSDavid du Colombier if(d->mode & DLOCK)
15089a747e4fSDavid du Colombier dir.mode |= DMEXCL;
15099a747e4fSDavid du Colombier if(d->mode & DAPND)
15109a747e4fSDavid du Colombier dir.mode |= DMAPPEND;
15119a747e4fSDavid du Colombier if(d->mode & DDIR)
15129a747e4fSDavid du Colombier dir.mode |= DMDIR;
15139a747e4fSDavid du Colombier }
15149a747e4fSDavid du Colombier else if(dir.qid.type == 0xFF){
15159a747e4fSDavid du Colombier /* nothing to do */
15169a747e4fSDavid du Colombier }
15179a747e4fSDavid du Colombier else if(dir.mode == ~0)
15189a747e4fSDavid du Colombier dir.mode = (dir.qid.type<<24)|(d->mode & 0777);
15199a747e4fSDavid du Colombier else if(dir.qid.type != ((dir.mode>>24) & 0xFF)){
15209a747e4fSDavid du Colombier error = Eqidmode;
15219a747e4fSDavid du Colombier goto out;
15229a747e4fSDavid du Colombier }
15239a747e4fSDavid du Colombier
15249a747e4fSDavid du Colombier /*
15259a747e4fSDavid du Colombier * Check for unknown type/mode bits
15269a747e4fSDavid du Colombier * and an attempt to change the directory bit.
15279a747e4fSDavid du Colombier */
15289a747e4fSDavid du Colombier if(dir.mode & ~(DMDIR|DMAPPEND|DMEXCL|0777)){
15299a747e4fSDavid du Colombier error = Enotm;
15309a747e4fSDavid du Colombier goto out;
15319a747e4fSDavid du Colombier }
15329a747e4fSDavid du Colombier if(d->mode & DDIR)
15339a747e4fSDavid du Colombier mode = DMDIR;
15349a747e4fSDavid du Colombier else
15359a747e4fSDavid du Colombier mode = 0;
15369a747e4fSDavid du Colombier if((dir.mode^mode) & DMDIR){
15379a747e4fSDavid du Colombier error = Enotd;
15389a747e4fSDavid du Colombier goto out;
15399a747e4fSDavid du Colombier }
15409a747e4fSDavid du Colombier
15419a747e4fSDavid du Colombier if(dir.mtime == ~0)
15429a747e4fSDavid du Colombier dir.mtime = d->mtime;
15439a747e4fSDavid du Colombier if(dir.length == ~0)
15449a747e4fSDavid du Colombier dir.length = d->size;
15459a747e4fSDavid du Colombier
15469a747e4fSDavid du Colombier /*
15479a747e4fSDavid du Colombier * Currently, can't change length.
15489a747e4fSDavid du Colombier */
15499a747e4fSDavid du Colombier if(dir.length != d->size){
15509a747e4fSDavid du Colombier error = Enotl;
15519a747e4fSDavid du Colombier goto out;
15529a747e4fSDavid du Colombier }
15539a747e4fSDavid du Colombier
15549a747e4fSDavid du Colombier /*
15559a747e4fSDavid du Colombier * if chown,
15569a747e4fSDavid du Colombier * must be god
15579a747e4fSDavid du Colombier * wstatallow set to allow chown during boot
15589a747e4fSDavid du Colombier */
15599a747e4fSDavid du Colombier if(uid != d->uid && !wstatallow) {
15609a747e4fSDavid du Colombier error = Enotu;
15619a747e4fSDavid du Colombier goto out;
15629a747e4fSDavid du Colombier }
15639a747e4fSDavid du Colombier
15649a747e4fSDavid du Colombier /*
15659a747e4fSDavid du Colombier * if chgroup,
15669a747e4fSDavid du Colombier * must be either
15679a747e4fSDavid du Colombier * a) owner and in new group
15689a747e4fSDavid du Colombier * b) leader of both groups
15699a747e4fSDavid du Colombier * wstatallow and writeallow are set to allow chgrp during boot
15709a747e4fSDavid du Colombier */
15719a747e4fSDavid du Colombier while(gid != d->gid) {
15729a747e4fSDavid du Colombier if(wstatallow || writeallow)
15739a747e4fSDavid du Colombier break;
15749a747e4fSDavid du Colombier if(d->uid == file->uid && ingroup(file->uid, gid))
15759a747e4fSDavid du Colombier break;
15769a747e4fSDavid du Colombier if(leadgroup(file->uid, gid))
15779a747e4fSDavid du Colombier if(leadgroup(file->uid, d->gid))
15789a747e4fSDavid du Colombier break;
15799a747e4fSDavid du Colombier error = Enotg;
15809a747e4fSDavid du Colombier goto out;
15819a747e4fSDavid du Colombier }
15829a747e4fSDavid du Colombier
15839a747e4fSDavid du Colombier /*
15849a747e4fSDavid du Colombier * if rename,
15859a747e4fSDavid du Colombier * must have write permission in parent
15869a747e4fSDavid du Colombier */
15879a747e4fSDavid du Colombier while(strncmp(d->name, dir.name, sizeof(d->name)) != 0) {
15889a747e4fSDavid du Colombier if(checkname(dir.name) || d1 == nil) {
15899a747e4fSDavid du Colombier error = Ename;
15909a747e4fSDavid du Colombier goto out;
15919a747e4fSDavid du Colombier }
15929a747e4fSDavid du Colombier if(strcmp(dir.name, ".") == 0 || strcmp(xd.name, "..") == 0) {
15939a747e4fSDavid du Colombier error = Ename;
15949a747e4fSDavid du Colombier goto out;
15959a747e4fSDavid du Colombier }
15969a747e4fSDavid du Colombier
15979a747e4fSDavid du Colombier /*
15989a747e4fSDavid du Colombier * drop entry to prevent lock, then
15999a747e4fSDavid du Colombier * check that destination name is unique,
16009a747e4fSDavid du Colombier */
16019a747e4fSDavid du Colombier putbuf(p);
16029a747e4fSDavid du Colombier for(addr = 0; ; addr++) {
16039a747e4fSDavid du Colombier if((p = dnodebuf(p1, d1, addr, 0)) == nil)
16049a747e4fSDavid du Colombier break;
16059a747e4fSDavid du Colombier if(checktag(p, Tdir, d1->qid.path)) {
16069a747e4fSDavid du Colombier putbuf(p);
16079a747e4fSDavid du Colombier continue;
16089a747e4fSDavid du Colombier }
16099a747e4fSDavid du Colombier for(slot = 0; slot < DIRPERBUF; slot++) {
16109a747e4fSDavid du Colombier d = getdir(p, slot);
16119a747e4fSDavid du Colombier if(!(d->mode & DALLOC))
16129a747e4fSDavid du Colombier continue;
16139a747e4fSDavid du Colombier if(strncmp(dir.name, d->name, sizeof(d->name)) == 0) {
16149a747e4fSDavid du Colombier error = Eexist;
16159a747e4fSDavid du Colombier goto out;
16169a747e4fSDavid du Colombier }
16179a747e4fSDavid du Colombier }
16189a747e4fSDavid du Colombier putbuf(p);
16199a747e4fSDavid du Colombier }
16209a747e4fSDavid du Colombier
16219a747e4fSDavid du Colombier /*
16229a747e4fSDavid du Colombier * reacquire entry
16239a747e4fSDavid du Colombier */
16249a747e4fSDavid du Colombier if((p = getbuf(file->fs->dev, file->addr, Bread)) == nil){
16259a747e4fSDavid du Colombier error = Ephase;
16269a747e4fSDavid du Colombier goto out;
16279a747e4fSDavid du Colombier }
16289a747e4fSDavid du Colombier d = getdir(p, file->slot);
16299a747e4fSDavid du Colombier if(d == nil || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
16309a747e4fSDavid du Colombier error = Ephase;
16319a747e4fSDavid du Colombier goto out;
16329a747e4fSDavid du Colombier }
16339a747e4fSDavid du Colombier
16349a747e4fSDavid du Colombier if(wstatallow || writeallow) /* set to allow rename during boot */
16359a747e4fSDavid du Colombier break;
16369a747e4fSDavid du Colombier if(d1 == nil || iaccess(file, d1, DWRITE)) {
16379a747e4fSDavid du Colombier error = Eaccess;
16389a747e4fSDavid du Colombier goto out;
16399a747e4fSDavid du Colombier }
16409a747e4fSDavid du Colombier break;
16419a747e4fSDavid du Colombier }
16429a747e4fSDavid du Colombier
16439a747e4fSDavid du Colombier /*
16449a747e4fSDavid du Colombier * if mode/time, either
16459a747e4fSDavid du Colombier * a) owner
16469a747e4fSDavid du Colombier * b) leader of either group
16479a747e4fSDavid du Colombier */
16489a747e4fSDavid du Colombier mode = dir.mode & 0777;
16499a747e4fSDavid du Colombier if(dir.mode & DMAPPEND)
16509a747e4fSDavid du Colombier mode |= DAPND;
16519a747e4fSDavid du Colombier if(dir.mode & DMEXCL)
16529a747e4fSDavid du Colombier mode |= DLOCK;
16539a747e4fSDavid du Colombier while(d->mtime != dir.mtime || ((d->mode^mode) & (DAPND|DLOCK|0777))) {
16549a747e4fSDavid du Colombier if(wstatallow) /* set to allow chmod during boot */
16559a747e4fSDavid du Colombier break;
16569a747e4fSDavid du Colombier if(d->uid == file->uid)
16579a747e4fSDavid du Colombier break;
16589a747e4fSDavid du Colombier if(leadgroup(file->uid, gid))
16599a747e4fSDavid du Colombier break;
16609a747e4fSDavid du Colombier if(leadgroup(file->uid, d->gid))
16619a747e4fSDavid du Colombier break;
16629a747e4fSDavid du Colombier error = Enotu;
16639a747e4fSDavid du Colombier goto out;
16649a747e4fSDavid du Colombier }
16659a747e4fSDavid du Colombier d->mtime = dir.mtime;
16669a747e4fSDavid du Colombier d->uid = uid;
16679a747e4fSDavid du Colombier d->gid = gid;
16689a747e4fSDavid du Colombier d->mode = (mode & (DAPND|DLOCK|0777)) | (d->mode & (DALLOC|DDIR));
16699a747e4fSDavid du Colombier
16709a747e4fSDavid du Colombier strncpy(d->name, dir.name, sizeof(d->name));
1671*229d2d34SDavid du Colombier accessdir(p, d, FWSTAT);
16729a747e4fSDavid du Colombier
16739a747e4fSDavid du Colombier out:
16749a747e4fSDavid du Colombier if(p != nil)
16759a747e4fSDavid du Colombier putbuf(p);
16769a747e4fSDavid du Colombier if(p1 != nil)
16779a747e4fSDavid du Colombier putbuf(p1);
16789a747e4fSDavid du Colombier if(file != nil)
16799a747e4fSDavid du Colombier qunlock(file);
16809a747e4fSDavid du Colombier
16819a747e4fSDavid du Colombier return error;
16829a747e4fSDavid du Colombier }
16839a747e4fSDavid du Colombier
16849a747e4fSDavid du Colombier static int
recv(Chan * c,uchar * buf,int n)16859a747e4fSDavid du Colombier recv(Chan *c, uchar *buf, int n)
16869a747e4fSDavid du Colombier {
16879a747e4fSDavid du Colombier int fd, m, len;
16889a747e4fSDavid du Colombier
16899a747e4fSDavid du Colombier fd = c->chan;
16909a747e4fSDavid du Colombier /* read count */
16919a747e4fSDavid du Colombier qlock(&c->rlock);
16929a747e4fSDavid du Colombier m = readn(fd, buf, BIT32SZ);
16939a747e4fSDavid du Colombier if(m != BIT32SZ){
16949a747e4fSDavid du Colombier qunlock(&c->rlock);
16959a747e4fSDavid du Colombier if(m < 0){
16969a747e4fSDavid du Colombier print("readn(BIT32SZ) fails: %r\n");
16979a747e4fSDavid du Colombier return -1;
16989a747e4fSDavid du Colombier }
16999a747e4fSDavid du Colombier print("readn(BIT32SZ) returns %d: %r\n", m);
17009a747e4fSDavid du Colombier return 0;
17019a747e4fSDavid du Colombier }
17029a747e4fSDavid du Colombier
17039a747e4fSDavid du Colombier len = GBIT32(buf);
17049a747e4fSDavid du Colombier if(len <= BIT32SZ || len > n){
17059a747e4fSDavid du Colombier print("recv bad length %d\n", len);
17069a747e4fSDavid du Colombier werrstr("bad length in 9P2000 message header");
17079a747e4fSDavid du Colombier qunlock(&c->rlock);
17089a747e4fSDavid du Colombier return -1;
17099a747e4fSDavid du Colombier }
17109a747e4fSDavid du Colombier len -= BIT32SZ;
17119a747e4fSDavid du Colombier m = readn(fd, buf+BIT32SZ, len);
17129a747e4fSDavid du Colombier qunlock(&c->rlock);
17139a747e4fSDavid du Colombier if(m < len){
17149a747e4fSDavid du Colombier print("recv wanted %d got %d\n", len, m);
17159a747e4fSDavid du Colombier return 0;
17169a747e4fSDavid du Colombier }
17179a747e4fSDavid du Colombier return BIT32SZ+m;
17189a747e4fSDavid du Colombier }
17199a747e4fSDavid du Colombier
17209a747e4fSDavid du Colombier static void
send(Chan * c,uchar * buf,int n)17219a747e4fSDavid du Colombier send(Chan *c, uchar *buf, int n)
17229a747e4fSDavid du Colombier {
17239a747e4fSDavid du Colombier int fd, m;
17249a747e4fSDavid du Colombier
17259a747e4fSDavid du Colombier fd = c->chan;
17269a747e4fSDavid du Colombier qlock(&c->wlock);
17279a747e4fSDavid du Colombier m = write(fd, buf, n);
17289a747e4fSDavid du Colombier qunlock(&c->wlock);
17299a747e4fSDavid du Colombier if(m == n)
17309a747e4fSDavid du Colombier return;
17319a747e4fSDavid du Colombier panic("write failed");
17329a747e4fSDavid du Colombier }
17339a747e4fSDavid du Colombier
17349a747e4fSDavid du Colombier void
serve9p2(Chan * chan,uchar * ib,int nib)17359a747e4fSDavid du Colombier serve9p2(Chan *chan, uchar *ib, int nib)
17369a747e4fSDavid du Colombier {
17379a747e4fSDavid du Colombier uchar inbuf[MSIZE+IOHDRSZ], outbuf[MSIZE+IOHDRSZ];
17389a747e4fSDavid du Colombier Fcall f, r;
17399a747e4fSDavid du Colombier char ename[64];
17409a747e4fSDavid du Colombier int error, n, type;
17419a747e4fSDavid du Colombier
17429a747e4fSDavid du Colombier chan->msize = MSIZE;
17439a747e4fSDavid du Colombier fmtinstall('F', fcallfmt);
17449a747e4fSDavid du Colombier
17459a747e4fSDavid du Colombier for(;;){
17469a747e4fSDavid du Colombier if(nib){
17479a747e4fSDavid du Colombier memmove(inbuf, ib, nib);
17489a747e4fSDavid du Colombier n = nib;
17499a747e4fSDavid du Colombier nib = 0;
17509a747e4fSDavid du Colombier }else
17519a747e4fSDavid du Colombier n = recv(chan, inbuf, sizeof inbuf);
17529a747e4fSDavid du Colombier if(chat){
17539a747e4fSDavid du Colombier print("read msg %d (fd %d)\n", n, chan->chan);
17549a747e4fSDavid du Colombier if(n <= 0)
17559a747e4fSDavid du Colombier print("\terr: %r\n");
17569a747e4fSDavid du Colombier }
17579a747e4fSDavid du Colombier if(n == 0 && (chan == cons.srvchan || chan == cons.chan))
17589a747e4fSDavid du Colombier continue;
17599a747e4fSDavid du Colombier if(n <= 0)
17609a747e4fSDavid du Colombier break;
17619a747e4fSDavid du Colombier if(convM2S(inbuf, n, &f) != n){
17629a747e4fSDavid du Colombier print("9p2: cannot decode\n");
17639a747e4fSDavid du Colombier continue;
17649a747e4fSDavid du Colombier }
17659a747e4fSDavid du Colombier
17669a747e4fSDavid du Colombier type = f.type;
17679a747e4fSDavid du Colombier if(type < Tversion || type >= Tmax || (type&1) || type == Terror){
17689a747e4fSDavid du Colombier print("9p2: bad message type %d\n", type);
17699a747e4fSDavid du Colombier continue;
17709a747e4fSDavid du Colombier }
17719a747e4fSDavid du Colombier
17729a747e4fSDavid du Colombier if(CHAT(chan))
17739a747e4fSDavid du Colombier print("9p2: f %F\n", &f);
17749a747e4fSDavid du Colombier
17759a747e4fSDavid du Colombier r.type = type+1;
17769a747e4fSDavid du Colombier r.tag = f.tag;
17779a747e4fSDavid du Colombier error = 0;
17789a747e4fSDavid du Colombier
17799a747e4fSDavid du Colombier rlock(&mainlock);
17809a747e4fSDavid du Colombier rlock(&chan->reflock);
17819a747e4fSDavid du Colombier switch(type){
17829a747e4fSDavid du Colombier default:
17839a747e4fSDavid du Colombier r.type = Rerror;
17849a747e4fSDavid du Colombier snprint(ename, sizeof ename, "unknown message: %F", &f);
17859a747e4fSDavid du Colombier r.ename = ename;
17869a747e4fSDavid du Colombier break;
17879a747e4fSDavid du Colombier case Tversion:
17889a747e4fSDavid du Colombier error = fsversion(chan, &f, &r);
17899a747e4fSDavid du Colombier break;
17909a747e4fSDavid du Colombier case Tauth:
17919a747e4fSDavid du Colombier error = fsauth(chan, &f, &r);
17929a747e4fSDavid du Colombier break;
17939a747e4fSDavid du Colombier case Tattach:
17949a747e4fSDavid du Colombier error = fsattach(chan, &f, &r);
17959a747e4fSDavid du Colombier break;
17969a747e4fSDavid du Colombier case Tflush:
17979a747e4fSDavid du Colombier error = fsflush(chan, &f, &r);
17989a747e4fSDavid du Colombier break;
17999a747e4fSDavid du Colombier case Twalk:
18009a747e4fSDavid du Colombier error = fswalk(chan, &f, &r);
18019a747e4fSDavid du Colombier break;
18029a747e4fSDavid du Colombier case Topen:
18039a747e4fSDavid du Colombier error = fsopen(chan, &f, &r);
18049a747e4fSDavid du Colombier break;
18059a747e4fSDavid du Colombier case Tcreate:
18069a747e4fSDavid du Colombier error = fscreate(chan, &f, &r);
18079a747e4fSDavid du Colombier break;
18089a747e4fSDavid du Colombier case Tread:
18099a747e4fSDavid du Colombier r.data = (char*)inbuf;
18109a747e4fSDavid du Colombier error = fsread(chan, &f, &r);
18119a747e4fSDavid du Colombier break;
18129a747e4fSDavid du Colombier case Twrite:
18139a747e4fSDavid du Colombier error = fswrite(chan, &f, &r);
18149a747e4fSDavid du Colombier break;
18159a747e4fSDavid du Colombier case Tclunk:
18169a747e4fSDavid du Colombier error = fsclunk(chan, &f, &r);
18179a747e4fSDavid du Colombier break;
18189a747e4fSDavid du Colombier case Tremove:
18199a747e4fSDavid du Colombier error = fsremove(chan, &f, &r);
18209a747e4fSDavid du Colombier break;
18219a747e4fSDavid du Colombier case Tstat:
18229a747e4fSDavid du Colombier error = fsstat(chan, &f, &r, inbuf);
18239a747e4fSDavid du Colombier break;
18249a747e4fSDavid du Colombier case Twstat:
18259a747e4fSDavid du Colombier error = fswstat(chan, &f, &r, (char*)outbuf);
18269a747e4fSDavid du Colombier break;
18279a747e4fSDavid du Colombier }
18289a747e4fSDavid du Colombier runlock(&chan->reflock);
18299a747e4fSDavid du Colombier runlock(&mainlock);
18309a747e4fSDavid du Colombier
18319a747e4fSDavid du Colombier if(error != 0){
18329a747e4fSDavid du Colombier r.type = Rerror;
18339a747e4fSDavid du Colombier if(error >= MAXERR){
18349a747e4fSDavid du Colombier snprint(ename, sizeof(ename), "error %d", error);
18359a747e4fSDavid du Colombier r.ename = ename;
18369a747e4fSDavid du Colombier }
18379a747e4fSDavid du Colombier else
18389a747e4fSDavid du Colombier r.ename = errstring[error];
18399a747e4fSDavid du Colombier }
18409a747e4fSDavid du Colombier if(CHAT(chan))
18419a747e4fSDavid du Colombier print("9p2: r %F\n", &r);
18429a747e4fSDavid du Colombier
18439a747e4fSDavid du Colombier n = convS2M(&r, outbuf, sizeof outbuf);
18449a747e4fSDavid du Colombier if(n == 0){
18459a747e4fSDavid du Colombier type = r.type;
18469a747e4fSDavid du Colombier r.type = Rerror;
18479a747e4fSDavid du Colombier snprint(ename, sizeof(ename), "9p2: convS2M: type %d", type);
18489a747e4fSDavid du Colombier r.ename = ename;
18499a747e4fSDavid du Colombier print(ename);
18509a747e4fSDavid du Colombier n = convS2M(&r, outbuf, sizeof outbuf);
18519a747e4fSDavid du Colombier if(n == 0){
18529a747e4fSDavid du Colombier /*
18539a747e4fSDavid du Colombier * What to do here, the failure notification failed?
18549a747e4fSDavid du Colombier */
18559a747e4fSDavid du Colombier panic("can't write anything at all");
18569a747e4fSDavid du Colombier }
18579a747e4fSDavid du Colombier }
18589a747e4fSDavid du Colombier send(chan, outbuf, n);
18599a747e4fSDavid du Colombier }
18609a747e4fSDavid du Colombier fileinit(chan);
18619a747e4fSDavid du Colombier close(chan->chan);
18629a747e4fSDavid du Colombier if(chan == cons.srvchan || chan == cons.chan)
18639a747e4fSDavid du Colombier print("console chan read error");
18649a747e4fSDavid du Colombier }
1865b7b24591SDavid du Colombier
1866