# 2.11BSD#431 - /usr/src/bin/tar.c

##### Functions

    backtape          X
    bread             X
    bsrch             X
    checkdir          X
    checkf            X
    checksum          X
    checkupdate       X
    checkw            X
    cmp               X
    dodirtimes        X
    done              X
    dorep             X
    dotable           X
    doxtract          X
    endtape           X
    flushtape         X
    getbuf            X
    getcwd            X
    getdir            X
    getmem            X
    longt             X
    lookup            X
    main              X
    mterr             X
    onhup             X
    onintr            X
    onquit            X
    onterm            X
    openmt            X
    passtape          X
    pmode             X
    prefix            X
    putempty          X
    putfile           X
    readtape          X
    readtbuf          X
    response          X
    selectbits        X
    setimes           X
    tomodes           X
    usage             X
    wantit            X
    writetbuf         X

##### Variables

    Bflag             X
    Fflag             X
    cflag             X
    chksum            X
    copyright         X
    dblock            X
    dirstack          X
    fflag             X
    first             X
    freemem           X
    hflag             X
    high              X
    iflag             X
    ihead             X
    low               X
    m                 X
    m1                X
    m2                X
    m3                X
    m4                X
    m5                X
    m6                X
    m7                X
    m8                X
    m9                X
    magtape           X
    mflag             X
    mt                X
    mtime             X
    nblock            X
    njab              X
    oflag             X
    pflag             X
    prtlinkerr        X
    recno             X
    rflag             X
    stbuf             X
    tbuf              X
    term              X
    tflag             X
    tname             X
    usefile           X
    vflag             X
    wflag             X
    xflag             X

##### Macros

    N                 X
    NAMSIZ            X
    NBLOCK            X
    NTIM              X
    RGRP              X
    ROTH              X
    ROWN              X
    SGID              X
    STXT              X
    SUID              X
    TBLOCK            X
    WGRP              X
    WOTH              X
    WOWN              X
    XGRP              X
    XOTH              X
    XOWN              X
    max               X
    min               X
    writetape         X

##### struct's

    header            X
    linkbuf           X

