Update Red Hat Copyright Notices
[nbdkit.git] / plugins / partitioning / partition-gpt.c
blobe2f0abac60c6ea170783943056aa8e53f91f623b
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 "ascii-ctype.h"
45 #include "byte-swapping.h"
46 #include "hexdigit.h"
48 #include "efi-crc32.h"
49 #include "gpt.h"
50 #include "regions.h"
51 #include "virtual-disk.h"
53 static void create_gpt_partition_header (const void *pt, bool is_primary,
54 unsigned char *out);
55 static void create_gpt_partition_table (unsigned char *out);
56 static void create_gpt_partition_table_entry (const struct region *region,
57 bool bootable,
58 char partition_type_guid[16],
59 unsigned char *out);
60 static void create_gpt_protective_mbr (unsigned char *out);
62 void
63 create_gpt_layout (void)
65 void *pt;
67 /* Protective MBR. LBA 0 */
68 create_gpt_protective_mbr (primary);
70 /* Primary partition table. LBA 2-(LBAs+1) */
71 pt = &primary[2*SECTOR_SIZE];
72 create_gpt_partition_table (pt);
74 /* Partition table header. LBA 1 */
75 create_gpt_partition_header (pt, true, &primary[SECTOR_SIZE]);
77 /* Backup partition table. LBA -(LBAs+2) */
78 pt = secondary;
79 create_gpt_partition_table (pt);
81 /* Backup partition table header. LBA -1 */
82 create_gpt_partition_header (pt, false, &secondary[GPT_PTA_LBAs*SECTOR_SIZE]);
85 static void
86 create_gpt_partition_header (const void *pt, bool is_primary,
87 unsigned char *out)
89 uint64_t nr_lbas;
90 struct gpt_header *header = (struct gpt_header *) out;
92 nr_lbas = virtual_size (&the_regions) / SECTOR_SIZE;
94 memset (header, 0, sizeof *header);
95 memcpy (header->signature, GPT_SIGNATURE, sizeof (header->signature));
96 memcpy (header->revision, GPT_REVISION, sizeof (header->revision));
97 header->header_size = htole32 (sizeof *header);
98 if (is_primary) {
99 header->current_lba = htole64 (1);
100 header->backup_lba = htole64 (nr_lbas - 1);
102 else {
103 header->current_lba = htole64 (nr_lbas - 1);
104 header->backup_lba = htole64 (1);
106 header->first_usable_lba = htole64 (2 + GPT_PTA_LBAs);
107 header->last_usable_lba = htole64 (nr_lbas - GPT_PTA_LBAs - 2);
108 if (is_primary)
109 header->partition_entries_lba = htole64 (2);
110 else
111 header->partition_entries_lba = htole64 (nr_lbas - GPT_PTA_LBAs - 1);
112 header->nr_partition_entries = htole32 (GPT_PTA_SIZE);
113 header->size_partition_entry = htole32 (GPT_PT_ENTRY_SIZE);
114 header->crc_partitions =
115 htole32 (efi_crc32 (pt, GPT_PT_ENTRY_SIZE * GPT_PTA_SIZE));
117 /* Must be computed last. */
118 header->crc = htole32 (efi_crc32 (header, sizeof *header));
121 static void
122 create_gpt_partition_table (unsigned char *out)
124 size_t i, j;
126 for (j = 0; j < nr_regions (&the_regions); ++j) {
127 const struct region *region = &the_regions.ptr[j];
129 if (region->type == region_file) {
130 i = region->u.i;
131 assert (i < GPT_PTA_SIZE);
132 create_gpt_partition_table_entry (region, i == 0,
133 the_files.ptr[i].type_guid,
134 out);
135 out += GPT_PT_ENTRY_SIZE;
140 static void
141 create_gpt_partition_table_entry (const struct region *region,
142 bool bootable,
143 char partition_type_guid[16],
144 unsigned char *out)
146 size_t i, len;
147 const char *filename;
148 struct gpt_entry *entry = (struct gpt_entry *) out;
150 assert (sizeof (struct gpt_entry) == GPT_PT_ENTRY_SIZE);
152 memcpy (entry->partition_type_guid, partition_type_guid, 16);
154 memcpy (entry->unique_guid, the_files.ptr[region->u.i].guid, 16);
156 entry->first_lba = htole64 (region->start / SECTOR_SIZE);
157 entry->last_lba = htole64 (region->end / SECTOR_SIZE);
158 entry->attributes = htole64 (bootable ? 4 : 0);
160 /* If the filename is 7 bit ASCII then this will reproduce it as a
161 * UTF-16LE string.
163 * Is this a security risk? It reveals something about paths on the
164 * server to clients. XXX
166 filename = the_files.ptr[region->u.i].filename;
167 len = strlen (filename);
168 if (len < 36) {
169 for (i = 0; i < len; ++i)
170 if ((unsigned char) filename[i] > 127)
171 goto out;
173 for (i = 0; i < len; ++i) {
174 entry->name[2*i] = filename[i];
175 entry->name[2*i+1] = 0;
178 out: ;
181 static void
182 create_gpt_protective_mbr (unsigned char *out)
184 struct region region;
185 uint64_t end;
187 /* Protective MBR creates a partition with partition ID 0xee which
188 * covers the whole of the disk, or as much of the disk as
189 * expressible with MBR.
191 region.start = 512;
192 end = virtual_size (&the_regions) - 1;
193 if (end > UINT32_MAX * SECTOR_SIZE)
194 end = UINT32_MAX * SECTOR_SIZE;
195 region.end = end;
196 region.len = region.end - region.start + 1;
198 create_mbr_partition_table_entry (&region, false, 0xee, &out[0x1be]);
200 /* Boot signature. */
201 out[0x1fe] = 0x55;
202 out[0x1ff] = 0xaa;
205 /* Try to parse a GPT GUID. */
207 parse_guid (const char *str, char *out)
209 size_t i;
210 size_t len = strlen (str);
212 if (len == 36)
213 /* nothing */;
214 else if (len == 38 && str[0] == '{' && str[37] == '}') {
215 str++;
216 len -= 2;
218 else
219 return -1;
221 assert (len == 36);
223 if (str[8] != '-' || str[13] != '-' || str[18] != '-' || str[23] != '-')
224 return -1;
226 for (i = 0; i < 8; ++i)
227 if (!ascii_isxdigit (str[i]))
228 return -1;
229 for (i = 9; i < 13; ++i)
230 if (!ascii_isxdigit (str[i]))
231 return -1;
232 for (i = 14; i < 18; ++i)
233 if (!ascii_isxdigit (str[i]))
234 return -1;
235 for (i = 19; i < 23; ++i)
236 if (!ascii_isxdigit (str[i]))
237 return -1;
238 for (i = 24; i < 36; ++i)
239 if (!ascii_isxdigit (str[i]))
240 return -1;
242 /* The first, second and third blocks are parsed as little endian,
243 * while the fourth and fifth blocks are big endian.
245 *out++ = hexbyte (str[6], str[7]); /* first block */
246 *out++ = hexbyte (str[4], str[5]);
247 *out++ = hexbyte (str[2], str[3]);
248 *out++ = hexbyte (str[0], str[1]);
250 *out++ = hexbyte (str[11], str[12]); /* second block */
251 *out++ = hexbyte (str[9], str[10]);
253 *out++ = hexbyte (str[16], str[17]); /* third block */
254 *out++ = hexbyte (str[14], str[15]);
256 *out++ = hexbyte (str[19], str[20]); /* fourth block */
257 *out++ = hexbyte (str[21], str[22]);
259 *out++ = hexbyte (str[24], str[25]); /* fifth block */
260 *out++ = hexbyte (str[26], str[27]);
261 *out++ = hexbyte (str[28], str[29]);
262 *out++ = hexbyte (str[30], str[31]);
263 *out++ = hexbyte (str[32], str[33]);
264 *out++ = hexbyte (str[34], str[35]);
266 return 0;