untgz.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:16k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * untgz.c -- Display contents and extract files from a gzip'd TAR file
  3.  *
  4.  * written by Pedro A. Aranda Gutierrez <paag@tid.es>
  5.  * adaptation to Unix by Jean-loup Gailly <jloup@gzip.org>
  6.  * various fixes by Cosmin Truta <cosmint@cs.ubbcluj.ro>
  7.  */
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <time.h>
  12. #include <errno.h>
  13. #include "zlib.h"
  14. #ifdef unix
  15. #  include <unistd.h>
  16. #else
  17. #  include <direct.h>
  18. #  include <io.h>
  19. #endif
  20. #ifdef WIN32
  21. #include <windows.h>
  22. #  ifndef F_OK
  23. #    define F_OK  0
  24. #  endif
  25. #  define mkdir(dirname,mode)   _mkdir(dirname)
  26. #  ifdef _MSC_VER
  27. #    define access(path,mode)   _access(path,mode)
  28. #    define chmod(path,mode)    _chmod(path,mode)
  29. #    define strdup(str)         _strdup(str)
  30. #  endif
  31. #else
  32. #  include <utime.h>
  33. #endif
  34. /* values used in typeflag field */
  35. #define REGTYPE  '0'            /* regular file */
  36. #define AREGTYPE ''           /* regular file */
  37. #define LNKTYPE  '1'            /* link */
  38. #define SYMTYPE  '2'            /* reserved */
  39. #define CHRTYPE  '3'            /* character special */
  40. #define BLKTYPE  '4'            /* block special */
  41. #define DIRTYPE  '5'            /* directory */
  42. #define FIFOTYPE '6'            /* FIFO special */
  43. #define CONTTYPE '7'            /* reserved */
  44. /* GNU tar extensions */
  45. #define GNUTYPE_DUMPDIR  'D'    /* file names from dumped directory */
  46. #define GNUTYPE_LONGLINK 'K'    /* long link name */
  47. #define GNUTYPE_LONGNAME 'L'    /* long file name */
  48. #define GNUTYPE_MULTIVOL 'M'    /* continuation of file from another volume */
  49. #define GNUTYPE_NAMES    'N'    /* file name that does not fit into main hdr */
  50. #define GNUTYPE_SPARSE   'S'    /* sparse file */
  51. #define GNUTYPE_VOLHDR   'V'    /* tape/volume header */
  52. /* tar header */
  53. #define BLOCKSIZE     512
  54. #define SHORTNAMESIZE 100
  55. struct tar_header
  56. {                               /* byte offset */
  57.   char name[100];               /*   0 */
  58.   char mode[8];                 /* 100 */
  59.   char uid[8];                  /* 108 */
  60.   char gid[8];                  /* 116 */
  61.   char size[12];                /* 124 */
  62.   char mtime[12];               /* 136 */
  63.   char chksum[8];               /* 148 */
  64.   char typeflag;                /* 156 */
  65.   char linkname[100];           /* 157 */
  66.   char magic[6];                /* 257 */
  67.   char version[2];              /* 263 */
  68.   char uname[32];               /* 265 */
  69.   char gname[32];               /* 297 */
  70.   char devmajor[8];             /* 329 */
  71.   char devminor[8];             /* 337 */
  72.   char prefix[155];             /* 345 */
  73.                                 /* 500 */
  74. };
  75. union tar_buffer
  76. {
  77.   char               buffer[BLOCKSIZE];
  78.   struct tar_header  header;
  79. };
  80. struct attr_item
  81. {
  82.   struct attr_item  *next;
  83.   char              *fname;
  84.   int                mode;
  85.   time_t             time;
  86. };
  87. enum { TGZ_EXTRACT, TGZ_LIST, TGZ_INVALID };
  88. char *TGZfname          OF((const char *));
  89. void TGZnotfound        OF((const char *));
  90. int getoct              OF((char *, int));
  91. char *strtime           OF((time_t *));
  92. int setfiletime         OF((char *, time_t));
  93. void push_attr          OF((struct attr_item **, char *, int, time_t));
  94. void restore_attr       OF((struct attr_item **));
  95. int ExprMatch           OF((char *, char *));
  96. int makedir             OF((char *));
  97. int matchname           OF((int, int, char **, char *));
  98. void error              OF((const char *));
  99. int tar                 OF((gzFile, int, int, int, char **));
  100. void help               OF((int));
  101. int main                OF((int, char **));
  102. char *prog;
  103. const char *TGZsuffix[] = { "", ".tar", ".tar.gz", ".taz", ".tgz", NULL };
  104. /* return the file name of the TGZ archive */
  105. /* or NULL if it does not exist */
  106. char *TGZfname (const char *arcname)
  107. {
  108.   static char buffer[1024];
  109.   int origlen,i;
  110.   strcpy(buffer,arcname);
  111.   origlen = strlen(buffer);
  112.   for (i=0; TGZsuffix[i]; i++)
  113.     {
  114.        strcpy(buffer+origlen,TGZsuffix[i]);
  115.        if (access(buffer,F_OK) == 0)
  116.          return buffer;
  117.     }
  118.   return NULL;
  119. }
  120. /* error message for the filename */
  121. void TGZnotfound (const char *arcname)
  122. {
  123.   int i;
  124.   fprintf(stderr,"%s: Couldn't find ",prog);
  125.   for (i=0;TGZsuffix[i];i++)
  126.     fprintf(stderr,(TGZsuffix[i+1]) ? "%s%s, " : "or %s%sn",
  127.             arcname,
  128.             TGZsuffix[i]);
  129.   exit(1);
  130. }
  131. /* convert octal digits to int */
  132. /* on error return -1 */
  133. int getoct (char *p,int width)
  134. {
  135.   int result = 0;
  136.   char c;
  137.   while (width--)
  138.     {
  139.       c = *p++;
  140.       if (c == 0)
  141.         break;
  142.       if (c == ' ')
  143.         continue;
  144.       if (c < '0' || c > '7')
  145.         return -1;
  146.       result = result * 8 + (c - '0');
  147.     }
  148.   return result;
  149. }
  150. /* convert time_t to string */
  151. /* use the "YYYY/MM/DD hh:mm:ss" format */
  152. char *strtime (time_t *t)
  153. {
  154.   struct tm   *local;
  155.   static char result[32];
  156.   local = localtime(t);
  157.   sprintf(result,"%4d/%02d/%02d %02d:%02d:%02d",
  158.           local->tm_year+1900, local->tm_mon+1, local->tm_mday,
  159.           local->tm_hour, local->tm_min, local->tm_sec);
  160.   return result;
  161. }
  162. /* set file time */
  163. int setfiletime (char *fname,time_t ftime)
  164. {
  165. #ifdef WIN32
  166.   static int isWinNT = -1;
  167.   SYSTEMTIME st;
  168.   FILETIME locft, modft;
  169.   struct tm *loctm;
  170.   HANDLE hFile;
  171.   int result;
  172.   loctm = localtime(&ftime);
  173.   if (loctm == NULL)
  174.     return -1;
  175.   st.wYear         = (WORD)loctm->tm_year + 1900;
  176.   st.wMonth        = (WORD)loctm->tm_mon + 1;
  177.   st.wDayOfWeek    = (WORD)loctm->tm_wday;
  178.   st.wDay          = (WORD)loctm->tm_mday;
  179.   st.wHour         = (WORD)loctm->tm_hour;
  180.   st.wMinute       = (WORD)loctm->tm_min;
  181.   st.wSecond       = (WORD)loctm->tm_sec;
  182.   st.wMilliseconds = 0;
  183.   if (!SystemTimeToFileTime(&st, &locft) ||
  184.       !LocalFileTimeToFileTime(&locft, &modft))
  185.     return -1;
  186.   if (isWinNT < 0)
  187.     isWinNT = (GetVersion() < 0x80000000) ? 1 : 0;
  188.   hFile = CreateFile(fname, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
  189.                      (isWinNT ? FILE_FLAG_BACKUP_SEMANTICS : 0),
  190.                      NULL);
  191.   if (hFile == INVALID_HANDLE_VALUE)
  192.     return -1;
  193.   result = SetFileTime(hFile, NULL, NULL, &modft) ? 0 : -1;
  194.   CloseHandle(hFile);
  195.   return result;
  196. #else
  197.   struct utimbuf settime;
  198.   settime.actime = settime.modtime = ftime;
  199.   return utime(fname,&settime);
  200. #endif
  201. }
  202. /* push file attributes */
  203. void push_attr(struct attr_item **list,char *fname,int mode,time_t time)
  204. {
  205.   struct attr_item *item;
  206.   item = (struct attr_item *)malloc(sizeof(struct attr_item));
  207.   if (item == NULL)
  208.     error("Out of memory");
  209.   item->fname = strdup(fname);
  210.   item->mode  = mode;
  211.   item->time  = time;
  212.   item->next  = *list;
  213.   *list       = item;
  214. }
  215. /* restore file attributes */
  216. void restore_attr(struct attr_item **list)
  217. {
  218.   struct attr_item *item, *prev;
  219.   for (item = *list; item != NULL; )
  220.     {
  221.       setfiletime(item->fname,item->time);
  222.       chmod(item->fname,item->mode);
  223.       prev = item;
  224.       item = item->next;
  225.       free(prev);
  226.     }
  227.   *list = NULL;
  228. }
  229. /* match regular expression */
  230. #define ISSPECIAL(c) (((c) == '*') || ((c) == '/'))
  231. int ExprMatch (char *string,char *expr)
  232. {
  233.   while (1)
  234.     {
  235.       if (ISSPECIAL(*expr))
  236.         {
  237.           if (*expr == '/')
  238.             {
  239.               if (*string != '\' && *string != '/')
  240.                 return 0;
  241.               string ++; expr++;
  242.             }
  243.           else if (*expr == '*')
  244.             {
  245.               if (*expr ++ == 0)
  246.                 return 1;
  247.               while (*++string != *expr)
  248.                 if (*string == 0)
  249.                   return 0;
  250.             }
  251.         }
  252.       else
  253.         {
  254.           if (*string != *expr)
  255.             return 0;
  256.           if (*expr++ == 0)
  257.             return 1;
  258.           string++;
  259.         }
  260.     }
  261. }
  262. /* recursive mkdir */
  263. /* abort on ENOENT; ignore other errors like "directory already exists" */
  264. /* return 1 if OK */
  265. /*        0 on error */
  266. int makedir (char *newdir)
  267. {
  268.   char *buffer = strdup(newdir);
  269.   char *p;
  270.   int  len = strlen(buffer);
  271.   if (len <= 0) {
  272.     free(buffer);
  273.     return 0;
  274.   }
  275.   if (buffer[len-1] == '/') {
  276.     buffer[len-1] = '';
  277.   }
  278.   if (mkdir(buffer, 0755) == 0)
  279.     {
  280.       free(buffer);
  281.       return 1;
  282.     }
  283.   p = buffer+1;
  284.   while (1)
  285.     {
  286.       char hold;
  287.       while(*p && *p != '\' && *p != '/')
  288.         p++;
  289.       hold = *p;
  290.       *p = 0;
  291.       if ((mkdir(buffer, 0755) == -1) && (errno == ENOENT))
  292.         {
  293.           fprintf(stderr,"%s: Couldn't create directory %sn",prog,buffer);
  294.           free(buffer);
  295.           return 0;
  296.         }
  297.       if (hold == 0)
  298.         break;
  299.       *p++ = hold;
  300.     }
  301.   free(buffer);
  302.   return 1;
  303. }
  304. int matchname (int arg,int argc,char **argv,char *fname)
  305. {
  306.   if (arg == argc)      /* no arguments given (untgz tgzarchive) */
  307.     return 1;
  308.   while (arg < argc)
  309.     if (ExprMatch(fname,argv[arg++]))
  310.       return 1;
  311.   return 0; /* ignore this for the moment being */
  312. }
  313. /* tar file list or extract */
  314. int tar (gzFile in,int action,int arg,int argc,char **argv)
  315. {
  316.   union  tar_buffer buffer;
  317.   int    len;
  318.   int    err;
  319.   int    getheader = 1;
  320.   int    remaining = 0;
  321.   FILE   *outfile = NULL;
  322.   char   fname[BLOCKSIZE];
  323.   int    tarmode;
  324.   time_t tartime;
  325.   struct attr_item *attributes = NULL;
  326.   if (action == TGZ_LIST)
  327.     printf("    date      time     size                       filen"
  328.            " ---------- -------- --------- -------------------------------------n");
  329.   while (1)
  330.     {
  331.       len = gzread(in, &buffer, BLOCKSIZE);
  332.       if (len < 0)
  333.         error(gzerror(in, &err));
  334.       /*
  335.        * Always expect complete blocks to process
  336.        * the tar information.
  337.        */
  338.       if (len != BLOCKSIZE)
  339.         {
  340.           action = TGZ_INVALID; /* force error exit */
  341.           remaining = 0;        /* force I/O cleanup */
  342.         }
  343.       /*
  344.        * If we have to get a tar header
  345.        */
  346.       if (getheader >= 1)
  347.         {
  348.           /*
  349.            * if we met the end of the tar
  350.            * or the end-of-tar block,
  351.            * we are done
  352.            */
  353.           if (len == 0 || buffer.header.name[0] == 0)
  354.             break;
  355.           tarmode = getoct(buffer.header.mode,8);
  356.           tartime = (time_t)getoct(buffer.header.mtime,12);
  357.           if (tarmode == -1 || tartime == (time_t)-1)
  358.             {
  359.               buffer.header.name[0] = 0;
  360.               action = TGZ_INVALID;
  361.             }
  362.           if (getheader == 1)
  363.             {
  364.               strncpy(fname,buffer.header.name,SHORTNAMESIZE);
  365.               if (fname[SHORTNAMESIZE-1] != 0)
  366.                   fname[SHORTNAMESIZE] = 0;
  367.             }
  368.           else
  369.             {
  370.               /*
  371.                * The file name is longer than SHORTNAMESIZE
  372.                */
  373.               if (strncmp(fname,buffer.header.name,SHORTNAMESIZE-1) != 0)
  374.                   error("bad long name");
  375.               getheader = 1;
  376.             }
  377.           /*
  378.            * Act according to the type flag
  379.            */
  380.           switch (buffer.header.typeflag)
  381.             {
  382.             case DIRTYPE:
  383.               if (action == TGZ_LIST)
  384.                 printf(" %s     <dir> %sn",strtime(&tartime),fname);
  385.               if (action == TGZ_EXTRACT)
  386.                 {
  387.                   makedir(fname);
  388.                   push_attr(&attributes,fname,tarmode,tartime);
  389.                 }
  390.               break;
  391.             case REGTYPE:
  392.             case AREGTYPE:
  393.               remaining = getoct(buffer.header.size,12);
  394.               if (remaining == -1)
  395.                 {
  396.                   action = TGZ_INVALID;
  397.                   break;
  398.                 }
  399.               if (action == TGZ_LIST)
  400.                 printf(" %s %9d %sn",strtime(&tartime),remaining,fname);
  401.               else if (action == TGZ_EXTRACT)
  402.                 {
  403.                   if (matchname(arg,argc,argv,fname))
  404.                     {
  405.                       outfile = fopen(fname,"wb");
  406.                       if (outfile == NULL) {
  407.                         /* try creating directory */
  408.                         char *p = strrchr(fname, '/');
  409.                         if (p != NULL) {
  410.                           *p = '';
  411.                           makedir(fname);
  412.                           *p = '/';
  413.                           outfile = fopen(fname,"wb");
  414.                         }
  415.                       }
  416.                       if (outfile != NULL)
  417.                         printf("Extracting %sn",fname);
  418.                       else
  419.                         fprintf(stderr, "%s: Couldn't create %s",prog,fname);
  420.                     }
  421.                   else
  422.                     outfile = NULL;
  423.                 }
  424.               getheader = 0;
  425.               break;
  426.             case GNUTYPE_LONGLINK:
  427.             case GNUTYPE_LONGNAME:
  428.               remaining = getoct(buffer.header.size,12);
  429.               if (remaining < 0 || remaining >= BLOCKSIZE)
  430.                 {
  431.                   action = TGZ_INVALID;
  432.                   break;
  433.                 }
  434.               len = gzread(in, fname, BLOCKSIZE);
  435.               if (len < 0)
  436.                 error(gzerror(in, &err));
  437.               if (fname[BLOCKSIZE-1] != 0 || (int)strlen(fname) > remaining)
  438.                 {
  439.                   action = TGZ_INVALID;
  440.                   break;
  441.                 }
  442.               getheader = 2;
  443.               break;
  444.             default:
  445.               if (action == TGZ_LIST)
  446.                 printf(" %s     <---> %sn",strtime(&tartime),fname);
  447.               break;
  448.             }
  449.         }
  450.       else
  451.         {
  452.           unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining;
  453.           if (outfile != NULL)
  454.             {
  455.               if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes)
  456.                 {
  457.                   fprintf(stderr,
  458.                     "%s: Error writing %s -- skippingn",prog,fname);
  459.                   fclose(outfile);
  460.                   outfile = NULL;
  461.                   remove(fname);
  462.                 }
  463.             }
  464.           remaining -= bytes;
  465.         }
  466.       if (remaining == 0)
  467.         {
  468.           getheader = 1;
  469.           if (outfile != NULL)
  470.             {
  471.               fclose(outfile);
  472.               outfile = NULL;
  473.               if (action != TGZ_INVALID)
  474.                 push_attr(&attributes,fname,tarmode,tartime);
  475.             }
  476.         }
  477.       /*
  478.        * Abandon if errors are found
  479.        */
  480.       if (action == TGZ_INVALID)
  481.         {
  482.           error("broken archive");
  483.           break;
  484.         }
  485.     }
  486.   /*
  487.    * Restore file modes and time stamps
  488.    */
  489.   restore_attr(&attributes);
  490.   if (gzclose(in) != Z_OK)
  491.     error("failed gzclose");
  492.   return 0;
  493. }
  494. /* ============================================================ */
  495. void help(int exitval)
  496. {
  497.   printf("untgz version 0.2.1n"
  498.          "  using zlib version %snn",
  499.          zlibVersion());
  500.   printf("Usage: untgz file.tgz            extract all filesn"
  501.          "       untgz file.tgz fname ...  extract selected filesn"
  502.          "       untgz -l file.tgz         list archive contentsn"
  503.          "       untgz -h                  display this helpn");
  504.   exit(exitval);
  505. }
  506. void error(const char *msg)
  507. {
  508.   fprintf(stderr, "%s: %sn", prog, msg);
  509.   exit(1);
  510. }
  511. /* ============================================================ */
  512. #if defined(WIN32) && defined(__GNUC__)
  513. int _CRT_glob = 0;      /* disable argument globbing in MinGW */
  514. #endif
  515. int main(int argc,char **argv)
  516. {
  517.     int         action = TGZ_EXTRACT;
  518.     int         arg = 1;
  519.     char        *TGZfile;
  520.     gzFile      *f;
  521.     prog = strrchr(argv[0],'\');
  522.     if (prog == NULL)
  523.       {
  524.         prog = strrchr(argv[0],'/');
  525.         if (prog == NULL)
  526.           {
  527.             prog = strrchr(argv[0],':');
  528.             if (prog == NULL)
  529.               prog = argv[0];
  530.             else
  531.               prog++;
  532.           }
  533.         else
  534.           prog++;
  535.       }
  536.     else
  537.       prog++;
  538.     if (argc == 1)
  539.       help(0);
  540.     if (strcmp(argv[arg],"-l") == 0)
  541.       {
  542.         action = TGZ_LIST;
  543.         if (argc == ++arg)
  544.           help(0);
  545.       }
  546.     else if (strcmp(argv[arg],"-h") == 0)
  547.       {
  548.         help(0);
  549.       }
  550.     if ((TGZfile = TGZfname(argv[arg])) == NULL)
  551.       TGZnotfound(argv[arg]);
  552.     ++arg;
  553.     if ((action == TGZ_LIST) && (arg != argc))
  554.       help(1);
  555. /*
  556.  *  Process the TGZ file
  557.  */
  558.     switch(action)
  559.       {
  560.       case TGZ_LIST:
  561.       case TGZ_EXTRACT:
  562.         f = gzopen(TGZfile,"rb");
  563.         if (f == NULL)
  564.           {
  565.             fprintf(stderr,"%s: Couldn't gzopen %sn",prog,TGZfile);
  566.             return 1;
  567.           }
  568.         exit(tar(f, action, arg, argc, argv));
  569.       break;
  570.       default:
  571.         error("Unknown option");
  572.         exit(1);
  573.       }
  574.     return 0;
  575. }