aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTim Kientzle <kientzle@FreeBSD.org>2004-07-24 17:46:45 +0000
committerTim Kientzle <kientzle@FreeBSD.org>2004-07-24 17:46:45 +0000
commit45e13f191fe7c409272ed4cfbbc75f88a4e4f915 (patch)
tree2249be6464441f01f2a4f6bd0f6635ac194dc03c /lib
parent572bde2aea65923e1ee1aa98c5aba50c54fd5cd4 (diff)
Notes
Diffstat (limited to 'lib')
-rw-r--r--lib/libarchive/archive_read_support_format_tar.c100
1 files changed, 68 insertions, 32 deletions
diff --git a/lib/libarchive/archive_read_support_format_tar.c b/lib/libarchive/archive_read_support_format_tar.c
index ce71675f9319..d49838c0a70a 100644
--- a/lib/libarchive/archive_read_support_format_tar.c
+++ b/lib/libarchive/archive_read_support_format_tar.c
@@ -173,6 +173,28 @@ static int tar_read_header(struct archive *, struct tar *,
struct archive_entry *, struct stat *);
static int utf8_decode(wchar_t *, const char *, size_t length);
+/*
+ * ANSI C99 defines constants for these, but not everyone supports
+ * those constants, so I define a couple of static variables here and
+ * compute the values. These calculations should be portable to any
+ * 2s-complement architecture.
+ */
+#ifdef UINT64_MAX
+static const uint64_t max_uint64 = UINT64_MAX;
+#else
+static const uint64_t max_uint64 = ~(uint64_t)0;
+#endif
+#ifdef INT64_MAX
+static const int64_t max_int64 = INT64_MAX;
+#else
+static const int64_t max_int64 = (int64_t)((~(uint64_t)0) >> 1);
+#endif
+#ifdef INT64_MIN
+static const int64_t min_int64 = INT64_MIN;
+#else
+static const int64_t min_int64 = (int64_t)(~max_int64);
+#endif
+
int
archive_read_support_format_gnutar(struct archive *a)
{
@@ -1154,9 +1176,10 @@ pax_time(const wchar_t *p, int64_t *ps, long *pn)
int64_t s;
unsigned long l;
int sign;
+ int64_t limit, last_digit_limit;
- static const int64_t limit64 = INT64_MAX / 10;
- static const char last_digit_limit64 = INT64_MAX % 10;
+ limit = max_int64 / 10;
+ last_digit_limit = max_int64 % 10;
s = 0;
sign = 1;
@@ -1166,9 +1189,9 @@ pax_time(const wchar_t *p, int64_t *ps, long *pn)
}
while (*p >= '0' && *p <= '9') {
digit = *p - '0';
- if (s > limit64 ||
- (s == limit64 && digit > last_digit_limit64)) {
- s = UINT64_MAX; /* Truncate on overflow */
+ if (s > limit ||
+ (s == limit && digit > last_digit_limit)) {
+ s = max_uint64;
break;
}
s = (s * 10) + digit;
@@ -1346,6 +1369,10 @@ gnu_parse_sparse_data(struct archive *a, struct tar *tar,
static int64_t
tar_atol(const char *p, unsigned char_cnt)
{
+ /*
+ * Technically, GNU tar considers a field to be in base-256
+ * only if the first byte is 0xff or 0x80.
+ */
if (*p & 0x80)
return (tar_atol256(p, char_cnt));
return (tar_atol8(p, char_cnt));
@@ -1359,12 +1386,12 @@ tar_atol(const char *p, unsigned char_cnt)
static int64_t
tar_atol8(const char *p, unsigned char_cnt)
{
- int64_t l;
- int digit, sign;
+ int64_t l, limit, last_digit_limit;
+ int digit, sign, base;
- static const int64_t limit = INT64_MAX / 8;
- static const int base = 8;
- static const char last_digit_limit = INT64_MAX % 8;
+ base = 8;
+ limit = max_int64 / base;
+ last_digit_limit = max_int64 % base;
while (*p == ' ' || *p == '\t')
p++;
@@ -1378,7 +1405,7 @@ tar_atol8(const char *p, unsigned char_cnt)
digit = *p - '0';
while (digit >= 0 && digit < base && char_cnt-- > 0) {
if (l>limit || (l == limit && digit > last_digit_limit)) {
- l = UINT64_MAX; /* Truncate on overflow */
+ l = max_uint64; /* Truncate on overflow. */
break;
}
l = (l * base) + digit;
@@ -1396,12 +1423,12 @@ tar_atol8(const char *p, unsigned char_cnt)
static int64_t
tar_atol10(const wchar_t *p, unsigned char_cnt)
{
- int64_t l;
- int digit, sign;
+ int64_t l, limit, last_digit_limit;
+ int base, digit, sign;
- static const int64_t limit = INT64_MAX / 10;
- static const int base = 10;
- static const char last_digit_limit = INT64_MAX % 10;
+ base = 10;
+ limit = max_int64 / base;
+ last_digit_limit = max_int64 % base;
while (*p == ' ' || *p == '\t')
p++;
@@ -1415,7 +1442,7 @@ tar_atol10(const wchar_t *p, unsigned char_cnt)
digit = *p - '0';
while (digit >= 0 && digit < base && char_cnt-- > 0) {
if (l > limit || (l == limit && digit > last_digit_limit)) {
- l = UINT64_MAX; /* Truncate on overflow */
+ l = max_uint64; /* Truncate on overflow. */
break;
}
l = (l * base) + digit;
@@ -1424,29 +1451,38 @@ tar_atol10(const wchar_t *p, unsigned char_cnt)
return (sign < 0) ? -l : l;
}
-
-
/*
- * Parse a base-256 integer.
+ * Parse a base-256 integer. This is just a straight signed binary
+ * value in big-endian order, except that the high-order bit is
+ * ignored. Remember that "int64_t" may or may not be exactly 64
+ * bits; the implementation here tries to avoid making any assumptions
+ * about the actual size of an int64_t. It does assume we're using
+ * twos-complement arithmetic, though.
*/
static int64_t
-tar_atol256(const char *p, unsigned char_cnt)
+tar_atol256(const char *_p, unsigned char_cnt)
{
- int64_t l;
- int digit;
+ int64_t l, upper_limit, lower_limit;
+ const unsigned char *p = _p;
- const int64_t limit = INT64_MAX / 256;
+ upper_limit = max_int64 / 256;
+ lower_limit = min_int64 / 256;
- /* Ignore high bit of first byte (that's the base-256 flag). */
- l = 0;
- digit = 0x7f & *(const unsigned char *)p;
- while (char_cnt-- > 0) {
- if (l > limit) {
- l = INT64_MAX; /* Truncate on overflow */
+ /* Pad with 1 or 0 bits, depending on sign. */
+ if ((0x40 & *p) == 0x40)
+ l = (int64_t)-1;
+ else
+ l = 0;
+ l = (l << 6) | (0x3f & *p++);
+ while (--char_cnt > 0) {
+ if (l > upper_limit) {
+ l = max_int64; /* Truncate on overflow */
+ break;
+ } else if (l < lower_limit) {
+ l = min_int64;
break;
}
- l = (l << 8) + digit;
- digit = *(const unsigned char *)++p;
+ l = (l << 8) | (0xff & (int64_t)*p++);
}
return (l);
}