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