Blob
1 /* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */2 /* See COPYRIGHT */4 #include <u.h>5 #include <libc.h>6 #include <fcall.h>7 #include <9pclient.h>8 #include <thread.h>9 #include "fsimpl.h"11 static int _fssend(Mux*, void*);12 static void *_fsrecv(Mux*);13 static int _fsgettag(Mux*, void*);14 static int _fssettag(Mux*, void*, uint);16 int chatty9pclient;18 enum19 {20 CFidchunk = 3221 };23 CFsys*24 fsinit(int fd)25 {26 CFsys *fs;27 int n;29 fmtinstall('F', fcallfmt);30 fmtinstall('D', dirfmt);31 fmtinstall('M', dirmodefmt);33 fs = mallocz(sizeof(CFsys), 1);34 if(fs == nil){35 werrstr("mallocz: %r");36 return nil;37 }38 fs->fd = fd;39 fs->ref = 1;40 fs->mux.aux = fs;41 fs->mux.mintag = 0;42 fs->mux.maxtag = 256;43 fs->mux.send = _fssend;44 fs->mux.recv = _fsrecv;45 fs->mux.gettag = _fsgettag;46 fs->mux.settag = _fssettag;47 fs->iorecv = ioproc();48 fs->iosend = ioproc();49 muxinit(&fs->mux);51 strcpy(fs->version, "9P2000");52 if((n = fsversion(fs, 8192, fs->version, sizeof fs->version)) < 0){53 werrstr("fsversion: %r");54 _fsunmount(fs);55 return nil;56 }57 fs->msize = n;58 return fs;59 }61 CFid*62 fsroot(CFsys *fs)63 {64 /* N.B. no incref */65 return fs->root;66 }68 CFsys*69 fsmount(int fd, char *aname)70 {71 CFsys *fs;72 CFid *fid;74 fs = fsinit(fd);75 if(fs == nil)76 return nil;78 if((fid = fsattach(fs, nil, getuser(), aname)) == nil){79 _fsunmount(fs);80 return nil;81 }82 fssetroot(fs, fid);83 return fs;84 }86 void87 _fsunmount(CFsys *fs)88 {89 fs->fd = -1;90 fsunmount(fs);91 }93 void94 fsunmount(CFsys *fs)95 {96 fsclose(fs->root);97 fs->root = nil;98 _fsdecref(fs);99 }101 void102 _fsdecref(CFsys *fs)103 {104 CFid *f, **l, *next;106 qlock(&fs->lk);107 --fs->ref;108 /*fprint(2, "fsdecref %p to %d\n", fs, fs->ref); */109 if(fs->ref == 0){110 if(fs->fd >= 0)111 close(fs->fd);112 /* trim the list down to just the first in each chunk */113 for(l=&fs->freefid; *l; ){114 if((*l)->fid%CFidchunk == 0)115 l = &(*l)->next;116 else117 *l = (*l)->next;118 }119 /* now free the list */120 for(f=fs->freefid; f; f=next){121 next = f->next;122 free(f);123 }124 closeioproc(fs->iorecv);125 closeioproc(fs->iosend);126 free(fs);127 return;128 }129 qunlock(&fs->lk);130 }132 int133 fsversion(CFsys *fs, int msize, char *version, int nversion)134 {135 void *freep;136 int r, oldmintag, oldmaxtag;137 Fcall tx, rx;139 tx.tag = 0;140 tx.type = Tversion;141 tx.version = version;142 tx.msize = msize;144 /*145 * bit of a clumsy hack -- force libmux to use NOTAG as tag.146 * version can only be sent when there are no other messages147 * outstanding on the wire, so this is more reasonable than it looks.148 */149 oldmintag = fs->mux.mintag;150 oldmaxtag = fs->mux.maxtag;151 fs->mux.mintag = NOTAG;152 fs->mux.maxtag = NOTAG+1;153 r = _fsrpc(fs, &tx, &rx, &freep);154 fs->mux.mintag = oldmintag;155 fs->mux.maxtag = oldmaxtag;156 if(r < 0){157 werrstr("fsrpc: %r");158 return -1;159 }161 strecpy(version, version+nversion, rx.version);162 free(freep);163 fs->msize = rx.msize;164 return rx.msize;165 }167 CFid*168 fsattach(CFsys *fs, CFid *afid, char *user, char *aname)169 {170 Fcall tx, rx;171 CFid *fid;173 if(aname == nil)174 aname = "";176 if((fid = _fsgetfid(fs)) == nil)177 return nil;179 tx.tag = 0;180 tx.type = Tattach;181 tx.afid = afid ? afid->fid : NOFID;182 tx.fid = fid->fid;183 tx.uname = user;184 tx.aname = aname;186 if(_fsrpc(fs, &tx, &rx, 0) < 0){187 _fsputfid(fid);188 return nil;189 }190 fid->qid = rx.qid;191 return fid;192 }194 void195 fssetroot(CFsys *fs, CFid *fid)196 {197 if(fs->root)198 _fsputfid(fs->root);199 fs->root = fid;200 }202 int203 _fsrpc(CFsys *fs, Fcall *tx, Fcall *rx, void **freep)204 {205 int n, nn;206 void *tpkt, *rpkt;208 n = sizeS2M(tx);209 tpkt = malloc(n);210 if(freep)211 *freep = nil;212 if(tpkt == nil)213 return -1;214 tx->tag = 0;215 if(chatty9pclient)216 fprint(2, "<- %F\n", tx);217 nn = convS2M(tx, tpkt, n);218 if(nn != n){219 free(tpkt);220 werrstr("lib9pclient: sizeS2M convS2M mismatch");221 fprint(2, "%r\n");222 return -1;223 }224 rpkt = muxrpc(&fs->mux, tpkt);225 free(tpkt);226 if(rpkt == nil){227 werrstr("muxrpc: %r");228 return -1;229 }230 n = GBIT32((uchar*)rpkt);231 nn = convM2S(rpkt, n, rx);232 if(nn != n){233 free(rpkt);234 werrstr("lib9pclient: convM2S packet size mismatch %d %d", n, nn);235 fprint(2, "%r\n");236 return -1;237 }238 if(chatty9pclient)239 fprint(2, "-> %F\n", rx);240 if(rx->type == Rerror){241 werrstr("%s", rx->ename);242 free(rpkt);243 return -1;244 }245 if(rx->type != tx->type+1){246 werrstr("packet type mismatch -- tx %d rx %d",247 tx->type, rx->type);248 free(rpkt);249 return -1;250 }251 if(freep)252 *freep = rpkt;253 else254 free(rpkt);255 return 0;256 }258 CFid*259 _fsgetfid(CFsys *fs)260 {261 int i;262 CFid *f;264 qlock(&fs->lk);265 if(fs->freefid == nil){266 f = mallocz(sizeof(CFid)*CFidchunk, 1);267 if(f == nil){268 qunlock(&fs->lk);269 return nil;270 }271 for(i=0; i<CFidchunk; i++){272 f[i].fid = fs->nextfid++;273 f[i].next = &f[i+1];274 f[i].fs = fs;275 }276 f[i-1].next = nil;277 fs->freefid = f;278 }279 f = fs->freefid;280 fs->freefid = f->next;281 fs->ref++;282 qunlock(&fs->lk);283 f->offset = 0;284 f->mode = -1;285 f->qid.path = 0;286 f->qid.vers = 0;287 f->qid.type = 0;288 return f;289 }291 void292 _fsputfid(CFid *f)293 {294 CFsys *fs;296 fs = f->fs;297 qlock(&fs->lk);298 f->next = fs->freefid;299 fs->freefid = f;300 qunlock(&fs->lk);301 _fsdecref(fs);302 }304 static int305 _fsgettag(Mux *mux, void *pkt)306 {307 return GBIT16((uchar*)pkt+5);308 }310 static int311 _fssettag(Mux *mux, void *pkt, uint tag)312 {313 PBIT16((uchar*)pkt+5, tag);314 return 0;315 }317 static int318 _fssend(Mux *mux, void *pkt)319 {320 CFsys *fs;322 fs = mux->aux;323 return iowrite(fs->iosend, fs->fd, pkt, GBIT32((uchar*)pkt));324 }326 static void*327 _fsrecv(Mux *mux)328 {329 uchar *pkt;330 uchar buf[4];331 int n, nfd;332 CFsys *fs;334 fs = mux->aux;335 n = ioreadn(fs->iorecv, fs->fd, buf, 4);336 if(n != 4)337 return nil;338 n = GBIT32(buf);339 pkt = malloc(n+4);340 if(pkt == nil){341 fprint(2, "lib9pclient out of memory reading 9p packet; here comes trouble\n");342 return nil;343 }344 PBIT32(pkt, n);345 if(ioreadn(fs->iorecv, fs->fd, pkt+4, n-4) != n-4){346 free(pkt);347 return nil;348 }349 if(pkt[4] == Ropenfd){350 if((nfd=iorecvfd(fs->iorecv, fs->fd)) < 0){351 fprint(2, "recv fd error: %r\n");352 free(pkt);353 return nil;354 }355 PBIT32(pkt+n-4, nfd);356 }357 return pkt;358 }