~kris/9p

9hist

0d5dc81693a0775c2c84736fc888643b2096b19a — David du Colombier 26 years ago 6636732
Plan 9 from Bell Labs 1999-12-30
M ip/devip.c => ip/devip.c +21 -17
@@ 172,11 172,17 @@ ipgen(Chan *c, Dirtab*, int, int s, Dir *dp)

	switch(TYPE(c->qid)) {
	case Qtopdir:
		if(s == DEVDOTDOT){
			q = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0};
			sprint(name, "#I%lud", c->dev);
			devdir(c, q, name, 0, network, 0555, dp);
			return 1;
		}
		if(s < f->np) {
			if(f->p[s]->connect == nil)
				return 0;	/* protocol with no user interface */
			q = (Qid){QID(s, 0, Qprotodir)|CHDIR, 0};
			devdir(c, q, f->p[s]->name, 0, network, CHDIR|0555, dp);
			devdir(c, q, f->p[s]->name, 0, network, 0555, dp);
			return 1;
		}
		s -= f->np;


@@ 189,11 195,17 @@ ipgen(Chan *c, Dirtab*, int, int s, Dir *dp)
	case Qipselftab:
		return ip1gen(c, TYPE(c->qid), dp);
	case Qprotodir:
		if(s == DEVDOTDOT){
			q = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0};
			sprint(name, "#I%lud", c->dev);
			devdir(c, q, name, 0, network, 0555, dp);
			return 1;
		}
		if(s < f->p[PROTO(c->qid)]->ac) {
			cv = f->p[PROTO(c->qid)]->conv[s];
			sprint(name, "%d", s);
			q = (Qid){QID(PROTO(c->qid), s, Qconvdir)|CHDIR, 0};
			devdir(c, q, name, 0, cv->owner, CHDIR|0555, dp);
			devdir(c, q, name, 0, cv->owner, 0555, dp);
			return 1;
		}
		s -= f->p[PROTO(c->qid)]->ac;


@@ 202,6 214,12 @@ ipgen(Chan *c, Dirtab*, int, int s, Dir *dp)
	case Qstats:
		return ip2gen(c, TYPE(c->qid), dp);
	case Qconvdir:
		if(s == DEVDOTDOT){
			s = PROTO(c->qid);
			q = (Qid){QID(s, 0, Qprotodir)|CHDIR, 0};
			devdir(c, q, f->p[s]->name, 0, network, 0555, dp);
			return 1;
		}
		return ip3gen(c, s+Qconvbase, dp);
	case Qctl:
	case Qdata:


@@ 285,21 303,7 @@ ipclone(Chan* c, Chan* nc)
static int
ipwalk(Chan* c, char* name)
{
	if(strcmp(name, "..") != 0)
		return devwalk(c, name, nil, 0, ipgen);

	switch(TYPE(c->qid)){
	case Qtopdir:
	case Qprotodir:
		c->qid = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0};
		break;
	case Qconvdir:
		c->qid = (Qid){QID(PROTO(c->qid), 0, Qprotodir)|CHDIR, 0};
		break;
	default:
		panic("ipwalk %lux", c->qid.path);
	}
	return 1;
	return devwalk(c, name, nil, 0, ipgen);
}

static void

