Update Red Hat Copyright Notices
[nbdkit.git] / plugins / data / data.c
blob37096f1bf75b42b5eb590ac52985308418325074
1 /* nbdkit
2 * Copyright Red Hat
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
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
30 * SUCH DAMAGE.
33 #include <config.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdint.h>
38 #include <inttypes.h>
39 #include <string.h>
41 #if defined (HAVE_GNUTLS) && defined (HAVE_GNUTLS_BASE64_DECODE2)
42 #include <gnutls/gnutls.h>
43 #endif
45 #define NBDKIT_API_VERSION 2
46 #include <nbdkit-plugin.h>
48 #include "allocator.h"
49 #include "cleanup.h"
50 #include "vector.h"
52 #include "data.h"
53 #include "format.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;
64 /* Allocator. */
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. */
77 static void
78 data_unload (void)
80 if (a)
81 a->f->free (a);
84 /* Parse the base64 parameter. */
85 static int
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;
90 int err;
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));
97 return -1;
100 if (a->f->write (a, out.data, out.size, 0) == -1)
101 return -1;
102 free (out.data);
103 *size_ret = out.size;
104 return 0;
105 #else
106 nbdkit_error ("base64 is not supported in this build of the plugin");
107 return -1;
108 #endif
111 static int
112 data_config (const char *key, const char *value)
114 int64_t r;
116 if (strcmp (key, "size") == 0) {
117 r = nbdkit_parse_size (value);
118 if (r == -1)
119 return -1;
120 size = r;
122 else if (strcmp (key, "allocator") == 0) {
123 allocator_type = value;
125 else if (strcmp (key, "raw") == 0) {
126 if (data_seen != NOT_SEEN) {
127 seen_error:
128 nbdkit_error ("raw|base64|data parameter must be specified exactly once");
129 return -1;
131 data_seen = RAW;
132 data_param = value;
134 else if (strcmp (key, "base64") == 0) {
135 if (data_seen != NOT_SEEN) goto seen_error;
136 data_seen = BASE64;
137 data_param = value;
139 else if (strcmp (key, "data") == 0) {
140 if (data_seen != NOT_SEEN) goto seen_error;
141 data_seen = DATA;
142 data_param = value;
144 else {
145 if (param_list_append (&params,
146 (struct param){ .key = key, .value = value })
147 == -1) {
148 nbdkit_error ("realloc: %m");
149 return -1;
153 return 0;
156 const char *
157 get_extra_param (const char *name)
159 size_t i;
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. */
167 return NULL;
170 /* Check the raw|base64|data was specified. */
171 static int
172 data_config_complete (void)
174 if (data_seen == NOT_SEEN) {
175 nbdkit_error ("raw|base64|data parameter was not specified");
176 return -1;
179 if (data_seen != DATA && params.len != 0) {
180 nbdkit_error ("extra parameters passed and not using data='...'");
181 return -1;
184 return 0;
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. */
195 static int
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);
201 if (a == NULL)
202 return -1;
204 switch (data_seen) {
205 case RAW:
206 data_size = strlen (data_param);
207 if (a->f->write (a, data_param, data_size, 0) == -1)
208 return -1;
209 break;
211 case BASE64:
212 if (read_base64 (data_param, &data_size) == -1)
213 return -1;
214 break;
216 case DATA:
217 if (read_data_format (data_param, a, &data_size) == -1)
218 return -1;
219 break;
221 case NOT_SEEN:
222 default:
223 abort ();
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.
231 if (size == -1)
232 size = data_size;
233 nbdkit_debug ("final size: %" PRIi64, size);
235 if (a->f->set_size_hint (a, size) == -1)
236 return -1;
238 return 0;
241 /* Provide a way to detect if the base64 feature is supported. */
242 static void
243 data_dump_plugin (void)
245 #if defined (HAVE_GNUTLS) && defined (HAVE_GNUTLS_BASE64_DECODE2)
246 printf ("data_base64=yes\n");
247 #endif
248 #ifdef HAVE_MLOCK
249 printf ("mlock=yes\n");
250 #else
251 printf ("mlock=no\n");
252 #endif
253 #ifdef HAVE_LIBZSTD
254 printf ("zstd=yes\n");
255 #else
256 printf ("zstd=no\n");
257 #endif
260 #define THREAD_MODEL NBDKIT_THREAD_MODEL_PARALLEL
262 /* Create the per-connection handle. */
263 static void *
264 data_open (int readonly)
266 return NBDKIT_HANDLE_NOT_NEEDED;
269 /* Get the disk size. */
270 static int64_t
271 data_get_size (void *handle)
273 return size;
276 /* Flush is a no-op, so advertise native FUA support */
277 static int
278 data_can_fua (void *handle)
280 return NBDKIT_FUA_NATIVE;
283 /* Serves the same data over multiple connections. */
284 static int
285 data_can_multi_conn (void *handle)
287 return 1;
290 /* Cache. */
291 static int
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;
300 /* Fast zero. */
301 static int
302 data_can_fast_zero (void *handle)
304 return 1;
307 /* Read data. */
308 static int
309 data_pread (void *handle, void *buf, uint32_t count, uint64_t offset,
310 uint32_t flags)
312 assert (!flags);
313 return a->f->read (a, buf, count, offset);
316 /* Write data. */
317 static int
318 data_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset,
319 uint32_t flags)
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);
326 /* Zero. */
327 static int
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). */
338 static int
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 */
347 static int
348 data_flush (void *handle, uint32_t flags)
350 return 0;
353 /* Extents. */
354 static int
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 = {
362 .name = "data",
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,
371 .open = data_open,
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,
377 .pread = data_pread,
378 .pwrite = data_pwrite,
379 .zero = data_zero,
380 .trim = data_trim,
381 .flush = data_flush,
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)