|
|
1.1 root 1: /*
2:
3: Copyright 1990,1991,1992 Eric R. Smith. All rights reserved.
4:
5: */
6:
7:
8:
9: /* DOS directory functions */
10:
11:
12:
13: #include "mint.h"
14:
15:
16:
17: /* change to a new drive: should always return a map of valid drives */
18:
19:
20:
21: long
22:
23: d_setdrv(d)
24:
25: int d;
26:
27: {
28:
29: long r;
30:
31: extern long dosdrvs; /* in filesys.c */
32:
33:
34:
35: r = drvmap() | dosdrvs | PSEUDODRVS;
36:
37:
38:
39: TRACE("Dsetdrv(%d)", d);
40:
41: if (d < 0 || d >= NUM_DRIVES || (r & (1L << d)) == 0) {
42:
43: DEBUG("Dsetdrv: invalid drive %d", d);
44:
45: return r;
46:
47: }
48:
49:
50:
51: curproc->base->p_defdrv = curproc->curdrv = d;
52:
53: return r;
54:
55: }
56:
57:
58:
59: long
60:
61: d_getdrv()
62:
63: {
64:
65: TRACE("Dgetdrv");
66:
67: return curproc->curdrv;
68:
69: }
70:
71:
72:
73: long
74:
75: d_free(buf, d)
76:
77: long *buf;
78:
79: int d;
80:
81: {
82:
83: fcookie *dir;
84:
85:
86:
87: TRACE("Dfree(%d)", d);
88:
89:
90:
91: /* drive 0 means current drive, otherwise it's d-1 */
92:
93: if (d)
94:
95: d = d-1;
96:
97: else
98:
99: d = curproc->curdrv;
100:
101:
102:
103: if (d < 0 || d >= NUM_DRIVES)
104:
105: return EDRIVE;
106:
107:
108:
109: /* check for a media change -- we don't care much either way, but it
110:
111: * does keep the results more accurate
112:
113: */
114:
115: (void)disk_changed(d);
116:
117:
118:
119: /* use current directory, not root, since it's more likely that
120:
121: * programs are interested in the latter (this makes U: work much
122:
123: * better)
124:
125: */
126:
127: dir = &curproc->curdir[d];
128:
129: if (!dir->fs) {
130:
131: DEBUG("Dfree: bad drive");
132:
133: return EDRIVE;
134:
135: }
136:
137:
138:
139: return (*dir->fs->dfree)(dir, buf);
140:
141: }
142:
143:
144:
145: /* temp1 is a convenient place for path2fs puts the last component of
146:
147: * the path name
148:
149: */
150:
151:
152:
153: extern char temp1[PATH_MAX]; /* in filesys.c */
154:
155:
156:
157: long
158:
159: d_create(path)
160:
161: const char *path;
162:
163: {
164:
165: fcookie dir;
166:
167: long r;
168:
169:
170:
171: TRACE("Dcreate(%s)", path);
172:
173:
174:
175: r = path2cookie(path, temp1, &dir);
176:
177: if (r) {
178:
179: DEBUG("Dcreate(%s): returning %ld", path, r);
180:
181: return r; /* an error occured */
182:
183: }
184:
185: /* check for write permission on the directory */
186:
187: r = dir_access(&dir, S_IWOTH);
188:
189: if (r) {
190:
191: DEBUG("Dcreate(%s): access to directory denied",path);
192:
193: return r;
194:
195: }
196:
197: return (*dir.fs->mkdir)(&dir, temp1, DEFAULT_DIRMODE & ~curproc->umask);
198:
199: }
200:
201:
202:
203: long
204:
205: d_delete(path)
206:
207: const char *path;
208:
209: {
210:
211: fcookie parentdir, targdir;
212:
213: long r;
214:
215: PROC *p;
216:
217: int i;
218:
219: XATTR xattr;
220:
221:
222:
223: TRACE("Ddelete(%s)", path);
224:
225:
226:
227: r = path2cookie(path, temp1, &parentdir);
228:
229:
230:
231: if (r) {
232:
233: DEBUG("Ddelete(%s): error %lx", path, r);
234:
235: return r;
236:
237: }
238:
239: /* check for write permission on the directory which the target
240:
241: * is located
242:
243: */
244:
245: if (r = dir_access(&parentdir, S_IWOTH)) {
246:
247: DEBUG("Ddelete(%s): access to directory denied", path);
248:
249: return r;
250:
251: }
252:
253:
254:
255: /* now get the info on the file itself */
256:
257:
258:
259: r = relpath2cookie(&parentdir, temp1, NULL, &targdir, 0);
260:
261: if (r || (r = (*targdir.fs->getxattr)(&targdir, &xattr))) {
262:
263: DEBUG("Ddelete: error %ld on %s", r, path);
264:
265: return r;
266:
267: }
268:
269:
270:
271: /* if the "directory" is a symbolic link, really unlink it */
272:
273: if ( (xattr.mode & S_IFMT) == S_IFLNK ) {
274:
275: return (*parentdir.fs->remove)(&parentdir, temp1);
276:
277: }
278:
279: if ( (xattr.mode & S_IFMT) != S_IFDIR ) {
280:
281: DEBUG("Ddelete: %s is not a directory", path);
282:
283: return EPTHNF;
284:
285: }
286:
287:
288:
289: /* don't delete anyone else's root or current directory */
290:
291: for (p = proclist; p; p = p->gl_next) {
292:
293: if (p->wait_q == ZOMBIE_Q || p->wait_q == TSR_Q)
294:
295: continue;
296:
297: for (i = 0; i < NUM_DRIVES; i++) {
298:
299: if (samefile(&targdir, &p->root[i])) {
300:
301: DEBUG("Ddelete: directory %s is a root directory",
302:
303: path);
304:
305: return EACCDN;
306:
307: } else if (samefile(&targdir, &p->curdir[i])) {
308:
309: if (i == p->curdrv && p != curproc)
310:
311: DEBUG("Ddelete: directory %s is in use",
312:
313: path);
314:
315: else {
316:
317: p->curdir[i] = p->root[i];
318:
319: }
320:
321: }
322:
323: }
324:
325: }
326:
327:
328:
329: return (*parentdir.fs->rmdir)(&parentdir, temp1);
330:
331: }
332:
333:
334:
335: long
336:
337: d_setpath(path)
338:
339: const char *path;
340:
341: {
342:
343: fcookie dir;
344:
345: int drv = curproc->curdrv;
346:
347: int i;
348:
349: char c;
350:
351: long r;
352:
353: XATTR xattr;
354:
355:
356:
357: TRACE("Dsetpath(%s)", path);
358:
359:
360:
361: r = path2cookie(path, follow_links, &dir);
362:
363:
364:
365: if (r) {
366:
367: DEBUG("Dsetpath(%s): returning %ld", path, r);
368:
369: return r;
370:
371: }
372:
373:
374:
375: if (path[0] && path[1] == ':') {
376:
377: c = *path;
378:
379: if (c >= 'a' && c <= 'z')
380:
381: drv = c-'a';
382:
383: else if (c >= 'A' && c <= 'Z')
384:
385: drv = c-'A';
386:
387: }
388:
389:
390:
391: r = (*dir.fs->getxattr)(&dir, &xattr);
392:
393:
394:
395: if (r < 0) {
396:
397: DEBUG("Dsetpath: file '%s': attributes not found", path);
398:
399: return r;
400:
401: }
402:
403:
404:
405: if (!(xattr.attr & FA_DIR)) {
406:
407: DEBUG("Dsetpath(%s): not a directory",path);
408:
409: return EPTHNF;
410:
411: }
412:
413:
414:
415: /*
416:
417: * watch out for symbolic links; if c:\foo is a link to d:\bar, then
418:
419: * "cd c:\foo" should also change the drive to d:
420:
421: */
422:
423: if (drv != UNIDRV && dir.dev != curproc->root[drv].dev) {
424:
425: for (i = 0; i < NUM_DRIVES; i++) {
426:
427: if (curproc->root[i].dev == dir.dev &&
428:
429: curproc->root[i].fs == dir.fs) {
430:
431: if (drv == curproc->curdrv)
432:
433: curproc->curdrv = i;
434:
435: drv = i;
436:
437: break;
438:
439: }
440:
441: }
442:
443: }
444:
445: curproc->curdir[drv] = dir;
446:
447: return 0;
448:
449: }
450:
451:
452:
453: long
454:
455: d_getpath(path, drv)
456:
457: char *path;
458:
459: int drv;
460:
461: {
462:
463: fcookie *dir, *root;
464:
465:
466:
467: TRACE("Dgetpath(%c)", drv + '@');
468:
469: if (drv < 0 || drv > NUM_DRIVES)
470:
471: return EDRIVE;
472:
473:
474:
475: drv = (drv == 0) ? curproc->curdrv : drv-1;
476:
477:
478:
479: root = &curproc->root[drv];
480:
481:
482:
483: if (!root->fs) { /* maybe not initialized yet? */
484:
485: changedrv(drv);
486:
487: root = &curproc->curdir[drv];
488:
489: if (!root->fs)
490:
491: return EDRIVE;
492:
493: }
494:
495: dir = &curproc->curdir[drv];
496:
497:
498:
499: return (*root->fs->getname)(root, dir, path);
500:
501: }
502:
503:
504:
505: long
506:
507: f_setdta(dta)
508:
509: DTABUF *dta;
510:
511: {
512:
513:
514:
515: TRACE("Fsetdta: %lx", dta);
516:
517: curproc->dta = dta;
518:
519: curproc->base->p_dta = (char *)dta;
520:
521: return 0;
522:
523: }
524:
525:
526:
527: long
528:
529: f_getdta()
530:
531: {
532:
533: long r;
534:
535:
536:
537: r = (long)curproc->dta;
538:
539: TRACE("Fgetdta: returning %lx", r);
540:
541: return r;
542:
543: }
544:
545:
546:
547: /*
548:
549: * Fsfirst/next are actually implemented in terms of opendir/readdir/closedir.
550:
551: */
552:
553:
554:
555: long
556:
557: f_sfirst(path, attrib)
558:
559: const char *path;
560:
561: int attrib;
562:
563: {
564:
565: char *s, *slash;
566:
567: FILESYS *fs;
568:
569: fcookie dir, newdir;
570:
571: DTABUF *dta;
572:
573: DIR *dirh;
574:
575: XATTR xattr;
576:
577: long r;
578:
579: int i, havelabel;
580:
581:
582:
583: /* a special hack just for ksh0.4 -- it uses '/' in a search where
584:
585: * '\' was better. Note that normally we shouldn't go around changing
586:
587: * the strings that people send us!
588:
589: */
590:
591: if (curproc->domain == DOM_MINT && !strncmp(path, "x:/*.", 5))
592:
593: ((char *)path)[2] = '\\';
594:
595:
596:
597: TRACE("Fsfirst(%s, %x)", path, attrib);
598:
599:
600:
601: r = path2cookie(path, temp1, &dir);
602:
603:
604:
605: if (r) {
606:
607: DEBUG("Fsfirst(%s): path2cookie returned %ld", path, r);
608:
609: return r;
610:
611: }
612:
613:
614:
615: /*
616:
617: * we need to split the last name (which may be a pattern) off from
618:
619: * the rest of the path, even if FS_KNOPARSE is true
620:
621: */
622:
623: slash = 0;
624:
625: s = temp1;
626:
627: while (*s) {
628:
629: if (*s == '\\')
630:
631: slash = s;
632:
633: s++;
634:
635: }
636:
637:
638:
639: if (slash) {
640:
641: *slash++ = 0; /* slash now points to a name or pattern */
642:
643: r = relpath2cookie(&dir, temp1, follow_links, &newdir, 0);
644:
645: if (r) {
646:
647: DEBUG("Fsfirst(%s): lookup returned %ld", path, r);
648:
649: return r;
650:
651: }
652:
653: dir = newdir;
654:
655: } else {
656:
657: slash = temp1;
658:
659: }
660:
661:
662:
663: /* BUG? what if there really is an empty file name? */
664:
665: if (!*slash) {
666:
667: DEBUG("Fsfirst: empty pattern");
668:
669: return EFILNF;
670:
671: }
672:
673:
674:
675: fs = dir.fs;
676:
677: dta = curproc->dta;
678:
679:
680:
681: /* Now, see if we can find a DIR slot for the search. We use the following
682:
683: * heuristics to try to avoid destroying a slot:
684:
685: * (1) if the search doesn't use wildcards, don't bother with a slot
686:
687: * (2) if an existing slot was for the same DTA address, re-use it
688:
689: * (3) if there's a free slot, re-use it. Slots are freed when the
690:
691: * corresponding search is terminated.
692:
693: */
694:
695:
696:
697: for (i = 0; i < NUM_SEARCH; i++) {
698:
699: if (curproc->srchdta[i] == dta) {
700:
701: dirh = &curproc->srchdir[i];
702:
703: if (dirh->fc.fs) {
704:
705: (*dirh->fc.fs->closedir)(dirh);
706:
707: dirh->fc.fs = 0;
708:
709: }
710:
711: curproc->srchdta[i] = 0; /* slot is now free */
712:
713: }
714:
715: }
716:
717:
718:
719: /* copy the pattern over into dta_pat into TOS 8.3 form */
720:
721: /* remember that "slash" now points at the pattern (it follows the last \,
722:
723: if any)
724:
725: */
726:
727: copy8_3(dta->dta_pat, slash);
728:
729:
730:
731: /* if attrib & FA_LABEL, read the volume label */
732:
733: /* BUG: the label date and time are wrong. Does it matter?
734:
735: */
736:
737: havelabel = 0;
738:
739: if (attrib & FA_LABEL) {
740:
741: r = (*fs->readlabel)(&dir, dta->dta_name, TOS_NAMELEN);
742:
743: dta->dta_attrib = FA_LABEL;
744:
745: dta->dta_time = dta->dta_date = 0;
746:
747: dta->dta_size = 0;
748:
749: dta->magic = EVALID;
750:
751: if (r == 0 && !pat_match(dta->dta_name, dta->dta_pat))
752:
753: r = EFILNF;
754:
755: if (attrib == FA_LABEL)
756:
757: return r;
758:
759: else if (r == 0)
760:
761: havelabel = 1;
762:
763: }
764:
765:
766:
767: if (!havelabel && has_wild(slash) == 0) { /* no wild cards in pattern */
768:
769: r = relpath2cookie(&dir, slash, follow_links, &newdir, 0);
770:
771: if (r == 0) {
772:
773: r = (*newdir.fs->getxattr)(&newdir, &xattr);
774:
775: }
776:
777: if (r) {
778:
779: DEBUG("Fsfirst(%s): couldn't get file attributes",path);
780:
781: return r;
782:
783: }
784:
785: dta->magic = EVALID;
786:
787: dta->dta_attrib = xattr.attr;
788:
789: dta->dta_time = xattr.mtime;
790:
791: dta->dta_date = xattr.mdate;
792:
793: dta->dta_size = xattr.size;
794:
795: strncpy(dta->dta_name, slash, TOS_NAMELEN-1);
796:
797: dta->dta_name[TOS_NAMELEN-1] = 0;
798:
799: if (curproc->domain == DOM_TOS &&
800:
801: !(fs->fsflags & FS_CASESENSITIVE))
802:
803: strupr(dta->dta_name);
804:
805:
806:
807: return 0;
808:
809: }
810:
811:
812:
813: /* There is a wild card. Try to find a slot for an opendir/readdir
814:
815: * search. NOTE: we also come here if we were asked to search for
816:
817: * volume labels and found one.
818:
819: */
820:
821: for (i = 0; i < NUM_SEARCH; i++) {
822:
823: if (curproc->srchdta[i] == 0)
824:
825: break;
826:
827: }
828:
829: if (i == NUM_SEARCH) {
830:
831: int oldest = 0; int oldtime = curproc->srchtim[0];
832:
833:
834:
835: DEBUG("Fsfirst(%s): having to re-use a directory slot!",path);
836:
837: for (i = 1; i < NUM_SEARCH; i++) {
838:
839: if (curproc->srchtim[i] < oldtime) {
840:
841: oldest = i;
842:
843: oldtime = curproc->srchtim[i];
844:
845: }
846:
847: }
848:
849: /* OK, close this directory for re-use */
850:
851: i = oldest;
852:
853: dirh = &curproc->srchdir[i];
854:
855: if (dirh->fc.fs) {
856:
857: (*dirh->fc.fs->closedir)(dirh);
858:
859: dirh->fc.fs = 0;
860:
861: }
862:
863: curproc->srchdta[i] = 0;
864:
865: }
866:
867:
868:
869: /* check to see if we have read permission on the directory (and make
870:
871: * sure that it really is a directory!
872:
873: */
874:
875: r = dir_access(&dir, S_IROTH);
876:
877: if (r) {
878:
879: DEBUG("Fsfirst(%s): access to directory denied",path);
880:
881: return r;
882:
883: }
884:
885:
886:
887: /* set up the directory for a search */
888:
889: dirh = &curproc->srchdir[i];
890:
891: dirh->fc = dir;
892:
893: dirh->index = 0;
894:
895: dirh->flags = TOS_SEARCH;
896:
897: r = (*dir.fs->opendir)(dirh, dirh->flags);
898:
899: if (r != 0) {
900:
901: DEBUG("Fsfirst(%s): couldn't open directory (error %ld)",
902:
903: path, r);
904:
905: return r;
906:
907: }
908:
909:
910:
911: /* mark the slot as in-use */
912:
913: curproc->srchdta[i] = dta;
914:
915:
916:
917: /* set up the DTA for Fsnext */
918:
919: dta->index = i;
920:
921: dta->magic = SVALID;
922:
923: dta->dta_sattrib = attrib;
924:
925:
926:
927: /* OK, now basically just do Fsnext, except that instead of ENMFIL we
928:
929: * return EFILNF.
930:
931: * NOTE: If we already have found a volume label from the search above,
932:
933: * then we skip the f_snext and just return that.
934:
935: */
936:
937: if (havelabel)
938:
939: return 0;
940:
941:
942:
943: r = f_snext();
944:
945: if (r == ENMFIL) r = EFILNF;
946:
947: if (r)
948:
949: TRACE("Fsfirst: returning %ld", r);
950:
951: return r;
952:
953: }
954:
955:
956:
957: /*
958:
959: * Counter for Fsfirst/Fsnext, so that we know which search slots are
960:
961: * least recently used. This is updated once per second by the code
962:
963: * in timeout.c.
964:
965: * BUG: 1/second is pretty low granularity
966:
967: */
968:
969:
970:
971: long searchtime;
972:
973:
974:
975: long
976:
977: f_snext()
978:
979: {
980:
981: static char buf[TOS_NAMELEN+1];
982:
983: DTABUF *dta = curproc->dta;
984:
985: FILESYS *fs;
986:
987: fcookie fc;
988:
989: int i;
990:
991: DIR *dirh;
992:
993: long r;
994:
995: XATTR xattr;
996:
997:
998:
999: TRACE("Fsnext");
1000:
1001:
1002:
1003: if (dta->magic == EVALID) {
1004:
1005: DEBUG("Fsnext: DTA marked a failing search");
1006:
1007: return ENMFIL;
1008:
1009: }
1010:
1011: if (dta->magic != SVALID) {
1012:
1013: DEBUG("Fsnext: dta incorrectly set up");
1014:
1015: return EINVFN;
1016:
1017: }
1018:
1019:
1020:
1021: i = dta->index;
1022:
1023: dirh = &curproc->srchdir[i];
1024:
1025: curproc->srchtim[i] = searchtime;
1026:
1027:
1028:
1029: fs = dirh->fc.fs;
1030:
1031: if (!fs) /* oops -- the directory got closed somehow */
1032:
1033: return EINTRN;
1034:
1035:
1036:
1037: /* BUG: f_snext and readdir should check for disk media changes */
1038:
1039:
1040:
1041: for(;;) {
1042:
1043: r = (*fs->readdir)(dirh, buf, TOS_NAMELEN+1, &fc);
1044:
1045:
1046:
1047: if (r == ENAMETOOLONG) {
1048:
1049: DEBUG("Fsnext: name too long");
1050:
1051: continue; /* TOS programs never see these names */
1052:
1053: }
1054:
1055: if (r != 0) {
1056:
1057: baderror:
1058:
1059: (void)(*fs->closedir)(dirh);
1060:
1061: dirh->fc.fs = 0;
1062:
1063: curproc->srchdta[i] = 0;
1064:
1065: dta->magic = EVALID;
1066:
1067: if (r != ENMFIL)
1068:
1069: DEBUG("Fsnext: returning %ld", r);
1070:
1071: return r;
1072:
1073: }
1074:
1075:
1076:
1077: if (!pat_match(buf, dta->dta_pat))
1078:
1079: continue; /* different patterns */
1080:
1081:
1082:
1083: /* check for search attributes */
1084:
1085: r = (*fc.fs->getxattr)(&fc, &xattr);
1086:
1087: if (r) {
1088:
1089: DEBUG("Fsnext: couldn't get file attributes");
1090:
1091: goto baderror;
1092:
1093: }
1094:
1095: /* if the file is a symbolic link, try to find what it's linked to */
1096:
1097: if ( (xattr.mode & S_IFMT) == S_IFLNK ) {
1098:
1099: char linkedto[PATH_MAX];
1100:
1101: r = (*fc.fs->readlink)(&fc, linkedto, PATH_MAX);
1102:
1103: if (r == 0) {
1104:
1105: /* the "1" tells relpath2cookie that we read a link */
1106:
1107: r = relpath2cookie(&dirh->fc, linkedto,
1108:
1109: follow_links, &fc, 1);
1110:
1111: if (r == 0)
1112:
1113: r = (*fc.fs->getxattr)(&fc, &xattr);
1114:
1115: }
1116:
1117: if (r) {
1118:
1119: DEBUG("Fsnext: couldn't follow link: error %ld",
1120:
1121: r);
1122:
1123: }
1124:
1125: }
1126:
1127:
1128:
1129: /* silly TOS rules for matching attributes */
1130:
1131: if (xattr.attr == 0) break;
1132:
1133: if (xattr.attr & 0x21) break;
1134:
1135: if (dta->dta_sattrib & xattr.attr)
1136:
1137: break;
1138:
1139: }
1140:
1141:
1142:
1143: /* here, we have a match */
1144:
1145: dta->dta_attrib = xattr.attr;
1146:
1147: dta->dta_time = xattr.mtime;
1148:
1149: dta->dta_date = xattr.mdate;
1150:
1151: dta->dta_size = xattr.size;
1152:
1153: strcpy(dta->dta_name, buf);
1154:
1155:
1156:
1157: if (curproc->domain == DOM_TOS && !(fs->fsflags & FS_CASESENSITIVE)) {
1158:
1159: strupr(dta->dta_name);
1160:
1161: }
1162:
1163: return 0;
1164:
1165: }
1166:
1167:
1168:
1169: long
1170:
1171: f_attrib(name, rwflag, attr)
1172:
1173: const char *name;
1174:
1175: int rwflag;
1176:
1177: int attr;
1178:
1179: {
1180:
1181: fcookie fc;
1182:
1183: XATTR xattr;
1184:
1185: long r;
1186:
1187:
1188:
1189: TRACE("Fattrib(%s, %d)", name, attr);
1190:
1191:
1192:
1193: r = path2cookie(name, (char *)0, &fc);
1194:
1195:
1196:
1197: if (r) {
1198:
1199: DEBUG("Fattrib(%s): error %ld", name, r);
1200:
1201: return r;
1202:
1203: }
1204:
1205:
1206:
1207: r = (*fc.fs->getxattr)(&fc, &xattr);
1208:
1209:
1210:
1211: if (r) {
1212:
1213: DEBUG("Fattrib(%s): getxattr returned %ld", name, r);
1214:
1215: return r;
1216:
1217: }
1218:
1219:
1220:
1221: if (rwflag) {
1222:
1223: if (attr & (FA_LABEL|FA_DIR)) {
1224:
1225: DEBUG("Fattrib(%s): illegal attributes specified",name);
1226:
1227: return EACCDN;
1228:
1229: } else if (curproc->euid && curproc->euid != xattr.uid) {
1230:
1231: DEBUG("Fattrib(%s): not the file's owner",name);
1232:
1233: return EACCDN;
1234:
1235: } else if (xattr.attr & (FA_LABEL|FA_DIR)) {
1236:
1237: DEBUG("Fattrib(%s): file is a volume label "
1238:
1239: "or directory",name);
1240:
1241: return EACCDN;
1242:
1243: }
1244:
1245: return (*fc.fs->chattr)(&fc, attr);
1246:
1247: } else {
1248:
1249: return xattr.attr;
1250:
1251: }
1252:
1253: }
1254:
1255:
1256:
1257: long
1258:
1259: f_delete(name)
1260:
1261: const char *name;
1262:
1263: {
1264:
1265: fcookie dir;
1266:
1267: long r;
1268:
1269:
1270:
1271: TRACE("Fdelete(%s)", name);
1272:
1273:
1274:
1275: r = path2cookie(name, temp1, &dir);
1276:
1277:
1278:
1279: if (r) {
1280:
1281: DEBUG("Fdelete: error %ld", r);
1282:
1283: return r;
1284:
1285: }
1286:
1287:
1288:
1289: /* check for write permission on directory */
1290:
1291: r = dir_access(&dir, S_IWOTH);
1292:
1293: if (r) {
1294:
1295: DEBUG("Fdelete(%s): write access to directory denied",name);
1296:
1297: return r;
1298:
1299: }
1300:
1301: /* BUG: we should check here for a read-only file */
1302:
1303: return (*dir.fs->remove)(&dir,temp1);
1304:
1305: }
1306:
1307:
1308:
1309: long
1310:
1311: f_rename(junk, old, new)
1312:
1313: int junk; /* ignored, for TOS compatibility */
1314:
1315: const char *old, *new;
1316:
1317: {
1318:
1319: fcookie olddir, newdir, oldfil;
1320:
1321: XATTR xattr;
1322:
1323: char temp2[PATH_MAX];
1324:
1325: long r;
1326:
1327:
1328:
1329: TRACE("Frename(%s, %s)", old, new);
1330:
1331:
1332:
1333: r = path2cookie(old, temp2, &olddir);
1334:
1335: if (r) {
1336:
1337: DEBUG("Frename(%s,%s): error parsing old name",old,new);
1338:
1339: return r;
1340:
1341: }
1342:
1343: /* check for permissions on the old file
1344:
1345: * GEMDOS doesn't allow rename if the file is FA_RDONLY
1346:
1347: * we enforce this restriction only on regular files; processes,
1348:
1349: * directories, and character special files can be renamed at will
1350:
1351: */
1352:
1353: r = relpath2cookie(&olddir, temp2, follow_links, &oldfil, 0);
1354:
1355: if (r) {
1356:
1357: DEBUG("Frename(%s,%s): old file not found",old,new);
1358:
1359: return r;
1360:
1361: }
1362:
1363: r = (*oldfil.fs->getxattr)(&oldfil, &xattr);
1364:
1365: if (r ||
1366:
1367: ((xattr.mode & S_IFMT) == S_IFREG && (xattr.attr & FA_RDONLY)) )
1368:
1369: {
1370:
1371: DEBUG("Frename(%s,%s): access to old file not granted",old,new);
1372:
1373: return EACCDN;
1374:
1375: }
1376:
1377: r = path2cookie(new, temp1, &newdir);
1378:
1379: if (r) {
1380:
1381: DEBUG("Frename(%s,%s): error parsing new name",old,new);
1382:
1383: return r;
1384:
1385: }
1386:
1387:
1388:
1389: if (newdir.fs != olddir.fs) {
1390:
1391: DEBUG("Frename(%s,%s): different file systems",old,new);
1392:
1393: return EXDEV; /* cross device rename */
1394:
1395: }
1396:
1397:
1398:
1399: /* check for write permission on both directories */
1400:
1401: r = dir_access(&olddir, S_IWOTH);
1402:
1403: if (!r) r = dir_access(&newdir, S_IWOTH);
1404:
1405: if (r) {
1406:
1407: DEBUG("Frename(%s,%s): access to a directory denied",old,new);
1408:
1409: return r;
1410:
1411: }
1412:
1413: return (*newdir.fs->rename)(&olddir, temp2, &newdir, temp1);
1414:
1415: }
1416:
1417:
1418:
1419: /*
1420:
1421: * GEMDOS extension: Dpathconf(name, which)
1422:
1423: * returns information about filesystem-imposed limits; "name" is the name
1424:
1425: * of a file or directory about which the limit information is requested;
1426:
1427: * "which" is the limit requested, as follows:
1428:
1429: * -1 max. value of "which" allowed
1430:
1431: * 0 internal limit on open files, if any
1432:
1433: * 1 max. number of links to a file {LINK_MAX}
1434:
1435: * 2 max. path name length {PATH_MAX}
1436:
1437: * 3 max. file name length {NAME_MAX}
1438:
1439: * 4 no. of bytes in atomic write to FIFO {PIPE_BUF}
1440:
1441: * 5 file name truncation rules
1442:
1443: * 6 file name case translation rules
1444:
1445: *
1446:
1447: * unlimited values are returned as 0x7fffffffL
1448:
1449: *
1450:
1451: * see also Sysconf() in dos.c
1452:
1453: */
1454:
1455:
1456:
1457: long
1458:
1459: d_pathconf(name, which)
1460:
1461: const char *name;
1462:
1463: int which;
1464:
1465: {
1466:
1467: fcookie dir;
1468:
1469: long r;
1470:
1471:
1472:
1473: r = path2cookie(name, (char *)0, &dir);
1474:
1475: if (r) {
1476:
1477: DEBUG("Dpathconf(%s): bad path",name);
1478:
1479: return r;
1480:
1481: }
1482:
1483: r = (*dir.fs->pathconf)(&dir, which);
1484:
1485: if (which == DP_CASE && r == EINVFN) {
1486:
1487: /* backward compatibility with old .XFS files */
1488:
1489: return (dir.fs->fsflags & FS_CASESENSITIVE) ? DP_CASESENS :
1490:
1491: DP_CASEINSENS;
1492:
1493: }
1494:
1495: return r;
1496:
1497: }
1498:
1499:
1500:
1501: /*
1502:
1503: * GEMDOS extension: Opendir/Readdir/Rewinddir/Closedir offer a new,
1504:
1505: * POSIX-like alternative to Fsfirst/Fsnext, and as a bonus allow for
1506:
1507: * arbitrary length file names
1508:
1509: */
1510:
1511:
1512:
1513: long
1514:
1515: d_opendir(name, flag)
1516:
1517: const char *name;
1518:
1519: int flag;
1520:
1521: {
1522:
1523: DIR *dirh;
1524:
1525: fcookie dir;
1526:
1527: long r;
1528:
1529:
1530:
1531: r = path2cookie(name, follow_links, &dir);
1532:
1533: if (r) {
1534:
1535: DEBUG("Dopendir(%s): error %ld", name, r);
1536:
1537: return r;
1538:
1539: }
1540:
1541: r = dir_access(&dir, S_IROTH);
1542:
1543: if (r) {
1544:
1545: DEBUG("Dopendir(%s): read permission denied", name);
1546:
1547: return r;
1548:
1549: }
1550:
1551:
1552:
1553: dirh = (DIR *)umalloc(SIZEOF(DIR));
1554:
1555: if (!dirh) return ENSMEM;
1556:
1557:
1558:
1559: dirh->fc = dir;
1560:
1561: dirh->index = 0;
1562:
1563: dirh->flags = flag;
1564:
1565: r = (*dir.fs->opendir)(dirh, flag);
1566:
1567: if (r) {
1568:
1569: DEBUG("d_opendir(%s): opendir returned %ld", name, r);
1570:
1571: ufree(dirh);
1572:
1573: return r;
1574:
1575: }
1576:
1577: return (long)dirh;
1578:
1579: }
1580:
1581:
1582:
1583: long
1584:
1585: d_readdir(len, handle, buf)
1586:
1587: int len;
1588:
1589: long handle;
1590:
1591: char *buf;
1592:
1593: {
1594:
1595: DIR *dirh = (DIR *)handle;
1596:
1597: fcookie fc;
1598:
1599:
1600:
1601: if (!dirh->fc.fs)
1602:
1603: return EIHNDL;
1604:
1605: return (*dirh->fc.fs->readdir)(dirh, buf, len, &fc);
1606:
1607: }
1608:
1609:
1610:
1611: long
1612:
1613: d_rewind(handle)
1614:
1615: long handle;
1616:
1617: {
1618:
1619: DIR *dirh = (DIR *)handle;
1620:
1621:
1622:
1623: if (!dirh->fc.fs)
1624:
1625: return EIHNDL;
1626:
1627: return (*dirh->fc.fs->rewinddir)(dirh);
1628:
1629: }
1630:
1631:
1632:
1633: long
1634:
1635: d_closedir(handle)
1636:
1637: long handle;
1638:
1639: {
1640:
1641: long r;
1642:
1643: DIR *dirh = (DIR *)handle;
1644:
1645:
1646:
1647: if (!dirh->fc.fs)
1648:
1649: return EIHNDL;
1650:
1651: r = (*dirh->fc.fs->closedir)(dirh);
1652:
1653: dirh->fc.fs = 0;
1654:
1655:
1656:
1657: if (r) {
1658:
1659: DEBUG("Dclosedir: error %ld", r);
1660:
1661: }
1662:
1663: ufree(dirh);
1664:
1665: return r;
1666:
1667: }
1668:
1669:
1670:
1671: /*
1672:
1673: * GEMDOS extension: Fxattr gets extended attributes for a file. "flag"
1674:
1675: * is 0 if symbolic links are to be followed (like stat), 1 if not (like
1676:
1677: * lstat).
1678:
1679: */
1680:
1681:
1682:
1683: long
1684:
1685: f_xattr(flag, name, xattr)
1686:
1687: int flag;
1688:
1689: const char *name;
1690:
1691: XATTR *xattr;
1692:
1693: {
1694:
1695: fcookie fc;
1696:
1697: long r;
1698:
1699:
1700:
1701: TRACE("Fxattr(%d, %s)", flag, name);
1702:
1703:
1704:
1705: r = path2cookie(name, flag ? (char *)0 : follow_links, &fc);
1706:
1707: if (r) {
1708:
1709: DEBUG("Fxattr(%s): path2cookie returned %ld", name, r);
1710:
1711: return r;
1712:
1713: }
1714:
1715: r = (*fc.fs->getxattr)(&fc, xattr);
1716:
1717: if (r) {
1718:
1719: DEBUG("Fxattr(%s): returning %ld", name, r);
1720:
1721: }
1722:
1723: return r;
1724:
1725: }
1726:
1727:
1728:
1729: /*
1730:
1731: * GEMDOS extension: Flink(old, new) creates a hard link named "new"
1732:
1733: * to the file "old".
1734:
1735: */
1736:
1737:
1738:
1739: long
1740:
1741: f_link(old, new)
1742:
1743: const char *old, *new;
1744:
1745: {
1746:
1747: fcookie olddir, newdir;
1748:
1749: char temp2[PATH_MAX];
1750:
1751: long r;
1752:
1753:
1754:
1755: TRACE("Flink(%s, %s)", old, new);
1756:
1757:
1758:
1759: r = path2cookie(old, temp2, &olddir);
1760:
1761: if (r) {
1762:
1763: DEBUG("Flink(%s,%s): error parsing old name",old,new);
1764:
1765: return r;
1766:
1767: }
1768:
1769: r = path2cookie(new, temp1, &newdir);
1770:
1771: if (r) {
1772:
1773: DEBUG("Flink(%s,%s): error parsing new name",old,new);
1774:
1775: return r;
1776:
1777: }
1778:
1779:
1780:
1781: if (newdir.fs != olddir.fs) {
1782:
1783: DEBUG("Flink(%s,%s): different file systems",old,new);
1784:
1785: return EXDEV; /* cross device link */
1786:
1787: }
1788:
1789:
1790:
1791: /* check for write permission on the destination directory */
1792:
1793:
1794:
1795: r = dir_access(&newdir, S_IWOTH);
1796:
1797: if (r) {
1798:
1799: DEBUG("Flink(%s,%s): access to directory denied",old,new);
1800:
1801: return r;
1802:
1803: }
1804:
1805: return (*newdir.fs->hardlink)(&olddir, temp2, &newdir, temp1);
1806:
1807: }
1808:
1809:
1810:
1811: /*
1812:
1813: * GEMDOS extension: Fsymlink(old, new): create a symbolic link named
1814:
1815: * "new" that contains the path "old".
1816:
1817: */
1818:
1819:
1820:
1821: long
1822:
1823: f_symlink(old, new)
1824:
1825: const char *old, *new;
1826:
1827: {
1828:
1829: fcookie newdir;
1830:
1831: long r;
1832:
1833:
1834:
1835: TRACE("Fsymlink(%s, %s)", old, new);
1836:
1837:
1838:
1839: r = path2cookie(new, temp1, &newdir);
1840:
1841: if (r) {
1842:
1843: DEBUG("Fsymlink(%s,%s): error parsing %s", old,new,new);
1844:
1845: return r;
1846:
1847: }
1848:
1849: r = dir_access(&newdir, S_IWOTH);
1850:
1851: if (r) {
1852:
1853: DEBUG("Fsymlink(%s,%s): access to directory denied",old,new);
1854:
1855: return r;
1856:
1857: }
1858:
1859: return (*newdir.fs->symlink)(&newdir, temp1, old);
1860:
1861: }
1862:
1863:
1864:
1865: /*
1866:
1867: * GEMDOS extension: Freadlink(buflen, buf, linkfile):
1868:
1869: * read the contents of the symbolic link "linkfile" into the buffer
1870:
1871: * "buf", which has length "buflen".
1872:
1873: */
1874:
1875:
1876:
1877: long
1878:
1879: f_readlink(buflen, buf, linkfile)
1880:
1881: int buflen;
1882:
1883: char *buf;
1884:
1885: const char *linkfile;
1886:
1887: {
1888:
1889: fcookie file;
1890:
1891: long r;
1892:
1893: XATTR xattr;
1894:
1895:
1896:
1897: TRACE("Freadlink(%s)", linkfile);
1898:
1899:
1900:
1901: r = path2cookie(linkfile, (char *)0, &file);
1902:
1903: if (r) {
1904:
1905: DEBUG("Freadlink: unable to find %s", linkfile);
1906:
1907: return r;
1908:
1909: }
1910:
1911: r = (*file.fs->getxattr)(&file, &xattr);
1912:
1913: if (r) {
1914:
1915: DEBUG("Freadlink: unable to get attributes for %s", linkfile);
1916:
1917: return r;
1918:
1919: }
1920:
1921: if ( (xattr.mode & S_IFMT) == S_IFLNK )
1922:
1923: return (*file.fs->readlink)(&file, buf, buflen);
1924:
1925:
1926:
1927: DEBUG("Freadlink: %s is not a link", linkfile);
1928:
1929: return EACCDN;
1930:
1931: }
1932:
1933:
1934:
1935: /*
1936:
1937: * GEMDOS extension: Dcntl(): do file system specific functions
1938:
1939: */
1940:
1941:
1942:
1943: long
1944:
1945: d_cntl(cmd, name, arg)
1946:
1947: int cmd;
1948:
1949: const char *name;
1950:
1951: long arg;
1952:
1953: {
1954:
1955: fcookie dir;
1956:
1957: long r;
1958:
1959:
1960:
1961: TRACE("Dcntl(cmd=%x, file=%s, arg=%lx)", cmd, name, arg);
1962:
1963:
1964:
1965: r = path2cookie(name, temp1, &dir);
1966:
1967: if (r) {
1968:
1969: DEBUG("Dcntl: couldn't find %s", name);
1970:
1971: return r;
1972:
1973: }
1974:
1975: return (*dir.fs->fscntl)(&dir, temp1, cmd, arg);
1976:
1977: }
1978:
1979:
1980:
1981: /*
1982:
1983: * GEMDOS extension: Fchown(name, uid, gid) changes the user and group
1984:
1985: * ownerships of a file to "uid" and "gid" respectively.
1986:
1987: */
1988:
1989:
1990:
1991: long
1992:
1993: f_chown(name, uid, gid)
1994:
1995: const char *name;
1996:
1997: int uid, gid;
1998:
1999: {
2000:
2001: fcookie fc;
2002:
2003: XATTR xattr;
2004:
2005: long r;
2006:
2007:
2008:
2009: TRACE("Fchown(%s, %d, %d)", name, uid, gid);
2010:
2011:
2012:
2013: r = path2cookie(name, follow_links, &fc);
2014:
2015: if (r) {
2016:
2017: DEBUG("Fchown(%s): error %ld", name, r);
2018:
2019: return r;
2020:
2021: }
2022:
2023:
2024:
2025: /* MiNT acts like _POSIX_CHOWN_RESTRICTED: a non-privileged process can
2026:
2027: * only change the ownership of a file that is owned by this user, to
2028:
2029: * the effective group id of the process
2030:
2031: */
2032:
2033: if (curproc->euid) {
2034:
2035: if (curproc->egid != gid) return EACCDN;
2036:
2037: r = (*fc.fs->getxattr)(&fc, &xattr);
2038:
2039: if (r) {
2040:
2041: DEBUG("Fchown(%s): unable to get file attributes",name);
2042:
2043: return r;
2044:
2045: }
2046:
2047: if (xattr.uid != curproc->euid || xattr.uid != uid) {
2048:
2049: DEBUG("Fchown(%s): not the file's owner",name);
2050:
2051: return EACCDN;
2052:
2053: }
2054:
2055: }
2056:
2057: return (*fc.fs->chown)(&fc, uid, gid);
2058:
2059: }
2060:
2061:
2062:
2063: /*
2064:
2065: * GEMDOS extension: Fchmod(file, mode) changes a file's access
2066:
2067: * permissions.
2068:
2069: */
2070:
2071:
2072:
2073: long
2074:
2075: f_chmod(name, mode)
2076:
2077: const char *name;
2078:
2079: unsigned mode;
2080:
2081: {
2082:
2083: fcookie fc;
2084:
2085: long r;
2086:
2087: XATTR xattr;
2088:
2089:
2090:
2091: TRACE("Fchmod(%s, %o)", name, mode);
2092:
2093: r = path2cookie(name, follow_links, &fc);
2094:
2095: if (r) {
2096:
2097: DEBUG("Fchmod(%s): error %ld", name, r);
2098:
2099: return r;
2100:
2101: }
2102:
2103: r = (*fc.fs->getxattr)(&fc, &xattr);
2104:
2105: if (r) {
2106:
2107: DEBUG("Fchmod(%s): couldn't get file attributes",name);
2108:
2109: return r;
2110:
2111: }
2112:
2113: if (curproc->euid && curproc->euid != xattr.uid) {
2114:
2115: DEBUG("Fchmod(%s): not the file's owner",name);
2116:
2117: return EACCDN;
2118:
2119: }
2120:
2121: r = (*fc.fs->chmode)(&fc, mode & ~S_IFMT);
2122:
2123: if (r) DEBUG("Fchmod: error %ld", r);
2124:
2125: return r;
2126:
2127: }
2128:
2129:
2130:
2131: /*
2132:
2133: * GEMDOS extension: Dlock(mode, dev): locks or unlocks access to
2134:
2135: * a BIOS device. "mode" is 0 for unlock, 1 for lock; "dev" is a
2136:
2137: * BIOS device (0 for A:, 1 for B:, etc.).
2138:
2139: * Returns: 0 if the operation was successful
2140:
2141: * EACCDN if a lock attempt is made on a drive that is being
2142:
2143: * used
2144:
2145: * ELOCKED if the drive is locked by another process
2146:
2147: * ENSLOCK if a program attempts to unlock a drive it
2148:
2149: * hasn't locked.
2150:
2151: */
2152:
2153:
2154:
2155: PROC *dlockproc[NUM_DRIVES];
2156:
2157:
2158:
2159: long
2160:
2161: d_lock(mode, dev)
2162:
2163: int mode, dev;
2164:
2165: {
2166:
2167: PROC *p;
2168:
2169: FILEPTR *f;
2170:
2171: int i;
2172:
2173: DIR *dirh;
2174:
2175:
2176:
2177: TRACE("Dlock(%x,%c:)", mode, dev+'A');
2178:
2179: if (dev < 0 || dev >= NUM_DRIVES) return EDRIVE;
2180:
2181:
2182:
2183: if ( (mode&1) == 0) { /* unlock */
2184:
2185: if (dlockproc[dev] == curproc) {
2186:
2187: dlockproc[dev] = 0;
2188:
2189: changedrv(dev);
2190:
2191: return 0;
2192:
2193: }
2194:
2195: DEBUG("Dlock: no such lock");
2196:
2197: return ENSLOCK;
2198:
2199: }
2200:
2201:
2202:
2203: /* code for locking */
2204:
2205: /* is the drive already locked? */
2206:
2207: if (dlockproc[dev]) {
2208:
2209: DEBUG("Dlock: drive already locked");
2210:
2211: return (dlockproc[dev] == curproc) ? 0 : ELOCKED;
2212:
2213: }
2214:
2215: /* see if the drive is in use */
2216:
2217: for (p = proclist; p; p = p->gl_next) {
2218:
2219: if (p->wait_q == ZOMBIE_Q || p->wait_q == TSR_Q)
2220:
2221: continue;
2222:
2223: for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
2224:
2225: if ( ((f = p->handle[i]) != 0) && (f->fc.dev == dev) ) {
2226:
2227: DEBUG("Dlock: process %d has an open handle on the drive", p->pid);
2228:
2229: return EACCDN;
2230:
2231: }
2232:
2233: }
2234:
2235: for (i = 0; i < NUM_SEARCH; i++) {
2236:
2237: dirh = &curproc->srchdir[i];
2238:
2239: if (dirh && dirh->fc.fs && dirh->fc.dev == dev) {
2240:
2241: DEBUG("Dlock: process %d has an open directory on the drive",p->pid);
2242:
2243: return EACCDN;
2244:
2245: }
2246:
2247: }
2248:
2249: }
2250:
2251:
2252:
2253: /* if we reach here, the drive is not in use */
2254:
2255: /* we lock it by setting dlockproc and by setting all root and current
2256:
2257: * directories referring to the device to a null file system
2258:
2259: */
2260:
2261: for (p = proclist; p; p = p->gl_next) {
2262:
2263: for (i = 0; i < NUM_DRIVES; i++) {
2264:
2265: if (p->root[i].dev == dev)
2266:
2267: p->root[i].fs = 0;
2268:
2269: if (p->curdir[i].dev == dev)
2270:
2271: p->curdir[i].fs = 0;
2272:
2273: }
2274:
2275: }
2276:
2277:
2278:
2279: dlockproc[dev] = curproc;
2280:
2281: return 0;
2282:
2283: }
2284:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.