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 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 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 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 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 67 devreset(void) 68 { 69 } 70 71 void 72 devinit(void) 73 { 74 } 75 76 Chan* 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* 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* 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 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 return 0; 221 } 222 223 long 224 devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen) 225 { 226 long k, m, dsz; 227 struct{ 228 Dir; 229 char slop[100]; 230 }dir; 231 232 k = c->offset; 233 for(m=0; m<n; k++) { 234 switch((*gen)(c, tab, ntab, k, &dir)){ 235 case -1: 236 return m; 237 238 case 0: 239 c->offset++; /* BUG??? (was DIRLEN: skip entry) */ 240 break; 241 242 case 1: 243 dsz = convD2M(&dir, (uchar*)d, n-m); 244 if(dsz <= BIT16SZ){ /* <= not < because this isn't stat; read is stuck */ 245 if(m == 0) 246 return -1; 247 return m; 248 } 249 m += dsz; 250 d += dsz; 251 break; 252 } 253 } 254 255 return m; 256 } 257 258 /* 259 * error(Eperm) if open permission not granted for up->user. 260 */ 261 void 262 devpermcheck(char *fileuid, ulong perm, int omode) 263 { 264 ulong t; 265 static int access[] = { 0400, 0200, 0600, 0100 }; 266 267 if(strcmp(up->user, fileuid) == 0) 268 perm <<= 0; 269 else 270 if(strcmp(up->user, eve) == 0) 271 perm <<= 3; 272 else 273 perm <<= 6; 274 275 t = access[omode&3]; 276 if((t&perm) != t) 277 error(Eperm); 278 } 279 280 Chan* 281 devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen) 282 { 283 int i; 284 Dir dir; 285 286 for(i=0;; i++) { 287 switch((*gen)(c, tab, ntab, i, &dir)){ 288 case -1: 289 goto Return; 290 case 0: 291 break; 292 case 1: 293 if(c->qid.path == dir.qid.path) { 294 devpermcheck(dir.uid, dir.mode, omode); 295 goto Return; 296 } 297 break; 298 } 299 } 300 Return: 301 c->offset = 0; 302 if((c->qid.type&QTDIR) && omode!=OREAD) 303 error(Eperm); 304 c->mode = openmode(omode); 305 c->flag |= COPEN; 306 return c; 307 } 308 309 void 310 devcreate(Chan*, char*, int, ulong) 311 { 312 error(Eperm); 313 } 314 315 Block* 316 devbread(Chan *, long, ulong) 317 { 318 panic("no block read"); 319 return nil; 320 } 321 322 long 323 devbwrite(Chan *, Block *, ulong) 324 { 325 panic("no block write"); 326 return 0; 327 } 328 329 void 330 devremove(Chan*) 331 { 332 error(Eperm); 333 } 334 335 int 336 devwstat(Chan*, uchar*, int) 337 { 338 error(Eperm); 339 return 0; 340 } 341