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 fprint(2, "%r\n");55 _fsunmount(fs);56 return nil;57 }58 fs->msize = n;59 return fs;60 }62 CFid*63 fsroot(CFsys *fs)64 {65 /* N.B. no incref */66 return fs->root;67 }69 CFsys*70 fsmount(int fd, char *aname)71 {72 CFsys *fs;73 CFid *fid;75 fs = fsinit(fd);76 if(fs == nil)77 return nil;79 if((fid = fsattach(fs, nil, getuser(), aname)) == nil){80 _fsunmount(fs);81 return nil;82 }83 fssetroot(fs, fid);84 return fs;85 }87 void88 _fsunmount(CFsys *fs)89 {90 fs->fd = -1;91 fsunmount(fs);92 }94 void95 fsunmount(CFsys *fs)96 {97 fsclose(fs->root);98 fs->root = nil;99 _fsdecref(fs);100 }102 void103 _fsdecref(CFsys *fs)104 {105 CFid *f, **l, *next;107 qlock(&fs->lk);108 --fs->ref;109 //fprint(2, "fsdecref %p to %d\n", fs, fs->ref);110 if(fs->ref == 0){111 if(fs->fd >= 0)112 close(fs->fd);113 /* trim the list down to just the first in each chunk */114 for(l=&fs->freefid; *l; ){115 if((*l)->fid%CFidchunk == 0)116 l = &(*l)->next;117 else118 *l = (*l)->next;119 }120 /* now free the list */121 for(f=fs->freefid; f; f=next){122 next = f->next;123 free(f);124 }125 closeioproc(fs->iorecv);126 closeioproc(fs->iosend);127 free(fs);128 return;129 }130 qunlock(&fs->lk);131 }133 int134 fsversion(CFsys *fs, int msize, char *version, int nversion)135 {136 void *freep;137 int r, oldmintag, oldmaxtag;138 Fcall tx, rx;140 tx.tag = 0;141 tx.type = Tversion;142 tx.version = version;143 tx.msize = msize;145 /*146 * bit of a clumsy hack -- force libmux to use NOTAG as tag.147 * version can only be sent when there are no other messages148 * outstanding on the wire, so this is more reasonable than it looks.149 */150 oldmintag = fs->mux.mintag;151 oldmaxtag = fs->mux.maxtag;152 fs->mux.mintag = NOTAG;153 fs->mux.maxtag = NOTAG+1;154 r = _fsrpc(fs, &tx, &rx, &freep);155 fs->mux.mintag = oldmintag;156 fs->mux.maxtag = oldmaxtag;157 if(r < 0){158 werrstr("fsrpc: %r");159 return -1;160 }162 strecpy(version, version+nversion, rx.version);163 free(freep);164 fs->msize = rx.msize;165 return rx.msize;166 }168 CFid*169 fsattach(CFsys *fs, CFid *afid, char *user, char *aname)170 {171 Fcall tx, rx;172 CFid *fid;174 if(aname == nil)175 aname = "";177 if((fid = _fsgetfid(fs)) == nil)178 return nil;180 tx.tag = 0;181 tx.type = Tattach;182 tx.afid = afid ? afid->fid : NOFID;183 tx.fid = fid->fid;184 tx.uname = user;185 tx.aname = aname;187 if(_fsrpc(fs, &tx, &rx, 0) < 0){188 _fsputfid(fid);189 return nil;190 }191 fid->qid = rx.qid;192 return fid;193 }195 void196 fssetroot(CFsys *fs, CFid *fid)197 {198 if(fs->root)199 _fsputfid(fs->root);200 fs->root = fid;201 }203 int204 _fsrpc(CFsys *fs, Fcall *tx, Fcall *rx, void **freep)205 {206 int n, nn;207 void *tpkt, *rpkt;209 n = sizeS2M(tx);210 tpkt = malloc(n);211 if(freep)212 *freep = nil;213 if(tpkt == nil)214 return -1;215 tx->tag = 0;216 if(chatty9pclient)217 fprint(2, "<- %F\n", tx);218 nn = convS2M(tx, tpkt, n);219 if(nn != n){220 free(tpkt);221 werrstr("lib9pclient: sizeS2M convS2M mismatch");222 fprint(2, "%r\n");223 return -1;224 }225 rpkt = muxrpc(&fs->mux, tpkt);226 free(tpkt);227 if(rpkt == nil){228 werrstr("muxrpc: %r");229 return -1;230 }231 n = GBIT32((uchar*)rpkt);232 nn = convM2S(rpkt, n, rx);233 if(nn != n){234 free(rpkt);235 werrstr("lib9pclient: convM2S packet size mismatch %d %d", n, nn);236 fprint(2, "%r\n");237 return -1;238 }239 if(chatty9pclient)240 fprint(2, "-> %F\n", rx);241 if(rx->type == Rerror){242 werrstr("%s", rx->ename);243 free(rpkt);244 return -1;245 }246 if(rx->type != tx->type+1){247 werrstr("packet type mismatch -- tx %d rx %d",248 tx->type, rx->type);249 free(rpkt);250 return -1;251 }252 if(freep)253 *freep = rpkt;254 else255 free(rpkt);256 return 0;257 }259 CFid*260 _fsgetfid(CFsys *fs)261 {262 int i;263 CFid *f;265 qlock(&fs->lk);266 if(fs->freefid == nil){267 f = mallocz(sizeof(CFid)*CFidchunk, 1);268 if(f == nil){269 qunlock(&fs->lk);270 return nil;271 }272 for(i=0; i<CFidchunk; i++){273 f[i].fid = fs->nextfid++;274 f[i].next = &f[i+1];275 f[i].fs = fs;276 }277 f[i-1].next = nil;278 fs->freefid = f;279 }280 f = fs->freefid;281 fs->freefid = f->next;282 fs->ref++;283 qunlock(&fs->lk);284 f->offset = 0;285 f->mode = -1;286 f->qid.path = 0;287 f->qid.vers = 0;288 f->qid.type = 0;289 return f;290 }292 void293 _fsputfid(CFid *f)294 {295 CFsys *fs;297 fs = f->fs;298 qlock(&fs->lk);299 f->next = fs->freefid;300 fs->freefid = f;301 qunlock(&fs->lk);302 _fsdecref(fs);303 }305 static int306 _fsgettag(Mux *mux, void *pkt)307 {308 return GBIT16((uchar*)pkt+5);309 }311 static int312 _fssettag(Mux *mux, void *pkt, uint tag)313 {314 PBIT16((uchar*)pkt+5, tag);315 return 0;316 }318 static int319 _fssend(Mux *mux, void *pkt)320 {321 CFsys *fs;323 fs = mux->aux;324 return iowrite(fs->iosend, fs->fd, pkt, GBIT32((uchar*)pkt));325 }327 static void*328 _fsrecv(Mux *mux)329 {330 uchar *pkt;331 uchar buf[4];332 int n, nfd;333 CFsys *fs;335 fs = mux->aux;336 n = ioreadn(fs->iorecv, fs->fd, buf, 4);337 if(n != 4)338 return nil;339 n = GBIT32(buf);340 pkt = malloc(n+4);341 if(pkt == nil){342 fprint(2, "lib9pclient out of memory reading 9p packet; here comes trouble\n");343 return nil;344 }345 PBIT32(pkt, n);346 if(ioreadn(fs->iorecv, fs->fd, pkt+4, n-4) != n-4){347 free(pkt);348 return nil;349 }350 if(pkt[4] == Ropenfd){351 if((nfd=iorecvfd(fs->iorecv, fs->fd)) < 0){352 fprint(2, "recv fd error: %r\n");353 free(pkt);354 return nil;355 }356 PBIT32(pkt+n-4, nfd);357 }358 return pkt;359 }