##### unions's

    hblock            X

       1: /*
       2:  * Copyright (c) 1980 Regents of the University of California.
       3:  * All rights reserved.  The Berkeley software License Agreement
       4:  * specifies the terms and conditions for redistribution.
       5:  */
       6:
       7: #ifndef lint
       8: char copyright[] =
       9: "@(#) Copyright (c) 1980 Regents of the University of California.\n\
      10:  All rights reserved.\n";
      11: #endif not lint
      12:
      13: #ifndef lint
      14: static char sccsid[] = "@(#)tar.c	5.7 (Berkeley) 4/26/86";
      15: #endif not lint
      16:
      17: /*
      18:  * Tape Archival Program
      19:  */
      20: #include <stdio.h>
      21: #include <sys/param.h>
      22: #include <sys/stat.h>
      23: #include <sys/dir.h>
      24: #include <sys/ioctl.h>
      25: #include <sys/mtio.h>
      26: #include <sys/time.h>
      27: #include <signal.h>
      28: #include <errno.h>
      29: #include <fcntl.h>
      30:
      31: #define TBLOCK  512
      32: #define NBLOCK  20
      33: #define NAMSIZ  100
      34:
      35: #define writetape(b)    writetbuf(b, 1)
      36: #define min(a,b)  ((a) < (b) ? (a) : (b))
      37: #define max(a,b)  ((a) > (b) ? (a) : (b))
      38:
      39: union hblock {
      40:     char dummy[TBLOCK];
      41:     struct header {
      42:         char name[NAMSIZ];
      43:         char mode[8];
      44:         char uid[8];
      45:         char gid[8];
      46:         char size[12];
      47:         char mtime[12];
      48:         char chksum[8];
      49:         char linkflag;
      50:         char linkname[NAMSIZ];
      51:     } dbuf;
      52: };
      53:
      54: struct linkbuf {
      55:     ino_t   inum;
      56:     dev_t   devnum;
      57:     int count;
      58:     char    pathname[NAMSIZ];
      59:     struct  linkbuf *nextp;
      60: };
      61:
      62: union   hblock dblock;
      63: union   hblock *tbuf;
      64: struct  linkbuf *ihead;
      65: struct  stat stbuf;
      66:
      67: int rflag;
      68: int xflag;
      69: int vflag;
      70: int tflag;
      71: int cflag;
      72: int mflag;
      73: int fflag;
      74: int iflag;
      75: int oflag;
      76: int pflag;
      77: int wflag;
      78: int hflag;
      79: int Bflag;
      80: int Fflag;
      81:
      82: int mt;
      83: int term;
      84: int chksum;
      85: int recno;
      86: int first;
      87: int prtlinkerr;
      88: int freemem = 1;
      89: int nblock = 0;
      90: int onintr();
      91: int onquit();
      92: int onhup();
      93: #ifdef notdef
      94: int onterm();
      95: #endif
      96:
      97: daddr_t low;
      98: daddr_t high;
      99: daddr_t bsrch();
     100:
     101: FILE    *vfile = stdout;
     102: FILE    *tfile;
     103: char    tname[] = "/tmp/tarXXXXXX";
     104: char    *usefile;
     105: char    magtape[] = "/dev/rmt8";
     106: char    *malloc();
     107: long    time();
     108: off_t   lseek();
     109: char    *mktemp();
     110: char    *sprintf();
     111: char    *strcat();
     112: char    *strcpy();
     113: char    *rindex();
     114: char    *getcwd();
     115: char    *getwd();
     116: char    *getmem();
     117:
     118: main(argc, argv)
     119: int argc;
     120: char    *argv[];
     121: {
     122:     char *cp;
     123:
     124:     if (argc < 2)
     125:         usage();
     126:
     127:     tfile = NULL;
     128:     usefile =  magtape;
     129:     argv[argc] = 0;
     130:     argv++;
     131:     for (cp = *argv++; *cp; cp++)
     132:         switch(*cp) {
     133:
     134:         case 'f':
     135:             if (*argv == 0) {
     136:                 fprintf(stderr,
     137:             "tar: tapefile must be specified with 'f' option\n");
     138:                 usage();
     139:             }
     140:             usefile = *argv++;
     141:             fflag++;
     142:             break;
     143:
     144:         case 'c':
     145:             cflag++;
     146:             rflag++;
     147:             break;
     148:
     149:         case 'o':
     150:             oflag++;
     151:             break;
     152:
     153:         case 'p':
     154:             pflag++;
     155:             break;
     156:
     157:         case 'u':
     158:             mktemp(tname);
     159:             if ((tfile = fopen(tname, "w")) == NULL) {
     160:                 fprintf(stderr,
     161:                  "tar: cannot create temporary file (%s)\n",
     162:                  tname);
     163:                 done(1);
     164:             }
     165:             fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n");
     166:             /*FALL THRU*/
     167:
     168:         case 'r':
     169:             rflag++;
     170:             break;
     171:
     172:         case 'v':
     173:             vflag++;
     174:             break;
     175:
     176:         case 'w':
     177:             wflag++;
     178:             break;
     179:
     180:         case 'x':
     181:             xflag++;
     182:             break;
     183:
     184:         case 't':
     185:             tflag++;
     186:             break;
     187:
     188:         case 'm':
     189:             mflag++;
     190:             break;
     191:
     192:         case '-':
     193:             break;
     194:
     195:         case '0':
     196:         case '1':
     197:         case '4':
     198:         case '5':
     199:         case '7':
     200:         case '8':
     201:             magtape[8] = *cp;
     202:             usefile = magtape;
     203:             break;
     204:
     205:         case 'b':
     206:             if (*argv == 0) {
     207:                 fprintf(stderr,
     208:             "tar: blocksize must be specified with 'b' option\n");
     209:                 usage();
     210:             }
     211:             nblock = atoi(*argv);
     212:             if (nblock <= 0) {
     213:                 fprintf(stderr,
     214:                     "tar: invalid blocksize \"%s\"\n", *argv);
     215:                 done(1);
     216:             }
     217:             argv++;
     218:             break;
     219:
     220:         case 'l':
     221:             prtlinkerr++;
     222:             break;
     223:
     224:         case 'h':
     225:             hflag++;
     226:             break;
     227:
     228:         case 'i':
     229:             iflag++;
     230:             break;
     231:
     232:         case 'B':
     233:             Bflag++;
     234:             break;
     235:
     236:         case 'F':
     237:             Fflag++;
     238:             break;
     239:
     240:         default:
     241:             fprintf(stderr, "tar: %c: unknown option\n", *cp);
     242:             usage();
     243:         }
     244:
     245:     if (!rflag && !xflag && !tflag)
     246:         usage();
     247:     if (rflag) {
     248:         if (cflag && tfile != NULL)
     249:             usage();
     250:         if (signal(SIGINT, SIG_IGN) != SIG_IGN)
     251:             (void) signal(SIGINT, onintr);
     252:         if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
     253:             (void) signal(SIGHUP, onhup);
     254:         if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
     255:             (void) signal(SIGQUIT, onquit);
     256: #ifdef notdef
     257:         if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
     258:             (void) signal(SIGTERM, onterm);
     259: #endif
     260:         mt = openmt(usefile, 1);
     261:         dorep(argv);
     262:         done(0);
     263:     }
     264:     mt = openmt(usefile, 0);
     265:     if (xflag)
     266:         doxtract(argv);
     267:     else
     268:         dotable(argv);
     269:     done(0);
     270: }
     271:
     272: usage()
     273: {
     274:     fprintf(stderr,
     275: "tar: usage: tar -{txru}[cvfblmhopwBi] [tapefile] [blocksize] file1 file2...\n");
     276:     done(1);
     277: }
     278:
     279: int
     280: openmt(tape, writing)
     281:     char *tape;
     282:     int writing;
     283: {
     284:
     285:     if (strcmp(tape, "-") == 0) {
     286:         /*
     287: 		 * Read from standard input or write to standard output.
     288: 		 */
     289:         if (writing) {
     290:             if (cflag == 0) {
     291:                 fprintf(stderr,
     292:              "tar: can only create standard output archives\n");
     293:                 done(1);
     294:             }
     295:             vfile = stderr;
     296:             setlinebuf(vfile);
     297:             mt = dup(1);
     298:         } else {
     299:             mt = dup(0);
     300:             Bflag++;
     301:         }
     302:     } else {
     303:         /*
     304: 		 * Use file or tape on local machine.
     305: 		 */
     306:         if (writing) {
     307:             if (cflag)
     308:                 mt = open(tape, O_RDWR|O_CREAT|O_TRUNC, 0666);
     309:             else
     310:                 mt = open(tape, O_RDWR);
     311:         } else
     312:             mt = open(tape, O_RDONLY);
     313:         if (mt < 0) {
     314:             fprintf(stderr, "tar: ");
     315:             perror(tape);
     316:             done(1);
     317:         }
     318:     }
     319:     return(mt);
     320: }
     321:
     322: dorep(argv)
     323:     char *argv[];
     324: {
     325:     register char *cp, *cp2;
     326:     char wdir[MAXPATHLEN], tempdir[MAXPATHLEN], *parent;
     327:
     328:     if (!cflag) {
     329:         getdir();
     330:         do {
     331:             passtape();
     332:             if (term)
     333:                 done(0);
     334:             getdir();
     335:         } while (!endtape());
     336:         backtape();
     337:         if (tfile != NULL) {
     338:             char buf[200];
     339:
     340:             sprintf(buf,
     341: "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s",
     342:                 tname, tname, tname, tname, tname, tname);
     343:             fflush(tfile);
     344:             system(buf);
     345:             freopen(tname, "r", tfile);
     346:             fstat(fileno(tfile), &stbuf);
     347:             high = stbuf.st_size;
     348:         }
     349:     }
     350:
     351:     (void) getcwd(wdir);
     352:     while (*argv && ! term) {
     353:         cp2 = *argv;
     354:         if (!strcmp(cp2, "-C") && argv[1]) {
     355:             argv++;
     356:             if (chdir(*argv) < 0) {
     357:                 fprintf(stderr, "tar: can't change directories to ");
     358:                 perror(*argv);
     359:             } else
     360:                 (void) getcwd(wdir);
     361:             argv++;
     362:             continue;
     363:         }
     364:
     365:         if (*argv[0] == '/'){
     366:             parent = "";
     367:         } else {
     368:             parent = wdir;
     369:         }
     370:
     371:         for (cp = *argv; *cp; cp++)
     372:             if (*cp == '/')
     373:                 cp2 = cp;
     374:         if (cp2 != *argv) {
     375:             *cp2 = '\0';
     376:             if (chdir(*argv) < 0) {
     377:                 fprintf(stderr, "tar: can't change directories to ");
     378:                 perror(*argv);
     379:                 continue;
     380:             }
     381:             parent = getcwd(tempdir);
     382:             *cp2 = '/';
     383:             cp2++;
     384:         }
     385:         putfile(*argv++, cp2, parent);
     386:         if (chdir(wdir) < 0) {
     387:             fprintf(stderr, "tar: cannot change back?: ");
     388:             perror(wdir);
     389:         }
     390:     }
     391:     putempty();
     392:     putempty();
     393:     flushtape();
     394:     if (prtlinkerr == 0)
     395:         return;
     396:     for (; ihead != NULL; ihead = ihead->nextp) {
     397:         if (ihead->count == 0)
     398:             continue;
     399:         fprintf(stderr, "tar: missing links to %s\n", ihead->pathname);
     400:     }
     401: }
     402:
     403: endtape()
     404: {
     405:     return (dblock.dbuf.name[0] == '\0');
     406: }
     407:
     408: getdir()
     409: {
     410:     register struct stat *sp;
     411:     int i;
     412:
     413: top:
     414:     readtape((char *)&dblock);
     415:     if (dblock.dbuf.name[0] == '\0')
     416:         return;
     417:     sp = &stbuf;
     418:     sscanf(dblock.dbuf.mode, "%o", &i);
     419:     sp->st_mode = i;
     420:     sscanf(dblock.dbuf.uid, "%o", &i);
     421:     sp->st_uid = i;
     422:     sscanf(dblock.dbuf.gid, "%o", &i);
     423:     sp->st_gid = i;
     424:     sscanf(dblock.dbuf.size, "%lo", &sp->st_size);
     425:     sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime);
     426:     sscanf(dblock.dbuf.chksum, "%o", &chksum);
     427:     if (chksum != (i = checksum())) {
     428:         fprintf(stderr, "tar: directory checksum error (%d != %d)\n",
     429:             chksum, i);
     430:         if (iflag)
     431:             goto top;
     432:         done(2);
     433:     }
     434:     if (tfile != NULL)
     435:         fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime);
     436: }
     437:
     438: passtape()
     439: {
     440:     long blocks;
     441:     char *bufp;
     442:
     443:     if (dblock.dbuf.linkflag == '1')
     444:         return;
     445:     blocks = stbuf.st_size;
     446:     blocks += TBLOCK-1;
     447:     blocks /= TBLOCK;
     448:
     449:     while (blocks-- > 0)
     450:         (void) readtbuf(&bufp, TBLOCK);
     451: }
     452:
     453: putfile(longname, shortname, parent)
     454:     char *longname;
     455:     char *shortname;
     456:     char *parent;
     457: {
     458:     int infile = 0;
     459:     long blocks;
     460:     char buf[TBLOCK];
     461:     char *bigbuf;
     462:     register char *cp;
     463:     struct direct *dp;
     464:     DIR *dirp;
     465:     register int i;
     466:     long l;
     467:     char newparent[NAMSIZ+64];
     468:     extern int errno;
     469:     int maxread;
     470:     int hint;       /* amount to write to get "in sync" */
     471:
     472:     if (!hflag)
     473:         i = lstat(shortname, &stbuf);
     474:     else
     475:         i = stat(shortname, &stbuf);
     476:     if (i < 0) {
     477:         fprintf(stderr, "tar: ");
     478:         perror(longname);
     479:         return;
     480:     }
     481:     if (tfile != NULL && checkupdate(longname) == 0)
     482:         return;
     483:     if (checkw('r', longname) == 0)
     484:         return;
     485:     if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0)
     486:         return;
     487:
     488:     switch (stbuf.st_mode & S_IFMT) {
     489:     case S_IFDIR:
     490:         for (i = 0, cp = buf; *cp++ = longname[i++];)
     491:             ;
     492:         *--cp = '/';
     493:         *++cp = 0  ;
     494:         if (!oflag) {
     495:             if ((cp - buf) >= NAMSIZ) {
     496:                 fprintf(stderr, "tar: %s: file name too long\n",
     497:                     longname);
     498:                 return;
     499:             }
     500:             stbuf.st_size = 0;
     501:             tomodes(&stbuf);
     502:             strcpy(dblock.dbuf.name,buf);
     503:             sprintf(dblock.dbuf.chksum, "%6o", checksum());
     504:             (void) writetape((char *)&dblock);
     505:         }
     506:         sprintf(newparent, "%s/%s", parent, shortname);
     507:         if (chdir(shortname) < 0) {
     508:             perror(shortname);
     509:             return;
     510:         }
     511:         if ((dirp = opendir(".")) == NULL) {
     512:             fprintf(stderr, "tar: %s: directory read error\n",
     513:                 longname);
     514:             if (chdir(parent) < 0) {
     515:                 fprintf(stderr, "tar: cannot change back?: ");
     516:                 perror(parent);
     517:             }
     518:             return;
     519:         }
     520:         while ((dp = readdir(dirp)) != NULL && !term) {
     521:             if (dp->d_ino == 0)
     522:                 continue;
     523:             if (!strcmp(".", dp->d_name) ||
     524:                 !strcmp("..", dp->d_name))
     525:                 continue;
     526:             strcpy(cp, dp->d_name);
     527:             l = telldir(dirp);
     528:             closedir(dirp);
     529:             putfile(buf, cp, newparent);
     530:             dirp = opendir(".");
     531:             seekdir(dirp, l);
     532:         }
     533:         closedir(dirp);
     534:         if (chdir(parent) < 0) {
     535:             fprintf(stderr, "tar: cannot change back?: ");
     536:             perror(parent);
     537:         }
     538:         break;
     539:
     540:     case S_IFLNK:
     541:         tomodes(&stbuf);
     542:         if (strlen(longname) >= NAMSIZ) {
     543:             fprintf(stderr, "tar: %s: file name too long\n",
     544:                 longname);
     545:             return;
     546:         }
     547:         strcpy(dblock.dbuf.name, longname);
     548:         if (stbuf.st_size + 1 >= NAMSIZ) {
     549:             fprintf(stderr, "tar: %s: symbolic link too long\n",
     550:                 longname);
     551:             return;
     552:         }
     553:         i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1);
     554:         if (i < 0) {
     555:             fprintf(stderr, "tar: can't read symbolic link ");
     556:             perror(longname);
     557:             return;
     558:         }
     559:         dblock.dbuf.linkname[i] = '\0';
     560:         dblock.dbuf.linkflag = '2';
     561:         if (vflag)
     562:             fprintf(vfile, "a %s symbolic link to %s\n",
     563:                 longname, dblock.dbuf.linkname);
     564:         sprintf(dblock.dbuf.size, "%11lo", 0L);
     565:         sprintf(dblock.dbuf.chksum, "%6o", checksum());
     566:         (void) writetape((char *)&dblock);
     567:         break;
     568:
     569:     case S_IFREG:
     570:         if ((infile = open(shortname, 0)) < 0) {
     571:             fprintf(stderr, "tar: ");
     572:             perror(longname);
     573:             return;
     574:         }
     575:         tomodes(&stbuf);
     576:         if (strlen(longname) >= NAMSIZ) {
     577:             fprintf(stderr, "tar: %s: file name too long\n",
     578:                 longname);
     579:             close(infile);
     580:             return;
     581:         }
     582:         strcpy(dblock.dbuf.name, longname);
     583:         if (stbuf.st_nlink > 1) {
     584:             struct linkbuf *lp;
     585:             int found = 0;
     586:
     587:             for (lp = ihead; lp != NULL; lp = lp->nextp)
     588:                 if (lp->inum == stbuf.st_ino &&
     589:                     lp->devnum == stbuf.st_dev) {
     590:                     found++;
     591:                     break;
     592:                 }
     593:             if (found) {
     594:                 strcpy(dblock.dbuf.linkname, lp->pathname);
     595:                 dblock.dbuf.linkflag = '1';
     596:                 sprintf(dblock.dbuf.chksum, "%6o", checksum());
     597:                 (void) writetape( (char *) &dblock);
     598:                 if (vflag)
     599:                     fprintf(vfile, "a %s link to %s\n",
     600:                         longname, lp->pathname);
     601:                 lp->count--;
     602:                 close(infile);
     603:                 return;
     604:             }
     605:             lp = (struct linkbuf *) getmem(sizeof(*lp));
     606:             if (lp != NULL) {
     607:                 lp->nextp = ihead;
     608:                 ihead = lp;
     609:                 lp->inum = stbuf.st_ino;
     610:                 lp->devnum = stbuf.st_dev;
     611:                 lp->count = stbuf.st_nlink - 1;
     612:                 strcpy(lp->pathname, longname);
     613:             }
     614:         }
     615:         blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK;
     616:         if (vflag)
     617:             fprintf(vfile, "a %s %ld blocks\n", longname, blocks);
     618:         sprintf(dblock.dbuf.chksum, "%6o", checksum());
     619:         hint = writetape((char *)&dblock);
     620:         maxread = max(stbuf.st_blksize, (nblock * TBLOCK));
     621:         if ((bigbuf = malloc((unsigned)maxread)) == 0) {
     622:             maxread = TBLOCK;
     623:             bigbuf = buf;
     624:         }
     625:
     626:         while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0
     627:           && blocks > 0) {
     628:             register int nblks;
     629:
     630:             nblks = ((i-1)/TBLOCK)+1;
     631:             if (nblks > blocks)
     632:                 nblks = blocks;
     633:             hint = writetbuf(bigbuf, nblks);
     634:             blocks -= nblks;
     635:         }
     636:         close(infile);
     637:         if (bigbuf != buf)
     638:             free(bigbuf);
     639:         if (i < 0) {
     640:             fprintf(stderr, "tar: Read error on ");
     641:             perror(longname);
     642:         } else if (blocks != 0 || i != 0)
     643:             fprintf(stderr, "tar: %s: file changed size\n",
     644:                 longname);
     645:         while (--blocks >=  0)
     646:             putempty();
     647:         break;
     648:
     649:     default:
     650:         fprintf(stderr, "tar: %s is not a file. Not dumped\n",
     651:             longname);
     652:         break;
     653:     }
     654: }
     655:
     656: doxtract(argv)
     657:     char *argv[];
     658: {
     659:     long blocks, bytes;
     660:     int ofile, i;
     661:     extern int errno;
     662:
     663:     for (;;) {
     664:         if ((i = wantit(argv)) == 0)
     665:             continue;
     666:         if (i == -1)
     667:             break;      /* end of tape */
     668:         if (checkw('x', dblock.dbuf.name) == 0) {
     669:             passtape();
     670:             continue;
     671:         }
     672:         if (Fflag) {
     673:             char *s;
     674:
     675:             if ((s = rindex(dblock.dbuf.name, '/')) == 0)
     676:                 s = dblock.dbuf.name;
     677:             else
     678:                 s++;
     679:             if (checkf(s, stbuf.st_mode, Fflag) == 0) {
     680:                 passtape();
     681:                 continue;
     682:             }
     683:         }
     684:         if (checkdir(dblock.dbuf.name)) {   /* have a directory */
     685:             if (mflag == 0)
     686:                 dodirtimes(&dblock);
     687:             continue;
     688:         }
     689:         if (dblock.dbuf.linkflag == '2') {  /* symlink */
     690:             /*
     691: 			 * only unlink non directories or empty
     692: 			 * directories
     693: 			 */
     694:             if (rmdir(dblock.dbuf.name) < 0) {
     695:                 if (errno == ENOTDIR)
     696:                     unlink(dblock.dbuf.name);
     697:             }
     698:             if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) {
     699:                 fprintf(stderr, "tar: %s: symbolic link failed: ",
     700:                     dblock.dbuf.name);
     701:                 perror("");
     702:                 continue;
     703:             }
     704:             if (vflag)
     705:                 fprintf(vfile, "x %s symbolic link to %s\n",
     706:                     dblock.dbuf.name, dblock.dbuf.linkname);
     707: #ifdef notdef
     708:             /* ignore alien orders */
     709:             chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
     710:             if (mflag == 0)
     711:                 setimes(dblock.dbuf.name, stbuf.st_mtime);
     712:             if (pflag)
     713:                 chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
     714: #endif
     715:             continue;
     716:         }
     717:         if (dblock.dbuf.linkflag == '1') {  /* regular link */
     718:             /*
     719: 			 * only unlink non directories or empty
     720: 			 * directories
     721: 			 */
     722:             if (rmdir(dblock.dbuf.name) < 0) {
     723:                 if (errno == ENOTDIR)
     724:                     unlink(dblock.dbuf.name);
     725:             }
     726:             if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) {
     727:                 fprintf(stderr, "tar: can't link %s to %s: ",
     728:                     dblock.dbuf.name, dblock.dbuf.linkname);
     729:                 perror("");
     730:                 continue;
     731:             }
     732:             if (vflag)
     733:                 fprintf(vfile, "%s linked to %s\n",
     734:                     dblock.dbuf.name, dblock.dbuf.linkname);
     735:             continue;
     736:         }
     737:         if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) {
     738:             fprintf(stderr, "tar: can't create %s: ",
     739:                 dblock.dbuf.name);
     740:             perror("");
     741:             passtape();
     742:             continue;
     743:         }
     744:         chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
     745:         blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK;
     746:         if (vflag)
     747:             fprintf(vfile, "x %s, %ld bytes, %ld tape blocks\n",
     748:                 dblock.dbuf.name, bytes, blocks);
     749:         for (; blocks > 0;) {
     750:             register int nread;
     751:             char    *bufp;
     752:             register int nwant;
     753:
     754:             nwant = NBLOCK*TBLOCK;
     755:             if (nwant > (blocks*TBLOCK))
     756:                 nwant = (blocks*TBLOCK);
     757:             nread = readtbuf(&bufp, nwant);
     758:             if (write(ofile, bufp, (int)min(nread, bytes)) < 0) {
     759:                 fprintf(stderr,
     760:                     "tar: %s: HELP - extract write error",
     761:                     dblock.dbuf.name);
     762:                 perror("");
     763:                 done(2);
     764:             }
     765:             bytes -= nread;
     766:             blocks -= (((nread-1)/TBLOCK)+1);
     767:         }
     768:         close(ofile);
     769:         if (mflag == 0)
     770:             setimes(dblock.dbuf.name, stbuf.st_mtime);
     771:         if (pflag)
     772:             chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
     773:     }
     774:     if (mflag == 0) {
     775:         dblock.dbuf.name[0] = '\0'; /* process the whole stack */
     776:         dodirtimes(&dblock);
     777:     }
     778: }
     779:
     780: dotable(argv)
     781:     char *argv[];
     782: {
     783:     register int i;
     784:
     785:     for (;;) {
     786:         if ((i = wantit(argv)) == 0)
     787:             continue;
     788:         if (i == -1)
     789:             break;      /* end of tape */
     790:         if (vflag)
     791:             longt(&stbuf);
     792:         printf("%s", dblock.dbuf.name);
     793:         if (dblock.dbuf.linkflag == '1')
     794:             printf(" linked to %s", dblock.dbuf.linkname);
     795:         if (dblock.dbuf.linkflag == '2')
     796:             printf(" symbolic link to %s", dblock.dbuf.linkname);
     797:         printf("\n");
     798:         passtape();
     799:     }
     800: }
     801:
     802: putempty()
     803: {
     804:     char buf[TBLOCK];
     805:
     806:     bzero(buf, sizeof (buf));
     807:     (void) writetape(buf);
     808: }
     809:
     810: longt(st)
     811:     register struct stat *st;
     812: {
     813:     register char *cp;
     814:     char *ctime();
     815:
     816:     pmode(st);
     817:     printf("%3d/%1d", st->st_uid, st->st_gid);
     818:     printf("%7ld", st->st_size);
     819:     cp = ctime(&st->st_mtime);
     820:     printf(" %-12.12s %-4.4s ", cp+4, cp+20);
     821: }
     822:
     823: #define SUID    04000
     824: #define SGID    02000
     825: #define ROWN    0400
     826: #define WOWN    0200
     827: #define XOWN    0100
     828: #define RGRP    040
     829: #define WGRP    020
     830: #define XGRP    010
     831: #define ROTH    04
     832: #define WOTH    02
     833: #define XOTH    01
     834: #define STXT    01000
     835: int m1[] = { 1, ROWN, 'r', '-' };
     836: int m2[] = { 1, WOWN, 'w', '-' };
     837: int m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
     838: int m4[] = { 1, RGRP, 'r', '-' };
     839: int m5[] = { 1, WGRP, 'w', '-' };
     840: int m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
     841: int m7[] = { 1, ROTH, 'r', '-' };
     842: int m8[] = { 1, WOTH, 'w', '-' };
     843: int m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
     844:
     845: int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
     846:
     847: pmode(st)
     848:     register struct stat *st;
     849: {
     850:     register int **mp;
     851:
     852:     for (mp = &m[0]; mp < &m[9];)
     853:         selectbits(*mp++, st);
     854: }
     855:
     856: selectbits(pairp, st)
     857:     int *pairp;
     858:     struct stat *st;
     859: {
     860:     register int n, *ap;
     861:
     862:     ap = pairp;
     863:     n = *ap++;
     864:     while (--n>=0 && (st->st_mode&*ap++)==0)
     865:         ap++;
     866:     putchar(*ap);
     867: }
     868:
     869: /*
     870:  * Make all directories needed by `name'.  If `name' is itself
     871:  * a directory on the tar tape (indicated by a trailing '/'),
     872:  * return 1; else 0.
     873:  */
     874: checkdir(name)
     875:     register char *name;
     876: {
     877:     register char *cp;
     878:
     879:     /*
     880: 	 * Quick check for existence of directory.
     881: 	 */
     882:     if ((cp = rindex(name, '/')) == 0)
     883:         return (0);
     884:     *cp = '\0';
     885:     if (access(name, 0) == 0) { /* already exists */
     886:         *cp = '/';
     887:         return (cp[1] == '\0'); /* return (lastchar == '/') */
     888:     }
     889:     *cp = '/';
     890:
     891:     /*
     892: 	 * No luck, try to make all directories in path.
     893: 	 */
     894:     for (cp = name; *cp; cp++) {
     895:         if (*cp != '/')
     896:             continue;
     897:         *cp = '\0';
     898:         if (access(name, 0) < 0) {
     899:             if (mkdir(name, 0777) < 0) {
     900:                 perror(name);
     901:                 *cp = '/';
     902:                 return (0);
     903:             }
     904:             chown(name, stbuf.st_uid, stbuf.st_gid);
     905:             if (pflag && cp[1] == '\0') /* dir on the tape */
     906:                 chmod(name, stbuf.st_mode & 07777);
     907:         }
     908:         *cp = '/';
     909:     }
     910:     return (cp[-1]=='/');
     911: }
     912:
     913: onintr()
     914: {
     915:     (void) signal(SIGINT, SIG_IGN);
     916:     term++;
     917: }
     918:
     919: onquit()
     920: {
     921:     (void) signal(SIGQUIT, SIG_IGN);
     922:     term++;
     923: }
     924:
     925: onhup()
     926: {
     927:     (void) signal(SIGHUP, SIG_IGN);
     928:     term++;
     929: }
     930:
     931: #ifdef notdef
     932: onterm()
     933: {
     934:     (void) signal(SIGTERM, SIG_IGN);
     935:     term++;
     936: }
     937: #endif
     938:
     939: tomodes(sp)
     940: register struct stat *sp;
     941: {
     942:     register char *cp;
     943:
     944:     for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
     945:         *cp = '\0';
     946:     sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777);
     947:     sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid);
     948:     sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid);
     949:     sprintf(dblock.dbuf.size, "%11lo ", sp->st_size);
     950:     sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime);
     951: }
     952:
     953: checksum()
     954: {
     955:     register i;
     956:     register char *cp;
     957:
     958:     for (cp = dblock.dbuf.chksum;
     959:          cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++)
     960:         *cp = ' ';
     961:     i = 0;
     962:     for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
     963:         i += *cp;
     964:     return (i);
     965: }
     966:
     967: checkw(c, name)
     968:     char *name;
     969: {
     970:     if (!wflag)
     971:         return (1);
     972:     printf("%c ", c);
     973:     if (vflag)
     974:         longt(&stbuf);
     975:     printf("%s: ", name);
     976:     return (response() == 'y');
     977: }
     978:
     979: response()
     980: {
     981:     char c;
     982:
     983:     c = getchar();
     984:     if (c != '\n')
     985:         while (getchar() != '\n')
     986:             ;
     987:     else
     988:         c = 'n';
     989:     return (c);
     990: }
     991:
     992: checkf(name, mode, howmuch)
     993:     char *name;
     994:     int mode, howmuch;
     995: {
     996:     int l;
     997:
     998:     if ((mode & S_IFMT) == S_IFDIR){
     999:         if ((strcmp(name, "SCCS")==0) || (strcmp(name, "RCS")==0))
    1000:             return(0);
    1001:         return(1);
    1002:     }
    1003:     if ((l = strlen(name)) < 3)
    1004:         return (1);
    1005:     if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o')
    1006:         return (0);
    1007:     if (strcmp(name, "core") == 0 ||
    1008:         strcmp(name, "errs") == 0 ||
    1009:         (howmuch > 1 && strcmp(name, "a.out") == 0))
    1010:         return (0);
    1011:     /* SHOULD CHECK IF IT IS EXECUTABLE */
    1012:     return (1);
    1013: }
    1014:
    1015: /* Is the current file a new file, or the newest one of the same name? */
    1016: checkupdate(arg)
    1017:     char *arg;
    1018: {
    1019:     char name[100];
    1020:     long mtime;
    1021:     daddr_t seekp;
    1022:     daddr_t lookup();
    1023:
    1024:     rewind(tfile);
    1025:     for (;;) {
    1026:         if ((seekp = lookup(arg)) < 0)
    1027:             return (1);
    1028:         fseek(tfile, seekp, 0);
    1029:         fscanf(tfile, "%s %lo", name, &mtime);
    1030:         return (stbuf.st_mtime > mtime);
    1031:     }
    1032: }
    1033:
    1034: done(n)
    1035: {
    1036:     unlink(tname);
    1037:     exit(n);
    1038: }
    1039:
    1040: /*
    1041:  * Do we want the next entry on the tape, i.e. is it selected?  If
    1042:  * not, skip over the entire entry.  Return -1 if reached end of tape.
    1043:  */
    1044: wantit(argv)
    1045:     char *argv[];
    1046: {
    1047:     register char **cp;
    1048:
    1049:     getdir();
    1050:     if (endtape())
    1051:         return (-1);
    1052:     if (*argv == 0)
    1053:         return (1);
    1054:     for (cp = argv; *cp; cp++)
    1055:         if (prefix(*cp, dblock.dbuf.name))
    1056:             return (1);
    1057:     passtape();
    1058:     return (0);
    1059: }
    1060:
    1061: /*
    1062:  * Does s2 begin with the string s1, on a directory boundary?
    1063:  */
    1064: prefix(s1, s2)
    1065:     register char *s1, *s2;
    1066: {
    1067:     while (*s1)
    1068:         if (*s1++ != *s2++)
    1069:             return (0);
    1070:     if (*s2)
    1071:         return (*s2 == '/');
    1072:     return (1);
    1073: }
    1074:
    1075: #define N   200
    1076: int njab;
    1077:
    1078: daddr_t
    1079: lookup(s)
    1080:     char *s;
    1081: {
    1082:     register i;
    1083:     daddr_t a;
    1084:
    1085:     for(i=0; s[i]; i++)
    1086:         if (s[i] == ' ')
    1087:             break;
    1088:     a = bsrch(s, i, low, high);
    1089:     return (a);
    1090: }
    1091:
    1092: daddr_t
    1093: bsrch(s, n, l, h)
    1094:     daddr_t l, h;
    1095:     char *s;
    1096: {
    1097:     register i, j;
    1098:     char b[N];
    1099:     daddr_t m, m1;
    1100:
    1101:     njab = 0;
    1102:
    1103: loop:
    1104:     if (l >= h)
    1105:         return ((daddr_t) -1);
    1106:     m = l + (h-l)/2 - N/2;
    1107:     if (m < l)
    1108:         m = l;
    1109:     fseek(tfile, m, 0);
    1110:     fread(b, 1, N, tfile);
    1111:     njab++;
    1112:     for(i=0; i<N; i++) {
    1113:         if (b[i] == '\n')
    1114:             break;
    1115:         m++;
    1116:     }
    1117:     if (m >= h)
    1118:         return ((daddr_t) -1);
    1119:     m1 = m;
    1120:     j = i;
    1121:     for(i++; i<N; i++) {
    1122:         m1++;
    1123:         if (b[i] == '\n')
    1124:             break;
    1125:     }
    1126:     i = cmp(b+j, s, n);
    1127:     if (i < 0) {
    1128:         h = m;
    1129:         goto loop;
    1130:     }
    1131:     if (i > 0) {
    1132:         l = m1;
    1133:         goto loop;
    1134:     }
    1135:     return (m);
    1136: }
    1137:
    1138: cmp(b, s, n)
    1139:     char *b, *s;
    1140: {
    1141:     register i;
    1142:
    1143:     if (b[0] != '\n')
    1144:         exit(2);
    1145:     for(i=0; i<n; i++) {
    1146:         if (b[i+1] > s[i])
    1147:             return (-1);
    1148:         if (b[i+1] < s[i])
    1149:             return (1);
    1150:     }
    1151:     return (b[i+1] == ' '? 0 : -1);
    1152: }
    1153:
    1154: readtape(buffer)
    1155:     char *buffer;
    1156: {
    1157:     char *bufp;
    1158:
    1159:     if (first == 0)
    1160:         getbuf();
    1161:     (void) readtbuf(&bufp, TBLOCK);
    1162:     bcopy(bufp, buffer, TBLOCK);
    1163:     return(TBLOCK);
    1164: }
    1165:
    1166: readtbuf(bufpp, size)
    1167:     char **bufpp;
    1168:     int size;
    1169: {
    1170:     register int i;
    1171:
    1172:     if (recno >= nblock || first == 0) {
    1173:         if ((i = bread(mt, (char *)tbuf, TBLOCK*nblock)) < 0)
    1174:             mterr("read", i, 3);
    1175:         if (first == 0) {
    1176:             if ((i % TBLOCK) != 0) {
    1177:                 fprintf(stderr, "tar: tape blocksize error\n");
    1178:                 done(3);
    1179:             }
    1180:             i /= TBLOCK;
    1181:             if (i != nblock) {
    1182:                 fprintf(stderr, "tar: blocksize = %d\n", i);
    1183:                 nblock = i;
    1184:             }
    1185:             first = 1;
    1186:         }
    1187:         recno = 0;
    1188:     }
    1189:     if (size > ((nblock-recno)*TBLOCK))
    1190:         size = (nblock-recno)*TBLOCK;
    1191:     *bufpp = (char *)&tbuf[recno];
    1192:     recno += (size/TBLOCK);
    1193:     return (size);
    1194: }
    1195:
    1196: writetbuf(buffer, n)
    1197:     register char *buffer;
    1198:     register int n;
    1199: {
    1200:     int i;
    1201:
    1202:     if (first == 0) {
    1203:         getbuf();
    1204:         first = 1;
    1205:     }
    1206:     if (recno >= nblock) {
    1207:         i = write(mt, (char *)tbuf, TBLOCK*nblock);
    1208:         if (i != TBLOCK*nblock)
    1209:             mterr("write", i, 2);
    1210:         recno = 0;
    1211:     }
    1212:
    1213:     /*
    1214: 	 *  Special case:  We have an empty tape buffer, and the
    1215: 	 *  users data size is >= the tape block size:  Avoid
    1216: 	 *  the bcopy and dma direct to tape.  BIG WIN.  Add the
    1217: 	 *  residual to the tape buffer.
    1218: 	 */
    1219:     while (recno == 0 && n >= nblock) {
    1220:         i = write(mt, buffer, TBLOCK*nblock);
    1221:         if (i != TBLOCK*nblock)
    1222:             mterr("write", i, 2);
    1223:         n -= nblock;
    1224:         buffer += (nblock * TBLOCK);
    1225:     }
    1226:
    1227:     while (n-- > 0) {
    1228:         bcopy(buffer, (char *)&tbuf[recno++], TBLOCK);
    1229:         buffer += TBLOCK;
    1230:         if (recno >= nblock) {
    1231:             i = write(mt, (char *)tbuf, TBLOCK*nblock);
    1232:             if (i != TBLOCK*nblock)
    1233:                 mterr("write", i, 2);
    1234:             recno = 0;
    1235:         }
    1236:     }
    1237:
    1238:     /* Tell the user how much to write to get in sync */
    1239:     return (nblock - recno);
    1240: }
    1241:
    1242: backtape()
    1243: {
    1244:     static int mtdev = 1;
    1245:     static struct mtop mtop = {MTBSR, 1};
    1246:     struct mtget mtget;
    1247:
    1248:     if (mtdev == 1)
    1249:         mtdev = ioctl(mt, MTIOCGET, (char *)&mtget);
    1250:     if (mtdev == 0) {
    1251:         if (ioctl(mt, MTIOCTOP, (char *)&mtop) < 0) {
    1252:             fprintf(stderr, "tar: tape backspace error: ");
    1253:             perror("");
    1254:             done(4);
    1255:         }
    1256:     } else
    1257:         lseek(mt, (daddr_t) -TBLOCK*nblock, 1);
    1258:     recno--;
    1259: }
    1260:
    1261: flushtape()
    1262: {
    1263:     int i;
    1264:
    1265:     i = write(mt, (char *)tbuf, TBLOCK*nblock);
    1266:     if (i != TBLOCK*nblock)
    1267:         mterr("write", i, 2);
    1268: }
    1269:
    1270: mterr(operation, i, exitcode)
    1271:     char *operation;
    1272:     int i;
    1273: {
    1274:     fprintf(stderr, "tar: tape %s error: ", operation);
    1275:     if (i < 0)
    1276:         perror("");
    1277:     else
    1278:         fprintf(stderr, "unexpected EOF\n");
    1279:     done(exitcode);
    1280: }
    1281:
    1282: bread(fd, buf, size)
    1283:     int fd;
    1284:     char *buf;
    1285:     int size;
    1286: {
    1287:     int count;
    1288:     static int lastread = 0;
    1289:
    1290:     if (!Bflag)
    1291:         return (read(fd, buf, size));
    1292:
    1293:     for (count = 0; count < size; count += lastread) {
    1294:         lastread = read(fd, buf, size - count);
    1295:         if (lastread <= 0) {
    1296:             if (count > 0)
    1297:                 return (count);
    1298:             return (lastread);
    1299:         }
    1300:         buf += lastread;
    1301:     }
    1302:     return (count);
    1303: }
    1304:
    1305: char *
    1306: getcwd(buf)
    1307:     char *buf;
    1308: {
    1309:     if (getwd(buf) == NULL) {
    1310:         fprintf(stderr, "tar: %s\n", buf);
    1311:         exit(1);
    1312:     }
    1313:     return (buf);
    1314: }
    1315:
    1316: getbuf()
    1317: {
    1318:
    1319:     if (nblock == 0) {
    1320:         fstat(mt, &stbuf);
    1321:         if ((stbuf.st_mode & S_IFMT) == S_IFCHR)
    1322:             nblock = NBLOCK;
    1323:         else {
    1324:             nblock = stbuf.st_blksize / TBLOCK;
    1325:             if (nblock == 0)
    1326:                 nblock = NBLOCK;
    1327:         }
    1328:     }
    1329:     tbuf = (union hblock *)malloc((unsigned)nblock*TBLOCK);
    1330:     if (tbuf == NULL) {
    1331:         fprintf(stderr, "tar: blocksize %d too big, can't get memory\n",
    1332:             nblock);
    1333:         done(1);
    1334:     }
    1335: }
    1336:
    1337: /*
    1338:  * Save this directory and its mtime on the stack, popping and setting
    1339:  * the mtimes of any stacked dirs which aren't parents of this one.
    1340:  * A null directory causes the entire stack to be unwound and set.
    1341:  *
    1342:  * Since all the elements of the directory "stack" share a common
    1343:  * prefix, we can make do with one string.  We keep only the current
    1344:  * directory path, with an associated array of mtime's, one for each
    1345:  * '/' in the path.  A negative mtime means no mtime.  The mtime's are
    1346:  * offset by one (first index 1, not 0) because calling this with a null
    1347:  * directory causes mtime[0] to be set.
    1348:  *
    1349:  * This stack algorithm is not guaranteed to work for tapes created
    1350:  * with the 'r' option, but the vast majority of tapes with
    1351:  * directories are not.  This avoids saving every directory record on
    1352:  * the tape and setting all the times at the end.
    1353:  */
    1354: char dirstack[NAMSIZ];
    1355: #define NTIM (NAMSIZ/2+1)       /* a/b/c/d/... */
    1356: time_t mtime[NTIM];
    1357:
    1358: dodirtimes(hp)
    1359:     union hblock *hp;
    1360: {
    1361:     register char *p = dirstack;
    1362:     register char *q = hp->dbuf.name;
    1363:     register int ndir = 0;
    1364:     char *savp;
    1365:     int savndir;
    1366:
    1367:     /* Find common prefix */
    1368:     while (*p == *q) {
    1369:         if (*p++ == '/')
    1370:             ++ndir;
    1371:         q++;
    1372:     }
    1373:
    1374:     savp = p;
    1375:     savndir = ndir;
    1376:     while (*p) {
    1377:         /*
    1378: 		 * Not a child: unwind the stack, setting the times.
    1379: 		 * The order we do this doesn't matter, so we go "forward."
    1380: 		 */
    1381:         if (*p++ == '/')
    1382:             if (mtime[++ndir] >= 0) {
    1383:                 *--p = '\0';    /* zap the slash */
    1384:                 setimes(dirstack, mtime[ndir]);
    1385:                 *p++ = '/';
    1386:             }
    1387:     }
    1388:     p = savp;
    1389:     ndir = savndir;
    1390:
    1391:     /* Push this one on the "stack" */
    1392:     while (*p = *q++)   /* append the rest of the new dir */
    1393:         if (*p++ == '/')
    1394:             mtime[++ndir] = -1;
    1395:     mtime[ndir] = stbuf.st_mtime;   /* overwrite the last one */
    1396: }
    1397:
    1398: setimes(path, mt)
    1399:     char *path;
    1400:     time_t mt;
    1401: {
    1402:     struct timeval tv[2];
    1403:
    1404:     tv[0].tv_sec = time((time_t *) 0);
    1405:     tv[1].tv_sec = mt;
    1406:     tv[0].tv_usec = tv[1].tv_usec = 0;
    1407:     if (utimes(path, tv) < 0) {
    1408:         fprintf(stderr, "tar: can't set time on %s: ", path);
    1409:         perror("");
    1410:     }
    1411: }
    1412:
    1413: char *
    1414: getmem(size)
    1415: {
    1416:     char *p = malloc((unsigned) size);
    1417:
    1418:     if (p == NULL && freemem) {
    1419:         fprintf(stderr,
    1420:             "tar: out of memory, link and directory modtime info lost\n");
    1421:         freemem = 0;
    1422:     }
    1423:     return (p);
    1424: }

