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;17 int eofkill9pclient;19 enum20 {21 CFidchunk = 3222 };24 CFsys*25 fsinit(int fd)26 {27 CFsys *fs;28 int n;30 fmtinstall('F', fcallfmt);31 fmtinstall('D', dirfmt);32 fmtinstall('M', dirmodefmt);34 fs = mallocz(sizeof(CFsys), 1);35 if(fs == nil){36 werrstr("mallocz: %r");37 return nil;38 }39 fs->fd = fd;40 fs->ref = 1;41 fs->mux.aux = fs;42 fs->mux.mintag = 0;43 fs->mux.maxtag = 256;44 fs->mux.send = _fssend;45 fs->mux.recv = _fsrecv;46 fs->mux.gettag = _fsgettag;47 fs->mux.settag = _fssettag;48 fs->iorecv = ioproc();49 fs->iosend = ioproc();50 muxinit(&fs->mux);52 strcpy(fs->version, "9P2000.u");53 if((n = fsversion(fs, 8192, fs->version, sizeof fs->version)) < 0){54 werrstr("fsversion: %r");55 _fsunmount(fs);56 return nil;57 }58 if(strcmp(fs->version, "9P2000.u") == 0)59 fs->dotu = 1;60 fs->msize = n;61 return fs;62 }64 CFid*65 fsroot(CFsys *fs)66 {67 /* N.B. no incref */68 return fs->root;69 }71 CFsys*72 fsmount(int fd, char *aname)73 {74 CFsys *fs;75 CFid *fid;77 fs = fsinit(fd);78 if(fs == nil)79 return nil;81 if((fid = fsattach(fs, nil, getuser(), aname)) == nil){82 _fsunmount(fs);83 return nil;84 }85 fssetroot(fs, fid);86 return fs;87 }89 void90 _fsunmount(CFsys *fs)91 {92 fs->fd = -1;93 fsunmount(fs);94 }96 void97 fsunmount(CFsys *fs)98 {99 fsclose(fs->root);100 fs->root = nil;101 _fsdecref(fs);102 }104 void105 _fsdecref(CFsys *fs)106 {107 CFid *f, **l, *next;109 qlock(&fs->lk);110 --fs->ref;111 /*fprint(2, "fsdecref %p to %d\n", fs, fs->ref); */112 if(fs->ref == 0){113 if(fs->fd >= 0)114 close(fs->fd);115 /* trim the list down to just the first in each chunk */116 for(l=&fs->freefid; *l; ){117 if((*l)->fid%CFidchunk == 0)118 l = &(*l)->next;119 else120 *l = (*l)->next;121 }122 /* now free the list */123 for(f=fs->freefid; f; f=next){124 next = f->next;125 free(f);126 }127 closeioproc(fs->iorecv);128 closeioproc(fs->iosend);129 free(fs);130 return;131 }132 qunlock(&fs->lk);133 }135 int136 fsversion(CFsys *fs, int msize, char *version, int nversion)137 {138 void *freep;139 int r, oldmintag, oldmaxtag;140 Fcall tx, rx;142 tx.tag = 0;143 tx.type = Tversion;144 tx.version = version;145 tx.msize = msize;147 /*148 * bit of a clumsy hack -- force libmux to use NOTAG as tag.149 * version can only be sent when there are no other messages150 * outstanding on the wire, so this is more reasonable than it looks.151 */152 oldmintag = fs->mux.mintag;153 oldmaxtag = fs->mux.maxtag;154 fs->mux.mintag = NOTAG;155 fs->mux.maxtag = NOTAG+1;156 r = _fsrpc(fs, &tx, &rx, &freep);157 fs->mux.mintag = oldmintag;158 fs->mux.maxtag = oldmaxtag;159 if(r < 0){160 werrstr("fsrpc: %r");161 return -1;162 }164 strecpy(version, version+nversion, rx.version);165 free(freep);166 fs->msize = rx.msize;167 return rx.msize;168 }170 CFid*171 fsattach(CFsys *fs, CFid *afid, char *user, char *aname)172 {173 Fcall tx, rx;174 CFid *fid;176 if(aname == nil)177 aname = "";179 if((fid = _fsgetfid(fs)) == nil)180 return nil;182 tx.tag = 0;183 tx.type = Tattach;184 tx.afid = afid ? afid->fid : NOFID;185 tx.fid = fid->fid;186 tx.uname = user;187 tx.aname = aname;189 if(_fsrpc(fs, &tx, &rx, 0) < 0){190 _fsputfid(fid);191 return nil;192 }193 fid->qid = rx.qid;194 return fid;195 }197 void198 fssetroot(CFsys *fs, CFid *fid)199 {200 if(fs->root)201 _fsputfid(fs->root);202 fs->root = fid;203 }205 int206 _fsrpc(CFsys *fs, Fcall *tx, Fcall *rx, void **freep)207 {208 int n, nn;209 void *tpkt, *rpkt;211 n = sizeS2Mu(tx, fs->dotu);212 tpkt = malloc(n);213 if(freep)214 *freep = nil;215 if(tpkt == nil)216 return -1;217 tx->tag = 0;218 if(chatty9pclient)219 fprint(2, "<- %F\n", tx);220 nn = convS2Mu(tx, tpkt, n, fs->dotu);221 if(nn != n){222 free(tpkt);223 werrstr("lib9pclient: sizeS2M convS2M mismatch");224 fprint(2, "%r\n");225 return -1;226 }227 rpkt = muxrpc(&fs->mux, tpkt);228 free(tpkt);229 if(rpkt == nil){230 werrstr("muxrpc: %r");231 return -1;232 }233 n = GBIT32((uchar*)rpkt);234 nn = convM2Su(rpkt, n, rx, fs->dotu);235 if(nn != n){236 free(rpkt);237 werrstr("lib9pclient: convM2S packet size mismatch %d %d", n, nn);238 fprint(2, "%r\n");239 return -1;240 }241 if(chatty9pclient)242 fprint(2, "-> %F\n", rx);243 if(rx->type == Rerror){244 werrstr("%s", rx->ename);245 free(rpkt);246 return -1;247 }248 if(rx->type != tx->type+1){249 werrstr("packet type mismatch -- tx %d rx %d",250 tx->type, rx->type);251 free(rpkt);252 return -1;253 }254 if(freep)255 *freep = rpkt;256 else257 free(rpkt);258 return 0;259 }261 CFid*262 _fsgetfid(CFsys *fs)263 {264 int i;265 CFid *f;267 qlock(&fs->lk);268 if(fs->freefid == nil){269 f = mallocz(sizeof(CFid)*CFidchunk, 1);270 if(f == nil){271 qunlock(&fs->lk);272 return nil;273 }274 for(i=0; i<CFidchunk; i++){275 f[i].fid = fs->nextfid++;276 f[i].next = &f[i+1];277 f[i].fs = fs;278 }279 f[i-1].next = nil;280 fs->freefid = f;281 }282 f = fs->freefid;283 fs->freefid = f->next;284 fs->ref++;285 qunlock(&fs->lk);286 f->offset = 0;287 f->mode = -1;288 f->qid.path = 0;289 f->qid.vers = 0;290 f->qid.type = 0;291 return f;292 }294 void295 _fsputfid(CFid *f)296 {297 CFsys *fs;299 fs = f->fs;300 qlock(&fs->lk);301 f->next = fs->freefid;302 fs->freefid = f;303 qunlock(&fs->lk);304 _fsdecref(fs);305 }307 static int308 _fsgettag(Mux *mux, void *pkt)309 {310 return GBIT16((uchar*)pkt+5);311 }313 static int314 _fssettag(Mux *mux, void *pkt, uint tag)315 {316 PBIT16((uchar*)pkt+5, tag);317 return 0;318 }320 static int321 _fssend(Mux *mux, void *pkt)322 {323 CFsys *fs;324 int n;326 fs = mux->aux;327 n = iowrite(fs->iosend, fs->fd, pkt, GBIT32((uchar*)pkt));328 if(n < 0 && eofkill9pclient)329 threadexitsall(nil);330 return n;331 }333 static void*334 _fsrecv(Mux *mux)335 {336 uchar *pkt;337 uchar buf[4];338 int n, nfd;339 CFsys *fs;341 fs = mux->aux;342 n = ioreadn(fs->iorecv, fs->fd, buf, 4);343 if(n != 4){344 if(eofkill9pclient)345 threadexitsall(nil);346 return nil;347 }348 n = GBIT32(buf);349 pkt = malloc(n+4);350 if(pkt == nil){351 fprint(2, "lib9pclient out of memory reading 9p packet; here comes trouble\n");352 return nil;353 }354 PBIT32(pkt, n);355 if(ioreadn(fs->iorecv, fs->fd, pkt+4, n-4) != n-4){356 free(pkt);357 return nil;358 }359 if(pkt[4] == Ropenfd){360 if((nfd=iorecvfd(fs->iorecv, fs->fd)) < 0){361 fprint(2, "recv fd error: %r\n");362 free(pkt);363 return nil;364 }365 PBIT32(pkt+n-4, nfd);366 }367 return pkt;368 }370 Qid371 fsqid(CFid *fid)372 {373 return fid->qid;374 }