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