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>
45 # define _(String) gettext (String)
47 # define _(String) (String)
48 #endif /* ENABLE_NLS */
50 #define EFI_PMBR_OSTYPE_EFI 0xEE
51 #define MSDOS_MBR_SIGNATURE 0xaa55
53 #define GPT_HEADER_SIGNATURE 0x5452415020494645LL
55 /* NOTE: the document that describes revision 1.00 is labelled "version 1.02",
56 * so some implementors got confused...
58 #define GPT_HEADER_REVISION_V1_02 0x00010200
59 #define GPT_HEADER_REVISION_V1_00 0x00010000
60 #define GPT_HEADER_REVISION_V0_99 0x00009900
62 typedef uint16_t efi_char16_t; /* UNICODE character */
63 typedef struct _GuidPartitionTableHeader_t GuidPartitionTableHeader_t;
64 typedef struct _GuidPartitionEntryAttributes_t GuidPartitionEntryAttributes_t;
65 typedef struct _GuidPartitionEntry_t GuidPartitionEntry_t;
66 typedef struct _PartitionRecord_t PartitionRecord_t;
67 typedef struct _LegacyMBR_t LegacyMBR_t;
68 typedef struct _GPTDiskData GPTDiskData;
72 uint16_t time_hi_and_version;
73 uint8_t clock_seq_hi_and_reserved;
74 uint8_t clock_seq_low;
76 } /* __attribute__ ((packed)) */ efi_guid_t;
77 /* commented out "__attribute__ ((packed))" to work around gcc bug (fixed
78 * in gcc3.1): __attribute__ ((packed)) breaks addressing on initialized
79 * data. It turns out we don't need it in this case, so it doesn't break
83 #define UNUSED_ENTRY_GUID \
84 ((efi_guid_t) { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
85 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
86 #define PARTITION_SYSTEM_GUID \
87 ((efi_guid_t) { PED_CPU_TO_LE32 (0xC12A7328), PED_CPU_TO_LE16 (0xF81F), \
88 PED_CPU_TO_LE16 (0x11d2), 0xBA, 0x4B, \
89 { 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }})
90 #define PARTITION_BIOS_GRUB_GUID \
91 ((efi_guid_t) { PED_CPU_TO_LE32 (0x21686148), PED_CPU_TO_LE16 (0x6449), \
92 PED_CPU_TO_LE16 (0x6E6f), 0x74, 0x4E, \
93 { 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 }})
94 #define LEGACY_MBR_PARTITION_GUID \
95 ((efi_guid_t) { PED_CPU_TO_LE32 (0x024DEE41), PED_CPU_TO_LE16 (0x33E7), \
96 PED_CPU_TO_LE16 (0x11d3, 0x9D, 0x69, \
97 { 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }})
98 #define PARTITION_MSFT_RESERVED_GUID \
99 ((efi_guid_t) { PED_CPU_TO_LE32 (0xE3C9E316), PED_CPU_TO_LE16 (0x0B5C), \
100 PED_CPU_TO_LE16 (0x4DB8), 0x81, 0x7D, \
101 { 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE }})
102 #define PARTITION_BASIC_DATA_GUID \
103 ((efi_guid_t) { PED_CPU_TO_LE32 (0xEBD0A0A2), PED_CPU_TO_LE16 (0xB9E5), \
104 PED_CPU_TO_LE16 (0x4433), 0x87, 0xC0, \
105 { 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }})
106 #define PARTITION_RAID_GUID \
107 ((efi_guid_t) { PED_CPU_TO_LE32 (0xa19d880f), PED_CPU_TO_LE16 (0x05fc), \
108 PED_CPU_TO_LE16 (0x4d3b), 0xa0, 0x06, \
109 { 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e }})
110 #define PARTITION_SWAP_GUID \
111 ((efi_guid_t) { PED_CPU_TO_LE32 (0x0657fd6d), PED_CPU_TO_LE16 (0xa4ab), \
112 PED_CPU_TO_LE16 (0x43c4), 0x84, 0xe5, \
113 { 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f }})
114 #define PARTITION_LVM_GUID \
115 ((efi_guid_t) { PED_CPU_TO_LE32 (0xe6d6d379), PED_CPU_TO_LE16 (0xf507), \
116 PED_CPU_TO_LE16 (0x44c2), 0xa2, 0x3c, \
117 { 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 }})
118 #define PARTITION_RESERVED_GUID \
119 ((efi_guid_t) { PED_CPU_TO_LE32 (0x8da63339), PED_CPU_TO_LE16 (0x0007), \
120 PED_CPU_TO_LE16 (0x60c0), 0xc4, 0x36, \
121 { 0x08, 0x3a, 0xc8, 0x23, 0x09, 0x08 }})
122 #define PARTITION_HPSERVICE_GUID \
123 ((efi_guid_t) { PED_CPU_TO_LE32 (0xe2a1e728), PED_CPU_TO_LE16 (0x32e3), \
124 PED_CPU_TO_LE16 (0x11d6), 0xa6, 0x82, \
125 { 0x7b, 0x03, 0xa0, 0x00, 0x00, 0x00 }})
126 #define PARTITION_APPLE_HFS_GUID \
127 ((efi_guid_t) { PED_CPU_TO_LE32 (0x48465300), PED_CPU_TO_LE16 (0x0000), \
128 PED_CPU_TO_LE16 (0x11AA), 0xaa, 0x11, \
129 { 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC }})
131 struct __attribute__ ((packed)) _GuidPartitionTableHeader_t {
135 uint32_t HeaderCRC32;
138 uint64_t AlternateLBA;
139 uint64_t FirstUsableLBA;
140 uint64_t LastUsableLBA;
142 uint64_t PartitionEntryLBA;
143 uint32_t NumberOfPartitionEntries;
144 uint32_t SizeOfPartitionEntry;
145 uint32_t PartitionEntryArrayCRC32;
149 struct __attribute__ ((packed)) _GuidPartitionEntryAttributes_t {
150 #ifdef __GNUC__ /* XXX narrow this down to !TinyCC */
151 uint64_t RequiredToFunction:1;
152 uint64_t Reserved:47;
153 uint64_t GuidSpecific:16;
155 # warning "Using crippled partition entry type"
156 uint32_t RequiredToFunction:1;
157 uint32_t Reserved:32;
159 uint32_t GuidSpecific:16;
163 struct __attribute__ ((packed)) _GuidPartitionEntry_t {
164 efi_guid_t PartitionTypeGuid;
165 efi_guid_t UniquePartitionGuid;
166 uint64_t StartingLBA;
168 GuidPartitionEntryAttributes_t Attributes;
169 efi_char16_t PartitionName[72 / sizeof(efi_char16_t)];
172 #define GPT_PMBR_LBA 0
173 #define GPT_PMBR_SECTORS 1
174 #define GPT_PRIMARY_HEADER_LBA 1
175 #define GPT_HEADER_SECTORS 1
176 #define GPT_PRIMARY_PART_TABLE_LBA 2
179 These values are only defaults. The actual on-disk structures
180 may define different sizes, so use those unless creating a new GPT disk!
183 #define GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE 16384
185 /* Number of actual partition entries should be calculated as: */
186 #define GPT_DEFAULT_PARTITION_ENTRIES \
187 (GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / \
188 sizeof(GuidPartitionEntry_t))
191 struct __attribute__ ((packed)) _PartitionRecord_t {
192 /* Not used by EFI firmware. Set to 0x80 to indicate that this
193 is the bootable legacy partition. */
194 uint8_t BootIndicator;
196 /* Start of partition in CHS address, not used by EFI firmware. */
199 /* Start of partition in CHS address, not used by EFI firmware. */
202 /* Start of partition in CHS address, not used by EFI firmware. */
205 /* OS type. A value of 0xEF defines an EFI system partition.
206 Other values are reserved for legacy operating systems, and
207 allocated independently of the EFI specification. */
210 /* End of partition in CHS address, not used by EFI firmware. */
213 /* End of partition in CHS address, not used by EFI firmware. */
216 /* End of partition in CHS address, not used by EFI firmware. */
219 /* Starting LBA address of the partition on the disk. Used by
220 EFI firmware to define the start of the partition. */
221 uint32_t StartingLBA;
223 /* Size of partition in LBA. Used by EFI firmware to determine
224 the size of the partition. */
228 /* Protected Master Boot Record & Legacy MBR share same structure */
229 /* Needs to be packed because the u16s force misalignment. */
230 struct __attribute__ ((packed)) _LegacyMBR_t {
231 uint8_t BootCode[440];
232 uint32_t UniqueMBRSignature;
234 PartitionRecord_t PartitionRecord[4];
238 /* uses libparted's disk_specific field in PedDisk, to store our info */
239 struct __attribute__ ((packed)) _GPTDiskData {
240 PedGeometry data_area;
245 /* uses libparted's disk_specific field in PedPartition, to store our info */
246 typedef struct _GPTPartitionData {
259 static PedDiskType gpt_disk_type;
262 static inline uint32_t
263 pth_get_size (const PedDevice* dev)
265 return GPT_HEADER_SECTORS * dev->sector_size;
269 static inline uint32_t
270 pth_get_size_static (const PedDevice* dev)
272 return sizeof (GuidPartitionTableHeader_t) - sizeof (uint8_t*);
276 static inline uint32_t
277 pth_get_size_rsv2 (const PedDevice* dev)
279 return pth_get_size(dev) - pth_get_size_static(dev);
283 static GuidPartitionTableHeader_t*
284 pth_new (const PedDevice* dev)
286 GuidPartitionTableHeader_t* pth = ped_malloc (
287 sizeof (GuidPartitionTableHeader_t)
290 pth->Reserved2 = ped_malloc ( pth_get_size_rsv2 (dev) );
296 static GuidPartitionTableHeader_t*
297 pth_new_zeroed (const PedDevice* dev)
299 GuidPartitionTableHeader_t* pth = pth_new (dev);
301 memset (pth, 0, pth_get_size_static (dev));
302 memset (pth->Reserved2, 0, pth_get_size_rsv2 (dev));
308 static GuidPartitionTableHeader_t*
309 pth_new_from_raw (const PedDevice* dev, const uint8_t* pth_raw)
311 GuidPartitionTableHeader_t* pth = pth_new (dev);
313 PED_ASSERT (pth_raw != NULL, return 0);
315 memcpy (pth, pth_raw, pth_get_size_static (dev));
316 memcpy (pth->Reserved2, pth_raw + pth_get_size_static (dev),
317 pth_get_size_rsv2 (dev));
323 pth_free (GuidPartitionTableHeader_t* pth)
325 PED_ASSERT (pth != NULL, return);
326 PED_ASSERT (pth->Reserved2 != NULL, return);
328 free (pth->Reserved2);
333 pth_get_raw (const PedDevice* dev, const GuidPartitionTableHeader_t* pth)
335 uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
336 int size_static = pth_get_size_static (dev);
338 PED_ASSERT (pth != NULL, return 0);
339 PED_ASSERT (pth->Reserved2 != NULL, return 0);
341 memcpy (pth_raw, pth, size_static);
342 memcpy (pth_raw + size_static, pth->Reserved2, pth_get_size_rsv2 (dev));
349 * swap_uuid_and_efi_guid() - converts between uuid formats
350 * @uuid - uuid_t in either format (converts it to the other)
352 * There are two different representations for Globally Unique Identifiers
355 * The RFC specifies a UUID as a string of 16 bytes, essentially
356 * a big-endian array of char.
357 * Intel, in their EFI Specification, references the same RFC, but
358 * then defines a GUID as a structure of little-endian fields.
359 * Coincidentally, both structures have the same format when unparsed.
361 * When read from disk, EFI GUIDs are in struct of little endian format,
362 * and need to be converted to be treated as uuid_t in memory.
364 * When writing to disk, uuid_ts need to be converted into EFI GUIDs.
369 swap_uuid_and_efi_guid(uuid_t uuid)
371 efi_guid_t *guid = (efi_guid_t *)uuid;
373 PED_ASSERT(uuid != NULL, return);
374 guid->time_low = PED_SWAP32(guid->time_low);
375 guid->time_mid = PED_SWAP16(guid->time_mid);
376 guid->time_hi_and_version = PED_SWAP16(guid->time_hi_and_version);
379 /* returns the EFI-style CRC32 value for buf
380 * This function uses the crc32 function by Gary S. Brown,
381 * but seeds the function with ~0, and xor's with ~0 at the end.
383 static inline uint32_t
384 efi_crc32(const void *buf, unsigned long len)
386 return (__efi_crc32(buf, len, ~0L) ^ ~0L);
389 static inline uint32_t
390 pth_crc32(const PedDevice* dev, const GuidPartitionTableHeader_t* pth)
392 uint8_t* pth_raw = pth_get_raw (dev, pth);
395 PED_ASSERT (dev != NULL, return 0);
396 PED_ASSERT (pth != NULL, return 0);
398 crc32 = efi_crc32 (pth_raw, PED_LE32_TO_CPU (pth->HeaderSize));
406 guid_cmp (efi_guid_t left, efi_guid_t right)
408 return memcmp(&left, &right, sizeof(efi_guid_t));
411 /* checks if 'mbr' is a protective MBR partition table */
413 _pmbr_is_valid (const LegacyMBR_t* mbr)
417 PED_ASSERT(mbr != NULL, return 0);
419 if (mbr->Signature != PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE))
421 for (i = 0; i < 4; i++) {
422 if (mbr->PartitionRecord[i].OSType == EFI_PMBR_OSTYPE_EFI)
429 gpt_probe (const PedDevice * dev)
431 GuidPartitionTableHeader_t* gpt = NULL;
432 uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
433 LegacyMBR_t legacy_mbr;
434 int gpt_sig_found = 0;
436 PED_ASSERT (dev != NULL, return 0);
438 if (ped_device_read(dev, pth_raw, 1, GPT_HEADER_SECTORS)
439 || ped_device_read(dev, pth_raw, dev->length - 1, GPT_HEADER_SECTORS)) {
440 gpt = pth_new_from_raw (dev, pth_raw);
441 if (gpt->Signature == PED_CPU_TO_LE64(GPT_HEADER_SIGNATURE))
454 if (ped_device_read(dev, &legacy_mbr, 0, GPT_HEADER_SECTORS)) {
455 if (!_pmbr_is_valid (&legacy_mbr)) {
456 int ex_status = ped_exception_throw (
457 PED_EXCEPTION_WARNING,
458 PED_EXCEPTION_YES_NO,
459 _("%s contains GPT signatures, indicating that it has "
460 "a GPT table. However, it does not have a valid "
461 "fake msdos partition table, as it should. Perhaps "
462 "it was corrupted -- possibly by a program that "
463 "doesn't understand GPT partition tables. Or "
464 "perhaps you deleted the GPT table, and are now "
465 "using an msdos partition table. Is this a GPT "
468 if (ex_status == PED_EXCEPTION_NO)
476 #ifndef DISCOVER_ONLY
477 /* writes zeros to the PMBR and the primary and alternate GPTHs and PTEs */
479 gpt_clobber(PedDevice * dev)
482 uint8_t* zeroed_pth_raw = ped_malloc (pth_get_size (dev));
483 uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
484 GuidPartitionTableHeader_t* gpt;
486 PED_ASSERT (dev != NULL, return 0);
488 memset(&pmbr, 0, sizeof(pmbr));
489 memset(zeroed_pth_raw, 0, pth_get_size (dev));
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))
500 gpt = pth_new_from_raw (dev, pth_raw);
502 if (!ped_device_write(dev, &pmbr, GPT_PMBR_LBA, GPT_PMBR_SECTORS))
503 goto error_free_with_gpt;
504 if (!ped_device_write(dev, &zeroed_pth_raw,
505 GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS))
506 goto error_free_with_gpt;
507 if (!ped_device_write(dev, &zeroed_pth_raw, dev->length - GPT_HEADER_SECTORS,
509 goto error_free_with_gpt;
511 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA) < dev->length - 1) {
512 if (!ped_device_write(dev, gpt,
513 PED_LE64_TO_CPU (gpt->AlternateLBA),
526 free (zeroed_pth_raw);
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 = gpt->SizeOfPartitionEntry;
612 if (sope % 8 != 0 || sope < sizeof(GuidPartitionEntry_t) )
615 origcrc = gpt->HeaderCRC32;
616 gpt->HeaderCRC32 = 0;
617 crc = pth_crc32 (dev, gpt);
618 gpt->HeaderCRC32 = origcrc;
620 return crc == PED_LE32_TO_CPU (origcrc);
624 _read_header (const PedDevice* dev, GuidPartitionTableHeader_t** gpt,
627 uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
629 PED_ASSERT (dev != NULL, return 0);
631 if (!ped_device_read (dev, pth_raw, where, GPT_HEADER_SECTORS)) {
636 *gpt = pth_new_from_raw (dev, pth_raw);
640 if (_header_is_valid (dev, *gpt))
648 _parse_header (PedDisk* disk, GuidPartitionTableHeader_t* gpt,
651 GPTDiskData* gpt_disk_data = disk->disk_specific;
652 PedSector first_usable;
653 PedSector last_usable;
654 PedSector last_usable_if_grown, last_usable_min_default;
655 static int asked_already;
657 PED_ASSERT (_header_is_valid (disk->dev, gpt), return 0);
659 #ifndef DISCOVER_ONLY
660 if (PED_LE32_TO_CPU (gpt->Revision) > GPT_HEADER_REVISION_V1_02) {
661 if (ped_exception_throw (
662 PED_EXCEPTION_WARNING,
663 PED_EXCEPTION_IGNORE_CANCEL,
664 _("The format of the GPT partition table is version "
665 "%x, which is newer than what Parted can "
666 "recognise. Please tell us! bug-parted@gnu.org"),
667 PED_LE32_TO_CPU (gpt->Revision))
668 != PED_EXCEPTION_IGNORE)
673 first_usable = PED_LE64_TO_CPU (gpt->FirstUsableLBA);
674 last_usable = PED_LE64_TO_CPU (gpt->LastUsableLBA);
678 Need to check whether the volume has grown, the LastUsableLBA is
679 normally set to disk->dev->length - 2 - ptes_size (at least for parted
680 created volumes), where ptes_size is the number of entries *
681 size of each entry / sector size or 16k / sector size, whatever the greater.
682 If the volume has grown, offer the user the chance to use the new
683 space or continue with the current usable area. Only ask once per
688 = (disk->dev->length - 2 -
689 ((PedSector)(PED_LE32_TO_CPU(gpt->NumberOfPartitionEntries)) *
690 (PedSector)(PED_LE32_TO_CPU(gpt->SizeOfPartitionEntry)) /
691 disk->dev->sector_size));
693 last_usable_min_default = disk->dev->length - 2 -
694 GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / disk->dev->sector_size;
696 if ( last_usable_if_grown > last_usable_min_default ) {
698 last_usable_if_grown = last_usable_min_default;
702 PED_ASSERT (last_usable > first_usable, return 0);
703 PED_ASSERT (last_usable <= disk->dev->length, return 0);
705 PED_ASSERT (last_usable_if_grown > first_usable, return 0);
706 PED_ASSERT (last_usable_if_grown <= disk->dev->length, return 0);
708 if ( !asked_already && last_usable < last_usable_if_grown ) {
710 PedExceptionOption q;
712 q = ped_exception_throw (PED_EXCEPTION_WARNING,
713 PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE,
714 _("Not all of the space available to %s appears "
715 "to be used, you can fix the GPT to use all of the "
716 "space (an extra %llu blocks) or continue with the "
717 "current setting? "), disk->dev->path,
718 (uint64_t)(last_usable_if_grown - last_usable));
721 if (q == PED_EXCEPTION_FIX) {
723 last_usable = last_usable_if_grown;
727 else if (q != PED_EXCEPTION_UNHANDLED ) {
733 ped_geometry_init (&gpt_disk_data->data_area, disk->dev,
734 first_usable, last_usable - first_usable + 1);
737 gpt_disk_data->entry_count
738 = PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries);
739 PED_ASSERT (gpt_disk_data->entry_count > 0, return 0);
740 PED_ASSERT (gpt_disk_data->entry_count <= 8192, return 0);
742 gpt_disk_data->uuid = gpt->DiskGUID;
748 _parse_part_entry (PedDisk* disk, GuidPartitionEntry_t* pte)
751 GPTPartitionData* gpt_part_data;
754 part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
755 PED_LE64_TO_CPU(pte->StartingLBA),
756 PED_LE64_TO_CPU(pte->EndingLBA));
760 gpt_part_data = part->disk_specific;
761 gpt_part_data->type = pte->PartitionTypeGuid;
762 gpt_part_data->uuid = pte->UniquePartitionGuid;
763 for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
764 gpt_part_data->name[i] = (efi_char16_t) PED_LE16_TO_CPU(
765 (uint16_t) pte->PartitionName[i]);
766 gpt_part_data->name[i] = 0;
768 gpt_part_data->lvm = gpt_part_data->raid
769 = gpt_part_data->boot = gpt_part_data->hp_service
770 = gpt_part_data->hidden = gpt_part_data->msftres
771 = gpt_part_data->bios_grub = 0;
773 if (pte->Attributes.RequiredToFunction & 0x1)
774 gpt_part_data->hidden = 1;
776 if (!guid_cmp (gpt_part_data->type, PARTITION_SYSTEM_GUID))
777 gpt_part_data->boot = 1;
778 else if (!guid_cmp (gpt_part_data->type, PARTITION_BIOS_GRUB_GUID))
779 gpt_part_data->bios_grub = 1;
780 else if (!guid_cmp (gpt_part_data->type, PARTITION_RAID_GUID))
781 gpt_part_data->raid = 1;
782 else if (!guid_cmp (gpt_part_data->type, PARTITION_LVM_GUID))
783 gpt_part_data->lvm = 1;
784 else if (!guid_cmp (gpt_part_data->type, PARTITION_HPSERVICE_GUID))
785 gpt_part_data->hp_service = 1;
786 else if (!guid_cmp (gpt_part_data->type, PARTITION_MSFT_RESERVED_GUID))
787 gpt_part_data->msftres = 1;
792 /************************************************************
793 * Intel is changing the EFI Spec. (after v1.02) to say that a
794 * disk is considered to have a GPT label only if the GPT
795 * structures are correct, and the MBR is actually a Protective
796 * MBR (has one 0xEE type partition).
797 * Problem occurs when a GPT-partitioned disk is then
798 * edited with a legacy (non-GPT-aware) application, such as
799 * fdisk (which doesn't generally erase the PGPT or AGPT).
800 * How should such a disk get handled? As a GPT disk (throwing
801 * away the fdisk changes), or as an MSDOS disk (throwing away
802 * the GPT information). Previously, I've taken the GPT-is-right,
803 * MBR is wrong, approach, to stay consistent with the EFI Spec.
804 * Intel disagrees, saying the disk should then be treated
805 * as having a msdos label, not a GPT label. If this is true,
806 * then what's the point of having an AGPT, since if the PGPT
807 * is screwed up, likely the PMBR is too, and the PMBR becomes
808 * a single point of failure.
809 * So, in the Linux kernel, I'm going to test for PMBR, and
810 * warn if it's not there, and treat the disk as MSDOS, with a note
811 * for users to use Parted to "fix up" their disk if they
812 * really want it to be considered GPT.
813 ************************************************************/
815 gpt_read (PedDisk * disk)
817 GPTDiskData *gpt_disk_data = disk->disk_specific;
818 GuidPartitionTableHeader_t* gpt;
822 #ifndef DISCOVER_ONLY
826 ped_disk_delete_all (disk);
829 * motivation: let the user decide about the pmbr... during
830 * ped_disk_probe(), they probably didn't get a choice...
832 if (!gpt_probe (disk->dev))
835 if (_read_header (disk->dev, &gpt, 1)) {
836 /* There used to be a GPT partition table here, with an
837 alternate LBA that extended beyond the current
838 end-of-device. Treat it as a non-match. */
839 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
840 > disk->dev->length - 1)
843 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
844 < disk->dev->length - 1) {
846 #ifndef DISCOVER_ONLY
847 switch (ped_exception_throw (
849 PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL | PED_EXCEPTION_IGNORE,
850 _("The backup GPT table is not at the end of the disk, as it "
851 "should be. This might mean that another operating system "
852 "believes the disk is smaller. Fix, by moving the backup "
853 "to the end (and removing the old backup)?"))) {
854 case PED_EXCEPTION_CANCEL:
856 case PED_EXCEPTION_FIX:
859 ped_malloc (pth_get_size (disk->dev));
861 memset (zeros, 0, disk->dev->sector_size);
862 ped_device_write (disk->dev, zeros,
863 PED_LE64_TO_CPU (gpt->AlternateLBA),
872 #endif /* !DISCOVER_ONLY */
874 } else { /* primary GPT *not* ok */
875 int alternate_ok = 0;
877 #ifndef DISCOVER_ONLY
881 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
882 < disk->dev->length - 1) {
883 alternate_ok = _read_header (disk->dev, &gpt,
884 PED_LE64_TO_CPU(gpt->AlternateLBA));
887 alternate_ok = _read_header (disk->dev, &gpt,
888 disk->dev->length - 1);
892 if (ped_exception_throw (
894 PED_EXCEPTION_OK_CANCEL,
895 _("The primary GPT table is corrupt, but the "
896 "backup appears OK, so that will be used."))
897 == PED_EXCEPTION_CANCEL)
900 ped_exception_throw (
902 PED_EXCEPTION_CANCEL,
903 _("Both the primary and backup GPT tables "
904 "are corrupt. Try making a fresh table, "
905 "and using Parted's rescue feature to "
906 "recover partitions."));
911 if (!_parse_header (disk, gpt, &write_back))
914 ptes_sectors = ped_div_round_up (gpt->SizeOfPartitionEntry
915 * gpt_disk_data->entry_count,
916 disk->dev->sector_size);
918 if (xalloc_oversized (ptes_sectors, disk->dev->sector_size))
920 ptes = ped_malloc (ptes_sectors * disk->dev->sector_size);
922 if (!ped_device_read (disk->dev, ptes,
923 PED_LE64_TO_CPU(gpt->PartitionEntryLBA),
925 goto error_free_ptes;
927 for (i = 0; i < gpt_disk_data->entry_count; i++) {
928 GuidPartitionEntry_t* pte
929 = (GuidPartitionEntry_t*) ((char *)ptes + i
930 * gpt->SizeOfPartitionEntry);
932 PedConstraint* constraint_exact;
934 if (!guid_cmp (pte->PartitionTypeGuid, UNUSED_ENTRY_GUID))
937 part = _parse_part_entry (disk, pte);
939 goto error_delete_all;
941 part->fs_type = ped_file_system_probe (&part->geom);
944 constraint_exact = ped_constraint_exact (&part->geom);
945 if (!ped_disk_add_partition(disk, part, constraint_exact)) {
946 ped_partition_destroy (part);
947 goto error_delete_all;
949 ped_constraint_destroy (constraint_exact);
953 #ifndef DISCOVER_ONLY
955 ped_disk_commit_to_dev (disk);
962 ped_disk_delete_all (disk);
971 #ifndef DISCOVER_ONLY
972 /* Write the protective MBR (to keep DOS happy) */
974 _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. */
982 if (ped_device_read (dev, &pmbr, 0, GPT_PMBR_SECTORS) < GPT_PMBR_SECTORS)
983 memset (&pmbr, 0, sizeof(pmbr));
985 /* Zero out all the legacy partitions.
986 There are 4 PartitionRecords. */
987 memset (pmbr.PartitionRecord, 0, sizeof pmbr.PartitionRecord);
989 pmbr.Signature = PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE);
990 pmbr.PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI;
991 pmbr.PartitionRecord[0].StartSector = 1;
992 pmbr.PartitionRecord[0].EndHead = 0xFE;
993 pmbr.PartitionRecord[0].EndSector = 0xFF;
994 pmbr.PartitionRecord[0].EndTrack = 0xFF;
995 pmbr.PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32(1);
996 if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
997 pmbr.PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(0xFFFFFFFF);
999 pmbr.PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(dev->length - 1UL);
1001 return ped_device_write (dev, &pmbr, GPT_PMBR_LBA, GPT_PMBR_SECTORS);
1005 _generate_header (const PedDisk* disk, int alternate, uint32_t ptes_crc,
1006 GuidPartitionTableHeader_t** gpt_p)
1008 GPTDiskData* gpt_disk_data = disk->disk_specific;
1009 GuidPartitionTableHeader_t* gpt;
1011 *gpt_p = pth_new_zeroed (disk->dev);
1015 gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE);
1016 gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00);
1019 gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev));
1020 gpt->HeaderCRC32 = 0;
1024 PedSector ptes_size = gpt_disk_data->entry_count
1025 * sizeof (GuidPartitionEntry_t) / disk->dev->sector_size;
1027 gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1028 gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
1029 gpt->PartitionEntryLBA
1030 = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_size);
1032 gpt->MyLBA = PED_CPU_TO_LE64 (1);
1033 gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1034 gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
1037 gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
1038 gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
1039 gpt->DiskGUID = gpt_disk_data->uuid;
1040 gpt->NumberOfPartitionEntries
1041 = PED_CPU_TO_LE32 (gpt_disk_data->entry_count);
1042 gpt->SizeOfPartitionEntry
1043 = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t));
1044 gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32 (ptes_crc);
1045 gpt->HeaderCRC32 = PED_CPU_TO_LE32 (pth_crc32 (disk->dev, gpt));
1049 _partition_generate_part_entry (PedPartition* part, GuidPartitionEntry_t* pte)
1051 GPTPartitionData* gpt_part_data = part->disk_specific;
1054 PED_ASSERT (gpt_part_data != NULL, return);
1056 pte->PartitionTypeGuid = gpt_part_data->type;
1057 pte->UniquePartitionGuid = gpt_part_data->uuid;
1058 pte->StartingLBA = PED_CPU_TO_LE64(part->geom.start);
1059 pte->EndingLBA = PED_CPU_TO_LE64(part->geom.end);
1060 memset (&pte->Attributes, 0, sizeof (GuidPartitionEntryAttributes_t));
1062 if (gpt_part_data->hidden)
1063 pte->Attributes.RequiredToFunction = 1;
1065 for (i = 0; i < 72 / sizeof(efi_char16_t); i++)
1066 pte->PartitionName[i]
1067 = (efi_char16_t) PED_CPU_TO_LE16(
1068 (uint16_t) gpt_part_data->name[i]);
1072 gpt_write(const PedDisk * disk)
1074 GPTDiskData* gpt_disk_data;
1075 GuidPartitionEntry_t* ptes;
1078 GuidPartitionTableHeader_t* gpt;
1082 PED_ASSERT (disk != NULL, goto error);
1083 PED_ASSERT (disk->dev != NULL, goto error);
1084 PED_ASSERT (disk->disk_specific != NULL, goto error);
1086 gpt_disk_data = disk->disk_specific;
1088 ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
1089 ptes = (GuidPartitionEntry_t*) ped_malloc (ptes_size);
1092 memset (ptes, 0, ptes_size);
1093 for (part = ped_disk_next_partition (disk, NULL); part;
1094 part = ped_disk_next_partition (disk, part)) {
1095 if (part->type != 0)
1097 _partition_generate_part_entry (part, &ptes[part->num - 1]);
1100 ptes_crc = efi_crc32 (ptes, ptes_size);
1102 /* Write protective MBR */
1103 if (!_write_pmbr (disk->dev))
1104 goto error_free_ptes;
1106 /* Write PTH and PTEs */
1107 _generate_header (disk, 0, ptes_crc, &gpt);
1108 pth_raw = pth_get_raw (disk->dev, gpt);
1110 bool write_ok = ped_device_write (disk->dev, pth_raw, 1, 1);
1113 goto error_free_ptes;
1114 if (!ped_device_write (disk->dev, ptes, 2,
1115 ptes_size / disk->dev->sector_size))
1116 goto error_free_ptes;
1118 /* Write Alternate PTH & PTEs */
1119 _generate_header (disk, 1, ptes_crc, &gpt);
1120 pth_raw = pth_get_raw (disk->dev, gpt);
1122 write_ok = ped_device_write (disk->dev, pth_raw,
1123 disk->dev->length - 1, 1);
1126 goto error_free_ptes;
1127 if (!ped_device_write (disk->dev, ptes,
1128 disk->dev->length - 1 - ptes_size / disk->dev->sector_size,
1129 ptes_size / disk->dev->sector_size))
1130 goto error_free_ptes;
1133 return ped_device_sync (disk->dev);
1140 #endif /* !DISCOVER_ONLY */
1143 add_metadata_part(PedDisk * disk, PedSector start, PedSector length)
1146 PedConstraint* constraint_exact;
1147 PED_ASSERT(disk != NULL, return 0);
1149 part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1150 start, start + length - 1);
1154 constraint_exact = ped_constraint_exact (&part->geom);
1155 if (!ped_disk_add_partition (disk, part, constraint_exact))
1156 goto error_destroy_constraint;
1157 ped_constraint_destroy (constraint_exact);
1160 error_destroy_constraint:
1161 ped_constraint_destroy (constraint_exact);
1162 ped_partition_destroy (part);
1167 static PedPartition*
1168 gpt_partition_new (const PedDisk* disk,
1169 PedPartitionType part_type, const PedFileSystemType* fs_type,
1170 PedSector start, PedSector end)
1173 GPTPartitionData* gpt_part_data;
1175 part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1182 gpt_part_data = part->disk_specific =
1183 ped_malloc (sizeof (GPTPartitionData));
1185 goto error_free_part;
1187 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1188 gpt_part_data->lvm = 0;
1189 gpt_part_data->raid = 0;
1190 gpt_part_data->boot = 0;
1191 gpt_part_data->bios_grub = 0;
1192 gpt_part_data->hp_service = 0;
1193 gpt_part_data->hidden = 0;
1194 gpt_part_data->msftres = 0;
1195 uuid_generate ((unsigned char*) &gpt_part_data->uuid);
1196 swap_uuid_and_efi_guid((unsigned char*)(&gpt_part_data->uuid));
1197 memset (gpt_part_data->name, 0, sizeof gpt_part_data->name);
1201 _ped_partition_free (part);
1206 static PedPartition*
1207 gpt_partition_duplicate (const PedPartition* part)
1209 PedPartition* result;
1210 GPTPartitionData* part_data = part->disk_specific;
1211 GPTPartitionData* result_data;
1213 result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
1214 part->geom.start, part->geom.end);
1217 result->num = part->num;
1219 if (result->type != 0)
1222 result_data = result->disk_specific =
1223 ped_malloc (sizeof (GPTPartitionData));
1225 goto error_free_part;
1227 result_data->type = part_data->type;
1228 result_data->uuid = part_data->uuid;
1229 strcpy (result_data->name, part_data->name);
1233 _ped_partition_free (result);
1239 gpt_partition_destroy (PedPartition *part)
1241 if (part->type == 0) {
1242 PED_ASSERT (part->disk_specific != NULL, return);
1243 free (part->disk_specific);
1246 _ped_partition_free (part);
1250 gpt_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
1252 GPTPartitionData* gpt_part_data = part->disk_specific;
1254 PED_ASSERT (gpt_part_data != NULL, return 0);
1256 part->fs_type = fs_type;
1258 if (gpt_part_data->lvm) {
1259 gpt_part_data->type = PARTITION_LVM_GUID;
1262 if (gpt_part_data->raid) {
1263 gpt_part_data->type = PARTITION_RAID_GUID;
1266 if (gpt_part_data->boot) {
1267 gpt_part_data->type = PARTITION_SYSTEM_GUID;
1270 if (gpt_part_data->bios_grub) {
1271 gpt_part_data->type = PARTITION_BIOS_GRUB_GUID;
1274 if (gpt_part_data->hp_service) {
1275 gpt_part_data->type = PARTITION_HPSERVICE_GUID;
1278 if (gpt_part_data->msftres) {
1279 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1284 if (strncmp (fs_type->name, "fat", 3) == 0
1285 || strcmp (fs_type->name, "ntfs") == 0) {
1286 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1289 if (strncmp (fs_type->name, "hfs", 3) == 0) {
1290 gpt_part_data->type = PARTITION_APPLE_HFS_GUID;
1293 if (strstr (fs_type->name, "swap")) {
1294 gpt_part_data->type = PARTITION_SWAP_GUID;
1299 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1303 /* Allocate metadata partitions for the GPTH and PTES */
1305 gpt_alloc_metadata (PedDisk * disk)
1307 PedSector gptlength, pteslength = 0;
1308 GPTDiskData *gpt_disk_data;
1310 PED_ASSERT(disk != NULL, return 0);
1311 PED_ASSERT(disk->dev != NULL, return 0);
1312 PED_ASSERT(disk->disk_specific != NULL, return 0);
1313 gpt_disk_data = disk->disk_specific;
1315 gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t),
1316 disk->dev->sector_size);
1317 pteslength = ped_div_round_up (gpt_disk_data->entry_count
1318 * sizeof (GuidPartitionEntry_t), disk->dev->sector_size);
1320 /* metadata at the start of the disk includes the MBR */
1321 if (!add_metadata_part(disk, GPT_PMBR_LBA,
1322 GPT_PMBR_SECTORS + gptlength + pteslength))
1325 /* metadata at the end of the disk */
1326 if (!add_metadata_part(disk, disk->dev->length - gptlength - pteslength,
1327 gptlength + pteslength))
1333 /* Does nothing, as the read/new/destroy functions maintain part->num */
1335 gpt_partition_enumerate (PedPartition* part)
1337 GPTDiskData* gpt_disk_data = part->disk->disk_specific;
1340 /* never change the partition numbers */
1341 if (part->num != -1)
1344 for (i = 1; i <= gpt_disk_data->entry_count; i++) {
1345 if (!ped_disk_get_partition (part->disk, i)) {
1351 PED_ASSERT (0, return 0);
1353 return 0; /* used if debug is disabled */
1357 gpt_partition_set_flag(PedPartition *part,
1358 PedPartitionFlag flag,
1361 GPTPartitionData *gpt_part_data;
1362 PED_ASSERT(part != NULL, return 0);
1363 PED_ASSERT(part->disk_specific != NULL, return 0);
1364 gpt_part_data = part->disk_specific;
1367 case PED_PARTITION_BOOT:
1368 gpt_part_data->boot = state;
1371 = gpt_part_data->lvm
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_BIOS_GRUB:
1377 gpt_part_data->bios_grub = state;
1380 = gpt_part_data->lvm
1381 = gpt_part_data->boot
1382 = gpt_part_data->hp_service
1383 = gpt_part_data->msftres = 0;
1384 return gpt_partition_set_system (part, part->fs_type);
1385 case PED_PARTITION_RAID:
1386 gpt_part_data->raid = state;
1389 = gpt_part_data->lvm
1390 = gpt_part_data->bios_grub
1391 = gpt_part_data->hp_service
1392 = gpt_part_data->msftres = 0;
1393 return gpt_partition_set_system (part, part->fs_type);
1394 case PED_PARTITION_LVM:
1395 gpt_part_data->lvm = state;
1398 = gpt_part_data->raid
1399 = gpt_part_data->bios_grub
1400 = gpt_part_data->hp_service
1401 = gpt_part_data->msftres = 0;
1402 return gpt_partition_set_system (part, part->fs_type);
1403 case PED_PARTITION_HPSERVICE:
1404 gpt_part_data->hp_service = state;
1407 = gpt_part_data->raid
1408 = gpt_part_data->lvm
1409 = gpt_part_data->bios_grub
1410 = gpt_part_data->msftres = 0;
1411 return gpt_partition_set_system (part, part->fs_type);
1412 case PED_PARTITION_MSFT_RESERVED:
1413 gpt_part_data->msftres = state;
1416 = gpt_part_data->raid
1417 = gpt_part_data->lvm
1418 = gpt_part_data->bios_grub
1419 = gpt_part_data->hp_service = 0;
1420 return gpt_partition_set_system (part, part->fs_type);
1421 case PED_PARTITION_HIDDEN:
1422 gpt_part_data->hidden = state;
1424 case PED_PARTITION_SWAP:
1425 case PED_PARTITION_ROOT:
1426 case PED_PARTITION_LBA:
1434 gpt_partition_get_flag(const PedPartition *part, PedPartitionFlag flag)
1436 GPTPartitionData *gpt_part_data;
1437 PED_ASSERT(part->disk_specific != NULL, return 0);
1438 gpt_part_data = part->disk_specific;
1441 case PED_PARTITION_RAID:
1442 return gpt_part_data->raid;
1443 case PED_PARTITION_LVM:
1444 return gpt_part_data->lvm;
1445 case PED_PARTITION_BOOT:
1446 return gpt_part_data->boot;
1447 case PED_PARTITION_BIOS_GRUB:
1448 return gpt_part_data->bios_grub;
1449 case PED_PARTITION_HPSERVICE:
1450 return gpt_part_data->hp_service;
1451 case PED_PARTITION_MSFT_RESERVED:
1452 return gpt_part_data->msftres;
1453 case PED_PARTITION_HIDDEN:
1454 return gpt_part_data->hidden;
1455 case PED_PARTITION_SWAP:
1456 case PED_PARTITION_LBA:
1457 case PED_PARTITION_ROOT:
1465 gpt_partition_is_flag_available(const PedPartition * part,
1466 PedPartitionFlag flag)
1469 case PED_PARTITION_RAID:
1470 case PED_PARTITION_LVM:
1471 case PED_PARTITION_BOOT:
1472 case PED_PARTITION_BIOS_GRUB:
1473 case PED_PARTITION_HPSERVICE:
1474 case PED_PARTITION_MSFT_RESERVED:
1475 case PED_PARTITION_HIDDEN:
1477 case PED_PARTITION_SWAP:
1478 case PED_PARTITION_ROOT:
1479 case PED_PARTITION_LBA:
1487 gpt_partition_set_name (PedPartition *part, const char *name)
1489 GPTPartitionData *gpt_part_data = part->disk_specific;
1491 strncpy (gpt_part_data->name, name, 36);
1492 gpt_part_data->name [36] = 0;
1496 gpt_partition_get_name (const PedPartition * part)
1498 GPTPartitionData* gpt_part_data = part->disk_specific;
1499 return gpt_part_data->name;
1503 gpt_get_max_primary_partition_count (const PedDisk *disk)
1505 const GPTDiskData* gpt_disk_data = disk->disk_specific;
1506 return gpt_disk_data->entry_count;
1510 * From (http://developer.apple.com/technotes/tn2006/tn2166.html Chapter 5).
1511 * According to the specs the first LBA (LBA0) is not relevant (it exists
1512 * to maintain compatibility). on the second LBA(LBA1) gpt places the
1513 * header. The header is as big as the block size. After the header we
1514 * find the Entry array. Each element of said array, describes each
1515 * partition. One can have as much elements as can fit between the end of
1516 * the second LBA (where the header ends) and the FirstUsableLBA.
1517 * FirstUsableLBA is the first logical block that is used for contents
1518 * and is defined in header.
1520 * /---------------------------------------------------\
1521 * | BLOCK0 | HEADER | Entry Array | First Usable LBA |
1523 * \---------------------------------------------------/
1525 * /----------/ \----------\
1526 * /-----------------------------------------\
1527 * | E1 | E2 | E3 |...............| EN |
1528 * \-----------------------------------------/
1530 * The number of possible partitions or supported partitions is:
1531 * SP = FirstUsableLBA*Blocksize - 2*Blocksize / SizeOfPartitionEntry
1532 * SP = Blocksize(FirstusableLBA - 2) / SizeOfPartitoinEntry
1535 gpt_get_max_supported_partition_count (const PedDisk *disk, int *max_n)
1537 GuidPartitionTableHeader_t *pth = NULL;
1538 uint8_t *pth_raw = ped_malloc (pth_get_size (disk->dev));
1540 if (ped_device_read (disk->dev, pth_raw, 1, GPT_HEADER_SECTORS)
1541 || ped_device_read (disk->dev, pth_raw,
1542 disk->dev->length, GPT_HEADER_SECTORS))
1543 pth = pth_new_from_raw (disk->dev, pth_raw);
1549 *max_n = (disk->dev->sector_size * (pth->FirstUsableLBA - 2)
1550 / pth->SizeOfPartitionEntry);
1555 static PedConstraint*
1556 _non_metadata_constraint (const PedDisk* disk)
1558 GPTDiskData* gpt_disk_data = disk->disk_specific;
1560 return ped_constraint_new_from_max (&gpt_disk_data->data_area);
1564 gpt_partition_align (PedPartition* part, const PedConstraint* constraint)
1566 PED_ASSERT (part != NULL, return 0);
1568 if (_ped_partition_attempt_align (part, constraint,
1569 _non_metadata_constraint (part->disk)))
1572 #ifndef DISCOVER_ONLY
1573 ped_exception_throw (
1574 PED_EXCEPTION_ERROR,
1575 PED_EXCEPTION_CANCEL,
1576 _("Unable to satisfy all constraints on the partition."));
1581 static PedDiskOps gpt_disk_ops = {
1583 #ifndef DISCOVER_ONLY
1584 clobber: gpt_clobber,
1589 duplicate: gpt_duplicate,
1592 #ifndef DISCOVER_ONLY
1597 partition_new: gpt_partition_new,
1598 partition_duplicate: gpt_partition_duplicate,
1599 partition_destroy: gpt_partition_destroy,
1600 partition_set_system: gpt_partition_set_system,
1601 partition_set_flag: gpt_partition_set_flag,
1602 partition_get_flag: gpt_partition_get_flag,
1603 partition_is_flag_available: gpt_partition_is_flag_available,
1604 partition_set_name: gpt_partition_set_name,
1605 partition_get_name: gpt_partition_get_name,
1606 partition_align: gpt_partition_align,
1607 partition_enumerate: gpt_partition_enumerate,
1608 alloc_metadata: gpt_alloc_metadata,
1609 get_max_primary_partition_count: gpt_get_max_primary_partition_count,
1610 get_max_supported_partition_count: gpt_get_max_supported_partition_count
1613 static PedDiskType gpt_disk_type = {
1617 features: PED_DISK_TYPE_PARTITION_NAME
1623 PED_ASSERT (sizeof (GuidPartitionEntryAttributes_t) == 8, return);
1624 PED_ASSERT (sizeof (GuidPartitionEntry_t) == 128, return);
1626 ped_disk_type_register (&gpt_disk_type);
1632 ped_disk_type_unregister (&gpt_disk_type);