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