123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- /*
- * 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.ref = 1;
- c->dev = 0;
- c->offset = 0;
- c->iounit = 0;
- c->aux = 0;
- c->name = 0;
- return c;
- }
- void
- chanfree(Chan *c)
- {
- c->flag = CFREE;
- cnameclose(c->name);
- free(c);
- }
- void
- cclose(Chan *c)
- {
- if(c->flag&CFREE)
- panic("cclose %#p", getcallerpc());
- if(decref(&c->ref))
- 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->ref);
- return nc;
- }
- enum
- {
- CNAMESLOP = 20
- };
- static Ref ncname;
- void cleancname(Cname*);
- int
- isdotdot(char *p)
- {
- return p[0]=='.' && p[1]=='.' && p[2]=='\0';
- }
- int
- incref(Ref *r)
- {
- int x;
- lock(&r->lock);
- x = ++r->ref;
- unlock(&r->lock);
- return x;
- }
- int
- decref(Ref *r)
- {
- int x;
- lock(&r->lock);
- x = --r->ref;
- unlock(&r->lock);
- 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.ref = 1;
- incref(&ncname);
- return n;
- }
- void
- cnameclose(Cname *n)
- {
- if(n == nil)
- return;
- if(decref(&n->ref))
- 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.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 ..
- */
- void
- cleancname(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);
- }
- void
- isdir(Chan *c)
- {
- if(c->qid.type & QTDIR)
- return;
- error(Enotdir);
- }
|