+ enum archive_format format;
+
+ if (strcmp (header->header.magic, TMAGIC) == 0)
+ {
+ if (header->star_header.prefix[130] == 0
+ && ISOCTAL (header->star_header.atime[0])
+ && header->star_header.atime[11] == ' '
+ && ISOCTAL (header->star_header.ctime[0])
+ && header->star_header.ctime[11] == ' ')
+ format = STAR_FORMAT;
+ else
+ format = POSIX_FORMAT;
+ }
+ else if (strcmp (header->header.magic, OLDGNU_MAGIC) == 0)
+ format = OLDGNU_FORMAT;
+ else
+ format = V7_FORMAT;
+ *format_pointer = format;
+
+ stat_info->stat.st_mode = MODE_FROM_HEADER (header->header.mode);
+ stat_info->stat.st_mtime = TIME_FROM_HEADER (header->header.mtime);
+ assign_string (&stat_info->uname, header->header.uname);
+ assign_string (&stat_info->gname, header->header.gname);
+ stat_info->devmajor = MAJOR_FROM_HEADER (header->header.devmajor);
+ stat_info->devminor = MINOR_FROM_HEADER (header->header.devminor);
+
+ if (format == OLDGNU_FORMAT && incremental_option)
+ {
+ stat_info->stat.st_atime = TIME_FROM_HEADER (header->oldgnu_header.atime);
+ stat_info->stat.st_ctime = TIME_FROM_HEADER (header->oldgnu_header.ctime);
+ }
+
+ if (format == V7_FORMAT)
+ {
+ stat_info->stat.st_uid = UID_FROM_HEADER (header->header.uid);
+ stat_info->stat.st_gid = GID_FROM_HEADER (header->header.gid);
+ stat_info->stat.st_rdev = 0;
+ }
+ else
+ {
+
+ if (format == STAR_FORMAT)
+ {
+ stat_info->stat.st_atime = TIME_FROM_HEADER (header->star_header.atime);
+ stat_info->stat.st_ctime = TIME_FROM_HEADER (header->star_header.ctime);
+ }
+
+ if (do_user_group)
+ {
+ /* FIXME: Decide if this should somewhat depend on -p. */
+
+ if (numeric_owner_option
+ || !*header->header.uname
+ || !uname_to_uid (header->header.uname, &stat_info->stat.st_uid))
+ stat_info->stat.st_uid = UID_FROM_HEADER (header->header.uid);
+
+ if (numeric_owner_option
+ || !*header->header.gname
+ || !gname_to_gid (header->header.gname, &stat_info->stat.st_gid))
+ stat_info->stat.st_gid = GID_FROM_HEADER (header->header.gid);
+ }
+
+ switch (header->header.typeflag)
+ {
+ case BLKTYPE:
+ case CHRTYPE:
+ stat_info->stat.st_rdev = makedev (stat_info->devmajor, stat_info->devminor);
+ break;
+
+ default:
+ stat_info->stat.st_rdev = 0;
+ }
+ }
+
+ if (extended_header.size)
+ xheader_decode (stat_info);
+}
+
+/* Convert buffer at WHERE0 of size DIGS from external format to
+ uintmax_t. The data is of type TYPE. The buffer must represent a
+ value in the range -MINUS_MINVAL through MAXVAL. DIGS must be
+ positive. Return -1 on error, diagnosing the error if TYPE is
+ nonzero. */
+static uintmax_t
+from_header (char const *where0, size_t digs, char const *type,
+ uintmax_t minus_minval, uintmax_t maxval)
+{
+ uintmax_t value;
+ char const *where = where0;
+ char const *lim = where + digs;
+ int negative = 0;
+
+ /* Accommodate buggy tar of unknown vintage, which outputs leading
+ NUL if the previous field overflows. */
+ where += !*where;
+
+ /* Accommodate older tars, which output leading spaces. */
+ for (;;)
+ {
+ if (where == lim)
+ {
+ if (type)
+ ERROR ((0, 0,
+ _("Blanks in header where numeric %s value expected"),
+ type));
+ return -1;
+ }
+ if (!ISSPACE ((unsigned char) *where))
+ break;
+ where++;
+ }
+
+ value = 0;
+ if (ISODIGIT (*where))
+ {
+ char const *where1 = where;
+ uintmax_t overflow = 0;
+
+ for (;;)
+ {
+ value += *where++ - '0';
+ if (where == lim || ! ISODIGIT (*where))
+ break;
+ overflow |= value ^ (value << LG_8 >> LG_8);
+ value <<= LG_8;
+ }
+
+ /* Parse the output of older, unportable tars, which generate
+ negative values in two's complement octal. If the leading
+ nonzero digit is 1, we can't recover the original value
+ reliably; so do this only if the digit is 2 or more. This
+ catches the common case of 32-bit negative time stamps. */
+ if ((overflow || maxval < value) && '2' <= *where1 && type)
+ {
+ /* Compute the negative of the input value, assuming two's
+ complement. */
+ int digit = (*where1 - '0') | 4;
+ overflow = 0;
+ value = 0;
+ where = where1;
+ for (;;)
+ {
+ value += 7 - digit;
+ where++;
+ if (where == lim || ! ISODIGIT (*where))
+ break;
+ digit = *where - '0';
+ overflow |= value ^ (value << LG_8 >> LG_8);
+ value <<= LG_8;
+ }
+ value++;
+ overflow |= !value;
+
+ if (!overflow && value <= minus_minval)
+ {
+ WARN ((0, 0,
+ _("Archive octal value %.*s is out of %s range; assuming two's complement"),
+ (int) (where - where1), where1, type));
+ negative = 1;
+ }
+ }