📄 nfs.c
字号:
mode &= (attr.mode&0777) | ~0777; gid = attr.gid; if(r->ifcall.perm&DMDIR) mk = nfsMkdir; else mk = nfsCreate; if((*mk)(aux->auth, r->tag, &aux->handle, r->ifcall.name, &h, mode, gid, &have, &attr) < 0 || (!have && nfsGetattr(aux->auth, r->tag, &h, &attr) < 0)){ responderrstr(r); return; } attrToQid(&attr, &r->fid->qid); aux->parent = aux->handle; aux->handle = h; free(aux->name); aux->name = estrdup9p(r->ifcall.name); r->ofcall.qid = r->fid->qid; respond(r, nil);}voidfsreaddir(Req *r){ FidAux *aux; uchar *p, *freeme, *ep, *p9, *ep9; char *s; uint count; int n, (*unpack)(uchar*, uchar*, uchar**, Nfs3Entry*); Nfs3Entry e; u64int cookie; Dir d; aux = r->fid->aux; /* * r->ifcall.count seems a reasonable estimate to * how much NFS entry data we want. is it? */ if(r->ifcall.offset) cookie = aux->cookie; else cookie = 0; if(nfsReadDir(aux->auth, r->tag, &aux->handle, r->ifcall.count, cookie, &p, &count, &unpack, &freeme) < 0){ responderrstr(r); return; } ep = p+count; p9 = (uchar*)r->ofcall.data; ep9 = p9+r->ifcall.count; /* * BUG: Issue all of the stat requests in parallel. */ while(p < ep && p9 < ep9){ if((*unpack)(p, ep, &p, &e) < 0) break; aux->cookie = e.cookie; if(strcmp(e.name, ".") == 0 || strcmp(e.name, "..") == 0) continue; for(s=e.name; (uchar)*s >= ' '; s++) ; if(*s != 0) /* bad character in name */ continue; if(!e.haveAttr && !e.haveHandle) if(nfsLookup(aux->auth, r->tag, &aux->handle, e.name, &e.handle, &e.haveAttr, &e.attr) < 0) continue; if(!e.haveAttr) if(nfsGetattr(aux->auth, r->tag, &e.handle, &e.attr) < 0) continue; memset(&d, 0, sizeof d); attrToDir(&e.attr, &d); d.name = e.name; if((n = convD2M(&d, p9, ep9-p9)) <= BIT16SZ) break; p9 += n; } free(freeme); r->ofcall.count = p9 - (uchar*)r->ofcall.data; respond(r, nil);} voidfsread(Req *r){ uchar *p, *freeme; uint count; FidAux *aux; if(r->fid->qid.type&QTDIR){ fsreaddir(r); return; } aux = r->fid->aux; if(nfsRead(aux->auth, r->tag, &aux->handle, r->ifcall.count, r->ifcall.offset, &p, &count, &freeme) < 0){ responderrstr(r); return; } r->ofcall.data = (char*)p; r->ofcall.count = count; respond(r, nil); free(freeme);}voidfswrite(Req *r){ uint count; FidAux *aux; aux = r->fid->aux; if(nfsWrite(aux->auth, r->tag, &aux->handle, (uchar*)r->ifcall.data, r->ifcall.count, r->ifcall.offset, &count) < 0){ responderrstr(r); return; } r->ofcall.count = count; respond(r, nil);}voidfsremove(Req *r){ int n; FidAux *aux; aux = r->fid->aux; if(aux->name == nil){ respond(r, "nfs3client botch -- don't know parent handle in remove"); return; } if(r->fid->qid.type&QTDIR) n = nfsRmdir(aux->auth, r->tag, &aux->parent, aux->name); else n = nfsRemove(aux->auth, r->tag, &aux->parent, aux->name); if(n < 0){ responderrstr(r); return; } respond(r, nil);}voidfsstat(Req *r){ FidAux *aux; Nfs3Attr attr; aux = r->fid->aux; if(nfsGetattr(aux->auth, r->tag, &aux->handle, &attr) < 0){ responderrstr(r); return; } memset(&r->d, 0, sizeof r->d); attrToDir(&attr, &r->d); r->d.name = estrdup9p(aux->name ? aux->name : "???"); respond(r, nil);}voidfswstat(Req *r){ int op, sync; FidAux *aux; Nfs3SetAttr attr; memset(&attr, 0, sizeof attr); aux = r->fid->aux; /* Fill out stat first to catch errors */ op = 0; sync = 1; if(~r->d.mode){ if(r->d.mode&(DMAPPEND|DMEXCL)){ respond(r, "wstat -- DMAPPEND and DMEXCL bits not supported"); return; } op = 1; sync = 0; attr.setMode = 1; attr.mode = r->d.mode & 0777; } if(r->d.uid && r->d.uid[0]){ attr.setUid = 1; if(strtouid(r->d.uid, &attr.uid) < 0){ respond(r, "wstat -- unknown uid"); return; } op = 1; sync = 0; } if(r->d.gid && r->d.gid[0]){ attr.setGid = 1; if(strtogid(r->d.gid, &attr.gid) < 0){ respond(r, "wstat -- unknown gid"); return; } op = 1; sync = 0; } if(~r->d.length){ attr.setSize = 1; attr.size = r->d.length; op = 1; sync = 0; } if(~r->d.mtime){ attr.setMtime = Nfs3SetTimeClient; attr.mtime.sec = r->d.mtime; op = 1; sync = 0; } if(~r->d.atime){ attr.setAtime = Nfs3SetTimeClient; attr.atime.sec = r->d.atime; op = 1; sync = 0; } /* Try rename first because it's more likely to fail (?) */ if(r->d.name && r->d.name[0]){ if(aux->name == nil){ respond(r, "nfsclient botch -- don't know parent handle in rename"); return; } if(nfsRename(aux->auth, r->tag, &aux->parent, aux->name, &aux->parent, r->d.name) < 0){ responderrstr(r); return; } free(aux->name); aux->name = estrdup9p(r->d.name); sync = 0; } /* * Now we have a problem. The rename succeeded * but the setattr could fail. Sic transit atomicity. */ if(op){ if(nfsSetattr(aux->auth, r->tag, &aux->handle, &attr) < 0){ responderrstr(r); return; } } if(sync){ /* NFS commit */ if(nfsCommit(aux->auth, r->tag, &aux->handle) < 0){ responderrstr(r); return; } } respond(r, nil);}char*fswalk1(Fid *fid, char *name, void *v){ u1int have; ulong tag; FidAux *aux; Nfs3Attr attr; Nfs3Handle h; tag = *(ulong*)v; aux = fid->aux; if(nfsLookup(aux->auth, tag, &aux->handle, name, &h, &have, &attr) < 0 || (!have && nfsGetattr(aux->auth, tag, &h, &attr) < 0)){ rerrstr(aux->err, sizeof aux->err); return aux->err; } aux->parent = aux->handle; aux->handle = h; free(aux->name); if(strcmp(name, "..") == 0) aux->name = nil; else aux->name = estrdup9p(name); attrToQid(&attr, &fid->qid); return nil;}char*fsclone(Fid *fid, Fid *newfid, void*){ FidAux *a, *na; a = fid->aux; na = emalloc9p(sizeof(FidAux)); *na = *a; if(na->name) na->name = estrdup9p(na->name); newfid->aux = na; if(na->auth) na->auth->ref++; return nil;}voidfswalk(Req *r){ walkandclone(r, fswalk1, fsclone, &r->tag);}voidfsflush(Req *r){ Req *or; /* * Send on the flush channel(s). * The library will make sure the response * is delayed as necessary. */ or = r->oldreq; if(nfscli) sendul(nfscli->flushchan, (ulong)or->tag); if(mntcli) sendul(mntcli->flushchan, (ulong)or->tag); respond(r, nil);}voidfsdispatch(void *v){ Req *r; r = v; switch(r->ifcall.type){ default: respond(r, "unknown type"); break; case Tattach: fsattach(r); break; case Topen: fsopen(r); break; case Tcreate: fscreate(r); break; case Tread: fsread(r); break; case Twrite: fswrite(r); break; case Tremove: fsremove(r); break; case Tflush: fsflush(r); break; case Tstat: fsstat(r); break; case Twstat: fswstat(r); break; case Twalk: fswalk(r); break; }}voidfsthread(void*){ Req *r; while((r = recvp(fschan)) != nil) threadcreate(fsdispatch, r, SunStackSize);}voidfssend(Req *r){ sendp(fschan, r);}voidfsdie(Srv*){ threadexitsall(nil);}Srv fs ={.destroyfid = fsdestroyfid,.attach= fssend,.open= fssend,.create= fssend,.read= fssend,.write= fssend,.remove= fssend,.flush= fssend,.stat= fssend,.wstat= fssend,.walk= fssend,.end= fsdie};voidusage(void){ fprint(2, "usage: nfs [-DRv] [-p perm] [-s srvname] [-u passwd group] addr [addr]\n"); fprint(2, "\taddr - address of portmapper server\n"); fprint(2, "\taddr addr - addresses of mount server and nfs server\n"); exits("usage");}char*netchangeport(char *addr, uint port, char *buf, uint nbuf){ char *r; strecpy(buf, buf+nbuf, addr); r = strrchr(buf, '!'); if(r == nil) return nil; r++; seprint(r, buf+nbuf, "%ud", port); return buf;}char mbuf[256], nbuf[256];char *mountaddr, *nfsaddr;Channel *csync;int chattyrpc;void dialproc(void*);voidthreadmain(int argc, char **argv){ char *srvname, *passwd, *group, *addr, *p; SunClient *cli; int proto; uint mport, nport; ulong perm; Dir d; perm = 0600; passwd = nil; group = nil; srvname = nil; sys = sysname(); if(sys == nil) sys = "plan9"; ARGBEGIN{ default: usage(); case 'D': chatty9p++; break; case 'R': chattyrpc++; break; case 'p': perm = strtol(EARGF(usage()), &p, 8); if(perm==0 || *p != 0) usage(); break; case 's': srvname = EARGF(usage()); break; case 'u': passwd = EARGF(usage()); group = EARGF(usage()); break; case 'v': verbose++; break; }ARGEND if(argc != 1 && argc != 2) usage(); if(srvname == nil) srvname = argv[0]; fmtinstall('B', sunRpcFmt); fmtinstall('C', sunCallFmt); fmtinstall('H', encodefmt); sunFmtInstall(&portProg); sunFmtInstall(&nfs3Prog); sunFmtInstall(&nfsMount3Prog); if(passwd && (map = readmap(passwd, group)) == nil) fprint(2, "warning: reading %s and %s: %r\n", passwd, group); if(map == nil) map = &emptymap; if(argc == 1){ addr = netmkaddr(argv[0], "udp", "portmap"); if((cli = sunDial(addr)) == nil) sysfatal("dial %s: %r", addr); cli->chatty = chattyrpc; sunClientProg(cli, &portProg); if(strstr(addr, "udp!")) proto = PortProtoUdp; else proto = PortProtoTcp; if(getport(cli, NfsMount3Program, NfsMount3Version, proto, &mport) < 0) sysfatal("lookup mount program port: %r"); if(getport(cli, Nfs3Program, Nfs3Version, proto, &nport) < 0) sysfatal("lookup nfs program port: %r"); sunClientClose(cli); mountaddr = netchangeport(addr, mport, mbuf, sizeof mbuf); nfsaddr = netchangeport(addr, nport, nbuf, sizeof nbuf); strcat(mountaddr, "!r"); strcat(nfsaddr, "!r"); if(verbose) fprint(2, "nfs %s %s\n", mountaddr, nfsaddr); }else{ mountaddr = argv[0]; nfsaddr = argv[1]; } /* have to dial in another proc because it creates threads */ csync = chancreate(sizeof(void*), 0); proccreate(dialproc, nil, SunStackSize); recvp(csync); threadpostmountsrv(&fs, srvname, nil, 0); if(perm != 0600){ p = smprint("/srv/%s", srvname); if(p){ nulldir(&d); d.mode = perm; dirwstat(p, &d); } } threadexits(nil);}voiddialproc(void*){ rfork(RFNAMEG); rfork(RFNOTEG); if((mntcli = sunDial(mountaddr)) == nil) sysfatal("dial mount program at %s: %r", mountaddr); mntcli->chatty = chattyrpc; sunClientProg(mntcli, &nfsMount3Prog); if(mountNull(0) < 0) sysfatal("execute nop with mnt server at %s: %r", mountaddr); if((nfscli = sunDial(nfsaddr)) == nil) sysfatal("dial nfs program at %s: %r", nfsaddr); nfscli->chatty = chattyrpc; sunClientProg(nfscli, &nfs3Prog); if(nfsNull(0) < 0) sysfatal("execute nop with nfs server at %s: %r", nfsaddr); fschan = chancreate(sizeof(Req*), 0); threadcreate(fsthread, nil, SunStackSize); sendp(csync, 0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -