Annotation of src/usr.bin/mg/fileio.c, Revision 1.8
1.1 deraadt 1: /*
1.7 millert 2: * POSIX fileio.c
1.1 deraadt 3: */
4: #include "def.h"
5:
1.7 millert 6: static FILE *ffp;
1.1 deraadt 7:
8: #include <sys/types.h>
9: #include <sys/stat.h>
10: #include <sys/dir.h>
11:
12: /*
13: * Open a file for reading.
14: */
1.7 millert 15: int
16: ffropen(fn, bp)
17: char *fn;
18: BUFFER *bp;
19: {
20: struct stat statbuf;
21:
22: if ((ffp = fopen(fn, "r")) == NULL)
1.1 deraadt 23: return (FIOFNF);
24: if (bp && fstat(fileno(ffp), &statbuf) == 0) {
1.7 millert 25: /* set highorder bit to make sure this isn't all zero */
1.1 deraadt 26: bp->b_fi.fi_mode = statbuf.st_mode | 0x8000;
27: bp->b_fi.fi_uid = statbuf.st_uid;
28: bp->b_fi.fi_gid = statbuf.st_gid;
29: }
30: return (FIOSUC);
31: }
32:
33: /*
34: * Open a file for writing.
35: * Return TRUE if all is well, and
36: * FALSE on error (cannot create).
37: */
1.7 millert 38: int
39: ffwopen(fn, bp)
40: char *fn;
41: BUFFER *bp;
42: {
43:
44: if ((ffp = fopen(fn, "w")) == NULL) {
1.1 deraadt 45: ewprintf("Cannot open file for writing");
46: return (FIOERR);
47: }
1.7 millert 48:
49: /*
50: * If we have file information, use it. We don't bother to check for
51: * errors, because there's no a lot we can do about it. Certainly
52: * trying to change ownership will fail if we aren' root. That's
53: * probably OK. If we don't have info, no need to get it, since any
54: * future writes will do the same thing.
1.1 deraadt 55: */
56: if (bp && bp->b_fi.fi_mode) {
57: chmod(fn, bp->b_fi.fi_mode & 07777);
58: chown(fn, bp->b_fi.fi_uid, bp->b_fi.fi_gid);
59: }
60: return (FIOSUC);
61: }
62:
63: /*
64: * Close a file.
1.7 millert 65: * XXX - Should look at the status.
1.1 deraadt 66: */
1.7 millert 67: /* ARGSUSED */
68: int
69: ffclose(bp)
70: BUFFER *bp;
71: {
72:
1.1 deraadt 73: (VOID) fclose(ffp);
74: return (FIOSUC);
75: }
76:
77: /*
78: * Write a buffer to the already
79: * opened file. bp points to the
80: * buffer. Return the status.
81: * Check only at the newline and
82: * end of buffer.
83: */
1.7 millert 84: int
1.1 deraadt 85: ffputbuf(bp)
1.7 millert 86: BUFFER *bp;
1.1 deraadt 87: {
1.7 millert 88: char *cp;
89: char *cpend;
90: LINE *lp;
91: LINE *lpend;
92:
93: lpend = bp->b_linep;
94: lp = lforw(lpend);
95: do {
96: cp = <ext(lp)[0]; /* begining of line */
97: cpend = &cp[llength(lp)]; /* end of line */
98: while (cp != cpend) {
99: putc(*cp, ffp);
100: cp++; /* putc may evaluate arguments
101: more than once */
102: }
103: lp = lforw(lp);
104: if (lp == lpend)
105: break; /* no implied \n on last line */
106: putc('\n', ffp);
107: } while (!ferror(ffp));
108: if (ferror(ffp)) {
109: ewprintf("Write I/O error");
110: return FIOERR;
111: }
112: return (FIOSUC);
1.1 deraadt 113: }
114:
115: /*
116: * Read a line from a file, and store the bytes
117: * in the supplied buffer. Stop on end of file or end of
118: * line. When FIOEOF is returned, there is a valid line
119: * of data without the normally implied \n.
120: */
1.7 millert 121: int
1.1 deraadt 122: ffgetline(buf, nbuf, nbytes)
1.7 millert 123: char *buf;
124: int nbuf;
125: int *nbytes;
1.1 deraadt 126: {
1.7 millert 127: int c;
128: int i;
1.1 deraadt 129:
130: i = 0;
1.7 millert 131: while ((c = getc(ffp)) != EOF && c != '\n') {
1.1 deraadt 132: buf[i++] = c;
1.7 millert 133: if (i >= nbuf)
134: return FIOLONG;
1.1 deraadt 135: }
1.7 millert 136: if (c == EOF && ferror(ffp) != FALSE) {
1.1 deraadt 137: ewprintf("File read error");
138: return FIOERR;
139: }
140: *nbytes = i;
1.7 millert 141: return c == EOF ? FIOEOF : FIOSUC;
1.1 deraadt 142: }
143:
144: #ifndef NO_BACKUP
145: /*
146: * Rename the file "fname" into a backup
147: * copy. On Unix the backup has the same name as the
148: * original file, with a "~" on the end; this seems to
149: * be newest of the new-speak. The error handling is
150: * all in "file.c". The "unlink" is perhaps not the
151: * right thing here; I don't care that much as
152: * I don't enable backups myself.
153: */
1.7 millert 154: int
155: fbackupfile(fn)
156: char *fn;
157: {
158: char *nname;
1.1 deraadt 159:
1.7 millert 160: if ((nname = malloc((unsigned) (strlen(fn) + 1 + 1))) == NULL) {
1.1 deraadt 161: ewprintf("Can't get %d bytes", strlen(fn) + 1);
162: return (ABORT);
163: }
164: (void) strcpy(nname, fn);
1.5 millert 165: (void) strcat(nname, "~");
166: if (rename(fn, nname) < 0) {
1.1 deraadt 167: free(nname);
168: return (FALSE);
169: }
170: free(nname);
171: return (TRUE);
172: }
173: #endif
174:
175: /*
176: * The string "fn" is a file name.
177: * Perform any required appending of directory name or case adjustments.
178: * If NO_DIR is not defined, the same file should be refered to even if the
179: * working directory changes.
180: */
181: #ifdef SYMBLINK
182: #include <sys/types.h>
183: #include <sys/stat.h>
184: #ifndef MAXLINK
185: #define MAXLINK 8 /* maximum symbolic links to follow */
186: #endif
187: #endif
188: #include <pwd.h>
189: #ifndef NO_DIR
1.7 millert 190: extern char *wdir;
1.1 deraadt 191: #endif
192:
1.7 millert 193: char *
194: adjustname(fn)
195: char *fn;
1.1 deraadt 196: {
1.7 millert 197: char *cp;
198: static char fnb[NFILEN];
199: struct passwd *pwent;
1.1 deraadt 200: #ifdef SYMBLINK
1.7 millert 201: struct stat statbuf;
202: int i, j;
203: char linkbuf[NFILEN];
1.1 deraadt 204: #endif
205:
1.7 millert 206: switch (*fn) {
207: case '/':
208: cp = fnb;
209: *cp++ = *fn++;
210: break;
1.1 deraadt 211: case '~':
1.7 millert 212: fn++;
1.8 ! millert 213: cp = getenv("HOME");
! 214: if (cp != NULL && *cp != '\0' && (*fn == '/' || *fn == '\0')) {
! 215: (VOID) strcpy(fnb, cp);
1.7 millert 216: cp = fnb + strlen(fnb);
217: if (*fn)
218: fn++;
219: break;
1.1 deraadt 220: } else {
1.7 millert 221: cp = fnb;
222: while (*fn && *fn != '/')
223: *cp++ = *fn++;
224: *cp = '\0';
225: if ((pwent = getpwnam(fnb)) != NULL) {
226: (VOID) strcpy(fnb, pwent->pw_dir);
227: cp = fnb + strlen(fnb);
228: break;
229: } else {
230: fn -= strlen(fnb) + 1;
231: /* can't find ~user, continue to default case */
232: }
1.1 deraadt 233: }
234: default:
235: #ifndef NODIR
1.7 millert 236: strcpy(fnb, wdir);
237: cp = fnb + strlen(fnb);
238: break;
1.1 deraadt 239: #else
1.7 millert 240: return fn; /* punt */
1.1 deraadt 241: #endif
1.7 millert 242: }
243: if (cp != fnb && cp[-1] != '/')
244: *cp++ = '/';
245: while (*fn) {
246: switch (*fn) {
247: case '.':
248: switch (fn[1]) {
249: case '\0':
250: *--cp = '\0';
251: return fnb;
252: case '/':
253: fn += 2;
254: continue;
255: case '.':
256: if (fn[2] != '/' && fn[2] != '\0')
257: break;
1.1 deraadt 258: #ifdef SYMBLINK
1.7 millert 259: cp[-1] = '\0';
260: for (j = MAXLINK; j-- &&
261: lstat(fnb, &statbuf) != -1 &&
262: (statbuf.st_mode & S_IFMT) == S_IFLNK &&
263: (i = readlink(fnb, linkbuf, sizeof linkbuf))
264: != -1;) {
265: if (linkbuf[0] != '/') {
266: --cp;
267: while (cp > fnb && *--cp != '/') {
268: }
269: ++cp;
270: (VOID) strncpy(cp, linkbuf, i);
271: cp += i;
272: } else {
273: (VOID) strncpy(fnb, linkbuf, i);
274: cp = fnb + i;
275: }
276: if (cp[-1] != '/')
277: *cp++ = '\0';
278: else
279: cp[-1] = '\0';
1.1 deraadt 280: }
1.7 millert 281: cp[-1] = '/';
1.1 deraadt 282: #endif
1.7 millert 283: --cp;
284: while (cp > fnb && *--cp != '/') {
285: }
286: ++cp;
287: if (fn[2] == '\0') {
288: *--cp = '\0';
289: return fnb;
290: }
291: fn += 3;
292: continue;
293: default:
294: break;
295: }
296: break;
297: case '/':
298: fn++;
299: continue;
300: default:
301: break;
302: }
303: while (*fn && (*cp++ = *fn++) != '/') {
304: }
305: }
306: if (cp[-1] == '/')
307: --cp;
308: *cp = '\0';
309: return fnb;
1.1 deraadt 310: }
311:
312: #ifndef NO_STARTUP
313: #include <sys/file.h>
314:
315: /*
316: * Find a startup file for the user and return its name. As a service
317: * to other pieces of code that may want to find a startup file (like
318: * the terminal driver in particular), accepts a suffix to be appended
319: * to the startup file name.
320: */
321: char *
322: startupfile(suffix)
1.7 millert 323: char *suffix;
1.1 deraadt 324: {
1.7 millert 325: char *file;
326: static char home[NFILEN];
1.1 deraadt 327:
1.8 ! millert 328: if ((file = getenv("HOME")) == NULL || *file == '\0')
1.7 millert 329: goto notfound;
330: if (strlen(file) + 7 >= NFILEN - 1)
331: goto notfound;
1.1 deraadt 332: (VOID) strcpy(home, file);
333: (VOID) strcat(home, "/.mg");
334: if (suffix != NULL) {
335: (VOID) strcat(home, "-");
336: (VOID) strcat(home, suffix);
337: }
1.7 millert 338: if (access(home, F_OK) == 0)
339: return home;
1.1 deraadt 340:
341: notfound:
342: #ifdef STARTUPFILE
343: file = STARTUPFILE;
344: if (suffix != NULL) {
345: (VOID) strcpy(home, file);
346: (VOID) strcat(home, "-");
347: (VOID) strcat(home, suffix);
348: file = home;
349: }
1.7 millert 350: if (access(file, F_OK) == 0)
351: return file;
1.1 deraadt 352: #endif
353:
354: return NULL;
355: }
356: #endif
357:
358: #ifndef NO_DIRED
1.4 millert 359: #include <sys/wait.h>
1.1 deraadt 360: #include "kbd.h"
361:
1.7 millert 362: int
1.1 deraadt 363: copy(frname, toname)
1.7 millert 364: char *frname;
365: char *toname;
1.1 deraadt 366: {
1.7 millert 367: pid_t pid;
368: int status;
1.1 deraadt 369:
1.7 millert 370: if ((pid = vfork())) {
371: if (pid == -1)
372: return -1;
373: execl("/bin/cp", "cp", frname, toname, (char *) NULL);
374: _exit(1); /* shouldn't happen */
375: }
376: while (wait(&status) != pid);
377: return status == 0;
378: }
379:
380: BUFFER *
381: dired_(dirname)
382: char *dirname;
383: {
384: BUFFER *bp;
385: FILE *dirpipe;
386: char line[256];
387:
388: if ((dirname = adjustname(dirname)) == NULL) {
389: ewprintf("Bad directory name");
390: return NULL;
391: }
392: if (dirname[strlen(dirname) - 1] != '/')
393: (VOID) strcat(dirname, "/");
394: if ((bp = findbuffer(dirname)) == NULL) {
395: ewprintf("Could not create buffer");
396: return NULL;
397: }
398: if (bclear(bp) != TRUE)
399: return FALSE;
400: (VOID) strcpy(line, "ls -al ");
401: (VOID) strcpy(&line[7], dirname);
402: if ((dirpipe = popen(line, "r")) == NULL) {
403: ewprintf("Problem opening pipe to ls");
404: return NULL;
405: }
406: line[0] = line[1] = ' ';
407: while (fgets(&line[2], 254, dirpipe) != NULL) {
408: line[strlen(line) - 1] = '\0'; /* remove ^J */
409: (VOID) addline(bp, line);
410: }
411: if (pclose(dirpipe) == -1) {
412: ewprintf("Problem closing pipe to ls");
413: return NULL;
414: }
415: bp->b_dotp = lforw(bp->b_linep); /* go to first line */
416: (VOID) strncpy(bp->b_fname, dirname, NFILEN);
417: if ((bp->b_modes[0] = name_mode("dired")) == NULL) {
418: bp->b_modes[0] = &map_table[0];
419: ewprintf("Could not find mode dired");
420: return NULL;
421: }
422: bp->b_nmodes = 0;
423: return bp;
1.1 deraadt 424: }
425:
1.7 millert 426: int
1.1 deraadt 427: d_makename(lp, fn)
1.7 millert 428: LINE *lp;
429: char *fn;
1.1 deraadt 430: {
1.7 millert 431: char *cp;
1.1 deraadt 432:
1.7 millert 433: if (llength(lp) <= 56)
434: return ABORT;
435: (VOID) strcpy(fn, curbp->b_fname);
436: cp = fn + strlen(fn);
437: bcopy(&lp->l_text[56], cp, llength(lp) - 56);
438: cp[llength(lp) - 56] = '\0';
439: return lgetc(lp, 2) == 'd';
1.1 deraadt 440: }
1.7 millert 441: #endif /* NO_DIRED */
1.1 deraadt 442:
443: struct filelist {
1.7 millert 444: LIST fl_l;
445: char fl_name[NFILEN + 2];
1.1 deraadt 446: };
447:
1.7 millert 448: /*
449: * these things had better be contiguous, because we're going to refer to the
450: * end of dirbuf + 1 byte
451: */
452: struct dirent dirbuf;
453: char dirdummy;
1.1 deraadt 454:
455: /*
456: * return list of file names that match the name in buf.
457: * System V version. listing is a flag indicating whether the
458: * list is being used for printing a listing rather than
459: * completion. In that case, trailing * and / are put on
460: * for executables and directories. The list is not sorted.
461: */
462:
1.7 millert 463: LIST *
464: make_file_list(buf, listing)
465: char *buf;
466: int listing;
467: {
468: char *dir, *file, *cp;
469: int len, i, preflen;
470: int fp;
471: LIST *last;
472: struct filelist *current;
473: char prefixx[NFILEN + 1];
474: struct stat statbuf;
475: char statname[NFILEN + 2];
476:
477: /*
478: * We need three different strings: dir - the name of the directory
479: * containing what the user typed. Must be a real unix file name,
480: * e.g. no ~user, etc.. Must not end in /. prefix - the portion of
481: * what the user typed that is before the names we are going to find
482: * in the directory. Must have a trailing / if the user typed it.
483: * names from the directory. we open dir, and return prefix
484: * concatenated with names.
485: */
486:
487: /* first we get a directory name we can look up */
488: /*
489: * Names ending in . are potentially odd, because adjustname will
490: * treat foo/.. as a reference to another directory, whereas we are
491: * interested in names starting with ..
492: */
493: len = strlen(buf);
494: if (buf[len - 1] == '.') {
495: buf[len - 1] = 'x';
496: dir = adjustname(buf);
497: buf[len - 1] = '.';
498: } else
499: dir = adjustname(buf);
500: /*
501: * If the user typed a trailing / or the empty string
502: * he wants us to use his file spec as a directory name.
503: */
504: if (buf[0] && buf[strlen(buf) - 1] != '/') {
505: file = strrchr(dir, '/');
506: if (file) {
507: *file = 0;
508: if (*dir == 0)
509: dir = "/";
510: } else {
511: return (NULL);
512: }
1.1 deraadt 513: }
1.7 millert 514: /* Now we get the prefix of the name the user typed. */
515: strcpy(prefixx, buf);
516: cp = strrchr(prefixx, '/');
517: if (cp == NULL)
518: prefixx[0] = 0;
519: else
520: cp[1] = 0;
521:
522: preflen = strlen(prefixx);
523: /* cp is the tail of buf that really needs to be compared */
524: cp = buf + preflen;
525: len = strlen(cp);
526:
527: /*
528: * Now make sure that file names will fit in the buffers allocated.
529: * SV files are fairly short. For BSD, something more general would
530: * be required.
531: */
532: if ((preflen + MAXNAMLEN) > NFILEN)
533: return (NULL);
534: if ((strlen(dir) + MAXNAMLEN) > NFILEN)
535: listing = 0;
536:
537: /* loop over the specified directory, making up the list of files */
538:
539: /*
540: * Note that it is worth our time to filter out names that don't
541: * match, even though our caller is going to do so again, and to
542: * avoid doing the stat if completion is being done, because stat'ing
543: * every file in the directory is relatively expensive.
544: */
1.1 deraadt 545:
1.7 millert 546: fp = open(dir, 0);
547: if (fp < 0) {
548: return (NULL);
549: }
550: last = NULL;
551: /* clear entry after last so we can treat d_name as ASCIZ */
552: dirbuf.d_name[MAXNAMLEN] = 0;
553: while (1) {
554: if (read(fp, &dirbuf, sizeof(struct dirent)) <= 0) {
1.1 deraadt 555: break;
1.7 millert 556: }
557: if (dirbuf.d_ino == 0) /* entry not allocated */
558: continue;
559: for (i = 0; i < len; ++i) {
560: if (cp[i] != dirbuf.d_name[i])
561: break;
562: }
563: if (i < len)
564: continue;
565: current = (struct filelist *) malloc(sizeof(struct filelist));
566: current->fl_l.l_next = last;
567: current->fl_l.l_name = current->fl_name;
568: last = (LIST *) current;
569: strcpy(current->fl_name, prefixx);
570: strcat(current->fl_name, dirbuf.d_name);
571: if (listing) {
572: statbuf.st_mode = 0;
573: strcpy(statname, dir);
574: strcat(statname, "/");
575: strcat(statname, dirbuf.d_name);
576: stat(statname, &statbuf);
577: if (statbuf.st_mode & 040000)
578: strcat(current->fl_name, "/");
579: else if (statbuf.st_mode & 0100)
580: strcat(current->fl_name, "*");
581: }
1.1 deraadt 582: }
1.7 millert 583: close(fp);
1.1 deraadt 584:
1.7 millert 585: return (last);
1.1 deraadt 586: }