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 if(qid->path & 0xFFFFFFFF00000000LL)
31 panic("mkqid9p1: path %lluX", (Wideoff)qid->path);
32 qid9p1->path = qid->path & 0xFFFFFFFF;
34 qid9p1->path |= QPDIR;
35 qid9p1->version = qid->vers;
39 mktype9p2(int mode9p1)
57 mkmode9p2(int mode9p1)
61 mode = mode9p1 & 0777;
75 mkqid9p2(Qid* qid, Qid9p1* qid9p1, int mode9p1)
77 qid->path = (ulong)(qid9p1->path & ~QPDIR);
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)){
486 p1 = dnodebuf1(p, d, addr, 0, file->uid);
488 if(p1 == nil || checktag(p1, Tdir, qpath)){
493 if(file->fs->dev->type == Devro)
495 for(slot = 0; slot < DIRPERBUF; slot++){
496 d1 = getdir(p1, slot);
497 if ((d1->mode & mask) != DALLOC ||
498 strncmp(wname, d1->name, NAMELEN) != 0)
503 if((w = newwp()) == nil){
507 w->addr = file->addr;
508 w->slot = file->slot;
511 slot += DIRPERBUF*addr;
519 file->addr = p1->addr;
520 mkqid(&file->qid, d1, 1);
537 walk(Chan* chan, Fcall* f, Fcall* r)
540 File *file, *nfile, tfile;
543 * The file identified by f->fid must be valid in the
544 * current session and must not have been opened for I/O
545 * by an open or create message.
547 if((file = filep(chan, f->fid, 0)) == nil)
555 * If newfid is not the same as fid, allocate a new file;
556 * a side effect is checking newfid is not already in use (error);
557 * if there are no names to walk this will be equivalent to a
558 * simple 'clone' operation.
559 * Otherwise, fid and newfid are the same and if there are names
560 * to walk make a copy of 'file' to be used during the walk as
561 * 'file' must only be updated on success.
562 * Finally, it's a no-op if newfid is the same as fid and f->nwname
566 if(f->newfid != f->fid){
567 if((nfile = filep(chan, f->newfid, 1)) == nil){
571 } else if(f->nwname != 0){
573 memset(nfile, 0, sizeof(File));
583 * Should check name is not too long.
586 for(nwname = 0; nwname < f->nwname; nwname++){
587 error = walkname(nfile, f->wname[nwname], &r->wqid[r->nwqid]);
588 if(error != 0 || ++r->nwqid >= MAXDAT/sizeof(Qid))
594 * Newfid must be different to fid (see above)
595 * so this is a simple 'clone' operation - there's
596 * nothing to do except unlock unless there's
600 freewp(nfile->wpath);
605 } else if(r->nwqid < f->nwname){
607 * Didn't walk all elements, 'clunk' nfile
608 * and leave 'file' alone.
609 * Clear error if some of the elements were
612 freewp(nfile->wpath);
621 * Walked all elements. If newfid is the same
622 * as fid must update 'file' from the temporary
623 * copy used during the walk.
624 * Otherwise just unlock (when using tfile there's
625 * no need to unlock as it's a local).
628 file->qid = nfile->qid;
630 file->wpath = nfile->wpath;
631 file->addr = nfile->addr;
632 file->slot = nfile->slot;
642 fs_open(Chan* chan, Fcall* f, Fcall* r)
652 if((file = filep(chan, f->fid, 0)) == nil){
662 * if remove on close, check access here
664 ro = file->fs->dev->type == Devro;
665 if(f->mode & ORCLOSE){
671 * check on parent directory of file to be deleted
673 if(file->wpath == 0 || file->wpath->addr == file->addr){
677 p = getbuf(file->fs->dev, file->wpath->addr, Brd);
678 if(p == nil || checktag(p, Tdir, QPNONE)){
682 d = getdir(p, file->wpath->slot);
683 if(d == nil || !(d->mode & DALLOC)){
687 if(iaccess(file, d, DWRITE)){
693 p = getbuf(file->fs->dev, file->addr, Brd);
694 if(p == nil || checktag(p, Tdir, QPNONE)){
698 d = getdir(p, file->slot);
699 if(d == nil || !(d->mode & DALLOC)){
703 if(error = mkqidcmp(&file->qid, d))
709 if(iaccess(file, d, DREAD))
715 if((d->mode & DDIR) || iaccess(file, d, DWRITE))
726 || iaccess(file, d, DREAD)
727 || iaccess(file, d, DWRITE))
737 if((d->mode & DDIR) || iaccess(file, d, DEXEC))
746 if(f->mode & OTRUNC){
747 if((d->mode & DDIR) || iaccess(file, d, DWRITE))
756 if((t = tlocked(p, d)) == nil){
761 if(f->mode & ORCLOSE)
764 if((f->mode & OTRUNC) && !(d->mode & DAPND)){
765 dtrunc(p, d, file->uid);
766 qid.vers = d->qid.version;
785 r->iounit = chan->msize-IOHDRSZ;
791 fs_create(Chan* chan, Fcall* f, Fcall* r)
796 int error, slot, slot1, fmod;
797 Off addr, addr1, path;
803 if((file = filep(chan, f->fid, 0)) == nil){
807 if(file->fs->dev->type == Devro){
811 if(file->qid.type & QTAUTH){
816 p = getbuf(file->fs->dev, file->addr, Brd);
817 if(p == nil || checktag(p, Tdir, QPNONE)){
821 d = getdir(p, file->slot);
822 if(d == nil || !(d->mode & DALLOC)){
826 if(error = mkqidcmp(&file->qid, d))
828 if(!(d->mode & DDIR)){
832 if(iaccess(file, d, DWRITE)) {
836 accessdir(p, d, FREAD, file->uid);
839 * Check the name is valid (and will fit in an old
840 * directory entry for the moment).
842 if(error = checkname(f->name))
847 for(addr = 0; ; addr++){
848 if((p1 = dnodebuf(p, d, addr, 0, file->uid)) == nil){
851 p1 = dnodebuf(p, d, addr, Tdir, file->uid);
857 if(checktag(p1, Tdir, d->qid.path)){
861 for(slot = 0; slot < DIRPERBUF; slot++){
862 d1 = getdir(p1, slot);
863 if(!(d1->mode & DALLOC)){
866 slot1 = slot + addr*DIRPERBUF;
870 if(strncmp(f->name, d1->name, sizeof(d1->name)) == 0){
881 case OREAD: /* seems only useful to make directories */
898 if((f->mode & OTRUNC) || (f->perm & DMAPPEND) || (fmod & FWRITE))
903 path = qidpathgen(file->fs->dev);
904 if((p1 = getbuf(file->fs->dev, addr1, Brd|Bimm|Bmod)) == nil)
906 d1 = getdir(p1, slot1);
907 if(d1 == nil || checktag(p1, Tdir, d->qid.path)) {
911 if(d1->mode & DALLOC){
916 strncpy(d1->name, f->name, NAMELEN);
917 if(chan == cons.chan){
923 f->perm &= d->mode | ~0666;
925 f->perm &= d->mode | ~0777;
929 d1->mode = DALLOC | (f->perm & 0777);
930 if(f->perm & DMDIR) {
932 d1->qid.path |= QPDIR;
934 if(f->perm & DMAPPEND)
939 if(f->perm & DMEXCL){
942 /* if nil, out of tlock structures */
944 accessdir(p1, d1, FWRITE, file->uid);
945 mkqid(&r->qid, d1, 0);
947 accessdir(p, d, FWRITE, file->uid);
950 * do a walk to new directory entry
952 if((w = newwp()) == nil){
956 w->addr = file->addr;
957 w->slot = file->slot;
965 if(f->mode & ORCLOSE)
985 r->iounit = chan->msize-IOHDRSZ;
991 fs_read(Chan* chan, Fcall* f, Fcall* r, uchar* data)
997 Off addr, offset, start;
999 int error, iounit, nread, count, mask, n, o, slot;
1009 if((file = filep(chan, f->fid, 0)) == nil){
1013 if(!(file->open & FREAD)){
1017 iounit = chan->msize-IOHDRSZ;
1018 if(count < 0 || count > iounit){
1026 if(file->qid.type & QTAUTH){
1027 nread = authread(file, (uchar*)data, count);
1032 p = getbuf(file->fs->dev, file->addr, Brd);
1033 if(p == nil || checktag(p, Tdir, QPNONE)){
1037 d = getdir(p, file->slot);
1038 if(d == nil || !(d->mode & DALLOC)){
1042 if(error = mkqidcmp(&file->qid, d))
1044 if(t = file->tlock){
1046 if(t->time < tim || t->file != file){
1050 /* renew the lock */
1051 t->time = tim + TLOCK;
1053 accessdir(p, d, FREAD, file->uid);
1056 if(offset >= d->size)
1058 else if(offset+count > d->size)
1059 count = d->size - offset;
1062 p = getbuf(file->fs->dev, file->addr, Brd);
1063 if(p == nil || checktag(p, Tdir, QPNONE)){
1067 d = getdir(p, file->slot);
1068 if(d == nil || !(d->mode & DALLOC)){
1073 addr = offset / BUFSIZE;
1074 file->lastra = dbufread(p, d, addr, file->lastra, file->uid);
1075 o = offset % BUFSIZE;
1079 p1 = dnodebuf1(p, d, addr, 0, file->uid);
1082 if(checktag(p1, Tfile, QPNONE)){
1087 memmove(data+nread, p1->iobuf+o, n);
1090 memset(data+nread, 0, n);
1099 * Pick up where we left off last time if nothing has changed,
1100 * otherwise must scan from the beginning.
1102 if(offset == file->doffset /*&& file->qid.vers == file->dvers*/){
1103 addr = file->dslot/DIRPERBUF;
1104 slot = file->dslot%DIRPERBUF;
1112 dmb = mballoc(iounit, chan, Mbreply1);
1116 * This is just a check to ensure the entry hasn't
1117 * gone away during the read of each directory block.
1119 p = getbuf(file->fs->dev, file->addr, Brd);
1120 if(p == nil || checktag(p, Tdir, QPNONE)){
1124 d = getdir(p, file->slot);
1125 if(d == nil || !(d->mode & DALLOC)){
1130 p1 = dnodebuf1(p, d, addr, 0, file->uid);
1134 if(checktag(p1, Tdir, QPNONE)){
1141 if(file->fs->dev->type == Devro)
1143 for(; slot < DIRPERBUF; slot++){
1144 d1 = getdir(p1, slot);
1145 if((d1->mode & mask) != DALLOC)
1147 mkdir9p2(&dir, d1, dmb->data);
1148 n = convD2M(&dir, data+nread, iounit - nread);
1171 file->doffset = offset;
1172 file->dvers = file->qid.vers;
1173 file->dslot = slot+DIRPERBUF*addr;
1178 * Do we need this any more?
1179 count = f->count - nread;
1181 memset(data+nread, 0, count);
1188 r->data = (char*)data;
1194 fs_write(Chan* chan, Fcall* f, Fcall* r)
1200 Off offset, addr, qpath;
1202 int count, error, nwrite, o, n;
1211 if((file = filep(chan, f->fid, 0)) == nil){
1215 if(!(file->open & FWRITE)){
1219 if(count < 0 || count > chan->msize-IOHDRSZ){
1228 if(file->qid.type & QTAUTH){
1229 nwrite = authwrite(file, (uchar*)f->data, count);
1233 } else if(file->fs->dev->type == Devro){
1238 if ((p = getbuf(file->fs->dev, file->addr, Brd|Bmod)) == nil ||
1239 (d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)) {
1243 if(error = mkqidcmp(&file->qid, d))
1245 if(t = file->tlock) {
1247 if(t->time < tim || t->file != file){
1251 /* renew the lock */
1252 t->time = tim + TLOCK;
1254 accessdir(p, d, FWRITE, file->uid);
1257 if(offset+count > d->size)
1258 d->size = offset+count;
1261 p = getbuf(file->fs->dev, file->addr, Brd|Bmod);
1266 d = getdir(p, file->slot);
1267 if(d == nil || !(d->mode & DALLOC)){
1272 addr = offset / BUFSIZE;
1273 o = offset % BUFSIZE;
1277 qpath = d->qid.path;
1278 p1 = dnodebuf1(p, d, addr, Tfile, file->uid);
1284 if(checktag(p1, Tfile, qpath)){
1289 memmove(p1->iobuf+o, f->data+nwrite, n);
1317 if(f->fs->dev->type == Devro) {
1322 * check on parent directory of file to be deleted
1324 if(f->wpath == 0 || f->wpath->addr == f->addr) {
1328 p1 = getbuf(f->fs->dev, f->wpath->addr, Brd);
1329 d1 = getdir(p1, f->wpath->slot);
1330 if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
1334 if(iaccess(f, d1, DWRITE)) {
1338 accessdir(p1, d1, FWRITE, f->uid);
1343 * check on file to be deleted
1345 p = getbuf(f->fs->dev, f->addr, Brd);
1346 d = getdir(p, f->slot);
1347 if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
1351 if(err = mkqidcmp(&f->qid, d))
1355 * if deleting a directory, make sure it is empty
1357 if((d->mode & DDIR))
1358 for(addr=0;; addr++) {
1359 p1 = dnodebuf(p, d, addr, 0, f->uid);
1362 if(checktag(p1, Tdir, d->qid.path)) {
1366 for(slot=0; slot<DIRPERBUF; slot++) {
1367 d1 = getdir(p1, slot);
1368 if(!(d1->mode & DALLOC))
1379 dtrunc(p, d, f->uid);
1380 memset(d, 0, sizeof(Dentry));
1381 settag(p, Tdir, QPNONE);
1392 _clunk(File* file, int remove)
1398 if(t = file->tlock){
1400 t->time = 0; /* free the lock */
1403 if(remove && (file->qid.type & QTAUTH) == 0)
1404 error = doremove(file);
1406 freewp(file->wpath);
1407 authfree(file->auth);
1416 clunk(Chan* chan, Fcall* f, Fcall*)
1420 if((file = filep(chan, f->fid, 0)) == nil)
1423 _clunk(file, file->open & FREMOV);
1428 fs_remove(Chan* chan, Fcall* f, Fcall*)
1432 if((file = filep(chan, f->fid, 0)) == nil)
1434 return _clunk(file, 1);
1438 fs_stat(Chan* chan, Fcall* f, Fcall* r, uchar* data)
1448 if((file = filep(chan, f->fid, 0)) == nil)
1450 if(file->qid.type & QTAUTH){
1451 memset(&dentry, 0, sizeof dentry);
1453 mkqid9p1(&d->qid, &file->qid);
1454 strcpy(d->name, "#¿");
1458 d->atime = time(nil);
1459 d->mtime = d->atime;
1462 p = getbuf(file->fs->dev, file->addr, Brd);
1463 if(p == nil || checktag(p, Tdir, QPNONE)){
1467 d = getdir(p, file->slot);
1468 if(d == nil || !(d->mode & DALLOC)){
1472 if(error = mkqidcmp(&file->qid, d))
1475 if(d->qid.path == QPROOT) /* stat of root gives time */
1476 d->atime = time(nil);
1478 len = mkdir9p2(&dir, d, data);
1481 if((r->nstat = convD2M(&dir, data, chan->msize - len)) == 0)
1495 fs_wstat(Chan* chan, Fcall* f, Fcall*, char* strs)
1500 int error, err, gid, gl, muid, op, slot, tsync, uid;
1504 if(convM2D(f->stat, f->nstat, &dir, strs) == 0)
1509 * if filesystem is read-only, can't change anything.
1511 if((file = filep(chan, f->fid, 0)) == nil)
1514 if(file->fs->dev->type == Devro){
1518 if(file->qid.type & QTAUTH){
1524 * Get the current entry and check it is still valid.
1526 p = getbuf(file->fs->dev, file->addr, Brd);
1527 if(p == nil || checktag(p, Tdir, QPNONE)){
1531 d = getdir(p, file->slot);
1532 if(d == nil || !(d->mode & DALLOC)){
1536 if(error = mkqidcmp(&file->qid, d))
1540 * Run through each of the (sub-)fields in the provided Dir
1541 * checking for validity and whether it's a default:
1542 * .type, .dev and .atime are completely ignored and not checked;
1543 * .qid.path, .qid.vers and .muid are checked for validity but
1544 * any attempt to change them is an error.
1545 * .qid.type/.mode, .mtime, .name, .length, .uid and .gid can
1546 * possibly be changed (and .muid iff is god).
1548 * 'Op' flags there are changed fields, i.e. it's not a no-op.
1549 * 'Tsync' flags all fields are defaulted.
1552 if(dir.qid.path != ~0){
1553 if(dir.qid.path != file->qid.path){
1559 if(dir.qid.vers != ~0){
1560 if(dir.qid.vers != file->qid.vers){
1568 * .qid.type and .mode have some bits in common. Only .mode
1569 * is currently needed for comparisons with the old mode but
1570 * if there are changes to the bits also encoded in .qid.type
1571 * then file->qid must be updated appropriately later.
1573 if(dir.qid.type == (uchar)~0){
1575 dir.qid.type = mktype9p2(d->mode);
1577 dir.qid.type = dir.mode>>24;
1581 dir.mode = mkmode9p2(d->mode);
1586 * Check dir.qid.type and dir.mode agree, check for any unknown
1587 * type/mode bits, check for an attempt to change the directory bit.
1589 if(dir.qid.type != ((dir.mode>>24) & 0xFF)){
1593 if(dir.mode & ~(DMDIR|DMAPPEND|DMEXCL|DMTMP|0777)){
1598 op = dir.mode^mkmode9p2(d->mode);
1604 if(dir.mtime != ~0){
1605 if(dir.mtime != d->mtime)
1609 dir.mtime = d->mtime;
1611 if(dir.length == ~(Off)0)
1612 dir.length = d->size;
1614 if (dir.length < 0) {
1617 } else if(dir.length != d->size)
1623 * Check for permission to change .mode, .mtime or .length,
1624 * must be owner or leader of either group, for which test gid
1625 * is needed; permission checks on gid will be done later.
1626 * 'Gl' counts whether neither, one or both groups are led.
1628 if(dir.gid != nil && *dir.gid != '\0'){
1629 gid = strtouid(dir.gid);
1633 gl = leadgroup(file->uid, gid) != 0;
1634 gl += leadgroup(file->uid, d->gid) != 0;
1636 if(op && !isallowed(file) && d->uid != file->uid && !gl){
1643 * Check .name is valid and different to the current.
1645 if(dir.name != nil && *dir.name != '\0'){
1646 if(error = checkname(dir.name))
1648 if(strncmp(dir.name, d->name, NAMELEN))
1657 * If the name is really to be changed check it's unique
1658 * and there is write permission in the parent.
1660 if(dir.name != d->name){
1663 * Must drop current entry to prevent
1664 * deadlock when searching that new name
1665 * already exists below.
1670 if(file->wpath == nil){
1674 p1 = getbuf(file->fs->dev, file->wpath->addr, Brd);
1675 if(p1 == nil || checktag(p1, Tdir, QPNONE)){
1679 d1 = getdir(p1, file->wpath->slot);
1680 if(d1 == nil || !(d1->mode & DALLOC)){
1686 * Check entries in parent for new name.
1688 for(addr = 0; ; addr++){
1689 if((p = dnodebuf(p1, d1, addr, 0, file->uid)) == nil)
1691 if(checktag(p, Tdir, d1->qid.path)){
1695 for(slot = 0; slot < DIRPERBUF; slot++){
1696 d = getdir(p, slot);
1697 if(!(d->mode & DALLOC) ||
1698 strncmp(dir.name, d->name, sizeof d->name))
1707 * Reacquire entry and check it's still OK.
1709 p = getbuf(file->fs->dev, file->addr, Brd);
1710 if(p == nil || checktag(p, Tdir, QPNONE)){
1714 d = getdir(p, file->slot);
1715 if(d == nil || !(d->mode & DALLOC)){
1721 * Check write permission in the parent.
1723 if(iaccess(file, d1, DWRITE)){
1730 * Check for permission to change owner - must be god.
1732 if(dir.uid != nil && *dir.uid != '\0'){
1733 uid = strtouid(dir.uid);
1735 if(!isallowed(file)){
1744 if(dir.muid != nil && *dir.muid != '\0'){
1745 muid = strtouid(dir.muid);
1746 if(muid != d->muid){
1747 if(!isallowed(file)){
1758 * Check for permission to change group, must be
1759 * either owner and in new group or leader of both groups.
1763 && !(d->uid == file->uid && ingroup(file->uid, gid))
1772 * Checks all done, update if necessary.
1775 d->mode = mkmode9p1(dir.mode);
1776 file->qid.type = mktype9p2(d->mode);
1777 d->mtime = dir.mtime;
1778 if (dir.length < d->size) {
1779 err = dtrunclen(p, d, dir.length, uid);
1783 d->size = dir.length;
1784 if(dir.name != d->name)
1785 strncpy(d->name, dir.name, NAMELEN);
1792 accessdir(p, d, FREAD, file->uid);
1805 serve9p2(Msgbuf* mb)
1815 fmtinstall('F', fcallfmt);
1820 * 0 return means i don't understand this message,
1821 * 1 return means i dealt with it, including error
1824 if(convM2S(mb->data, mb->count, &f) != mb->count){
1825 fprint(2, "didn't like %d byte message\n", mb->count);
1829 if(type < Tversion || type >= Tmax || (type & 1) || type == Terror)
1834 fprint(2, "9p2: f %F\n", &f);
1844 snprint(ename, sizeof(ename), "unknown message: %F", &f);
1848 error = version(chan, &f, &r);
1851 error = auth(chan, &f, &r);
1854 error = attach(chan, &f, &r);
1857 error = flush(chan, &f, &r);
1860 error = walk(chan, &f, &r);
1863 error = fs_open(chan, &f, &r);
1866 error = fs_create(chan, &f, &r);
1869 data = mballoc(chan->msize, chan, Mbreply1);
1870 error = fs_read(chan, &f, &r, data->data);
1873 error = fs_write(chan, &f, &r);
1876 error = clunk(chan, &f, &r);
1879 error = fs_remove(chan, &f, &r);
1882 data = mballoc(chan->msize, chan, Mbreply1);
1883 error = fs_stat(chan, &f, &r, data->data);
1886 data = mballoc(chan->msize, chan, Mbreply1);
1887 error = fs_wstat(chan, &f, &r, (char*)data->data);
1894 r.ename = chan->err;
1895 else if(error >= MAXERR){
1896 snprint(ename, sizeof(ename), "error %d", error);
1899 r.ename = errstr9p[error];
1902 fprint(2, "9p2: r %F\n", &r);
1904 rmb = mballoc(chan->msize, chan, Mbreply2);
1905 n = convS2M(&r, rmb->data, chan->msize);
1913 * If a Tversion has not been seen on the chan then
1914 * chan->msize will be 0. In that case craft a special
1915 * Rerror message. It's fortunate that the mballoc above
1916 * for rmb will have returned a Msgbuf of MAXMSG size
1917 * when given a request with count of 0...
1919 if(chan->msize == 0){
1920 r.ename = "Tversion not seen";
1921 n = convS2M(&r, rmb->data, MAXMSG);
1923 snprint(ename, sizeof(ename), "9p2: convS2M: type %d",
1926 n = convS2M(&r, rmb->data, chan->msize);
1928 fprint(2, "%s\n", r.ename);
1931 * What to do here, the failure notification failed?
1938 rmb->param = mb->param;
1940 /* done 9P processing, write reply to network */
1941 fs_send(chan->reply, rmb);