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