#### Defined functions

backtape defined in line 1242; used 1 times

- in line 336

bread defined in line 1282; used 1 times

- in line 1173

bsrch defined in line 1092; used 2 times

- in line 99, 1088

checkdir defined in line 874; used 1 times

- in line 684

checkf defined in line 992; used 2 times

- in line 485, 679

checksum defined in line 953; used 5 times

- in line 427, 503, 565, 596, 618

checkupdate defined in line 1016; used 1 times

- in line 481

checkw defined in line 967; used 2 times

- in line 483, 668

cmp defined in line 1138; used 1 times

- in line 1126

dodirtimes defined in line 1358; used 2 times

- in line 686, 776

done defined in line 1034; used 14 times

- in line 163, 215, 262, 269, 276, 293, 316, 333, 432, 763, 1178, 1254, 1279, 1333

dorep defined in line 322; used 1 times

- in line 261

dotable defined in line 780; used 1 times

- in line 268

doxtract defined in line 656; used 1 times

- in line 266

endtape defined in line 403; used 2 times

- in line 335, 1050

flushtape defined in line 1261; used 1 times

- in line 393

getbuf defined in line 1316; used 2 times

- in line 1160, 1203

getcwd defined in line 1305; used 4 times

- in line 114, 351, 360, 381

getdir defined in line 408; used 3 times

