[Libguestfs] [PATCH nbdkit 1/4] Add reflection plugin.

Richard W.M. Jones rjones at redhat.com
Sun Sep 15 14:55:42 UTC 2019


The source for the easter egg example is not included, but it is:

        org 0x7c00
        ;  clear screen
        mov ah,0
        mov al,3
        int 0x10
        ; print string
        mov ah,0x13
        mov bl,0xa
        mov al,1
        mov cx,len
        mov dh,0
        mov dl,0
        mov bp,hello
        int 0x10
        hlt
hello:  db "*** Hello from nbdkit! ***",0xd,0xa
len:    equ $-hello
        ; pad to end of sector
        times 510-($-$$) db 0
        ; boot signature
        db 0x55,0xaa
---
 configure.ac                                  |   2 +
 docs/nbdkit-plugin.pod                        |   2 +
 plugins/data/nbdkit-data-plugin.pod           |   1 +
 plugins/memory/nbdkit-memory-plugin.pod       |   3 +-
 plugins/reflection/Makefile.am                |  64 +++++
 .../reflection/nbdkit-reflection-plugin.pod   | 104 +++++++
 plugins/reflection/reflection.c               | 265 ++++++++++++++++++
 tests/Makefile.am                             |   8 +
 tests/test-reflection-base64.sh               |  98 +++++++
 tests/test-reflection-raw.sh                  |  68 +++++
 10 files changed, 614 insertions(+), 1 deletion(-)

diff --git a/configure.ac b/configure.ac
index 4af403c..8261a7f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -846,6 +846,7 @@ non_lang_plugins="\
         partitioning \
         pattern \
         random \
+        reflection \
         split \
         ssh \
         streaming \
@@ -922,6 +923,7 @@ AC_CONFIG_FILES([Makefile
                  plugins/perl/Makefile
                  plugins/python/Makefile
                  plugins/random/Makefile
+                 plugins/reflection/Makefile
                  plugins/ruby/Makefile
                  plugins/rust/Cargo.toml
                  plugins/rust/Makefile
diff --git a/docs/nbdkit-plugin.pod b/docs/nbdkit-plugin.pod
index e465410..39fa643 100644
--- a/docs/nbdkit-plugin.pod
+++ b/docs/nbdkit-plugin.pod
@@ -389,6 +389,8 @@ client data, be cautious when parsing it.>
 
 On error, C<nbdkit_error> is called and the call returns C<NULL>.
 
+See also L<nbdkit-reflection-plugin(1)>.
+
 =head1 CALLBACKS
 
 =head2 C<.name>
diff --git a/plugins/data/nbdkit-data-plugin.pod b/plugins/data/nbdkit-data-plugin.pod
index b0957ad..fd342b4 100644
--- a/plugins/data/nbdkit-data-plugin.pod
+++ b/plugins/data/nbdkit-data-plugin.pod
@@ -240,6 +240,7 @@ L<nbdkit-null-plugin(1)>,
 L<nbdkit-partitioning-plugin(1)>,
 L<nbdkit-pattern-plugin(1)>,
 L<nbdkit-random-plugin(1)>,
+L<nbdkit-reflection-plugin(1)>,
 L<nbdkit-zero-plugin(1)>,
 L<https://github.com/libguestfs/nbdkit/blob/master/plugins/data/disk2data.pl>,
 L<https://en.wikipedia.org/wiki/Base64>.
diff --git a/plugins/memory/nbdkit-memory-plugin.pod b/plugins/memory/nbdkit-memory-plugin.pod
index 76824d6..4503651 100644
--- a/plugins/memory/nbdkit-memory-plugin.pod
+++ b/plugins/memory/nbdkit-memory-plugin.pod
@@ -86,7 +86,8 @@ L<nbdkit(1)>,
 L<nbdkit-plugin(3)>,
 L<nbdkit-loop(1)>,
 L<nbdkit-data-plugin(1)>,
-L<nbdkit-file-plugin(1)>.
+L<nbdkit-file-plugin(1)>,
+L<nbdkit-reflection-plugin(1)>.
 
 =head1 AUTHORS
 
