4 * 9P protocol interface
8 RELOAD = 0, /* commands written to ctl file */
14 static void rflush(Fcall*),
15 rauth(Fcall*), rattach(Fcall*),
16 rclone(Fcall*), rwalk(Fcall*),
18 rcreate(Fcall*), rread(Fcall*),
19 rwrite(Fcall*), rclunk(Fcall*),
20 rremove(Fcall*), rstat(Fcall*),
21 rwstat(Fcall*), rversion(Fcall*);
23 static Fid* newfid(int);
24 static void reply(Fcall*, char*);
26 static void (*fcalls[])(Fcall*) = {
43 static Keyword cmds[] = {
59 while((n = read9pmsg(srvfd, rbuf, sizeof rbuf-1)) != 0){
61 fatal("mount read: %r");
62 if(convM2S(rbuf, n, &rhdr) != n){
64 fprint(2, "%s: malformed message\n", argv0);
65 fatal("convM2S format error: %r");
68 fprint(debugfd, "<-%F\n", &rhdr);/**/
70 if(!fcalls[rhdr.type])
71 reply(&rhdr, "bad fcall type");
73 (*fcalls[rhdr.type])(&rhdr);
78 * write a protocol reply to the client
81 reply(Fcall *r, char *error)
92 fprint(debugfd, "->%F\n", r);/**/
93 n = convS2M(r, rbuf, sizeof rbuf);
96 if(write(srvfd, rbuf, n) < 0)
102 * lookup a fid. if not found, create a new one.
113 for(f = fids; f; f = f->next){
118 } else if(!ff && !f->busy)
122 ff = mallocz(sizeof(*f), 1);
134 f->version = "9P2000";
135 if(f->msize > MAXRPC)
143 reply(f, "ratfs: authentication not required");
158 if((d=dirstat(conffile)) != nil && d->mtime > lastconftime)
161 if((d=dirstat(ctlfile)) != nil && d->mtime > lastctltime)
166 fidp = newfid(f->fid);
169 fidp->name = root->d.name;
170 fidp->uid = atom(f->uname);
171 f->qid = root->d.qid;
180 fidp = newfid(f->fid);
181 if(fidp->node && fidp->node->d.type == Dummynode){
182 reply(f, "can't clone an address");
185 nf = newfid(f->newfid);
187 nf->node = fidp->node;
189 nf->name = fidp->name;
203 fidp = newfid(f->fid);
204 if(fidp->node && fidp->node->d.type == Dummynode){
205 reply(f, "can't walk an address node");
208 if(f->fid == f->newfid)
211 nf = newfid(f->newfid);
213 nf->node = fidp->node;
215 nf->name = fidp->name;
221 for(i=0; i<f->nwname; i++){
222 err = walk(f->wname[i], nf);
225 r.wqid[i] = nf->node->d.qid;
229 if(i < f->nwname && f->fid != f->newfid){
235 if(i > 0 && i < f->nwname && f->fid == f->newfid){
237 * try to put things back;
238 * we never get this sort of call from the kernel
243 memmove(f->wqid, r.wqid, sizeof f->wqid);
252 * We don't have to do full permission checking because most files
253 * have restricted semantics:
254 * The ctl file is only writable
255 * All others, including directories, are only readable
263 fidp = newfid(f->fid);
268 mode = f->mode&(OREAD|OWRITE|ORDWR);
269 if(fidp->node->d.type == Ctlfile) {
271 reply(f, "permission denied");
276 reply(f, "permission denied or operation not supported");
280 f->qid = fidp->node->d.qid;
286 permitted(Fid *fp, Node *np, int mask)
291 return (fp->uid==np->d.uid && (mode&(mask<<6)))
292 || (fp->uid==np->d.gid && (mode&(mask<<3)))
297 * creates are only allowed in the "trusted" subdirectory
298 * we also assume that the groupid == the uid
306 fidp = newfid(f->fid);
308 if((np->d.mode&DMDIR) == 0){
309 reply(f, "not a directory");
313 if(!permitted(fidp, np, AWRITE)) {
314 reply(f, "permission denied");
318 /* Ignore the supplied mode and force it to be non-writable */
320 np = newnode(np, f->name, Trustedtemp, 0444, trustedqid++);
321 if(trustedqid >= Qaddrfile) /* wrap QIDs */
322 trustedqid = Qtrustedfile;
323 cidrparse(&np->ip, f->name);
325 np->d.uid = fidp->uid;
326 np->d.gid = np->d.uid;
327 np->d.muid = np->d.muid;
335 * only directories can be read. everthing else returns EOF.
345 fidp = newfid(f->fid);
346 f->data = (char*)rbuf+IOHDRSZ;
347 if(fidp->open == 0) {
348 reply(f, "file not open");
351 if ((fidp->node->d.mode&DMDIR) == 0){
361 switch(fidp->node->d.type) {
365 f->count = dread(fidp, cnt);
369 f->count = hread(fidp, cnt);
372 reply(f, "can't read this type of file");
380 * only the 'ctl' file in the top level directory is writable
388 char *err, *argv[10];
390 fidp = newfid(f->fid);
391 if(fidp->node->d.mode & DMDIR){
392 reply(f, "directories are not writable");
395 if(fidp->open == 0) {
396 reply(f, "file not open");
400 if (!permitted(fidp, fidp->node, AWRITE)) {
401 reply(f, "permission denied");
405 f->data[f->count] = 0; /* the extra byte in rbuf leaves room */
406 n = tokenize(f->data, argv, 10);
408 switch(findkey(argv[0], cmds)){
415 debugfd = create(argv[1], OWRITE, 0666);
417 err = "create failed";
427 err = "unknown command";
438 fidp = newfid(f->fid);
448 * no files or directories are removable; this becomes clunk;
456 fidp = newfid(f->fid);
459 * only trusted temporary files can be removed
460 * and only by their owner.
462 if(fidp->node->d.type != Trustedtemp){
463 reply(f, "can't be removed");
466 if(fidp->uid != fidp->node->d.uid){
467 reply(f, "permission denied");
470 dir = fidp->node->parent;
471 for(np = dir->children; np; np = np->sibs)
472 if(np->sibs == fidp->node)
475 np->sibs = fidp->node->sibs;
477 dir->children = fidp->node->sibs;
493 fidp = newfid(f->fid);
494 if (fidp->node->d.type == Dummynode)
495 dummy.d.name = fidp->name;
496 f->stat = (uchar*)rbuf+4+1+2+2; /* knows about stat(5) */
497 f->nstat = convD2M(&fidp->node->d, f->stat, MAXRPC);
498 if(f->nstat <= BIT16SZ)
499 reply(f, "ratfs: convD2M");
508 reply(f, "wstat not implemented");