diff --git a/Makefile b/Makefile index a1cc457b..377093d3 100644 --- a/Makefile +++ b/Makefile @@ -173,7 +173,8 @@ libbtrfs_objects = common/send-stream.o common/send-utils.o kernel-lib/rbtree.o common/device-scan.o common/path-utils.o \ common/utils.o libbtrfsutil/subvolume.o libbtrfsutil/stubs.o \ crypto/hash.o crypto/xxhash.o $(CRYPTO_OBJECTS) \ - common/open-utils.o common/units.o common/device-utils.o + common/open-utils.o common/units.o common/device-utils.o \ + common/parse-utils.o libbtrfs_headers = common/send-stream.h common/send-utils.h send.h kernel-lib/rbtree.h btrfs-list.h \ crypto/crc32c.h kernel-lib/list.h kerncompat.h \ kernel-lib/radix-tree.h kernel-lib/sizes.h kernel-lib/raid56.h \ diff --git a/cmds/filesystem.c b/cmds/filesystem.c index db8433ba..4ca155a4 100644 --- a/cmds/filesystem.c +++ b/cmds/filesystem.c @@ -46,6 +46,7 @@ #include "common/device-scan.h" #include "common/device-utils.h" #include "common/open-utils.h" +#include "common/parse-utils.h" /* * for btrfs fi show, we maintain a hash of fsids we've already printed. diff --git a/cmds/qgroup.c b/cmds/qgroup.c index 7dc1d5d9..ab4bf5b9 100644 --- a/cmds/qgroup.c +++ b/cmds/qgroup.c @@ -30,6 +30,7 @@ #include "common/utils.h" #include "common/help.h" #include "common/units.h" +#include "common/parse-utils.h" static const char * const qgroup_cmd_group_usage[] = { "btrfs qgroup [options] ", diff --git a/common/parse-utils.c b/common/parse-utils.c new file mode 100644 index 00000000..12e13b48 --- /dev/null +++ b/common/parse-utils.c @@ -0,0 +1,127 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#include "kerncompat.h" +#include +#include +#include "common/parse-utils.h" +#include "common/messages.h" + +u64 parse_size_from_string(const char *s) +{ + char c; + char *endptr; + u64 mult = 1; + u64 ret; + + if (!s) { + error("size value is empty"); + exit(1); + } + if (s[0] == '-') { + error("size value '%s' is less equal than 0", s); + exit(1); + } + ret = strtoull(s, &endptr, 10); + if (endptr == s) { + error("size value '%s' is invalid", s); + exit(1); + } + if (endptr[0] && endptr[1]) { + error("illegal suffix contains character '%c' in wrong position", + endptr[1]); + exit(1); + } + /* + * strtoll returns LLONG_MAX when overflow, if this happens, + * need to call strtoull to get the real size + */ + if (errno == ERANGE && ret == ULLONG_MAX) { + error("size value '%s' is too large for u64", s); + exit(1); + } + if (endptr[0]) { + c = tolower(endptr[0]); + switch (c) { + case 'e': + mult *= 1024; + /* fallthrough */ + case 'p': + mult *= 1024; + /* fallthrough */ + case 't': + mult *= 1024; + /* fallthrough */ + case 'g': + mult *= 1024; + /* fallthrough */ + case 'm': + mult *= 1024; + /* fallthrough */ + case 'k': + mult *= 1024; + /* fallthrough */ + case 'b': + break; + default: + error("unknown size descriptor '%c'", c); + exit(1); + } + } + /* Check whether ret * mult overflow */ + if (fls64(ret) + fls64(mult) - 1 > 64) { + error("size value '%s' is too large for u64", s); + exit(1); + } + ret *= mult; + return ret; +} + +enum btrfs_csum_type parse_csum_type(const char *s) +{ + if (strcasecmp(s, "crc32c") == 0) { + return BTRFS_CSUM_TYPE_CRC32; + } else if (strcasecmp(s, "xxhash64") == 0 || + strcasecmp(s, "xxhash") == 0) { + return BTRFS_CSUM_TYPE_XXHASH; + } else if (strcasecmp(s, "sha256") == 0) { + return BTRFS_CSUM_TYPE_SHA256; + } else if (strcasecmp(s, "blake2b") == 0 || + strcasecmp(s, "blake2") == 0) { + return BTRFS_CSUM_TYPE_BLAKE2; + } else { + error("unknown csum type %s", s); + exit(1); + } + /* not reached */ + return 0; +} + +/* + * Find last set bit in a 64-bit word. Returns 0 if value is 0 or the position + * of the last set bit if value is nonzero. The last (most significant) bit is + * at position 64. + */ +int fls64(u64 x) +{ + int i; + + for (i = 0; i < 64; i++) + if (x << i & (1ULL << 63)) + return 64 - i; + return 64 - i; +} + diff --git a/common/parse-utils.h b/common/parse-utils.h new file mode 100644 index 00000000..8133d64e --- /dev/null +++ b/common/parse-utils.h @@ -0,0 +1,28 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#ifndef __PARSE_UTILS_H__ +#define __PARSE_UTILS_H__ + +#include "kerncompat.h" +#include "kernel-shared/ctree.h" + +u64 parse_size_from_string(const char *s); +enum btrfs_csum_type parse_csum_type(const char *s); + +int fls64(u64 x); + +#endif diff --git a/common/utils.c b/common/utils.c index 418001af..8bcc00ff 100644 --- a/common/utils.c +++ b/common/utils.c @@ -227,90 +227,6 @@ int set_label(const char *btrfs_dev, const char *label) return ret; } -/* - * A not-so-good version fls64. No fascinating optimization since - * no one except parse_size_from_string uses it - */ -static int fls64(u64 x) -{ - int i; - - for (i = 0; i <64; i++) - if (x << i & (1ULL << 63)) - return 64 - i; - return 64 - i; -} - -u64 parse_size_from_string(const char *s) -{ - char c; - char *endptr; - u64 mult = 1; - u64 ret; - - if (!s) { - error("size value is empty"); - exit(1); - } - if (s[0] == '-') { - error("size value '%s' is less equal than 0", s); - exit(1); - } - ret = strtoull(s, &endptr, 10); - if (endptr == s) { - error("size value '%s' is invalid", s); - exit(1); - } - if (endptr[0] && endptr[1]) { - error("illegal suffix contains character '%c' in wrong position", - endptr[1]); - exit(1); - } - /* - * strtoll returns LLONG_MAX when overflow, if this happens, - * need to call strtoull to get the real size - */ - if (errno == ERANGE && ret == ULLONG_MAX) { - error("size value '%s' is too large for u64", s); - exit(1); - } - if (endptr[0]) { - c = tolower(endptr[0]); - switch (c) { - case 'e': - mult *= 1024; - /* fallthrough */ - case 'p': - mult *= 1024; - /* fallthrough */ - case 't': - mult *= 1024; - /* fallthrough */ - case 'g': - mult *= 1024; - /* fallthrough */ - case 'm': - mult *= 1024; - /* fallthrough */ - case 'k': - mult *= 1024; - /* fallthrough */ - case 'b': - break; - default: - error("unknown size descriptor '%c'", c); - exit(1); - } - } - /* Check whether ret * mult overflow */ - if (fls64(ret) + fls64(mult) - 1 > 64) { - error("size value '%s' is too large for u64", s); - exit(1); - } - ret *= mult; - return ret; -} - u64 parse_qgroupid(const char *p) { char *s = strchr(p, '/'); @@ -365,26 +281,6 @@ err: exit(-1); } -enum btrfs_csum_type parse_csum_type(const char *s) -{ - if (strcasecmp(s, "crc32c") == 0) { - return BTRFS_CSUM_TYPE_CRC32; - } else if (strcasecmp(s, "xxhash64") == 0 || - strcasecmp(s, "xxhash") == 0) { - return BTRFS_CSUM_TYPE_XXHASH; - } else if (strcasecmp(s, "sha256") == 0) { - return BTRFS_CSUM_TYPE_SHA256; - } else if (strcasecmp(s, "blake2b") == 0 || - strcasecmp(s, "blake2") == 0) { - return BTRFS_CSUM_TYPE_BLAKE2; - } else { - error("unknown csum type %s", s); - exit(1); - } - /* not reached */ - return 0; -} - void btrfs_format_csum(u16 csum_type, const u8 *data, char *output) { int i; diff --git a/common/utils.h b/common/utils.h index 45a4cea3..2369be94 100644 --- a/common/utils.h +++ b/common/utils.h @@ -42,12 +42,9 @@ enum exclusive_operation { BTRFS_EXCLOP_UNKNOWN = -1, }; -enum btrfs_csum_type parse_csum_type(const char *s); - /* 2 for "0x", 2 for each byte, plus nul */ #define BTRFS_CSUM_STRING_LEN (2 + 2 * BTRFS_CSUM_SIZE + 1) void btrfs_format_csum(u16 csum_type, const u8 *data, char *output); -u64 parse_size_from_string(const char *s); u64 parse_qgroupid(const char *p); u64 arg_strtou64(const char *str); int get_fs_info(const char *path, struct btrfs_ioctl_fs_info_args *fi_args, diff --git a/convert/main.c b/convert/main.c index 815a8636..68f85988 100644 --- a/convert/main.c +++ b/convert/main.c @@ -100,6 +100,7 @@ #include "common/task-utils.h" #include "common/path-utils.h" #include "common/help.h" +#include "common/parse-utils.h" #include "mkfs/common.h" #include "convert/common.h" #include "convert/source-fs.h" diff --git a/mkfs/main.c b/mkfs/main.c index 1a9c3f7e..c544c133 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -44,6 +44,7 @@ #include "kernel-lib/list_sort.h" #include "common/help.h" #include "common/rbtree-utils.h" +#include "common/parse-utils.h" #include "mkfs/common.h" #include "mkfs/rootdir.h" #include "common/fsfeatures.h"