348 lines · 9.4 KB · C
RawDownload
/* * Convert integer string representation to an integer. * If an integer doesn't fit into specified type, -E is returned. * * Integer starts with optional sign. * kstrtou*() functions do not accept sign "-". * * Radix 0 means autodetection: leading "0x" implies radix 16, * leading "0" implies radix 8, otherwise radix is 10. * Autodetection hints work after optional sign, but not before. * * If -E is returned, result is not touched. */#include <linux/ctype.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/math64.h>#include <linux/export.h>#include <linux/types.h>#include <asm/uaccess.h>#include "kstrtox.h" const char *_parse_integer_fixup_radix(const char *s, unsigned int *base){	if (*base == 0) {		if (s[0] == '0') {			if (_tolower(s[1]) == 'x' && isxdigit(s[2]))				*base = 16;			else				*base = 8;		} else			*base = 10;	}	if (*base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')		s += 2;	return s;} /* * Convert non-negative integer string representation in explicitly given radix * to an integer. * Return number of characters consumed maybe or-ed with overflow bit. * If overflow occurs, result integer (incorrect) is still returned. * * Don't you dare use this function. */unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *p){	unsigned long long res;	unsigned int rv;	int overflow; 	res = 0;	rv = 0;	overflow = 0;	while (*s) {		unsigned int val; 		if ('0' <= *s && *s <= '9')			val = *s - '0';		else if ('a' <= _tolower(*s) && _tolower(*s) <= 'f')			val = _tolower(*s) - 'a' + 10;		else			break; 		if (val >= base)			break;		/*		 * Check for overflow only if we are within range of		 * it in the max base we support (16)		 */		if (unlikely(res & (~0ull << 60))) {			if (res > div_u64(ULLONG_MAX - val, base))				overflow = 1;		}		res = res * base + val;		rv++;		s++;	}	*p = res;	if (overflow)		rv |= KSTRTOX_OVERFLOW;	return rv;} static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res){	unsigned long long _res;	unsigned int rv; 	s = _parse_integer_fixup_radix(s, &base);	rv = _parse_integer(s, base, &_res);	if (rv & KSTRTOX_OVERFLOW)		return -ERANGE;	rv &= ~KSTRTOX_OVERFLOW;	if (rv == 0)		return -EINVAL;	s += rv;	if (*s == '\n')		s++;	if (*s)		return -EINVAL;	*res = _res;	return 0;} /** * kstrtoull - convert a string to an unsigned long long * @s: The start of the string. The string must be null-terminated, and may also *  include a single newline before its terminating null. The first character *  may also be a plus sign, but not a minus sign. * @base: The number base to use. The maximum supported base is 16. If base is *  given as 0, then the base of the string is automatically detected with the *  conventional semantics - If it begins with 0x the number will be parsed as a *  hexadecimal (case insensitive), if it otherwise begins with 0, it will be *  parsed as an octal number. Otherwise it will be parsed as a decimal. * @res: Where to write the result of the conversion on success. * * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. * Used as a replacement for the obsolete simple_strtoull. Return code must * be checked. */int kstrtoull(const char *s, unsigned int base, unsigned long long *res){	if (s[0] == '+')		s++;	return _kstrtoull(s, base, res);}EXPORT_SYMBOL(kstrtoull); /** * kstrtoll - convert a string to a long long * @s: The start of the string. The string must be null-terminated, and may also *  include a single newline before its terminating null. The first character *  may also be a plus sign or a minus sign. * @base: The number base to use. The maximum supported base is 16. If base is *  given as 0, then the base of the string is automatically detected with the *  conventional semantics - If it begins with 0x the number will be parsed as a *  hexadecimal (case insensitive), if it otherwise begins with 0, it will be *  parsed as an octal number. Otherwise it will be parsed as a decimal. * @res: Where to write the result of the conversion on success. * * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. * Used as a replacement for the obsolete simple_strtoull. Return code must * be checked. */int kstrtoll(const char *s, unsigned int base, long long *res){	unsigned long long tmp;	int rv; 	if (s[0] == '-') {		rv = _kstrtoull(s + 1, base, &tmp);		if (rv < 0)			return rv;		if ((long long)(-tmp) >= 0)			return -ERANGE;		*res = -tmp;	} else {		rv = kstrtoull(s, base, &tmp);		if (rv < 0)			return rv;		if ((long long)tmp < 0)			return -ERANGE;		*res = tmp;	}	return 0;}EXPORT_SYMBOL(kstrtoll); /* Internal, do not use. */int _kstrtoul(const char *s, unsigned int base, unsigned long *res){	unsigned long long tmp;	int rv; 	rv = kstrtoull(s, base, &tmp);	if (rv < 0)		return rv;	if (tmp != (unsigned long long)(unsigned long)tmp)		return -ERANGE;	*res = tmp;	return 0;}EXPORT_SYMBOL(_kstrtoul); /* Internal, do not use. */int _kstrtol(const char *s, unsigned int base, long *res){	long long tmp;	int rv; 	rv = kstrtoll(s, base, &tmp);	if (rv < 0)		return rv;	if (tmp != (long long)(long)tmp)		return -ERANGE;	*res = tmp;	return 0;}EXPORT_SYMBOL(_kstrtol); /** * kstrtouint - convert a string to an unsigned int * @s: The start of the string. The string must be null-terminated, and may also *  include a single newline before its terminating null. The first character *  may also be a plus sign, but not a minus sign. * @base: The number base to use. The maximum supported base is 16. If base is *  given as 0, then the base of the string is automatically detected with the *  conventional semantics - If it begins with 0x the number will be parsed as a *  hexadecimal (case insensitive), if it otherwise begins with 0, it will be *  parsed as an octal number. Otherwise it will be parsed as a decimal. * @res: Where to write the result of the conversion on success. * * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. * Used as a replacement for the obsolete simple_strtoull. Return code must * be checked. */int kstrtouint(const char *s, unsigned int base, unsigned int *res){	unsigned long long tmp;	int rv; 	rv = kstrtoull(s, base, &tmp);	if (rv < 0)		return rv;	if (tmp != (unsigned long long)(unsigned int)tmp)		return -ERANGE;	*res = tmp;	return 0;}EXPORT_SYMBOL(kstrtouint); /** * kstrtoint - convert a string to an int * @s: The start of the string. The string must be null-terminated, and may also *  include a single newline before its terminating null. The first character *  may also be a plus sign or a minus sign. * @base: The number base to use. The maximum supported base is 16. If base is *  given as 0, then the base of the string is automatically detected with the *  conventional semantics - If it begins with 0x the number will be parsed as a *  hexadecimal (case insensitive), if it otherwise begins with 0, it will be *  parsed as an octal number. Otherwise it will be parsed as a decimal. * @res: Where to write the result of the conversion on success. * * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. * Used as a replacement for the obsolete simple_strtoull. Return code must * be checked. */int kstrtoint(const char *s, unsigned int base, int *res){	long long tmp;	int rv; 	rv = kstrtoll(s, base, &tmp);	if (rv < 0)		return rv;	if (tmp != (long long)(int)tmp)		return -ERANGE;	*res = tmp;	return 0;}EXPORT_SYMBOL(kstrtoint); int kstrtou16(const char *s, unsigned int base, u16 *res){	unsigned long long tmp;	int rv; 	rv = kstrtoull(s, base, &tmp);	if (rv < 0)		return rv;	if (tmp != (unsigned long long)(u16)tmp)		return -ERANGE;	*res = tmp;	return 0;}EXPORT_SYMBOL(kstrtou16); int kstrtos16(const char *s, unsigned int base, s16 *res){	long long tmp;	int rv; 	rv = kstrtoll(s, base, &tmp);	if (rv < 0)		return rv;	if (tmp != (long long)(s16)tmp)		return -ERANGE;	*res = tmp;	return 0;}EXPORT_SYMBOL(kstrtos16); int kstrtou8(const char *s, unsigned int base, u8 *res){	unsigned long long tmp;	int rv; 	rv = kstrtoull(s, base, &tmp);	if (rv < 0)		return rv;	if (tmp != (unsigned long long)(u8)tmp)		return -ERANGE;	*res = tmp;	return 0;}EXPORT_SYMBOL(kstrtou8); int kstrtos8(const char *s, unsigned int base, s8 *res){	long long tmp;	int rv; 	rv = kstrtoll(s, base, &tmp);	if (rv < 0)		return rv;	if (tmp != (long long)(s8)tmp)		return -ERANGE;	*res = tmp;	return 0;}EXPORT_SYMBOL(kstrtos8); #define kstrto_from_user(f, g, type)					\int f(const char __user *s, size_t count, unsigned int base, type *res)	\{									\	/* sign, base 2 representation, newline, terminator */		\	char buf[1 + sizeof(type) * 8 + 1 + 1];				\									\	count = min(count, sizeof(buf) - 1);				\	if (copy_from_user(buf, s, count))				\		return -EFAULT;						\	buf[count] = '\0';						\	return g(buf, base, res);					\}									\EXPORT_SYMBOL(f) kstrto_from_user(kstrtoull_from_user,	kstrtoull,	unsigned long long);kstrto_from_user(kstrtoll_from_user,	kstrtoll,	long long);kstrto_from_user(kstrtoul_from_user,	kstrtoul,	unsigned long);kstrto_from_user(kstrtol_from_user,	kstrtol,	long);kstrto_from_user(kstrtouint_from_user,	kstrtouint,	unsigned int);kstrto_from_user(kstrtoint_from_user,	kstrtoint,	int);kstrto_from_user(kstrtou16_from_user,	kstrtou16,	u16);kstrto_from_user(kstrtos16_from_user,	kstrtos16,	s16);kstrto_from_user(kstrtou8_from_user,	kstrtou8,	u8);kstrto_from_user(kstrtos8_from_user,	kstrtos8,	s8);