[BACK]Return to fileio.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mg

Annotation of src/usr.bin/mg/fileio.c, Revision 1.10

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