vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

dev.c (8241B)


      1 #include	"u.h"
      2 #include	"lib.h"
      3 #include	"mem.h"
      4 #include	"dat.h"
      5 #include	"fns.h"
      6 #include	"error.h"
      7 
      8 extern ulong	kerndate;
      9 
     10 void
     11 mkqid(Qid *q, vlong path, ulong vers, int type)
     12 {
     13 	q->type = type;
     14 	q->vers = vers;
     15 	q->path = path;
     16 }
     17 
     18 int
     19 devno(int c, int user)
     20 {
     21 	int i;
     22 
     23 	for(i = 0; devtab[i] != nil; i++) {
     24 		if(devtab[i]->dc == c)
     25 			return i;
     26 	}
     27 	if(user == 0)
     28 		panic("devno %C %#ux", c, c);
     29 
     30 	return -1;
     31 }
     32 
     33 void
     34 devdir(Chan *c, Qid qid, char *n, vlong length, char *user, long perm, Dir *db)
     35 {
     36 	db->name = n;
     37 	if(c->flag&CMSG)
     38 		qid.type |= QTMOUNT;
     39 	db->qid = qid;
     40 	db->type = devtab[c->type]->dc;
     41 	db->dev = c->dev;
     42 	db->mode = perm;
     43 	db->mode |= qid.type << 24;
     44 	db->atime = seconds();
     45 	db->mtime = kerndate;
     46 	db->length = length;
     47 	db->uid = user;
     48 	db->gid = eve;
     49 	db->muid = user;
     50 }
     51 
     52 /*
     53  * (here, Devgen is the prototype; devgen is the function in dev.c.)
     54  * 
     55  * a Devgen is expected to return the directory entry for ".."
     56  * if you pass it s==DEVDOTDOT (-1).  otherwise...
     57  * 
     58  * there are two contradictory rules.
     59  * 
     60  * (i) if c is a directory, a Devgen is expected to list its children
     61  * as you iterate s.
     62  * 
     63  * (ii) whether or not c is a directory, a Devgen is expected to list
     64  * its siblings as you iterate s.
     65  * 
     66  * devgen always returns the list of children in the root
     67  * directory.  thus it follows (i) when c is the root and (ii) otherwise.
     68  * many other Devgens follow (i) when c is a directory and (ii) otherwise.
     69  * 
     70  * devwalk assumes (i).  it knows that devgen breaks (i)
     71  * for children that are themselves directories, and explicitly catches them.
     72  * 
     73  * devstat assumes (ii).  if the Devgen in question follows (i)
     74  * for this particular c, devstat will not find the necessary info.
     75  * with our particular Devgen functions, this happens only for
     76  * directories, so devstat makes something up, assuming
     77  * c->name, c->qid, eve, DMDIR|0555.
     78  * 
     79  * devdirread assumes (i).  the callers have to make sure
     80  * that the Devgen satisfies (i) for the chan being read.
     81  */
     82 /*
     83  * the zeroth element of the table MUST be the directory itself for ..
     84 */
     85 int
     86 devgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
     87 {
     88 	if(tab == 0)
     89 		return -1;
     90 	if(i == DEVDOTDOT){
     91 		/* nothing */
     92 	}else if(name){
     93 		for(i=1; i<ntab; i++)
     94 			if(strcmp(tab[i].name, name) == 0)
     95 				break;
     96 		if(i==ntab)
     97 			return -1;
     98 		tab += i;
     99 	}else{
    100 		/* skip over the first element, that for . itself */
    101 		i++;
    102 		if(i >= ntab)
    103 			return -1;
    104 		tab += i;
    105 	}
    106 	devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
    107 	return 1;
    108 }
    109 
    110 void
    111 devreset(void)
    112 {
    113 }
    114 
    115 void
    116 devinit(void)
    117 {
    118 }
    119 
    120 void
    121 devshutdown(void)
    122 {
    123 }
    124 
    125 Chan*
    126 devattach(int tc, char *spec)
    127 {
    128 	int n;
    129 	Chan *c;
    130 	char *buf;
    131 
    132 	c = newchan();
    133 	mkqid(&c->qid, 0, 0, QTDIR);
    134 	c->type = devno(tc, 0);
    135 	if(spec == nil)
    136 		spec = "";
    137 	n = 1+UTFmax+strlen(spec)+1;
    138 	buf = smalloc(n);
    139 	snprint(buf, n, "#%C%s", tc, spec);
    140 	c->path = newpath(buf);
    141 	free(buf);
    142 	return c;
    143 }
    144 
    145 
    146 Chan*
    147 devclone(Chan *c)
    148 {
    149 	Chan *nc;
    150 
    151 	if(c->flag & COPEN)
    152 		panic("clone of open file type %C\n", devtab[c->type]->dc);
    153 
    154 	nc = newchan();
    155 
    156 	nc->type = c->type;
    157 	nc->dev = c->dev;
    158 	nc->mode = c->mode;
    159 	nc->qid = c->qid;
    160 	nc->offset = c->offset;
    161 	nc->umh = nil;
    162 	nc->aux = c->aux;
    163 	nc->mqid = c->mqid;
    164 	nc->mcp = c->mcp;
    165 	return nc;
    166 }
    167 
    168 Walkqid*
    169 devwalk(Chan *c, Chan *nc, char **name, int nname, Dirtab *tab, int ntab, Devgen *gen)
    170 {
    171 	int i, j, alloc;
    172 	Walkqid *wq;
    173 	char *n;
    174 	Dir dir;
    175 
    176 	if(nname > 0)
    177 		isdir(c);
    178 
    179 	alloc = 0;
    180 	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
    181 	if(waserror()){
    182 		if(alloc && wq->clone!=nil)
    183 			cclose(wq->clone);
    184 		free(wq);
    185 		return nil;
    186 	}
    187 	if(nc == nil){
    188 		nc = devclone(c);
    189 		nc->type = 0;	/* device doesn't know about this channel yet */
    190 		alloc = 1;
    191 	}
    192 	wq->clone = nc;
    193 
    194 	for(j=0; j<nname; j++){
    195 		if(!(nc->qid.type&QTDIR)){
    196 			if(j==0)
    197 				error(Enotdir);
    198 			goto Done;
    199 		}
    200 		n = name[j];
    201 		if(strcmp(n, ".") == 0){
    202     Accept:
    203 			wq->qid[wq->nqid++] = nc->qid;
    204 			continue;
    205 		}
    206 		if(strcmp(n, "..") == 0){
    207 			if((*gen)(nc, nil, tab, ntab, DEVDOTDOT, &dir) != 1){
    208 				print("devgen walk .. in dev%s %llux broken\n",
    209 					devtab[nc->type]->name, nc->qid.path);
    210 				error("broken devgen");
    211 			}
    212 			nc->qid = dir.qid;
    213 			goto Accept;
    214 		}
    215 		/*
    216 		 * Ugly problem: If we're using devgen, make sure we're
    217 		 * walking the directory itself, represented by the first
    218 		 * entry in the table, and not trying to step into a sub-
    219 		 * directory of the table, e.g. /net/net. Devgen itself
    220 		 * should take care of the problem, but it doesn't have
    221 		 * the necessary information (that we're doing a walk).
    222 		 */
    223 		if(gen==devgen && nc->qid.path!=tab[0].qid.path)
    224 			goto Notfound;
    225 		for(i=0;; i++) {
    226 			switch((*gen)(nc, n, tab, ntab, i, &dir)){
    227 			case -1:
    228 			Notfound:
    229 				if(j == 0)
    230 					error(Enonexist);
    231 				kstrcpy(up->errstr, Enonexist, ERRMAX);
    232 				goto Done;
    233 			case 0:
    234 				continue;
    235 			case 1:
    236 				if(strcmp(n, dir.name) == 0){
    237 					nc->qid = dir.qid;
    238 					goto Accept;
    239 				}
    240 				continue;
    241 			}
    242 		}
    243 	}
    244 	/*
    245 	 * We processed at least one name, so will return some data.
    246 	 * If we didn't process all nname entries succesfully, we drop
    247 	 * the cloned channel and return just the Qids of the walks.
    248 	 */
    249 Done:
    250 	poperror();
    251 	if(wq->nqid < nname){
    252 		if(alloc)
    253 			cclose(wq->clone);
    254 		wq->clone = nil;
    255 	}else if(wq->clone){
    256 		/* attach cloned channel to same device */
    257 		wq->clone->type = c->type;
    258 	}
    259 	return wq;
    260 }
    261 
    262 int
    263 devstat(Chan *c, uchar *db, int n, Dirtab *tab, int ntab, Devgen *gen)
    264 {
    265 	int i;
    266 	Dir dir;
    267 	char *p, *elem;
    268 
    269 	for(i=0;; i++){
    270 		switch((*gen)(c, nil, tab, ntab, i, &dir)){
    271 		case -1:
    272 			if(c->qid.type & QTDIR){
    273 				if(c->path == nil)
    274 					elem = "???";
    275 				else if(strcmp(c->path->s, "/") == 0)
    276 					elem = "/";
    277 				else
    278 					for(elem=p=c->path->s; *p; p++)
    279 						if(*p == '/')
    280 							elem = p+1;
    281 				devdir(c, c->qid, elem, 0, eve, DMDIR|0555, &dir);
    282 				n = convD2M(&dir, db, n);
    283 				if(n == 0)
    284 					error(Ebadarg);
    285 				return n;
    286 			}
    287 
    288 			error(Enonexist);
    289 		case 0:
    290 			break;
    291 		case 1:
    292 			if(c->qid.path == dir.qid.path) {
    293 				if(c->flag&CMSG)
    294 					dir.mode |= DMMOUNT;
    295 				n = convD2M(&dir, db, n);
    296 				if(n == 0)
    297 					error(Ebadarg);
    298 				return n;
    299 			}
    300 			break;
    301 		}
    302 	}
    303 }
    304 
    305 long
    306 devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen)
    307 {
    308 	long m, dsz;
    309 	Dir dir;
    310 
    311 	for(m=0; m<n; c->dri++) {
    312 		switch((*gen)(c, nil, tab, ntab, c->dri, &dir)){
    313 		case -1:
    314 			return m;
    315 
    316 		case 0:
    317 			break;
    318 
    319 		case 1:
    320 			dsz = convD2M(&dir, (uchar*)d, n-m);
    321 			if(dsz <= BIT16SZ){	/* <= not < because this isn't stat; read is stuck */
    322 				if(m == 0)
    323 					error(Eshort);
    324 				return m;
    325 			}
    326 			m += dsz;
    327 			d += dsz;
    328 			break;
    329 		}
    330 	}
    331 
    332 	return m;
    333 }
    334 
    335 /*
    336  * error(Eperm) if open permission not granted for up->user.
    337  */
    338 void
    339 devpermcheck(char *fileuid, ulong perm, int omode)
    340 {
    341 	ulong t;
    342 	static int access[] = { 0400, 0200, 0600, 0100 };
    343 
    344 	if(strcmp(up->user, fileuid) == 0)
    345 		perm <<= 0;
    346 	else
    347 	if(strcmp(up->user, eve) == 0)
    348 		perm <<= 3;
    349 	else
    350 		perm <<= 6;
    351 
    352 	t = access[omode&3];
    353 	if((t&perm) != t)
    354 		error(Eperm);
    355 }
    356 
    357 Chan*
    358 devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen)
    359 {
    360 	int i;
    361 	Dir dir;
    362 
    363 	for(i=0;; i++) {
    364 		switch((*gen)(c, nil, tab, ntab, i, &dir)){
    365 		case -1:
    366 			goto Return;
    367 		case 0:
    368 			break;
    369 		case 1:
    370 			if(c->qid.path == dir.qid.path) {
    371 				devpermcheck(dir.uid, dir.mode, omode);
    372 				goto Return;
    373 			}
    374 			break;
    375 		}
    376 	}
    377 Return:
    378 	c->offset = 0;
    379 	if((c->qid.type&QTDIR) && omode!=OREAD)
    380 		error(Eperm);
    381 	c->mode = openmode(omode);
    382 	c->flag |= COPEN;
    383 	return c;
    384 }
    385 
    386 void
    387 devcreate(Chan *c, char *name, int mode, ulong perm)
    388 {
    389 	error(Eperm);
    390 }
    391 
    392 Block*
    393 devbread(Chan *c, long n, ulong offset)
    394 {
    395 	Block *bp;
    396 
    397 	bp = allocb(n);
    398 	if(bp == 0)
    399 		error(Enomem);
    400 	if(waserror()) {
    401 		freeb(bp);
    402 		nexterror();
    403 	}
    404 	bp->wp += devtab[c->type]->read(c, bp->wp, n, offset);
    405 	poperror();
    406 	return bp;
    407 }
    408 
    409 long
    410 devbwrite(Chan *c, Block *bp, ulong offset)
    411 {
    412 	long n;
    413 
    414 	if(waserror()) {
    415 		freeb(bp);
    416 		nexterror();
    417 	}
    418 	n = devtab[c->type]->write(c, bp->rp, BLEN(bp), offset);
    419 	poperror();
    420 	freeb(bp);
    421 
    422 	return n;
    423 }
    424 
    425 void
    426 devremove(Chan *c)
    427 {
    428 	error(Eperm);
    429 }
    430 
    431 int
    432 devwstat(Chan *c, uchar *stat, int nstat)
    433 {
    434 	error(Eperm);
    435 	return 0;
    436 }
    437 
    438 void
    439 devpower(int toggle)
    440 {
    441 	error(Eperm);
    442 }
    443 
    444 int
    445 devconfig(int toggle, char *name, DevConf *conf)
    446 {
    447 	error(Eperm);
    448 	return 0;
    449 }