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
40 #include <nbdkit-plugin.h>
42 #include "isaligned.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
54 create_virtual_disk_layout (void)
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");
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));
78 nbdkit_error ("malloc: %m");
81 for (i
= 0; i
< the_files
.len
-3; ++i
) {
82 ebr
[i
] = calloc (1, SECTOR_SIZE
);
84 nbdkit_error ("malloc: %m");
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");
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");
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",
109 region_data
, primary
) == -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)
119 /* The partitions. */
120 for (i
= 0; i
< the_files
.len
; ++i
) {
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",
133 region_data
, ebr
[i
-3]) == -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)
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)
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
?
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 ();
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 ();