Merge code from upstream libtar + bug fixes

All updates and fixes applied from upstream libtar as of
March 1, 2016.

Debug flag is disabled, however non-debug output now
provides 1 line of useful output per object extracted.

I've also merged some fixes from CyanogenMod's
fork of libtar:

From: Tom Marshall <tdm@cyngn.com>
Date: Thu, 11 Feb 2016 16:24:40 -0800
Subject: libtar: Cleanup, secure, and extend numeric fields
Commit: e18b457ea1cbf6be1adc3b75450ed1c737cd82ea

From: Tom Marshall <tdm@cyngn.com>
Date: Thu, 11 Feb 2016 12:49:30 -0800
Subject: libtar: Make file sizes 64-bit clean
Commit: e628c2025549a24018bc568351465130a05daafb

From: Tom Marshall <tdm@cyngn.com>
Date: Thu, 17 Apr 2014 09:39:25 -0700
Subject: libtar: Add methods for in-memory files
Commit: 8ec5627a8ff0a91724c6d5b344f0e887da922527

From: Tom Marshall <tdm@cyngn.com>
Date: Wed, 2 Jul 2014 09:34:40 -0700
Subject: libtar: Fix hardlink extract
Commit: 166d83a51e0c51abcea37694dbd7df92d03c1f56

From: philz-cwm6 <phytowardt@gmail.com>
Date: Sat, 26 Apr 2014 01:11:35 +0200
Subject: libtar: Various bug fixes and enhancements
Commit: a271d763e94235ccee9ecaabdb52bf4b9b2f8c06
(Some of this was not merged in, as better solutions were
available from upstream libtar)

From: Tom Marshall <tdm@cyngn.com>
Date: Wed, 9 Apr 2014 09:35:54 -0700
Subject: libtar: Add const qualifiers to reduce compile warnings
Commit: 0600afa19fe827d06d3fcf24a7aabd52dbf487b4

