nbdkit/SOURCES/0019-common-include-Add-loc...

560 lines
19 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From 9a99549f5df6ef69dd1d2b509c13aaff4e431742 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 19 May 2020 16:11:28 +0100
Subject: [PATCH 19/19] common/include: Add locale-safe ascii_strcasecmp and
ascii_strncasecmp.
These are derived from the FreeBSD functions here:
https://github.com/freebsd/freebsd/blob/master/sys/libkern/strcasecmp.c
Thanks: Eric Blake.
(cherry picked from commit 46a29b8e91d69e812d78df53e91b526a560000fe)
---
.gitignore | 1 +
common/include/Makefile.am | 6 +++
common/include/ascii-ctype.h | 6 +++
common/include/ascii-string.h | 77 ++++++++++++++++++++++++++++
common/include/test-ascii-string.c | 79 +++++++++++++++++++++++++++++
plugins/curl/curl.c | 7 +--
plugins/info/info.c | 17 ++++---
plugins/nbd/nbd.c | 8 +--
plugins/partitioning/partitioning.c | 10 ++--
plugins/sh/call.c | 25 ++++-----
server/main.c | 8 +--
server/public.c | 21 ++++----
12 files changed, 222 insertions(+), 43 deletions(-)
create mode 100644 common/include/ascii-string.h
create mode 100644 common/include/test-ascii-string.c
diff --git a/.gitignore b/.gitignore
index 523894b7..aa148f04 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,6 +27,7 @@ Makefile.in
/autom4te.cache
/common/bitmap/test-bitmap
/common/include/test-ascii-ctype
+/common/include/test-ascii-string
/common/include/test-byte-swapping
/common/include/test-current-dir-name
/common/include/test-isaligned
diff --git a/common/include/Makefile.am b/common/include/Makefile.am
index d7b0d7a8..eff71863 100644
--- a/common/include/Makefile.am
+++ b/common/include/Makefile.am
@@ -35,6 +35,7 @@ include $(top_srcdir)/common-rules.mk
# plugins and/or filters. They are not installed.
EXTRA_DIST = \
ascii-ctype.h \
+ ascii-string.h \
byte-swapping.h \
exit-with-parent.h \
get-current-dir-name.h \
@@ -52,6 +53,7 @@ EXTRA_DIST = \
TESTS = \
test-ascii-ctype \
+ test-ascii-string \
test-byte-swapping \
test-current-dir-name \
test-isaligned \
@@ -68,6 +70,10 @@ test_ascii_ctype_SOURCES = test-ascii-ctype.c ascii-ctype.h
test_ascii_ctype_CPPFLAGS = -I$(srcdir)
test_ascii_ctype_CFLAGS = $(WARNINGS_CFLAGS)
+test_ascii_string_SOURCES = test-ascii-string.c ascii-string.h
+test_ascii_string_CPPFLAGS = -I$(srcdir)
+test_ascii_string_CFLAGS = $(WARNINGS_CFLAGS)
+
test_byte_swapping_SOURCES = test-byte-swapping.c byte-swapping.h
test_byte_swapping_CPPFLAGS = -I$(srcdir)
test_byte_swapping_CFLAGS = $(WARNINGS_CFLAGS)
diff --git a/common/include/ascii-ctype.h b/common/include/ascii-ctype.h
index 5e8bf237..a700563e 100644
--- a/common/include/ascii-ctype.h
+++ b/common/include/ascii-ctype.h
@@ -49,6 +49,9 @@
#define ascii_isspace(c) \
((c) == '\t' || (c) == '\n' || (c) == '\f' || (c) == '\r' || (c) == ' ')
+#define ascii_isupper(c) \
+ ((c) >= 'A' && (c) <= 'Z')
+
#define ascii_isxdigit(c) \
((c) == '0' || (c) == '1' || (c) == '2' || (c) == '3' || (c) == '4' || \
(c) == '5' || (c) == '6' || (c) == '7' || (c) == '8' || (c) == '9' || \
@@ -57,4 +60,7 @@
(c) == 'A' || (c) == 'B' || (c) == 'C' || \
(c) == 'D' || (c) == 'E' || (c) == 'F')
+#define ascii_tolower(c) \
+ (ascii_isupper ((c)) ? (c) - 'A' + 'a' : (c))
+
#endif /* NBDKIT_ASCII_CTYPE_H */
diff --git a/common/include/ascii-string.h b/common/include/ascii-string.h
new file mode 100644
index 00000000..0a60d5f4
--- /dev/null
+++ b/common/include/ascii-string.h
@@ -0,0 +1,77 @@
+/* nbdkit
+ * Copyright (C) 2013-2020 Red Hat Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Red Hat nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* Case insensitive string comparison functions (like strcasecmp,
+ * strncasecmp) which work correctly in any locale. They can only be
+ * used for comparison when one or both strings is 7 bit ASCII.
+ */
+
+#ifndef NBDKIT_ASCII_STRING_H
+#define NBDKIT_ASCII_STRING_H
+
+#include "ascii-ctype.h"
+
+static inline int
+ascii_strcasecmp (const char *s1, const char *s2)
+{
+ const unsigned char *us1 = (const unsigned char *)s1;
+ const unsigned char *us2 = (const unsigned char *)s2;
+
+ while (ascii_tolower (*us1) == ascii_tolower (*us2)) {
+ if (*us1++ == '\0')
+ return 0;
+ us2++;
+ }
+
+ return ascii_tolower (*us1) - ascii_tolower (*us2);
+}
+
+static inline int
+ascii_strncasecmp (const char *s1, const char *s2, size_t n)
+{
+ if (n != 0) {
+ const unsigned char *us1 = (const unsigned char *)s1;
+ const unsigned char *us2 = (const unsigned char *)s2;
+
+ do {
+ if (ascii_tolower (*us1) != ascii_tolower (*us2))
+ return ascii_tolower (*us1) - ascii_tolower (*us2);
+ if (*us1++ == '\0')
+ break;
+ us2++;
+ } while (--n != 0);
+ }
+
+ return 0;
+}
+
+#endif /* NBDKIT_ASCII_STRING_H */
diff --git a/common/include/test-ascii-string.c b/common/include/test-ascii-string.c
new file mode 100644
index 00000000..0fa4a483
--- /dev/null
+++ b/common/include/test-ascii-string.c
@@ -0,0 +1,79 @@
+/* nbdkit
+ * Copyright (C) 2020 Red Hat Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Red Hat nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "ascii-string.h"
+
+int
+main (void)
+{
+ assert (ascii_strcasecmp ("", "") == 0);
+ assert (ascii_strcasecmp ("a", "a") == 0);
+ assert (ascii_strcasecmp ("abc", "abc") == 0);
+ assert (ascii_strcasecmp ("a", "b") < 0);
+ assert (ascii_strcasecmp ("b", "a") > 0);
+ assert (ascii_strcasecmp ("aa", "a") > 0);
+
+ /* Second string contains Turkish dotless lowercase letter ı. */
+ assert (ascii_strcasecmp ("hi", "hı") != 0);
+
+ /* Check that we got our rounding behaviour correct. */
+ assert (ascii_strcasecmp ("\x1", "\x7f") < 0);
+ assert (ascii_strcasecmp ("\x1", "\x80") < 0);
+ assert (ascii_strcasecmp ("\x1", "\x81") < 0);
+ assert (ascii_strcasecmp ("\x1", "\xff") < 0);
+
+ assert (ascii_strncasecmp ("", "", 0) == 0);
+ assert (ascii_strncasecmp ("a", "a", 1) == 0);
+ assert (ascii_strncasecmp ("abc", "abc", 3) == 0);
+ assert (ascii_strncasecmp ("abc", "def", 0) == 0);
+ assert (ascii_strncasecmp ("abc", "abd", 2) == 0);
+ assert (ascii_strncasecmp ("a", "b", 1) < 0);
+ assert (ascii_strncasecmp ("b", "a", 1) > 0);
+ assert (ascii_strncasecmp ("aa", "a", 2) > 0);
+ assert (ascii_strncasecmp ("aa", "a", 100) > 0);
+
+ assert (ascii_strncasecmp ("hi", "hı", 1) == 0);
+ assert (ascii_strncasecmp ("hi", "hı", 2) != 0);
+
+ assert (ascii_strncasecmp ("\x1", "\x7f", 1) < 0);
+ assert (ascii_strncasecmp ("\x1", "\x80", 1) < 0);
+ assert (ascii_strncasecmp ("\x1", "\x81", 1) < 0);
+ assert (ascii_strncasecmp ("\x1", "\xff", 1) < 0);
+
+ exit (EXIT_SUCCESS);
+}
diff --git a/plugins/curl/curl.c b/plugins/curl/curl.c
index ac30cbdd..00f0628a 100644
--- a/plugins/curl/curl.c
+++ b/plugins/curl/curl.c
@@ -58,6 +58,7 @@
#include "cleanup.h"
#include "ascii-ctype.h"
+#include "ascii-string.h"
static const char *url = NULL;
static const char *user = NULL;
@@ -419,8 +420,8 @@ curl_open (int readonly)
#endif
nbdkit_debug ("content length: %" PRIi64, h->exportsize);
- if (strncasecmp (url, "http://", strlen ("http://")) == 0 ||
- strncasecmp (url, "https://", strlen ("https://")) == 0) {
+ if (ascii_strncasecmp (url, "http://", strlen ("http://")) == 0 ||
+ ascii_strncasecmp (url, "https://", strlen ("https://")) == 0) {
if (!h->accept_range) {
nbdkit_error ("server does not support 'range' (byte range) requests");
goto err;
@@ -504,7 +505,7 @@ header_cb (void *ptr, size_t size, size_t nmemb, void *opaque)
const char *bytes = "bytes";
if (realsize >= strlen (accept_ranges) &&
- strncasecmp (header, accept_ranges, strlen (accept_ranges)) == 0) {
+ ascii_strncasecmp (header, accept_ranges, strlen (accept_ranges)) == 0) {
const char *p = strchr (header, ':') + 1;
/* Skip whitespace between the header name and value. */
diff --git a/plugins/info/info.c b/plugins/info/info.c
index 329a3684..e04d672b 100644
--- a/plugins/info/info.c
+++ b/plugins/info/info.c
@@ -49,6 +49,7 @@
#include <nbdkit-plugin.h>
+#include "ascii-string.h"
#include "byte-swapping.h"
#include "tvdiff.h"
@@ -76,12 +77,12 @@ static int
info_config (const char *key, const char *value)
{
if (strcmp (key, "mode") == 0) {
- if (strcasecmp (value, "exportname") == 0 ||
- strcasecmp (value, "export-name") == 0) {
+ if (ascii_strcasecmp (value, "exportname") == 0 ||
+ ascii_strcasecmp (value, "export-name") == 0) {
mode = MODE_EXPORTNAME;
}
- else if (strcasecmp (value, "base64exportname") == 0 ||
- strcasecmp (value, "base64-export-name") == 0) {
+ else if (ascii_strcasecmp (value, "base64exportname") == 0 ||
+ ascii_strcasecmp (value, "base64-export-name") == 0) {
#ifdef HAVE_BASE64
mode = MODE_BASE64EXPORTNAME;
#else
@@ -89,13 +90,13 @@ info_config (const char *key, const char *value)
return -1;
#endif
}
- else if (strcasecmp (value, "address") == 0)
+ else if (ascii_strcasecmp (value, "address") == 0)
mode = MODE_ADDRESS;
- else if (strcasecmp (value, "time") == 0)
+ else if (ascii_strcasecmp (value, "time") == 0)
mode = MODE_TIME;
- else if (strcasecmp (value, "uptime") == 0)
+ else if (ascii_strcasecmp (value, "uptime") == 0)
mode = MODE_UPTIME;
- else if (strcasecmp (value, "conntime") == 0)
+ else if (ascii_strcasecmp (value, "conntime") == 0)
mode = MODE_CONNTIME;
else {
nbdkit_error ("unknown mode: '%s'", value);
diff --git a/plugins/nbd/nbd.c b/plugins/nbd/nbd.c
index d020beec..980ce8ec 100644
--- a/plugins/nbd/nbd.c
+++ b/plugins/nbd/nbd.c
@@ -52,6 +52,8 @@
#define NBDKIT_API_VERSION 2
#include <nbdkit-plugin.h>
+
+#include "ascii-string.h"
#include "byte-swapping.h"
#include "cleanup.h"
#include "utils.h"
@@ -152,9 +154,9 @@ nbdplug_config (const char *key, const char *value)
shared = r;
}
else if (strcmp (key, "tls") == 0) {
- if (strcasecmp (value, "require") == 0 ||
- strcasecmp (value, "required") == 0 ||
- strcasecmp (value, "force") == 0)
+ if (ascii_strcasecmp (value, "require") == 0 ||
+ ascii_strcasecmp (value, "required") == 0 ||
+ ascii_strcasecmp (value, "force") == 0)
tls = LIBNBD_TLS_REQUIRE;
else {
r = nbdkit_parse_bool (value);
diff --git a/plugins/partitioning/partitioning.c b/plugins/partitioning/partitioning.c
index 6e426b93..e35764dc 100644
--- a/plugins/partitioning/partitioning.c
+++ b/plugins/partitioning/partitioning.c
@@ -48,6 +48,7 @@
#include <nbdkit-plugin.h>
+#include "ascii-string.h"
#include "byte-swapping.h"
#include "isaligned.h"
#include "iszero.h"
@@ -176,9 +177,10 @@ partitioning_config (const char *key, const char *value)
nr_files++;
}
else if (strcmp (key, "partition-type") == 0) {
- if (strcasecmp (value, "mbr") == 0 || strcasecmp (value, "dos") == 0)
+ if (ascii_strcasecmp (value, "mbr") == 0 ||
+ ascii_strcasecmp (value, "dos") == 0)
parttype = PARTTYPE_MBR;
- else if (strcasecmp (value, "gpt") == 0)
+ else if (ascii_strcasecmp (value, "gpt") == 0)
parttype = PARTTYPE_GPT;
else {
nbdkit_error ("unknown partition-type: %s", value);
@@ -209,13 +211,13 @@ partitioning_config (const char *key, const char *value)
alignment = r;
}
else if (strcmp (key, "mbr-id") == 0) {
- if (strcasecmp (value, "default") == 0)
+ if (ascii_strcasecmp (value, "default") == 0)
mbr_id = DEFAULT_MBR_ID;
else if (nbdkit_parse_uint8_t ("mbr-id", value, &mbr_id) == -1)
return -1;
}
else if (strcmp (key, "type-guid") == 0) {
- if (strcasecmp (value, "default") == 0)
+ if (ascii_strcasecmp (value, "default") == 0)
parse_guid (DEFAULT_TYPE_GUID, type_guid);
else if (parse_guid (value, type_guid) == -1) {
nbdkit_error ("could not validate GUID: %s", value);
diff --git a/plugins/sh/call.c b/plugins/sh/call.c
index ba9f055f..554e2f78 100644
--- a/plugins/sh/call.c
+++ b/plugins/sh/call.c
@@ -48,6 +48,7 @@
#include <nbdkit-plugin.h>
#include "ascii-ctype.h"
+#include "ascii-string.h"
#include "cleanup.h"
#include "utils.h"
@@ -332,48 +333,48 @@ handle_script_error (const char *argv0, char *ebuf, size_t len)
}
/* Recognize the errno values that match NBD protocol errors */
- if (strncasecmp (ebuf, "EPERM", 5) == 0) {
+ if (ascii_strncasecmp (ebuf, "EPERM", 5) == 0) {
err = EPERM;
skip = 5;
}
- else if (strncasecmp (ebuf, "EIO", 3) == 0) {
+ else if (ascii_strncasecmp (ebuf, "EIO", 3) == 0) {
err = EIO;
skip = 3;
}
- else if (strncasecmp (ebuf, "ENOMEM", 6) == 0) {
+ else if (ascii_strncasecmp (ebuf, "ENOMEM", 6) == 0) {
err = ENOMEM;
skip = 6;
}
- else if (strncasecmp (ebuf, "EINVAL", 6) == 0) {
+ else if (ascii_strncasecmp (ebuf, "EINVAL", 6) == 0) {
err = EINVAL;
skip = 6;
}
- else if (strncasecmp (ebuf, "ENOSPC", 6) == 0) {
+ else if (ascii_strncasecmp (ebuf, "ENOSPC", 6) == 0) {
err = ENOSPC;
skip = 6;
}
- else if (strncasecmp (ebuf, "EOVERFLOW", 9) == 0) {
+ else if (ascii_strncasecmp (ebuf, "EOVERFLOW", 9) == 0) {
err = EOVERFLOW;
skip = 9;
}
- else if (strncasecmp (ebuf, "ESHUTDOWN", 9) == 0) {
+ else if (ascii_strncasecmp (ebuf, "ESHUTDOWN", 9) == 0) {
err = ESHUTDOWN;
skip = 9;
}
- else if (strncasecmp (ebuf, "ENOTSUP", 7) == 0) {
+ else if (ascii_strncasecmp (ebuf, "ENOTSUP", 7) == 0) {
err = ENOTSUP;
skip = 7;
}
- else if (strncasecmp (ebuf, "EOPNOTSUPP", 10) == 0) {
+ else if (ascii_strncasecmp (ebuf, "EOPNOTSUPP", 10) == 0) {
err = EOPNOTSUPP;
skip = 10;
}
/* Other errno values that server/protocol.c treats specially */
- else if (strncasecmp (ebuf, "EROFS", 5) == 0) {
+ else if (ascii_strncasecmp (ebuf, "EROFS", 5) == 0) {
err = EROFS;
skip = 5;
}
- else if (strncasecmp (ebuf, "EDQUOT", 6) == 0) {
+ else if (ascii_strncasecmp (ebuf, "EDQUOT", 6) == 0) {
#ifdef EDQUOT
err = EDQUOT;
#else
@@ -381,7 +382,7 @@ handle_script_error (const char *argv0, char *ebuf, size_t len)
#endif
skip = 6;
}
- else if (strncasecmp (ebuf, "EFBIG", 5) == 0) {
+ else if (ascii_strncasecmp (ebuf, "EFBIG", 5) == 0) {
err = EFBIG;
skip = 5;
}
diff --git a/server/main.c b/server/main.c
index 11ba1e6d..08116d74 100644
--- a/server/main.c
+++ b/server/main.c
@@ -55,6 +55,8 @@
#include <dlfcn.h>
+#include "ascii-string.h"
+
#include "internal.h"
#include "nbd-protocol.h"
#include "options.h"
@@ -282,9 +284,9 @@ main (int argc, char *argv[])
case TLS_OPTION:
tls_set_on_cli = true;
- if (strcasecmp (optarg, "require") == 0 ||
- strcasecmp (optarg, "required") == 0 ||
- strcasecmp (optarg, "force") == 0)
+ if (ascii_strcasecmp (optarg, "require") == 0 ||
+ ascii_strcasecmp (optarg, "required") == 0 ||
+ ascii_strcasecmp (optarg, "force") == 0)
tls = 2;
else {
tls = nbdkit_parse_bool (optarg);
diff --git a/server/public.c b/server/public.c
index 98b78482..919f082d 100644
--- a/server/public.c
+++ b/server/public.c
@@ -52,6 +52,7 @@
#include <sys/socket.h>
#include "ascii-ctype.h"
+#include "ascii-string.h"
#include "get-current-dir-name.h"
#include "internal.h"
@@ -385,19 +386,19 @@ int
nbdkit_parse_bool (const char *str)
{
if (!strcmp (str, "1") ||
- !strcasecmp (str, "true") ||
- !strcasecmp (str, "t") ||
- !strcasecmp (str, "yes") ||
- !strcasecmp (str, "y") ||
- !strcasecmp (str, "on"))
+ !ascii_strcasecmp (str, "true") ||
+ !ascii_strcasecmp (str, "t") ||
+ !ascii_strcasecmp (str, "yes") ||
+ !ascii_strcasecmp (str, "y") ||
+ !ascii_strcasecmp (str, "on"))
return 1;
if (!strcmp (str, "0") ||
- !strcasecmp (str, "false") ||
- !strcasecmp (str, "f") ||
- !strcasecmp (str, "no") ||
- !strcasecmp (str, "n") ||
- !strcasecmp (str, "off"))
+ !ascii_strcasecmp (str, "false") ||
+ !ascii_strcasecmp (str, "f") ||
+ !ascii_strcasecmp (str, "no") ||
+ !ascii_strcasecmp (str, "n") ||
+ !ascii_strcasecmp (str, "off"))
return 0;
nbdkit_error ("could not decipher boolean (%s)", str);
--
2.18.2