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 return nil;36 fs->fd = fd;37 fs->ref = 1;38 fs->mux.aux = fs;39 fs->mux.mintag = 0;40 fs->mux.maxtag = 256;41 fs->mux.send = _fssend;42 fs->mux.recv = _fsrecv;43 fs->mux.gettag = _fsgettag;44 fs->mux.settag = _fssettag;45 fs->iorecv = ioproc();46 fs->iosend = ioproc();47 muxinit(&fs->mux);49 strcpy(fs->version, "9P2000");50 if((n = fsversion(fs, 8192, fs->version, sizeof fs->version)) < 0){51 _fsunmount(fs);52 return nil;53 }54 fs->msize = n;55 return fs;56 }58 CFid*59 fsroot(CFsys *fs)60 {61 /* N.B. no incref */62 return fs->root;63 }65 CFsys*66 fsmount(int fd, char *aname)67 {68 CFsys *fs;69 CFid *fid;71 fs = fsinit(fd);72 if(fs == nil)73 return nil;75 if((fid = fsattach(fs, nil, getuser(), aname)) == nil){76 _fsunmount(fs);77 return nil;78 }79 fssetroot(fs, fid);80 return fs;81 }83 void84 _fsunmount(CFsys *fs)85 {86 fs->fd = -1;87 fsunmount(fs);88 }90 void91 fsunmount(CFsys *fs)92 {93 fsclose(fs->root);94 fs->root = nil;95 _fsdecref(fs);96 }98 void99 _fsdecref(CFsys *fs)100 {101 CFid *f, **l, *next;103 qlock(&fs->lk);104 --fs->ref;105 //fprint(2, "fsdecref %p to %d\n", fs, fs->ref);106 if(fs->ref == 0){107 if(fs->fd >= 0)108 close(fs->fd);109 /* trim the list down to just the first in each chunk */110 for(l=&fs->freefid; *l; ){111 if((*l)->fid%CFidchunk == 0)112 l = &(*l)->next;113 else114 *l = (*l)->next;115 }116 /* now free the list */117 for(f=fs->freefid; f; f=next){118 next = f->next;119 free(f);120 }121 closeioproc(fs->iorecv);122 closeioproc(fs->iosend);123 free(fs);124 return;125 }126 qunlock(&fs->lk);127 }129 int130 fsversion(CFsys *fs, int msize, char *version, int nversion)131 {132 void *freep;133 int r, oldmintag, oldmaxtag;134 Fcall tx, rx;136 tx.tag = 0;137 tx.type = Tversion;138 tx.version = version;139 tx.msize = msize;141 /*142 * bit of a clumsy hack -- force libmux to use NOTAG as tag.143 * version can only be sent when there are no other messages144 * outstanding on the wire, so this is more reasonable than it looks.145 */146 oldmintag = fs->mux.mintag;147 oldmaxtag = fs->mux.maxtag;148 fs->mux.mintag = NOTAG;149 fs->mux.maxtag = NOTAG+1;150 r = _fsrpc(fs, &tx, &rx, &freep);151 fs->mux.mintag = oldmintag;152 fs->mux.maxtag = oldmaxtag;153 if(r < 0)154 return -1;156 strecpy(version, version+nversion, rx.version);157 free(freep);158 fs->msize = rx.msize;159 return rx.msize;160 }162 CFid*163 fsattach(CFsys *fs, CFid *afid, char *user, char *aname)164 {165 Fcall tx, rx;166 CFid *fid;168 if(aname == nil)169 aname = "";171 if((fid = _fsgetfid(fs)) == nil)172 return nil;174 tx.tag = 0;175 tx.type = Tattach;176 tx.afid = afid ? afid->fid : NOFID;177 tx.fid = fid->fid;178 tx.uname = user;179 tx.aname = aname;181 if(_fsrpc(fs, &tx, &rx, 0) < 0){182 _fsputfid(fid);183 return nil;184 }185 fid->qid = rx.qid;186 return fid;187 }189 void190 fssetroot(CFsys *fs, CFid *fid)191 {192 if(fs->root)193 _fsputfid(fs->root);194 fs->root = fid;195 }197 int198 _fsrpc(CFsys *fs, Fcall *tx, Fcall *rx, void **freep)199 {200 int n, nn;201 void *tpkt, *rpkt;203 n = sizeS2M(tx);204 tpkt = malloc(n);205 if(freep)206 *freep = nil;207 if(tpkt == nil)208 return -1;209 tx->tag = 0;210 if(chatty9pclient)211 fprint(2, "<- %F\n", tx);212 nn = convS2M(tx, tpkt, n);213 if(nn != n){214 free(tpkt);215 werrstr("libfs: sizeS2M convS2M mismatch");216 fprint(2, "%r\n");217 return -1;218 }219 rpkt = muxrpc(&fs->mux, tpkt);220 free(tpkt);221 if(rpkt == nil)222 return -1;223 n = GBIT32((uchar*)rpkt);224 nn = convM2S(rpkt, n, rx);225 if(nn != n){226 free(rpkt);227 werrstr("libfs: convM2S packet size mismatch %d %d", n, nn);228 fprint(2, "%r\n");229 return -1;230 }231 if(chatty9pclient)232 fprint(2, "-> %F\n", rx);233 if(rx->type == Rerror){234 werrstr("%s", rx->ename);235 free(rpkt);236 return -1;237 }238 if(rx->type != tx->type+1){239 werrstr("packet type mismatch -- tx %d rx %d",240 tx->type, rx->type);241 free(rpkt);242 return -1;243 }244 if(freep)245 *freep = rpkt;246 else247 free(rpkt);248 return 0;249 }251 CFid*252 _fsgetfid(CFsys *fs)253 {254 int i;255 CFid *f;257 qlock(&fs->lk);258 if(fs->freefid == nil){259 f = mallocz(sizeof(CFid)*CFidchunk, 1);260 if(f == nil){261 qunlock(&fs->lk);262 return nil;263 }264 for(i=0; i<CFidchunk; i++){265 f[i].fid = fs->nextfid++;266 f[i].next = &f[i+1];267 f[i].fs = fs;268 }269 f[i-1].next = nil;270 fs->freefid = f;271 }272 f = fs->freefid;273 fs->freefid = f->next;274 fs->ref++;275 qunlock(&fs->lk);276 f->offset = 0;277 f->mode = -1;278 f->qid.path = 0;279 f->qid.vers = 0;280 f->qid.type = 0;281 return f;282 }284 void285 _fsputfid(CFid *f)286 {287 CFsys *fs;289 fs = f->fs;290 qlock(&fs->lk);291 f->next = fs->freefid;292 fs->freefid = f;293 qunlock(&fs->lk);294 _fsdecref(fs);295 }297 static int298 _fsgettag(Mux *mux, void *pkt)299 {300 return GBIT16((uchar*)pkt+5);301 }303 static int304 _fssettag(Mux *mux, void *pkt, uint tag)305 {306 PBIT16((uchar*)pkt+5, tag);307 return 0;308 }310 static int311 _fssend(Mux *mux, void *pkt)312 {313 CFsys *fs;315 fs = mux->aux;316 return iowrite(fs->iosend, fs->fd, pkt, GBIT32((uchar*)pkt));317 }319 static void*320 _fsrecv(Mux *mux)321 {322 uchar *pkt;323 uchar buf[4];324 int n, nfd;325 CFsys *fs;327 fs = mux->aux;328 n = ioreadn(fs->iorecv, fs->fd, buf, 4);329 if(n != 4)330 return nil;331 n = GBIT32(buf);332 pkt = malloc(n+4);333 if(pkt == nil){334 fprint(2, "libfs out of memory reading 9p packet; here comes trouble\n");335 return nil;336 }337 PBIT32(pkt, n);338 if(ioreadn(fs->iorecv, fs->fd, pkt+4, n-4) != n-4){339 free(pkt);340 return nil;341 }342 if(pkt[4] == Ropenfd){343 if((nfd=iorecvfd(fs->iorecv, fs->fd)) < 0){344 fprint(2, "recv fd error: %r\n");345 free(pkt);346 return nil;347 }348 PBIT32(pkt+n-4, nfd);349 }350 return pkt;351 }