[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.2

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