4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 #if defined (HAVE_GNUTLS) && defined (HAVE_GNUTLS_BASE64_DECODE2)
42 #include <gnutls/gnutls.h>
45 #define NBDKIT_API_VERSION 2
46 #include <nbdkit-plugin.h>
48 #include "allocator.h"
55 /* Data (raw|base64|data) parameter. */
56 static enum { NOT_SEEN
, RAW
, BASE64
, DATA
} data_seen
= NOT_SEEN
;
57 static const char *data_param
;
59 /* size= parameter on the command line. After configuration, it is
60 * set to the final size.
62 static int64_t size
= -1;
65 static struct allocator
*a
;
66 const char *allocator_type
= "sparse";
68 /* Debug directory operations (-D data.dir=1). */
69 NBDKIT_DLL_PUBLIC
int data_debug_dir
;
71 /* Collect extra parameters for data $VARs. */
72 struct param
{ const char *key
; const char *value
; };
73 DEFINE_VECTOR_TYPE (param_list
, struct param
);
74 static param_list params
;
76 /* On unload, free the sparse array. */
84 /* Parse the base64 parameter. */
86 read_base64 (const char *value
, uint64_t *size_ret
)
88 #if defined (HAVE_GNUTLS) && defined (HAVE_GNUTLS_BASE64_DECODE2)
89 gnutls_datum_t in
, out
;
92 in
.data
= (unsigned char *) value
;
93 in
.size
= strlen (value
);
94 err
= gnutls_base64_decode2 (&in
, &out
);
95 if (err
!= GNUTLS_E_SUCCESS
) {
96 nbdkit_error ("base64: %s", gnutls_strerror (err
));
100 if (a
->f
->write (a
, out
.data
, out
.size
, 0) == -1)
103 *size_ret
= out
.size
;
106 nbdkit_error ("base64 is not supported in this build of the plugin");
112 data_config (const char *key
, const char *value
)
116 if (strcmp (key
, "size") == 0) {
117 r
= nbdkit_parse_size (value
);
122 else if (strcmp (key
, "allocator") == 0) {
123 allocator_type
= value
;
125 else if (strcmp (key
, "raw") == 0) {
126 if (data_seen
!= NOT_SEEN
) {
128 nbdkit_error ("raw|base64|data parameter must be specified exactly once");
134 else if (strcmp (key
, "base64") == 0) {
135 if (data_seen
!= NOT_SEEN
) goto seen_error
;
139 else if (strcmp (key
, "data") == 0) {
140 if (data_seen
!= NOT_SEEN
) goto seen_error
;
145 if (param_list_append (¶ms
,
146 (struct param
){ .key
= key
, .value
= value
})
148 nbdkit_error ("realloc: %m");
157 get_extra_param (const char *name
)
161 for (i
= 0; i
< params
.len
; ++i
) {
162 if (strcmp (params
.ptr
[i
].key
, name
) == 0)
163 return params
.ptr
[i
].value
;
166 /* XXX Allow $size to work by returning @$size. */
170 /* Check the raw|base64|data was specified. */
172 data_config_complete (void)
174 if (data_seen
== NOT_SEEN
) {
175 nbdkit_error ("raw|base64|data parameter was not specified");
179 if (data_seen
!= DATA
&& params
.len
!= 0) {
180 nbdkit_error ("extra parameters passed and not using data='...'");
187 #define data_config_help \
188 "allocator=sparse|... Backend allocation strategy\n" \
189 "base64=... Specify base64 disk data on the command line\n" \
190 "[data=]... Specify disk data using special format\n" \
191 "raw=... Specify raw disk data\n" \
192 "size=<SIZE> Size of the backing disk"
194 /* Parse raw|base64|data parameter and set the final size. */
196 data_get_ready (void)
198 uint64_t data_size
= 0; /* Size of data specified on the command line. */
200 a
= create_allocator (allocator_type
, data_debug_dir
);
206 data_size
= strlen (data_param
);
207 if (a
->f
->write (a
, data_param
, data_size
, 0) == -1)
212 if (read_base64 (data_param
, &data_size
) == -1)
217 if (read_data_format (data_param
, a
, &data_size
) == -1)
226 nbdkit_debug ("implicit data size: %" PRIi64
, data_size
);
228 /* If size == -1 it means the size= parameter was not given so we
229 * must use the data size.
233 nbdkit_debug ("final size: %" PRIi64
, size
);
235 if (a
->f
->set_size_hint (a
, size
) == -1)
241 /* Provide a way to detect if the base64 feature is supported. */
243 data_dump_plugin (void)
245 #if defined (HAVE_GNUTLS) && defined (HAVE_GNUTLS_BASE64_DECODE2)
246 printf ("data_base64=yes\n");
249 printf ("mlock=yes\n");
251 printf ("mlock=no\n");
254 printf ("zstd=yes\n");
256 printf ("zstd=no\n");
260 #define THREAD_MODEL NBDKIT_THREAD_MODEL_PARALLEL
262 /* Create the per-connection handle. */
264 data_open (int readonly
)
266 return NBDKIT_HANDLE_NOT_NEEDED
;
269 /* Get the disk size. */
271 data_get_size (void *handle
)
276 /* Flush is a no-op, so advertise native FUA support */
278 data_can_fua (void *handle
)
280 return NBDKIT_FUA_NATIVE
;
283 /* Serves the same data over multiple connections. */
285 data_can_multi_conn (void *handle
)
292 data_can_cache (void *handle
)
294 /* Everything is already in memory, returning this without
295 * implementing .cache lets nbdkit do the correct no-op.
297 return NBDKIT_CACHE_NATIVE
;
302 data_can_fast_zero (void *handle
)
309 data_pread (void *handle
, void *buf
, uint32_t count
, uint64_t offset
,
313 return a
->f
->read (a
, buf
, count
, offset
);
318 data_pwrite (void *handle
, const void *buf
, uint32_t count
, uint64_t offset
,
321 /* Flushing, and thus FUA flag, is a no-op */
322 assert ((flags
& ~NBDKIT_FLAG_FUA
) == 0);
323 return a
->f
->write (a
, buf
, count
, offset
);
328 data_zero (void *handle
, uint32_t count
, uint64_t offset
, uint32_t flags
)
330 /* Flushing, and thus FUA flag, is a no-op. Assume that
331 * a->f->zero generally beats writes, so FAST_ZERO is a no-op. */
332 assert ((flags
& ~(NBDKIT_FLAG_FUA
| NBDKIT_FLAG_MAY_TRIM
|
333 NBDKIT_FLAG_FAST_ZERO
)) == 0);
334 return a
->f
->zero (a
, count
, offset
);
337 /* Trim (same as zero). */
339 data_trim (void *handle
, uint32_t count
, uint64_t offset
, uint32_t flags
)
341 /* Flushing, and thus FUA flag, is a no-op */
342 assert ((flags
& ~NBDKIT_FLAG_FUA
) == 0);
343 return a
->f
->zero (a
, count
, offset
);
346 /* Nothing is persistent, so flush is trivially supported */
348 data_flush (void *handle
, uint32_t flags
)
355 data_extents (void *handle
, uint32_t count
, uint64_t offset
,
356 uint32_t flags
, struct nbdkit_extents
*extents
)
358 return a
->f
->extents (a
, count
, offset
, extents
);
361 static struct nbdkit_plugin plugin
= {
363 .version
= PACKAGE_VERSION
,
364 .unload
= data_unload
,
365 .config
= data_config
,
366 .config_complete
= data_config_complete
,
367 .config_help
= data_config_help
,
368 .magic_config_key
= "data",
369 .dump_plugin
= data_dump_plugin
,
370 .get_ready
= data_get_ready
,
372 .get_size
= data_get_size
,
373 .can_multi_conn
= data_can_multi_conn
,
374 .can_fua
= data_can_fua
,
375 .can_cache
= data_can_cache
,
376 .can_fast_zero
= data_can_fast_zero
,
378 .pwrite
= data_pwrite
,
382 .extents
= data_extents
,
383 /* In this plugin, errno is preserved properly along error return
384 * paths from failed system calls.
386 .errno_is_preserved
= 1,
389 NBDKIT_REGISTER_PLUGIN (plugin
)