5 * buggery to give false qid for
6 * the top 2 levels of the dump fs
9 mkqid(Qid* qid, Dentry *d, int buggery)
13 if(buggery && d->qid.path == QPROOT && (d->qid.path & QPDIR)){
15 if(c >= '0' && c <= '9'){
17 qid->vers = d->qid.version;
20 c = (c-'0')*10 + (d->name[1]-'0');
27 mkqid9p2(qid, &d->qid, d->mode);
31 mkqidcmp(Qid* qid, Dentry *d)
36 if(qid->path==tmp.path && (qid->type&QTDIR)==(tmp.type&QTDIR))
42 f_nop(Chan *cp, Oldfcall *in, Oldfcall *ou)
48 print("c_nop %d\n", cp->chan);
52 f_flush(Chan *cp, Oldfcall *in, Oldfcall *ou)
58 print("c_flush %d\n", cp->chan);
59 runlock(&cp->reflock);
61 wunlock(&cp->reflock);
66 f_session(Chan *cp, Oldfcall *in, Oldfcall *ou)
69 print("c_session %d\n", cp->chan);
71 memmove(cp->rchal, in->chal, sizeof(cp->rchal));
72 if(wstatallow || cp == cons.srvchan){
73 memset(ou->chal, 0, sizeof(ou->chal));
74 memset(ou->authid, 0, sizeof(ou->authid));
77 memmove(ou->chal, cp->chal, sizeof(ou->chal));
78 memmove(ou->authid, nvr.authid, sizeof(ou->authid));
80 sprint(ou->authdom, "%s.%s", service, nvr.authdom);
85 f_attach(Chan *cp, Oldfcall *in, Oldfcall *ou)
95 print("c_attach %d\n", cp->chan);
96 print(" fid = %d\n", in->fid);
97 print(" uid = %s\n", in->uname);
98 print(" arg = %s\n", in->aname);
101 ou->qid = QID9P1(0,0);
103 if(!in->aname[0]) /* default */
104 strncpy(in->aname, filesys[0].name, sizeof(in->aname));
106 f = filep(cp, in->fid, 1);
113 if(authorize(cp, in, ou) == 0 || strcmp(in->uname, "adm") == 0){
117 u = strtouid(in->uname);
124 fs = fsstr(in->aname);
129 raddr = getraddr(fs->dev);
130 p = getbuf(fs->dev, raddr, Bread);
132 if(!d || checktag(p, Tdir, QPROOT) || !(d->mode & DALLOC)) {
137 if(iaccess(f, d, DREAD)) {
141 accessdir(p, d, FREAD);
142 mkqid(&f->qid, d, 1);
150 mkqid9p1(&ou->qid, &f->qid);
163 f_clone(Chan *cp, Oldfcall *in, Oldfcall *ou)
169 print("c_clone %d\n", cp->chan);
170 print(" old fid = %d\n", in->fid);
171 print(" new fid = %d\n", in->newfid);
180 f1 = filep(cp, fid, 0);
181 f2 = filep(cp, fid1, 1);
184 f2 = filep(cp, fid1, 1);
185 f1 = filep(cp, fid, 0);
195 f2->open = f1->open & ~FREMOV;
201 f2->wpath = getwp(f1->wpath);
212 f_walk(Chan *cp, Oldfcall *in, Oldfcall *ou)
222 print("c_walk %d\n", cp->chan);
223 print(" fid = %d\n", in->fid);
224 print(" name = %s\n", in->name);
228 ou->qid = QID9P1(0,0);
230 f = filep(cp, in->fid, 0);
235 p = getbuf(f->fs->dev, f->addr, Bread);
236 d = getdir(p, f->slot);
237 if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
241 if(!(d->mode & DDIR)) {
245 if(ou->err = mkqidcmp(&f->qid, d))
247 if(cp != cons.chan && iaccess(f, d, DEXEC)) {
251 accessdir(p, d, FREAD);
252 if(strcmp(in->name, ".") == 0)
254 if(strcmp(in->name, "..") == 0) {
259 addr = f->wpath->addr;
260 slot = f->wpath->slot;
261 p1 = getbuf(f->fs->dev, addr, Bread);
262 d1 = getdir(p1, slot);
263 if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
274 for(addr=0;; addr++) {
275 p1 = dnodebuf(p, d, addr, 0);
276 if(!p1 || checktag(p1, Tdir, d->qid.path) ) {
282 for(slot=0; slot<DIRPERBUF; slot++) {
283 d1 = getdir(p1, slot);
284 if(!(d1->mode & DALLOC))
286 if(strncmp(in->name, d1->name, sizeof(in->name)))
301 slot += DIRPERBUF*addr;
309 mkqid(&f->qid, d1, 1);
314 mkqid9p1(&ou->qid, &f->qid);
325 f_clunk(Chan *cp, Oldfcall *in, Oldfcall *ou)
332 print("c_clunk %d\n", cp->chan);
333 print(" fid = %d\n", in->fid);
336 f = filep(cp, in->fid, 0);
344 if(t->time < tim || t->file != f)
346 t->time = 0; /* free the lock */
350 ou->err = doremove(f, 0);
362 f_clwalk(Chan *cp, Oldfcall *in, Oldfcall *ou)
367 print("c_clwalk macro\n");
369 f_clone(cp, in, ou); /* sets tag, fid */
373 in->fid = in->newfid;
374 f_walk(cp, in, ou); /* sets tag, fid, qid */
378 * if error is "no entry"
379 * return non error and fid
382 f_clunk(cp, in, ou); /* sets tag, fid */
386 print(" error: %s\n", errstring[er]);
395 f_clunk(cp, in, ou); /* sets tag, fid */
406 f_open(Chan *cp, Oldfcall *in, Oldfcall *ou)
416 print("c_open %d\n", cp->chan);
417 print(" fid = %d\n", in->fid);
418 print(" mode = %o\n", in->mode);
422 f = filep(cp, in->fid, 0);
429 * if remove on close, check access here
431 ro = isro(f->fs->dev) || (cp != cons.chan && writegroup && !ingroup(f->uid, writegroup));
432 if(in->mode & MRCLOSE) {
438 * check on parent directory of file to be deleted
440 if(f->wpath == 0 || f->wpath->addr == f->addr) {
444 p = getbuf(f->fs->dev, f->wpath->addr, Bread);
445 d = getdir(p, f->wpath->slot);
446 if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
450 if(iaccess(f, d, DWRITE)) {
456 p = getbuf(f->fs->dev, f->addr, Bread);
457 d = getdir(p, f->slot);
458 if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
462 if(ou->err = mkqidcmp(&f->qid, d))
465 switch(in->mode & 7) {
468 if(iaccess(f, d, DREAD) && !writeallow)
474 if((d->mode & DDIR) ||
475 (iaccess(f, d, DWRITE) && !writeallow))
485 if((d->mode & DDIR) ||
486 (iaccess(f, d, DREAD) && !writeallow) ||
487 (iaccess(f, d, DWRITE) && !writeallow))
497 if((d->mode & DDIR) ||
498 iaccess(f, d, DEXEC))
507 if(in->mode & MTRUNC) {
508 if((d->mode & DDIR) ||
509 (iaccess(f, d, DWRITE) && !writeallow))
517 if(d->mode & DLOCK) {
525 if(in->mode & MRCLOSE)
528 if(in->mode & MTRUNC)
529 if(!(d->mode & DAPND))
533 mkqid9p1(&ou->qid, &qid);
549 f_create(Chan *cp, Oldfcall *in, Oldfcall *ou)
554 int slot, slot1, fmod;
555 long addr, addr1, path;
561 print("c_create %d\n", cp->chan);
562 print(" fid = %d\n", in->fid);
563 print(" name = %s\n", in->name);
564 print(" perm = %lx+%lo\n", (in->perm>>28)&0xf,
566 print(" mode = %d\n", in->mode);
570 f = filep(cp, in->fid, 0);
575 if(isro(f->fs->dev) || (cp != cons.chan && writegroup && !ingroup(f->uid, writegroup))) {
580 p = getbuf(f->fs->dev, f->addr, Bread);
581 d = getdir(p, f->slot);
582 if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
586 if(ou->err = mkqidcmp(&f->qid, d))
588 if(!(d->mode & DDIR)) {
592 if(cp != cons.chan && iaccess(f, d, DWRITE) && !writeallow) {
596 accessdir(p, d, FREAD);
597 if(!strncmp(in->name, ".", sizeof(in->name)) ||
598 !strncmp(in->name, "..", sizeof(in->name))) {
602 if(checkname(in->name)) {
608 for(addr=0;; addr++) {
609 p1 = dnodebuf(p, d, addr, 0);
613 p1 = dnodebuf(p, d, addr, Tdir);
619 if(checktag(p1, Tdir, d->qid.path)) {
623 for(slot=0; slot<DIRPERBUF; slot++) {
624 d1 = getdir(p1, slot);
625 if(!(d1->mode & DALLOC)) {
628 slot1 = slot + addr*DIRPERBUF;
632 if(!strncmp(in->name, d1->name, sizeof(in->name))) {
640 switch(in->mode & 7) {
642 case MREAD: /* seems only useful to make directories */
659 if((in->mode & MTRUNC) || (in->perm & PAPND) || (fmod & FWRITE))
664 path = qidpathgen(&f->fs->dev);
665 p1 = getbuf(f->fs->dev, addr1, Bread|Bimm|Bmod);
666 d1 = getdir(p1, slot1);
667 if(!d1 || checktag(p1, Tdir, d->qid.path)) {
672 if(d1->mode & DALLOC) {
677 strncpy(d1->name, in->name, sizeof(in->name));
679 * bogus argument passing -- see console.c
681 if(cp == cons.chan) {
687 in->perm &= d->mode | ~0666;
689 in->perm &= d->mode | ~0777;
693 d1->mode = DALLOC | (in->perm & 0777);
694 if(in->perm & PDIR) {
696 d1->qid.path |= QPDIR;
701 if(in->perm & PLOCK) {
705 accessdir(p1, d1, FWRITE);
708 accessdir(p, d, FWRITE);
711 * do a walk to new directory entry
725 if(in->mode & MRCLOSE)
732 mkqid9p1(&ou->qid, &qid);
751 f_read(Chan *cp, Oldfcall *in, Oldfcall *ou)
757 long addr, offset, tim;
758 int nread, count, n, o, slot;
761 print("c_read %d\n", cp->chan);
762 print(" fid = %d\n", in->fid);
763 print(" offset = %ld\n", in->offset);
764 print(" count = %ld\n", in->count);
771 f = filep(cp, in->fid, 0);
776 if(!(f->open & FREAD)) {
780 if(count < 0 || count > MAXDAT) {
788 p = getbuf(f->fs->dev, f->addr, Bread);
789 d = getdir(p, f->slot);
790 if(!d || !(d->mode & DALLOC)) {
794 if(ou->err = mkqidcmp(&f->qid, d))
798 if(t->time < tim || t->file != f) {
803 t->time = tim + TLOCK;
805 accessdir(p, d, FREAD);
810 if(offset >= d->size)
812 else if(offset+count > d->size)
813 count = d->size - offset;
815 addr = offset / BUFSIZE;
816 if(addr == f->lastra+1)
817 dbufread(p, d, addr+1);
819 o = offset % BUFSIZE;
823 p1 = dnodebuf(p, d, addr, 0);
825 if(checktag(p1, Tfile, QPNONE)) {
830 memmove(ou->data+nread, p1->iobuf+o, n);
833 memset(ou->data+nread, 0, n);
841 p1 = dnodebuf(p, d, addr, 0);
844 if(checktag(p1, Tdir, QPNONE)) {
850 for(slot=0; slot<DIRPERBUF; slot++) {
851 d1 = getdir(p1, slot);
852 if(!(d1->mode & DALLOC))
862 if(convD2M9p1(d1, ou->data+nread) != n)
863 print("dirread convD2M\n");
872 count = in->count - nread;
874 memset(ou->data+nread, 0, count);
882 print(" nread = %d\n", nread);
886 f_write(Chan *cp, Oldfcall *in, Oldfcall *ou)
892 long offset, addr, tim;
893 int count, nwrite, o, n;
896 print("c_write %d\n", cp->chan);
897 print(" fid = %d\n", in->fid);
898 print(" offset = %ld\n", in->offset);
899 print(" count = %ld\n", in->count);
906 f = filep(cp, in->fid, 0);
911 if(!(f->open & FWRITE)) {
915 if(isro(f->fs->dev) || (cp != cons.chan && writegroup && !ingroup(f->uid, writegroup))) {
919 if(count < 0 || count > MAXDAT) {
927 p = getbuf(f->fs->dev, f->addr, Bread|Bmod);
928 d = getdir(p, f->slot);
929 if(!d || !(d->mode & DALLOC)) {
933 if(ou->err = mkqidcmp(&f->qid, d))
937 if(t->time < tim || t->file != f) {
942 t->time = tim + TLOCK;
944 accessdir(p, d, FWRITE);
947 if(offset+count > d->size)
948 d->size = offset+count;
950 addr = offset / BUFSIZE;
951 o = offset % BUFSIZE;
955 p1 = dnodebuf(p, d, addr, Tfile);
960 if(checktag(p1, Tfile, d->qid.path)) {
965 memmove(p1->iobuf+o, in->data+nwrite, n);
973 print(" nwrite = %d\n", nwrite);
985 doremove(File *f, int iscon)
994 if(isro(f->fs->dev) || (f->cp != cons.chan && writegroup && !ingroup(f->uid, writegroup))) {
999 * check on parent directory of file to be deleted
1001 if(f->wpath == 0 || f->wpath->addr == f->addr) {
1005 p1 = getbuf(f->fs->dev, f->wpath->addr, Bread);
1006 d1 = getdir(p1, f->wpath->slot);
1007 if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
1011 if(!iscon && iaccess(f, d1, DWRITE)) {
1015 accessdir(p1, d1, FWRITE);
1020 * check on file to be deleted
1022 p = getbuf(f->fs->dev, f->addr, Bread);
1023 d = getdir(p, f->slot);
1024 if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
1028 if(err = mkqidcmp(&f->qid, d))
1032 * if deleting a directory, make sure it is empty
1034 if((d->mode & DDIR))
1035 for(addr=0;; addr++) {
1036 p1 = dnodebuf(p, d, addr, 0);
1039 if(checktag(p1, Tdir, d->qid.path)) {
1043 for(slot=0; slot<DIRPERBUF; slot++) {
1044 d1 = getdir(p1, slot);
1045 if(!(d1->mode & DALLOC))
1057 memset(d, 0, sizeof(Dentry));
1058 settag(p, Tdir, QPNONE);
1069 f_remove(Chan *cp, Oldfcall *in, Oldfcall *ou)
1074 print("c_remove %d\n", cp->chan);
1075 print(" fid = %d\n", in->fid);
1078 f = filep(cp, in->fid, 0);
1083 ou->err = doremove(f, cp==cons.chan);
1092 f_stat(Chan *cp, Oldfcall *in, Oldfcall *ou)
1099 print("c_stat %d\n", cp->chan);
1100 print(" fid = %d\n", in->fid);
1104 memset(ou->stat, 0, sizeof(ou->stat));
1105 f = filep(cp, in->fid, 0);
1110 p = getbuf(f->fs->dev, f->addr, Bread);
1111 d = getdir(p, f->slot);
1112 if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
1116 if(ou->err = mkqidcmp(&f->qid, d))
1118 if(d->qid.path == QPROOT) /* stat of root gives time */
1120 if(convD2M9p1(d, ou->stat) != DIRREC)
1121 print("stat convD2M\n");
1132 f_wstat(Chan *cp, Oldfcall *in, Oldfcall *ou)
1141 print("c_wstat %d\n", cp->chan);
1142 print(" fid = %d\n", in->fid);
1148 f = filep(cp, in->fid, 0);
1153 if(isro(f->fs->dev) || (cp != cons.chan && writegroup && !ingroup(f->uid, writegroup))) {
1162 p1 = getbuf(f->fs->dev, f->wpath->addr, Bread);
1163 d1 = getdir(p1, f->wpath->slot);
1164 if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
1170 p = getbuf(f->fs->dev, f->addr, Bread);
1171 d = getdir(p, f->slot);
1172 if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
1176 if(ou->err = mkqidcmp(&f->qid, d))
1179 convM2D9p1(in->stat, &xd);
1181 print(" d.name = %s\n", xd.name);
1182 print(" d.uid = %d\n", xd.uid);
1183 print(" d.gid = %d\n", xd.gid);
1184 print(" d.mode = %.4x\n", xd.mode);
1191 while(xd.uid != d->uid) {
1192 if(wstatallow) /* set to allow chown during boot */
1201 * a) owner and in new group
1202 * b) leader of both groups
1204 while(xd.gid != d->gid) {
1205 if(wstatallow || writeallow) /* set to allow chgrp during boot */
1207 if(d->uid == f->uid && ingroup(f->uid, xd.gid))
1209 if(leadgroup(f->uid, xd.gid))
1210 if(leadgroup(f->uid, d->gid))
1218 * must have write permission in parent
1221 strncpy(xd.name, d->name, sizeof(xd.name));
1222 while(strncmp(d->name, xd.name, sizeof(d->name)) != 0) {
1223 if(checkname(xd.name)) {
1228 if(strcmp(xd.name, ".") == 0 || strcmp(xd.name, "..") == 0) {
1234 * drop entry to prevent lock, then
1235 * check that destination name is unique,
1238 for(addr=0;; addr++) {
1239 p = dnodebuf(p1, d1, addr, 0);
1242 if(checktag(p, Tdir, d1->qid.path)) {
1246 for(slot=0; slot<DIRPERBUF; slot++) {
1247 d = getdir(p, slot);
1248 if(!(d->mode & DALLOC))
1250 if(!strncmp(xd.name, d->name, sizeof(xd.name))) {
1261 p = getbuf(f->fs->dev, f->addr, Bread);
1262 d = getdir(p, f->slot);
1263 if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
1268 if(wstatallow || writeallow) /* set to allow rename during boot */
1270 if(!d1 || iaccess(f, d1, DWRITE)) {
1278 * if mode/time, either
1280 * b) leader of either group
1282 while(d->mtime != xd.mtime ||
1283 ((d->mode^xd.mode) & (DAPND|DLOCK|0777))) {
1284 if(wstatallow) /* set to allow chmod during boot */
1286 if(d->uid == f->uid)
1288 if(leadgroup(f->uid, xd.gid))
1290 if(leadgroup(f->uid, d->gid))
1295 d->mtime = xd.mtime;
1298 d->mode = (xd.mode & (DAPND|DLOCK|0777)) | (d->mode & (DALLOC|DDIR));
1300 strncpy(d->name, xd.name, sizeof(d->name));
1304 d->atime = xd.atime;
1306 d->mtime = xd.mtime;
1308 accessdir(p, d, FWSTAT);
1321 (*call9p1[MAXSYSCALL])(Chan*, Oldfcall*, Oldfcall*) =
1324 [Tosession9p1] f_session,
1325 [Tsession9p1] f_session,
1326 [Tflush9p1] f_flush,
1327 [Toattach9p1] f_attach,
1328 [Tattach9p1] f_attach,
1329 [Tclone9p1] f_clone,
1332 [Tcreate9p1] f_create,
1334 [Twrite9p1] f_write,
1335 [Tclunk9p1] f_clunk,
1336 [Tremove9p1] f_remove,
1338 [Twstat9p1] f_wstat,
1339 [Tclwalk9p1] f_clwalk,
1343 send(Chan *c, uchar *buf, int n)
1348 m = write(fd, buf, n);
1351 panic("write failed");
1355 error9p1(Chan *c, uchar *buf)
1365 serve9p1(Chan *chan, uchar *ib, int nib)
1368 uchar inbuf[MAXMSG+MAXDAT], outbuf[MAXMSG+MAXDAT];
1373 memmove(inbuf, ib, nib);
1377 n = read(chan->chan, inbuf, sizeof inbuf);
1379 print("read msg %d\n", n);
1380 if(n == 0 && (chan == cons.srvchan || chan == cons.chan))
1384 if(convM2S9p1(inbuf, &fi, n) != n){
1385 error9p1(chan, outbuf);
1390 if(t < 0 || t >= MAXSYSCALL || (t&1) || !call9p1[t]) {
1391 print("9p1: bad message type\n");
1392 error9p1(chan, outbuf);
1397 print("9p1: fi %O\n", &fi);
1400 * set up reply message
1404 fo.data = (char*)outbuf + 8;
1407 * call the file system
1410 cons.rate.count += n;
1413 * call the file system
1416 rlock(&chan->reflock);
1418 (*call9p1[t])(chan, &fi, &fo);
1420 runlock(&chan->reflock);
1427 print("9p1: fo %O\n", &fo);
1430 strcpy(fo.ename, errstring[fo.err]);
1432 print(" error: %s\n", fo.ename);
1433 fo.type = Terror9p1+1;
1436 n = convS2M9p1(&fo, outbuf);
1438 print("9p1: bad S2M conversion\n");
1439 error9p1(chan, outbuf);
1443 cons.rate.count += n;
1444 send(chan, outbuf, n);