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, *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 for(f=fs->freefid; f; f=next){97 next = f->next;98 if(f->fid%Fidchunk == 0)99 free(f);100 }101 free(fs);102 }103 qunlock(&fs->lk);104 }106 int107 fsversion(Fsys *fs, int msize, char *version, int nversion)108 {109 void *freep;110 Fcall tx, rx;112 tx.tag = 0;113 tx.type = Tversion;114 tx.version = version;115 tx.msize = msize;117 if(fsrpc(fs, &tx, &rx, &freep) < 0)118 return -1;119 strecpy(version, version+nversion, rx.version);120 free(freep);121 return rx.msize;122 }124 Fid*125 fsattach(Fsys *fs, Fid *afid, char *user, char *aname)126 {127 Fcall tx, rx;128 Fid *fid;130 if(aname == nil)131 aname = "";133 if((fid = _fsgetfid(fs)) == nil)134 return nil;136 tx.tag = 0;137 tx.type = Tattach;138 tx.afid = afid ? afid->fid : NOFID;139 tx.fid = fid->fid;140 tx.uname = user;141 tx.aname = aname;143 if(fsrpc(fs, &tx, &rx, 0) < 0){144 _fsputfid(fid);145 return nil;146 }147 fid->qid = rx.qid;148 return fid;149 }151 int152 fsrpc(Fsys *fs, Fcall *tx, Fcall *rx, void **freep)153 {154 int n, nn;155 void *tpkt, *rpkt;157 n = sizeS2M(tx);158 tpkt = malloc(n);159 if(freep)160 *freep = nil;161 if(tpkt == nil)162 return -1;163 //fprint(2, "<- %F\n", tx);164 nn = convS2M(tx, tpkt, n);165 if(nn != n){166 free(tpkt);167 werrstr("libfs: sizeS2M convS2M mismatch");168 fprint(2, "%r\n");169 return -1;170 }171 rpkt = muxrpc(&fs->mux, tpkt);172 free(tpkt);173 if(rpkt == nil)174 return -1;175 n = GBIT32((uchar*)rpkt);176 nn = convM2S(rpkt, n, rx);177 if(nn != n){178 free(rpkt);179 werrstr("libfs: convM2S packet size mismatch %d %d", n, nn);180 fprint(2, "%r\n");181 return -1;182 }183 //fprint(2, "-> %F\n", rx);184 if(rx->type == Rerror){185 werrstr("%s", rx->ename);186 free(rpkt);187 return -1;188 }189 if(rx->type != tx->type+1){190 werrstr("packet type mismatch -- tx %d rx %d",191 tx->type, rx->type);192 free(rpkt);193 return -1;194 }195 if(freep)196 *freep = rpkt;197 else198 free(rpkt);199 return 0;200 }202 Fid*203 _fsgetfid(Fsys *fs)204 {205 int i;206 Fid *f;208 qlock(&fs->lk);209 if(fs->freefid == nil){210 f = mallocz(sizeof(Fid)*Fidchunk, 1);211 if(f == nil){212 qunlock(&fs->lk);213 return nil;214 }215 for(i=0; i<Fidchunk; i++){216 f[i].fid = fs->nextfid++;217 f[i].next = &f[i+1];218 f[i].fs = fs;219 }220 f[i-1].next = nil;221 fs->freefid = f;222 }223 f = fs->freefid;224 fs->freefid = f->next;225 fs->ref++;226 qunlock(&fs->lk);227 return f;228 }230 void231 _fsputfid(Fid *f)232 {233 Fsys *fs;235 fs = f->fs;236 qlock(&fs->lk);237 f->next = fs->freefid;238 fs->freefid = f;239 qunlock(&fs->lk);240 _fsdecref(fs);241 }243 static int244 _fsgettag(Mux *mux, void *pkt)245 {246 return GBIT16((uchar*)pkt+5);247 }249 static int250 _fssettag(Mux *mux, void *pkt, uint tag)251 {252 PBIT16((uchar*)pkt+5, tag);253 return 0;254 }256 static int257 _fssend(Mux *mux, void *pkt)258 {259 Fsys *fs;261 fs = mux->aux;262 return threadwrite(fs->fd, pkt, GBIT32((uchar*)pkt));263 }265 static void*266 _fsrecv(Mux *mux)267 {268 uchar *pkt;269 uchar buf[4];270 int n, nfd;271 Fsys *fs;273 fs = mux->aux;274 n = threadreadn(fs->fd, buf, 4);275 if(n != 4)276 return nil;277 n = GBIT32(buf);278 pkt = malloc(n+4);279 if(pkt == nil){280 fprint(2, "libfs out of memory reading 9p packet; here comes trouble\n");281 return nil;282 }283 PBIT32(pkt, n);284 if(threadreadn(fs->fd, pkt+4, n-4) != n-4){285 free(pkt);286 return nil;287 }288 if(pkt[4] == Ropenfd){289 if((nfd=threadrecvfd(fs->fd)) < 0){290 fprint(2, "recv fd error: %r\n");291 free(pkt);292 return nil;293 }294 PBIT32(pkt+n-4, nfd);295 }296 return pkt;297 }