📄 9p2.c
字号:
} else if(r->nwqid < f->nwname){ /* * Didn't walk all elements, 'clunk' nfile * and leave 'file' alone. * Clear error if some of the elements were * walked OK. */ freewp(nfile->wpath); if(nfile != &tfile){ qunlock(nfile); freefp(nfile); } if(r->nwqid != 0) error = 0; } else{ /* * Walked all elements. If newfid is the same * as fid must update 'file' from the temporary * copy used during the walk. * Otherwise just unlock (when using tfile there's * no need to unlock as it's a local). */ if(nfile == &tfile){ file->qid = nfile->qid; freewp(file->wpath); file->wpath = nfile->wpath; file->addr = nfile->addr; file->slot = nfile->slot; } else qunlock(nfile); } qunlock(file); return error;}static intopen(Chan* chan, Fcall* f, Fcall* r){ Iobuf *p; Dentry *d; File *file; Tlock *t; Qid qid; int error, ro, fmod, wok; wok = 0; p = nil; if(chan == cons.chan || writeallow) wok = 1; if((file = filep(chan, f->fid, 0)) == nil){ error = Efid; goto out; } if(file->open != 0){ error = Emode; goto out; } /* * if remove on close, check access here */ ro = file->fs->dev->type == Devro; if(f->mode & ORCLOSE){ if(ro){ error = Eronly; goto out; } /* * check on parent directory of file to be deleted */ if(file->wpath == 0 || file->wpath->addr == file->addr){ error = Ephase; goto out; } p = getbuf(file->fs->dev, file->wpath->addr, Bread); if(p == nil || checktag(p, Tdir, QPNONE)){ error = Ephase; goto out; } d = getdir(p, file->wpath->slot); if(d == nil || !(d->mode & DALLOC)){ error = Ephase; goto out; } if(iaccess(file, d, DWRITE)){ error = Eaccess; goto out; } putbuf(p); } p = getbuf(file->fs->dev, file->addr, Bread); if(p == nil || checktag(p, Tdir, QPNONE)){ error = Ealloc; goto out; } d = getdir(p, file->slot); if(d == nil || !(d->mode & DALLOC)){ error = Ealloc; goto out; } if(error = mkqidcmp(&file->qid, d)) goto out; mkqid(&qid, d, 1); switch(f->mode & 7){ case OREAD: if(iaccess(file, d, DREAD) && !wok) goto badaccess; fmod = FREAD; break; case OWRITE: if((d->mode & DDIR) || (iaccess(file, d, DWRITE) && !wok)) goto badaccess; if(ro){ error = Eronly; goto out; } fmod = FWRITE; break; case ORDWR: if((d->mode & DDIR) || (iaccess(file, d, DREAD) && !wok) || (iaccess(file, d, DWRITE) && !wok)) goto badaccess; if(ro){ error = Eronly; goto out; } fmod = FREAD+FWRITE; break; case OEXEC: if((d->mode & DDIR) || (iaccess(file, d, DEXEC) && !wok)) goto badaccess; fmod = FREAD; break; default: error = Emode; goto out; } if(f->mode & OTRUNC){ if((d->mode & DDIR) || (iaccess(file, d, DWRITE) && !wok)) goto badaccess; if(ro){ error = Eronly; goto out; } } t = 0; if(d->mode & DLOCK){ if((t = tlocked(p, d)) == nil){ error = Elocked; goto out; } } if(f->mode & ORCLOSE) fmod |= FREMOV; file->open = fmod; if((f->mode & OTRUNC) && !(d->mode & DAPND)){ dtrunc(p, d, file->uid); qid.vers = d->qid.version; } r->qid = qid; file->tlock = t; if(t != nil) t->file = file; file->lastra = 1; goto out;badaccess: error = Eaccess; file->open = 0;out: if(p != nil) putbuf(p); if(file != nil) qunlock(file); r->iounit = chan->msize-IOHDRSZ; return error;}static intcreate(Chan* chan, Fcall* f, Fcall* r){ Iobuf *p, *p1; Dentry *d, *d1; File *file; int error, slot, slot1, fmod, wok; Off addr, addr1, path; Tlock *t; Wpath *w; wok = 0; p = nil; if(chan == cons.chan || writeallow) wok = 1; if((file = filep(chan, f->fid, 0)) == nil){ error = Efid; goto out; } if(file->fs->dev->type == Devro){ error = Eronly; goto out; } if(file->qid.type & QTAUTH){ error = Emode; goto out; } p = getbuf(file->fs->dev, file->addr, Bread); if(p == nil || checktag(p, Tdir, QPNONE)){ error = Ealloc; goto out; } d = getdir(p, file->slot); if(d == nil || !(d->mode & DALLOC)){ error = Ealloc; goto out; } if(error = mkqidcmp(&file->qid, d)) goto out; if(!(d->mode & DDIR)){ error = Edir2; goto out; } if(iaccess(file, d, DWRITE) && !wok) { error = Eaccess; goto out; } accessdir(p, d, FREAD, file->uid); /* * Check the name is valid (and will fit in an old * directory entry for the moment). */ if(error = checkname9p2(f->name)) goto out; addr1 = 0; slot1 = 0; /* set */ for(addr = 0; ; addr++){ if((p1 = dnodebuf(p, d, addr, 0, file->uid)) == nil){ if(addr1 != 0) break; p1 = dnodebuf(p, d, addr, Tdir, file->uid); } if(p1 == nil){ error = Efull; goto out; } if(checktag(p1, Tdir, d->qid.path)){ putbuf(p1); goto phase; } for(slot = 0; slot < DIRPERBUF; slot++){ d1 = getdir(p1, slot); if(!(d1->mode & DALLOC)){ if(addr1 == 0){ addr1 = p1->addr; slot1 = slot + addr*DIRPERBUF; } continue; } if(strncmp(f->name, d1->name, sizeof(d1->name)) == 0){ putbuf(p1); error = Eexist; goto out; } } putbuf(p1); } switch(f->mode & 7){ case OEXEC: case OREAD: /* seems only useful to make directories */ fmod = FREAD; break; case OWRITE: fmod = FWRITE; break; case ORDWR: fmod = FREAD+FWRITE; break; default: error = Emode; goto out; } if(f->perm & PDIR) if((f->mode & OTRUNC) || (f->perm & PAPND) || (fmod & FWRITE)) goto badaccess; /* * do it */ path = qidpathgen(file->fs->dev); if((p1 = getbuf(file->fs->dev, addr1, Bread|Bimm|Bmod)) == nil) goto phase; d1 = getdir(p1, slot1); if(d1 == nil || checktag(p1, Tdir, d->qid.path)) { putbuf(p1); goto phase; } if(d1->mode & DALLOC){ putbuf(p1); goto phase; } strncpy(d1->name, f->name, sizeof(d1->name)); if(chan == cons.chan){ d1->uid = cons.uid; d1->gid = cons.gid; } else{ d1->uid = file->uid; d1->gid = d->gid; f->perm &= d->mode | ~0666; if(f->perm & PDIR) f->perm &= d->mode | ~0777; } d1->qid.path = path; d1->qid.version = 0; d1->mode = DALLOC | (f->perm & 0777); if(f->perm & PDIR) { d1->mode |= DDIR; d1->qid.path |= QPDIR; } if(f->perm & PAPND) d1->mode |= DAPND; t = nil; if(f->perm & PLOCK){ d1->mode |= DLOCK; t = tlocked(p1, d1); /* if nil, out of tlock structures */ } accessdir(p1, d1, FWRITE, file->uid); mkqid(&r->qid, d1, 0); putbuf(p1); accessdir(p, d, FWRITE, file->uid); /* * do a walk to new directory entry */ if((w = newwp()) == nil){ error = Ewalk; goto out; } w->addr = file->addr; w->slot = file->slot; w->up = file->wpath; file->wpath = w; file->qid = r->qid; file->tlock = t; if(t != nil) t->file = file; file->lastra = 1; if(f->mode & ORCLOSE) fmod |= FREMOV; file->open = fmod; file->addr = addr1; file->slot = slot1; goto out;badaccess: error = Eaccess; goto out;phase: error = Ephase;out: if(p != nil) putbuf(p); if(file != nil) qunlock(file); r->iounit = chan->msize-IOHDRSZ; return error;}static intread(Chan* chan, Fcall* f, Fcall* r, uchar* data){ Iobuf *p, *p1; File *file; Dentry *d, *d1; Tlock *t; Off addr, offset, start; Timet tim; int error, iounit, nread, count, n, o, slot; Msgbuf *dmb; Dir dir; p = nil; error = 0; count = f->count; offset = f->offset; nread = 0; if((file = filep(chan, f->fid, 0)) == nil){ error = Efid; goto out; } if(!(file->open & FREAD)){ error = Eopen; goto out; } iounit = chan->msize-IOHDRSZ; if(count < 0 || count > iounit){ error = Ecount; goto out; } if(offset < 0){ error = Eoffset; goto out; } if(file->qid.type & QTAUTH){ nread = authread(file, (uchar*)data, count); if(nread < 0) error = Eauth2; goto out; } p = getbuf(file->fs->dev, file->addr, Bread); if(p == nil || checktag(p, Tdir, QPNONE)){ error = Ealloc; goto out; } d = getdir(p, file->slot); if(d == nil || !(d->mode & DALLOC)){ error = Ealloc; goto out; } if(error = mkqidcmp(&file->qid, d)) goto out; if(t = file->tlock){ tim = toytime(); if(t->time < tim || t->file != file){ error = Ebroken; goto out; } /* renew the lock */ t->time = tim + TLOCK; } accessdir(p, d, FREAD, file->uid); if(d->mode & DDIR) goto dread; if(offset+count > d->size) count = d->size - offset; while(count > 0){ if(p == nil){ p = getbuf(file->fs->dev, file->addr, Bread); if(p == nil || checktag(p, Tdir, QPNONE)){ error = Ealloc; goto out; } d = getdir(p, file->slot); if(d == nil || !(d->mode & DALLOC)){ error = Ealloc; goto out; } } addr = offset / BUFSIZE; file->lastra = dbufread(p, d, addr, file->lastra, file->uid); o = offset % BUFSIZE; n = BUFSIZE - o; if(n > count) n = count; p1 = dnodebuf1(p, d, addr, 0, file->uid); p = nil; if(p1 != nil){ if(checktag(p1, Tfile, QPNONE)){ error = Ephase; putbuf(p1); goto out; } memmove(data+nread, p1->iobuf+o, n); putbuf(p1); } else memset(data+nread, 0, n); count -= n; nread += n; offset += n; } goto out;dread: /* * Pick up where we left off last time if nothing has changed, * otherwise must scan from the beginning. */ if(offset == file->doffset /*&& file->qid.vers == file->dvers*/){ addr = file->dslot/DIRPERBUF; slot = file->dslot%DIRPERBUF; start = offset; } else{ addr = 0; slot = 0; start = 0; } dmb = mballoc(iounit, chan, Mbreply1); for (;;) { if(p == nil){ /* * This is just a check to ensure the entry hasn't * gone away during the read of each directory block. */ p = getbuf(file->fs->dev, file->addr, Bread); if(p == nil || checktag(p, Tdir, QPNONE)){ error = Ealloc; goto out1; } d = getdir(p, file->slot); if(d == nil || !(d->mode & DALLOC)){ error = Ealloc; goto out1; } } p1 = dnodebuf1(p, d, addr, 0, file->uid); p = nil; if(p1 == nil) goto out1; if(checktag(p1, Tdir, QPNONE)){ error = Ephase; putbuf(p1); goto out1; } for(; slot < DIRPERBUF; slot++){ d1 = getdir(p1, slot); if(!(d1->mode & DALLOC)) continue; mkdir9p2(&dir, d1, dmb->data); n = convD2M(&dir, data+nread, iounit - nread); if(n <= BIT16SZ){ putbuf(p1); goto out1; } start += n; if(start < offset) continue; if(count < n){ putbuf(p1); goto out1; } count -= n; nread += n; offset += n; } putbuf(p1); slot = 0; addr++; }out1: mbfree(dmb); if(error == 0){ file->doffset = offset; file->dvers = file->qid.vers; file->dslot = slot+DIRPERBUF*addr; }out: /* * Do we need this any more? count = f->count - nread; if(count > 0) memset(data+nread, 0, count); */ if(p != nil) putbuf(p); if(file != nil) qunlock(file); r->count = nread; r->data = (char*)data; return error;}static intwrite(Chan* chan, Fcall* f, Fcall* r){ Iobuf *p, *p1; Dentry *d; File *file; Tlock *t; Off offset, addr, qpath; Timet tim; int count, error, nwrite, o, n; error = 0; offset = f->offset; count = f->count; nwrite = 0; p = nil; if((file = filep(chan, f->fid, 0)) == nil){ error = Efid; goto out; } if(!(file->open & FWRITE)){ error = Eopen; goto out; } if(count < 0 || count > chan->msize-IOHDRSZ){ error = Ecount; goto out; } if(offset < 0) { error = Eoffset; goto out; } if(file->qid.type & QTAUTH){ nwrite = authwrite(file, (uchar*)f->data, count); if(nwrite < 0) error = Eauth2; goto out;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -