kusano fc6ab3
/*
kusano fc6ab3
 * untgz.c -- Display contents and extract files from a gzip'd TAR file
kusano fc6ab3
 *
kusano fc6ab3
 * written by Pedro A. Aranda Gutierrez <paag@tid.es></paag@tid.es>
kusano fc6ab3
 * adaptation to Unix by Jean-loup Gailly <jloup@gzip.org></jloup@gzip.org>
kusano fc6ab3
 * various fixes by Cosmin Truta <cosmint@cs.ubbcluj.ro></cosmint@cs.ubbcluj.ro>
kusano fc6ab3
 */
kusano fc6ab3
kusano fc6ab3
#include <stdio.h></stdio.h>
kusano fc6ab3
#include <stdlib.h></stdlib.h>
kusano fc6ab3
#include <string.h></string.h>
kusano fc6ab3
#include <time.h></time.h>
kusano fc6ab3
#include <errno.h></errno.h>
kusano fc6ab3
kusano fc6ab3
#include "zlib.h"
kusano fc6ab3
kusano fc6ab3
#ifdef unix
kusano fc6ab3
#  include <unistd.h></unistd.h>
kusano fc6ab3
#else
kusano fc6ab3
#  include <direct.h></direct.h>
kusano fc6ab3
#  include <io.h></io.h>
kusano fc6ab3
#endif
kusano fc6ab3
kusano fc6ab3
#ifdef WIN32
kusano fc6ab3
#include <windows.h></windows.h>
kusano fc6ab3
#  ifndef F_OK
kusano fc6ab3
#    define F_OK  0
kusano fc6ab3
#  endif
kusano fc6ab3
#  define mkdir(dirname,mode)   _mkdir(dirname)
kusano fc6ab3
#  ifdef _MSC_VER
kusano fc6ab3
#    define access(path,mode)   _access(path,mode)
kusano fc6ab3
#    define chmod(path,mode)    _chmod(path,mode)
kusano fc6ab3
#    define strdup(str)         _strdup(str)
kusano fc6ab3
#  endif
kusano fc6ab3
#else
kusano fc6ab3
#  include <utime.h></utime.h>
kusano fc6ab3
#endif
kusano fc6ab3
kusano fc6ab3
kusano fc6ab3
/* values used in typeflag field */
kusano fc6ab3
kusano fc6ab3
#define REGTYPE  '0'            /* regular file */
kusano fc6ab3
#define AREGTYPE '\0'           /* regular file */
kusano fc6ab3
#define LNKTYPE  '1'            /* link */
kusano fc6ab3
#define SYMTYPE  '2'            /* reserved */
kusano fc6ab3
#define CHRTYPE  '3'            /* character special */
kusano fc6ab3
#define BLKTYPE  '4'            /* block special */
kusano fc6ab3
#define DIRTYPE  '5'            /* directory */
kusano fc6ab3
#define FIFOTYPE '6'            /* FIFO special */
kusano fc6ab3
#define CONTTYPE '7'            /* reserved */
kusano fc6ab3
kusano fc6ab3
/* GNU tar extensions */
kusano fc6ab3
kusano fc6ab3
#define GNUTYPE_DUMPDIR  'D'    /* file names from dumped directory */
kusano fc6ab3
#define GNUTYPE_LONGLINK 'K'    /* long link name */
kusano fc6ab3
#define GNUTYPE_LONGNAME 'L'    /* long file name */
kusano fc6ab3
#define GNUTYPE_MULTIVOL 'M'    /* continuation of file from another volume */
kusano fc6ab3
#define GNUTYPE_NAMES    'N'    /* file name that does not fit into main hdr */
kusano fc6ab3
#define GNUTYPE_SPARSE   'S'    /* sparse file */
kusano fc6ab3
#define GNUTYPE_VOLHDR   'V'    /* tape/volume header */
kusano fc6ab3
kusano fc6ab3
kusano fc6ab3
/* tar header */
kusano fc6ab3
kusano fc6ab3
#define BLOCKSIZE     512
kusano fc6ab3
#define SHORTNAMESIZE 100
kusano fc6ab3
kusano fc6ab3
struct tar_header
kusano fc6ab3
{                               /* byte offset */
kusano fc6ab3
  char name[100];               /*   0 */
kusano fc6ab3
  char mode[8];                 /* 100 */
kusano fc6ab3
  char uid[8];                  /* 108 */
kusano fc6ab3
  char gid[8];                  /* 116 */
kusano fc6ab3
  char size[12];                /* 124 */
kusano fc6ab3
  char mtime[12];               /* 136 */
kusano fc6ab3
  char chksum[8];               /* 148 */
kusano fc6ab3
  char typeflag;                /* 156 */
kusano fc6ab3
  char linkname[100];           /* 157 */
kusano fc6ab3
  char magic[6];                /* 257 */
kusano fc6ab3
  char version[2];              /* 263 */
kusano fc6ab3
  char uname[32];               /* 265 */
kusano fc6ab3
  char gname[32];               /* 297 */
kusano fc6ab3
  char devmajor[8];             /* 329 */
kusano fc6ab3
  char devminor[8];             /* 337 */
kusano fc6ab3
  char prefix[155];             /* 345 */
kusano fc6ab3
                                /* 500 */
kusano fc6ab3
};
kusano fc6ab3
kusano fc6ab3
union tar_buffer
kusano fc6ab3
{
kusano fc6ab3
  char               buffer[BLOCKSIZE];
kusano fc6ab3
  struct tar_header  header;
kusano fc6ab3
};
kusano fc6ab3
kusano fc6ab3
struct attr_item
kusano fc6ab3
{
kusano fc6ab3
  struct attr_item  *next;
kusano fc6ab3
  char              *fname;
kusano fc6ab3
  int                mode;
kusano fc6ab3
  time_t             time;
kusano fc6ab3
};
kusano fc6ab3
kusano fc6ab3
enum { TGZ_EXTRACT, TGZ_LIST, TGZ_INVALID };
kusano fc6ab3
kusano fc6ab3
char *TGZfname          OF((const char *));
kusano fc6ab3
void TGZnotfound        OF((const char *));
kusano fc6ab3
kusano fc6ab3
int getoct              OF((char *, int));
kusano fc6ab3
char *strtime           OF((time_t *));
kusano fc6ab3
int setfiletime         OF((char *, time_t));
kusano fc6ab3
void push_attr          OF((struct attr_item **, char *, int, time_t));
kusano fc6ab3
void restore_attr       OF((struct attr_item **));
kusano fc6ab3
kusano fc6ab3
int ExprMatch           OF((char *, char *));
kusano fc6ab3
kusano fc6ab3
int makedir             OF((char *));
kusano fc6ab3
int matchname           OF((int, int, char **, char *));
kusano fc6ab3
kusano fc6ab3
void error              OF((const char *));
kusano fc6ab3
int tar                 OF((gzFile, int, int, int, char **));
kusano fc6ab3
kusano fc6ab3
void help               OF((int));
kusano fc6ab3
int main                OF((int, char **));
kusano fc6ab3
kusano fc6ab3
char *prog;
kusano fc6ab3
kusano fc6ab3
const char *TGZsuffix[] = { "\0", ".tar", ".tar.gz", ".taz", ".tgz", NULL };
kusano fc6ab3
kusano fc6ab3
/* return the file name of the TGZ archive */
kusano fc6ab3
/* or NULL if it does not exist */
kusano fc6ab3
kusano fc6ab3
char *TGZfname (const char *arcname)
kusano fc6ab3
{
kusano fc6ab3
  static char buffer[1024];
kusano fc6ab3
  int origlen,i;
kusano fc6ab3
kusano fc6ab3
  strcpy(buffer,arcname);
kusano fc6ab3
  origlen = strlen(buffer);
kusano fc6ab3
kusano fc6ab3
  for (i=0; TGZsuffix[i]; i++)
kusano fc6ab3
    {
kusano fc6ab3
       strcpy(buffer+origlen,TGZsuffix[i]);
kusano fc6ab3
       if (access(buffer,F_OK) == 0)
kusano fc6ab3
         return buffer;
kusano fc6ab3
    }
kusano fc6ab3
  return NULL;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
kusano fc6ab3
/* error message for the filename */
kusano fc6ab3
kusano fc6ab3
void TGZnotfound (const char *arcname)
kusano fc6ab3
{
kusano fc6ab3
  int i;
kusano fc6ab3
kusano fc6ab3
  fprintf(stderr,"%s: Couldn't find ",prog);
kusano fc6ab3
  for (i=0;TGZsuffix[i];i++)
kusano fc6ab3
    fprintf(stderr,(TGZsuffix[i+1]) ? "%s%s, " : "or %s%s\n",
kusano fc6ab3
            arcname,
kusano fc6ab3
            TGZsuffix[i]);
kusano fc6ab3
  exit(1);
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
kusano fc6ab3
/* convert octal digits to int */
kusano fc6ab3
/* on error return -1 */
kusano fc6ab3
kusano fc6ab3
int getoct (char *p,int width)
kusano fc6ab3
{
kusano fc6ab3
  int result = 0;
kusano fc6ab3
  char c;
kusano fc6ab3
kusano fc6ab3
  while (width--)
kusano fc6ab3
    {
kusano fc6ab3
      c = *p++;
kusano fc6ab3
      if (c == 0)
kusano fc6ab3
        break;
kusano fc6ab3
      if (c == ' ')
kusano fc6ab3
        continue;
kusano fc6ab3
      if (c < '0' || c > '7')
kusano fc6ab3
        return -1;
kusano fc6ab3
      result = result * 8 + (c - '0');
kusano fc6ab3
    }
kusano fc6ab3
  return result;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
kusano fc6ab3
/* convert time_t to string */
kusano fc6ab3
/* use the "YYYY/MM/DD hh:mm:ss" format */
kusano fc6ab3
kusano fc6ab3
char *strtime (time_t *t)
kusano fc6ab3
{
kusano fc6ab3
  struct tm   *local;
kusano fc6ab3
  static char result[32];
kusano fc6ab3
kusano fc6ab3
  local = localtime(t);
kusano fc6ab3
  sprintf(result,"%4d/%02d/%02d %02d:%02d:%02d",
kusano fc6ab3
          local->tm_year+1900, local->tm_mon+1, local->tm_mday,
kusano fc6ab3
          local->tm_hour, local->tm_min, local->tm_sec);
kusano fc6ab3
  return result;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
kusano fc6ab3
/* set file time */
kusano fc6ab3
kusano fc6ab3
int setfiletime (char *fname,time_t ftime)
kusano fc6ab3
{
kusano fc6ab3
#ifdef WIN32
kusano fc6ab3
  static int isWinNT = -1;
kusano fc6ab3
  SYSTEMTIME st;
kusano fc6ab3
  FILETIME locft, modft;
kusano fc6ab3
  struct tm *loctm;
kusano fc6ab3
  HANDLE hFile;
kusano fc6ab3
  int result;
kusano fc6ab3
kusano fc6ab3
  loctm = localtime(&ftime);
kusano fc6ab3
  if (loctm == NULL)
kusano fc6ab3
    return -1;
kusano fc6ab3
kusano fc6ab3
  st.wYear         = (WORD)loctm->tm_year + 1900;
kusano fc6ab3
  st.wMonth        = (WORD)loctm->tm_mon + 1;
kusano fc6ab3
  st.wDayOfWeek    = (WORD)loctm->tm_wday;
kusano fc6ab3
  st.wDay          = (WORD)loctm->tm_mday;
kusano fc6ab3
  st.wHour         = (WORD)loctm->tm_hour;
kusano fc6ab3
  st.wMinute       = (WORD)loctm->tm_min;
kusano fc6ab3
  st.wSecond       = (WORD)loctm->tm_sec;
kusano fc6ab3
  st.wMilliseconds = 0;
kusano fc6ab3
  if (!SystemTimeToFileTime(&st, &locft) ||
kusano fc6ab3
      !LocalFileTimeToFileTime(&locft, &modft))
kusano fc6ab3
    return -1;
kusano fc6ab3
kusano fc6ab3
  if (isWinNT < 0)
kusano fc6ab3
    isWinNT = (GetVersion() < 0x80000000) ? 1 : 0;
kusano fc6ab3
  hFile = CreateFile(fname, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
kusano fc6ab3
                     (isWinNT ? FILE_FLAG_BACKUP_SEMANTICS : 0),
kusano fc6ab3
                     NULL);
kusano fc6ab3
  if (hFile == INVALID_HANDLE_VALUE)
kusano fc6ab3
    return -1;
kusano fc6ab3
  result = SetFileTime(hFile, NULL, NULL, &modft) ? 0 : -1;
kusano fc6ab3
  CloseHandle(hFile);
kusano fc6ab3
  return result;
kusano fc6ab3
#else
kusano fc6ab3
  struct utimbuf settime;
kusano fc6ab3
kusano fc6ab3
  settime.actime = settime.modtime = ftime;
kusano fc6ab3
  return utime(fname,&settime);
kusano fc6ab3
#endif
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
kusano fc6ab3
/* push file attributes */
kusano fc6ab3
kusano fc6ab3
void push_attr(struct attr_item **list,char *fname,int mode,time_t time)
kusano fc6ab3
{
kusano fc6ab3
  struct attr_item *item;
kusano fc6ab3
kusano fc6ab3
  item = (struct attr_item *)malloc(sizeof(struct attr_item));
kusano fc6ab3
  if (item == NULL)
kusano fc6ab3
    error("Out of memory");
kusano fc6ab3
  item->fname = strdup(fname);
kusano fc6ab3
  item->mode  = mode;
kusano fc6ab3
  item->time  = time;
kusano fc6ab3
  item->next  = *list;
kusano fc6ab3
  *list       = item;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
kusano fc6ab3
/* restore file attributes */
kusano fc6ab3
kusano fc6ab3
void restore_attr(struct attr_item **list)
kusano fc6ab3
{
kusano fc6ab3
  struct attr_item *item, *prev;
kusano fc6ab3
kusano fc6ab3
  for (item = *list; item != NULL; )
kusano fc6ab3
    {
kusano fc6ab3
      setfiletime(item->fname,item->time);
kusano fc6ab3
      chmod(item->fname,item->mode);
kusano fc6ab3
      prev = item;
kusano fc6ab3
      item = item->next;
kusano fc6ab3
      free(prev);
kusano fc6ab3
    }
kusano fc6ab3
  *list = NULL;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
kusano fc6ab3
/* match regular expression */
kusano fc6ab3
kusano fc6ab3
#define ISSPECIAL(c) (((c) == '*') || ((c) == '/'))
kusano fc6ab3
kusano fc6ab3
int ExprMatch (char *string,char *expr)
kusano fc6ab3
{
kusano fc6ab3
  while (1)
kusano fc6ab3
    {
kusano fc6ab3
      if (ISSPECIAL(*expr))
kusano fc6ab3
        {
kusano fc6ab3
          if (*expr == '/')
kusano fc6ab3
            {
kusano fc6ab3
              if (*string != '\\' && *string != '/')
kusano fc6ab3
                return 0;
kusano fc6ab3
              string ++; expr++;
kusano fc6ab3
            }
kusano fc6ab3
          else if (*expr == '*')
kusano fc6ab3
            {
kusano fc6ab3
              if (*expr ++ == 0)
kusano fc6ab3
                return 1;
kusano fc6ab3
              while (*++string != *expr)
kusano fc6ab3
                if (*string == 0)
kusano fc6ab3
                  return 0;
kusano fc6ab3
            }
kusano fc6ab3
        }
kusano fc6ab3
      else
kusano fc6ab3
        {
kusano fc6ab3
          if (*string != *expr)
kusano fc6ab3
            return 0;
kusano fc6ab3
          if (*expr++ == 0)
kusano fc6ab3
            return 1;
kusano fc6ab3
          string++;
kusano fc6ab3
        }
kusano fc6ab3
    }
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
kusano fc6ab3
/* recursive mkdir */
kusano fc6ab3
/* abort on ENOENT; ignore other errors like "directory already exists" */
kusano fc6ab3
/* return 1 if OK */
kusano fc6ab3
/*        0 on error */
kusano fc6ab3
kusano fc6ab3
int makedir (char *newdir)
kusano fc6ab3
{
kusano fc6ab3
  char *buffer = strdup(newdir);
kusano fc6ab3
  char *p;
kusano fc6ab3
  int  len = strlen(buffer);
kusano fc6ab3
kusano fc6ab3
  if (len <= 0) {
kusano fc6ab3
    free(buffer);
kusano fc6ab3
    return 0;
kusano fc6ab3
  }
kusano fc6ab3
  if (buffer[len-1] == '/') {
kusano fc6ab3
    buffer[len-1] = '\0';
kusano fc6ab3
  }
kusano fc6ab3
  if (mkdir(buffer, 0755) == 0)
kusano fc6ab3
    {
kusano fc6ab3
      free(buffer);
kusano fc6ab3
      return 1;
kusano fc6ab3
    }
kusano fc6ab3
kusano fc6ab3
  p = buffer+1;
kusano fc6ab3
  while (1)
kusano fc6ab3
    {
kusano fc6ab3
      char hold;
kusano fc6ab3
kusano fc6ab3
      while(*p && *p != '\\' && *p != '/')
kusano fc6ab3
        p++;
kusano fc6ab3
      hold = *p;
kusano fc6ab3
      *p = 0;
kusano fc6ab3
      if ((mkdir(buffer, 0755) == -1) && (errno == ENOENT))
kusano fc6ab3
        {
kusano fc6ab3
          fprintf(stderr,"%s: Couldn't create directory %s\n",prog,buffer);
kusano fc6ab3
          free(buffer);
kusano fc6ab3
          return 0;
kusano fc6ab3
        }
kusano fc6ab3
      if (hold == 0)
kusano fc6ab3
        break;
kusano fc6ab3
      *p++ = hold;
kusano fc6ab3
    }
kusano fc6ab3
  free(buffer);
kusano fc6ab3
  return 1;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
kusano fc6ab3
int matchname (int arg,int argc,char **argv,char *fname)
kusano fc6ab3
{
kusano fc6ab3
  if (arg == argc)      /* no arguments given (untgz tgzarchive) */
kusano fc6ab3
    return 1;
kusano fc6ab3
kusano fc6ab3
  while (arg < argc)
kusano fc6ab3
    if (ExprMatch(fname,argv[arg++]))
kusano fc6ab3
      return 1;
kusano fc6ab3
kusano fc6ab3
  return 0; /* ignore this for the moment being */
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
kusano fc6ab3
/* tar file list or extract */
kusano fc6ab3
kusano fc6ab3
int tar (gzFile in,int action,int arg,int argc,char **argv)
kusano fc6ab3
{
kusano fc6ab3
  union  tar_buffer buffer;
kusano fc6ab3
  int    len;
kusano fc6ab3
  int    err;
kusano fc6ab3
  int    getheader = 1;
kusano fc6ab3
  int    remaining = 0;
kusano fc6ab3
  FILE   *outfile = NULL;
kusano fc6ab3
  char   fname[BLOCKSIZE];
kusano fc6ab3
  int    tarmode;
kusano fc6ab3
  time_t tartime;
kusano fc6ab3
  struct attr_item *attributes = NULL;
kusano fc6ab3
kusano fc6ab3
  if (action == TGZ_LIST)
kusano fc6ab3
    printf("    date      time     size                       file\n"
kusano fc6ab3
           " ---------- -------- --------- -------------------------------------\n");
kusano fc6ab3
  while (1)
kusano fc6ab3
    {
kusano fc6ab3
      len = gzread(in, &buffer, BLOCKSIZE);
kusano fc6ab3
      if (len < 0)
kusano fc6ab3
        error(gzerror(in, &err));
kusano fc6ab3
      /*
kusano fc6ab3
       * Always expect complete blocks to process
kusano fc6ab3
       * the tar information.
kusano fc6ab3
       */
kusano fc6ab3
      if (len != BLOCKSIZE)
kusano fc6ab3
        {
kusano fc6ab3
          action = TGZ_INVALID; /* force error exit */
kusano fc6ab3
          remaining = 0;        /* force I/O cleanup */
kusano fc6ab3
        }
kusano fc6ab3
kusano fc6ab3
      /*
kusano fc6ab3
       * If we have to get a tar header
kusano fc6ab3
       */
kusano fc6ab3
      if (getheader >= 1)
kusano fc6ab3
        {
kusano fc6ab3
          /*
kusano fc6ab3
           * if we met the end of the tar
kusano fc6ab3
           * or the end-of-tar block,
kusano fc6ab3
           * we are done
kusano fc6ab3
           */
kusano fc6ab3
          if (len == 0 || buffer.header.name[0] == 0)
kusano fc6ab3
            break;
kusano fc6ab3
kusano fc6ab3
          tarmode = getoct(buffer.header.mode,8);
kusano fc6ab3
          tartime = (time_t)getoct(buffer.header.mtime,12);
kusano fc6ab3
          if (tarmode == -1 || tartime == (time_t)-1)
kusano fc6ab3
            {
kusano fc6ab3
              buffer.header.name[0] = 0;
kusano fc6ab3
              action = TGZ_INVALID;
kusano fc6ab3
            }
kusano fc6ab3
kusano fc6ab3
          if (getheader == 1)
kusano fc6ab3
            {
kusano fc6ab3
              strncpy(fname,buffer.header.name,SHORTNAMESIZE);
kusano fc6ab3
              if (fname[SHORTNAMESIZE-1] != 0)
kusano fc6ab3
                  fname[SHORTNAMESIZE] = 0;
kusano fc6ab3
            }
kusano fc6ab3
          else
kusano fc6ab3
            {
kusano fc6ab3
              /*
kusano fc6ab3
               * The file name is longer than SHORTNAMESIZE
kusano fc6ab3
               */
kusano fc6ab3
              if (strncmp(fname,buffer.header.name,SHORTNAMESIZE-1) != 0)
kusano fc6ab3
                  error("bad long name");
kusano fc6ab3
              getheader = 1;
kusano fc6ab3
            }
kusano fc6ab3
kusano fc6ab3
          /*
kusano fc6ab3
           * Act according to the type flag
kusano fc6ab3
           */
kusano fc6ab3
          switch (buffer.header.typeflag)
kusano fc6ab3
            {
kusano fc6ab3
            case DIRTYPE:
kusano fc6ab3
              if (action == TGZ_LIST)
kusano fc6ab3
                printf(" %s     <dir> %s\n",strtime(&tartime),fname);</dir>
kusano fc6ab3
              if (action == TGZ_EXTRACT)
kusano fc6ab3
                {
kusano fc6ab3
                  makedir(fname);
kusano fc6ab3
                  push_attr(&attributes,fname,tarmode,tartime);
kusano fc6ab3
                }
kusano fc6ab3
              break;
kusano fc6ab3
            case REGTYPE:
kusano fc6ab3
            case AREGTYPE:
kusano fc6ab3
              remaining = getoct(buffer.header.size,12);
kusano fc6ab3
              if (remaining == -1)
kusano fc6ab3
                {
kusano fc6ab3
                  action = TGZ_INVALID;
kusano fc6ab3
                  break;
kusano fc6ab3
                }
kusano fc6ab3
              if (action == TGZ_LIST)
kusano fc6ab3
                printf(" %s %9d %s\n",strtime(&tartime),remaining,fname);
kusano fc6ab3
              else if (action == TGZ_EXTRACT)
kusano fc6ab3
                {
kusano fc6ab3
                  if (matchname(arg,argc,argv,fname))
kusano fc6ab3
                    {
kusano fc6ab3
                      outfile = fopen(fname,"wb");
kusano fc6ab3
                      if (outfile == NULL) {
kusano fc6ab3
                        /* try creating directory */
kusano fc6ab3
                        char *p = strrchr(fname, '/');
kusano fc6ab3
                        if (p != NULL) {
kusano fc6ab3
                          *p = '\0';
kusano fc6ab3
                          makedir(fname);
kusano fc6ab3
                          *p = '/';
kusano fc6ab3
                          outfile = fopen(fname,"wb");
kusano fc6ab3
                        }
kusano fc6ab3
                      }
kusano fc6ab3
                      if (outfile != NULL)
kusano fc6ab3
                        printf("Extracting %s\n",fname);
kusano fc6ab3
                      else
kusano fc6ab3
                        fprintf(stderr, "%s: Couldn't create %s",prog,fname);
kusano fc6ab3
                    }
kusano fc6ab3
                  else
kusano fc6ab3
                    outfile = NULL;
kusano fc6ab3
                }
kusano fc6ab3
              getheader = 0;
kusano fc6ab3
              break;
kusano fc6ab3
            case GNUTYPE_LONGLINK:
kusano fc6ab3
            case GNUTYPE_LONGNAME:
kusano fc6ab3
              remaining = getoct(buffer.header.size,12);
kusano fc6ab3
              if (remaining < 0 || remaining >= BLOCKSIZE)
kusano fc6ab3
                {
kusano fc6ab3
                  action = TGZ_INVALID;
kusano fc6ab3
                  break;
kusano fc6ab3
                }
kusano fc6ab3
              len = gzread(in, fname, BLOCKSIZE);
kusano fc6ab3
              if (len < 0)
kusano fc6ab3
                error(gzerror(in, &err));
kusano fc6ab3
              if (fname[BLOCKSIZE-1] != 0 || (int)strlen(fname) > remaining)
kusano fc6ab3
                {
kusano fc6ab3
                  action = TGZ_INVALID;
kusano fc6ab3
                  break;
kusano fc6ab3
                }
kusano fc6ab3
              getheader = 2;
kusano fc6ab3
              break;
kusano fc6ab3
            default:
kusano fc6ab3
              if (action == TGZ_LIST)
kusano fc6ab3
                printf(" %s     <---> %s\n",strtime(&tartime),fname);
kusano fc6ab3
              break;
kusano fc6ab3
            }
kusano fc6ab3
        }
kusano fc6ab3
      else
kusano fc6ab3
        {
kusano fc6ab3
          unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining;
kusano fc6ab3
kusano fc6ab3
          if (outfile != NULL)
kusano fc6ab3
            {
kusano fc6ab3
              if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes)
kusano fc6ab3
                {
kusano fc6ab3
                  fprintf(stderr,
kusano fc6ab3
                    "%s: Error writing %s -- skipping\n",prog,fname);
kusano fc6ab3
                  fclose(outfile);
kusano fc6ab3
                  outfile = NULL;
kusano fc6ab3
                  remove(fname);
kusano fc6ab3
                }
kusano fc6ab3
            }
kusano fc6ab3
          remaining -= bytes;
kusano fc6ab3
        }
kusano fc6ab3
kusano fc6ab3
      if (remaining == 0)
kusano fc6ab3
        {
kusano fc6ab3
          getheader = 1;
kusano fc6ab3
          if (outfile != NULL)
kusano fc6ab3
            {
kusano fc6ab3
              fclose(outfile);
kusano fc6ab3
              outfile = NULL;
kusano fc6ab3
              if (action != TGZ_INVALID)
kusano fc6ab3
                push_attr(&attributes,fname,tarmode,tartime);
kusano fc6ab3
            }
kusano fc6ab3
        }
kusano fc6ab3
kusano fc6ab3
      /*
kusano fc6ab3
       * Abandon if errors are found
kusano fc6ab3
       */
kusano fc6ab3
      if (action == TGZ_INVALID)
kusano fc6ab3
        {
kusano fc6ab3
          error("broken archive");
kusano fc6ab3
          break;
kusano fc6ab3
        }
kusano fc6ab3
    }
kusano fc6ab3
kusano fc6ab3
  /*
kusano fc6ab3
   * Restore file modes and time stamps
kusano fc6ab3
   */
kusano fc6ab3
  restore_attr(&attributes);
kusano fc6ab3
kusano fc6ab3
  if (gzclose(in) != Z_OK)
kusano fc6ab3
    error("failed gzclose");
kusano fc6ab3
kusano fc6ab3
  return 0;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
kusano fc6ab3
/* ============================================================ */
kusano fc6ab3
kusano fc6ab3
void help(int exitval)
kusano fc6ab3
{
kusano fc6ab3
  printf("untgz version 0.2.1\n"
kusano fc6ab3
         "  using zlib version %s\n\n",
kusano fc6ab3
         zlibVersion());
kusano fc6ab3
  printf("Usage: untgz file.tgz            extract all files\n"
kusano fc6ab3
         "       untgz file.tgz fname ...  extract selected files\n"
kusano fc6ab3
         "       untgz -l file.tgz         list archive contents\n"
kusano fc6ab3
         "       untgz -h                  display this help\n");
kusano fc6ab3
  exit(exitval);
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
void error(const char *msg)
kusano fc6ab3
{
kusano fc6ab3
  fprintf(stderr, "%s: %s\n", prog, msg);
kusano fc6ab3
  exit(1);
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
kusano fc6ab3
/* ============================================================ */
kusano fc6ab3
kusano fc6ab3
#if defined(WIN32) && defined(__GNUC__)
kusano fc6ab3
int _CRT_glob = 0;      /* disable argument globbing in MinGW */
kusano fc6ab3
#endif
kusano fc6ab3
kusano fc6ab3
int main(int argc,char **argv)
kusano fc6ab3
{
kusano fc6ab3
    int         action = TGZ_EXTRACT;
kusano fc6ab3
    int         arg = 1;
kusano fc6ab3
    char        *TGZfile;
kusano fc6ab3
    gzFile      *f;
kusano fc6ab3
kusano fc6ab3
    prog = strrchr(argv[0],'\\');
kusano fc6ab3
    if (prog == NULL)
kusano fc6ab3
      {
kusano fc6ab3
        prog = strrchr(argv[0],'/');
kusano fc6ab3
        if (prog == NULL)
kusano fc6ab3
          {
kusano fc6ab3
            prog = strrchr(argv[0],':');
kusano fc6ab3
            if (prog == NULL)
kusano fc6ab3
              prog = argv[0];
kusano fc6ab3
            else
kusano fc6ab3
              prog++;
kusano fc6ab3
          }
kusano fc6ab3
        else
kusano fc6ab3
          prog++;
kusano fc6ab3
      }
kusano fc6ab3
    else
kusano fc6ab3
      prog++;
kusano fc6ab3
kusano fc6ab3
    if (argc == 1)
kusano fc6ab3
      help(0);
kusano fc6ab3
kusano fc6ab3
    if (strcmp(argv[arg],"-l") == 0)
kusano fc6ab3
      {
kusano fc6ab3
        action = TGZ_LIST;
kusano fc6ab3
        if (argc == ++arg)
kusano fc6ab3
          help(0);
kusano fc6ab3
      }
kusano fc6ab3
    else if (strcmp(argv[arg],"-h") == 0)
kusano fc6ab3
      {
kusano fc6ab3
        help(0);
kusano fc6ab3
      }
kusano fc6ab3
kusano fc6ab3
    if ((TGZfile = TGZfname(argv[arg])) == NULL)
kusano fc6ab3
      TGZnotfound(argv[arg]);
kusano fc6ab3
kusano fc6ab3
    ++arg;
kusano fc6ab3
    if ((action == TGZ_LIST) && (arg != argc))
kusano fc6ab3
      help(1);
kusano fc6ab3
kusano fc6ab3
/*
kusano fc6ab3
 *  Process the TGZ file
kusano fc6ab3
 */
kusano fc6ab3
    switch(action)
kusano fc6ab3
      {
kusano fc6ab3
      case TGZ_LIST:
kusano fc6ab3
      case TGZ_EXTRACT:
kusano fc6ab3
        f = gzopen(TGZfile,"rb");
kusano fc6ab3
        if (f == NULL)
kusano fc6ab3
          {
kusano fc6ab3
            fprintf(stderr,"%s: Couldn't gzopen %s\n",prog,TGZfile);
kusano fc6ab3
            return 1;
kusano fc6ab3
          }
kusano fc6ab3
        exit(tar(f, action, arg, argc, argv));
kusano fc6ab3
      break;
kusano fc6ab3
kusano fc6ab3
      default:
kusano fc6ab3
        error("Unknown option");
kusano fc6ab3
        exit(1);
kusano fc6ab3
      }
kusano fc6ab3
kusano fc6ab3
    return 0;
kusano fc6ab3
}