- in line 329-334(2), 1049

getmem defined in line 1413; used 2 times

- in line 116, 605

longt defined in line 810; used 2 times

- in line 791, 974

lookup defined in line 1078; used 2 times

- in line 1022-1026(2)

main defined in line 118; never used
mterr defined in line 1270; used 5 times

- in line 1174, 1209, 1222, 1233, 1267

onhup defined in line 925; used 2 times

- in line 92, 253

onintr defined in line 913; used 2 times

- in line 90, 251

onquit defined in line 919; used 2 times

- in line 91, 255

onterm defined in line 932; used 2 times

- in line 94, 258

openmt defined in line 279; used 2 times

- in line 260-264(2)

passtape defined in line 438; used 6 times

- in line 331, 669, 680, 741, 798, 1057

pmode defined in line 847; used 1 times

- in line 816

prefix defined in line 1064; used 1 times

- in line 1055

putempty defined in line 802; used 3 times

- in line 391-392(2), 646

putfile defined in line 453; used 2 times

- in line 385, 529

readtape defined in line 1154; used 1 times

- in line 414

readtbuf defined in line 1166; used 3 times

- in line 450, 757, 1161

response defined in line 979; used 1 times

- in line 976

selectbits defined in line 856; used 1 times

- in line 853

setimes defined in line 1398; used 3 times

