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>
44 # define _(String) gettext (String)
46 # define _(String) (String)
47 #endif /* ENABLE_NLS */
49 #define EFI_PMBR_OSTYPE_EFI 0xEE
50 #define MSDOS_MBR_SIGNATURE 0xaa55
52 #define GPT_HEADER_SIGNATURE 0x5452415020494645LL
54 /* NOTE: the document that describes revision 1.00 is labelled "version 1.02",
55 * so some implementors got confused...
57 #define GPT_HEADER_REVISION_V1_02 0x00010200
58 #define GPT_HEADER_REVISION_V1_00 0x00010000
59 #define GPT_HEADER_REVISION_V0_99 0x00009900
61 typedef uint16_t efi_char16_t; /* UNICODE character */
62 typedef struct _GuidPartitionTableHeader_t GuidPartitionTableHeader_t;
63 typedef struct _GuidPartitionEntryAttributes_t GuidPartitionEntryAttributes_t;
64 typedef struct _GuidPartitionEntry_t GuidPartitionEntry_t;
65 typedef struct _PartitionRecord_t PartitionRecord_t;
66 typedef struct _LegacyMBR_t LegacyMBR_t;
67 typedef struct _GPTDiskData GPTDiskData;
71 uint16_t time_hi_and_version;
72 uint8_t clock_seq_hi_and_reserved;
73 uint8_t clock_seq_low;
75 } /* __attribute__ ((packed)) */ efi_guid_t;
76 /* commented out "__attribute__ ((packed))" to work around gcc bug (fixed
77 * in gcc3.1): __attribute__ ((packed)) breaks addressing on initialized
78 * data. It turns out we don't need it in this case, so it doesn't break
82 #define UNUSED_ENTRY_GUID \
83 ((efi_guid_t) { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
84 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
85 #define PARTITION_SYSTEM_GUID \
86 ((efi_guid_t) { PED_CPU_TO_LE32 (0xC12A7328), PED_CPU_TO_LE16 (0xF81F), \
87 PED_CPU_TO_LE16 (0x11d2), 0xBA, 0x4B, \
88 { 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }})
89 #define PARTITION_BIOS_GRUB_GUID \
90 ((efi_guid_t) { PED_CPU_TO_LE32 (0x21686148), PED_CPU_TO_LE16 (0x6449), \
91 PED_CPU_TO_LE16 (0x6E6f), 0x74, 0x4E, \
92 { 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 }})
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 }})
130 struct __attribute__ ((packed)) _GuidPartitionTableHeader_t {
134 uint32_t HeaderCRC32;
137 uint64_t AlternateLBA;
138 uint64_t FirstUsableLBA;
139 uint64_t LastUsableLBA;
141 uint64_t PartitionEntryLBA;
142 uint32_t NumberOfPartitionEntries;
143 uint32_t SizeOfPartitionEntry;
144 uint32_t PartitionEntryArrayCRC32;
148 struct __attribute__ ((packed)) _GuidPartitionEntryAttributes_t {
149 #ifdef __GNUC__ /* XXX narrow this down to !TinyCC */
150 uint64_t RequiredToFunction:1;
151 uint64_t Reserved:47;
152 uint64_t GuidSpecific:16;
154 # warning "Using crippled partition entry type"
155 uint32_t RequiredToFunction:1;
156 uint32_t Reserved:32;
158 uint32_t GuidSpecific:16;
162 struct __attribute__ ((packed)) _GuidPartitionEntry_t {
163 efi_guid_t PartitionTypeGuid;
164 efi_guid_t UniquePartitionGuid;
165 uint64_t StartingLBA;
167 GuidPartitionEntryAttributes_t Attributes;
168 efi_char16_t PartitionName[72 / sizeof(efi_char16_t)];
171 #define GPT_PMBR_LBA 0
172 #define GPT_PMBR_SECTORS 1
173 #define GPT_PRIMARY_HEADER_LBA 1
174 #define GPT_HEADER_SECTORS 1
175 #define GPT_PRIMARY_PART_TABLE_LBA 2
178 These values are only defaults. The actual on-disk structures
179 may define different sizes, so use those unless creating a new GPT disk!
182 #define GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE 16384
184 /* Number of actual partition entries should be calculated as: */
185 #define GPT_DEFAULT_PARTITION_ENTRIES \
186 (GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / \
187 sizeof(GuidPartitionEntry_t))
190 struct __attribute__ ((packed)) _PartitionRecord_t {
191 /* Not used by EFI firmware. Set to 0x80 to indicate that this
192 is the bootable legacy partition. */
193 uint8_t BootIndicator;
195 /* Start of partition in CHS address, not used by EFI firmware. */
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 /* OS type. A value of 0xEF defines an EFI system partition.
205 Other values are reserved for legacy operating systems, and
206 allocated independently of the EFI specification. */
209 /* End of partition in CHS address, not used by EFI firmware. */
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 /* Starting LBA address of the partition on the disk. Used by
219 EFI firmware to define the start of the partition. */
220 uint32_t StartingLBA;
222 /* Size of partition in LBA. Used by EFI firmware to determine
223 the size of the partition. */
227 /* Protected Master Boot Record & Legacy MBR share same structure */
228 /* Needs to be packed because the u16s force misalignment. */
229 struct __attribute__ ((packed)) _LegacyMBR_t {
230 uint8_t BootCode[440];
231 uint32_t UniqueMBRSignature;
233 PartitionRecord_t PartitionRecord[4];
237 /* uses libparted's disk_specific field in PedDisk, to store our info */
238 struct __attribute__ ((packed)) _GPTDiskData {
239 PedGeometry data_area;
244 /* uses libparted's disk_specific field in PedPartition, to store our info */
245 typedef struct _GPTPartitionData {
258 static PedDiskType gpt_disk_type;
261 static inline uint32_t
262 pth_get_size (const PedDevice* dev)
264 return GPT_HEADER_SECTORS * dev->sector_size;
268 static inline uint32_t
269 pth_get_size_static (const PedDevice* dev)
271 return sizeof (GuidPartitionTableHeader_t) - sizeof (uint8_t*);
275 static inline uint32_t
276 pth_get_size_rsv2 (const PedDevice* dev)
278 return pth_get_size(dev) - pth_get_size_static(dev);
282 static GuidPartitionTableHeader_t*
283 pth_new (const PedDevice* dev)
285 GuidPartitionTableHeader_t* pth = ped_malloc (
286 sizeof (GuidPartitionTableHeader_t)
289 pth->Reserved2 = ped_malloc ( pth_get_size_rsv2 (dev) );
295 static GuidPartitionTableHeader_t*
296 pth_new_zeroed (const PedDevice* dev)
298 GuidPartitionTableHeader_t* pth = pth_new (dev);
300 memset (pth, 0, pth_get_size_static (dev));
301 memset (pth->Reserved2, 0, pth_get_size_rsv2 (dev));
307 static GuidPartitionTableHeader_t*
308 pth_new_from_raw (const PedDevice* dev, const uint8_t* pth_raw)
310 GuidPartitionTableHeader_t* pth = pth_new (dev);
312 PED_ASSERT (pth_raw != NULL, return 0);
314 memcpy (pth, pth_raw, pth_get_size_static (dev));
315 memcpy (pth->Reserved2, pth_raw + pth_get_size_static (dev),
316 pth_get_size_rsv2 (dev));
322 pth_free (GuidPartitionTableHeader_t* pth)
324 PED_ASSERT (pth != NULL, return);
325 PED_ASSERT (pth->Reserved2 != NULL, return);
327 free (pth->Reserved2);
332 pth_get_raw (const PedDevice* dev, const GuidPartitionTableHeader_t* pth)
334 uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
335 int size_static = pth_get_size_static (dev);
337 PED_ASSERT (pth != NULL, return 0);
338 PED_ASSERT (pth->Reserved2 != NULL, return 0);
340 memcpy (pth_raw, pth, size_static);
341 memcpy (pth_raw + size_static, pth->Reserved2, pth_get_size_rsv2 (dev));
348 * swap_uuid_and_efi_guid() - converts between uuid formats
349 * @uuid - uuid_t in either format (converts it to the other)
351 * There are two different representations for Globally Unique Identifiers
354 * The RFC specifies a UUID as a string of 16 bytes, essentially
355 * a big-endian array of char.
356 * Intel, in their EFI Specification, references the same RFC, but
357 * then defines a GUID as a structure of little-endian fields.
358 * Coincidentally, both structures have the same format when unparsed.
360 * When read from disk, EFI GUIDs are in struct of little endian format,
361 * and need to be converted to be treated as uuid_t in memory.
363 * When writing to disk, uuid_ts need to be converted into EFI GUIDs.
368 swap_uuid_and_efi_guid(uuid_t uuid)
370 efi_guid_t *guid = (efi_guid_t *)uuid;
372 PED_ASSERT(uuid != NULL, return);
373 guid->time_low = PED_SWAP32(guid->time_low);
374 guid->time_mid = PED_SWAP16(guid->time_mid);
375 guid->time_hi_and_version = PED_SWAP16(guid->time_hi_and_version);
378 /* returns the EFI-style CRC32 value for buf
379 * This function uses the crc32 function by Gary S. Brown,
380 * but seeds the function with ~0, and xor's with ~0 at the end.
382 static inline uint32_t
383 efi_crc32(const void *buf, unsigned long len)
385 return (__efi_crc32(buf, len, ~0L) ^ ~0L);
388 static inline uint32_t
389 pth_crc32(const PedDevice* dev, const GuidPartitionTableHeader_t* pth)
391 uint8_t* pth_raw = pth_get_raw (dev, pth);
394 PED_ASSERT (dev != NULL, return 0);
395 PED_ASSERT (pth != NULL, return 0);
397 crc32 = efi_crc32 (pth_raw, PED_LE32_TO_CPU (pth->HeaderSize));
405 guid_cmp (efi_guid_t left, efi_guid_t right)
407 return memcmp(&left, &right, sizeof(efi_guid_t));
410 /* checks if 'mbr' is a protective MBR partition table */
412 _pmbr_is_valid (const LegacyMBR_t* mbr)
416 PED_ASSERT(mbr != NULL, return 0);
418 if (mbr->Signature != PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE))
420 for (i = 0; i < 4; i++) {
421 if (mbr->PartitionRecord[i].OSType == EFI_PMBR_OSTYPE_EFI)
428 gpt_probe (const PedDevice * dev)
430 GuidPartitionTableHeader_t* gpt = NULL;
431 uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
432 LegacyMBR_t legacy_mbr;
433 int gpt_sig_found = 0;
435 PED_ASSERT (dev != NULL, return 0);
437 if (ped_device_read(dev, pth_raw, 1, GPT_HEADER_SECTORS)
438 || ped_device_read(dev, pth_raw, dev->length - 1, GPT_HEADER_SECTORS)) {
439 gpt = pth_new_from_raw (dev, pth_raw);
440 if (gpt->Signature == PED_CPU_TO_LE64(GPT_HEADER_SIGNATURE))
453 if (ped_device_read(dev, &legacy_mbr, 0, GPT_HEADER_SECTORS)) {
454 if (!_pmbr_is_valid (&legacy_mbr)) {
455 int ex_status = ped_exception_throw (
456 PED_EXCEPTION_WARNING,
457 PED_EXCEPTION_YES_NO,
458 _("%s contains GPT signatures, indicating that it has "
459 "a GPT table. However, it does not have a valid "
460 "fake msdos partition table, as it should. Perhaps "
461 "it was corrupted -- possibly by a program that "
462 "doesn't understand GPT partition tables. Or "
463 "perhaps you deleted the GPT table, and are now "
464 "using an msdos partition table. Is this a GPT "
467 if (ex_status == PED_EXCEPTION_NO)
475 #ifndef DISCOVER_ONLY
476 /* writes zeros to the PMBR and the primary and alternate GPTHs and PTEs */
478 gpt_clobber(PedDevice * dev)
481 uint8_t* zeroed_pth_raw = ped_malloc (pth_get_size (dev));
482 uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
483 GuidPartitionTableHeader_t* gpt;
485 PED_ASSERT (dev != NULL, return 0);
487 memset(&pmbr, 0, sizeof(pmbr));
488 memset(zeroed_pth_raw, 0, pth_get_size (dev));
491 * TO DISCUSS: check whether checksum is correct?
492 * If not, we might get a wrong AlternateLBA field and destroy
493 * one sector of random data.
495 if (!ped_device_read(dev, pth_raw,
496 GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS))
499 gpt = pth_new_from_raw (dev, pth_raw);
501 if (!ped_device_write(dev, &pmbr, GPT_PMBR_LBA, GPT_PMBR_SECTORS))
502 goto error_free_with_gpt;
503 if (!ped_device_write(dev, &zeroed_pth_raw,
504 GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS))
505 goto error_free_with_gpt;
506 if (!ped_device_write(dev, &zeroed_pth_raw, dev->length - GPT_HEADER_SECTORS,
508 goto error_free_with_gpt;
510 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA) < dev->length - 1) {
511 if (!ped_device_write(dev, gpt,
512 PED_LE64_TO_CPU (gpt->AlternateLBA),
525 free (zeroed_pth_raw);
528 #endif /* !DISCOVER_ONLY */
531 gpt_alloc (const PedDevice * dev)
534 GPTDiskData *gpt_disk_data;
535 PedSector data_start, data_end;
537 disk = _ped_disk_alloc ((PedDevice*)dev, &gpt_disk_type);
540 disk->disk_specific = gpt_disk_data = ped_malloc (sizeof (GPTDiskData));
541 if (!disk->disk_specific)
542 goto error_free_disk;
544 data_start = 2 + GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
545 data_end = dev->length - 2
546 - GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
547 ped_geometry_init (&gpt_disk_data->data_area, dev, data_start,
548 data_end - data_start + 1);
549 gpt_disk_data->entry_count = GPT_DEFAULT_PARTITION_ENTRIES;
550 uuid_generate ((unsigned char*) &gpt_disk_data->uuid);
551 swap_uuid_and_efi_guid((unsigned char*)(&gpt_disk_data->uuid));
561 gpt_duplicate (const PedDisk* disk)
564 GPTDiskData* new_disk_data;
565 GPTDiskData* old_disk_data;
567 new_disk = ped_disk_new_fresh (disk->dev, &gpt_disk_type);
571 old_disk_data = disk->disk_specific;
572 new_disk_data = new_disk->disk_specific;
574 ped_geometry_init (&new_disk_data->data_area, disk->dev,
575 old_disk_data->data_area.start,
576 old_disk_data->data_area.length);
577 new_disk_data->entry_count = old_disk_data->entry_count;
578 new_disk_data->uuid = old_disk_data->uuid;
583 gpt_free(PedDisk * disk)
585 ped_disk_delete_all (disk);
586 free (disk->disk_specific);
587 _ped_disk_free (disk);
591 _header_is_valid (const PedDevice* dev, GuidPartitionTableHeader_t* gpt)
593 uint32_t crc, origcrc;
595 if (PED_LE64_TO_CPU (gpt->Signature) != GPT_HEADER_SIGNATURE)
598 * "While the GUID Partition Table Header's size may increase
599 * in the future it cannot span more than one block on the
600 * device." EFI Specification, version 1.10, 11.2.2.1
602 if (PED_LE32_TO_CPU (gpt->HeaderSize) < pth_get_size_static (dev)
603 || PED_LE32_TO_CPU (gpt->HeaderSize) > dev->sector_size)
606 origcrc = gpt->HeaderCRC32;
607 gpt->HeaderCRC32 = 0;
608 crc = pth_crc32 (dev, gpt);
609 gpt->HeaderCRC32 = origcrc;
611 return crc == PED_LE32_TO_CPU (origcrc);
615 _read_header (const PedDevice* dev, GuidPartitionTableHeader_t** gpt,
618 uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
620 PED_ASSERT (dev != NULL, return 0);
622 if (!ped_device_read (dev, pth_raw, where, GPT_HEADER_SECTORS)) {
627 *gpt = pth_new_from_raw (dev, pth_raw);
631 if (_header_is_valid (dev, *gpt))
639 _parse_header (PedDisk* disk, 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) {
652 if (ped_exception_throw (
653 PED_EXCEPTION_WARNING,
654 PED_EXCEPTION_IGNORE_CANCEL,
655 _("The format of the GPT partition table is version "
656 "%x, which is newer than what Parted can "
657 "recognise. Please tell us! bug-parted@gnu.org"),
658 PED_LE32_TO_CPU (gpt->Revision))
659 != PED_EXCEPTION_IGNORE)
664 first_usable = PED_LE64_TO_CPU (gpt->FirstUsableLBA);
665 last_usable = PED_LE64_TO_CPU (gpt->LastUsableLBA);
669 Need to check whether the volume has grown, the LastUsableLBA is
670 normally set to disk->dev->length - 2 - ptes_size (at least for parted
671 created volumes), where ptes_size is the number of entries *
672 size of each entry / sector size or 16k / sector size, whatever the greater.
673 If the volume has grown, offer the user the chance to use the new
674 space or continue with the current usable area. Only ask once per
679 = (disk->dev->length - 2 -
680 ((PedSector)(PED_LE32_TO_CPU(gpt->NumberOfPartitionEntries)) *
681 (PedSector)(PED_LE32_TO_CPU(gpt->SizeOfPartitionEntry)) /
682 disk->dev->sector_size));
684 last_usable_min_default = disk->dev->length - 2 -
685 GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / disk->dev->sector_size;
687 if ( last_usable_if_grown > last_usable_min_default ) {
689 last_usable_if_grown = last_usable_min_default;
693 PED_ASSERT (last_usable > first_usable, return 0);
694 PED_ASSERT (last_usable <= disk->dev->length, return 0);
696 PED_ASSERT (last_usable_if_grown > first_usable, return 0);
697 PED_ASSERT (last_usable_if_grown <= disk->dev->length, return 0);
699 if ( !asked_already && last_usable < last_usable_if_grown ) {
701 PedExceptionOption q;
703 q = ped_exception_throw (PED_EXCEPTION_WARNING,
704 PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE,
705 _("Not all of the space available to %s appears "
706 "to be used, you can fix the GPT to use all of the "
707 "space (an extra %llu blocks) or continue with the "
708 "current setting? "), disk->dev->path,
709 (uint64_t)(last_usable_if_grown - last_usable));
712 if (q == PED_EXCEPTION_FIX) {
714 last_usable = last_usable_if_grown;
718 else if (q != PED_EXCEPTION_UNHANDLED ) {
724 ped_geometry_init (&gpt_disk_data->data_area, disk->dev,
725 first_usable, last_usable - first_usable + 1);
728 gpt_disk_data->entry_count
729 = PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries);
730 PED_ASSERT (gpt_disk_data->entry_count > 0, return 0);
731 PED_ASSERT (gpt_disk_data->entry_count <= 8192, return 0);
733 gpt_disk_data->uuid = gpt->DiskGUID;
739 _parse_part_entry (PedDisk* disk, GuidPartitionEntry_t* pte)
742 GPTPartitionData* gpt_part_data;
745 part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
746 PED_LE64_TO_CPU(pte->StartingLBA),
747 PED_LE64_TO_CPU(pte->EndingLBA));
751 gpt_part_data = part->disk_specific;
752 gpt_part_data->type = pte->PartitionTypeGuid;
753 gpt_part_data->uuid = pte->UniquePartitionGuid;
754 for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
755 gpt_part_data->name[i] = (efi_char16_t) PED_LE16_TO_CPU(
756 (uint16_t) pte->PartitionName[i]);
757 gpt_part_data->name[i] = 0;
759 gpt_part_data->lvm = gpt_part_data->raid
760 = gpt_part_data->boot = gpt_part_data->hp_service
761 = gpt_part_data->hidden = gpt_part_data->msftres
762 = gpt_part_data->bios_grub = 0;
764 if (pte->Attributes.RequiredToFunction & 0x1)
765 gpt_part_data->hidden = 1;
767 if (!guid_cmp (gpt_part_data->type, PARTITION_SYSTEM_GUID))
768 gpt_part_data->boot = 1;
769 else if (!guid_cmp (gpt_part_data->type, PARTITION_BIOS_GRUB_GUID))
770 gpt_part_data->bios_grub = 1;
771 else if (!guid_cmp (gpt_part_data->type, PARTITION_RAID_GUID))
772 gpt_part_data->raid = 1;
773 else if (!guid_cmp (gpt_part_data->type, PARTITION_LVM_GUID))
774 gpt_part_data->lvm = 1;
775 else if (!guid_cmp (gpt_part_data->type, PARTITION_HPSERVICE_GUID))
776 gpt_part_data->hp_service = 1;
777 else if (!guid_cmp (gpt_part_data->type, PARTITION_MSFT_RESERVED_GUID))
778 gpt_part_data->msftres = 1;
783 /************************************************************
784 * Intel is changing the EFI Spec. (after v1.02) to say that a
785 * disk is considered to have a GPT label only if the GPT
786 * structures are correct, and the MBR is actually a Protective
787 * MBR (has one 0xEE type partition).
788 * Problem occurs when a GPT-partitioned disk is then
789 * edited with a legacy (non-GPT-aware) application, such as
790 * fdisk (which doesn't generally erase the PGPT or AGPT).
791 * How should such a disk get handled? As a GPT disk (throwing
792 * away the fdisk changes), or as an MSDOS disk (throwing away
793 * the GPT information). Previously, I've taken the GPT-is-right,
794 * MBR is wrong, approach, to stay consistent with the EFI Spec.
795 * Intel disagrees, saying the disk should then be treated
796 * as having a msdos label, not a GPT label. If this is true,
797 * then what's the point of having an AGPT, since if the PGPT
798 * is screwed up, likely the PMBR is too, and the PMBR becomes
799 * a single point of failure.
800 * So, in the Linux kernel, I'm going to test for PMBR, and
801 * warn if it's not there, and treat the disk as MSDOS, with a note
802 * for users to use Parted to "fix up" their disk if they
803 * really want it to be considered GPT.
804 ************************************************************/
806 gpt_read (PedDisk * disk)
808 GPTDiskData *gpt_disk_data = disk->disk_specific;
809 GuidPartitionTableHeader_t* gpt;
810 GuidPartitionEntry_t* ptes;
813 #ifndef DISCOVER_ONLY
817 ped_disk_delete_all (disk);
820 * motivation: let the user decide about the pmbr... during
821 * ped_disk_probe(), they probably didn't get a choice...
823 if (!gpt_probe (disk->dev))
826 if (_read_header (disk->dev, &gpt, 1)) {
827 /* There used to be a GPT partition table here, with an
828 alternate LBA that extended beyond the current
829 end-of-device. Treat it as a non-match. */
830 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
831 > disk->dev->length - 1)
834 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
835 < disk->dev->length - 1) {
837 #ifndef DISCOVER_ONLY
838 switch (ped_exception_throw (
840 PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL | PED_EXCEPTION_IGNORE,
841 _("The backup GPT table is not at the end of the disk, as it "
842 "should be. This might mean that another operating system "
843 "believes the disk is smaller. Fix, by moving the backup "
844 "to the end (and removing the old backup)?"))) {
845 case PED_EXCEPTION_CANCEL:
847 case PED_EXCEPTION_FIX:
850 ped_malloc (pth_get_size (disk->dev));
852 memset (zeros, 0, disk->dev->sector_size);
853 ped_device_write (disk->dev, zeros,
854 PED_LE64_TO_CPU (gpt->AlternateLBA),
863 #endif /* !DISCOVER_ONLY */
865 } else { /* primary GPT *not* ok */
866 int alternate_ok = 0;
868 #ifndef DISCOVER_ONLY
872 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
873 < disk->dev->length - 1) {
874 alternate_ok = _read_header (disk->dev, &gpt,
875 PED_LE64_TO_CPU(gpt->AlternateLBA));
878 alternate_ok = _read_header (disk->dev, &gpt,
879 disk->dev->length - 1);
883 if (ped_exception_throw (
885 PED_EXCEPTION_OK_CANCEL,
886 _("The primary GPT table is corrupt, but the "
887 "backup appears OK, so that will be used."))
888 == PED_EXCEPTION_CANCEL)
891 ped_exception_throw (
893 PED_EXCEPTION_CANCEL,
894 _("Both the primary and backup GPT tables "
895 "are corrupt. Try making a fresh table, "
896 "and using Parted's rescue feature to "
897 "recover partitions."));
902 if (!_parse_header (disk, gpt, &write_back))
906 ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
907 ptes = (GuidPartitionEntry_t*) ped_malloc (ptes_size);
908 if (!ped_device_read (disk->dev, ptes,
909 PED_LE64_TO_CPU(gpt->PartitionEntryLBA),
910 ptes_size / disk->dev->sector_size))
911 goto error_free_ptes;
913 for (i = 0; i < gpt_disk_data->entry_count; i++) {
915 PedConstraint* constraint_exact;
917 if (!guid_cmp (ptes[i].PartitionTypeGuid, UNUSED_ENTRY_GUID))
920 part = _parse_part_entry (disk, &ptes[i]);
922 goto error_delete_all;
924 part->fs_type = ped_file_system_probe (&part->geom);
927 constraint_exact = ped_constraint_exact (&part->geom);
928 if (!ped_disk_add_partition(disk, part, constraint_exact)) {
929 ped_partition_destroy (part);
930 goto error_delete_all;
932 ped_constraint_destroy (constraint_exact);
936 #ifndef DISCOVER_ONLY
938 ped_disk_commit_to_dev (disk);
945 ped_disk_delete_all (disk);
954 #ifndef DISCOVER_ONLY
955 /* Writes the protective MBR (to keep DOS happy) */
957 _write_pmbr (PedDevice * dev)
961 memset(&pmbr, 0, sizeof(pmbr));
962 pmbr.Signature = PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE);
963 pmbr.PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI;
964 pmbr.PartitionRecord[0].StartSector = 1;
965 pmbr.PartitionRecord[0].EndHead = 0xFE;
966 pmbr.PartitionRecord[0].EndSector = 0xFF;
967 pmbr.PartitionRecord[0].EndTrack = 0xFF;
968 pmbr.PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32(1);
969 if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
970 pmbr.PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(0xFFFFFFFF);
972 pmbr.PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(dev->length - 1UL);
974 return ped_device_write (dev, &pmbr, GPT_PMBR_LBA, GPT_PMBR_SECTORS);
978 _generate_header (const PedDisk* disk, int alternate, uint32_t ptes_crc,
979 GuidPartitionTableHeader_t** gpt_p)
981 GPTDiskData* gpt_disk_data = disk->disk_specific;
982 GuidPartitionTableHeader_t* gpt;
984 *gpt_p = pth_new_zeroed (disk->dev);
988 gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE);
989 gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00);
992 gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev));
993 gpt->HeaderCRC32 = 0;
997 PedSector ptes_size = gpt_disk_data->entry_count
998 * sizeof (GuidPartitionEntry_t) / disk->dev->sector_size;
1000 gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1001 gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
1002 gpt->PartitionEntryLBA
1003 = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_size);
1005 gpt->MyLBA = PED_CPU_TO_LE64 (1);
1006 gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1007 gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
1010 gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
1011 gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
1012 gpt->DiskGUID = gpt_disk_data->uuid;
1013 gpt->NumberOfPartitionEntries
1014 = PED_CPU_TO_LE32 (gpt_disk_data->entry_count);
1015 gpt->SizeOfPartitionEntry
1016 = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t));
1017 gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32 (ptes_crc);
1018 gpt->HeaderCRC32 = PED_CPU_TO_LE32 (pth_crc32 (disk->dev, gpt));
1022 _partition_generate_part_entry (PedPartition* part, GuidPartitionEntry_t* pte)
1024 GPTPartitionData* gpt_part_data = part->disk_specific;
1027 PED_ASSERT (gpt_part_data != NULL, return);
1029 pte->PartitionTypeGuid = gpt_part_data->type;
1030 pte->UniquePartitionGuid = gpt_part_data->uuid;
1031 pte->StartingLBA = PED_CPU_TO_LE64(part->geom.start);
1032 pte->EndingLBA = PED_CPU_TO_LE64(part->geom.end);
1033 memset (&pte->Attributes, 0, sizeof (GuidPartitionEntryAttributes_t));
1035 if (gpt_part_data->hidden)
1036 pte->Attributes.RequiredToFunction = 1;
1038 for (i = 0; i < 72 / sizeof(efi_char16_t); i++)
1039 pte->PartitionName[i]
1040 = (efi_char16_t) PED_CPU_TO_LE16(
1041 (uint16_t) gpt_part_data->name[i]);
1045 gpt_write(const PedDisk * disk)
1047 GPTDiskData* gpt_disk_data;
1048 GuidPartitionEntry_t* ptes;
1051 GuidPartitionTableHeader_t* gpt;
1055 PED_ASSERT (disk != NULL, goto error);
1056 PED_ASSERT (disk->dev != NULL, goto error);
1057 PED_ASSERT (disk->disk_specific != NULL, goto error);
1059 gpt_disk_data = disk->disk_specific;
1061 ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
1062 ptes = (GuidPartitionEntry_t*) ped_malloc (ptes_size);
1065 memset (ptes, 0, ptes_size);
1066 for (part = ped_disk_next_partition (disk, NULL); part;
1067 part = ped_disk_next_partition (disk, part)) {
1068 if (part->type != 0)
1070 _partition_generate_part_entry (part, &ptes[part->num - 1]);
1073 ptes_crc = efi_crc32 (ptes, ptes_size);
1075 /* Write protective MBR */
1076 if (!_write_pmbr (disk->dev))
1077 goto error_free_ptes;
1079 /* Write PTH and PTEs */
1080 _generate_header (disk, 0, ptes_crc, &gpt);
1081 pth_raw = pth_get_raw (disk->dev, gpt);
1083 bool write_ok = ped_device_write (disk->dev, pth_raw, 1, 1);
1086 goto error_free_ptes;
1087 if (!ped_device_write (disk->dev, ptes, 2,
1088 ptes_size / disk->dev->sector_size))
1089 goto error_free_ptes;
1091 /* Write Alternate PTH & PTEs */
1092 _generate_header (disk, 1, ptes_crc, &gpt);
1093 pth_raw = pth_get_raw (disk->dev, gpt);
1095 write_ok = ped_device_write (disk->dev, pth_raw,
1096 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;
1106 return ped_device_sync (disk->dev);
1113 #endif /* !DISCOVER_ONLY */
1116 add_metadata_part(PedDisk * disk, PedSector start, PedSector length)
1119 PedConstraint* constraint_exact;
1120 PED_ASSERT(disk != NULL, return 0);
1122 part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1123 start, start + length - 1);
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);
1133 error_destroy_constraint:
1134 ped_constraint_destroy (constraint_exact);
1135 ped_partition_destroy (part);
1140 static PedPartition*
1141 gpt_partition_new (const PedDisk* disk,
1142 PedPartitionType part_type, const PedFileSystemType* fs_type,
1143 PedSector start, PedSector end)
1146 GPTPartitionData* gpt_part_data;
1148 part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1155 gpt_part_data = part->disk_specific =
1156 ped_malloc (sizeof (GPTPartitionData));
1158 goto error_free_part;
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->bios_grub = 0;
1165 gpt_part_data->hp_service = 0;
1166 gpt_part_data->hidden = 0;
1167 gpt_part_data->msftres = 0;
1168 uuid_generate ((unsigned char*) &gpt_part_data->uuid);
1169 swap_uuid_and_efi_guid((unsigned char*)(&gpt_part_data->uuid));
1170 memset (gpt_part_data->name, 0, sizeof gpt_part_data->name);
1174 _ped_partition_free (part);
1179 static PedPartition*
1180 gpt_partition_duplicate (const PedPartition* part)
1182 PedPartition* result;
1183 GPTPartitionData* part_data = part->disk_specific;
1184 GPTPartitionData* result_data;
1186 result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
1187 part->geom.start, part->geom.end);
1190 result->num = part->num;
1192 if (result->type != 0)
1195 result_data = result->disk_specific =
1196 ped_malloc (sizeof (GPTPartitionData));
1198 goto error_free_part;
1200 result_data->type = part_data->type;
1201 result_data->uuid = part_data->uuid;
1202 strcpy (result_data->name, part_data->name);
1206 _ped_partition_free (result);
1212 gpt_partition_destroy (PedPartition *part)
1214 if (part->type == 0) {
1215 PED_ASSERT (part->disk_specific != NULL, return);
1216 free (part->disk_specific);
1219 _ped_partition_free (part);
1223 gpt_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
1225 GPTPartitionData* gpt_part_data = part->disk_specific;
1227 PED_ASSERT (gpt_part_data != NULL, return 0);
1229 part->fs_type = fs_type;
1231 if (gpt_part_data->lvm) {
1232 gpt_part_data->type = PARTITION_LVM_GUID;
1235 if (gpt_part_data->raid) {
1236 gpt_part_data->type = PARTITION_RAID_GUID;
1239 if (gpt_part_data->boot) {
1240 gpt_part_data->type = PARTITION_SYSTEM_GUID;
1243 if (gpt_part_data->bios_grub) {
1244 gpt_part_data->type = PARTITION_BIOS_GRUB_GUID;
1247 if (gpt_part_data->hp_service) {
1248 gpt_part_data->type = PARTITION_HPSERVICE_GUID;
1251 if (gpt_part_data->msftres) {
1252 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1257 if (strncmp (fs_type->name, "fat", 3) == 0
1258 || strcmp (fs_type->name, "ntfs") == 0) {
1259 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1262 if (strncmp (fs_type->name, "hfs", 3) == 0) {
1263 gpt_part_data->type = PARTITION_APPLE_HFS_GUID;
1266 if (strstr (fs_type->name, "swap")) {
1267 gpt_part_data->type = PARTITION_SWAP_GUID;
1272 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1276 /* Allocate metadata partitions for the GPTH and PTES */
1278 gpt_alloc_metadata (PedDisk * disk)
1280 PedSector gptlength, pteslength = 0;
1281 GPTDiskData *gpt_disk_data;
1283 PED_ASSERT(disk != NULL, return 0);
1284 PED_ASSERT(disk->dev != NULL, return 0);
1285 PED_ASSERT(disk->disk_specific != NULL, return 0);
1286 gpt_disk_data = disk->disk_specific;
1288 gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t),
1289 disk->dev->sector_size);
1290 pteslength = ped_div_round_up (gpt_disk_data->entry_count
1291 * sizeof (GuidPartitionEntry_t), disk->dev->sector_size);
1293 /* metadata at the start of the disk includes the MBR */
1294 if (!add_metadata_part(disk, GPT_PMBR_LBA,
1295 GPT_PMBR_SECTORS + gptlength + pteslength))
1298 /* metadata at the end of the disk */
1299 if (!add_metadata_part(disk, disk->dev->length - gptlength - pteslength,
1300 gptlength + pteslength))
1306 /* Does nothing, as the read/new/destroy functions maintain part->num */
1308 gpt_partition_enumerate (PedPartition* part)
1310 GPTDiskData* gpt_disk_data = part->disk->disk_specific;
1313 /* never change the partition numbers */
1314 if (part->num != -1)
1317 for (i = 1; i <= gpt_disk_data->entry_count; i++) {
1318 if (!ped_disk_get_partition (part->disk, i)) {
1324 PED_ASSERT (0, return 0);
1326 return 0; /* used if debug is disabled */
1330 gpt_partition_set_flag(PedPartition *part,
1331 PedPartitionFlag flag,
1334 GPTPartitionData *gpt_part_data;
1335 PED_ASSERT(part != NULL, return 0);
1336 PED_ASSERT(part->disk_specific != NULL, return 0);
1337 gpt_part_data = part->disk_specific;
1340 case PED_PARTITION_BOOT:
1341 gpt_part_data->boot = state;
1344 = gpt_part_data->lvm
1345 = gpt_part_data->bios_grub
1346 = gpt_part_data->hp_service
1347 = gpt_part_data->msftres = 0;
1348 return gpt_partition_set_system (part, part->fs_type);
1349 case PED_PARTITION_BIOS_GRUB:
1350 gpt_part_data->bios_grub = state;
1353 = gpt_part_data->lvm
1354 = gpt_part_data->boot
1355 = gpt_part_data->hp_service
1356 = gpt_part_data->msftres = 0;
1357 return gpt_partition_set_system (part, part->fs_type);
1358 case PED_PARTITION_RAID:
1359 gpt_part_data->raid = state;
1362 = gpt_part_data->lvm
1363 = gpt_part_data->bios_grub
1364 = gpt_part_data->hp_service
1365 = gpt_part_data->msftres = 0;
1366 return gpt_partition_set_system (part, part->fs_type);
1367 case PED_PARTITION_LVM:
1368 gpt_part_data->lvm = state;
1371 = gpt_part_data->raid
1372 = gpt_part_data->bios_grub
1373 = gpt_part_data->hp_service
1374 = gpt_part_data->msftres = 0;
1375 return gpt_partition_set_system (part, part->fs_type);
1376 case PED_PARTITION_HPSERVICE:
1377 gpt_part_data->hp_service = state;
1380 = gpt_part_data->raid
1381 = gpt_part_data->lvm
1382 = gpt_part_data->bios_grub
1383 = gpt_part_data->msftres = 0;
1384 return gpt_partition_set_system (part, part->fs_type);
1385 case PED_PARTITION_MSFT_RESERVED:
1386 gpt_part_data->msftres = state;
1389 = gpt_part_data->raid
1390 = gpt_part_data->lvm
1391 = gpt_part_data->bios_grub
1392 = gpt_part_data->hp_service = 0;
1393 return gpt_partition_set_system (part, part->fs_type);
1394 case PED_PARTITION_HIDDEN:
1395 gpt_part_data->hidden = state;
1397 case PED_PARTITION_SWAP:
1398 case PED_PARTITION_ROOT:
1399 case PED_PARTITION_LBA:
1407 gpt_partition_get_flag(const PedPartition *part, PedPartitionFlag flag)
1409 GPTPartitionData *gpt_part_data;
1410 PED_ASSERT(part->disk_specific != NULL, return 0);
1411 gpt_part_data = part->disk_specific;
1414 case PED_PARTITION_RAID:
1415 return gpt_part_data->raid;
1416 case PED_PARTITION_LVM:
1417 return gpt_part_data->lvm;
1418 case PED_PARTITION_BOOT:
1419 return gpt_part_data->boot;
1420 case PED_PARTITION_BIOS_GRUB:
1421 return gpt_part_data->bios_grub;
1422 case PED_PARTITION_HPSERVICE:
1423 return gpt_part_data->hp_service;
1424 case PED_PARTITION_MSFT_RESERVED:
1425 return gpt_part_data->msftres;
1426 case PED_PARTITION_HIDDEN:
1427 return gpt_part_data->hidden;
1428 case PED_PARTITION_SWAP:
1429 case PED_PARTITION_LBA:
1430 case PED_PARTITION_ROOT:
1438 gpt_partition_is_flag_available(const PedPartition * part,
1439 PedPartitionFlag flag)
1442 case PED_PARTITION_RAID:
1443 case PED_PARTITION_LVM:
1444 case PED_PARTITION_BOOT:
1445 case PED_PARTITION_BIOS_GRUB:
1446 case PED_PARTITION_HPSERVICE:
1447 case PED_PARTITION_MSFT_RESERVED:
1448 case PED_PARTITION_HIDDEN:
1450 case PED_PARTITION_SWAP:
1451 case PED_PARTITION_ROOT:
1452 case PED_PARTITION_LBA:
1460 gpt_partition_set_name (PedPartition *part, const char *name)
1462 GPTPartitionData *gpt_part_data = part->disk_specific;
1464 strncpy (gpt_part_data->name, name, 36);
1465 gpt_part_data->name [36] = 0;
1469 gpt_partition_get_name (const PedPartition * part)
1471 GPTPartitionData* gpt_part_data = part->disk_specific;
1472 return gpt_part_data->name;
1476 gpt_get_max_primary_partition_count (const PedDisk *disk)
1478 const GPTDiskData* gpt_disk_data = disk->disk_specific;
1479 return gpt_disk_data->entry_count;
1483 * From (http://developer.apple.com/technotes/tn2006/tn2166.html Chapter 5).
1484 * According to the specs the first LBA (LBA0) is not relevant (it exists
1485 * to maintain compatibility). on the second LBA(LBA1) gpt places the
1486 * header. The header is as big as the block size. After the header we
1487 * find the Entry array. Each element of said array, describes each
1488 * partition. One can have as much elements as can fit between the end of
1489 * the second LBA (where the header ends) and the FirstUsableLBA.
1490 * FirstUsableLBA is the first logical block that is used for contents
1491 * and is defined in header.
1493 * /---------------------------------------------------\
1494 * | BLOCK0 | HEADER | Entry Array | First Usable LBA |
1496 * \---------------------------------------------------/
1498 * /----------/ \----------\
1499 * /-----------------------------------------\
1500 * | E1 | E2 | E3 |...............| EN |
1501 * \-----------------------------------------/
1503 * The number of possible partitions or supported partitions is:
1504 * SP = FirstUsableLBA*Blocksize - 2*Blocksize / SizeOfPartitionEntry
1505 * SP = Blocksize(FirstusableLBA - 2) / SizeOfPartitoinEntry
1508 gpt_get_max_supported_partition_count (const PedDisk *disk, int *max_n)
1510 GuidPartitionTableHeader_t *pth = NULL;
1511 uint8_t *pth_raw = ped_malloc (pth_get_size (disk->dev));
1513 if (ped_device_read (disk->dev, pth_raw, 1, GPT_HEADER_SECTORS)
1514 || ped_device_read (disk->dev, pth_raw,
1515 disk->dev->length, GPT_HEADER_SECTORS))
1516 pth = pth_new_from_raw (disk->dev, pth_raw);
1522 *max_n = (disk->dev->sector_size * (pth->FirstUsableLBA - 2)
1523 / pth->SizeOfPartitionEntry);
1528 static PedConstraint*
1529 _non_metadata_constraint (const PedDisk* disk)
1531 GPTDiskData* gpt_disk_data = disk->disk_specific;
1533 return ped_constraint_new_from_max (&gpt_disk_data->data_area);
1537 gpt_partition_align (PedPartition* part, const PedConstraint* constraint)
1539 PED_ASSERT (part != NULL, return 0);
1541 if (_ped_partition_attempt_align (part, constraint,
1542 _non_metadata_constraint (part->disk)))
1545 #ifndef DISCOVER_ONLY
1546 ped_exception_throw (
1547 PED_EXCEPTION_ERROR,
1548 PED_EXCEPTION_CANCEL,
1549 _("Unable to satisfy all constraints on the partition."));
1554 static PedDiskOps gpt_disk_ops = {
1556 #ifndef DISCOVER_ONLY
1557 clobber: gpt_clobber,
1562 duplicate: gpt_duplicate,
1565 #ifndef DISCOVER_ONLY
1570 partition_new: gpt_partition_new,
1571 partition_duplicate: gpt_partition_duplicate,
1572 partition_destroy: gpt_partition_destroy,
1573 partition_set_system: gpt_partition_set_system,
1574 partition_set_flag: gpt_partition_set_flag,
1575 partition_get_flag: gpt_partition_get_flag,
1576 partition_is_flag_available: gpt_partition_is_flag_available,
1577 partition_set_name: gpt_partition_set_name,
1578 partition_get_name: gpt_partition_get_name,
1579 partition_align: gpt_partition_align,
1580 partition_enumerate: gpt_partition_enumerate,
1581 alloc_metadata: gpt_alloc_metadata,
1582 get_max_primary_partition_count: gpt_get_max_primary_partition_count,
1583 get_max_supported_partition_count: gpt_get_max_supported_partition_count
1586 static PedDiskType gpt_disk_type = {
1590 features: PED_DISK_TYPE_PARTITION_NAME
1596 PED_ASSERT (sizeof (GuidPartitionEntryAttributes_t) == 8, return);
1597 PED_ASSERT (sizeof (GuidPartitionEntry_t) == 128, return);
1599 ped_disk_type_register (&gpt_disk_type);
1605 ped_disk_type_unregister (&gpt_disk_type);