Skip to content

Commit

Permalink
utils: parse_byte_size_string()
Browse files Browse the repository at this point in the history
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
  • Loading branch information
Christian Brauner committed Nov 8, 2017
1 parent dd7ebed commit d123380
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 0 deletions.
67 changes: 67 additions & 0 deletions src/lxc/utils.c
Expand Up @@ -47,6 +47,7 @@
#include "log.h"
#include "lxclock.h"
#include "namespace.h"
#include "parse.h"
#include "utils.h"

#ifndef PR_SET_MM
Expand Down Expand Up @@ -2451,3 +2452,69 @@ uint64_t lxc_getpagesize(void)

return pgsz;
}

int parse_byte_size_string(const char *s, int64_t *converted)
{
int ret, suffix_len;
long long int conv;
int64_t mltpl, overflow;
char *end;
char dup[LXC_NUMSTRLEN64 + 2];
char suffix[3];

if (!s || !strcmp(s, ""))
return -EINVAL;

end = stpncpy(dup, s, sizeof(dup));
if (*end != '\0')
return -EINVAL;

if (isdigit(*(end - 1)))
suffix_len = 0;
else if (isalpha(*(end - 1)))
suffix_len = 1;
else
return -EINVAL;

if ((end - 2) == dup && !isdigit(*(end - 2)))
return -EINVAL;

if (isalpha(*(end - 2))) {
if (suffix_len == 1)
suffix_len++;
else
return -EINVAL;
}

if (suffix_len > 0) {
memcpy(suffix, end - suffix_len, suffix_len);
*(suffix + suffix_len) = '\0';
*(end - suffix_len) = '\0';
}
dup[lxc_char_right_gc(dup, strlen(dup))] = '\0';

ret = lxc_safe_long_long(dup, &conv);
if (ret < 0)
return -ret;

if (suffix_len != 2) {
*converted = conv;
return 0;
}

if (!strcmp(suffix, "kB"))
mltpl = 1024;
else if (!strcmp(suffix, "MB"))
mltpl = 1024 * 1024;
else if (!strcmp(suffix, "GB"))
mltpl = 1024 * 1024 * 1024;
else
return -EINVAL;

overflow = conv * mltpl;
if (conv != 0 && (overflow / conv) != mltpl)
return -ERANGE;

*converted = overflow;
return 0;
}
2 changes: 2 additions & 0 deletions src/lxc/utils.h
Expand Up @@ -421,6 +421,8 @@ extern int lxc_safe_int(const char *numstr, int *converted);
extern int lxc_safe_long(const char *numstr, long int *converted);
extern int lxc_safe_long_long(const char *numstr, long long int *converted);
extern int lxc_safe_ulong(const char *numstr, unsigned long *converted);
/* Handles B, kb, MB, GB. Detects overflows and reports -ERANGE. */
extern int parse_byte_size_string(const char *s, int64_t *converted);

/* Switch to a new uid and gid. */
extern int lxc_switch_uid_gid(uid_t uid, gid_t gid);
Expand Down
83 changes: 83 additions & 0 deletions src/tests/lxc-test-utils.c
Expand Up @@ -380,6 +380,88 @@ void test_lxc_string_in_array(void)
lxc_test_assert_abort(lxc_string_in_array("XYZ", (const char *[]){"BERTA", "ARQWE(9", "C8Zhkd", "7U", "XYZ", "UOIZ9", "=)()", NULL}));
}

void test_parse_byte_size_string(void)
{
int ret;
int64_t n;

ret = parse_byte_size_string("0", &n);
if (ret < 0)
exit(EXIT_FAILURE);
if (n != 0)
exit(EXIT_FAILURE);

ret = parse_byte_size_string("1", &n);
if (ret < 0)
exit(EXIT_FAILURE);
if (n != 1)
exit(EXIT_FAILURE);

ret = parse_byte_size_string("1 ", &n);
if (ret == 0)
exit(EXIT_FAILURE);

ret = parse_byte_size_string("1B", &n);
if (ret < 0)
exit(EXIT_FAILURE);
if (n != 1)
exit(EXIT_FAILURE);

ret = parse_byte_size_string("1kB", &n);
if (ret < 0)
exit(EXIT_FAILURE);
if (n != 1024)
exit(EXIT_FAILURE);

ret = parse_byte_size_string("1MB", &n);
if (ret < 0)
exit(EXIT_FAILURE);
if (n != 1048576)
exit(EXIT_FAILURE);

ret = parse_byte_size_string("1GB", &n);
if (ret < 0)
exit(EXIT_FAILURE);
if (n != 1073741824)
exit(EXIT_FAILURE);

ret = parse_byte_size_string("1TB", &n);
if (ret == 0)
exit(EXIT_FAILURE);

ret = parse_byte_size_string("1 B", &n);
if (ret < 0)
exit(EXIT_FAILURE);
if (n != 1)
exit(EXIT_FAILURE);

ret = parse_byte_size_string("1 kB", &n);
if (ret < 0)
exit(EXIT_FAILURE);
if (n != 1024)
exit(EXIT_FAILURE);

ret = parse_byte_size_string("1 MB", &n);
if (ret < 0)
exit(EXIT_FAILURE);
if (n != 1048576)
exit(EXIT_FAILURE);

ret = parse_byte_size_string("1 GB", &n);
if (ret < 0)
exit(EXIT_FAILURE);
if (n != 1073741824)
exit(EXIT_FAILURE);

ret = parse_byte_size_string("1 TB", &n);
if (ret == 0)
exit(EXIT_FAILURE);

ret = parse_byte_size_string("asdf", &n);
if (ret == 0)
exit(EXIT_FAILURE);
}

int main(int argc, char *argv[])
{
test_lxc_string_replace();
Expand All @@ -389,6 +471,7 @@ int main(int argc, char *argv[])
test_lxc_safe_uint();
test_lxc_safe_int();
test_lxc_safe_long();
test_parse_byte_size_string();

exit(EXIT_SUCCESS);
}

0 comments on commit d123380

Please sign in to comment.