|
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 |
}
|