]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
utils: parse_byte_size_string()
authorChristian Brauner <christian.brauner@ubuntu.com>
Wed, 18 Oct 2017 17:53:37 +0000 (19:53 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Thu, 9 Nov 2017 00:06:32 +0000 (01:06 +0100)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/utils.c
src/lxc/utils.h
src/tests/lxc-test-utils.c

index f6b6584e27e6defcfe7cbe1c24af1a457f9cf8bb..887afdd03cf7c59c61ceaacd961da850b381f2c0 100644 (file)
@@ -47,6 +47,7 @@
 #include "log.h"
 #include "lxclock.h"
 #include "namespace.h"
+#include "parse.h"
 #include "utils.h"
 
 #ifndef PR_SET_MM
@@ -2448,3 +2449,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;
+}
index 315d87768f2c37782500dee01e6ae522950ec732..62c2d3c72674dd4fced0fe50eaa6b50ecf0dcd79 100644 (file)
@@ -412,6 +412,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. */
 int lxc_switch_uid_gid(uid_t uid, gid_t gid);
index aba7706abcb1d85823b5f47e366941066b6187e1..4c3c17a783419b1d3b01ba00704002d2ee44c21d 100644 (file)
@@ -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();
@@ -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);
 }