4 enum { MSIZE = MAXDAT+MAXMSG };
7 mkmode9p1(ulong mode9p2)
12 * Assume this is for an allocated entry.
14 mode = DALLOC|(mode9p2 & 0777);
17 if(mode9p2 & DMAPPEND)
28 mkqid9p1(Qid9p1* qid9p1, Qid* qid)
30 qid9p1->path = qid->path;
32 qid9p1->path ^= QPDIR;
33 qid9p1->version = qid->vers;
37 mktype9p2(int mode9p1)
55 mkmode9p2(int mode9p1)
59 mode = mode9p1 & 0777;
73 mkqid9p2(Qid* qid, Qid9p1* qid9p1, int mode9p1)
75 qid->path = qid9p1->path;
78 qid->vers = qid9p1->version;
79 qid->type = mktype9p2(mode9p1);
83 mkdir9p2(Dir* dir, Dentry* dentry, void* strs)
87 memset(dir, 0, sizeof(Dir));
88 mkqid(&dir->qid, dentry, 1);
89 dir->mode = mkmode9p2(dentry->mode);
90 dir->atime = dentry->atime;
91 dir->mtime = dentry->mtime;
92 dir->length = dentry->size;
96 strncpy(p, dentry->name, NAMELEN);
101 uidtostr(p, dentry->uid, 1);
105 uidtostr(p, dentry->gid, 1);
109 uidtostr(p, dentry->muid, 1);
116 * buggery to give false qid for
117 * the top 2 levels of the dump fs
120 mkqid(Qid* qid, Dentry *d, int buggery)
124 if(buggery && d->qid.path == (QPDIR|QPROOT)){
126 if(isascii(c) && isdigit(c)){
128 qid->vers = d->qid.version;
131 c = (c-'0')*10 + (d->name[1]-'0');
132 if(c >= 1 && c <= 12)
138 mkqid9p2(qid, &d->qid, d->mode);
142 mkqidcmp(Qid* qid, Dentry *d)
147 if(qid->path == tmp.path && qid->type == tmp.type)
153 version(Chan* chan, Fcall* f, Fcall* r)
155 if(chan->protocol != nil || f->msize < 256)
164 * Should check the '.' stuff here.
166 if(strcmp(f->version, VERSION9P) == 0){
167 r->version = VERSION9P;
168 chan->protocol = serve9p2;
169 chan->msize = r->msize;
171 r->version = "unknown";
179 auth(Chan* chan, Fcall* f, Fcall* r)
191 return Eauthdisabled;
196 if(strcmp(f->uname, "none") == 0)
199 if(!aname[0]) /* default */
201 file = filep(chan, f->afid, 1);
212 file->qid.path = authpath.hi++;
214 file->qid.type = QTAUTH;
217 file->open = FREAD+FWRITE;
221 if((file->auth = authnew()) == nil){
236 authorize(Chan* chan, Fcall* f)
241 db = cons.flags & authdebugflag;
244 uid = strtouid(f->uname);
246 fprint(2, "permission granted by noauth uid %s = %d\n",
251 if(f->afid == NOFID && (!nonone || chan->authok)){
252 uid = strtouid(f->uname);
254 fprint(2, "permission granted to none: uid %s = %d\n",
259 af = filep(chan, f->afid, 0);
262 fprint(2, "authorize: af == nil\n");
266 /* fake read to get auth info */
267 authread(af, nil, 0);
270 fprint(2, "authorize: uid is %d\n", uid);
280 attach(Chan* chan, Fcall* f, Fcall* r)
291 if(!aname[0]) /* default */
295 file = filep(chan, f->fid, 1);
302 if(chan != cons.chan){
303 if(noattach && strcmp(f->uname, "none")) {
307 u = authorize(chan, f);
321 raddr = getraddr(fs->dev);
322 p = getbuf(fs->dev, raddr, Brd);
323 if(p == nil || checktag(p, Tdir, QPROOT)){
328 if(d == nil || !(d->mode & DALLOC)){
332 if(iaccess(file, d, DEXEC) ||
333 file->uid == 0 && fs->dev->type == Devro) {
335 * 'none' not allowed on dump
340 accessdir(p, d, FREAD, file->uid);
341 mkqid(&file->qid, d, 1);
351 snprint(chan->whoname, sizeof(chan->whoname), "%s", f->uname);
352 chan->whotime = time(nil);
365 flush(Chan* chan, Fcall*, Fcall*)
367 runlock(&chan->reflock);
368 wlock(&chan->reflock);
369 wunlock(&chan->reflock);
370 rlock(&chan->reflock);
376 clone(File* nfile, File* file)
380 nfile->qid = file->qid;
383 nfile->wpath = file->wpath;
384 for(wpath = nfile->wpath; wpath != nil; wpath = wpath->up)
388 nfile->fs = file->fs;
389 nfile->addr = file->addr;
390 nfile->slot = file->slot;
391 nfile->uid = file->uid;
392 nfile->open = file->open & ~FREMOV;
396 walkname(File* file, char* wname, Qid* wqid)
401 int error, slot, mask;
407 * File must not have been opened for I/O by an open
408 * or create message and must represent a directory.
415 p = getbuf(file->fs->dev, file->addr, Brd);
416 if(p == nil || checktag(p, Tdir, QPNONE)){
420 d = getdir(p, file->slot);
421 if(d == nil || !(d->mode & DALLOC)){
425 if(!(d->mode & DDIR)){
429 if(error = mkqidcmp(&file->qid, d))
433 * For walked elements the implied user must
434 * have permission to search the directory.
436 if(iaccess(file, d, DEXEC)){
440 accessdir(p, d, FREAD, file->uid);
442 if(strcmp(wname, ".") == 0){
448 if(strcmp(wname, "..") == 0){
453 addr = file->wpath->addr;
454 slot = file->wpath->slot;
455 p1 = getbuf(file->fs->dev, addr, Brd);
456 if(p1 == nil || checktag(p1, Tdir, QPNONE)){
460 d1 = getdir(p1, slot);
461 if(d == nil || !(d1->mode & DALLOC)){
467 file->wpath = file->wpath->up;
472 for(addr = 0; ; addr++){
474 p = getbuf(file->fs->dev, file->addr, Brd);
475 if(p == nil || checktag(p, Tdir, QPNONE)){
479 d = getdir(p, file->slot);
480 if(d == nil || !(d->mode & DALLOC)){
485 p1 = dnodebuf1(p, d, addr, 0, file->uid);
487 if(p1 == nil || checktag(p1, Tdir, d->qid.path ^ QPDIR)){
492 if(file->fs->dev->type == Devro)
494 for(slot = 0; slot < DIRPERBUF; slot++){
495 d1 = getdir(p1, slot);
496 if ((d1->mode & mask) != DALLOC ||
497 strncmp(wname, d1->name, NAMELEN) != 0)
502 if((w = newwp()) == nil){
506 w->addr = file->addr;
507 w->slot = file->slot;
510 slot += DIRPERBUF*addr;
518 file->addr = p1->addr;
519 mkqid(&file->qid, d1, 1);
536 walk(Chan* chan, Fcall* f, Fcall* r)
539 File *file, *nfile, tfile;
542 * The file identified by f->fid must be valid in the
543 * current session and must not have been opened for I/O
544 * by an open or create message.
546 if((file = filep(chan, f->fid, 0)) == nil)
554 * If newfid is not the same as fid, allocate a new file;
555 * a side effect is checking newfid is not already in use (error);
556 * if there are no names to walk this will be equivalent to a
557 * simple 'clone' operation.
558 * Otherwise, fid and newfid are the same and if there are names
559 * to walk make a copy of 'file' to be used during the walk as
560 * 'file' must only be updated on success.
561 * Finally, it's a no-op if newfid is the same as fid and f->nwname
565 if(f->newfid != f->fid){
566 if((nfile = filep(chan, f->newfid, 1)) == nil){
570 } else if(f->nwname != 0){
572 memset(nfile, 0, sizeof(File));
582 * Should check name is not too long.
585 for(nwname = 0; nwname < f->nwname; nwname++){
586 error = walkname(nfile, f->wname[nwname], &r->wqid[r->nwqid]);
587 if(error != 0 || ++r->nwqid >= MAXDAT/sizeof(Qid))
593 * Newfid must be different to fid (see above)
594 * so this is a simple 'clone' operation - there's
595 * nothing to do except unlock unless there's
599 freewp(nfile->wpath);
604 } else if(r->nwqid < f->nwname){
606 * Didn't walk all elements, 'clunk' nfile
607 * and leave 'file' alone.
608 * Clear error if some of the elements were
611 freewp(nfile->wpath);
620 * Walked all elements. If newfid is the same
621 * as fid must update 'file' from the temporary
622 * copy used during the walk.
623 * Otherwise just unlock (when using tfile there's
624 * no need to unlock as it's a local).
627 file->qid = nfile->qid;
629 file->wpath = nfile->wpath;
630 file->addr = nfile->addr;
631 file->slot = nfile->slot;
641 fs_open(Chan* chan, Fcall* f, Fcall* r)
651 if((file = filep(chan, f->fid, 0)) == nil){
661 * if remove on close, check access here
663 ro = file->fs->dev->type == Devro;
664 if(f->mode & ORCLOSE){
670 * check on parent directory of file to be deleted
672 if(file->wpath == 0 || file->wpath->addr == file->addr){
676 p = getbuf(file->fs->dev, file->wpath->addr, Brd);
677 if(p == nil || checktag(p, Tdir, QPNONE)){
681 d = getdir(p, file->wpath->slot);
682 if(d == nil || !(d->mode & DALLOC)){
686 if(iaccess(file, d, DWRITE)){
692 p = getbuf(file->fs->dev, file->addr, Brd);
693 if(p == nil || checktag(p, Tdir, QPNONE)){
697 d = getdir(p, file->slot);
698 if(d == nil || !(d->mode & DALLOC)){
702 if(error = mkqidcmp(&file->qid, d))
708 if(iaccess(file, d, DREAD))
714 if((d->mode & DDIR) || iaccess(file, d, DWRITE))
725 || iaccess(file, d, DREAD)
726 || iaccess(file, d, DWRITE))
736 if((d->mode & DDIR) || iaccess(file, d, DEXEC))
745 if(f->mode & OTRUNC){
746 if((d->mode & DDIR) || iaccess(file, d, DWRITE))
755 if((t = tlocked(p, d)) == nil){
760 if(f->mode & ORCLOSE)
763 if((f->mode & OTRUNC) && !(d->mode & DAPND)){
764 dtrunc(p, d, file->uid);
765 qid.vers = d->qid.version;
784 r->iounit = chan->msize-IOHDRSZ;
790 fs_create(Chan* chan, Fcall* f, Fcall* r)
795 int error, slot, slot1, fmod;
796 Off addr, addr1, path;
802 if((file = filep(chan, f->fid, 0)) == nil){
806 if(file->fs->dev->type == Devro){
810 if(file->qid.type & QTAUTH){
815 p = getbuf(file->fs->dev, file->addr, Brd);
816 if(p == nil || checktag(p, Tdir, QPNONE)){
820 d = getdir(p, file->slot);
821 if(d == nil || !(d->mode & DALLOC)){
825 if(error = mkqidcmp(&file->qid, d))
827 if(!(d->mode & DDIR)){
831 if(iaccess(file, d, DWRITE)) {
835 accessdir(p, d, FREAD, file->uid);
838 * Check the name is valid (and will fit in an old
839 * directory entry for the moment).
841 if(error = checkname(f->name))
846 for(addr = 0; ; addr++){
847 if((p1 = dnodebuf(p, d, addr, 0, file->uid)) == nil){
850 p1 = dnodebuf(p, d, addr, Tdir, file->uid);
856 if(checktag(p1, Tdir, d->qid.path ^ QPDIR)){
860 for(slot = 0; slot < DIRPERBUF; slot++){
861 d1 = getdir(p1, slot);
862 if(!(d1->mode & DALLOC)){
865 slot1 = slot + addr*DIRPERBUF;
869 if(strncmp(f->name, d1->name, sizeof(d1->name)) == 0){
880 case OREAD: /* seems only useful to make directories */
897 if((f->mode & OTRUNC) || (f->perm & DMAPPEND) || (fmod & FWRITE))
902 path = qidpathgen(file->fs->dev);
903 if((p1 = getbuf(file->fs->dev, addr1, Brd|Bimm|Bmod)) == nil)
905 d1 = getdir(p1, slot1);
906 if(d1 == nil || checktag(p1, Tdir, d->qid.path ^ QPDIR)) {
910 if(d1->mode & DALLOC){
915 strncpy(d1->name, f->name, NAMELEN);
916 if(chan == cons.chan){
922 f->perm &= d->mode | ~0666;
924 f->perm &= d->mode | ~0777;
928 d1->mode = DALLOC | (f->perm & 0777);
929 if(f->perm & DMDIR) {
931 d1->qid.path ^= QPDIR;
933 if(f->perm & DMAPPEND)
938 if(f->perm & DMEXCL){
941 /* if nil, out of tlock structures */
943 accessdir(p1, d1, FWRITE, file->uid);
944 mkqid(&r->qid, d1, 0);
946 accessdir(p, d, FWRITE, file->uid);
949 * do a walk to new directory entry
951 if((w = newwp()) == nil){
955 w->addr = file->addr;
956 w->slot = file->slot;
964 if(f->mode & ORCLOSE)
984 r->iounit = chan->msize-IOHDRSZ;
990 fs_read(Chan* chan, Fcall* f, Fcall* r, uchar* data)
996 Off addr, offset, start;
998 int error, iounit, nread, count, mask, n, o, slot;
1008 if((file = filep(chan, f->fid, 0)) == nil){
1012 if(!(file->open & FREAD)){
1016 iounit = chan->msize-IOHDRSZ;
1017 if(count < 0 || count > iounit){
1025 if(file->qid.type & QTAUTH){
1026 nread = authread(file, (uchar*)data, count);
1031 p = getbuf(file->fs->dev, file->addr, Brd);
1032 if(p == nil || checktag(p, Tdir, QPNONE)){
1036 d = getdir(p, file->slot);
1037 if(d == nil || !(d->mode & DALLOC)){
1041 if(error = mkqidcmp(&file->qid, d))
1043 if(t = file->tlock){
1045 if(t->time < tim || t->file != file){
1049 /* renew the lock */
1050 t->time = tim + TLOCK;
1052 accessdir(p, d, FREAD, file->uid);
1055 if(offset >= d->size)
1057 else if(offset+count > d->size)
1058 count = d->size - offset;
1061 p = getbuf(file->fs->dev, file->addr, Brd);
1062 if(p == nil || checktag(p, Tdir, QPNONE)){
1066 d = getdir(p, file->slot);
1067 if(d == nil || !(d->mode & DALLOC)){
1072 addr = offset / BUFSIZE;
1073 file->lastra = dbufread(p, d, addr, file->lastra, file->uid);
1074 o = offset % BUFSIZE;
1078 p1 = dnodebuf1(p, d, addr, 0, file->uid);
1081 if(checktag(p1, Tfile, QPNONE)){
1086 memmove(data+nread, p1->iobuf+o, n);
1089 memset(data+nread, 0, n);
1098 * Pick up where we left off last time if nothing has changed,
1099 * otherwise must scan from the beginning.
1101 if(offset == file->doffset /*&& file->qid.vers == file->dvers*/){
1102 addr = file->dslot/DIRPERBUF;
1103 slot = file->dslot%DIRPERBUF;
1111 dmb = mballoc(iounit, chan, Mbreply1);
1115 * This is just a check to ensure the entry hasn't
1116 * gone away during the read of each directory block.
1118 p = getbuf(file->fs->dev, file->addr, Brd);
1119 if(p == nil || checktag(p, Tdir, QPNONE)){
1123 d = getdir(p, file->slot);
1124 if(d == nil || !(d->mode & DALLOC)){
1129 p1 = dnodebuf1(p, d, addr, 0, file->uid);
1133 if(checktag(p1, Tdir, QPNONE)){
1140 if(file->fs->dev->type == Devro)
1142 for(; slot < DIRPERBUF; slot++){
1143 d1 = getdir(p1, slot);
1144 if((d1->mode & mask) != DALLOC)
1146 mkdir9p2(&dir, d1, dmb->data);
1147 n = convD2M(&dir, data+nread, iounit - nread);
1170 file->doffset = offset;
1171 file->dvers = file->qid.vers;
1172 file->dslot = slot+DIRPERBUF*addr;
1177 * Do we need this any more?
1178 count = f->count - nread;
1180 memset(data+nread, 0, count);
1187 r->data = (char*)data;
1193 fs_write(Chan* chan, Fcall* f, Fcall* r)
1199 Off offset, addr, qpath;
1201 int count, error, nwrite, o, n;
1210 if((file = filep(chan, f->fid, 0)) == nil){
1214 if(!(file->open & FWRITE)){
1218 if(count < 0 || count > chan->msize-IOHDRSZ){
1227 if(file->qid.type & QTAUTH){
1228 nwrite = authwrite(file, (uchar*)f->data, count);
1232 } else if(file->fs->dev->type == Devro){
1237 if ((p = getbuf(file->fs->dev, file->addr, Brd|Bmod)) == nil ||
1238 (d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)) {
1242 if(error = mkqidcmp(&file->qid, d))
1244 if(t = file->tlock) {
1246 if(t->time < tim || t->file != file){
1250 /* renew the lock */
1251 t->time = tim + TLOCK;
1253 accessdir(p, d, FWRITE, file->uid);
1256 if(offset+count > d->size)
1257 d->size = offset+count;
1260 p = getbuf(file->fs->dev, file->addr, Brd|Bmod);
1265 d = getdir(p, file->slot);
1266 if(d == nil || !(d->mode & DALLOC)){
1271 addr = offset / BUFSIZE;
1272 o = offset % BUFSIZE;
1276 qpath = d->qid.path;
1277 p1 = dnodebuf1(p, d, addr, Tfile, file->uid);
1283 if(checktag(p1, Tfile, qpath)){
1288 memmove(p1->iobuf+o, f->data+nwrite, n);
1316 if(f->fs->dev->type == Devro) {
1321 * check on parent directory of file to be deleted
1323 if(f->wpath == 0 || f->wpath->addr == f->addr) {
1327 p1 = getbuf(f->fs->dev, f->wpath->addr, Brd);
1328 d1 = getdir(p1, f->wpath->slot);
1329 if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
1333 if(iaccess(f, d1, DWRITE)) {
1337 accessdir(p1, d1, FWRITE, f->uid);
1342 * check on file to be deleted
1344 p = getbuf(f->fs->dev, f->addr, Brd);
1345 d = getdir(p, f->slot);
1346 if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
1350 if(err = mkqidcmp(&f->qid, d))
1354 * if deleting a directory, make sure it is empty
1356 if((d->mode & DDIR))
1357 for(addr=0;; addr++) {
1358 p1 = dnodebuf(p, d, addr, 0, f->uid);
1361 if(checktag(p1, Tdir, d->qid.path ^ QPDIR)) {
1365 for(slot=0; slot<DIRPERBUF; slot++) {
1366 d1 = getdir(p1, slot);
1367 if(!(d1->mode & DALLOC))
1378 dtrunc(p, d, f->uid);
1379 memset(d, 0, sizeof(Dentry));
1380 settag(p, Tdir, QPNONE);
1391 _clunk(File* file, int remove)
1397 if(t = file->tlock){
1399 t->time = 0; /* free the lock */
1402 if(remove && (file->qid.type & QTAUTH) == 0)
1403 error = doremove(file);
1405 freewp(file->wpath);
1406 authfree(file->auth);
1415 clunk(Chan* chan, Fcall* f, Fcall*)
1419 if((file = filep(chan, f->fid, 0)) == nil)
1422 _clunk(file, file->open & FREMOV);
1427 fs_remove(Chan* chan, Fcall* f, Fcall*)
1431 if((file = filep(chan, f->fid, 0)) == nil)
1433 return _clunk(file, 1);
1437 fs_stat(Chan* chan, Fcall* f, Fcall* r, uchar* data)
1447 if((file = filep(chan, f->fid, 0)) == nil)
1449 if(file->qid.type & QTAUTH){
1450 memset(&dentry, 0, sizeof dentry);
1452 mkqid9p1(&d->qid, &file->qid);
1453 strcpy(d->name, "#¿");
1457 d->atime = time(nil);
1458 d->mtime = d->atime;
1461 p = getbuf(file->fs->dev, file->addr, Brd);
1462 if(p == nil || checktag(p, Tdir, QPNONE)){
1466 d = getdir(p, file->slot);
1467 if(d == nil || !(d->mode & DALLOC)){
1471 if(error = mkqidcmp(&file->qid, d))
1474 if(d->qid.path == (QPROOT|QPDIR)) /* stat of root gives time */
1475 d->atime = time(nil);
1477 len = mkdir9p2(&dir, d, data);
1480 if((r->nstat = convD2M(&dir, data, chan->msize - len)) == 0)
1494 fs_wstat(Chan* chan, Fcall* f, Fcall*, char* strs)
1499 int error, err, gid, gl, muid, op, slot, tsync, uid;
1503 if(convM2D(f->stat, f->nstat, &dir, strs) == 0)
1508 * if filesystem is read-only, can't change anything.
1510 if((file = filep(chan, f->fid, 0)) == nil)
1513 if(file->fs->dev->type == Devro){
1517 if(file->qid.type & QTAUTH){
1523 * Get the current entry and check it is still valid.
1525 p = getbuf(file->fs->dev, file->addr, Brd);
1526 if(p == nil || checktag(p, Tdir, QPNONE)){
1530 d = getdir(p, file->slot);
1531 if(d == nil || !(d->mode & DALLOC)){
1535 if(error = mkqidcmp(&file->qid, d))
1539 * Run through each of the (sub-)fields in the provided Dir
1540 * checking for validity and whether it's a default:
1541 * .type, .dev and .atime are completely ignored and not checked;
1542 * .qid.path, .qid.vers and .muid are checked for validity but
1543 * any attempt to change them is an error.
1544 * .qid.type/.mode, .mtime, .name, .length, .uid and .gid can
1545 * possibly be changed (and .muid iff is god).
1547 * 'Op' flags there are changed fields, i.e. it's not a no-op.
1548 * 'Tsync' flags all fields are defaulted.
1551 if(dir.qid.path != ~0){
1552 if(dir.qid.path != file->qid.path){
1558 if(dir.qid.vers != ~0){
1559 if(dir.qid.vers != file->qid.vers){
1567 * .qid.type and .mode have some bits in common. Only .mode
1568 * is currently needed for comparisons with the old mode but
1569 * if there are changes to the bits also encoded in .qid.type
1570 * then file->qid must be updated appropriately later.
1572 if(dir.qid.type == (uchar)~0){
1574 dir.qid.type = mktype9p2(d->mode);
1576 dir.qid.type = dir.mode>>24;
1580 dir.mode = mkmode9p2(d->mode);
1585 * Check dir.qid.type and dir.mode agree, check for any unknown
1586 * type/mode bits, check for an attempt to change the directory bit.
1588 if(dir.qid.type != ((dir.mode>>24) & 0xFF)){
1592 if(dir.mode & ~(DMDIR|DMAPPEND|DMEXCL|DMTMP|0777)){
1597 op = dir.mode^mkmode9p2(d->mode);
1603 if(dir.mtime != ~0){
1604 if(dir.mtime != d->mtime)
1608 dir.mtime = d->mtime;
1610 if(dir.length == ~(Off)0)
1611 dir.length = d->size;
1613 if (dir.length < 0) {
1616 } else if(dir.length != d->size)
1622 * Check for permission to change .mode, .mtime or .length,
1623 * must be owner or leader of either group, for which test gid
1624 * is needed; permission checks on gid will be done later.
1625 * 'Gl' counts whether neither, one or both groups are led.
1627 if(dir.gid != nil && *dir.gid != '\0'){
1628 gid = strtouid(dir.gid);
1632 gl = leadgroup(file->uid, gid) != 0;
1633 gl += leadgroup(file->uid, d->gid) != 0;
1635 if(op && !isallowed(file) && d->uid != file->uid && !gl){
1642 * Check .name is valid and different to the current.
1644 if(dir.name != nil && *dir.name != '\0'){
1645 if(error = checkname(dir.name))
1647 if(strncmp(dir.name, d->name, NAMELEN))
1656 * If the name is really to be changed check it's unique
1657 * and there is write permission in the parent.
1659 if(dir.name != d->name){
1662 * Must drop current entry to prevent
1663 * deadlock when searching that new name
1664 * already exists below.
1669 if(file->wpath == nil){
1673 p1 = getbuf(file->fs->dev, file->wpath->addr, Brd);
1674 if(p1 == nil || checktag(p1, Tdir, QPNONE)){
1678 d1 = getdir(p1, file->wpath->slot);
1679 if(d1 == nil || !(d1->mode & DALLOC)){
1685 * Check entries in parent for new name.
1687 for(addr = 0; ; addr++){
1688 if((p = dnodebuf(p1, d1, addr, 0, file->uid)) == nil)
1690 if(checktag(p, Tdir, d1->qid.path ^ QPDIR)){
1694 for(slot = 0; slot < DIRPERBUF; slot++){
1695 d = getdir(p, slot);
1696 if(!(d->mode & DALLOC) ||
1697 strncmp(dir.name, d->name, sizeof d->name))
1706 * Reacquire entry and check it's still OK.
1708 p = getbuf(file->fs->dev, file->addr, Brd);
1709 if(p == nil || checktag(p, Tdir, QPNONE)){
1713 d = getdir(p, file->slot);
1714 if(d == nil || !(d->mode & DALLOC)){
1720 * Check write permission in the parent.
1722 if(iaccess(file, d1, DWRITE)){
1729 * Check for permission to change owner - must be god.
1731 if(dir.uid != nil && *dir.uid != '\0'){
1732 uid = strtouid(dir.uid);
1734 if(!isallowed(file)){
1743 if(dir.muid != nil && *dir.muid != '\0'){
1744 muid = strtouid(dir.muid);
1745 if(muid != d->muid){
1746 if(!isallowed(file)){
1757 * Check for permission to change group, must be
1758 * either owner and in new group or leader of both groups.
1762 && !(d->uid == file->uid && ingroup(file->uid, gid))
1771 * Checks all done, update if necessary.
1774 d->mode = mkmode9p1(dir.mode);
1775 file->qid.type = mktype9p2(d->mode);
1776 d->mtime = dir.mtime;
1777 if (dir.length < d->size) {
1778 err = dtrunclen(p, d, dir.length, uid);
1782 d->size = dir.length;
1783 if(dir.name != d->name)
1784 strncpy(d->name, dir.name, NAMELEN);
1791 accessdir(p, d, FREAD, file->uid);
1804 serve9p2(Msgbuf* mb)
1814 fmtinstall('F', fcallfmt);
1819 * 0 return means i don't understand this message,
1820 * 1 return means i dealt with it, including error
1823 if(convM2S(mb->data, mb->count, &f) != mb->count){
1824 fprint(2, "didn't like %d byte message\n", mb->count);
1828 if(type < Tversion || type >= Tmax || (type & 1) || type == Terror)
1833 fprint(2, "9p2: f %F\n", &f);
1843 snprint(ename, sizeof(ename), "unknown message: %F", &f);
1847 error = version(chan, &f, &r);
1850 error = auth(chan, &f, &r);
1853 error = attach(chan, &f, &r);
1856 error = flush(chan, &f, &r);
1859 error = walk(chan, &f, &r);
1862 error = fs_open(chan, &f, &r);
1865 error = fs_create(chan, &f, &r);
1868 data = mballoc(chan->msize, chan, Mbreply1);
1869 error = fs_read(chan, &f, &r, data->data);
1872 error = fs_write(chan, &f, &r);
1875 error = clunk(chan, &f, &r);
1878 error = fs_remove(chan, &f, &r);
1881 data = mballoc(chan->msize, chan, Mbreply1);
1882 error = fs_stat(chan, &f, &r, data->data);
1885 data = mballoc(chan->msize, chan, Mbreply1);
1886 error = fs_wstat(chan, &f, &r, (char*)data->data);
1893 r.ename = chan->err;
1894 else if(error >= MAXERR){
1895 snprint(ename, sizeof(ename), "error %d", error);
1898 r.ename = errstr9p[error];
1901 fprint(2, "9p2: r %F\n", &r);
1903 rmb = mballoc(chan->msize, chan, Mbreply2);
1904 n = convS2M(&r, rmb->data, chan->msize);
1912 * If a Tversion has not been seen on the chan then
1913 * chan->msize will be 0. In that case craft a special
1914 * Rerror message. It's fortunate that the mballoc above
1915 * for rmb will have returned a Msgbuf of MAXMSG size
1916 * when given a request with count of 0...
1918 if(chan->msize == 0){
1919 r.ename = "Tversion not seen";
1920 n = convS2M(&r, rmb->data, MAXMSG);
1922 snprint(ename, sizeof(ename), "9p2: convS2M: type %d",
1925 n = convS2M(&r, rmb->data, chan->msize);
1927 fprint(2, "%s\n", r.ename);
1930 * What to do here, the failure notification failed?
1937 rmb->param = mb->param;
1939 /* done 9P processing, write reply to network */
1940 fs_send(chan->reply, rmb);