diff --git a/plugins/reflection/Makefile.am b/plugins/reflection/Makefile.am
new file mode 100644
index 0000000..40aa786
--- /dev/null
+++ b/plugins/reflection/Makefile.am
@@ -0,0 +1,64 @@
+# nbdkit
+# Copyright (C) 2017-2019 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 $(top_srcdir)/common-rules.mk
+
+EXTRA_DIST = nbdkit-reflection-plugin.pod
+
+plugin_LTLIBRARIES = nbdkit-reflection-plugin.la
+
+nbdkit_reflection_plugin_la_SOURCES = \
+	reflection.c \
+	$(top_srcdir)/include/nbdkit-plugin.h \
+	$(NULL)
+
+nbdkit_reflection_plugin_la_CPPFLAGS = \
+	-I$(top_srcdir)/include \
+	$(NULL)
+nbdkit_reflection_plugin_la_CFLAGS = $(WARNINGS_CFLAGS)
+nbdkit_reflection_plugin_la_LDFLAGS = \
+	-module -avoid-version -shared \
+	-Wl,--version-script=$(top_srcdir)/plugins/plugins.syms \
+	$(NULL)
+nbdkit_reflection_plugin_la_LIBADD = \
+	$(NULL)
+
+if HAVE_POD
+
+man_MANS = nbdkit-reflection-plugin.1
+CLEANFILES += $(man_MANS)
+
+nbdkit-reflection-plugin.1: nbdkit-reflection-plugin.pod
+	$(PODWRAPPER) --section=1 --man $@ \
+	    --html $(top_builddir)/html/$@.html \
+	    $<
+
+endif HAVE_POD
diff --git a/plugins/reflection/nbdkit-reflection-plugin.pod b/plugins/reflection/nbdkit-reflection-plugin.pod
new file mode 100644
index 0000000..1b260b6
--- /dev/null
+++ b/plugins/reflection/nbdkit-reflection-plugin.pod
@@ -0,0 +1,104 @@
+=head1 NAME
+
+nbdkit-reflection-plugin - reflect export name back to the client
+
+=head1 SYNOPSIS
+
+ nbdkit reflection [mode=]exportname|base64exportname
+
+=head1 DESCRIPTION
+
+C<nbdkit-reflection-plugin> is a test plugin which reflects
+information sent by the client back to the client.
+
+In its default mode (C<mode=exportname>) it converts the export name
+passed from the client into a disk image.  C<mode=base64exportname> is
+similar except the client must base64-encode the data in the export
+name, allowing arbitrary binary data to be sent (see L</EXAMPLES>
+below to make this clearer).
+
+The plugin only supports read-only access.  To make the disk writable,
+add L<nbdkit-cow-filter(1)> on top.
+
+=head1 EXAMPLES
+
+Create a reflection disk.  By setting the export name to C<"hello">
+when we open it, a virtual disk of only 5 bytes containing these
+characters is created.  We then display the contents:
+
+ $ nbdkit reflection mode=exportname
+ $ nbdsh -u 'nbd://localhost/hello' -c - <<'EOF'
+ size = h.get_size()
+ print("size = %d" % size)
+ buf = h.pread(size, 0)
+ print("buf = %r" % buf)
+ EOF
+
+ size = 5
+ buf = b"hello"
+
+By running a reflection plugin, you can pass whole bootable VMs on the
+qemu command line:
+
+ $ nbdkit reflection mode=base64exportname
+ $ qemu-system-x86_64 \
+   -drive 'snapshot=on,file.driver=nbd,file.host=localhost,file.port=10809,file.export=
+ tACwA80QtBOzCrABuRwAtgCyAL0ZfM0Q9CoqKiBIZWxsbyBmcm9tIG5iZGtp
+ dCEgKioqDQoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAVao=
+ '
+
+=head1 PARAMETERS
+
+=over 4
+
+=item [B<mode=>]B<base64exportname>
+
+Reflect the export name passed by the client, assuming the client
+string is base64 encoded.
+
+This mode is only supported if nbdkit was compiled with GnuTLS E<ge>
+3.6.0.  You can find out by checking if:
+
+ $ nbdkit reflection --dump-plugin
+
+contains:
+
+ reflection_base64=yes
+
+=item [B<mode=>]B<exportname>
+
+Reflect the raw export name passed by the client.  Note the export
+name cannot contain ASCII NUL characters.
+
+This is the default mode.
+
+C<mode=> is a magic config key and may be omitted in most cases.
+See L<nbdkit(1)/Magic parameters>.
+
+=back
+
+=head1 SEE ALSO
+
+L<nbdkit(1)>,
+L<nbdkit-plugin(3)>,
+L<nbdkit-cow-filter(1)>,
+L<nbdkit-data-plugin(1)>,
+L<nbdkit-memory-plugin(1)/Preloading small amounts of data>.
+
+=head1 AUTHORS
+
+Richard W.M. Jones
+
+=head1 COPYRIGHT
+
+Copyright (C) 2019 Red Hat Inc.
diff --git a/plugins/reflection/reflection.c b/plugins/reflection/reflection.c
new file mode 100644
index 0000000..74f7169
--- /dev/null
+++ b/plugins/reflection/reflection.c
@@ -0,0 +1,265 @@
+/* nbdkit
+ * Copyright (C) 2017-2019 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 <string.h>
+
+#if defined(HAVE_GNUTLS) && defined(HAVE_GNUTLS_BASE64_DECODE2)
+#include <gnutls/gnutls.h>
+#define HAVE_BASE64 1
+#endif
+
+#define NBDKIT_API_VERSION 2
+
+#include <nbdkit-plugin.h>
+
+/* The mode. */
+enum mode {
+  MODE_EXPORTNAME,
+  MODE_BASE64EXPORTNAME,
+};
+static enum mode mode = MODE_EXPORTNAME;
+
+static int
+reflection_config (const char *key, const char *value)
+{
+  if (strcmp (key, "mode") == 0) {
+    if (strcasecmp (value, "exportname") == 0) {
+      mode = MODE_EXPORTNAME;
+    }
+    else if (strcasecmp (value, "base64exportname") == 0) {
+#ifdef HAVE_BASE64
+      mode = MODE_BASE64EXPORTNAME;
+#else
+      nbdkit_error ("the plugin was compiled without base64 support");
+      return -1;
+#endif
+    }
+    else {
+      nbdkit_error ("unknown mode: '%s'", value);
+      return -1;
+    }
+  }
+  else {
+    nbdkit_error ("unknown parameter '%s'", key);
+    return -1;
+  }
+
+  return 0;
+}
+
+#define reflection_config_help \
+  "mode=MODE    Plugin mode."
+
+/* Provide a way to detect if the base64 feature is supported. */
+static void
+reflection_dump_plugin (void)
+{
+#ifdef HAVE_BASE64
+  printf ("reflection_base64=yes\n");
+#endif
+}
+
+/* Per-connection handle. */
+struct handle {
+  void *data;                   /* Block device data. */
+  size_t len;                   /* Length of data in bytes. */
+};
+
+static int
+decode_base64 (const char *data, size_t len, struct handle *ret)
+{
+#ifdef HAVE_BASE64
+  gnutls_datum_t in, out;
+  int err;
+
+  /* For unclear reasons gnutls_base64_decode2 won't handle an empty
+   * string, even though base64("") == "".
+   * https://tools.ietf.org/html/rfc4648#section-10
+   * https://gitlab.com/gnutls/gnutls/issues/834
+   * So we have to special-case it.
+   */
+  if (len == 0) {
+    ret->data = NULL;
+    ret->len = 0;
+    return 0;
+  }
+
+  in.data = (unsigned char *) data;
+  in.size = len;
+  err = gnutls_base64_decode2 (&in, &out);
+  if (err != GNUTLS_E_SUCCESS) {
+    nbdkit_error ("base64: %s", gnutls_strerror (err));
+    /* We don't have to free out.data.  I verified that it is freed on
+     * the error path of gnutls_base64_decode2.
+     */
+    return -1;
+  }
+
+  ret->data = out.data;         /* caller frees, eventually */
+  ret->len = out.size;
+  return 0;
+#else
+  nbdkit_error ("the plugin was compiled without base64 support");
+  return -1;
+#endif
+}
+
+/* Create the per-connection handle.
+ *
+ * This is a rather unusual plugin because it has to parse data sent
+ * by the client.  For security reasons, be careful about:
+ *
+ * - Returning more data than is sent by the client.
+ *
+ * - Inputs that result in unbounded output.
+ *
+ * - Inputs that could hang, crash or exploit the server.
+ */
+static void *
+reflection_open (int readonly)
+{
+  const char *export_name;
+  size_t export_name_len;
+  struct handle *h;
+
+  h = malloc (sizeof *h);
+  if (h == NULL) {
+    nbdkit_error ("malloc: %m");
+    return NULL;
+  }
+
+  switch (mode) {
+  case MODE_EXPORTNAME:
+  case MODE_BASE64EXPORTNAME:
+    export_name = nbdkit_export_name ();
+    if (export_name == NULL) {
+      free (h);
+      return NULL;
+    }
+    export_name_len = strlen (export_name);
+
+    if (mode == MODE_EXPORTNAME) {
+      h->len = export_name_len;
+      h->data = strdup (export_name);
+      if (h->data == NULL) {
+        nbdkit_error ("strdup: %m");
+        free (h);
+        return NULL;
+      }
+      return h;
+    }
+    else /* mode == MODE_BASE64EXPORTNAME */ {
+      if (decode_base64 (export_name, export_name_len, h) == -1) {
+        free (h);
+        return NULL;
+      }
+      return h;
+    }
+
+  default:
+    abort ();
+  }
+}
+
+/* Close the per-connection handle. */
+static void
+reflection_close (void *handle)
+{
+  struct handle *h = handle;
+
+  free (h->data);
+  free (h);
+}
+
+#define THREAD_MODEL NBDKIT_THREAD_MODEL_PARALLEL
+
+/* Get the disk size. */
+static int64_t
+reflection_get_size (void *handle)
+{
+  struct handle *h = handle;
+
+  return (int64_t) h->len;
+}
+
+/* Read-only plugin so multi-conn is safe. */
+static int
+reflection_can_multi_conn (void *handle)
+{
+  return 1;
+}
+
+/* Cache. */
+static int
+reflection_can_cache (void *handle)
+{
+  /* Everything is already in memory, returning this without
+   * implementing .cache lets nbdkit do the correct no-op.
+   */
+  return NBDKIT_CACHE_NATIVE;
+}
+
+/* Read data. */
+static int
+reflection_pread (void *handle, void *buf, uint32_t count, uint64_t offset,
+                  uint32_t flags)
+{
+  struct handle *h = handle;
+
+  memcpy (buf, h->data + offset, count);
+  return 0;
+}
+
+static struct nbdkit_plugin plugin = {
+  .name              = "reflection",
+  .version           = PACKAGE_VERSION,
+  .config            = reflection_config,
+  .config_help       = reflection_config_help,
+  .dump_plugin       = reflection_dump_plugin,
+  .magic_config_key  = "mode",
+  .open              = reflection_open,
+  .close             = reflection_close,
+  .get_size          = reflection_get_size,
+  .can_multi_conn    = reflection_can_multi_conn,
+  .can_cache         = reflection_can_cache,
+  .pread             = reflection_pread,
+  /* In this plugin, errno is preserved properly along error return
+   * paths from failed system calls.
+   */
+  .errno_is_preserved = 1,
+};
+
+NBDKIT_REGISTER_PLUGIN(plugin)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 9eec75e..69d5d5e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -111,6 +111,8 @@ EXTRA_DIST = \
 	test-rate-dynamic.sh \
 	test.rb \
 	test-readahead-copy.sh \
