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