1 /* 2 * Plan 9 file system interface 3 */ 4 #include "dat.h" 5 #include "fns.h" 6 #include "error.h" 7 8 typedef struct Fsinfo Fsinfo; 9 struct Fsinfo 10 { 11 int fd; 12 QLock; /* serialise access to offset */ 13 ulong offset; /* offset used only for directory reads */ 14 Cname* name; /* Plan 9's name for file */ 15 Qid rootqid; /* Plan 9's qid for Inferno's root */ 16 char* root; /* prefix to strip from all names in diagnostics */ 17 }; 18 #define FS(c) ((Fsinfo*)((c)->aux)) 19 20 char rootdir[MAXROOT] = ROOT; 21 22 static void 23 fserr(Fsinfo *f) 24 { 25 int n; 26 char *p; 27 28 oserrstr(up->env->errstr, ERRMAX); 29 if(f != nil && *up->env->errstr == '\'' && (n = strlen(f->root)) > 1){ 30 /* don't reveal full names */ 31 if(strncmp(up->env->errstr+1, f->root, n-1) == 0){ 32 p = up->env->errstr+1+n; 33 memmove(up->env->errstr+1, p, strlen(p)+1); 34 } 35 } 36 error(up->env->errstr); 37 } 38 39 static void 40 fsfree(Chan *c) 41 { 42 cnameclose(FS(c)->name); 43 free(c->aux); 44 } 45 46 Chan* 47 fsattach(char *spec) 48 { 49 Chan *c; 50 Dir *d; 51 char *root; 52 Qid rootqid; 53 static int devno; 54 static Lock l; 55 56 if(!emptystr(spec)){ 57 if(strcmp(spec, "*") != 0) 58 error(Ebadspec); 59 root = "/"; 60 }else 61 root = rootdir; 62 63 d = dirstat(root); 64 if(d == nil) 65 fserr(nil); 66 rootqid = d->qid; 67 free(d); 68 69 c = devattach('U', spec); 70 lock(&l); 71 c->dev = devno++; 72 c->qid = rootqid; 73 unlock(&l); 74 c->aux = smalloc(sizeof(Fsinfo)); 75 FS(c)->name = newcname(root); 76 FS(c)->rootqid = rootqid; 77 FS(c)->fd = -1; 78 FS(c)->root = root; 79 80 return c; 81 } 82 83 Walkqid* 84 fswalk(Chan *c, Chan *nc, char **name, int nname) 85 { 86 int j, alloc; 87 Walkqid *wq; 88 Dir *dir; 89 char *n; 90 Cname *current, *next; 91 Qid rootqid; 92 93 if(nname > 0) 94 isdir(c); /* do we need this? */ 95 96 alloc = 0; 97 current = nil; 98 wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); 99 if(waserror()){ 100 if(alloc && wq->clone!=nil) 101 cclose(wq->clone); 102 cnameclose(current); 103 free(wq); 104 return nil; 105 } 106 if(nc == nil){ 107 nc = devclone(c); 108 nc->type = 0; 109 alloc = 1; 110 } 111 wq->clone = nc; 112 113 rootqid = FS(c)->rootqid; 114 current = FS(c)->name; 115 if(current != nil) 116 incref(¤t->r); 117 for(j=0; j<nname; j++){ 118 if(!(nc->qid.type&QTDIR)){ 119 if(j==0) 120 error(Enotdir); 121 break; 122 } 123 n = name[j]; 124 if(strcmp(n, ".") != 0 && !(isdotdot(n) && nc->qid.path == rootqid.path)){ /* TO DO: underlying qids aliased */ 125 //print("** ufs walk '%s' -> %s\n", current->s, n); 126 next = current; 127 incref(&next->r); 128 next = addelem(current, n); 129 dir = dirstat(next->s); 130 if(dir == nil){ 131 cnameclose(next); 132 if(j == 0) 133 error(Enonexist); 134 strcpy(up->env->errstr, Enonexist); 135 break; 136 } 137 nc->qid = dir->qid; 138 free(dir); 139 cnameclose(current); 140 current = next; 141 } 142 wq->qid[wq->nqid++] = nc->qid; 143 } 144 // print("** ufs walk '%s'\n", current->s); 145 146 poperror(); 147 if(wq->nqid < nname){ 148 cnameclose(current); 149 if(alloc) 150 cclose(wq->clone); 151 wq->clone = nil; 152 }else if(wq->clone){ 153 /* now attach to our device */ 154 nc->aux = smalloc(sizeof(Fsinfo)); 155 nc->type = c->type; 156 FS(nc)->rootqid = FS(c)->rootqid; 157 FS(nc)->name = current; 158 FS(nc)->fd = -1; 159 FS(nc)->root = FS(c)->root; 160 }else 161 panic("fswalk: can't happen"); 162 return wq; 163 } 164 165 int 166 fsstat(Chan *c, uchar *dp, int n) 167 { 168 if(FS(c)->fd >= 0) 169 n = fstat(FS(c)->fd, dp, n); 170 else 171 n = stat(FS(c)->name->s, dp, n); 172 if(n < 0) 173 fserr(FS(c)); 174 /* TO DO: change name to / if rootqid */ 175 return n; 176 } 177 178 Chan* 179 fsopen(Chan *c, int mode) 180 { 181 osenter(); 182 FS(c)->fd = open(FS(c)->name->s, mode); 183 osleave(); 184 if(FS(c)->fd < 0) 185 fserr(FS(c)); 186 c->mode = openmode(mode); 187 c->offset = 0; 188 FS(c)->offset = 0; 189 c->flag |= COPEN; 190 return c; 191 } 192 193 void 194 fscreate(Chan *c, char *name, int mode, ulong perm) 195 { 196 Dir *d; 197 Cname *n; 198 199 if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) 200 error(Efilename); 201 n = addelem(newcname(FS(c)->name->s), name); 202 osenter(); 203 FS(c)->fd = create(n->s, mode, perm); 204 osleave(); 205 if(FS(c)->fd < 0) { 206 cnameclose(n); 207 fserr(FS(c)); 208 } 209 d = dirfstat(FS(c)->fd); 210 if(d == nil) { 211 cnameclose(n); 212 close(FS(c)->fd); 213 FS(c)->fd = -1; 214 fserr(FS(c)); 215 } 216 c->qid = d->qid; 217 free(d); 218 219 cnameclose(FS(c)->name); 220 FS(c)->name = n; 221 222 c->mode = openmode(mode); 223 c->offset = 0; 224 FS(c)->offset = 0; 225 c->flag |= COPEN; 226 } 227 228 void 229 fsclose(Chan *c) 230 { 231 if(c->flag & COPEN){ 232 osenter(); 233 close(FS(c)->fd); 234 osleave(); 235 } 236 /* don't need to check for CRCLOSE, because Plan 9 itself implements ORCLOSE */ 237 fsfree(c); 238 } 239 240 static long 241 fsdirread(Chan *c, void *va, long count, vlong offset) 242 { 243 long n, r; 244 static char slop[16384]; 245 246 if(FS(c)->offset != offset){ 247 seek(FS(c)->fd, 0, 0); 248 for(n=0; n<offset;) { 249 r = offset - n; 250 if(r > sizeof(slop)) 251 r = sizeof(slop); 252 osenter(); 253 r = read(FS(c)->fd, slop, r); 254 osleave(); 255 if(r <= 0){ 256 FS(c)->offset = n; 257 return 0; 258 } 259 n += r; 260 } 261 FS(c)->offset = offset; 262 } 263 osenter(); 264 r = read(FS(c)->fd, va, count); 265 osleave(); 266 if(r < 0) 267 return r; 268 FS(c)->offset = offset+r; 269 return r; 270 } 271 272 long 273 fsread(Chan *c, void *va, long n, vlong offset) 274 { 275 int r; 276 277 if(c->qid.type & QTDIR){ /* need to maintain offset only for directories */ 278 qlock(FS(c)); 279 if(waserror()){ 280 qunlock(FS(c)); 281 nexterror(); 282 } 283 r = fsdirread(c, va, n, offset); 284 poperror(); 285 qunlock(FS(c)); 286 }else{ 287 osenter(); 288 r = pread(FS(c)->fd, va, n, offset); 289 osleave(); 290 } 291 if(r < 0) 292 fserr(FS(c)); 293 return r; 294 } 295 296 long 297 fswrite(Chan *c, void *va, long n, vlong offset) 298 { 299 int r; 300 301 osenter(); 302 r = pwrite(FS(c)->fd, va, n, offset); 303 osleave(); 304 if(r < 0) 305 fserr(FS(c)); 306 return r; 307 } 308 309 void 310 fsremove(Chan *c) 311 { 312 int r; 313 314 if(waserror()){ 315 fsfree(c); 316 nexterror(); 317 } 318 osenter(); 319 r = remove(FS(c)->name->s); 320 osleave(); 321 if(r < 0) 322 fserr(FS(c)); 323 poperror(); 324 fsfree(c); 325 } 326 327 int 328 fswstat(Chan *c, uchar *dp, int n) 329 { 330 osenter(); 331 if(FS(c)->fd >= 0) 332 n = fwstat(FS(c)->fd, dp, n); 333 else 334 n = wstat(FS(c)->name->s, dp, n); 335 osleave(); 336 if(n < 0) 337 fserr(FS(c)); 338 return n; 339 } 340 341 void 342 setid(char *name, int owner) 343 { 344 if(!owner || iseve()) 345 kstrdup(&up->env->user, name); 346 } 347 348 Dev fsdevtab = { 349 'U', 350 "fs", 351 352 devinit, 353 fsattach, 354 fswalk, 355 fsstat, 356 fsopen, 357 fscreate, 358 fsclose, 359 fsread, 360 devbread, 361 fswrite, 362 devbwrite, 363 fsremove, 364 fswstat 365 }; 366