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