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