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