strdup-posix
strerror
strnlen
-strtoimax
-strtol
-strtoumax
symlinkat
sys_stat
timespec
xalloc
xalloc-die
xgetcwd
-xstrtoimax
xstrtoumax
xvasprintf
year2038-recommended
}
else if (strncmp (str, "sleep=", 6) == 0)
{
+ char const *arg = str + 6;
char *p;
- intmax_t sleepsec = strtoimax (str + 6, &p, 10);
- if (*p || sleepsec < 0)
- FATAL_ERROR ((0, 0, _("%s: not a valid timeout"), str));
- time_t n = ckd_add (&n, sleepsec, 0) ? TYPE_MAXIMUM (time_t) : n;
act = alloc_action (cop_sleep);
- act->v.time = n;
+ act->v.time = stoint (arg, &p, NULL, 0, TYPE_MAXIMUM (time_t));
+ if ((p == arg) | *p)
+ FATAL_ERROR ((0, 0, _("%s: not a valid timeout"), str));
}
else if (strcmp (str, "totals") == 0)
alloc_action (cop_totals);
"D"
};
-static long
+static intmax_t
getwidth (FILE *fp)
{
char const *columns;
columns = getenv ("COLUMNS");
if (columns)
{
- long int col = strtol (columns, NULL, 10);
- if (0 < col)
+ char *end;
+ intmax_t col = stoint (columns, &end, NULL, 0, INTMAX_MAX);
+ if (! (*end | !col))
return col;
}
case '*':
{
- long w = arg ? strtol (arg, NULL, 10) : getwidth (fp);
+ intmax_t w;
+ if (!arg)
+ w = getwidth (fp);
+ else
+ {
+ char *end;
+ w = stoint (arg, &end, NULL, 0, INTMAX_MAX);
+ if ((end == arg) | *end)
+ w = 80;
+ }
for (; w > len; len++)
fputc (' ', fp);
}
/* Specified file name for incremental list. */
extern const char *listed_incremental_option;
-/* Incremental dump level */
-extern int incremental_level;
+/* Incremental dump level: either -1, 0, or 1. */
+extern signed char incremental_level;
/* Check device numbers when doing incremental dumps. */
extern bool check_device_option;
enum { SYSINT_BUFSIZE =
max (UINTMAX_STRSIZE_BOUND, INT_BUFSIZE_BOUND (intmax_t)) };
char *sysinttostr (uintmax_t, intmax_t, uintmax_t, char buf[SYSINT_BUFSIZE]);
-intmax_t strtosysint (char const *, char **, intmax_t, uintmax_t);
+intmax_t stoint (char const *, char **, bool *, intmax_t, uintmax_t);
char *timetostr (time_t, char buf[SYSINT_BUFSIZE]);
void code_ns_fraction (int ns, char *p);
enum { BILLION = 1000000000, LOG10_BILLION = 9 };
read_incr_db_01 (int version, const char *initbuf)
{
int n;
- uintmax_t u;
char *buf = NULL;
size_t bufsize = 0;
char *ebuf;
if (version == 1 && *ebuf)
{
char const *buf_ns = ebuf + 1;
- errno = 0;
- u = strtoumax (buf_ns, &ebuf, 10);
- if (!errno && BILLION <= u)
- errno = ERANGE;
- if (errno || buf_ns == ebuf)
+ bool overflow;
+ newer_mtime_option.tv_nsec
+ = stoint (buf_ns, &ebuf, &overflow, 0, BILLION - 1);
+ if ((ebuf == buf_ns) | *ebuf | overflow)
{
- ERROR ((0, errno, "%s:%ld: %s",
+ ERROR ((0, 0, "%s:%ld: %s",
quotearg_colon (listed_incremental_option),
lineno,
_("Invalid time stamp")));
newer_mtime_option.tv_sec = TYPE_MINIMUM (time_t);
newer_mtime_option.tv_nsec = -1;
}
- else
- newer_mtime_option.tv_nsec = u;
}
}
quotearg_colon (listed_incremental_option), lineno,
_("Invalid modification time")));
- errno = 0;
- u = strtoumax (strp, &ebuf, 10);
- if (!errno && BILLION <= u)
- errno = ERANGE;
- if (errno || strp == ebuf || *ebuf != ' ')
+ bool overflow;
+ mtime.tv_nsec = stoint (strp, &ebuf, &overflow, 0, BILLION - 1);
+ if ((ebuf == strp) | (*ebuf != ' ') | overflow)
{
- FATAL_ERROR ((0, errno, "%s:%ld: %s",
+ FATAL_ERROR ((0, 0, "%s:%ld: %s",
quotearg_colon (listed_incremental_option), lineno,
_("Invalid modification time (nanoseconds)")));
mtime.tv_nsec = -1;
}
- else
- mtime.tv_nsec = u;
strp = ebuf;
}
else
mtime.tv_sec = mtime.tv_nsec = 0;
- dev = strtosysint (strp, &ebuf,
- TYPE_MINIMUM (dev_t), TYPE_MAXIMUM (dev_t));
- strp = ebuf;
- if (errno || *strp != ' ')
- FATAL_ERROR ((0, errno, "%s:%ld: %s",
+ bool overflow;
+ dev = stoint (strp, &ebuf, &overflow,
+ TYPE_MINIMUM (dev_t), TYPE_MAXIMUM (dev_t));
+ if ((ebuf == strp) | (*ebuf != ' ') | overflow)
+ FATAL_ERROR ((0, 0, "%s:%ld: %s",
quotearg_colon (listed_incremental_option), lineno,
_("Invalid device number")));
+ strp = ebuf + 1;
- ino = strtosysint (strp, &ebuf,
- TYPE_MINIMUM (ino_t), TYPE_MAXIMUM (ino_t));
- strp = ebuf;
- if (errno || *strp != ' ')
- FATAL_ERROR ((0, errno, "%s:%ld: %s",
+ ino = stoint (strp, &ebuf, &overflow,
+ TYPE_MINIMUM (ino_t), TYPE_MAXIMUM (ino_t));
+ if ((ebuf == strp) | (*ebuf != ' ') | overflow)
+ FATAL_ERROR ((0, 0, "%s:%ld: %s",
quotearg_colon (listed_incremental_option), lineno,
_("Invalid inode number")));
+ strp = ebuf + 1;
- strp++;
unquote_string (strp);
note_directory (strp, mtime, dev, ino, nfs, false, NULL);
}
{
int i;
char buf[INT_BUFSIZE_BOUND (intmax_t)];
- int conversion_errno;
int c = getc (fp);
bool negative = c == '-';
fieldname, buf, uc));
}
- *pval = strtosysint (buf, NULL, min_val, max_val);
- conversion_errno = errno;
+ char *bufend;
+ bool overflow;
+ *pval = stoint (buf, &bufend, &overflow, min_val, max_val);
- switch (conversion_errno)
- {
- case ERANGE:
- FATAL_ERROR ((0, conversion_errno,
- _("%s: byte %jd: (valid range %jd..%ju)\n\t%s %s"),
- quotearg_colon (listed_incremental_option),
- intmax (ftello (fp)), min_val, max_val, fieldname, buf));
- default:
- FATAL_ERROR ((0, conversion_errno,
- _("%s: byte %jd: %s %s"),
- quotearg_colon (listed_incremental_option),
- intmax (ftello (fp)), fieldname, buf));
- case 0:
- break;
- }
+ if (buf == bufend)
+ FATAL_ERROR ((0, EINVAL,
+ _("%s: byte %jd: %s %s"),
+ quotearg_colon (listed_incremental_option),
+ intmax (ftello (fp)), fieldname, buf));
+ if (overflow)
+ FATAL_ERROR ((0, ERANGE,
+ _("%s: byte %jd: (valid range %jd..%ju)\n\t%s %s"),
+ quotearg_colon (listed_incremental_option),
+ intmax (ftello (fp)), min_val, max_val, fieldname, buf));
return true;
}
if (0 < getline (&buf, &bufsize, listed_incremental_stream))
{
char *ebuf;
- uintmax_t incremental_version;
+ int incremental_version;
if (strncmp (buf, PACKAGE_NAME, sizeof PACKAGE_NAME - 1) == 0)
{
if (!*ebuf)
ERROR((1, 0, _("Bad incremental file format")));
- incremental_version = strtoumax (ebuf + 1, NULL, 10);
+ ebuf++;
+ if (! ('0' <= *ebuf && *ebuf <= '0' + TAR_INCREMENTAL_VERSION
+ && !c_isdigit (ebuf[1])))
+ ERROR ((1, 0, _("Unsupported incremental format version: %s"),
+ ebuf));
+ incremental_version = *ebuf - '0';
}
else
incremental_version = 0;
break;
default:
- ERROR ((1, 0, _("Unsupported incremental format version: %"PRIuMAX),
- incremental_version));
+ unreachable ();
}
-
}
if (ferror (listed_incremental_stream))
return map1->orig_id == map2->orig_id;
}
-static int
+static bool
parse_id (uintmax_t *retval,
char const *arg, char const *what, uintmax_t maxval,
char const *file, unsigned line)
{
- uintmax_t v;
char *p;
-
- errno = 0;
- v = strtoumax (arg, &p, 10);
- if (*p || errno)
+ bool overflow;
+ *retval = stoint (arg, &p, &overflow, 0, maxval);
+
+ if ((p == arg) | *p)
{
error (0, 0, _("%s:%u: invalid %s: %s"), file, line, what, arg);
- return -1;
+ return false;
}
- if (v > maxval)
+ if (overflow)
{
error (0, 0, _("%s:%u: %s out of range: %s"), file, line, what, arg);
- return -1;
+ return false;
}
- *retval = v;
- return 0;
+ return true;
}
static void
int wsopt;
unsigned line;
int err = 0;
-
+
fp = fopen (file, "r");
if (!fp)
open_fatal (file);
uintmax_t orig_id, new_id;
char *name = NULL;
char *colon;
-
+
++line;
if (wordsplit (buf, &ws, wsopt))
FATAL_ERROR ((0, 0, _("%s:%u: cannot split line: %s"),
if (ws.ws_wordv[0][0] == '+')
{
- if (parse_id (&orig_id, ws.ws_wordv[0]+1, what, maxval, file, line))
+ if (!parse_id (&orig_id, ws.ws_wordv[0]+1, what, maxval, file, line))
{
err = 1;
continue;
if (colon > ws.ws_wordv[1])
name = ws.ws_wordv[1];
*colon++ = 0;
- if (parse_id (&new_id, colon, what, maxval, file, line))
+ if (!parse_id (&new_id, colon, what, maxval, file, line))
{
err = 1;
continue;
}
else if (ws.ws_wordv[1][0] == '+')
{
- if (parse_id (&new_id, ws.ws_wordv[1], what, maxval, file, line))
+ if (!parse_id (&new_id, ws.ws_wordv[1], what, maxval, file, line))
{
err = 1;
continue;
ent->orig_id = orig_id;
ent->new_id = new_id;
ent->new_name = name ? xstrdup (name) : NULL;
-
+
if (!((*ptab
|| (*ptab = hash_initialize (0, 0, map_hash, map_compare, 0)))
&& hash_insert (*ptab, ent)))
owner_map_translate (uid_t uid, uid_t *new_uid, char const **new_name)
{
int rc = 1;
-
+
if (owner_map)
{
struct mapentry ent, *res;
-
+
ent.orig_id = uid;
res = hash_lookup (owner_map, &ent);
if (res)
group_map_translate (gid_t gid, gid_t *new_gid, char const **new_name)
{
int rc = 1;
-
+
if (group_map)
{
struct mapentry ent, *res;
-
+
ent.orig_id = gid;
res = hash_lookup (group_map, &ent);
if (res)
*new_name = group_name_option;
rc = 0;
}
-
+
return rc;
}
return sysinttostr (t, TYPE_MINIMUM (time_t), TYPE_MAXIMUM (time_t), buf);
}
-/* Convert a prefix of the string ARG to a system integer type whose
- minimum value is MINVAL and maximum MAXVAL. If MINVAL is negative,
+/* Convert a prefix of the string ARG to a system integer type.
+ If ARGLIM, set *ARGLIM to point to just after the prefix.
+ If OVERFLOW, set *OVERFLOW to true or false
+ depending on whether the input is out of MINVAL..MAXVAL range.
+ If the input is out of that range, return an extreme value.
+ MINVAL must not be positive.
+
+ If MINVAL is negative, MAXVAL can be at most INTMAX_MAX, and
negative integers MINVAL .. -1 are assumed to be represented using
leading '-' in the usual way. If the represented value exceeds
INTMAX_MAX, return a negative integer V such that (uintmax_t) V
- yields the represented value. If ARGLIM is nonnull, store into
- *ARGLIM a pointer to the first character after the prefix.
+ yields the represented value.
+
+ On conversion error: if ARGLIM set *ARGLIM = ARG; if OVERFLOW set
+ *OVERFLOW = false; then return 0.
This is the inverse of sysinttostr.
- On a normal return, set errno = 0.
- On conversion error, return 0 and set errno = EINVAL.
- On overflow, return an extreme value and set errno = ERANGE. */
+ Sample call to this function:
+
+ char *s_end;
+ bool overflow;
+ idx_t i = stoint (s, &s_end, &overflow, 0, IDX_MAX);
+ if ((s_end == s) | *s_end | overflow)
+ diagnose_invalid (s);
+
+ This example uses "|" instead of "||" for fewer branches at runtime,
+ which tends to be more efficient on modern processors.
+
+ This function is named "stoint" instead of "strtoint" because
+ <string.h> reserves names beginning with "str". */
+
intmax_t
-strtosysint (char const *arg, char **arglim, intmax_t minval, uintmax_t maxval)
+stoint (char const *arg, char **arglim, bool *overflow,
+ intmax_t minval, uintmax_t maxval)
{
static_assert (INTMAX_MAX <= UINTMAX_MAX);
+ char const *p = arg;
+ intmax_t i;
+ bool v = false;
- errno = 0;
- if (maxval <= INTMAX_MAX)
+ if (c_isdigit (*p))
{
- if (c_isdigit (arg[*arg == '-']))
+ if (minval < 0)
{
- intmax_t i = strtoimax (arg, arglim, 10);
- intmax_t imaxval = maxval;
- if (minval <= i && i <= imaxval)
- return i;
- errno = ERANGE;
- return i < minval ? minval : maxval;
+ i = *p - '0';
+
+ while (c_isdigit (*++p))
+ {
+ v |= ckd_mul (&i, i, 10);
+ v |= ckd_add (&i, i, *p - '0');
+ }
+
+ v |= maxval < i;
+ if (v)
+ i = maxval;
+ }
+ else
+ {
+ uintmax_t u = *p - '0';
+
+ while (c_isdigit (*++p))
+ {
+ v |= ckd_mul (&u, u, 10);
+ v |= ckd_add (&u, u, *p - '0');
+ }
+
+ v |= maxval < u;
+ if (v)
+ u = maxval;
+ i = represent_uintmax (u);
}
}
- else
+ else if (minval < 0 && *p == '-' && c_isdigit (p[1]))
{
- if (c_isdigit (*arg))
+ p++;
+ i = - (*p - '0');
+
+ while (c_isdigit (*++p))
{
- uintmax_t i = strtoumax (arg, arglim, 10);
- if (i <= maxval)
- return represent_uintmax (i);
- errno = ERANGE;
- return maxval;
+ v |= ckd_mul (&i, i, 10);
+ v |= ckd_sub (&i, i, *p - '0');
}
+
+ v |= i < minval;
+ if (v)
+ i = minval;
}
+ else
+ i = 0;
- errno = EINVAL;
- return 0;
+ if (arglim)
+ *arglim = (char *) p;
+ if (overflow)
+ *overflow = v;
+ return i;
}
/* Output fraction and trailing digits appropriate for a nanoseconds
struct timespec
decode_timespec (char const *arg, char **arg_lim, bool parse_fraction)
{
- time_t s = TYPE_MINIMUM (time_t);
int ns = -1;
- char const *p = arg;
- bool negative = *arg == '-';
- struct timespec r;
-
- if (! c_isdigit (arg[negative]))
- errno = EINVAL;
- else
+ bool overflow;
+ time_t s = stoint (arg, arg_lim, &overflow,
+ TYPE_MINIMUM (time_t), TYPE_MAXIMUM (time_t));
+ char const *p = *arg_lim;
+ if (p != arg)
{
- errno = 0;
-
- if (negative)
- {
- intmax_t i = strtoimax (arg, arg_lim, 10);
- if (TYPE_SIGNED (time_t) ? TYPE_MINIMUM (time_t) <= i : 0 <= i)
- s = i;
- else
- errno = ERANGE;
- }
- else
- {
- uintmax_t i = strtoumax (arg, arg_lim, 10);
- if (i <= TYPE_MAXIMUM (time_t))
- s = i;
- else
- errno = ERANGE;
- }
-
- p = *arg_lim;
ns = 0;
if (parse_fraction && *p == '.')
else
trailing_nonzero |= *p != '0';
+ *arg_lim = (char *) p;
+
while (digits < LOG10_BILLION)
digits++, ns *= 10;
- if (negative)
+ if (*arg == '-')
{
/* Convert "-1.10000000000001" to s == -2, ns == 89999999.
I.e., truncate time stamps towards minus infinity while
converting them to internal form. */
ns += trailing_nonzero;
if (ns != 0)
- {
- if (s == TYPE_MINIMUM (time_t))
- ns = -1;
- else
- {
- s--;
- ns = BILLION - ns;
- }
- }
+ ns = ckd_sub (&s, s, 1) ? -1 : BILLION - ns;
}
}
- if (errno == ERANGE)
+ if (overflow)
ns = -1;
}
- *arg_lim = (char *) p;
- r.tv_sec = s;
- r.tv_nsec = ns;
- return r;
+ return (struct timespec) { .tv_sec = s, .tv_nsec = ns };
}
\f
/* File handling. */
static bool
decode_num (uintmax_t *num, char const *arg, uintmax_t maxval)
{
- uintmax_t u;
char *arg_lim;
-
- if (!c_isdigit (*arg))
- return false;
-
- errno = 0;
- u = strtoumax (arg, &arg_lim, 10);
-
- if (! (u <= maxval && errno != ERANGE) || *arg_lim)
- return false;
-
- *num = u;
- return true;
+ bool overflow;
+ *num = stoint (arg, &arg_lim, &overflow, 0, maxval);
+ return ! ((arg_lim == arg) | *arg_lim | overflow);
}
static bool
enum old_files old_files_option;
bool keep_directory_symlink_option;
const char *listed_incremental_option;
-int incremental_level;
+signed char incremental_level;
bool check_device_option;
struct mode_change *mode_option;
mode_t initial_umask;
static uintmax_t
parse_owner_group (char *arg, uintmax_t field_max, char const **name_option)
{
- uintmax_t u = UINTMAX_MAX;
- char *end;
- char const *name = 0;
- char const *invalid_num = 0;
+ char const *name = NULL;
+ char const *num = arg;
char *colon = strchr (arg, ':');
-
if (colon)
{
- char const *num = colon + 1;
+ num = colon + 1;
*colon = '\0';
- if (*arg)
+ if (arg != colon)
name = arg;
- if (num && (! (xstrtoumax (num, &end, 10, &u, "") == LONGINT_OK
- && u <= field_max)))
- invalid_num = num;
}
- else
- {
- uintmax_t u1;
- switch ('0' <= *arg && *arg <= '9'
- ? xstrtoumax (arg, &end, 10, &u1, "")
- : LONGINT_INVALID)
- {
- default:
- name = arg;
- break;
- case LONGINT_OK:
- if (u1 <= field_max)
- {
- u = u1;
- break;
- }
- FALLTHROUGH;
- case LONGINT_OVERFLOW:
- invalid_num = arg;
- break;
- }
- }
-
- if (invalid_num)
- FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (invalid_num),
+ bool overflow;
+ char *end;
+ uintmax_t u = stoint (num, &end, &overflow, 0, field_max);
+ if ((end == num) | *end | overflow)
+ FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (num),
_("Invalid owner or group ID")));
- if (name)
+ if (name_option)
*name_option = name;
return u;
}
case 'b':
{
- uintmax_t u;
- if (! (xstrtoumax (arg, 0, 10, &u, "") == LONGINT_OK
- && !ckd_add (&blocking_factor, u, 0)
- && 0 < blocking_factor
- && !ckd_mul (&record_size, u, BLOCKSIZE)
- && record_size <= min (SSIZE_MAX, SIZE_MAX)))
+ bool overflow;
+ char *end;
+ blocking_factor = stoint (arg, &end, &overflow, 0,
+ (min (IDX_MAX, min (SSIZE_MAX, SIZE_MAX))
+ / BLOCKSIZE));
+ if ((end == arg) | *end | overflow | !blocking_factor)
USAGE_ERROR ((0, 0, "%s: %s", quotearg_colon (arg),
_("Invalid blocking factor")));
+ record_size = blocking_factor * BLOCKSIZE;
}
break;
case LEVEL_OPTION:
{
- uintmax_t u;
- if (! (xstrtoumax (arg, nullptr, 10, &u, "") == LONGINT_OK
- && ckd_add (&incremental_level, u, 0)))
+ char *end;
+ incremental_level = stoint (arg, &end, NULL, 0, 1);
+ if ((end == arg) | *end)
USAGE_ERROR ((0, 0, _("Invalid incremental level value")));
}
break;
sparse_option = true;
{
char *p;
- bool ok;
- switch (xstrtoimax (arg, &p, 10, &tar_sparse_major, ""))
- {
- case LONGINT_OK:
- tar_sparse_minor = 0;
- ok = 0 <= tar_sparse_major;
- break;
-
- case LONGINT_INVALID_SUFFIX_CHAR:
- ok = (*p == '.'
- && (xstrtoimax (p + 1, nullptr, 10, &tar_sparse_minor, "")
- == LONGINT_OK)
- && 0 <= tar_sparse_minor && 0 <= tar_sparse_major);
- break;
-
- default:
- ok = false;
- break;
- }
- if (!ok)
+ bool vmajor, vminor;
+ tar_sparse_major = stoint (arg, &p, &vmajor, 0, INTMAX_MAX);
+ if ((p != arg) & (*p == '.'))
+ tar_sparse_minor = stoint (p + 1, &p, &vminor, 0, INTMAX_MAX);
+ if ((p == arg) | *p | vmajor | vminor)
USAGE_ERROR ((0, 0, _("Invalid sparse version value")));
}
break;
checkpoint_compile_action (".");
arg++;
}
- checkpoint_option = strtoimax (arg, &p, 0);
- if (*p || checkpoint_option <= 0)
+ checkpoint_option = stoint (arg, &p, NULL, 0, INTMAX_MAX);
+ if (*p | (checkpoint_option <= 0))
FATAL_ERROR ((0, 0,
_("invalid --checkpoint value")));
}
occurrence_option = 1;
else
{
- uintmax_t u;
- if (xstrtoumax (arg, 0, 10, &u, "") == LONGINT_OK)
- occurrence_option = u;
- else
+ char *end;
+ occurrence_option = stoint (arg, &end, NULL, 0, UINTMAX_MAX);
+ if (*end)
FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (arg),
_("Invalid number")));
}
case STRIP_COMPONENTS_OPTION:
{
- uintmax_t u;
- if (! (xstrtoumax (arg, 0, 10, &u, "") == LONGINT_OK
- && !ckd_add (&strip_name_components, u, 0)))
+ char *end;
+ strip_name_components = stoint (arg, &end, NULL, 0, SIZE_MAX);
+ if (*end)
USAGE_ERROR ((0, 0, "%s: %s", quotearg_colon (arg),
_("Invalid number of elements")));
}
case '5': case '6': case '7': case '8': case '9':
{
char *endp;
- intmax_t match_number = strtoimax (p, &endp, 10);
- assume (0 <= match_number);
- if (ckd_add (&tf->match_number, match_number, 0))
- tf->match_number = IDX_MAX;
+ tf->match_number = stoint (p, &endp, NULL, 0, IDX_MAX);
p = endp - 1;
}
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
- intmax_t n = strtoimax (cur, &cur, 10);
- assume (0 <= n);
+ idx_t n = stoint (cur, &cur, NULL, 0, IDX_MAX);
if (tf->regex.re_nsub < n)
USAGE_ERROR ((0, 0, _("Invalid transform replacement:"
" back reference out of range")));
{
char *start = *ptr;
char *p = start;
- size_t len;
char *len_lim;
char const *keyword;
char *nextp;
- size_t len_max = xhdr->buffer + xhdr->size - start;
+ idx_t len_max = xhdr->buffer + xhdr->size - start;
while (*p == ' ' || *p == '\t')
p++;
- if (! c_isdigit (*p))
+ idx_t len = stoint (p, &len_lim, NULL, 0, IDX_MAX);
+
+ if (len_lim == p)
{
+ /* The length is missing.
+ FIXME: Comment why this is diagnosed only if (*p), or change code. */
if (*p)
ERROR ((0, 0, _("Malformed extended header: missing length")));
return false;
}
- len = strtoumax (p, &len_lim, 10);
-
if (len_max < len)
{
- int len_len = len_lim - p;
+ /* Avoid giant diagnostics, as this won't help user. */
+ int len_len = min (len_lim - p, 1000);
+
ERROR ((0, 0, _("Extended header length %.*s is out of range"),
len_len, p));
return false;
char const *keyword)
{
char *arg_lim;
- intmax_t u = strtosysint (arg, &arg_lim, minval, maxval);
+ bool overflow;
+ intmax_t u = stoint (arg, &arg_lim, &overflow, minval, maxval);
- if (errno == EINVAL || *arg_lim)
+ if ((arg_lim == arg) | *arg_lim)
{
ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"),
keyword, arg));
return false;
}
- if (errno == ERANGE)
+ if (overflow)
{
out_of_range_header (keyword, arg, minval, maxval);
return false;
char const *arg,
MAYBE_UNUSED size_t size)
{
- int offset = 1;
+ bool offset = true;
struct sp_array e;
st->sparse_map_avail = 0;
- while (1)
+ while (true)
{
- intmax_t u;
char *delim;
-
- if (!c_isdigit (*arg))
+ bool overflow;
+ off_t u = stoint (arg, &delim, &overflow, 0, TYPE_MAXIMUM (off_t));
+ if (delim == arg)
{
ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"),
keyword, arg));
return;
}
- errno = 0;
- u = strtoimax (arg, &delim, 10);
- if (TYPE_MAXIMUM (off_t) < u)
- {
- u = TYPE_MAXIMUM (off_t);
- errno = ERANGE;
- }
if (offset)
{
e.offset = u;
- if (errno == ERANGE)
+ if (overflow)
{
out_of_range_header (keyword, arg, 0, TYPE_MAXIMUM (off_t));
return;
else
{
e.numbytes = u;
- if (errno == ERANGE)
+ if (overflow)
{
out_of_range_header (keyword, arg, 0, TYPE_MAXIMUM (off_t));
return;