home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 January / Chip_2001-01_cd1.bin / tema / mysql / mysql-3.23.28g-win-source.exe / zlib / contrib / untgz / untgz.c
C/C++ Source or Header  |  1999-10-12  |  10KB  |  479 lines

  1. /*
  2.  * untgz.c -- Display contents and/or extract file from
  3.  * a gzip'd TAR file
  4.  * written by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
  5.  * adaptation to Unix by Jean-loup Gailly <jloup@gzip.org>
  6.  */
  7.  
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <time.h>
  12. #include <utime.h>
  13. #include <errno.h>
  14. #include <fcntl.h>
  15. #ifdef unix
  16. # include <unistd.h>
  17. #else
  18. # include <direct.h>
  19. # include <io.h>
  20. #endif
  21.  
  22. #include "zlib.h"
  23.  
  24. /* Values used in typeflag field.  */
  25.  
  26. #define REGTYPE     '0'        /* regular file */
  27. #define AREGTYPE '\0'        /* regular file */
  28. #define LNKTYPE  '1'        /* link */
  29. #define SYMTYPE  '2'        /* reserved */
  30. #define CHRTYPE  '3'        /* character special */
  31. #define BLKTYPE  '4'        /* block special */
  32. #define DIRTYPE  '5'        /* directory */
  33. #define FIFOTYPE '6'        /* FIFO special */
  34. #define CONTTYPE '7'        /* reserved */
  35.  
  36. #define BLOCKSIZE 512
  37.  
  38. struct tar_header
  39. {                /* byte offset */
  40.   char name[100];        /*   0 */
  41.   char mode[8];            /* 100 */
  42.   char uid[8];            /* 108 */
  43.   char gid[8];            /* 116 */
  44.   char size[12];        /* 124 */
  45.   char mtime[12];        /* 136 */
  46.   char chksum[8];        /* 148 */
  47.   char typeflag;        /* 156 */
  48.   char linkname[100];        /* 157 */
  49.   char magic[6];        /* 257 */
  50.   char version[2];        /* 263 */
  51.   char uname[32];        /* 265 */
  52.   char gname[32];        /* 297 */
  53.   char devmajor[8];        /* 329 */
  54.   char devminor[8];        /* 337 */
  55.   char prefix[155];        /* 345 */
  56.                 /* 500 */
  57. };
  58.  
  59. union tar_buffer {
  60.   char               buffer[BLOCKSIZE];
  61.   struct tar_header  header;
  62. };
  63.  
  64. enum { TGZ_EXTRACT = 0, TGZ_LIST };
  65.  
  66. static char *TGZfname    OF((const char *));
  67. void TGZnotfound    OF((const char *));
  68.  
  69. int getoct        OF((char *, int));
  70. char *strtime        OF((time_t *));
  71. int ExprMatch        OF((char *,char *));
  72.  
  73. int makedir        OF((char *));
  74. int matchname        OF((int,int,char **,char *));
  75.  
  76. void error        OF((const char *));
  77. int  tar        OF((gzFile, int, int, int, char **));
  78.  
  79. void help        OF((int));
  80. int main        OF((int, char **));
  81.  
  82. char *prog;
  83.  
  84. /* This will give a benign warning */
  85.  
  86. static char *TGZprefix[] = { "\0", ".tgz", ".tar.gz", NULL };
  87.  
  88. /* Return the real name of the TGZ archive */
  89. /* or NULL if it does not exist. */
  90.  
  91. static char *TGZfname OF((const char *fname))
  92. {
  93.   static char buffer[1024];
  94.   int origlen,i;
  95.   
  96.   strcpy(buffer,fname);
  97.   origlen = strlen(buffer);
  98.  
  99.   for (i=0; TGZprefix[i]; i++)
  100.     {
  101.        strcpy(buffer+origlen,TGZprefix[i]);
  102.        if (access(buffer,F_OK) == 0)
  103.          return buffer;
  104.     }
  105.   return NULL;
  106. }
  107.  
  108. /* error message for the filename */
  109.  
  110. void TGZnotfound OF((const char *fname))
  111. {
  112.   int i;
  113.  
  114.   fprintf(stderr,"%s : couldn't find ",prog);
  115.   for (i=0;TGZprefix[i];i++)
  116.     fprintf(stderr,(TGZprefix[i+1]) ? "%s%s, " : "or %s%s\n",
  117.             fname,
  118.             TGZprefix[i]);
  119.   exit(1);
  120. }
  121.  
  122.  
  123. /* help functions */
  124.  
  125. int getoct(char *p,int width)
  126. {
  127.   int result = 0;
  128.   char c;
  129.   
  130.   while (width --)
  131.     {
  132.       c = *p++;
  133.       if (c == ' ')
  134.     continue;
  135.       if (c == 0)
  136.     break;
  137.       result = result * 8 + (c - '0');
  138.     }
  139.   return result;
  140. }
  141.  
  142. char *strtime (time_t *t)
  143. {
  144.   struct tm   *local;
  145.   static char result[32];
  146.  
  147.   local = localtime(t);
  148.   sprintf(result,"%2d/%02d/%4d %02d:%02d:%02d",
  149.       local->tm_mday, local->tm_mon+1, local->tm_year+1900,
  150.       local->tm_hour, local->tm_min,   local->tm_sec);
  151.   return result;
  152. }
  153.  
  154.  
  155. /* regular expression matching */
  156.  
  157. #define ISSPECIAL(c) (((c) == '*') || ((c) == '/'))
  158.  
  159. int ExprMatch(char *string,char *expr)
  160. {
  161.   while (1)
  162.     {
  163.       if (ISSPECIAL(*expr))
  164.     {
  165.       if (*expr == '/')
  166.         {
  167.           if (*string != '\\' && *string != '/')
  168.         return 0;
  169.           string ++; expr++;
  170.         }
  171.       else if (*expr == '*')
  172.         {
  173.           if (*expr ++ == 0)
  174.         return 1;
  175.           while (*++string != *expr)
  176.         if (*string == 0)
  177.           return 0;
  178.         }
  179.     }
  180.       else
  181.     {
  182.       if (*string != *expr)
  183.         return 0;
  184.       if (*expr++ == 0)
  185.         return 1;
  186.       string++;
  187.     }
  188.     }
  189. }
  190.  
  191. /* recursive make directory */
  192. /* abort if you get an ENOENT errno somewhere in the middle */
  193. /* e.g. ignore error "mkdir on existing directory" */
  194. /* */
  195. /* return 1 if OK */
  196. /*        0 on error */
  197.  
  198. int makedir (char *newdir)
  199. {
  200.   char *buffer = strdup(newdir);
  201.   char *p;
  202.   int  len = strlen(buffer);
  203.   
  204.   if (len <= 0) {
  205.     free(buffer);
  206.     return 0;
  207.   }
  208.   if (buffer[len-1] == '/') {
  209.     buffer[len-1] = '\0';
  210.   }
  211.   if (mkdir(buffer, 0775) == 0)
  212.     {
  213.       free(buffer);
  214.       return 1;
  215.     }
  216.  
  217.   p = buffer+1;
  218.   while (1)
  219.     {
  220.       char hold;
  221.       
  222.       while(*p && *p != '\\' && *p != '/')
  223.     p++;
  224.       hold = *p;
  225.       *p = 0;
  226.       if ((mkdir(buffer, 0775) == -1) && (errno == ENOENT))
  227.     {
  228.       fprintf(stderr,"%s: couldn't create directory %s\n",prog,buffer);
  229.       free(buffer);
  230.       return 0;
  231.     }
  232.       if (hold == 0)
  233.     break;
  234.       *p++ = hold;
  235.     }
  236.   free(buffer);
  237.   return 1;
  238. }
  239.  
  240. int matchname (int arg,int argc,char **argv,char *fname)
  241. {
  242.   if (arg == argc)        /* no arguments given (untgz tgzarchive) */
  243.     return 1;
  244.  
  245.   while (arg < argc)
  246.     if (ExprMatch(fname,argv[arg++]))
  247.       return 1;
  248.  
  249.   return 0; /* ignore this for the moment being */
  250. }
  251.  
  252.  
  253. /* Tar file list or extract */
  254.  
  255. int tar (gzFile in,int action,int arg,int argc,char **argv)
  256. {
  257.   union  tar_buffer buffer;
  258.   int    len;
  259.   int    err;
  260.   int    getheader = 1;
  261.   int    remaining = 0;
  262.   FILE   *outfile = NULL;
  263.   char   fname[BLOCKSIZE];
  264.   time_t tartime;
  265.   
  266.   if (action == TGZ_LIST)
  267.     printf("     day      time     size                       file\n"
  268.        " ---------- -------- --------- -------------------------------------\n");
  269.   while (1)
  270.     {
  271.       len = gzread(in, &buffer, BLOCKSIZE);
  272.       if (len < 0)
  273.     error (gzerror(in, &err));
  274.       /*
  275.        * if we met the end of the tar
  276.        * or the end-of-tar block,
  277.        * we are done
  278.        */
  279.       if ((len == 0)  || (buffer.header.name[0]== 0))
  280.     break;
  281.       
  282.       /*
  283.        * Always expect complete blocks to process
  284.        * the tar information.
  285.        */
  286.       if (len != BLOCKSIZE)
  287.     error("gzread: incomplete block read");
  288.       
  289.       /*
  290.        * If we have to get a tar header
  291.        */
  292.       if (getheader == 1)
  293.     {
  294.       tartime = (time_t)getoct(buffer.header.mtime,12);
  295.       strcpy(fname,buffer.header.name);
  296.       
  297.       switch (buffer.header.typeflag)
  298.         {
  299.         case DIRTYPE:
  300.           if (action == TGZ_LIST)
  301.         printf(" %s     <dir> %s\n",strtime(&tartime),fname);
  302.           if (action == TGZ_EXTRACT)
  303.         makedir(fname);
  304.           break;
  305.         case REGTYPE:
  306.         case AREGTYPE:
  307.           remaining = getoct(buffer.header.size,12);
  308.           if (action == TGZ_LIST)
  309.         printf(" %s %9d %s\n",strtime(&tartime),remaining,fname);
  310.           if (action == TGZ_EXTRACT)
  311.         {
  312.           if ((remaining) && (matchname(arg,argc,argv,fname)))
  313.             {
  314.               outfile = fopen(fname,"wb");
  315.               if (outfile == NULL) {
  316.             /* try creating directory */
  317.             char *p = strrchr(fname, '/');
  318.             if (p != NULL) {
  319.               *p = '\0';
  320.               makedir(fname);
  321.               *p = '/';
  322.               outfile = fopen(fname,"wb");
  323.             }
  324.               }
  325.               fprintf(stderr,
  326.                   "%s %s\n",
  327.                   (outfile) ? "Extracting" : "Couldn't create",
  328.                   fname);
  329.             }
  330.           else
  331.             outfile = NULL;
  332.         }
  333.           /*
  334.            * could have no contents
  335.            */
  336.           getheader = (remaining) ? 0 : 1;
  337.           break;
  338.         default:
  339.           if (action == TGZ_LIST)
  340.         printf(" %s     <---> %s\n",strtime(&tartime),fname);
  341.           break;
  342.         }
  343.     }
  344.       else
  345.     {
  346.       unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining;
  347.  
  348.       if ((action == TGZ_EXTRACT) && (outfile != NULL))
  349.         {
  350.           if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes)
  351.         {
  352.           fprintf(stderr,"%s : error writing %s skipping...\n",prog,fname);
  353.           fclose(outfile);
  354.           unlink(fname);
  355.         }
  356.         }
  357.       remaining -= bytes;
  358.       if (remaining == 0)
  359.         {
  360.           getheader = 1;
  361.           if ((action == TGZ_EXTRACT) && (outfile != NULL))
  362.         {
  363.           struct utimbuf settime;
  364.  
  365.           settime.actime = settime.modtime = tartime;
  366.  
  367.           fclose(outfile);
  368.           outfile = NULL;
  369.           utime(fname,&settime);
  370.         }
  371.         }
  372.     }
  373.     }
  374.   
  375.   if (gzclose(in) != Z_OK)
  376.     error("failed gzclose");
  377.  
  378.   return 0;
  379. }
  380.  
  381.  
  382. /* =========================================================== */
  383.  
  384. void help(int exitval)
  385. {
  386.   fprintf(stderr,
  387.       "untgz v 0.1\n"
  388.       " an sample application of zlib 1.0.4\n\n"
  389.           "Usage : untgz TGZfile            to extract all files\n"
  390.           "        untgz TGZfile fname ...  to extract selected files\n"
  391.           "        untgz -l TGZfile         to list archive contents\n"
  392.           "        untgz -h                 to display this help\n\n");
  393.   exit(exitval);
  394. }
  395.  
  396. void error(const char *msg)
  397. {
  398.     fprintf(stderr, "%s: %s\n", prog, msg);
  399.     exit(1);
  400. }
  401.  
  402.  
  403. /* ====================================================================== */
  404.  
  405. int _CRT_glob = 0;    /* disable globbing of the arguments */
  406.  
  407. int main(int argc,char **argv)
  408. {
  409.     int     action = TGZ_EXTRACT;
  410.     int     arg = 1;
  411.     char    *TGZfile;
  412.     gzFile    *f;
  413.     
  414.  
  415.     prog = strrchr(argv[0],'\\');
  416.     if (prog == NULL)
  417.       {
  418.     prog = strrchr(argv[0],'/');
  419.     if (prog == NULL)
  420.       {
  421.         prog = strrchr(argv[0],':');
  422.         if (prog == NULL)
  423.           prog = argv[0];
  424.         else
  425.           prog++;
  426.       }
  427.     else
  428.       prog++;
  429.       }
  430.     else
  431.       prog++;
  432.     
  433.     if (argc == 1)
  434.       help(0);
  435.  
  436.     if (strcmp(argv[arg],"-l") == 0)
  437.       {
  438.     action = TGZ_LIST;
  439.     if (argc == ++arg)
  440.       help(0);
  441.       }
  442.     else if (strcmp(argv[arg],"-h") == 0)
  443.       {
  444.     help(0);
  445.       }
  446.  
  447.     if ((TGZfile = TGZfname(argv[arg])) == NULL)
  448.       TGZnotfound(argv[arg]);            
  449.  
  450.     ++arg;
  451.     if ((action == TGZ_LIST) && (arg != argc))
  452.       help(1);
  453.  
  454. /*
  455.  *  Process the TGZ file
  456.  */
  457.     switch(action)
  458.       {
  459.       case TGZ_LIST:
  460.       case TGZ_EXTRACT:
  461.     f = gzopen(TGZfile,"rb");
  462.     if (f == NULL)
  463.       {
  464.         fprintf(stderr,"%s: Couldn't gzopen %s\n",
  465.             prog,
  466.             TGZfile);
  467.         return 1;
  468.       }
  469.     exit(tar(f, action, arg, argc, argv));
  470.       break;
  471.     
  472.       default:
  473.     error("Unknown option!");
  474.     exit(1);
  475.       }
  476.  
  477.     return 0;
  478. }
  479.