[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.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 = &ltext(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: }