summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-07-24 13:36:50 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-07-24 18:10:34 +0200
commit4fdfd1f62a9d50298b0bb71e8bea04174af4a3ab (patch)
treed511b488ce77ef2b0b84b26ead69a1d01375491c
parent30fbd496a1793b4374873144432f9b7a996a689d (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.ac3
-rw-r--r--include/tar.h4
-rw-r--r--lib/tar/read_header.c19
-rw-r--r--m4/m4_ax_compile_check_sizeof.m4115
-rw-r--r--tests/tar_gnu.c13
-rw-r--r--tests/tar_pax.c12
-rw-r--r--tests/tar_ustar.c13
-rw-r--r--tests/tar_xattr_bsd.c1
-rw-r--r--tests/tar_xattr_schily.c1
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);