plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

fs.c (6137B)


      1 /* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
      2 /* See COPYRIGHT */
      3 
      4 #include <u.h>
      5 #include <libc.h>
      6 #include <fcall.h>
      7 #include <9pclient.h>
      8 #include <thread.h>
      9 #include "fsimpl.h"
     10 
     11 static int _fssend(Mux*, void*);
     12 static void *_fsrecv(Mux*);
     13 static int _fsgettag(Mux*, void*);
     14 static int _fssettag(Mux*, void*, uint);
     15 
     16 int chatty9pclient;
     17 int eofkill9pclient;
     18 
     19 enum
     20 {
     21 	CFidchunk = 32
     22 };
     23 
     24 CFsys*
     25 fsinit(int fd)
     26 {
     27 	CFsys *fs;
     28 	int n;
     29 
     30 	fmtinstall('F', fcallfmt);
     31 	fmtinstall('D', dirfmt);
     32 	fmtinstall('M', dirmodefmt);
     33 
     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);
     51 
     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 }
     61 
     62 CFid*
     63 fsroot(CFsys *fs)
     64 {
     65 	/* N.B. no incref */
     66 	return fs->root;
     67 }
     68 
     69 CFsys*
     70 fsmount(int fd, char *aname)
     71 {
     72 	CFsys *fs;
     73 	CFid *fid;
     74 
     75 	fs = fsinit(fd);
     76 	if(fs == nil)
     77 		return nil;
     78 
     79 	if((fid = fsattach(fs, nil, getuser(), aname)) == nil){
     80 		_fsunmount(fs);
     81 		return nil;
     82 	}
     83 	fssetroot(fs, fid);
     84 	return fs;
     85 }
     86 
     87 void
     88 _fsunmount(CFsys *fs)
     89 {
     90 	fs->fd = -1;
     91 	fsunmount(fs);
     92 }
     93 
     94 void
     95 fsunmount(CFsys *fs)
     96 {
     97 	fsclose(fs->root);
     98 	fs->root = nil;
     99 	_fsdecref(fs);
    100 }
    101 
    102 void
    103 _fsdecref(CFsys *fs)
    104 {
    105 	CFid *f, **l, *next;
    106 
    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;
    119 		}
    120 		/* now free the list */
    121 		for(f=fs->freefid; f; f=next){
    122 			next = f->next;
    123 			free(f);
    124 		}
    125 		closeioproc(fs->iorecv);
    126 		closeioproc(fs->iosend);
    127 		free(fs);
    128 		return;
    129 	}
    130 	qunlock(&fs->lk);
    131 }
    132 
    133 int
    134 fsversion(CFsys *fs, int msize, char *version, int nversion)
    135 {
    136 	void *freep;
    137 	int r, oldmintag, oldmaxtag;
    138 	Fcall tx, rx;
    139 
    140 	tx.tag = 0;
    141 	tx.type = Tversion;
    142 	tx.version = version;
    143 	tx.msize = msize;
    144 
    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;
    160 	}
    161 
    162 	strecpy(version, version+nversion, rx.version);
    163 	free(freep);
    164 	fs->msize = rx.msize;
    165 	return rx.msize;
    166 }
    167 
    168 CFid*
    169 fsattach(CFsys *fs, CFid *afid, char *user, char *aname)
    170 {
    171 	Fcall tx, rx;
    172 	CFid *fid;
    173 
    174 	if(aname == nil)
    175 		aname = "";
    176 
    177 	if((fid = _fsgetfid(fs)) == nil)
    178 		return nil;
    179 
    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;
    186 
    187 	if(_fsrpc(fs, &tx, &rx, 0) < 0){
    188 		_fsputfid(fid);
    189 		return nil;
    190 	}
    191 	fid->qid = rx.qid;
    192 	return fid;
    193 }
    194 
    195 void
    196 fssetroot(CFsys *fs, CFid *fid)
    197 {
    198 	if(fs->root)
    199 		_fsputfid(fs->root);
    200 	fs->root = fid;
    201 }
    202 
    203 int
    204 _fsrpc(CFsys *fs, Fcall *tx, Fcall *rx, void **freep)
    205 {
    206 	int n, nn;
    207 	void *tpkt, *rpkt;
    208 
    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;
    224 	}
    225 	rpkt = muxrpc(&fs->mux, tpkt);
    226 	free(tpkt);
    227 	if(rpkt == nil){
    228 		werrstr("muxrpc: %r");
    229 		return -1;
    230 	}
    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;
    238 	}
    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;
    245 	}
    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;
    251 	}
    252 	if(freep)
    253 		*freep = rpkt;
    254 	else
    255 		free(rpkt);
    256 	return 0;
    257 }
    258 
    259 CFid*
    260 _fsgetfid(CFsys *fs)
    261 {
    262 	int i;
    263 	CFid *f;
    264 
    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;
    271 		}
    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;
    276 		}
    277 		f[i-1].next = nil;
    278 		fs->freefid = f;
    279 	}
    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;
    290 }
    291 
    292 void
    293 _fsputfid(CFid *f)
    294 {
    295 	CFsys *fs;
    296 
    297 	fs = f->fs;
    298 	qlock(&fs->lk);
    299 	f->next = fs->freefid;
    300 	fs->freefid = f;
    301 	qunlock(&fs->lk);
    302 	_fsdecref(fs);
    303 }
    304 
    305 static int
    306 _fsgettag(Mux *mux, void *pkt)
    307 {
    308 	return GBIT16((uchar*)pkt+5);
    309 }
    310 
    311 static int
    312 _fssettag(Mux *mux, void *pkt, uint tag)
    313 {
    314 	PBIT16((uchar*)pkt+5, tag);
    315 	return 0;
    316 }
    317 
    318 static int
    319 _fssend(Mux *mux, void *pkt)
    320 {
    321 	CFsys *fs;
    322 	int n;
    323 
    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;
    329 }
    330 
    331 static void*
    332 _fsrecv(Mux *mux)
    333 {
    334 	uchar *pkt;
    335 	uchar buf[4];
    336 	int n, nfd;
    337 	CFsys *fs;
    338 
    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;
    345 	}
    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;
    351 	}
    352 	PBIT32(pkt, n);
    353 	if(ioreadn(fs->iorecv, fs->fd, pkt+4, n-4) != n-4){
    354 		free(pkt);
    355 		return nil;
    356 	}
    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;
    362 		}
    363 		PBIT32(pkt+n-4, nfd);
    364 	}
    365 	return pkt;
    366 }
    367 
    368 Qid
    369 fsqid(CFid *fid)
    370 {
    371 	return fid->qid;
    372 }