diff --git a/Makefile b/Makefile index 9f60a13..9d1293a 100644 --- a/Makefile +++ b/Makefile @@ -56,6 +56,7 @@ LIBUTILSRC =\ libutil/md5.c\ libutil/mkdirp.c\ libutil/mode.c\ + libutil/parseoffset.c\ libutil/putword.c\ libutil/reallocarray.c\ libutil/recurse.c\ diff --git a/libutil/parseoffset.c b/libutil/parseoffset.c new file mode 100644 index 0000000..451d913 --- /dev/null +++ b/libutil/parseoffset.c @@ -0,0 +1,59 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include + +#include "../util.h" + +off_t +parseoffset(const char *str) +{ + off_t res; + size_t scale; + int base = 10; + char *end; + + /* bases */ + if (!strncasecmp(str, "0x", strlen("0x"))) { + base = 16; + } else if (*str == '0') { + str++; + base = 8; + } + + res = strtol(str, &end, base); + if (res < 0) { + weprintf("invalid file offset: %s\n", str); + return -1; + } + + /* suffix */ + if (*end) { + switch (toupper((int)*end)) { + case 'B': + scale = 512L; + break; + case 'K': + scale = 1024L; + break; + case 'M': + scale = 1024L * 1024L; + break; + case 'G': + scale = 1024L * 1024L * 1024L; + break; + default: + weprintf("invalid file offset suffix: %s\n", str); + return -1; + } + } + + /* prevent overflow */ + if (res > (SIZE_MAX / scale)) { + weprintf("file offset out of range: %s\n", str); + return -1; + } + + return res; +} diff --git a/util.h b/util.h index b0bf0f4..4c973d1 100644 --- a/util.h +++ b/util.h @@ -68,6 +68,7 @@ void fnck(const char *, const char *, int (*)(const char *, const char *, int), mode_t getumask(void); char *humansize(off_t); mode_t parsemode(const char *, mode_t, mode_t); +off_t parseoffset(const char *); void putword(FILE *, const char *); #undef strtonum long long strtonum(const char *, long long, long long, const char **);