Implement s3fs_strtoofft via strtoll

This tightens error checking and aligns s3fs with known good behavior.
This commit is contained in:
Andrew Gaul 2019-07-12 18:52:35 -07:00
parent e936854493
commit 4adcd4a6c8
3 changed files with 18 additions and 38 deletions

View File

@ -17,6 +17,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
#include <cerrno>
#include <climits> #include <climits>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
@ -24,6 +25,7 @@
#include <syslog.h> #include <syslog.h>
#include <ctime> #include <ctime>
#include <stdexcept>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <map> #include <map>
@ -50,45 +52,18 @@ template std::string str(unsigned long long value);
static const char hexAlphabet[] = "0123456789ABCDEF"; static const char hexAlphabet[] = "0123456789ABCDEF";
// replacement for C++11 std::stoll
off_t s3fs_strtoofft(const char* str, bool is_base_16) off_t s3fs_strtoofft(const char* str, bool is_base_16)
{ {
if(!str || '\0' == *str){ errno = 0;
return 0; char *temp;
long long result = strtoll(str, &temp, is_base_16 ? 16 : 10);
if(temp == str || *temp != '\0'){
throw std::invalid_argument("s3fs_strtoofft");
} }
off_t result; if((result == LLONG_MIN || result == LLONG_MAX) && errno == ERANGE){
bool chk_space; throw std::out_of_range("s3fs_strtoofft");
bool chk_base16_prefix;
for(result = 0, chk_space = false, chk_base16_prefix = false; '\0' != *str; str++){
// check head space
if(!chk_space && isspace(*str)){
continue;
}else if(!chk_space){
chk_space = true;
}
// check prefix for base 16
if(!chk_base16_prefix){
chk_base16_prefix = true;
if('0' == *str && ('x' == str[1] || 'X' == str[1])){
is_base_16 = true;
str++;
continue;
}
}
// check like isalnum and set data
result *= (is_base_16 ? 16 : 10);
if('0' <= *str && '9' >= *str){
result += static_cast<off_t>(*str - '0');
}else if(is_base_16){
if('A' <= *str && *str <= 'F'){
result += static_cast<off_t>(*str - 'A' + 0x0a);
}else if('a' <= *str && *str <= 'f'){
result += static_cast<off_t>(*str - 'a' + 0x0a);
}else{
return 0;
}
}else{
return 0;
}
} }
return result; return result;
} }

View File

@ -35,7 +35,7 @@ static inline int STR2NCMP(const char *str1, const char *str2) { return strncmp(
template <class T> std::string str(T value); template <class T> std::string str(T value);
// Convert string to off_t. Does not signal invalid input. // Convert string to off_t. Throws std::invalid_argument and std::out_of_range on bad input.
off_t s3fs_strtoofft(const char* str, bool is_base_16 = false); off_t s3fs_strtoofft(const char* str, bool is_base_16 = false);
std::string trim_left(const std::string &s, const std::string &t = SPACES); std::string trim_left(const std::string &s, const std::string &t = SPACES);

View File

@ -79,7 +79,12 @@ void test_strtoofft()
{ {
ASSERT_EQUALS(s3fs_strtoofft("0"), static_cast<off_t>(0L)); ASSERT_EQUALS(s3fs_strtoofft("0"), static_cast<off_t>(0L));
ASSERT_EQUALS(s3fs_strtoofft("9"), static_cast<off_t>(9L)); ASSERT_EQUALS(s3fs_strtoofft("9"), static_cast<off_t>(9L));
ASSERT_EQUALS(s3fs_strtoofft("A"), static_cast<off_t>(0L)); try{
s3fs_strtoofft("A");
abort();
}catch(std::exception &e){
// expected
}
ASSERT_EQUALS(s3fs_strtoofft("A", /*is_base_16=*/ true), static_cast<off_t>(10L)); ASSERT_EQUALS(s3fs_strtoofft("A", /*is_base_16=*/ true), static_cast<off_t>(10L));
ASSERT_EQUALS(s3fs_strtoofft("F", /*is_base_16=*/ true), static_cast<off_t>(15L)); ASSERT_EQUALS(s3fs_strtoofft("F", /*is_base_16=*/ true), static_cast<off_t>(15L));
ASSERT_EQUALS(s3fs_strtoofft("a", /*is_base_16=*/ true), static_cast<off_t>(10L)); ASSERT_EQUALS(s3fs_strtoofft("a", /*is_base_16=*/ true), static_cast<off_t>(10L));