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;
823 #ifndef DISCOVER_ONLY
827 ped_disk_delete_all (disk);
830 * motivation: let the user decide about the pmbr... during
831 * ped_disk_probe(), they probably didn't get a choice...
833 if (!gpt_probe (disk->dev))
836 if (_read_header (disk->dev, &gpt, 1)) {
837 /* There used to be a GPT partition table here, with an
838 alternate LBA that extended beyond the current
839 end-of-device. Treat it as a non-match. */
840 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
841 > disk->dev->length - 1)
844 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
845 < disk->dev->length - 1) {
847 #ifndef DISCOVER_ONLY
848 switch (ped_exception_throw (
850 PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL | PED_EXCEPTION_IGNORE,
851 _("The backup GPT table is not at the end of the disk, as it "
852 "should be. This might mean that another operating system "
853 "believes the disk is smaller. Fix, by moving the backup "
854 "to the end (and removing the old backup)?"))) {
855 case PED_EXCEPTION_CANCEL:
857 case PED_EXCEPTION_FIX:
860 ped_malloc (pth_get_size (disk->dev));
862 memset (zeros, 0, disk->dev->sector_size);
863 ped_device_write (disk->dev, zeros,
864 PED_LE64_TO_CPU (gpt->AlternateLBA),
873 #endif /* !DISCOVER_ONLY */
875 } else { /* primary GPT *not* ok */
876 int alternate_ok = 0;
878 #ifndef DISCOVER_ONLY
882 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
883 < disk->dev->length - 1) {
884 alternate_ok = _read_header (disk->dev, &gpt,
885 PED_LE64_TO_CPU(gpt->AlternateLBA));
888 alternate_ok = _read_header (disk->dev, &gpt,
889 disk->dev->length - 1);
893 if (ped_exception_throw (
895 PED_EXCEPTION_OK_CANCEL,
896 _("The primary GPT table is corrupt, but the "
897 "backup appears OK, so that will be used."))
898 == PED_EXCEPTION_CANCEL)
901 ped_exception_throw (
903 PED_EXCEPTION_CANCEL,
904 _("Both the primary and backup GPT tables "
905 "are corrupt. Try making a fresh table, "
906 "and using Parted's rescue feature to "
907 "recover partitions."));
912 if (!_parse_header (disk, gpt, &write_back))
915 uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
916 size_t ptes_bytes = p_ent_size * gpt_disk_data->entry_count;
917 size_t ptes_sectors = ped_div_round_up (ptes_bytes,
918 disk->dev->sector_size);
920 if (xalloc_oversized (ptes_sectors, disk->dev->sector_size))
922 ptes = ped_malloc (ptes_sectors * disk->dev->sector_size);
924 if (!ped_device_read (disk->dev, ptes,
925 PED_LE64_TO_CPU(gpt->PartitionEntryLBA),
927 goto error_free_ptes;
929 uint32_t ptes_crc = efi_crc32 (ptes, ptes_bytes);
930 if (ptes_crc != gpt->PartitionEntryArrayCRC32) {
931 ped_exception_throw (
933 PED_EXCEPTION_CANCEL,
934 _("partition table array (FIXME:which?) CRC mismatch"));
935 goto error_free_ptes;
938 for (i = 0; i < gpt_disk_data->entry_count; i++) {
939 GuidPartitionEntry_t* pte
940 = (GuidPartitionEntry_t*) ((char *)ptes + i * p_ent_size);
942 PedConstraint* constraint_exact;
944 if (!guid_cmp (pte->PartitionTypeGuid, UNUSED_ENTRY_GUID))
947 part = _parse_part_entry (disk, pte);
949 goto error_delete_all;
951 part->fs_type = ped_file_system_probe (&part->geom);
954 constraint_exact = ped_constraint_exact (&part->geom);
955 if (!ped_disk_add_partition(disk, part, constraint_exact)) {
956 ped_partition_destroy (part);
957 goto error_delete_all;
959 ped_constraint_destroy (constraint_exact);
963 #ifndef DISCOVER_ONLY
965 ped_disk_commit_to_dev (disk);
972 ped_disk_delete_all (disk);
981 #ifndef DISCOVER_ONLY
982 /* Write the protective MBR (to keep DOS happy) */
984 _write_pmbr (PedDevice * dev)
986 /* The UEFI spec is not clear about what to do with the following
987 elements of the Protective MBR (pmbr): BootCode (0-440B),
988 UniqueMBRSignature (440B-444B) and Unknown (444B-446B).
989 With this in mind, we try not to modify these elements. */
991 if (!ptt_read_sector (dev, 0, &s0))
993 LegacyMBR_t *pmbr = s0;
995 /* Zero out the legacy partitions. */
996 memset (pmbr->PartitionRecord, 0, sizeof pmbr->PartitionRecord);
998 pmbr->Signature = PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE);
999 pmbr->PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI;
1000 pmbr->PartitionRecord[0].StartSector = 1;
1001 pmbr->PartitionRecord[0].EndHead = 0xFE;
1002 pmbr->PartitionRecord[0].EndSector = 0xFF;
1003 pmbr->PartitionRecord[0].EndTrack = 0xFF;
1004 pmbr->PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32(1);
1005 if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
1006 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(0xFFFFFFFF);
1008 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(dev->length - 1UL);
1010 int write_ok = ped_device_write (dev, pmbr, GPT_PMBR_LBA,
1017 _generate_header (const PedDisk* disk, int alternate, uint32_t ptes_crc,
1018 GuidPartitionTableHeader_t** gpt_p)
1020 GPTDiskData* gpt_disk_data = disk->disk_specific;
1021 GuidPartitionTableHeader_t* gpt;
1023 *gpt_p = pth_new_zeroed (disk->dev);
1027 gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE);
1028 gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00);
1031 gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev));
1032 gpt->HeaderCRC32 = 0;
1036 PedSector ptes_size = gpt_disk_data->entry_count
1037 * sizeof (GuidPartitionEntry_t) / disk->dev->sector_size;
1039 gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1040 gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
1041 gpt->PartitionEntryLBA
1042 = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_size);
1044 gpt->MyLBA = PED_CPU_TO_LE64 (1);
1045 gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1046 gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
1049 gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
1050 gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
1051 gpt->DiskGUID = gpt_disk_data->uuid;
1052 gpt->NumberOfPartitionEntries
1053 = PED_CPU_TO_LE32 (gpt_disk_data->entry_count);
1054 gpt->SizeOfPartitionEntry
1055 = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t));
1056 gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32 (ptes_crc);
1057 gpt->HeaderCRC32 = PED_CPU_TO_LE32 (pth_crc32 (disk->dev, gpt));
1061 _partition_generate_part_entry (PedPartition* part, GuidPartitionEntry_t* pte)
1063 GPTPartitionData* gpt_part_data = part->disk_specific;
1066 PED_ASSERT (gpt_part_data != NULL, return);
1068 pte->PartitionTypeGuid = gpt_part_data->type;
1069 pte->UniquePartitionGuid = gpt_part_data->uuid;
1070 pte->StartingLBA = PED_CPU_TO_LE64(part->geom.start);
1071 pte->EndingLBA = PED_CPU_TO_LE64(part->geom.end);
1072 memset (&pte->Attributes, 0, sizeof (GuidPartitionEntryAttributes_t));
1074 if (gpt_part_data->hidden)
1075 pte->Attributes.RequiredToFunction = 1;
1077 for (i = 0; i < 72 / sizeof(efi_char16_t); i++)
1078 pte->PartitionName[i]
1079 = (efi_char16_t) PED_CPU_TO_LE16(
1080 (uint16_t) gpt_part_data->name[i]);
1084 gpt_write(const PedDisk * disk)
1086 GPTDiskData* gpt_disk_data;
1087 GuidPartitionEntry_t* ptes;
1090 GuidPartitionTableHeader_t* gpt;
1094 PED_ASSERT (disk != NULL, goto error);
1095 PED_ASSERT (disk->dev != NULL, goto error);
1096 PED_ASSERT (disk->disk_specific != NULL, goto error);
1098 gpt_disk_data = disk->disk_specific;
1100 ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
1101 ptes = (GuidPartitionEntry_t*) ped_malloc (ptes_size);
1104 memset (ptes, 0, ptes_size);
1105 for (part = ped_disk_next_partition (disk, NULL); part;
1106 part = ped_disk_next_partition (disk, part)) {
1107 if (part->type != 0)
1109 _partition_generate_part_entry (part, &ptes[part->num - 1]);
1112 ptes_crc = efi_crc32 (ptes, ptes_size);
1114 /* Write protective MBR */
1115 if (!_write_pmbr (disk->dev))
1116 goto error_free_ptes;
1118 /* Write PTH and PTEs */
1119 _generate_header (disk, 0, ptes_crc, &gpt);
1120 pth_raw = pth_get_raw (disk->dev, gpt);
1122 bool write_ok = ped_device_write (disk->dev, pth_raw, 1, 1);
1125 goto error_free_ptes;
1126 if (!ped_device_write (disk->dev, ptes, 2,
1127 ptes_size / disk->dev->sector_size))
1128 goto error_free_ptes;
1130 /* Write Alternate PTH & PTEs */
1131 _generate_header (disk, 1, ptes_crc, &gpt);
1132 pth_raw = pth_get_raw (disk->dev, gpt);
1134 write_ok = ped_device_write (disk->dev, pth_raw,
1135 disk->dev->length - 1, 1);
1138 goto error_free_ptes;
1139 if (!ped_device_write (disk->dev, ptes,
1140 disk->dev->length - 1 - ptes_size / disk->dev->sector_size,
1141 ptes_size / disk->dev->sector_size))
1142 goto error_free_ptes;
1145 return ped_device_sync (disk->dev);
1153 #endif /* !DISCOVER_ONLY */
1156 add_metadata_part(PedDisk * disk, PedSector start, PedSector length)
1159 PedConstraint* constraint_exact;
1160 PED_ASSERT(disk != NULL, return 0);
1162 part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1163 start, start + length - 1);
1167 constraint_exact = ped_constraint_exact (&part->geom);
1168 if (!ped_disk_add_partition (disk, part, constraint_exact))
1169 goto error_destroy_constraint;
1170 ped_constraint_destroy (constraint_exact);
1173 error_destroy_constraint:
1174 ped_constraint_destroy (constraint_exact);
1175 ped_partition_destroy (part);
1180 static PedPartition*
1181 gpt_partition_new (const PedDisk* disk,
1182 PedPartitionType part_type, const PedFileSystemType* fs_type,
1183 PedSector start, PedSector end)
1186 GPTPartitionData* gpt_part_data;
1188 part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1195 gpt_part_data = part->disk_specific =
1196 ped_malloc (sizeof (GPTPartitionData));
1198 goto error_free_part;
1200 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1201 gpt_part_data->lvm = 0;
1202 gpt_part_data->raid = 0;
1203 gpt_part_data->boot = 0;
1204 gpt_part_data->bios_grub = 0;
1205 gpt_part_data->hp_service = 0;
1206 gpt_part_data->hidden = 0;
1207 gpt_part_data->msftres = 0;
1208 uuid_generate ((unsigned char*) &gpt_part_data->uuid);
1209 swap_uuid_and_efi_guid((unsigned char*)(&gpt_part_data->uuid));
1210 memset (gpt_part_data->name, 0, sizeof gpt_part_data->name);
1214 _ped_partition_free (part);
1219 static PedPartition*
1220 gpt_partition_duplicate (const PedPartition* part)
1222 PedPartition* result;
1223 GPTPartitionData* part_data = part->disk_specific;
1224 GPTPartitionData* result_data;
1226 result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
1227 part->geom.start, part->geom.end);
1230 result->num = part->num;
1232 if (result->type != 0)
1235 result_data = result->disk_specific =
1236 ped_malloc (sizeof (GPTPartitionData));
1238 goto error_free_part;
1240 result_data->type = part_data->type;
1241 result_data->uuid = part_data->uuid;
1242 strcpy (result_data->name, part_data->name);
1246 _ped_partition_free (result);
1252 gpt_partition_destroy (PedPartition *part)
1254 if (part->type == 0) {
1255 PED_ASSERT (part->disk_specific != NULL, return);
1256 free (part->disk_specific);
1259 _ped_partition_free (part);
1263 gpt_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
1265 GPTPartitionData* gpt_part_data = part->disk_specific;
1267 PED_ASSERT (gpt_part_data != NULL, return 0);
1269 part->fs_type = fs_type;
1271 if (gpt_part_data->lvm) {
1272 gpt_part_data->type = PARTITION_LVM_GUID;
1275 if (gpt_part_data->raid) {
1276 gpt_part_data->type = PARTITION_RAID_GUID;
1279 if (gpt_part_data->boot) {
1280 gpt_part_data->type = PARTITION_SYSTEM_GUID;
1283 if (gpt_part_data->bios_grub) {
1284 gpt_part_data->type = PARTITION_BIOS_GRUB_GUID;
1287 if (gpt_part_data->hp_service) {
1288 gpt_part_data->type = PARTITION_HPSERVICE_GUID;
1291 if (gpt_part_data->msftres) {
1292 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1297 if (strncmp (fs_type->name, "fat", 3) == 0
1298 || strcmp (fs_type->name, "ntfs") == 0) {
1299 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1302 if (strncmp (fs_type->name, "hfs", 3) == 0) {
1303 gpt_part_data->type = PARTITION_APPLE_HFS_GUID;
1306 if (strstr (fs_type->name, "swap")) {
1307 gpt_part_data->type = PARTITION_SWAP_GUID;
1312 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1316 /* Allocate metadata partitions for the GPTH and PTES */
1318 gpt_alloc_metadata (PedDisk * disk)
1320 PedSector gptlength, pteslength = 0;
1321 GPTDiskData *gpt_disk_data;
1323 PED_ASSERT(disk != NULL, return 0);
1324 PED_ASSERT(disk->dev != NULL, return 0);
1325 PED_ASSERT(disk->disk_specific != NULL, return 0);
1326 gpt_disk_data = disk->disk_specific;
1328 gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t),
1329 disk->dev->sector_size);
1330 pteslength = ped_div_round_up (gpt_disk_data->entry_count
1331 * sizeof (GuidPartitionEntry_t), disk->dev->sector_size);
1333 /* metadata at the start of the disk includes the MBR */
1334 if (!add_metadata_part(disk, GPT_PMBR_LBA,
1335 GPT_PMBR_SECTORS + gptlength + pteslength))
1338 /* metadata at the end of the disk */
1339 if (!add_metadata_part(disk, disk->dev->length - gptlength - pteslength,
1340 gptlength + pteslength))
1346 /* Does nothing, as the read/new/destroy functions maintain part->num */
1348 gpt_partition_enumerate (PedPartition* part)
1350 GPTDiskData* gpt_disk_data = part->disk->disk_specific;
1353 /* never change the partition numbers */
1354 if (part->num != -1)
1357 for (i = 1; i <= gpt_disk_data->entry_count; i++) {
1358 if (!ped_disk_get_partition (part->disk, i)) {
1364 PED_ASSERT (0, return 0);
1366 return 0; /* used if debug is disabled */
1370 gpt_partition_set_flag(PedPartition *part,
1371 PedPartitionFlag flag,
1374 GPTPartitionData *gpt_part_data;
1375 PED_ASSERT(part != NULL, return 0);
1376 PED_ASSERT(part->disk_specific != NULL, return 0);
1377 gpt_part_data = part->disk_specific;
1380 case PED_PARTITION_BOOT:
1381 gpt_part_data->boot = state;
1384 = gpt_part_data->lvm
1385 = gpt_part_data->bios_grub
1386 = gpt_part_data->hp_service
1387 = gpt_part_data->msftres = 0;
1388 return gpt_partition_set_system (part, part->fs_type);
1389 case PED_PARTITION_BIOS_GRUB:
1390 gpt_part_data->bios_grub = state;
1393 = gpt_part_data->lvm
1394 = gpt_part_data->boot
1395 = gpt_part_data->hp_service
1396 = gpt_part_data->msftres = 0;
1397 return gpt_partition_set_system (part, part->fs_type);
1398 case PED_PARTITION_RAID:
1399 gpt_part_data->raid = state;
1402 = gpt_part_data->lvm
1403 = gpt_part_data->bios_grub
1404 = gpt_part_data->hp_service
1405 = gpt_part_data->msftres = 0;
1406 return gpt_partition_set_system (part, part->fs_type);
1407 case PED_PARTITION_LVM:
1408 gpt_part_data->lvm = state;
1411 = gpt_part_data->raid
1412 = gpt_part_data->bios_grub
1413 = gpt_part_data->hp_service
1414 = gpt_part_data->msftres = 0;
1415 return gpt_partition_set_system (part, part->fs_type);
1416 case PED_PARTITION_HPSERVICE:
1417 gpt_part_data->hp_service = state;
1420 = gpt_part_data->raid
1421 = gpt_part_data->lvm
1422 = gpt_part_data->bios_grub
1423 = gpt_part_data->msftres = 0;
1424 return gpt_partition_set_system (part, part->fs_type);
1425 case PED_PARTITION_MSFT_RESERVED:
1426 gpt_part_data->msftres = state;
1429 = gpt_part_data->raid
1430 = gpt_part_data->lvm
1431 = gpt_part_data->bios_grub
1432 = gpt_part_data->hp_service = 0;
1433 return gpt_partition_set_system (part, part->fs_type);
1434 case PED_PARTITION_HIDDEN:
1435 gpt_part_data->hidden = state;
1437 case PED_PARTITION_SWAP:
1438 case PED_PARTITION_ROOT:
1439 case PED_PARTITION_LBA:
1447 gpt_partition_get_flag(const PedPartition *part, PedPartitionFlag flag)
1449 GPTPartitionData *gpt_part_data;
1450 PED_ASSERT(part->disk_specific != NULL, return 0);
1451 gpt_part_data = part->disk_specific;
1454 case PED_PARTITION_RAID:
1455 return gpt_part_data->raid;
1456 case PED_PARTITION_LVM:
1457 return gpt_part_data->lvm;
1458 case PED_PARTITION_BOOT:
1459 return gpt_part_data->boot;
1460 case PED_PARTITION_BIOS_GRUB:
1461 return gpt_part_data->bios_grub;
1462 case PED_PARTITION_HPSERVICE:
1463 return gpt_part_data->hp_service;
1464 case PED_PARTITION_MSFT_RESERVED:
1465 return gpt_part_data->msftres;
1466 case PED_PARTITION_HIDDEN:
1467 return gpt_part_data->hidden;
1468 case PED_PARTITION_SWAP:
1469 case PED_PARTITION_LBA:
1470 case PED_PARTITION_ROOT:
1478 gpt_partition_is_flag_available(const PedPartition * part,
1479 PedPartitionFlag flag)
1482 case PED_PARTITION_RAID:
1483 case PED_PARTITION_LVM:
1484 case PED_PARTITION_BOOT:
1485 case PED_PARTITION_BIOS_GRUB:
1486 case PED_PARTITION_HPSERVICE:
1487 case PED_PARTITION_MSFT_RESERVED:
1488 case PED_PARTITION_HIDDEN:
1490 case PED_PARTITION_SWAP:
1491 case PED_PARTITION_ROOT:
1492 case PED_PARTITION_LBA:
1500 gpt_partition_set_name (PedPartition *part, const char *name)
1502 GPTPartitionData *gpt_part_data = part->disk_specific;
1504 strncpy (gpt_part_data->name, name, 36);
1505 gpt_part_data->name [36] = 0;
1509 gpt_partition_get_name (const PedPartition * part)
1511 GPTPartitionData* gpt_part_data = part->disk_specific;
1512 return gpt_part_data->name;
1516 gpt_get_max_primary_partition_count (const PedDisk *disk)
1518 const GPTDiskData* gpt_disk_data = disk->disk_specific;
1519 return gpt_disk_data->entry_count;
1523 * From (http://developer.apple.com/technotes/tn2006/tn2166.html Chapter 5).
1524 * According to the specs the first LBA (LBA0) is not relevant (it exists
1525 * to maintain compatibility). on the second LBA(LBA1) gpt places the
1526 * header. The header is as big as the block size. After the header we
1527 * find the Entry array. Each element of said array, describes each
1528 * partition. One can have as much elements as can fit between the end of
1529 * the second LBA (where the header ends) and the FirstUsableLBA.
1530 * FirstUsableLBA is the first logical block that is used for contents
1531 * and is defined in header.
1533 * /---------------------------------------------------\
1534 * | BLOCK0 | HEADER | Entry Array | First Usable LBA |
1536 * \---------------------------------------------------/
1538 * /----------/ \----------\
1539 * /-----------------------------------------\
1540 * | E1 | E2 | E3 |...............| EN |
1541 * \-----------------------------------------/
1543 * The number of possible partitions or supported partitions is:
1544 * SP = FirstUsableLBA*Blocksize - 2*Blocksize / SizeOfPartitionEntry
1545 * SP = Blocksize(FirstusableLBA - 2) / SizeOfPartitoinEntry
1548 gpt_get_max_supported_partition_count (const PedDisk *disk, int *max_n)
1550 GuidPartitionTableHeader_t *pth = NULL;
1551 uint8_t *pth_raw = ped_malloc (pth_get_size (disk->dev));
1553 if (ped_device_read (disk->dev, pth_raw, 1, GPT_HEADER_SECTORS)
1554 || ped_device_read (disk->dev, pth_raw,
1555 disk->dev->length, GPT_HEADER_SECTORS))
1556 pth = pth_new_from_raw (disk->dev, pth_raw);
1562 *max_n = (disk->dev->sector_size * (pth->FirstUsableLBA - 2)
1563 / PED_LE32_TO_CPU (pth->SizeOfPartitionEntry));
1568 static PedConstraint*
1569 _non_metadata_constraint (const PedDisk* disk)
1571 GPTDiskData* gpt_disk_data = disk->disk_specific;
1573 return ped_constraint_new_from_max (&gpt_disk_data->data_area);
1577 gpt_partition_align (PedPartition* part, const PedConstraint* constraint)
1579 PED_ASSERT (part != NULL, return 0);
1581 if (_ped_partition_attempt_align (part, constraint,
1582 _non_metadata_constraint (part->disk)))
1585 #ifndef DISCOVER_ONLY
1586 ped_exception_throw (
1587 PED_EXCEPTION_ERROR,
1588 PED_EXCEPTION_CANCEL,
1589 _("Unable to satisfy all constraints on the partition."));
1595 gpt_partition_check (const PedPartition* part)
1600 static PedDiskOps gpt_disk_ops = {
1602 #ifndef DISCOVER_ONLY
1603 clobber: gpt_clobber,
1608 duplicate: gpt_duplicate,
1611 #ifndef DISCOVER_ONLY
1616 partition_new: gpt_partition_new,
1617 partition_duplicate: gpt_partition_duplicate,
1618 partition_destroy: gpt_partition_destroy,
1619 partition_set_system: gpt_partition_set_system,
1620 partition_set_flag: gpt_partition_set_flag,
1621 partition_get_flag: gpt_partition_get_flag,
1622 partition_is_flag_available: gpt_partition_is_flag_available,
1623 partition_set_name: gpt_partition_set_name,
1624 partition_get_name: gpt_partition_get_name,
1625 partition_align: gpt_partition_align,
1626 partition_enumerate: gpt_partition_enumerate,
1627 partition_check: gpt_partition_check,
1628 alloc_metadata: gpt_alloc_metadata,
1629 get_max_primary_partition_count: gpt_get_max_primary_partition_count,
1630 get_max_supported_partition_count: gpt_get_max_supported_partition_count
1633 static PedDiskType gpt_disk_type = {
1637 features: PED_DISK_TYPE_PARTITION_NAME
1643 PED_ASSERT (sizeof (GuidPartitionEntryAttributes_t) == 8, return);
1644 PED_ASSERT (sizeof (GuidPartitionEntry_t) == 128, return);
1646 ped_disk_type_register (&gpt_disk_type);
1652 ped_disk_type_unregister (&gpt_disk_type);