📄 9p2.c
字号:
goto out; } if((p = getbuf(file->fs->dev, file->addr, Bread|Bmod)) == nil){ error = Ealloc; goto out; } if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){ error = Ealloc; goto out; } if(error = mkqidcmp(&file->qid, d)) goto out; if(t = file->tlock) { tim = time(0); if(t->time < tim || t->file != file){ error = Ebroken; goto out; } /* renew the lock */ t->time = tim + TLOCK; } accessdir(p, d, FWRITE); if(d->mode & DAPND) offset = d->size; if(offset+count > d->size) d->size = offset+count; while(count > 0){ if(p == nil){ p = getbuf(file->fs->dev, file->addr, Bread|Bmod); if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){ error = Ealloc; goto out; } } addr = offset / BUFSIZE; o = offset % BUFSIZE; n = BUFSIZE - o; if(n > count) n = count; qpath = d->qid.path; p1 = dnodebuf1(p, d, addr, Tfile); p = nil; if(p1 == nil) { error = Efull; goto out; } if(checktag(p1, Tfile, qpath)){ putbuf(p1); error = Ephase; goto out; } memmove(p1->iobuf+o, f->data+nwrite, n); p1->flags |= Bmod; putbuf(p1); count -= n; nwrite += n; offset += n; }out: if(p != nil) putbuf(p); if(file != nil) qunlock(file); r->count = nwrite; return error;}static int_clunk(File* file, int remove, int wok){ Tlock *t; int error; error = 0; if(t = file->tlock){ if(t->file == file) t->time = 0; /* free the lock */ file->tlock = 0; } if(remove) error = doremove(file, wok); file->open = 0; freewp(file->wpath); freefp(file); qunlock(file); return error;}static intfsclunk(Chan* chan, Fcall* f, Fcall*){ File *file; if((file = filep(chan, f->fid, 0)) == nil) return Efid; _clunk(file, file->open & FREMOV, 0); return 0;}static intfsremove(Chan* chan, Fcall* f, Fcall*){ File *file; if((file = filep(chan, f->fid, 0)) == nil) return Efid; return _clunk(file, 1, chan == cons.chan);}static intfsstat(Chan* chan, Fcall* f, Fcall* r, uchar* data){ Dir dir; Iobuf *p; Dentry *d; File *file; int error, len; if((file = filep(chan, f->fid, 0)) == nil) return Efid; p = getbuf(file->fs->dev, file->addr, Bread); if(p == nil || checktag(p, Tdir, QPNONE)){ error = Edir1; goto out; } if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){ error = Ealloc; goto out; } if(error = mkqidcmp(&file->qid, d)) goto out; if(d->qid.path == QPROOT) /* stat of root gives time */ d->atime = time(0); len = dir9p2(&dir, d, data); data += len; if((r->nstat = convD2M(&dir, data, chan->msize - len)) == 0) error = Ersc; else r->stat = data;out: if(p != nil) putbuf(p); if(file != nil) qunlock(file); return error;}static intfswstat(Chan* chan, Fcall* f, Fcall*, char *strs){ Iobuf *p, *p1; Dentry *d, *d1, xd; File *file; int error, slot, uid, gid, l; long addr; Dir dir; ulong mode; p = p1 = nil; d1 = nil; if((file = filep(chan, f->fid, 0)) == nil){ error = Efid; goto out; } /* * if user none, * can't do anything * unless allow. */ if(file->uid == 0 && !wstatallow){ error = Eaccess; goto out; } if(isro(file->fs->dev) || (writegroup && !ingroup(file->uid, writegroup))){ error = Eronly; goto out; } /* * first get parent */ if(file->wpath){ p1 = getbuf(file->fs->dev, file->wpath->addr, Bread); if(p1 == nil){ error = Ephase; goto out; } d1 = getdir(p1, file->wpath->slot); if(d1 == nil || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)){ error = Ephase; goto out; } } if((p = getbuf(file->fs->dev, file->addr, Bread)) == nil){ error = Ealloc; goto out; } d = getdir(p, file->slot); if(d == nil || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)){ error = Ealloc; goto out; } if(error = mkqidcmp(&file->qid, d)) goto out; /* * Convert the message and fix up * fields not to be changed. */ if(convM2D(f->stat, f->nstat, &dir, strs) == 0){ print("9p2: convM2D returns 0\n"); error = Econvert; goto out; } if(dir.uid == nil || strlen(dir.uid) == 0) uid = d->uid; else uid = strtouid(dir.uid); if(dir.gid == nil || strlen(dir.gid) == 0) gid = d->gid; else gid = strtouid(dir.gid); if(dir.name == nil || strlen(dir.name) == 0) dir.name = d->name; else{ if((l = checkname9p2(dir.name)) == 0){ error = Ename; goto out; } if(l > NAMELEN){ error = Etoolong; goto out; } } /* * Before doing sanity checks, find out what the * new 'mode' should be: * if 'type' and 'mode' are both defaults, take the * new mode from the old directory entry; * else if 'type' is the default, use the new mode entry; * else if 'mode' is the default, create the new mode from * 'type' or'ed with the old directory mode; * else neither are defaults, use the new mode but check * it agrees with 'type'. */ if(dir.qid.type == 0xFF && dir.mode == ~0){ dir.mode = d->mode & 0777; if(d->mode & DLOCK) dir.mode |= DMEXCL; if(d->mode & DAPND) dir.mode |= DMAPPEND; if(d->mode & DDIR) dir.mode |= DMDIR; } else if(dir.qid.type == 0xFF){ /* nothing to do */ } else if(dir.mode == ~0) dir.mode = (dir.qid.type<<24)|(d->mode & 0777); else if(dir.qid.type != ((dir.mode>>24) & 0xFF)){ error = Eqidmode; goto out; } /* * Check for unknown type/mode bits * and an attempt to change the directory bit. */ if(dir.mode & ~(DMDIR|DMAPPEND|DMEXCL|0777)){ error = Enotm; goto out; } if(d->mode & DDIR) mode = DMDIR; else mode = 0; if((dir.mode^mode) & DMDIR){ error = Enotd; goto out; } if(dir.mtime == ~0) dir.mtime = d->mtime; if(dir.length == ~0) dir.length = d->size; /* * Currently, can't change length. */ if(dir.length != d->size){ error = Enotl; goto out; } /* * if chown, * must be god * wstatallow set to allow chown during boot */ if(uid != d->uid && !wstatallow) { error = Enotu; goto out; } /* * if chgroup, * must be either * a) owner and in new group * b) leader of both groups * wstatallow and writeallow are set to allow chgrp during boot */ while(gid != d->gid) { if(wstatallow || writeallow) break; if(d->uid == file->uid && ingroup(file->uid, gid)) break; if(leadgroup(file->uid, gid)) if(leadgroup(file->uid, d->gid)) break; error = Enotg; goto out; } /* * if rename, * must have write permission in parent */ while(strncmp(d->name, dir.name, sizeof(d->name)) != 0) { if(checkname(dir.name) || d1 == nil) { error = Ename; goto out; } if(strcmp(dir.name, ".") == 0 || strcmp(xd.name, "..") == 0) { error = Ename; goto out; } /* * drop entry to prevent lock, then * check that destination name is unique, */ putbuf(p); for(addr = 0; ; addr++) { if((p = dnodebuf(p1, d1, addr, 0)) == nil) break; if(checktag(p, Tdir, d1->qid.path)) { putbuf(p); continue; } for(slot = 0; slot < DIRPERBUF; slot++) { d = getdir(p, slot); if(!(d->mode & DALLOC)) continue; if(strncmp(dir.name, d->name, sizeof(d->name)) == 0) { error = Eexist; goto out; } } putbuf(p); } /* * reacquire entry */ if((p = getbuf(file->fs->dev, file->addr, Bread)) == nil){ error = Ephase; goto out; } d = getdir(p, file->slot); if(d == nil || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) { error = Ephase; goto out; } if(wstatallow || writeallow) /* set to allow rename during boot */ break; if(d1 == nil || iaccess(file, d1, DWRITE)) { error = Eaccess; goto out; } break; } /* * if mode/time, either * a) owner * b) leader of either group */ mode = dir.mode & 0777; if(dir.mode & DMAPPEND) mode |= DAPND; if(dir.mode & DMEXCL) mode |= DLOCK; while(d->mtime != dir.mtime || ((d->mode^mode) & (DAPND|DLOCK|0777))) { if(wstatallow) /* set to allow chmod during boot */ break; if(d->uid == file->uid) break; if(leadgroup(file->uid, gid)) break; if(leadgroup(file->uid, d->gid)) break; error = Enotu; goto out; } d->mtime = dir.mtime; d->uid = uid; d->gid = gid; d->mode = (mode & (DAPND|DLOCK|0777)) | (d->mode & (DALLOC|DDIR)); strncpy(d->name, dir.name, sizeof(d->name)); accessdir(p, d, FWSTAT);out: if(p != nil) putbuf(p); if(p1 != nil) putbuf(p1); if(file != nil) qunlock(file); return error;}static intrecv(Chan *c, uchar *buf, int n){ int fd, m, len; fd = c->chan; /* read count */ qlock(&c->rlock); m = readn(fd, buf, BIT32SZ); if(m != BIT32SZ){ qunlock(&c->rlock); if(m < 0){ print("readn(BIT32SZ) fails: %r\n"); return -1; } print("readn(BIT32SZ) returns %d: %r\n", m); return 0; } len = GBIT32(buf); if(len <= BIT32SZ || len > n){ print("recv bad length %d\n", len); werrstr("bad length in 9P2000 message header"); qunlock(&c->rlock); return -1; } len -= BIT32SZ; m = readn(fd, buf+BIT32SZ, len); qunlock(&c->rlock); if(m < len){ print("recv wanted %d got %d\n", len, m); return 0; } return BIT32SZ+m;}static voidsend(Chan *c, uchar *buf, int n){ int fd, m; fd = c->chan; qlock(&c->wlock); m = write(fd, buf, n); qunlock(&c->wlock); if(m == n) return; panic("write failed");}voidserve9p2(Chan *chan, uchar *ib, int nib){ uchar inbuf[MSIZE+IOHDRSZ], outbuf[MSIZE+IOHDRSZ]; Fcall f, r; char ename[64]; int error, n, type; chan->msize = MSIZE; fmtinstall('F', fcallfmt); for(;;){ if(nib){ memmove(inbuf, ib, nib); n = nib; nib = 0; }else n = recv(chan, inbuf, sizeof inbuf); if(chat){ print("read msg %d (fd %d)\n", n, chan->chan); if(n <= 0) print("\terr: %r\n"); } if(n == 0 && (chan == cons.srvchan || chan == cons.chan)) continue; if(n <= 0) break; if(convM2S(inbuf, n, &f) != n){ print("9p2: cannot decode\n"); continue; } type = f.type; if(type < Tversion || type >= Tmax || (type&1) || type == Terror){ print("9p2: bad message type %d\n", type); continue; } if(CHAT(chan)) print("9p2: f %F\n", &f); r.type = type+1; r.tag = f.tag; error = 0; rlock(&mainlock); rlock(&chan->reflock); switch(type){ default: r.type = Rerror; snprint(ename, sizeof ename, "unknown message: %F", &f); r.ename = ename; break; case Tversion: error = fsversion(chan, &f, &r); break; case Tauth: error = fsauth(chan, &f, &r); break; case Tattach: error = fsattach(chan, &f, &r); break; case Tflush: error = fsflush(chan, &f, &r); break; case Twalk: error = fswalk(chan, &f, &r); break; case Topen: error = fsopen(chan, &f, &r); break; case Tcreate: error = fscreate(chan, &f, &r); break; case Tread: r.data = (char*)inbuf; error = fsread(chan, &f, &r); break; case Twrite: error = fswrite(chan, &f, &r); break; case Tclunk: error = fsclunk(chan, &f, &r); break; case Tremove: error = fsremove(chan, &f, &r); break; case Tstat: error = fsstat(chan, &f, &r, inbuf); break; case Twstat: error = fswstat(chan, &f, &r, (char*)outbuf); break; } runlock(&chan->reflock); runlock(&mainlock); if(error != 0){ r.type = Rerror; if(error >= MAXERR){ snprint(ename, sizeof(ename), "error %d", error); r.ename = ename; } else r.ename = errstring[error]; } if(CHAT(chan)) print("9p2: r %F\n", &r); n = convS2M(&r, outbuf, sizeof outbuf); if(n == 0){ type = r.type; r.type = Rerror; snprint(ename, sizeof(ename), "9p2: convS2M: type %d", type); r.ename = ename; print(ename); n = convS2M(&r, outbuf, sizeof outbuf); if(n == 0){ /* * What to do here, the failure notification failed? */ panic("can't write anything at all"); } } send(chan, outbuf, n); } fileinit(chan); close(chan->chan); if(chan == cons.srvchan || chan == cons.chan) print("console chan read error");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -