212 lines · 3.0 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include	<u.h>#include	<libc.h>#include	"compat.h"#include	"error.h" Chan*newchan(void){	Chan *c; 	c = smalloc(sizeof(Chan)); 	/* if you get an error before associating with a dev,	   close calls rootclose, a nop */	c->type = 0;	c->flag = 0;	c->ref = 1;	c->dev = 0;	c->offset = 0;	c->iounit = 0;	c->aux = 0;	c->name = 0;	return c;} voidchanfree(Chan *c){	c->flag = CFREE; 	cnameclose(c->name);	free(c);} voidcclose(Chan *c){	if(c->flag&CFREE)		panic("cclose %#p", getcallerpc(&c));	if(decref(c))		return; 	if(!waserror()){		devtab[c->type]->close(c);		poperror();	} 	chanfree(c);} Chan*cclone(Chan *c){	Chan *nc;	Walkqid *wq; 	wq = devtab[c->type]->walk(c, nil, nil, 0);	if(wq == nil)		error("clone failed");	nc = wq->clone;	free(wq);	nc->name = c->name;	if(c->name)		incref(c->name);	return nc;} enum{	CNAMESLOP	= 20}; static Ref ncname; void cleancname(Cname*); intisdotdot(char *p){	return p[0]=='.' && p[1]=='.' && p[2]=='\0';} intincref(Ref *r){	int x; 	lock(r);	x = ++r->ref;	unlock(r);	return x;} intdecref(Ref *r){	int x; 	lock(r);	x = --r->ref;	unlock(r);	if(x < 0)		panic("decref"); 	return x;} Cname*newcname(char *s){	Cname *n;	int i; 	n = smalloc(sizeof(Cname));	i = strlen(s);	n->len = i;	n->alen = i+CNAMESLOP;	n->s = smalloc(n->alen);	memmove(n->s, s, i+1);	n->ref = 1;	incref(&ncname);	return n;} voidcnameclose(Cname *n){	if(n == nil)		return;	if(decref(n))		return;	decref(&ncname);	free(n->s);	free(n);} Cname*addelem(Cname *n, char *s){	int i, a;	char *t;	Cname *new; 	if(s[0]=='.' && s[1]=='\0')		return n; 	if(n->ref > 1){		/* copy on write */		new = newcname(n->s);		cnameclose(n);		n = new;	} 	i = strlen(s);	if(n->len+1+i+1 > n->alen){		a = n->len+1+i+1 + CNAMESLOP;		t = smalloc(a);		memmove(t, n->s, n->len+1);		free(n->s);		n->s = t;		n->alen = a;	}	if(n->len>0 && n->s[n->len-1]!='/' && s[0]!='/')	/* don't insert extra slash if one is present */		n->s[n->len++] = '/';	memmove(n->s+n->len, s, i+1);	n->len += i;	if(isdotdot(s))		cleancname(n);	return n;} /* * In place, rewrite name to compress multiple /, eliminate ., and process .. */voidcleancname(Cname *n){	char *p; 	if(n->s[0] == '#'){		p = strchr(n->s, '/');		if(p == nil)			return;		cleanname(p); 		/*		 * 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);} voidisdir(Chan *c){	if(c->qid.type & QTDIR)		return;	error(Enotdir);}