Update Red Hat Copyright Notices
[nbdkit.git] / plugins / partitioning / partition-mbr.c
blobaccb399d04e5c926243ac85bfe1e090f99b52235
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 <string.h>
39 #include <inttypes.h>
40 #include <assert.h>
42 #include <nbdkit-plugin.h>
44 #include "byte-swapping.h"
46 #include "isaligned.h"
47 #include "rounding.h"
49 #include "regions.h"
50 #include "virtual-disk.h"
52 static const struct region *find_file_region (size_t i, size_t *j);
53 static const struct region *find_ebr_region (size_t i, size_t *j);
55 /* Create the MBR and optionally EBRs. */
56 void
57 create_mbr_layout (void)
59 size_t i, j = 0;
61 /* Boot signature. */
62 primary[0x1fe] = 0x55;
63 primary[0x1ff] = 0xaa;
65 if (the_files.len <= 4) {
66 /* Basic MBR with no extended partition. */
67 for (i = 0; i < the_files.len; ++i) {
68 const struct region *region = find_file_region (i, &j);
70 create_mbr_partition_table_entry (region, i == 0, the_files.ptr[i].mbr_id,
71 &primary[0x1be + 16*i]);
74 else {
75 struct region region;
76 const struct region *rptr, *eptr0, *eptr;
78 /* The first three primary partitions correspond to the first
79 * three files.
81 for (i = 0; i < 3; ++i) {
82 rptr = find_file_region (i, &j);
83 create_mbr_partition_table_entry (rptr, i == 0, the_files.ptr[i].mbr_id,
84 &primary[0x1be + 16*i]);
87 /* The fourth partition is an extended PTE and does not correspond
88 * to any file. This partition starts with the first EBR, so find
89 * it. The partition extends to the end of the disk.
91 eptr0 = find_ebr_region (3, &j);
92 region.start = eptr0->start;
93 region.end = virtual_size (&the_regions) - 1; /* to end of disk */
94 region.len = region.end - region.start + 1;
95 create_mbr_partition_table_entry (&region, false, 0xf, &primary[0x1ee]);
97 /* The remaining files are mapped to logical partitions living in
98 * the fourth extended partition.
100 for (i = 3; i < the_files.len; ++i) {
101 if (i == 3)
102 eptr = eptr0;
103 else
104 eptr = find_ebr_region (i, &j);
105 rptr = find_file_region (i, &j);
107 /* Signature. */
108 ebr[i-3][0x1fe] = 0x55;
109 ebr[i-3][0x1ff] = 0xaa;
111 /* First entry in EBR contains:
112 * offset from EBR sector to the first sector of the logical partition
113 * total count of sectors in the logical partition
115 region.start = rptr->start - eptr->start;
116 region.len = rptr->len;
117 create_mbr_partition_table_entry (&region, false, the_files.ptr[i].mbr_id,
118 &ebr[i-3][0x1be]);
120 if (i < the_files.len-1) {
121 size_t j2 = j;
122 const struct region *enext = find_ebr_region (i+1, &j2);
123 const struct region *rnext = find_file_region (i+1, &j2);
125 /* Second entry in the EBR contains:
126 * address of next EBR relative to extended partition
127 * total count of sectors in the next logical partition including
128 * next EBR
130 region.start = enext->start - eptr0->start;
131 region.len = rnext->end - enext->start + 1;
132 create_mbr_partition_table_entry (&region, false, 0xf,
133 &ebr[i-3][0x1ce]);
139 /* Find the region corresponding to file[i].
140 * j is a scratch register ensuring we only do a linear scan.
142 static const struct region *
143 find_file_region (size_t i, size_t *j)
145 const struct region *region;
147 for (; *j < nr_regions (&the_regions); ++(*j)) {
148 region = &the_regions.ptr[*j];
149 if (region->type == region_file && region->u.i == i)
150 return region;
152 abort ();
155 /* Find the region corresponding to EBR of file[i] (i >= 3).
156 * j is a scratch register ensuring we only do a linear scan.
158 static const struct region *
159 find_ebr_region (size_t i, size_t *j)
161 const struct region *region;
163 assert (i >= 3);
165 for (; *j < nr_regions (&the_regions); ++(*j)) {
166 region = &the_regions.ptr[*j];
167 if (region->type == region_data && region->u.data == ebr[i-3])
168 return region;
170 abort ();
173 static void
174 chs_too_large (unsigned char *out)
176 const int c = 1023, h = 254, s = 63;
178 out[0] = h;
179 out[1] = (c & 0x300) >> 2 | s;
180 out[2] = c & 0xff;
183 void
184 create_mbr_partition_table_entry (const struct region *region,
185 bool bootable, int partition_id,
186 unsigned char *out)
188 uint64_t start_sector, nr_sectors;
189 uint32_t u32;
191 assert (IS_ALIGNED (region->start, SECTOR_SIZE));
193 start_sector = region->start / SECTOR_SIZE;
194 nr_sectors = DIV_ROUND_UP (region->len, SECTOR_SIZE);
196 /* The total_size test in partitioning_config_complete should catch
197 * this earlier.
199 assert (start_sector <= UINT32_MAX);
200 assert (nr_sectors <= UINT32_MAX);
202 out[0] = bootable ? 0x80 : 0;
203 chs_too_large (&out[1]);
204 out[4] = partition_id;
205 chs_too_large (&out[5]);
206 u32 = htole32 (start_sector);
207 memcpy (&out[8], &u32, 4);
208 u32 = htole32 (nr_sectors);
209 memcpy (&out[12], &u32, 4);