Update Red Hat Copyright Notices
[nbdkit.git] / plugins / partitioning / virtual-disk.c
blob27ea24d6cd7a174de9e81f845aad560c994d66cb
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 <inttypes.h>
38 #include <assert.h>
40 #include <nbdkit-plugin.h>
42 #include "isaligned.h"
44 #include "regions.h"
45 #include "virtual-disk.h"
47 static int create_partition_table (void);
49 /* Called once we have the list of filenames and have selected a
50 * partition type. This creates the virtual disk layout as a list of
51 * regions.
53 int
54 create_virtual_disk_layout (void)
56 size_t i;
58 assert (nr_regions (&the_regions) == 0);
59 assert (the_files.len > 0);
60 assert (primary == NULL);
61 assert (secondary == NULL);
63 /* Allocate the virtual partition table. */
64 if (parttype == PARTTYPE_MBR) {
65 primary = calloc (1, SECTOR_SIZE);
66 if (primary == NULL) {
67 nbdkit_error ("malloc: %m");
68 return -1;
71 if (the_files.len > 4) {
72 /* The first 3 primary partitions will be real partitions, the
73 * 4th will be an extended partition, and so we need to store
74 * EBRs for the_files.size-3 logical partitions.
76 ebr = malloc (sizeof (unsigned char *) * (the_files.len-3));
77 if (ebr == NULL) {
78 nbdkit_error ("malloc: %m");
79 return -1;
81 for (i = 0; i < the_files.len-3; ++i) {
82 ebr[i] = calloc (1, SECTOR_SIZE);
83 if (ebr[i] == NULL) {
84 nbdkit_error ("malloc: %m");
85 return -1;
90 else /* PARTTYPE_GPT */ {
91 /* Protective MBR + PT header + PTA = 2 + GPT_PTA_LBAs */
92 primary = calloc (2+GPT_PTA_LBAs, SECTOR_SIZE);
93 if (primary == NULL) {
94 nbdkit_error ("malloc: %m");
95 return -1;
97 /* Secondary PTA + PT secondary header = GPT_PTA_LBAs + 1 */
98 secondary = calloc (GPT_PTA_LBAs+1, SECTOR_SIZE);
99 if (secondary == NULL) {
100 nbdkit_error ("malloc: %m");
101 return -1;
105 /* Virtual primary partition table region at the start of the disk. */
106 if (parttype == PARTTYPE_MBR) {
107 if (append_region_len (&the_regions, "MBR",
108 SECTOR_SIZE, 0, 0,
109 region_data, primary) == -1)
110 return -1;
112 else /* PARTTYPE_GPT */ {
113 if (append_region_len (&the_regions, "GPT primary",
114 (2+GPT_PTA_LBAs) * SECTOR_SIZE, 0, 0,
115 region_data, primary) == -1)
116 return -1;
119 /* The partitions. */
120 for (i = 0; i < the_files.len; ++i) {
121 uint64_t offset;
123 offset = virtual_size (&the_regions);
124 /* Because we add padding after each partition, this invariant
125 * must always be true.
127 assert (IS_ALIGNED (offset, SECTOR_SIZE));
129 /* Logical partitions are preceeded by an EBR. */
130 if (parttype == PARTTYPE_MBR && the_files.len > 4 && i >= 3) {
131 if (append_region_len (&the_regions, "EBR",
132 SECTOR_SIZE, 0, 0,
133 region_data, ebr[i-3]) == -1)
134 return -1;
137 /* Create the partition region for this file.
138 * Make sure each partition is aligned for best performance.
139 * If the file size is not a multiple of SECTOR_SIZE then
140 * add a padding region at the end to round it up.
142 if (append_region_len (&the_regions, the_files.ptr[i].filename,
143 the_files.ptr[i].statbuf.st_size,
144 the_files.ptr[i].alignment, SECTOR_SIZE,
145 region_file, i) == -1)
146 return -1;
149 /* For GPT add the virtual secondary/backup partition table. */
150 if (parttype == PARTTYPE_GPT) {
151 if (append_region_len (&the_regions, "GPT secondary",
152 (GPT_PTA_LBAs+1) * SECTOR_SIZE, 0, 0,
153 region_data, secondary) == -1)
154 return -1;
157 if (partitioning_debug_regions) {
158 for (i = 0; i < nr_regions (&the_regions); ++i) {
159 const struct region *region = &the_regions.ptr[i];
161 nbdkit_debug ("region[%zu]: %" PRIx64 "-%" PRIx64 " type=%s",
162 i, region->start, region->end,
163 region->type == region_file ?
164 the_files.ptr[region->u.i].filename :
165 region->type == region_data ?
166 "data" : "zero");
170 /* We must have created some regions. */
171 assert (nr_regions (&the_regions) > 0);
173 /* Check the final alignment of all the partitions is the same as
174 * what was requested.
176 for (i = 0; i < nr_regions (&the_regions); ++i) {
177 const struct region *region = &the_regions.ptr[i];
179 if (region->type == region_file)
180 assert (IS_ALIGNED (region->start, the_files.ptr[region->u.i].alignment));
183 return create_partition_table ();
186 static int
187 create_partition_table (void)
189 /* The caller has already created the disk layout and allocated
190 * space in memory for the partition table.
192 assert (nr_regions (&the_regions) > 0);
193 assert (primary != NULL);
194 if (parttype == PARTTYPE_GPT)
195 assert (secondary != NULL);
197 if (parttype == PARTTYPE_MBR)
198 create_mbr_layout ();
199 else /* parttype == PARTTYPE_GPT */
200 create_gpt_layout ();
202 return 0;