home *** CD-ROM | disk | FTP | other *** search
/ RISC DISC 2 / RISC_DISC_2.iso / pd_share / utilities / cli / nspark / unarc_c < prev    next >
Encoding:
Text File  |  1994-12-12  |  10.9 KB  |  500 lines

  1. /*
  2.  * unarchive files
  3.  *
  4.  * $Header: unarc.c 1.19 94/12/12 $
  5.  * $Log:    unarc.c,v $
  6.  * Revision 1.19  94/12/12  17:29:30  arb
  7.  * Added support for ArcFS writesize
  8.  *
  9.  * Revision 1.18  93/08/20  12:30:02  arb
  10.  * Added support for ArcFS archive detection
  11.  *
  12.  * Revision 1.17  93/08/20  11:54:55  arb
  13.  * Prevent printing of spaces and LF if in quiet mode
  14.  *
  15.  * Revision 1.16  93/03/05  14:45:43  arb
  16.  * Added <string.h> for RISCOS, needed for strcpy
  17.  *
  18.  * Revision 1.15  92/12/23  13:26:05  duplain
  19.  * Added total-printing if in verbose mode.
  20.  * 
  21.  * Revision 1.14  92/12/08  10:20:33  duplain
  22.  * Added call to append_type() if apptype non zero.
  23.  * 
  24.  * Revision 1.13  92/12/07  17:19:21  duplain
  25.  * reformatted source.
  26.  * 
  27.  * Revision 1.12  92/11/04  16:56:35  duplain
  28.  * Added printing of CRC value if debugging.
  29.  * 
  30.  * Revision 1.11  92/10/29  13:40:05  duplain
  31.  * Fixed prompt_user function definition.
  32.  * 
  33.  * Revision 1.10  92/10/23  14:31:28  duplain
  34.  * Changed prompt_user() output text.
  35.  * 
  36.  * Revision 1.9  92/10/06  12:17:49  duplain
  37.  * Changed header used with verbose option.
  38.  * 
  39.  * Revision 1.8  92/10/05  11:00:37  duplain
  40.  * Recoded user-prompt when files already exists during unarchiving.
  41.  * 
  42.  * Revision 1.7  92/10/02  17:41:14  duplain
  43.  * Fix "end-of-subarchive" problem.
  44.  * 
  45.  * Revision 1.6  92/10/02  10:03:20  duplain
  46.  * Changed "OS_FILE" to "OS_File" for log file entry.
  47.  * 
  48.  * Revision 1.5  92/10/01  13:39:30  duplain
  49.  * Removed "goto do_retry" when header->complen > arcsize.
  50.  * 
  51.  * Revision 1.4  92/10/01  12:17:16  duplain
  52.  * Fixed calculation of archive file size when unpacking/testing.
  53.  * 
  54.  * Revision 1.3  92/10/01  11:22:59  duplain
  55.  * Added retry processing.
  56.  * 
  57.  * Revision 1.2  92/09/30  10:27:51  duplain
  58.  * Added logfile processing.
  59.  * 
  60.  * Revision 1.1  92/09/29  18:02:27  duplain
  61.  * Initial revision
  62.  * 
  63.  */
  64.  
  65. #include <stdio.h>
  66. #include <ctype.h>
  67. #include "spark.h"
  68. #include "store.h"
  69. #include "pack.h"
  70. #include "compress.h"
  71. #include "main.h"
  72. #include "io.h"
  73. #include "misc.h"
  74. #include "os.h"
  75. #include "error.h"
  76. #include "crc.h"
  77. #include "arcfs.h"
  78. #ifdef RISCOS
  79. #include <string.h>    /* for strcpy */
  80. #endif
  81.  
  82. #ifdef UNIX
  83. static char rcsid[] = "$Header: unarc.c 1.19 94/12/12 $";
  84. #endif /* UNIX */
  85.  
  86. char prompt_user P__((char *filename));
  87. char *get_newname P__((void));
  88.  
  89. int
  90. do_unarc()
  91. {
  92.     FILE *ifp, *ofp = NULL, *lfp = NULL;
  93.     Header *header = NULL;
  94.     char *pathname = NULL;
  95.     char fullname[PATHNAMELEN];
  96.     int level = 0, ret = 0, retrying = 0;
  97.     Word arcsize;
  98.     Word nbytes = 0;
  99.     int nfiles = 0;
  100.     Status status;
  101.  
  102.     ifp = fopen(archive, R_OPENMODE);
  103.     if (!ifp) {
  104.     ifp = fopen(name_dot_arc(archive), R_OPENMODE);
  105.     if (!ifp) {
  106.         if (!quiet)
  107.         error("cannot open archive \"%s\"", archive);
  108.         return (1);
  109.     }
  110.     archive = name_dot_arc(archive);
  111.     }
  112.  
  113.     arcsize = filesize(archive);
  114.     if (!arcsize && !quiet) {
  115.     error("cannot get size of archive file");
  116.     fclose(ifp);
  117.     return (1);
  118.     }
  119.  
  120.     if (!testing && !listing && logfile) {
  121.     lfp = fopen(logfile, W_OPENMODE);
  122.     if (!lfp) 
  123.         warning("unable to open logfile \"%s\"", logfile);
  124.     }
  125.  
  126.     if (!quiet && verbose) {
  127.     puts("filename                          size load/date exec/time type status");
  128.     puts("--------                          ---- --------- --------- ---- ------");
  129.     }
  130.  
  131.     /*
  132.      * read compressed files from archive until end of file...
  133.      */
  134.     while (1) {
  135.     static Header dirheader;
  136.     Byte comptype, first;
  137.  
  138.     header = NULL;
  139.     if ((arcfs==0) && ((first = read_byte(ifp)) != STARTBYTE))
  140.     {
  141.         if ((first == 'A') &&
  142.         (read_byte(ifp) == 'r') &&
  143.         (read_byte(ifp) == 'c') &&
  144.         (read_byte(ifp) == 'h') &&
  145.         (read_byte(ifp) == 'i') &&
  146.         (read_byte(ifp) == 'v') &&
  147.         (read_byte(ifp) == 'e') &&
  148.         (read_byte(ifp) == '\0'))
  149.         {
  150. #ifdef DEBUGGING
  151.         if (debugging) printf("ArcFS format archive\n");
  152. #endif /* DEBUGGING */
  153.         arcfs = 1;
  154.         }
  155.         else
  156.         break;
  157.     }
  158. retry_loop:
  159.     header = read_header(ifp);
  160.     comptype = header->comptype & 0x7f;
  161. #ifdef DEBUGGING
  162.     if (debugging) {
  163.         printf("archive file length = %ld  level = %d\n", arcsize, level);
  164.         print_header(header);
  165.     }
  166. #endif /* DEBUGGING */
  167.  
  168.     /*
  169.      * If this is a compress _file_ then check archive size against
  170.      * compress-file length...
  171.      */
  172.     if (comptype && !(comptype == CT_NOTCOMP2 &&
  173.               (header->load & 0xffffff00) == 0xfffddc00)) {
  174.         if (header->complen > arcsize) {
  175. #ifdef DEBUGGING
  176.         if (debugging)
  177.             puts("compressed len > archive file len");
  178. #endif /* DEBUGGING */
  179.         header = NULL;
  180.         break;
  181.         } else
  182.         arcsize -= header->complen;
  183.     }
  184.  
  185.     if (!comptype) {        /* end of archive ? */
  186.         if (!level)
  187.         break;
  188.         level--;
  189.         /*
  190.          * stamp directory now that all files have
  191.          * been written into it
  192.          */
  193.         if (!testing && !listing && stamp && inlist(pathname))
  194.         if (filestamp(&dirheader, pathname) < 0 && !quiet)
  195.             printf("error stamping %s\n", pathname);
  196.         pathname = uplevel();
  197.         continue;
  198.     }
  199.  
  200.     /*
  201.      * test for directory or file (file type = &DDC = archive)
  202.      */
  203.     if (comptype == CT_NOTCOMP2 &&
  204.         (header->load & 0xffffff00) == 0xfffddc00) {
  205.         level++;
  206.         pathname = downlevel(header->name);
  207.         dirheader = *header;        /* make copy of header */
  208.  
  209.         /*
  210.          * create directory
  211.          */
  212.         if (!testing && !listing && inlist(pathname))
  213.         switch (exist(pathname)) {
  214.         case NOEXIST:
  215.             if (makedir(pathname) < 0 && !quiet) {
  216.             printf("error making %s... aborting", pathname);
  217.             ret = 4;
  218.             break;
  219.             }
  220.             break;
  221.  
  222.         case ISFILE:
  223.             if (!quiet)
  224.             printf("%s exists as a file... aborting", pathname);
  225.             ret = 4;
  226.             goto unarc_exit;
  227.         case ISDIR:
  228.         default:
  229.             break;
  230.         }
  231.     } else {    /* file */
  232.         if (pathname)
  233.         sprintf(fullname, "%s%c%s", pathname, PATHSEP,
  234.             header->name);
  235.         else
  236.         strcpy(fullname, header->name);
  237.                 
  238.         if (!inlist(fullname)) {
  239.         fseek(ifp, (long)header->complen, 1);
  240.         continue;
  241.         }
  242.         
  243.         /*
  244.          * print the archive file details...
  245.          */
  246.         if (!quiet) {
  247.         printf("%-30s", fullname);
  248.         if (verbose)
  249.             print_details(header);
  250.         }
  251.  
  252.         /* add to totals */
  253.             nbytes += header->origlen;
  254.             nfiles++;
  255.  
  256.         if (listing) {
  257.         /* if listing, nothing more to do */
  258.         if (!quiet) putchar('\n');
  259.         fseek(ifp, (long)header->complen, 1);
  260.         continue;
  261.         } else
  262.         if (!quiet) putchar(' ');
  263.  
  264.         /*
  265.          * append the filetype to the name
  266.          */
  267.             if (apptype)
  268.         append_type(header, fullname);
  269.  
  270.         /*
  271.          * if actually unarchiving then check if the file already exists
  272.          */
  273.         if (!testing) {
  274. test_exist:
  275.         switch(exist(fullname)) {
  276.         case ISFILE:
  277.             if (!force) {
  278.             char c = prompt_user(fullname);
  279.             if (c == 'a') 
  280.                 force = 1;
  281.             else if (c == 'n') {
  282.                 fseek(ifp, (long)header->complen, 1);
  283.                 continue;
  284.             } else if (c == 'r') {
  285.                 char *newname = get_newname();
  286.                 if (pathname)
  287.                 sprintf(fullname, "%s%c%s", pathname, PATHSEP, newname);
  288.                 else
  289.                 strcpy(fullname, newname);
  290.                 goto test_exist;
  291.             }
  292.             /* if (c == 'y') FALLTHROUGH */
  293.             }
  294.             break;
  295.         case ISDIR:
  296.             if (!quiet)
  297.             puts("exists as a directory... skipping");
  298.             continue;
  299.         case NOEXIST:
  300.         default:
  301.             break;
  302.         }
  303.         ofp = fopen(fullname, W_OPENMODE);
  304.         if (!ofp) {
  305.             if (!quiet)
  306.             printf("unable to create");
  307.             continue;
  308.         }
  309.         }
  310.  
  311.         /*
  312.          * do the unpacking
  313.          */
  314.         crcsize = writesize = header->origlen;
  315.         switch (comptype) {
  316.         case CT_NOTCOMP:
  317.         case CT_NOTCOMP2:
  318.         status = unstore(header, ifp, ofp);
  319.         break;
  320.         case CT_CRUNCH:
  321.         status = uncompress(header, ifp, ofp, CRUNCH);
  322.         break;
  323.         case CT_PACK:
  324.         status = unpack(header, ifp, ofp);
  325.         break;
  326.         case CT_SQUASH:
  327.         status = uncompress(header, ifp, ofp, SQUASH);
  328.         break;
  329.         case CT_COMP:
  330.         status = uncompress(header, ifp, ofp, COMPRESS);
  331.         break;
  332.         default:
  333.         printf("unsupported archive type %d\n", comptype);
  334.         if (retrying)
  335.             goto do_retry;
  336.         fseek(ifp, (long)header->complen, 1);
  337.         continue;
  338.         }
  339.  
  340.         if (!testing && ofp) {
  341.         fclose(ofp);
  342.         ofp = NULL;
  343.         }
  344.     
  345.         /*
  346.          * check if unarchiving failed.
  347.          * (RERR check is not in switch() because `break'
  348.          * needs to escape from while())
  349.          */
  350.         if (status == RERR) {
  351.         if (!quiet)
  352.             error("error reading archive");
  353.         ret = 3;
  354.         break;
  355.         }
  356.         switch (status) {
  357.         case WERR:
  358.         if (!quiet)
  359.             printf("error writing file");
  360.         break;
  361.         case CRCERR:
  362.         if (!quiet)
  363.             printf("failed CRC check");
  364. #ifdef DEBUGGING
  365.         if (debugging) {
  366.             printf("  calculated CRC=0x%x", crc);
  367.         }
  368. #endif /* DEBUGGING */
  369.         break;
  370.         case NOERR:
  371.         if (!testing && stamp)
  372.             if (filestamp(header, fullname) < 0 && !quiet)
  373.             printf("\nerror stamping %s", fullname);
  374.         /* 
  375.          * XXX: if the filename has had it's filetype appended to
  376.          * it, it may be longer than 10 characters long making this
  377.          * file useless.  We could truncate the filename but there is
  378.          * no need to under UNIX... bit of a mismatch!
  379.          */
  380.         if (!testing && lfp)
  381.             fprintf(lfp, "SYS \"OS_File\", 1, \"%s\", &%lx, &%lx,, &%x\n", riscos_path(fullname), header->load, header->exec, header->attr);
  382.         break;
  383.         default:
  384.         break;
  385.         }
  386.  
  387.         if (!quiet) putchar('\n');
  388.         if (ret)
  389.         break;
  390.     }
  391.     }
  392.  
  393.     /*
  394.      * find out why header wasn't found
  395.      */
  396.     if (!header)
  397.     switch(check_stream(ifp)) {
  398.     case FNOERR:
  399.         if (!quiet)
  400.         printf("bad archive header");
  401.         if (retry && !listing) {
  402.         puts("... retrying");
  403. do_retry:
  404.         retrying++;
  405.         while (check_stream(ifp) == FNOERR)
  406.             if (read_byte(ifp) == STARTBYTE) {
  407.             Byte byte = read_byte(ifp);
  408.             switch(byte & 0x7f) {
  409.             case (CT_NOTCOMP):
  410.             case (CT_NOTCOMP2):
  411.             case (CT_CRUNCH):
  412.             case (CT_PACK):
  413.             case (CT_SQUASH):
  414.             case (CT_COMP):
  415.                 ungetc((int)byte, ifp);
  416.                 goto retry_loop;
  417.                 /* NOTREACHED */
  418.             default:
  419.                 break;
  420.             }
  421.             }
  422.         } else {
  423.         retrying = 0;
  424.         if (!quiet) putchar('\n');
  425.         }
  426.         ret = 2;
  427.         break;
  428.     case FRWERR:
  429.         if (!quiet)
  430.         puts("error reading archive");
  431.         ret = 3;
  432.         break;
  433.     case FEND:
  434.     default:
  435.         break;
  436.     }
  437.  
  438. unarc_exit:
  439.  
  440.     if (verbose)
  441.         printf("total of %ld bytes in %d files\n", nbytes, nfiles);
  442.  
  443.     if (ofp)
  444.     fclose(ofp);
  445.     if (lfp)
  446.     fclose(lfp);
  447.     if (ifp)
  448.     fclose(ifp);
  449.     return (ret);
  450. }
  451.  
  452. /*
  453.  * the file being extracted already exists, so ask user what to do...
  454.  */
  455. char
  456. prompt_user(filename)
  457.     char *filename;
  458. {
  459.     int c;
  460.     char buffer[80];
  461.  
  462.     while (1) {
  463.     printf("\n\"%s\" exists, overwrite ? (Yes/No/All/Rename): ", filename);
  464.     fflush(stdout);
  465.     read(0, buffer, sizeof(buffer)-1);
  466.     if (isupper(*buffer))
  467.         c = tolower(*buffer);
  468.     else
  469.         c = *buffer;
  470.     if (c == 'y' || c == 'n' || c == 'a' || c == 'r')
  471.         break;        
  472.     }
  473.     return (c);
  474. }
  475.  
  476. /*
  477.  * user wants to rename file, so get the leaf name of the new file...
  478.  */
  479. char *
  480. get_newname()
  481. {
  482.     int c;
  483.     static char buffer[80];
  484.  
  485.     while (1) {
  486.     printf( "enter new filename: ");
  487.     fflush(stdout);
  488.     c = read(0, buffer, sizeof(buffer)-1);
  489.     buffer[c ? c-1 : 0] = '\0';
  490.     if (!*buffer)
  491.         continue;
  492.     for (c = 0; buffer[c]; c++)
  493.         if (buffer[c] == PATHSEP) {
  494.         puts("*** new file must extract into this directory ***");
  495.         continue;
  496.         }
  497.     return (buffer);
  498.     }
  499. }                        
  500.