Line data Source code
1 : /* 2 : * Unix SMB/CIFS implementation. 3 : * 4 : * Copyright (C) Swen Schillig 2019 5 : * 6 : * ** NOTE! The following LGPL license applies to this file. 7 : * ** This does NOT imply that all of Samba is released 8 : * ** under the LGPL 9 : * 10 : * This library is free software; you can redistribute it and/or 11 : * modify it under the terms of the GNU Lesser General Public 12 : * License as published by the Free Software Foundation; either 13 : * version 3 of the License, or (at your option) any later version. 14 : * 15 : * This library is distributed in the hope that it will be useful, 16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 : * Lesser General Public License for more details. 19 : * 20 : * You should have received a copy of the GNU Lesser General Public 21 : * License along with this library; if not, see <http://www.gnu.org/licenses/>. 22 : */ 23 : 24 : #include "replace.h" 25 : #include "smb_strtox.h" 26 : 27 : /** 28 : * Convert a string to an unsigned long integer 29 : * 30 : * @param nptr pointer to string which is to be converted 31 : * @param endptr [optional] reference to remainder of the string 32 : * @param base base of the numbering scheme 33 : * @param err error occurred during conversion 34 : * @flags controlling conversion feature 35 : * @result result of the conversion as provided by strtoul 36 : * 37 : * The following flags are supported 38 : * SMB_STR_STANDARD # raise error if negative or non-numeric 39 : * SMB_STR_ALLOW_NEGATIVE # allow strings with a leading "-" 40 : * SMB_STR_FULL_STR_CONV # entire string must be converted 41 : * SMB_STR_ALLOW_NO_CONVERSION # allow empty strings or non-numeric 42 : * SMB_STR_GLIBC_STANDARD # act exactly as the standard glibc strtoul 43 : * 44 : * The following errors are detected 45 : * - wrong base 46 : * - value overflow 47 : * - string with a leading "-" indicating a negative number 48 : * - no conversion due to empty string or not representing a number 49 : */ 50 : unsigned long int 51 720302533 : smb_strtoul(const char *nptr, char **endptr, int base, int *err, int flags) 52 : { 53 9404272 : unsigned long int val; 54 720302533 : int saved_errno = errno; 55 720302533 : char *needle = NULL; 56 720302533 : char *tmp_endptr = NULL; 57 : 58 720302533 : errno = 0; 59 720302533 : *err = 0; 60 : 61 720302533 : val = strtoul(nptr, &tmp_endptr, base); 62 : 63 720302533 : if (endptr != NULL) { 64 619969598 : *endptr = tmp_endptr; 65 : } 66 : 67 720302533 : if (errno != 0) { 68 0 : *err = errno; 69 0 : errno = saved_errno; 70 0 : return val; 71 : } 72 : 73 720302533 : if ((flags & SMB_STR_ALLOW_NO_CONVERSION) == 0) { 74 : /* got an invalid number-string resulting in no conversion */ 75 720302531 : if (nptr == tmp_endptr) { 76 452 : *err = EINVAL; 77 452 : goto out; 78 : } 79 : } 80 : 81 720302081 : if ((flags & SMB_STR_ALLOW_NEGATIVE ) == 0) { 82 : /* did we convert a negative "number" ? */ 83 720302079 : needle = strchr(nptr, '-'); 84 720302079 : if (needle != NULL && needle < tmp_endptr) { 85 3 : *err = EINVAL; 86 3 : goto out; 87 : } 88 : } 89 : 90 720302078 : if ((flags & SMB_STR_FULL_STR_CONV) != 0) { 91 : /* did we convert the entire string ? */ 92 880864 : if (tmp_endptr[0] != '\0') { 93 6 : *err = EINVAL; 94 6 : goto out; 95 : } 96 : } 97 : 98 720302072 : out: 99 720302533 : errno = saved_errno; 100 720302533 : return val; 101 : } 102 : 103 : /** 104 : * Convert a string to an unsigned long long integer 105 : * 106 : * @param nptr pointer to string which is to be converted 107 : * @param endptr [optional] reference to remainder of the string 108 : * @param base base of the numbering scheme 109 : * @param err error occurred during conversion 110 : * @flags controlling conversion feature 111 : * @result result of the conversion as provided by strtoull 112 : * 113 : * The following flags are supported 114 : * SMB_STR_STANDARD # raise error if negative or non-numeric 115 : * SMB_STR_ALLOW_NEGATIVE # allow strings with a leading "-" 116 : * SMB_STR_FULL_STR_CONV # entire string must be converted 117 : * SMB_STR_ALLOW_NO_CONVERSION # allow empty strings or non-numeric 118 : * SMB_STR_GLIBC_STANDARD # act exactly as the standard glibc strtoul 119 : * 120 : * The following errors are detected 121 : * - wrong base 122 : * - value overflow 123 : * - string with a leading "-" indicating a negative number 124 : * - no conversion due to empty string or not representing a number 125 : */ 126 : unsigned long long int 127 111276083 : smb_strtoull(const char *nptr, char **endptr, int base, int *err, int flags) 128 : { 129 3105970 : unsigned long long int val; 130 111276083 : int saved_errno = errno; 131 111276083 : char *needle = NULL; 132 111276083 : char *tmp_endptr = NULL; 133 : 134 111276083 : errno = 0; 135 111276083 : *err = 0; 136 : 137 111276083 : val = strtoull(nptr, &tmp_endptr, base); 138 : 139 111276083 : if (endptr != NULL) { 140 109410756 : *endptr = tmp_endptr; 141 : } 142 : 143 111276083 : if (errno != 0) { 144 44 : *err = errno; 145 44 : errno = saved_errno; 146 44 : return val; 147 : } 148 : 149 111276039 : if ((flags & SMB_STR_ALLOW_NO_CONVERSION) == 0) { 150 : /* got an invalid number-string resulting in no conversion */ 151 111176781 : if (nptr == tmp_endptr) { 152 6114768 : *err = EINVAL; 153 6114768 : goto out; 154 : } 155 : } 156 : 157 105161271 : if ((flags & SMB_STR_ALLOW_NEGATIVE ) == 0) { 158 : /* did we convert a negative "number" ? */ 159 105161269 : needle = strchr(nptr, '-'); 160 105161269 : if (needle != NULL && needle < tmp_endptr) { 161 4 : *err = EINVAL; 162 4 : goto out; 163 : } 164 : } 165 : 166 105161267 : if ((flags & SMB_STR_FULL_STR_CONV) != 0) { 167 : /* did we convert the entire string ? */ 168 2378 : if (tmp_endptr[0] != '\0') { 169 4 : *err = EINVAL; 170 4 : goto out; 171 : } 172 : } 173 : 174 105161263 : out: 175 111276039 : errno = saved_errno; 176 111276039 : return val; 177 : }