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 } 221 222 long 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 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* 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 309 devcreate(Chan*, char*, int, ulong) 310 { 311 error(Eperm); 312 } 313 314 Block* 315 devbread(Chan *, long, ulong) 316 { 317 panic("no block read"); 318 return nil; 319 } 320 321 long 322 devbwrite(Chan *, Block *, ulong) 323 { 324 panic("no block write"); 325 return 0; 326 } 327 328 void 329 devremove(Chan*) 330 { 331 error(Eperm); 332 } 333 334 int 335 devwstat(Chan*, uchar*, int) 336 { 337 error(Eperm); 338 return 0; 339 } 340