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 = 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)
976 /* The UEFI spec is not clear about what to do with the following
977 elements of the Protective MBR (pmbr): BootCode (0-440B),
978 UniqueMBRSignature (440B-444B) and Unknown (444B-446B).
979 With this in mind, we try not to modify these elements. */
981 if (!ptt_read_sector (dev, 0, &s0))
983 LegacyMBR_t *pmbr = s0;
985 /* Zero out the legacy partitions. */
986 memset (pmbr->PartitionRecord, 0, sizeof pmbr->PartitionRecord);
988 pmbr->Signature = PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE);
989 pmbr->PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI;
990 pmbr->PartitionRecord[0].StartSector = 1;
991 pmbr->PartitionRecord[0].EndHead = 0xFE;
992 pmbr->PartitionRecord[0].EndSector = 0xFF;
993 pmbr->PartitionRecord[0].EndTrack = 0xFF;
994 pmbr->PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32(1);
995 if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
996 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(0xFFFFFFFF);
998 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(dev->length - 1UL);
1000 int write_ok = ped_device_write (dev, pmbr, GPT_PMBR_LBA,
1007 _generate_header (const PedDisk* disk, int alternate, uint32_t ptes_crc,
1008 GuidPartitionTableHeader_t** gpt_p)
1010 GPTDiskData* gpt_disk_data = disk->disk_specific;
1011 GuidPartitionTableHeader_t* gpt;
1013 *gpt_p = pth_new_zeroed (disk->dev);
1017 gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE);
1018 gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00);
1021 gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev));
1022 gpt->HeaderCRC32 = 0;
1026 PedSector ptes_size = gpt_disk_data->entry_count
1027 * sizeof (GuidPartitionEntry_t) / disk->dev->sector_size;
1029 gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1030 gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
1031 gpt->PartitionEntryLBA
1032 = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_size);
1034 gpt->MyLBA = PED_CPU_TO_LE64 (1);
1035 gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1036 gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
1039 gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
1040 gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
1041 gpt->DiskGUID = gpt_disk_data->uuid;
1042 gpt->NumberOfPartitionEntries
1043 = PED_CPU_TO_LE32 (gpt_disk_data->entry_count);
1044 gpt->SizeOfPartitionEntry
1045 = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t));
1046 gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32 (ptes_crc);
1047 gpt->HeaderCRC32 = PED_CPU_TO_LE32 (pth_crc32 (disk->dev, gpt));
1051 _partition_generate_part_entry (PedPartition* part, GuidPartitionEntry_t* pte)
1053 GPTPartitionData* gpt_part_data = part->disk_specific;
1056 PED_ASSERT (gpt_part_data != NULL, return);
1058 pte->PartitionTypeGuid = gpt_part_data->type;
1059 pte->UniquePartitionGuid = gpt_part_data->uuid;
1060 pte->StartingLBA = PED_CPU_TO_LE64(part->geom.start);
1061 pte->EndingLBA = PED_CPU_TO_LE64(part->geom.end);
1062 memset (&pte->Attributes, 0, sizeof (GuidPartitionEntryAttributes_t));
1064 if (gpt_part_data->hidden)
1065 pte->Attributes.RequiredToFunction = 1;
1067 for (i = 0; i < 72 / sizeof(efi_char16_t); i++)
1068 pte->PartitionName[i]
1069 = (efi_char16_t) PED_CPU_TO_LE16(
1070 (uint16_t) gpt_part_data->name[i]);
1074 gpt_write(const PedDisk * disk)
1076 GPTDiskData* gpt_disk_data;
1077 GuidPartitionEntry_t* ptes;
1080 GuidPartitionTableHeader_t* gpt;
1084 PED_ASSERT (disk != NULL, goto error);
1085 PED_ASSERT (disk->dev != NULL, goto error);
1086 PED_ASSERT (disk->disk_specific != NULL, goto error);
1088 gpt_disk_data = disk->disk_specific;
1090 ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
1091 ptes = (GuidPartitionEntry_t*) ped_malloc (ptes_size);
1094 memset (ptes, 0, ptes_size);
1095 for (part = ped_disk_next_partition (disk, NULL); part;
1096 part = ped_disk_next_partition (disk, part)) {
1097 if (part->type != 0)
1099 _partition_generate_part_entry (part, &ptes[part->num - 1]);
1102 ptes_crc = efi_crc32 (ptes, ptes_size);
1104 /* Write protective MBR */
1105 if (!_write_pmbr (disk->dev))
1106 goto error_free_ptes;
1108 /* Write PTH and PTEs */
1109 _generate_header (disk, 0, ptes_crc, &gpt);
1110 pth_raw = pth_get_raw (disk->dev, gpt);
1112 bool write_ok = ped_device_write (disk->dev, pth_raw, 1, 1);
1115 goto error_free_ptes;
1116 if (!ped_device_write (disk->dev, ptes, 2,
1117 ptes_size / disk->dev->sector_size))
1118 goto error_free_ptes;
1120 /* Write Alternate PTH & PTEs */
1121 _generate_header (disk, 1, ptes_crc, &gpt);
1122 pth_raw = pth_get_raw (disk->dev, gpt);
1124 write_ok = ped_device_write (disk->dev, pth_raw,
1125 disk->dev->length - 1, 1);
1128 goto error_free_ptes;
1129 if (!ped_device_write (disk->dev, ptes,
1130 disk->dev->length - 1 - ptes_size / disk->dev->sector_size,
1131 ptes_size / disk->dev->sector_size))
1132 goto error_free_ptes;
1135 return ped_device_sync (disk->dev);
1143 #endif /* !DISCOVER_ONLY */
1146 add_metadata_part(PedDisk * disk, PedSector start, PedSector length)
1149 PedConstraint* constraint_exact;
1150 PED_ASSERT(disk != NULL, return 0);
1152 part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1153 start, start + length - 1);
1157 constraint_exact = ped_constraint_exact (&part->geom);
1158 if (!ped_disk_add_partition (disk, part, constraint_exact))
1159 goto error_destroy_constraint;
1160 ped_constraint_destroy (constraint_exact);
1163 error_destroy_constraint:
1164 ped_constraint_destroy (constraint_exact);
1165 ped_partition_destroy (part);
1170 static PedPartition*
1171 gpt_partition_new (const PedDisk* disk,
1172 PedPartitionType part_type, const PedFileSystemType* fs_type,
1173 PedSector start, PedSector end)
1176 GPTPartitionData* gpt_part_data;
1178 part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1185 gpt_part_data = part->disk_specific =
1186 ped_malloc (sizeof (GPTPartitionData));
1188 goto error_free_part;
1190 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1191 gpt_part_data->lvm = 0;
1192 gpt_part_data->raid = 0;
1193 gpt_part_data->boot = 0;
1194 gpt_part_data->bios_grub = 0;
1195 gpt_part_data->hp_service = 0;
1196 gpt_part_data->hidden = 0;
1197 gpt_part_data->msftres = 0;
1198 uuid_generate ((unsigned char*) &gpt_part_data->uuid);
1199 swap_uuid_and_efi_guid((unsigned char*)(&gpt_part_data->uuid));
1200 memset (gpt_part_data->name, 0, sizeof gpt_part_data->name);
1204 _ped_partition_free (part);
1209 static PedPartition*
1210 gpt_partition_duplicate (const PedPartition* part)
1212 PedPartition* result;
1213 GPTPartitionData* part_data = part->disk_specific;
1214 GPTPartitionData* result_data;
1216 result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
1217 part->geom.start, part->geom.end);
1220 result->num = part->num;
1222 if (result->type != 0)
1225 result_data = result->disk_specific =
1226 ped_malloc (sizeof (GPTPartitionData));
1228 goto error_free_part;
1230 result_data->type = part_data->type;
1231 result_data->uuid = part_data->uuid;
1232 strcpy (result_data->name, part_data->name);
1236 _ped_partition_free (result);
1242 gpt_partition_destroy (PedPartition *part)
1244 if (part->type == 0) {
1245 PED_ASSERT (part->disk_specific != NULL, return);
1246 free (part->disk_specific);
1249 _ped_partition_free (part);
1253 gpt_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
1255 GPTPartitionData* gpt_part_data = part->disk_specific;
1257 PED_ASSERT (gpt_part_data != NULL, return 0);
1259 part->fs_type = fs_type;
1261 if (gpt_part_data->lvm) {
1262 gpt_part_data->type = PARTITION_LVM_GUID;
1265 if (gpt_part_data->raid) {
1266 gpt_part_data->type = PARTITION_RAID_GUID;
1269 if (gpt_part_data->boot) {
1270 gpt_part_data->type = PARTITION_SYSTEM_GUID;
1273 if (gpt_part_data->bios_grub) {
1274 gpt_part_data->type = PARTITION_BIOS_GRUB_GUID;
1277 if (gpt_part_data->hp_service) {
1278 gpt_part_data->type = PARTITION_HPSERVICE_GUID;
1281 if (gpt_part_data->msftres) {
1282 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1287 if (strncmp (fs_type->name, "fat", 3) == 0
1288 || strcmp (fs_type->name, "ntfs") == 0) {
1289 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1292 if (strncmp (fs_type->name, "hfs", 3) == 0) {
1293 gpt_part_data->type = PARTITION_APPLE_HFS_GUID;
1296 if (strstr (fs_type->name, "swap")) {
1297 gpt_part_data->type = PARTITION_SWAP_GUID;
1302 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1306 /* Allocate metadata partitions for the GPTH and PTES */
1308 gpt_alloc_metadata (PedDisk * disk)
1310 PedSector gptlength, pteslength = 0;
1311 GPTDiskData *gpt_disk_data;
1313 PED_ASSERT(disk != NULL, return 0);
1314 PED_ASSERT(disk->dev != NULL, return 0);
1315 PED_ASSERT(disk->disk_specific != NULL, return 0);
1316 gpt_disk_data = disk->disk_specific;
1318 gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t),
1319 disk->dev->sector_size);
1320 pteslength = ped_div_round_up (gpt_disk_data->entry_count
1321 * sizeof (GuidPartitionEntry_t), disk->dev->sector_size);
1323 /* metadata at the start of the disk includes the MBR */
1324 if (!add_metadata_part(disk, GPT_PMBR_LBA,
1325 GPT_PMBR_SECTORS + gptlength + pteslength))
1328 /* metadata at the end of the disk */
1329 if (!add_metadata_part(disk, disk->dev->length - gptlength - pteslength,
1330 gptlength + pteslength))
1336 /* Does nothing, as the read/new/destroy functions maintain part->num */
1338 gpt_partition_enumerate (PedPartition* part)
1340 GPTDiskData* gpt_disk_data = part->disk->disk_specific;
1343 /* never change the partition numbers */
1344 if (part->num != -1)
1347 for (i = 1; i <= gpt_disk_data->entry_count; i++) {
1348 if (!ped_disk_get_partition (part->disk, i)) {
1354 PED_ASSERT (0, return 0);
1356 return 0; /* used if debug is disabled */
1360 gpt_partition_set_flag(PedPartition *part,
1361 PedPartitionFlag flag,
1364 GPTPartitionData *gpt_part_data;
1365 PED_ASSERT(part != NULL, return 0);
1366 PED_ASSERT(part->disk_specific != NULL, return 0);
1367 gpt_part_data = part->disk_specific;
1370 case PED_PARTITION_BOOT:
1371 gpt_part_data->boot = state;
1374 = gpt_part_data->lvm
1375 = gpt_part_data->bios_grub
1376 = gpt_part_data->hp_service
1377 = gpt_part_data->msftres = 0;
1378 return gpt_partition_set_system (part, part->fs_type);
1379 case PED_PARTITION_BIOS_GRUB:
1380 gpt_part_data->bios_grub = state;
1383 = gpt_part_data->lvm
1384 = gpt_part_data->boot
1385 = gpt_part_data->hp_service
1386 = gpt_part_data->msftres = 0;
1387 return gpt_partition_set_system (part, part->fs_type);
1388 case PED_PARTITION_RAID:
1389 gpt_part_data->raid = state;
1392 = gpt_part_data->lvm
1393 = gpt_part_data->bios_grub
1394 = gpt_part_data->hp_service
1395 = gpt_part_data->msftres = 0;
1396 return gpt_partition_set_system (part, part->fs_type);
1397 case PED_PARTITION_LVM:
1398 gpt_part_data->lvm = state;
1401 = gpt_part_data->raid
1402 = gpt_part_data->bios_grub
1403 = gpt_part_data->hp_service
1404 = gpt_part_data->msftres = 0;
1405 return gpt_partition_set_system (part, part->fs_type);
1406 case PED_PARTITION_HPSERVICE:
1407 gpt_part_data->hp_service = state;
1410 = gpt_part_data->raid
1411 = gpt_part_data->lvm
1412 = gpt_part_data->bios_grub
1413 = gpt_part_data->msftres = 0;
1414 return gpt_partition_set_system (part, part->fs_type);
1415 case PED_PARTITION_MSFT_RESERVED:
1416 gpt_part_data->msftres = state;
1419 = gpt_part_data->raid
1420 = gpt_part_data->lvm
1421 = gpt_part_data->bios_grub
1422 = gpt_part_data->hp_service = 0;
1423 return gpt_partition_set_system (part, part->fs_type);
1424 case PED_PARTITION_HIDDEN:
1425 gpt_part_data->hidden = state;
1427 case PED_PARTITION_SWAP:
1428 case PED_PARTITION_ROOT:
1429 case PED_PARTITION_LBA:
1437 gpt_partition_get_flag(const PedPartition *part, PedPartitionFlag flag)
1439 GPTPartitionData *gpt_part_data;
1440 PED_ASSERT(part->disk_specific != NULL, return 0);
1441 gpt_part_data = part->disk_specific;
1444 case PED_PARTITION_RAID:
1445 return gpt_part_data->raid;
1446 case PED_PARTITION_LVM:
1447 return gpt_part_data->lvm;
1448 case PED_PARTITION_BOOT:
1449 return gpt_part_data->boot;
1450 case PED_PARTITION_BIOS_GRUB:
1451 return gpt_part_data->bios_grub;
1452 case PED_PARTITION_HPSERVICE:
1453 return gpt_part_data->hp_service;
1454 case PED_PARTITION_MSFT_RESERVED:
1455 return gpt_part_data->msftres;
1456 case PED_PARTITION_HIDDEN:
1457 return gpt_part_data->hidden;
1458 case PED_PARTITION_SWAP:
1459 case PED_PARTITION_LBA:
1460 case PED_PARTITION_ROOT:
1468 gpt_partition_is_flag_available(const PedPartition * part,
1469 PedPartitionFlag flag)
1472 case PED_PARTITION_RAID:
1473 case PED_PARTITION_LVM:
1474 case PED_PARTITION_BOOT:
1475 case PED_PARTITION_BIOS_GRUB:
1476 case PED_PARTITION_HPSERVICE:
1477 case PED_PARTITION_MSFT_RESERVED:
1478 case PED_PARTITION_HIDDEN:
1480 case PED_PARTITION_SWAP:
1481 case PED_PARTITION_ROOT:
1482 case PED_PARTITION_LBA:
1490 gpt_partition_set_name (PedPartition *part, const char *name)
1492 GPTPartitionData *gpt_part_data = part->disk_specific;
1494 strncpy (gpt_part_data->name, name, 36);
1495 gpt_part_data->name [36] = 0;
1499 gpt_partition_get_name (const PedPartition * part)
1501 GPTPartitionData* gpt_part_data = part->disk_specific;
1502 return gpt_part_data->name;
1506 gpt_get_max_primary_partition_count (const PedDisk *disk)
1508 const GPTDiskData* gpt_disk_data = disk->disk_specific;
1509 return gpt_disk_data->entry_count;
1513 * From (http://developer.apple.com/technotes/tn2006/tn2166.html Chapter 5).
1514 * According to the specs the first LBA (LBA0) is not relevant (it exists
1515 * to maintain compatibility). on the second LBA(LBA1) gpt places the
1516 * header. The header is as big as the block size. After the header we
1517 * find the Entry array. Each element of said array, describes each
1518 * partition. One can have as much elements as can fit between the end of
1519 * the second LBA (where the header ends) and the FirstUsableLBA.
1520 * FirstUsableLBA is the first logical block that is used for contents
1521 * and is defined in header.
1523 * /---------------------------------------------------\
1524 * | BLOCK0 | HEADER | Entry Array | First Usable LBA |
1526 * \---------------------------------------------------/
1528 * /----------/ \----------\
1529 * /-----------------------------------------\
1530 * | E1 | E2 | E3 |...............| EN |
1531 * \-----------------------------------------/
1533 * The number of possible partitions or supported partitions is:
1534 * SP = FirstUsableLBA*Blocksize - 2*Blocksize / SizeOfPartitionEntry
1535 * SP = Blocksize(FirstusableLBA - 2) / SizeOfPartitoinEntry
1538 gpt_get_max_supported_partition_count (const PedDisk *disk, int *max_n)
1540 GuidPartitionTableHeader_t *pth = NULL;
1541 uint8_t *pth_raw = ped_malloc (pth_get_size (disk->dev));
1543 if (ped_device_read (disk->dev, pth_raw, 1, GPT_HEADER_SECTORS)
1544 || ped_device_read (disk->dev, pth_raw,
1545 disk->dev->length, GPT_HEADER_SECTORS))
1546 pth = pth_new_from_raw (disk->dev, pth_raw);
1552 *max_n = (disk->dev->sector_size * (pth->FirstUsableLBA - 2)
1553 / pth->SizeOfPartitionEntry);
1558 static PedConstraint*
1559 _non_metadata_constraint (const PedDisk* disk)
1561 GPTDiskData* gpt_disk_data = disk->disk_specific;
1563 return ped_constraint_new_from_max (&gpt_disk_data->data_area);
1567 gpt_partition_align (PedPartition* part, const PedConstraint* constraint)
1569 PED_ASSERT (part != NULL, return 0);
1571 if (_ped_partition_attempt_align (part, constraint,
1572 _non_metadata_constraint (part->disk)))
1575 #ifndef DISCOVER_ONLY
1576 ped_exception_throw (
1577 PED_EXCEPTION_ERROR,
1578 PED_EXCEPTION_CANCEL,
1579 _("Unable to satisfy all constraints on the partition."));
1585 gpt_partition_check (const PedPartition* part)
1590 static PedDiskOps gpt_disk_ops = {
1592 #ifndef DISCOVER_ONLY
1593 clobber: gpt_clobber,
1598 duplicate: gpt_duplicate,
1601 #ifndef DISCOVER_ONLY
1606 partition_new: gpt_partition_new,
1607 partition_duplicate: gpt_partition_duplicate,
1608 partition_destroy: gpt_partition_destroy,
1609 partition_set_system: gpt_partition_set_system,
1610 partition_set_flag: gpt_partition_set_flag,
1611 partition_get_flag: gpt_partition_get_flag,
1612 partition_is_flag_available: gpt_partition_is_flag_available,
1613 partition_set_name: gpt_partition_set_name,
1614 partition_get_name: gpt_partition_get_name,
1615 partition_align: gpt_partition_align,
1616 partition_enumerate: gpt_partition_enumerate,
1617 partition_check: gpt_partition_check,
1618 alloc_metadata: gpt_alloc_metadata,
1619 get_max_primary_partition_count: gpt_get_max_primary_partition_count,
1620 get_max_supported_partition_count: gpt_get_max_supported_partition_count
1623 static PedDiskType gpt_disk_type = {
1627 features: PED_DISK_TYPE_PARTITION_NAME
1633 PED_ASSERT (sizeof (GuidPartitionEntryAttributes_t) == 8, return);
1634 PED_ASSERT (sizeof (GuidPartitionEntry_t) == 128, return);
1636 ped_disk_type_register (&gpt_disk_type);
1642 ped_disk_type_unregister (&gpt_disk_type);