- in line 711, 770, 1384

tomodes defined in line 939; used 3 times

- in line 501, 541, 575

usage defined in line 272; used 6 times

- in line 125, 138, 209, 242-249(3)

wantit defined in line 1044; used 2 times

- in line 664, 786

writetbuf defined in line 1196; used 2 times

- in line 35, 633

#### Defined variables

Bflag defined in line 79; used 3 times

- in line 233, 300, 1290

Fflag defined in line 80; used 5 times

- in line 237, 485(2), 672, 679

cflag defined in line 71; used 5 times

- in line 145, 248, 290, 307, 328

chksum defined in line 84; used 12 times

- in line 48, 426-429(4), 503, 565, 596, 618, 958-959(3)

copyright defined in line 8; never used
dblock defined in line 62; used 82 times

- in line 405, 414-426(8), 435(2), 443, 502-504(3), 547, 553, 559-566(6), 582, 594-597(4), 618-619(2), 668, 675-676(2), 684-700(8), 706-728(12), 734-748(6), 761, 770-776(4), 792-796(5), 944-950(7), 958-962(5), 1055

dirstack defined in line 1354; used 2 times

- in line 1361, 1384

fflag defined in line 73; used 1 times

- in line 141

first defined in line 86; used 6 times

- in line 1159, 1172-1175(2), 1185, 1202-1204(2)

