OSS-Fuzz Issue 806: integer overflow in mtree_atol10

Rework the mtree_atol10 integer parser so it can parse
INT64_MIN without overflowing the intermediate value.

While here, make this function behave a little more predictably for
too-large input: It now always advances the pointer to the first
non-digit character.
diff --git a/libarchive/archive_read_support_format_mtree.c b/libarchive/archive_read_support_format_mtree.c
index 4231ff5..00d3250 100644
--- a/libarchive/archive_read_support_format_mtree.c
+++ b/libarchive/archive_read_support_format_mtree.c
@@ -1857,33 +1857,38 @@
  * Note that this implementation does not (and should not!) obey
  * locale settings; you cannot simply substitute strtol here, since
  * it does obey locale.
+ *
+ * Convert the number pointed to by 'p' into a 64-bit signed integer.
+ * On return, 'p' points to the first non-digit following the number.
+ * On overflow, the function returns INT64_MIN or INT64_MAX.
  */
 static int64_t
 mtree_atol10(char **p)
 {
-	int64_t l, limit, last_digit_limit;
-	int base, digit, sign;
-
-	base = 10;
+	const int base = 10;
+	const int64_t limit = INT64_MAX / base;
+	const int64_t last_digit_limit = INT64_MAX % base;
+	int64_t l;
+	int sign;
 
 	if (**p == '-') {
 		sign = -1;
-		limit = ((uint64_t)(INT64_MAX) + 1) / base;
-		last_digit_limit = ((uint64_t)(INT64_MAX) + 1) % base;
 		++(*p);
 	} else {
 		sign = 1;
-		limit = INT64_MAX / base;
-		last_digit_limit = INT64_MAX % base;
 	}
 
 	l = 0;
-	digit = **p - '0';
-	while (digit >= 0 && digit < base) {
-		if (l > limit || (l == limit && digit > last_digit_limit))
+	while (**p >= '0' && **p < '0' + base) {
+		int digit = **p - '0';
+		if (l > limit || (l == limit && digit > last_digit_limit)) {
+			while (**p >= '0' && **p < '0' + base) {
+				++(*p);
+			}
 			return (sign < 0) ? INT64_MIN : INT64_MAX;
+		}
 		l = (l * base) + digit;
-		digit = *++(*p) - '0';
+		++(*p);
 	}
 	return (sign < 0) ? -l : l;
 }