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