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;
74 uint16_t time_hi_and_version;
75 uint8_t clock_seq_hi_and_reserved;
76 uint8_t clock_seq_low;
78 } /* __attribute__ ((packed)) */ efi_guid_t;
79 /* commented out "__attribute__ ((packed))" to work around gcc bug (fixed
80 * in gcc3.1): __attribute__ ((packed)) breaks addressing on initialized
81 * data. It turns out we don't need it in this case, so it doesn't break
85 #define UNUSED_ENTRY_GUID \
86 ((efi_guid_t) { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
87 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
88 #define PARTITION_SYSTEM_GUID \
89 ((efi_guid_t) { PED_CPU_TO_LE32 (0xC12A7328), PED_CPU_TO_LE16 (0xF81F), \
90 PED_CPU_TO_LE16 (0x11d2), 0xBA, 0x4B, \
91 { 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }})
92 #define PARTITION_BIOS_GRUB_GUID \
93 ((efi_guid_t) { PED_CPU_TO_LE32 (0x21686148), PED_CPU_TO_LE16 (0x6449), \
94 PED_CPU_TO_LE16 (0x6E6f), 0x74, 0x4E, \
95 { 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 }})
96 #define LEGACY_MBR_PARTITION_GUID \
97 ((efi_guid_t) { PED_CPU_TO_LE32 (0x024DEE41), PED_CPU_TO_LE16 (0x33E7), \
98 PED_CPU_TO_LE16 (0x11d3, 0x9D, 0x69, \
99 { 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }})
100 #define PARTITION_MSFT_RESERVED_GUID \
101 ((efi_guid_t) { PED_CPU_TO_LE32 (0xE3C9E316), PED_CPU_TO_LE16 (0x0B5C), \
102 PED_CPU_TO_LE16 (0x4DB8), 0x81, 0x7D, \
103 { 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE }})
104 #define PARTITION_BASIC_DATA_GUID \
105 ((efi_guid_t) { PED_CPU_TO_LE32 (0xEBD0A0A2), PED_CPU_TO_LE16 (0xB9E5), \
106 PED_CPU_TO_LE16 (0x4433), 0x87, 0xC0, \
107 { 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }})
108 #define PARTITION_RAID_GUID \
109 ((efi_guid_t) { PED_CPU_TO_LE32 (0xa19d880f), PED_CPU_TO_LE16 (0x05fc), \
110 PED_CPU_TO_LE16 (0x4d3b), 0xa0, 0x06, \
111 { 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e }})
112 #define PARTITION_SWAP_GUID \
113 ((efi_guid_t) { PED_CPU_TO_LE32 (0x0657fd6d), PED_CPU_TO_LE16 (0xa4ab), \
114 PED_CPU_TO_LE16 (0x43c4), 0x84, 0xe5, \
115 { 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f }})
116 #define PARTITION_LVM_GUID \
117 ((efi_guid_t) { PED_CPU_TO_LE32 (0xe6d6d379), PED_CPU_TO_LE16 (0xf507), \
118 PED_CPU_TO_LE16 (0x44c2), 0xa2, 0x3c, \
119 { 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 }})
120 #define PARTITION_RESERVED_GUID \
121 ((efi_guid_t) { PED_CPU_TO_LE32 (0x8da63339), PED_CPU_TO_LE16 (0x0007), \
122 PED_CPU_TO_LE16 (0x60c0), 0xc4, 0x36, \
123 { 0x08, 0x3a, 0xc8, 0x23, 0x09, 0x08 }})
124 #define PARTITION_HPSERVICE_GUID \
125 ((efi_guid_t) { PED_CPU_TO_LE32 (0xe2a1e728), PED_CPU_TO_LE16 (0x32e3), \
126 PED_CPU_TO_LE16 (0x11d6), 0xa6, 0x82, \
127 { 0x7b, 0x03, 0xa0, 0x00, 0x00, 0x00 }})
128 #define PARTITION_APPLE_HFS_GUID \
129 ((efi_guid_t) { PED_CPU_TO_LE32 (0x48465300), PED_CPU_TO_LE16 (0x0000), \
130 PED_CPU_TO_LE16 (0x11AA), 0xaa, 0x11, \
131 { 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC }})
133 struct __attribute__ ((packed)) _GuidPartitionTableHeader_t {
137 uint32_t HeaderCRC32;
140 uint64_t AlternateLBA;
141 uint64_t FirstUsableLBA;
142 uint64_t LastUsableLBA;
144 uint64_t PartitionEntryLBA;
145 uint32_t NumberOfPartitionEntries;
146 uint32_t SizeOfPartitionEntry;
147 uint32_t PartitionEntryArrayCRC32;
151 struct __attribute__ ((packed)) _GuidPartitionEntryAttributes_t {
152 #ifdef __GNUC__ /* XXX narrow this down to !TinyCC */
153 uint64_t RequiredToFunction:1;
154 uint64_t Reserved:47;
155 uint64_t GuidSpecific:16;
157 # warning "Using crippled partition entry type"
158 uint32_t RequiredToFunction:1;
159 uint32_t Reserved:32;
161 uint32_t GuidSpecific:16;
165 struct __attribute__ ((packed)) _GuidPartitionEntry_t {
166 efi_guid_t PartitionTypeGuid;
167 efi_guid_t UniquePartitionGuid;
168 uint64_t StartingLBA;
170 GuidPartitionEntryAttributes_t Attributes;
171 efi_char16_t PartitionName[72 / sizeof(efi_char16_t)];
174 #define GPT_PMBR_LBA 0
175 #define GPT_PMBR_SECTORS 1
176 #define GPT_PRIMARY_HEADER_LBA 1
177 #define GPT_HEADER_SECTORS 1
178 #define GPT_PRIMARY_PART_TABLE_LBA 2
181 These values are only defaults. The actual on-disk structures
182 may define different sizes, so use those unless creating a new GPT disk!
185 #define GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE 16384
187 /* Number of actual partition entries should be calculated as: */
188 #define GPT_DEFAULT_PARTITION_ENTRIES \
189 (GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / \
190 sizeof(GuidPartitionEntry_t))
193 struct __attribute__ ((packed)) _PartitionRecord_t {
194 /* Not used by EFI firmware. Set to 0x80 to indicate that this
195 is the bootable legacy partition. */
196 uint8_t BootIndicator;
198 /* Start of partition in CHS address, not used by EFI firmware. */
201 /* Start of partition in CHS address, not used by EFI firmware. */
204 /* Start of partition in CHS address, not used by EFI firmware. */
207 /* OS type. A value of 0xEF defines an EFI system partition.
208 Other values are reserved for legacy operating systems, and
209 allocated independently of the EFI specification. */
212 /* End of partition in CHS address, not used by EFI firmware. */
215 /* End of partition in CHS address, not used by EFI firmware. */
218 /* End of partition in CHS address, not used by EFI firmware. */
221 /* Starting LBA address of the partition on the disk. Used by
222 EFI firmware to define the start of the partition. */
223 uint32_t StartingLBA;
225 /* Size of partition in LBA. Used by EFI firmware to determine
226 the size of the partition. */
230 /* Protected Master Boot Record & Legacy MBR share same structure */
231 /* Needs to be packed because the u16s force misalignment. */
232 struct __attribute__ ((packed)) _LegacyMBR_t {
233 uint8_t BootCode[440];
234 uint32_t UniqueMBRSignature;
236 PartitionRecord_t PartitionRecord[4];
240 /* uses libparted's disk_specific field in PedDisk, to store our info */
241 struct __attribute__ ((packed)) _GPTDiskData {
242 PedGeometry data_area;
247 /* uses libparted's disk_specific field in PedPartition, to store our info */
248 typedef struct _GPTPartitionData {
261 static PedDiskType gpt_disk_type;
264 static inline uint32_t
265 pth_get_size (const PedDevice* dev)
267 return GPT_HEADER_SECTORS * dev->sector_size;
271 static inline uint32_t
272 pth_get_size_static (const PedDevice* dev)
274 return sizeof (GuidPartitionTableHeader_t) - sizeof (uint8_t*);
278 static inline uint32_t
279 pth_get_size_rsv2 (const PedDevice* dev)
281 return pth_get_size(dev) - pth_get_size_static(dev);
285 static GuidPartitionTableHeader_t*
286 pth_new (const PedDevice* dev)
288 GuidPartitionTableHeader_t* pth = ped_malloc (
289 sizeof (GuidPartitionTableHeader_t)
292 pth->Reserved2 = ped_malloc ( pth_get_size_rsv2 (dev) );
298 static GuidPartitionTableHeader_t*
299 pth_new_zeroed (const PedDevice* dev)
301 GuidPartitionTableHeader_t* pth = pth_new (dev);
303 memset (pth, 0, pth_get_size_static (dev));
304 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)
327 PED_ASSERT (pth != NULL, return);
328 PED_ASSERT (pth->Reserved2 != NULL, return);
330 free (pth->Reserved2);
335 pth_get_raw (const PedDevice* dev, const GuidPartitionTableHeader_t* pth)
337 uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
338 int size_static = pth_get_size_static (dev);
340 PED_ASSERT (pth != NULL, return 0);
341 PED_ASSERT (pth->Reserved2 != NULL, return 0);
343 memcpy (pth_raw, pth, size_static);
344 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);
397 PED_ASSERT (dev != NULL, return 0);
398 PED_ASSERT (pth != NULL, return 0);
400 crc32 = efi_crc32 (pth_raw, PED_LE32_TO_CPU (pth->HeaderSize));
408 guid_cmp (efi_guid_t left, efi_guid_t right)
410 return memcmp(&left, &right, sizeof(efi_guid_t));
413 /* checks if 'mbr' is a protective MBR partition table */
415 _pmbr_is_valid (const LegacyMBR_t* mbr)
419 PED_ASSERT(mbr != NULL, return 0);
421 if (mbr->Signature != PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE))
423 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)) {
441 gpt = pth_new_from_raw (dev, pth_raw);
442 if (gpt->Signature == PED_CPU_TO_LE64(GPT_HEADER_SIGNATURE))
457 if (!ptt_read_sector (dev, 0, &label))
461 if (!_pmbr_is_valid ( (const LegacyMBR_t *) label)) {
462 int ex_status = ped_exception_throw (
463 PED_EXCEPTION_WARNING,
464 PED_EXCEPTION_YES_NO,
465 _("%s contains GPT signatures, indicating that it has "
466 "a GPT table. However, it does not have a valid "
467 "fake msdos partition table, as it should. Perhaps "
468 "it was corrupted -- possibly by a program that "
469 "doesn't understand GPT partition tables. Or "
470 "perhaps you deleted the GPT table, and are now "
471 "using an msdos partition table. Is this a GPT "
474 if (ex_status == PED_EXCEPTION_NO)
482 #ifndef DISCOVER_ONLY
483 /* writes zeros to the PMBR and the primary and alternate GPTHs and PTEs */
485 gpt_clobber(PedDevice * dev)
487 uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
488 GuidPartitionTableHeader_t* gpt;
490 PED_ASSERT (dev != NULL, return 0);
493 * TO DISCUSS: check whether checksum is correct?
494 * If not, we might get a wrong AlternateLBA field and destroy
495 * one sector of random data.
497 if (!ped_device_read(dev, pth_raw,
498 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) {
515 if (!ped_device_write(dev, gpt,
516 PED_LE64_TO_CPU (gpt->AlternateLBA),
529 #endif /* !DISCOVER_ONLY */
532 gpt_alloc (const PedDevice * dev)
535 GPTDiskData *gpt_disk_data;
536 PedSector data_start, data_end;
538 disk = _ped_disk_alloc ((PedDevice*)dev, &gpt_disk_type);
541 disk->disk_specific = gpt_disk_data = ped_malloc (sizeof (GPTDiskData));
542 if (!disk->disk_specific)
543 goto error_free_disk;
545 data_start = 2 + GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
546 data_end = dev->length - 2
547 - GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
548 ped_geometry_init (&gpt_disk_data->data_area, dev, data_start,
549 data_end - data_start + 1);
550 gpt_disk_data->entry_count = GPT_DEFAULT_PARTITION_ENTRIES;
551 uuid_generate ((unsigned char*) &gpt_disk_data->uuid);
552 swap_uuid_and_efi_guid((unsigned char*)(&gpt_disk_data->uuid));
562 gpt_duplicate (const PedDisk* disk)
565 GPTDiskData* new_disk_data;
566 GPTDiskData* old_disk_data;
568 new_disk = ped_disk_new_fresh (disk->dev, &gpt_disk_type);
572 old_disk_data = disk->disk_specific;
573 new_disk_data = new_disk->disk_specific;
575 ped_geometry_init (&new_disk_data->data_area, disk->dev,
576 old_disk_data->data_area.start,
577 old_disk_data->data_area.length);
578 new_disk_data->entry_count = old_disk_data->entry_count;
579 new_disk_data->uuid = old_disk_data->uuid;
584 gpt_free(PedDisk * disk)
586 ped_disk_delete_all (disk);
587 free (disk->disk_specific);
588 _ped_disk_free (disk);
592 _header_is_valid (const PedDevice* dev, GuidPartitionTableHeader_t* gpt)
594 uint32_t crc, origcrc;
596 if (PED_LE64_TO_CPU (gpt->Signature) != GPT_HEADER_SIGNATURE)
599 * "While the GUID Partition Table Header's size may increase
600 * in the future it cannot span more than one block on the
601 * device." EFI Specification, version 1.10, 11.2.2.1
603 if (PED_LE32_TO_CPU (gpt->HeaderSize) < pth_get_size_static (dev)
604 || PED_LE32_TO_CPU (gpt->HeaderSize) > dev->sector_size)
608 * the SizeOfPartitionEntry must be a multiple of 8 and
609 * no smaller than the size of the PartitionEntry structure.
611 uint32_t sope = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
613 || sope < sizeof (GuidPartitionEntry_t)
614 || (UINT32_MAX >> 4) < sope)
617 origcrc = gpt->HeaderCRC32;
618 gpt->HeaderCRC32 = 0;
619 crc = pth_crc32 (dev, gpt);
620 gpt->HeaderCRC32 = origcrc;
622 return crc == PED_LE32_TO_CPU (origcrc);
626 _read_header (const PedDevice* dev, GuidPartitionTableHeader_t** gpt,
629 uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
631 PED_ASSERT (dev != NULL, return 0);
633 if (!ped_device_read (dev, pth_raw, where, GPT_HEADER_SECTORS)) {
638 *gpt = pth_new_from_raw (dev, pth_raw);
642 if (_header_is_valid (dev, *gpt))
650 _parse_header (PedDisk* disk, GuidPartitionTableHeader_t* gpt,
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;
659 PED_ASSERT (_header_is_valid (disk->dev, gpt), return 0);
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)
675 first_usable = PED_LE64_TO_CPU (gpt->FirstUsableLBA);
676 last_usable = PED_LE64_TO_CPU (gpt->LastUsableLBA);
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
690 = (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));
695 last_usable_min_default = disk->dev->length - 2 -
696 GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / disk->dev->sector_size;
698 if ( last_usable_if_grown > last_usable_min_default ) {
700 last_usable_if_grown = last_usable_min_default;
704 PED_ASSERT (last_usable > first_usable, return 0);
705 PED_ASSERT (last_usable <= disk->dev->length, return 0);
707 PED_ASSERT (last_usable_if_grown > first_usable, return 0);
708 PED_ASSERT (last_usable_if_grown <= disk->dev->length, return 0);
710 if ( !asked_already && last_usable < last_usable_if_grown ) {
712 PedExceptionOption q;
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));
723 if (q == PED_EXCEPTION_FIX) {
725 last_usable = last_usable_if_grown;
729 else if (q != PED_EXCEPTION_UNHANDLED ) {
735 ped_geometry_init (&gpt_disk_data->data_area, disk->dev,
736 first_usable, last_usable - first_usable + 1);
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);
744 gpt_disk_data->uuid = gpt->DiskGUID;
750 _parse_part_entry (PedDisk* disk, GuidPartitionEntry_t* pte)
753 GPTPartitionData* gpt_part_data;
756 part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
757 PED_LE64_TO_CPU(pte->StartingLBA),
758 PED_LE64_TO_CPU(pte->EndingLBA));
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;
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
773 = gpt_part_data->bios_grub = 0;
775 if (pte->Attributes.RequiredToFunction & 0x1)
776 gpt_part_data->hidden = 1;
778 if (!guid_cmp (gpt_part_data->type, PARTITION_SYSTEM_GUID))
779 gpt_part_data->boot = 1;
780 else if (!guid_cmp (gpt_part_data->type, PARTITION_BIOS_GRUB_GUID))
781 gpt_part_data->bios_grub = 1;
782 else if (!guid_cmp (gpt_part_data->type, PARTITION_RAID_GUID))
783 gpt_part_data->raid = 1;
784 else if (!guid_cmp (gpt_part_data->type, PARTITION_LVM_GUID))
785 gpt_part_data->lvm = 1;
786 else if (!guid_cmp (gpt_part_data->type, PARTITION_HPSERVICE_GUID))
787 gpt_part_data->hp_service = 1;
788 else if (!guid_cmp (gpt_part_data->type, PARTITION_MSFT_RESERVED_GUID))
789 gpt_part_data->msftres = 1;
794 /************************************************************
795 * Intel is changing the EFI Spec. (after v1.02) to say that a
796 * disk is considered to have a GPT label only if the GPT
797 * structures are correct, and the MBR is actually a Protective
798 * MBR (has one 0xEE type partition).
799 * Problem occurs when a GPT-partitioned disk is then
800 * edited with a legacy (non-GPT-aware) application, such as
801 * fdisk (which doesn't generally erase the PGPT or AGPT).
802 * How should such a disk get handled? As a GPT disk (throwing
803 * away the fdisk changes), or as an MSDOS disk (throwing away
804 * the GPT information). Previously, I've taken the GPT-is-right,
805 * MBR is wrong, approach, to stay consistent with the EFI Spec.
806 * Intel disagrees, saying the disk should then be treated
807 * as having a msdos label, not a GPT label. If this is true,
808 * then what's the point of having an AGPT, since if the PGPT
809 * is screwed up, likely the PMBR is too, and the PMBR becomes
810 * a single point of failure.
811 * So, in the Linux kernel, I'm going to test for PMBR, and
812 * warn if it's not there, and treat the disk as MSDOS, with a note
813 * for users to use Parted to "fix up" their disk if they
814 * really want it to be considered GPT.
815 ************************************************************/
817 gpt_read (PedDisk * disk)
819 GPTDiskData *gpt_disk_data = disk->disk_specific;
820 GuidPartitionTableHeader_t* gpt;
824 #ifndef DISCOVER_ONLY
828 ped_disk_delete_all (disk);
831 * motivation: let the user decide about the pmbr... during
832 * ped_disk_probe(), they probably didn't get a choice...
834 if (!gpt_probe (disk->dev))
837 if (_read_header (disk->dev, &gpt, 1)) {
838 /* There used to be a GPT partition table here, with an
839 alternate LBA that extended beyond the current
840 end-of-device. Treat it as a non-match. */
841 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
842 > disk->dev->length - 1)
845 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
846 < disk->dev->length - 1) {
848 #ifndef DISCOVER_ONLY
849 switch (ped_exception_throw (
851 PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL | PED_EXCEPTION_IGNORE,
852 _("The backup GPT table is not at the end of the disk, as it "
853 "should be. This might mean that another operating system "
854 "believes the disk is smaller. Fix, by moving the backup "
855 "to the end (and removing the old backup)?"))) {
856 case PED_EXCEPTION_CANCEL:
858 case PED_EXCEPTION_FIX:
861 ped_malloc (pth_get_size (disk->dev));
863 memset (zeros, 0, disk->dev->sector_size);
864 ped_device_write (disk->dev, zeros,
865 PED_LE64_TO_CPU (gpt->AlternateLBA),
874 #endif /* !DISCOVER_ONLY */
876 } else { /* primary GPT *not* ok */
877 int alternate_ok = 0;
879 #ifndef DISCOVER_ONLY
883 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
884 < disk->dev->length - 1) {
885 alternate_ok = _read_header (disk->dev, &gpt,
886 PED_LE64_TO_CPU(gpt->AlternateLBA));
889 alternate_ok = _read_header (disk->dev, &gpt,
890 disk->dev->length - 1);
894 if (ped_exception_throw (
896 PED_EXCEPTION_OK_CANCEL,
897 _("The primary GPT table is corrupt, but the "
898 "backup appears OK, so that will be used."))
899 == PED_EXCEPTION_CANCEL)
902 ped_exception_throw (
904 PED_EXCEPTION_CANCEL,
905 _("Both the primary and backup GPT tables "
906 "are corrupt. Try making a fresh table, "
907 "and using Parted's rescue feature to "
908 "recover partitions."));
913 if (!_parse_header (disk, gpt, &write_back))
916 uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
917 ptes_sectors = ped_div_round_up (p_ent_size
918 * gpt_disk_data->entry_count,
919 disk->dev->sector_size);
921 if (xalloc_oversized (ptes_sectors, disk->dev->sector_size))
923 ptes = ped_malloc (ptes_sectors * disk->dev->sector_size);
925 if (!ped_device_read (disk->dev, ptes,
926 PED_LE64_TO_CPU(gpt->PartitionEntryLBA),
928 goto error_free_ptes;
930 for (i = 0; i < gpt_disk_data->entry_count; i++) {
931 GuidPartitionEntry_t* pte
932 = (GuidPartitionEntry_t*) ((char *)ptes + i * p_ent_size);
934 PedConstraint* constraint_exact;
936 if (!guid_cmp (pte->PartitionTypeGuid, UNUSED_ENTRY_GUID))
939 part = _parse_part_entry (disk, pte);
941 goto error_delete_all;
943 part->fs_type = ped_file_system_probe (&part->geom);
946 constraint_exact = ped_constraint_exact (&part->geom);
947 if (!ped_disk_add_partition(disk, part, constraint_exact)) {
948 ped_partition_destroy (part);
949 goto error_delete_all;
951 ped_constraint_destroy (constraint_exact);
955 #ifndef DISCOVER_ONLY
957 ped_disk_commit_to_dev (disk);
964 ped_disk_delete_all (disk);
973 #ifndef DISCOVER_ONLY
974 /* Write the protective MBR (to keep DOS happy) */
976 _write_pmbr (PedDevice * dev)
978 /* The UEFI spec is not clear about what to do with the following
979 elements of the Protective MBR (pmbr): BootCode (0-440B),
980 UniqueMBRSignature (440B-444B) and Unknown (444B-446B).
981 With this in mind, we try not to modify these elements. */
983 if (!ptt_read_sector (dev, 0, &s0))
985 LegacyMBR_t *pmbr = s0;
987 /* Zero out the legacy partitions. */
988 memset (pmbr->PartitionRecord, 0, sizeof pmbr->PartitionRecord);
990 pmbr->Signature = PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE);
991 pmbr->PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI;
992 pmbr->PartitionRecord[0].StartSector = 1;
993 pmbr->PartitionRecord[0].EndHead = 0xFE;
994 pmbr->PartitionRecord[0].EndSector = 0xFF;
995 pmbr->PartitionRecord[0].EndTrack = 0xFF;
996 pmbr->PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32(1);
997 if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
998 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(0xFFFFFFFF);
1000 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(dev->length - 1UL);
1002 int write_ok = ped_device_write (dev, pmbr, GPT_PMBR_LBA,
1009 _generate_header (const PedDisk* disk, int alternate, uint32_t ptes_crc,
1010 GuidPartitionTableHeader_t** gpt_p)
1012 GPTDiskData* gpt_disk_data = disk->disk_specific;
1013 GuidPartitionTableHeader_t* gpt;
1015 *gpt_p = pth_new_zeroed (disk->dev);
1019 gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE);
1020 gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00);
1023 gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev));
1024 gpt->HeaderCRC32 = 0;
1028 PedSector ptes_size = gpt_disk_data->entry_count
1029 * sizeof (GuidPartitionEntry_t) / disk->dev->sector_size;
1031 gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1032 gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
1033 gpt->PartitionEntryLBA
1034 = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_size);
1036 gpt->MyLBA = PED_CPU_TO_LE64 (1);
1037 gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1038 gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
1041 gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
1042 gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
1043 gpt->DiskGUID = gpt_disk_data->uuid;
1044 gpt->NumberOfPartitionEntries
1045 = PED_CPU_TO_LE32 (gpt_disk_data->entry_count);
1046 gpt->SizeOfPartitionEntry
1047 = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t));
1048 gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32 (ptes_crc);
1049 gpt->HeaderCRC32 = PED_CPU_TO_LE32 (pth_crc32 (disk->dev, gpt));
1053 _partition_generate_part_entry (PedPartition* part, GuidPartitionEntry_t* pte)
1055 GPTPartitionData* gpt_part_data = part->disk_specific;
1058 PED_ASSERT (gpt_part_data != NULL, return);
1060 pte->PartitionTypeGuid = gpt_part_data->type;
1061 pte->UniquePartitionGuid = gpt_part_data->uuid;
1062 pte->StartingLBA = PED_CPU_TO_LE64(part->geom.start);
1063 pte->EndingLBA = PED_CPU_TO_LE64(part->geom.end);
1064 memset (&pte->Attributes, 0, sizeof (GuidPartitionEntryAttributes_t));
1066 if (gpt_part_data->hidden)
1067 pte->Attributes.RequiredToFunction = 1;
1069 for (i = 0; i < 72 / sizeof(efi_char16_t); i++)
1070 pte->PartitionName[i]
1071 = (efi_char16_t) PED_CPU_TO_LE16(
1072 (uint16_t) gpt_part_data->name[i]);
1076 gpt_write(const PedDisk * disk)
1078 GPTDiskData* gpt_disk_data;
1079 GuidPartitionEntry_t* ptes;
1082 GuidPartitionTableHeader_t* gpt;
1086 PED_ASSERT (disk != NULL, goto error);
1087 PED_ASSERT (disk->dev != NULL, goto error);
1088 PED_ASSERT (disk->disk_specific != NULL, goto error);
1090 gpt_disk_data = disk->disk_specific;
1092 ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
1093 ptes = (GuidPartitionEntry_t*) ped_malloc (ptes_size);
1096 memset (ptes, 0, ptes_size);
1097 for (part = ped_disk_next_partition (disk, NULL); part;
1098 part = ped_disk_next_partition (disk, part)) {
1099 if (part->type != 0)
1101 _partition_generate_part_entry (part, &ptes[part->num - 1]);
1104 ptes_crc = efi_crc32 (ptes, ptes_size);
1106 /* Write protective MBR */
1107 if (!_write_pmbr (disk->dev))
1108 goto error_free_ptes;
1110 /* Write PTH and PTEs */
1111 _generate_header (disk, 0, ptes_crc, &gpt);
1112 pth_raw = pth_get_raw (disk->dev, gpt);
1114 bool write_ok = ped_device_write (disk->dev, pth_raw, 1, 1);
1117 goto error_free_ptes;
1118 if (!ped_device_write (disk->dev, ptes, 2,
1119 ptes_size / disk->dev->sector_size))
1120 goto error_free_ptes;
1122 /* Write Alternate PTH & PTEs */
1123 _generate_header (disk, 1, ptes_crc, &gpt);
1124 pth_raw = pth_get_raw (disk->dev, gpt);
1126 write_ok = ped_device_write (disk->dev, pth_raw,
1127 disk->dev->length - 1, 1);
1130 goto error_free_ptes;
1131 if (!ped_device_write (disk->dev, ptes,
1132 disk->dev->length - 1 - ptes_size / disk->dev->sector_size,
1133 ptes_size / disk->dev->sector_size))
1134 goto error_free_ptes;
1137 return ped_device_sync (disk->dev);
1145 #endif /* !DISCOVER_ONLY */
1148 add_metadata_part(PedDisk * disk, PedSector start, PedSector length)
1151 PedConstraint* constraint_exact;
1152 PED_ASSERT(disk != NULL, return 0);
1154 part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1155 start, start + length - 1);
1159 constraint_exact = ped_constraint_exact (&part->geom);
1160 if (!ped_disk_add_partition (disk, part, constraint_exact))
1161 goto error_destroy_constraint;
1162 ped_constraint_destroy (constraint_exact);
1165 error_destroy_constraint:
1166 ped_constraint_destroy (constraint_exact);
1167 ped_partition_destroy (part);
1172 static PedPartition*
1173 gpt_partition_new (const PedDisk* disk,
1174 PedPartitionType part_type, const PedFileSystemType* fs_type,
1175 PedSector start, PedSector end)
1178 GPTPartitionData* gpt_part_data;
1180 part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1187 gpt_part_data = part->disk_specific =
1188 ped_malloc (sizeof (GPTPartitionData));
1190 goto error_free_part;
1192 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1193 gpt_part_data->lvm = 0;
1194 gpt_part_data->raid = 0;
1195 gpt_part_data->boot = 0;
1196 gpt_part_data->bios_grub = 0;
1197 gpt_part_data->hp_service = 0;
1198 gpt_part_data->hidden = 0;
1199 gpt_part_data->msftres = 0;
1200 uuid_generate ((unsigned char*) &gpt_part_data->uuid);
1201 swap_uuid_and_efi_guid((unsigned char*)(&gpt_part_data->uuid));
1202 memset (gpt_part_data->name, 0, sizeof gpt_part_data->name);
1206 _ped_partition_free (part);
1211 static PedPartition*
1212 gpt_partition_duplicate (const PedPartition* part)
1214 PedPartition* result;
1215 GPTPartitionData* part_data = part->disk_specific;
1216 GPTPartitionData* result_data;
1218 result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
1219 part->geom.start, part->geom.end);
1222 result->num = part->num;
1224 if (result->type != 0)
1227 result_data = result->disk_specific =
1228 ped_malloc (sizeof (GPTPartitionData));
1230 goto error_free_part;
1232 result_data->type = part_data->type;
1233 result_data->uuid = part_data->uuid;
1234 strcpy (result_data->name, part_data->name);
1238 _ped_partition_free (result);
1244 gpt_partition_destroy (PedPartition *part)
1246 if (part->type == 0) {
1247 PED_ASSERT (part->disk_specific != NULL, return);
1248 free (part->disk_specific);
1251 _ped_partition_free (part);
1255 gpt_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
1257 GPTPartitionData* gpt_part_data = part->disk_specific;
1259 PED_ASSERT (gpt_part_data != NULL, return 0);
1261 part->fs_type = fs_type;
1263 if (gpt_part_data->lvm) {
1264 gpt_part_data->type = PARTITION_LVM_GUID;
1267 if (gpt_part_data->raid) {
1268 gpt_part_data->type = PARTITION_RAID_GUID;
1271 if (gpt_part_data->boot) {
1272 gpt_part_data->type = PARTITION_SYSTEM_GUID;
1275 if (gpt_part_data->bios_grub) {
1276 gpt_part_data->type = PARTITION_BIOS_GRUB_GUID;
1279 if (gpt_part_data->hp_service) {
1280 gpt_part_data->type = PARTITION_HPSERVICE_GUID;
1283 if (gpt_part_data->msftres) {
1284 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1289 if (strncmp (fs_type->name, "fat", 3) == 0
1290 || strcmp (fs_type->name, "ntfs") == 0) {
1291 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1294 if (strncmp (fs_type->name, "hfs", 3) == 0) {
1295 gpt_part_data->type = PARTITION_APPLE_HFS_GUID;
1298 if (strstr (fs_type->name, "swap")) {
1299 gpt_part_data->type = PARTITION_SWAP_GUID;
1304 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1308 /* Allocate metadata partitions for the GPTH and PTES */
1310 gpt_alloc_metadata (PedDisk * disk)
1312 PedSector gptlength, pteslength = 0;
1313 GPTDiskData *gpt_disk_data;
1315 PED_ASSERT(disk != NULL, return 0);
1316 PED_ASSERT(disk->dev != NULL, return 0);
1317 PED_ASSERT(disk->disk_specific != NULL, return 0);
1318 gpt_disk_data = disk->disk_specific;
1320 gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t),
1321 disk->dev->sector_size);
1322 pteslength = ped_div_round_up (gpt_disk_data->entry_count
1323 * sizeof (GuidPartitionEntry_t), disk->dev->sector_size);
1325 /* metadata at the start of the disk includes the MBR */
1326 if (!add_metadata_part(disk, GPT_PMBR_LBA,
1327 GPT_PMBR_SECTORS + gptlength + pteslength))
1330 /* metadata at the end of the disk */
1331 if (!add_metadata_part(disk, disk->dev->length - gptlength - pteslength,
1332 gptlength + pteslength))
1338 /* Does nothing, as the read/new/destroy functions maintain part->num */
1340 gpt_partition_enumerate (PedPartition* part)
1342 GPTDiskData* gpt_disk_data = part->disk->disk_specific;
1345 /* never change the partition numbers */
1346 if (part->num != -1)
1349 for (i = 1; i <= gpt_disk_data->entry_count; i++) {
1350 if (!ped_disk_get_partition (part->disk, i)) {
1356 PED_ASSERT (0, return 0);
1358 return 0; /* used if debug is disabled */
1362 gpt_partition_set_flag(PedPartition *part,
1363 PedPartitionFlag flag,
1366 GPTPartitionData *gpt_part_data;
1367 PED_ASSERT(part != NULL, return 0);
1368 PED_ASSERT(part->disk_specific != NULL, return 0);
1369 gpt_part_data = part->disk_specific;
1372 case PED_PARTITION_BOOT:
1373 gpt_part_data->boot = state;
1376 = gpt_part_data->lvm
1377 = gpt_part_data->bios_grub
1378 = gpt_part_data->hp_service
1379 = gpt_part_data->msftres = 0;
1380 return gpt_partition_set_system (part, part->fs_type);
1381 case PED_PARTITION_BIOS_GRUB:
1382 gpt_part_data->bios_grub = state;
1385 = gpt_part_data->lvm
1386 = gpt_part_data->boot
1387 = gpt_part_data->hp_service
1388 = gpt_part_data->msftres = 0;
1389 return gpt_partition_set_system (part, part->fs_type);
1390 case PED_PARTITION_RAID:
1391 gpt_part_data->raid = state;
1394 = gpt_part_data->lvm
1395 = gpt_part_data->bios_grub
1396 = gpt_part_data->hp_service
1397 = gpt_part_data->msftres = 0;
1398 return gpt_partition_set_system (part, part->fs_type);
1399 case PED_PARTITION_LVM:
1400 gpt_part_data->lvm = state;
1403 = gpt_part_data->raid
1404 = gpt_part_data->bios_grub
1405 = gpt_part_data->hp_service
1406 = gpt_part_data->msftres = 0;
1407 return gpt_partition_set_system (part, part->fs_type);
1408 case PED_PARTITION_HPSERVICE:
1409 gpt_part_data->hp_service = state;
1412 = gpt_part_data->raid
1413 = gpt_part_data->lvm
1414 = gpt_part_data->bios_grub
1415 = gpt_part_data->msftres = 0;
1416 return gpt_partition_set_system (part, part->fs_type);
1417 case PED_PARTITION_MSFT_RESERVED:
1418 gpt_part_data->msftres = state;
1421 = gpt_part_data->raid
1422 = gpt_part_data->lvm
1423 = gpt_part_data->bios_grub
1424 = gpt_part_data->hp_service = 0;
1425 return gpt_partition_set_system (part, part->fs_type);
1426 case PED_PARTITION_HIDDEN:
1427 gpt_part_data->hidden = state;
1429 case PED_PARTITION_SWAP:
1430 case PED_PARTITION_ROOT:
1431 case PED_PARTITION_LBA:
1439 gpt_partition_get_flag(const PedPartition *part, PedPartitionFlag flag)
1441 GPTPartitionData *gpt_part_data;
1442 PED_ASSERT(part->disk_specific != NULL, return 0);
1443 gpt_part_data = part->disk_specific;
1446 case PED_PARTITION_RAID:
1447 return gpt_part_data->raid;
1448 case PED_PARTITION_LVM:
1449 return gpt_part_data->lvm;
1450 case PED_PARTITION_BOOT:
1451 return gpt_part_data->boot;
1452 case PED_PARTITION_BIOS_GRUB:
1453 return gpt_part_data->bios_grub;
1454 case PED_PARTITION_HPSERVICE:
1455 return gpt_part_data->hp_service;
1456 case PED_PARTITION_MSFT_RESERVED:
1457 return gpt_part_data->msftres;
1458 case PED_PARTITION_HIDDEN:
1459 return gpt_part_data->hidden;
1460 case PED_PARTITION_SWAP:
1461 case PED_PARTITION_LBA:
1462 case PED_PARTITION_ROOT:
1470 gpt_partition_is_flag_available(const PedPartition * part,
1471 PedPartitionFlag flag)
1474 case PED_PARTITION_RAID:
1475 case PED_PARTITION_LVM:
1476 case PED_PARTITION_BOOT:
1477 case PED_PARTITION_BIOS_GRUB:
1478 case PED_PARTITION_HPSERVICE:
1479 case PED_PARTITION_MSFT_RESERVED:
1480 case PED_PARTITION_HIDDEN:
1482 case PED_PARTITION_SWAP:
1483 case PED_PARTITION_ROOT:
1484 case PED_PARTITION_LBA:
1492 gpt_partition_set_name (PedPartition *part, const char *name)
1494 GPTPartitionData *gpt_part_data = part->disk_specific;
1496 strncpy (gpt_part_data->name, name, 36);
1497 gpt_part_data->name [36] = 0;
1501 gpt_partition_get_name (const PedPartition * part)
1503 GPTPartitionData* gpt_part_data = part->disk_specific;
1504 return gpt_part_data->name;
1508 gpt_get_max_primary_partition_count (const PedDisk *disk)
1510 const GPTDiskData* gpt_disk_data = disk->disk_specific;
1511 return gpt_disk_data->entry_count;
1515 * From (http://developer.apple.com/technotes/tn2006/tn2166.html Chapter 5).
1516 * According to the specs the first LBA (LBA0) is not relevant (it exists
1517 * to maintain compatibility). on the second LBA(LBA1) gpt places the
1518 * header. The header is as big as the block size. After the header we
1519 * find the Entry array. Each element of said array, describes each
1520 * partition. One can have as much elements as can fit between the end of
1521 * the second LBA (where the header ends) and the FirstUsableLBA.
1522 * FirstUsableLBA is the first logical block that is used for contents
1523 * and is defined in header.
1525 * /---------------------------------------------------\
1526 * | BLOCK0 | HEADER | Entry Array | First Usable LBA |
1528 * \---------------------------------------------------/
1530 * /----------/ \----------\
1531 * /-----------------------------------------\
1532 * | E1 | E2 | E3 |...............| EN |
1533 * \-----------------------------------------/
1535 * The number of possible partitions or supported partitions is:
1536 * SP = FirstUsableLBA*Blocksize - 2*Blocksize / SizeOfPartitionEntry
1537 * SP = Blocksize(FirstusableLBA - 2) / SizeOfPartitoinEntry
1540 gpt_get_max_supported_partition_count (const PedDisk *disk, int *max_n)
1542 GuidPartitionTableHeader_t *pth = NULL;
1543 uint8_t *pth_raw = ped_malloc (pth_get_size (disk->dev));
1545 if (ped_device_read (disk->dev, pth_raw, 1, GPT_HEADER_SECTORS)
1546 || ped_device_read (disk->dev, pth_raw,
1547 disk->dev->length, GPT_HEADER_SECTORS))
1548 pth = pth_new_from_raw (disk->dev, pth_raw);
1554 *max_n = (disk->dev->sector_size * (pth->FirstUsableLBA - 2)
1555 / PED_LE32_TO_CPU (pth->SizeOfPartitionEntry));
1560 static PedConstraint*
1561 _non_metadata_constraint (const PedDisk* disk)
1563 GPTDiskData* gpt_disk_data = disk->disk_specific;
1565 return ped_constraint_new_from_max (&gpt_disk_data->data_area);
1569 gpt_partition_align (PedPartition* part, const PedConstraint* constraint)
1571 PED_ASSERT (part != NULL, return 0);
1573 if (_ped_partition_attempt_align (part, constraint,
1574 _non_metadata_constraint (part->disk)))
1577 #ifndef DISCOVER_ONLY
1578 ped_exception_throw (
1579 PED_EXCEPTION_ERROR,
1580 PED_EXCEPTION_CANCEL,
1581 _("Unable to satisfy all constraints on the partition."));
1587 gpt_partition_check (const PedPartition* part)
1592 static PedDiskOps gpt_disk_ops = {
1594 #ifndef DISCOVER_ONLY
1595 clobber: gpt_clobber,
1600 duplicate: gpt_duplicate,
1603 #ifndef DISCOVER_ONLY
1608 partition_new: gpt_partition_new,
1609 partition_duplicate: gpt_partition_duplicate,
1610 partition_destroy: gpt_partition_destroy,
1611 partition_set_system: gpt_partition_set_system,
1612 partition_set_flag: gpt_partition_set_flag,
1613 partition_get_flag: gpt_partition_get_flag,
1614 partition_is_flag_available: gpt_partition_is_flag_available,
1615 partition_set_name: gpt_partition_set_name,
1616 partition_get_name: gpt_partition_get_name,
1617 partition_align: gpt_partition_align,
1618 partition_enumerate: gpt_partition_enumerate,
1619 partition_check: gpt_partition_check,
1620 alloc_metadata: gpt_alloc_metadata,
1621 get_max_primary_partition_count: gpt_get_max_primary_partition_count,
1622 get_max_supported_partition_count: gpt_get_max_supported_partition_count
1625 static PedDiskType gpt_disk_type = {
1629 features: PED_DISK_TYPE_PARTITION_NAME
1635 PED_ASSERT (sizeof (GuidPartitionEntryAttributes_t) == 8, return);
1636 PED_ASSERT (sizeof (GuidPartitionEntry_t) == 128, return);
1638 ped_disk_type_register (&gpt_disk_type);
1644 ped_disk_type_unregister (&gpt_disk_type);