/* * untgz.c -- Display contents and extract files from a gzip'd TAR file * * written by Pedro A. Aranda Gutierrez <paag@tid.es> * adaptation to Unix by Jean-loup Gailly <jloup@gzip.org> * various fixes by Cosmin Truta <cosmint@cs.ubbcluj.ro> * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution.
*/
#ifdef _WIN32 # include <direct.h> # include <io.h> # include <windows.h> # ifndef F_OK # define F_OK 0 # endif # define mkdir(dirname,mode) _mkdir(dirname) # ifdef _MSC_VER # define access(path,mode) _access(path,mode) # define chmod(path,mode) _chmod(path,mode) # define strdup(str) _strdup(str) # endif #else # include <sys/stat.h> # include <unistd.h> # include <utime.h> #endif
/* values used in typeflag field */
#define REGTYPE '0'/* regular file */ #define AREGTYPE '\0'/* regular file */ #define LNKTYPE '1'/* link */ #define SYMTYPE '2'/* reserved */ #define CHRTYPE '3'/* character special */ #define BLKTYPE '4'/* block special */ #define DIRTYPE '5'/* directory */ #define FIFOTYPE '6'/* FIFO special */ #define CONTTYPE '7'/* reserved */
/* GNU tar extensions */
#define GNUTYPE_DUMPDIR 'D'/* file names from dumped directory */ #define GNUTYPE_LONGLINK 'K'/* long link name */ #define GNUTYPE_LONGNAME 'L'/* long file name */ #define GNUTYPE_MULTIVOL 'M'/* continuation of file from another volume */ #define GNUTYPE_NAMES 'N'/* file name that does not fit into main hdr */ #define GNUTYPE_SPARSE 'S'/* sparse file */ #define GNUTYPE_VOLHDR 'V'/* tape/volume header */
/* convert octal digits to int */ /* on error return -1 */
int getoct (char *p,int width)
{ int result = 0; char c;
while (width--)
{
c = *p++; if (c == 0) break; if (c == ' ') continue; if (c < '0' || c > '7') return -1;
result = result * 8 + (c - '0');
} return result;
}
/* convert time_t to string */ /* use the "YYYY/MM/DD hh:mm:ss" format */
int matchname (int arg,int argc,char **argv,char *fname)
{ if (arg == argc) /* no arguments given (untgz tgzarchive) */ return 1;
while (arg < argc) if (ExprMatch(fname,argv[arg++])) return 1;
return 0; /* ignore this for the moment being */
}
/* tar file list or extract */
int tar (gzFile in,int action,int arg,int argc,char **argv)
{ union tar_buffer buffer; int len; int err; int getheader = 1; int remaining = 0;
FILE *outfile = NULL; char fname[BLOCKSIZE]; int tarmode;
time_t tartime; struct attr_item *attributes = NULL;
if (action == TGZ_LIST)
printf(" date time size file\n" " ---------- -------- --------- -------------------------------------\n"); while (1)
{
len = gzread(in, &buffer, BLOCKSIZE); if (len < 0)
error(gzerror(in, &err)); /* * Always expect complete blocks to process * the tar information.
*/ if (len != BLOCKSIZE)
{
action = TGZ_INVALID; /* force error exit */
remaining = 0; /* force I/O cleanup */
}
/* * If we have to get a tar header
*/ if (getheader >= 1)
{ /* * if we met the end of the tar * or the end-of-tar block, * we are done
*/ if (len == 0 || buffer.header.name[0] == 0) break;
if (getheader == 1)
{
strncpy(fname,buffer.header.name,SHORTNAMESIZE); if (fname[SHORTNAMESIZE-1] != 0)
fname[SHORTNAMESIZE] = 0;
} else
{ /* * The file name is longer than SHORTNAMESIZE
*/ if (strncmp(fname,buffer.header.name,SHORTNAMESIZE-1) != 0)
error("bad long name");
getheader = 1;
}
/* * Act according to the type flag
*/ switch (buffer.header.typeflag)
{ case DIRTYPE: if (action == TGZ_LIST)
printf(" %s %s\n",strtime(&tartime),fname); if (action == TGZ_EXTRACT)
{
makedir(fname);
push_attr(&attributes,fname,tarmode,tartime);
} break; case REGTYPE: case AREGTYPE:
remaining = getoct(buffer.header.size,12); if (remaining == -1)
{
action = TGZ_INVALID; break;
} if (action == TGZ_LIST)
printf(" %s %9d %s\n",strtime(&tartime),remaining,fname); elseif (action == TGZ_EXTRACT)
{ if (matchname(arg,argc,argv,fname))
{
outfile = fopen(fname,"wb"); if (outfile == NULL) { /* try creating directory */ char *p = strrchr(fname, '/'); if (p != NULL) {
*p = '\0';
makedir(fname);
*p = '/';
outfile = fopen(fname,"wb");
}
} if (outfile != NULL)
printf("Extracting %s\n",fname); else
fprintf(stderr, "%s: Couldn't create %s",prog,fname);
} else
outfile = NULL;
}
getheader = 0; break; case GNUTYPE_LONGLINK: case GNUTYPE_LONGNAME:
remaining = getoct(buffer.header.size,12); if (remaining < 0 || remaining >= BLOCKSIZE)
{
action = TGZ_INVALID; break;
}
len = gzread(in, fname, BLOCKSIZE); if (len < 0)
error(gzerror(in, &err)); if (fname[BLOCKSIZE-1] != 0 || (int)strlen(fname) > remaining)
{
action = TGZ_INVALID; break;
}
getheader = 2; break; default: if (action == TGZ_LIST)
printf(" %s <---> %s\n",strtime(&tartime),fname); break;
}
} else
{ unsignedint bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.