diff options
| author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-07-24 13:36:50 +0200 | 
|---|---|---|
| committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-07-24 18:10:34 +0200 | 
| commit | 4fdfd1f62a9d50298b0bb71e8bea04174af4a3ab (patch) | |
| tree | d511b488ce77ef2b0b84b26ead69a1d01375491c | |
| parent | 30fbd496a1793b4374873144432f9b7a996a689d (diff) | |
Fix processing of tar mtime on 32 bit systems
struct stat uses time_t to store time values. On some 32 bit systems,
this may be a 32 bit integer.
This patch adds a broken-out 64 bit time value to tar_header_decoded_t
and makes sure to clamp the value to +/- (2^32 - 1) if required when
writing it back to a struct stat.
Reported-by: Matt Turner <mattst88@gmail.com>
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
| -rw-r--r-- | configure.ac | 3 | ||||
| -rw-r--r-- | include/tar.h | 4 | ||||
| -rw-r--r-- | lib/tar/read_header.c | 19 | ||||
| -rw-r--r-- | m4/m4_ax_compile_check_sizeof.m4 | 115 | ||||
| -rw-r--r-- | tests/tar_gnu.c | 13 | ||||
| -rw-r--r-- | tests/tar_pax.c | 12 | ||||
| -rw-r--r-- | tests/tar_ustar.c | 13 | ||||
| -rw-r--r-- | tests/tar_xattr_bsd.c | 1 | ||||
| -rw-r--r-- | tests/tar_xattr_schily.c | 1 | 
9 files changed, 174 insertions, 7 deletions
diff --git a/configure.ac b/configure.ac index 1141236..870c572 100644 --- a/configure.ac +++ b/configure.ac @@ -156,6 +156,9 @@ if test "x$have_compressor" != "xyes"; then  	AC_MSG_ERROR([no compressor available. At lest one is required])  fi +##### additional checks ##### +AX_COMPILE_CHECK_SIZEOF(time_t) +  ##### generate output #####  AC_CONFIG_HEADERS([config.h]) diff --git a/include/tar.h b/include/tar.h index 5ac0763..e6a506a 100644 --- a/include/tar.h +++ b/include/tar.h @@ -74,6 +74,10 @@ typedef struct {  	uint64_t record_size;  	bool unknown_record;  	tar_xattr_t *xattr; + +	/* broken out since struct stat could contain +	   32 bit values on 32 bit systems. */ +	int64_t mtime;  } tar_header_decoded_t;  #define TAR_TYPE_FILE '0' diff --git a/lib/tar/read_header.c b/lib/tar/read_header.c index 043b5ff..a083c2f 100644 --- a/lib/tar/read_header.c +++ b/lib/tar/read_header.c @@ -129,11 +129,11 @@ static int read_pax_header(int fd, uint64_t entsize, unsigned int *set_by_pax,  			if (line[6] == '-') {  				if (pax_read_decimal(line + 7, &field))  					goto fail; -				out->sb.st_mtime = -((int64_t)field); +				out->mtime = -((int64_t)field);  			} else {  				if (pax_read_decimal(line + 6, &field))  					goto fail; -				out->sb.st_mtime = field; +				out->mtime = field;  			}  			*set_by_pax |= PAX_MTIME;  		} else if (!strncmp(line, "GNU.sparse.name=", 16)) { @@ -284,9 +284,9 @@ static int decode_header(const tar_header_t *hdr, unsigned int set_by_pax,  			return -1;  		if (field & 0x8000000000000000UL) {  			field = ~field + 1; -			out->sb.st_mtime = -((int64_t)field); +			out->mtime = -((int64_t)field);  		} else { -			out->sb.st_mtime = field; +			out->mtime = field;  		}  	} @@ -338,6 +338,17 @@ static int decode_header(const tar_header_t *hdr, unsigned int set_by_pax,  		break;  	} +#if SIZEOF_TIME_T < 8 +	if (out->mtime > (int64_t)INT32_MAX) { +		out->sb.st_mtime = INT32_MAX; +	} else if (out->mtime < (int64_t)INT32_MIN) { +		out->sb.st_mtime = INT32_MIN; +	} else { +		out->sb.st_mtime = out->mtime; +	} +#else +	out->sb.st_mtime = out->mtime; +#endif  	return 0;  } diff --git a/m4/m4_ax_compile_check_sizeof.m4 b/m4/m4_ax_compile_check_sizeof.m4 new file mode 100644 index 0000000..f834df6 --- /dev/null +++ b/m4/m4_ax_compile_check_sizeof.m4 @@ -0,0 +1,115 @@ +# ============================================================================ +#  https://www.gnu.org/software/autoconf-archive/ax_compile_check_sizeof.html +# ============================================================================ +# +# SYNOPSIS +# +#   AX_COMPILE_CHECK_SIZEOF(TYPE [, HEADERS [, EXTRA_SIZES...]]) +# +# DESCRIPTION +# +#   This macro checks for the size of TYPE using compile checks, not run +#   checks. You can supply extra HEADERS to look into. the check will cycle +#   through 1 2 4 8 16 and any EXTRA_SIZES the user supplies. If a match is +#   found, it will #define SIZEOF_`TYPE' to that value. Otherwise it will +#   emit a configure time error indicating the size of the type could not be +#   determined. +# +#   The trick is that C will not allow duplicate case labels. While this is +#   valid C code: +# +#     switch (0) case 0: case 1:; +# +#   The following is not: +# +#     switch (0) case 0: case 0:; +# +#   Thus, the AC_COMPILE_IFELSE will fail if the currently tried size does +#   not match. +# +#   Here is an example skeleton configure.in script, demonstrating the +#   macro's usage: +# +#     AC_PROG_CC +#     AC_CHECK_HEADERS(stddef.h unistd.h) +#     AC_TYPE_SIZE_T +#     AC_CHECK_TYPE(ssize_t, int) +# +#     headers='#ifdef HAVE_STDDEF_H +#     #include <stddef.h> +#     #endif +#     #ifdef HAVE_UNISTD_H +#     #include <unistd.h> +#     #endif +#     ' +# +#     AX_COMPILE_CHECK_SIZEOF(char) +#     AX_COMPILE_CHECK_SIZEOF(short) +#     AX_COMPILE_CHECK_SIZEOF(int) +#     AX_COMPILE_CHECK_SIZEOF(long) +#     AX_COMPILE_CHECK_SIZEOF(unsigned char *) +#     AX_COMPILE_CHECK_SIZEOF(void *) +#     AX_COMPILE_CHECK_SIZEOF(size_t, $headers) +#     AX_COMPILE_CHECK_SIZEOF(ssize_t, $headers) +#     AX_COMPILE_CHECK_SIZEOF(ptrdiff_t, $headers) +#     AX_COMPILE_CHECK_SIZEOF(off_t, $headers) +# +# LICENSE +# +#   Copyright (c) 2008 Kaveh Ghazi <ghazi@caip.rutgers.edu> +#   Copyright (c) 2017 Reini Urban <rurban@cpan.org> +# +#   This program is free software: you can redistribute it and/or modify it +#   under the terms of the GNU General Public License as published by the +#   Free Software Foundation, either version 3 of the License, or (at your +#   option) any later version. +# +#   This program is distributed in the hope that it will be useful, but +#   WITHOUT ANY WARRANTY; without even the implied warranty of +#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +#   Public License for more details. +# +#   You should have received a copy of the GNU General Public License along +#   with this program. If not, see <https://www.gnu.org/licenses/>. +# +#   As a special exception, the respective Autoconf Macro's copyright owner +#   gives unlimited permission to copy, distribute and modify the configure +#   scripts that are the output of Autoconf when processing the Macro. You +#   need not follow the terms of the GNU General Public License when using +#   or distributing such scripts, even though portions of the text of the +#   Macro appear in them. The GNU General Public License (GPL) does govern +#   all other use of the material that constitutes the Autoconf Macro. +# +#   This special exception to the GPL applies to versions of the Autoconf +#   Macro released by the Autoconf Archive. When you make and distribute a +#   modified version of the Autoconf Macro, you may extend this special +#   exception to the GPL to apply to your modified version as well. + +#serial 8 + +AU_ALIAS([AC_COMPILE_CHECK_SIZEOF], [AX_COMPILE_CHECK_SIZEOF]) +AC_DEFUN([AX_COMPILE_CHECK_SIZEOF], +[changequote(<<, >>)dnl +dnl The name to #define. +define(<<AC_TYPE_NAME>>, translit(sizeof_$1, [a-z *], [A-Z_P]))dnl +dnl The cache variable name. +define(<<AC_CV_NAME>>, translit(ac_cv_sizeof_$1, [ *], [_p]))dnl +changequote([, ])dnl +AC_MSG_CHECKING(size of $1) +AC_CACHE_VAL(AC_CV_NAME, +[for ac_size in 4 8 1 2 16 $3 ; do # List sizes in rough order of prevalence. +  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include <sys/types.h> +$2 +]], [[switch (0) case 0: case (sizeof ($1) == $ac_size):;]])], [AC_CV_NAME=$ac_size]) +  if test x$AC_CV_NAME != x ; then break; fi +done +]) +if test x$AC_CV_NAME = x ; then +  AC_MSG_ERROR([cannot determine a size for $1]) +fi +AC_MSG_RESULT($AC_CV_NAME) +AC_DEFINE_UNQUOTED(AC_TYPE_NAME, $AC_CV_NAME, [The number of bytes in type $1]) +undefine([AC_TYPE_NAME])dnl +undefine([AC_CV_NAME])dnl +]) diff --git a/tests/tar_gnu.c b/tests/tar_gnu.c index c5f8ddb..4f78da7 100644 --- a/tests/tar_gnu.c +++ b/tests/tar_gnu.c @@ -48,6 +48,7 @@ int main(void)  	assert(hdr.sb.st_gid == 01750);  	assert(hdr.sb.st_size == 5);  	assert(hdr.sb.st_mtime == 1542905892); +	assert(hdr.mtime == 1542905892);  	assert(strcmp(hdr.name, "input.txt") == 0);  	assert(!hdr.unknown_record);  	assert(read_data("data0", fd, buffer, 5) == 0); @@ -63,6 +64,7 @@ int main(void)  	assert(hdr.sb.st_gid == 01750);  	assert(hdr.sb.st_size == 5);  	assert(hdr.sb.st_mtime == 013375560044); +	assert(hdr.mtime == 013375560044);  	assert(strcmp(hdr.name, "input.txt") == 0);  	assert(!hdr.unknown_record);  	assert(read_data("data1", fd, buffer, 5) == 0); @@ -78,6 +80,7 @@ int main(void)  	assert(hdr.sb.st_gid == 01750);  	assert(hdr.sb.st_size == 8589934592);  	assert(hdr.sb.st_mtime == 013375730126); +	assert(hdr.mtime == 013375730126);  	assert(strcmp(hdr.name, "big-file.bin") == 0);  	assert(!hdr.unknown_record);  	clear_header(&hdr); @@ -90,6 +93,7 @@ int main(void)  	assert(hdr.sb.st_gid == 0x80000000);  	assert(hdr.sb.st_size == 5);  	assert(hdr.sb.st_mtime == 013376036700); +	assert(hdr.mtime == 013376036700);  	assert(strcmp(hdr.name, "input.txt") == 0);  	assert(!hdr.unknown_record);  	assert(read_data("data2", fd, buffer, 5) == 0); @@ -104,7 +108,12 @@ int main(void)  	assert(hdr.sb.st_uid == 01750);  	assert(hdr.sb.st_gid == 01750);  	assert(hdr.sb.st_size == 5); -	assert(hdr.sb.st_mtime == 8589934592); +#if SIZEOF_TIME_T < 8 +	assert(hdr.sb.st_mtime == INT32_MAX); +#else +	assert(hdr.sb.st_mtime == 8589934592L); +#endif +	assert(hdr.mtime == 8589934592L);  	assert(strcmp(hdr.name, "input.txt") == 0);  	assert(!hdr.unknown_record);  	assert(read_data("data3", fd, buffer, 5) == 0); @@ -120,6 +129,7 @@ int main(void)  	assert(hdr.sb.st_gid == 01750);  	assert(hdr.sb.st_size == 5);  	assert(hdr.sb.st_mtime == -315622800); +	assert(hdr.mtime == -315622800);  	assert(strcmp(hdr.name, "input.txt") == 0);  	assert(!hdr.unknown_record);  	assert(read_data("data4", fd, buffer, 5) == 0); @@ -135,6 +145,7 @@ int main(void)  	assert(hdr.sb.st_gid == 01750);  	assert(hdr.sb.st_size == 5);  	assert(hdr.sb.st_mtime == 1542909670); +	assert(hdr.mtime == 1542909670);  	assert(strcmp(hdr.name, filename) == 0);  	assert(!hdr.unknown_record);  	assert(read_data("data5", fd, buffer, 5) == 0); diff --git a/tests/tar_pax.c b/tests/tar_pax.c index c383427..9ca12ff 100644 --- a/tests/tar_pax.c +++ b/tests/tar_pax.c @@ -48,6 +48,7 @@ int main(void)  	assert(hdr.sb.st_gid == 01750);  	assert(hdr.sb.st_size == 5);  	assert(hdr.sb.st_mtime == 1542905892); +	assert(hdr.mtime == 1542905892);  	assert(strcmp(hdr.name, "input.txt") == 0);  	assert(!hdr.unknown_record);  	assert(read_data("data0", fd, buffer, 5) == 0); @@ -63,6 +64,7 @@ int main(void)  	assert(hdr.sb.st_gid == 01750);  	assert(hdr.sb.st_size == 8589934592);  	assert(hdr.sb.st_mtime == 1542959190); +	assert(hdr.mtime == 1542959190);  	assert(strcmp(hdr.name, "big-file.bin") == 0);  	assert(!hdr.unknown_record);  	clear_header(&hdr); @@ -75,6 +77,7 @@ int main(void)  	assert(hdr.sb.st_gid == 2147483648);  	assert(hdr.sb.st_size == 5);  	assert(hdr.sb.st_mtime == 013376036700); +	assert(hdr.mtime == 013376036700);  	assert(strcmp(hdr.name, "input.txt") == 0);  	assert(!hdr.unknown_record);  	assert(read_data("data1", fd, buffer, 5) == 0); @@ -89,7 +92,12 @@ int main(void)  	assert(hdr.sb.st_uid == 01750);  	assert(hdr.sb.st_gid == 01750);  	assert(hdr.sb.st_size == 5); -	assert(hdr.sb.st_mtime == 8589934592); +#if SIZEOF_TIME_T < 8 +	assert(hdr.sb.st_mtime == INT32_MAX); +#else +	assert(hdr.sb.st_mtime == 8589934592L); +#endif +	assert(hdr.mtime == 8589934592L);  	assert(strcmp(hdr.name, "input.txt") == 0);  	assert(!hdr.unknown_record);  	assert(read_data("data2", fd, buffer, 5) == 0); @@ -105,6 +113,7 @@ int main(void)  	assert(hdr.sb.st_gid == 01750);  	assert(hdr.sb.st_size == 5);  	assert(hdr.sb.st_mtime == -315622800); +	assert(hdr.mtime == -315622800);  	assert(strcmp(hdr.name, "input.txt") == 0);  	assert(!hdr.unknown_record);  	assert(read_data("data3", fd, buffer, 5) == 0); @@ -120,6 +129,7 @@ int main(void)  	assert(hdr.sb.st_gid == 01750);  	assert(hdr.sb.st_size == 5);  	assert(hdr.sb.st_mtime == 1542909670); +	assert(hdr.mtime == 1542909670);  	assert(strcmp(hdr.name, filename) == 0);  	assert(!hdr.unknown_record);  	assert(read_data("data4", fd, buffer, 5) == 0); diff --git a/tests/tar_ustar.c b/tests/tar_ustar.c index d497b15..695665f 100644 --- a/tests/tar_ustar.c +++ b/tests/tar_ustar.c @@ -48,6 +48,7 @@ int main(void)  	assert(hdr.sb.st_gid == 01750);  	assert(hdr.sb.st_size == 5);  	assert(hdr.sb.st_mtime == 1542905892); +	assert(hdr.mtime == 1542905892);  	assert(strcmp(hdr.name, "input.txt") == 0);  	assert(!hdr.unknown_record);  	assert(read_data("data0", fd, buffer, 5) == 0); @@ -63,6 +64,7 @@ int main(void)  	assert(hdr.sb.st_gid == 01750);  	assert(hdr.sb.st_size == 5);  	assert(hdr.sb.st_mtime == 1542905892); +	assert(hdr.mtime == 1542905892);  	assert(strcmp(hdr.name, "input.txt") == 0);  	assert(!hdr.unknown_record);  	assert(read_data("data1", fd, buffer, 5) == 0); @@ -78,6 +80,7 @@ int main(void)  	assert(hdr.sb.st_gid == 01750);  	assert(hdr.sb.st_size == 5);  	assert(hdr.sb.st_mtime == 1542905892); +	assert(hdr.mtime == 1542905892);  	assert(strcmp(hdr.name, "input.txt") == 0);  	assert(!hdr.unknown_record);  	assert(read_data("data2", fd, buffer, 5) == 0); @@ -93,6 +96,7 @@ int main(void)  	assert(hdr.sb.st_gid == 01750);  	assert(hdr.sb.st_size == 8589934592);  	assert(hdr.sb.st_mtime == 013375730126); +	assert(hdr.mtime == 013375730126);  	assert(strcmp(hdr.name, "big-file.bin") == 0);  	assert(!hdr.unknown_record);  	clear_header(&hdr); @@ -105,6 +109,7 @@ int main(void)  	assert(hdr.sb.st_gid == 8388608);  	assert(hdr.sb.st_size == 5);  	assert(hdr.sb.st_mtime == 013376036700); +	assert(hdr.mtime == 013376036700);  	assert(strcmp(hdr.name, "input.txt") == 0);  	assert(!hdr.unknown_record);  	assert(read_data("data3", fd, buffer, 5) == 0); @@ -119,7 +124,12 @@ int main(void)  	assert(hdr.sb.st_uid == 01750);  	assert(hdr.sb.st_gid == 01750);  	assert(hdr.sb.st_size == 5); -	assert(hdr.sb.st_mtime == 8589934592); +#if SIZEOF_TIME_T < 8 +	assert(hdr.sb.st_mtime == INT32_MAX); +#else +	assert(hdr.sb.st_mtime == 8589934592L); +#endif +	assert(hdr.mtime == 8589934592L);  	assert(strcmp(hdr.name, "input.txt") == 0);  	assert(!hdr.unknown_record);  	assert(read_data("data4", fd, buffer, 5) == 0); @@ -135,6 +145,7 @@ int main(void)  	assert(hdr.sb.st_gid == 01750);  	assert(hdr.sb.st_size == 5);  	assert(hdr.sb.st_mtime == 1542909670); +	assert(hdr.mtime == 1542909670);  	assert(strcmp(hdr.name, filename) == 0);  	assert(!hdr.unknown_record);  	assert(read_data("data5", fd, buffer, 5) == 0); diff --git a/tests/tar_xattr_bsd.c b/tests/tar_xattr_bsd.c index 360448f..b2a1290 100644 --- a/tests/tar_xattr_bsd.c +++ b/tests/tar_xattr_bsd.c @@ -43,6 +43,7 @@ int main(void)  	assert(hdr.sb.st_gid == 01750);  	assert(hdr.sb.st_size == 5);  	assert(hdr.sb.st_mtime == 1543094477); +	assert(hdr.mtime == 1543094477);  	assert(strcmp(hdr.name, "input.txt") == 0);  	assert(!hdr.unknown_record);  	assert(read_data("data0", fd, buffer, 5) == 0); diff --git a/tests/tar_xattr_schily.c b/tests/tar_xattr_schily.c index e49bdd9..9030a45 100644 --- a/tests/tar_xattr_schily.c +++ b/tests/tar_xattr_schily.c @@ -43,6 +43,7 @@ int main(void)  	assert(hdr.sb.st_gid == 01750);  	assert(hdr.sb.st_size == 5);  	assert(hdr.sb.st_mtime == 1543094477); +	assert(hdr.mtime == 1543094477);  	assert(strcmp(hdr.name, "input.txt") == 0);  	assert(!hdr.unknown_record);  	assert(read_data("data0", fd, buffer, 5) == 0);  | 