freemem defined in line 88; used 2 times

- in line 1418-1421(2)

hflag defined in line 78; used 2 times

- in line 225, 472

high defined in line 98; used 2 times

- in line 347, 1088

iflag defined in line 74; used 2 times

- in line 229, 430

ihead defined in line 64; used 8 times

- in line 396-399(5), 587, 607-608(2)

low defined in line 97; used 1 times

- in line 1088

m defined in line 845; used 12 times

- in line 852(2), 1099, 1106-1109(4), 1115-1119(3), 1128, 1135

m1 defined in line 835; used 5 times

- in line 845, 1099, 1119-1122(2), 1132

m2 defined in line 836; used 1 times

- in line 845

m3 defined in line 837; used 1 times

- in line 845

m4 defined in line 838; used 1 times

- in line 845

m5 defined in line 839; used 1 times

- in line 845

m6 defined in line 840; used 1 times

- in line 845

m7 defined in line 841; used 1 times

- in line 845

m8 defined in line 842; used 1 times

- in line 845

m9 defined in line 843; used 1 times

- in line 845

magtape defined in line 105; used 3 times

- in line 128, 201-202(2)

mflag defined in line 72; used 5 times

- in line 189, 685, 710, 769-774(2)

mt defined in line 82; used 21 times

- in line 260-264(2), 297-299(2), 308-313(4), 319, 1173, 1207, 1220, 1231, 1249-1251(2), 1257, 1265, 1320, 1398-1405(3)

