6d91b5f0 |
/*
* Copyright (C) 2004 Nigel Horne <njh@bandsman.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* |
f92f5b94 |
* Much of this code is based on minitar.c which is in the public domain. |
a0dfa4f3 |
* Author: Charles G. Waldman (cgw@pgt.com), Aug 4 1998 |
f49103d6 |
* There are many tar files that this code cannot decode. |
a0dfa4f3 |
* |
6d91b5f0 |
* Change History:
* $Log: untar.c,v $ |
255e314c |
* Revision 1.25 2005/03/22 21:26:27 kojm
* add support for old fashioned tar archives
* |
59403b26 |
* Revision 1.24 2005/03/20 18:34:18 nigelhorne
* Minor tidy
* |
65ee94da |
* Revision 1.23 2005/03/20 09:09:25 nigelhorne
* Consolidate NAME_MAX
* |
f4ff13a5 |
* Revision 1.22 2005/03/10 08:52:10 nigelhorne
* Tidy
* |
ad6b0de4 |
* Revision 1.21 2005/02/16 22:19:21 nigelhorne
* Check file close
* |
e1dce709 |
* Revision 1.20 2005/02/13 22:25:41 kojm
* do not try to continue if there's no space on device
* |
275dc42a |
* Revision 1.19 2004/12/16 15:34:57 nigelhorne
* Tidy
* |
ab537286 |
* Revision 1.18 2004/11/20 13:15:46 nigelhorne
* Better handling of false file type identification
* |
0f750119 |
* Revision 1.17 2004/10/27 06:36:38 nigelhorne
* Handle type '1' files
* |
89cf36c6 |
* Revision 1.16 2004/10/20 12:21:11 nigelhorne
* Print warning message about LongLink
* |
77880aed |
* Revision 1.15 2004/10/16 16:08:46 nigelhorne
* Handle empty files in the middle of archives
* |
f49103d6 |
* Revision 1.14 2004/10/13 10:18:54 nigelhorne
* Added a few extra file types
* |
0698fd8b |
* Revision 1.13 2004/10/04 13:46:50 nigelhorne
* Handle GNU tar files
* |
7e91785c |
* Revision 1.12 2004/10/04 10:53:15 nigelhorne
* Handle tar files less than 512 bytes
* |
5eeffbb9 |
* Revision 1.11 2004/10/01 13:50:47 nigelhorne
* Minor code tidy
* |
16b89181 |
* Revision 1.10 2004/09/20 13:37:44 kojm
* 0.80rc
* |
7d80d0c1 |
* Revision 1.9 2004/09/14 10:29:31 nigelhorne
* Fix compilation error on AIX and OSF
* |
ea54f8ca |
* Revision 1.8 2004/09/12 23:43:45 kojm
* return with CL_EFORMAT instead of CL_EDSIG
* |
b96838ed |
* Revision 1.7 2004/09/12 19:51:59 nigelhorne
* Now builds with --enable-debug
* |
03eaed11 |
* Revision 1.6 2004/09/08 16:02:34 nigelhorne
* fclose on error
* |
9f9ac4ec |
* Revision 1.5 2004/09/06 14:16:48 nigelhorne
* Added CYGWIN support
* |
4ff385dd |
* Revision 1.4 2004/09/06 08:45:44 nigelhorne
* Code Tidy
* |
f92f5b94 |
* Revision 1.3 2004/09/06 08:34:47 nigelhorne
* Randomise extracted file names from tar file
* |
a0dfa4f3 |
* Revision 1.2 2004/09/05 18:58:21 nigelhorne
* Extract files completed
* |
6d91b5f0 |
* Revision 1.1 2004/09/05 15:28:10 nigelhorne
* First draft
*
*/ |
255e314c |
static char const rcsid[] = "$Id: untar.c,v 1.25 2005/03/22 21:26:27 kojm Exp $"; |
a0dfa4f3 |
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h> |
f92f5b94 |
#include <fcntl.h> |
5eeffbb9 |
#include <sys/param.h> /* for NAME_MAX */ |
a0dfa4f3 |
#include "clamav.h"
#include "others.h" |
f92f5b94 |
#include "untar.h" |
b96838ed |
#include "mbox.h" |
f92f5b94 |
#include "blob.h" |
a0dfa4f3 |
#define BLOCKSIZE 512
|
7d80d0c1 |
#ifndef O_BINARY
#define O_BINARY 0
#endif
|
f92f5b94 |
static int
octal(const char *str) |
a0dfa4f3 |
{
int ret = -1;
|
f4ff13a5 |
(void)sscanf(str, "%o", (unsigned int *)&ret); |
a0dfa4f3 |
return ret;
}
int |
255e314c |
cli_untar(const char *dir, int desc, unsigned int posix) |
a0dfa4f3 |
{
int size = 0;
int in_block = 0; |
f92f5b94 |
char fullname[NAME_MAX + 1]; |
7e91785c |
FILE *outfile = NULL; |
a0dfa4f3 |
cli_dbgmsg("In untar(%s, %d)\n", dir ? dir : "", desc);
for(;;) {
char block[BLOCKSIZE]; |
f4ff13a5 |
const int nread = cli_readn(desc, block, (unsigned int)sizeof(block)); |
a0dfa4f3 |
if(!in_block && nread == 0)
break;
|
7e91785c |
if(nread < 0) { |
03eaed11 |
if(outfile)
fclose(outfile); |
7e91785c |
cli_errmsg("cli_untar: block read error\n"); |
a0dfa4f3 |
return CL_EIO;
}
if(!in_block) {
char type; |
4ff385dd |
const char *suffix; |
f92f5b94 |
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;
} |
a0dfa4f3 |
|
5eeffbb9 |
if(block[0] == '\0') /* We're done */ |
a0dfa4f3 |
break;
|
b96838ed |
/* Notice assumption that BLOCKSIZE > 262 */ |
255e314c |
if(posix) {
strncpy(magic, block+257, 5);
magic[5] = '\0';
if(strcmp(magic, "ustar") != 0) {
cli_dbgmsg("Incorrect magic string '%s' in tar header\n", magic);
return CL_EFORMAT;
} |
a0dfa4f3 |
}
type = block[156];
|
f49103d6 |
/*
* Extra types from djgardner@users.sourceforge.net
*/ |
a0dfa4f3 |
switch(type) { |
f49103d6 |
case '0': /* plain file */
case '\0': /* plain file */
case '7': /* contiguous file */ |
a0dfa4f3 |
directory = 0;
break; |
0f750119 |
case '1': /* Link to already archived file */ |
f49103d6 |
case '5': /* directory */
case '2': /* sym link */
case '3': /* char device */
case '4': /* block device */
case '6': /* fifo special */ |
a0dfa4f3 |
directory = 1;
break; |
89cf36c6 |
case 'L': /* GNU extension - ././@LongLink */
cli_errmsg("cli_untar: only standard TAR files are currently supported\n", type);
return CL_EFORMAT; |
a0dfa4f3 |
default: |
ab537286 |
/*cli_errmsg("cli_untar: unknown type flag %c\n", type);
return CL_EFORMAT;*/
/*
* It isn't really a tar file
*/
cli_dbgmsg("cli_untar: unknown type flag %c\n", type);
/*
* We don't know that it's clean at all,
* it would be better to have a
* CL_CONTINUE return value since it
* may be a different format
*/
return CL_CLEAN; |
a0dfa4f3 |
}
|
f49103d6 |
if(directory) {
in_block = 0; |
a0dfa4f3 |
continue; |
f49103d6 |
} |
a0dfa4f3 |
|
f92f5b94 |
strncpy(name, block, 100);
name[100] = '\0'; |
a0dfa4f3 |
|
f92f5b94 |
/*
* 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; |
a0dfa4f3 |
}
} |
f92f5b94 |
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); |
03eaed11 |
if(size < 0) { |
f92f5b94 |
cli_errmsg("Invalid size in tar header\n");
fclose(outfile); |
ea54f8ca |
return CL_EFORMAT; |
f92f5b94 |
} |
77880aed |
cli_dbgmsg("cli_untar: size = %d\n", size); |
a0dfa4f3 |
} else { /* write or continue writing file contents */
const int nbytes = size>512? 512:size; |
59403b26 |
const int nwritten = fwrite(block, 1, (size_t)nbytes, outfile); |
a0dfa4f3 |
if(nwritten != nbytes) { |
e1dce709 |
cli_errmsg("cli_untar: only wrote %d bytes to file %s (out of disk space?)\n", |
a0dfa4f3 |
nwritten, fullname); |
e1dce709 |
fclose(outfile);
return CL_EIO; |
a0dfa4f3 |
}
size -= nbytes;
} |
77880aed |
if (size == 0)
in_block = 0; |
a0dfa4f3 |
} |
f92f5b94 |
if(outfile) |
ad6b0de4 |
return fclose(outfile);
|
ea54f8ca |
return 0; |
a0dfa4f3 |
} |