xref: /plan9-contrib/sys/src/cmd/vnc/chan.c (revision 74f16c8187aab477889167f2422d0597b1b7d0ff)
19a747e4fSDavid du Colombier #include	<u.h>
29a747e4fSDavid du Colombier #include	<libc.h>
39a747e4fSDavid du Colombier #include	"compat.h"
49a747e4fSDavid du Colombier #include	"error.h"
59a747e4fSDavid du Colombier 
69a747e4fSDavid du Colombier Chan*
newchan(void)79a747e4fSDavid du Colombier newchan(void)
89a747e4fSDavid du Colombier {
99a747e4fSDavid du Colombier 	Chan *c;
109a747e4fSDavid du Colombier 
119a747e4fSDavid du Colombier 	c = smalloc(sizeof(Chan));
129a747e4fSDavid du Colombier 
139a747e4fSDavid du Colombier 	/* if you get an error before associating with a dev,
149a747e4fSDavid du Colombier 	   close calls rootclose, a nop */
159a747e4fSDavid du Colombier 	c->type = 0;
169a747e4fSDavid du Colombier 	c->flag = 0;
179a747e4fSDavid du Colombier 	c->ref = 1;
189a747e4fSDavid du Colombier 	c->dev = 0;
199a747e4fSDavid du Colombier 	c->offset = 0;
209a747e4fSDavid du Colombier 	c->iounit = 0;
219a747e4fSDavid du Colombier 	c->aux = 0;
229a747e4fSDavid du Colombier 	c->name = 0;
239a747e4fSDavid du Colombier 	return c;
249a747e4fSDavid du Colombier }
259a747e4fSDavid du Colombier 
269a747e4fSDavid du Colombier void
chanfree(Chan * c)279a747e4fSDavid du Colombier chanfree(Chan *c)
289a747e4fSDavid du Colombier {
299a747e4fSDavid du Colombier 	c->flag = CFREE;
309a747e4fSDavid du Colombier 
319a747e4fSDavid du Colombier 	cnameclose(c->name);
32f8e525acSDavid du Colombier 	free(c);
339a747e4fSDavid du Colombier }
349a747e4fSDavid du Colombier 
359a747e4fSDavid du Colombier void
cclose(Chan * c)369a747e4fSDavid du Colombier cclose(Chan *c)
379a747e4fSDavid du Colombier {
389a747e4fSDavid du Colombier 	if(c->flag&CFREE)
39*74f16c81SDavid du Colombier 		panic("cclose %#p", getcallerpc(&c));
409a747e4fSDavid du Colombier 	if(decref(c))
419a747e4fSDavid du Colombier 		return;
429a747e4fSDavid du Colombier 
439a747e4fSDavid du Colombier 	if(!waserror()){
449a747e4fSDavid du Colombier 		devtab[c->type]->close(c);
459a747e4fSDavid du Colombier 		poperror();
469a747e4fSDavid du Colombier 	}
479a747e4fSDavid du Colombier 
489a747e4fSDavid du Colombier 	chanfree(c);
499a747e4fSDavid du Colombier }
509a747e4fSDavid du Colombier 
519a747e4fSDavid du Colombier Chan*
cclone(Chan * c)529a747e4fSDavid du Colombier cclone(Chan *c)
539a747e4fSDavid du Colombier {
549a747e4fSDavid du Colombier 	Chan *nc;
559a747e4fSDavid du Colombier 	Walkqid *wq;
569a747e4fSDavid du Colombier 
579a747e4fSDavid du Colombier 	wq = devtab[c->type]->walk(c, nil, nil, 0);
589a747e4fSDavid du Colombier 	if(wq == nil)
599a747e4fSDavid du Colombier 		error("clone failed");
609a747e4fSDavid du Colombier 	nc = wq->clone;
619a747e4fSDavid du Colombier 	free(wq);
629a747e4fSDavid du Colombier 	nc->name = c->name;
639a747e4fSDavid du Colombier 	if(c->name)
649a747e4fSDavid du Colombier 		incref(c->name);
659a747e4fSDavid du Colombier 	return nc;
669a747e4fSDavid du Colombier }
679a747e4fSDavid du Colombier 
689a747e4fSDavid du Colombier enum
699a747e4fSDavid du Colombier {
709a747e4fSDavid du Colombier 	CNAMESLOP	= 20
719a747e4fSDavid du Colombier };
729a747e4fSDavid du Colombier 
739a747e4fSDavid du Colombier static Ref ncname;
749a747e4fSDavid du Colombier 
759a747e4fSDavid du Colombier void cleancname(Cname*);
769a747e4fSDavid du Colombier 
779a747e4fSDavid du Colombier int
isdotdot(char * p)789a747e4fSDavid du Colombier isdotdot(char *p)
799a747e4fSDavid du Colombier {
809a747e4fSDavid du Colombier 	return p[0]=='.' && p[1]=='.' && p[2]=='\0';
819a747e4fSDavid du Colombier }
829a747e4fSDavid du Colombier 
839a747e4fSDavid du Colombier int
incref(Ref * r)849a747e4fSDavid du Colombier incref(Ref *r)
859a747e4fSDavid du Colombier {
869a747e4fSDavid du Colombier 	int x;
879a747e4fSDavid du Colombier 
889a747e4fSDavid du Colombier 	lock(r);
899a747e4fSDavid du Colombier 	x = ++r->ref;
909a747e4fSDavid du Colombier 	unlock(r);
919a747e4fSDavid du Colombier 	return x;
929a747e4fSDavid du Colombier }
939a747e4fSDavid du Colombier 
949a747e4fSDavid du Colombier int
decref(Ref * r)959a747e4fSDavid du Colombier decref(Ref *r)
969a747e4fSDavid du Colombier {
979a747e4fSDavid du Colombier 	int x;
989a747e4fSDavid du Colombier 
999a747e4fSDavid du Colombier 	lock(r);
1009a747e4fSDavid du Colombier 	x = --r->ref;
1019a747e4fSDavid du Colombier 	unlock(r);
1029a747e4fSDavid du Colombier 	if(x < 0)
1039a747e4fSDavid du Colombier 		panic("decref");
1049a747e4fSDavid du Colombier 
1059a747e4fSDavid du Colombier 	return x;
1069a747e4fSDavid du Colombier }
1079a747e4fSDavid du Colombier 
1089a747e4fSDavid du Colombier Cname*
newcname(char * s)1099a747e4fSDavid du Colombier newcname(char *s)
1109a747e4fSDavid du Colombier {
1119a747e4fSDavid du Colombier 	Cname *n;
1129a747e4fSDavid du Colombier 	int i;
1139a747e4fSDavid du Colombier 
1149a747e4fSDavid du Colombier 	n = smalloc(sizeof(Cname));
1159a747e4fSDavid du Colombier 	i = strlen(s);
1169a747e4fSDavid du Colombier 	n->len = i;
1179a747e4fSDavid du Colombier 	n->alen = i+CNAMESLOP;
1189a747e4fSDavid du Colombier 	n->s = smalloc(n->alen);
1199a747e4fSDavid du Colombier 	memmove(n->s, s, i+1);
1209a747e4fSDavid du Colombier 	n->ref = 1;
1219a747e4fSDavid du Colombier 	incref(&ncname);
1229a747e4fSDavid du Colombier 	return n;
1239a747e4fSDavid du Colombier }
1249a747e4fSDavid du Colombier 
1259a747e4fSDavid du Colombier void
cnameclose(Cname * n)1269a747e4fSDavid du Colombier cnameclose(Cname *n)
1279a747e4fSDavid du Colombier {
1289a747e4fSDavid du Colombier 	if(n == nil)
1299a747e4fSDavid du Colombier 		return;
1309a747e4fSDavid du Colombier 	if(decref(n))
1319a747e4fSDavid du Colombier 		return;
1329a747e4fSDavid du Colombier 	decref(&ncname);
1339a747e4fSDavid du Colombier 	free(n->s);
1349a747e4fSDavid du Colombier 	free(n);
1359a747e4fSDavid du Colombier }
1369a747e4fSDavid du Colombier 
1379a747e4fSDavid du Colombier Cname*
addelem(Cname * n,char * s)1389a747e4fSDavid du Colombier addelem(Cname *n, char *s)
1399a747e4fSDavid du Colombier {
1409a747e4fSDavid du Colombier 	int i, a;
1419a747e4fSDavid du Colombier 	char *t;
1429a747e4fSDavid du Colombier 	Cname *new;
1439a747e4fSDavid du Colombier 
1449a747e4fSDavid du Colombier 	if(s[0]=='.' && s[1]=='\0')
1459a747e4fSDavid du Colombier 		return n;
1469a747e4fSDavid du Colombier 
1479a747e4fSDavid du Colombier 	if(n->ref > 1){
1489a747e4fSDavid du Colombier 		/* copy on write */
1499a747e4fSDavid du Colombier 		new = newcname(n->s);
1509a747e4fSDavid du Colombier 		cnameclose(n);
1519a747e4fSDavid du Colombier 		n = new;
1529a747e4fSDavid du Colombier 	}
1539a747e4fSDavid du Colombier 
1549a747e4fSDavid du Colombier 	i = strlen(s);
1559a747e4fSDavid du Colombier 	if(n->len+1+i+1 > n->alen){
1569a747e4fSDavid du Colombier 		a = n->len+1+i+1 + CNAMESLOP;
1579a747e4fSDavid du Colombier 		t = smalloc(a);
1589a747e4fSDavid du Colombier 		memmove(t, n->s, n->len+1);
1599a747e4fSDavid du Colombier 		free(n->s);
1609a747e4fSDavid du Colombier 		n->s = t;
1619a747e4fSDavid du Colombier 		n->alen = a;
1629a747e4fSDavid du Colombier 	}
1639a747e4fSDavid du Colombier 	if(n->len>0 && n->s[n->len-1]!='/' && s[0]!='/')	/* don't insert extra slash if one is present */
1649a747e4fSDavid du Colombier 		n->s[n->len++] = '/';
1659a747e4fSDavid du Colombier 	memmove(n->s+n->len, s, i+1);
1669a747e4fSDavid du Colombier 	n->len += i;
1679a747e4fSDavid du Colombier 	if(isdotdot(s))
1689a747e4fSDavid du Colombier 		cleancname(n);
1699a747e4fSDavid du Colombier 	return n;
1709a747e4fSDavid du Colombier }
1719a747e4fSDavid du Colombier 
1729a747e4fSDavid du Colombier /*
1739a747e4fSDavid du Colombier  * In place, rewrite name to compress multiple /, eliminate ., and process ..
1749a747e4fSDavid du Colombier  */
1759a747e4fSDavid du Colombier void
cleancname(Cname * n)1769a747e4fSDavid du Colombier cleancname(Cname *n)
1779a747e4fSDavid du Colombier {
1789a747e4fSDavid du Colombier 	char *p;
1799a747e4fSDavid du Colombier 
1809a747e4fSDavid du Colombier 	if(n->s[0] == '#'){
1819a747e4fSDavid du Colombier 		p = strchr(n->s, '/');
1829a747e4fSDavid du Colombier 		if(p == nil)
1839a747e4fSDavid du Colombier 			return;
1849a747e4fSDavid du Colombier 		cleanname(p);
1859a747e4fSDavid du Colombier 
1869a747e4fSDavid du Colombier 		/*
1879a747e4fSDavid du Colombier 		 * The correct name is #i rather than #i/,
1889a747e4fSDavid du Colombier 		 * but the correct name of #/ is #/.
1899a747e4fSDavid du Colombier 		 */
1909a747e4fSDavid du Colombier 		if(strcmp(p, "/")==0 && n->s[1] != '/')
1919a747e4fSDavid du Colombier 			*p = '\0';
1929a747e4fSDavid du Colombier 	}else
1939a747e4fSDavid du Colombier 		cleanname(n->s);
1949a747e4fSDavid du Colombier 	n->len = strlen(n->s);
1959a747e4fSDavid du Colombier }
1969a747e4fSDavid du Colombier 
1979a747e4fSDavid du Colombier void
isdir(Chan * c)1989a747e4fSDavid du Colombier isdir(Chan *c)
1999a747e4fSDavid du Colombier {
2009a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR)
2019a747e4fSDavid du Colombier 		return;
2029a747e4fSDavid du Colombier 	error(Enotdir);
2039a747e4fSDavid du Colombier }
204