|
|
1.1 ! root 1: /* ! 2: ! 3: Copyright 1990,1991,1992 Eric R. Smith. All rights reserved. ! 4: ! 5: */ ! 6: ! 7: ! 8: ! 9: /* ! 10: ! 11: * various file system interface things ! 12: ! 13: */ ! 14: ! 15: ! 16: ! 17: #include "mint.h" ! 18: ! 19: ! 20: ! 21: FILESYS *active_fs; ! 22: ! 23: FILESYS *drives[NUM_DRIVES]; ! 24: ! 25: ! 26: ! 27: FILEPTR *flist; /* a list of free file pointers */ ! 28: ! 29: ! 30: ! 31: char follow_links[1]; /* dummy "name" used as a parameter to path2cookie */ ! 32: ! 33: ! 34: ! 35: /* vector of valid drives, according to GEMDOS */ ! 36: ! 37: /* note that this isn't necessarily the same as what the BIOS thinks of ! 38: ! 39: * as valid ! 40: ! 41: */ ! 42: ! 43: long dosdrvs; ! 44: ! 45: ! 46: ! 47: /* ! 48: ! 49: * Initialize a specific drive. This is called whenever a new drive ! 50: ! 51: * is accessed, or when media change occurs on an old drive. ! 52: ! 53: * Assumption: at this point, active_fs is a valid pointer ! 54: ! 55: * to a list of file systems. ! 56: ! 57: */ ! 58: ! 59: ! 60: ! 61: /* table of processes holding locks on drives */ ! 62: ! 63: extern PROC *dlockproc[]; /* in dosdir.c */ ! 64: ! 65: ! 66: ! 67: void ! 68: ! 69: init_drive(i) ! 70: ! 71: int i; ! 72: ! 73: { ! 74: ! 75: long r; ! 76: ! 77: FILESYS *fs; ! 78: ! 79: fcookie root_dir; ! 80: ! 81: ! 82: ! 83: TRACE("init_drive(%c)", i+'A'); ! 84: ! 85: ! 86: ! 87: drives[i] = 0; /* no file system */ ! 88: ! 89: if (i >= 0 && i < NUM_DRIVES) { ! 90: ! 91: if (dlockproc[i]) return; ! 92: ! 93: } ! 94: ! 95: ! 96: ! 97: for (fs = active_fs; fs; fs = fs->next) { ! 98: ! 99: r = (*fs->root)(i, &root_dir); ! 100: ! 101: if (r == 0) { ! 102: ! 103: drives[i] = root_dir.fs; ! 104: ! 105: break; ! 106: ! 107: } ! 108: ! 109: } ! 110: ! 111: } ! 112: ! 113: ! 114: ! 115: /* ! 116: ! 117: * initialize the file system ! 118: ! 119: */ ! 120: ! 121: ! 122: ! 123: #define NUMFPS 40 /* initial number of file pointers */ ! 124: ! 125: ! 126: ! 127: void ! 128: ! 129: init_filesys() ! 130: ! 131: { ! 132: ! 133: static FILEPTR initial[NUMFPS+1]; ! 134: ! 135: long drv; ! 136: ! 137: int i; ! 138: ! 139: extern FILESYS tos_filesys, bios_filesys, pipe_filesys, ! 140: ! 141: proc_filesys, uni_filesys; ! 142: ! 143: ! 144: ! 145: /* get the vector of connected GEMDOS drives */ ! 146: ! 147: dosdrvs = Dsetdrv(Dgetdrv()) | drvmap(); ! 148: ! 149: ! 150: ! 151: /* set up some initial file pointers */ ! 152: ! 153: for (i = 0; i < NUMFPS; i++) { ! 154: ! 155: initial[i].devinfo = (ulong) (&initial[i+1]); ! 156: ! 157: } ! 158: ! 159: initial[NUMFPS].devinfo = 0; ! 160: ! 161: flist = initial; ! 162: ! 163: ! 164: ! 165: /* set up the file systems */ ! 166: ! 167: tos_filesys.next = 0; ! 168: ! 169: bios_filesys.next = &tos_filesys; ! 170: ! 171: pipe_filesys.next = &bios_filesys; ! 172: ! 173: proc_filesys.next = &pipe_filesys; ! 174: ! 175: uni_filesys.next = &proc_filesys; ! 176: ! 177: ! 178: ! 179: active_fs = &uni_filesys; ! 180: ! 181: ! 182: ! 183: /* initialize the BIOS file system */ ! 184: ! 185: biosfs_init(); ! 186: ! 187: ! 188: ! 189: /* initialize the unified file system */ ! 190: ! 191: unifs_init(); ! 192: ! 193: ! 194: ! 195: drv = dosdrvs | PSEUDODRVS; ! 196: ! 197: ! 198: ! 199: #if 0 ! 200: ! 201: /* now run through the systems and see who's interested in what drives */ ! 202: ! 203: /* THIS IS NOW DONE AUTOMAGICALLY IN path2cookie */ ! 204: ! 205: for (i = 0; i < NUM_DRIVES; i++) { ! 206: ! 207: if ( drv & (1L << i) ) ! 208: ! 209: init_drive(i); ! 210: ! 211: } ! 212: ! 213: #endif ! 214: ! 215: } ! 216: ! 217: ! 218: ! 219: /* ! 220: ! 221: * load file systems from disk ! 222: ! 223: * this routine is called after process 0 is set up, but before any user ! 224: ! 225: * processes are run ! 226: ! 227: * ! 228: ! 229: * NOTE that a number of directory changes take place here: we look first ! 230: ! 231: * in the current directory, then in the directory \mint, and finally ! 232: ! 233: * the d_lock() calls force us into the root directory. ! 234: ! 235: */ ! 236: ! 237: ! 238: ! 239: typedef FILESYS * (*FSFUNC) P_((struct kerinfo *)); ! 240: ! 241: ! 242: ! 243: void ! 244: ! 245: load_filesys() ! 246: ! 247: { ! 248: ! 249: long r; ! 250: ! 251: BASEPAGE *b; ! 252: ! 253: FILESYS *fs; ! 254: ! 255: FSFUNC initf; ! 256: ! 257: static DTABUF dta; ! 258: ! 259: int i; ! 260: ! 261: extern struct kerinfo kernelinfo; /* in main.c */ ! 262: ! 263: #define NPATHS 2 ! 264: ! 265: static const char *paths[NPATHS] = {"", "\\mint"}; ! 266: ! 267: ! 268: ! 269: curproc->dta = &dta; ! 270: ! 271: ! 272: ! 273: for (i = 0; i < NPATHS; i++) { ! 274: ! 275: if (*paths[i]) ! 276: ! 277: d_setpath(paths[i]); ! 278: ! 279: r = f_sfirst("*.xfs", 0); ! 280: ! 281: while (r == 0) { ! 282: ! 283: b = (BASEPAGE *)p_exec(3, dta.dta_name, (char *)"", (char *)0); ! 284: ! 285: if ( ((long)b) < 0 ) { ! 286: ! 287: DEBUG("Error loading file system %s", dta.dta_name); ! 288: ! 289: continue; ! 290: ! 291: } ! 292: ! 293: /* we leave a little bit of slop at the end of the loaded stuff */ ! 294: ! 295: m_shrink(0, (virtaddr)b, 512 + b->p_tlen + b->p_dlen + b->p_blen); ! 296: ! 297: initf = (FSFUNC)b->p_tbase; ! 298: ! 299: fs = (*initf)(&kernelinfo); ! 300: ! 301: TRACE("initializing %s", dta.dta_name); ! 302: ! 303: ! 304: ! 305: if (fs) { ! 306: ! 307: TRACE("%s loaded OK", dta.dta_name); ! 308: ! 309: fs->next = active_fs; ! 310: ! 311: active_fs = fs; ! 312: ! 313: } else { ! 314: ! 315: DEBUG("%s returned null", dta.dta_name); ! 316: ! 317: } ! 318: ! 319: r = f_snext(); ! 320: ! 321: } ! 322: ! 323: } ! 324: ! 325: ! 326: ! 327: /* here, we invalidate all old drives EXCEPT for ones we're already using (at ! 328: ! 329: * this point, only the bios devices should be open) ! 330: ! 331: * this gives newly loaded file systems a chance to replace the ! 332: ! 333: * default tosfs.c ! 334: ! 335: */ ! 336: ! 337: for (i = 0; i < NUM_DRIVES; i++) { ! 338: ! 339: if (d_lock(1, i) == 0) /* lock if possible */ ! 340: ! 341: d_lock(0, i); /* and then unlock */ ! 342: ! 343: } ! 344: ! 345: } ! 346: ! 347: ! 348: ! 349: void ! 350: ! 351: close_filesys() ! 352: ! 353: { ! 354: ! 355: PROC *p; ! 356: ! 357: FILEPTR *f; ! 358: ! 359: int i; ! 360: ! 361: ! 362: ! 363: TRACE("close_filesys"); ! 364: ! 365: /* close every open file */ ! 366: ! 367: for (p = proclist; p; p = p->gl_next) { ! 368: ! 369: for (i = MIN_HANDLE; i < MAX_OPEN; i++) { ! 370: ! 371: if ( (f = p->handle[i]) != 0) { ! 372: ! 373: if (p->wait_q == TSR_Q || p->wait_q == ZOMBIE_Q) ! 374: ! 375: ALERT("Open file for dead process?"); ! 376: ! 377: do_pclose(p, f); ! 378: ! 379: } ! 380: ! 381: } ! 382: ! 383: } ! 384: ! 385: } ! 386: ! 387: ! 388: ! 389: /* ! 390: ! 391: * "media change" routine: called when a media change is detected on device ! 392: ! 393: * d, which may or may not be a BIOS device. All handles associated with ! 394: ! 395: * the device are closed, and all directories invalidated. This routine ! 396: ! 397: * does all the dirty work, and is called automatically when ! 398: ! 399: * disk_changed detects a media change. ! 400: ! 401: */ ! 402: ! 403: ! 404: ! 405: void ! 406: ! 407: changedrv(d) ! 408: ! 409: unsigned d; ! 410: ! 411: { ! 412: ! 413: PROC *p; ! 414: ! 415: int i; ! 416: ! 417: FILEPTR *f; ! 418: ! 419: FILESYS *fs; ! 420: ! 421: DIR *dirh; ! 422: ! 423: fcookie dir; ! 424: ! 425: int warned = (d & 0xf000) == PROC_BASE_DEV; ! 426: ! 427: int r; ! 428: ! 429: ! 430: ! 431: /* re-initialize the device, if it was a BIOS device */ ! 432: ! 433: if (d < NUM_DRIVES) { ! 434: ! 435: fs = drives[d]; ! 436: ! 437: if (fs) { ! 438: ! 439: (void)(*fs->dskchng)(d); ! 440: ! 441: } ! 442: ! 443: init_drive(d); ! 444: ! 445: } ! 446: ! 447: ! 448: ! 449: for (p = proclist; p; p = p->gl_next) { ! 450: ! 451: /* invalidate all open files on this device */ ! 452: ! 453: for (i = MIN_HANDLE; i < MAX_OPEN; i++) { ! 454: ! 455: if (((f = p->handle[i]) != 0) && (f->fc.dev == d)) { ! 456: ! 457: if (!warned) { ! 458: ! 459: ALERT( ! 460: ! 461: "Files were open on a changed drive (0x%x)!", d); ! 462: ! 463: warned++; ! 464: ! 465: } ! 466: ! 467: ! 468: ! 469: /* we set f->dev to NULL to indicate to do_pclose that this is an ! 470: ! 471: * emergency close, and that it shouldn't try to make any ! 472: ! 473: * calls to the device driver since the file has gone away ! 474: ! 475: */ ! 476: ! 477: f->dev = NULL; ! 478: ! 479: (void)do_pclose(p, f); ! 480: ! 481: p->handle[i] = 0; ! 482: ! 483: } ! 484: ! 485: } ! 486: ! 487: ! 488: ! 489: /* terminate any active directory searches on the drive */ ! 490: ! 491: /* BUG: This handles only Fsfirst/Fsnext searches! */ ! 492: ! 493: for (i = 0; i < NUM_SEARCH; i++) { ! 494: ! 495: dirh = &curproc->srchdir[i]; ! 496: ! 497: if (dirh->fc.fs && dirh->fc.dev == d) { ! 498: ! 499: dirh->fc.fs = 0; ! 500: ! 501: curproc->srchdta[i] = 0; ! 502: ! 503: } ! 504: ! 505: } ! 506: ! 507: ! 508: ! 509: if (d >= NUM_DRIVES) continue; ! 510: ! 511: ! 512: ! 513: /* change any active directories on the device to the (new) root */ ! 514: ! 515: fs = drives[d]; ! 516: ! 517: if (fs) { ! 518: ! 519: r = (*fs->root)(d, &dir); ! 520: ! 521: if (r != E_OK) dir.fs = 0; ! 522: ! 523: } else { ! 524: ! 525: dir.fs = 0; dir.dev = d; ! 526: ! 527: } ! 528: ! 529: ! 530: ! 531: for (i = 0; i < NUM_DRIVES; i++) { ! 532: ! 533: if (p->root[i].dev == d) ! 534: ! 535: p->root[i] = dir; ! 536: ! 537: if (p->curdir[i].dev == d) ! 538: ! 539: p->curdir[i] = dir; ! 540: ! 541: } ! 542: ! 543: } ! 544: ! 545: } ! 546: ! 547: ! 548: ! 549: /* ! 550: ! 551: * check for media change: if the drive has changed, call changedrv to ! 552: ! 553: * invalidate any open files and file handles associated with it, and ! 554: ! 555: * call the file system's media change routine. ! 556: ! 557: * returns: 0 if no change, 1 if change ! 558: ! 559: */ ! 560: ! 561: ! 562: ! 563: int ! 564: ! 565: disk_changed(d) ! 566: ! 567: int d; ! 568: ! 569: { ! 570: ! 571: short r; ! 572: ! 573: FILESYS *fs; ! 574: ! 575: static char tmpbuf[8192]; ! 576: ! 577: ! 578: ! 579: /* for now, only check BIOS devices */ ! 580: ! 581: if (d < 0 || d >= NUM_DRIVES) ! 582: ! 583: return 0; ! 584: ! 585: ! 586: ! 587: /* has the drive been initialized yet? If not, then initialize it and return ! 588: ! 589: * "no change" ! 590: ! 591: */ ! 592: ! 593: if (!(fs = drives[d])) { ! 594: ! 595: TRACE("drive %c not yet initialized", d+'A'); ! 596: ! 597: changedrv(d); ! 598: ! 599: return 0; ! 600: ! 601: } ! 602: ! 603: ! 604: ! 605: /* We have to do this stuff no matter what, because someone may have installed ! 606: ! 607: * vectors to force a media change... ! 608: ! 609: * PROBLEM: AHDI may get upset if the drive isn't valid. ! 610: ! 611: * SOLUTION: don't change the default PSEUDODRIVES setting! ! 612: ! 613: */ ! 614: ! 615: r = mediach(d); ! 616: ! 617: if (r == 1) { /* drive _may_ have changed */ ! 618: ! 619: r = rwabs(0, tmpbuf, 1, 0, d, 0L); /* check the BIOS */ ! 620: ! 621: if (r != E_CHNG) { /* nope, no change */ ! 622: ! 623: return 0; ! 624: ! 625: } ! 626: ! 627: r = 2; /* drive was definitely changed */ ! 628: ! 629: } ! 630: ! 631: if (r == 2) { ! 632: ! 633: fs = drives[d]; /* get filesystem associated with drive */ ! 634: ! 635: if ((*fs->dskchng)(d)) { /* does the fs agree that it changed? */ ! 636: ! 637: changedrv(d); /* yes -- do the change */ ! 638: ! 639: return 1; ! 640: ! 641: } ! 642: ! 643: } ! 644: ! 645: return 0; ! 646: ! 647: } ! 648: ! 649: ! 650: ! 651: /* ! 652: ! 653: * routines for parsing path names ! 654: ! 655: */ ! 656: ! 657: ! 658: ! 659: char temp1[PATH_MAX]; /* temporary storage for file names */ ! 660: ! 661: ! 662: ! 663: #define DIRSEP(p) ((p) == '\\') ! 664: ! 665: ! 666: ! 667: /* ! 668: ! 669: * relpath2cookie converts a TOS file name into a file cookie representing ! 670: ! 671: * the directory the file resides in, and a character string representing ! 672: ! 673: * the name of the file in that directory. The character string is ! 674: ! 675: * copied into the "lastname" array. If lastname is NULL, then the cookie ! 676: ! 677: * returned actually represents the file, instead of just the directory ! 678: ! 679: * the file is in. ! 680: ! 681: * ! 682: ! 683: * note that lastname, if non-null, should be big enough to contain all the ! 684: ! 685: * characters in "path", since if the file system doesn't want the kernel ! 686: ! 687: * to do path name parsing we may end up just copying path to lastname ! 688: ! 689: * and returning the current or root directory, as appropriate ! 690: ! 691: * ! 692: ! 693: * "relto" is the directory relative to which the search should start. ! 694: ! 695: * if you just want the current directory, use path2cookie instead. ! 696: ! 697: * ! 698: ! 699: * "depth" is used to control recursion in symbolic links; if it exceeds ! 700: ! 701: * MAX_LINKS, we return ELOOP. ! 702: ! 703: * ! 704: ! 705: * N.B.: "depth" is also overloaded to control whether drive letter ! 706: ! 707: * interpretation is performed; if drive == 0, it is assumed that ! 708: ! 709: * drive letters should _not_ be interpreted; if drive > 0, it ! 710: ! 711: * is assumed that they should be, since we are in this case following ! 712: ! 713: * a symbolic link. ! 714: ! 715: */ ! 716: ! 717: ! 718: ! 719: #define MAX_LINKS 4 ! 720: ! 721: ! 722: ! 723: long ! 724: ! 725: relpath2cookie(relto, path, lastname, res, depth) ! 726: ! 727: fcookie *relto; ! 728: ! 729: const char *path; ! 730: ! 731: char *lastname; ! 732: ! 733: fcookie *res; ! 734: ! 735: int depth; ! 736: ! 737: { ! 738: ! 739: static fcookie dir; ! 740: ! 741: int drv; ! 742: ! 743: int len; ! 744: ! 745: char c, *s; ! 746: ! 747: XATTR xattr; ! 748: ! 749: static char newpath[16] = "U:\\DEV\\"; ! 750: ! 751: char temp2[PATH_MAX]; ! 752: ! 753: char linkstuff[PATH_MAX]; ! 754: ! 755: long r = 0; ! 756: ! 757: ! 758: ! 759: /* dolast: 0 == return a cookie for the directory the file is in ! 760: ! 761: * 1 == return a cookie for the file itself, don't follow links ! 762: ! 763: * 2 == return a cookie for whatever the file points at ! 764: ! 765: */ ! 766: ! 767: int dolast = 0; ! 768: ! 769: int i = 0; ! 770: ! 771: ! 772: ! 773: TRACE("relpath2cookie(%s)", path); ! 774: ! 775: ! 776: ! 777: if (depth > MAX_LINKS) return ELOOP; ! 778: ! 779: ! 780: ! 781: if (!lastname) { ! 782: ! 783: dolast = 1; ! 784: ! 785: lastname = temp2; ! 786: ! 787: } else if (lastname == follow_links) { ! 788: ! 789: dolast = 2; ! 790: ! 791: lastname = temp2; ! 792: ! 793: } ! 794: ! 795: ! 796: ! 797: *lastname = 0; ! 798: ! 799: ! 800: ! 801: /* special cases: CON:, AUX:, etc. should be converted to U:\DEV\CON, ! 802: ! 803: * U:\DEV\AUX, etc. ! 804: ! 805: */ ! 806: ! 807: if (strlen(path) == 4 && path[3] == ':') { ! 808: ! 809: strncpy(newpath+7, path, 3); ! 810: ! 811: path = newpath; ! 812: ! 813: } ! 814: ! 815: ! 816: ! 817: /* first, check for a drive letter */ ! 818: ! 819: /* BUG: a '\' at the start of a symbolic link is relative to the current ! 820: ! 821: * drive of the process, not the drive the link is located on ! 822: ! 823: */ ! 824: ! 825: if (path[1] == ':' && depth > 0) { ! 826: ! 827: c = path[0]; ! 828: ! 829: if (c >= 'a' && c <= 'z') ! 830: ! 831: drv = c - 'a'; ! 832: ! 833: else if (c >= 'A' && c <= 'Z') ! 834: ! 835: drv = c - 'A'; ! 836: ! 837: else ! 838: ! 839: goto nodrive; ! 840: ! 841: path += 2; ! 842: ! 843: i = 1; /* remember that we saw a drive letter */ ! 844: ! 845: } else { ! 846: ! 847: nodrive: ! 848: ! 849: drv = curproc->curdrv; ! 850: ! 851: } ! 852: ! 853: ! 854: ! 855: /* see if the path is rooted from '\\' */ ! 856: ! 857: if (DIRSEP(*path)) { ! 858: ! 859: while(DIRSEP(*path))path++; ! 860: ! 861: dir = curproc->root[drv]; ! 862: ! 863: } else { ! 864: ! 865: if (i) { /* an explicit drive letter was given */ ! 866: ! 867: dir = curproc->curdir[drv]; ! 868: ! 869: } ! 870: ! 871: else ! 872: ! 873: dir = *relto; ! 874: ! 875: } ! 876: ! 877: ! 878: ! 879: if (!dir.fs) { ! 880: ! 881: changedrv(dir.dev); ! 882: ! 883: dir = curproc->root[drv]; ! 884: ! 885: } ! 886: ! 887: ! 888: ! 889: if (!dir.fs) { ! 890: ! 891: DEBUG("path2cookie: no file system"); ! 892: ! 893: return EDRIVE; ! 894: ! 895: } ! 896: ! 897: ! 898: ! 899: *res = dir; ! 900: ! 901: if (!*path) { /* nothing more to do */ ! 902: ! 903: return 0; ! 904: ! 905: } ! 906: ! 907: ! 908: ! 909: /* here's where we come when we've gone across a mount point */ ! 910: ! 911: ! 912: ! 913: restart_mount: ! 914: ! 915: ! 916: ! 917: /* see if there has been a disk change; if so, return E_CHNG. ! 918: ! 919: * path2cookie will restart the search automatically; other functions ! 920: ! 921: * that call relpath2cookie directly will have to fail gracefully ! 922: ! 923: */ ! 924: ! 925: if (disk_changed(dir.dev)) { ! 926: ! 927: return E_CHNG; ! 928: ! 929: } ! 930: ! 931: ! 932: ! 933: if (dir.fs->fsflags & FS_KNOPARSE) { ! 934: ! 935: if (!dolast) { ! 936: ! 937: strncpy(lastname, path, PATH_MAX-1); ! 938: ! 939: lastname[PATH_MAX - 1] = 0; ! 940: ! 941: r = 0; ! 942: ! 943: } else { ! 944: ! 945: r = (*dir.fs->lookup)(&dir, path, res); ! 946: ! 947: } ! 948: ! 949: goto check_for_mount; ! 950: ! 951: } ! 952: ! 953: ! 954: ! 955: /* parse all but (possibly) the last component of the path name */ ! 956: ! 957: ! 958: ! 959: for(;;) { ! 960: ! 961: /* if nothing left in path, and we don't care about links, ! 962: ! 963: * then we're finished ! 964: ! 965: */ ! 966: ! 967: if (dolast < 2 && !*path) { ! 968: ! 969: dir = *res; ! 970: ! 971: break; ! 972: ! 973: } ! 974: ! 975: /* first, check to see if we're allowed to read this link/directory ! 976: ! 977: * NOTE: at this point, "res" contains the new 'directory', and ! 978: ! 979: * "dir" contains the old directory we were in (in case we need ! 980: ! 981: * to call relpath2cookie on a link) ! 982: ! 983: */ ! 984: ! 985: r = (res->fs->getxattr)(res, &xattr); ! 986: ! 987: if (r != 0) { ! 988: ! 989: DEBUG("path2cookie: couldn't get file attributes"); ! 990: ! 991: break; ! 992: ! 993: } ! 994: ! 995: /* if the "directory" is a link, follow it */ ! 996: ! 997: i = depth; ! 998: ! 999: while ( (xattr.mode & S_IFMT) == S_IFLNK ) { ! 1000: ! 1001: if (i++ > MAX_LINKS) ! 1002: ! 1003: return ELOOP; ! 1004: ! 1005: r = (res->fs->readlink)(res, linkstuff, PATH_MAX); ! 1006: ! 1007: if (r) { ! 1008: ! 1009: DEBUG("error reading symbolic link"); ! 1010: ! 1011: break; ! 1012: ! 1013: } ! 1014: ! 1015: r = relpath2cookie(&dir, linkstuff, follow_links, res, ! 1016: ! 1017: depth+1); ! 1018: ! 1019: if (r) { ! 1020: ! 1021: DEBUG("error following symbolic link"); ! 1022: ! 1023: break; ! 1024: ! 1025: } ! 1026: ! 1027: (void)(res->fs->getxattr)(res, &xattr); ! 1028: ! 1029: } ! 1030: ! 1031: ! 1032: ! 1033: /* if there's nothing left in the path, we can break here */ ! 1034: ! 1035: if (!*path) { ! 1036: ! 1037: dir = *res; ! 1038: ! 1039: break; ! 1040: ! 1041: } ! 1042: ! 1043: ! 1044: ! 1045: /* the "directory" had better, in fact, be a directory */ ! 1046: ! 1047: if ( (xattr.mode & S_IFMT) != S_IFDIR ) { ! 1048: ! 1049: return EPTHNF; ! 1050: ! 1051: } ! 1052: ! 1053: /* and we had better have search permission to it */ ! 1054: ! 1055: if (denyaccess(&xattr, S_IXOTH)) { ! 1056: ! 1057: DEBUG("search permission in directory denied"); ! 1058: ! 1059: return EPTHNF; ! 1060: ! 1061: } ! 1062: ! 1063: ! 1064: ! 1065: dir = *res; ! 1066: ! 1067: ! 1068: ! 1069: /* next, peel off the next name in the path */ ! 1070: ! 1071: len = 0; ! 1072: ! 1073: s = lastname; ! 1074: ! 1075: c = *path; ! 1076: ! 1077: while (c && !DIRSEP(c)) { ! 1078: ! 1079: if (len++ < PATH_MAX) ! 1080: ! 1081: *s++ = c; ! 1082: ! 1083: c = *++path; ! 1084: ! 1085: } ! 1086: ! 1087: *s = 0; ! 1088: ! 1089: while(DIRSEP(*path))path++; ! 1090: ! 1091: ! 1092: ! 1093: /* if there are no more names in the path, then we may be done */ ! 1094: ! 1095: if (dolast == 0 && !*path) ! 1096: ! 1097: break; ! 1098: ! 1099: ! 1100: ! 1101: r = (*dir.fs->lookup)(&dir, lastname, res); ! 1102: ! 1103: if (r) { /* error? */ ! 1104: ! 1105: DEBUG("path2cookie: lookup returned %ld", r); ! 1106: ! 1107: dir = *res; ! 1108: ! 1109: break; ! 1110: ! 1111: } ! 1112: ! 1113: } ! 1114: ! 1115: ! 1116: ! 1117: check_for_mount: ! 1118: ! 1119: ! 1120: ! 1121: if (r == EMOUNT) { /* hmmm... a ".." at a mount point, maybe */ ! 1122: ! 1123: fcookie mounteddir; ! 1124: ! 1125: r = (*dir.fs->root)(dir.dev, &mounteddir); ! 1126: ! 1127: if (r == 0 && drv == UNIDRV) { ! 1128: ! 1129: if (dir.fs == mounteddir.fs && ! 1130: ! 1131: dir.index == mounteddir.index && ! 1132: ! 1133: dir.dev == mounteddir.dev) { ! 1134: ! 1135: *res = dir = curproc->root[UNIDRV]; ! 1136: ! 1137: TRACE("path2cookie: restarting from mount point"); ! 1138: ! 1139: goto restart_mount; ! 1140: ! 1141: } ! 1142: ! 1143: } ! 1144: ! 1145: else r = 0; ! 1146: ! 1147: } ! 1148: ! 1149: ! 1150: ! 1151: return r; ! 1152: ! 1153: } ! 1154: ! 1155: ! 1156: ! 1157: #define MAX_TRYS 8 ! 1158: ! 1159: ! 1160: ! 1161: long ! 1162: ! 1163: path2cookie(path, lastname, res) ! 1164: ! 1165: const char *path; ! 1166: ! 1167: char *lastname; ! 1168: ! 1169: fcookie *res; ! 1170: ! 1171: { ! 1172: ! 1173: fcookie *dir; ! 1174: ! 1175: long r; ! 1176: ! 1177: /* AHDI sometimes will keep insisting that a media change occured; ! 1178: ! 1179: * we limit the number or retrys to avoid hanging the system ! 1180: ! 1181: */ ! 1182: ! 1183: int trycnt = 0; ! 1184: ! 1185: ! 1186: ! 1187: dir = &curproc->curdir[curproc->curdrv]; ! 1188: ! 1189: ! 1190: ! 1191: do { ! 1192: ! 1193: /* NOTE: depth == 1 is necessary; see the comments before relpath2cookie */ ! 1194: ! 1195: r = relpath2cookie(dir, path, lastname, res, 1); ! 1196: ! 1197: if (r == E_CHNG) ! 1198: ! 1199: DEBUG("path2cookie: restarting due to media change"); ! 1200: ! 1201: } while (r == E_CHNG && trycnt++ < MAX_TRYS); ! 1202: ! 1203: ! 1204: ! 1205: return r; ! 1206: ! 1207: } ! 1208: ! 1209: ! 1210: ! 1211: /* ! 1212: ! 1213: * new_fileptr, dispose_fileptr: allocate (deallocate) a file pointer ! 1214: ! 1215: */ ! 1216: ! 1217: ! 1218: ! 1219: FILEPTR * ! 1220: ! 1221: new_fileptr() ! 1222: ! 1223: { ! 1224: ! 1225: FILEPTR *f; ! 1226: ! 1227: ! 1228: ! 1229: if ((f = flist)) { ! 1230: ! 1231: flist = f->next; ! 1232: ! 1233: f->next = 0; ! 1234: ! 1235: return f; ! 1236: ! 1237: } ! 1238: ! 1239: f = kmalloc(SIZEOF(FILEPTR)); ! 1240: ! 1241: if (!f) { ! 1242: ! 1243: FATAL("new_fileptr: out of memory"); ! 1244: ! 1245: } ! 1246: ! 1247: else { ! 1248: ! 1249: f->next = 0; ! 1250: ! 1251: } ! 1252: ! 1253: return f; ! 1254: ! 1255: } ! 1256: ! 1257: ! 1258: ! 1259: void ! 1260: ! 1261: dispose_fileptr(f) ! 1262: ! 1263: FILEPTR *f; ! 1264: ! 1265: { ! 1266: ! 1267: if (f->links != 0) { ! 1268: ! 1269: FATAL("dispose_fileptr: f->links == %d", f->links); ! 1270: ! 1271: } ! 1272: ! 1273: f->next = flist; ! 1274: ! 1275: flist = f; ! 1276: ! 1277: } ! 1278: ! 1279: ! 1280: ! 1281: /* ! 1282: ! 1283: * denyshare(list, f): "list" points at the first FILEPTR in a ! 1284: ! 1285: * chained list of open FILEPTRS referring to the same file; ! 1286: ! 1287: * f is a newly opened FILEPTR. Every FILEPTR in the given list is ! 1288: ! 1289: * checked to see if its "open" mode (in list->flags) is compatible with ! 1290: ! 1291: * the open mode in f->flags. If not (for example, if f was opened with ! 1292: ! 1293: * a "read" mode and some other file has the O_DENYREAD share mode), ! 1294: ! 1295: * then 1 is returned. If all the open FILEPTRs in the list are ! 1296: ! 1297: * compatible with f, then 0 is returned. ! 1298: ! 1299: * This is not as complicated as it sounds. In practice, just keep a ! 1300: ! 1301: * list of open FILEPTRs attached to each file, and put something like ! 1302: ! 1303: * if (denyshare(thisfile->openfileptrlist, newfileptr)) ! 1304: ! 1305: * return EACCDN; ! 1306: ! 1307: * in the device open routine. ! 1308: ! 1309: */ ! 1310: ! 1311: ! 1312: ! 1313: int ! 1314: ! 1315: denyshare(list, f) ! 1316: ! 1317: FILEPTR *list, *f; ! 1318: ! 1319: { ! 1320: ! 1321: int newrm, newsm; ! 1322: ! 1323: int oldrm, oldsm; ! 1324: ! 1325: int i; ! 1326: ! 1327: ! 1328: ! 1329: newrm = f->flags & O_RWMODE; ! 1330: ! 1331: newsm = f->flags & O_SHMODE; ! 1332: ! 1333: ! 1334: ! 1335: for ( ; list; list = list->next) { ! 1336: ! 1337: oldrm = list->flags & O_RWMODE; ! 1338: ! 1339: oldsm = list->flags & O_SHMODE; ! 1340: ! 1341: if (oldsm == O_DENYW || oldsm == O_DENYRW) { ! 1342: ! 1343: if (newrm != O_RDONLY) { ! 1344: ! 1345: DEBUG("write access denied"); ! 1346: ! 1347: return 1; ! 1348: ! 1349: } ! 1350: ! 1351: } ! 1352: ! 1353: if (oldsm == O_DENYR || oldsm == O_DENYRW) { ! 1354: ! 1355: if (newrm != O_WRONLY) { ! 1356: ! 1357: DEBUG("read access denied"); ! 1358: ! 1359: return 1; ! 1360: ! 1361: } ! 1362: ! 1363: } ! 1364: ! 1365: if (newsm == O_DENYW || newsm == O_DENYRW) { ! 1366: ! 1367: if (oldrm != O_RDONLY) { ! 1368: ! 1369: DEBUG("couldn't deny writes"); ! 1370: ! 1371: return 1; ! 1372: ! 1373: } ! 1374: ! 1375: } ! 1376: ! 1377: if (newsm == O_DENYR || newsm == O_DENYRW) { ! 1378: ! 1379: if (oldrm != O_WRONLY) { ! 1380: ! 1381: DEBUG("couldn't deny reads"); ! 1382: ! 1383: return 1; ! 1384: ! 1385: } ! 1386: ! 1387: } ! 1388: ! 1389: /* If either sm == O_COMPAT, then we check to make sure ! 1390: ! 1391: that the file pointers are owned by the same process (O_COMPAT means ! 1392: ! 1393: "deny access to any other processes"). Also, once a file is opened ! 1394: ! 1395: in compatibility mode, it can't be opened in any other mode. ! 1396: ! 1397: */ ! 1398: ! 1399: if (newsm == O_COMPAT || oldsm == O_COMPAT) { ! 1400: ! 1401: if (newsm != O_COMPAT || oldsm != O_COMPAT) { ! 1402: ! 1403: DEBUG("O_COMPAT mode conflict"); ! 1404: ! 1405: return 1; ! 1406: ! 1407: } ! 1408: ! 1409: for (i = MIN_HANDLE; i < MAX_OPEN; i++) { ! 1410: ! 1411: if (curproc->handle[i] == list) ! 1412: ! 1413: goto found; ! 1414: ! 1415: } ! 1416: ! 1417: /* old file pointer is not open by this process */ ! 1418: ! 1419: DEBUG("O_COMPAT file was opened by another process"); ! 1420: ! 1421: return 1; ! 1422: ! 1423: found: ! 1424: ! 1425: ; /* everything is OK */ ! 1426: ! 1427: } ! 1428: ! 1429: } ! 1430: ! 1431: return 0; ! 1432: ! 1433: } ! 1434: ! 1435: ! 1436: ! 1437: /* ! 1438: ! 1439: * denyaccess(XATTR *xattr, unsigned perm): checks to see if the access ! 1440: ! 1441: * specified by perm (which must be some combination of S_IROTH, S_IWOTH, ! 1442: ! 1443: * and S_IXOTH) should be granted to the current process ! 1444: ! 1445: * on a file with the given extended attributes. Returns 0 if access ! 1446: ! 1447: * by the current process is OK, 1 if not. ! 1448: ! 1449: */ ! 1450: ! 1451: ! 1452: ! 1453: int ! 1454: ! 1455: denyaccess(xattr, perm) ! 1456: ! 1457: XATTR *xattr; ! 1458: ! 1459: unsigned perm; ! 1460: ! 1461: { ! 1462: ! 1463: unsigned mode; ! 1464: ! 1465: ! 1466: ! 1467: /* the super-user can do anything! */ ! 1468: ! 1469: if (curproc->euid == 0) ! 1470: ! 1471: return 0; ! 1472: ! 1473: ! 1474: ! 1475: mode = xattr->mode; ! 1476: ! 1477: if (curproc->euid == xattr->uid) ! 1478: ! 1479: perm = perm << 6; ! 1480: ! 1481: else if (curproc->egid == xattr->gid) ! 1482: ! 1483: perm = perm << 3; ! 1484: ! 1485: if ((mode & perm) != perm) return 1; /* access denied */ ! 1486: ! 1487: return 0; ! 1488: ! 1489: } ! 1490: ! 1491: ! 1492: ! 1493: /* ! 1494: ! 1495: * Checks a lock against a list of locks to see if there is a conflict. ! 1496: ! 1497: * This is a utility to be used by file systems, somewhat like denyshare ! 1498: ! 1499: * above. Returns 0 if there is no conflict, or a pointer to the ! 1500: ! 1501: * conflicting LOCK structure if there is. ! 1502: ! 1503: * ! 1504: ! 1505: * Conflicts occur for overlapping locks if the process id's are ! 1506: ! 1507: * different and if at least one of the locks is a write lock. ! 1508: ! 1509: * ! 1510: ! 1511: * NOTE: we assume before being called that the locks have been converted ! 1512: ! 1513: * so that l_start is absolute. not relative to the current position or ! 1514: ! 1515: * end of file. ! 1516: ! 1517: */ ! 1518: ! 1519: ! 1520: ! 1521: LOCK * ! 1522: ! 1523: denylock(list, lck) ! 1524: ! 1525: LOCK *list, *lck; ! 1526: ! 1527: { ! 1528: ! 1529: LOCK *t; ! 1530: ! 1531: unsigned long tstart, tend; ! 1532: ! 1533: unsigned long lstart, lend; ! 1534: ! 1535: int pid = curproc->pid; ! 1536: ! 1537: int ltype; ! 1538: ! 1539: ! 1540: ! 1541: ltype = lck->l.l_type; ! 1542: ! 1543: lstart = lck->l.l_start; ! 1544: ! 1545: ! 1546: ! 1547: if (lck->l.l_len == 0) ! 1548: ! 1549: lend = 0xffffffff; ! 1550: ! 1551: else ! 1552: ! 1553: lend = lstart + lck->l.l_len; ! 1554: ! 1555: ! 1556: ! 1557: for (t = list; t; t = t->next) { ! 1558: ! 1559: tstart = t->l.l_start; ! 1560: ! 1561: if (t->l.l_len == 0) ! 1562: ! 1563: tend = 0xffffffff; ! 1564: ! 1565: else ! 1566: ! 1567: tend = tstart + t->l.l_len; ! 1568: ! 1569: ! 1570: ! 1571: /* look for overlapping locks */ ! 1572: ! 1573: if (tstart <= lstart && tend >= lstart && t->l.l_pid != pid && ! 1574: ! 1575: (ltype == F_WRLCK || t->l.l_type == F_WRLCK)) ! 1576: ! 1577: break; ! 1578: ! 1579: if (lstart <= tstart && lend >= tstart && t->l.l_pid != pid && ! 1580: ! 1581: (ltype == F_WRLCK || t->l.l_type == F_WRLCK)) ! 1582: ! 1583: break; ! 1584: ! 1585: } ! 1586: ! 1587: return t; ! 1588: ! 1589: } ! 1590: ! 1591: ! 1592: ! 1593: /* ! 1594: ! 1595: * check to see that a file is a directory, and that write permission ! 1596: ! 1597: * is granted; return an error code, or 0 if everything is ok. ! 1598: ! 1599: */ ! 1600: ! 1601: long ! 1602: ! 1603: dir_access(dir, perm) ! 1604: ! 1605: fcookie *dir; ! 1606: ! 1607: unsigned perm; ! 1608: ! 1609: { ! 1610: ! 1611: XATTR xattr; ! 1612: ! 1613: long r; ! 1614: ! 1615: ! 1616: ! 1617: r = (*dir->fs->getxattr)(dir, &xattr); ! 1618: ! 1619: if (r) return r; ! 1620: ! 1621: if ( (xattr.mode & S_IFMT) != S_IFDIR ) { ! 1622: ! 1623: DEBUG("file is not a directory"); ! 1624: ! 1625: return EPTHNF; ! 1626: ! 1627: } ! 1628: ! 1629: if (denyaccess(&xattr, perm)) { ! 1630: ! 1631: DEBUG("no permission for directory"); ! 1632: ! 1633: return EACCDN; ! 1634: ! 1635: } ! 1636: ! 1637: return 0; ! 1638: ! 1639: } ! 1640: ! 1641: ! 1642: ! 1643: /* ! 1644: ! 1645: * returns 1 if the given name contains a wildcard character ! 1646: ! 1647: */ ! 1648: ! 1649: ! 1650: ! 1651: int ! 1652: ! 1653: has_wild(name) ! 1654: ! 1655: const char *name; ! 1656: ! 1657: { ! 1658: ! 1659: char c; ! 1660: ! 1661: ! 1662: ! 1663: while (c = *name++) { ! 1664: ! 1665: if (c == '*' || c == '?') return 1; ! 1666: ! 1667: } ! 1668: ! 1669: return 0; ! 1670: ! 1671: } ! 1672: ! 1673: ! 1674: ! 1675: /* ! 1676: ! 1677: * void copy8_3(dest, src): convert a file name (src) into DOS 8.3 format ! 1678: ! 1679: * (in dest). Note the following things: ! 1680: ! 1681: * if a field has less than the required number of characters, it is ! 1682: ! 1683: * padded with blanks ! 1684: ! 1685: * a '*' means to pad the rest of the field with '?' characters ! 1686: ! 1687: * special things to watch for: ! 1688: ! 1689: * "." and ".." are more or less left alone ! 1690: ! 1691: * "*.*" is recognized as a special pattern, for which dest is set ! 1692: ! 1693: * to just "*" ! 1694: ! 1695: * Long names are truncated. Any extensions after the first one are ! 1696: ! 1697: * ignored, i.e. foo.bar.c -> foo.bar, foo.c.bar->foo.c. ! 1698: ! 1699: */ ! 1700: ! 1701: ! 1702: ! 1703: void ! 1704: ! 1705: copy8_3(dest, src) ! 1706: ! 1707: char *dest; ! 1708: ! 1709: const char *src; ! 1710: ! 1711: { ! 1712: ! 1713: char fill = ' ', c; ! 1714: ! 1715: int i; ! 1716: ! 1717: ! 1718: ! 1719: if (src[0] == '.') { ! 1720: ! 1721: if (src[1] == 0) { ! 1722: ! 1723: strcpy(dest, ". . "); ! 1724: ! 1725: return; ! 1726: ! 1727: } ! 1728: ! 1729: if (src[1] == '.' && src[2] == 0) { ! 1730: ! 1731: strcpy(dest, ".. . "); ! 1732: ! 1733: return; ! 1734: ! 1735: } ! 1736: ! 1737: } ! 1738: ! 1739: if (src[0] == '*' && src[1] == '.' && src[2] == '*' && src[3] == 0) { ! 1740: ! 1741: dest[0] = '*'; ! 1742: ! 1743: dest[1] = 0; ! 1744: ! 1745: return; ! 1746: ! 1747: } ! 1748: ! 1749: ! 1750: ! 1751: for (i = 0; i < 8; i++) { ! 1752: ! 1753: c = *src++; ! 1754: ! 1755: if (!c || c == '.') break; ! 1756: ! 1757: if (c == '*') { ! 1758: ! 1759: fill = c = '?'; ! 1760: ! 1761: } ! 1762: ! 1763: *dest++ = toupper(c); ! 1764: ! 1765: } ! 1766: ! 1767: while (i++ < 8) { ! 1768: ! 1769: *dest++ = fill; ! 1770: ! 1771: } ! 1772: ! 1773: *dest++ = '.'; ! 1774: ! 1775: i = 0; ! 1776: ! 1777: fill = ' '; ! 1778: ! 1779: while (c && c != '.') ! 1780: ! 1781: c = *src++; ! 1782: ! 1783: ! 1784: ! 1785: if (c) { ! 1786: ! 1787: for( ;i < 3; i++) { ! 1788: ! 1789: c = *src++; ! 1790: ! 1791: if (!c || c == '.') break; ! 1792: ! 1793: if (c == '*') ! 1794: ! 1795: c = fill = '?'; ! 1796: ! 1797: *dest++ = toupper(c); ! 1798: ! 1799: } ! 1800: ! 1801: } ! 1802: ! 1803: while (i++ < 3) ! 1804: ! 1805: *dest++ = fill; ! 1806: ! 1807: *dest++ = 0; ! 1808: ! 1809: } ! 1810: ! 1811: ! 1812: ! 1813: /* ! 1814: ! 1815: * int pat_match(name, patrn): returns 1 if "name" matches the template in ! 1816: ! 1817: * "patrn", 0 if not. "patrn" is assumed to have been expanded in 8.3 ! 1818: ! 1819: * format by copy8_3; "name" need not be. Any '?' characters in patrn ! 1820: ! 1821: * will match any character in name. Note that if "patrn" has a '*' as ! 1822: ! 1823: * the first character, it will always match; this will happen only if ! 1824: ! 1825: * the original pattern (before copy8_3 was applied) was "*.*". ! 1826: ! 1827: * ! 1828: ! 1829: * BUGS: acts a lot like the silly TOS pattern matcher. ! 1830: ! 1831: */ ! 1832: ! 1833: ! 1834: ! 1835: int ! 1836: ! 1837: pat_match(name, template) ! 1838: ! 1839: const char *name, *template; ! 1840: ! 1841: { ! 1842: ! 1843: register char *s, c; ! 1844: ! 1845: char expname[TOS_NAMELEN+1]; ! 1846: ! 1847: ! 1848: ! 1849: if (*template == '*') return 1; ! 1850: ! 1851: copy8_3(expname, name); ! 1852: ! 1853: ! 1854: ! 1855: s = expname; ! 1856: ! 1857: while (c = *template++) { ! 1858: ! 1859: if (c != *s && c != '?') ! 1860: ! 1861: return 0; ! 1862: ! 1863: s++; ! 1864: ! 1865: } ! 1866: ! 1867: return 1; ! 1868: ! 1869: } ! 1870: ! 1871: ! 1872: ! 1873: /* ! 1874: ! 1875: * int samefile(fcookie *a, fcookie *b): returns 1 if the two cookies ! 1876: ! 1877: * refer to the same file or directory, 0 otherwise ! 1878: ! 1879: */ ! 1880: ! 1881: ! 1882: ! 1883: int ! 1884: ! 1885: samefile(a, b) ! 1886: ! 1887: fcookie *a, *b; ! 1888: ! 1889: { ! 1890: ! 1891: if (a->fs == b->fs && a->dev == b->dev && a->index == b->index) ! 1892: ! 1893: return 1; ! 1894: ! 1895: return 0; ! 1896: ! 1897: } ! 1898:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.