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.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 void
90 _fsunmount(CFsys *fs)
91 {
92 fs->fd = -1;
93 fsunmount(fs);
94 }
96 void
97 fsunmount(CFsys *fs)
98 {
99 fsclose(fs->root);
100 fs->root = nil;
101 _fsdecref(fs);
104 void
105 _fsdecref(CFsys *fs)
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 else
120 *l = (*l)->next;
122 /* now free the list */
123 for(f=fs->freefid; f; f=next){
124 next = f->next;
125 free(f);
127 closeioproc(fs->iorecv);
128 closeioproc(fs->iosend);
129 free(fs);
130 return;
132 qunlock(&fs->lk);
135 int
136 fsversion(CFsys *fs, int msize, char *version, int nversion)
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 messages
150 * 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;
164 strecpy(version, version+nversion, rx.version);
165 free(freep);
166 fs->msize = rx.msize;
167 return rx.msize;
170 CFid*
171 fsattach(CFsys *fs, CFid *afid, char *user, char *aname)
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;
193 fid->qid = rx.qid;
194 return fid;
197 void
198 fssetroot(CFsys *fs, CFid *fid)
200 if(fs->root)
201 _fsputfid(fs->root);
202 fs->root = fid;
205 int
206 _fsrpc(CFsys *fs, Fcall *tx, Fcall *rx, void **freep)
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;
227 rpkt = muxrpc(&fs->mux, tpkt);
228 free(tpkt);
229 if(rpkt == nil){
230 werrstr("muxrpc: %r");
231 return -1;
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;
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;
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;
254 if(freep)
255 *freep = rpkt;
256 else
257 free(rpkt);
258 return 0;
261 CFid*
262 _fsgetfid(CFsys *fs)
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;
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;
279 f[i-1].next = nil;
280 fs->freefid = f;
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;
294 void
295 _fsputfid(CFid *f)
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);
307 static int
308 _fsgettag(Mux *mux, void *pkt)
310 return GBIT16((uchar*)pkt+5);
313 static int
314 _fssettag(Mux *mux, void *pkt, uint tag)
316 PBIT16((uchar*)pkt+5, tag);
317 return 0;
320 static int
321 _fssend(Mux *mux, void *pkt)
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;
333 static void*
334 _fsrecv(Mux *mux)
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;
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;
354 PBIT32(pkt, n);
355 if(ioreadn(fs->iorecv, fs->fd, pkt+4, n-4) != n-4){
356 free(pkt);
357 return nil;
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;
365 PBIT32(pkt+n-4, nfd);
367 return pkt;
370 Qid
371 fsqid(CFid *fid)
373 return fid->qid;