2 libparted - a library for manipulating disk partitions
4 original version by Matt Domsch <Matt_Domsch@dell.com>
5 Disclaimed into the Public Domain
7 Portions Copyright (C) 2001-2003, 2005-2009 Free Software Foundation, Inc.
9 EFI GUID Partition Table handling
10 Per Intel EFI Specification v1.02
11 http://developer.intel.com/technology/efi/efi.htm
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 3 of the License, or
16 (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
29 #include <parted/parted.h>
30 #include <parted/debug.h>
31 #include <parted/endian.h>
32 #include <parted/crc32.h>
35 #include <sys/types.h>
36 #include <sys/ioctl.h>
39 #include <uuid/uuid.h>
47 # define _(String) gettext (String)
49 # define _(String) (String)
50 #endif /* ENABLE_NLS */
52 #define EFI_PMBR_OSTYPE_EFI 0xEE
53 #define MSDOS_MBR_SIGNATURE 0xaa55
55 #define GPT_HEADER_SIGNATURE 0x5452415020494645LL
57 /* NOTE: the document that describes revision 1.00 is labelled "version 1.02",
58 * so some implementors got confused...
60 #define GPT_HEADER_REVISION_V1_02 0x00010200
61 #define GPT_HEADER_REVISION_V1_00 0x00010000
62 #define GPT_HEADER_REVISION_V0_99 0x00009900
64 typedef uint16_t efi_char16_t; /* UNICODE character */
65 typedef struct _GuidPartitionTableHeader_t GuidPartitionTableHeader_t;
66 typedef struct _GuidPartitionEntryAttributes_t GuidPartitionEntryAttributes_t;
67 typedef struct _GuidPartitionEntry_t GuidPartitionEntry_t;
68 typedef struct _PartitionRecord_t PartitionRecord_t;
69 typedef struct _LegacyMBR_t LegacyMBR_t;
70 typedef struct _GPTDiskData GPTDiskData;
75 uint16_t time_hi_and_version;
76 uint8_t clock_seq_hi_and_reserved;
77 uint8_t clock_seq_low;
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
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 PARTITION_BIOS_GRUB_GUID \
94 ((efi_guid_t) { PED_CPU_TO_LE32 (0x21686148), PED_CPU_TO_LE16 (0x6449), \
95 PED_CPU_TO_LE16 (0x6E6f), 0x74, 0x4E, \
96 { 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 }})
97 #define LEGACY_MBR_PARTITION_GUID \
98 ((efi_guid_t) { PED_CPU_TO_LE32 (0x024DEE41), PED_CPU_TO_LE16 (0x33E7), \
99 PED_CPU_TO_LE16 (0x11d3, 0x9D, 0x69, \
100 { 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }})
101 #define PARTITION_MSFT_RESERVED_GUID \
102 ((efi_guid_t) { PED_CPU_TO_LE32 (0xE3C9E316), PED_CPU_TO_LE16 (0x0B5C), \
103 PED_CPU_TO_LE16 (0x4DB8), 0x81, 0x7D, \
104 { 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE }})
105 #define PARTITION_BASIC_DATA_GUID \
106 ((efi_guid_t) { PED_CPU_TO_LE32 (0xEBD0A0A2), PED_CPU_TO_LE16 (0xB9E5), \
107 PED_CPU_TO_LE16 (0x4433), 0x87, 0xC0, \
108 { 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }})
109 #define PARTITION_RAID_GUID \
110 ((efi_guid_t) { PED_CPU_TO_LE32 (0xa19d880f), PED_CPU_TO_LE16 (0x05fc), \
111 PED_CPU_TO_LE16 (0x4d3b), 0xa0, 0x06, \
112 { 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e }})
113 #define PARTITION_SWAP_GUID \
114 ((efi_guid_t) { PED_CPU_TO_LE32 (0x0657fd6d), PED_CPU_TO_LE16 (0xa4ab), \
115 PED_CPU_TO_LE16 (0x43c4), 0x84, 0xe5, \
116 { 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f }})
117 #define PARTITION_LVM_GUID \
118 ((efi_guid_t) { PED_CPU_TO_LE32 (0xe6d6d379), PED_CPU_TO_LE16 (0xf507), \
119 PED_CPU_TO_LE16 (0x44c2), 0xa2, 0x3c, \
120 { 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 }})
121 #define PARTITION_RESERVED_GUID \
122 ((efi_guid_t) { PED_CPU_TO_LE32 (0x8da63339), PED_CPU_TO_LE16 (0x0007), \
123 PED_CPU_TO_LE16 (0x60c0), 0xc4, 0x36, \
124 { 0x08, 0x3a, 0xc8, 0x23, 0x09, 0x08 }})
125 #define PARTITION_HPSERVICE_GUID \
126 ((efi_guid_t) { PED_CPU_TO_LE32 (0xe2a1e728), PED_CPU_TO_LE16 (0x32e3), \
127 PED_CPU_TO_LE16 (0x11d6), 0xa6, 0x82, \
128 { 0x7b, 0x03, 0xa0, 0x00, 0x00, 0x00 }})
129 #define PARTITION_APPLE_HFS_GUID \
130 ((efi_guid_t) { PED_CPU_TO_LE32 (0x48465300), PED_CPU_TO_LE16 (0x0000), \
131 PED_CPU_TO_LE16 (0x11AA), 0xaa, 0x11, \
132 { 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC }})
134 struct __attribute__ ((packed)) _GuidPartitionTableHeader_t
139 uint32_t HeaderCRC32;
142 uint64_t AlternateLBA;
143 uint64_t FirstUsableLBA;
144 uint64_t LastUsableLBA;
146 uint64_t PartitionEntryLBA;
147 uint32_t NumberOfPartitionEntries;
148 uint32_t SizeOfPartitionEntry;
149 uint32_t PartitionEntryArrayCRC32;
153 struct __attribute__ ((packed)) _GuidPartitionEntryAttributes_t
155 #ifdef __GNUC__ /* XXX narrow this down to !TinyCC */
156 uint64_t RequiredToFunction:1;
157 uint64_t Reserved:47;
158 uint64_t GuidSpecific:16;
160 # warning "Using crippled partition entry type"
161 uint32_t RequiredToFunction:1;
162 uint32_t Reserved:32;
164 uint32_t GuidSpecific:16;
168 struct __attribute__ ((packed)) _GuidPartitionEntry_t
170 efi_guid_t PartitionTypeGuid;
171 efi_guid_t UniquePartitionGuid;
172 uint64_t StartingLBA;
174 GuidPartitionEntryAttributes_t Attributes;
175 efi_char16_t PartitionName[72 / sizeof (efi_char16_t)];
178 #define GPT_PMBR_LBA 0
179 #define GPT_PMBR_SECTORS 1
180 #define GPT_PRIMARY_HEADER_LBA 1
181 #define GPT_HEADER_SECTORS 1
182 #define GPT_PRIMARY_PART_TABLE_LBA 2
185 These values are only defaults. The actual on-disk structures
186 may define different sizes, so use those unless creating a new GPT disk!
189 #define GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE 16384
191 /* Number of actual partition entries should be calculated as: */
192 #define GPT_DEFAULT_PARTITION_ENTRIES \
193 (GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / \
194 sizeof(GuidPartitionEntry_t))
196 struct __attribute__ ((packed)) _PartitionRecord_t
198 /* Not used by EFI firmware. Set to 0x80 to indicate that this
199 is the bootable legacy partition. */
200 uint8_t BootIndicator;
202 /* Start of partition in CHS address, not used by EFI firmware. */
205 /* Start of partition in CHS address, not used by EFI firmware. */
208 /* Start of partition in CHS address, not used by EFI firmware. */
211 /* OS type. A value of 0xEF defines an EFI system partition.
212 Other values are reserved for legacy operating systems, and
213 allocated independently of the EFI specification. */
216 /* End of partition in CHS address, not used by EFI firmware. */
219 /* End of partition in CHS address, not used by EFI firmware. */
222 /* End of partition in CHS address, not used by EFI firmware. */
225 /* Starting LBA address of the partition on the disk. Used by
226 EFI firmware to define the start of the partition. */
227 uint32_t StartingLBA;
229 /* Size of partition in LBA. Used by EFI firmware to determine
230 the size of the partition. */
234 /* Protected Master Boot Record & Legacy MBR share same structure */
235 /* Needs to be packed because the u16s force misalignment. */
236 struct __attribute__ ((packed)) _LegacyMBR_t
238 uint8_t BootCode[440];
239 uint32_t UniqueMBRSignature;
241 PartitionRecord_t PartitionRecord[4];
245 /* uses libparted's disk_specific field in PedDisk, to store our info */
246 struct __attribute__ ((packed)) _GPTDiskData
248 PedGeometry data_area;
253 /* uses libparted's disk_specific field in PedPartition, to store our info */
254 typedef struct _GPTPartitionData
268 static PedDiskType gpt_disk_type;
270 static inline uint32_t
271 pth_get_size (const PedDevice *dev)
273 return GPT_HEADER_SECTORS * dev->sector_size;
276 static inline uint32_t
277 pth_get_size_static (const PedDevice *dev)
279 return sizeof (GuidPartitionTableHeader_t) - sizeof (uint8_t *);
282 static inline uint32_t
283 pth_get_size_rsv2 (const PedDevice *dev)
285 return pth_get_size (dev) - pth_get_size_static (dev);
288 static GuidPartitionTableHeader_t *
289 pth_new (const PedDevice *dev)
291 GuidPartitionTableHeader_t *pth =
292 ped_malloc (sizeof (GuidPartitionTableHeader_t) + sizeof (uint8_t));
294 pth->Reserved2 = ped_malloc (pth_get_size_rsv2 (dev));
299 static GuidPartitionTableHeader_t *
300 pth_new_zeroed (const PedDevice *dev)
302 GuidPartitionTableHeader_t *pth = pth_new (dev);
304 memset (pth, 0, pth_get_size_static (dev));
305 memset (pth->Reserved2, 0, pth_get_size_rsv2 (dev));
310 static GuidPartitionTableHeader_t *
311 pth_new_from_raw (const PedDevice *dev, const uint8_t *pth_raw)
313 GuidPartitionTableHeader_t *pth = pth_new (dev);
315 PED_ASSERT (pth_raw != NULL, return 0);
317 memcpy (pth, pth_raw, pth_get_size_static (dev));
318 memcpy (pth->Reserved2, pth_raw + pth_get_size_static (dev),
319 pth_get_size_rsv2 (dev));
325 pth_free (GuidPartitionTableHeader_t *pth)
329 PED_ASSERT (pth->Reserved2 != NULL, return);
331 free (pth->Reserved2);
336 pth_get_raw (const PedDevice *dev, const GuidPartitionTableHeader_t *pth)
338 uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
339 int size_static = pth_get_size_static (dev);
341 PED_ASSERT (pth != NULL, return 0);
342 PED_ASSERT (pth->Reserved2 != NULL, return 0);
344 memcpy (pth_raw, pth, size_static);
345 memcpy (pth_raw + size_static, pth->Reserved2, pth_get_size_rsv2 (dev));
351 * swap_uuid_and_efi_guid() - converts between uuid formats
352 * @uuid - uuid_t in either format (converts it to the other)
354 * There are two different representations for Globally Unique Identifiers
357 * The RFC specifies a UUID as a string of 16 bytes, essentially
358 * a big-endian array of char.
359 * Intel, in their EFI Specification, references the same RFC, but
360 * then defines a GUID as a structure of little-endian fields.
361 * Coincidentally, both structures have the same format when unparsed.
363 * When read from disk, EFI GUIDs are in struct of little endian format,
364 * and need to be converted to be treated as uuid_t in memory.
366 * When writing to disk, uuid_ts need to be converted into EFI GUIDs.
371 swap_uuid_and_efi_guid (uuid_t uuid)
373 efi_guid_t *guid = (efi_guid_t *) uuid;
375 PED_ASSERT (uuid != NULL, return);
376 guid->time_low = PED_SWAP32 (guid->time_low);
377 guid->time_mid = PED_SWAP16 (guid->time_mid);
378 guid->time_hi_and_version = PED_SWAP16 (guid->time_hi_and_version);
381 /* returns the EFI-style CRC32 value for buf
382 * This function uses the crc32 function by Gary S. Brown,
383 * but seeds the function with ~0, and xor's with ~0 at the end.
385 static inline uint32_t
386 efi_crc32 (const void *buf, unsigned long len)
388 return (__efi_crc32 (buf, len, ~0L) ^ ~0L);
391 static inline uint32_t
392 pth_crc32 (const PedDevice *dev, const GuidPartitionTableHeader_t *pth)
394 uint8_t *pth_raw = pth_get_raw (dev, pth);
396 PED_ASSERT (dev != NULL, return 0);
397 PED_ASSERT (pth != NULL, return 0);
399 uint32_t crc32 = efi_crc32 (pth_raw, PED_LE32_TO_CPU (pth->HeaderSize));
407 guid_cmp (efi_guid_t left, efi_guid_t right)
409 return memcmp (&left, &right, sizeof (efi_guid_t));
412 /* checks if 'mbr' is a protective MBR partition table */
414 _pmbr_is_valid (const LegacyMBR_t *mbr)
418 PED_ASSERT (mbr != NULL, return 0);
420 if (mbr->Signature != PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE))
422 for (i = 0; i < 4; i++)
424 if (mbr->PartitionRecord[i].OSType == EFI_PMBR_OSTYPE_EFI)
431 gpt_probe (const PedDevice *dev)
433 GuidPartitionTableHeader_t *gpt = NULL;
434 uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
435 int gpt_sig_found = 0;
437 PED_ASSERT (dev != NULL, return 0);
439 if (ped_device_read (dev, pth_raw, 1, GPT_HEADER_SECTORS)
440 || ped_device_read (dev, pth_raw, dev->length - 1, GPT_HEADER_SECTORS))
442 gpt = pth_new_from_raw (dev, pth_raw);
443 if (gpt->Signature == PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE))
455 if (!ptt_read_sector (dev, 0, &label))
459 if (!_pmbr_is_valid ((const LegacyMBR_t *) label))
461 int ex_status = ped_exception_throw
462 (PED_EXCEPTION_WARNING,
463 PED_EXCEPTION_YES_NO,
464 _("%s contains GPT signatures, indicating that it has "
465 "a GPT table. However, it does not have a valid "
466 "fake msdos partition table, as it should. Perhaps "
467 "it was corrupted -- possibly by a program that "
468 "doesn't understand GPT partition tables. Or "
469 "perhaps you deleted the GPT table, and are now "
470 "using an msdos partition table. Is this a GPT "
473 if (ex_status == PED_EXCEPTION_NO)
481 #ifndef DISCOVER_ONLY
482 /* writes zeros to the PMBR and the primary and alternate GPTHs and PTEs */
484 gpt_clobber (PedDevice *dev)
486 uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
487 GuidPartitionTableHeader_t *gpt;
489 PED_ASSERT (dev != NULL, return 0);
492 * TO DISCUSS: check whether checksum is correct?
493 * If not, we might get a wrong AlternateLBA field and destroy
494 * one sector of random data.
496 if (!ped_device_read (dev, pth_raw,
497 GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS))
503 gpt = pth_new_from_raw (dev, pth_raw);
506 if (!ptt_clear_sectors (dev, GPT_PMBR_LBA, GPT_PMBR_SECTORS))
507 goto error_free_with_gpt;
508 if (!ptt_clear_sectors (dev, GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS))
509 goto error_free_with_gpt;
510 if (!ptt_clear_sectors (dev, dev->length - GPT_HEADER_SECTORS,
512 goto error_free_with_gpt;
514 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA) < dev->length - 1)
516 if (!ped_device_write (dev, gpt,
517 PED_LE64_TO_CPU (gpt->AlternateLBA),
530 #endif /* !DISCOVER_ONLY */
533 gpt_alloc (const PedDevice *dev)
536 GPTDiskData *gpt_disk_data;
537 PedSector data_start, data_end;
539 disk = _ped_disk_alloc ((PedDevice *) dev, &gpt_disk_type);
542 disk->disk_specific = gpt_disk_data = ped_malloc (sizeof (GPTDiskData));
543 if (!disk->disk_specific)
544 goto error_free_disk;
546 data_start = 2 + GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
547 data_end = dev->length - 2
548 - GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
549 ped_geometry_init (&gpt_disk_data->data_area, dev, data_start,
550 data_end - data_start + 1);
551 gpt_disk_data->entry_count = GPT_DEFAULT_PARTITION_ENTRIES;
552 uuid_generate ((unsigned char *) &gpt_disk_data->uuid);
553 swap_uuid_and_efi_guid ((unsigned char *) (&gpt_disk_data->uuid));
563 gpt_duplicate (const PedDisk *disk)
566 GPTDiskData *new_disk_data;
567 GPTDiskData *old_disk_data;
569 new_disk = ped_disk_new_fresh (disk->dev, &gpt_disk_type);
573 old_disk_data = disk->disk_specific;
574 new_disk_data = new_disk->disk_specific;
576 ped_geometry_init (&new_disk_data->data_area, disk->dev,
577 old_disk_data->data_area.start,
578 old_disk_data->data_area.length);
579 new_disk_data->entry_count = old_disk_data->entry_count;
580 new_disk_data->uuid = old_disk_data->uuid;
585 gpt_free (PedDisk *disk)
587 ped_disk_delete_all (disk);
588 free (disk->disk_specific);
589 _ped_disk_free (disk);
593 _header_is_valid (const PedDevice *dev, GuidPartitionTableHeader_t *gpt,
596 uint32_t crc, origcrc;
598 if (PED_LE64_TO_CPU (gpt->Signature) != GPT_HEADER_SIGNATURE)
601 * "While the GUID Partition Table Header's size may increase
602 * in the future it cannot span more than one block on the
603 * device." EFI Specification, version 1.10, 11.2.2.1
605 if (PED_LE32_TO_CPU (gpt->HeaderSize) < pth_get_size_static (dev)
606 || PED_LE32_TO_CPU (gpt->HeaderSize) > dev->sector_size)
609 /* The SizeOfPartitionEntry must be a multiple of 8 and
610 no smaller than the size of the PartitionEntry structure.
611 We also require that be no larger than 1/16th of UINT32_MAX,
612 as an additional sanity check. */
613 uint32_t sope = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
615 || sope < sizeof (GuidPartitionEntry_t) || (UINT32_MAX >> 4) < sope)
618 if (PED_LE64_TO_CPU (gpt->MyLBA) != my_lba)
621 PedSector alt_lba = PED_LE64_TO_CPU (gpt->AlternateLBA);
622 /* The backup table's AlternateLBA must be 1. */
623 if (my_lba != 1 && alt_lba != 1)
626 /* The alt_lba must never be the same as my_lba. */
627 if (alt_lba == my_lba)
630 origcrc = gpt->HeaderCRC32;
631 gpt->HeaderCRC32 = 0;
632 crc = pth_crc32 (dev, gpt);
633 gpt->HeaderCRC32 = origcrc;
635 return crc == PED_LE32_TO_CPU (origcrc);
639 _parse_header (PedDisk *disk, const GuidPartitionTableHeader_t *gpt,
642 GPTDiskData *gpt_disk_data = disk->disk_specific;
643 PedSector first_usable;
644 PedSector last_usable;
645 PedSector last_usable_if_grown, last_usable_min_default;
646 static int asked_already;
648 // PED_ASSERT (_header_is_valid (disk->dev, gpt), return 0);
650 #ifndef DISCOVER_ONLY
651 if (PED_LE32_TO_CPU (gpt->Revision) > GPT_HEADER_REVISION_V1_02)
653 if (ped_exception_throw
654 (PED_EXCEPTION_WARNING,
655 PED_EXCEPTION_IGNORE_CANCEL,
656 _("The format of the GPT partition table is version "
657 "%x, which is newer than what Parted can "
658 "recognise. Please tell us! bug-parted@gnu.org"),
659 PED_LE32_TO_CPU (gpt->Revision)) != PED_EXCEPTION_IGNORE)
664 first_usable = PED_LE64_TO_CPU (gpt->FirstUsableLBA);
665 last_usable = PED_LE64_TO_CPU (gpt->LastUsableLBA);
667 /* Need to check whether the volume has grown, the LastUsableLBA is
668 normally set to disk->dev->length - 2 - ptes_size (at least for parted
669 created volumes), where ptes_size is the number of entries *
670 size of each entry / sector size or 16k / sector size, whatever the greater.
671 If the volume has grown, offer the user the chance to use the new
672 space or continue with the current usable area. Only ask once per
673 parted invocation. */
676 = (disk->dev->length - 2 -
677 ((PedSector) (PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries)) *
678 (PedSector) (PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry)) /
679 disk->dev->sector_size));
681 last_usable_min_default = disk->dev->length - 2 -
682 GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / disk->dev->sector_size;
684 if (last_usable_if_grown > last_usable_min_default)
686 last_usable_if_grown = last_usable_min_default;
689 PED_ASSERT (last_usable > first_usable, return 0);
690 PED_ASSERT (last_usable <= disk->dev->length, return 0);
692 PED_ASSERT (last_usable_if_grown > first_usable, return 0);
693 PED_ASSERT (last_usable_if_grown <= disk->dev->length, return 0);
695 if (!asked_already && last_usable < last_usable_if_grown)
698 PedExceptionOption q;
700 q = ped_exception_throw
701 (PED_EXCEPTION_WARNING,
702 PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE,
703 _("Not all of the space available to %s appears "
704 "to be used, you can fix the GPT to use all of the "
705 "space (an extra %llu blocks) or continue with the "
706 "current setting? "), disk->dev->path,
707 (uint64_t) (last_usable_if_grown - last_usable));
709 if (q == PED_EXCEPTION_FIX)
711 last_usable = last_usable_if_grown;
714 else if (q != PED_EXCEPTION_UNHANDLED)
720 ped_geometry_init (&gpt_disk_data->data_area, disk->dev,
721 first_usable, last_usable - first_usable + 1);
723 gpt_disk_data->entry_count
724 = PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries);
725 PED_ASSERT (gpt_disk_data->entry_count > 0, return 0);
726 PED_ASSERT (gpt_disk_data->entry_count <= 8192, return 0);
728 gpt_disk_data->uuid = gpt->DiskGUID;
733 static PedPartition *
734 _parse_part_entry (PedDisk *disk, GuidPartitionEntry_t *pte)
737 GPTPartitionData *gpt_part_data;
740 part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
741 PED_LE64_TO_CPU (pte->StartingLBA),
742 PED_LE64_TO_CPU (pte->EndingLBA));
746 gpt_part_data = part->disk_specific;
747 gpt_part_data->type = pte->PartitionTypeGuid;
748 gpt_part_data->uuid = pte->UniquePartitionGuid;
749 for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
750 gpt_part_data->name[i] =
751 (efi_char16_t) PED_LE16_TO_CPU ((uint16_t) pte->PartitionName[i]);
752 gpt_part_data->name[i] = 0;
754 gpt_part_data->lvm = gpt_part_data->raid
755 = gpt_part_data->boot = gpt_part_data->hp_service
756 = gpt_part_data->hidden = gpt_part_data->msftres
757 = gpt_part_data->bios_grub = 0;
759 if (pte->Attributes.RequiredToFunction & 0x1)
760 gpt_part_data->hidden = 1;
762 if (!guid_cmp (gpt_part_data->type, PARTITION_SYSTEM_GUID))
763 gpt_part_data->boot = 1;
764 else if (!guid_cmp (gpt_part_data->type, PARTITION_BIOS_GRUB_GUID))
765 gpt_part_data->bios_grub = 1;
766 else if (!guid_cmp (gpt_part_data->type, PARTITION_RAID_GUID))
767 gpt_part_data->raid = 1;
768 else if (!guid_cmp (gpt_part_data->type, PARTITION_LVM_GUID))
769 gpt_part_data->lvm = 1;
770 else if (!guid_cmp (gpt_part_data->type, PARTITION_HPSERVICE_GUID))
771 gpt_part_data->hp_service = 1;
772 else if (!guid_cmp (gpt_part_data->type, PARTITION_MSFT_RESERVED_GUID))
773 gpt_part_data->msftres = 1;
778 /* Read the primary GPT at sector 1 of DEV.
779 Verify its CRC and that of its partition entry array.
780 If they are valid, read the backup GPT specified by AlternateLBA.
781 If not, read the backup GPT in the last sector of the disk.
782 Return 1 if any read fails.
783 Upon successful verification of the primary GPT, set *PRIMARY_GPT, else NULL.
784 Upon successful verification of the backup GPT, set *BACKUP_GPT, else NULL.
785 If we've set *BACKUP_GPT to non-NULL, set *BACKUP_LBA to the sector
786 number in which it was found. */
788 gpt_read_headers (PedDevice *dev,
789 GuidPartitionTableHeader_t **primary_gpt,
790 GuidPartitionTableHeader_t **backup_gpt,
791 PedSector *backup_sector_num_p)
797 if (!ptt_read_sector (dev, 1, &s1))
800 GuidPartitionTableHeader_t *t = pth_new_from_raw (dev, s1);
804 GuidPartitionTableHeader_t *pri = t;
806 bool valid_primary = _header_is_valid (dev, pri, 1);
810 PedSector backup_sector_num =
812 ? PED_LE64_TO_CPU (pri->AlternateLBA)
816 if (!ptt_read_sector (dev, backup_sector_num, &s_bak))
818 t = pth_new_from_raw (dev, s_bak);
822 GuidPartitionTableHeader_t *bak = t;
823 if (_header_is_valid (dev, bak, backup_sector_num))
826 *backup_sector_num_p = backup_sector_num;
832 /************************************************************
833 * Intel is changing the EFI Spec. (after v1.02) to say that a
834 * disk is considered to have a GPT label only if the GPT
835 * structures are correct, and the MBR is actually a Protective
836 * MBR (has one 0xEE type partition).
837 * Problem occurs when a GPT-partitioned disk is then
838 * edited with a legacy (non-GPT-aware) application, such as
839 * fdisk (which doesn't generally erase the PGPT or AGPT).
840 * How should such a disk get handled? As a GPT disk (throwing
841 * away the fdisk changes), or as an MSDOS disk (throwing away
842 * the GPT information). Previously, I've taken the GPT-is-right,
843 * MBR is wrong, approach, to stay consistent with the EFI Spec.
844 * Intel disagrees, saying the disk should then be treated
845 * as having a msdos label, not a GPT label. If this is true,
846 * then what's the point of having an AGPT, since if the PGPT
847 * is screwed up, likely the PMBR is too, and the PMBR becomes
848 * a single point of failure.
849 * So, in the Linux kernel, I'm going to test for PMBR, and
850 * warn if it's not there, and treat the disk as MSDOS, with a note
851 * for users to use Parted to "fix up" their disk if they
852 * really want it to be considered GPT.
853 ************************************************************/
855 gpt_read (PedDisk *disk)
857 GPTDiskData *gpt_disk_data = disk->disk_specific;
860 #ifndef DISCOVER_ONLY
864 ped_disk_delete_all (disk);
866 /* motivation: let the user decide about the pmbr... during
867 ped_disk_probe(), they probably didn't get a choice... */
868 if (!gpt_probe (disk->dev))
871 GuidPartitionTableHeader_t *gpt = NULL;
872 GuidPartitionTableHeader_t *primary_gpt;
873 GuidPartitionTableHeader_t *backup_gpt;
874 PedSector backup_sector_num;
875 int read_failure = gpt_read_headers (disk->dev, &primary_gpt, &backup_gpt,
879 /* This includes the case in which there used to be a GPT partition
880 table here, with an alternate LBA that extended beyond the current
881 end-of-device. It's treated as a non-match. */
883 /* Another possibility:
884 The primary header is ok, but backup is corrupt.
885 In the UEFI spec, this means the primary GUID table
886 is officially invalid. */
887 pth_free (backup_gpt);
888 pth_free (primary_gpt);
892 if (primary_gpt && backup_gpt)
894 /* Both are valid. */
895 if (PED_LE64_TO_CPU (primary_gpt->AlternateLBA) < disk->dev->length - 1)
897 #ifndef DISCOVER_ONLY
898 switch (ped_exception_throw
899 (PED_EXCEPTION_ERROR,
900 (PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL
901 | PED_EXCEPTION_IGNORE),
902 _("The backup GPT table is not at the end of the disk, as it "
903 "should be. This might mean that another operating system "
904 "believes the disk is smaller. Fix, by moving the backup "
905 "to the end (and removing the old backup)?")))
907 case PED_EXCEPTION_CANCEL:
909 case PED_EXCEPTION_FIX:
910 ptt_clear_sectors (disk->dev,
911 PED_LE64_TO_CPU (primary_gpt->AlternateLBA), 1);
917 #endif /* !DISCOVER_ONLY */
920 pth_free (backup_gpt);
922 else if (!primary_gpt && !backup_gpt)
924 /* Both are corrupt. */
925 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
926 _("Both the primary and backup GPT tables "
927 "are corrupt. Try making a fresh table, "
928 "and using Parted's rescue feature to "
929 "recover partitions."));
932 else if (primary_gpt && !backup_gpt)
934 /* The primary header is ok, but backup is corrupt. */
935 if (ped_exception_throw
936 (PED_EXCEPTION_ERROR, PED_EXCEPTION_OK_CANCEL,
937 _("The backup GPT table is corrupt, but the "
938 "primary appears OK, so that will be used."))
939 == PED_EXCEPTION_CANCEL)
944 else /* !primary_gpt && backup_gpt */
946 /* primary GPT corrupt, backup is ok. */
947 if (ped_exception_throw
948 (PED_EXCEPTION_ERROR, PED_EXCEPTION_OK_CANCEL,
949 _("The primary GPT table is corrupt, but the "
950 "backup appears OK, so that will be used."))
951 == PED_EXCEPTION_CANCEL)
959 if (!_parse_header (disk, gpt, &write_back))
962 uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
963 size_t ptes_bytes = p_ent_size * gpt_disk_data->entry_count;
964 size_t ptes_sectors = ped_div_round_up (ptes_bytes,
965 disk->dev->sector_size);
967 if (xalloc_oversized (ptes_sectors, disk->dev->sector_size))
969 ptes = ped_malloc (ptes_sectors * disk->dev->sector_size);
971 if (!ped_device_read (disk->dev, ptes,
972 PED_LE64_TO_CPU (gpt->PartitionEntryLBA),
974 goto error_free_ptes;
976 uint32_t ptes_crc = efi_crc32 (ptes, ptes_bytes);
977 if (ptes_crc != gpt->PartitionEntryArrayCRC32)
980 (PED_EXCEPTION_ERROR,
981 PED_EXCEPTION_CANCEL,
982 _("primary partition table array CRC mismatch"));
983 goto error_free_ptes;
986 for (i = 0; i < gpt_disk_data->entry_count; i++)
988 GuidPartitionEntry_t *pte
989 = (GuidPartitionEntry_t *) ((char *) ptes + i * p_ent_size);
991 PedConstraint *constraint_exact;
993 if (!guid_cmp (pte->PartitionTypeGuid, UNUSED_ENTRY_GUID))
996 part = _parse_part_entry (disk, pte);
998 goto error_delete_all;
1000 part->fs_type = ped_file_system_probe (&part->geom);
1003 constraint_exact = ped_constraint_exact (&part->geom);
1004 if (!ped_disk_add_partition (disk, part, constraint_exact))
1006 ped_partition_destroy (part);
1007 goto error_delete_all;
1009 ped_constraint_destroy (constraint_exact);
1013 #ifndef DISCOVER_ONLY
1015 ped_disk_commit_to_dev (disk);
1022 ped_disk_delete_all (disk);
1026 pth_free (primary_gpt);
1027 pth_free (backup_gpt);
1033 #ifndef DISCOVER_ONLY
1034 /* Write the protective MBR (to keep DOS happy) */
1036 _write_pmbr (PedDevice *dev)
1038 /* The UEFI spec is not clear about what to do with the following
1039 elements of the Protective MBR (pmbr): BootCode (0-440B),
1040 UniqueMBRSignature (440B-444B) and Unknown (444B-446B).
1041 With this in mind, we try not to modify these elements. */
1043 if (!ptt_read_sector (dev, 0, &s0))
1045 LegacyMBR_t *pmbr = s0;
1047 /* Zero out the legacy partitions. */
1048 memset (pmbr->PartitionRecord, 0, sizeof pmbr->PartitionRecord);
1050 pmbr->Signature = PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE);
1051 pmbr->PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI;
1052 pmbr->PartitionRecord[0].StartSector = 1;
1053 pmbr->PartitionRecord[0].EndHead = 0xFE;
1054 pmbr->PartitionRecord[0].EndSector = 0xFF;
1055 pmbr->PartitionRecord[0].EndTrack = 0xFF;
1056 pmbr->PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32 (1);
1057 if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
1058 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (0xFFFFFFFF);
1060 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (dev->length - 1UL);
1062 int write_ok = ped_device_write (dev, pmbr, GPT_PMBR_LBA,
1069 _generate_header (const PedDisk *disk, int alternate, uint32_t ptes_crc,
1070 GuidPartitionTableHeader_t **gpt_p)
1072 GPTDiskData *gpt_disk_data = disk->disk_specific;
1073 GuidPartitionTableHeader_t *gpt;
1075 *gpt_p = pth_new_zeroed (disk->dev);
1079 gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE);
1080 gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00);
1083 gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev));
1084 gpt->HeaderCRC32 = 0;
1089 PedSector ptes_size = gpt_disk_data->entry_count
1090 * sizeof (GuidPartitionEntry_t) / disk->dev->sector_size;
1092 gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1093 gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
1094 gpt->PartitionEntryLBA
1095 = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_size);
1099 gpt->MyLBA = PED_CPU_TO_LE64 (1);
1100 gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1101 gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
1104 gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
1105 gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
1106 gpt->DiskGUID = gpt_disk_data->uuid;
1107 gpt->NumberOfPartitionEntries
1108 = PED_CPU_TO_LE32 (gpt_disk_data->entry_count);
1109 gpt->SizeOfPartitionEntry = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t));
1110 gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32 (ptes_crc);
1111 gpt->HeaderCRC32 = PED_CPU_TO_LE32 (pth_crc32 (disk->dev, gpt));
1115 _partition_generate_part_entry (PedPartition *part, GuidPartitionEntry_t *pte)
1117 GPTPartitionData *gpt_part_data = part->disk_specific;
1120 PED_ASSERT (gpt_part_data != NULL, return);
1122 pte->PartitionTypeGuid = gpt_part_data->type;
1123 pte->UniquePartitionGuid = gpt_part_data->uuid;
1124 pte->StartingLBA = PED_CPU_TO_LE64 (part->geom.start);
1125 pte->EndingLBA = PED_CPU_TO_LE64 (part->geom.end);
1126 memset (&pte->Attributes, 0, sizeof (GuidPartitionEntryAttributes_t));
1128 if (gpt_part_data->hidden)
1129 pte->Attributes.RequiredToFunction = 1;
1131 for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
1132 pte->PartitionName[i]
1133 = (efi_char16_t) PED_CPU_TO_LE16 ((uint16_t) gpt_part_data->name[i]);
1137 gpt_write (const PedDisk *disk)
1139 GPTDiskData *gpt_disk_data;
1140 GuidPartitionEntry_t *ptes;
1143 GuidPartitionTableHeader_t *gpt;
1147 PED_ASSERT (disk != NULL, goto error);
1148 PED_ASSERT (disk->dev != NULL, goto error);
1149 PED_ASSERT (disk->disk_specific != NULL, goto error);
1151 gpt_disk_data = disk->disk_specific;
1153 ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
1154 ptes = (GuidPartitionEntry_t *) ped_malloc (ptes_size);
1157 memset (ptes, 0, ptes_size);
1158 for (part = ped_disk_next_partition (disk, NULL); part;
1159 part = ped_disk_next_partition (disk, part))
1161 if (part->type != 0)
1163 _partition_generate_part_entry (part, &ptes[part->num - 1]);
1166 ptes_crc = efi_crc32 (ptes, ptes_size);
1168 /* Write protective MBR */
1169 if (!_write_pmbr (disk->dev))
1170 goto error_free_ptes;
1172 /* Write PTH and PTEs */
1173 _generate_header (disk, 0, ptes_crc, &gpt);
1174 pth_raw = pth_get_raw (disk->dev, gpt);
1176 bool write_ok = ped_device_write (disk->dev, pth_raw, 1, 1);
1179 goto error_free_ptes;
1180 if (!ped_device_write (disk->dev, ptes, 2,
1181 ptes_size / disk->dev->sector_size))
1182 goto error_free_ptes;
1184 /* Write Alternate PTH & PTEs */
1185 _generate_header (disk, 1, ptes_crc, &gpt);
1186 pth_raw = pth_get_raw (disk->dev, gpt);
1188 write_ok = ped_device_write (disk->dev, pth_raw, disk->dev->length - 1, 1);
1191 goto error_free_ptes;
1192 if (!ped_device_write (disk->dev, ptes,
1193 disk->dev->length - 1 -
1194 ptes_size / disk->dev->sector_size,
1195 ptes_size / disk->dev->sector_size))
1196 goto error_free_ptes;
1199 return ped_device_sync (disk->dev);
1207 #endif /* !DISCOVER_ONLY */
1210 add_metadata_part (PedDisk *disk, PedSector start, PedSector length)
1213 PedConstraint *constraint_exact;
1214 PED_ASSERT (disk != NULL, return 0);
1216 part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1217 start, start + length - 1);
1221 constraint_exact = ped_constraint_exact (&part->geom);
1222 if (!ped_disk_add_partition (disk, part, constraint_exact))
1223 goto error_destroy_constraint;
1224 ped_constraint_destroy (constraint_exact);
1227 error_destroy_constraint:
1228 ped_constraint_destroy (constraint_exact);
1229 ped_partition_destroy (part);
1234 static PedPartition *
1235 gpt_partition_new (const PedDisk *disk,
1236 PedPartitionType part_type,
1237 const PedFileSystemType *fs_type, PedSector start,
1241 GPTPartitionData *gpt_part_data;
1243 part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1250 gpt_part_data = part->disk_specific =
1251 ped_malloc (sizeof (GPTPartitionData));
1253 goto error_free_part;
1255 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1256 gpt_part_data->lvm = 0;
1257 gpt_part_data->raid = 0;
1258 gpt_part_data->boot = 0;
1259 gpt_part_data->bios_grub = 0;
1260 gpt_part_data->hp_service = 0;
1261 gpt_part_data->hidden = 0;
1262 gpt_part_data->msftres = 0;
1263 uuid_generate ((unsigned char *) &gpt_part_data->uuid);
1264 swap_uuid_and_efi_guid ((unsigned char *) (&gpt_part_data->uuid));
1265 memset (gpt_part_data->name, 0, sizeof gpt_part_data->name);
1269 _ped_partition_free (part);
1274 static PedPartition *
1275 gpt_partition_duplicate (const PedPartition *part)
1277 PedPartition *result;
1278 GPTPartitionData *part_data = part->disk_specific;
1279 GPTPartitionData *result_data;
1281 result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
1282 part->geom.start, part->geom.end);
1285 result->num = part->num;
1287 if (result->type != 0)
1290 result_data = result->disk_specific =
1291 ped_malloc (sizeof (GPTPartitionData));
1293 goto error_free_part;
1295 result_data->type = part_data->type;
1296 result_data->uuid = part_data->uuid;
1297 strcpy (result_data->name, part_data->name);
1301 _ped_partition_free (result);
1307 gpt_partition_destroy (PedPartition *part)
1309 if (part->type == 0)
1311 PED_ASSERT (part->disk_specific != NULL, return);
1312 free (part->disk_specific);
1315 _ped_partition_free (part);
1319 gpt_partition_set_system (PedPartition *part,
1320 const PedFileSystemType *fs_type)
1322 GPTPartitionData *gpt_part_data = part->disk_specific;
1324 PED_ASSERT (gpt_part_data != NULL, return 0);
1326 part->fs_type = fs_type;
1328 if (gpt_part_data->lvm)
1330 gpt_part_data->type = PARTITION_LVM_GUID;
1333 if (gpt_part_data->raid)
1335 gpt_part_data->type = PARTITION_RAID_GUID;
1338 if (gpt_part_data->boot)
1340 gpt_part_data->type = PARTITION_SYSTEM_GUID;
1343 if (gpt_part_data->bios_grub)
1345 gpt_part_data->type = PARTITION_BIOS_GRUB_GUID;
1348 if (gpt_part_data->hp_service)
1350 gpt_part_data->type = PARTITION_HPSERVICE_GUID;
1353 if (gpt_part_data->msftres)
1355 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1361 if (strncmp (fs_type->name, "fat", 3) == 0
1362 || strcmp (fs_type->name, "ntfs") == 0)
1364 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1367 if (strncmp (fs_type->name, "hfs", 3) == 0)
1369 gpt_part_data->type = PARTITION_APPLE_HFS_GUID;
1372 if (strstr (fs_type->name, "swap"))
1374 gpt_part_data->type = PARTITION_SWAP_GUID;
1379 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1383 /* Allocate metadata partitions for the GPTH and PTES */
1385 gpt_alloc_metadata (PedDisk *disk)
1387 PedSector gptlength, pteslength = 0;
1388 GPTDiskData *gpt_disk_data;
1390 PED_ASSERT (disk != NULL, return 0);
1391 PED_ASSERT (disk->dev != NULL, return 0);
1392 PED_ASSERT (disk->disk_specific != NULL, return 0);
1393 gpt_disk_data = disk->disk_specific;
1395 gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t),
1396 disk->dev->sector_size);
1397 pteslength = ped_div_round_up (gpt_disk_data->entry_count
1398 * sizeof (GuidPartitionEntry_t),
1399 disk->dev->sector_size);
1401 /* metadata at the start of the disk includes the MBR */
1402 if (!add_metadata_part (disk, GPT_PMBR_LBA,
1403 GPT_PMBR_SECTORS + gptlength + pteslength))
1406 /* metadata at the end of the disk */
1407 if (!add_metadata_part (disk, disk->dev->length - gptlength - pteslength,
1408 gptlength + pteslength))
1414 /* Does nothing, as the read/new/destroy functions maintain part->num */
1416 gpt_partition_enumerate (PedPartition *part)
1418 GPTDiskData *gpt_disk_data = part->disk->disk_specific;
1421 /* never change the partition numbers */
1422 if (part->num != -1)
1425 for (i = 1; i <= gpt_disk_data->entry_count; i++)
1427 if (!ped_disk_get_partition (part->disk, i))
1434 PED_ASSERT (0, return 0);
1436 return 0; /* used if debug is disabled */
1440 gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
1442 GPTPartitionData *gpt_part_data;
1443 PED_ASSERT (part != NULL, return 0);
1444 PED_ASSERT (part->disk_specific != NULL, return 0);
1445 gpt_part_data = part->disk_specific;
1449 case PED_PARTITION_BOOT:
1450 gpt_part_data->boot = state;
1453 = gpt_part_data->lvm
1454 = gpt_part_data->bios_grub
1455 = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
1456 return gpt_partition_set_system (part, part->fs_type);
1457 case PED_PARTITION_BIOS_GRUB:
1458 gpt_part_data->bios_grub = state;
1461 = gpt_part_data->lvm
1462 = gpt_part_data->boot
1463 = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
1464 return gpt_partition_set_system (part, part->fs_type);
1465 case PED_PARTITION_RAID:
1466 gpt_part_data->raid = state;
1469 = gpt_part_data->lvm
1470 = gpt_part_data->bios_grub
1471 = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
1472 return gpt_partition_set_system (part, part->fs_type);
1473 case PED_PARTITION_LVM:
1474 gpt_part_data->lvm = state;
1477 = gpt_part_data->raid
1478 = gpt_part_data->bios_grub
1479 = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
1480 return gpt_partition_set_system (part, part->fs_type);
1481 case PED_PARTITION_HPSERVICE:
1482 gpt_part_data->hp_service = state;
1485 = gpt_part_data->raid
1486 = gpt_part_data->lvm
1487 = gpt_part_data->bios_grub = gpt_part_data->msftres = 0;
1488 return gpt_partition_set_system (part, part->fs_type);
1489 case PED_PARTITION_MSFT_RESERVED:
1490 gpt_part_data->msftres = state;
1493 = gpt_part_data->raid
1494 = gpt_part_data->lvm
1495 = gpt_part_data->bios_grub = gpt_part_data->hp_service = 0;
1496 return gpt_partition_set_system (part, part->fs_type);
1497 case PED_PARTITION_HIDDEN:
1498 gpt_part_data->hidden = state;
1500 case PED_PARTITION_SWAP:
1501 case PED_PARTITION_ROOT:
1502 case PED_PARTITION_LBA:
1510 gpt_partition_get_flag (const PedPartition *part, PedPartitionFlag flag)
1512 GPTPartitionData *gpt_part_data;
1513 PED_ASSERT (part->disk_specific != NULL, return 0);
1514 gpt_part_data = part->disk_specific;
1518 case PED_PARTITION_RAID:
1519 return gpt_part_data->raid;
1520 case PED_PARTITION_LVM:
1521 return gpt_part_data->lvm;
1522 case PED_PARTITION_BOOT:
1523 return gpt_part_data->boot;
1524 case PED_PARTITION_BIOS_GRUB:
1525 return gpt_part_data->bios_grub;
1526 case PED_PARTITION_HPSERVICE:
1527 return gpt_part_data->hp_service;
1528 case PED_PARTITION_MSFT_RESERVED:
1529 return gpt_part_data->msftres;
1530 case PED_PARTITION_HIDDEN:
1531 return gpt_part_data->hidden;
1532 case PED_PARTITION_SWAP:
1533 case PED_PARTITION_LBA:
1534 case PED_PARTITION_ROOT:
1542 gpt_partition_is_flag_available (const PedPartition *part,
1543 PedPartitionFlag flag)
1547 case PED_PARTITION_RAID:
1548 case PED_PARTITION_LVM:
1549 case PED_PARTITION_BOOT:
1550 case PED_PARTITION_BIOS_GRUB:
1551 case PED_PARTITION_HPSERVICE:
1552 case PED_PARTITION_MSFT_RESERVED:
1553 case PED_PARTITION_HIDDEN:
1555 case PED_PARTITION_SWAP:
1556 case PED_PARTITION_ROOT:
1557 case PED_PARTITION_LBA:
1565 gpt_partition_set_name (PedPartition *part, const char *name)
1567 GPTPartitionData *gpt_part_data = part->disk_specific;
1569 strncpy (gpt_part_data->name, name, 36);
1570 gpt_part_data->name[36] = 0;
1574 gpt_partition_get_name (const PedPartition *part)
1576 GPTPartitionData *gpt_part_data = part->disk_specific;
1577 return gpt_part_data->name;
1581 gpt_get_max_primary_partition_count (const PedDisk *disk)
1583 const GPTDiskData *gpt_disk_data = disk->disk_specific;
1584 return gpt_disk_data->entry_count;
1588 * From (http://developer.apple.com/technotes/tn2006/tn2166.html Chapter 5).
1589 * According to the specs the first LBA (LBA0) is not relevant (it exists
1590 * to maintain compatibility). on the second LBA(LBA1) gpt places the
1591 * header. The header is as big as the block size. After the header we
1592 * find the Entry array. Each element of said array, describes each
1593 * partition. One can have as much elements as can fit between the end of
1594 * the second LBA (where the header ends) and the FirstUsableLBA.
1595 * FirstUsableLBA is the first logical block that is used for contents
1596 * and is defined in header.
1598 * /---------------------------------------------------\
1599 * | BLOCK0 | HEADER | Entry Array | First Usable LBA |
1601 * \---------------------------------------------------/
1603 * /----------/ \----------\
1604 * /-----------------------------------------\
1605 * | E1 | E2 | E3 |...............| EN |
1606 * \-----------------------------------------/
1608 * The number of possible partitions or supported partitions is:
1609 * SP = FirstUsableLBA*Blocksize - 2*Blocksize / SizeOfPartitionEntry
1610 * SP = Blocksize(FirstusableLBA - 2) / SizeOfPartitoinEntry
1613 gpt_get_max_supported_partition_count (const PedDisk *disk, int *max_n)
1615 GuidPartitionTableHeader_t *pth = NULL;
1616 uint8_t *pth_raw = ped_malloc (pth_get_size (disk->dev));
1618 if (ped_device_read (disk->dev, pth_raw, 1, GPT_HEADER_SECTORS)
1619 || ped_device_read (disk->dev, pth_raw,
1620 disk->dev->length, GPT_HEADER_SECTORS))
1621 pth = pth_new_from_raw (disk->dev, pth_raw);
1627 *max_n = (disk->dev->sector_size * (pth->FirstUsableLBA - 2)
1628 / PED_LE32_TO_CPU (pth->SizeOfPartitionEntry));
1633 static PedConstraint *
1634 _non_metadata_constraint (const PedDisk *disk)
1636 GPTDiskData *gpt_disk_data = disk->disk_specific;
1638 return ped_constraint_new_from_max (&gpt_disk_data->data_area);
1642 gpt_partition_align (PedPartition *part, const PedConstraint *constraint)
1644 PED_ASSERT (part != NULL, return 0);
1646 if (_ped_partition_attempt_align (part, constraint,
1647 _non_metadata_constraint (part->disk)))
1650 #ifndef DISCOVER_ONLY
1651 ped_exception_throw (PED_EXCEPTION_ERROR,
1652 PED_EXCEPTION_CANCEL,
1653 _("Unable to satisfy all constraints on the partition."));
1659 gpt_partition_check (const PedPartition *part)
1664 #ifdef DISCOVER_ONLY
1665 # define NULL_IF_DISCOVER_ONLY(val) NULL
1667 # define NULL_IF_DISCOVER_ONLY(val) val
1670 static PedDiskOps gpt_disk_ops =
1673 clobber: NULL_IF_DISCOVER_ONLY (gpt_clobber),
1675 duplicate: gpt_duplicate,
1678 write: NULL_IF_DISCOVER_ONLY (gpt_write),
1679 partition_new: gpt_partition_new,
1680 partition_duplicate: gpt_partition_duplicate,
1681 partition_destroy: gpt_partition_destroy,
1682 partition_set_system: gpt_partition_set_system,
1683 partition_set_flag: gpt_partition_set_flag,
1684 partition_get_flag: gpt_partition_get_flag,
1685 partition_is_flag_available: gpt_partition_is_flag_available,
1686 partition_set_name: gpt_partition_set_name,
1687 partition_get_name: gpt_partition_get_name,
1688 partition_align: gpt_partition_align,
1689 partition_enumerate: gpt_partition_enumerate,
1690 partition_check: gpt_partition_check,
1691 alloc_metadata: gpt_alloc_metadata,
1692 get_max_primary_partition_count: gpt_get_max_primary_partition_count,
1693 get_max_supported_partition_count: gpt_get_max_supported_partition_count
1696 static PedDiskType gpt_disk_type =
1701 features: PED_DISK_TYPE_PARTITION_NAME
1705 ped_disk_gpt_init ()
1707 PED_ASSERT (sizeof (GuidPartitionEntryAttributes_t) == 8, return);
1708 PED_ASSERT (sizeof (GuidPartitionEntry_t) == 128, return);
1710 ped_disk_type_register (&gpt_disk_type);
1714 ped_disk_gpt_done ()
1716 ped_disk_type_unregister (&gpt_disk_type);