pkg://xemacs-21.2.47-src.tar.gz:7588333/
xemacs-21.2.47/
nt/minitar.c
downloads
/* Minitar: extract .tar.gz files on Win32 platforms.
Uses zlib for decompression.
This is very simple-minded, it ignores checksums, and any type of file
that is not a plain file or a directory. Nonetheless it is useful.
Author: Charles G. Waldman (cgw@pgt.com), Aug 4 1998
This file is placed in the public domain; you can
do whatever you like with it. There is NO WARRANTY.
If it breaks, you get to keep both pieces */
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <io.h>
#include <zlib.h>
static int
Usage(char *name)
{
fprintf(stderr,"Usage: %s file.tar.gz [base-dir]\n",name);
fprintf(stderr,"\tExtracts the contents compressed tar file to base-dir\n");
exit(-1);
}
#define BLOCKSIZE 512
#define MAXNAMELEN 1024
static int
octal(char *str)
{
int ret = -1;
sscanf(str,"%o",&ret);
return ret;
}
/* this is like mkdir -p, except if there is no trailing slash,
the final component is assumed to be a file, rather than a
path component, so it is not created as a directory */
static int
makepath(char *path)
{
char tmp[MAXNAMELEN];
char *cp;
for (cp=path; cp; cp = (char*)strchr(cp+1,'/')){
if (!*cp)
break;
if (*cp != '/')
continue;
strncpy(tmp, path, cp-path);
tmp[cp-path] = '\0';
if (strlen(tmp) == 0)
continue;
#ifdef WIN32_NATIVE
if (mkdir(tmp)){
#else
if (mkdir(tmp,0777)){
#endif
if (errno == EEXIST)
continue;
else
return -1;
}
}
return 0;
}
int
main(int argc, char **argv)
{
char fullname[MAXNAMELEN];
char *basedir = ".";
char *tarfile;
int size;
char osize[13];
char name[101];
char magic[7];
char type;
gzFile *infile = (gzFile*)0;
FILE *outfile = (FILE*)0;
char block[BLOCKSIZE];
int nbytes, nread, nwritten;
int in_block = 0;
int directory = 0;
if (argc < 2 || argc > 3)
Usage(argv[0]);
tarfile = argv[1];
if (argc==3)
basedir = argv[2];
if (! (infile = gzopen(tarfile,"rb"))){
fprintf(stderr,"Cannot open %s\n", tarfile);
exit(-2);
}
while (1){
nread = gzread(infile,block,512);
if (!in_block && nread == 0)
break;
if (nread != BLOCKSIZE){
fprintf(stderr,"Error: incomplete block read. Exiting.\n");
exit(-2);
}
if (!in_block){
if (block[0]=='\0') /* We're done */
break;
strncpy(magic,block+257,6);
magic[6] = '\0';
if (strcmp(magic,"ustar ")){
fprintf(stderr,
"Error: incorrect magic number in tar header. Exiting\n");
}
strncpy(name,block,100);
name[100] = '\0';
sprintf(fullname,"%s/%s",basedir,name);
printf("%s\n",fullname);
type = block[156];
switch(type){
case '0':
case '\0':
directory = 0;
break;
case '5':
directory = 1;
break;
default:
fprintf(stderr,"Error: unknown type flag %c. Exiting.\n",type);
break;
}
if (directory){
in_block = 0;
/* makepath will ignore the final path component, so make sure
dirnames have a trailing slash */
if (fullname[strlen(fullname)-1] != '/')
strcat(fullname,"/");
if (makepath(fullname)){
fprintf(stderr, "Error: cannot create directory %s. Exiting.\n",
fullname);
exit(-2);
}
continue;
} else { /*file */
in_block = 1;
if (outfile){
if (fclose(outfile)){
fprintf(stderr,"Error: cannot close file %s. Exiting.\n",
fullname);
exit(-2);
}
outfile = (FILE*)0;
}
if ( !(outfile = fopen(fullname,"wb"))){
/*try creating the directory, maybe it's not there */
if (makepath(fullname)){
fprintf(stderr,"Error: cannot create file %s. Exiting.\n",
fullname);
exit(-2);
}
/* now try again to open the file */
if (!(outfile = fopen(fullname,"wb"))){
fprintf(stderr,"Error: cannot create file %s. Exiting.\n",
fullname);
exit(-2);
}
}
strncpy(osize,block+124,12);
osize[12] = '\0';
size = octal(osize);
if (size<0){
fprintf(stderr,"Error: invalid size in tar header. Exiting.\n");
exit(-2);
}
}
} else { /* write or continue writing file contents */
nbytes = size>512? 512:size;
nwritten = fwrite(block, 1, nbytes, outfile);
if (nwritten != nbytes){
fprintf(stderr, "Error: only wrote %d bytes to file %s. Exiting.\n",
nwritten, fullname);
}
size -= nbytes;
if (size==0)
in_block = 0;
}
}
exit (0);
}