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 enum
19 {
20 CFidchunk = 32
21 };
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 werrstr("mallocz: %r");
36 return nil;
37 }
38 fs->fd = fd;
39 fs->ref = 1;
40 fs->mux.aux = fs;
41 fs->mux.mintag = 0;
42 fs->mux.maxtag = 256;
43 fs->mux.send = _fssend;
44 fs->mux.recv = _fsrecv;
45 fs->mux.gettag = _fsgettag;
46 fs->mux.settag = _fssettag;
47 fs->iorecv = ioproc();
48 fs->iosend = ioproc();
49 muxinit(&fs->mux);
51 strcpy(fs->version, "9P2000");
52 if((n = fsversion(fs, 8192, fs->version, sizeof fs->version)) < 0){
53 werrstr("fsversion: %r");
54 _fsunmount(fs);
55 return nil;
56 }
57 fs->msize = n;
58 return fs;
59 }
61 CFid*
62 fsroot(CFsys *fs)
63 {
64 /* N.B. no incref */
65 return fs->root;
66 }
68 CFsys*
69 fsmount(int fd, char *aname)
70 {
71 CFsys *fs;
72 CFid *fid;
74 fs = fsinit(fd);
75 if(fs == nil)
76 return nil;
78 if((fid = fsattach(fs, nil, getuser(), aname)) == nil){
79 _fsunmount(fs);
80 return nil;
81 }
82 fssetroot(fs, fid);
83 return fs;
84 }
86 void
87 _fsunmount(CFsys *fs)
88 {
89 fs->fd = -1;
90 fsunmount(fs);
91 }
93 void
94 fsunmount(CFsys *fs)
95 {
96 fsclose(fs->root);
97 fs->root = nil;
98 _fsdecref(fs);
99 }
101 void
102 _fsdecref(CFsys *fs)
104 CFid *f, **l, *next;
106 qlock(&fs->lk);
107 --fs->ref;
108 /*fprint(2, "fsdecref %p to %d\n", fs, fs->ref); */
109 if(fs->ref == 0){
110 if(fs->fd >= 0)
111 close(fs->fd);
112 /* trim the list down to just the first in each chunk */
113 for(l=&fs->freefid; *l; ){
114 if((*l)->fid%CFidchunk == 0)
115 l = &(*l)->next;
116 else
117 *l = (*l)->next;
119 /* now free the list */
120 for(f=fs->freefid; f; f=next){
121 next = f->next;
122 free(f);
124 closeioproc(fs->iorecv);
125 closeioproc(fs->iosend);
126 free(fs);
127 return;
129 qunlock(&fs->lk);
132 int
133 fsversion(CFsys *fs, int msize, char *version, int nversion)
135 void *freep;
136 int r, oldmintag, oldmaxtag;
137 Fcall tx, rx;
139 tx.tag = 0;
140 tx.type = Tversion;
141 tx.version = version;
142 tx.msize = msize;
144 /*
145 * bit of a clumsy hack -- force libmux to use NOTAG as tag.
146 * version can only be sent when there are no other messages
147 * outstanding on the wire, so this is more reasonable than it looks.
148 */
149 oldmintag = fs->mux.mintag;
150 oldmaxtag = fs->mux.maxtag;
151 fs->mux.mintag = NOTAG;
152 fs->mux.maxtag = NOTAG+1;
153 r = _fsrpc(fs, &tx, &rx, &freep);
154 fs->mux.mintag = oldmintag;
155 fs->mux.maxtag = oldmaxtag;
156 if(r < 0){
157 werrstr("fsrpc: %r");
158 return -1;
161 strecpy(version, version+nversion, rx.version);
162 free(freep);
163 fs->msize = rx.msize;
164 return rx.msize;
167 CFid*
168 fsattach(CFsys *fs, CFid *afid, char *user, char *aname)
170 Fcall tx, rx;
171 CFid *fid;
173 if(aname == nil)
174 aname = "";
176 if((fid = _fsgetfid(fs)) == nil)
177 return nil;
179 tx.tag = 0;
180 tx.type = Tattach;
181 tx.afid = afid ? afid->fid : NOFID;
182 tx.fid = fid->fid;
183 tx.uname = user;
184 tx.aname = aname;
186 if(_fsrpc(fs, &tx, &rx, 0) < 0){
187 _fsputfid(fid);
188 return nil;
190 fid->qid = rx.qid;
191 return fid;
194 void
195 fssetroot(CFsys *fs, CFid *fid)
197 if(fs->root)
198 _fsputfid(fs->root);
199 fs->root = fid;
202 int
203 _fsrpc(CFsys *fs, Fcall *tx, Fcall *rx, void **freep)
205 int n, nn;
206 void *tpkt, *rpkt;
208 n = sizeS2M(tx);
209 tpkt = malloc(n);
210 if(freep)
211 *freep = nil;
212 if(tpkt == nil)
213 return -1;
214 tx->tag = 0;
215 if(chatty9pclient)
216 fprint(2, "<- %F\n", tx);
217 nn = convS2M(tx, tpkt, n);
218 if(nn != n){
219 free(tpkt);
220 werrstr("lib9pclient: sizeS2M convS2M mismatch");
221 fprint(2, "%r\n");
222 return -1;
224 rpkt = muxrpc(&fs->mux, tpkt);
225 free(tpkt);
226 if(rpkt == nil){
227 werrstr("muxrpc: %r");
228 return -1;
230 n = GBIT32((uchar*)rpkt);
231 nn = convM2S(rpkt, n, rx);
232 if(nn != n){
233 free(rpkt);
234 werrstr("lib9pclient: convM2S packet size mismatch %d %d", n, nn);
235 fprint(2, "%r\n");
236 return -1;
238 if(chatty9pclient)
239 fprint(2, "-> %F\n", rx);
240 if(rx->type == Rerror){
241 werrstr("%s", rx->ename);
242 free(rpkt);
243 return -1;
245 if(rx->type != tx->type+1){
246 werrstr("packet type mismatch -- tx %d rx %d",
247 tx->type, rx->type);
248 free(rpkt);
249 return -1;
251 if(freep)
252 *freep = rpkt;
253 else
254 free(rpkt);
255 return 0;
258 CFid*
259 _fsgetfid(CFsys *fs)
261 int i;
262 CFid *f;
264 qlock(&fs->lk);
265 if(fs->freefid == nil){
266 f = mallocz(sizeof(CFid)*CFidchunk, 1);
267 if(f == nil){
268 qunlock(&fs->lk);
269 return nil;
271 for(i=0; i<CFidchunk; i++){
272 f[i].fid = fs->nextfid++;
273 f[i].next = &f[i+1];
274 f[i].fs = fs;
276 f[i-1].next = nil;
277 fs->freefid = f;
279 f = fs->freefid;
280 fs->freefid = f->next;
281 fs->ref++;
282 qunlock(&fs->lk);
283 f->offset = 0;
284 f->mode = -1;
285 f->qid.path = 0;
286 f->qid.vers = 0;
287 f->qid.type = 0;
288 return f;
291 void
292 _fsputfid(CFid *f)
294 CFsys *fs;
296 fs = f->fs;
297 qlock(&fs->lk);
298 f->next = fs->freefid;
299 fs->freefid = f;
300 qunlock(&fs->lk);
301 _fsdecref(fs);
304 static int
305 _fsgettag(Mux *mux, void *pkt)
307 return GBIT16((uchar*)pkt+5);
310 static int
311 _fssettag(Mux *mux, void *pkt, uint tag)
313 PBIT16((uchar*)pkt+5, tag);
314 return 0;
317 static int
318 _fssend(Mux *mux, void *pkt)
320 CFsys *fs;
322 fs = mux->aux;
323 return iowrite(fs->iosend, fs->fd, pkt, GBIT32((uchar*)pkt));
326 static void*
327 _fsrecv(Mux *mux)
329 uchar *pkt;
330 uchar buf[4];
331 int n, nfd;
332 CFsys *fs;
334 fs = mux->aux;
335 n = ioreadn(fs->iorecv, fs->fd, buf, 4);
336 if(n != 4)
337 return nil;
338 n = GBIT32(buf);
339 pkt = malloc(n+4);
340 if(pkt == nil){
341 fprint(2, "lib9pclient out of memory reading 9p packet; here comes trouble\n");
342 return nil;
344 PBIT32(pkt, n);
345 if(ioreadn(fs->iorecv, fs->fd, pkt+4, n-4) != n-4){
346 free(pkt);
347 return nil;
349 if(pkt[4] == Ropenfd){
350 if((nfd=iorecvfd(fs->iorecv, fs->fd)) < 0){
351 fprint(2, "recv fd error: %r\n");
352 free(pkt);
353 return nil;
355 PBIT32(pkt+n-4, nfd);
357 return pkt;