home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / language / sozobon2 / ar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-23  |  16.2 KB  |  867 lines

  1. /* Copyright (c) 1988 by Sozobon, Limited.  Author: Tony Andrews
  2.  *
  3.  * Permission is granted to anyone to use this software for any purpose
  4.  * on any computer system, and to redistribute it freely, with the
  5.  * following restrictions:
  6.  * 1) No charge may be made other than reasonable charges for reproduction.
  7.  * 2) Modified versions must be clearly marked as such.
  8.  * 3) The authors are not responsible for any harmful consequences
  9.  *    of using this software, even if they result from defects in it.
  10.  */
  11.  
  12. static    char    Version[] =
  13. "ar: version 1.01  Copyright (c) 1988 by Sozobon, Limited.";
  14.  
  15. /*
  16.  * ar - archive manipulation program
  17.  */
  18.  
  19. #include <stdio.h>
  20. #include <fcntl.h>
  21. #include <ar.h>
  22.  
  23. #ifndef    FALSE
  24. #define    FALSE    (0)
  25. #define    TRUE    !FALSE
  26. #endif
  27.  
  28. /*
  29.  * Program options
  30.  */
  31. int    vflag = FALSE;    /* verbose option */
  32. int    cflag = FALSE;    /* suppress archive creation message */
  33. int    Vflag = FALSE;    /* print the version message */
  34.  
  35. /*
  36.  * Basic Command
  37.  */
  38. #define    NONE    0    /* missing command spec */
  39. #define    DELETE    1    /* delete members */
  40. #define    REPLACE    2    /* replace (or add) members */
  41. #define    QAPPEND    3    /* quickly append to the archive */
  42. #define    TABLE    4    /* table of contents */
  43. #define    PRINT    5    /* print a member */
  44. #define    MOVE    6    /* move to the end of the archive */
  45. #define    EXTRACT    7    /* extract members */
  46.  
  47. int    cmd = 0;    /* the command we're executing */
  48.  
  49. char    *afile;        /* name of the archive we're messing with */
  50. char    **files;    /* piece of argv starting at the file list */
  51.  
  52. #define    NAMLEN    14        /* length of a file name in the archive */
  53.  
  54. #define    TFILE    "ar_tmp.xxx"    /* temp file base name */
  55. char    tfile[128];        /* actual temp file name */
  56.  
  57. extern    long    lseek();
  58.  
  59. usage()
  60. {
  61.     fprintf(stderr, "usage: ar {drqtpmx}[vcV] afile [name] ...\n");
  62.     exit(1);
  63. }
  64.  
  65. main(argc, argv)
  66. int    argc;
  67. char    *argv[];
  68. {
  69.     char    *strrchr();
  70.     register int    status;
  71.     register char    *s;
  72.  
  73.     if (argc < 2)
  74.         usage();
  75.  
  76.     s = (argv[1][0] == '-') ? &argv[1][1] : &argv[1][0];
  77.  
  78.     /*
  79.      * Get the command character
  80.      */
  81.     switch (*s) {
  82.  
  83.     case 'd':
  84.         cmd = DELETE;    break;
  85.     case 'r':
  86.         cmd = REPLACE;    break;
  87.     case 'q':
  88.         cmd = QAPPEND;    break;
  89.     case 't':
  90.         cmd = TABLE;    break;
  91.     case 'p':
  92.         cmd = PRINT;    break;
  93.     case 'm':
  94.         cmd = MOVE;    break;
  95.     case 'x':
  96.         cmd = EXTRACT;    break;
  97.     case 'V':
  98.         Vflag = TRUE;    break;
  99.  
  100.     default:
  101.         fprintf(stderr, "ar: invalid command character '%c'\n", *s);
  102.         usage();
  103.     }
  104.  
  105.     /*
  106.      * Check for optional flags
  107.      */
  108.     for (++s; *s ;++s) {
  109.         switch (*s) {
  110.         case 'v':
  111.             vflag = TRUE;    break;
  112.         case 'c':
  113.             cflag = TRUE;    break;
  114.         case 'V':
  115.             Vflag = TRUE;    break;
  116.         default:
  117.             fprintf(stderr, "ar: invalid option flag '%c'\n", *s);
  118.             usage();
  119.         }
  120.     }
  121.  
  122.     if (Vflag)
  123.         printf("%s\n", Version);
  124.  
  125.     if (argc < 3)
  126.         usage();
  127.  
  128.     afile = argv[2];
  129.     files = &argv[3];
  130.  
  131.     /*
  132.      * Construct the temp file name based on the directory of the
  133.      * archive file.
  134.      */
  135.     if (strrchr(afile, '\\') != NULL) {
  136.         strcpy(tfile, afile);
  137.         s = strrchr(tfile, '\\');
  138.         strcpy(s+1, TFILE);
  139.     } else
  140.         strcpy(tfile, TFILE);    /* in the current directory */
  141.  
  142.     switch (cmd) {
  143.  
  144.     case DELETE:
  145.         status = dodelete();
  146.         break;
  147.  
  148.     case REPLACE:
  149.         status = doreplace();
  150.         break;
  151.  
  152.     case QAPPEND:
  153.         status = doqappend();
  154.         break;
  155.  
  156.     case TABLE:
  157.         status = dotable();
  158.         break;
  159.  
  160.     case PRINT:
  161.         status = doprint();
  162.         break;
  163.  
  164.     case MOVE:
  165.         status = domove();
  166.         break;
  167.  
  168.     case EXTRACT:
  169.         status = doextract();
  170.         break;
  171.  
  172.     default:
  173.         fprintf(stderr, "ar: invalid operation\n");
  174.         usage();
  175.     }
  176.  
  177.     exit(status);
  178. }
  179.  
  180. error(s)
  181. char    *s;
  182. {
  183.     fprintf(stderr, "ar: fatal error - %s\n", s);
  184.     exit(1);
  185. }
  186.  
  187. /*
  188.  * inlist(f) - is file 'f' in the file list on the command line?
  189.  */
  190. int
  191. inlist(f)
  192. register char    *f;
  193. {
  194.     register int    i;
  195.  
  196.     for (i=0; files[i] != NULL ;i++) {
  197.         if (strncmp(f, files[i], NAMLEN) == 0)
  198.             return TRUE;
  199.     }
  200.     return FALSE;
  201. }
  202.  
  203. /*
  204.  * dellist(f) - remove file 'f' from the command line list
  205.  *
  206.  * We 'delete' an entry by truncating it to zero.
  207.  */
  208. dellist(f)
  209. register char    *f;
  210. {
  211.     register int    i;
  212.  
  213.     for (i=0; files[i] != NULL ;i++) {
  214.         if (strncmp(f, files[i], NAMLEN) == 0)
  215.             files[i][0] = '\0';
  216.     }
  217. }
  218.  
  219. /*
  220.  * copy(ofd, nfd, size) - copy a file
  221.  *
  222.  * Copies 'size' bytes from 'ofd' to 'nfd', which must both reference
  223.  * open file descriptors.
  224.  */
  225. #define    BSIZE    8192    /* buffer size */
  226.  
  227. int
  228. copy(ofd, nfd, size)
  229. register int    ofd, nfd;
  230. long    size;
  231. {
  232.     static    char    buf[BSIZE];
  233.     register int    n;
  234.  
  235.     for (n = size; n >= BSIZE; n -= BSIZE) {
  236.         if (read(ofd, buf, BSIZE) != BSIZE)
  237.             return FALSE;
  238.         if (write(nfd, buf, BSIZE) != BSIZE) {
  239.             fprintf(stderr, "ar: disk out of space\n");
  240.             return FALSE;
  241.         }
  242.     }
  243.  
  244.     if (n > 0) {
  245.         if (read(ofd, buf, n) != n)
  246.             return FALSE;
  247.         if (write(nfd, buf, n) != n) {
  248.             fprintf(stderr, "ar: disk out of space\n");
  249.             return FALSE;
  250.         }
  251.     }
  252.     return TRUE;
  253. }
  254.  
  255. /*
  256.  * chkhdr(fd) - make sure the magic number is right
  257.  */
  258. chkhdr(fd)
  259. int    fd;
  260. {
  261.     int    magic;
  262.  
  263.     if (read(fd, &magic, 2) != 2)
  264.         error("chkhdr: malformed archive");
  265.  
  266.     if (magic != ARMAG1 && magic != ARMAG2)
  267.         error("chkhdr: bad magic");
  268. }
  269.  
  270. /*
  271.  * tostart(fd) - move to the start of the archive
  272.  */
  273. tostart(fd)
  274. int    fd;
  275. {
  276.     lseek(fd, 2L, 0);
  277. }
  278.  
  279. /*
  280.  * gethdr(fd, a) - read a header at the current file position
  281.  *
  282.  * Returns TRUE on success, FALSE at eof.
  283.  */
  284. int
  285. gethdr(fd, a)
  286. int    fd;
  287. struct    ar_hdr    *a;
  288. {
  289.     if (read(fd, a, ARHSZ) == ARHSZ)
  290.         return (a->ar_name[0] != '\0');
  291.     else
  292.         return FALSE;
  293. }
  294.  
  295. /*
  296.  * skipit(fd, a) - skip the current archive element
  297.  *
  298.  * Assumes that we're still positioned right after the header.
  299.  * Returns TRUE on success, FALSE on failure.
  300.  */
  301. int
  302. skipit(fd, a)
  303. int    fd;
  304. struct    ar_hdr    *a;
  305. {
  306.     return (lseek(fd, a->ar_size, 1) >= 0);
  307. }
  308.  
  309. /*
  310.  * moveto(fd, name, ar) - find the object 'name' in the given archive
  311.  *
  312.  * Finds the given element in the archive referenced by the given
  313.  * file desciptor. Leaves the file pointer positioned after the
  314.  * header for the element, at the start of the contents. Return the
  315.  * header via pointer 'ar'.
  316.  *
  317.  * Returns TRUE on success, FALSE if no such name found.
  318.  */
  319. int
  320. moveto(fd, name, ar)
  321. register int    fd;
  322. register char    *name;
  323. register struct    ar_hdr    *ar;
  324. {
  325.     tostart(fd);
  326.  
  327.     while (gethdr(fd, ar)) {
  328.         if (strncmp(ar->ar_name, name, NAMLEN) == 0)
  329.             return TRUE;
  330.         if (!skipit(fd, ar))
  331.             break;
  332.     }
  333.  
  334.     return FALSE;
  335. }
  336.  
  337. /*
  338.  * modestr(mode) - return the string representation of a mode word
  339.  */
  340. char *
  341. modestr(mode)
  342. register int    mode;
  343. {
  344.     static    char    mstr[10];
  345.  
  346.     mstr[9] = '\0';
  347.  
  348.     mstr[8] = (mode & 0001) ? 'x' : '-';
  349.     mstr[7] = (mode & 0002) ? 'w' : '-';
  350.     mstr[6] = (mode & 0004) ? 'r' : '-';
  351.  
  352.     mstr[5] = (mode & 0010) ? 'x' : '-';
  353.     mstr[4] = (mode & 0020) ? 'w' : '-';
  354.     mstr[3] = (mode & 0040) ? 'r' : '-';
  355.  
  356.     mstr[2] = (mode & 0100) ? 'x' : '-';
  357.     mstr[1] = (mode & 0200) ? 'w' : '-';
  358.     mstr[0] = (mode & 0400) ? 'r' : '-';
  359.  
  360.     return mstr;
  361. }
  362.  
  363. /*
  364.  * ropen(f) - open archive 'f' for reading
  365.  *
  366.  * Open the named archive 'read only' and check the magic word.
  367.  */
  368. int
  369. ropen(f)
  370. char    *f;
  371. {
  372.     register int    fd;
  373.  
  374.     if ((fd = open(f, O_RDONLY)) < 0)
  375.         return -1;
  376.  
  377.     chkhdr(fd);
  378.  
  379.     return fd;
  380. }
  381.  
  382. /*
  383.  * wopen(f) - open archive 'f' for writing
  384.  *
  385.  * If the archive already exists, open it and check it's magic.
  386.  * If it doesn't exists, create it, and write a valid magic word.
  387.  */
  388. int
  389. wopen(f, domsg)
  390. char    *f;
  391. int    domsg;
  392. {
  393.     register int    fd;
  394.     int    magic;
  395.  
  396.     if ((fd = open(f, O_RDWR)) < 0) {    /* doesn't exist */
  397.         if ((fd = creat(f, 0)) < 0) {
  398.             fprintf(stderr, "ar: can't create archive '%s'\n", f);
  399.             exit(1);
  400.         }
  401.         if (!cflag && domsg)
  402.             printf("ar: creating archive '%s'\n", f);
  403.  
  404.         magic = ARMAG1;
  405.         write(fd, &magic, 2);
  406.     } else
  407.         chkhdr(fd);
  408.  
  409.     return fd;
  410. }
  411.  
  412. /*
  413.  * wclose(f) - close archive opened with wopen.
  414.  *
  415.  * Write four null bytes to the end of the archive and then close
  416.  * it. This doesn't bother anyone, and seems to make one of the
  417.  * utilities with the 'aln' linker happy.
  418.  */
  419. int
  420. wclose(fd)
  421. int    fd;
  422. {
  423.     long    foo = 0;
  424.  
  425.     write(fd, &foo, 4);
  426.     close(fd);
  427. }
  428.  
  429. /*
  430.  * putfile(fd, f, achar) - write file 'f' to an open archive file
  431.  *
  432.  * The file named by 'f' is written as an archive member to the open
  433.  * file descriptor 'fd'. The "action" character 'achar' is used to
  434.  * print a message if the verbose option is set.
  435.  */
  436. putfile(fd, f, achar)
  437. register int    fd;
  438. register char    *f;
  439. char    achar;
  440. {
  441.     register int    xfd;
  442.     struct    ar_hdr    a;
  443.     register long    size;
  444.     char    null = 0;
  445.  
  446.     if ((xfd = open(f, O_RDONLY)) < 0) {
  447.         printf("%s: can't open\n", f);
  448.         return;
  449.     }
  450.     strncpy(a.ar_name, f, NAMLEN);
  451.     a.ar_date = 0;
  452.     a.ar_uid = 0;
  453.     a.ar_gid = 0;
  454.     a.ar_mode = 0666;
  455.     a.ar_fill = 0;
  456.     /*
  457.      * Get the size of the file by doing an lseek. This is
  458.      * easier and more portable than doing the equivalent
  459.      * of an fstat().
  460.      */
  461.     a.ar_size = size = lseek(xfd, 0L, 2);
  462.  
  463.     /*
  464.      * If the file size is odd, pad it out with an extra
  465.      * byte to be compatible with the Alcyon ar68.prg
  466.      */
  467.     if (size & 1)
  468.         a.ar_size++;
  469.  
  470.     if (write(fd, &a, ARHSZ) != ARHSZ)
  471.         error("ar: can't write to archive");
  472.  
  473.     if (vflag)
  474.         printf("%c %s\n", achar, f);
  475.  
  476.     lseek(xfd, 0L, 0);        /* rewind */
  477.     if (!copy(xfd, fd, size))
  478.         error("ar: can't write to archive");
  479.  
  480.     close(xfd);
  481.  
  482.     if (size != a.ar_size)        /* need a pad byte? */
  483.         write(fd, &null, 1);
  484. }
  485.  
  486. /*
  487.  * Functions to perform the basic commands
  488.  */
  489.  
  490. int
  491. dodelete()
  492. {
  493.     register int    fd, tfd;
  494.     register int    i;
  495.     struct    ar_hdr    a;
  496.  
  497.     if (files[0] == NULL)    /* no work to do */
  498.         return 0;
  499.  
  500.     tfd = wopen(tfile, FALSE);
  501.  
  502.     if ((fd = ropen(afile)) < 0)
  503.         error("can't read archive");
  504.  
  505.     while (gethdr(fd, &a)) {
  506.  
  507.         if (inlist(a.ar_name)) {
  508.  
  509.             /*
  510.              * Skip over the copy in the original archive.
  511.              */
  512.             if (!skipit(fd, &a)) {
  513.                 close(tfd);
  514.                 close(fd);
  515.                 unlink(tfile);
  516.                 error("delete: malformed archive");
  517.             }
  518.             if (vflag)
  519.                 printf("d %s\n", a.ar_name);
  520.  
  521.             dellist(a.ar_name);
  522.     
  523.         } else {    /* copy from the old archive */
  524.  
  525.             if (write(tfd, &a, ARHSZ) != ARHSZ) {
  526.                 close(tfd);
  527.                 close(fd);
  528.                 unlink(tfile);
  529.                 error("delete: can't write to archive");
  530.             }
  531.             copy(fd, tfd, a.ar_size);
  532.         }
  533.     }
  534.     close(fd);
  535.     wclose(tfd);
  536.  
  537.     /*
  538.      * Note any files not found
  539.      */
  540.     for (i=0; files[i] != NULL ;i++) {
  541.         if (files[i][0] != '\0')
  542.             printf("%s: not found\n", files[i]);
  543.     }
  544.  
  545.     /*
  546.      * Unlink the original archive and rename the
  547.      * temp file on top of it.
  548.      */
  549.     unlink(afile);
  550.     rename(tfile, afile);
  551.  
  552.     return 0;
  553. }
  554.  
  555. int
  556. doreplace()
  557. {
  558.     register int    fd, tfd;
  559.     register int    i;
  560.     struct    ar_hdr    a;
  561.  
  562.     if (files[0] == NULL)    /* no work to do */
  563.         return 0;
  564.  
  565.     tfd = wopen(tfile, FALSE);
  566.  
  567.     /*
  568.      * If there's no current archive, skip the section dealing
  569.      * with updates, and just append the named files to the
  570.      * newly created archive.
  571.      */
  572.     if ((fd = ropen(afile)) < 0) {
  573.         if (!cflag)
  574.             printf("ar: creating archive '%s'\n", afile);
  575.         goto append;
  576.     }
  577.  
  578.     while (gethdr(fd, &a)) {
  579.  
  580.         if (inlist(a.ar_name)) {
  581.  
  582.             /*
  583.              * Skip over the old copy in the original archive.
  584.              */
  585.             if (!skipit(fd, &a)) {
  586.                 close(tfd);
  587.                 close(fd);
  588.                 unlink(tfile);
  589.                 error("doreplace: malformed archive");
  590.             }
  591.  
  592.             putfile(tfd, a.ar_name, 'r');
  593.  
  594.             dellist(a.ar_name);
  595.  
  596.         } else {    /* copy from the old archive */
  597.  
  598.             if (write(tfd, &a, ARHSZ) != ARHSZ) {
  599.                 close(tfd);
  600.                 close(fd);
  601.                 unlink(tfile);
  602.                 error("replace: can't write to archive");
  603.             }
  604.             copy(fd, tfd, a.ar_size);
  605.         }
  606.     }
  607.     close(fd);
  608.  
  609.     /*
  610.      * Now go back through the file list and append any files
  611.      * that didn't turn up in the old archive.
  612.      */
  613. append:
  614.     for (i=0; files[i] != NULL ;i++) {
  615.         if (files[i][0] != '\0')    /* wasn't deleted before */
  616.             putfile(tfd, files[i], 'a');
  617.     }
  618.     wclose(tfd);
  619.  
  620.     /*
  621.      * Unlink the original archive and rename the
  622.      * temp file on top of it.
  623.      */
  624.     unlink(afile);
  625.     rename(tfile, afile);
  626.  
  627.     return 0;
  628. }
  629.  
  630. int
  631. doqappend()
  632. {
  633.     register int    fd;
  634.     register int    i;
  635.     struct    ar_hdr    a;
  636.     long    fpos;
  637.  
  638.     if (files[0] == NULL)    /* no work to do */
  639.         return 0;
  640.  
  641.     fd = wopen(afile, TRUE);
  642.  
  643.     /*
  644.      * Get positioned just after the last member
  645.      */
  646.     fpos = 2;
  647.     while (gethdr(fd, &a)) {
  648.         if (!skipit(fd, &a))
  649.             error("doqappend: malformed archive");
  650.         fpos = lseek(fd, 0L, 1);
  651.     }
  652.     /*
  653.      * Go back to the end of the last valid archive member
  654.      */
  655.     lseek(fd, fpos, 0);
  656.  
  657.     for (i=0; files[i] != NULL ;i++)
  658.         putfile(fd, files[i], 'a');
  659.  
  660.     wclose(fd);
  661.     return 0;
  662. }
  663.  
  664. int
  665. dotable()
  666. {
  667.     register int    fd;
  668.     register int    i;
  669.     struct    ar_hdr    a;
  670.  
  671.     if ((fd = ropen(afile)) < 0)
  672.         error("can't read archive");
  673.  
  674.     if (files[0] == NULL) {
  675.         while (gethdr(fd, &a)) {
  676.             if (vflag)
  677.                 printf("%s%6d/%6d%7ld %.14s\n",
  678.                     modestr(a.ar_mode),
  679.                     a.ar_uid, a.ar_gid,
  680.                     a.ar_size, a.ar_name);
  681.             else
  682.                 printf("%.14s\n", a.ar_name);
  683.             if (!skipit(fd, &a))
  684.                 break;
  685.         }
  686.         close(fd);
  687.         return 0;
  688.     }
  689.  
  690.     for (i=0; files[i] != NULL ;i++) {
  691.         if (moveto(fd, files[i], &a)) {
  692.             if (vflag)
  693.                 printf("%s%6d/%6d%7ld %.14s\n",
  694.                     modestr(a.ar_mode),
  695.                     a.ar_uid, a.ar_gid,
  696.                     a.ar_size, a.ar_name);
  697.             else
  698.                 printf("%.14s\n", a.ar_name);
  699.         } else
  700.             fprintf(stderr, "%s: not found\n", files[i]);
  701.     }
  702.     close(fd);
  703.     return 0;
  704. }
  705.  
  706. int
  707. doprint()
  708. {
  709.     register int    fd;
  710.     register int    i;
  711.     struct    ar_hdr    a;
  712.  
  713.     /*
  714.      * If no file names given, error.
  715.      */
  716.     if (files[0] == NULL) {
  717.         fprintf(stderr, "ar: no filenames given\n");
  718.         return 1;
  719.     }
  720.  
  721.     if ((fd = ropen(afile)) < 0)
  722.         error("can't read archive");
  723.  
  724.     for (i=0; files[i] != NULL ;i++) {
  725.         if (moveto(fd, files[i], &a))
  726.             copy(fd, 1, a.ar_size);
  727.         else
  728.             fprintf(stderr, "%s: not found\n", files[i]);
  729.     }
  730.     close(fd);
  731.  
  732.     return 0;
  733. }
  734.  
  735. int
  736. domove()
  737. {
  738.     register int    fd, tfd;
  739.     register int    i;
  740.     struct    ar_hdr    a;
  741.  
  742.     if (files[0] == NULL)    /* no work to do */
  743.         return 0;
  744.  
  745.     tfd = wopen(tfile, FALSE);
  746.  
  747.     if ((fd = ropen(afile)) < 0) {
  748.         fprintf(stderr, "ar: can't open archive '%s'\n", afile);
  749.         exit(1);
  750.     }
  751.  
  752.     while (gethdr(fd, &a)) {
  753.  
  754.         if (inlist(a.ar_name)) {
  755.  
  756.             /*
  757.              * Don't copy anything that we need
  758.              * to move to the end.
  759.              */
  760.             if (!skipit(fd, &a)) {
  761.                 close(tfd);
  762.                 close(fd);
  763.                 unlink(tfile);
  764.                 error("domove: malformed archive");
  765.             }
  766.  
  767.         } else {    /* copy from the old archive */
  768.  
  769.             if (write(tfd, &a, ARHSZ) != ARHSZ) {
  770.                 close(tfd);
  771.                 close(fd);
  772.                 unlink(tfile);
  773.                 error("move: can't write to archive");
  774.             }
  775.             if (!copy(fd, tfd, a.ar_size)) {
  776.                 close(tfd);
  777.                 close(fd);
  778.                 unlink(tfile);
  779.                 error("move: can't write to archive");
  780.             }
  781.         }
  782.     }
  783.  
  784.     /*
  785.      * Now everything that isn't to be moved has been copied
  786.      * to the temp file. Now go back and get the stuff to be
  787.      * moved and copy it.
  788.      */
  789.     for (i=0; files[i] != NULL ;i++) {
  790.  
  791.         if (moveto(fd, files[i], &a)) {
  792.             if (vflag)
  793.                 printf("m %s\n", files[i]);
  794.  
  795.             if (write(tfd, &a, ARHSZ) != ARHSZ) {
  796.                 close(tfd);
  797.                 close(fd);
  798.                 unlink(tfile);
  799.                 error("move: can't write to archive");
  800.             }
  801.             if (!copy(fd, tfd, a.ar_size)) {
  802.                 close(tfd);
  803.                 close(fd);
  804.                 unlink(tfile);
  805.                 error("move: can't write to archive");
  806.             }
  807.         } else
  808.             printf("%s: not in archive\n", files[i]);
  809.     }
  810.     close(fd);
  811.     wclose(tfd);
  812.  
  813.     /*
  814.      * Unlink the original archive and rename the
  815.      * temp file on top of it.
  816.      */
  817.     unlink(afile);
  818.     rename(tfile, afile);
  819.  
  820.     return 0;
  821. }
  822.  
  823. int
  824. doextract()
  825. {
  826.     register int    fd, xfd;
  827.     register int    i;
  828.     struct    ar_hdr    a;
  829.  
  830.     if ((fd = ropen(afile)) < 0)
  831.         error("can't read archive");
  832.  
  833.     /*
  834.      * If no file names given, extract everything.
  835.      */
  836.     if (files[0] == NULL) {
  837.         while (gethdr(fd, &a)) {
  838.             if ((xfd = creat(a.ar_name, 0)) < 0) {
  839.                 fprintf(stderr,"%s: can't create\n", a.ar_name);
  840.                 continue;
  841.             }
  842.             if (vflag)
  843.                 printf("x %s\n", a.ar_name);
  844.             copy(fd, xfd, a.ar_size);
  845.             close(xfd);
  846.         }
  847.         close(fd);
  848.         return 0;
  849.     }
  850.  
  851.     for (i=0; files[i] != NULL ;i++) {
  852.         if (moveto(fd, files[i], &a)) {
  853.             if ((xfd = creat(files[i], 0)) >= 0) {
  854.                 if (vflag)
  855.                     printf("x %s\n", a.ar_name);
  856.                 copy(fd, xfd, a.ar_size);
  857.                 close(xfd);
  858.             } else
  859.                 fprintf(stderr, "%s: can't create\n", files[i]);
  860.         } else
  861.             fprintf(stderr, "%s: not found\n", files[i]);
  862.     }
  863.     close(fd);
  864.  
  865.     return 0;
  866. }
  867.