1 /*
2 libparted - a library for manipulating disk partitions
3
4 original version by Matt Domsch <Matt_Domsch@dell.com>
5 Disclaimed into the Public Domain
6
7 Portions Copyright (C) 2001, 2002, 2003, 2005, 2006, 2007
8 Free Software Foundation, Inc.
9
10 EFI GUID Partition Table handling
11 Per Intel EFI Specification v1.02
12 http://developer.intel.com/technology/efi/efi.htm
13
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 3 of the License, or
17 (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 */
27
28 #include <config.h>
29
30 #include <parted/parted.h>
31 #include <parted/debug.h>
32 #include <parted/endian.h>
33 #include <parted/crc32.h>
34 #include <inttypes.h>
35 #include <stdio.h>
36 #include <sys/types.h>
37 #include <sys/ioctl.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40 #include <uuid/uuid.h>
41
42 #if ENABLE_NLS
43 # include <libintl.h>
44 # define _(String) gettext (String)
45 #else
46 # define _(String) (String)
47 #endif /* ENABLE_NLS */
48
49 #define EFI_PMBR_OSTYPE_EFI 0xEE
50 #define MSDOS_MBR_SIGNATURE 0xaa55
51
52 #define GPT_HEADER_SIGNATURE 0x5452415020494645LL
53
54 /* NOTE: the document that describes revision 1.00 is labelled "version 1.02",
55 * so some implementors got confused...
56 */
57 #define GPT_HEADER_REVISION_V1_02 0x00010200
58 #define GPT_HEADER_REVISION_V1_00 0x00010000
59 #define GPT_HEADER_REVISION_V0_99 0x00009900
60
61 #ifdef __sun
62 #define __attribute__(X) /*nothing*/
63 #endif /* __sun */
64
65 typedef uint16_t efi_char16_t; /* UNICODE character */
66 typedef struct _GuidPartitionTableHeader_t GuidPartitionTableHeader_t;
67 typedef struct _GuidPartitionEntryAttributes_t GuidPartitionEntryAttributes_t;
68 typedef struct _GuidPartitionEntry_t GuidPartitionEntry_t;
69 typedef struct _PartitionRecord_t PartitionRecord_t;
70 typedef struct _LegacyMBR_t LegacyMBR_t;
71 typedef struct _GPTDiskData GPTDiskData;
72 typedef struct {
73 uint32_t time_low;
74 uint16_t time_mid;
75 uint16_t time_hi_and_version;
76 uint8_t clock_seq_hi_and_reserved;
77 uint8_t clock_seq_low;
78 uint8_t node[6];
79 } /* __attribute__ ((packed)) */ efi_guid_t;
80 /* commented out "__attribute__ ((packed))" to work around gcc bug (fixed
81 * in gcc3.1): __attribute__ ((packed)) breaks addressing on initialized
82 * data. It turns out we don't need it in this case, so it doesn't break
83 * anything :)
84 */
85
86 #define UNUSED_ENTRY_GUID \
87 ((efi_guid_t) { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
88 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
89 #define PARTITION_SYSTEM_GUID \
90 ((efi_guid_t) { PED_CPU_TO_LE32 (0xC12A7328), PED_CPU_TO_LE16 (0xF81F), \
91 PED_CPU_TO_LE16 (0x11d2), 0xBA, 0x4B, \
92 { 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }})
93 #define LEGACY_MBR_PARTITION_GUID \
94 ((efi_guid_t) { PED_CPU_TO_LE32 (0x024DEE41), PED_CPU_TO_LE16 (0x33E7), \
95 PED_CPU_TO_LE16 (0x11d3, 0x9D, 0x69, \
96 { 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }})
97 #define PARTITION_MSFT_RESERVED_GUID \
98 ((efi_guid_t) { PED_CPU_TO_LE32 (0xE3C9E316), PED_CPU_TO_LE16 (0x0B5C), \
99 PED_CPU_TO_LE16 (0x4DB8), 0x81, 0x7D, \
100 { 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE }})
101 #define PARTITION_BASIC_DATA_GUID \
102 ((efi_guid_t) { PED_CPU_TO_LE32 (0xEBD0A0A2), PED_CPU_TO_LE16 (0xB9E5), \
103 PED_CPU_TO_LE16 (0x4433), 0x87, 0xC0, \
104 { 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }})
105 #define PARTITION_RAID_GUID \
106 ((efi_guid_t) { PED_CPU_TO_LE32 (0xa19d880f), PED_CPU_TO_LE16 (0x05fc), \
107 PED_CPU_TO_LE16 (0x4d3b), 0xa0, 0x06, \
108 { 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e }})
109 #define PARTITION_SWAP_GUID \
110 ((efi_guid_t) { PED_CPU_TO_LE32 (0x0657fd6d), PED_CPU_TO_LE16 (0xa4ab), \
111 PED_CPU_TO_LE16 (0x43c4), 0x84, 0xe5, \
112 { 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f }})
113 #define PARTITION_LVM_GUID \
114 ((efi_guid_t) { PED_CPU_TO_LE32 (0xe6d6d379), PED_CPU_TO_LE16 (0xf507), \
115 PED_CPU_TO_LE16 (0x44c2), 0xa2, 0x3c, \
116 { 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 }})
117 #define PARTITION_RESERVED_GUID \
118 ((efi_guid_t) { PED_CPU_TO_LE32 (0x8da63339), PED_CPU_TO_LE16 (0x0007), \
119 PED_CPU_TO_LE16 (0x60c0), 0xc4, 0x36, \
120 { 0x08, 0x3a, 0xc8, 0x23, 0x09, 0x08 }})
121 #define PARTITION_HPSERVICE_GUID \
122 ((efi_guid_t) { PED_CPU_TO_LE32 (0xe2a1e728), PED_CPU_TO_LE16 (0x32e3), \
123 PED_CPU_TO_LE16 (0x11d6), 0xa6, 0x82, \
124 { 0x7b, 0x03, 0xa0, 0x00, 0x00, 0x00 }})
125 #define PARTITION_APPLE_HFS_GUID \
126 ((efi_guid_t) { PED_CPU_TO_LE32 (0x48465300), PED_CPU_TO_LE16 (0x0000), \
127 PED_CPU_TO_LE16 (0x11AA), 0xaa, 0x11, \
128 { 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC }})
129
130 #ifdef __sun
131 #pragma pack(1)
132 #endif
133 struct __attribute__ ((packed)) _GuidPartitionTableHeader_t {
134 uint64_t Signature;
135 uint32_t Revision;
136 uint32_t HeaderSize;
137 uint32_t HeaderCRC32;
138 uint32_t Reserved1;
139 uint64_t MyLBA;
140 uint64_t AlternateLBA;
141 uint64_t FirstUsableLBA;
142 uint64_t LastUsableLBA;
143 efi_guid_t DiskGUID;
144 uint64_t PartitionEntryLBA;
145 uint32_t NumberOfPartitionEntries;
146 uint32_t SizeOfPartitionEntry;
147 uint32_t PartitionEntryArrayCRC32;
148 uint8_t* Reserved2;
149 };
150
151 struct __attribute__ ((packed)) _GuidPartitionEntryAttributes_t {
152 #if defined(__GNUC__) || defined(__sun) /* XXX narrow this down to !TinyCC */
153 uint64_t RequiredToFunction:1;
154 uint64_t Reserved:47;
155 uint64_t GuidSpecific:16;
156 #else
157 uint32_t RequiredToFunction:1;
158 uint32_t Reserved:32;
159 uint32_t LOST:5;
160 uint32_t GuidSpecific:16;
161 #endif
162 };
163
164 struct __attribute__ ((packed)) _GuidPartitionEntry_t {
165 efi_guid_t PartitionTypeGuid;
166 efi_guid_t UniquePartitionGuid;
167 uint64_t StartingLBA;
168 uint64_t EndingLBA;
169 GuidPartitionEntryAttributes_t Attributes;
170 efi_char16_t PartitionName[72 / sizeof(efi_char16_t)];
171 };
172 #ifdef __sun
173 #pragma pack()
174 #endif
175
176 #define GPT_PMBR_LBA 0
177 #define GPT_PMBR_SECTORS 1
178 #define GPT_PRIMARY_HEADER_LBA 1
179 #define GPT_HEADER_SECTORS 1
180 #define GPT_PRIMARY_PART_TABLE_LBA 2
181
182 /*
183 These values are only defaults. The actual on-disk structures
184 may define different sizes, so use those unless creating a new GPT disk!
185 */
186
187 #define GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE 16384
188
189 /* Number of actual partition entries should be calculated as: */
190 #define GPT_DEFAULT_PARTITION_ENTRIES \
191 (GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / \
192 sizeof(GuidPartitionEntry_t))
193
194
195 #ifdef __sun
196 #pragma pack(1)
197 #endif
198 struct __attribute__ ((packed)) _PartitionRecord_t {
199 /* Not used by EFI firmware. Set to 0x80 to indicate that this
200 is the bootable legacy partition. */
201 uint8_t BootIndicator;
202
203 /* Start of partition in CHS address, not used by EFI firmware. */
204 uint8_t StartHead;
205
206 /* Start of partition in CHS address, not used by EFI firmware. */
207 uint8_t StartSector;
208
209 /* Start of partition in CHS address, not used by EFI firmware. */
210 uint8_t StartTrack;
211
212 /* OS type. A value of 0xEF defines an EFI system partition.
213 Other values are reserved for legacy operating systems, and
214 allocated independently of the EFI specification. */
215 uint8_t OSType;
216
217 /* End of partition in CHS address, not used by EFI firmware. */
218 uint8_t EndHead;
219
220 /* End of partition in CHS address, not used by EFI firmware. */
221 uint8_t EndSector;
222
223 /* End of partition in CHS address, not used by EFI firmware. */
224 uint8_t EndTrack;
225
226 /* Starting LBA address of the partition on the disk. Used by
227 EFI firmware to define the start of the partition. */
228 uint32_t StartingLBA;
229
230 /* Size of partition in LBA. Used by EFI firmware to determine
231 the size of the partition. */
232 uint32_t SizeInLBA;
233 };
234
235 /* Protected Master Boot Record & Legacy MBR share same structure */
236 /* Needs to be packed because the u16s force misalignment. */
237 struct __attribute__ ((packed)) _LegacyMBR_t {
238 uint8_t BootCode[440];
239 uint32_t UniqueMBRSignature;
240 uint16_t Unknown;
241 PartitionRecord_t PartitionRecord[4];
242 uint16_t Signature;
243 };
244
245 /* uses libparted's disk_specific field in PedDisk, to store our info */
246 struct __attribute__ ((packed)) _GPTDiskData {
247 PedGeometry data_area;
248 int entry_count;
249 efi_guid_t uuid;
250 };
251 #ifdef __sun
252 #pragma pack()
253 #endif
254
255 /* uses libparted's disk_specific field in PedPartition, to store our info */
256 typedef struct _GPTPartitionData {
257 efi_guid_t type;
258 efi_guid_t uuid;
259 char name[37];
260 int lvm;
261 int raid;
262 int boot;
263 int hp_service;
264 int hidden;
265 int msftres;
266 } GPTPartitionData;
267
268 static PedDiskType gpt_disk_type;
269
270
271 static inline uint32_t
pth_get_size(const PedDevice * dev)272 pth_get_size (const PedDevice* dev)
273 {
274 return GPT_HEADER_SECTORS * dev->sector_size;
275 }
276
277
278 static inline uint32_t
pth_get_size_static(const PedDevice * dev)279 pth_get_size_static (const PedDevice* dev)
280 {
281 return sizeof (GuidPartitionTableHeader_t) - sizeof (uint8_t*);
282 }
283
284
285 static inline uint32_t
pth_get_size_rsv2(const PedDevice * dev)286 pth_get_size_rsv2 (const PedDevice* dev)
287 {
288 return pth_get_size(dev) - pth_get_size_static(dev);
289 }
290
291
292 static GuidPartitionTableHeader_t*
pth_new(const PedDevice * dev)293 pth_new (const PedDevice* dev)
294 {
295 GuidPartitionTableHeader_t* pth = ped_malloc (
296 sizeof (GuidPartitionTableHeader_t)
297 + sizeof (uint8_t));
298
299 pth->Reserved2 = ped_malloc ( pth_get_size_rsv2 (dev) );
300
301 return pth;
302 }
303
304
305 static GuidPartitionTableHeader_t*
pth_new_zeroed(const PedDevice * dev)306 pth_new_zeroed (const PedDevice* dev)
307 {
308 GuidPartitionTableHeader_t* pth = pth_new (dev);
309
310 memset (pth, 0, pth_get_size_static (dev));
311 memset (pth->Reserved2, 0, pth_get_size_rsv2 (dev));
312
313 return (pth);
314 }
315
316
317 static GuidPartitionTableHeader_t*
pth_new_from_raw(const PedDevice * dev,const uint8_t * pth_raw)318 pth_new_from_raw (const PedDevice* dev, const uint8_t* pth_raw)
319 {
320 GuidPartitionTableHeader_t* pth = pth_new (dev);
321
322 PED_ASSERT (pth_raw != NULL, return 0);
323
324 memcpy (pth, pth_raw, pth_get_size_static (dev));
325 memcpy (pth->Reserved2, pth_raw + pth_get_size_static (dev),
326 pth_get_size_rsv2 (dev));
327
328 return pth;
329 }
330
331 static void
pth_free(GuidPartitionTableHeader_t * pth)332 pth_free (GuidPartitionTableHeader_t* pth)
333 {
334 PED_ASSERT (pth != NULL, return);
335 PED_ASSERT (pth->Reserved2 != NULL, return);
336
337 ped_free (pth->Reserved2);
338 ped_free (pth);
339 }
340
341 static uint8_t*
pth_get_raw(const PedDevice * dev,const GuidPartitionTableHeader_t * pth)342 pth_get_raw (const PedDevice* dev, const GuidPartitionTableHeader_t* pth)
343 {
344 uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
345 int size_static = pth_get_size_static (dev);
346
347 PED_ASSERT (pth != NULL, return 0);
348 PED_ASSERT (pth->Reserved2 != NULL, return 0);
349
350 memcpy (pth_raw, pth, size_static);
351 memcpy (pth_raw + size_static, pth->Reserved2, pth_get_size_rsv2 (dev));
352
353 return pth_raw;
354 }
355
356
357 /**
358 * swap_uuid_and_efi_guid() - converts between uuid formats
359 * @uuid - uuid_t in either format (converts it to the other)
360 *
361 * There are two different representations for Globally Unique Identifiers
362 * (GUIDs or UUIDs).
363 *
364 * The RFC specifies a UUID as a string of 16 bytes, essentially
365 * a big-endian array of char.
366 * Intel, in their EFI Specification, references the same RFC, but
367 * then defines a GUID as a structure of little-endian fields.
368 * Coincidentally, both structures have the same format when unparsed.
369 *
370 * When read from disk, EFI GUIDs are in struct of little endian format,
371 * and need to be converted to be treated as uuid_t in memory.
372 *
373 * When writing to disk, uuid_ts need to be converted into EFI GUIDs.
374 *
375 * Blame Intel.
376 */
377 static void
swap_uuid_and_efi_guid(uuid_t uuid)378 swap_uuid_and_efi_guid(uuid_t uuid)
379 {
380 efi_guid_t *guid = (efi_guid_t *)uuid;
381
382 PED_ASSERT(uuid != NULL, return);
383 guid->time_low = PED_SWAP32(guid->time_low);
384 guid->time_mid = PED_SWAP16(guid->time_mid);
385 guid->time_hi_and_version = PED_SWAP16(guid->time_hi_and_version);
386 }
387
388 /* returns the EFI-style CRC32 value for buf
389 * This function uses the crc32 function by Gary S. Brown,
390 * but seeds the function with ~0, and xor's with ~0 at the end.
391 */
392 static inline uint32_t
efi_crc32(const void * buf,unsigned long len)393 efi_crc32(const void *buf, unsigned long len)
394 {
395 return (__efi_crc32(buf, len, ~0L) ^ ~0L);
396 }
397
398 static inline uint32_t
pth_crc32(const PedDevice * dev,const GuidPartitionTableHeader_t * pth)399 pth_crc32(const PedDevice* dev, const GuidPartitionTableHeader_t* pth)
400 {
401 uint8_t* pth_raw = pth_get_raw (dev, pth);
402 uint32_t crc32 = 0;
403
404 PED_ASSERT (dev != NULL, return 0);
405 PED_ASSERT (pth != NULL, return 0);
406
407 crc32 = efi_crc32 (pth_raw, PED_LE32_TO_CPU (pth->HeaderSize));
408
409 ped_free (pth_raw);
410
411 return crc32;
412 }
413
414 static inline int
guid_cmp(efi_guid_t left,efi_guid_t right)415 guid_cmp (efi_guid_t left, efi_guid_t right)
416 {
417 return memcmp(&left, &right, sizeof(efi_guid_t));
418 }
419
420 /* checks if 'mbr' is a protective MBR partition table */
421 static inline int
_pmbr_is_valid(const LegacyMBR_t * mbr)422 _pmbr_is_valid (const LegacyMBR_t* mbr)
423 {
424 int i;
425
426 PED_ASSERT(mbr != NULL, return 0);
427
428 if (mbr->Signature != PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE))
429 return 0;
430 for (i = 0; i < 4; i++) {
431 if (mbr->PartitionRecord[i].OSType == EFI_PMBR_OSTYPE_EFI)
432 return 1;
433 }
434 return 0;
435 }
436
437 static int
gpt_probe(const PedDevice * dev)438 gpt_probe (const PedDevice * dev)
439 {
440 GuidPartitionTableHeader_t* gpt = NULL;
441 uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
442 LegacyMBR_t legacy_mbr;
443 int gpt_sig_found = 0;
444
445 PED_ASSERT (dev != NULL, return 0);
446 PED_ASSERT (pth_raw != NULL, return 0);
447
448 if (ped_device_read(dev, pth_raw, 1, GPT_HEADER_SECTORS)
449 || ped_device_read(dev, pth_raw, dev->length - 1, GPT_HEADER_SECTORS)) {
450 gpt = pth_new_from_raw (dev, pth_raw);
451 if (gpt->Signature == PED_CPU_TO_LE64(GPT_HEADER_SIGNATURE))
452 gpt_sig_found = 1;
453 }
454
455 ped_free (pth_raw);
456
457 if (gpt)
458 pth_free (gpt);
459
460
461 if (!gpt_sig_found)
462 return 0;
463
464 if (ped_device_read(dev, &legacy_mbr, 0, GPT_HEADER_SECTORS)) {
465 if (!_pmbr_is_valid (&legacy_mbr)) {
466 int ex_status = ped_exception_throw (
467 PED_EXCEPTION_WARNING,
468 PED_EXCEPTION_YES_NO,
469 _("%s contains GPT signatures, indicating that it has "
470 "a GPT table. However, it does not have a valid "
471 "fake msdos partition table, as it should. Perhaps "
472 "it was corrupted -- possibly by a program that "
473 "doesn't understand GPT partition tables. Or "
474 "perhaps you deleted the GPT table, and are now "
475 "using an msdos partition table. Is this a GPT "
476 "partition table?"),
477 dev->path);
478 if (ex_status == PED_EXCEPTION_NO)
479 return 0;
480 }
481 }
482
483 return 1;
484 }
485
486 #ifndef DISCOVER_ONLY
487 /* writes zeros to the PMBR and the primary and alternate GPTHs and PTEs */
488 static int
gpt_clobber(PedDevice * dev)489 gpt_clobber(PedDevice * dev)
490 {
491 LegacyMBR_t pmbr;
492 uint8_t* zeroed_pth_raw = ped_malloc (pth_get_size (dev));
493 uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
494 GuidPartitionTableHeader_t* gpt;
495
496 PED_ASSERT (dev != NULL, return 0);
497
498 memset(&pmbr, 0, sizeof(pmbr));
499 memset(zeroed_pth_raw, 0, pth_get_size (dev));
500
501 /*
502 * TO DISCUSS: check whether checksum is correct?
503 * If not, we might get a wrong AlternateLBA field and destroy
504 * one sector of random data.
505 */
506 if (!ped_device_read(dev, pth_raw,
507 GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS))
508 goto error_free;
509
510 gpt = pth_new_from_raw (dev, pth_raw);
511
512 if (!ped_device_write(dev, &pmbr, GPT_PMBR_LBA, GPT_PMBR_SECTORS))
513 goto error_free_with_gpt;
514 if (!ped_device_write(dev, &zeroed_pth_raw,
515 GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS))
516 goto error_free_with_gpt;
517 if (!ped_device_write(dev, &zeroed_pth_raw, dev->length - GPT_HEADER_SECTORS,
518 GPT_HEADER_SECTORS))
519 goto error_free_with_gpt;
520
521 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA) < dev->length - 1) {
522 if (!ped_device_write(dev, gpt,
523 PED_LE64_TO_CPU (gpt->AlternateLBA),
524 GPT_HEADER_SECTORS))
525 return 0;
526 }
527
528 pth_free (gpt);
529
530 return 1;
531
532 error_free_with_gpt:
533 pth_free (gpt);
534 error_free:
535 ped_free (pth_raw);
536 ped_free (zeroed_pth_raw);
537 return 0;
538 }
539 #endif /* !DISCOVER_ONLY */
540
541 static PedDisk *
gpt_alloc(const PedDevice * dev)542 gpt_alloc (const PedDevice * dev)
543 {
544 PedDisk* disk;
545 GPTDiskData *gpt_disk_data;
546 PedSector data_start, data_end;
547
548 disk = _ped_disk_alloc ((PedDevice*)dev, &gpt_disk_type);
549 if (!disk)
550 goto error;
551 disk->disk_specific = gpt_disk_data = ped_malloc (sizeof (GPTDiskData));
552 if (!disk->disk_specific)
553 goto error_free_disk;
554
555 data_start = 2 + GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
556 data_end = dev->length - 2
557 - GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
558 ped_geometry_init (&gpt_disk_data->data_area, dev, data_start,
559 data_end - data_start + 1);
560 gpt_disk_data->entry_count = GPT_DEFAULT_PARTITION_ENTRIES;
561 uuid_generate ((unsigned char*) &gpt_disk_data->uuid);
562 swap_uuid_and_efi_guid((unsigned char*)(&gpt_disk_data->uuid));
563 return disk;
564
565 error_free_disk:
566 ped_free (disk);
567 error:
568 return NULL;
569 }
570
571 static PedDisk*
gpt_duplicate(const PedDisk * disk)572 gpt_duplicate (const PedDisk* disk)
573 {
574 PedDisk* new_disk;
575 GPTDiskData* new_disk_data;
576 GPTDiskData* old_disk_data;
577
578 new_disk = ped_disk_new_fresh (disk->dev, &gpt_disk_type);
579 if (!new_disk)
580 return NULL;
581
582 old_disk_data = disk->disk_specific;
583 new_disk_data = new_disk->disk_specific;
584
585 ped_geometry_init (&new_disk_data->data_area, disk->dev,
586 old_disk_data->data_area.start,
587 old_disk_data->data_area.length);
588 new_disk_data->entry_count = old_disk_data->entry_count;
589 new_disk_data->uuid = old_disk_data->uuid;
590 return new_disk;
591 }
592
593 static void
gpt_free(PedDisk * disk)594 gpt_free(PedDisk * disk)
595 {
596 ped_disk_delete_all (disk);
597 ped_free (disk->disk_specific);
598 _ped_disk_free (disk);
599 }
600
601 static int
_header_is_valid(const PedDevice * dev,GuidPartitionTableHeader_t * gpt)602 _header_is_valid (const PedDevice* dev, GuidPartitionTableHeader_t* gpt)
603 {
604 uint32_t crc, origcrc;
605
606 if (PED_LE64_TO_CPU (gpt->Signature) != GPT_HEADER_SIGNATURE)
607 return 0;
608 /*
609 * "While the GUID Partition Table Header's size may increase
610 * in the future it cannot span more than one block on the
611 * device." EFI Specification, version 1.10, 11.2.2.1
612 */
613 if (PED_LE32_TO_CPU (gpt->HeaderSize) < pth_get_size_static (dev)
614 || PED_LE32_TO_CPU (gpt->HeaderSize) > dev->sector_size)
615 return 0;
616
617 origcrc = gpt->HeaderCRC32;
618 gpt->HeaderCRC32 = 0;
619 crc = pth_crc32 (dev, gpt);
620 gpt->HeaderCRC32 = origcrc;
621
622 return crc == PED_LE32_TO_CPU (origcrc);
623 }
624
625 static int
_read_header(const PedDevice * dev,GuidPartitionTableHeader_t ** gpt,PedSector where)626 _read_header (const PedDevice* dev, GuidPartitionTableHeader_t** gpt,
627 PedSector where)
628 {
629 uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
630
631 PED_ASSERT (dev != NULL, return 0);
632
633 if (!ped_device_read (dev, pth_raw, where, GPT_HEADER_SECTORS)) {
634 ped_free (pth_raw);
635 return 0;
636 }
637
638 *gpt = pth_new_from_raw (dev, pth_raw);
639
640 ped_free (pth_raw);
641
642 if (_header_is_valid (dev, *gpt))
643 return 1;
644
645 pth_free (*gpt);
646 return 0;
647 }
648
649 static int
_parse_header(PedDisk * disk,GuidPartitionTableHeader_t * gpt,int * update_needed)650 _parse_header (PedDisk* disk, GuidPartitionTableHeader_t* gpt,
651 int *update_needed)
652 {
653 GPTDiskData* gpt_disk_data = disk->disk_specific;
654 PedSector first_usable;
655 PedSector last_usable;
656 PedSector last_usable_if_grown, last_usable_min_default;
657 static int asked_already;
658
659 PED_ASSERT (_header_is_valid (disk->dev, gpt), return 0);
660
661 #ifndef DISCOVER_ONLY
662 if (PED_LE32_TO_CPU (gpt->Revision) > GPT_HEADER_REVISION_V1_02) {
663 if (ped_exception_throw (
664 PED_EXCEPTION_WARNING,
665 PED_EXCEPTION_IGNORE_CANCEL,
666 _("The format of the GPT partition table is version "
667 "%x, which is newer than what Parted can "
668 "recognise. Please tell us! bug-parted@gnu.org"),
669 PED_LE32_TO_CPU (gpt->Revision))
670 != PED_EXCEPTION_IGNORE)
671 return 0;
672 }
673 #endif
674
675 first_usable = PED_LE64_TO_CPU (gpt->FirstUsableLBA);
676 last_usable = PED_LE64_TO_CPU (gpt->LastUsableLBA);
677
678
679 /*
680 Need to check whether the volume has grown, the LastUsableLBA is
681 normally set to disk->dev->length - 2 - ptes_size (at least for parted
682 created volumes), where ptes_size is the number of entries *
683 size of each entry / sector size or 16k / sector size, whatever the greater.
684 If the volume has grown, offer the user the chance to use the new
685 space or continue with the current usable area. Only ask once per
686 parted invocation.
687 */
688
689 last_usable_if_grown
690 = PED_CPU_TO_LE64 (disk->dev->length - 2 -
691 ((PedSector)(PED_LE32_TO_CPU(gpt->NumberOfPartitionEntries)) *
692 (PedSector)(PED_LE32_TO_CPU(gpt->SizeOfPartitionEntry)) /
693 disk->dev->sector_size));
694
695 last_usable_min_default = disk->dev->length - 2 -
696 GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / disk->dev->sector_size;
697
698 if ( last_usable_if_grown > last_usable_min_default ) {
699
700 last_usable_if_grown = last_usable_min_default;
701 }
702
703
704 PED_ASSERT (last_usable > first_usable, return 0);
705 PED_ASSERT (last_usable <= disk->dev->length, return 0);
706
707 PED_ASSERT (last_usable_if_grown > first_usable, return 0);
708 PED_ASSERT (last_usable_if_grown <= disk->dev->length, return 0);
709
710 if ( !asked_already && last_usable < last_usable_if_grown ) {
711
712 PedExceptionOption q;
713
714 q = ped_exception_throw (PED_EXCEPTION_WARNING,
715 PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE,
716 _("Not all of the space available to %s appears "
717 "to be used, you can fix the GPT to use all of the "
718 "space (an extra %llu blocks) or continue with the "
719 "current setting? "), disk->dev->path,
720 (uint64_t)(last_usable_if_grown - last_usable));
721
722
723 if (q == PED_EXCEPTION_FIX) {
724
725 last_usable = last_usable_if_grown;
726 *update_needed = 1;
727
728 }
729 else if (q != PED_EXCEPTION_UNHANDLED ) {
730
731 asked_already = 1;
732 }
733 }
734
735 ped_geometry_init (&gpt_disk_data->data_area, disk->dev,
736 first_usable, last_usable - first_usable + 1);
737
738
739 gpt_disk_data->entry_count
740 = PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries);
741 PED_ASSERT (gpt_disk_data->entry_count > 0, return 0);
742 PED_ASSERT (gpt_disk_data->entry_count <= 8192, return 0);
743
744 gpt_disk_data->uuid = gpt->DiskGUID;
745
746 return 1;
747 }
748
749 static PedPartition*
_parse_part_entry(PedDisk * disk,GuidPartitionEntry_t * pte)750 _parse_part_entry (PedDisk* disk, GuidPartitionEntry_t* pte)
751 {
752 PedPartition* part;
753 GPTPartitionData* gpt_part_data;
754 unsigned int i;
755
756 part = ped_partition_new (disk, 0, NULL,
757 PED_LE64_TO_CPU(pte->StartingLBA),
758 PED_LE64_TO_CPU(pte->EndingLBA));
759 if (!part)
760 return NULL;
761
762 gpt_part_data = part->disk_specific;
763 gpt_part_data->type = pte->PartitionTypeGuid;
764 gpt_part_data->uuid = pte->UniquePartitionGuid;
765 for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
766 gpt_part_data->name[i] = (efi_char16_t) PED_LE16_TO_CPU(
767 (uint16_t) pte->PartitionName[i]);
768 gpt_part_data->name[i] = 0;
769
770 gpt_part_data->lvm = gpt_part_data->raid
771 = gpt_part_data->boot = gpt_part_data->hp_service
772 = gpt_part_data->hidden = gpt_part_data->msftres = 0;
773
774 if (pte->Attributes.RequiredToFunction & 0x1)
775 gpt_part_data->hidden = 1;
776
777 if (!guid_cmp (gpt_part_data->type, PARTITION_SYSTEM_GUID))
778 gpt_part_data->boot = 1;
779 else if (!guid_cmp (gpt_part_data->type, PARTITION_RAID_GUID))
780 gpt_part_data->raid = 1;
781 else if (!guid_cmp (gpt_part_data->type, PARTITION_LVM_GUID))
782 gpt_part_data->lvm = 1;
783 else if (!guid_cmp (gpt_part_data->type, PARTITION_HPSERVICE_GUID))
784 gpt_part_data->hp_service = 1;
785 else if (!guid_cmp (gpt_part_data->type, PARTITION_MSFT_RESERVED_GUID))
786 gpt_part_data->msftres = 1;
787
788 return part;
789 }
790
791 /************************************************************
792 * Intel is changing the EFI Spec. (after v1.02) to say that a
793 * disk is considered to have a GPT label only if the GPT
794 * structures are correct, and the MBR is actually a Protective
795 * MBR (has one 0xEE type partition).
796 * Problem occurs when a GPT-partitioned disk is then
797 * edited with a legacy (non-GPT-aware) application, such as
798 * fdisk (which doesn't generally erase the PGPT or AGPT).
799 * How should such a disk get handled? As a GPT disk (throwing
800 * away the fdisk changes), or as an MSDOS disk (throwing away
801 * the GPT information). Previously, I've taken the GPT-is-right,
802 * MBR is wrong, approach, to stay consistent with the EFI Spec.
803 * Intel disagrees, saying the disk should then be treated
804 * as having a msdos label, not a GPT label. If this is true,
805 * then what's the point of having an AGPT, since if the PGPT
806 * is screwed up, likely the PMBR is too, and the PMBR becomes
807 * a single point of failure.
808 * So, in the Linux kernel, I'm going to test for PMBR, and
809 * warn if it's not there, and treat the disk as MSDOS, with a note
810 * for users to use Parted to "fix up" their disk if they
811 * really want it to be considered GPT.
812 ************************************************************/
813 static int
gpt_read(PedDisk * disk)814 gpt_read (PedDisk * disk)
815 {
816 GPTDiskData *gpt_disk_data = disk->disk_specific;
817 GuidPartitionTableHeader_t* gpt;
818 GuidPartitionEntry_t* ptes;
819 int ptes_size;
820 int i;
821 #ifndef DISCOVER_ONLY
822 int write_back = 0;
823 #endif
824
825 ped_disk_delete_all (disk);
826
827 /*
828 * motivation: let the user decide about the pmbr... during
829 * ped_disk_probe(), they probably didn't get a choice...
830 */
831 if (!gpt_probe (disk->dev))
832 goto error;
833
834 if (_read_header (disk->dev, &gpt, 1)) {
835 PED_ASSERT ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
836 <= disk->dev->length - 1, goto error_free_gpt);
837 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
838 < disk->dev->length - 1) {
839 char* zeros = ped_malloc (pth_get_size (disk->dev));
840
841 #ifndef DISCOVER_ONLY
842 if (ped_exception_throw (
843 PED_EXCEPTION_ERROR,
844 PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL,
845 _("The backup GPT table is not at the end of the disk, as it "
846 "should be. This might mean that another operating system "
847 "believes the disk is smaller. Fix, by moving the backup "
848 "to the end (and removing the old backup)?"))
849 == PED_EXCEPTION_CANCEL)
850 goto error_free_gpt;
851
852 write_back = 1;
853 memset (zeros, 0, disk->dev->sector_size);
854 ped_device_write (disk->dev, zeros,
855 PED_LE64_TO_CPU (gpt->AlternateLBA),
856 1);
857 #endif /* !DISCOVER_ONLY */
858 }
859 } else { /* primary GPT *not* ok */
860 int alternate_ok = 0;
861
862 #ifndef DISCOVER_ONLY
863 write_back = 1;
864 #endif
865
866 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
867 < disk->dev->length - 1) {
868 alternate_ok = _read_header (disk->dev, &gpt,
869 PED_LE64_TO_CPU(gpt->AlternateLBA));
870 }
871 if (!alternate_ok) {
872 alternate_ok = _read_header (disk->dev, &gpt,
873 disk->dev->length - 1);
874 }
875
876 if (alternate_ok) {
877 if (ped_exception_throw (
878 PED_EXCEPTION_ERROR,
879 PED_EXCEPTION_OK_CANCEL,
880 _("The primary GPT table is corrupt, but the "
881 "backup appears OK, so that will be used."))
882 == PED_EXCEPTION_CANCEL)
883 goto error_free_gpt;
884 } else {
885 ped_exception_throw (
886 PED_EXCEPTION_ERROR,
887 PED_EXCEPTION_CANCEL,
888 _("Both the primary and backup GPT tables "
889 "are corrupt. Try making a fresh table, "
890 "and using Parted's rescue feature to "
891 "recover partitions."));
892 goto error;
893 }
894 }
895
896 if (!_parse_header (disk, gpt, &write_back))
897 goto error_free_gpt;
898
899 /*
900 * ptes_size is in bytes and must be a multiple of sector_size.
901 */
902 ptes_size = ped_round_up_to(
903 sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count,
904 disk->dev->sector_size);
905 ptes = (GuidPartitionEntry_t*) ped_malloc (ptes_size);
906
907 if (!ped_device_read (disk->dev, ptes,
908 PED_LE64_TO_CPU(gpt->PartitionEntryLBA),
909 ptes_size / disk->dev->sector_size))
910 goto error_free_ptes;
911
912 for (i = 0; i < gpt_disk_data->entry_count; i++) {
913 PedPartition* part;
914 PedConstraint* constraint_exact;
915
916 if (!guid_cmp (ptes[i].PartitionTypeGuid, UNUSED_ENTRY_GUID))
917 continue;
918
919 part = _parse_part_entry (disk, &ptes[i]);
920 if (!part)
921 goto error_delete_all;
922
923 part->fs_type = ped_file_system_probe (&part->geom);
924 part->num = i + 1;
925
926 constraint_exact = ped_constraint_exact (&part->geom);
927 if (!ped_disk_add_partition(disk, part, constraint_exact)) {
928 ped_partition_destroy (part);
929 goto error_delete_all;
930 }
931 ped_constraint_destroy (constraint_exact);
932 }
933 ped_free (ptes);
934
935 #ifndef DISCOVER_ONLY
936 if (write_back)
937 ped_disk_commit_to_dev (disk);
938 #endif
939
940 return 1;
941
942 error_delete_all:
943 ped_disk_delete_all (disk);
944 error_free_ptes:
945 ped_free (ptes);
946 error_free_gpt:
947 pth_free (gpt);
948 error:
949 return 0;
950 }
951
952 #ifndef DISCOVER_ONLY
953 /* Writes the protective MBR (to keep DOS happy) */
954 static int
_write_pmbr(PedDevice * dev)955 _write_pmbr (PedDevice * dev)
956 {
957 LegacyMBR_t pmbr;
958
959 memset(&pmbr, 0, sizeof(pmbr));
960 pmbr.Signature = PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE);
961 pmbr.PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI;
962 pmbr.PartitionRecord[0].StartSector = 1;
963 pmbr.PartitionRecord[0].EndHead = 0xFE;
964 pmbr.PartitionRecord[0].EndSector = 0xFF;
965 pmbr.PartitionRecord[0].EndTrack = 0xFF;
966 pmbr.PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32(1);
967 if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
968 pmbr.PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(0xFFFFFFFF);
969 else
970 pmbr.PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(dev->length - 1UL);
971
972 return ped_device_write (dev, &pmbr, GPT_PMBR_LBA, GPT_PMBR_SECTORS);
973 }
974
975 static void
_generate_header(const PedDisk * disk,int alternate,uint32_t ptes_crc,GuidPartitionTableHeader_t ** gpt_p)976 _generate_header (const PedDisk* disk, int alternate, uint32_t ptes_crc,
977 GuidPartitionTableHeader_t** gpt_p)
978 {
979 GPTDiskData* gpt_disk_data = disk->disk_specific;
980 GuidPartitionTableHeader_t* gpt;
981
982 *gpt_p = pth_new_zeroed (disk->dev);
983
984 gpt = *gpt_p;
985
986 gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE);
987 gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00);
988
989 /* per 1.00 spec */
990 gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev));
991 gpt->HeaderCRC32 = 0;
992 gpt->Reserved1 = 0;
993
994 if (alternate) {
995 /*
996 * ptes_size is in sectors
997 */
998 PedSector ptes_size = ped_div_round_up(
999 gpt_disk_data->entry_count *
1000 sizeof (GuidPartitionEntry_t),
1001 disk->dev->sector_size);
1002
1003 gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1004 gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
1005 gpt->PartitionEntryLBA
1006 = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_size);
1007 } else {
1008 gpt->MyLBA = PED_CPU_TO_LE64 (1);
1009 gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1010 gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
1011 }
1012
1013 gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
1014 gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
1015 gpt->DiskGUID = gpt_disk_data->uuid;
1016 gpt->NumberOfPartitionEntries
1017 = PED_CPU_TO_LE32 (gpt_disk_data->entry_count);
1018 gpt->SizeOfPartitionEntry
1019 = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t));
1020 gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32 (ptes_crc);
1021 gpt->HeaderCRC32 = PED_CPU_TO_LE32 (pth_crc32 (disk->dev, gpt));
1022 }
1023
1024 static void
_partition_generate_part_entry(PedPartition * part,GuidPartitionEntry_t * pte)1025 _partition_generate_part_entry (PedPartition* part, GuidPartitionEntry_t* pte)
1026 {
1027 GPTPartitionData* gpt_part_data = part->disk_specific;
1028 unsigned int i;
1029
1030 PED_ASSERT (gpt_part_data != NULL, return);
1031
1032 pte->PartitionTypeGuid = gpt_part_data->type;
1033 pte->UniquePartitionGuid = gpt_part_data->uuid;
1034 pte->StartingLBA = PED_CPU_TO_LE64(part->geom.start);
1035 pte->EndingLBA = PED_CPU_TO_LE64(part->geom.end);
1036 memset (&pte->Attributes, 0, sizeof (GuidPartitionEntryAttributes_t));
1037
1038 if (gpt_part_data->hidden)
1039 pte->Attributes.RequiredToFunction = 1;
1040
1041 for (i = 0; i < 72 / sizeof(efi_char16_t); i++)
1042 pte->PartitionName[i]
1043 = (efi_char16_t) PED_CPU_TO_LE16(
1044 (uint16_t) gpt_part_data->name[i]);
1045 }
1046
1047 static int
gpt_write(const PedDisk * disk)1048 gpt_write(const PedDisk * disk)
1049 {
1050 GPTDiskData* gpt_disk_data;
1051 GuidPartitionEntry_t* ptes;
1052 uint32_t ptes_crc;
1053 uint8_t* pth_raw = ped_malloc (pth_get_size (disk->dev));
1054 GuidPartitionTableHeader_t* gpt;
1055 PedPartition* part;
1056 int ptes_size;
1057
1058 PED_ASSERT (disk != NULL, goto error);
1059 PED_ASSERT (disk->dev != NULL, goto error);
1060 PED_ASSERT (disk->disk_specific != NULL, goto error);
1061
1062 gpt_disk_data = disk->disk_specific;
1063
1064 /*
1065 * ptes_size is in bytes and must be a multiple of sector_size.
1066 */
1067 ptes_size = ped_round_up_to(
1068 sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count,
1069 disk->dev->sector_size);
1070 ptes = (GuidPartitionEntry_t*) ped_malloc (ptes_size);
1071 if (!ptes)
1072 goto error;
1073 memset (ptes, 0, ptes_size);
1074 for (part = ped_disk_next_partition (disk, NULL); part;
1075 part = ped_disk_next_partition (disk, part)) {
1076 if (part->type != 0)
1077 continue;
1078 _partition_generate_part_entry (part, &ptes[part->num - 1]);
1079 }
1080
1081 ptes_crc = efi_crc32 (ptes, ptes_size);
1082
1083 /* Write protective MBR */
1084 if (!_write_pmbr (disk->dev))
1085 goto error_free_ptes;
1086
1087 /* Write PTH and PTEs */
1088 _generate_header (disk, 0, ptes_crc, &gpt);
1089 pth_raw = pth_get_raw (disk->dev, gpt);
1090 if (!ped_device_write (disk->dev, pth_raw, 1, 1))
1091 goto error_free_ptes;
1092 if (!ped_device_write (disk->dev, ptes, 2, ptes_size / disk->dev->sector_size))
1093 goto error_free_ptes;
1094
1095 /* Write Alternate PTH & PTEs */
1096 _generate_header (disk, 1, ptes_crc, &gpt);
1097 pth_raw = pth_get_raw (disk->dev, gpt);
1098 if (!ped_device_write (disk->dev, pth_raw, disk->dev->length - 1, 1))
1099 goto error_free_ptes;
1100 if (!ped_device_write (disk->dev, ptes,
1101 disk->dev->length - 1 - ptes_size / disk->dev->sector_size,
1102 ptes_size / disk->dev->sector_size))
1103 goto error_free_ptes;
1104
1105 ped_free (ptes);
1106 return ped_device_sync (disk->dev);
1107
1108 error_free_ptes:
1109 ped_free (ptes);
1110 error:
1111 return 0;
1112 }
1113 #endif /* !DISCOVER_ONLY */
1114
1115 static int
add_metadata_part(PedDisk * disk,PedSector start,PedSector length)1116 add_metadata_part(PedDisk * disk, PedSector start, PedSector length)
1117 {
1118 PedPartition* part;
1119 PedConstraint* constraint_exact;
1120 PED_ASSERT(disk != NULL, return 0);
1121
1122 part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1123 start, start + length - 1);
1124 if (!part)
1125 goto error;
1126
1127 constraint_exact = ped_constraint_exact (&part->geom);
1128 if (!ped_disk_add_partition (disk, part, constraint_exact))
1129 goto error_destroy_constraint;
1130 ped_constraint_destroy (constraint_exact);
1131 return 1;
1132
1133 error_destroy_constraint:
1134 ped_constraint_destroy (constraint_exact);
1135 ped_partition_destroy (part);
1136 error:
1137 return 0;
1138 }
1139
1140 static PedPartition*
gpt_partition_new(const PedDisk * disk,PedPartitionType part_type,const PedFileSystemType * fs_type,PedSector start,PedSector end)1141 gpt_partition_new (const PedDisk* disk,
1142 PedPartitionType part_type, const PedFileSystemType* fs_type,
1143 PedSector start, PedSector end)
1144 {
1145 PedPartition* part;
1146 GPTPartitionData* gpt_part_data;
1147
1148 part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1149 if (!part)
1150 goto error;
1151
1152 if (part_type != 0)
1153 return part;
1154
1155 gpt_part_data = part->disk_specific =
1156 ped_malloc (sizeof (GPTPartitionData));
1157 if (!gpt_part_data)
1158 goto error_free_part;
1159
1160 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1161 gpt_part_data->lvm = 0;
1162 gpt_part_data->raid = 0;
1163 gpt_part_data->boot = 0;
1164 gpt_part_data->hp_service = 0;
1165 gpt_part_data->hidden = 0;
1166 gpt_part_data->msftres = 0;
1167 uuid_generate ((unsigned char*) &gpt_part_data->uuid);
1168 swap_uuid_and_efi_guid((unsigned char*)(&gpt_part_data->uuid));
1169 strcpy (gpt_part_data->name, "");
1170 return part;
1171
1172 error_free_part:
1173 _ped_partition_free (part);
1174 error:
1175 return NULL;
1176 }
1177
1178 static PedPartition*
gpt_partition_duplicate(const PedPartition * part)1179 gpt_partition_duplicate (const PedPartition* part)
1180 {
1181 PedPartition* result;
1182 GPTPartitionData* part_data = part->disk_specific;
1183 GPTPartitionData* result_data;
1184
1185 result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
1186 part->geom.start, part->geom.end);
1187 if (!result)
1188 goto error;
1189 result->num = part->num;
1190
1191 if (result->type != 0)
1192 return result;
1193
1194 result_data = result->disk_specific =
1195 ped_malloc (sizeof (GPTPartitionData));
1196 if (!result_data)
1197 goto error_free_part;
1198
1199 result_data->type = part_data->type;
1200 result_data->uuid = part_data->uuid;
1201 strcpy (result_data->name, part_data->name);
1202 return result;
1203
1204 error_free_part:
1205 _ped_partition_free (result);
1206 error:
1207 return NULL;
1208 }
1209
1210 static void
gpt_partition_destroy(PedPartition * part)1211 gpt_partition_destroy (PedPartition *part)
1212 {
1213 if (part->type == 0) {
1214 PED_ASSERT (part->disk_specific != NULL, return);
1215 ped_free (part->disk_specific);
1216 }
1217
1218 _ped_partition_free (part);
1219 }
1220
1221 static int
gpt_partition_set_system(PedPartition * part,const PedFileSystemType * fs_type)1222 gpt_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
1223 {
1224 GPTPartitionData* gpt_part_data = part->disk_specific;
1225
1226 PED_ASSERT (gpt_part_data != NULL, return 0);
1227
1228 part->fs_type = fs_type;
1229
1230 if (gpt_part_data->lvm) {
1231 gpt_part_data->type = PARTITION_LVM_GUID;
1232 return 1;
1233 }
1234 if (gpt_part_data->raid) {
1235 gpt_part_data->type = PARTITION_RAID_GUID;
1236 return 1;
1237 }
1238 if (gpt_part_data->boot) {
1239 gpt_part_data->type = PARTITION_SYSTEM_GUID;
1240 return 1;
1241 }
1242 if (gpt_part_data->hp_service) {
1243 gpt_part_data->type = PARTITION_HPSERVICE_GUID;
1244 return 1;
1245 }
1246 if (gpt_part_data->msftres) {
1247 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1248 return 1;
1249 }
1250
1251 if (fs_type) {
1252 if (strncmp (fs_type->name, "fat", 3) == 0
1253 || strcmp (fs_type->name, "ntfs") == 0) {
1254 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1255 return 1;
1256 }
1257 if (strncmp (fs_type->name, "hfs", 3) == 0) {
1258 gpt_part_data->type = PARTITION_APPLE_HFS_GUID;
1259 return 1;
1260 }
1261 if (strstr (fs_type->name, "swap")) {
1262 gpt_part_data->type = PARTITION_SWAP_GUID;
1263 return 1;
1264 }
1265 }
1266
1267 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1268 return 1;
1269 }
1270
1271 /* Allocate metadata partitions for the GPTH and PTES */
1272 static int
gpt_alloc_metadata(PedDisk * disk)1273 gpt_alloc_metadata (PedDisk * disk)
1274 {
1275 PedSector gptlength, pteslength = 0;
1276 GPTDiskData *gpt_disk_data;
1277
1278 PED_ASSERT(disk != NULL, return 0);
1279 PED_ASSERT(disk->dev != NULL, return 0);
1280 PED_ASSERT(disk->disk_specific != NULL, return 0);
1281 gpt_disk_data = disk->disk_specific;
1282
1283 gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t),
1284 disk->dev->sector_size);
1285 pteslength = ped_div_round_up (gpt_disk_data->entry_count
1286 * sizeof (GuidPartitionEntry_t), disk->dev->sector_size);
1287
1288 /* metadata at the start of the disk includes the MBR */
1289 if (!add_metadata_part(disk, GPT_PMBR_LBA,
1290 GPT_PMBR_SECTORS + gptlength + pteslength))
1291 return 0;
1292
1293 /* metadata at the end of the disk */
1294 if (!add_metadata_part(disk, disk->dev->length - gptlength - pteslength,
1295 gptlength + pteslength))
1296 return 0;
1297
1298 return 1;
1299 }
1300
1301 /* Does nothing, as the read/new/destroy functions maintain part->num */
1302 static int
gpt_partition_enumerate(PedPartition * part)1303 gpt_partition_enumerate (PedPartition* part)
1304 {
1305 GPTDiskData* gpt_disk_data = part->disk->disk_specific;
1306 int i;
1307
1308 /* never change the partition numbers */
1309 if (part->num != -1)
1310 return 1;
1311
1312 for (i = 1; i <= gpt_disk_data->entry_count; i++) {
1313 if (!ped_disk_get_partition (part->disk, i)) {
1314 part->num = i;
1315 return 1;
1316 }
1317 }
1318
1319 PED_ASSERT (0, return 0);
1320
1321 return 0; /* used if debug is disabled */
1322 }
1323
1324 static int
gpt_partition_set_flag(PedPartition * part,PedPartitionFlag flag,int state)1325 gpt_partition_set_flag(PedPartition *part,
1326 PedPartitionFlag flag,
1327 int state)
1328 {
1329 GPTPartitionData *gpt_part_data;
1330 PED_ASSERT(part != NULL, return 0);
1331 PED_ASSERT(part->disk_specific != NULL, return 0);
1332 gpt_part_data = part->disk_specific;
1333
1334 switch (flag) {
1335 case PED_PARTITION_BOOT:
1336 gpt_part_data->boot = state;
1337 if (state)
1338 gpt_part_data->raid
1339 = gpt_part_data->lvm
1340 = gpt_part_data->hp_service
1341 = gpt_part_data->msftres = 0;
1342 return gpt_partition_set_system (part, part->fs_type);
1343 case PED_PARTITION_RAID:
1344 gpt_part_data->raid = state;
1345 if (state)
1346 gpt_part_data->boot
1347 = gpt_part_data->lvm
1348 = gpt_part_data->hp_service
1349 = gpt_part_data->msftres = 0;
1350 return gpt_partition_set_system (part, part->fs_type);
1351 case PED_PARTITION_LVM:
1352 gpt_part_data->lvm = state;
1353 if (state)
1354 gpt_part_data->boot
1355 = gpt_part_data->raid
1356 = gpt_part_data->hp_service
1357 = gpt_part_data->msftres = 0;
1358 return gpt_partition_set_system (part, part->fs_type);
1359 case PED_PARTITION_HPSERVICE:
1360 gpt_part_data->hp_service = state;
1361 if (state)
1362 gpt_part_data->boot
1363 = gpt_part_data->raid
1364 = gpt_part_data->lvm
1365 = gpt_part_data->msftres = 0;
1366 return gpt_partition_set_system (part, part->fs_type);
1367 case PED_PARTITION_MSFT_RESERVED:
1368 gpt_part_data->msftres = state;
1369 if (state)
1370 gpt_part_data->boot
1371 = gpt_part_data->raid
1372 = gpt_part_data->lvm
1373 = gpt_part_data->hp_service = 0;
1374 return gpt_partition_set_system (part, part->fs_type);
1375 case PED_PARTITION_HIDDEN:
1376 gpt_part_data->hidden = state;
1377 return 1;
1378 case PED_PARTITION_SWAP:
1379 case PED_PARTITION_ROOT:
1380 case PED_PARTITION_LBA:
1381 default:
1382 return 0;
1383 }
1384 return 1;
1385 }
1386
1387 static int
gpt_partition_get_flag(const PedPartition * part,PedPartitionFlag flag)1388 gpt_partition_get_flag(const PedPartition *part, PedPartitionFlag flag)
1389 {
1390 GPTPartitionData *gpt_part_data;
1391 PED_ASSERT(part->disk_specific != NULL, return 0);
1392 gpt_part_data = part->disk_specific;
1393
1394 switch (flag) {
1395 case PED_PARTITION_RAID:
1396 return gpt_part_data->raid;
1397 case PED_PARTITION_LVM:
1398 return gpt_part_data->lvm;
1399 case PED_PARTITION_BOOT:
1400 return gpt_part_data->boot;
1401 case PED_PARTITION_HPSERVICE:
1402 return gpt_part_data->hp_service;
1403 case PED_PARTITION_MSFT_RESERVED:
1404 return gpt_part_data->msftres;
1405 case PED_PARTITION_HIDDEN:
1406 return gpt_part_data->hidden;
1407 case PED_PARTITION_SWAP:
1408 case PED_PARTITION_LBA:
1409 case PED_PARTITION_ROOT:
1410 default:
1411 return 0;
1412 }
1413 return 0;
1414 }
1415
1416 static int
gpt_partition_is_flag_available(const PedPartition * part,PedPartitionFlag flag)1417 gpt_partition_is_flag_available(const PedPartition * part,
1418 PedPartitionFlag flag)
1419 {
1420 switch (flag) {
1421 case PED_PARTITION_RAID:
1422 case PED_PARTITION_LVM:
1423 case PED_PARTITION_BOOT:
1424 case PED_PARTITION_HPSERVICE:
1425 case PED_PARTITION_MSFT_RESERVED:
1426 case PED_PARTITION_HIDDEN:
1427 return 1;
1428 case PED_PARTITION_SWAP:
1429 case PED_PARTITION_ROOT:
1430 case PED_PARTITION_LBA:
1431 default:
1432 return 0;
1433 }
1434 return 0;
1435 }
1436
1437 static void
gpt_partition_set_name(PedPartition * part,const char * name)1438 gpt_partition_set_name (PedPartition *part, const char *name)
1439 {
1440 GPTPartitionData *gpt_part_data = part->disk_specific;
1441
1442 strncpy (gpt_part_data->name, name, 36);
1443 gpt_part_data->name [36] = 0;
1444 }
1445
1446 static const char *
gpt_partition_get_name(const PedPartition * part)1447 gpt_partition_get_name (const PedPartition * part)
1448 {
1449 GPTPartitionData* gpt_part_data = part->disk_specific;
1450 return gpt_part_data->name;
1451 }
1452
1453 static int
gpt_get_max_primary_partition_count(const PedDisk * disk)1454 gpt_get_max_primary_partition_count (const PedDisk *disk)
1455 {
1456 const GPTDiskData* gpt_disk_data = disk->disk_specific;
1457 return gpt_disk_data->entry_count;
1458 }
1459
1460 static PedConstraint*
_non_metadata_constraint(const PedDisk * disk)1461 _non_metadata_constraint (const PedDisk* disk)
1462 {
1463 GPTDiskData* gpt_disk_data = disk->disk_specific;
1464
1465 return ped_constraint_new_from_max (&gpt_disk_data->data_area);
1466 }
1467
1468 static int
gpt_partition_align(PedPartition * part,const PedConstraint * constraint)1469 gpt_partition_align (PedPartition* part, const PedConstraint* constraint)
1470 {
1471 PED_ASSERT (part != NULL, return 0);
1472
1473 if (_ped_partition_attempt_align (part, constraint,
1474 _non_metadata_constraint (part->disk)))
1475 return 1;
1476
1477 #ifndef DISCOVER_ONLY
1478 ped_exception_throw (
1479 PED_EXCEPTION_ERROR,
1480 PED_EXCEPTION_CANCEL,
1481 _("Unable to satisfy all constraints on the partition."));
1482 #endif
1483 return 0;
1484 }
1485
1486 static PedDiskOps gpt_disk_ops = {
1487 .probe = gpt_probe,
1488 #ifndef DISCOVER_ONLY
1489 .clobber = gpt_clobber,
1490 #else
1491 .clobber = NULL,
1492 #endif
1493 .alloc = gpt_alloc,
1494 .duplicate = gpt_duplicate,
1495 .free = gpt_free,
1496 .read = gpt_read,
1497 #ifndef DISCOVER_ONLY
1498 .write = gpt_write,
1499 #else
1500 .write = NULL,
1501 #endif
1502
1503 .partition_new = gpt_partition_new,
1504 .partition_duplicate = gpt_partition_duplicate,
1505 .partition_destroy = gpt_partition_destroy,
1506 .partition_set_system = gpt_partition_set_system,
1507 .partition_set_flag = gpt_partition_set_flag,
1508 .partition_get_flag = gpt_partition_get_flag,
1509 .partition_is_flag_available = gpt_partition_is_flag_available,
1510 .partition_set_name = gpt_partition_set_name,
1511 .partition_get_name = gpt_partition_get_name,
1512 .partition_align = gpt_partition_align,
1513 .partition_enumerate = gpt_partition_enumerate,
1514 .alloc_metadata = gpt_alloc_metadata,
1515 .get_max_primary_partition_count = gpt_get_max_primary_partition_count
1516 };
1517
1518 static PedDiskType gpt_disk_type = {
1519 .next = NULL,
1520 .name = "gpt",
1521 .ops = &gpt_disk_ops,
1522 .features = PED_DISK_TYPE_PARTITION_NAME
1523 };
1524
1525 void
ped_disk_gpt_init()1526 ped_disk_gpt_init()
1527 {
1528 PED_ASSERT (sizeof (GuidPartitionEntryAttributes_t) == 8, return);
1529 PED_ASSERT (sizeof (GuidPartitionEntry_t) == 128, return);
1530
1531 ped_disk_type_register (&gpt_disk_type);
1532 }
1533
1534 void
ped_disk_gpt_done()1535 ped_disk_gpt_done()
1536 {
1537 ped_disk_type_unregister (&gpt_disk_type);
1538 }
1539