xref: /plan9/sys/src/cmd/vnc/dev.c (revision b85a83648eec38fe82b6f00adfd7828ceec5ee8d)
1 #include	<u.h>
2 #include	<libc.h>
3 #include	<fcall.h>
4 #include	"compat.h"
5 #include	"error.h"
6 
7 extern ulong	kerndate;
8 
9 void
mkqid(Qid * q,vlong path,ulong vers,int type)10 mkqid(Qid *q, vlong path, ulong vers, int type)
11 {
12 	q->type = type;
13 	q->vers = vers;
14 	q->path = path;
15 }
16 
17 int
devno(int c,int user)18 devno(int c, int user)
19 {
20 	int i;
21 
22 	for(i = 0; devtab[i] != nil; i++){
23 		if(devtab[i]->dc == c)
24 			return i;
25 	}
26 	if(user == 0)
27 		panic("devno %C 0x%ux", c, c);
28 
29 	return -1;
30 }
31 
32 void
devdir(Chan * c,Qid qid,char * n,vlong length,char * user,long perm,Dir * db)33 devdir(Chan *c, Qid qid, char *n, vlong length, char *user, long perm, Dir *db)
34 {
35 	db->name = n;
36 	db->qid = qid;
37 	db->type = devtab[c->type]->dc;
38 	db->dev = c->dev;
39 	db->mode = (qid.type << 24) | perm;
40 	db->atime = seconds();
41 	db->mtime = kerndate;
42 	db->length = length;
43 	db->uid = user;
44 	db->gid = eve;
45 	db->muid = user;
46 }
47 
48 /*
49  * the zeroth element of the table MUST be the directory itself for ..
50 */
51 int
devgen(Chan * c,Dirtab * tab,int ntab,int i,Dir * dp)52 devgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp)
53 {
54 	if(tab == 0)
55 		return -1;
56 	if(i != DEVDOTDOT){
57 		i++; /* skip first element for . itself */
58 		if(i >= ntab)
59 			return -1;
60 		tab += i;
61 	}
62 	devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
63 	return 1;
64 }
65 
66 void
devreset(void)67 devreset(void)
68 {
69 }
70 
71 void
devinit(void)72 devinit(void)
73 {
74 }
75 
76 Chan*
devattach(int tc,char * spec)77 devattach(int tc, char *spec)
78 {
79 	Chan *c;
80 	char *buf;
81 
82 	c = newchan();
83 	mkqid(&c->qid, 0, 0, QTDIR);
84 	c->type = devno(tc, 0);
85 	if(spec == nil)
86 		spec = "";
87 	buf = smalloc(4+strlen(spec)+1);
88 	sprint(buf, "#%C%s", tc, spec);
89 	c->name = newcname(buf);
90 	free(buf);
91 	return c;
92 }
93 
94 
95 Chan*
devclone(Chan * c)96 devclone(Chan *c)
97 {
98 	Chan *nc;
99 
100 	if(c->flag & COPEN)
101 		panic("clone of open file type %C\n", devtab[c->type]->dc);
102 
103 	nc = newchan();
104 
105 	nc->type = c->type;
106 	nc->dev = c->dev;
107 	nc->mode = c->mode;
108 	nc->qid = c->qid;
109 	nc->offset = c->offset;
110 	nc->aux = c->aux;
111 	return nc;
112 }
113 
114 Walkqid*
devwalk(Chan * c,Chan * nc,char ** name,int nname,Dirtab * tab,int ntab,Devgen * gen)115 devwalk(Chan *c, Chan *nc, char **name, int nname, Dirtab *tab, int ntab, Devgen *gen)
116 {
117 	int i, j, alloc;
118 	Walkqid *wq;
119 	char *n;
120 	Dir dir;
121 
122 	isdir(c);
123 
124 	alloc = 0;
125 	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
126 	if(waserror()){
127 		if(alloc && wq->clone!=nil)
128 			cclose(wq->clone);
129 		free(wq);
130 		return nil;
131 	}
132 	if(nc == nil){
133 		nc = devclone(c);
134 		nc->type = 0;	/* device doesn't know about this channel yet */
135 		alloc = 1;
136 	}
137 	wq->clone = nc;
138 
139 	for(j=0; j<nname; j++){
140 		isdir(nc);
141 		n = name[j];
142 		if(strcmp(n, ".") == 0){
143     Accept:
144 			wq->qid[wq->nqid++] = nc->qid;
145 			continue;
146 		}
147 		if(strcmp(n, "..") == 0){
148 			(*gen)(nc, tab, ntab, DEVDOTDOT, &dir);
149 			nc->qid = dir.qid;
150 			goto Accept;
151 		}
152 		for(i=0;; i++){
153 			switch((*gen)(nc, tab, ntab, i, &dir)){
154 			case -1:
155 				if(j == 0)
156 					error(Enonexist);
157 				strncpy(up->error, Enonexist, ERRMAX);
158 				goto Done;
159 			case 0:
160 				continue;
161 			case 1:
162 				if(strcmp(n, dir.name) == 0){
163 					nc->qid = dir.qid;
164 					goto Accept;
165 				}
166 				continue;
167 			}
168 		}
169 	}
170 	/*
171 	 * We processed at least one name, so will return some data.
172 	 * If we didn't process all nname entries succesfully, we drop
173 	 * the cloned channel and return just the Qids of the walks.
174 	 */
175 Done:
176 	poperror();
177 	if(wq->nqid < nname){
178 		if(alloc)
179 			cclose(wq->clone);
180 		wq->clone = nil;
181 	}else if(wq->clone){
182 		/* attach cloned channel to same device */
183 		wq->clone->type = c->type;
184 	}
185 	return wq;
186 }
187 
188 int
devstat(Chan * c,uchar * db,int n,Dirtab * tab,int ntab,Devgen * gen)189 devstat(Chan *c, uchar *db, int n, Dirtab *tab, int ntab, Devgen *gen)
190 {
191 	int i;
192 	Dir dir;
193 	char *p, *elem;
194 
195 	for(i=0;; i++)
196 		switch((*gen)(c, tab, ntab, i, &dir)){
197 		case -1:
198 			if(c->qid.type & QTDIR){
199 				if(c->name == nil)
200 					elem = "???";
201 				else if(strcmp(c->name->s, "/") == 0)
202 					elem = "/";
203 				else
204 					for(elem=p=c->name->s; *p; p++)
205 						if(*p == '/')
206 							elem = p+1;
207 				devdir(c, c->qid, elem, 0, eve, DMDIR|0555, &dir);
208 				return convD2M(&dir, db, n);
209 			}
210 
211 			error(Enonexist);
212 		case 0:
213 			break;
214 		case 1:
215 			if(c->qid.path == dir.qid.path){
216 				return convD2M(&dir, db, n);
217 			}
218 			break;
219 		}
220 }
221 
222 long
devdirread(Chan * c,char * d,long n,Dirtab * tab,int ntab,Devgen * gen)223 devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen)
224 {
225 	long k, m, dsz;
226 	struct{
227 		Dir;
228 		char slop[100];
229 	}dir;
230 
231 	k = c->offset;
232 	for(m=0; m<n; k++){
233 		switch((*gen)(c, tab, ntab, k, &dir)){
234 		case -1:
235 			return m;
236 
237 		case 0:
238 			c->offset++;	/* BUG??? (was DIRLEN: skip entry) */
239 			break;
240 
241 		case 1:
242 			dsz = convD2M(&dir, (uchar*)d, n-m);
243 			if(dsz <= BIT16SZ){	/* <= not < because this isn't stat; read is stuck */
244 				if(m == 0)
245 					return -1;
246 				return m;
247 			}
248 			m += dsz;
249 			d += dsz;
250 			break;
251 		}
252 	}
253 
254 	return m;
255 }
256 
257 /*
258  * error(Eperm) if open permission not granted for up->user.
259  */
260 void
devpermcheck(char * fileuid,ulong perm,int omode)261 devpermcheck(char *fileuid, ulong perm, int omode)
262 {
263 	ulong t;
264 	static int access[] = { 0400, 0200, 0600, 0100 };
265 
266 	if(strcmp(up->user, fileuid) == 0)
267 		perm <<= 0;
268 	else
269 	if(strcmp(up->user, eve) == 0)
270 		perm <<= 3;
271 	else
272 		perm <<= 6;
273 
274 	t = access[omode&3];
275 	if((t&perm) != t)
276 		error(Eperm);
277 }
278 
279 Chan*
devopen(Chan * c,int omode,Dirtab * tab,int ntab,Devgen * gen)280 devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen)
281 {
282 	int i;
283 	Dir dir;
284 
285 	for(i=0;; i++){
286 		switch((*gen)(c, tab, ntab, i, &dir)){
287 		case -1:
288 			goto Return;
289 		case 0:
290 			break;
291 		case 1:
292 			if(c->qid.path == dir.qid.path){
293 				devpermcheck(dir.uid, dir.mode, omode);
294 				goto Return;
295 			}
296 			break;
297 		}
298 	}
299 Return:
300 	c->offset = 0;
301 	if((c->qid.type&QTDIR) && omode!=OREAD)
302 		error(Eperm);
303 	c->mode = openmode(omode);
304 	c->flag |= COPEN;
305 	return c;
306 }
307 
308 void
devcreate(Chan *,char *,int,ulong)309 devcreate(Chan*, char*, int, ulong)
310 {
311 	error(Eperm);
312 }
313 
314 Block*
devbread(Chan *,long,ulong)315 devbread(Chan *, long, ulong)
316 {
317 	panic("no block read");
318 	return nil;
319 }
320 
321 long
devbwrite(Chan *,Block *,ulong)322 devbwrite(Chan *, Block *, ulong)
323 {
324 	panic("no block write");
325 	return 0;
326 }
327 
328 void
devremove(Chan *)329 devremove(Chan*)
330 {
331 	error(Eperm);
332 }
333 
334 int
devwstat(Chan *,uchar *,int)335 devwstat(Chan*, uchar*, int)
336 {
337 	error(Eperm);
338 	return 0;
339 }
340