Update Red Hat Copyright Notices
[nbdkit.git] / plugins / linuxdisk / linuxdisk.c
blob315fdf16068d4fe6ded04c9e0d22f40c1cd0d6b5
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 <stdbool.h>
38 #include <inttypes.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <time.h>
43 #define NBDKIT_API_VERSION 2
45 #include <nbdkit-plugin.h>
47 #include "random.h"
48 #include "regions.h"
50 #include "virtual-disk.h"
52 /* Directory, label, type, size parameters. */
53 const char *dir;
54 const char *label;
55 const char *type = "ext2";
56 int64_t size;
57 bool size_add_estimate; /* if size=+SIZE was used */
59 /* Virtual disk. */
60 static struct virtual_disk disk;
62 /* Used to create a random GUID for the partition. */
63 struct random_state random_state;
65 static void
66 linuxdisk_load (void)
68 init_virtual_disk (&disk);
69 xsrandom (time (NULL), &random_state);
72 static void
73 linuxdisk_unload (void)
75 free_virtual_disk (&disk);
78 static int
79 linuxdisk_config (const char *key, const char *value)
81 if (strcmp (key, "dir") == 0) {
82 if (dir != NULL) {
83 /* TODO: Support merging of multiple directories, like iso plugin. */
84 nbdkit_error ("dir=<DIRECTORY> must only be set once");
85 return -1;
87 /* We don't actually need to use realpath here because the
88 * directory is only used in .get_ready, before we chdir. Not
89 * doing realpath is helpful because on Windows it will munge the
90 * path in such a way that external mke2fs cannot parse it.
92 dir = value;
94 else if (strcmp (key, "label") == 0) {
95 label = value;
97 else if (strcmp (key, "type") == 0) {
98 if (strncmp (value, "ext", 3) != 0) {
99 nbdkit_error ("type=<TYPE> must be an filesystem type "
100 "supported by e2fsprogs");
101 return -1;
103 type = value;
105 else if (strcmp (key, "size") == 0) {
106 if (value[0] == '+') {
107 size_add_estimate = true;
108 value++;
110 else
111 size_add_estimate = false;
112 size = nbdkit_parse_size (value);
113 if (size == -1)
114 return -1;
116 else {
117 nbdkit_error ("unknown parameter '%s'", key);
118 return -1;
121 return 0;
124 static int
125 linuxdisk_config_complete (void)
127 if (dir == NULL) {
128 nbdkit_error ("you must supply the dir=<DIRECTORY> parameter "
129 "after the plugin name on the command line");
130 return -1;
133 return 0;
136 #define linuxdisk_config_help \
137 "dir=<DIRECTORY> (required) The directory to serve.\n" \
138 "label=<LABEL> The filesystem label.\n" \
139 "type=ext2|ext3|ext4 The filesystem type.\n" \
140 "size=[+]<SIZE> The virtual filesystem size."
142 static int
143 linuxdisk_get_ready (void)
145 return create_virtual_disk (&disk);
148 static void *
149 linuxdisk_open (int readonly)
151 return NBDKIT_HANDLE_NOT_NEEDED;
154 #define THREAD_MODEL NBDKIT_THREAD_MODEL_PARALLEL
156 /* Get the file size. */
157 static int64_t
158 linuxdisk_get_size (void *handle)
160 return virtual_size (&disk.regions);
163 /* Serves the same data over multiple connections. */
164 static int
165 linuxdisk_can_multi_conn (void *handle)
167 return 1;
170 /* Cache. */
171 static int
172 linuxdisk_can_cache (void *handle)
174 /* Let nbdkit call pread to populate the file system cache. */
175 return NBDKIT_CACHE_EMULATE;
178 /* Read data from the virtual disk. */
179 static int
180 linuxdisk_pread (void *handle, void *buf, uint32_t count, uint64_t offset,
181 uint32_t flags)
183 while (count > 0) {
184 const struct region *region = find_region (&disk.regions, offset);
185 size_t len;
186 ssize_t r;
188 /* Length to end of region. */
189 len = region->end - offset + 1;
190 if (len > count)
191 len = count;
193 switch (region->type) {
194 case region_file:
195 /* We don't use region->u.i since there is only one backing
196 * file, and we have that open already (in ‘disk.fd’).
198 r = pread (disk.fd, buf, len, offset - region->start);
199 if (r == -1) {
200 nbdkit_error ("pread: %m");
201 return -1;
203 if (r == 0) {
204 nbdkit_error ("pread: unexpected end of file");
205 return -1;
207 len = r;
208 break;
210 case region_data:
211 memcpy (buf, &region->u.data[offset - region->start], len);
212 break;
214 case region_zero:
215 memset (buf, 0, len);
216 break;
219 count -= len;
220 buf += len;
221 offset += len;
224 return 0;
227 static struct nbdkit_plugin plugin = {
228 .name = "linuxdisk",
229 .longname = "nbdkit Linux virtual disk plugin",
230 .version = PACKAGE_VERSION,
231 .load = linuxdisk_load,
232 .unload = linuxdisk_unload,
233 .config = linuxdisk_config,
234 .config_complete = linuxdisk_config_complete,
235 .config_help = linuxdisk_config_help,
236 .magic_config_key = "dir",
237 .get_ready = linuxdisk_get_ready,
238 .open = linuxdisk_open,
239 .get_size = linuxdisk_get_size,
240 .can_multi_conn = linuxdisk_can_multi_conn,
241 .can_cache = linuxdisk_can_cache,
242 .pread = linuxdisk_pread,
243 .errno_is_preserved = 1,
246 NBDKIT_REGISTER_PLUGIN (plugin)