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 <fs.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 enum17 {18 Fidchunk = 3219 };21 Fsys*22 fsinit(int fd)23 {24 Fsys *fs;26 fmtinstall('F', fcallfmt);27 fmtinstall('D', dirfmt);28 fmtinstall('M', dirmodefmt);30 fs = mallocz(sizeof(Fsys), 1);31 if(fs == nil)32 return nil;33 fs->fd = fd;34 fs->ref = 1;35 fs->mux.aux = fs;36 fs->mux.mintag = 0;37 fs->mux.maxtag = 256;38 fs->mux.send = _fssend;39 fs->mux.recv = _fsrecv;40 fs->mux.gettag = _fsgettag;41 fs->mux.settag = _fssettag;42 muxinit(&fs->mux);43 return fs;44 }46 Fid*47 fsroot(Fsys *fs)48 {49 /* N.B. no incref */50 return fs->root;51 }53 Fsys*54 fsmount(int fd, char *aname)55 {56 int n;57 char *user;58 Fsys *fs;60 fs = fsinit(fd);61 if(fs == nil)62 return nil;63 strcpy(fs->version, "9P2000");64 if((n = fsversion(fs, 8192, fs->version, sizeof fs->version)) < 0){65 Error:66 fs->fd = -1;67 fsunmount(fs);68 return nil;69 }70 fs->msize = n;72 user = getuser();73 if((fs->root = fsattach(fs, nil, getuser(), aname)) == nil)74 goto Error;75 return fs;76 }78 void79 fsunmount(Fsys *fs)80 {81 fsclose(fs->root);82 fs->root = nil;83 _fsdecref(fs);84 }86 void87 _fsdecref(Fsys *fs)88 {89 Fid *f, **l, *next;91 qlock(&fs->lk);92 --fs->ref;93 //fprint(2, "fsdecref %p to %d\n", fs, fs->ref);94 if(fs->ref == 0){95 close(fs->fd);96 /* trim the list down to just the first in each chunk */97 for(l=&fs->freefid; *l; ){98 if((*l)->fid%Fidchunk == 0)99 l = &(*l)->next;100 else101 *l = (*l)->next;102 }103 /* now free the list */104 for(f=fs->freefid; f; f=next){105 next = f->next;106 free(f);107 }108 free(fs);109 return;110 }111 qunlock(&fs->lk);112 }114 int115 fsversion(Fsys *fs, int msize, char *version, int nversion)116 {117 void *freep;118 Fcall tx, rx;120 tx.tag = 0;121 tx.type = Tversion;122 tx.version = version;123 tx.msize = msize;125 if(fsrpc(fs, &tx, &rx, &freep) < 0)126 return -1;127 strecpy(version, version+nversion, rx.version);128 free(freep);129 return rx.msize;130 }132 Fid*133 fsattach(Fsys *fs, Fid *afid, char *user, char *aname)134 {135 Fcall tx, rx;136 Fid *fid;138 if(aname == nil)139 aname = "";141 if((fid = _fsgetfid(fs)) == nil)142 return nil;144 tx.tag = 0;145 tx.type = Tattach;146 tx.afid = afid ? afid->fid : NOFID;147 tx.fid = fid->fid;148 tx.uname = user;149 tx.aname = aname;151 if(fsrpc(fs, &tx, &rx, 0) < 0){152 _fsputfid(fid);153 return nil;154 }155 fid->qid = rx.qid;156 return fid;157 }159 int160 fsrpc(Fsys *fs, Fcall *tx, Fcall *rx, void **freep)161 {162 int n, nn;163 void *tpkt, *rpkt;165 n = sizeS2M(tx);166 tpkt = malloc(n);167 if(freep)168 *freep = nil;169 if(tpkt == nil)170 return -1;171 //fprint(2, "<- %F\n", tx);172 nn = convS2M(tx, tpkt, n);173 if(nn != n){174 free(tpkt);175 werrstr("libfs: sizeS2M convS2M mismatch");176 fprint(2, "%r\n");177 return -1;178 }179 rpkt = muxrpc(&fs->mux, tpkt);180 free(tpkt);181 if(rpkt == nil)182 return -1;183 n = GBIT32((uchar*)rpkt);184 nn = convM2S(rpkt, n, rx);185 if(nn != n){186 free(rpkt);187 werrstr("libfs: convM2S packet size mismatch %d %d", n, nn);188 fprint(2, "%r\n");189 return -1;190 }191 //fprint(2, "-> %F\n", rx);192 if(rx->type == Rerror){193 werrstr("%s", rx->ename);194 free(rpkt);195 return -1;196 }197 if(rx->type != tx->type+1){198 werrstr("packet type mismatch -- tx %d rx %d",199 tx->type, rx->type);200 free(rpkt);201 return -1;202 }203 if(freep)204 *freep = rpkt;205 else206 free(rpkt);207 return 0;208 }210 Fid*211 _fsgetfid(Fsys *fs)212 {213 int i;214 Fid *f;216 qlock(&fs->lk);217 if(fs->freefid == nil){218 f = mallocz(sizeof(Fid)*Fidchunk, 1);219 if(f == nil){220 qunlock(&fs->lk);221 return nil;222 }223 for(i=0; i<Fidchunk; i++){224 f[i].fid = fs->nextfid++;225 f[i].next = &f[i+1];226 f[i].fs = fs;227 }228 f[i-1].next = nil;229 fs->freefid = f;230 }231 f = fs->freefid;232 fs->freefid = f->next;233 fs->ref++;234 qunlock(&fs->lk);235 return f;236 }238 void239 _fsputfid(Fid *f)240 {241 Fsys *fs;243 fs = f->fs;244 qlock(&fs->lk);245 f->next = fs->freefid;246 fs->freefid = f;247 qunlock(&fs->lk);248 _fsdecref(fs);249 }251 static int252 _fsgettag(Mux *mux, void *pkt)253 {254 return GBIT16((uchar*)pkt+5);255 }257 static int258 _fssettag(Mux *mux, void *pkt, uint tag)259 {260 PBIT16((uchar*)pkt+5, tag);261 return 0;262 }264 static int265 _fssend(Mux *mux, void *pkt)266 {267 Fsys *fs;269 fs = mux->aux;270 return threadwrite(fs->fd, pkt, GBIT32((uchar*)pkt));271 }273 static void*274 _fsrecv(Mux *mux)275 {276 uchar *pkt;277 uchar buf[4];278 int n, nfd;279 Fsys *fs;281 fs = mux->aux;282 n = threadreadn(fs->fd, buf, 4);283 if(n != 4)284 return nil;285 n = GBIT32(buf);286 pkt = malloc(n+4);287 if(pkt == nil){288 fprint(2, "libfs out of memory reading 9p packet; here comes trouble\n");289 return nil;290 }291 PBIT32(pkt, n);292 if(threadreadn(fs->fd, pkt+4, n-4) != n-4){293 free(pkt);294 return nil;295 }296 if(pkt[4] == Ropenfd){297 if((nfd=threadrecvfd(fs->fd)) < 0){298 fprint(2, "recv fd error: %r\n");299 free(pkt);300 return nil;301 }302 PBIT32(pkt+n-4, nfd);303 }304 return pkt;305 }