mtime defined in line 1356; used 11 times

- in line 47, 425, 435, 950, 1020, 1029-1030(2), 1382-1384(2), 1394-1395(2)

nblock defined in line 89; used 31 times

- in line 211-212(2), 620, 1172-1173(2), 1181-1183(2), 1189-1190(2), 1206-1208(3), 1219-1224(5), 1230-1232(3), 1239, 1257, 1265-1266(2), 1319-1332(7)

njab defined in line 1076; used 2 times

- in line 1101, 1111

oflag defined in line 75; used 2 times

- in line 150, 494

pflag defined in line 76; used 4 times

- in line 154, 712, 771, 905

prtlinkerr defined in line 87; used 2 times

- in line 221, 394

recno defined in line 85; used 14 times

- in line 1172, 1187-1192(5), 1206-1210(2), 1219, 1228-1239(4), 1258

rflag defined in line 67; used 4 times

- in line 146, 169, 245-247(2)

sccsid defined in line 14; never used
stbuf defined in line 65; used 42 times

- in line 346-347(2), 417, 445, 473-475(2), 485-488(2), 500-501(2), 541, 548, 575, 583-589(3), 609-620(5), 679, 709-713(4), 737, 744-745(3), 770-772(2), 791, 904-906(3), 974, 1030, 1320-1324(3), 1395

