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
43 #define NBDKIT_API_VERSION 2
45 #include <nbdkit-plugin.h>
50 #include "virtual-disk.h"
52 /* Directory, label, type, size parameters. */
55 const char *type
= "ext2";
57 bool size_add_estimate
; /* if size=+SIZE was used */
60 static struct virtual_disk disk
;
62 /* Used to create a random GUID for the partition. */
63 struct random_state random_state
;
68 init_virtual_disk (&disk
);
69 xsrandom (time (NULL
), &random_state
);
73 linuxdisk_unload (void)
75 free_virtual_disk (&disk
);
79 linuxdisk_config (const char *key
, const char *value
)
81 if (strcmp (key
, "dir") == 0) {
83 /* TODO: Support merging of multiple directories, like iso plugin. */
84 nbdkit_error ("dir=<DIRECTORY> must only be set once");
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.
94 else if (strcmp (key
, "label") == 0) {
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");
105 else if (strcmp (key
, "size") == 0) {
106 if (value
[0] == '+') {
107 size_add_estimate
= true;
111 size_add_estimate
= false;
112 size
= nbdkit_parse_size (value
);
117 nbdkit_error ("unknown parameter '%s'", key
);
125 linuxdisk_config_complete (void)
128 nbdkit_error ("you must supply the dir=<DIRECTORY> parameter "
129 "after the plugin name on the command line");
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."
143 linuxdisk_get_ready (void)
145 return create_virtual_disk (&disk
);
149 linuxdisk_open (int readonly
)
151 return NBDKIT_HANDLE_NOT_NEEDED
;
154 #define THREAD_MODEL NBDKIT_THREAD_MODEL_PARALLEL
156 /* Get the file size. */
158 linuxdisk_get_size (void *handle
)
160 return virtual_size (&disk
.regions
);
163 /* Serves the same data over multiple connections. */
165 linuxdisk_can_multi_conn (void *handle
)
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. */
180 linuxdisk_pread (void *handle
, void *buf
, uint32_t count
, uint64_t offset
,
184 const struct region
*region
= find_region (&disk
.regions
, offset
);
188 /* Length to end of region. */
189 len
= region
->end
- offset
+ 1;
193 switch (region
->type
) {
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
);
200 nbdkit_error ("pread: %m");
204 nbdkit_error ("pread: unexpected end of file");
211 memcpy (buf
, ®ion
->u
.data
[offset
- region
->start
], len
);
215 memset (buf
, 0, len
);
227 static struct nbdkit_plugin plugin
= {
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
)