+	test-reflection-base64.sh \
+	test-reflection-raw.sh \
 	test-shutdown.sh \
 	test-ssh.sh \
 	test.tcl \
@@ -602,6 +604,12 @@ test_random_CPPFLAGS = -I $(top_srcdir)/common/include
 test_random_CFLAGS = $(WARNINGS_CFLAGS) $(LIBGUESTFS_CFLAGS)
 test_random_LDADD = libtest.la $(LIBGUESTFS_LIBS)
 
+# reflection plugin test.
+TESTS += \
+	test-reflection-base64.sh \
+	test-reflection-raw.sh \
+	$(NULL)
+
 # split files plugin test.
 check_DATA += split1 split2 split3
 CLEANFILES += split1 split2 split3
diff --git a/tests/test-reflection-base64.sh b/tests/test-reflection-base64.sh
new file mode 100755
index 0000000..cf21bf0
--- /dev/null
+++ b/tests/test-reflection-base64.sh
@@ -0,0 +1,98 @@
+#!/usr/bin/env bash
+# nbdkit
+# Copyright (C) 2018-2019 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.
+
+# Test the relection plugin with base64-encoded export name.
+
+source ./functions.sh
+set -e
+set -x
+
+requires nbdsh --version
+# XXX This needs to test $PYTHON somehow.
+#requires python -c 'import base64'
+
+# Test if mode=base64exportname is supported in this build.
+if ! nbdkit reflection --dump-plugin | grep -sq "reflection_base64=yes"; then
+    echo "$0: mode=base64exportname is not supported in this build"
+    exit 77
+fi
+
+sock=`mktemp -u`
+files="reflection-base64.out reflection-base64.pid $sock"
+rm -f $files
+cleanup_fn rm -f $files
+
+# Run nbdkit.
+start_nbdkit -P reflection-base64.pid -U $sock \
+       reflection mode=base64exportname
+
+export e sock
+for e in "" "test" "テスト" \
+         "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+do
+    nbdsh -c '
+import os
+import base64
+
+e = os.environ["e"]
+b = base64.b64encode(e.encode("utf-8")).decode("utf-8")
+print ("e = %r, b = %r" % (e,b))
+h.set_export_name (b)
+h.connect_unix (os.environ["sock"])
+
+size = h.get_size ()
+assert size == len (e.encode("utf-8"))
+
+# Zero-sized reads are not defined in the NBD protocol.
+if size > 0:
+   buf = h.pread (size, 0)
+   assert buf == e.encode("utf-8")
+'
+done
+
+# Test that it fails if the caller passes in non-base64 data.  The
+# server drops the connection in this case so it's not very graceful
+# but we should at least get an nbd.Error and not something else.
+nbdsh -c '
+import os
+import sys
+
+h.set_export_name ("xyz")
+try:
+    h.connect_unix (os.environ["sock"])
+    # This should not happen.
+    sys.exit (1)
+except nbd.Error as ex:
+    sys.exit (0)
+# This should not happen.
+sys.exit (1)
+'
diff --git a/tests/test-reflection-raw.sh b/tests/test-reflection-raw.sh
new file mode 100755
index 0000000..675e316
--- /dev/null
+++ b/tests/test-reflection-raw.sh
@@ -0,0 +1,68 @@
+#!/usr/bin/env bash
+# nbdkit
+# Copyright (C) 2018-2019 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.
+
+# Test the relection plugin with raw export name.
+
+source ./functions.sh
+set -e
+set -x
+
+requires nbdsh --version
+
+sock=`mktemp -u`
+files="reflection-raw.out reflection-raw.pid $sock"
+rm -f $files
+cleanup_fn rm -f $files
+
+# Run nbdkit.
+start_nbdkit -P reflection-raw.pid -U $sock reflection
+
+for e in "" "test" "テスト" \
+         "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+do
+    export e sock
+    nbdsh -c '
+import os
+
+e = os.environ["e"]
+h.set_export_name (e)
+h.connect_unix (os.environ["sock"])
+
+size = h.get_size ()
+assert size == len (e.encode("utf-8"))
+
+# Zero-sized reads are not defined in the NBD protocol.
+if size > 0:
+   buf = h.pread (size, 0)
+   assert buf == e.encode("utf-8")
+'
+done
-- 
2.23.0




More information about the Libguestfs mailing list