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
diff --git a/libtar/ChangeLog b/libtar/ChangeLog
index cde7675..03bef68 100644
--- a/libtar/ChangeLog
+++ b/libtar/ChangeLog
@@ -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
diff --git a/libtar/append.c b/libtar/append.c
index 1831990..4be679c 100644
--- a/libtar/append.c
+++ b/libtar/append.c
@@ -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 @@
/* 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 @@
/* 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 @@
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 @@
/* 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 @@
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 @@
/* 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 @@
{
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;
}
-
diff --git a/libtar/basename.c b/libtar/basename.c
index 2ac1e13..32108d6 100644
--- a/libtar/basename.c
+++ b/libtar/basename.c
@@ -64,7 +64,7 @@
while (startp > path && *(startp - 1) != '/')
startp--;
- if (endp - startp + 1 > sizeof(bname)) {
+ if (endp - startp + 1 > (int)sizeof(bname)) {
errno = ENAMETOOLONG;
return(NULL);
}
diff --git a/libtar/block.c b/libtar/block.c
index 6ed9e60..5d3c9d8 100644
--- a/libtar/block.c
+++ b/libtar/block.c
@@ -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 @@
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 @@
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 @@
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 @@
}
#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 @@
{
int i, j;
char type2;
- size_t sz, sz2;
+ uint64_t sz, sz2;
char *ptr;
char buf[T_BLOCKSIZE];
@@ -457,7 +442,7 @@
}
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)
{
diff --git a/libtar/compat.h b/libtar/compat.h
index d086294..70ac2f4 100644
--- a/libtar/compat.h
+++ b/libtar/compat.h
@@ -12,10 +12,6 @@
# include <libgen.h>
#endif
-#ifdef HAVE_SELINUX
-#include "selinux/selinux.h"
-#endif
-
#if defined(NEED_BASENAME) && !defined(HAVE_BASENAME)
diff --git a/libtar/decode.c b/libtar/decode.c
index 383306d..1a3d0ee 100644
--- a/libtar/decode.c
+++ b/libtar/decode.c
@@ -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 @@
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 @@
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 @@
{
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 @@
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;
diff --git a/libtar/dirname.c b/libtar/dirname.c
index 986db4a..4e06067 100644
--- a/libtar/dirname.c
+++ b/libtar/dirname.c
@@ -67,7 +67,7 @@
} while (endp > path && *endp == '/');
}
- if (endp - path + 1 > sizeof(bname)) {
+ if (endp - path + 1 > (int)sizeof(bname)) {
errno = ENAMETOOLONG;
return(NULL);
}
diff --git a/libtar/encode.c b/libtar/encode.c
index 662eff5..c937152 100644
--- a/libtar/encode.c
+++ b/libtar/encode.c
@@ -68,10 +68,11 @@
/* 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 @@
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
- /* classic tar format */
- snprintf(t->th_buf.name, 100, "%s%s", pathname, suffix);
+ 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);
+ }
#ifdef DEBUG
puts("returning from th_set_path()...");
@@ -116,23 +134,28 @@
/* 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 @@
{
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 @@
{
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 @@
else
th_set_size(t, 0);
}
-
-
diff --git a/libtar/extract.c b/libtar/extract.c
index 69e08bd..257e140 100644
--- a/libtar/extract.c
+++ b/libtar/extract.c
@@ -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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
/* 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 @@
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 @@
}
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 @@
/* 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 @@
/* 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 @@
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 @@
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 @@
/* 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 @@
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 @@
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 @@
/* 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 @@
/* 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 @@
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 @@
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;
+}
diff --git a/libtar/handle.c b/libtar/handle.c
index ae974b9..28a7dc2 100644
--- a/libtar/handle.c
+++ b/libtar/handle.c
@@ -31,7 +31,7 @@
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 @@
/* 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 @@
(*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 @@
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 @@
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;
diff --git a/libtar/libtar.h b/libtar/libtar.h
index d2c4d00..4a51375 100644
--- a/libtar/libtar.h
+++ b/libtar/libtar.h
@@ -26,6 +26,7 @@
/* 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 @@
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 @@
#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 @@
/* 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 @@
* 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 @@
#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 @@
/* 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 @@
/***** 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 @@
#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_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);
diff --git a/libtar/libtar_listhash.h b/libtar/libtar_listhash.h
index fa33cfd..48c0d74 100644
--- a/libtar/libtar_listhash.h
+++ b/libtar/libtar_listhash.h
@@ -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_del(libtar_hash_t *,
libtar_hashptr_t *);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* ! libtar_LISTHASH_H */
diff --git a/libtar/output.c b/libtar/output.c
index a2db929..d2bf8bb 100644
--- a/libtar/output.c
+++ b/libtar/output.c
@@ -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 @@
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 @@
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));
diff --git a/libtar/util.c b/libtar/util.c
index 31e8315..f472f38 100644
--- a/libtar/util.c
+++ b/libtar/util.c
@@ -126,7 +126,6 @@
return sum;
}
-
/* calculate a signed header checksum */
int
th_signed_crc_calc(TAR *t)
@@ -141,25 +140,73 @@
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);
}
-
-
diff --git a/libtar/wrapper.c b/libtar/wrapper.c
index 82f045f..d3d285f 100644
--- a/libtar/wrapper.c
+++ b/libtar/wrapper.c
@@ -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 @@
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 @@
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 @@
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;
}