Change-Id: I6d008cb6fdf950f835bbed63aeb8727cc5c86083
This commit is contained in:
James Christopher Adduono
2016-03-01 16:01:53 -05:00
committed by Ethan Yonker
parent 64ffe730a6
commit 6f57f7c601
15 changed files with 897 additions and 405 deletions
+331 -11
View File
@@ -1,15 +1,335 @@
2002-12-09 added list_empty() and hash_empty() functions
NOTE:
All releases below marked (Chris Frey) are maintenance releases
done by Chris Frey, temporarily stepping in for Mark Roth.
These releases are git-based only and can be found at:
http://repo.or.cz/w/libtar.git
2002-09-12 fixed list_iterate function to return -1 if it gets
an invalid argument
Both git downloads and tarball downloads are possible at this site.
include <config.h> and <compat.h> from source files, not
from header file, since header file is sometimes
installed as part of a user-visible API
(those APIs should eventually be redesigned without the
listhash code being publicly visible, but for now we
need to accomodate this)
2002-07-07 modified list iterate function to return int
(returns -1 if plugin function returns -1)
libtar 1.2.20 - 2013/10/09 (Chris Frey)
-------------
Added extern "C" protectors to listhash.h
Added autoconf checks for __thread compiler support
Fixed size_t overflow bug, as reported by Timo Warns
Fixed thread-safe bug in th_get_pathname() (Sergey Zhitomirsky)
libtar 1.2.19 - 2012/12/11 (Chris Frey)
-------------
Removed varargs.h and all dependencies, to avoid user compile errors
Fixed some short int / int compiler warnings in va_arg() usage
Fixed some gcc built-in compiler warnings
Changed autoconf support code from AC_RUN_ to AC_COMPILE_ to fix
issues reported during cross-compiling.
Applied most of Jan Cermak's const char* function argument patch.
libtar 1.2.18 - 2012/08/02 (Chris Frey)
-------------
Added more forgiving CRC checking logic when reading tar files
Note: If your application uses the macro th_crc_ok(), then to gain full
advantage of the changes in this version, you will need to recompile
your application against the new headers. Otherwise, the library is
drop-in replaceable, as usual.
libtar 1.2.17 - 2012/07/24 (Chris Frey)
-------------
Applied Tim Band's checksum patch from mailing list (thanks!)
libtar 1.2.16 - 2012/05/17 (Chris Frey)
-------------
Fixed build system to allow for out-of-source tree builds
libtar 1.2.15 - 2012/05/10 (Chris Frey)
-------------
Chris Frey (1):
Fixed harmless buffer overflow which is caught by FORTIFY on some systems
libtar 1.2.14 - 2011/12/22 (Chris Frey)
-------------
Chris Frey (1):
Fixed truncation check, so 100 char names get GNU extension support when enabled
libtar 1.2.13 - 2011/06/13 (Chris Frey)
-------------
Chris Frey (10):
Fixed incorrect URL in readme
Added autoconf/ as macro dir
Added autogen.sh script to build a fresh configure
Renamed autoconf/aclocal.m4 to psg.m4 so aclocal isn't so confused
Removed m4 includes, and straightened out [] m4 quoting for modern autoconfs
Removed auto-generated files
Added datarootdir to Makefile.in's
Fixed header warnings
Applied Marcin Gibula's patch fixing tar_extract_glob()
Changed root Makefile.in to Makefile.am, which make autoreconf workable
Glenn McGrath (1):
Use libtool to build dynamic library
James Morrison (1):
Document stupidity of tartype_t in libtar.c.
Magnus Holmgren (1):
Escape hyphens that should be minus signs in man pages.
Per Lidén (2):
Fix memory leak in th_get_pathname
Reduce memory used by libtar when extracting files.
------------------------------------------------------------------------------
libtar 1.2.11 - 3/2/03
-------------
- updated autoconf macros, compat code, and listhash code
- fixed tar_extract_regfile() to pass mode argument to open()
(caused EPERM on Solaris NFS clients)
- updated README
------------------------------------------------------------------------------
libtar 1.2.10 - 12/15/02
-------------
- updated README
- minor Makefile fixes
- fixed TH_ISREG() macro to not return true for hard links
------------------------------------------------------------------------------
libtar 1.2.9 - 11/19/02
------------
- fixed th_read() to return 1 on EOF
(thanks to Yves Crespin <Crespin.Quartz@WANADOO.FR> for the bug report)
- minor portability fixes
(thanks to Yves Crespin <Crespin.Quartz@WANADOO.FR> for the bug report)
- fixed segfault on extracting filenames with 8-bit ASCII characters
(thanks to Per Liden <per@FUKT.BTH.SE> for the patch)
- fixed TH_ISDIR() macro and th_get_mode() function to handle old
archives that don't set the typeflag field right for directories
- use 0777 instead of 0755 in mkdirhier()
(thanks to Yves Crespin <Crespin.Quartz@WANADOO.FR> for the bug report)
------------------------------------------------------------------------------
libtar 1.2.8 - 9/13/02
------------
- added "-I../listhash" to CPPFLAGS in libtar/Makefile.in
(thanks to Kris Warkentin <kewarken@QNX.COM> for the bug report)
- added .PHONY target to Makefile.in
(thanks to Steven Engelhardt <sengelha@YAHOO.COM> for the bug report)
------------------------------------------------------------------------------
libtar 1.2.7 - 9/12/02
------------
- fixed minor bugs in listhash code
(thanks to Jim Knoble <jmknoble@pobox.com> for the bug reports)
------------------------------------------------------------------------------
libtar 1.2.6 - 9/10/02
------------
- updated COPYRIGHT file
- do not check magic field by default
(replaced TAR_IGNORE_MAGIC option with TAR_CHECK_MAGIC to enable check)
- fixed th_get_mode() not to modify S_IFMT bits if they were already set
- fixed TH_IS*() macros to check the S_IFMT mode bits in addition to typeflag
(this allows us to handle old tar archives that set mode bits but not
typeflag field for directories and other special files)
- updated to autoconf-2.53
- restructured autoconf macros
- added "b" to gzoflags in gzopen_frontend() for win32 compatibility
(thanks to Kris Eric Warkentin <kewarken@QNX.COM> for reporting this)
- if O_BINARY is defined (as on win32), set that bit in oflags in tar_open()
(thanks to Kris Eric Warkentin <kewarken@QNX.COM> for reporting this)
- also use O_BINARY in when calling open() from tar_extract_regfile()
(based on patch from Graeme Peterson <gp@qnx.com>)
- added COMPAT_FUNC_MAKEDEV macro to handle 3-arg version of makedev()
(based on patch from Graeme Peterson <gp@qnx.com>)
------------------------------------------------------------------------------
libtar 1.2.5 - 2/20/02
------------
- updated to autoconf-2.52
- improved Makefile portability
- fixed memory leak in hard-link detection code
(thanks to Michael Kamp <kamp@HITT.NL> for the bug report)
- fixed memory leak in symlink handling code
(thanks to Michael Kamp <kamp@HITT.NL> for the bug report)
- fixed memory leak in GNU long filename code
------------------------------------------------------------------------------
libtar 1.2.4 - 7/24/01
------------
- code cleanups to make gcc -Wall happy
(thanks to Jim Knoble <jmknoble@POBOX.COM> for the patch)
- call utime() before chmod() in tar_set_file_perms() for cygwin
(thanks to Kris Eric Warkentin <kewarken@QNX.COM> for reporting this)
- added "-g" flag to trigger GNU extensions in libtar binary
- fixed buffer termination bugs in POSIX filename prefix encoding
(thanks to Joerg Schilling <schilling@fokus.gmd.de> for reporting this)
- fixed bug in th_crc_calc() for filenames with 8-bit ASCII characters
(thanks to Hamdouni El Bachir <bach@zehc.net> for reporting the bug
and Antoniu-George SAVU <santoniu@libertysurf.fr> for the patch)
- fixed backwards conditional expression in th_read()
(thanks to Antoniu-George SAVU <santoniu@LIBERTYSURF.FR> for the patch)
- added new tar_open() options to replace compile-time settings:
TAR_IGNORE_EOT, TAR_IGNORE_MAGIC, TAR_CHECK_VERSION, TAR_IGNORE_CRC
(based on feedback from Kris Eric Warkentin <kewarken@QNX.COM>)
------------------------------------------------------------------------------
libtar 1.2.3 - 6/26/01
------------
- misc portability fixes for OpenBSD
- fixed libtar.h to work with C++ programs
- fixed tar_extract_file() to properly check for pre-existing symlinks
(based on patch from Per Lid?n <per@fukt.hk-r.se>)
- fixed hash creation in tar_init()
- replaced mkdirhier() with non-recursive version
- updated autoconf macros, compat code, and listhash code
- reformatted code for readability
------------------------------------------------------------------------------
libtar 1.2.2 - 1/12/01
------------
- fixed th_print_long_ls() to not truncate user and group names
- code cleanups to make -Wall happy
------------------------------------------------------------------------------
libtar 1.2.1 - 1/8/01
------------
- updated WSG_ENCAP autoconf macro
- fixed autoconf macros to behave properly when a config.cache file
is present
- fixed doc/Makefile.in to create links during compilation, not
installation
- fixed listhash manpage .so link lists
------------------------------------------------------------------------------
libtar 1.2 - 1/4/01
----------
- minor code cleanups
------------------------------------------------------------------------------
libtar 1.1.b8 - 1/2/01
-------------
- updated WSG_ENCAP autoconf macro
------------------------------------------------------------------------------
libtar 1.1.b7 - 12/13/00
-------------
- fixed autoconf snprintf() test to make sure it NUL-terminates
------------------------------------------------------------------------------
libtar 1.1.b6 - 11/30/00
-------------
- added $(DESTDIR) to Makefiles
- Makefile changes to support WSG_PKG and WSG_ENCAP autoconf macros
- changed lib/output.c to use strftime() where available
------------------------------------------------------------------------------
libtar 1.1.b5 - 10/29/00
-------------
- Makefile fix
------------------------------------------------------------------------------
libtar 1.1.b4 - 10/29/00
-------------
- more directory reorganization
- minor Makefile cleanups
- minor portability fixes
- added function typecasting to avoid compiler warnings
------------------------------------------------------------------------------
libtar 1.1.b3 - 10/26/00
-------------
- updated aclocal.m4
- updated README
- updated manpages
- minor directory structure changes because of CVS setup
------------------------------------------------------------------------------
libtar 1.1.b2 - 10/5/00
-------------
- added --without-zlib configure option
- minor portability fixes
------------------------------------------------------------------------------
libtar 1.1.b1 - 8/21/00
-------------
- API changes:
- implemented tar_fdopen()
- implemented tar_fd()
- added TAR **t argument to tar_open() instead of returning dynamic memory
- if TAR_NOOVERWRITE is set in options and O_CREAT is set in oflags,
tar_open() automatically sets O_EXCL as well
------------------------------------------------------------------------------
libtar 1.1.b0 - 7/10/00
-------------
- API changes:
- replaced internal table of tar file types with a tartype_t passed to
tar_open() by the caller
(allows file access methods to be defined dynamically)
- fixed tar_append_tree() to grok normal files as well as directories
- replaced mk_dirs_for_file() with mkdirhier() from epkg
- replaced strtok_r() with strsep()
- updated list/hash code to new interface
- autoconf changes:
- added aclocal.m4 to clean up configure.in
- minor portability fixes related to lib/fnmatch.c
- fixed a bug in tar_open() where the result of open() was being
checked for 0 instead of -1 to detect error
- updated libtar driver program to handle both .tar.gz and ordinary .tar
via the -z option
+95 -21
View File
@@ -13,8 +13,11 @@
#include <internal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <sys/param.h>
#include <sys/types.h>
@@ -28,7 +31,7 @@
#endif
#ifdef HAVE_SELINUX
#include "selinux/selinux.h"
# include "selinux/selinux.h"
#endif
struct tar_dev
@@ -57,7 +60,7 @@ tar_dev_free(tar_dev_t *tdp)
/* appends a file to the tar archive */
int
tar_append_file(TAR *t, char *realname, char *savename)
tar_append_file(TAR *t, const char *realname, const char *savename)
{
struct stat s;
int i;
@@ -82,38 +85,46 @@ tar_append_file(TAR *t, char *realname, char *savename)
/* set header block */
#ifdef DEBUG
puts(" tar_append_file(): setting header block...");
puts("tar_append_file(): setting header block...");
#endif
memset(&(t->th_buf), 0, sizeof(struct tar_header));
th_set_from_stat(t, &s);
/* set the header path */
#ifdef DEBUG
puts(" tar_append_file(): setting header path...");
puts("tar_append_file(): setting header path...");
#endif
th_set_path(t, (savename ? savename : realname));
#ifdef HAVE_SELINUX
/* get selinux context */
if(t->options & TAR_STORE_SELINUX) {
if(t->th_buf.selinux_context != NULL) {
if (t->options & TAR_STORE_SELINUX)
{
if (t->th_buf.selinux_context != NULL)
{
free(t->th_buf.selinux_context);
t->th_buf.selinux_context = NULL;
}
security_context_t selinux_context = NULL;
if (lgetfilecon(realname, &selinux_context) >= 0) {
if (lgetfilecon(realname, &selinux_context) >= 0)
{
t->th_buf.selinux_context = strdup(selinux_context);
printf("setting selinux context: %s\n", selinux_context);
printf(" ==> set selinux context: %s\n", selinux_context);
freecon(selinux_context);
}
else
{
#ifdef DEBUG
perror("Failed to get selinux context");
#endif
}
}
#endif
/* check if it's a hardlink */
#ifdef DEBUG
puts(" tar_append_file(): checking inode cache for hardlink...");
puts("tar_append_file(): checking inode cache for hardlink...");
#endif
libtar_hashptr_reset(&hp);
if (libtar_hash_getkey(t->h, &hp, &(s.st_dev),
@@ -171,7 +182,7 @@ tar_append_file(TAR *t, char *realname, char *savename)
i = MAXPATHLEN - 1;
path[i] = '\0';
#ifdef DEBUG
printf(" tar_append_file(): encoding symlink \"%s\" -> "
printf("tar_append_file(): encoding symlink \"%s\" -> "
"\"%s\"...\n", realname, path);
#endif
th_set_link(t, path);
@@ -179,10 +190,10 @@ tar_append_file(TAR *t, char *realname, char *savename)
/* print file info */
if (t->options & TAR_VERBOSE)
th_print_long_ls(t);
printf("%s\n", th_get_pathname(t));
#ifdef DEBUG
puts(" tar_append_file(): writing header");
puts("tar_append_file(): writing header");
#endif
/* write header */
if (th_write(t) != 0)
@@ -193,7 +204,7 @@ tar_append_file(TAR *t, char *realname, char *savename)
return -1;
}
#ifdef DEBUG
puts(" tar_append_file(): back from th_write()");
puts("tar_append_file(): back from th_write()");
#endif
/* if it's a regular file, write the contents as well */
@@ -229,14 +240,19 @@ tar_append_eof(TAR *t)
/* add file contents to a tarchive */
int
tar_append_regfile(TAR *t, char *realname)
tar_append_regfile(TAR *t, const char *realname)
{
char block[T_BLOCKSIZE];
int filefd;
int j;
size_t size, i;
int64_t i, size;
ssize_t j;
int rv = -1;
#if defined(O_BINARY)
filefd = open(realname, O_RDONLY|O_BINARY);
#else
filefd = open(realname, O_RDONLY);
#endif
if (filefd == -1)
{
#ifdef DEBUG
@@ -253,25 +269,83 @@ tar_append_regfile(TAR *t, char *realname)
{
if (j != -1)
errno = EINVAL;
return -1;
goto fail;
}
if (tar_block_write(t, &block) == -1)
return -1;
goto fail;
}
if (i > 0)
{
j = read(filefd, &block, i);
if (j == -1)
goto fail;
memset(&(block[i]), 0, T_BLOCKSIZE - i);
if (tar_block_write(t, &block) == -1)
goto fail;
}
/* success! */
rv = 0;
fail:
close(filefd);
return rv;
}
/* add file contents to a tarchive */
int
tar_append_file_contents(TAR *t, const char *savename, mode_t mode,
uid_t uid, gid_t gid, void *buf, size_t len)
{
struct stat st;
memset(&st, 0, sizeof(st));
st.st_mode = S_IFREG | mode;
st.st_uid = uid;
st.st_gid = gid;
st.st_mtime = time(NULL);
st.st_size = len;
th_set_from_stat(t, &st);
th_set_path(t, savename);
/* write header */
if (th_write(t) != 0)
{
#ifdef DEBUG
fprintf(stderr, "tar_append_file_contents(): could not write header, t->fd = %d\n", t->fd);
#endif
return -1;
}
return tar_append_buffer(t, buf, len);
}
int
tar_append_buffer(TAR *t, void *buf, size_t len)
{
char block[T_BLOCKSIZE];
int filefd;
int i, j;
size_t size = len;
for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
{
if (tar_block_write(t, buf) == -1)
return -1;
buf = (char *)buf + T_BLOCKSIZE;
}
if (i > 0)
{
memcpy(block, buf, i);
memset(&(block[i]), 0, T_BLOCKSIZE - i);
if (tar_block_write(t, &block) == -1)
return -1;
}
close(filefd);
return 0;
}
+1 -1
View File
@@ -64,7 +64,7 @@ openbsd_basename(path)
while (startp > path && *(startp - 1) != '/')
startp--;
if (endp - startp + 1 > sizeof(bname)) {
if (endp - startp + 1 > (int)sizeof(bname)) {
errno = ENAMETOOLONG;
return(NULL);
}
+37 -52
View File
@@ -11,7 +11,6 @@
*/
#include <internal.h>
#include <stdio.h>
#include <errno.h>
#ifdef STDC_HEADERS
@@ -27,6 +26,17 @@
#define SELINUX_TAG_LEN 21
/* read a header block */
/* FIXME: the return value of this function should match the return value
of tar_block_read(), which is a macro which references a prototype
that returns a ssize_t. So far, this is safe, since tar_block_read()
only ever reads 512 (T_BLOCKSIZE) bytes at a time, so any difference
in size of ssize_t and int is of negligible risk. BUT, if
T_BLOCKSIZE ever changes, or ever becomes a variable parameter
controllable by the user, all the code that calls it,
including this function and all code that calls it, should be
fixed for security reasons.
Thanks to Chris Palmer for the critique.
*/
int
th_read_internal(TAR *t)
{
@@ -93,8 +103,8 @@ th_read_internal(TAR *t)
int
th_read(TAR *t)
{
int i, j;
size_t sz;
int i;
size_t sz, j, blocks;
char *ptr;
#ifdef DEBUG
@@ -126,21 +136,26 @@ th_read(TAR *t)
if (TH_ISLONGLINK(t))
{
sz = th_get_size(t);
j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
blocks = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
if (blocks > ((size_t)-1 / T_BLOCKSIZE))
{
errno = E2BIG;
return -1;
}
#ifdef DEBUG
printf(" th_read(): GNU long linkname detected "
"(%ld bytes, %d blocks)\n", sz, j);
"(%ld bytes, %d blocks)\n", sz, blocks);
#endif
t->th_buf.gnu_longlink = (char *)malloc(j * T_BLOCKSIZE);
t->th_buf.gnu_longlink = (char *)malloc(blocks * T_BLOCKSIZE);
if (t->th_buf.gnu_longlink == NULL)
return -1;
for (ptr = t->th_buf.gnu_longlink; j > 0;
j--, ptr += T_BLOCKSIZE)
for (j = 0, ptr = t->th_buf.gnu_longlink; j < blocks;
j++, ptr += T_BLOCKSIZE)
{
#ifdef DEBUG
printf(" th_read(): reading long linkname "
"(%d blocks left, ptr == %ld)\n", j, ptr);
"(%d blocks left, ptr == %ld)\n", blocks-j, ptr);
#endif
i = tar_block_read(t, ptr);
if (i != T_BLOCKSIZE)
@@ -171,21 +186,26 @@ th_read(TAR *t)
if (TH_ISLONGNAME(t))
{
sz = th_get_size(t);
j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
blocks = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
if (blocks > ((size_t)-1 / T_BLOCKSIZE))
{
errno = E2BIG;
return -1;
}
#ifdef DEBUG
printf(" th_read(): GNU long filename detected "
"(%ld bytes, %d blocks)\n", sz, j);
"(%ld bytes, %d blocks)\n", sz, blocks);
#endif
t->th_buf.gnu_longname = (char *)malloc(j * T_BLOCKSIZE);
t->th_buf.gnu_longname = (char *)malloc(blocks * T_BLOCKSIZE);
if (t->th_buf.gnu_longname == NULL)
return -1;
for (ptr = t->th_buf.gnu_longname; j > 0;
j--, ptr += T_BLOCKSIZE)
for (j = 0, ptr = t->th_buf.gnu_longname; j < blocks;
j++, ptr += T_BLOCKSIZE)
{
#ifdef DEBUG
printf(" th_read(): reading long filename "
"(%d blocks left, ptr == %ld)\n", j, ptr);
"(%d blocks left, ptr == %ld)\n", blocks-j, ptr);
#endif
i = tar_block_read(t, ptr);
if (i != T_BLOCKSIZE)
@@ -263,41 +283,6 @@ th_read(TAR *t)
}
#endif
#if 0
/*
** work-around for old archive files with broken typeflag fields
** NOTE: I fixed this in the TH_IS*() macros instead
*/
/*
** (directories are signified with a trailing '/')
*/
if (t->th_buf.typeflag == AREGTYPE
&& t->th_buf.name[strlen(t->th_buf.name) - 1] == '/')
t->th_buf.typeflag = DIRTYPE;
/*
** fallback to using mode bits
*/
if (t->th_buf.typeflag == AREGTYPE)
{
mode = (mode_t)oct_to_int(t->th_buf.mode);
if (S_ISREG(mode))
t->th_buf.typeflag = REGTYPE;
else if (S_ISDIR(mode))
t->th_buf.typeflag = DIRTYPE;
else if (S_ISFIFO(mode))
t->th_buf.typeflag = FIFOTYPE;
else if (S_ISCHR(mode))
t->th_buf.typeflag = CHRTYPE;
else if (S_ISBLK(mode))
t->th_buf.typeflag = BLKTYPE;
else if (S_ISLNK(mode))
t->th_buf.typeflag = SYMTYPE;
}
#endif
return 0;
}
@@ -308,7 +293,7 @@ th_write(TAR *t)
{
int i, j;
char type2;
size_t sz, sz2;
uint64_t sz, sz2;
char *ptr;
char buf[T_BLOCKSIZE];
@@ -457,7 +442,7 @@ th_write(TAR *t)
}
memset(buf, 0, T_BLOCKSIZE);
snprintf(buf, T_BLOCKSIZE, "%d "SELINUX_TAG"%s\n", sz, t->th_buf.selinux_context);
snprintf(buf, T_BLOCKSIZE, "%d "SELINUX_TAG"%s\n", (int)sz, t->th_buf.selinux_context);
i = tar_block_write(t, &buf);
if (i != T_BLOCKSIZE)
{
-4
View File
@@ -12,10 +12,6 @@
# include <libgen.h>
#endif
#ifdef HAVE_SELINUX
#include "selinux/selinux.h"
#endif
#if defined(NEED_BASENAME) && !defined(HAVE_BASENAME)
+32 -19
View File
@@ -13,6 +13,7 @@
#include <internal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/param.h>
#include <pwd.h>
#include <grp.h>
@@ -26,22 +27,30 @@
char *
th_get_pathname(TAR *t)
{
char filename[MAXPATHLEN];
if (t->th_buf.gnu_longname) {
printf("returning gnu longname\n");
if (t->th_buf.gnu_longname)
return t->th_buf.gnu_longname;
}
if (t->th_buf.prefix[0] != '\0')
/* allocate the th_pathname buffer if not already */
if (t->th_pathname == NULL)
{
snprintf(filename, sizeof(filename), "%.155s/%.100s",
t->th_buf.prefix, t->th_buf.name);
return strdup(filename);
t->th_pathname = malloc(MAXPATHLEN * sizeof(char));
if (t->th_pathname == NULL)
/* out of memory */
return NULL;
}
snprintf(filename, sizeof(filename), "%.100s", t->th_buf.name);
return strdup(filename);
if (t->th_buf.prefix[0] == '\0')
{
snprintf(t->th_pathname, MAXPATHLEN, "%.100s", t->th_buf.name);
}
else
{
snprintf(t->th_pathname, MAXPATHLEN, "%.155s/%.100s",
t->th_buf.prefix, t->th_buf.name);
}
/* will be deallocated in tar_close() */
return t->th_pathname;
}
@@ -51,9 +60,11 @@ th_get_uid(TAR *t)
int uid;
struct passwd *pw;
pw = getpwnam(t->th_buf.uname);
if (pw != NULL)
return pw->pw_uid;
if (!(t->options & TAR_USE_NUMERIC_ID)) {
pw = getpwnam(t->th_buf.uname);
if (pw != NULL)
return pw->pw_uid;
}
/* if the password entry doesn't exist */
sscanf(t->th_buf.uid, "%o", &uid);
@@ -67,9 +78,11 @@ th_get_gid(TAR *t)
int gid;
struct group *gr;
gr = getgrnam(t->th_buf.gname);
if (gr != NULL)
return gr->gr_gid;
if (!(t->options & TAR_USE_NUMERIC_ID)) {
gr = getgrnam(t->th_buf.gname);
if (gr != NULL)
return gr->gr_gid;
}
/* if the group entry doesn't exist */
sscanf(t->th_buf.gid, "%o", &gid);
@@ -82,7 +95,7 @@ th_get_mode(TAR *t)
{
mode_t mode;
mode = (mode_t)oct_to_int(t->th_buf.mode);
mode = (mode_t)oct_to_int(t->th_buf.mode, sizeof(t->th_buf.mode));
if (! (mode & S_IFMT))
{
switch (t->th_buf.typeflag)
@@ -103,7 +116,7 @@ th_get_mode(TAR *t)
mode |= S_IFIFO;
break;
case AREGTYPE:
if (t->th_buf.name[strlen(t->th_buf.name) - 1] == '/')
if (t->th_buf.name[strnlen(t->th_buf.name, T_NAMELEN) - 1] == '/')
{
mode |= S_IFDIR;
break;
+1 -1
View File
@@ -67,7 +67,7 @@ openbsd_dirname(path)
} while (endp > path && *endp == '/');
}
if (endp - path + 1 > sizeof(bname)) {
if (endp - path + 1 > (int)sizeof(bname)) {
errno = ENAMETOOLONG;
return(NULL);
}
+54 -29
View File
@@ -68,10 +68,11 @@ th_set_type(TAR *t, mode_t mode)
/* encode file path */
void
th_set_path(TAR *t, char *pathname)
th_set_path(TAR *t, const char *pathname)
{
char suffix[2] = "";
char *tmp;
size_t pathname_len = strlen(pathname);
#ifdef DEBUG
printf("in th_set_path(th, pathname=\"%s\")\n", pathname);
@@ -81,32 +82,49 @@ th_set_path(TAR *t, char *pathname)
free(t->th_buf.gnu_longname);
t->th_buf.gnu_longname = NULL;
if (pathname[strlen(pathname) - 1] != '/' && TH_ISDIR(t))
/* old archive compatibility (not needed for gnu): add trailing / to directories */
if (pathname[pathname_len - 1] != '/' && TH_ISDIR(t))
strcpy(suffix, "/");
if (strlen(pathname) > T_NAMELEN-1 && (t->options & TAR_GNU))
if (pathname_len >= T_NAMELEN && (t->options & TAR_GNU))
{
/* GNU-style long name */
/* GNU-style long name (no file name length limit) */
t->th_buf.gnu_longname = strdup(pathname);
strncpy(t->th_buf.name, t->th_buf.gnu_longname, T_NAMELEN);
}
else if (strlen(pathname) > T_NAMELEN)
else if (pathname_len >= T_NAMELEN)
{
/* POSIX-style prefix field */
tmp = strchr(&(pathname[strlen(pathname) - T_NAMELEN - 1]), '/');
/* POSIX-style prefix field:
* The maximum length of a file name is limited to 256 characters,
* provided that the file name can be split at a directory separator
* in two parts. The first part being at most 155 bytes long and
* the second part being at most 100 bytes long. So, in most cases
* the maximum file name length will be shorter than 256 characters.
*/
char tail_path[T_NAMELEN + 1];
tmp = strchr(&(pathname[pathname_len - T_NAMELEN]), '/');
if (tmp == NULL)
{
printf("!!! '/' not found in \"%s\"\n", pathname);
return;
}
snprintf(t->th_buf.name, 100, "%s%s", &(tmp[1]), suffix);
snprintf(t->th_buf.prefix,
((tmp - pathname + 1) <
155 ? (tmp - pathname + 1) : 155), "%s", pathname);
snprintf(tail_path, T_NAMELEN + 1, "%s%s", &tmp[1], suffix);
strncpy(t->th_buf.name, tail_path, T_NAMELEN);
/*
* first part, max = 155 == sizeof(t->th_buf.prefix) , include NULL if it fits
* trailing '/' is added during decode: decode.c/th_get_pathname()
*/
if (tmp - pathname >= 155) {
strncpy(t->th_buf.prefix, pathname, 155);
} else {
snprintf(t->th_buf.prefix, (tmp - pathname + 1), "%s", pathname);
}
}
else {
/* any short name for all formats, or classic tar format (99 chars max) */
snprintf(t->th_buf.name, T_NAMELEN, "%s%s", pathname, suffix);
}
else
/* classic tar format */
snprintf(t->th_buf.name, 100, "%s%s", pathname, suffix);
#ifdef DEBUG
puts("returning from th_set_path()...");
@@ -116,23 +134,28 @@ th_set_path(TAR *t, char *pathname)
/* encode link path */
void
th_set_link(TAR *t, char *linkname)
th_set_link(TAR *t, const char *linkname)
{
#ifdef DEBUG
printf("==> th_set_link(th, linkname=\"%s\")\n", linkname);
#endif
if (strlen(linkname) > T_NAMELEN-1 && (t->options & TAR_GNU))
if (strlen(linkname) >= T_NAMELEN && (t->options & TAR_GNU))
{
/* GNU longlink format */
/* --format=gnu: GNU-style long name (no file name length limit) */
t->th_buf.gnu_longlink = strdup(linkname);
strcpy(t->th_buf.linkname, "././@LongLink");
}
else
else if (strlen(linkname) >= T_NAMELEN)
{
/* classic tar format */
strlcpy(t->th_buf.linkname, linkname,
sizeof(t->th_buf.linkname));
/* --format=ustar: 100 chars max limit for symbolic links */
strncpy(t->th_buf.linkname, linkname, T_NAMELEN);
if (t->th_buf.gnu_longlink != NULL)
free(t->th_buf.gnu_longlink);
t->th_buf.gnu_longlink = NULL;
} else {
/* all short links or v7 tar format: The maximum length of a symbolic link name is limited to 99 characters */
snprintf(t->th_buf.linkname, T_NAMELEN, "%s", linkname);
if (t->th_buf.gnu_longlink != NULL)
free(t->th_buf.gnu_longlink);
t->th_buf.gnu_longlink = NULL;
@@ -159,9 +182,11 @@ th_set_user(TAR *t, uid_t uid)
{
struct passwd *pw;
pw = getpwuid(uid);
if (pw != NULL)
strlcpy(t->th_buf.uname, pw->pw_name, sizeof(t->th_buf.uname));
if (!(t->options & TAR_USE_NUMERIC_ID)) {
pw = getpwuid(uid);
if (pw != NULL)
strlcpy(t->th_buf.uname, pw->pw_name, sizeof(t->th_buf.uname));
}
int_to_oct(uid, t->th_buf.uid, 8);
}
@@ -173,9 +198,11 @@ th_set_group(TAR *t, gid_t gid)
{
struct group *gr;
gr = getgrgid(gid);
if (gr != NULL)
strlcpy(t->th_buf.gname, gr->gr_name, sizeof(t->th_buf.gname));
if (!(t->options & TAR_USE_NUMERIC_ID)) {
gr = getgrgid(gid);
if (gr != NULL)
strlcpy(t->th_buf.gname, gr->gr_name, sizeof(t->th_buf.gname));
}
int_to_oct(gid, t->th_buf.gid, 8);
}
@@ -209,5 +236,3 @@ th_set_from_stat(TAR *t, struct stat *s)
else
th_set_size(t, 0);
}
+171 -140
View File
@@ -13,14 +13,13 @@
#include <internal.h>
#include <stdio.h>
#include <string.h>
#include <sys/param.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <utime.h>
#include <string.h>
#define DEBUG
#ifdef STDC_HEADERS
# include <stdlib.h>
#endif
@@ -29,26 +28,30 @@
# include <unistd.h>
#endif
#define DEBUG
#ifdef HAVE_SELINUX
# include "selinux/selinux.h"
#endif
static int
tar_set_file_perms(TAR *t, char *realname)
tar_set_file_perms(TAR *t, const char *realname)
{
mode_t mode;
uid_t uid;
gid_t gid;
struct utimbuf ut;
char *filename;
const char *filename;
char *pn;
filename = (realname ? realname : th_get_pathname(t));
pn = th_get_pathname(t);
filename = (realname ? realname : pn);
mode = th_get_mode(t);
uid = th_get_uid(t);
gid = th_get_gid(t);
ut.modtime = ut.actime = th_get_mtime(t);
#ifdef DEBUG
printf(" ==> setting perms: %s (mode %04o, uid %d, gid %d)\n",
filename, mode, uid, gid);
printf("tar_set_file_perms(): setting perms: %s (mode %04o, uid %d, gid %d)\n",
filename, mode, uid, gid);
#endif
/* change owner/group */
@@ -95,12 +98,15 @@ tar_set_file_perms(TAR *t, char *realname)
/* switchboard */
int
tar_extract_file(TAR *t, char *realname, char *prefix, const int *progress_fd)
tar_extract_file(TAR *t, const char *realname, const char *prefix, const int *progress_fd)
{
int i;
#ifdef LIBTAR_FILE_HASH
char *lnp;
char *pn;
int pathname_len;
int realname_len;
#endif
if (t->options & TAR_NOOVERWRITE)
{
@@ -115,44 +121,31 @@ tar_extract_file(TAR *t, char *realname, char *prefix, const int *progress_fd)
if (TH_ISDIR(t))
{
printf("dir\n");
i = tar_extract_dir(t, realname);
if (i == 1)
i = 0;
}
else if (TH_ISLNK(t)) {
printf("link\n");
else if (TH_ISLNK(t))
i = tar_extract_hardlink(t, realname, prefix);
}
else if (TH_ISSYM(t)) {
printf("sym\n");
else if (TH_ISSYM(t))
i = tar_extract_symlink(t, realname);
}
else if (TH_ISCHR(t)) {
printf("chr\n");
else if (TH_ISCHR(t))
i = tar_extract_chardev(t, realname);
}
else if (TH_ISBLK(t)) {
printf("blk\n");
else if (TH_ISBLK(t))
i = tar_extract_blockdev(t, realname);
}
else if (TH_ISFIFO(t)) {
printf("fifo\n");
else if (TH_ISFIFO(t))
i = tar_extract_fifo(t, realname);
}
else /* if (TH_ISREG(t)) */ {
printf("reg\n");
else /* if (TH_ISREG(t)) */
i = tar_extract_regfile(t, realname, progress_fd);
}
if (i != 0) {
printf("FAILED RESTORE OF FILE i: %s\n", realname);
fprintf(stderr, "tar_extract_file(): failed to extract %s !!!\n", realname);
return i;
}
i = tar_set_file_perms(t, realname);
if (i != 0) {
printf("FAILED SETTING PERMS: %d\n", i);
fprintf(stderr, "tar_extract_file(): failed to set permissions on %s !!!\n", realname);
return i;
}
@@ -160,51 +153,48 @@ tar_extract_file(TAR *t, char *realname, char *prefix, const int *progress_fd)
if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL)
{
#ifdef DEBUG
printf(" Restoring SELinux context %s to file %s\n", t->th_buf.selinux_context, realname);
printf("tar_extract_file(): restoring SELinux context %s to file %s\n", t->th_buf.selinux_context, realname);
#endif
if (lsetfilecon(realname, t->th_buf.selinux_context) < 0) {
fprintf(stderr, "Failed to restore SELinux context %s!\n", strerror(errno));
}
if (lsetfilecon(realname, t->th_buf.selinux_context) < 0)
fprintf(stderr, "tar_extract_file(): failed to restore SELinux context %s to file %s !!!\n", t->th_buf.selinux_context, realname);
}
#endif
/*
pathname_len = strlen(th_get_pathname(t)) + 1;
#ifdef LIBTAR_FILE_HASH
pn = th_get_pathname(t);
pathname_len = strlen(pn) + 1;
realname_len = strlen(realname) + 1;
lnp = (char *)calloc(1, pathname_len + realname_len);
if (lnp == NULL)
return -1;
strcpy(&lnp[0], th_get_pathname(t));
strcpy(&lnp[0], pn);
strcpy(&lnp[pathname_len], realname);
#ifdef DEBUG
printf("tar_extract_file(): calling libtar_hash_add(): key=\"%s\", "
"value=\"%s\"\n", th_get_pathname(t), realname);
"value=\"%s\"\n", pn, realname);
#endif
if (libtar_hash_add(t->h, lnp) != 0)
return -1;
free(lnp);
*/
#endif
return 0;
}
/* extract regular file */
int
tar_extract_regfile(TAR *t, char *realname, const int *progress_fd)
tar_extract_regfile(TAR *t, const char *realname, const int *progress_fd)
{
//mode_t mode;
size_t size, i;
//uid_t uid;
//gid_t gid;
int64_t size, i;
ssize_t k;
int fdout;
int k;
char buf[T_BLOCKSIZE];
char *filename;
const char *filename;
char *pn;
fflush(NULL);
#ifdef DEBUG
printf("==> tar_extract_regfile(t=0x%lx, realname=\"%s\")\n", t,
realname);
printf(" ==> tar_extract_regfile(realname=\"%s\")\n", realname);
#endif
if (!TH_ISREG(t))
@@ -213,21 +203,16 @@ tar_extract_regfile(TAR *t, char *realname, const int *progress_fd)
return -1;
}
filename = (realname ? realname : th_get_pathname(t));
//mode = th_get_mode(t);
pn = th_get_pathname(t);
filename = (realname ? realname : pn);
size = th_get_size(t);
//uid = th_get_uid(t);
//gid = th_get_gid(t);
if (mkdirhier(dirname(filename)) == -1)
return -1;
#ifdef DEBUG
//printf(" ==> extracting: %s (mode %04o, uid %d, gid %d, %d bytes)\n",
// filename, mode, uid, gid, size);
printf(" ==> extracting: %s (file size %d bytes)\n",
filename, size);
#endif
printf(" ==> extracting: %s (file size %lld bytes)\n",
filename, size);
fdout = open(filename, O_WRONLY | O_CREAT | O_TRUNC
#ifdef O_BINARY
| O_BINARY
@@ -241,41 +226,25 @@ tar_extract_regfile(TAR *t, char *realname, const int *progress_fd)
return -1;
}
#if 0
/* change the owner. (will only work if run as root) */
if (fchown(fdout, uid, gid) == -1 && errno != EPERM)
{
#ifdef DEBUG
perror("fchown()");
#endif
return -1;
}
/* make sure the mode isn't inheritted from a file we're overwriting */
if (fchmod(fdout, mode & 07777) == -1)
{
#ifdef DEBUG
perror("fchmod()");
#endif
return -1;
}
#endif
/* extract the file */
for (i = size; i > 0; i -= tar_min(i, T_BLOCKSIZE))
for (i = size; i > 0; i -= T_BLOCKSIZE)
{
k = tar_block_read(t, buf);
if (k != T_BLOCKSIZE)
{
if (k != -1)
errno = EINVAL;
close(fdout);
return -1;
}
/* write block to output file */
if (write(fdout, buf,
((i > T_BLOCKSIZE) ? T_BLOCKSIZE : i)) == -1)
{
close(fdout);
return -1;
}
}
/* close output file */
@@ -286,7 +255,8 @@ tar_extract_regfile(TAR *t, char *realname, const int *progress_fd)
printf("### done extracting %s\n", filename);
#endif
if (*progress_fd != 0) {
if (*progress_fd != 0)
{
unsigned long long file_size = (unsigned long long)(size);
write(*progress_fd, &file_size, sizeof(file_size));
}
@@ -299,8 +269,8 @@ tar_extract_regfile(TAR *t, char *realname, const int *progress_fd)
int
tar_skip_regfile(TAR *t)
{
int k;
size_t size, i;
int64_t size, i;
ssize_t k;
char buf[T_BLOCKSIZE];
if (!TH_ISREG(t))
@@ -310,7 +280,7 @@ tar_skip_regfile(TAR *t)
}
size = th_get_size(t);
for (i = size; i > 0; i -= tar_min(i, T_BLOCKSIZE))
for (i = size; i > 0; i -= T_BLOCKSIZE)
{
k = tar_block_read(t, buf);
if (k != T_BLOCKSIZE)
@@ -327,10 +297,12 @@ tar_skip_regfile(TAR *t)
/* hardlink */
int
tar_extract_hardlink(TAR * t, char *realname, char *prefix)
tar_extract_hardlink(TAR * t, const char *realname, const char *prefix)
{
char *filename;
const char *filename;
char *pn;
char *linktgt = NULL;
char *newtgt = NULL;
char *lnp;
libtar_hashptr_t hp;
@@ -340,9 +312,12 @@ tar_extract_hardlink(TAR * t, char *realname, char *prefix)
return -1;
}
filename = (realname ? realname : th_get_pathname(t));
pn = th_get_pathname(t);
filename = (realname ? realname : pn);
if (mkdirhier(dirname(filename)) == -1)
return -1;
if (unlink(filename) == -1 && errno != ENOENT)
return -1;
libtar_hashptr_reset(&hp);
if (libtar_hash_getkey(t->h, &hp, th_get_linkname(t),
(libtar_matchfunc_t)libtar_str_match) != 0)
@@ -352,17 +327,15 @@ tar_extract_hardlink(TAR * t, char *realname, char *prefix)
}
else
linktgt = th_get_linkname(t);
char *newtgt = strdup(linktgt);
newtgt = strdup(linktgt);
sprintf(linktgt, "%s/%s", prefix, newtgt);
#ifdef DEBUG
printf(" ==> extracting: %s (link to %s)\n", filename, linktgt);
#endif
if (link(linktgt, filename) == -1)
{
#ifdef DEBUG
perror("link()");
#endif
printf("Failed restore of hardlink '%s' but returning as if nothing bad happened anyway\n", filename);
fprintf(stderr, "tar_extract_hardlink(): failed restore of hardlink '%s' but returning as if nothing bad happened\n", filename);
return 0; // Used to be -1
}
@@ -372,33 +345,28 @@ tar_extract_hardlink(TAR * t, char *realname, char *prefix)
/* symlink */
int
tar_extract_symlink(TAR *t, char *realname)
tar_extract_symlink(TAR *t, const char *realname)
{
char *filename;
const char *filename;
char *pn;
if (!TH_ISSYM(t))
{
printf("not a sym\n");
errno = EINVAL;
return -1;
}
filename = (realname ? realname : th_get_pathname(t));
printf("file: %s\n", filename);
if (mkdirhier(dirname(filename)) == -1) {
printf("mkdirhier\n");
pn = th_get_pathname(t);
filename = (realname ? realname : pn);
if (mkdirhier(dirname(filename)) == -1)
return -1;
}
if (unlink(filename) == -1 && errno != ENOENT) {
printf("unlink\n");
if (unlink(filename) == -1 && errno != ENOENT)
return -1;
}
#ifdef DEBUG
printf(" ==> extracting: %s (symlink to %s)\n",
filename, th_get_linkname(t));
#endif
if (symlink(th_get_linkname(t), filename) == -1)
{
#ifdef DEBUG
@@ -413,11 +381,12 @@ tar_extract_symlink(TAR *t, char *realname)
/* character device */
int
tar_extract_chardev(TAR *t, char *realname)
tar_extract_chardev(TAR *t, const char *realname)
{
mode_t mode;
unsigned long devmaj, devmin;
char *filename;
const char *filename;
char *pn;
if (!TH_ISCHR(t))
{
@@ -425,7 +394,8 @@ tar_extract_chardev(TAR *t, char *realname)
return -1;
}
filename = (realname ? realname : th_get_pathname(t));
pn = th_get_pathname(t);
filename = (realname ? realname : pn);
mode = th_get_mode(t);
devmaj = th_get_devmajor(t);
devmin = th_get_devminor(t);
@@ -433,17 +403,14 @@ tar_extract_chardev(TAR *t, char *realname)
if (mkdirhier(dirname(filename)) == -1)
return -1;
#ifdef DEBUG
printf(" ==> extracting: %s (character device %ld,%ld)\n",
filename, devmaj, devmin);
#endif
if (mknod(filename, mode | S_IFCHR,
compat_makedev(devmaj, devmin)) == -1)
{
#ifdef DEBUG
printf("mknod() failed, returning good anyway");
#endif
return 0;
fprintf(stderr, "tar_extract_chardev(): failed restore of character device '%s' but returning as if nothing bad happened\n", filename);
return 0; // Used to be -1
}
return 0;
@@ -452,11 +419,12 @@ tar_extract_chardev(TAR *t, char *realname)
/* block device */
int
tar_extract_blockdev(TAR *t, char *realname)
tar_extract_blockdev(TAR *t, const char *realname)
{
mode_t mode;
unsigned long devmaj, devmin;
char *filename;
const char *filename;
char *pn;
if (!TH_ISBLK(t))
{
@@ -464,7 +432,8 @@ tar_extract_blockdev(TAR *t, char *realname)
return -1;
}
filename = (realname ? realname : th_get_pathname(t));
pn = th_get_pathname(t);
filename = (realname ? realname : pn);
mode = th_get_mode(t);
devmaj = th_get_devmajor(t);
devmin = th_get_devminor(t);
@@ -472,17 +441,14 @@ tar_extract_blockdev(TAR *t, char *realname)
if (mkdirhier(dirname(filename)) == -1)
return -1;
#ifdef DEBUG
printf(" ==> extracting: %s (block device %ld,%ld)\n",
filename, devmaj, devmin);
#endif
if (mknod(filename, mode | S_IFBLK,
compat_makedev(devmaj, devmin)) == -1)
{
#ifdef DEBUG
printf("mknod() failed but returning anyway");
#endif
return 0;
fprintf(stderr, "tar_extract_blockdev(): failed restore of block device '%s' but returning as if nothing bad happened\n", filename);
return 0; // Used to be -1
}
return 0;
@@ -491,35 +457,45 @@ tar_extract_blockdev(TAR *t, char *realname)
/* directory */
int
tar_extract_dir(TAR *t, char *realname)
tar_extract_dir(TAR *t, const char *realname)
{
mode_t mode;
char *filename;
const char *filename;
char *pn;
if (!TH_ISDIR(t))
{
errno = EINVAL;
return -1;
}
filename = (realname ? realname : th_get_pathname(t));
pn = th_get_pathname(t);
filename = (realname ? realname : pn);
mode = th_get_mode(t);
if (mkdirhier(dirname(filename)) == -1) {
printf("tar_extract_dir mkdirhier failed\n");
if (mkdirhier(dirname(filename)) == -1)
return -1;
}
#ifdef DEBUG
printf(" ==> extracting: %s (mode %04o, directory)\n", filename,
mode);
#endif
if (mkdir(filename, mode) == -1)
{
if (errno == EEXIST)
{
if (chmod(filename, mode) == -1)
{
#ifdef DEBUG
printf(" *** using existing directory");
perror("chmod()");
#endif
return -1;
}
else
{
#ifdef DEBUG
puts(" *** using existing directory");
#endif
return 1;
}
}
else
{
@@ -536,10 +512,11 @@ tar_extract_dir(TAR *t, char *realname)
/* FIFO */
int
tar_extract_fifo(TAR *t, char *realname)
tar_extract_fifo(TAR *t, const char *realname)
{
mode_t mode;
char *filename;
const char *filename;
char *pn;
if (!TH_ISFIFO(t))
{
@@ -547,15 +524,16 @@ tar_extract_fifo(TAR *t, char *realname)
return -1;
}
filename = (realname ? realname : th_get_pathname(t));
pn = th_get_pathname(t);
filename = (realname ? realname : pn);
mode = th_get_mode(t);
if (mkdirhier(dirname(filename)) == -1)
return -1;
#ifdef DEBUG
printf(" ==> extracting: %s (fifo)\n", filename);
#endif
if (mkfifo(filename, mode) == -1)
{
#ifdef DEBUG
@@ -567,4 +545,57 @@ tar_extract_fifo(TAR *t, char *realname)
return 0;
}
/* extract file contents from a tarchive */
int
tar_extract_file_contents(TAR *t, void *buf, size_t *lenp)
{
char block[T_BLOCKSIZE];
int64_t size, i;
ssize_t k;
#ifdef DEBUG
printf(" ==> tar_extract_file_contents\n");
#endif
if (!TH_ISREG(t))
{
errno = EINVAL;
return -1;
}
size = th_get_size(t);
if ((uint64_t)size > *lenp)
{
errno = ENOSPC;
return -1;
}
/* extract the file */
for (i = size; i >= T_BLOCKSIZE; i -= T_BLOCKSIZE)
{
k = tar_block_read(t, buf);
if (k != T_BLOCKSIZE)
{
if (k != -1)
errno = EINVAL;
return -1;
}
buf = (char *)buf + T_BLOCKSIZE;
}
if (i > 0) {
k = tar_block_read(t, block);
if (k != T_BLOCKSIZE)
{
if (k != -1)
errno = EINVAL;
return -1;
}
memcpy(buf, block, i);
}
*lenp = (size_t)size;
#ifdef DEBUG
printf("### done extracting contents\n");
#endif
return 0;
}
+6 -3
View File
@@ -31,7 +31,7 @@ static tartype_t default_type = { open, close, read, write };
static int
tar_init(TAR **t, char *pathname, tartype_t *type,
tar_init(TAR **t, const char *pathname, tartype_t *type,
int oflags, int mode, int options)
{
if ((oflags & O_ACCMODE) == O_RDWR)
@@ -66,7 +66,7 @@ tar_init(TAR **t, char *pathname, tartype_t *type,
/* open a new tarfile handle */
int
tar_open(TAR **t, char *pathname, tartype_t *type,
tar_open(TAR **t, const char *pathname, tartype_t *type,
int oflags, int mode, int options)
{
if (tar_init(t, pathname, type, oflags, mode, options) == -1)
@@ -82,6 +82,7 @@ tar_open(TAR **t, char *pathname, tartype_t *type,
(*t)->fd = (*((*t)->type->openfunc))(pathname, oflags, mode);
if ((*t)->fd == -1)
{
libtar_hash_free((*t)->h, NULL);
free(*t);
return -1;
}
@@ -91,7 +92,7 @@ tar_open(TAR **t, char *pathname, tartype_t *type,
int
tar_fdopen(TAR **t, int fd, char *pathname, tartype_t *type,
tar_fdopen(TAR **t, int fd, const char *pathname, tartype_t *type,
int oflags, int mode, int options)
{
if (tar_init(t, pathname, type, oflags, mode, options) == -1)
@@ -121,6 +122,8 @@ tar_close(TAR *t)
libtar_hash_free(t->h, ((t->oflags & O_ACCMODE) == O_RDONLY
? free
: (libtar_freefunc_t)tar_dev_free));
if (t->th_pathname != NULL)
free(t->th_pathname);
free(t);
return i;
+58 -36
View File
@@ -26,6 +26,7 @@ extern "C"
/* useful constants */
/* see FIXME note in block.c regarding T_BLOCKSIZE */
#define T_BLOCKSIZE 512
#define T_NAMELEN 100
#define T_PREFIXLEN 155
@@ -85,12 +86,15 @@ tartype_t;
typedef struct
{
tartype_t *type;
char *pathname;
const char *pathname;
long fd;
int oflags;
int options;
struct tar_header th_buf;
libtar_hash_t *h;
/* introduced in libtar 1.2.21 */
char *th_pathname;
}
TAR;
@@ -103,6 +107,7 @@ TAR;
#define TAR_CHECK_VERSION 32 /* check version in file header */
#define TAR_IGNORE_CRC 64 /* ignore CRC in file header */
#define TAR_STORE_SELINUX 128 /* store selinux context */
#define TAR_USE_NUMERIC_ID 256 /* favor numeric owner over names */
/* this is obsolete - it's here for backwards-compatibility only */
#define TAR_IGNORE_MAGIC 0
@@ -111,11 +116,11 @@ extern const char libtar_version[];
/* open a new tarfile handle */
int tar_open(TAR **t, char *pathname, tartype_t *type,
int tar_open(TAR **t, const char *pathname, tartype_t *type,
int oflags, int mode, int options);
/* make a tarfile handle out of a previously-opened descriptor */
int tar_fdopen(TAR **t, int fd, char *pathname, tartype_t *type,
int tar_fdopen(TAR **t, int fd, const char *pathname, tartype_t *type,
int oflags, int mode, int options);
/* returns the descriptor associated with t */
@@ -139,14 +144,27 @@ void tar_dev_free(struct tar_dev *tdp);
* realname = path of file to append
* savename = name to save the file under in the archive
*/
int tar_append_file(TAR *t, char *realname, char *savename);
int tar_append_file(TAR *t, const char *realname, const char *savename);
/* write EOF indicator */
int tar_append_eof(TAR *t);
/* add file contents to a tarchive */
int tar_append_regfile(TAR *t, char *realname);
int tar_append_regfile(TAR *t, const char *realname);
/* Appends in-memory file contents to a tarchive.
* Arguments:
* t = TAR handle to append to
* savename = name to save the file under in the archive
* mode = mode
* uid, gid = owner
* buf, len = in-memory buffer
*/
int tar_append_file_contents(TAR *t, const char *savename, mode_t mode,
uid_t uid, gid_t gid, void *buf, size_t len);
/* add buffer to a tarchive */
int tar_append_buffer(TAR *t, void *buf, size_t len);
/***** block.c *************************************************************/
@@ -167,31 +185,32 @@ int th_write(TAR *t);
#define TH_ISREG(t) ((t)->th_buf.typeflag == REGTYPE \
|| (t)->th_buf.typeflag == AREGTYPE \
|| (t)->th_buf.typeflag == CONTTYPE \
|| (S_ISREG((mode_t)oct_to_int((t)->th_buf.mode)) \
|| (S_ISREG((mode_t)oct_to_int((t)->th_buf.mode, sizeof((t)->th_buf.mode))) \
&& (t)->th_buf.typeflag != LNKTYPE))
#define TH_ISLNK(t) ((t)->th_buf.typeflag == LNKTYPE)
#define TH_ISSYM(t) ((t)->th_buf.typeflag == SYMTYPE \
|| S_ISLNK((mode_t)oct_to_int((t)->th_buf.mode)))
|| S_ISLNK((mode_t)oct_to_int((t)->th_buf.mode, sizeof((t)->th_buf.mode))))
#define TH_ISCHR(t) ((t)->th_buf.typeflag == CHRTYPE \
|| S_ISCHR((mode_t)oct_to_int((t)->th_buf.mode)))
|| S_ISCHR((mode_t)oct_to_int((t)->th_buf.mode, sizeof((t)->th_buf.mode))))
#define TH_ISBLK(t) ((t)->th_buf.typeflag == BLKTYPE \
|| S_ISBLK((mode_t)oct_to_int((t)->th_buf.mode)))
|| S_ISBLK((mode_t)oct_to_int((t)->th_buf.mode, sizeof((t)->th_buf.mode))))
#define TH_ISDIR(t) ((t)->th_buf.typeflag == DIRTYPE \
|| S_ISDIR((mode_t)oct_to_int((t)->th_buf.mode)) \
|| S_ISDIR((mode_t)oct_to_int((t)->th_buf.mode, sizeof((t)->th_buf.mode))) \
|| ((t)->th_buf.typeflag == AREGTYPE \
&& ((t)->th_buf.name[strlen((t)->th_buf.name) - 1] == '/')))
&& strnlen((t)->th_buf.name, T_NAMELEN) \
&& ((t)->th_buf.name[strnlen((t)->th_buf.name, T_NAMELEN) - 1] == '/')))
#define TH_ISFIFO(t) ((t)->th_buf.typeflag == FIFOTYPE \
|| S_ISFIFO((mode_t)oct_to_int((t)->th_buf.mode)))
|| S_ISFIFO((mode_t)oct_to_int((t)->th_buf.mode, sizeof((t)->th_buf.mode))))
#define TH_ISLONGNAME(t) ((t)->th_buf.typeflag == GNU_LONGNAME_TYPE)
#define TH_ISLONGLINK(t) ((t)->th_buf.typeflag == GNU_LONGLINK_TYPE)
#define TH_ISEXTHEADER(t) ((t)->th_buf.typeflag == TH_EXT_TYPE)
/* decode tar header info */
#define th_get_crc(t) oct_to_int((t)->th_buf.chksum)
#define th_get_size(t) oct_to_int((t)->th_buf.size)
#define th_get_mtime(t) oct_to_int((t)->th_buf.mtime)
#define th_get_devmajor(t) oct_to_int((t)->th_buf.devmajor)
#define th_get_devminor(t) oct_to_int((t)->th_buf.devminor)
#define th_get_crc(t) oct_to_int((t)->th_buf.chksum, sizeof((t)->th_buf.chksum))
#define th_get_size(t) oct_to_int_ex((t)->th_buf.size, sizeof((t)->th_buf.size))
#define th_get_mtime(t) oct_to_int_ex((t)->th_buf.mtime, sizeof((t)->th_buf.mtime))
#define th_get_devmajor(t) oct_to_int((t)->th_buf.devmajor, sizeof((t)->th_buf.devmajor))
#define th_get_devminor(t) oct_to_int((t)->th_buf.devminor, sizeof((t)->th_buf.devminor))
#define th_get_linkname(t) ((t)->th_buf.gnu_longlink \
? (t)->th_buf.gnu_longlink \
: (t)->th_buf.linkname)
@@ -205,16 +224,16 @@ gid_t th_get_gid(TAR *t);
/* encode file info in th_header */
void th_set_type(TAR *t, mode_t mode);
void th_set_path(TAR *t, char *pathname);
void th_set_link(TAR *t, char *linkname);
void th_set_path(TAR *t, const char *pathname);
void th_set_link(TAR *t, const char *linkname);
void th_set_device(TAR *t, dev_t device);
void th_set_user(TAR *t, uid_t uid);
void th_set_group(TAR *t, gid_t gid);
void th_set_mode(TAR *t, mode_t fmode);
#define th_set_mtime(t, fmtime) \
int_to_oct_nonull((fmtime), (t)->th_buf.mtime, 12)
int_to_oct_ex((fmtime), (t)->th_buf.mtime, sizeof((t)->th_buf.mtime))
#define th_set_size(t, fsize) \
int_to_oct_nonull((fsize), (t)->th_buf.size, 12)
int_to_oct_ex((fsize), (t)->th_buf.size, sizeof((t)->th_buf.size))
/* encode everything at once (except the pathname and linkname) */
void th_set_from_stat(TAR *t, struct stat *s);
@@ -226,20 +245,22 @@ void th_finish(TAR *t);
/***** extract.c ***********************************************************/
/* sequentially extract next file from t */
int tar_extract_file(TAR *t, char *realname, char *prefix, const int *progress_fd);
int tar_extract_file(TAR *t, const char *realname, const char *prefix, const int *progress_fd);
/* extract different file types */
int tar_extract_dir(TAR *t, char *realname);
int tar_extract_hardlink(TAR *t, char *realname, char *prefix);
int tar_extract_symlink(TAR *t, char *realname);
int tar_extract_chardev(TAR *t, char *realname);
int tar_extract_blockdev(TAR *t, char *realname);
int tar_extract_fifo(TAR *t, char *realname);
int tar_extract_dir(TAR *t, const char *realname);
int tar_extract_hardlink(TAR *t, const char *realname, const char *prefix);
int tar_extract_symlink(TAR *t, const char *realname);
int tar_extract_chardev(TAR *t, const char *realname);
int tar_extract_blockdev(TAR *t, const char *realname);
int tar_extract_fifo(TAR *t, const char *realname);
/* for regfiles, we need to extract the content blocks as well */
int tar_extract_regfile(TAR *t, char *realname, const int *progress_fd);
int tar_extract_regfile(TAR *t, const char *realname, const int *progress_fd);
int tar_skip_regfile(TAR *t);
/* extract regfile to buffer */
int tar_extract_file_contents(TAR *t, void *buf, size_t *lenp);
/***** output.c ************************************************************/
@@ -280,16 +301,17 @@ int th_signed_crc_calc(TAR *t);
#define th_crc_ok(t) (th_get_crc(t) == th_crc_calc(t) || th_get_crc(t) == th_signed_crc_calc(t))
/* string-octal to integer conversion */
int oct_to_int(char *oct);
int64_t oct_to_int(char *oct, size_t len);
/* string-octal or binary to integer conversion */
int64_t oct_to_int_ex(char *oct, size_t len);
/* integer to NULL-terminated string-octal conversion */
#define int_to_oct(num, oct, octlen) \
snprintf((oct), (octlen), "%*lo ", (octlen) - 2, (unsigned long)(num))
void int_to_oct(int64_t num, char *oct, size_t octlen);
/* integer to string-octal conversion, no NULL */
void int_to_oct_nonull(int num, char *oct, size_t octlen);
/* integer to string-octal conversion, or binary as necessary */
void int_to_oct_ex(int64_t num, char *oct, size_t octlen);
#define tar_min(x, y) (x < y ? x : y)
/***** wrapper.c **********************************************************/
@@ -298,7 +320,7 @@ int tar_extract_glob(TAR *t, char *globname, char *prefix);
int tar_extract_all(TAR *t, char *prefix, const int *progress_fd);
/* add a whole tree of files */
int tar_append_tree(TAR *t, char *realdir, char *savedir, char *exclude);
int tar_append_tree(TAR *t, char *realdir, char *savedir);
/* find an entry */
int tar_find(TAR *t, char *searchstr);
+7
View File
@@ -15,6 +15,9 @@
#ifndef libtar_LISTHASH_H
#define libtar_LISTHASH_H
#ifdef __cplusplus
extern "C" {
#endif
/***** list.c **********************************************************/
@@ -192,5 +195,9 @@ int libtar_hash_add(libtar_hash_t *, void *);
int libtar_hash_del(libtar_hash_t *,
libtar_hashptr_t *);
#ifdef __cplusplus
}
#endif
#endif /* ! libtar_LISTHASH_H */
+4 -3
View File
@@ -13,6 +13,7 @@
#include <internal.h>
#include <stdio.h>
#include <stdlib.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
@@ -83,14 +84,14 @@ th_print_long_ls(TAR *t)
uid = th_get_uid(t);
pw = getpwuid(uid);
if (pw == NULL)
if ((t->options & TAR_USE_NUMERIC_ID) || pw == NULL)
snprintf(username, sizeof(username), "%d", uid);
else
strlcpy(username, pw->pw_name, sizeof(username));
gid = th_get_gid(t);
gr = getgrgid(gid);
if (gr == NULL)
if ((t->options & TAR_USE_NUMERIC_ID) || gr == NULL)
snprintf(groupname, sizeof(groupname), "%d", gid);
else
strlcpy(groupname, gr->gr_name, sizeof(groupname));
@@ -99,7 +100,7 @@ th_print_long_ls(TAR *t)
printf("%.10s %-8.8s %-8.8s ", modestring, username, groupname);
if (TH_ISCHR(t) || TH_ISBLK(t))
printf(" %3d, %3d ", th_get_devmajor(t), th_get_devminor(t));
printf(" %3d, %3d ", (int)th_get_devmajor(t), (int)th_get_devminor(t));
else
printf("%9ld ", (long)th_get_size(t));
+61 -14
View File
@@ -126,7 +126,6 @@ th_crc_calc(TAR *t)
return sum;
}
/* calculate a signed header checksum */
int
th_signed_crc_calc(TAR *t)
@@ -141,25 +140,73 @@ th_signed_crc_calc(TAR *t)
return sum;
}
/* string-octal to integer conversion */
int
oct_to_int(char *oct)
int64_t
oct_to_int(char *oct, size_t octlen)
{
int i;
long long int val;
char tmp[octlen + 1];
sscanf(oct, "%o", &i);
return i;
memcpy(tmp, oct, octlen);
tmp[octlen] = '\0';
return sscanf(oct, "%llo", &val) == 1 ? (int64_t)val : 0;
}
/* integer to string-octal conversion, no NULL */
/* string-octal or binary to integer conversion */
int64_t oct_to_int_ex(char *oct, size_t octlen)
{
if (*(unsigned char *)oct & 0x80) {
int64_t val = 0;
char tmp[octlen];
unsigned char *p;
unsigned int i;
memcpy(tmp, oct, octlen);
*tmp &= 0x7f;
p = (unsigned char *)tmp + octlen - sizeof(val);
for (i = 0; i < sizeof(val); ++i) {
val <<= 8;
val |= *(p++);
}
return val;
}
return oct_to_int(oct, octlen);
}
/* integer to NULL-terminated string-octal conversion */
void int_to_oct(int64_t num, char *oct, size_t octlen)
{
char tmp[sizeof(num)*3 + 1];
int olen;
olen = sprintf(tmp, "%0*llo", (int)octlen, (long long)num);
memcpy(oct, tmp + olen - octlen + 1, octlen);
}
/* integer to string-octal conversion, or binary as necessary */
void
int_to_oct_nonull(int num, char *oct, size_t octlen)
int_to_oct_ex(int64_t num, char *oct, size_t octlen)
{
snprintf(oct, octlen, "%*lo", octlen - 1, (unsigned long)num);
oct[octlen - 1] = ' ';
if (num < 0 || num >= ((int64_t)1 << ((octlen - 1) * 3))) {
unsigned char *p;
unsigned int i;
memset(oct, 0, octlen);
p = (unsigned char *)oct + octlen;
for (i = 0; i < sizeof(num); ++i) {
*(--p) = num & 0xff;
num >>= 8;
}
if (num < 0) {
for (; i < octlen; ++i) {
*(--p) = 0xff;
}
}
*(unsigned char *)oct |= 0x80;
return;
}
int_to_oct(num, oct, octlen);
}
+39 -71
View File
@@ -10,18 +10,19 @@
** University of Illinois at Urbana-Champaign
*/
#define DEBUG
#include <internal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/param.h>
#include <dirent.h>
#include <errno.h>
#include <stdlib.h>
#ifdef STDC_HEADERS
# include <string.h>
#endif
int
tar_extract_glob(TAR *t, char *globname, char *prefix)
{
@@ -44,7 +45,7 @@ tar_extract_glob(TAR *t, char *globname, char *prefix)
snprintf(buf, sizeof(buf), "%s/%s", prefix, filename);
else
strlcpy(buf, filename, sizeof(buf));
if (tar_extract_file(t, filename, prefix, &fd) != 0)
if (tar_extract_file(t, buf, prefix, &fd) != 0)
return -1;
}
@@ -58,11 +59,12 @@ tar_extract_all(TAR *t, char *prefix, const int *progress_fd)
char *filename;
char buf[MAXPATHLEN];
int i;
printf("prefix: %s\n", prefix);
#ifdef DEBUG
printf("==> tar_extract_all(TAR *t, \"%s\")\n",
(prefix ? prefix : "(null)"));
#endif
while ((i = th_read(t)) == 0)
{
#ifdef DEBUG
@@ -79,105 +81,71 @@ tar_extract_all(TAR *t, char *prefix, const int *progress_fd)
printf(" tar_extract_all(): calling tar_extract_file(t, "
"\"%s\")\n", buf);
#endif
printf("item name: '%s'\n", filename);
if (tar_extract_file(t, buf, prefix, progress_fd) != 0)
return -1;
}
return (i == 1 ? 0 : -1);
}
int
tar_append_tree(TAR *t, char *realdir, char *savedir, char *exclude)
tar_append_tree(TAR *t, char *realdir, char *savedir)
{
#ifdef DEBUG
printf("==> tar_append_tree(0x%lx, \"%s\", \"%s\")\n",
(long unsigned int)t, realdir, (savedir ? savedir : "[NULL]"));
#endif
char temp[1024];
int skip = 0, i, n_spaces = 0;
char ** excluded = NULL;
char * p = NULL;
if (exclude) {
strcpy(temp, exclude);
p = strtok(exclude, " ");
if (p == NULL) {
excluded = realloc(excluded, sizeof(char*) * (++n_spaces));
excluded[0] = temp;
} else {
while (p) {
excluded = realloc(excluded, sizeof(char*) * (++n_spaces));
excluded[n_spaces-1] = p;
p = strtok(NULL, " ");
}
}
excluded = realloc(excluded, sizeof(char*) * (n_spaces+1));
excluded[n_spaces] = 0;
for (i = 0; i < (n_spaces+1); i++) {
if (realdir == excluded[i]) {
printf(" excluding '%s'\n", excluded[i]);
skip = 1;
break;
}
}
}
if (skip == 0) {
if (tar_append_file(t, realdir, savedir) != 0)
return -1;
}
char realpath[MAXPATHLEN];
char savepath[MAXPATHLEN];
struct dirent *dent;
DIR *dp;
struct stat s;
#ifdef DEBUG
printf("==> tar_append_tree(0x%lx, \"%s\", \"%s\")\n",
t, realdir, (savedir ? savedir : "[NULL]"));
#endif
if (tar_append_file(t, realdir, savedir) != 0)
return -1;
#ifdef DEBUG
puts(" tar_append_tree(): done with tar_append_file()...");
#endif
dp = opendir(realdir);
if (dp == NULL) {
if (dp == NULL)
{
if (errno == ENOTDIR)
return 0;
return -1;
}
while ((dent = readdir(dp)) != NULL) {
if(strcmp(dent->d_name, ".") == 0
|| strcmp(dent->d_name, "..") == 0)
while ((dent = readdir(dp)) != NULL)
{
if (strcmp(dent->d_name, ".") == 0 ||
strcmp(dent->d_name, "..") == 0)
continue;
if (exclude) {
int omit = 0;
for (i = 0; i < (n_spaces+1); i++) {
if (excluded[i] != NULL) {
if (strcmp(dent->d_name, excluded[i]) == 0 || strcmp(excluded[i], realdir) == 0) {
printf(" excluding '%s'\n", excluded[i]);
omit = 1;
break;
}
}
}
if (omit)
continue;
}
snprintf(realpath, MAXPATHLEN, "%s/%s", realdir, dent->d_name);
snprintf(realpath, MAXPATHLEN, "%s/%s", realdir,
dent->d_name);
if (savedir)
snprintf(savepath, MAXPATHLEN, "%s/%s", savedir, dent->d_name);
snprintf(savepath, MAXPATHLEN, "%s/%s", savedir,
dent->d_name);
if (lstat(realpath, &s) != 0)
return -1;
if (S_ISDIR(s.st_mode)) {
if (tar_append_tree(t, realpath, (savedir ? savepath : NULL), (exclude ? exclude : NULL)) != 0)
return -1;
continue;
} else {
if (tar_append_file(t, realpath, (savedir ? savepath : NULL)) != 0)
if (S_ISDIR(s.st_mode))
{
if (tar_append_tree(t, realpath,
(savedir ? savepath : NULL)) != 0)
return -1;
continue;
}
if (tar_append_file(t, realpath,
(savedir ? savepath : NULL)) != 0)
return -1;
}
closedir(dp);
free(excluded);
return 0;
}