|
|
1.1 ! root 1: /* ! 2: ! 3: Copyright 1991,1992 Eric R. Smith. All rights reserved. ! 4: ! 5: */ ! 6: ! 7: ! 8: ! 9: /* a VERY simple tosfs.c ! 10: ! 11: * this one is extremely brain-damaged, but will serve OK for a ! 12: ! 13: * skeleton in which to put a "real" tosfs.c ! 14: ! 15: */ ! 16: ! 17: ! 18: ! 19: #include "mint.h" ! 20: ! 21: ! 22: ! 23: /* search mask for anything OTHER THAN a volume label */ ! 24: ! 25: #define FILEORDIR 0x37 ! 26: ! 27: ! 28: ! 29: #ifndef Flock ! 30: ! 31: /* this may need to be adjusted for your compiler/library */ ! 32: ! 33: extern long gemdos(); ! 34: ! 35: #define Flock(handle, mode, start, len) gemdos(0x5c, handle, mode, start, len) ! 36: ! 37: #endif ! 38: ! 39: ! 40: ! 41: char tmpbuf[PATH_MAX+1]; ! 42: ! 43: ! 44: ! 45: static long tos_root P_((int drv, fcookie *fc)); ! 46: ! 47: static long tos_lookup P_((fcookie *dir, const char *name, fcookie *fc)); ! 48: ! 49: static long tos_getxattr P_((fcookie *fc, XATTR *xattr)); ! 50: ! 51: static long tos_chattr P_((fcookie *fc, int attrib)); ! 52: ! 53: static long tos_chown P_((fcookie *fc, int uid, int gid)); ! 54: ! 55: static long tos_chmode P_((fcookie *fc, unsigned mode)); ! 56: ! 57: static long tos_mkdir P_((fcookie *dir, const char *name, unsigned mode)); ! 58: ! 59: static long tos_rmdir P_((fcookie *dir, const char *name)); ! 60: ! 61: static long tos_remove P_((fcookie *dir, const char *name)); ! 62: ! 63: static long tos_getname P_((fcookie *root, fcookie *dir, char *pathname)); ! 64: ! 65: static long tos_rename P_((fcookie *olddir, char *oldname, ! 66: ! 67: fcookie *newdir, const char *newname)); ! 68: ! 69: static long tos_opendir P_((DIR *dirh, int flags)); ! 70: ! 71: static long tos_readdir P_((DIR *dirh, char *nm, int nmlen, fcookie *)); ! 72: ! 73: static long tos_rewinddir P_((DIR *dirh)); ! 74: ! 75: static long tos_closedir P_((DIR *dirh)); ! 76: ! 77: static long tos_pathconf P_((fcookie *dir, int which)); ! 78: ! 79: static long tos_dfree P_((fcookie *dir, long *buf)); ! 80: ! 81: static long tos_writelabel P_((fcookie *dir, const char *name)); ! 82: ! 83: static long tos_readlabel P_((fcookie *dir, char *name, int namelen)); ! 84: ! 85: ! 86: ! 87: static long tos_creat P_((fcookie *dir, const char *name, unsigned mode, ! 88: ! 89: int attrib, fcookie *fc)); ! 90: ! 91: static DEVDRV * tos_getdev P_((fcookie *fc, long *devsp)); ! 92: ! 93: static long tos_open P_((FILEPTR *f)); ! 94: ! 95: static long tos_write P_((FILEPTR *f, const char *buf, long bytes)); ! 96: ! 97: static long tos_read P_((FILEPTR *f, char *buf, long bytes)); ! 98: ! 99: static long tos_lseek P_((FILEPTR *f, long where, int whence)); ! 100: ! 101: static long tos_ioctl P_((FILEPTR *f, int mode, void *buf)); ! 102: ! 103: static long tos_datime P_((FILEPTR *f, short *time, int rwflag)); ! 104: ! 105: static long tos_close P_((FILEPTR *f, int pid)); ! 106: ! 107: static long tos_dskchng P_((int drv)); ! 108: ! 109: ! 110: ! 111: /* some routines from biosfs.c */ ! 112: ! 113: extern long null_select P_((FILEPTR *f, long p, int mode)); ! 114: ! 115: extern void null_unselect P_((FILEPTR *f, long p, int mode)); ! 116: ! 117: ! 118: ! 119: DEVDRV tos_device = { ! 120: ! 121: tos_open, tos_write, tos_read, tos_lseek, tos_ioctl, tos_datime, ! 122: ! 123: tos_close, null_select, null_unselect ! 124: ! 125: }; ! 126: ! 127: ! 128: ! 129: FILESYS tos_filesys = { ! 130: ! 131: (FILESYS *)0, ! 132: ! 133: FS_KNOPARSE | FS_NOXBIT, ! 134: ! 135: tos_root, ! 136: ! 137: tos_lookup, tos_creat, tos_getdev, tos_getxattr, ! 138: ! 139: tos_chattr, tos_chown, tos_chmode, ! 140: ! 141: tos_mkdir, tos_rmdir, tos_remove, tos_getname, tos_rename, ! 142: ! 143: tos_opendir, tos_readdir, tos_rewinddir, tos_closedir, ! 144: ! 145: tos_pathconf, tos_dfree, tos_writelabel, tos_readlabel, ! 146: ! 147: nosymlink, noreadlink, nohardlink, nofscntl, tos_dskchng ! 148: ! 149: }; ! 150: ! 151: ! 152: ! 153: /* some utility functions and variables: see end of file */ ! 154: ! 155: static DTABUF *lastdta; /* last DTA buffer we asked TOS about */ ! 156: ! 157: static DTABUF foo; ! 158: ! 159: static void do_setdta P_((DTABUF *dta)); ! 160: ! 161: static int executable_extension P_((char *)); ! 162: ! 163: ! 164: ! 165: /* this array keeps track of which drives have been changed */ ! 166: ! 167: /* a nonzero entry means that the corresponding drive has been changed, ! 168: ! 169: * but GEMDOS doesn't know it yet ! 170: ! 171: */ ! 172: ! 173: static char drvchanged[NUM_DRIVES]; ! 174: ! 175: ! 176: ! 177: /* force TOS to see a media change */ ! 178: ! 179: static void force_mediach P_((int drv)); ! 180: ! 181: static long Newgetbpb P_((int)); ! 182: ! 183: static long Newmediach P_((int)); ! 184: ! 185: static long Newrwabs P_((int, void *, int, int, int, long)); ! 186: ! 187: ! 188: ! 189: #define NUM_INDICES 128 ! 190: ! 191: #define MIN_AGE 8 ! 192: ! 193: ! 194: ! 195: struct tindex { ! 196: ! 197: char *name; /* full path name */ ! 198: ! 199: FILEPTR *open; /* fileptrs for this file; OR ! 200: ! 201: * count of number of open directories ! 202: ! 203: */ ! 204: ! 205: LOCK *locks; /* locks on this file */ ! 206: ! 207: /* file status */ ! 208: ! 209: long size; ! 210: ! 211: short time; ! 212: ! 213: short date; ! 214: ! 215: short attr; ! 216: ! 217: short valid; /* 1 if the above status is still valid */ ! 218: ! 219: short stamp; /* age of this index, for garbage collection */ ! 220: ! 221: } gl_ti[NUM_INDICES]; ! 222: ! 223: ! 224: ! 225: /* temporary index for files found by readdir */ ! 226: ! 227: static struct tindex tmpindex; ! 228: ! 229: static char tmpiname[PATH_MAX]; ! 230: ! 231: ! 232: ! 233: static struct tindex *tstrindex P_((char *s)); ! 234: ! 235: static int tfullpath P_((char *result, struct tindex *base, const char *name)); ! 236: ! 237: static struct tindex *garbage_collect P_((void)); ! 238: ! 239: ! 240: ! 241: static short tclock; /* #calls to tfullpath since last garbage ! 242: ! 243: collection */ ! 244: ! 245: ! 246: ! 247: /* some extra flags for the attr field */ ! 248: ! 249: ! 250: ! 251: /* ! 252: ! 253: * is a string the name of a file with executable extension? ! 254: ! 255: */ ! 256: ! 257: #define FA_EXEC 0x4000 ! 258: ! 259: /* ! 260: ! 261: * should the file be deleted when it is closed? ! 262: ! 263: */ ! 264: ! 265: #define FA_DELETE 0x2000 ! 266: ! 267: ! 268: ! 269: /* ! 270: ! 271: * NOTE: call executable_extension only on a DTA name returned from ! 272: ! 273: * Fsfirst(), not on an arbitrary path ! 274: ! 275: */ ! 276: ! 277: ! 278: ! 279: static int ! 280: ! 281: executable_extension(s) ! 282: ! 283: char *s; ! 284: ! 285: { ! 286: ! 287: while (*s && *s != '.') s++; ! 288: ! 289: if (!*s) return 0; ! 290: ! 291: s++; ! 292: ! 293: if (s[0] == 'T') { ! 294: ! 295: return (s[1] == 'T' && s[2] == 'P') || ! 296: ! 297: (s[1] == 'O' && s[2] == 'S'); ! 298: ! 299: } ! 300: ! 301: if (s[0] == 'P') ! 302: ! 303: return s[1] == 'R' && s[2] == 'G'; ! 304: ! 305: if (s[0] == 'A') ! 306: ! 307: return s[1] == 'P' && s[2] == 'P'; ! 308: ! 309: if (s[0] == 'G') ! 310: ! 311: return s[1] == 'T' && s[2] == 'P'; ! 312: ! 313: return 0; ! 314: ! 315: } ! 316: ! 317: ! 318: ! 319: /* ! 320: ! 321: * Look in the table of tos indices to see if an index corresponding ! 322: ! 323: * to this file name already exists. If so, mark it as being used ! 324: ! 325: * and return it. If not, find an empty slot and make an index for ! 326: ! 327: * this string. If no empty slots exist, garbage collect and ! 328: ! 329: * try again. ! 330: ! 331: * ! 332: ! 333: * This routine is pretty dumb; we really should use a hash table ! 334: ! 335: * of some sort ! 336: ! 337: */ ! 338: ! 339: ! 340: ! 341: static struct tindex *tstrindex(s) ! 342: ! 343: char *s; ! 344: ! 345: { ! 346: ! 347: int i; ! 348: ! 349: char *r; ! 350: ! 351: struct tindex *t, *free = 0; ! 352: ! 353: ! 354: ! 355: assert(s != 0); ! 356: ! 357: t = gl_ti; ! 358: ! 359: for (i = 0; i < NUM_INDICES; i++, t++) { ! 360: ! 361: if (t->name && !stricmp(t->name, s)) { ! 362: ! 363: t->stamp = tclock; /* update use time */ ! 364: ! 365: return t; ! 366: ! 367: } ! 368: ! 369: else if (!t->name && !free) ! 370: ! 371: free = t; ! 372: ! 373: } ! 374: ! 375: if (!free) { ! 376: ! 377: free = garbage_collect(); ! 378: ! 379: } ! 380: ! 381: if (!free) { ! 382: ! 383: FATAL("tosfs: unable to get a file name index"); ! 384: ! 385: } ! 386: ! 387: r = kmalloc((long)strlen(s)+1); ! 388: ! 389: if (!r) { ! 390: ! 391: FATAL("tosfs: unable to allocate space for a file name"); ! 392: ! 393: } ! 394: ! 395: strcpy(r, s); ! 396: ! 397: free->name = r; ! 398: ! 399: free->stamp = tclock; ! 400: ! 401: free->open = 0; ! 402: ! 403: free->locks = 0; ! 404: ! 405: ! 406: ! 407: /* check to see if this file was recently returned by opendir() */ ! 408: ! 409: if (tmpindex.valid && tclock - tmpindex.stamp < MIN_AGE && ! 410: ! 411: !stricmp(free->name, tmpindex.name)) { ! 412: ! 413: free->size = tmpindex.size; ! 414: ! 415: free->time = tmpindex.time; ! 416: ! 417: free->date = tmpindex.date; ! 418: ! 419: free->attr = tmpindex.attr; ! 420: ! 421: free->valid = 1; ! 422: ! 423: tmpindex.valid = 0; ! 424: ! 425: } else ! 426: ! 427: free->valid = 0; ! 428: ! 429: return free; ! 430: ! 431: } ! 432: ! 433: ! 434: ! 435: /* ! 436: ! 437: * garbage collection routine: for any TOS index older than MIN_AGE, ! 438: ! 439: * check through all current processes to see if it's in use. If ! 440: ! 441: * not, free the corresponding string. ! 442: ! 443: * Returns: a pointer to a newly freed index, or NULL. ! 444: ! 445: */ ! 446: ! 447: ! 448: ! 449: /* it's unlikely that the kernel would need to hold onto a file cookie ! 450: ! 451: for longer than this many calls to tstrindex() without first ! 452: ! 453: saving the cookie in a directory or file pointer ! 454: ! 455: */ ! 456: ! 457: ! 458: ! 459: static struct tindex * ! 460: ! 461: garbage_collect() ! 462: ! 463: { ! 464: ! 465: struct tindex *free, *t; ! 466: ! 467: fcookie *fc, *gc; ! 468: ! 469: PROC *p; ! 470: ! 471: int i, j; ! 472: ! 473: int age; ! 474: ! 475: ! 476: ! 477: free = 0; ! 478: ! 479: t = gl_ti; ! 480: ! 481: for (i = 0; i < NUM_INDICES; i++,t++) { ! 482: ! 483: if (!t->name) continue; ! 484: ! 485: age = tclock - t->stamp; ! 486: ! 487: t->stamp = 0; ! 488: ! 489: assert(age >= 0); ! 490: ! 491: if (age > MIN_AGE) { ! 492: ! 493: /* see if any process is using this index */ ! 494: ! 495: if (t->open) ! 496: ! 497: goto found_index; ! 498: ! 499: for (p = proclist; p; p = p->gl_next) { ! 500: ! 501: fc = p->curdir; ! 502: ! 503: gc = p->root; ! 504: ! 505: for (j = 0; j < NUM_DRIVES; j++,fc++,gc++) { ! 506: ! 507: if (( fc->fs == &tos_filesys && ! 508: ! 509: fc->index == (long)t ) || ! 510: ! 511: ( gc->fs == &tos_filesys && ! 512: ! 513: gc->index == (long)t ) ) ! 514: ! 515: goto found_index; ! 516: ! 517: } ! 518: ! 519: } ! 520: ! 521: /* here, we couldn't find the index in use by any proc. */ ! 522: ! 523: kfree(t->name); ! 524: ! 525: t->name = 0; ! 526: ! 527: if (!free) ! 528: ! 529: free = t; ! 530: ! 531: found_index: ! 532: ! 533: ; ! 534: ! 535: } else { ! 536: ! 537: /* make sure that future garbage collections might look at this file */ ! 538: ! 539: t->stamp = -age; ! 540: ! 541: } ! 542: ! 543: } ! 544: ! 545: ! 546: ! 547: tclock = 0; /* reset the clock */ ! 548: ! 549: tmpindex.valid = 0; /* expire the temporary Fsfirst buffer */ ! 550: ! 551: return free; ! 552: ! 553: } ! 554: ! 555: ! 556: ! 557: #define DIRSEP(c) ((c) == '\\') ! 558: ! 559: ! 560: ! 561: static int ! 562: ! 563: tfullpath(result, basei, path) ! 564: ! 565: char *result; ! 566: ! 567: struct tindex *basei; ! 568: ! 569: const char *path; ! 570: ! 571: { ! 572: ! 573: #define TNMTEMP 32 ! 574: ! 575: char *n, name[TNMTEMP+1]; ! 576: ! 577: int dom; ! 578: ! 579: int namelen, pathlen; ! 580: ! 581: char *base = basei->name; ! 582: ! 583: int r = 0; ! 584: ! 585: ! 586: ! 587: basei->stamp = ++tclock; ! 588: ! 589: if (tclock > 10000) { ! 590: ! 591: /* garbage collect every so often whether we need it or not */ ! 592: ! 593: (void)garbage_collect(); ! 594: ! 595: } ! 596: ! 597: if (!*path) { ! 598: ! 599: strncpy(result, base, PATH_MAX-1); ! 600: ! 601: return r; ! 602: ! 603: } ! 604: ! 605: ! 606: ! 607: dom = curproc->domain; ! 608: ! 609: ! 610: ! 611: strncpy(result, base, PATH_MAX-1); ! 612: ! 613: ! 614: ! 615: pathlen = strlen(result); ! 616: ! 617: ! 618: ! 619: /* now path is relative to what's currently in "result" */ ! 620: ! 621: ! 622: ! 623: while(*path) { ! 624: ! 625: /* get next name in path */ ! 626: ! 627: n = name; namelen = 0; ! 628: ! 629: while (*path && !DIRSEP(*path)) { ! 630: ! 631: /* BUG: we really should to the translation to DOS 8.3 ! 632: ! 633: * format *here*, so that really long names are truncated ! 634: ! 635: * correctly. ! 636: ! 637: */ ! 638: ! 639: if (namelen < TNMTEMP) { ! 640: ! 641: *n++ = toupper(*path); path++; namelen++; ! 642: ! 643: } ! 644: ! 645: else ! 646: ! 647: path++; ! 648: ! 649: } ! 650: ! 651: *n++ = 0; ! 652: ! 653: while (DIRSEP(*path)) path++; ! 654: ! 655: /* check for "." and ".." */ ! 656: ! 657: if (!strcmp(name, ".")) continue; ! 658: ! 659: if (!strcmp(name, "..")) { ! 660: ! 661: n = strrchr(result, '\\'); ! 662: ! 663: if (n) { ! 664: ! 665: *n = 0; ! 666: ! 667: pathlen = n - result; ! 668: ! 669: } ! 670: ! 671: else r = EMOUNT; ! 672: ! 673: continue; ! 674: ! 675: } ! 676: ! 677: if (pathlen + namelen < PATH_MAX - 1) { ! 678: ! 679: strcat(result, "\\"); ! 680: ! 681: pathlen++; ! 682: ! 683: ! 684: ! 685: /* make sure the name is restricted to DOS 8.3 format */ ! 686: ! 687: for (base = result; *base; base++) ! 688: ! 689: ; ! 690: ! 691: n = name; ! 692: ! 693: namelen = 0; ! 694: ! 695: while (*n && *n != '.' && namelen++ < 8) { ! 696: ! 697: *base++ = *n++; ! 698: ! 699: pathlen++; ! 700: ! 701: } ! 702: ! 703: while (*n && *n != '.') n++; ! 704: ! 705: if (*n == '.' && *(n+1) != 0) { ! 706: ! 707: *base++ = *n++; ! 708: ! 709: pathlen++; ! 710: ! 711: namelen = 0; ! 712: ! 713: while (*n && namelen++ < 3) { ! 714: ! 715: *base++ = *n++; ! 716: ! 717: pathlen++; ! 718: ! 719: } ! 720: ! 721: } ! 722: ! 723: *base = 0; ! 724: ! 725: } ! 726: ! 727: } ! 728: ! 729: return r; ! 730: ! 731: } ! 732: ! 733: ! 734: ! 735: static long ! 736: ! 737: tos_root(drv, fc) ! 738: ! 739: int drv; ! 740: ! 741: fcookie *fc; ! 742: ! 743: { ! 744: ! 745: struct tindex *ti; ! 746: ! 747: ! 748: ! 749: ksprintf(tmpbuf, "%c:", drv+'A'); ! 750: ! 751: fc->fs = &tos_filesys; ! 752: ! 753: fc->dev = drv; ! 754: ! 755: ti = tstrindex(tmpbuf); ! 756: ! 757: ti->size = ti->date = ti->time = 0; ! 758: ! 759: ti->attr = FA_DIR; ! 760: ! 761: ti->valid = 1; ! 762: ! 763: fc->index = (long)ti; ! 764: ! 765: ! 766: ! 767: /* if the drive has changed, make sure GEMDOS knows it! */ ! 768: ! 769: if (drvchanged[drv]) { ! 770: ! 771: force_mediach(drv); ! 772: ! 773: } ! 774: ! 775: return 0; ! 776: ! 777: } ! 778: ! 779: ! 780: ! 781: static long ! 782: ! 783: tos_lookup(dir, name, fc) ! 784: ! 785: fcookie *dir; ! 786: ! 787: const char *name; ! 788: ! 789: fcookie *fc; ! 790: ! 791: { ! 792: ! 793: long r; ! 794: ! 795: struct tindex *ti = (struct tindex *)dir->index; ! 796: ! 797: ! 798: ! 799: r = tfullpath(tmpbuf, ti, name); ! 800: ! 801: ! 802: ! 803: /* if the name is empty or otherwise trivial, just return the directory */ ! 804: ! 805: if (!strcmp(ti->name, tmpbuf)) { ! 806: ! 807: *fc = *dir; ! 808: ! 809: return r; ! 810: ! 811: } ! 812: ! 813: ! 814: ! 815: /* is there already an index for this file?? If so, is it up to date?? */ ! 816: ! 817: ti = tstrindex(tmpbuf); ! 818: ! 819: if (!ti->valid) { ! 820: ! 821: if (tmpbuf[1] == ':' && tmpbuf[2] == 0) { ! 822: ! 823: /* a root directory -- lookup always succeeds */ ! 824: ! 825: foo.dta_size = 0; ! 826: ! 827: foo.dta_date = foo.dta_time = 0; ! 828: ! 829: foo.dta_attrib = FA_DIR; ! 830: ! 831: foo.dta_name[0] = 0; ! 832: ! 833: } else { ! 834: ! 835: do_setdta(&foo); ! 836: ! 837: r = Fsfirst(tmpbuf, FILEORDIR); ! 838: ! 839: if (r) { ! 840: ! 841: DEBUG("tos_lookup: Fsfirst(%s) returned %ld", tmpbuf, r); ! 842: ! 843: return r; ! 844: ! 845: } ! 846: ! 847: } ! 848: ! 849: ti->size = foo.dta_size; ! 850: ! 851: ti->date = foo.dta_date; ! 852: ! 853: ti->time = foo.dta_time; ! 854: ! 855: ti->attr = foo.dta_attrib; ! 856: ! 857: if (executable_extension(foo.dta_name)) ! 858: ! 859: ti->attr |= FA_EXEC; ! 860: ! 861: ti->valid = 1; ! 862: ! 863: } ! 864: ! 865: fc->fs = &tos_filesys; ! 866: ! 867: fc->index = (long)ti; ! 868: ! 869: fc->dev = dir->dev; ! 870: ! 871: return r; ! 872: ! 873: } ! 874: ! 875: ! 876: ! 877: static long ! 878: ! 879: tos_getxattr(fc, xattr) ! 880: ! 881: fcookie *fc; ! 882: ! 883: XATTR *xattr; ! 884: ! 885: { ! 886: ! 887: struct tindex *ti = (struct tindex *)fc->index; ! 888: ! 889: long r; ! 890: ! 891: static long junkindex = 0; ! 892: ! 893: ! 894: ! 895: xattr->index = junkindex++; ! 896: ! 897: xattr->dev = fc->dev; ! 898: ! 899: xattr->nlink = 1; ! 900: ! 901: xattr->uid = xattr->gid = 0; ! 902: ! 903: ! 904: ! 905: ti->stamp = ++tclock; ! 906: ! 907: if (!ti->valid) { ! 908: ! 909: do_setdta(&foo); ! 910: ! 911: if (ti->name[2] == 0) { /* a root directory */ ! 912: ! 913: /* actually, this can also happen if a program tries to open a file ! 914: ! 915: * with an empty name... so we should fail gracefully ! 916: ! 917: */ ! 918: ! 919: TRACE("tosfs: a root directory became invalid??"); ! 920: ! 921: goto around; ! 922: ! 923: } ! 924: ! 925: ! 926: ! 927: r = Fsfirst(ti->name, FILEORDIR); ! 928: ! 929: if (r < 0) ! 930: ! 931: FATAL("tosfs: search error on [%s]", ti->name); ! 932: ! 933: ti->size = foo.dta_size; ! 934: ! 935: ti->date = foo.dta_date; ! 936: ! 937: ti->time = foo.dta_time; ! 938: ! 939: ti->attr = foo.dta_attrib; ! 940: ! 941: if (executable_extension(foo.dta_name)) ! 942: ! 943: ti->attr |= FA_EXEC; ! 944: ! 945: around: ! 946: ! 947: ti->valid = 1; ! 948: ! 949: } ! 950: ! 951: xattr->size = ti->size; ! 952: ! 953: ! 954: ! 955: /* BUG: blksize isn't accurate if the sector size is not 512 */ ! 956: ! 957: xattr->blksize = 1024; ! 958: ! 959: xattr->nblocks = (xattr->size + 1023) / 1024; ! 960: ! 961: xattr->mdate = xattr->cdate = xattr->adate = ti->date; ! 962: ! 963: xattr->mtime = xattr->ctime = xattr->atime = ti->time; ! 964: ! 965: xattr->mode = (ti->attr & FA_DIR) ? (S_IFDIR | DEFAULT_DIRMODE) : ! 966: ! 967: (S_IFREG | DEFAULT_MODE); ! 968: ! 969: ! 970: ! 971: if (ti->attr & FA_RDONLY) { ! 972: ! 973: xattr->mode &= ~(S_IWUSR|S_IWGRP|S_IWOTH); ! 974: ! 975: } ! 976: ! 977: ! 978: ! 979: if (ti->attr & FA_EXEC) { ! 980: ! 981: xattr->mode |= (S_IXUSR|S_IXGRP|S_IXOTH); ! 982: ! 983: } ! 984: ! 985: xattr->attr = ti->attr & 0xff; ! 986: ! 987: return 0; ! 988: ! 989: } ! 990: ! 991: ! 992: ! 993: static long ! 994: ! 995: tos_chattr(fc, attrib) ! 996: ! 997: fcookie *fc; ! 998: ! 999: int attrib; ! 1000: ! 1001: { ! 1002: ! 1003: struct tindex *ti = (struct tindex *)fc->index; ! 1004: ! 1005: ! 1006: ! 1007: if (ti->attr & FA_DIR) { ! 1008: ! 1009: DEBUG("error: attempt to change attributes of a directory"); ! 1010: ! 1011: return EACCDN; ! 1012: ! 1013: } ! 1014: ! 1015: ti->valid = 0; ! 1016: ! 1017: (void)tfullpath(tmpbuf, ti, ""); ! 1018: ! 1019: return Fattrib(tmpbuf, 1, attrib); ! 1020: ! 1021: } ! 1022: ! 1023: ! 1024: ! 1025: static long ! 1026: ! 1027: tos_chown(dir, uid, gid) ! 1028: ! 1029: fcookie *dir; ! 1030: ! 1031: int uid, gid; ! 1032: ! 1033: { ! 1034: ! 1035: return EINVFN; ! 1036: ! 1037: } ! 1038: ! 1039: ! 1040: ! 1041: static long ! 1042: ! 1043: tos_chmode(fc, mode) ! 1044: ! 1045: fcookie *fc; ! 1046: ! 1047: unsigned mode; ! 1048: ! 1049: { ! 1050: ! 1051: int oldattr, newattr; ! 1052: ! 1053: long r; ! 1054: ! 1055: struct tindex *ti = (struct tindex *)fc->index; ! 1056: ! 1057: ! 1058: ! 1059: oldattr = Fattrib(ti->name, 0, 0); ! 1060: ! 1061: if (oldattr < 0) ! 1062: ! 1063: return oldattr; ! 1064: ! 1065: ! 1066: ! 1067: ti->valid = 0; ! 1068: ! 1069: ! 1070: ! 1071: if (!(mode & S_IWUSR)) ! 1072: ! 1073: newattr = oldattr | FA_RDONLY; ! 1074: ! 1075: else ! 1076: ! 1077: newattr = oldattr & ~FA_RDONLY; ! 1078: ! 1079: if (newattr != oldattr) ! 1080: ! 1081: r = Fattrib(ti->name, 1, newattr); ! 1082: ! 1083: else ! 1084: ! 1085: r = 0; ! 1086: ! 1087: return (r < 0) ? r : 0; ! 1088: ! 1089: } ! 1090: ! 1091: ! 1092: ! 1093: static long ! 1094: ! 1095: tos_mkdir(dir, name, mode) ! 1096: ! 1097: fcookie *dir; ! 1098: ! 1099: const char *name; ! 1100: ! 1101: unsigned mode; /* ignored under TOS */ ! 1102: ! 1103: { ! 1104: ! 1105: (void)tfullpath(tmpbuf, (struct tindex *)dir->index, name); ! 1106: ! 1107: tmpindex.valid = 0; ! 1108: ! 1109: ! 1110: ! 1111: return Dcreate(tmpbuf); ! 1112: ! 1113: } ! 1114: ! 1115: ! 1116: ! 1117: static long ! 1118: ! 1119: tos_rmdir(dir, name) ! 1120: ! 1121: fcookie *dir; ! 1122: ! 1123: const char *name; ! 1124: ! 1125: { ! 1126: ! 1127: struct tindex *ti; ! 1128: ! 1129: ! 1130: ! 1131: (void)tfullpath(tmpbuf, (struct tindex *)dir->index, name); ! 1132: ! 1133: ti = tstrindex(tmpbuf); ! 1134: ! 1135: ti->valid = 0; ! 1136: ! 1137: ! 1138: ! 1139: return Ddelete(tmpbuf); ! 1140: ! 1141: } ! 1142: ! 1143: ! 1144: ! 1145: static long ! 1146: ! 1147: tos_remove(dir, name) ! 1148: ! 1149: fcookie *dir; ! 1150: ! 1151: const char *name; ! 1152: ! 1153: { ! 1154: ! 1155: struct tindex *ti; ! 1156: ! 1157: ! 1158: ! 1159: (void)tfullpath(tmpbuf, (struct tindex *)dir->index, name); ! 1160: ! 1161: ! 1162: ! 1163: ti = tstrindex(tmpbuf); ! 1164: ! 1165: if (ti->open) { ! 1166: ! 1167: DEBUG("tos_remove: file is open, will be deleted later"); ! 1168: ! 1169: if (ti->attr & FA_RDONLY) ! 1170: ! 1171: return EACCDN; ! 1172: ! 1173: ti->attr |= FA_DELETE; ! 1174: ! 1175: return 0; ! 1176: ! 1177: } ! 1178: ! 1179: ti->valid = 0; ! 1180: ! 1181: return Fdelete(tmpbuf); ! 1182: ! 1183: } ! 1184: ! 1185: ! 1186: ! 1187: static long ! 1188: ! 1189: tos_getname(root, dir, pathname) ! 1190: ! 1191: fcookie *root, *dir; ! 1192: ! 1193: char *pathname; ! 1194: ! 1195: { ! 1196: ! 1197: ksprintf(pathname, "%s", ((struct tindex *)dir->index)->name + ! 1198: ! 1199: strlen(((struct tindex*)root->index)->name) ); ! 1200: ! 1201: if (curproc->domain == DOM_MINT) ! 1202: ! 1203: strlwr(pathname); ! 1204: ! 1205: ! 1206: ! 1207: return 0; ! 1208: ! 1209: } ! 1210: ! 1211: ! 1212: ! 1213: static long ! 1214: ! 1215: tos_rename(olddir, oldname, newdir, newname) ! 1216: ! 1217: fcookie *olddir; ! 1218: ! 1219: char *oldname; ! 1220: ! 1221: fcookie *newdir; ! 1222: ! 1223: const char *newname; ! 1224: ! 1225: { ! 1226: ! 1227: char newbuf[128]; ! 1228: ! 1229: struct tindex *ti; ! 1230: ! 1231: long r; ! 1232: ! 1233: ! 1234: ! 1235: (void)tfullpath(tmpbuf, (struct tindex *)olddir->index, oldname); ! 1236: ! 1237: (void)tfullpath(newbuf, (struct tindex *)newdir->index, newname); ! 1238: ! 1239: r = Frename(0, tmpbuf, newbuf); ! 1240: ! 1241: if (r == 0) { ! 1242: ! 1243: ti = tstrindex(tmpbuf); ! 1244: ! 1245: kfree(ti->name); ! 1246: ! 1247: ti->name = kmalloc((long)strlen(newbuf)+1); ! 1248: ! 1249: if (!ti->name) { ! 1250: ! 1251: FATAL("tosfs: unable to allocate space for a name"); ! 1252: ! 1253: } ! 1254: ! 1255: strcpy(ti->name, newbuf); ! 1256: ! 1257: ti->valid = 0; ! 1258: ! 1259: } ! 1260: ! 1261: return r; ! 1262: ! 1263: } ! 1264: ! 1265: ! 1266: ! 1267: #define DIR_FLAG(x) (x->fsstuff[0]) ! 1268: ! 1269: #define STARTSEARCH 0 /* opendir() was just called */ ! 1270: ! 1271: #define INSEARCH 1 /* readdir() has been called at least once */ ! 1272: ! 1273: #define NMFILE 2 /* no more files to read */ ! 1274: ! 1275: ! 1276: ! 1277: #define DIR_DTA(x) ((DTABUF *)(x->fsstuff + 2)) ! 1278: ! 1279: #define DIR_NAME(x) (x->fsstuff + 32) ! 1280: ! 1281: ! 1282: ! 1283: /* ! 1284: ! 1285: * The directory functions are a bit tricky. What we do is have ! 1286: ! 1287: * opendir() do Fsfirst; the first readdir() picks up this name, ! 1288: ! 1289: * subsequent readdir()'s have to do Fsnext ! 1290: ! 1291: */ ! 1292: ! 1293: ! 1294: ! 1295: static long ! 1296: ! 1297: tos_opendir(dirh, flags) ! 1298: ! 1299: DIR *dirh; ! 1300: ! 1301: int flags; ! 1302: ! 1303: { ! 1304: ! 1305: long r; ! 1306: ! 1307: struct tindex *t = (struct tindex *)dirh->fc.index; ! 1308: ! 1309: ! 1310: ! 1311: (void)tfullpath(tmpbuf, t, "*.*"); ! 1312: ! 1313: ! 1314: ! 1315: do_setdta(DIR_DTA(dirh)); ! 1316: ! 1317: ! 1318: ! 1319: r = Fsfirst(tmpbuf, FILEORDIR); ! 1320: ! 1321: ! 1322: ! 1323: if (r == 0) { ! 1324: ! 1325: t->open++; ! 1326: ! 1327: DIR_FLAG(dirh) = STARTSEARCH; ! 1328: ! 1329: return 0; ! 1330: ! 1331: } else if (r == EFILNF) { ! 1332: ! 1333: t->open++; ! 1334: ! 1335: DIR_FLAG(dirh) = NMFILE; ! 1336: ! 1337: return 0; ! 1338: ! 1339: } ! 1340: ! 1341: return r; ! 1342: ! 1343: } ! 1344: ! 1345: ! 1346: ! 1347: static long ! 1348: ! 1349: tos_readdir(dirh, name, namelen, fc) ! 1350: ! 1351: DIR *dirh; ! 1352: ! 1353: char *name; ! 1354: ! 1355: int namelen; ! 1356: ! 1357: fcookie *fc; ! 1358: ! 1359: { ! 1360: ! 1361: static long index = 0; ! 1362: ! 1363: long ret; ! 1364: ! 1365: int giveindex = dirh->flags == 0; ! 1366: ! 1367: struct tindex *ti; ! 1368: ! 1369: DTABUF *dta = DIR_DTA(dirh); ! 1370: ! 1371: ! 1372: ! 1373: again: ! 1374: ! 1375: if (DIR_FLAG(dirh) == NMFILE) ! 1376: ! 1377: return ENMFIL; ! 1378: ! 1379: ! 1380: ! 1381: if (DIR_FLAG(dirh) == STARTSEARCH) { ! 1382: ! 1383: DIR_FLAG(dirh) = INSEARCH; ! 1384: ! 1385: } else { ! 1386: ! 1387: assert(DIR_FLAG(dirh) == INSEARCH); ! 1388: ! 1389: do_setdta(dta); ! 1390: ! 1391: ret = Fsnext(); ! 1392: ! 1393: if (ret) { ! 1394: ! 1395: DIR_FLAG(dirh) = NMFILE; ! 1396: ! 1397: return ret; ! 1398: ! 1399: } ! 1400: ! 1401: } ! 1402: ! 1403: ! 1404: ! 1405: /* don't return volume labels from readdir */ ! 1406: ! 1407: if (dta->dta_attrib == FA_LABEL) goto again; ! 1408: ! 1409: ! 1410: ! 1411: fc->fs = &tos_filesys; ! 1412: ! 1413: fc->dev = dirh->fc.dev; ! 1414: ! 1415: ! 1416: ! 1417: (void)tfullpath(tmpiname, (struct tindex *)dirh->fc.index, DIR_NAME(dirh)); ! 1418: ! 1419: ! 1420: ! 1421: ti = &tmpindex; ! 1422: ! 1423: ti->name = tmpiname; ! 1424: ! 1425: ti->valid = 1; ! 1426: ! 1427: ti->size = dta->dta_size; ! 1428: ! 1429: ti->date = dta->dta_date; ! 1430: ! 1431: ti->time = dta->dta_time; ! 1432: ! 1433: ti->attr = dta->dta_attrib; ! 1434: ! 1435: ti->stamp = tclock; ! 1436: ! 1437: if (executable_extension(dta->dta_name)) ! 1438: ! 1439: ti->attr |= FA_EXEC; ! 1440: ! 1441: fc->index = (long)ti; ! 1442: ! 1443: ! 1444: ! 1445: if (giveindex) { ! 1446: ! 1447: namelen -= sizeof(long); ! 1448: ! 1449: if (namelen <= 0) return ERANGE; ! 1450: ! 1451: *((long *)name) = index++; ! 1452: ! 1453: name += sizeof(long); ! 1454: ! 1455: } ! 1456: ! 1457: strncpy(name, DIR_NAME(dirh), namelen-1); ! 1458: ! 1459: name[namelen-1] = 0; ! 1460: ! 1461: if (curproc->domain == DOM_MINT) { ! 1462: ! 1463: strlwr(name); ! 1464: ! 1465: } ! 1466: ! 1467: if (strlen(DIR_NAME(dirh)) >= namelen) ! 1468: ! 1469: return ENAMETOOLONG; ! 1470: ! 1471: else ! 1472: ! 1473: return 0; ! 1474: ! 1475: } ! 1476: ! 1477: ! 1478: ! 1479: static long ! 1480: ! 1481: tos_rewinddir(dirh) ! 1482: ! 1483: DIR *dirh; ! 1484: ! 1485: { ! 1486: ! 1487: struct tindex *ti = (struct tindex *)dirh->fc.index; ! 1488: ! 1489: long r; ! 1490: ! 1491: ! 1492: ! 1493: (void)tfullpath(tmpbuf, ti, "*.*"); ! 1494: ! 1495: do_setdta(DIR_DTA(dirh)); ! 1496: ! 1497: r = Fsfirst(tmpbuf, FILEORDIR); ! 1498: ! 1499: if (r == 0) { ! 1500: ! 1501: DIR_FLAG(dirh) = STARTSEARCH; ! 1502: ! 1503: } else { ! 1504: ! 1505: DIR_FLAG(dirh) = NMFILE; ! 1506: ! 1507: } ! 1508: ! 1509: return r; ! 1510: ! 1511: } ! 1512: ! 1513: ! 1514: ! 1515: static long ! 1516: ! 1517: tos_closedir(dirh) ! 1518: ! 1519: DIR *dirh; ! 1520: ! 1521: { ! 1522: ! 1523: struct tindex *t = (struct tindex *)dirh->fc.index; ! 1524: ! 1525: ! 1526: ! 1527: assert(t->open); ! 1528: ! 1529: --t->open; ! 1530: ! 1531: DIR_FLAG(dirh) = NMFILE; ! 1532: ! 1533: return 0; ! 1534: ! 1535: } ! 1536: ! 1537: ! 1538: ! 1539: static long ! 1540: ! 1541: tos_pathconf(dir, which) ! 1542: ! 1543: fcookie *dir; ! 1544: ! 1545: int which; ! 1546: ! 1547: { ! 1548: ! 1549: switch(which) { ! 1550: ! 1551: case -1: ! 1552: ! 1553: return DP_MAXREQ; ! 1554: ! 1555: case DP_IOPEN: ! 1556: ! 1557: return 60; /* we can only keep about this many open */ ! 1558: ! 1559: case DP_MAXLINKS: ! 1560: ! 1561: return 1; /* no hard links */ ! 1562: ! 1563: case DP_PATHMAX: ! 1564: ! 1565: return PATH_MAX; ! 1566: ! 1567: case DP_NAMEMAX: ! 1568: ! 1569: return 8+3+1; ! 1570: ! 1571: case DP_ATOMIC: ! 1572: ! 1573: return 512; /* we can write at least a sector atomically */ ! 1574: ! 1575: case DP_TRUNC: ! 1576: ! 1577: return DP_DOSTRUNC; /* DOS style file names */ ! 1578: ! 1579: case DP_CASE: ! 1580: ! 1581: return DP_CASECONV; /* names converted to upper case */ ! 1582: ! 1583: default: ! 1584: ! 1585: return EINVFN; ! 1586: ! 1587: } ! 1588: ! 1589: } ! 1590: ! 1591: ! 1592: ! 1593: long ! 1594: ! 1595: tos_dfree(dir, buf) ! 1596: ! 1597: fcookie *dir; ! 1598: ! 1599: long *buf; ! 1600: ! 1601: { ! 1602: ! 1603: return Dfree(buf, (dir->dev)+1); ! 1604: ! 1605: } ! 1606: ! 1607: ! 1608: ! 1609: /* ! 1610: ! 1611: * writelabel: creates a volume label ! 1612: ! 1613: * readlabel: reads a volume label ! 1614: ! 1615: * both of these are only guaranteed to work in the root directory ! 1616: ! 1617: */ ! 1618: ! 1619: ! 1620: ! 1621: /* ! 1622: ! 1623: * BUG: this should first delete any old labels, so that it will ! 1624: ! 1625: * work with TOS <1.4 ! 1626: ! 1627: */ ! 1628: ! 1629: ! 1630: ! 1631: long ! 1632: ! 1633: tos_writelabel(dir, name) ! 1634: ! 1635: fcookie *dir; ! 1636: ! 1637: const char *name; ! 1638: ! 1639: { ! 1640: ! 1641: long r; ! 1642: ! 1643: struct tindex *ti; ! 1644: ! 1645: ! 1646: ! 1647: (void)tfullpath(tmpbuf, (struct tindex *)dir->index, name); ! 1648: ! 1649: r = Fcreate(tmpbuf, FA_LABEL); ! 1650: ! 1651: if (r < 0) return r; ! 1652: ! 1653: (void)Fclose(r); ! 1654: ! 1655: ti = tstrindex(tmpbuf); ! 1656: ! 1657: ti->valid = 0; ! 1658: ! 1659: return 0; ! 1660: ! 1661: } ! 1662: ! 1663: ! 1664: ! 1665: long ! 1666: ! 1667: tos_readlabel(dir, name, namelen) ! 1668: ! 1669: fcookie *dir; ! 1670: ! 1671: char *name; ! 1672: ! 1673: int namelen; ! 1674: ! 1675: { ! 1676: ! 1677: long r; ! 1678: ! 1679: struct tindex *ti = (struct tindex *)dir->index; ! 1680: ! 1681: ! 1682: ! 1683: if (ti->name[2] != 0) /* not a root directory? */ ! 1684: ! 1685: return EFILNF; ! 1686: ! 1687: ! 1688: ! 1689: (void)tfullpath(tmpbuf, ti, "*.*"); ! 1690: ! 1691: do_setdta(&foo); ! 1692: ! 1693: r = Fsfirst(tmpbuf, FA_LABEL); ! 1694: ! 1695: if (r) ! 1696: ! 1697: return r; ! 1698: ! 1699: strncpy(name, foo.dta_name, namelen-1); ! 1700: ! 1701: return (strlen(foo.dta_name) < namelen) ? 0 : ENAMETOOLONG; ! 1702: ! 1703: } ! 1704: ! 1705: ! 1706: ! 1707: /* ! 1708: ! 1709: * TOS creat: this doesn't actually create the file, rather it ! 1710: ! 1711: * sets up a (fake) index for the file that will be used by ! 1712: ! 1713: * the later tos_open call. ! 1714: ! 1715: */ ! 1716: ! 1717: ! 1718: ! 1719: static long ! 1720: ! 1721: tos_creat(dir, name, mode, attrib, fc) ! 1722: ! 1723: fcookie *dir; ! 1724: ! 1725: const char *name; ! 1726: ! 1727: unsigned mode; ! 1728: ! 1729: int attrib; ! 1730: ! 1731: fcookie *fc; ! 1732: ! 1733: { ! 1734: ! 1735: struct tindex *ti; ! 1736: ! 1737: ! 1738: ! 1739: (void)tfullpath(tmpbuf, (struct tindex *)dir->index, name); ! 1740: ! 1741: ! 1742: ! 1743: ti = tstrindex(tmpbuf); ! 1744: ! 1745: ti->size = 0; ! 1746: ! 1747: ti->date = datestamp; ! 1748: ! 1749: ti->time = timestamp; ! 1750: ! 1751: ti->attr = attrib; ! 1752: ! 1753: ti->valid = 1; ! 1754: ! 1755: ! 1756: ! 1757: fc->fs = &tos_filesys; ! 1758: ! 1759: fc->index = (long)ti; ! 1760: ! 1761: fc->dev = dir->dev; ! 1762: ! 1763: return 0; ! 1764: ! 1765: } ! 1766: ! 1767: ! 1768: ! 1769: /* ! 1770: ! 1771: * TOS device driver ! 1772: ! 1773: */ ! 1774: ! 1775: ! 1776: ! 1777: static DEVDRV * ! 1778: ! 1779: tos_getdev(fc, devsp) ! 1780: ! 1781: fcookie *fc; ! 1782: ! 1783: long *devsp; ! 1784: ! 1785: { ! 1786: ! 1787: return &tos_device; ! 1788: ! 1789: } ! 1790: ! 1791: ! 1792: ! 1793: static long ! 1794: ! 1795: tos_open(f) ! 1796: ! 1797: FILEPTR *f; ! 1798: ! 1799: { ! 1800: ! 1801: struct tindex *ti; ! 1802: ! 1803: int mode = f->flags; ! 1804: ! 1805: int tosmode; ! 1806: ! 1807: long r; ! 1808: ! 1809: extern int flk; /* in main.c, set if _FLK cookie already present */ ! 1810: ! 1811: ! 1812: ! 1813: ti = (struct tindex *)(f->fc.index); ! 1814: ! 1815: assert(ti != 0); ! 1816: ! 1817: ! 1818: ! 1819: ti->stamp = ++tclock; ! 1820: ! 1821: ti->valid = 0; ! 1822: ! 1823: ! 1824: ! 1825: /* TEMPORARY HACK: change all modes to O_RDWR for files opened in ! 1826: ! 1827: * compatibility sharing mode. This is silly, but ! 1828: ! 1829: * allows broken TOS programs that write to read-only handles to continue ! 1830: ! 1831: * to work (it also helps file sharing, by making the realistic assumption ! 1832: ! 1833: * that any open TOS file can be written to). Eventually, ! 1834: ! 1835: * this should be tuneable by the user somehow. ! 1836: ! 1837: * ALSO: change O_COMPAT opens into O_DENYNONE; again, this may be temporary. ! 1838: ! 1839: */ ! 1840: ! 1841: if ( (mode & O_SHMODE) == O_COMPAT ) { ! 1842: ! 1843: f->flags = (mode & ~(O_RWMODE|O_SHMODE)) | O_RDWR | O_DENYNONE; ! 1844: ! 1845: } ! 1846: ! 1847: ! 1848: ! 1849: /* check to see that nobody has opened this file already in an ! 1850: ! 1851: * incompatible mode ! 1852: ! 1853: */ ! 1854: ! 1855: if (denyshare(ti->open, f)) { ! 1856: ! 1857: TRACE("tos_open: file sharing denied"); ! 1858: ! 1859: return EACCDN; ! 1860: ! 1861: } ! 1862: ! 1863: ! 1864: ! 1865: /* ! 1866: ! 1867: * now open the file; if O_TRUNC was specified, actually ! 1868: ! 1869: * create the file anew. ! 1870: ! 1871: * BUG: O_TRUNC without O_CREAT doesn't work right. The kernel doesn't ! 1872: ! 1873: * use this mode, anyways ! 1874: ! 1875: */ ! 1876: ! 1877: ! 1878: ! 1879: if (mode & O_TRUNC) { ! 1880: ! 1881: if (ti->open) { ! 1882: ! 1883: DEBUG("tos_open: attempt to truncate an open file"); ! 1884: ! 1885: return EACCDN; ! 1886: ! 1887: } ! 1888: ! 1889: r = Fcreate(ti->name, ti->attr); ! 1890: ! 1891: } else { ! 1892: ! 1893: if (flk) ! 1894: ! 1895: tosmode = mode & (O_RWMODE|O_SHMODE); ! 1896: ! 1897: else ! 1898: ! 1899: tosmode = (mode & O_RWMODE); ! 1900: ! 1901: if (tosmode == O_EXEC) tosmode = O_RDONLY; ! 1902: ! 1903: ! 1904: ! 1905: r = Fopen(ti->name, tosmode ); ! 1906: ! 1907: if (r == EFILNF && (mode & O_CREAT)) ! 1908: ! 1909: r = Fcreate(ti->name, ti->attr); ! 1910: ! 1911: } ! 1912: ! 1913: ! 1914: ! 1915: if (r < 0) { ! 1916: ! 1917: /* get rid of the index for the file, since it doesn't exist */ ! 1918: ! 1919: kfree(ti->name); ! 1920: ! 1921: ti->name = 0; ! 1922: ! 1923: ti->valid = 0; ! 1924: ! 1925: return r; ! 1926: ! 1927: } ! 1928: ! 1929: ! 1930: ! 1931: f->devinfo = r; ! 1932: ! 1933: ! 1934: ! 1935: f->next = ti->open; ! 1936: ! 1937: ti->open = f; ! 1938: ! 1939: return 0; ! 1940: ! 1941: } ! 1942: ! 1943: ! 1944: ! 1945: static long ! 1946: ! 1947: tos_write(f, buf, bytes) ! 1948: ! 1949: FILEPTR *f; const char *buf; long bytes; ! 1950: ! 1951: { ! 1952: ! 1953: struct tindex *ti = (struct tindex *)f->fc.index; ! 1954: ! 1955: ! 1956: ! 1957: ti->valid = 0; ! 1958: ! 1959: return Fwrite((int)f->devinfo, bytes, buf); ! 1960: ! 1961: } ! 1962: ! 1963: ! 1964: ! 1965: static long ! 1966: ! 1967: tos_read(f, buf, bytes) ! 1968: ! 1969: FILEPTR *f; char *buf; long bytes; ! 1970: ! 1971: { ! 1972: ! 1973: return Fread((int)f->devinfo, bytes, buf); ! 1974: ! 1975: } ! 1976: ! 1977: ! 1978: ! 1979: static long ! 1980: ! 1981: tos_lseek(f, where, whence) ! 1982: ! 1983: FILEPTR *f; long where; int whence; ! 1984: ! 1985: { ! 1986: ! 1987: long r; ! 1988: ! 1989: ! 1990: ! 1991: r = Fseek(where, (int)f->devinfo, whence); ! 1992: ! 1993: return r; ! 1994: ! 1995: } ! 1996: ! 1997: ! 1998: ! 1999: static long ! 2000: ! 2001: tos_ioctl(f, mode, buf) ! 2002: ! 2003: FILEPTR *f; int mode; void *buf; ! 2004: ! 2005: { ! 2006: ! 2007: LOCK t, *lck, **old; ! 2008: ! 2009: struct flock *fl; ! 2010: ! 2011: long r; ! 2012: ! 2013: struct tindex *ti; ! 2014: ! 2015: extern int flk; /* set in main.c if _FLK already installed */ ! 2016: ! 2017: ! 2018: ! 2019: if (mode == FIONREAD || mode == FIONWRITE) { ! 2020: ! 2021: *((long *)buf) = 1; ! 2022: ! 2023: return 0; ! 2024: ! 2025: } ! 2026: ! 2027: else if (mode == F_SETLK || mode == F_GETLK) { ! 2028: ! 2029: fl = ((struct flock *)buf); ! 2030: ! 2031: t.l = *fl; ! 2032: ! 2033: switch(t.l.l_whence) { ! 2034: ! 2035: case 0: ! 2036: ! 2037: break; ! 2038: ! 2039: case 1: /* SEEK_CUR */ ! 2040: ! 2041: r = Fseek(0L, (int)f->devinfo, 1); ! 2042: ! 2043: t.l.l_start += r; ! 2044: ! 2045: break; ! 2046: ! 2047: case 2: ! 2048: ! 2049: r = Fseek(0L, (int)f->devinfo, 1); ! 2050: ! 2051: t.l.l_start = Fseek(t.l.l_start, (int)f->devinfo, 2); ! 2052: ! 2053: (void)Fseek(r, (int)f->devinfo, 0); ! 2054: ! 2055: break; ! 2056: ! 2057: default: ! 2058: ! 2059: DEBUG("Invalid value for l_whence"); ! 2060: ! 2061: return EINVFN; ! 2062: ! 2063: } ! 2064: ! 2065: /* BUG: can't lock a file starting at >2gigabytes from the beginning */ ! 2066: ! 2067: if (t.l.l_start < 0) t.l.l_start = 0; ! 2068: ! 2069: t.l.l_whence = 0; ! 2070: ! 2071: ti = (struct tindex *)f->fc.index; ! 2072: ! 2073: ! 2074: ! 2075: if (mode == F_GETLK) { ! 2076: ! 2077: lck = denylock(ti->locks, &t); ! 2078: ! 2079: if (lck) ! 2080: ! 2081: *fl = lck->l; ! 2082: ! 2083: else ! 2084: ! 2085: fl->l_type = F_UNLCK; ! 2086: ! 2087: return 0; ! 2088: ! 2089: } ! 2090: ! 2091: ! 2092: ! 2093: if (t.l.l_type == F_UNLCK) { ! 2094: ! 2095: /* try to find the lock */ ! 2096: ! 2097: old = &ti->locks; ! 2098: ! 2099: lck = *old; ! 2100: ! 2101: while (lck) { ! 2102: ! 2103: if (lck->l.l_pid == curproc->pid && ! 2104: ! 2105: lck->l.l_start == t.l.l_start && ! 2106: ! 2107: lck->l.l_len == t.l.l_len) { ! 2108: ! 2109: /* found it -- remove the lock */ ! 2110: ! 2111: *old = lck->next; ! 2112: ! 2113: TRACE("tosfs: unlocked %s: %ld + %ld", ! 2114: ! 2115: ti->name, t.l.l_start, t.l.l_len); ! 2116: ! 2117: kfree(lck); ! 2118: ! 2119: if (flk) ! 2120: ! 2121: (void)Flock((int)f->devinfo, 1, ! 2122: ! 2123: t.l.l_start, t.l.l_len); ! 2124: ! 2125: break; ! 2126: ! 2127: } ! 2128: ! 2129: old = &lck->next; ! 2130: ! 2131: lck = lck->next; ! 2132: ! 2133: } ! 2134: ! 2135: return lck ? 0 : ENSLOCK; ! 2136: ! 2137: } ! 2138: ! 2139: TRACE("tosfs: lock %s: %ld + %ld", ti->name, ! 2140: ! 2141: t.l.l_start, t.l.l_len); ! 2142: ! 2143: /* see if there's a conflicting lock */ ! 2144: ! 2145: lck = denylock(ti->locks, &t); ! 2146: ! 2147: if (lck) { ! 2148: ! 2149: DEBUG("tosfs: lock conflicts with one held by %d", ! 2150: ! 2151: lck->l.l_pid); ! 2152: ! 2153: return ELOCKED; ! 2154: ! 2155: } ! 2156: ! 2157: /* if not, add this lock to the list */ ! 2158: ! 2159: lck = kmalloc(SIZEOF(LOCK)); ! 2160: ! 2161: if (!lck) return ENSMEM; ! 2162: ! 2163: /* see if other _FLK code might object */ ! 2164: ! 2165: if (flk) { ! 2166: ! 2167: r = Flock((int)f->devinfo, 0, t.l.l_start, t.l.l_len); ! 2168: ! 2169: if (r) { ! 2170: ! 2171: kfree(lck); ! 2172: ! 2173: return r; ! 2174: ! 2175: } ! 2176: ! 2177: } ! 2178: ! 2179: lck->l = t.l; ! 2180: ! 2181: lck->l.l_pid = curproc->pid; ! 2182: ! 2183: lck->next = ti->locks; ! 2184: ! 2185: ti->locks = lck; ! 2186: ! 2187: /* mark the file as being locked */ ! 2188: ! 2189: f->flags |= O_LOCK; ! 2190: ! 2191: return 0; ! 2192: ! 2193: } ! 2194: ! 2195: return EINVFN; ! 2196: ! 2197: } ! 2198: ! 2199: ! 2200: ! 2201: static long ! 2202: ! 2203: tos_datime(f, timeptr, rwflag) ! 2204: ! 2205: FILEPTR *f; ! 2206: ! 2207: short *timeptr; ! 2208: ! 2209: int rwflag; ! 2210: ! 2211: { ! 2212: ! 2213: if (rwflag) { ! 2214: ! 2215: struct tindex *ti = (struct tindex *)f->fc.index; ! 2216: ! 2217: ti->valid = 0; ! 2218: ! 2219: } ! 2220: ! 2221: return Fdatime(timeptr, (int)f->devinfo, rwflag); ! 2222: ! 2223: } ! 2224: ! 2225: ! 2226: ! 2227: static long ! 2228: ! 2229: tos_close(f, pid) ! 2230: ! 2231: FILEPTR *f; ! 2232: ! 2233: int pid; ! 2234: ! 2235: { ! 2236: ! 2237: LOCK *lck, **oldl; ! 2238: ! 2239: struct tindex *t; ! 2240: ! 2241: FILEPTR **old, *p; ! 2242: ! 2243: long r = 0; ! 2244: ! 2245: extern int flk; /* set in main.c */ ! 2246: ! 2247: ! 2248: ! 2249: t = (struct tindex *)(f->fc.index); ! 2250: ! 2251: /* if this handle was locked, remove any locks held by the process ! 2252: ! 2253: */ ! 2254: ! 2255: if (f->flags & O_LOCK) { ! 2256: ! 2257: TRACE("tos_close: releasing locks (file mode: %x)", f->flags); ! 2258: ! 2259: oldl = &t->locks; ! 2260: ! 2261: lck = *oldl; ! 2262: ! 2263: while (lck) { ! 2264: ! 2265: if (lck->l.l_pid == pid) { ! 2266: ! 2267: *oldl = lck->next; ! 2268: ! 2269: if (flk) ! 2270: ! 2271: (void)Flock((int)f->devinfo, 1, ! 2272: ! 2273: lck->l.l_start, lck->l.l_len); ! 2274: ! 2275: kfree(lck); ! 2276: ! 2277: } else { ! 2278: ! 2279: oldl = &lck->next; ! 2280: ! 2281: } ! 2282: ! 2283: lck = *oldl; ! 2284: ! 2285: } ! 2286: ! 2287: } ! 2288: ! 2289: ! 2290: ! 2291: if (f->links <= 0) { ! 2292: ! 2293: /* remove f from the list of open file pointers on this index */ ! 2294: ! 2295: t->valid = 0; ! 2296: ! 2297: old = &t->open; ! 2298: ! 2299: p = t->open; ! 2300: ! 2301: while (p && p != f) { ! 2302: ! 2303: old = &p->next; ! 2304: ! 2305: p = p->next; ! 2306: ! 2307: } ! 2308: ! 2309: assert(p); ! 2310: ! 2311: *old = f->next; ! 2312: ! 2313: f->next = 0; ! 2314: ! 2315: r = Fclose((int)f->devinfo); ! 2316: ! 2317: ! 2318: ! 2319: /* if the file was marked for deletion, delete it */ ! 2320: ! 2321: if (!t->open) { ! 2322: ! 2323: if (t->attr & FA_DELETE) { ! 2324: ! 2325: (void)Fdelete(t->name); ! 2326: ! 2327: t->name = 0; ! 2328: ! 2329: } ! 2330: ! 2331: } ! 2332: ! 2333: } ! 2334: ! 2335: return r; ! 2336: ! 2337: } ! 2338: ! 2339: ! 2340: ! 2341: /* ! 2342: ! 2343: * check for disk change: called by the kernel if Mediach returns a ! 2344: ! 2345: * non-zero value ! 2346: ! 2347: */ ! 2348: ! 2349: ! 2350: ! 2351: long ! 2352: ! 2353: tos_dskchng(drv) ! 2354: ! 2355: int drv; ! 2356: ! 2357: { ! 2358: ! 2359: char dlet; ! 2360: ! 2361: int i; ! 2362: ! 2363: struct tindex *ti; ! 2364: ! 2365: ! 2366: ! 2367: dlet = 'A' + drv; ! 2368: ! 2369: ti = gl_ti; ! 2370: ! 2371: for (i = 0; i < NUM_INDICES; i++, ti++) { ! 2372: ! 2373: if (ti->name[0] == dlet) { ! 2374: ! 2375: kfree(ti->name); ! 2376: ! 2377: ti->name = 0; ! 2378: ! 2379: } ! 2380: ! 2381: } ! 2382: ! 2383: /* ! 2384: ! 2385: * OK, make sure that GEMDOS knows to look for a change if we ! 2386: ! 2387: * ever use this drive again. ! 2388: ! 2389: */ ! 2390: ! 2391: drvchanged[drv] = 1; ! 2392: ! 2393: return 1; ! 2394: ! 2395: } ! 2396: ! 2397: ! 2398: ! 2399: /* ! 2400: ! 2401: * utility function: sets the TOS DTA, and also records what directory ! 2402: ! 2403: * this was in. This is just to save us a call into the kernel if the ! 2404: ! 2405: * correct DTA has already been set. ! 2406: ! 2407: */ ! 2408: ! 2409: ! 2410: ! 2411: static void ! 2412: ! 2413: do_setdta(dta) ! 2414: ! 2415: DTABUF *dta; ! 2416: ! 2417: { ! 2418: ! 2419: if (dta != lastdta) { ! 2420: ! 2421: Fsetdta(dta); ! 2422: ! 2423: lastdta = dta; ! 2424: ! 2425: } ! 2426: ! 2427: } ! 2428: ! 2429: ! 2430: ! 2431: /* ! 2432: ! 2433: * routines for forcing a media change on drive "drv" ! 2434: ! 2435: */ ! 2436: ! 2437: ! 2438: ! 2439: static int chdrv; ! 2440: ! 2441: ! 2442: ! 2443: /* new Getbpb function: when this is called, all the other ! 2444: ! 2445: * vectors can be un-installed ! 2446: ! 2447: */ ! 2448: ! 2449: ! 2450: ! 2451: static long (*Oldgetbpb) P_((int)); ! 2452: ! 2453: static long (*Oldmediach) P_((int)); ! 2454: ! 2455: static long (*Oldrwabs) P_((int, void *, int, int, int, long)); ! 2456: ! 2457: ! 2458: ! 2459: static long ! 2460: ! 2461: Newgetbpb(d) ! 2462: ! 2463: int d; ! 2464: ! 2465: { ! 2466: ! 2467: if (d == chdrv) { ! 2468: ! 2469: *((Func *)0x472L) = Oldgetbpb; ! 2470: ! 2471: *((Func *)0x476L) = Oldrwabs; ! 2472: ! 2473: *((Func *)0x47eL) = Oldmediach; ! 2474: ! 2475: } ! 2476: ! 2477: return (*Oldgetbpb)(d); ! 2478: ! 2479: } ! 2480: ! 2481: ! 2482: ! 2483: static long ! 2484: ! 2485: Newmediach(d) ! 2486: ! 2487: int d; ! 2488: ! 2489: { ! 2490: ! 2491: if (d == chdrv) ! 2492: ! 2493: return 2; ! 2494: ! 2495: return (*Oldmediach)(d); ! 2496: ! 2497: } ! 2498: ! 2499: ! 2500: ! 2501: static long ! 2502: ! 2503: Newrwabs(d, buf, a, b, c, l) ! 2504: ! 2505: int d; ! 2506: ! 2507: void *buf; ! 2508: ! 2509: int a, b, c; ! 2510: ! 2511: long l; ! 2512: ! 2513: { ! 2514: ! 2515: if (d == chdrv) ! 2516: ! 2517: return E_CHNG; ! 2518: ! 2519: return (*Oldrwabs)(d, buf, a, b, c, l); ! 2520: ! 2521: } ! 2522: ! 2523: ! 2524: ! 2525: static void ! 2526: ! 2527: force_mediach(d) ! 2528: ! 2529: int d; ! 2530: ! 2531: { ! 2532: ! 2533: long r; ! 2534: ! 2535: static char fname[] = "X:\\.INF"; ! 2536: ! 2537: ! 2538: ! 2539: TRACE("tosfs: disk change drive %c", d+'A'); ! 2540: ! 2541: ! 2542: ! 2543: chdrv = d; ! 2544: ! 2545: Oldrwabs = *((Func *)0x476L); ! 2546: ! 2547: if (Oldrwabs == Newrwabs) { ! 2548: ! 2549: ALERT("tosfs: error in media change code"); ! 2550: ! 2551: } else { ! 2552: ! 2553: *((Func *)0x476L) = Newrwabs; ! 2554: ! 2555: Oldmediach = *((Func *)0x47eL); ! 2556: ! 2557: *((Func *)0x47eL) = Newmediach; ! 2558: ! 2559: Oldgetbpb = *((Func *)0x472L); ! 2560: ! 2561: *((Func *)0x472L) = Newgetbpb; ! 2562: ! 2563: } ! 2564: ! 2565: ! 2566: ! 2567: fname[0] = d + 'A'; ! 2568: ! 2569: r = Fopen(fname, 0); ! 2570: ! 2571: if (r >= 0) (void)Fclose(r); ! 2572: ! 2573: ! 2574: ! 2575: drvchanged[d] = 0; ! 2576: ! 2577: } ! 2578:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.