plan9port

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

fs.c (9945B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <authsrv.h>
      4 #include <fcall.h>
      5 #include "tapefs.h"
      6 
      7 Fid	*fids;
      8 Ram	*ram;
      9 int	mfd[2];
     10 char	*user;
     11 uchar	mdata[Maxbuf+IOHDRSZ];
     12 int	messagesize = Maxbuf+IOHDRSZ;
     13 Fcall	rhdr;
     14 Fcall	thdr;
     15 ulong	path;
     16 Idmap	*uidmap;
     17 Idmap	*gidmap;
     18 int	replete;
     19 int	blocksize;		/* for 32v */
     20 int	verbose;
     21 int	newtap;		/* tap with time in sec */
     22 
     23 Fid *	newfid(int);
     24 int	ramstat(Ram*, uchar*, int);
     25 void	io(void);
     26 void	usage(void);
     27 int	perm(int);
     28 
     29 char	*rflush(Fid*), *rversion(Fid*), *rauth(Fid*),
     30 	*rattach(Fid*), *rwalk(Fid*),
     31 	*ropen(Fid*), *rcreate(Fid*),
     32 	*rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
     33 	*rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
     34 
     35 char 	*(*fcalls[Tmax])(Fid*);
     36 void
     37 initfcalls(void)
     38 {
     39 	fcalls[Tflush]=	rflush;
     40 	fcalls[Tversion]=	rversion;
     41 	fcalls[Tauth]=	rauth;
     42 	fcalls[Tattach]=	rattach;
     43 	fcalls[Twalk]=	rwalk;
     44 	fcalls[Topen]=	ropen;
     45 	fcalls[Tcreate]=	rcreate;
     46 	fcalls[Tread]=	rread;
     47 	fcalls[Twrite]=	rwrite;
     48 	fcalls[Tclunk]=	rclunk;
     49 	fcalls[Tremove]=	rremove;
     50 	fcalls[Tstat]=	rstat;
     51 	fcalls[Twstat]=	rwstat;
     52 }
     53 
     54 char	Eperm[] =	"permission denied";
     55 char	Enotdir[] =	"not a directory";
     56 char	Enoauth[] =	"tapefs: authentication not required";
     57 char	Enotexist[] =	"file does not exist";
     58 char	Einuse[] =	"file in use";
     59 char	Eexist[] =	"file exists";
     60 char	Enotowner[] =	"not owner";
     61 char	Eisopen[] = 	"file already open for I/O";
     62 char	Excl[] = 	"exclusive use file already open";
     63 char	Ename[] = 	"illegal name";
     64 
     65 void
     66 notifyf(void *a, char *s)
     67 {
     68 	USED(a);
     69 	if(strncmp(s, "interrupt", 9) == 0)
     70 		noted(NCONT);
     71 	noted(NDFLT);
     72 }
     73 
     74 void
     75 main(int argc, char *argv[])
     76 {
     77 	Ram *r;
     78 	char *defmnt, *defsrv;
     79 	int p[2];
     80 	char buf[TICKREQLEN];
     81 
     82 	fmtinstall('F', fcallfmt);
     83 	initfcalls();
     84 
     85 	defmnt = nil;
     86 	defsrv = nil;
     87 	ARGBEGIN{
     88 	case 'm':
     89 		defmnt = ARGF();
     90 		break;
     91 	case 's':
     92 		defsrv = ARGF();
     93 		break;
     94 	case 'p':			/* password file */
     95 		uidmap = getpass(ARGF());
     96 		break;
     97 	case 'g':			/* group file */
     98 		gidmap = getpass(ARGF());
     99 		break;
    100 	case 'v':
    101 		verbose++;
    102 
    103 	case 'n':
    104 		newtap++;
    105 		break;
    106 	default:
    107 		usage();
    108 	}ARGEND
    109 
    110 	if(argc==0)
    111 		error("no file to mount");
    112 	user = getuser();
    113 	if(user == nil)
    114 		user = "dmr";
    115 	ram = r = (Ram *)emalloc(sizeof(Ram));
    116 	r->busy = 1;
    117 	r->data = 0;
    118 	r->ndata = 0;
    119 	r->perm = DMDIR | 0775;
    120 	r->qid.path = 0;
    121 	r->qid.vers = 0;
    122 	r->qid.type = QTDIR;
    123 	r->parent = 0;
    124 	r->child = 0;
    125 	r->next = 0;
    126 	r->user = user;
    127 	r->group = user;
    128 	r->atime = time(0);
    129 	r->mtime = r->atime;
    130 	r->replete = 0;
    131 	r->name = estrdup(".");
    132 	populate(argv[0]);
    133 	r->replete |= replete;
    134 	if(pipe(p) < 0)
    135 		error("pipe failed");
    136 	mfd[0] = mfd[1] = p[0];
    137 	notify(notifyf);
    138 
    139 	switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
    140 	case -1:
    141 		error("fork");
    142 	case 0:
    143 		close(p[1]);
    144 		notify(notifyf);
    145 		io();
    146 		break;
    147 	default:
    148 		close(p[0]);	/* don't deadlock if child fails */
    149 		if(post9pservice(p[1], defsrv, defmnt) < 0){
    150 			sprint(buf, "post9pservice: %r");
    151 			error(buf);
    152 		}
    153 	}
    154 	exits(0);
    155 }
    156 
    157 char*
    158 rversion(Fid *unused)
    159 {
    160 	Fid *f;
    161 
    162 	USED(unused);
    163 
    164 	if(rhdr.msize < 256)
    165 		return "version: message too small";
    166 	if(rhdr.msize > messagesize)
    167 		rhdr.msize = messagesize;
    168 	else
    169 		messagesize = rhdr.msize;
    170 	thdr.msize = messagesize;
    171 	if(strncmp(rhdr.version, "9P2000", 6) != 0)
    172 		return "unrecognized 9P version";
    173 	thdr.version = "9P2000";
    174 
    175 	for(f = fids; f; f = f->next)
    176 		if(f->busy)
    177 			rclunk(f);
    178 	return 0;
    179 }
    180 
    181 char*
    182 rauth(Fid *unused)
    183 {
    184 	USED(unused);
    185 
    186 	return Enoauth;
    187 }
    188 
    189 char*
    190 rflush(Fid *f)
    191 {
    192 	USED(f);
    193 	return 0;
    194 }
    195 
    196 char*
    197 rattach(Fid *f)
    198 {
    199 	/* no authentication! */
    200 	f->busy = 1;
    201 	f->rclose = 0;
    202 	f->ram = ram;
    203 	thdr.qid = f->ram->qid;
    204 	if(rhdr.uname[0])
    205 		f->user = strdup(rhdr.uname);
    206 	else
    207 		f->user = "none";
    208 	return 0;
    209 }
    210 
    211 char*
    212 rwalk(Fid *f)
    213 {
    214 	Fid *nf;
    215 	Ram *r;
    216 	char *err;
    217 	char *name;
    218 	Ram *dir;
    219 	int i;
    220 
    221 	nf = nil;
    222 	if(f->ram->busy == 0)
    223 		return Enotexist;
    224 	if(f->open)
    225 		return Eisopen;
    226 	if(rhdr.newfid != rhdr.fid){
    227 		nf = newfid(rhdr.newfid);
    228 		nf->busy = 1;
    229 		nf->open = 0;
    230 		nf->rclose = 0;
    231 		nf->ram = f->ram;
    232 		nf->user = f->user;	/* no ref count; the leakage is minor */
    233 		f = nf;
    234 	}
    235 
    236 	thdr.nwqid = 0;
    237 	err = nil;
    238 	r = f->ram;
    239 
    240 	if(rhdr.nwname > 0){
    241 		for(i=0; i<rhdr.nwname; i++){
    242 			if((r->qid.type & QTDIR) == 0){
    243 				err = Enotdir;
    244 				break;
    245 			}
    246 			if(r->busy == 0){
    247 				err = Enotexist;
    248 				break;
    249 			}
    250 			r->atime = time(0);
    251 			name = rhdr.wname[i];
    252 			dir = r;
    253 			if(!perm(Pexec)){
    254 				err = Eperm;
    255 				break;
    256 			}
    257 			if(strcmp(name, "..") == 0){
    258 				r = dir->parent;
    259    Accept:
    260 				if(i == MAXWELEM){
    261 					err = "name too long";
    262 					break;
    263 				}
    264  				thdr.wqid[thdr.nwqid++] = r->qid;
    265 				continue;
    266 			}
    267 			if(!dir->replete)
    268 				popdir(dir);
    269 			for(r=dir->child; r; r=r->next)
    270 				if(r->busy && strcmp(name, r->name)==0)
    271 					goto Accept;
    272 			break;	/* file not found */
    273 		}
    274 
    275 		if(i==0 && err == nil)
    276 			err = Enotexist;
    277 	}
    278 
    279 	if(err!=nil || thdr.nwqid<rhdr.nwname){
    280 		if(nf){
    281 			nf->busy = 0;
    282 			nf->open = 0;
    283 			nf->ram = 0;
    284 		}
    285 	}else if(thdr.nwqid  == rhdr.nwname)
    286 		f->ram = r;
    287 
    288 	return err;
    289 
    290 }
    291 
    292 char *
    293 ropen(Fid *f)
    294 {
    295 	Ram *r;
    296 	int mode, trunc;
    297 
    298 	if(f->open)
    299 		return Eisopen;
    300 	r = f->ram;
    301 	if(r->busy == 0)
    302 		return Enotexist;
    303 	if(r->perm & DMEXCL)
    304 		if(r->open)
    305 			return Excl;
    306 	mode = rhdr.mode;
    307 	if(r->qid.type & QTDIR){
    308 		if(mode != OREAD)
    309 			return Eperm;
    310 		thdr.qid = r->qid;
    311 		return 0;
    312 	}
    313 	if(mode & ORCLOSE)
    314 		return Eperm;
    315 	trunc = mode & OTRUNC;
    316 	mode &= OPERM;
    317 	if(mode==OWRITE || mode==ORDWR || trunc)
    318 		if(!perm(Pwrite))
    319 			return Eperm;
    320 	if(mode==OREAD || mode==ORDWR)
    321 		if(!perm(Pread))
    322 			return Eperm;
    323 	if(mode==OEXEC)
    324 		if(!perm(Pexec))
    325 			return Eperm;
    326 	if(trunc && (r->perm&DMAPPEND)==0){
    327 		r->ndata = 0;
    328 		dotrunc(r);
    329 		r->qid.vers++;
    330 	}
    331 	thdr.qid = r->qid;
    332 	thdr.iounit = messagesize-IOHDRSZ;
    333 	f->open = 1;
    334 	r->open++;
    335 	return 0;
    336 }
    337 
    338 char *
    339 rcreate(Fid *f)
    340 {
    341 	USED(f);
    342 
    343 	return Eperm;
    344 }
    345 
    346 char*
    347 rread(Fid *f)
    348 {
    349 	int i, len;
    350 	Ram *r;
    351 	char *buf;
    352 	uvlong off, end;
    353 	int n, cnt;
    354 
    355 	if(f->ram->busy == 0)
    356 		return Enotexist;
    357 	n = 0;
    358 	thdr.count = 0;
    359 	off = rhdr.offset;
    360 	end = rhdr.offset + rhdr.count;
    361 	cnt = rhdr.count;
    362 	if(cnt > messagesize-IOHDRSZ)
    363 		cnt = messagesize-IOHDRSZ;
    364 	buf = thdr.data;
    365 	if(f->ram->qid.type & QTDIR){
    366 		if(!f->ram->replete)
    367 			popdir(f->ram);
    368 		for(i=0,r=f->ram->child; r!=nil && i<end; r=r->next){
    369 			if(!r->busy)
    370 				continue;
    371 			len = ramstat(r, (uchar*)buf+n, cnt-n);
    372 			if(len <= BIT16SZ)
    373 				break;
    374 			if(i >= off)
    375 				n += len;
    376 			i += len;
    377 		}
    378 		thdr.count = n;
    379 		return 0;
    380 	}
    381 	r = f->ram;
    382 	if(off >= r->ndata)
    383 		return 0;
    384 	r->atime = time(0);
    385 	n = cnt;
    386 	if(off+n > r->ndata)
    387 		n = r->ndata - off;
    388 	thdr.data = doread(r, off, n);
    389 	thdr.count = n;
    390 	return 0;
    391 }
    392 
    393 char*
    394 rwrite(Fid *f)
    395 {
    396 	Ram *r;
    397 	ulong off;
    398 	int cnt;
    399 
    400 	r = f->ram;
    401 	if(dopermw(f->ram)==0)
    402 		return Eperm;
    403 	if(r->busy == 0)
    404 		return Enotexist;
    405 	off = rhdr.offset;
    406 	if(r->perm & DMAPPEND)
    407 		off = r->ndata;
    408 	cnt = rhdr.count;
    409 	if(r->qid.type & QTDIR)
    410 		return "file is a directory";
    411 	if(off > 100*1024*1024)		/* sanity check */
    412 		return "write too big";
    413 	dowrite(r, rhdr.data, off, cnt);
    414 	r->qid.vers++;
    415 	r->mtime = time(0);
    416 	thdr.count = cnt;
    417 	return 0;
    418 }
    419 
    420 char *
    421 rclunk(Fid *f)
    422 {
    423 	if(f->open)
    424 		f->ram->open--;
    425 	f->busy = 0;
    426 	f->open = 0;
    427 	f->ram = 0;
    428 	return 0;
    429 }
    430 
    431 char *
    432 rremove(Fid *f)
    433 {
    434 	USED(f);
    435 	return Eperm;
    436 }
    437 
    438 char *
    439 rstat(Fid *f)
    440 {
    441 	if(f->ram->busy == 0)
    442 		return Enotexist;
    443 	thdr.nstat = ramstat(f->ram, thdr.stat, messagesize-IOHDRSZ);
    444 	return 0;
    445 }
    446 
    447 char *
    448 rwstat(Fid *f)
    449 {
    450 	if(f->ram->busy == 0)
    451 		return Enotexist;
    452 	return Eperm;
    453 }
    454 
    455 int
    456 ramstat(Ram *r, uchar *buf, int nbuf)
    457 {
    458 	Dir dir;
    459 
    460 	dir.name = r->name;
    461 	dir.qid = r->qid;
    462 	dir.mode = r->perm;
    463 	dir.length = r->ndata;
    464 	dir.uid = r->user;
    465 	dir.gid = r->group;
    466 	dir.muid = r->user;
    467 	dir.atime = r->atime;
    468 	dir.mtime = r->mtime;
    469 	return convD2M(&dir, buf, nbuf);
    470 }
    471 
    472 Fid *
    473 newfid(int fid)
    474 {
    475 	Fid *f, *ff;
    476 
    477 	ff = 0;
    478 	for(f = fids; f; f = f->next)
    479 		if(f->fid == fid)
    480 			return f;
    481 		else if(!ff && !f->busy)
    482 			ff = f;
    483 	if(ff){
    484 		ff->fid = fid;
    485 		ff->open = 0;
    486 		ff->busy = 1;
    487 	}
    488 	f = emalloc(sizeof *f);
    489 	f->ram = 0;
    490 	f->fid = fid;
    491 	f->busy = 1;
    492 	f->open = 0;
    493 	f->next = fids;
    494 	fids = f;
    495 	return f;
    496 }
    497 
    498 void
    499 io(void)
    500 {
    501 	char *err;
    502 	int n, nerr;
    503 	char buf[ERRMAX];
    504 
    505 	errstr(buf, sizeof buf);
    506 	for(nerr=0, buf[0]='\0'; nerr<100; nerr++){
    507 		/*
    508 		 * reading from a pipe or a network device
    509 		 * will give an error after a few eof reads
    510 		 * however, we cannot tell the difference
    511 		 * between a zero-length read and an interrupt
    512 		 * on the processes writing to us,
    513 		 * so we wait for the error
    514 		 */
    515 		n = read9pmsg(mfd[0], mdata, sizeof mdata);
    516 		if(n==0)
    517 			continue;
    518 		if(n < 0){
    519 			if(buf[0]=='\0')
    520 				errstr(buf, sizeof buf);
    521 			continue;
    522 		}
    523 		nerr = 0;
    524 		buf[0] = '\0';
    525 		if(convM2S(mdata, n, &rhdr) != n)
    526 			error("convert error in convM2S");
    527 
    528 		if(verbose)
    529 			fprint(2, "tapefs: <=%F\n", &rhdr);/**/
    530 
    531 		thdr.data = (char*)mdata + IOHDRSZ;
    532 		thdr.stat = mdata + IOHDRSZ;
    533 		if(!fcalls[rhdr.type])
    534 			err = "bad fcall type";
    535 		else
    536 			err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
    537 		if(err){
    538 			thdr.type = Rerror;
    539 			thdr.ename = err;
    540 		}else{
    541 			thdr.type = rhdr.type + 1;
    542 			thdr.fid = rhdr.fid;
    543 		}
    544 		thdr.tag = rhdr.tag;
    545 		n = convS2M(&thdr, mdata, messagesize);
    546 		if(n <= 0)
    547 			error("convert error in convS2M");
    548 		if(verbose)
    549 			fprint(2, "tapefs: =>%F\n", &thdr);/**/
    550 		if(write(mfd[1], mdata, n) != n)
    551 			error("mount write");
    552 	}
    553 	if(buf[0]=='\0' || strstr(buf, "hungup"))
    554 		exits("");
    555 	fprint(2, "%s: mount read: %s\n", argv0, buf);
    556 	exits(buf);
    557 }
    558 
    559 int
    560 perm(int p)
    561 {
    562 	if(p==Pwrite)
    563 		return 0;
    564 	return 1;
    565 }
    566 
    567 void
    568 error(char *s)
    569 {
    570 	fprint(2, "%s: %s: ", argv0, s);
    571 	perror("");
    572 	exits(s);
    573 }
    574 
    575 char*
    576 estrdup(char *s)
    577 {
    578 	char *t;
    579 
    580 	t = emalloc(strlen(s)+1);
    581 	strcpy(t, s);
    582 	return t;
    583 }
    584 
    585 void *
    586 emalloc(ulong n)
    587 {
    588 	void *p;
    589 	p = mallocz(n, 1);
    590 	if(!p)
    591 		error("out of memory");
    592 	return p;
    593 }
    594 
    595 void *
    596 erealloc(void *p, ulong n)
    597 {
    598 	p = realloc(p, n);
    599 	if(!p)
    600 		error("out of memory");
    601 	return p;
    602 }
    603 
    604 void
    605 usage(void)
    606 {
    607 	fprint(2, "usage: %s [-s] [-m mountpoint]\n", argv0);
    608 	exits("usage");
    609 }