domfs.c (12732B)
1 #include <u.h> 2 #include <libc.h> 3 #include <fcall.h> 4 #include <thread.h> 5 #include <9p.h> 6 7 typedef struct Finf Finf; /* file info */ 8 typedef struct DTree DTree; 9 typedef struct Node Node; 10 typedef struct Fusr Fusr; 11 12 enum { /* file types */ 13 ROOT, 14 TREE, 15 NODE, 16 NCTL, 17 USER, 18 NNEW, 19 TNEW, 20 21 REMV = -1, 22 }; 23 24 struct Finf { 25 uvlong id; 26 Qid qid; 27 int type; 28 void *aux; 29 }; 30 31 struct DTree { 32 uvlong id; 33 Node **nodes; 34 uvlong nidcount; 35 Finf *finf; 36 Finf *fnew; 37 }; 38 39 struct Node { 40 uvlong id; 41 DTree *tree; 42 Node *parent; 43 Node **children; 44 Fusr **files; 45 Finf *finf; 46 Finf *fctl; 47 }; 48 49 struct Fusr { 50 Node *node; 51 char *name; 52 char *data; 53 uvlong nsize; 54 Finf *finf; 55 }; 56 57 Finf **files, *rootf, *fnew; 58 59 DTree **trees; 60 static uvlong tcount; 61 62 long 63 stacksize(void **v) 64 { 65 long n; 66 if (v == nil) return 0; 67 for (n = 0; *v != nil; v++) n++; 68 return n; 69 } 70 71 void 72 stackpush(void ***v, void *new) 73 { 74 long n; 75 n = stacksize(*v); 76 *v = realloc(*v, (n + 2) * sizeof(void*)); 77 (*v)[n] = new; 78 (*v)[n+1] = nil; 79 } 80 81 void 82 stackremv(void ***v, void *w) 83 { 84 long i, n; 85 int remv; 86 remv = 0; 87 n = stacksize(*v); 88 for (i = 0; i < n; i++) { 89 if ((*v)[i] == w) remv = 1; 90 if (remv != 0) (*v)[i] = (*v)[i+1]; 91 } 92 if (remv != 0) *v = realloc(*v, (n) * sizeof(void*)); 93 } 94 95 Finf* 96 newfinf(int type, void *aux) 97 { 98 static uvlong id = 0; 99 Finf *new; 100 new = mallocz(sizeof(Finf), 1); 101 switch (type) { 102 case ROOT: 103 case TREE: 104 case NODE: 105 new->qid = (Qid){id, 0, QTDIR}; 106 break; 107 case NNEW: 108 case TNEW: 109 case NCTL: 110 case USER: 111 case REMV: 112 new->qid = (Qid){id, 0, QTFILE}; 113 break; 114 default: 115 sysfatal("newfinf: unknown file type %d", type); 116 } 117 new->id = id++; 118 new->type = type; 119 new->aux = aux; 120 return new; 121 } 122 123 DTree* 124 newtree(void) 125 { 126 static uvlong id; 127 DTree *new; 128 new = mallocz(sizeof(DTree), 1); 129 new->id = ++id; 130 new->finf = newfinf(TREE, new); 131 stackpush(&files, new->finf); 132 133 new->fnew = newfinf(NNEW, new); 134 stackpush(&files, new->fnew); 135 136 return new; 137 } 138 139 DTree* 140 gettree(DTree **trees, uvlong id) 141 { 142 DTree **tp; 143 if (trees == nil) return nil; 144 for (tp = trees; *tp != nil; tp++) 145 if ((*tp)->id == id) return *tp; 146 return nil; 147 } 148 149 Node* 150 newnode(DTree *T) 151 { 152 Node *new; 153 new = mallocz(sizeof(Node), 1); 154 new->id = ++T->nidcount; 155 new->finf = newfinf(NODE, new); 156 new->tree = T; 157 stackpush(&files, new->finf); 158 new->fctl = newfinf(NCTL, new); 159 stackpush(&files, new->fctl); 160 return new; 161 } 162 163 Node* 164 getnode(DTree *T, uvlong n) 165 { 166 Node **np; 167 if (T->nodes == nil) return nil; 168 for (np = T->nodes; *np != nil; np++) 169 if ((*np)->id == n) return *np; 170 return nil; 171 } 172 173 Fusr* 174 newfile(char *name) 175 { 176 Fusr *new; 177 new = mallocz(sizeof(Fusr), 1); 178 new->name = strdup(name); 179 new->finf = newfinf(USER, new); 180 stackpush(&files, new->finf); 181 return new; 182 } 183 184 Fusr* 185 getfile(Node *node, char *name) 186 { 187 Fusr **fp; 188 if (node->files == nil) return nil; 189 for (fp = node->files; *fp != nil; fp++) 190 if (strcmp(name, (*fp)->name) == 0) return *fp; 191 return nil; 192 } 193 194 void 195 fsattach(Req *r) 196 { 197 r->fid->qid = rootf->qid; 198 r->fid->aux = rootf; 199 r->ofcall.qid = r->fid->qid; 200 respond(r, nil); 201 } 202 203 int 204 dirgenroot(int n, Dir *dir, void*) 205 { 206 DTree *t; 207 if (n == 0) { 208 nulldir(dir); 209 dir->qid = fnew->qid; 210 dir->mode = 0666; 211 dir->atime = time(0); 212 dir->mtime = time(0); 213 dir->length = 0; 214 dir->name = strdup("new"); 215 dir->uid = strdup("domfs"); 216 dir->gid = strdup("domfs"); 217 dir->muid = strdup(""); 218 return 0; 219 } 220 n--; 221 if (trees == nil) return -1; 222 t = trees[n]; 223 if (t == nil) return -1; 224 nulldir(dir); 225 dir->qid = t->finf->qid; 226 dir->mode = 0777 | DMDIR; 227 dir->atime = time(0); 228 dir->mtime = time(0); 229 dir->length = 0; 230 dir->name = smprint("%ulld", t->id); 231 dir->uid = strdup("domfs"); 232 dir->gid = strdup("domfs"); 233 dir->muid = strdup(""); 234 return 0; 235 } 236 237 int 238 dirgentree(int n, Dir *dir, void *aux) 239 { 240 DTree *tree; 241 Node *node; 242 tree = aux; 243 if (tree == nil) return -1; 244 if (n == 0) { 245 nulldir(dir); 246 dir->qid = tree->fnew->qid; 247 dir->mode = 0666; 248 dir->atime = time(0); 249 dir->mtime = time(0); 250 dir->length = 0; 251 dir->name = strdup("new"); 252 dir->uid = strdup("domfs"); 253 dir->gid = strdup("domfs"); 254 dir->muid = strdup(""); 255 return 0; 256 } 257 n--; 258 if (tree->nodes == nil) return -1; 259 node = tree->nodes[n]; 260 if (node == nil) return -1; 261 nulldir(dir); 262 dir->qid = node->finf->qid; 263 dir->mode = 0777 | DMDIR; 264 dir->atime = time(0); 265 dir->mtime = time(0); 266 dir->length = 0; 267 dir->name = smprint("%ulld", node->id); 268 dir->uid = strdup("domfs"); 269 dir->gid = strdup("domfs"); 270 dir->muid = strdup(""); 271 return 0; 272 } 273 274 int 275 dirgennode(int n, Dir *dir, void *aux) 276 { 277 Node *node; 278 Fusr *file; 279 node = aux; 280 if (node == nil) return -1; 281 282 if (n == 0) { 283 nulldir(dir); 284 dir->qid = node->fctl->qid; 285 dir->mode = 0666; 286 dir->atime = time(0); 287 dir->mtime = time(0); 288 dir->length = 0; 289 dir->name = strdup("ctl"); 290 dir->uid = strdup("domfs"); 291 dir->gid = strdup("domfs"); 292 dir->muid = strdup(""); 293 return 0; 294 } 295 n--; 296 297 if (node->files == nil) return -1; 298 file = node->files[n]; 299 if (file == nil) return -1; 300 nulldir(dir); 301 dir->qid = file->finf->qid; 302 dir->mode = 0666; 303 dir->atime = time(0); 304 dir->mtime = time(0); 305 dir->length = file->nsize; 306 dir->name = strdup(file->name); 307 dir->uid = strdup("domfs"); 308 dir->gid = strdup("domfs"); 309 dir->muid = strdup(""); 310 return 0; 311 } 312 313 char * 314 nctl2str(Finf *f) 315 { 316 char *str; 317 Node *node, **cp; 318 uvlong parid; 319 long len, n; 320 if (f == nil) sysfatal("nctl2str: f == nil"); //return nil; 321 if (f->type != NCTL) sysfatal("nctl2str: f->type != NCTL"); //return nil; 322 node = f->aux; 323 if (node == nil) sysfatal("nctl2str: node == nil"); //return nil; 324 parid = (node->parent != nil) ? node->parent->id : 0; 325 326 str = smprint("parent %ulld\nchildren\n", parid); 327 len = strlen(str); 328 329 if (node->children == nil) return str; 330 for (cp = node->children; *cp != nil; cp++) { 331 char *buf; 332 str[len - 1] = ' '; 333 buf = smprint("%ulld\n", (*cp)->id); 334 n = strlen(buf); 335 str = realloc(str, len + n + 1); 336 memmove(str + len, buf, n); 337 str[len + n] = 0; 338 free(buf); 339 len += n; 340 } 341 return str; 342 } 343 344 char * 345 nctlparse(Finf *f, char *cmd) 346 { 347 Node *node; 348 DTree *tree; 349 int argc; 350 char **argv; 351 if (f->type != NCTL) sysfatal("nctlparse: f->type != NCTL"); 352 node = f->aux; 353 tree = node->tree; 354 argv = malloc(sizeof(char*) * 256); 355 argc = tokenize(cmd, argv, 256); 356 if (argc == 0) return nil; 357 if (strcmp(argv[0], "adopt") == 0) { 358 char *cpt; 359 Node *child; 360 uvlong id; 361 if (argc == 1) return "not enough args"; 362 id = strtoull(argv[1], &cpt, 10); 363 // TODO: check if parsed correctly 364 child = getnode(tree, id); 365 if (child == nil) return "no such node"; 366 if (child == node) return "can't adopt self"; 367 if (child->parent != nil) stackremv(&child->parent->children, child); 368 stackpush(&(node->children), child); 369 child->parent = node; 370 return nil; 371 } 372 return "unknown cmd"; 373 } 374 375 void 376 fsread(Req *r) 377 { 378 Finf *f; 379 char *buf; 380 Node *node; 381 DTree *tree; 382 f = r->fid->aux; 383 switch(f->type){ 384 case ROOT: 385 dirread9p(r, dirgenroot, nil); 386 break; 387 case TREE: 388 dirread9p(r, dirgentree, f->aux); 389 break; 390 case NODE: 391 dirread9p(r, dirgennode, f->aux); 392 break; 393 case USER: 394 readbuf(r, ((Fusr*)f->aux)->data, ((Fusr*)f->aux)->nsize); 395 break; 396 case NCTL: 397 // TODO: first line - parent, sec line - children 398 buf = nctl2str(f); 399 if (buf == nil) break; 400 readstr(r, buf); 401 free(buf); 402 break; 403 case TNEW: 404 if (r->ifcall.offset == 0) { 405 tree = newtree(); 406 stackpush(&trees, tree); 407 } else tree = gettree(trees, stacksize(trees)); 408 buf = smprint("%ulld\n", tree->id); 409 readstr(r, buf); 410 free(buf); 411 break; 412 case NNEW: 413 tree = f->aux; 414 if (r->ifcall.offset == 0) { 415 node = newnode(tree); 416 stackpush(&(tree->nodes), node); 417 } else node = getnode(tree, stacksize(tree->nodes)); 418 buf = smprint("%ulld\n", node->id); 419 readstr(r, buf); 420 free(buf); 421 break; 422 case REMV: 423 respond(r, "file does not exist"); 424 return; 425 default: 426 respond(r, "fsread: unknown file type"); 427 return; 428 } 429 respond(r, nil); 430 } 431 432 void 433 fswrite(Req *r) 434 { 435 char *buf, *rstr; 436 long off, nsize; 437 Finf *file; 438 Fusr *f; 439 file = r->fid->aux; 440 switch (file->type) { 441 case USER: 442 // TODO: finish this section 443 f = file->aux; 444 off = r->ifcall.offset; 445 if (r->d.mode & DMAPPEND) off = f->nsize; 446 nsize = off + r->ifcall.count; 447 if (nsize > f->nsize) f->nsize = nsize; 448 f->data = realloc(f->data, f->nsize); 449 memmove(f->data + off, r->ifcall.data, r->ifcall.count); 450 r->ofcall.count = r->ifcall.count; 451 rstr = nil; 452 break; 453 case NCTL: 454 buf = mallocz(r->ifcall.count + 1, 1); 455 memmove(buf, r->ifcall.data, r->ifcall.count); 456 rstr = nctlparse(file, buf); 457 free(buf); 458 r->ofcall.count = r->ifcall.count; 459 break; 460 default: 461 rstr = "permission denied"; 462 } 463 respond(r, rstr); 464 } 465 466 void 467 fscreate(Req *r) 468 { 469 Node *node; 470 Finf *rf; 471 Fusr *f; 472 rf = r->fid->aux; 473 if (rf->type != NODE) { 474 respond(r, "permission denied"); 475 return; 476 } 477 node = rf->aux; 478 f = newfile(r->ifcall.name); 479 f->node = node; 480 stackpush(&(node->files), f); 481 r->fid->qid = f->finf->qid; 482 r->ofcall.qid = r->fid->qid; 483 r->fid->aux = f->finf; 484 respond(r, nil); 485 } 486 487 void 488 fsremove(Req *r) 489 { 490 Finf *f; 491 f = r->fid->aux; 492 if (f->type != USER) { 493 respond(r, "remove prohibited"); 494 return; 495 } 496 f->type = REMV; 497 498 respond(r, nil); 499 } 500 501 char* 502 fsclone(Fid *oldfid, Fid *newfid) 503 { 504 newfid->aux = oldfid->aux; 505 return nil; 506 } 507 508 char* 509 fswalk1(Fid *fid, char *name, Qid *qid) 510 { 511 void *p; 512 char *chp; 513 uvlong id; 514 Finf *f, *nf; 515 f = fid->aux; 516 nf = nil; 517 switch (f->type){ 518 case ROOT: 519 if (strcmp("new", name) == 0) { 520 nf = fnew; 521 break; 522 } 523 id = strtoull(name, &chp, 10); 524 // TODO: check if parsed correctly 525 p = gettree(trees, id); 526 if (p == nil) return "file does not exist"; 527 nf = ((DTree*)p)->finf; 528 break; 529 case TREE: 530 if (strcmp("..", name) == 0) { 531 nf = rootf; 532 break; 533 } 534 if (strcmp("new", name) == 0) { 535 nf = ((DTree*)f->aux)->fnew; 536 break; 537 } 538 id = strtoull(name, &chp, 10); 539 // TODO: check if parsed correctly 540 p = getnode(f->aux, id); 541 if (p == nil) return "file does not exist"; 542 nf = ((Node*)p)->finf; 543 break; 544 case NODE: 545 if (strcmp("..", name) == 0) { 546 nf = ((Node*)f->aux)->tree->finf; 547 break; 548 } 549 if (strcmp("ctl", name) == 0) { 550 nf = ((Node*)f->aux)->fctl; 551 break; 552 } 553 p = getfile(f->aux, name); 554 if (p == nil) return "file does not exist"; 555 nf = ((Fusr*)p)->finf; 556 break; 557 case NNEW: 558 case TNEW: 559 case NCTL: 560 case USER: 561 case REMV: 562 return "walk on file, what?"; 563 break; 564 default: 565 sysfatal("fswalk1: unknown file type %d", f->type); 566 } 567 if (nf == nil) return "fswalk1: nf = nil"; 568 *qid = nf->qid; 569 fid->qid = *qid; 570 fid->aux = nf; 571 572 return nil; 573 } 574 575 void 576 fsstat(Req *r) 577 { 578 Finf *f; 579 f = r->fid->aux; 580 nulldir(&r->d); 581 r->d.type = L'M'; 582 r->d.dev = 1; 583 r->d.length = 0; 584 r->d.atime = time(0); 585 r->d.mtime = time(0); 586 r->d.uid = strdup("domfs"); 587 r->d.gid = strdup("domfs"); 588 r->d.muid = strdup(""); 589 r->d.qid = f->qid; 590 591 switch (f->type) { 592 case ROOT: 593 r->d.name = strdup("/"); 594 r->d.mode = 0777|DMDIR; 595 break; 596 case TREE: 597 r->d.name = smprint("%ulld", ((DTree*)f->aux)->id); 598 r->d.mode = 0777|DMDIR; 599 break; 600 case NODE: 601 r->d.name = smprint("%ulld", ((Node*)f->aux)->id); 602 r->d.mode = 0777|DMDIR; 603 break; 604 case USER: 605 r->d.name = strdup(((Fusr*)f->aux)->name); 606 r->d.mode = 0666; 607 break; 608 case REMV: 609 r->d.name = strdup(((Fusr*)f->aux)->name); 610 r->d.mode = -1; 611 break; 612 case NCTL: 613 r->d.name = strdup("ctl"); 614 r->d.mode = 0666; 615 break; 616 case TNEW: 617 r->d.name = strdup("new"); 618 r->d.mode = 0666; 619 break; 620 case NNEW: 621 r->d.name = strdup("new"); 622 r->d.mode = 0666; 623 break; 624 default: 625 sysfatal("fsstat: unknown file type %d", f->type); 626 } 627 628 respond(r, nil); 629 } 630 631 void 632 fsdestroyfid(Fid *fid) 633 { 634 /* 635 * TODO: this whole func is probably not correct; 636 * 9p(2) manpage's description of remove func recommends tracking fids that 637 * access file to be deleted, but I am not sure how to do it properly. 638 */ 639 640 Finf *f; 641 Fusr *fu; 642 f = fid->aux; 643 if(f != nil && f->type == REMV) { 644 fu = f->aux; 645 free(fu->data); 646 free(fu->name); 647 fu->nsize = 0; 648 stackremv(&(fu->node->files), fu); 649 free(fu); 650 stackremv(&files, &f); 651 free(f); 652 } 653 } 654 655 void 656 usage(void) 657 { 658 fprint(2, "usage %s [-D][-m /mnt/dom][-s service]\n", argv0); 659 exits("usage"); 660 } 661 662 void 663 main(int argc, char **argv) 664 { 665 char *srv, *mtpt; 666 srv = nil; 667 mtpt = "/mnt/dom"; 668 669 ARGBEGIN { 670 case 'm': 671 mtpt = EARGF(usage()); 672 break; 673 case 's': 674 srv = EARGF(usage()); 675 break; 676 case 'D': 677 chatty9p++; 678 break; 679 default: 680 usage(); 681 } ARGEND 682 683 rootf = newfinf(ROOT, &trees); 684 stackpush(&files, rootf); 685 fnew = newfinf(TNEW, &rootf); 686 stackpush(&files, fnew); 687 688 Srv fs = { 689 .attach = fsattach, 690 .read = fsread, 691 .write = fswrite, 692 .clone = fsclone, 693 .walk1 = fswalk1, 694 .stat = fsstat, 695 .create = fscreate, 696 .remove = fsremove, 697 .destroyfid = fsdestroyfid, 698 }; 699 700 postmountsrv(&fs, srv, mtpt, MREPL); 701 }