[Libguestfs] [PATCH 8/9] filters: Add nbdkit-offset-filter.

Richard W.M. Jones
Wed, 17 Jan 2018 20:53:55 -0000

This very basic filter allows you to select an offset and range within
a plugin, for example:

 nbdkit --filter=offset file file=foo offset=1M range=100M

which serves the byte range [ 1M .. 101M-1 ] from file ‘foo’.
---
 TODO                                    |   2 -
 configure.ac                            |   1 +
 filters/Makefile.am                     |   3 +-
 filters/offset/Makefile.am              |  62 ++++++++++++++
 filters/offset/nbdkit-offset-filter.pod |  99 +++++++++++++++++++++
 filters/offset/offset.c                 | 147 ++++++++++++++++++++++++++++++++
 6 files changed, 311 insertions(+), 3 deletions(-)

diff --git a/TODO b/TODO
index 0955db7..8eda0d7 100644
--- a/TODO
+++ b/TODO
@@ -44,8 +44,6 @@ Suggestions for filters

 * copy-on-write, a popular feature in other servers

-* export a subset using offset/size
-
 * export a single partition (like qemu-nbd -P)

 Composing nbdkit
diff --git a/configure.ac b/configure.ac
index 7032614..4892dc4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -513,6 +513,7 @@ AC_CONFIG_FILES([Makefile
                  plugins/vddk/Makefile
                  plugins/xz/Makefile
                  filters/Makefile
+                 filters/offset/Makefile
                  src/Makefile
                  src/nbdkit.pc
                  tests/Makefile])
diff --git a/filters/Makefile.am b/filters/Makefile.am
index ed1580b..91fbe6c 100644
--- a/filters/Makefile.am
+++ b/filters/Makefile.am
@@ -30,4 +30,5 @@
 # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.

