Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include	<u.h>
2
#include	<libc.h>
3
#include	"compat.h"
4
#include	"error.h"
5
 
6
Chan*
7
newchan(void)
8
{
9
	Chan *c;
10
 
11
	c = smalloc(sizeof(Chan));
12
 
13
	/* if you get an error before associating with a dev,
14
	   close calls rootclose, a nop */
15
	c->type = 0;
16
	c->flag = 0;
17
	c->ref = 1;
18
	c->dev = 0;
19
	c->offset = 0;
20
	c->iounit = 0;
21
	c->aux = 0;
22
	c->name = 0;
23
	return c;
24
}
25
 
26
void
27
chanfree(Chan *c)
28
{
29
	c->flag = CFREE;
30
 
31
	cnameclose(c->name);
32
	free(c);
33
}
34
 
35
void
36
cclose(Chan *c)
37
{
38
	if(c->flag&CFREE)
39
		panic("cclose %#p", getcallerpc(&c));
40
	if(decref(c))
41
		return;
42
 
43
	if(!waserror()){
44
		devtab[c->type]->close(c);
45
		poperror();
46
	}
47
 
48
	chanfree(c);
49
}
50
 
51
Chan*
52
cclone(Chan *c)
53
{
54
	Chan *nc;
55
	Walkqid *wq;
56
 
57
	wq = devtab[c->type]->walk(c, nil, nil, 0);
58
	if(wq == nil)
59
		error("clone failed");
60
	nc = wq->clone;
61
	free(wq);
62
	nc->name = c->name;
63
	if(c->name)
64
		incref(c->name);
65
	return nc;
66
}
67
 
68
enum
69
{
70
	CNAMESLOP	= 20
71
};
72
 
73
static Ref ncname;
74
 
75
void cleancname(Cname*);
76
 
77
int
78
isdotdot(char *p)
79
{
80
	return p[0]=='.' && p[1]=='.' && p[2]=='\0';
81
}
82
 
83
int
84
incref(Ref *r)
85
{
86
	int x;
87
 
88
	lock(r);
89
	x = ++r->ref;
90
	unlock(r);
91
	return x;
92
}
93
 
94
int
95
decref(Ref *r)
96
{
97
	int x;
98
 
99
	lock(r);
100
	x = --r->ref;
101
	unlock(r);
102
	if(x < 0)
103
		panic("decref");
104
 
105
	return x;
106
}
107
 
108
Cname*
109
newcname(char *s)
110
{
111
	Cname *n;
112
	int i;
113
 
114
	n = smalloc(sizeof(Cname));
115
	i = strlen(s);
116
	n->len = i;
117
	n->alen = i+CNAMESLOP;
118
	n->s = smalloc(n->alen);
119
	memmove(n->s, s, i+1);
120
	n->ref = 1;
121
	incref(&ncname);
122
	return n;
123
}
124
 
125
void
126
cnameclose(Cname *n)
127
{
128
	if(n == nil)
129
		return;
130
	if(decref(n))
131
		return;
132
	decref(&ncname);
133
	free(n->s);
134
	free(n);
135
}
136
 
137
Cname*
138
addelem(Cname *n, char *s)
139
{
140
	int i, a;
141
	char *t;
142
	Cname *new;
143
 
144
	if(s[0]=='.' && s[1]=='\0')
145
		return n;
146
 
147
	if(n->ref > 1){
148
		/* copy on write */
149
		new = newcname(n->s);
150
		cnameclose(n);
151
		n = new;
152
	}
153
 
154
	i = strlen(s);
155
	if(n->len+1+i+1 > n->alen){
156
		a = n->len+1+i+1 + CNAMESLOP;
157
		t = smalloc(a);
158
		memmove(t, n->s, n->len+1);
159
		free(n->s);
160
		n->s = t;
161
		n->alen = a;
162
	}
163
	if(n->len>0 && n->s[n->len-1]!='/' && s[0]!='/')	/* don't insert extra slash if one is present */
164
		n->s[n->len++] = '/';
165
	memmove(n->s+n->len, s, i+1);
166
	n->len += i;
167
	if(isdotdot(s))
168
		cleancname(n);
169
	return n;
170
}
171
 
172
/*
173
 * In place, rewrite name to compress multiple /, eliminate ., and process ..
174
 */
175
void
176
cleancname(Cname *n)
177
{
178
	char *p;
179
 
180
	if(n->s[0] == '#'){
181
		p = strchr(n->s, '/');
182
		if(p == nil)
183
			return;
184
		cleanname(p);
185
 
186
		/*
187
		 * The correct name is #i rather than #i/,
188
		 * but the correct name of #/ is #/.
189
		 */
190
		if(strcmp(p, "/")==0 && n->s[1] != '/')
191
			*p = '\0';
192
	}else
193
		cleanname(n->s);
194
	n->len = strlen(n->s);
195
}
196
 
197
void
198
isdir(Chan *c)
199
{
200
	if(c->qid.type & QTDIR)
201
		return;
202
	error(Enotdir);
203
}