This can be used to filter a single partition from a disk image.
---
TODO | 2 -
configure.ac | 1 +
filters/Makefile.am | 3 +-
filters/delay/delay.c | 12 +--
filters/offset/nbdkit-offset-filter.pod | 17 ++-
filters/offset/offset.c | 20 ++--
filters/partition/Makefile.am | 62 +++++++++++
filters/partition/nbdkit-partition-filter.pod | 94 +++++++++++++++++
filters/partition/partition.c | 145 ++++++++++++++++++++++++++
9 files changed, 336 insertions(+), 20 deletions(-)
diff --git a/TODO b/TODO
index 3ec45fd..b1f922e 100644
--- a/TODO
+++ b/TODO
@@ -41,8 +41,6 @@ Suggestions for filters
* copy-on-write, a popular feature in other servers
-* export a single partition (like qemu-nbd -P)
-
Composing nbdkit
----------------
diff --git a/configure.ac b/configure.ac
index 9376a2e..fd71ca6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -515,6 +515,7 @@ AC_CONFIG_FILES([Makefile
filters/Makefile
filters/delay/Makefile
filters/offset/Makefile
+ filters/partition/Makefile
src/Makefile
src/nbdkit.pc
tests/Makefile])
diff --git a/filters/Makefile.am b/filters/Makefile.am
index d4aa6c0..d918b81 100644
--- a/filters/Makefile.am
+++ b/filters/Makefile.am
@@ -32,4 +32,5 @@
SUBDIRS = \
delay \
- offset
+ offset \
+ partition
diff --git a/filters/delay/delay.c b/filters/delay/delay.c
index c8d9ef2..66b7e56 100644
--- a/filters/delay/delay.c
+++ b/filters/delay/delay.c
@@ -121,30 +121,30 @@ delay_config (nbdkit_next_config *next, void *nxdata,
/* Read data. */
static int
-delay_pread (struct nbdkit_next *next, void *nxdata,
+delay_pread (struct nbdkit_next_ops *next_ops, void *nxdata,
void *handle, void *buf, uint32_t count, uint64_t offset)
{
read_delay ();
- return next->pread (nxdata, buf, count, offset);
+ return next_ops->pread (nxdata, buf, count, offset);
}
/* Write data. */
static int
-delay_pwrite (struct nbdkit_next *next, void *nxdata,
+delay_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata,
void *handle,
const void *buf, uint32_t count, uint64_t offset)
{
write_delay ();
- return next->pwrite (nxdata, buf, count, offset);
+ return next_ops->pwrite (nxdata, buf, count, offset);
}
/* Zero data. */
static int
-delay_zero (struct nbdkit_next *next, void *nxdata,
+delay_zero (struct nbdkit_next_ops *next_ops, void *nxdata,
void *handle, uint32_t count, uint64_t offset, int may_trim)
{
write_delay ();
- return next->zero (nxdata, count, offset, may_trim);
+ return next_ops->zero (nxdata, count, offset, may_trim);
}
static struct nbdkit_filter filter = {
diff --git a/filters/offset/nbdkit-offset-filter.pod
b/filters/offset/nbdkit-offset-filter.pod
index 131a321..a95c2a6 100644
--- a/filters/offset/nbdkit-offset-filter.pod
+++ b/filters/offset/nbdkit-offset-filter.pod
@@ -36,7 +36,7 @@ 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
+=head1 EXAMPLES
Using L<nbdkit-file-plugin(1)>, serve the file C<disk.img> starting at
offset C<1M>. The total length served is C<100M> (the underlying file
@@ -44,11 +44,26 @@ must therefore be at least C<101M> in length):
nbdkit --filter=offset file file=disk.img offset=1M range=100M
+One way to serve a single partition from a disk is to find the start
+and length of the partition, eg using:
+
+ $ parted disk.img -- unit b print
+ ...
+ Number Start End Size Type File system Flags
+ 1 65536B 104792575B 104727040B primary ext2
+
+You can then serve the partition only using:
+
+ nbdkit --filter=offset file file=disk.img offset=65536 range=104727040
+
+An easier way to do this is with L<nbdkit-partition-filter(1)>.
+
=head1 SEE ALSO
L<nbdkit(1)>,
L<nbdkit-file-plugin(1)>,
L<nbdkit-filter(3)>.
+L<nbdkit-partition-filter(1)>.
=head1 AUTHORS
diff --git a/filters/offset/offset.c b/filters/offset/offset.c
index cd0c89b..892d5ec 100644
--- a/filters/offset/offset.c
+++ b/filters/offset/offset.c
@@ -81,10 +81,10 @@ offset_config_complete (nbdkit_next_config_complete *next, void
*nxdata)
/* Get the file size. */
static int64_t
-offset_get_size (struct nbdkit_next *next, void *nxdata,
+offset_get_size (struct nbdkit_next_ops *next_ops, void *nxdata,
void *handle)
{
- int64_t real_size = next->get_size (nxdata);
+ int64_t real_size = next_ops->get_size (nxdata);
if (range >= 0) {
if (offset + range > real_size) {
@@ -99,35 +99,35 @@ offset_get_size (struct nbdkit_next *next, void *nxdata,
/* Read data. */
static int
-offset_pread (struct nbdkit_next *next, void *nxdata,
+offset_pread (struct nbdkit_next_ops *next_ops, void *nxdata,
void *handle, void *buf, uint32_t count, uint64_t offs)
{
- return next->pread (nxdata, buf, count, offs + offset);
+ return next_ops->pread (nxdata, buf, count, offs + offset);
}
/* Write data. */
static int
-offset_pwrite (struct nbdkit_next *next, void *nxdata,
+offset_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata,
void *handle,
const void *buf, uint32_t count, uint64_t offs)
{
- return next->pwrite (nxdata, buf, count, offs + offset);
+ return next_ops->pwrite (nxdata, buf, count, offs + offset);
}
/* Trim data. */
static int
-offset_trim (struct nbdkit_next *next, void *nxdata,
+offset_trim (struct nbdkit_next_ops *next_ops, void *nxdata,
void *handle, uint32_t count, uint64_t offs)
{
- return next->trim (nxdata, count, offs + offset);
+ return next_ops->trim (nxdata, count, offs + offset);
}
/* Zero data. */
static int
-offset_zero (struct nbdkit_next *next, void *nxdata,
+offset_zero (struct nbdkit_next_ops *next_ops, void *nxdata,
void *handle, uint32_t count, uint64_t offs, int may_trim)
{
- return next->zero (nxdata, count, offs + offset, may_trim);
+ return next_ops->zero (nxdata, count, offs + offset, may_trim);
}
static struct nbdkit_filter filter = {
diff --git a/filters/partition/Makefile.am b/filters/partition/Makefile.am
new file mode 100644
index 0000000..0464e7c
--- /dev/null
+++ b/filters/partition/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-partition-filter.pod
+
+CLEANFILES = *~
+
+filterdir = $(libdir)/nbdkit/filters
+
+filter_LTLIBRARIES = nbdkit-partition-filter.la
+
+nbdkit_partition_filter_la_SOURCES = \
+ partition.c \
+ $(top_srcdir)/include/nbdkit-filter.h
+
+nbdkit_partition_filter_la_CPPFLAGS = \
+ -I$(top_srcdir)/include
+nbdkit_partition_filter_la_CFLAGS = \
+ $(WARNINGS_CFLAGS)
+nbdkit_partition_filter_la_LDFLAGS = \
+ -module -avoid-version -shared
+
+if HAVE_POD2MAN
+
+man_MANS = nbdkit-partition-filter.1
+CLEANFILES += $(man_MANS)
+
+nbdkit-partition-filter.1: nbdkit-partition-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/partition/nbdkit-partition-filter.pod
b/filters/partition/nbdkit-partition-filter.pod
new file mode 100644
index 0000000..133e73d
--- /dev/null
+++ b/filters/partition/nbdkit-partition-filter.pod
@@ -0,0 +1,94 @@
+=encoding utf8
+
+=head1 NAME
+
+nbdkit-partition-filter - nbdkit partition filter
+
+=head1 SYNOPSIS
+
+ nbdkit --filter=partition plugin partition=PART [plugin-args...]
+
+=head1 DESCRIPTION
+
+C<nbdkit-partition-filter> is a filter that limits requests to a
+single partition within a disk image that is served by another plugin.
+
+Partition numbers are specified by the required C<partition>
+parameter, and count from 1.
+
+This works like the C<qemu-nbd -P> option.
+
+=head1 PARAMETERS
+
+=over 4
+
+=item B<partition=PART>
+
+The partition number to serve, counting from 1.
+
+This parameter is required.
+
+=back
+
+=head1 EXAMPLE
+
+F<disk.img> is a partitioned disk image (eg. a virtual machine disk
+image). To serve the first partition only use:
+
+ nbdkit --filter=partition file file=disk.img partition=1
+
+=head1 SEE ALSO
+
+L<nbdkit(1)>,
+L<nbdkit-file-plugin(1)>,
+L<nbdkit-filter(3)>.
+L<nbdkit-offset-filter(1)>,
+L<parted(8)>.
+
+=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/partition/partition.c b/filters/partition/partition.c
new file mode 100644
index 0000000..2e18173
--- /dev/null
+++ b/filters/partition/partition.c
@@ -0,0 +1,145 @@
+/* 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 int partnum = -1;
+
+/* Called for each key=value passed on the command line. */
+static int
+partition_config (nbdkit_next_config *next, void *nxdata,
+ const char *key, const char *value)
+{
+ if (strcmp (key, "partition") == 0) {
+ if (sscanf (value, "%d", &partnum) != 1 || partnum <= 0) {
+ nbdkit_error ("invalid partition number");
+ return -1;
+ }
+ return 0;
+ }
+ else
+ return next (nxdata, key, value);
+}
+
+/* Check the user did pass partition number. */
+static int
+partition_config_complete (nbdkit_next_config_complete *next, void *nxdata)
+{
+ if (partnum == -1) {
+ nbdkit_error ("you must supply the partition parameter on the command
line");
+ return -1;
+ }
+
+ return next (nxdata);
+}
+
+#define partition_config_help \
+ "partition=<PART> (required) The partition number (counting from
1)."
+
+#if 0
+/* Get the file size. */
+static int64_t
+offset_get_size (struct nbdkit_next_ops *next_ops, void *nxdata,
+ void *handle)
+{
+ int64_t real_size = next_ops->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_ops *next_ops, void *nxdata,
+ void *handle, void *buf, uint32_t count, uint64_t offs)
+{
+ return next_ops->pread (nxdata, buf, count, offs + offset);
+}
+
+/* Write data. */
+static int
+offset_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata,
+ void *handle,
+ const void *buf, uint32_t count, uint64_t offs)
+{
+ return next_ops->pwrite (nxdata, buf, count, offs + offset);
+}
+
+/* Trim data. */
+static int
+offset_trim (struct nbdkit_next_ops *next_ops, void *nxdata,
+ void *handle, uint32_t count, uint64_t offs)
+{
+ return next_ops->trim (nxdata, count, offs + offset);
+}
+
+/* Zero data. */
+static int
+offset_zero (struct nbdkit_next_ops *next_ops, void *nxdata,
+ void *handle, uint32_t count, uint64_t offs, int may_trim)
+{
+ return next_ops->zero (nxdata, count, offs + offset, may_trim);
+}
+#endif
+
+static struct nbdkit_filter filter = {
+ .name = "partition",
+ .longname = "nbdkit partition filter",
+ .version = PACKAGE_VERSION,
+ .config = partition_config,
+ .config_complete = partition_config_complete,
+ .config_help = partition_config_help,
+#if 0
+ .get_size = offset_get_size,
+ .pread = offset_pread,
+ .pwrite = offset_pwrite,
+ .trim = offset_trim,
+ .zero = offset_zero,
+#endif
+};
+
+NBDKIT_REGISTER_FILTER(filter)
--
2.15.1