-#SUBDIRS +SUBDIRS = \
+	offset
diff --git a/filters/offset/Makefile.am b/filters/offset/Makefile.am
new file mode 100644
index 0000000..f6e253c
--- /dev/null
+++ b/filters/offset/Makefile.am
@@ -0,0 +1,62 @@
+# nbdkit
+# Copyright (C) 2018 Red Hat Inc.
+# All rights reserved.
+#
+# 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.
+
+EXTRA_DIST = nbdkit-offset-filter.pod
+
+CLEANFILES = *~
+
+filterdir = $(libdir)/nbdkit/filters
+
+filter_LTLIBRARIES = nbdkit-offset-filter.la
+
+nbdkit_offset_filter_la_SOURCES = \
+	offset.c \
+	$(top_srcdir)/include/nbdkit-filter.h
+
+nbdkit_offset_filter_la_CPPFLAGS = \
+	-I$(top_srcdir)/include
+nbdkit_offset_filter_la_CFLAGS = \
+	$(WARNINGS_CFLAGS)
+nbdkit_offset_filter_la_LDFLAGS = \
+	-module -avoid-version -shared
+
+if HAVE_POD2MAN
+
+man_MANS = nbdkit-offset-filter.1
+CLEANFILES += $(man_MANS)
+
+nbdkit-offset-filter.1: nbdkit-offset-filter.pod
+	$(POD2MAN) $(POD2MAN_ARGS) --section=1 --name=`basename $@ .1` $< $@.t
&& \
+	if grep 'POD ERROR' $@.t; then rm $@.t; exit 1; fi && \
+	mv $@.t $@
+
+endif
diff --git a/filters/offset/nbdkit-offset-filter.pod
b/filters/offset/nbdkit-offset-filter.pod
new file mode 100644
index 0000000..c7f7bdf
--- /dev/null
+++ b/filters/offset/nbdkit-offset-filter.pod
@@ -0,0 +1,99 @@
+=encoding utf8
+
+=head1 NAME
+
+nbdkit-offset-filter - nbdkit offset filter
+
+=head1 SYNOPSIS
+
+ nbdkit --filter=offset plugin offset=OFFSET range=LENGTH [plugin-args...]
+
+=head1 DESCRIPTION
+
+C<nbdkit-offset-filter> is a filter that limits requests to the byte
+range C<[offset .. range-1]> within another plugin.
+
+=head1 PARAMETERS
+
+=over 4
+
+=item B<offset=OFFSET>
+
+The start offset.
+
+This parameter is required.
+
+=item B<range=LENGTH>
+
+The length of data to serve.
+
+This is optional.  If not given then the range is served starting from
+the offset through to the end of the underlying file/device.
+
+=back
+
+Note it is an error if the range parameter is supplied and
+C<offset+range> is larger than the size of data served by the
+underlying plugin.
+
+=head1 EXAMPLE
+
+Using L<nbdkit-file-plugin(1)>, serve the C<100M> length range
+starting from C<1M> through to S<C<101M - 1 byte>> from the
file
+C<disk.img>:
+
+ nbdkit --filter=offset file file=disk.img offset=1M range=100M
+
+=head1 SEE ALSO
+
+L<nbdkit(1)>,
+L<nbdkit-file-plugin(1)>,
+L<nbdkit-filter(3)>.
+
+=head1 AUTHORS
+
+Richard W.M. Jones
+
+=head1 COPYRIGHT
+
+Copyright (C) 2018 Red Hat Inc.
+
+=head1 LICENSE
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+=over 4
+
+=item *
+
+Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+=item *
+
+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.
+
+=item *
+
+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.
+
+=back
+
+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.
diff --git a/filters/offset/offset.c b/filters/offset/offset.c
new file mode 100644
index 0000000..cd0c89b
--- /dev/null
+++ b/filters/offset/offset.c
@@ -0,0 +1,147 @@
+/* nbdkit
+ * Copyright (C) 2018 Red Hat Inc.
+ * All rights reserved.
+ *
+ * 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 <stdint.h>
+#include <string.h>
+
+#include <nbdkit-filter.h>
+
+static int64_t offset = -1, range = -1;
+
+/* Called for each key=value passed on the command line. */
+static int
+offset_config (nbdkit_next_config *next, void *nxdata,
+               const char *key, const char *value)
+{
+  if (strcmp (key, "offset") == 0) {
+    offset = nbdkit_parse_size (value);
+    if (offset == -1)
+      return -1;
+    return 0;
+  }
+  else if (strcmp (key, "range") == 0) {
+    range = nbdkit_parse_size (value);
+    if (range == -1)
+      return -1;
+    return 0;
+  }
+  else
+    return next (nxdata, key, value);
+}
+
+/* Check the user did pass both parameters. */
+static int
+offset_config_complete (nbdkit_next_config_complete *next, void *nxdata)
+{
+  if (offset == -1) {
+    nbdkit_error ("you must supply the offset parameter on the command
line");
+    return -1;
+  }
+
+  return next (nxdata);
+}
+
+#define offset_config_help \
+  "offset=<OFFSET>     (required) The start offset to serve.\n"
\
+  "range=<LENGTH>                 The total size to serve."
+
+/* Get the file size. */
+static int64_t
+offset_get_size (struct nbdkit_next *next, void *nxdata,
+                 void *handle)
+{
+  int64_t real_size = next->get_size (nxdata);
+
+  if (range >= 0) {
+    if (offset + range > real_size) {
+      nbdkit_error ("offset + range is larger than the real size of the
underlying file or device");
+      return -1;
+    }
+    return range;
+  }
+  else
+    return real_size - offset;
+}
+
+/* Read data. */
+static int
+offset_pread (struct nbdkit_next *next, void *nxdata,
+              void *handle, void *buf, uint32_t count, uint64_t offs)
+{
+  return next->pread (nxdata, buf, count, offs + offset);
+}
+
+/* Write data. */
+static int
+offset_pwrite (struct nbdkit_next *next, void *nxdata,
+               void *handle,
+               const void *buf, uint32_t count, uint64_t offs)
+{
+  return next->pwrite (nxdata, buf, count, offs + offset);
+}
+
+/* Trim data. */
+static int
+offset_trim (struct nbdkit_next *next, void *nxdata,
+             void *handle, uint32_t count, uint64_t offs)
+{
+  return next->trim (nxdata, count, offs + offset);
+}
+
+/* Zero data. */
+static int
+offset_zero (struct nbdkit_next *next, void *nxdata,
+             void *handle, uint32_t count, uint64_t offs, int may_trim)
+{
+  return next->zero (nxdata, count, offs + offset, may_trim);
+}
+
+static struct nbdkit_filter filter = {
+  .name              = "offset",
+  .longname          = "nbdkit offset filter",
+  .version           = PACKAGE_VERSION,
+  .config            = offset_config,
+  .config_complete   = offset_config_complete,
+  .config_help       = offset_config_help,
+  .get_size          = offset_get_size,
+  .pread             = offset_pread,
+  .pwrite            = offset_pwrite,
+  .trim              = offset_trim,
+  .zero              = offset_zero,
+};
+
+NBDKIT_REGISTER_FILTER(filter)
--
2.15.1