M pc/devastar.c => pc/devastar.c +5 -0
@@ 347,6 347,11 @@ astargen(Chan *c, Dirtab *, int , int i, Dir *db)

	sofar = 0;

	if(i == DEVDOTDOT){
		devdir(c, (Qid){CHDIR, 0}, "#G", 0, eve, 0555, db);
		return 1;
	}

	for(dev = 0; dev < nastar; dev++){
		if(sofar == i){
			sprint(db->name, "astar%dmem", astar[dev]->id);

M pc/devata.c => pc/devata.c +5 -0
@@ 248,6 248,11 @@ atagen(Chan* c, Dirtab*, int, int s, Dir* dirp)
	Partition *pp;
	vlong l;

	if(s == DEVDOTDOT){
		devdir(c, (Qid){CHDIR, 0}, "#H", 0, eve, 0555, dirp);
		return 1;
	}

	qid.vers = 0;
	drive = s/Npart;
	s = s % Npart;

M pc/devi82365.c => pc/devi82365.c +5 -0
@@ 482,6 482,11 @@ pcmgen(Chan *c, Dirtab *, int , int i, Dir *dp)
	Slot *pp;
	char name[NAMELEN];

	if(i == DEVDOTDOT){
		devdir(c, (Qid){CHDIR, 0}, "#y", 0, eve, 0555, dp);
		return 1;
	}

	if(i >= Nents*nslot)
		return -1;
	slotno = i/Nents;

M pc/devlpt.c => pc/devlpt.c +5 -0
@@ 59,6 59,11 @@ lptgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp)
	Qid qid;
	char name[NAMELEN];

	if(i == DEVDOTDOT){
		sprint(name, "#L%lud", c->dev+1);
		devdir(c, (Qid){CHDIR, 0}, name, 0, eve, 0555, dp);
		return 1;
	}
	if(tab==0 || i>=ntab)
		return -1;
	tab += i;

M pc/devusb.c => pc/devusb.c +12 -0
@@ 1389,6 1389,10 @@ usbgen(Chan *c, Dirtab*, int, int s, Dir *dp)
	 * Top level directory contains the name of the device.
	 */
	if(c->qid.path == CHDIR){
		if(s == DEVDOTDOT){
			devdir(c, (Qid){CHDIR, 0}, "#U", 0, eve, 0555, dp);
			return 1;
		}
		if(s == 0){
			devdir(c, (Qid){CHDIR|Q2nd, 0}, "usb", 0, eve, 0555, dp);
			return 1;


@@ 1401,6 1405,10 @@ usbgen(Chan *c, Dirtab*, int, int s, Dir *dp)
	 */
	t = QID(c->qid);
	if(t < Q3rd){
		if(s == DEVDOTDOT){
			devdir(c, (Qid){CHDIR, 0}, "#U", 0, eve, 0555, dp);
			return 1;
		}
		if(s < nelem(usbdir2)){
			tab = &usbdir2[s];
			devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);


@@ 1423,6 1431,10 @@ usbgen(Chan *c, Dirtab*, int, int s, Dir *dp)
	 */
	path = c->qid.path&~(CHDIR|QMASK);	/* slot component */
	q.vers = c->qid.vers;
	if(s == DEVDOTDOT){
		devdir(c, (Qid){CHDIR|Q2nd, 0}, "usb", 0, eve, 0555, dp);
		return 1;
	}
	if(s < nelem(usbdir3)){
		Dirtab *tab = &usbdir3[s];
		q.path = path | tab->qid.path;

M port/chan.c => port/chan.c +19 -48
@@ 19,7 19,7 @@ struct
}chanalloc;

#define SEP(c) ((c) == 0 || (c) == '/')
void cleancname(Cname*, int);
void cleancname(Cname*);

int
incref(Ref *r)


@@ 483,7 483,7 @@ updatecname(Chan *c, char *name, int dotdot)
		c->name = addelem(c->name, name);
	
	if(dotdot){
		cleancname(c->name, c->name->s[0]=='#');	/* could be cheaper */
		cleancname(c->name);	/* could be cheaper */
		c = undomount(c);
	}
	return c;


@@ 644,50 644,25 @@ saveregisters(void)
 * In place, rewrite name to compress multiple /, eliminate ., and process ..
 */
void
cleancname(Cname *n, int offset)
cleancname(Cname *n)
{
	char *p, *q, *dotdot, *name;
	int rooted;
	char *p;

	name = n->s+offset;
	rooted = name[0] == '/';
	if(n->s[0] == '#'){
		p = strchr(n->s, '/');
		if(p == nil)
			return;
		cleanname(p);

	/*
	 * invariants:
	 *	p points at beginning of path element we're considering.
	 *	q points just past the last path element we wrote (no slash).
	 *	dotdot points just past the point where .. cannot backtrack
	 *		any further (no slash).
	 */
	p = q = dotdot = name+rooted;
	while(*p) {
		if(p[0] == '/')	/* null element */
			p++;
		else if(p[0] == '.' && SEP(p[1]))
			p += 1;	/* don't count the separator in case it is nul */
		else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) {
			p += 2;
			if(q > dotdot) {	/* can backtrack */
				while(--q > dotdot && *q != '/')
					;
			} else if(!rooted) {	/* /.. is / but ./../ is .. */
				if(q != name)
					*q++ = '/';
				*q++ = '.';
				*q++ = '.';
				dotdot = q;
			}
		} else {	/* real path element */
			if(q != name+rooted)
				*q++ = '/';
			while((*q = *p) != '/' && *q != 0)
				p++, q++;
		}
	}
	if(q == name)	/* empty string is really ``.'' */
		*q++ = '.';
	*q = '\0';
	n->len = (q-name) + offset;
		/*
		 * The correct name is #i rather than #i/,
		 * but the correct name of #/ is #/.
		 */
		if(strcmp(p, "/")==0 && n->s[1] != '/')
			*p = '\0';
	}else
		cleanname(n->s);
	n->len = strlen(n->s);
}

/*


@@ 911,12 886,8 @@ namec(char *name, int amode, int omode, ulong perm)

	poperror();

	/* peculiar workaround for #/ */
	if(newname){
		if(cname->s[0]=='#' && cname->s[1]=='/')
			cleancname(cname, 1);
		else
			cleancname(cname, 0);
		cleancname(cname);
		cnameclose(c->name);
		c->name = cname;
	}else

M port/dev.c => port/dev.c +14 -2
@@ 42,12 42,19 @@ devdir(Chan *c, Qid qid, char *n, vlong length, char *user, long perm, Dir *db)
	memmove(db->gid, eve, NAMELEN);
}

//
// the zeroth element of the table MUST be the directory itself for ..
//
int
devgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp)
{
	if(tab==0 || i>=ntab)
	if(tab==0)
		return -1;
	tab += i;
	if(i!=DEVDOTDOT){
		if(i>=ntab)
			return -1;
		tab += i;
	}
	devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
	return 1;
}


@@ 111,6 118,11 @@ devwalk(Chan *c, char *name, Dirtab *tab, int ntab, Devgen *gen)
	isdir(c);
	if(name[0]=='.' && name[1]==0)
		return 1;
	if(name[0]=='.' && name[1]=='.' && name[2]==0){
		(*gen)(c, tab, ntab, DEVDOTDOT, &dir);
		c->qid = dir.qid;
		return 1;
	}
	for(i=0;; i++) {
		switch((*gen)(c, tab, ntab, i, &dir)){
		case -1:

M port/devbridge.c => port/devbridge.c +17 -15
@@ 222,21 222,6 @@ bridgeattach(char* spec)
static int
bridgewalk(Chan *c, char *name)
{
	if(strcmp(name, "..") == 0){
		switch(TYPE(c->qid)){
		case Qtopdir:
		case Qbridgedir:
			c->qid = (Qid){CHDIR|Qtopdir, 0};
			break;
		case Qportdir:
			c->qid = (Qid){CHDIR|Qbridgedir, 0};
			break;
		default:
			panic("bridgewalk %lux", c->qid.path);
		}
		return 1;
	}

	return devwalk(c, name, 0, 0, bridgegen);
}



@@ 431,6 416,23 @@ bridgegen(Chan *c, Dirtab*, int, int s, Dir *dp)
	Dirtab *dt;
	Qid qid;

	if(s  == DEVDOTDOT){
		switch(TYPE(c->qid)){
		case Qtopdir:
		case Qbridgedir:
			snprint(buf, "#B%d", c->dev);
			devdir(c, (Qid){CHDIR|Qtopdir, 0}, buf, 0, eve, 0555, dp);
			break;
		case Qportdir:
			sprint(buf, "bridge%ld", c->dev);
			devdir(c, (Qid){CHDIR|Qbridgedir, 0}, buf, 0, eve, 0555, dp);
			break;
		default:
			panic("bridgewalk %lux", c->qid.path);
		}
		return 1;
	}

	switch(type) {
	default:
		// non directory entries end up here

M port/devdraw.c => port/devdraw.c +21 -19
@@ 162,6 162,7 @@ extern	void		flushmemscreen(Rectangle);
	void		drawmesg(Client*, void*, int);
	void		drawuninstall(Client*, int);
	void		drawfreedimage(DImage*);
	Client*		drawclientofpath(ulong);

static	char Enodrawimage[] =	"unknown id for draw image";
static	char Enodrawscreen[] =	"unknown id for draw screen";


@@ 194,6 195,26 @@ drawgen(Chan *c, Dirtab *tab, int x, int s, Dir *dp)
	USED(tab, x);
	q.vers = 0;

	if(s == DEVDOTDOT){
		switch(QID(c->qid)){
		case Qtopdir:
		case Q2nd:
			devdir(c, (Qid){CHDIR|Qtopdir, 0}, "#i", 0, eve, 0500, dp);
			break;
		case Q3rd:
			cl = drawclientofpath(c->qid.path);
			if(cl == nil)
				strcpy(buf, "??");
			else
				sprint(buf, "%d", cl->clientid);
			devdir(c, (Qid){CHDIR|Q2nd, 0}, buf, 0, eve, 0500, dp);
			break;
		default:
			panic("drawwalk %lux", c->qid.path);
		}
		return 1;
	}

	/*
	 * Top level directory contains the name of the device.
	 */


@@ 855,25 876,6 @@ drawwalk(Chan *c, char *name)
{
	if(screendata.bdata == nil)
		error("no frame buffer");
	if(strcmp(name, "..") == 0){
		switch(QID(c->qid)){
		case Qtopdir:
			return 1;
		case Q2nd:
			c->qid = (Qid){CHDIR|Qtopdir, 0};
			break;
		case Q3rd:
			c->qid = (Qid){CHDIR|Q2nd, 0};
			break;
		default:
			panic("drawwalk %lux", c->qid.path);
		}
print("drawwalk: ..?\n");
//		op = c->path;
//		c->path = ptenter(&syspt, op, name);
//		decref(op);
		return 1;
	}
	return devwalk(c, name, 0, 0, drawgen);
}


M port/devdup.c => port/devdup.c +4 -0
@@ 13,6 13,10 @@ dupgen(Chan *c, Dirtab*, int, int s, Dir *dp)
	Chan *f;
	static int perm[] = { 0400, 0200, 0600, 0 };

	if(s == DEVDOTDOT){
		devdir(c, c->qid, "#d", 0, eve, 0555, dp);
		return 1;
	}
	if(s > fgrp->maxfd)
		return -1;
	if((f=fgrp->fd[s]) == 0)

M port/devenv.c => port/devenv.c +5 -0
@@ 17,6 17,11 @@ envgen(Chan *c, Dirtab*, int, int s, Dir *dp)
	Egrp *eg;
	Evalue *e;

	if(s == DEVDOTDOT){
		devdir(c, c->qid, "#e", 0, eve, 0775, dp);
		return 1;
	}

	eg = up->egrp;
	qlock(eg);


M port/devmnt.c => port/devmnt.c +7 -3
@@ 747,9 747,10 @@ mountmux(Mnt *m, Mntrpc *r)
	lock(m);
	l = &m->queue;
	for(q = *l; q; q = q->list) {
		if(q->request.tag == r->reply.tag
		|| q->flushed && q->flushtag == r->reply.tag) {
		if((q->flushed==0 && q->request.tag == r->reply.tag)
		|| (q->flushed && q->flushtag == r->reply.tag)) {
			*l = q->list;
			q->done = 1;
			unlock(m);
			if(q != r) {
				/*


@@ 760,7 761,6 @@ mountmux(Mnt *m, Mntrpc *r)
				q->rpc = r->rpc;
				r->rpc = dp;
				q->reply = r->reply;
				q->done = 1;
				if(mntstats != nil)
					(*mntstats)(q->request.type,
						m->c, q->stime,


@@ 787,6 787,10 @@ mntflush(Mnt *m, Mntrpc *r)
	Fcall flush;

	lock(m);
	if(r->done){
		unlock(m);
		return 1;
	}
	r->flushtag = m->flushtag++;
	if(m->flushtag == Tagend)
		m->flushtag = m->flushbase;

M port/devmntstats.c => port/devmntstats.c +5 -0
@@ 97,6 97,11 @@ mntstatsgen(Chan *c, Dirtab*, int, int i, Dir *dp)
	char name[NAMELEN];
	Mntstats *m;

	if(i == DEVDOTDOT){
		devdir(c, (Qid){CHDIR,0}, "#z", 0, eve, 0555, dp);
		return 1;
	}

	m = &msalloc.all[i];
	if(i > Nms || m->inuse == 0)
		return -1;

M port/devpipe.c => port/devpipe.c +5 -0
@@ 114,6 114,11 @@ pipegen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp)
{
	int id;

	if(i == DEVDOTDOT){
		devdir(c, c->qid, "#|", 0, eve, CHDIR|0555, dp);
		return 1;
	}

	id = NETID(c->qid.path);
	if(i > 1)
		id++;

M port/devproc.c => port/devproc.c +6 -5
@@ 82,6 82,12 @@ procgen(Chan *c, Dirtab *tab, int, int s, Dir *dp)
	char buf[NAMELEN];
	ulong pid, path, perm, len;

	if(s == DEVDOTDOT){
		c->qid.path = CHDIR;
		devdir(c, c->qid, "#p", 0, eve, 0555, dp);
		return 1;
	}

	if(c->qid.path == CHDIR){
		if(s >= conf.nproc)
			return -1;


@@ 142,11 148,6 @@ procattach(char *spec)
static int
procwalk(Chan *c, char *name)
{
	if(strcmp(name, "..") == 0) {
		c->qid.path = CHDIR;
		return 1;
	}

	return devwalk(c, name, 0, 0, procgen);
}


M port/devroot.c => port/devroot.c +1 -2
@@ 149,7 149,6 @@ rootread(Chan *c, void *buf, long n, vlong off)
	ulong t;
	Dirtab *d;
	uchar *data;
	Recover *r;
	ulong offset = off;

	t = c->qid.path & ~CHDIR;


@@ 169,7 168,7 @@ rootread(Chan *c, void *buf, long n, vlong off)
}

static long
rootwrite(Chan *c, void *buf, long n, vlong)
rootwrite(Chan *c, void*, long, vlong)
{
	switch(c->qid.path & ~CHDIR){
	default:

M port/devsd.c => port/devsd.c +5 -0
@@ 79,6 79,11 @@ sdgen(Chan *c, Dirtab*, int, int s, Dir *dirp)
	char name[2*NAMELEN];
	vlong l;

	if(s == DEVDOTDOT){
		devdir(c, qid, "#w", 0, eve, 0555, dirp);
		return 1;
	}

	d = disk;
	while(s >= d->npart) {
		s -= d->npart;

M port/devsdp.c => port/devsdp.c +17 -15
@@ 394,21 394,6 @@ sdpattach(char* spec)
static int
sdpwalk(Chan *c, char *name)
{
	if(strcmp(name, "..") == 0){
		switch(TYPE(c->qid)){
		case Qtopdir:
		case Qsdpdir:
			c->qid = (Qid){CHDIR|Qtopdir, 0};
			break;
		case Qconvdir:
			c->qid = (Qid){CHDIR|Qsdpdir, 0};
			break;
		default:
			panic("sdpwalk %lux", c->qid.path);
		}
		return 1;
	}

	return devwalk(c, name, 0, 0, sdpgen);
}



@@ 728,6 713,23 @@ sdpgen(Chan *c, Dirtab*, int, int s, Dir *dp)
	Dirtab *dt;
	Qid qid;

	if(s == DEVDOTDOT){
		switch(TYPE(c->qid)){
		case Qtopdir:
		case Qsdpdir:
			snprint(buf, sizeof(buf), "#E%d", c->dev);
			devdir(c, (Qid){CHDIR|Qtopdir, 0}, buf, 0, eve, 0555, dp);
			break;
		case Qconvdir:
			snprint(buf, sizeof(buf), "%d", s);
			devdir(c, (Qid){CHDIR|Qsdpdir, 0}, buf, 0, eve, 0555, dp);
			break;
		default:
			panic("sdpwalk %lux", c->qid.path);
		}
		return 1;
	}

	switch(type) {
	default:
		// non directory entries end up here

M port/devsrv.c => port/devsrv.c +5 -0
@@ 26,6 26,11 @@ srvgen(Chan *c, Dirtab*, int, int s, Dir *dp)
{
	Srv *sp;

	if(s == DEVDOTDOT){
		devdir(c, c->qid, "#s", 0, eve, 0555, dp);
		return 1;
	}

	qlock(&srvlk);
	for(sp = srv; sp && s; sp = sp->link)
		s--;

M port/devssl.c => port/devssl.c +16 -1
@@ 124,12 124,22 @@ sslgen(Chan *c, Dirtab *d, int nd, int s, Dir *dp)
	q.vers = 0;
	switch(TYPE(c->qid)) {
	case Qtopdir:
		if(s == DEVDOTDOT){
			q.path = QID(0, Qtopdir)|CHDIR;
			devdir(c, q, "#D", 0, eve, 0555, dp);
			return 1;
		}
		if(s > 0)
			return -1;
		q.path = QID(0, Qprotodir)|CHDIR;
		devdir(c, q, "ssl", 0, eve, 0555, dp);
		return 1;
	case Qprotodir:
		if(s == DEVDOTDOT){
			q.path = QID(0, Qtopdir)|CHDIR;
			devdir(c, q, ".", 0, eve, 0555, dp);
			return 1;
		}
		if(s < dshiwat) {
			sprint(name, "%d", s);
			q.path = QID(s, Qconvdir)|CHDIR;


@@ 138,7 148,7 @@ sslgen(Chan *c, Dirtab *d, int nd, int s, Dir *dp)
				nm = ds->user;
			else
				nm = eve;
			devdir(c, q, name, 0, nm, CHDIR|0555, dp);
			devdir(c, q, name, 0, nm, 0555, dp);
			return 1;
		}
		if(s > dshiwat)


@@ 147,6 157,11 @@ sslgen(Chan *c, Dirtab *d, int nd, int s, Dir *dp)
		devdir(c, q, "clone", 0, eve, 0555, dp);
		return 1;
	case Qconvdir:
		if(s == DEVDOTDOT){
			q.path = QID(0, Qprotodir)|CHDIR;
			devdir(c, q, "ssl", 0, eve, 0555, dp);
			return 1;
		}
		ds = dstate[CONV(c->qid)];
		if(ds != 0)
			nm = ds->user;

M port/devtinyfs.c => port/devtinyfs.c +6 -1
@@ 452,14 452,19 @@ tinyfsgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp)
	USED(ntab);
	USED(tab);

	qid.vers = 0;
	fs = &tinyfs.fs[c->dev];
	if(i >= fs->nf)
		return -1;
	if(i == DEVDOTDOT){
		qid.path = CHDIR;
		devdir(c, qid, ".", 0, eve, 0555, dp);
		return 1;
	}
	f = &fs->f[i];
	if(f->name[0] == 0)
		return 0;
	qid.path = i;
	qid.vers = 0;
	devdir(c, qid, f->name, f->length, eve, 0775, dp);
	return 1;
}

M port/netif.c => port/netif.c +15 -2
@@ 45,10 45,14 @@ netifgen(Chan *c, Dirtab *vp, int, int i, Dir *dp)
	/* top level directory contains the name of the network */
	if(c->qid.path == CHDIR){
		switch(i){
		case DEVDOTDOT:
			q.path = CHDIR;
			devdir(c, q, ".", 0, eve, CHDIR|0555, dp);
			break;
		case 0:
			q.path = CHDIR | N2ndqid;
			strcpy(buf, nif->name);
			devdir(c, q, buf, 0, eve, 0555, dp);
			devdir(c, q, buf, 0, eve, CHDIR|0555, dp);
			break;
		default:
			return -1;


@@ 60,6 64,10 @@ netifgen(Chan *c, Dirtab *vp, int, int i, Dir *dp)
	t = NETTYPE(c->qid.path);
	if(t == N2ndqid || t == Ncloneqid || t == Naddrqid){
		switch(i) {
		case DEVDOTDOT:
			q.path = CHDIR;
			devdir(c, q, ".", 0, eve, CHDIR|0555, dp);
			break;
		case 0:
			q.path = Ncloneqid;
			devdir(c, q, "clone", 0, eve, 0666, dp);


@@ 76,7 84,7 @@ netifgen(Chan *c, Dirtab *vp, int, int i, Dir *dp)
				return 0;
			q.path = CHDIR|NETQID(i, N3rdqid);
			sprint(buf, "%d", i);
			devdir(c, q, buf, 0, eve, 0555, dp);
			devdir(c, q, buf, 0, eve, CHDIR|0555, dp);
			break;
		}
		return 1;


@@ 94,6 102,11 @@ netifgen(Chan *c, Dirtab *vp, int, int i, Dir *dp)
		perm = 0666;
	}
	switch(i){
	case DEVDOTDOT:
		q.path = CHDIR | N2ndqid;
		strcpy(buf, nif->name);
		devdir(c, q, buf, 0, eve, CHDIR|0555, dp);
		break;
	case 0:
		q.path = NETQID(NETID(c->qid.path), Ndataqid);
		devdir(c, q, "data", 0, o, perm, dp);

M port/portdat.h => port/portdat.h +2 -0
@@ 739,6 739,8 @@ struct Cmdbuf

extern int nsyscall;

#define DEVDOTDOT -1

#pragma	varargck	argpos	print	1
#pragma	varargck	argpos	snprint	3
#pragma	varargck	argpos	sprint	2