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

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