|
|
1.1 root 1: /*
2: * simple unix filesystem interface;
3: * access local files through system calls
4: */
5:
6: #include <sys/types.h>
7: #include <sys/stat.h>
8: #include <stdio.h>
9: #include <errno.h>
10: #include <rf.h>
11: #include "zarf.h"
12:
13: extern int errno;
14:
15: static Rfile *rootf;
16: static int servuid, servgid;
17:
18: char rootname[200]; /* arbitrarily large */
19: extern Namemap *exulist, *exglist;
20:
21: #define rfmode(m) (m)
22: #define fsmode(m) (m)
23: #define FSPERM 07777 /* just the permission bits */
24:
25: static int clientdev();
26: static int maxopen();
27: static int samefile();
28:
29: char *malloc();
30: long lseek();
31:
32: /*
33: * init:
34: * return the root
35: */
36:
37: Rfile *
38: fsinit(argc, argv)
39: int argc;
40: char **argv;
41: {
42: register Rfile *f;
43: char *passwd = "/etc/passwd";
44: char *group = "/etc/group";
45: FILE *fp;
46: int foundex;
47:
48: foundex = 0;
49: while (--argc > 0) {
50: if (**++argv != '-')
51: continue; /* skip unknown args */
52: switch (argv[0][1]) {
53: case 'd':
54: if (--argc <= 0) {
55: rflog("-d: missing arg\n");
56: continue;
57: }
58: rfdebug = atoi(*++argv);
59: break;
60:
61: case 'p':
62: if (--argc <= 0) {
63: rflog("-p: missing arg\n");
64: continue;
65: }
66: passwd = *++argv;
67: break;
68:
69: case 'g':
70: if (--argc <= 0) {
71: rflog("-g: missing arg\n");
72: continue;
73: }
74: group = *++argv;
75: break;
76:
77: case 'r':
78: if (--argc <= 0) {
79: rflog("-r: missing arg\n");
80: continue;
81: }
82: strcpy(rootname, *++argv);
83: break;
84: case 'e':
85: if (--argc <= 0) {
86: rflog("-e: missing arg\n");
87: continue;
88: }
89: if (foundex == 0 && (fp = fopen(*++argv, "r")) != NULL) {
90: foundex = rdexcept(fp);
91: fclose(fp);
92: }
93: break;
94:
95: default:
96: rflog("unknown flag %s\n", *argv);
97: break;
98: }
99: }
100: rfuidmap = rfmkidmap(passwd, exulist);
101: rfgidmap = rfmkidmap(group, exglist);
102: if ((f = (Rfile *)malloc(sizeof(Rfile))) == NULL)
103: return (NULL);
104: if ((f->fs = malloc(sizeof(Fsfile))) == NULL) {
105: free((char *)f);
106: return (NULL);
107: }
108: if ((fsp(f)->name = malloc(strlen(rootname)+1)) == NULL) {
109: free(f->fs);
110: free((char *)f);
111: return (NULL);
112: }
113: if (rootname[0] == 0)
114: strcpy(rootname, "/");
115: strcpy(fsp(f)->name, rootname);
116: fsp(f)->fd = -1;
117: fsp(f)->flags = WONTREAD|WONTWRITE|NOSTAT;
118: fsstat(f);
119: maxopen(f, 0);
120: rootf = f;
121: umask(0);
122: servuid = geteuid();
123: servgid = getegid();
124: setgid(servgid); /* to avoid inconsistencies */
125: setuid(servuid);
126: return (f);
127: }
128:
129: Rfile *
130: fswalk(df, name)
131: Rfile *df;
132: char *name;
133: {
134: register Rfile *f;
135: char *nname;
136:
137: if (rfdebug)
138: rflog("walk %d,%ld '%s' '%s'\n", df->dev, df->ino, fsp(df)->name, name);
139: if ((f = (Rfile *)malloc(sizeof(Rfile))) == NULL) {
140: rflog("fswalk: no mem\n");
141: fserrno = RFEINVAL;
142: return (NULL);
143: }
144: if ((f->fs = malloc(sizeof(Fsfile))) == NULL) {
145: free((char *)f);
146: rflog("fswalk: no mem\n");
147: fserrno = RFEINVAL;
148: return (NULL);
149: }
150: if ((nname = malloc(strlen(fsp(df)->name) + strlen(name) + 2)) == NULL) {
151: free(f->fs);
152: free((char *)f);
153: rflog("fswalk: no mem\n");
154: fserrno = RFEINVAL;
155: return (NULL);
156: }
157: fsp(f)->name = nname;
158: strcpy(nname, fsp(df)->name);
159: strcat(nname, "/");
160: strcat(nname, name);
161: fsp(f)->fd = -1;
162: fsp(f)->flags = WONTREAD|WONTWRITE|NOSTAT;
163: if (fsstat(f) < 0)
164: goto bad;
165: /*
166: * hack to avoid hanging in open:
167: * don't open yet unless regular file (not device)
168: * and nonzero link count (not Research mounted stream)
169: * better not to defer open for ordinary files,
170: * in case someone unlinks the name we know
171: */
172: if ((fsmode(f->mode) & S_IFMT) == S_IFREG && f->nlink != 0)
173: maxopen(f, 0);
174: if (df == rootf) { /* magic for . and .., mostly for pwd */
175: #if NOTDEF
176: if (name[0] == 0 || strcmp(name, ".") == 0) {
177: close(fsp(f)->fd);
178: free(nname);
179: free(f->fs);
180: free((char *)f);
181: return (df);
182: }
183: #endif
184: if (strcmp(name, "..") == 0) {
185: close(fsp(f)->fd);
186: fserrno = 0; /* pseudo-error: popped out of root */
187: goto bad;
188: }
189: }
190: return (f);
191:
192: bad:
193: free(nname);
194: free(f->fs);
195: free((char *)f);
196: return (NULL);
197: }
198:
199: Rfile *
200: fscreate(df, name, mode, uid, gid)
201: Rfile *df;
202: char *name;
203: int mode;
204: int uid, gid;
205: {
206: register Rfile *f;
207: char *nname;
208:
209: if ((f = (Rfile *)malloc(sizeof(Rfile))) == NULL) {
210: rflog("fscreate: no mem\n");
211: fserrno = RFEINVAL;
212: return (NULL);
213: }
214: if ((f->fs = malloc(sizeof(Fsfile))) == NULL) {
215: free((char *)f);
216: rflog("fscreate: no mem\n");
217: fserrno = RFEINVAL;
218: return (NULL);
219: }
220: if ((nname = malloc(strlen(fsp(df)->name) + strlen(name) + 2)) == NULL) {
221: free(f->fs);
222: free((char *)f);
223: rflog("fscreate: no mem\n");
224: fserrno = RFEINVAL;
225: return (NULL);
226: }
227: fsp(f)->name = nname;
228: strcpy(nname, fsp(df)->name);
229: strcat(nname, "/");
230: strcat(nname, name);
231: if ((fsp(f)->fd = creat(nname, fsmode(mode))) < 0) {
232: fserrno = errno;
233: goto bad;
234: }
235: fsp(f)->flags = WONTREAD|NOSTAT;
236: if (fsstat(f) < 0) {
237: rflog("fscreate: can't stat %s, err %d\n", nname, errno);
238: fserrno = RFEINVAL;
239: close(fsp(f)->fd);
240: goto bad;
241: }
242: if (uid != f->uid || gid != f->gid) {
243: if (chown(nname, uid, gid) >= 0) {
244: f->uid = uid; /* stat would be too slow */
245: f->gid = gid;
246: } else if (servuid == 0) { /* if not root, ignore error */
247: rflog("fscreate: can't set owner %s err %d\n", nname, errno);
248: fserrno = errno;
249: close(fsp(f)->fd);
250: goto bad;
251: }
252: }
253: return (f);
254:
255: bad:
256: free(nname);
257: free(f->fs);
258: free((char *)f);
259: return (NULL);
260: }
261:
262: int
263: fsmkdir(df, name, mode, uid, gid)
264: register Rfile *df;
265: char *name;
266: int mode;
267: int uid, gid;
268: {
269: char *nname;
270: struct stat st;
271:
272: if ((nname = malloc(strlen(fsp(df)->name) + strlen(name) + 2)) == NULL) {
273: rflog("fsmkdir: no mem\n");
274: fserrno = RFEINVAL;
275: return (-1);
276: }
277: strcpy(nname, fsp(df)->name);
278: strcat(nname, "/");
279: strcat(nname, name);
280: if (mkdir(nname, fsmode(mode)) < 0) {
281: fserrno = errno;
282: free(nname);
283: return (-1);
284: }
285: if (stat(nname, &st) < 0
286: || (uid != st.st_uid || gid != st.st_gid) && chown(nname, uid, gid) < 0) {
287: rflog("fsmkdir: can't set owner %s err %d\n", nname, errno);
288: fserrno = errno;
289: rmdir(nname); /* maybe this will work */
290: free(nname);
291: return (-1);
292: }
293: free(nname);
294: return (0);
295: }
296:
297: int
298: fsrmdir(df, name)
299: register Rfile *df;
300: char *name;
301: {
302: char *nname;
303:
304: if ((nname = malloc(strlen(fsp(df)->name) + strlen(name) + 2)) == NULL) {
305: rflog("fsrmdir: no mem\n");
306: fserrno = RFEINVAL;
307: return (-1);
308: }
309: strcpy(nname, fsp(df)->name);
310: strcat(nname, "/");
311: strcat(nname, name);
312: if (rmdir(nname) < 0) {
313: fserrno = errno;
314: free(nname);
315: return (-1);
316: }
317: free(nname);
318: return (0);
319: }
320:
321: int
322: fsdelete(df, name)
323: register Rfile *df;
324: char *name;
325: {
326: char *nname;
327:
328: if ((nname = malloc(strlen(fsp(df)->name) + strlen(name) + 2)) == NULL) {
329: rflog("fsdelete: no mem\n");
330: fserrno = RFEINVAL;
331: return (-1);
332: }
333: strcpy(nname, fsp(df)->name);
334: strcat(nname, "/");
335: strcat(nname, name);
336: if (unlink(nname) < 0) {
337: fserrno = errno;
338: free(nname);
339: return (-1);
340: }
341: free(nname);
342: return (0);
343: }
344:
345: int
346: fslink(df, name, f)
347: register Rfile *df, *f;
348: char *name;
349: {
350: char *nname;
351:
352: if ((nname = malloc(strlen(fsp(df)->name) + strlen(name) + 2)) == NULL) {
353: rflog("fslink: no mem\n");
354: fserrno = RFEINVAL;
355: return (-1);
356: }
357: if (samefile(f) == 0) {
358: rflog("fslink: wrong file %s\n", fsp(f)->name);
359: fserrno = RFEINVAL;
360: return (-1);
361: }
362: strcpy(nname, fsp(df)->name);
363: strcat(nname, "/");
364: strcat(nname, name);
365: if (link(fsp(f)->name, nname) < 0) {
366: fserrno = errno;
367: free(nname);
368: return (-1);
369: }
370: free(nname);
371: return (0);
372: }
373:
374: int
375: fsdone(f)
376: register Rfile *f;
377: {
378:
379: if (fsp(f)->flags & DIDDIR)
380: dodircleanup(f);
381: close(fsp(f)->fd);
382: free(fsp(f)->name);
383: free(f->fs);
384: free((char *)f);
385: return (0);
386: }
387:
388: /*
389: * this should really use fchmod and fchown, but
390: * (1) some systems don't have them;
391: * (2) there must be code to call chmod anyway,
392: * else how can we chmod a file in mode 0 if not super-user?
393: * (3) there's no futime anyway
394: *
395: * the test in front is to skip samefile (and perhaps a spurious
396: * error message) if nothing is really changing;
397: * usually this just means ta or tm is being updated to the
398: * value the local system has already stored after read or write
399: */
400:
401: int
402: fsupdate(f, nf)
403: register Rfile *f, *nf;
404: {
405: long ft[2];
406: int nfd;
407: int status;
408:
409: if ((fsmode(nf->mode)&FSPERM) == (fsmode(f->mode)&FSPERM)
410: && nf->uid == f->uid && nf->gid == f->gid
411: && nf->ta == f->ta && nf->tm == f->tm
412: && nf->size == f->size)
413: return (0);
414: if (samefile(f) == 0) {
415: rflog("fsupdate: wrong file %s\n", fsp(f)->name);
416: fserrno = RFEINVAL;
417: return (-1);
418: }
419: status = -1;
420: if ((fsmode(nf->mode)&FSPERM) != (fsmode(f->mode)&FSPERM)) {
421: if (chmod(fsp(f)->name, fsmode(nf->mode) & FSPERM) < 0) {
422: fserrno = errno;
423: goto out;
424: }
425: }
426: if (nf->ta || nf->tm) {
427: ft[0] = nf->ta;
428: ft[1] = nf->tm;
429: if (utime(fsp(f)->name, ft) < 0) {
430: fserrno = errno;
431: goto out;
432: }
433: }
434: if (f->uid != nf->uid || f->gid != nf->gid) {
435: if (chown(fsp(f)->name, nf->uid, nf->gid) < 0) {
436: fserrno = errno;
437: goto out;
438: }
439: }
440: if (f->size != nf->size && nf->size == 0) {
441: if ((nfd = creat(fsp(f)->name, 0)) < 0) {
442: fserrno = errno;
443: goto out;
444: }
445: close(nfd);
446: }
447: status = 0;
448: out:
449: fsstat(f);
450: return (status);
451: }
452:
453: fsstat(f)
454: register Rfile *f;
455: {
456: struct stat st;
457:
458: if (fsp(f)->fd >= 0 && fstat(fsp(f)->fd, &st) < 0) {
459: fserrno = errno;
460: return (-1);
461: }
462: else if (stat(fsp(f)->name, &st) < 0) {
463: fserrno = errno;
464: return (-1);
465: }
466: if (fsp(f)->flags & NOSTAT)
467: fsp(f)->flags &=~ NOSTAT;
468: else if (clientdev(st.st_dev) != f->dev || st.st_ino != f->ino) {
469: rflog("fsstat: wrong file %s\n", fsp(f)->name);
470: fserrno = RFEINVAL;
471: return (-1);
472: }
473: f->ino = st.st_ino;
474: f->dev = clientdev(st.st_dev);
475: f->mode = rfmode(st.st_mode);
476: switch(st.st_mode & S_IFMT) {
477: case S_IFDIR:
478: f->type = RFTDIR;
479: break;
480:
481: case S_IFCHR:
482: case S_IFBLK:
483: f->mode &=~ 07777; /* deny access to devices */
484: /* fall through */
485: case S_IFREG:
486: f->type = RFTREG;
487: break;
488: }
489: f->nlink = st.st_nlink;
490: f->uid = st.st_uid;
491: f->gid = st.st_gid;
492: f->size = st.st_size;
493: f->ta = st.st_atime;
494: f->tm = st.st_mtime;
495: f->tc = st.st_ctime;
496: return (0);
497: }
498:
499: int
500: fsread(f, off, buf, len)
501: register Rfile *f;
502: long off;
503: char *buf;
504: int len;
505: {
506: register int n;
507:
508: if (fsp(f)->flags & WONTREAD)
509: maxopen(f, 0);
510: if (fsp(f)->flags & CANTREAD) {
511: fserrno = RFEACCES; /* probably */
512: return (-1);
513: }
514: lseek(fsp(f)->fd, off, 0);
515: if ((n = read(fsp(f)->fd, buf, len)) < 0)
516: fserrno = errno;
517: return (n);
518: }
519:
520: int
521: fsdirread(f, off, buf, len, offp)
522: register Rfile *f;
523: long off;
524: char *buf;
525: int len;
526: long *offp;
527: {
528:
529: if (fsp(f)->flags & WONTREAD)
530: maxopen(f, 0);
531: if (fsp(f)->flags & CANTREAD) {
532: fserrno = RFEACCES; /* probably */
533: return (-1);
534: }
535: fsp(f)->flags |= DIDDIR;
536: return (dodirread(f, buf, len, off, offp));
537: }
538:
539: int
540: fswrite(f, off, buf, len)
541: register Rfile *f;
542: long off;
543: char *buf;
544: int len;
545: {
546: register int n;
547:
548: if (fsp(f)->flags & WONTWRITE)
549: maxopen(f, 1);
550: if (fsp(f)->flags & CANTWRITE) {
551: fserrno = RFEACCES;
552: return (-1);
553: }
554: lseek(fsp(f)->fd, off, 0);
555: if ((n = write(fsp(f)->fd, buf, len)) < 0)
556: fserrno = errno;
557: else if (off + len > f->size)
558: f->size = off + len; /* should stat, but too slow */
559: return (n);
560: }
561:
562: /*
563: * turn a client st_dev into an rf minor device
564: * exactly eight bits allowed
565: */
566:
567: #define MAXDEVS 255
568:
569: int maxdev = 0;
570: dev_t devtab[MAXDEVS];
571:
572: static int
573: clientdev(d)
574: register dev_t d;
575: {
576: register int i;
577:
578: for (i = 0; i < maxdev; i++)
579: if (devtab[i] == d)
580: return (i);
581: if (i >= MAXDEVS) {
582: rflog("too many devs, can't map %x\n", d);
583: return (MAXDEVS);
584: }
585: devtab[i] = d;
586: maxdev = i + 1;
587: return (i);
588: }
589:
590: /*
591: * open a file as broadly as possible
592: * to avoid `text busy,' don't open for write
593: * unless specifically requested
594: * or unless file has no execute permissions (hack)
595: * directories usually have execute permissions (further hack)
596: */
597:
598: #define ANYEXEC ((RFPEX<<RFPOWNER)|(RFPEX<<RFPGROUP)|(RFPEX<<RFPOTHER))
599:
600: static int
601: maxopen(f, mustwrite)
602: register Rfile *f;
603: int mustwrite;
604: {
605: register Fsfile *fs;
606: int fd;
607: struct stat st;
608: register int flags;
609:
610: fd = -1;
611: fs = fsp(f);
612: flags = fs->flags;
613: if ((flags & (WONTREAD|WONTWRITE)) == 0)
614: return;
615: if ((flags & (CANTREAD|CANTWRITE)) == 0
616: && mustwrite || (f->mode & ANYEXEC) == 0) {
617: if ((fd = open(fs->name, 2)) >= 0)
618: flags &=~ (WONTREAD|WONTWRITE);
619: }
620: if ((flags & (CANTREAD|WONTREAD)) == WONTREAD) {
621: flags &=~ WONTREAD;
622: if ((fd = open(fs->name, 0)) < 0)
623: flags |= CANTREAD;
624: }
625: if (mustwrite && (flags & (CANTWRITE|WONTWRITE)) == WONTWRITE) {
626: flags &=~ WONTWRITE;
627: if ((fd = open(fs->name, 1)) < 0)
628: flags |= CANTWRITE;
629: }
630: if (fd >= 0) { /* if we opened something */
631: if ((flags & NOSTAT) == 0) {
632: if (fstat(fd, &st) < 0) {
633: rflog("maxopen: fstat %s err %d\n", fs->name, errno);
634: close(fd);
635: return; /* flags and fd unchanged */
636: } else if (clientdev(st.st_dev) != f->dev || st.st_ino != f->ino) {
637: rflog("maxopen: wrong file %s\n", fs->name);
638: close(fd);
639: return; /* flags and fd unchanged */
640: }
641: }
642: /* it's the same file, or we can't tell */
643: fs->flags = flags;
644: if (fs->fd >= 0)
645: close(fs->fd);
646: fs->fd = fd;
647: }
648: }
649:
650: /*
651: * is this the same file we opened?
652: * call before operations that must use name rather than fd
653: */
654:
655: static int
656: samefile(f)
657: register Rfile *f;
658: {
659: struct stat st;
660:
661: if (fsp(f)->flags & NOSTAT)
662: return (1); /* can't tell */
663: if (stat(fsp(f)->name, &st) < 0)
664: return (0);
665: if (clientdev(st.st_dev) != f->dev || st.st_ino != f->ino)
666: return (0);
667: return (1);
668: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.