tbuf defined in line 63; used 8 times

- in line 1173, 1191, 1207, 1228-1231(2), 1265, 1329-1330(2)

term defined in line 83; used 7 times

- in line 332, 352, 520, 916, 922, 928, 935

tflag defined in line 70; used 2 times

- in line 185, 245

tname defined in line 103; used 11 times

- in line 158-162(3), 342-345(7), 1036

usefile defined in line 104; used 5 times

- in line 128, 140, 202, 260-264(2)

vflag defined in line 69; used 9 times

- in line 173, 561, 598, 616, 704, 732, 746, 790, 973

wflag defined in line 77; used 2 times

- in line 177, 970

xflag defined in line 68; used 3 times

- in line 181, 245, 265

#### Defined struct's

header defined in line 41; never used
linkbuf defined in line 54; used 8 times

- in line 59-64(4), 584(2), 605(2)

#### Defined union's

hblock defined in line 39; used 8 times

- in line 62-63(4), 1329(2), 1359(2)

#### Defined macros

N defined in line 1075; used 5 times

- in line 1098, 1106-1112(3), 1121

NAMSIZ defined in line 33; used 11 times

- in line 42, 50, 58, 467, 495, 542, 548-553(2), 576, 1354-1355(2)

NBLOCK defined in line 32; used 3 times

- in line 754, 1322-1326(2)

NTIM defined in line 1355; used 1 times

- in line 1356

RGRP defined in line 828; used 1 times

- in line 838

ROTH defined in line 831; used 1 times

- in line 841

ROWN defined in line 825; used 1 times

- in line 835

SGID defined in line 824; used 1 times

- in line 840

STXT defined in line 834; used 1 times

- in line 843

SUID defined in line 823; used 1 times

- in line 837

TBLOCK defined in line 31; used 43 times

- in line 40, 446-450(3), 460, 615-630(6), 745(2), 754-756(3), 766, 804, 944, 962, 1161-1163(3), 1173-1180(3), 1189-1192(3), 1207-1208(2), 1220-1232(7), 1257, 1265-1266(2), 1324-1329(2)

WGRP defined in line 829; used 1 times

- in line 839

WOTH defined in line 832; used 1 times

- in line 842

WOWN defined in line 826; used 1 times

- in line 836

XGRP defined in line 830; used 1 times

- in line 840

XOTH defined in line 833; used 1 times

- in line 843

XOWN defined in line 827; used 1 times

- in line 837

max defined in line 37; used 1 times

- in line 620

min defined in line 36; used 2 times

- in line 626, 758

writetape defined in line 35; used 5 times

- in line 504, 566, 597, 619, 807

Last modified: 1989-10-03 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 5088 |