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 enum
20 {
21 CFidchunk = 32
22 };
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");
53 if((n = fsversion(fs, 8192, fs->version, sizeof fs->version)) < 0){
54 werrstr("fsversion: %r");
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 void
88 _fsunmount(CFsys *fs)
89 {
90 fs->fd = -1;
91 fsunmount(fs);
92 }
94 void
95 fsunmount(CFsys *fs)
96 {
97 fsclose(fs->root);
98 fs->root = nil;
99 _fsdecref(fs);
102 void
103 _fsdecref(CFsys *fs)
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 else
118 *l = (*l)->next;
120 /* now free the list */
121 for(f=fs->freefid; f; f=next){
122 next = f->next;
123 free(f);
125 closeioproc(fs->iorecv);
126 closeioproc(fs->iosend);
127 free(fs);
128 return;
130 qunlock(&fs->lk);
133 int
134 fsversion(CFsys *fs, int msize, char *version, int nversion)
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 messages
148 * 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;
162 strecpy(version, version+nversion, rx.version);
163 free(freep);
164 fs->msize = rx.msize;
165 return rx.msize;
168 CFid*
169 fsattach(CFsys *fs, CFid *afid, char *user, char *aname)
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;
191 fid->qid = rx.qid;
192 return fid;
195 void
196 fssetroot(CFsys *fs, CFid *fid)
198 if(fs->root)
199 _fsputfid(fs->root);
200 fs->root = fid;
203 int
204 _fsrpc(CFsys *fs, Fcall *tx, Fcall *rx, void **freep)
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;
225 rpkt = muxrpc(&fs->mux, tpkt);
226 free(tpkt);
227 if(rpkt == nil){
228 werrstr("muxrpc: %r");
229 return -1;
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;
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;
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;
252 if(freep)
253 *freep = rpkt;
254 else
255 free(rpkt);
256 return 0;
259 CFid*
260 _fsgetfid(CFsys *fs)
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;
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;
277 f[i-1].next = nil;
278 fs->freefid = f;
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;
292 void
293 _fsputfid(CFid *f)
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);
305 static int
306 _fsgettag(Mux *mux, void *pkt)
308 return GBIT16((uchar*)pkt+5);
311 static int
312 _fssettag(Mux *mux, void *pkt, uint tag)
314 PBIT16((uchar*)pkt+5, tag);
315 return 0;
318 static int
319 _fssend(Mux *mux, void *pkt)
321 CFsys *fs;
322 int n;
324 fs = mux->aux;
325 n = iowrite(fs->iosend, fs->fd, pkt, GBIT32((uchar*)pkt));
326 if(n < 0 && eofkill9pclient)
327 threadexitsall(nil);
328 return n;
331 static void*
332 _fsrecv(Mux *mux)
334 uchar *pkt;
335 uchar buf[4];
336 int n, nfd;
337 CFsys *fs;
339 fs = mux->aux;
340 n = ioreadn(fs->iorecv, fs->fd, buf, 4);
341 if(n != 4){
342 if(eofkill9pclient)
343 threadexitsall(nil);
344 return nil;
346 n = GBIT32(buf);
347 pkt = malloc(n+4);
348 if(pkt == nil){
349 fprint(2, "lib9pclient out of memory reading 9p packet; here comes trouble\n");
350 return nil;
352 PBIT32(pkt, n);
353 if(ioreadn(fs->iorecv, fs->fd, pkt+4, n-4) != n-4){
354 free(pkt);
355 return nil;
357 if(pkt[4] == Ropenfd){
358 if((nfd=iorecvfd(fs->iorecv, fs->fd)) < 0){
359 fprint(2, "recv fd error: %r\n");
360 free(pkt);
361 return nil;
363 PBIT32(pkt+n-4, nfd);
365 return pkt;
368 Qid
369 fsqid(CFid *fid)
371 return fid->qid;