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