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
42 #include <nbdkit-filter.h>
44 #include "byte-swapping.h"
47 #include "partition.h"
51 /* Called for each key=value passed on the command line. */
53 partition_config (nbdkit_next_config
*next
, nbdkit_backend
*nxdata
,
54 const char *key
, const char *value
)
56 if (strcmp (key
, "partition") == 0) {
57 if (nbdkit_parse_unsigned ("partition", value
, &partnum
) == -1)
60 nbdkit_error ("invalid partition number");
66 return next (nxdata
, key
, value
);
69 /* Check the user did pass partition number. */
71 partition_config_complete (nbdkit_next_config_complete
*next
,
72 nbdkit_backend
*nxdata
)
75 nbdkit_error ("you must supply the partition parameter on the command line");
82 #define partition_config_help \
83 "partition=<PART> (required) The partition number (counting from 1)."
91 /* Open a connection. */
93 partition_open (nbdkit_next_open
*next
, nbdkit_context
*nxdata
,
94 int readonly
, const char *exportname
, int is_tls
)
98 if (next (nxdata
, readonly
, exportname
) == -1)
101 h
= malloc (sizeof *h
);
103 nbdkit_error ("malloc: %m");
107 /* These are set in the prepare method. */
108 h
->offset
= h
->range
= -1;
113 partition_close (void *handle
)
115 struct handle
*h
= handle
;
121 partition_prepare (nbdkit_next
*next
,
122 void *handle
, int readonly
)
124 struct handle
*h
= handle
;
126 uint8_t lba01
[2*SECTOR_SIZE
]; /* LBA 0 and 1 */
130 size
= next
->get_size (next
);
133 if (size
< 2 * SECTOR_SIZE
) {
134 nbdkit_error ("disk is too small to be a partitioned disk");
138 nbdkit_debug ("disk size=%" PRIi64
, size
);
140 if (next
->pread (next
, lba01
, sizeof lba01
, 0, 0, &err
) == -1)
144 if (size
>= 2 * 34 * SECTOR_SIZE
&&
145 memcmp (&lba01
[SECTOR_SIZE
], "EFI PART", 8) == 0) {
146 r
= find_gpt_partition (next
, size
, &lba01
[SECTOR_SIZE
], &h
->offset
,
151 else if (lba01
[0x1fe] == 0x55 && lba01
[0x1ff] == 0xAA) {
152 r
= find_mbr_partition (next
, size
, lba01
, &h
->offset
, &h
->range
);
156 nbdkit_error ("disk does not contain MBR or GPT partition table signature");
162 /* The find_*_partition functions set h->offset & h->range to the
163 * partition boundaries. We additionally check that they are inside
164 * the underlying disk.
166 if (h
->offset
< 0 || h
->range
< 0 || h
->offset
+ h
->range
> size
) {
167 nbdkit_error ("partition is outside the disk");
171 nbdkit_debug ("partition offset=%" PRIi64
" range=%" PRIi64
,
172 h
->offset
, h
->range
);
179 partition_export_description (nbdkit_next
*next
,
182 struct handle
*h
= handle
;
183 const char *base
= next
->export_description (next
);
188 return nbdkit_printf_intern ("partition %d of %s disk: %s", partnum
, h
->type
,
192 /* Get the file size. */
194 partition_get_size (nbdkit_next
*next
,
197 struct handle
*h
= handle
;
204 partition_pread (nbdkit_next
*next
,
205 void *handle
, void *buf
, uint32_t count
, uint64_t offs
,
206 uint32_t flags
, int *err
)
208 struct handle
*h
= handle
;
210 return next
->pread (next
, buf
, count
, offs
+ h
->offset
, flags
, err
);
215 partition_pwrite (nbdkit_next
*next
,
217 const void *buf
, uint32_t count
, uint64_t offs
,
218 uint32_t flags
, int *err
)
220 struct handle
*h
= handle
;
222 return next
->pwrite (next
, buf
, count
, offs
+ h
->offset
, flags
, err
);
227 partition_trim (nbdkit_next
*next
,
228 void *handle
, uint32_t count
, uint64_t offs
, uint32_t flags
,
231 struct handle
*h
= handle
;
233 return next
->trim (next
, count
, offs
+ h
->offset
, flags
, err
);
238 partition_zero (nbdkit_next
*next
,
239 void *handle
, uint32_t count
, uint64_t offs
, uint32_t flags
,
242 struct handle
*h
= handle
;
244 return next
->zero (next
, count
, offs
+ h
->offset
, flags
, err
);
249 partition_extents (nbdkit_next
*next
,
250 void *handle
, uint32_t count
, uint64_t offs
, uint32_t flags
,
251 struct nbdkit_extents
*extents
, int *err
)
253 struct handle
*h
= handle
;
255 CLEANUP_EXTENTS_FREE
struct nbdkit_extents
*extents2
= NULL
;
256 struct nbdkit_extent e
;
258 extents2
= nbdkit_extents_new (offs
+ h
->offset
, h
->offset
+ h
->range
);
259 if (extents2
== NULL
) {
263 if (next
->extents (next
, count
, offs
+ h
->offset
, flags
, extents2
,
267 for (i
= 0; i
< nbdkit_extents_count (extents2
); ++i
) {
268 e
= nbdkit_get_extent (extents2
, i
);
269 e
.offset
-= h
->offset
;
270 if (nbdkit_add_extent (extents
, e
.offset
, e
.length
, e
.type
) == -1) {
280 partition_cache (nbdkit_next
*next
,
281 void *handle
, uint32_t count
, uint64_t offs
, uint32_t flags
,
284 struct handle
*h
= handle
;
286 return next
->cache (next
, count
, offs
+ h
->offset
, flags
, err
);
289 static struct nbdkit_filter filter
= {
291 .longname
= "nbdkit partition filter",
292 .config
= partition_config
,
293 .config_complete
= partition_config_complete
,
294 .config_help
= partition_config_help
,
295 .open
= partition_open
,
296 .prepare
= partition_prepare
,
297 .close
= partition_close
,
298 .export_description
= partition_export_description
,
299 .get_size
= partition_get_size
,
300 .pread
= partition_pread
,
301 .pwrite
= partition_pwrite
,
302 .trim
= partition_trim
,
303 .zero
= partition_zero
,
304 .extents
= partition_extents
,
305 .cache
= partition_cache
,
308 NBDKIT_REGISTER_FILTER (filter
)