file_header_t *file_header = archive_handle->file_header;
struct tar_header_t tar;
char *cp;
+ int tar_typeflag; /* can be "char", "int" seems give smaller code */
int i, sum_u, sum;
#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
int sum_s;
* POSIX says that checksum is done on unsigned bytes, but
* Sun and HP-UX gets it wrong... more details in
* GNU tar source. */
+ sum_u = ' ' * sizeof(tar.chksum);
#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
- sum_s = ' ' * sizeof(tar.chksum);
+ sum_s = sum_u;
#endif
- sum_u = ' ' * sizeof(tar.chksum);
for (i = 0; i < 148; i++) {
sum_u += ((unsigned char*)&tar)[i];
#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
sum_s += ((signed char*)&tar)[i];
#endif
}
- /* This field does not need special treatment (getOctal) */
- {
- char *endp; /* gcc likes temp var for &endp */
- sum = strtoul(tar.chksum, &endp, 8);
- if ((*endp != '\0' && *endp != ' ')
- || (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum))
- ) {
- bb_error_msg_and_die("invalid tar header checksum");
- }
- }
- /* don't use xstrtoul, tar.chksum may have leading spaces */
- sum = strtoul(tar.chksum, NULL, 8);
- if (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) {
+ /* Most tarfiles have tar.chksum NUL or space terminated, but
+ * github.com decided to be "special" and have unterminated field:
+ * 0090: 30343300 30303031 33323731 30000000 |043.000132710...|
+ * ^^^^^^^^|
+ * Need to use GET_OCTAL. This overwrites tar.typeflag ---+
+ * (the '0' char immediately after chksum in example above) with NUL.
+ */
+ tar_typeflag = (uint8_t)tar.typeflag; /* save it */
+ sum = GET_OCTAL(tar.chksum);
+ if (sum_u != sum
+ IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)
+ ) {
bb_error_msg_and_die("invalid tar header checksum");
}
- /* 0 is reserved for high perf file, treat as normal file */
- if (!tar.typeflag) tar.typeflag = '0';
- parse_names = (tar.typeflag >= '0' && tar.typeflag <= '7');
-
- /* getOctal trashes subsequent field, therefore we call it
+ /* GET_OCTAL trashes subsequent field, therefore we call it
* on fields in reverse order */
if (tar.devmajor[0]) {
char t = tar.prefix[0];
file_header->device = makedev(major, minor);
tar.prefix[0] = t;
}
+
+ /* 0 is reserved for high perf file, treat as normal file */
+ if (tar_typeflag == '\0') tar_typeflag = '0';
+ parse_names = (tar_typeflag >= '0' && tar_typeflag <= '7');
+
file_header->link_target = NULL;
if (!p_linkname && parse_names && tar.linkname[0]) {
file_header->link_target = xstrndup(tar.linkname, sizeof(tar.linkname));
/* Set bits 12-15 of the files mode */
/* (typeflag was not trashed because chksum does not use getOctal) */
- switch (tar.typeflag) {
+ switch (tar_typeflag) {
case '1': /* hardlink */
/* we mark hardlinks as regular files with zero size and a link name */
file_header->mode |= S_IFREG;
case 'x': { /* pax extended header */
if ((uoff_t)file_header->size > 0xfffff) /* paranoia */
goto skip_ext_hdr;
- process_pax_hdr(archive_handle, file_header->size, (tar.typeflag == 'g'));
+ process_pax_hdr(archive_handle, file_header->size, (tar_typeflag == 'g'));
goto again_after_align;
#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
/* See http://www.gnu.org/software/tar/manual/html_node/Extensions.html */
skip_ext_hdr:
{
off_t sz;
- bb_error_msg("warning: skipping header '%c'", tar.typeflag);
+ bb_error_msg("warning: skipping header '%c'", tar_typeflag);
sz = (file_header->size + 511) & ~(off_t)511;
archive_handle->offset += sz;
sz >>= 9; /* sz /= 512 but w/o contortions for signed div */
goto again_after_align;
}
default:
- bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag);
+ bb_error_msg_and_die("unknown typeflag: 0x%x", tar_typeflag);
}
#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS