diff --git a/SOURCES/0001-server-Allow-D-nbdkit.-debug-flags-for-the-core-serv.patch b/SOURCES/0001-server-Allow-D-nbdkit.-debug-flags-for-the-core-serv.patch
index a1c635b..758f2f0 100644
--- a/SOURCES/0001-server-Allow-D-nbdkit.-debug-flags-for-the-core-serv.patch
+++ b/SOURCES/0001-server-Allow-D-nbdkit.-debug-flags-for-the-core-serv.patch
@@ -1,7 +1,8 @@
 From d7836fb0a7131c725e3c02be7e48e99c671637c3 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Thu, 12 Dec 2019 08:57:15 +0000
-Subject: [PATCH] server: Allow -D nbdkit.* debug flags for the core server.
+Subject: [PATCH 01/19] server: Allow -D nbdkit.* debug flags for the core
+ server.
 
 These work like plugin/filter debug flags, but apply to the internals
 of the server.
@@ -15,7 +16,7 @@ of the server.
  4 files changed, 13 insertions(+), 1 deletion(-)
 
 diff --git a/docs/nbdkit.pod b/docs/nbdkit.pod
-index a2e72b1..346d833 100644
+index a2e72b13..346d8332 100644
 --- a/docs/nbdkit.pod
 +++ b/docs/nbdkit.pod
 @@ -177,6 +177,13 @@ Display brief command line usage information and exit.
@@ -33,7 +34,7 @@ index a2e72b1..346d833 100644
  
  Dump out the compile-time configuration values and exit.
 diff --git a/docs/synopsis.txt b/docs/synopsis.txt
-index 3c23937..c367542 100644
+index 3c239373..c3675422 100644
 --- a/docs/synopsis.txt
 +++ b/docs/synopsis.txt
 @@ -1,4 +1,4 @@
@@ -43,7 +44,7 @@ index 3c23937..c367542 100644
         [--filter FILTER ...] [-f|--foreground]
         [-g|--group GROUP] [-i|--ipaddr IPADDR]
 diff --git a/server/main.c b/server/main.c
-index d39941b..11ba1e6 100644
+index d39941b1..11ba1e6d 100644
 --- a/server/main.c
 +++ b/server/main.c
 @@ -563,6 +563,9 @@ main (int argc, char *argv[])
@@ -57,7 +58,7 @@ index d39941b..11ba1e6 100644
    free_debug_flags ();
  
 diff --git a/server/nbdkit.syms b/server/nbdkit.syms
-index 390972e..96c22c0 100644
+index 390972e2..96c22c07 100644
 --- a/server/nbdkit.syms
 +++ b/server/nbdkit.syms
 @@ -67,6 +67,8 @@
diff --git a/SOURCES/0002-server-Allow-D-debug-flags-to-contain-dots-for-names.patch b/SOURCES/0002-server-Allow-D-debug-flags-to-contain-dots-for-names.patch
index 1a87086..c7f1786 100644
--- a/SOURCES/0002-server-Allow-D-debug-flags-to-contain-dots-for-names.patch
+++ b/SOURCES/0002-server-Allow-D-debug-flags-to-contain-dots-for-names.patch
@@ -1,7 +1,8 @@
 From e5d2d44fff9214725506cbc84e7b3c035ec0eae9 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Thu, 12 Dec 2019 11:06:36 +0000
-Subject: [PATCH] server: Allow -D debug flags to contain dots for namespacing.
+Subject: [PATCH 02/19] server: Allow -D debug flags to contain dots for
+ namespacing.
 
 This is just a convenience.  Either of:
 
@@ -17,7 +18,7 @@ correspond to the same plugin variable "myplugin_debug_foo_bar".
  2 files changed, 17 insertions(+), 1 deletion(-)
 
 diff --git a/docs/nbdkit-plugin.pod b/docs/nbdkit-plugin.pod
-index b69cb82..879ddf0 100644
+index b69cb825..879ddf09 100644
 --- a/docs/nbdkit-plugin.pod
 +++ b/docs/nbdkit-plugin.pod
 @@ -1298,6 +1298,14 @@ You should only use this feature for debug settings.  For general
@@ -36,7 +37,7 @@ index b69cb82..879ddf0 100644
  
  The plugin is a C<*.so> file and possibly a manual page.  You can of
 diff --git a/server/debug-flags.c b/server/debug-flags.c
-index 9344d85..5e06f5e 100644
+index 9344d85c..5e06f5ed 100644
 --- a/server/debug-flags.c
 +++ b/server/debug-flags.c
 @@ -56,12 +56,20 @@ static char *
diff --git a/SOURCES/0003-server-Add-D-nbdkit.backend.controlpath-and-D-nbdkit.patch b/SOURCES/0003-server-Add-D-nbdkit.backend.controlpath-and-D-nbdkit.patch
index ce0a52f..7aac76a 100644
--- a/SOURCES/0003-server-Add-D-nbdkit.backend.controlpath-and-D-nbdkit.patch
+++ b/SOURCES/0003-server-Add-D-nbdkit.backend.controlpath-and-D-nbdkit.patch
@@ -1,7 +1,7 @@
 From 83c72d9bf9d6a9ccf6939b4ebd0028b62673a78a Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Thu, 12 Dec 2019 10:57:52 +0000
-Subject: [PATCH] server: Add -D nbdkit.backend.controlpath and -D
+Subject: [PATCH 03/19] server: Add -D nbdkit.backend.controlpath and -D
  nbdkit.backend.datapath.
 
 These can be used to suppress verbose debugging messages from the
@@ -20,7 +20,7 @@ Remove use of nofilter from the test.
  create mode 100755 tests/test-nbdkit-backend-debug.sh
 
 diff --git a/docs/nbdkit.pod b/docs/nbdkit.pod
-index 346d833..38e6bfc 100644
+index 346d8332..38e6bfca 100644
 --- a/docs/nbdkit.pod
 +++ b/docs/nbdkit.pod
 @@ -182,7 +182,7 @@ value C<N>.  See L<nbdkit-plugin(3)/Debug Flags>.
@@ -73,7 +73,7 @@ index 346d833..38e6bfc 100644
  
  nbdkit responds to the following signals:
 diff --git a/server/backend.c b/server/backend.c
-index b9fe2a2..208c07b 100644
+index b9fe2a21..208c07b1 100644
 --- a/server/backend.c
 +++ b/server/backend.c
 @@ -46,6 +46,22 @@
@@ -349,7 +349,7 @@ index b9fe2a2..208c07b 100644
    if (h->can_cache == NBDKIT_CACHE_EMULATE) {
      static char buf[MAX_REQUEST_SIZE]; /* data sink, never read */
 diff --git a/tests/Makefile.am b/tests/Makefile.am
-index 0134197..d225cc6 100644
+index 01341973..d225cc63 100644
 --- a/tests/Makefile.am
 +++ b/tests/Makefile.am
 @@ -135,6 +135,7 @@ EXTRA_DIST = \
@@ -372,7 +372,7 @@ index 0134197..d225cc6 100644
  
 diff --git a/tests/test-nbdkit-backend-debug.sh b/tests/test-nbdkit-backend-debug.sh
 new file mode 100755
-index 0000000..69a69a7
+index 00000000..69a69a7c
 --- /dev/null
 +++ b/tests/test-nbdkit-backend-debug.sh
 @@ -0,0 +1,70 @@
diff --git a/SOURCES/0004-python-Add-various-constants-to-the-API.patch b/SOURCES/0004-python-Add-various-constants-to-the-API.patch
index 8827874..8268475 100644
--- a/SOURCES/0004-python-Add-various-constants-to-the-API.patch
+++ b/SOURCES/0004-python-Add-various-constants-to-the-API.patch
@@ -1,7 +1,7 @@
 From b646050b8da51c39cf21f95fa847c12784a1169c Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Thu, 21 Nov 2019 15:02:44 +0000
-Subject: [PATCH] python: Add various constants to the API.
+Subject: [PATCH 04/19] python: Add various constants to the API.
 
 These are accessible from the plugin by:
 
@@ -20,7 +20,7 @@ have the complete set available for future use.
  1 file changed, 30 insertions(+)
 
 diff --git a/plugins/python/python.c b/plugins/python/python.c
-index 7052aac..47da083 100644
+index 7052aac0..47da0838 100644
 --- a/plugins/python/python.c
 +++ b/plugins/python/python.c
 @@ -231,6 +231,36 @@ create_nbdkit_module (void)
diff --git a/SOURCES/0005-python-Implement-nbdkit-API-version-2.patch b/SOURCES/0005-python-Implement-nbdkit-API-version-2.patch
index 382c54c..1fa6ee2 100644
--- a/SOURCES/0005-python-Implement-nbdkit-API-version-2.patch
+++ b/SOURCES/0005-python-Implement-nbdkit-API-version-2.patch
@@ -1,7 +1,7 @@
 From 49ef7e7d7c3602cc8e53d2052fce9d3a12840ea2 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Thu, 21 Nov 2019 15:44:39 +0000
-Subject: [PATCH] python: Implement nbdkit API version 2.
+Subject: [PATCH 05/19] python: Implement nbdkit API version 2.
 
 To avoid breaking existing plugins, Python plugins wishing to use
 version 2 of the API must opt in by declaring:
@@ -30,7 +30,7 @@ https://www.redhat.com/archives/libguestfs/2019-November/thread.html#00220
  6 files changed, 190 insertions(+), 75 deletions(-)
 
 diff --git a/plugins/python/example.py b/plugins/python/example.py
-index 60f9d7f..c04b7e2 100644
+index 60f9d7f0..c04b7e29 100644
 --- a/plugins/python/example.py
 +++ b/plugins/python/example.py
 @@ -34,6 +34,12 @@ import errno
@@ -76,7 +76,7 @@ index 60f9d7f..c04b7e2 100644
      else:
          nbdkit.set_error(errno.EOPNOTSUPP)
 diff --git a/plugins/python/nbdkit-python-plugin.pod b/plugins/python/nbdkit-python-plugin.pod
-index 3680fd6..4923d9d 100644
+index 3680fd65..4923d9da 100644
 --- a/plugins/python/nbdkit-python-plugin.pod
 +++ b/plugins/python/nbdkit-python-plugin.pod
 @@ -33,11 +33,12 @@ To write a Python nbdkit plugin, you create a Python file which
@@ -216,7 +216,7 @@ index 3680fd6..4923d9d 100644
  =back
  
 diff --git a/plugins/python/python.c b/plugins/python/python.c
-index 47da083..0f28595 100644
+index 47da0838..0f28595f 100644
 --- a/plugins/python/python.c
 +++ b/plugins/python/python.c
 @@ -46,6 +46,8 @@
@@ -475,7 +475,7 @@ index 47da083..0f28595 100644
      if (last_error == EOPNOTSUPP || last_error == ENOTSUP) {
        /* When user requests this particular error, we want to
 diff --git a/tests/python-exception.py b/tests/python-exception.py
-index d0c79bb..ee4a3f3 100644
+index d0c79bb0..ee4a3f3a 100644
 --- a/tests/python-exception.py
 +++ b/tests/python-exception.py
 @@ -62,5 +62,5 @@ def get_size(h):
@@ -487,7 +487,7 @@ index d0c79bb..ee4a3f3 100644
 +def pread(h, buf, offset):
 +    buf[:] = bytearray(len(buf))
 diff --git a/tests/shebang.py b/tests/shebang.py
-index 6f33623..0634589 100755
+index 6f336230..0634589a 100755
 --- a/tests/shebang.py
 +++ b/tests/shebang.py
 @@ -13,6 +13,7 @@ def get_size(h):
@@ -501,7 +501,7 @@ index 6f33623..0634589 100755
 +    end = offset + len(buf)
 +    buf[:] = disk[offset:end]
 diff --git a/tests/test.py b/tests/test.py
-index 9a2e947..4db5662 100644
+index 9a2e947d..4db56623 100644
 --- a/tests/test.py
 +++ b/tests/test.py
 @@ -3,6 +3,9 @@ import nbdkit
diff --git a/SOURCES/0006-python-Implement-cache.patch b/SOURCES/0006-python-Implement-cache.patch
index d6e0268..032327d 100644
--- a/SOURCES/0006-python-Implement-cache.patch
+++ b/SOURCES/0006-python-Implement-cache.patch
@@ -1,7 +1,7 @@
 From c5b1fac4c67078f0164bd23eab6d4d2b8c9830b0 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Thu, 21 Nov 2019 16:42:02 +0000
-Subject: [PATCH] python: Implement cache.
+Subject: [PATCH 06/19] python: Implement cache.
 
 However this does not implement can_cache, since that is not a simple
 boolean.
@@ -13,7 +13,7 @@ boolean.
  2 files changed, 44 insertions(+), 1 deletion(-)
 
 diff --git a/plugins/python/nbdkit-python-plugin.pod b/plugins/python/nbdkit-python-plugin.pod
-index 4923d9d..0ea8dee 100644
+index 4923d9da..0ea8deef 100644
 --- a/plugins/python/nbdkit-python-plugin.pod
 +++ b/plugins/python/nbdkit-python-plugin.pod
 @@ -289,6 +289,19 @@ because there is nothing to optimize if
@@ -45,7 +45,7 @@ index 4923d9d..0ea8dee 100644
  
  These are not yet supported.
 diff --git a/plugins/python/python.c b/plugins/python/python.c
-index 0f28595..c5cf38e 100644
+index 0f28595f..c5cf38e5 100644
 --- a/plugins/python/python.c
 +++ b/plugins/python/python.c
 @@ -714,6 +714,36 @@ py_zero (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
diff --git a/SOURCES/0007-python-Implement-can_zero-can_fast_zero.patch b/SOURCES/0007-python-Implement-can_zero-can_fast_zero.patch
index f308909..e6a82a4 100644
--- a/SOURCES/0007-python-Implement-can_zero-can_fast_zero.patch
+++ b/SOURCES/0007-python-Implement-can_zero-can_fast_zero.patch
@@ -1,7 +1,7 @@
 From 17721b316dd66b0a1ed792eeccd2489fb97828df Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Thu, 21 Nov 2019 16:42:59 +0000
-Subject: [PATCH] python: Implement can_zero, can_fast_zero.
+Subject: [PATCH 07/19] python: Implement can_zero, can_fast_zero.
 
 (cherry picked from commit 039f600d2ad7a9ff04523a165eb2fe41b9c87c01)
 ---
@@ -10,7 +10,7 @@ Subject: [PATCH] python: Implement can_zero, can_fast_zero.
  2 files changed, 28 insertions(+), 2 deletions(-)
 
 diff --git a/plugins/python/nbdkit-python-plugin.pod b/plugins/python/nbdkit-python-plugin.pod
-index 0ea8dee..1f1c30f 100644
+index 0ea8deef..1f1c30f6 100644
 --- a/plugins/python/nbdkit-python-plugin.pod
 +++ b/plugins/python/nbdkit-python-plugin.pod
 @@ -208,6 +208,20 @@ contents will be garbage collected.
@@ -44,7 +44,7 @@ index 0ea8dee..1f1c30f 100644
  C<can_multi_conn>,
  C<extents>.
 diff --git a/plugins/python/python.c b/plugins/python/python.c
-index c5cf38e..38fc119 100644
+index c5cf38e5..38fc1193 100644
 --- a/plugins/python/python.c
 +++ b/plugins/python/python.c
 @@ -797,6 +797,18 @@ py_can_trim (void *handle)
diff --git a/SOURCES/0008-python-Implement-can_multi_conn.patch b/SOURCES/0008-python-Implement-can_multi_conn.patch
index 242026f..d854076 100644
--- a/SOURCES/0008-python-Implement-can_multi_conn.patch
+++ b/SOURCES/0008-python-Implement-can_multi_conn.patch
@@ -1,7 +1,7 @@
 From 2a85ce81ad95eb2f9b2f29666480b814ea0f80d9 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Thu, 21 Nov 2019 16:46:11 +0000
-Subject: [PATCH] python: Implement can_multi_conn.
+Subject: [PATCH 08/19] python: Implement can_multi_conn.
 
 (cherry picked from commit 21dd7bf49d3238c7e75918d4bf324b617f458d83)
 ---
@@ -10,7 +10,7 @@ Subject: [PATCH] python: Implement can_multi_conn.
  2 files changed, 14 insertions(+), 1 deletion(-)
 
 diff --git a/plugins/python/nbdkit-python-plugin.pod b/plugins/python/nbdkit-python-plugin.pod
-index 1f1c30f..b92bb56 100644
+index 1f1c30f6..b92bb56a 100644
 --- a/plugins/python/nbdkit-python-plugin.pod
 +++ b/plugins/python/nbdkit-python-plugin.pod
 @@ -187,6 +187,13 @@ contents will be garbage collected.
@@ -36,7 +36,7 @@ index 1f1c30f..b92bb56 100644
  
  These are not yet supported.
 diff --git a/plugins/python/python.c b/plugins/python/python.c
-index 38fc119..b186b99 100644
+index 38fc1193..b186b991 100644
 --- a/plugins/python/python.c
 +++ b/plugins/python/python.c
 @@ -779,6 +779,12 @@ py_is_rotational (void *handle)
diff --git a/SOURCES/0009-python-Implement-can_fua-and-can_cache.patch b/SOURCES/0009-python-Implement-can_fua-and-can_cache.patch
index 8e60a5c..f979c4e 100644
--- a/SOURCES/0009-python-Implement-can_fua-and-can_cache.patch
+++ b/SOURCES/0009-python-Implement-can_fua-and-can_cache.patch
@@ -1,7 +1,7 @@
 From 38124a137974e1433d68732640ca7f88664557da Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Fri, 22 Nov 2019 19:25:53 +0000
-Subject: [PATCH] python: Implement can_fua and can_cache.
+Subject: [PATCH 09/19] python: Implement can_fua and can_cache.
 
 (cherry picked from commit 97c46f885edec5a61a96ac86eccb9d8c874c602e)
 ---
@@ -10,7 +10,7 @@ Subject: [PATCH] python: Implement can_fua and can_cache.
  2 files changed, 74 insertions(+), 2 deletions(-)
 
 diff --git a/plugins/python/nbdkit-python-plugin.pod b/plugins/python/nbdkit-python-plugin.pod
-index b92bb56..4065ec7 100644
+index b92bb56a..4065ec75 100644
 --- a/plugins/python/nbdkit-python-plugin.pod
 +++ b/plugins/python/nbdkit-python-plugin.pod
 @@ -229,6 +229,22 @@ contents will be garbage collected.
@@ -46,7 +46,7 @@ index b92bb56..4065ec7 100644
  C<extents>.
  
 diff --git a/plugins/python/python.c b/plugins/python/python.c
-index b186b99..5e2e526 100644
+index b186b991..5e2e5269 100644
 --- a/plugins/python/python.c
 +++ b/plugins/python/python.c
 @@ -815,6 +815,62 @@ py_can_fast_zero (void *handle)
diff --git a/SOURCES/0010-tests-Test-the-Python-plugin-thoroughly.patch b/SOURCES/0010-tests-Test-the-Python-plugin-thoroughly.patch
index ca3af69..27270af 100644
--- a/SOURCES/0010-tests-Test-the-Python-plugin-thoroughly.patch
+++ b/SOURCES/0010-tests-Test-the-Python-plugin-thoroughly.patch
@@ -1,7 +1,7 @@
 From 7cb79aef2a12f29f1286caf3858001e47214f871 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Thu, 21 Nov 2019 20:54:41 +0000
-Subject: [PATCH] tests: Test the Python plugin thoroughly.
+Subject: [PATCH 10/19] tests: Test the Python plugin thoroughly.
 
 This tests the Python plugin thoroughly by issuing client commands
 through libnbd and checking we get the expected results.
@@ -23,7 +23,7 @@ through libnbd and checking we get the expected results.
  create mode 100755 tests/test_python.py
 
 diff --git a/.gitignore b/.gitignore
-index b25ac7f..e25bd99 100644
+index b25ac7fe..e25bd99b 100644
 --- a/.gitignore
 +++ b/.gitignore
 @@ -71,6 +71,7 @@ Makefile.in
@@ -35,7 +35,7 @@ index b25ac7f..e25bd99 100644
  /tests/disk.gz
  /tests/disk.xz
 diff --git a/README b/README
-index 40f4cd3..05f1e06 100644
+index 40f4cd37..05f1e060 100644
 --- a/README
 +++ b/README
 @@ -130,6 +130,8 @@ For the Python plugin:
@@ -48,7 +48,7 @@ index 40f4cd3..05f1e06 100644
  
   - OCaml >= 4.02.2
 diff --git a/tests/Makefile.am b/tests/Makefile.am
-index d225cc6..09103fb 100644
+index d225cc63..09103fbb 100644
 --- a/tests/Makefile.am
 +++ b/tests/Makefile.am
 @@ -67,6 +67,7 @@ EXTRA_PROGRAMS =
@@ -91,7 +91,7 @@ index d225cc6..09103fb 100644
  endif HAVE_PYTHON
  
 diff --git a/tests/test-lang-plugins.c b/tests/test-lang-plugins.c
-index ffb1918..93f9938 100644
+index ffb19180..93f99381 100644
 --- a/tests/test-lang-plugins.c
 +++ b/tests/test-lang-plugins.c
 @@ -56,8 +56,7 @@ main (int argc, char *argv[])
@@ -106,7 +106,7 @@ index ffb1918..93f9938 100644
      exit (77);                  /* Tells automake to skip the test. */
 diff --git a/tests/test-python-plugin.py b/tests/test-python-plugin.py
 new file mode 100644
-index 0000000..8e90bc2
+index 00000000..8e90bc23
 --- /dev/null
 +++ b/tests/test-python-plugin.py
 @@ -0,0 +1,133 @@
@@ -245,7 +245,7 @@ index 0000000..8e90bc2
 +    # do nothing
 diff --git a/tests/test-python.sh b/tests/test-python.sh
 new file mode 100755
-index 0000000..50324d0
+index 00000000..50324d0f
 --- /dev/null
 +++ b/tests/test-python.sh
 @@ -0,0 +1,49 @@
@@ -300,7 +300,7 @@ index 0000000..50324d0
 +$PYTHON -m unittest test_python
 diff --git a/tests/test.py b/tests/test.py
 deleted file mode 100644
-index 4db5662..0000000
+index 4db56623..00000000
 --- a/tests/test.py
 +++ /dev/null
 @@ -1,60 +0,0 @@
@@ -366,7 +366,7 @@ index 4db5662..0000000
 -    disk[offset:offset+count] = bytearray(count)
 diff --git a/tests/test_python.py b/tests/test_python.py
 new file mode 100755
-index 0000000..6b9f297
+index 00000000..6b9f2979
 --- /dev/null
 +++ b/tests/test_python.py
 @@ -0,0 +1,222 @@
diff --git a/SOURCES/0011-New-filter-extentlist.patch b/SOURCES/0011-New-filter-extentlist.patch
index 6e8ca81..d33eb00 100644
--- a/SOURCES/0011-New-filter-extentlist.patch
+++ b/SOURCES/0011-New-filter-extentlist.patch
@@ -1,7 +1,7 @@
 From e744dcb38cc52cbe64977efcdd4bc60e802d1b17 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Thu, 23 Jan 2020 19:52:00 +0000
-Subject: [PATCH] New filter: extentlist.
+Subject: [PATCH 11/19] New filter: extentlist.
 
 Allows a list of extents to be placed on top of an existing plugin.
 
@@ -23,7 +23,7 @@ Allows a list of extents to be placed on top of an existing plugin.
  create mode 100755 tests/test-extentlist.sh
 
 diff --git a/TODO b/TODO
-index d2aca44..2a3e89d 100644
+index d2aca440..2a3e89dc 100644
 --- a/TODO
 +++ b/TODO
 @@ -187,6 +187,10 @@ Suggestions for filters
@@ -38,7 +38,7 @@ index d2aca44..2a3e89d 100644
  
  * allow other kinds of traffic shaping such as VBR
 diff --git a/configure.ac b/configure.ac
-index fde498b..41e68de 100644
+index fde498b8..41e68de3 100644
 --- a/configure.ac
 +++ b/configure.ac
 @@ -896,6 +896,7 @@ filters="\
@@ -58,7 +58,7 @@ index fde498b..41e68de 100644
                   filters/log/Makefile
                   filters/nocache/Makefile
 diff --git a/filters/cacheextents/nbdkit-cacheextents-filter.pod b/filters/cacheextents/nbdkit-cacheextents-filter.pod
-index fdd2285..bb2514a 100644
+index fdd2285a..bb2514a4 100644
 --- a/filters/cacheextents/nbdkit-cacheextents-filter.pod
 +++ b/filters/cacheextents/nbdkit-cacheextents-filter.pod
 @@ -52,6 +52,7 @@ C<nbdkit-cacheextents-filter> first appeared in nbdkit 1.14.
@@ -71,7 +71,7 @@ index fdd2285..bb2514a 100644
  L<nbdkit-filter(3)>,
 diff --git a/filters/extentlist/Makefile.am b/filters/extentlist/Makefile.am
 new file mode 100644
-index 0000000..88a9afe
+index 00000000..88a9afe1
 --- /dev/null
 +++ b/filters/extentlist/Makefile.am
 @@ -0,0 +1,67 @@
@@ -144,7 +144,7 @@ index 0000000..88a9afe
 +endif HAVE_POD
 diff --git a/filters/extentlist/extentlist.c b/filters/extentlist/extentlist.c
 new file mode 100644
-index 0000000..5f4990b
+index 00000000..5f4990b3
 --- /dev/null
 +++ b/filters/extentlist/extentlist.c
 @@ -0,0 +1,326 @@
@@ -476,7 +476,7 @@ index 0000000..5f4990b
 +NBDKIT_REGISTER_FILTER(filter)
 diff --git a/filters/extentlist/nbdkit-extentlist-filter.pod b/filters/extentlist/nbdkit-extentlist-filter.pod
 new file mode 100644
-index 0000000..adfb4ad
+index 00000000..adfb4ad8
 --- /dev/null
 +++ b/filters/extentlist/nbdkit-extentlist-filter.pod
 @@ -0,0 +1,90 @@
@@ -571,7 +571,7 @@ index 0000000..adfb4ad
 +
 +Copyright (C) 2020 Red Hat Inc.
 diff --git a/filters/noextents/nbdkit-noextents-filter.pod b/filters/noextents/nbdkit-noextents-filter.pod
-index 991ecfe..0260a5c 100644
+index 991ecfe8..0260a5cf 100644
 --- a/filters/noextents/nbdkit-noextents-filter.pod
 +++ b/filters/noextents/nbdkit-noextents-filter.pod
 @@ -47,6 +47,7 @@ C<nbdkit-noextents-filter> first appeared in nbdkit 1.14.
@@ -583,7 +583,7 @@ index 991ecfe..0260a5c 100644
  L<nbdkit-nocache-filter(1)>,
  L<nbdkit-noparallel-filter(1)>,
 diff --git a/tests/Makefile.am b/tests/Makefile.am
-index 09103fb..b99952f 100644
+index 09103fbb..b99952f4 100644
 --- a/tests/Makefile.am
 +++ b/tests/Makefile.am
 @@ -110,6 +110,7 @@ EXTRA_DIST = \
@@ -606,7 +606,7 @@ index 09103fb..b99952f 100644
  
 diff --git a/tests/test-extentlist.sh b/tests/test-extentlist.sh
 new file mode 100755
-index 0000000..7d05de4
+index 00000000..7d05de4f
 --- /dev/null
 +++ b/tests/test-extentlist.sh
 @@ -0,0 +1,175 @@
diff --git a/SOURCES/0012-extentlist-Documentation-and-test-fixes.patch b/SOURCES/0012-extentlist-Documentation-and-test-fixes.patch
index c0275ec..62bdab0 100644
--- a/SOURCES/0012-extentlist-Documentation-and-test-fixes.patch
+++ b/SOURCES/0012-extentlist-Documentation-and-test-fixes.patch
@@ -1,7 +1,7 @@
 From 2a3e909e9e1ccb608bde75b76524acd753b33889 Mon Sep 17 00:00:00 2001
 From: "Richard W.M. Jones" <rjones@redhat.com>
 Date: Sat, 25 Jan 2020 11:38:14 +0000
-Subject: [PATCH] extentlist: Documentation and test fixes.
+Subject: [PATCH 12/19] extentlist: Documentation and test fixes.
 
 Updates commit 3e770b6d6620a62546849a2863638041c0b00640.
 
@@ -15,7 +15,7 @@ Updates commit 3e770b6d6620a62546849a2863638041c0b00640.
  5 files changed, 26 insertions(+), 11 deletions(-)
 
 diff --git a/TODO b/TODO
-index 2a3e89d..e1ac71c 100644
+index 2a3e89dc..e1ac71cd 100644
 --- a/TODO
 +++ b/TODO
 @@ -187,10 +187,6 @@ Suggestions for filters
@@ -45,7 +45,7 @@ index 2a3e89d..e1ac71c 100644
  --------------------
  
 diff --git a/filters/extentlist/nbdkit-extentlist-filter.pod b/filters/extentlist/nbdkit-extentlist-filter.pod
-index adfb4ad..5d1a38a 100644
+index adfb4ad8..5d1a38ae 100644
 --- a/filters/extentlist/nbdkit-extentlist-filter.pod
 +++ b/filters/extentlist/nbdkit-extentlist-filter.pod
 @@ -4,7 +4,7 @@ nbdkit-extentlist-filter - place extent list over a plugin
@@ -84,7 +84,7 @@ index adfb4ad..5d1a38a 100644
  =head1 FILE FORMAT
  
 diff --git a/plugins/curl/nbdkit-curl-plugin.pod b/plugins/curl/nbdkit-curl-plugin.pod
-index 827e0bd..d3c8524 100644
+index 827e0bd1..d3c85248 100644
 --- a/plugins/curl/nbdkit-curl-plugin.pod
 +++ b/plugins/curl/nbdkit-curl-plugin.pod
 @@ -182,6 +182,7 @@ L<libcurl(3)>,
@@ -96,7 +96,7 @@ index 827e0bd..d3c8524 100644
  L<nbdkit-retry-filter(1)>,
  L<nbdkit-ssh-plugin(1)>,
 diff --git a/plugins/ssh/nbdkit-ssh-plugin.pod b/plugins/ssh/nbdkit-ssh-plugin.pod
-index 0a0421d..3fc3146 100644
+index 0a0421d5..3fc3146a 100644
 --- a/plugins/ssh/nbdkit-ssh-plugin.pod
 +++ b/plugins/ssh/nbdkit-ssh-plugin.pod
 @@ -316,6 +316,7 @@ C<nbdkit-ssh-plugin> first appeared in nbdkit 1.12.
@@ -108,7 +108,7 @@ index 0a0421d..3fc3146 100644
  L<nbdkit-retry-filter(1)>,
  L<nbdkit-plugin(3)>,
 diff --git a/tests/test-extentlist.sh b/tests/test-extentlist.sh
-index 7d05de4..73ce3ca 100755
+index 7d05de4f..73ce3ca6 100755
 --- a/tests/test-extentlist.sh
 +++ b/tests/test-extentlist.sh
 @@ -50,7 +50,7 @@ cleanup_fn rm $files
diff --git a/SOURCES/0013-vddk-Update-for-VDDK-7.0-RHBZ-1831969.patch b/SOURCES/0013-vddk-Update-for-VDDK-7.0-RHBZ-1831969.patch
new file mode 100644
index 0000000..dcfd092
--- /dev/null
+++ b/SOURCES/0013-vddk-Update-for-VDDK-7.0-RHBZ-1831969.patch
@@ -0,0 +1,51 @@
+From bf1eabb211004f3dc74dd243e2adf52a13290377 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Wed, 6 May 2020 09:33:32 +0100
+Subject: [PATCH 13/19] vddk: Update for VDDK 7.0 (RHBZ#1831969).
+
+This version of VDDK changes the soname to libvixDiskLib.so.7.
+
+Thanks: Ming Xie
+(cherry picked from commit 7f53999179af98aa47569c6771517f7dfa08c5d0)
+---
+ plugins/vddk/vddk-structs.h | 4 +++-
+ plugins/vddk/vddk.c         | 1 +
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/plugins/vddk/vddk-structs.h b/plugins/vddk/vddk-structs.h
+index 86087871..fff7201b 100644
+--- a/plugins/vddk/vddk-structs.h
++++ b/plugins/vddk/vddk-structs.h
+@@ -32,7 +32,7 @@
+ 
+ /* Types and structs that we pass to or return from the VDDK API.
+  *
+- * Updated to VDDK 6.7
++ * Updated to VDDK 7.0
+  */
+ 
+ #ifndef NBDKIT_VDDK_STRUCTS_H
+@@ -127,6 +127,8 @@ typedef struct VixDiskLibInfo {
+   int numLinks;
+   char *parentFileNameHint;
+   char *uuid;
++  uint32_t logicalSectorSize;   /* Added in 7.0. */
++  uint32_t physicalSectorSize;  /* Added in 7.0. */
+ } VixDiskLibInfo;
+ 
+ typedef struct {
+diff --git a/plugins/vddk/vddk.c b/plugins/vddk/vddk.c
+index 5d3764d6..97ef5297 100644
+--- a/plugins/vddk/vddk.c
++++ b/plugins/vddk/vddk.c
+@@ -149,6 +149,7 @@ vddk_load (void)
+ {
+   static const char *sonames[] = {
+     /* Prefer the newest library in case multiple exist. */
++    "libvixDiskLib.so.7",
+     "libvixDiskLib.so.6",
+     "libvixDiskLib.so.5",
+   };
+-- 
+2.18.2
+
diff --git a/SOURCES/0014-common-include-Add-ASCII-only-ctype-header-and-ascii.patch b/SOURCES/0014-common-include-Add-ASCII-only-ctype-header-and-ascii.patch
new file mode 100644
index 0000000..6383c63
--- /dev/null
+++ b/SOURCES/0014-common-include-Add-ASCII-only-ctype-header-and-ascii.patch
@@ -0,0 +1,354 @@
+From cb3d83d0606d5267752895151bb3c229c48d6fb6 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Tue, 19 May 2020 12:03:23 +0100
+Subject: [PATCH 14/19] common/include: Add ASCII-only ctype header and
+ ascii_is* functions.
+
+Our existing uses of <ctype.h> were not necessarily safe if the locale
+was changed.
+
+Also I removed the unnecessary use of isascii, deprecated by POSIX.1-2008.
+
+(cherry picked from commit 9f34db74786fdc92b290a7d47e4b003bd84fec69)
+---
+ .gitignore                           |  1 +
+ common/include/Makefile.am           |  6 +++
+ common/include/ascii-ctype.h         | 60 ++++++++++++++++++++++++++
+ common/include/test-ascii-ctype.c    | 63 ++++++++++++++++++++++++++++
+ plugins/partitioning/partition-gpt.c | 12 +++---
+ plugins/sh/Makefile.am               |  1 +
+ plugins/sh/call.c                    |  6 +--
+ server/backend.c                     |  7 ++--
+ server/public.c                      |  4 +-
+ 9 files changed, 146 insertions(+), 14 deletions(-)
+ create mode 100644 common/include/ascii-ctype.h
+ create mode 100644 common/include/test-ascii-ctype.c
+
+diff --git a/.gitignore b/.gitignore
+index e25bd99b..523894b7 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -26,6 +26,7 @@ Makefile.in
+ /aclocal.m4
+ /autom4te.cache
+ /common/bitmap/test-bitmap
++/common/include/test-ascii-ctype
+ /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 4482de37..d7b0d7a8 100644
+--- a/common/include/Makefile.am
++++ b/common/include/Makefile.am
+@@ -34,6 +34,7 @@ include $(top_srcdir)/common-rules.mk
+ # These headers contain only common code shared by the core server,
+ # plugins and/or filters.  They are not installed.
+ EXTRA_DIST = \
++	ascii-ctype.h \
+ 	byte-swapping.h \
+ 	exit-with-parent.h \
+ 	get-current-dir-name.h \
+@@ -50,6 +51,7 @@ EXTRA_DIST = \
+ # Unit tests.
+ 
+ TESTS = \
++	test-ascii-ctype \
+ 	test-byte-swapping \
+ 	test-current-dir-name \
+ 	test-isaligned \
+@@ -62,6 +64,10 @@ TESTS = \
+ 	$(NULL)
+ check_PROGRAMS = $(TESTS)
+ 
++test_ascii_ctype_SOURCES = test-ascii-ctype.c ascii-ctype.h
++test_ascii_ctype_CPPFLAGS = -I$(srcdir)
++test_ascii_ctype_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
+new file mode 100644
+index 00000000..5e8bf237
+--- /dev/null
++++ b/common/include/ascii-ctype.h
+@@ -0,0 +1,60 @@
++/* 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.
++ */
++
++/* Normal ctype functions are affected by the current locale.  For
++ * example isupper() might recognize Ä in some but not all locales.
++ * These functions match only 7 bit ASCII characters.
++ */
++
++#ifndef NBDKIT_ASCII_CTYPE_H
++#define NBDKIT_ASCII_CTYPE_H
++
++#define ascii_isalnum(c) (ascii_isalpha (c) || ascii_isdigit (c))
++
++#define ascii_isalpha(c)                                        \
++  (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
++
++#define ascii_isdigit(c)                        \
++  ((c) >= '0' && (c) <= '9')
++
++#define ascii_isspace(c)                                                \
++  ((c) == '\t' || (c) == '\n' || (c) == '\f' || (c) == '\r' || (c) == ' ')
++
++#define ascii_isxdigit(c)                                               \
++  ((c) == '0' || (c) == '1' || (c) == '2' || (c) == '3' || (c) == '4' || \
++   (c) == '5' || (c) == '6' || (c) == '7' || (c) == '8' || (c) == '9' || \
++   (c) == 'a' || (c) == 'b' || (c) == 'c' ||                            \
++   (c) == 'd' || (c) == 'e' || (c) == 'f' ||                            \
++   (c) == 'A' || (c) == 'B' || (c) == 'C' ||                            \
++   (c) == 'D' || (c) == 'E' || (c) == 'F')
++
++#endif /* NBDKIT_ASCII_CTYPE_H */
+diff --git a/common/include/test-ascii-ctype.c b/common/include/test-ascii-ctype.c
+new file mode 100644
+index 00000000..edf27aa6
+--- /dev/null
++++ b/common/include/test-ascii-ctype.c
+@@ -0,0 +1,63 @@
++/* 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-ctype.h"
++
++int
++main (void)
++{
++  assert (ascii_isspace (' '));
++  assert (ascii_isspace ('\t'));
++  assert (ascii_isspace ('\n'));
++  assert (! ascii_isspace ('a'));
++
++  assert (ascii_isalpha ('a'));
++  assert (ascii_isalpha ('Z'));
++  assert (ascii_isalpha ('z'));
++  assert (! ascii_isalpha (' '));
++  assert (! ascii_isalpha ('0'));
++  { const char *s = "Ä"; assert (! ascii_isalpha (s[0])); }
++  { const char *s = "®"; assert (! ascii_isalpha (s[0])); }
++
++  assert (ascii_isdigit ('0'));
++  assert (ascii_isdigit ('9'));
++  { const char *s = "Ø"; assert (! ascii_isdigit (s[0])); } /* U+00D8 */
++  { const char *s = "9"; assert (! ascii_isdigit (s[0])); } /* U+FF19 */
++
++  exit (EXIT_SUCCESS);
++}
+diff --git a/plugins/partitioning/partition-gpt.c b/plugins/partitioning/partition-gpt.c
+index 75b4643a..819e9abe 100644
+--- a/plugins/partitioning/partition-gpt.c
++++ b/plugins/partitioning/partition-gpt.c
+@@ -36,12 +36,12 @@
+ #include <stdlib.h>
+ #include <stdbool.h>
+ #include <string.h>
+-#include <ctype.h>
+ #include <inttypes.h>
+ #include <assert.h>
+ 
+ #include <nbdkit-plugin.h>
+ 
++#include "ascii-ctype.h"
+ #include "byte-swapping.h"
+ 
+ #include "efi-crc32.h"
+@@ -244,19 +244,19 @@ parse_guid (const char *str, char *out)
+     return -1;
+ 
+   for (i = 0; i < 8; ++i)
+-    if (!isxdigit (str[i]))
++    if (!ascii_isxdigit (str[i]))
+       return -1;
+   for (i = 9; i < 13; ++i)
+-    if (!isxdigit (str[i]))
++    if (!ascii_isxdigit (str[i]))
+       return -1;
+   for (i = 14; i < 18; ++i)
+-    if (!isxdigit (str[i]))
++    if (!ascii_isxdigit (str[i]))
+       return -1;
+   for (i = 19; i < 23; ++i)
+-    if (!isxdigit (str[i]))
++    if (!ascii_isxdigit (str[i]))
+       return -1;
+   for (i = 24; i < 36; ++i)
+-    if (!isxdigit (str[i]))
++    if (!ascii_isxdigit (str[i]))
+       return -1;
+ 
+   /* The first, second and third blocks are parsed as little endian,
+diff --git a/plugins/sh/Makefile.am b/plugins/sh/Makefile.am
+index 445cdcd5..1f42b64c 100644
+--- a/plugins/sh/Makefile.am
++++ b/plugins/sh/Makefile.am
+@@ -48,6 +48,7 @@ nbdkit_sh_plugin_la_SOURCES = \
+ 
+ nbdkit_sh_plugin_la_CPPFLAGS = \
+ 	-I$(top_srcdir)/include \
++	-I$(top_srcdir)/common/include \
+ 	-I$(top_srcdir)/common/utils \
+ 	$(NULL)
+ nbdkit_sh_plugin_la_CFLAGS = $(WARNINGS_CFLAGS)
+diff --git a/plugins/sh/call.c b/plugins/sh/call.c
+index 2d99a120..ae0cc0ac 100644
+--- a/plugins/sh/call.c
++++ b/plugins/sh/call.c
+@@ -44,10 +44,10 @@
+ #include <poll.h>
+ #include <sys/types.h>
+ #include <sys/wait.h>
+-#include <ctype.h>
+ 
+ #include <nbdkit-plugin.h>
+ 
++#include "ascii-ctype.h"
+ #include "cleanup.h"
+ #include "utils.h"
+ 
+@@ -392,7 +392,7 @@ handle_script_error (const char *argv0, char *ebuf, size_t len)
+   }
+ 
+   if (skip && ebuf[skip]) {
+-    if (!isspace ((unsigned char) ebuf[skip])) {
++    if (!ascii_isspace ((unsigned char) ebuf[skip])) {
+       /* Treat 'EINVALID' as EIO, not EINVAL */
+       err = EIO;
+       skip = 0;
+@@ -400,7 +400,7 @@ handle_script_error (const char *argv0, char *ebuf, size_t len)
+     else
+       do
+         skip++;
+-      while (isspace ((unsigned char) ebuf[skip]));
++      while (ascii_isspace ((unsigned char) ebuf[skip]));
+   }
+ 
+   while (len > 0 && ebuf[len-1] == '\n')
+diff --git a/server/backend.c b/server/backend.c
+index 208c07b1..9add341f 100644
+--- a/server/backend.c
++++ b/server/backend.c
+@@ -37,13 +37,14 @@
+ #include <inttypes.h>
+ #include <string.h>
+ #include <assert.h>
+-#include <ctype.h>
+ 
+ #include <dlfcn.h>
+ 
+-#include "internal.h"
++#include "ascii-ctype.h"
+ #include "minmax.h"
+ 
++#include "internal.h"
++
+ /* Helpers for registering a new backend. */
+ 
+ /* Use:
+@@ -100,7 +101,7 @@ backend_load (struct backend *b, const char *name, void (*load) (void))
+   for (i = 0; i < len; ++i) {
+     unsigned char c = name[i];
+ 
+-    if (!(isascii (c) && isalnum (c))) {
++    if (! ascii_isalnum (c)) {
+       fprintf (stderr,
+                "%s: %s: %s.name ('%s') field "
+                "must contain only ASCII alphanumeric characters\n",
+diff --git a/server/public.c b/server/public.c
+index 418945fe..98b78482 100644
+--- a/server/public.c
++++ b/server/public.c
+@@ -45,13 +45,13 @@
+ #include <string.h>
+ #include <unistd.h>
+ #include <limits.h>
+-#include <ctype.h>
+ #include <termios.h>
+ #include <errno.h>
+ #include <poll.h>
+ #include <signal.h>
+ #include <sys/socket.h>
+ 
++#include "ascii-ctype.h"
+ #include "get-current-dir-name.h"
+ 
+ #include "internal.h"
+@@ -210,7 +210,7 @@ nbdkit_parse_int64_t (const char *what, const char *str, int64_t *rp)
+  */
+ #define PARSE_ERROR_IF_NEGATIVE                                         \
+   do {                                                                  \
+-    while (isspace (*str))                                              \
++    while (ascii_isspace (*str))                                        \
+       str++;                                                            \
+     if (*str == '-') {                                                  \
+       nbdkit_error ("%s: negative numbers are not allowed", what);      \
+-- 
+2.18.2
+
diff --git a/SOURCES/0015-curl-Remove-some-useless-debug-messages.patch b/SOURCES/0015-curl-Remove-some-useless-debug-messages.patch
new file mode 100644
index 0000000..fe49773
--- /dev/null
+++ b/SOURCES/0015-curl-Remove-some-useless-debug-messages.patch
@@ -0,0 +1,46 @@
+From 0aa8e873e626c8af5f47e2e9896f33dcff4d7bb6 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Sat, 28 Mar 2020 16:59:55 +0000
+Subject: [PATCH 15/19] curl: Remove some useless debug messages.
+
+You can get the same information by setting -D curl.verbose=1
+
+(cherry picked from commit e3539d55241adcbf1bc8102c019a0dd0ae8a3407)
+---
+ plugins/curl/curl.c | 6 ------
+ 1 file changed, 6 deletions(-)
+
+diff --git a/plugins/curl/curl.c b/plugins/curl/curl.c
+index 007449bc..8b341ae0 100644
+--- a/plugins/curl/curl.c
++++ b/plugins/curl/curl.c
+@@ -311,8 +311,6 @@ curl_open (int readonly)
+     goto err;
+   }
+ 
+-  nbdkit_debug ("opened libcurl easy handle");
+-
+   /* Note this writes the output to stderr directly.  We should
+    * consider using CURLOPT_DEBUGFUNCTION so we can handle it with
+    * nbdkit_debug.
+@@ -340,8 +338,6 @@ curl_open (int readonly)
+     goto err;
+   }
+ 
+-  nbdkit_debug ("set libcurl URL: %s", url);
+-
+   curl_easy_setopt (h->c, CURLOPT_AUTOREFERER, 1);
+   curl_easy_setopt (h->c, CURLOPT_FOLLOWLOCATION, 1);
+   curl_easy_setopt (h->c, CURLOPT_FAILONERROR, 1);
+@@ -436,8 +432,6 @@ curl_open (int readonly)
+     curl_easy_setopt (h->c, CURLOPT_READDATA, h);
+   }
+ 
+-  nbdkit_debug ("returning new handle %p", h);
+-
+   return h;
+ 
+  err:
+-- 
+2.18.2
+
diff --git a/SOURCES/0016-curl-Fix-D-curl.verbose-1-option.patch b/SOURCES/0016-curl-Fix-D-curl.verbose-1-option.patch
new file mode 100644
index 0000000..51e0233
--- /dev/null
+++ b/SOURCES/0016-curl-Fix-D-curl.verbose-1-option.patch
@@ -0,0 +1,182 @@
+From f421e599d3507f22d3d06b2dab070811e7e4f41c Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Sat, 28 Mar 2020 18:22:42 +0000
+Subject: [PATCH 16/19] curl: Fix -D curl.verbose=1 option.
+
+It didn't work previously for various reasons:
+
+ - Passed int instead of long to curl_easy_setopt.
+
+ - No CURLOPT_DEBUGFUNCTION callback was supplied, so messages were
+   sent to stderr, which meant they were never logged for the majority
+   of use cases.
+
+This also removes extra debugging in the regular header callback.
+This is no longer needed as the now-working -D curl.verbose=1 option
+will log the headers.
+
+Fixes commit 2ba11ee8f154ad1c84e10b43479b265fca2e996b.
+
+(cherry picked from commit 6791c69bddf76577b65fa3ddfde652c0594ce340)
+---
+ plugins/curl/Makefile.am |  2 ++
+ plugins/curl/curl.c      | 73 ++++++++++++++++++++++++++++++----------
+ tests/test-curl.c        |  3 +-
+ 3 files changed, 60 insertions(+), 18 deletions(-)
+
+diff --git a/plugins/curl/Makefile.am b/plugins/curl/Makefile.am
+index 6595eb95..024ddb6d 100644
+--- a/plugins/curl/Makefile.am
++++ b/plugins/curl/Makefile.am
+@@ -44,6 +44,7 @@ nbdkit_curl_plugin_la_SOURCES = \
+ 
+ nbdkit_curl_plugin_la_CPPFLAGS = \
+ 	-I$(top_srcdir)/include \
++	-I$(top_srcdir)/common/utils \
+ 	$(NULL)
+ nbdkit_curl_plugin_la_CFLAGS = \
+ 	$(WARNINGS_CFLAGS) \
+@@ -51,6 +52,7 @@ nbdkit_curl_plugin_la_CFLAGS = \
+ 	$(NULL)
+ nbdkit_curl_plugin_la_LIBADD = \
+ 	$(CURL_LIBS) \
++	$(top_builddir)/common/utils/libutils.la \
+ 	$(NULL)
+ nbdkit_curl_plugin_la_LDFLAGS = \
+ 	-module -avoid-version -shared \
+diff --git a/plugins/curl/curl.c b/plugins/curl/curl.c
+index 8b341ae0..b1693dc0 100644
+--- a/plugins/curl/curl.c
++++ b/plugins/curl/curl.c
+@@ -56,6 +56,8 @@
+ 
+ #include <nbdkit-plugin.h>
+ 
++#include "cleanup.h"
++
+ static const char *url = NULL;
+ static const char *user = NULL;
+ static char *password = NULL;
+@@ -283,6 +285,8 @@ struct curl_handle {
+                   curl_easy_strerror ((r)), (h)->errbuf);       \
+   } while (0)
+ 
++static int debug_cb (CURL *handle, curl_infotype type,
++                     const char *data, size_t size, void *);
+ static size_t header_cb (void *ptr, size_t size, size_t nmemb, void *opaque);
+ static size_t write_cb (char *ptr, size_t size, size_t nmemb, void *opaque);
+ static size_t read_cb (void *ptr, size_t size, size_t nmemb, void *opaque);
+@@ -311,11 +315,13 @@ curl_open (int readonly)
+     goto err;
+   }
+ 
+-  /* Note this writes the output to stderr directly.  We should
+-   * consider using CURLOPT_DEBUGFUNCTION so we can handle it with
+-   * nbdkit_debug.
+-   */
+-  curl_easy_setopt (h->c, CURLOPT_VERBOSE, curl_debug_verbose);
++  if (curl_debug_verbose) {
++    /* NB: Constants must be explicitly long because the parameter is
++     * varargs.
++     */
++    curl_easy_setopt (h->c, CURLOPT_VERBOSE, 1L);
++    curl_easy_setopt (h->c, CURLOPT_DEBUGFUNCTION, debug_cb);
++  }
+ 
+   curl_easy_setopt (h->c, CURLOPT_ERRORBUFFER, h->errbuf);
+ 
+@@ -441,12 +447,56 @@ curl_open (int readonly)
+   return NULL;
+ }
+ 
++/* When using CURLOPT_VERBOSE, this callback is used to redirect
++ * messages to nbdkit_debug (instead of stderr).
++ */
++static int
++debug_cb (CURL *handle, curl_infotype type,
++          const char *data, size_t size, void *opaque)
++{
++  size_t origsize = size;
++  CLEANUP_FREE char *str;
++
++  /* The data parameter passed is NOT \0-terminated, but also it may
++   * have \n or \r\n line endings.  The only sane way to deal with
++   * this is to copy the string.  (The data strings may also be
++   * multi-line, but we don't deal with that here).
++   */
++  str = malloc (size + 1);
++  if (str == NULL)
++    goto out;
++  memcpy (str, data, size);
++  str[size] = '\0';
++
++  while (size > 0 && (str[size-1] == '\n' || str[size-1] == '\r')) {
++    str[size-1] = '\0';
++    size--;
++  }
++
++  switch (type) {
++  case CURLINFO_TEXT:
++    nbdkit_debug ("%s", str);
++    break;
++  case CURLINFO_HEADER_IN:
++    nbdkit_debug ("S: %s", str);
++    break;
++  case CURLINFO_HEADER_OUT:
++    nbdkit_debug ("C: %s", str);
++    break;
++  default:
++    /* Assume everything else is binary data that we cannot print. */
++    nbdkit_debug ("<data with size=%zu>", origsize);
++  }
++
++ out:
++  return 0;
++}
++
+ static size_t
+ header_cb (void *ptr, size_t size, size_t nmemb, void *opaque)
+ {
+   struct curl_handle *h = opaque;
+   size_t realsize = size * nmemb;
+-  size_t len;
+   const char *accept_line = "Accept-Ranges: bytes";
+   const char *line = ptr;
+ 
+@@ -454,17 +504,6 @@ header_cb (void *ptr, size_t size, size_t nmemb, void *opaque)
+       strncmp (line, accept_line, strlen (accept_line)) == 0)
+     h->accept_range = true;
+ 
+-  /* Useful to print the server headers when debugging.  However we
+-   * must strip off trailing \r?\n from each line.
+-   */
+-  len = realsize;
+-  if (len > 0 && line[len-1] == '\n')
+-    len--;
+-  if (len > 0 && line[len-1] == '\r')
+-    len--;
+-  if (len > 0)
+-    nbdkit_debug ("S: %.*s", (int) len, line);
+-
+   return realsize;
+ }
+ 
+diff --git a/tests/test-curl.c b/tests/test-curl.c
+index 2b7e3beb..165edb35 100644
+--- a/tests/test-curl.c
++++ b/tests/test-curl.c
+@@ -74,9 +74,10 @@ main (int argc, char *argv[])
+     exit (EXIT_FAILURE);
+   }
+   if (test_start_nbdkit ("curl",
++                         "-D", "curl.verbose=1",
++                         "http://localhost/disk",
+                          "cookie=foo=bar; baz=1;",
+                          usp_param, /* unix-socket-path=... */
+-                         "http://localhost/disk",
+                          NULL) == -1)
+     exit (EXIT_FAILURE);
+ 
+-- 
+2.18.2
+
diff --git a/SOURCES/0017-curl-Case-insensitive-check-for-accept-ranges-RHBZ-1.patch b/SOURCES/0017-curl-Case-insensitive-check-for-accept-ranges-RHBZ-1.patch
new file mode 100644
index 0000000..0e83b5d
--- /dev/null
+++ b/SOURCES/0017-curl-Case-insensitive-check-for-accept-ranges-RHBZ-1.patch
@@ -0,0 +1,116 @@
+From aa62596afcc9143aa663bf834d305441cdd4cc70 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Tue, 19 May 2020 11:15:07 +0100
+Subject: [PATCH 17/19] curl: Case insensitive check for accept-ranges
+ (RHBZ#1837337).
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When accessing an HTTP/2 server we read lowercase headers so the
+existing test for byte range support did not work.  You would see an
+error like this:
+
+  nbdkit: curl[1]: error: server does not support 'range' (byte range) requests
+
+This commit copies the bug fix which was recently added to qemu’s
+block/curl.c.
+
+qemu commits:
+
+  commit 69032253c33ae1774233c63cedf36d32242a85fc
+  Author: David Edmondson <david.edmondson@oracle.com>
+  Date:   Mon Feb 24 10:13:10 2020 +0000
+
+    block/curl: HTTP header field names are case insensitive
+
+  commit 7788a319399f17476ff1dd43164c869e320820a2
+  Author: David Edmondson <david.edmondson@oracle.com>
+  Date:   Mon Feb 24 10:13:09 2020 +0000
+
+    block/curl: HTTP header fields allow whitespace around values
+
+Thanks: David Edmondson, Pino Toscano, Zi Liu
+(cherry picked from commit c1260ec1f6538831e10f164567b53054a2ec0c2a)
+---
+ plugins/curl/Makefile.am |  1 +
+ plugins/curl/curl.c      | 29 ++++++++++++++++++++++++-----
+ tests/web-server.c       |  2 +-
+ 3 files changed, 26 insertions(+), 6 deletions(-)
+
+diff --git a/plugins/curl/Makefile.am b/plugins/curl/Makefile.am
+index 024ddb6d..3dbe3ca8 100644
+--- a/plugins/curl/Makefile.am
++++ b/plugins/curl/Makefile.am
+@@ -44,6 +44,7 @@ nbdkit_curl_plugin_la_SOURCES = \
+ 
+ nbdkit_curl_plugin_la_CPPFLAGS = \
+ 	-I$(top_srcdir)/include \
++	-I$(top_srcdir)/common/include \
+ 	-I$(top_srcdir)/common/utils \
+ 	$(NULL)
+ nbdkit_curl_plugin_la_CFLAGS = \
+diff --git a/plugins/curl/curl.c b/plugins/curl/curl.c
+index b1693dc0..ac30cbdd 100644
+--- a/plugins/curl/curl.c
++++ b/plugins/curl/curl.c
+@@ -57,6 +57,7 @@
+ #include <nbdkit-plugin.h>
+ 
+ #include "cleanup.h"
++#include "ascii-ctype.h"
+ 
+ static const char *url = NULL;
+ static const char *user = NULL;
+@@ -497,12 +498,30 @@ header_cb (void *ptr, size_t size, size_t nmemb, void *opaque)
+ {
+   struct curl_handle *h = opaque;
+   size_t realsize = size * nmemb;
+-  const char *accept_line = "Accept-Ranges: bytes";
+-  const char *line = ptr;
++  const char *header = ptr;
++  const char *end = header + realsize;
++  const char *accept_ranges = "accept-ranges:";
++  const char *bytes = "bytes";
+ 
+-  if (realsize >= strlen (accept_line) &&
+-      strncmp (line, accept_line, strlen (accept_line)) == 0)
+-    h->accept_range = true;
++  if (realsize >= strlen (accept_ranges) &&
++      strncasecmp (header, accept_ranges, strlen (accept_ranges)) == 0) {
++    const char *p = strchr (header, ':') + 1;
++
++    /* Skip whitespace between the header name and value. */
++    while (p < end && *p && ascii_isspace (*p))
++      p++;
++
++    if (end - p >= strlen (bytes)
++        && strncmp (p, bytes, strlen (bytes)) == 0) {
++      /* Check that there is nothing but whitespace after the value. */
++      p += strlen (bytes);
++      while (p < end && *p && ascii_isspace (*p))
++        p++;
++
++      if (p == end || !*p)
++        h->accept_range = true;
++    }
++  }
+ 
+   return realsize;
+ }
+diff --git a/tests/web-server.c b/tests/web-server.c
+index f27ee70d..f9f10917 100644
+--- a/tests/web-server.c
++++ b/tests/web-server.c
+@@ -235,7 +235,7 @@ handle_request (int s, bool headers_only)
+   const char response1_ok[] = "HTTP/1.1 200 OK\r\n";
+   const char response1_partial[] = "HTTP/1.1 206 Partial Content\r\n";
+   const char response2[] =
+-    "Accept-Ranges: bytes\r\n"
++    "Accept-rANGES:     bytes\r\n" /* See RHBZ#1837337 */
+     "Connection: keep-alive\r\n"
+     "Content-Type: application/octet-stream\r\n";
+   char response3[64];
+-- 
+2.18.2
+
diff --git a/SOURCES/0018-sh-Don-t-need-to-cast-parameter-of-ascii_is-to-unsig.patch b/SOURCES/0018-sh-Don-t-need-to-cast-parameter-of-ascii_is-to-unsig.patch
new file mode 100644
index 0000000..5bbed35
--- /dev/null
+++ b/SOURCES/0018-sh-Don-t-need-to-cast-parameter-of-ascii_is-to-unsig.patch
@@ -0,0 +1,41 @@
+From d5947881c2918196d61d7795adba0abb881a86b9 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones@redhat.com>
+Date: Tue, 19 May 2020 15:29:55 +0100
+Subject: [PATCH 18/19] sh: Don't need to cast parameter of ascii_is* to
+ (unsigned char).
+
+Our replacements for these functions are not undefined for negative
+values.
+
+Thanks: Eric Blake
+Fixes: commit 9f34db74786fdc92b290a7d47e4b003bd84fec69.
+(cherry picked from commit 06a79b8bb8cfd97a272223c967601d8858acb817)
+---
+ plugins/sh/call.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/plugins/sh/call.c b/plugins/sh/call.c
+index ae0cc0ac..ba9f055f 100644
+--- a/plugins/sh/call.c
++++ b/plugins/sh/call.c
+@@ -392,7 +392,7 @@ handle_script_error (const char *argv0, char *ebuf, size_t len)
+   }
+ 
+   if (skip && ebuf[skip]) {
+-    if (!ascii_isspace ((unsigned char) ebuf[skip])) {
++    if (!ascii_isspace (ebuf[skip])) {
+       /* Treat 'EINVALID' as EIO, not EINVAL */
+       err = EIO;
+       skip = 0;
+@@ -400,7 +400,7 @@ handle_script_error (const char *argv0, char *ebuf, size_t len)
+     else
+       do
+         skip++;
+-      while (ascii_isspace ((unsigned char) ebuf[skip]));
++      while (ascii_isspace (ebuf[skip]));
+   }
+ 
+   while (len > 0 && ebuf[len-1] == '\n')
+-- 
+2.18.2
+
diff --git a/SOURCES/0019-common-include-Add-locale-safe-ascii_strcasecmp-and-.patch b/SOURCES/0019-common-include-Add-locale-safe-ascii_strcasecmp-and-.patch
new file mode 100644
index 0000000..5437c9e
--- /dev/null
+++ b/SOURCES/0019-common-include-Add-locale-safe-ascii_strcasecmp-and-.patch
@@ -0,0 +1,559 @@
+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
+
diff --git a/SPECS/nbdkit.spec b/SPECS/nbdkit.spec
index 69154f9..416c628 100644
--- a/SPECS/nbdkit.spec
+++ b/SPECS/nbdkit.spec
@@ -27,7 +27,7 @@
 
 Name:           nbdkit
 Version:        1.16.2
-Release:        2%{?dist}
+Release:        4%{?dist}
 Summary:        NBD server
 
 License:        BSD
@@ -56,6 +56,13 @@ Patch0009:     0009-python-Implement-can_fua-and-can_cache.patch
 Patch0010:     0010-tests-Test-the-Python-plugin-thoroughly.patch
 Patch0011:     0011-New-filter-extentlist.patch
 Patch0012:     0012-extentlist-Documentation-and-test-fixes.patch
+Patch0013:     0013-vddk-Update-for-VDDK-7.0-RHBZ-1831969.patch
+Patch0014:     0014-common-include-Add-ASCII-only-ctype-header-and-ascii.patch
+Patch0015:     0015-curl-Remove-some-useless-debug-messages.patch
+Patch0016:     0016-curl-Fix-D-curl.verbose-1-option.patch
+Patch0017:     0017-curl-Case-insensitive-check-for-accept-ranges-RHBZ-1.patch
+Patch0018:     0018-sh-Don-t-need-to-cast-parameter-of-ascii_is-to-unsig.patch
+Patch0019:     0019-common-include-Add-locale-safe-ascii_strcasecmp-and-.patch
 
 %if 0%{patches_touch_autotools}
 BuildRequires: autoconf, automake, libtool
@@ -682,6 +689,10 @@ make %{?_smp_mflags} check || {
 
 
 %changelog
+* Thu Jun 04 2020 Danilo C. L. de Paula <ddepaula@redhat.com> - 1.16.2
+- Resolves: bz#1810193
+  (Upgrade components in virt:rhel module:stream for RHEL-8.3 release)
+
 * Mon Apr 27 2020 Danilo C. L. de Paula <ddepaula@redhat.com> - 1.16.2
 - Resolves: bz#1810193
   (Upgrade components in virt:rhel module:stream for RHEL-8.3 release)