fs.c (9945B)
1 #include <u.h> 2 #include <libc.h> 3 #include <authsrv.h> 4 #include <fcall.h> 5 #include "tapefs.h" 6 7 Fid *fids; 8 Ram *ram; 9 int mfd[2]; 10 char *user; 11 uchar mdata[Maxbuf+IOHDRSZ]; 12 int messagesize = Maxbuf+IOHDRSZ; 13 Fcall rhdr; 14 Fcall thdr; 15 ulong path; 16 Idmap *uidmap; 17 Idmap *gidmap; 18 int replete; 19 int blocksize; /* for 32v */ 20 int verbose; 21 int newtap; /* tap with time in sec */ 22 23 Fid * newfid(int); 24 int ramstat(Ram*, uchar*, int); 25 void io(void); 26 void usage(void); 27 int perm(int); 28 29 char *rflush(Fid*), *rversion(Fid*), *rauth(Fid*), 30 *rattach(Fid*), *rwalk(Fid*), 31 *ropen(Fid*), *rcreate(Fid*), 32 *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*), 33 *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*); 34 35 char *(*fcalls[Tmax])(Fid*); 36 void 37 initfcalls(void) 38 { 39 fcalls[Tflush]= rflush; 40 fcalls[Tversion]= rversion; 41 fcalls[Tauth]= rauth; 42 fcalls[Tattach]= rattach; 43 fcalls[Twalk]= rwalk; 44 fcalls[Topen]= ropen; 45 fcalls[Tcreate]= rcreate; 46 fcalls[Tread]= rread; 47 fcalls[Twrite]= rwrite; 48 fcalls[Tclunk]= rclunk; 49 fcalls[Tremove]= rremove; 50 fcalls[Tstat]= rstat; 51 fcalls[Twstat]= rwstat; 52 } 53 54 char Eperm[] = "permission denied"; 55 char Enotdir[] = "not a directory"; 56 char Enoauth[] = "tapefs: authentication not required"; 57 char Enotexist[] = "file does not exist"; 58 char Einuse[] = "file in use"; 59 char Eexist[] = "file exists"; 60 char Enotowner[] = "not owner"; 61 char Eisopen[] = "file already open for I/O"; 62 char Excl[] = "exclusive use file already open"; 63 char Ename[] = "illegal name"; 64 65 void 66 notifyf(void *a, char *s) 67 { 68 USED(a); 69 if(strncmp(s, "interrupt", 9) == 0) 70 noted(NCONT); 71 noted(NDFLT); 72 } 73 74 void 75 main(int argc, char *argv[]) 76 { 77 Ram *r; 78 char *defmnt, *defsrv; 79 int p[2]; 80 char buf[TICKREQLEN]; 81 82 fmtinstall('F', fcallfmt); 83 initfcalls(); 84 85 defmnt = nil; 86 defsrv = nil; 87 ARGBEGIN{ 88 case 'm': 89 defmnt = ARGF(); 90 break; 91 case 's': 92 defsrv = ARGF(); 93 break; 94 case 'p': /* password file */ 95 uidmap = getpass(ARGF()); 96 break; 97 case 'g': /* group file */ 98 gidmap = getpass(ARGF()); 99 break; 100 case 'v': 101 verbose++; 102 103 case 'n': 104 newtap++; 105 break; 106 default: 107 usage(); 108 }ARGEND 109 110 if(argc==0) 111 error("no file to mount"); 112 user = getuser(); 113 if(user == nil) 114 user = "dmr"; 115 ram = r = (Ram *)emalloc(sizeof(Ram)); 116 r->busy = 1; 117 r->data = 0; 118 r->ndata = 0; 119 r->perm = DMDIR | 0775; 120 r->qid.path = 0; 121 r->qid.vers = 0; 122 r->qid.type = QTDIR; 123 r->parent = 0; 124 r->child = 0; 125 r->next = 0; 126 r->user = user; 127 r->group = user; 128 r->atime = time(0); 129 r->mtime = r->atime; 130 r->replete = 0; 131 r->name = estrdup("."); 132 populate(argv[0]); 133 r->replete |= replete; 134 if(pipe(p) < 0) 135 error("pipe failed"); 136 mfd[0] = mfd[1] = p[0]; 137 notify(notifyf); 138 139 switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){ 140 case -1: 141 error("fork"); 142 case 0: 143 close(p[1]); 144 notify(notifyf); 145 io(); 146 break; 147 default: 148 close(p[0]); /* don't deadlock if child fails */ 149 if(post9pservice(p[1], defsrv, defmnt) < 0){ 150 sprint(buf, "post9pservice: %r"); 151 error(buf); 152 } 153 } 154 exits(0); 155 } 156 157 char* 158 rversion(Fid *unused) 159 { 160 Fid *f; 161 162 USED(unused); 163 164 if(rhdr.msize < 256) 165 return "version: message too small"; 166 if(rhdr.msize > messagesize) 167 rhdr.msize = messagesize; 168 else 169 messagesize = rhdr.msize; 170 thdr.msize = messagesize; 171 if(strncmp(rhdr.version, "9P2000", 6) != 0) 172 return "unrecognized 9P version"; 173 thdr.version = "9P2000"; 174 175 for(f = fids; f; f = f->next) 176 if(f->busy) 177 rclunk(f); 178 return 0; 179 } 180 181 char* 182 rauth(Fid *unused) 183 { 184 USED(unused); 185 186 return Enoauth; 187 } 188 189 char* 190 rflush(Fid *f) 191 { 192 USED(f); 193 return 0; 194 } 195 196 char* 197 rattach(Fid *f) 198 { 199 /* no authentication! */ 200 f->busy = 1; 201 f->rclose = 0; 202 f->ram = ram; 203 thdr.qid = f->ram->qid; 204 if(rhdr.uname[0]) 205 f->user = strdup(rhdr.uname); 206 else 207 f->user = "none"; 208 return 0; 209 } 210 211 char* 212 rwalk(Fid *f) 213 { 214 Fid *nf; 215 Ram *r; 216 char *err; 217 char *name; 218 Ram *dir; 219 int i; 220 221 nf = nil; 222 if(f->ram->busy == 0) 223 return Enotexist; 224 if(f->open) 225 return Eisopen; 226 if(rhdr.newfid != rhdr.fid){ 227 nf = newfid(rhdr.newfid); 228 nf->busy = 1; 229 nf->open = 0; 230 nf->rclose = 0; 231 nf->ram = f->ram; 232 nf->user = f->user; /* no ref count; the leakage is minor */ 233 f = nf; 234 } 235 236 thdr.nwqid = 0; 237 err = nil; 238 r = f->ram; 239 240 if(rhdr.nwname > 0){ 241 for(i=0; i<rhdr.nwname; i++){ 242 if((r->qid.type & QTDIR) == 0){ 243 err = Enotdir; 244 break; 245 } 246 if(r->busy == 0){ 247 err = Enotexist; 248 break; 249 } 250 r->atime = time(0); 251 name = rhdr.wname[i]; 252 dir = r; 253 if(!perm(Pexec)){ 254 err = Eperm; 255 break; 256 } 257 if(strcmp(name, "..") == 0){ 258 r = dir->parent; 259 Accept: 260 if(i == MAXWELEM){ 261 err = "name too long"; 262 break; 263 } 264 thdr.wqid[thdr.nwqid++] = r->qid; 265 continue; 266 } 267 if(!dir->replete) 268 popdir(dir); 269 for(r=dir->child; r; r=r->next) 270 if(r->busy && strcmp(name, r->name)==0) 271 goto Accept; 272 break; /* file not found */ 273 } 274 275 if(i==0 && err == nil) 276 err = Enotexist; 277 } 278 279 if(err!=nil || thdr.nwqid<rhdr.nwname){ 280 if(nf){ 281 nf->busy = 0; 282 nf->open = 0; 283 nf->ram = 0; 284 } 285 }else if(thdr.nwqid == rhdr.nwname) 286 f->ram = r; 287 288 return err; 289 290 } 291 292 char * 293 ropen(Fid *f) 294 { 295 Ram *r; 296 int mode, trunc; 297 298 if(f->open) 299 return Eisopen; 300 r = f->ram; 301 if(r->busy == 0) 302 return Enotexist; 303 if(r->perm & DMEXCL) 304 if(r->open) 305 return Excl; 306 mode = rhdr.mode; 307 if(r->qid.type & QTDIR){ 308 if(mode != OREAD) 309 return Eperm; 310 thdr.qid = r->qid; 311 return 0; 312 } 313 if(mode & ORCLOSE) 314 return Eperm; 315 trunc = mode & OTRUNC; 316 mode &= OPERM; 317 if(mode==OWRITE || mode==ORDWR || trunc) 318 if(!perm(Pwrite)) 319 return Eperm; 320 if(mode==OREAD || mode==ORDWR) 321 if(!perm(Pread)) 322 return Eperm; 323 if(mode==OEXEC) 324 if(!perm(Pexec)) 325 return Eperm; 326 if(trunc && (r->perm&DMAPPEND)==0){ 327 r->ndata = 0; 328 dotrunc(r); 329 r->qid.vers++; 330 } 331 thdr.qid = r->qid; 332 thdr.iounit = messagesize-IOHDRSZ; 333 f->open = 1; 334 r->open++; 335 return 0; 336 } 337 338 char * 339 rcreate(Fid *f) 340 { 341 USED(f); 342 343 return Eperm; 344 } 345 346 char* 347 rread(Fid *f) 348 { 349 int i, len; 350 Ram *r; 351 char *buf; 352 uvlong off, end; 353 int n, cnt; 354 355 if(f->ram->busy == 0) 356 return Enotexist; 357 n = 0; 358 thdr.count = 0; 359 off = rhdr.offset; 360 end = rhdr.offset + rhdr.count; 361 cnt = rhdr.count; 362 if(cnt > messagesize-IOHDRSZ) 363 cnt = messagesize-IOHDRSZ; 364 buf = thdr.data; 365 if(f->ram->qid.type & QTDIR){ 366 if(!f->ram->replete) 367 popdir(f->ram); 368 for(i=0,r=f->ram->child; r!=nil && i<end; r=r->next){ 369 if(!r->busy) 370 continue; 371 len = ramstat(r, (uchar*)buf+n, cnt-n); 372 if(len <= BIT16SZ) 373 break; 374 if(i >= off) 375 n += len; 376 i += len; 377 } 378 thdr.count = n; 379 return 0; 380 } 381 r = f->ram; 382 if(off >= r->ndata) 383 return 0; 384 r->atime = time(0); 385 n = cnt; 386 if(off+n > r->ndata) 387 n = r->ndata - off; 388 thdr.data = doread(r, off, n); 389 thdr.count = n; 390 return 0; 391 } 392 393 char* 394 rwrite(Fid *f) 395 { 396 Ram *r; 397 ulong off; 398 int cnt; 399 400 r = f->ram; 401 if(dopermw(f->ram)==0) 402 return Eperm; 403 if(r->busy == 0) 404 return Enotexist; 405 off = rhdr.offset; 406 if(r->perm & DMAPPEND) 407 off = r->ndata; 408 cnt = rhdr.count; 409 if(r->qid.type & QTDIR) 410 return "file is a directory"; 411 if(off > 100*1024*1024) /* sanity check */ 412 return "write too big"; 413 dowrite(r, rhdr.data, off, cnt); 414 r->qid.vers++; 415 r->mtime = time(0); 416 thdr.count = cnt; 417 return 0; 418 } 419 420 char * 421 rclunk(Fid *f) 422 { 423 if(f->open) 424 f->ram->open--; 425 f->busy = 0; 426 f->open = 0; 427 f->ram = 0; 428 return 0; 429 } 430 431 char * 432 rremove(Fid *f) 433 { 434 USED(f); 435 return Eperm; 436 } 437 438 char * 439 rstat(Fid *f) 440 { 441 if(f->ram->busy == 0) 442 return Enotexist; 443 thdr.nstat = ramstat(f->ram, thdr.stat, messagesize-IOHDRSZ); 444 return 0; 445 } 446 447 char * 448 rwstat(Fid *f) 449 { 450 if(f->ram->busy == 0) 451 return Enotexist; 452 return Eperm; 453 } 454 455 int 456 ramstat(Ram *r, uchar *buf, int nbuf) 457 { 458 Dir dir; 459 460 dir.name = r->name; 461 dir.qid = r->qid; 462 dir.mode = r->perm; 463 dir.length = r->ndata; 464 dir.uid = r->user; 465 dir.gid = r->group; 466 dir.muid = r->user; 467 dir.atime = r->atime; 468 dir.mtime = r->mtime; 469 return convD2M(&dir, buf, nbuf); 470 } 471 472 Fid * 473 newfid(int fid) 474 { 475 Fid *f, *ff; 476 477 ff = 0; 478 for(f = fids; f; f = f->next) 479 if(f->fid == fid) 480 return f; 481 else if(!ff && !f->busy) 482 ff = f; 483 if(ff){ 484 ff->fid = fid; 485 ff->open = 0; 486 ff->busy = 1; 487 } 488 f = emalloc(sizeof *f); 489 f->ram = 0; 490 f->fid = fid; 491 f->busy = 1; 492 f->open = 0; 493 f->next = fids; 494 fids = f; 495 return f; 496 } 497 498 void 499 io(void) 500 { 501 char *err; 502 int n, nerr; 503 char buf[ERRMAX]; 504 505 errstr(buf, sizeof buf); 506 for(nerr=0, buf[0]='\0'; nerr<100; nerr++){ 507 /* 508 * reading from a pipe or a network device 509 * will give an error after a few eof reads 510 * however, we cannot tell the difference 511 * between a zero-length read and an interrupt 512 * on the processes writing to us, 513 * so we wait for the error 514 */ 515 n = read9pmsg(mfd[0], mdata, sizeof mdata); 516 if(n==0) 517 continue; 518 if(n < 0){ 519 if(buf[0]=='\0') 520 errstr(buf, sizeof buf); 521 continue; 522 } 523 nerr = 0; 524 buf[0] = '\0'; 525 if(convM2S(mdata, n, &rhdr) != n) 526 error("convert error in convM2S"); 527 528 if(verbose) 529 fprint(2, "tapefs: <=%F\n", &rhdr);/**/ 530 531 thdr.data = (char*)mdata + IOHDRSZ; 532 thdr.stat = mdata + IOHDRSZ; 533 if(!fcalls[rhdr.type]) 534 err = "bad fcall type"; 535 else 536 err = (*fcalls[rhdr.type])(newfid(rhdr.fid)); 537 if(err){ 538 thdr.type = Rerror; 539 thdr.ename = err; 540 }else{ 541 thdr.type = rhdr.type + 1; 542 thdr.fid = rhdr.fid; 543 } 544 thdr.tag = rhdr.tag; 545 n = convS2M(&thdr, mdata, messagesize); 546 if(n <= 0) 547 error("convert error in convS2M"); 548 if(verbose) 549 fprint(2, "tapefs: =>%F\n", &thdr);/**/ 550 if(write(mfd[1], mdata, n) != n) 551 error("mount write"); 552 } 553 if(buf[0]=='\0' || strstr(buf, "hungup")) 554 exits(""); 555 fprint(2, "%s: mount read: %s\n", argv0, buf); 556 exits(buf); 557 } 558 559 int 560 perm(int p) 561 { 562 if(p==Pwrite) 563 return 0; 564 return 1; 565 } 566 567 void 568 error(char *s) 569 { 570 fprint(2, "%s: %s: ", argv0, s); 571 perror(""); 572 exits(s); 573 } 574 575 char* 576 estrdup(char *s) 577 { 578 char *t; 579 580 t = emalloc(strlen(s)+1); 581 strcpy(t, s); 582 return t; 583 } 584 585 void * 586 emalloc(ulong n) 587 { 588 void *p; 589 p = mallocz(n, 1); 590 if(!p) 591 error("out of memory"); 592 return p; 593 } 594 595 void * 596 erealloc(void *p, ulong n) 597 { 598 p = realloc(p, n); 599 if(!p) 600 error("out of memory"); 601 return p; 602 } 603 604 void 605 usage(void) 606 { 607 fprint(2, "usage: %s [-s] [-m mountpoint]\n", argv0); 608 exits("usage"); 609 }