|
|
|
|
@ -15,11 +15,14 @@ |
|
|
|
|
* along with this program; if not, write to the Free Software |
|
|
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|
|
|
|
* |
|
|
|
|
* Some of this code is based on minitar.c which is in the public domain. |
|
|
|
|
* Much of this code is based on minitar.c which is in the public domain. |
|
|
|
|
* Author: Charles G. Waldman (cgw@pgt.com), Aug 4 1998 |
|
|
|
|
* |
|
|
|
|
* Change History: |
|
|
|
|
* $Log: untar.c,v $ |
|
|
|
|
* Revision 1.3 2004/09/06 08:34:47 nigelhorne |
|
|
|
|
* Randomise extracted file names from tar file |
|
|
|
|
* |
|
|
|
|
* Revision 1.2 2004/09/05 18:58:21 nigelhorne |
|
|
|
|
* Extract files completed |
|
|
|
|
* |
|
|
|
|
@ -27,22 +30,25 @@ |
|
|
|
|
* First draft |
|
|
|
|
* |
|
|
|
|
*/ |
|
|
|
|
static char const rcsid[] = "$Id: untar.c,v 1.2 2004/09/05 18:58:21 nigelhorne Exp $"; |
|
|
|
|
static char const rcsid[] = "$Id: untar.c,v 1.3 2004/09/06 08:34:47 nigelhorne Exp $"; |
|
|
|
|
|
|
|
|
|
#include <stdio.h> |
|
|
|
|
#include <errno.h> |
|
|
|
|
#include <string.h> |
|
|
|
|
#include <unistd.h> |
|
|
|
|
#include <sys/stat.h> |
|
|
|
|
#include <fcntl.h> |
|
|
|
|
#include <sys/param.h> /* for NAME_MAX */ |
|
|
|
|
|
|
|
|
|
#include "clamav.h" |
|
|
|
|
#include "others.h" |
|
|
|
|
#include "untar.h" |
|
|
|
|
#include "blob.h" |
|
|
|
|
|
|
|
|
|
#define BLOCKSIZE 512 |
|
|
|
|
#define MAXNAMELEN 1024 |
|
|
|
|
|
|
|
|
|
static |
|
|
|
|
int octal(const char *str) |
|
|
|
|
static int |
|
|
|
|
octal(const char *str) |
|
|
|
|
{ |
|
|
|
|
int ret = -1; |
|
|
|
|
|
|
|
|
|
@ -55,13 +61,12 @@ cli_untar(const char *dir, int desc) |
|
|
|
|
{ |
|
|
|
|
int size = 0; |
|
|
|
|
int in_block = 0; |
|
|
|
|
int directory = 0; |
|
|
|
|
char fullname[NAME_MAX + 1]; |
|
|
|
|
FILE *outfile = (FILE*)0; |
|
|
|
|
|
|
|
|
|
cli_dbgmsg("In untar(%s, %d)\n", dir ? dir : "", desc); |
|
|
|
|
|
|
|
|
|
for(;;) { |
|
|
|
|
char fullname[MAXNAMELEN]; |
|
|
|
|
char block[BLOCKSIZE]; |
|
|
|
|
const int nread = read(desc, block, sizeof(block)); |
|
|
|
|
|
|
|
|
|
@ -74,9 +79,20 @@ cli_untar(const char *dir, int desc) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(!in_block) { |
|
|
|
|
char magic[7]; |
|
|
|
|
char name[101]; |
|
|
|
|
char type; |
|
|
|
|
char *suffix; |
|
|
|
|
size_t suffixLen = 0; |
|
|
|
|
int fd, directory; |
|
|
|
|
char magic[7], name[101], osize[13]; |
|
|
|
|
|
|
|
|
|
if(outfile) { |
|
|
|
|
if(fclose(outfile)) { |
|
|
|
|
cli_errmsg("cli_untar: cannot close file %s\n", |
|
|
|
|
fullname); |
|
|
|
|
return CL_EIO; |
|
|
|
|
} |
|
|
|
|
outfile = (FILE*)0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(block[0] == '\0') /* We're done */ |
|
|
|
|
break; |
|
|
|
|
@ -88,10 +104,6 @@ cli_untar(const char *dir, int desc) |
|
|
|
|
return CL_EDSIG; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
strncpy(name, block, 100); |
|
|
|
|
name[100] = '\0'; |
|
|
|
|
sprintf(fullname, "%s/%s", dir, name); |
|
|
|
|
cli_dbgmsg("cli_untar: extracting %s\n", fullname); |
|
|
|
|
type = block[156]; |
|
|
|
|
|
|
|
|
|
switch(type) { |
|
|
|
|
@ -109,33 +121,59 @@ cli_untar(const char *dir, int desc) |
|
|
|
|
|
|
|
|
|
if(directory) |
|
|
|
|
continue; |
|
|
|
|
else { /*file */ |
|
|
|
|
char osize[13]; |
|
|
|
|
|
|
|
|
|
in_block = 1; |
|
|
|
|
if(outfile) { |
|
|
|
|
if(fclose(outfile)) { |
|
|
|
|
cli_errmsg("cli_untar: cannot close file %s\n", |
|
|
|
|
fullname); |
|
|
|
|
return CL_EIO; |
|
|
|
|
} |
|
|
|
|
outfile = (FILE*)0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(!(outfile = fopen(fullname,"wb"))) { |
|
|
|
|
cli_errmsg("cli_untar: cannot create file %s\n", |
|
|
|
|
fullname); |
|
|
|
|
return CL_ETMPFILE; |
|
|
|
|
} |
|
|
|
|
strncpy(name, block, 100); |
|
|
|
|
name[100] = '\0'; |
|
|
|
|
|
|
|
|
|
strncpy(osize, block+124, 12); |
|
|
|
|
osize[12] = '\0'; |
|
|
|
|
size = octal(osize); |
|
|
|
|
if(size < 0){ |
|
|
|
|
cli_errmsg("Invalid size in tar header\n"); |
|
|
|
|
return CL_EDSIG; |
|
|
|
|
/*
|
|
|
|
|
* see also fileblobSetFilename() |
|
|
|
|
* TODO: check if the suffix needs to be put back |
|
|
|
|
*/ |
|
|
|
|
sanitiseName(name); |
|
|
|
|
suffix = strrchr(name, '.'); |
|
|
|
|
if(suffix == NULL) |
|
|
|
|
suffix = ""; |
|
|
|
|
else { |
|
|
|
|
suffixLen = strlen(suffix); |
|
|
|
|
if(suffixLen > 4) { |
|
|
|
|
/* Found a full stop which isn't a suffix */ |
|
|
|
|
suffix = ""; |
|
|
|
|
suffixLen = 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
snprintf(fullname, sizeof(fullname) - 1 - suffixLen, "%s/%.*sXXXXXX", dir, |
|
|
|
|
(int)(sizeof(fullname) - 9 - suffixLen - strlen(dir)), name); |
|
|
|
|
#if defined(C_LINUX) || defined(C_BSD) || defined(HAVE_MKSTEMP) || defined(C_SOLARIS) || defined(C_CYGWIN) |
|
|
|
|
fd = mkstemp(fullname); |
|
|
|
|
#else |
|
|
|
|
(void)mktemp(fullname); |
|
|
|
|
fd = open(fullname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC|O_BINARY, 0600); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
if(fd < 0) { |
|
|
|
|
cli_errmsg("Can't create temporary file %s: %s\n", fullname, strerror(errno)); |
|
|
|
|
cli_dbgmsg("%lu %d %d\n", suffixLen, sizeof(fullname), strlen(fullname)); |
|
|
|
|
return CL_ETMPFILE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cli_dbgmsg("cli_untar: extracting %s\n", fullname); |
|
|
|
|
|
|
|
|
|
in_block = 1; |
|
|
|
|
if((outfile = fdopen(fd, "wb")) == NULL) { |
|
|
|
|
cli_errmsg("cli_untar: cannot create file %s\n", |
|
|
|
|
fullname); |
|
|
|
|
close(fd); |
|
|
|
|
return CL_ETMPFILE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
strncpy(osize, block+124, 12); |
|
|
|
|
osize[12] = '\0'; |
|
|
|
|
size = octal(osize); |
|
|
|
|
if(size < 0){ |
|
|
|
|
cli_errmsg("Invalid size in tar header\n"); |
|
|
|
|
fclose(outfile); |
|
|
|
|
return CL_EDSIG; |
|
|
|
|
} |
|
|
|
|
} else { /* write or continue writing file contents */ |
|
|
|
|
const int nbytes = size>512? 512:size; |
|
|
|
|
const int nwritten = fwrite(block, 1, nbytes, outfile); |
|
|
|
|
@ -149,5 +187,7 @@ cli_untar(const char *dir, int desc) |
|
|
|
|
in_block = 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if(outfile) |
|
|
|
|
fclose(outfile); |
|
|
|
|
return CL_CLEAN; |
|
|
|
|
} |
|
|
|
|
|