OSDN Git Service

gpt: remove dead store
[android-x86/external-parted.git] / libparted / labels / gpt.c
1 /*
2     libparted - a library for manipulating disk partitions
3
4     original version by Matt Domsch <Matt_Domsch@dell.com>
5     Disclaimed into the Public Domain
6
7     Portions Copyright (C) 2001-2003, 2005-2009 Free Software Foundation, Inc.
8
9     EFI GUID Partition Table handling
10     Per Intel EFI Specification v1.02
11     http://developer.intel.com/technology/efi/efi.htm
12
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.
17
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.
22
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/>.
25 */
26
27 #include <config.h>
28
29 #include <parted/parted.h>
30 #include <parted/debug.h>
31 #include <parted/endian.h>
32 #include <parted/crc32.h>
33 #include <inttypes.h>
34 #include <stdio.h>
35 #include <sys/types.h>
36 #include <sys/ioctl.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <uuid/uuid.h>
40 #include <stdbool.h>
41 #include "xalloc.h"
42
43 #include "pt-tools.h"
44
45 #if ENABLE_NLS
46 #  include <libintl.h>
47 #  define _(String) gettext (String)
48 #else
49 #  define _(String) (String)
50 #endif /* ENABLE_NLS */
51
52 #define EFI_PMBR_OSTYPE_EFI 0xEE
53 #define MSDOS_MBR_SIGNATURE 0xaa55
54
55 #define GPT_HEADER_SIGNATURE 0x5452415020494645LL
56
57 /* NOTE: the document that describes revision 1.00 is labelled "version 1.02",
58  * so some implementors got confused...
59  */
60 #define GPT_HEADER_REVISION_V1_02 0x00010200
61 #define GPT_HEADER_REVISION_V1_00 0x00010000
62 #define GPT_HEADER_REVISION_V0_99 0x00009900
63
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;
71 typedef struct
72 {
73   uint32_t time_low;
74   uint16_t time_mid;
75   uint16_t time_hi_and_version;
76   uint8_t clock_seq_hi_and_reserved;
77   uint8_t clock_seq_low;
78   uint8_t node[6];
79 } /* __attribute__ ((packed)) */ efi_guid_t;
80 /* commented out "__attribute__ ((packed))" to work around gcc bug (fixed
81  * in gcc3.1): __attribute__ ((packed)) breaks addressing on initialized
82  * data.  It turns out we don't need it in this case, so it doesn't break
83  * anything :)
84  */
85
86 #define UNUSED_ENTRY_GUID    \
87     ((efi_guid_t) { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
88                     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
89 #define PARTITION_SYSTEM_GUID \
90     ((efi_guid_t) { PED_CPU_TO_LE32 (0xC12A7328), PED_CPU_TO_LE16 (0xF81F), \
91                     PED_CPU_TO_LE16 (0x11d2), 0xBA, 0x4B, \
92                     { 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }})
93 #define PARTITION_BIOS_GRUB_GUID \
94     ((efi_guid_t) { PED_CPU_TO_LE32 (0x21686148), PED_CPU_TO_LE16 (0x6449), \
95                     PED_CPU_TO_LE16 (0x6E6f), 0x74, 0x4E, \
96                     { 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 }})
97 #define LEGACY_MBR_PARTITION_GUID \
98     ((efi_guid_t) { PED_CPU_TO_LE32 (0x024DEE41), PED_CPU_TO_LE16 (0x33E7), \
99                     PED_CPU_TO_LE16 (0x11d3, 0x9D, 0x69, \
100                     { 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }})
101 #define PARTITION_MSFT_RESERVED_GUID \
102     ((efi_guid_t) { PED_CPU_TO_LE32 (0xE3C9E316), PED_CPU_TO_LE16 (0x0B5C), \
103                     PED_CPU_TO_LE16 (0x4DB8), 0x81, 0x7D, \
104                     { 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE }})
105 #define PARTITION_BASIC_DATA_GUID \
106     ((efi_guid_t) { PED_CPU_TO_LE32 (0xEBD0A0A2), PED_CPU_TO_LE16 (0xB9E5), \
107                     PED_CPU_TO_LE16 (0x4433), 0x87, 0xC0, \
108                     { 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }})
109 #define PARTITION_RAID_GUID \
110     ((efi_guid_t) { PED_CPU_TO_LE32 (0xa19d880f), PED_CPU_TO_LE16 (0x05fc), \
111                     PED_CPU_TO_LE16 (0x4d3b), 0xa0, 0x06, \
112                     { 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e }})
113 #define PARTITION_SWAP_GUID \
114     ((efi_guid_t) { PED_CPU_TO_LE32 (0x0657fd6d), PED_CPU_TO_LE16 (0xa4ab), \
115                     PED_CPU_TO_LE16 (0x43c4), 0x84, 0xe5, \
116                     { 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f }})
117 #define PARTITION_LVM_GUID \
118     ((efi_guid_t) { PED_CPU_TO_LE32 (0xe6d6d379), PED_CPU_TO_LE16 (0xf507), \
119                     PED_CPU_TO_LE16 (0x44c2), 0xa2, 0x3c, \
120                     { 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 }})
121 #define PARTITION_RESERVED_GUID \
122     ((efi_guid_t) { PED_CPU_TO_LE32 (0x8da63339), PED_CPU_TO_LE16 (0x0007), \
123                     PED_CPU_TO_LE16 (0x60c0), 0xc4, 0x36, \
124                     { 0x08, 0x3a, 0xc8, 0x23, 0x09, 0x08 }})
125 #define PARTITION_HPSERVICE_GUID \
126     ((efi_guid_t) { PED_CPU_TO_LE32 (0xe2a1e728), PED_CPU_TO_LE16 (0x32e3), \
127                     PED_CPU_TO_LE16 (0x11d6), 0xa6, 0x82, \
128                     { 0x7b, 0x03, 0xa0, 0x00, 0x00, 0x00 }})
129 #define PARTITION_APPLE_HFS_GUID \
130     ((efi_guid_t) { PED_CPU_TO_LE32 (0x48465300), PED_CPU_TO_LE16 (0x0000), \
131                     PED_CPU_TO_LE16 (0x11AA), 0xaa, 0x11, \
132                     { 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC }})
133
134 struct __attribute__ ((packed)) _GuidPartitionTableHeader_t
135 {
136   uint64_t Signature;
137   uint32_t Revision;
138   uint32_t HeaderSize;
139   uint32_t HeaderCRC32;
140   uint32_t Reserved1;
141   uint64_t MyLBA;
142   uint64_t AlternateLBA;
143   uint64_t FirstUsableLBA;
144   uint64_t LastUsableLBA;
145   efi_guid_t DiskGUID;
146   uint64_t PartitionEntryLBA;
147   uint32_t NumberOfPartitionEntries;
148   uint32_t SizeOfPartitionEntry;
149   uint32_t PartitionEntryArrayCRC32;
150   uint8_t *Reserved2;
151 };
152
153 struct __attribute__ ((packed)) _GuidPartitionEntryAttributes_t
154 {
155 #ifdef __GNUC__                 /* XXX narrow this down to !TinyCC */
156   uint64_t RequiredToFunction:1;
157   uint64_t Reserved:47;
158   uint64_t GuidSpecific:16;
159 #else
160 #       warning "Using crippled partition entry type"
161   uint32_t RequiredToFunction:1;
162   uint32_t Reserved:32;
163   uint32_t LOST:5;
164   uint32_t GuidSpecific:16;
165 #endif
166 };
167
168 struct __attribute__ ((packed)) _GuidPartitionEntry_t
169 {
170   efi_guid_t PartitionTypeGuid;
171   efi_guid_t UniquePartitionGuid;
172   uint64_t StartingLBA;
173   uint64_t EndingLBA;
174   GuidPartitionEntryAttributes_t Attributes;
175   efi_char16_t PartitionName[72 / sizeof (efi_char16_t)];
176 };
177
178 #define GPT_PMBR_LBA 0
179 #define GPT_PMBR_SECTORS 1
180 #define GPT_PRIMARY_HEADER_LBA 1
181 #define GPT_HEADER_SECTORS 1
182 #define GPT_PRIMARY_PART_TABLE_LBA 2
183
184 /*
185    These values are only defaults.  The actual on-disk structures
186    may define different sizes, so use those unless creating a new GPT disk!
187 */
188
189 #define GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE 16384
190
191 /* Number of actual partition entries should be calculated as: */
192 #define GPT_DEFAULT_PARTITION_ENTRIES \
193         (GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / \
194          sizeof(GuidPartitionEntry_t))
195
196 struct __attribute__ ((packed)) _PartitionRecord_t
197 {
198   /* Not used by EFI firmware. Set to 0x80 to indicate that this
199      is the bootable legacy partition. */
200   uint8_t BootIndicator;
201
202   /* Start of partition in CHS address, not used by EFI firmware. */
203   uint8_t StartHead;
204
205   /* Start of partition in CHS address, not used by EFI firmware. */
206   uint8_t StartSector;
207
208   /* Start of partition in CHS address, not used by EFI firmware. */
209   uint8_t StartTrack;
210
211   /* OS type. A value of 0xEF defines an EFI system partition.
212      Other values are reserved for legacy operating systems, and
213      allocated independently of the EFI specification. */
214   uint8_t OSType;
215
216   /* End of partition in CHS address, not used by EFI firmware. */
217   uint8_t EndHead;
218
219   /* End of partition in CHS address, not used by EFI firmware. */
220   uint8_t EndSector;
221
222   /* End of partition in CHS address, not used by EFI firmware. */
223   uint8_t EndTrack;
224
225   /* Starting LBA address of the partition on the disk. Used by
226      EFI firmware to define the start of the partition. */
227   uint32_t StartingLBA;
228
229   /* Size of partition in LBA. Used by EFI firmware to determine
230      the size of the partition. */
231   uint32_t SizeInLBA;
232 };
233
234 /* Protected Master Boot Record  & Legacy MBR share same structure */
235 /* Needs to be packed because the u16s force misalignment. */
236 struct __attribute__ ((packed)) _LegacyMBR_t
237 {
238   uint8_t BootCode[440];
239   uint32_t UniqueMBRSignature;
240   uint16_t Unknown;
241   PartitionRecord_t PartitionRecord[4];
242   uint16_t Signature;
243 };
244
245 /* uses libparted's disk_specific field in PedDisk, to store our info */
246 struct __attribute__ ((packed)) _GPTDiskData
247 {
248   PedGeometry data_area;
249   int entry_count;
250   efi_guid_t uuid;
251 };
252
253 /* uses libparted's disk_specific field in PedPartition, to store our info */
254 typedef struct _GPTPartitionData
255 {
256   efi_guid_t type;
257   efi_guid_t uuid;
258   char name[37];
259   int lvm;
260   int raid;
261   int boot;
262   int bios_grub;
263   int hp_service;
264   int hidden;
265   int msftres;
266 } GPTPartitionData;
267
268 static PedDiskType gpt_disk_type;
269
270 static inline uint32_t
271 pth_get_size (const PedDevice *dev)
272 {
273   return GPT_HEADER_SECTORS * dev->sector_size;
274 }
275
276 static inline uint32_t
277 pth_get_size_static (const PedDevice *dev)
278 {
279   return sizeof (GuidPartitionTableHeader_t) - sizeof (uint8_t *);
280 }
281
282 static inline uint32_t
283 pth_get_size_rsv2 (const PedDevice *dev)
284 {
285   return pth_get_size (dev) - pth_get_size_static (dev);
286 }
287
288 static GuidPartitionTableHeader_t *
289 pth_new (const PedDevice *dev)
290 {
291   GuidPartitionTableHeader_t *pth =
292     ped_malloc (sizeof (GuidPartitionTableHeader_t) + sizeof (uint8_t));
293
294   pth->Reserved2 = ped_malloc (pth_get_size_rsv2 (dev));
295
296   return pth;
297 }
298
299 static GuidPartitionTableHeader_t *
300 pth_new_zeroed (const PedDevice *dev)
301 {
302   GuidPartitionTableHeader_t *pth = pth_new (dev);
303
304   memset (pth, 0, pth_get_size_static (dev));
305   memset (pth->Reserved2, 0, pth_get_size_rsv2 (dev));
306
307   return (pth);
308 }
309
310 static GuidPartitionTableHeader_t *
311 pth_new_from_raw (const PedDevice *dev, const uint8_t *pth_raw)
312 {
313   GuidPartitionTableHeader_t *pth = pth_new (dev);
314
315   PED_ASSERT (pth_raw != NULL, return 0);
316
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));
320
321   return pth;
322 }
323
324 static void
325 pth_free (GuidPartitionTableHeader_t *pth)
326 {
327   if (pth == NULL)
328     return;
329   PED_ASSERT (pth->Reserved2 != NULL, return);
330
331   free (pth->Reserved2);
332   free (pth);
333 }
334
335 static uint8_t *
336 pth_get_raw (const PedDevice *dev, const GuidPartitionTableHeader_t *pth)
337 {
338   uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
339   int size_static = pth_get_size_static (dev);
340
341   PED_ASSERT (pth != NULL, return 0);
342   PED_ASSERT (pth->Reserved2 != NULL, return 0);
343
344   memcpy (pth_raw, pth, size_static);
345   memcpy (pth_raw + size_static, pth->Reserved2, pth_get_size_rsv2 (dev));
346
347   return pth_raw;
348 }
349
350 /**
351  * swap_uuid_and_efi_guid() - converts between uuid formats
352  * @uuid - uuid_t in either format (converts it to the other)
353  *
354  * There are two different representations for Globally Unique Identifiers
355  * (GUIDs or UUIDs).
356  *
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.
362  *
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.
365  *
366  * When writing to disk, uuid_ts need to be converted into EFI GUIDs.
367  *
368  * Blame Intel.
369  */
370 static void
371 swap_uuid_and_efi_guid (uuid_t uuid)
372 {
373   efi_guid_t *guid = (efi_guid_t *) uuid;
374
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);
379 }
380
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.
384  */
385 static inline uint32_t
386 efi_crc32 (const void *buf, unsigned long len)
387 {
388   return (__efi_crc32 (buf, len, ~0L) ^ ~0L);
389 }
390
391 static inline uint32_t
392 pth_crc32 (const PedDevice *dev, const GuidPartitionTableHeader_t *pth)
393 {
394   uint8_t *pth_raw = pth_get_raw (dev, pth);
395
396   PED_ASSERT (dev != NULL, return 0);
397   PED_ASSERT (pth != NULL, return 0);
398
399   uint32_t crc32 = efi_crc32 (pth_raw, PED_LE32_TO_CPU (pth->HeaderSize));
400
401   free (pth_raw);
402
403   return crc32;
404 }
405
406 static inline int
407 guid_cmp (efi_guid_t left, efi_guid_t right)
408 {
409   return memcmp (&left, &right, sizeof (efi_guid_t));
410 }
411
412 /* checks if 'mbr' is a protective MBR partition table */
413 static inline int
414 _pmbr_is_valid (const LegacyMBR_t *mbr)
415 {
416   int i;
417
418   PED_ASSERT (mbr != NULL, return 0);
419
420   if (mbr->Signature != PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE))
421     return 0;
422   for (i = 0; i < 4; i++)
423     {
424       if (mbr->PartitionRecord[i].OSType == EFI_PMBR_OSTYPE_EFI)
425         return 1;
426     }
427   return 0;
428 }
429
430 static int
431 gpt_probe (const PedDevice *dev)
432 {
433   GuidPartitionTableHeader_t *gpt = NULL;
434   uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
435   int gpt_sig_found = 0;
436
437   PED_ASSERT (dev != NULL, return 0);
438
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     {
442       gpt = pth_new_from_raw (dev, pth_raw);
443       if (gpt->Signature == PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE))
444         gpt_sig_found = 1;
445     }
446
447   free (pth_raw);
448
449   pth_free (gpt);
450
451   if (!gpt_sig_found)
452     return 0;
453
454   void *label;
455   if (!ptt_read_sector (dev, 0, &label))
456     return 0;
457
458   int ok = 1;
459   if (!_pmbr_is_valid ((const LegacyMBR_t *) label))
460     {
461       int ex_status = ped_exception_throw
462         (PED_EXCEPTION_WARNING,
463          PED_EXCEPTION_YES_NO,
464          _("%s contains GPT signatures, indicating that it has "
465            "a GPT table.  However, it does not have a valid "
466            "fake msdos partition table, as it should.  Perhaps "
467            "it was corrupted -- possibly by a program that "
468            "doesn't understand GPT partition tables.  Or "
469            "perhaps you deleted the GPT table, and are now "
470            "using an msdos partition table.  Is this a GPT "
471            "partition table?"),
472          dev->path);
473       if (ex_status == PED_EXCEPTION_NO)
474         ok = 0;
475     }
476
477   free (label);
478   return ok;
479 }
480
481 #ifndef DISCOVER_ONLY
482 /* writes zeros to the PMBR and the primary and alternate GPTHs and PTEs */
483 static int
484 gpt_clobber (PedDevice *dev)
485 {
486   uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
487   GuidPartitionTableHeader_t *gpt;
488
489   PED_ASSERT (dev != NULL, return 0);
490
491   /*
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.
495    */
496   if (!ped_device_read (dev, pth_raw,
497                         GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS))
498     {
499       free (pth_raw);
500       return 0;
501     }
502
503   gpt = pth_new_from_raw (dev, pth_raw);
504   free (pth_raw);
505
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,
511                           GPT_HEADER_SECTORS))
512     goto error_free_with_gpt;
513
514   if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA) < dev->length - 1)
515     {
516       if (!ped_device_write (dev, gpt,
517                              PED_LE64_TO_CPU (gpt->AlternateLBA),
518                              GPT_HEADER_SECTORS))
519         return 0;
520     }
521
522   pth_free (gpt);
523
524   return 1;
525
526 error_free_with_gpt:
527   pth_free (gpt);
528   return 0;
529 }
530 #endif /* !DISCOVER_ONLY */
531
532 static PedDisk *
533 gpt_alloc (const PedDevice *dev)
534 {
535   PedDisk *disk;
536   GPTDiskData *gpt_disk_data;
537   PedSector data_start, data_end;
538
539   disk = _ped_disk_alloc ((PedDevice *) dev, &gpt_disk_type);
540   if (!disk)
541     goto error;
542   disk->disk_specific = gpt_disk_data = ped_malloc (sizeof (GPTDiskData));
543   if (!disk->disk_specific)
544     goto error_free_disk;
545
546   data_start = 2 + GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
547   data_end = dev->length - 2
548     - GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
549   ped_geometry_init (&gpt_disk_data->data_area, dev, data_start,
550                      data_end - data_start + 1);
551   gpt_disk_data->entry_count = GPT_DEFAULT_PARTITION_ENTRIES;
552   uuid_generate ((unsigned char *) &gpt_disk_data->uuid);
553   swap_uuid_and_efi_guid ((unsigned char *) (&gpt_disk_data->uuid));
554   return disk;
555
556 error_free_disk:
557   free (disk);
558 error:
559   return NULL;
560 }
561
562 static PedDisk *
563 gpt_duplicate (const PedDisk *disk)
564 {
565   PedDisk *new_disk;
566   GPTDiskData *new_disk_data;
567   GPTDiskData *old_disk_data;
568
569   new_disk = ped_disk_new_fresh (disk->dev, &gpt_disk_type);
570   if (!new_disk)
571     return NULL;
572
573   old_disk_data = disk->disk_specific;
574   new_disk_data = new_disk->disk_specific;
575
576   ped_geometry_init (&new_disk_data->data_area, disk->dev,
577                      old_disk_data->data_area.start,
578                      old_disk_data->data_area.length);
579   new_disk_data->entry_count = old_disk_data->entry_count;
580   new_disk_data->uuid = old_disk_data->uuid;
581   return new_disk;
582 }
583
584 static void
585 gpt_free (PedDisk *disk)
586 {
587   ped_disk_delete_all (disk);
588   free (disk->disk_specific);
589   _ped_disk_free (disk);
590 }
591
592 static int
593 _header_is_valid (const PedDevice *dev, GuidPartitionTableHeader_t *gpt,
594                   PedSector my_lba)
595 {
596   uint32_t crc, origcrc;
597
598   if (PED_LE64_TO_CPU (gpt->Signature) != GPT_HEADER_SIGNATURE)
599     return 0;
600   /*
601    * "While the GUID Partition Table Header's size may increase
602    * in the future it cannot span more than one block on the
603    * device."  EFI Specification, version 1.10, 11.2.2.1
604    */
605   if (PED_LE32_TO_CPU (gpt->HeaderSize) < pth_get_size_static (dev)
606       || PED_LE32_TO_CPU (gpt->HeaderSize) > dev->sector_size)
607     return 0;
608
609   /* The SizeOfPartitionEntry must be a multiple of 8 and
610      no smaller than the size of the PartitionEntry structure.
611      We also require that be no larger than 1/16th of UINT32_MAX,
612      as an additional sanity check.  */
613   uint32_t sope = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
614   if (sope % 8 != 0
615       || sope < sizeof (GuidPartitionEntry_t) || (UINT32_MAX >> 4) < sope)
616     return 0;
617
618   if (PED_LE64_TO_CPU (gpt->MyLBA) != my_lba)
619     return 0;
620
621   PedSector alt_lba = PED_LE64_TO_CPU (gpt->AlternateLBA);
622   /* The backup table's AlternateLBA must be 1.  */
623   if (my_lba != 1 && alt_lba != 1)
624     return 0;
625
626   /* The alt_lba must never be the same as my_lba.  */
627   if (alt_lba == my_lba)
628     return 0;
629
630   origcrc = gpt->HeaderCRC32;
631   gpt->HeaderCRC32 = 0;
632   crc = pth_crc32 (dev, gpt);
633   gpt->HeaderCRC32 = origcrc;
634
635   return crc == PED_LE32_TO_CPU (origcrc);
636 }
637
638 static int
639 _parse_header (PedDisk *disk, const GuidPartitionTableHeader_t *gpt,
640                int *update_needed)
641 {
642   GPTDiskData *gpt_disk_data = disk->disk_specific;
643   PedSector first_usable;
644   PedSector last_usable;
645   PedSector last_usable_if_grown, last_usable_min_default;
646   static int asked_already;
647
648   // PED_ASSERT (_header_is_valid (disk->dev, gpt), return 0);
649
650 #ifndef DISCOVER_ONLY
651   if (PED_LE32_TO_CPU (gpt->Revision) > GPT_HEADER_REVISION_V1_02)
652     {
653       if (ped_exception_throw
654           (PED_EXCEPTION_WARNING,
655            PED_EXCEPTION_IGNORE_CANCEL,
656            _("The format of the GPT partition table is version "
657              "%x, which is newer than what Parted can "
658              "recognise.  Please tell us!  bug-parted@gnu.org"),
659            PED_LE32_TO_CPU (gpt->Revision)) != PED_EXCEPTION_IGNORE)
660         return 0;
661     }
662 #endif
663
664   first_usable = PED_LE64_TO_CPU (gpt->FirstUsableLBA);
665   last_usable = PED_LE64_TO_CPU (gpt->LastUsableLBA);
666
667   /* Need to check whether the volume has grown, the LastUsableLBA is
668      normally set to disk->dev->length - 2 - ptes_size (at least for parted
669      created volumes), where ptes_size is the number of entries *
670      size of each entry / sector size or 16k / sector size, whatever the greater.
671      If the volume has grown, offer the user the chance to use the new
672      space or continue with the current usable area.  Only ask once per
673      parted invocation. */
674
675   last_usable_if_grown
676     = (disk->dev->length - 2 -
677        ((PedSector) (PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries)) *
678         (PedSector) (PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry)) /
679         disk->dev->sector_size));
680
681   last_usable_min_default = disk->dev->length - 2 -
682     GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / disk->dev->sector_size;
683
684   if (last_usable_if_grown > last_usable_min_default)
685     {
686       last_usable_if_grown = last_usable_min_default;
687     }
688
689   PED_ASSERT (last_usable > first_usable, return 0);
690   PED_ASSERT (last_usable <= disk->dev->length, return 0);
691
692   PED_ASSERT (last_usable_if_grown > first_usable, return 0);
693   PED_ASSERT (last_usable_if_grown <= disk->dev->length, return 0);
694
695   if (!asked_already && last_usable < last_usable_if_grown)
696     {
697
698       PedExceptionOption q;
699
700       q = ped_exception_throw
701         (PED_EXCEPTION_WARNING,
702          PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE,
703          _("Not all of the space available to %s appears "
704            "to be used, you can fix the GPT to use all of the "
705            "space (an extra %llu blocks) or continue with the "
706            "current setting? "), disk->dev->path,
707          (uint64_t) (last_usable_if_grown - last_usable));
708
709       if (q == PED_EXCEPTION_FIX)
710         {
711           last_usable = last_usable_if_grown;
712           *update_needed = 1;
713         }
714       else if (q != PED_EXCEPTION_UNHANDLED)
715         {
716           asked_already = 1;
717         }
718     }
719
720   ped_geometry_init (&gpt_disk_data->data_area, disk->dev,
721                      first_usable, last_usable - first_usable + 1);
722
723   gpt_disk_data->entry_count
724     = PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries);
725   PED_ASSERT (gpt_disk_data->entry_count > 0, return 0);
726   PED_ASSERT (gpt_disk_data->entry_count <= 8192, return 0);
727
728   gpt_disk_data->uuid = gpt->DiskGUID;
729
730   return 1;
731 }
732
733 static PedPartition *
734 _parse_part_entry (PedDisk *disk, GuidPartitionEntry_t *pte)
735 {
736   PedPartition *part;
737   GPTPartitionData *gpt_part_data;
738   unsigned int i;
739
740   part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
741                             PED_LE64_TO_CPU (pte->StartingLBA),
742                             PED_LE64_TO_CPU (pte->EndingLBA));
743   if (!part)
744     return NULL;
745
746   gpt_part_data = part->disk_specific;
747   gpt_part_data->type = pte->PartitionTypeGuid;
748   gpt_part_data->uuid = pte->UniquePartitionGuid;
749   for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
750     gpt_part_data->name[i] =
751       (efi_char16_t) PED_LE16_TO_CPU ((uint16_t) pte->PartitionName[i]);
752   gpt_part_data->name[i] = 0;
753
754   gpt_part_data->lvm = gpt_part_data->raid
755     = gpt_part_data->boot = gpt_part_data->hp_service
756     = gpt_part_data->hidden = gpt_part_data->msftres
757     = gpt_part_data->bios_grub = 0;
758
759   if (pte->Attributes.RequiredToFunction & 0x1)
760     gpt_part_data->hidden = 1;
761
762   if (!guid_cmp (gpt_part_data->type, PARTITION_SYSTEM_GUID))
763     gpt_part_data->boot = 1;
764   else if (!guid_cmp (gpt_part_data->type, PARTITION_BIOS_GRUB_GUID))
765     gpt_part_data->bios_grub = 1;
766   else if (!guid_cmp (gpt_part_data->type, PARTITION_RAID_GUID))
767     gpt_part_data->raid = 1;
768   else if (!guid_cmp (gpt_part_data->type, PARTITION_LVM_GUID))
769     gpt_part_data->lvm = 1;
770   else if (!guid_cmp (gpt_part_data->type, PARTITION_HPSERVICE_GUID))
771     gpt_part_data->hp_service = 1;
772   else if (!guid_cmp (gpt_part_data->type, PARTITION_MSFT_RESERVED_GUID))
773     gpt_part_data->msftres = 1;
774
775   return part;
776 }
777
778 /* Read the primary GPT at sector 1 of DEV.
779    Verify its CRC and that of its partition entry array.
780    If they are valid, read the backup GPT specified by AlternateLBA.
781    If not, read the backup GPT in the last sector of the disk.
782    Return 1 if any read fails.
783    Upon successful verification of the primary GPT, set *PRIMARY_GPT, else NULL.
784    Upon successful verification of the backup GPT, set *BACKUP_GPT, else NULL.
785    If we've set *BACKUP_GPT to non-NULL, set *BACKUP_LBA to the sector
786    number in which it was found.  */
787 static int
788 gpt_read_headers (PedDevice *dev,
789                   GuidPartitionTableHeader_t **primary_gpt,
790                   GuidPartitionTableHeader_t **backup_gpt,
791                   PedSector *backup_sector_num_p)
792 {
793   *primary_gpt = NULL;
794   *backup_gpt = NULL;
795
796   void *s1;
797   if (!ptt_read_sector (dev, 1, &s1))
798     return 1;
799
800   GuidPartitionTableHeader_t *t = pth_new_from_raw (dev, s1);
801   free (s1);
802   if (t == NULL)
803     return 1;
804   GuidPartitionTableHeader_t *pri = t;
805
806   bool valid_primary = _header_is_valid (dev, pri, 1);
807   if (valid_primary)
808     *primary_gpt = pri;
809
810   PedSector backup_sector_num =
811     (valid_primary
812      ? PED_LE64_TO_CPU (pri->AlternateLBA)
813      : dev->length - 1);
814
815   void *s_bak;
816   if (!ptt_read_sector (dev, backup_sector_num, &s_bak))
817     return 1;
818   t = pth_new_from_raw (dev, s_bak);
819   if (t == NULL)
820     return 1;
821
822   GuidPartitionTableHeader_t *bak = t;
823   if (_header_is_valid (dev, bak, backup_sector_num))
824     {
825       *backup_gpt = bak;
826       *backup_sector_num_p = backup_sector_num;
827     }
828
829   return 0;
830 }
831
832 /************************************************************
833  *  Intel is changing the EFI Spec. (after v1.02) to say that a
834  *  disk is considered to have a GPT label only if the GPT
835  *  structures are correct, and the MBR is actually a Protective
836  *  MBR (has one 0xEE type partition).
837  *  Problem occurs when a GPT-partitioned disk is then
838  *  edited with a legacy (non-GPT-aware) application, such as
839  *  fdisk (which doesn't generally erase the PGPT or AGPT).
840  *  How should such a disk get handled?  As a GPT disk (throwing
841  *  away the fdisk changes), or as an MSDOS disk (throwing away
842  *  the GPT information).  Previously, I've taken the GPT-is-right,
843  *  MBR is wrong, approach, to stay consistent with the EFI Spec.
844  *  Intel disagrees, saying the disk should then be treated
845  *  as having a msdos label, not a GPT label.  If this is true,
846  *  then what's the point of having an AGPT, since if the PGPT
847  *  is screwed up, likely the PMBR is too, and the PMBR becomes
848  *  a single point of failure.
849  *  So, in the Linux kernel, I'm going to test for PMBR, and
850  *  warn if it's not there, and treat the disk as MSDOS, with a note
851  *  for users to use Parted to "fix up" their disk if they
852  *  really want it to be considered GPT.
853  ************************************************************/
854 static int
855 gpt_read (PedDisk *disk)
856 {
857   GPTDiskData *gpt_disk_data = disk->disk_specific;
858   void *ptes;
859   int i;
860 #ifndef DISCOVER_ONLY
861   int write_back = 1;
862 #endif
863
864   ped_disk_delete_all (disk);
865
866   /* motivation: let the user decide about the pmbr... during
867      ped_disk_probe(), they probably didn't get a choice... */
868   if (!gpt_probe (disk->dev))
869     goto error;
870
871   GuidPartitionTableHeader_t *gpt = NULL;
872   GuidPartitionTableHeader_t *primary_gpt;
873   GuidPartitionTableHeader_t *backup_gpt;
874   PedSector backup_sector_num;
875   int read_failure = gpt_read_headers (disk->dev, &primary_gpt, &backup_gpt,
876                                        &backup_sector_num);
877   if (read_failure)
878     {
879       /* This includes the case in which there used to be a GPT partition
880          table here, with an alternate LBA that extended beyond the current
881          end-of-device.  It's treated as a non-match.  */
882
883       /* Another possibility:
884          The primary header is ok, but backup is corrupt.
885          In the UEFI spec, this means the primary GUID table
886          is officially invalid.  */
887       pth_free (backup_gpt);
888       pth_free (primary_gpt);
889       return 0;
890     }
891
892   if (primary_gpt && backup_gpt)
893     {
894       /* Both are valid.  */
895       if (PED_LE64_TO_CPU (primary_gpt->AlternateLBA) < disk->dev->length - 1)
896         {
897 #ifndef DISCOVER_ONLY
898           switch (ped_exception_throw
899                   (PED_EXCEPTION_ERROR,
900                    (PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL
901                     | PED_EXCEPTION_IGNORE),
902                    _("The backup GPT table is not at the end of the disk, as it "
903                      "should be.  This might mean that another operating system "
904                      "believes the disk is smaller.  Fix, by moving the backup "
905                      "to the end (and removing the old backup)?")))
906             {
907             case PED_EXCEPTION_CANCEL:
908               goto error_free_gpt;
909             case PED_EXCEPTION_FIX:
910               ptt_clear_sectors (disk->dev,
911                                  PED_LE64_TO_CPU (primary_gpt->AlternateLBA), 1);
912               break;
913             default:
914               write_back = 0;
915               break;
916             }
917 #endif /* !DISCOVER_ONLY */
918         }
919       gpt = primary_gpt;
920       pth_free (backup_gpt);
921     }
922   else if (!primary_gpt && !backup_gpt)
923     {
924       /* Both are corrupt.  */
925       ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
926                            _("Both the primary and backup GPT tables "
927                              "are corrupt.  Try making a fresh table, "
928                              "and using Parted's rescue feature to "
929                              "recover partitions."));
930       goto error;
931     }
932   else if (primary_gpt && !backup_gpt)
933     {
934       /* The primary header is ok, but backup is corrupt.  */
935       if (ped_exception_throw
936           (PED_EXCEPTION_ERROR, PED_EXCEPTION_OK_CANCEL,
937            _("The backup GPT table is corrupt, but the "
938              "primary appears OK, so that will be used."))
939           == PED_EXCEPTION_CANCEL)
940         goto error_free_gpt;
941
942       gpt = primary_gpt;
943     }
944   else /* !primary_gpt && backup_gpt */
945     {
946       /* primary GPT corrupt, backup is ok.  */
947       if (ped_exception_throw
948           (PED_EXCEPTION_ERROR, PED_EXCEPTION_OK_CANCEL,
949            _("The primary GPT table is corrupt, but the "
950              "backup appears OK, so that will be used."))
951           == PED_EXCEPTION_CANCEL)
952         goto error_free_gpt;
953
954       gpt = backup_gpt;
955     }
956   backup_gpt = NULL;
957   primary_gpt = NULL;
958
959   if (!_parse_header (disk, gpt, &write_back))
960     goto error_free_gpt;
961
962   uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
963   size_t ptes_bytes = p_ent_size * gpt_disk_data->entry_count;
964   size_t ptes_sectors = ped_div_round_up (ptes_bytes,
965                                           disk->dev->sector_size);
966
967   if (xalloc_oversized (ptes_sectors, disk->dev->sector_size))
968     goto error_free_gpt;
969   ptes = ped_malloc (ptes_sectors * disk->dev->sector_size);
970
971   if (!ped_device_read (disk->dev, ptes,
972                         PED_LE64_TO_CPU (gpt->PartitionEntryLBA),
973                         ptes_sectors))
974     goto error_free_ptes;
975
976   uint32_t ptes_crc = efi_crc32 (ptes, ptes_bytes);
977   if (ptes_crc != gpt->PartitionEntryArrayCRC32)
978     {
979       ped_exception_throw
980         (PED_EXCEPTION_ERROR,
981          PED_EXCEPTION_CANCEL,
982          _("primary partition table array CRC mismatch"));
983       goto error_free_ptes;
984     }
985
986   for (i = 0; i < gpt_disk_data->entry_count; i++)
987     {
988       GuidPartitionEntry_t *pte
989         = (GuidPartitionEntry_t *) ((char *) ptes + i * p_ent_size);
990       PedPartition *part;
991       PedConstraint *constraint_exact;
992
993       if (!guid_cmp (pte->PartitionTypeGuid, UNUSED_ENTRY_GUID))
994         continue;
995
996       part = _parse_part_entry (disk, pte);
997       if (!part)
998         goto error_delete_all;
999
1000       part->fs_type = ped_file_system_probe (&part->geom);
1001       part->num = i + 1;
1002
1003       constraint_exact = ped_constraint_exact (&part->geom);
1004       if (!ped_disk_add_partition (disk, part, constraint_exact))
1005         {
1006           ped_partition_destroy (part);
1007           goto error_delete_all;
1008         }
1009       ped_constraint_destroy (constraint_exact);
1010     }
1011   free (ptes);
1012
1013 #ifndef DISCOVER_ONLY
1014   if (write_back)
1015     ped_disk_commit_to_dev (disk);
1016 #endif
1017
1018   pth_free (gpt);
1019   return 1;
1020
1021 error_delete_all:
1022   ped_disk_delete_all (disk);
1023 error_free_ptes:
1024   free (ptes);
1025 error_free_gpt:
1026   pth_free (primary_gpt);
1027   pth_free (backup_gpt);
1028   pth_free (gpt);
1029 error:
1030   return 0;
1031 }
1032
1033 #ifndef DISCOVER_ONLY
1034 /* Write the protective MBR (to keep DOS happy) */
1035 static int
1036 _write_pmbr (PedDevice *dev)
1037 {
1038   /* The UEFI spec is not clear about what to do with the following
1039      elements of the Protective MBR (pmbr): BootCode (0-440B),
1040      UniqueMBRSignature (440B-444B) and Unknown (444B-446B).
1041      With this in mind, we try not to modify these elements.  */
1042   void *s0;
1043   if (!ptt_read_sector (dev, 0, &s0))
1044     return 0;
1045   LegacyMBR_t *pmbr = s0;
1046
1047   /* Zero out the legacy partitions.  */
1048   memset (pmbr->PartitionRecord, 0, sizeof pmbr->PartitionRecord);
1049
1050   pmbr->Signature = PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE);
1051   pmbr->PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI;
1052   pmbr->PartitionRecord[0].StartSector = 1;
1053   pmbr->PartitionRecord[0].EndHead = 0xFE;
1054   pmbr->PartitionRecord[0].EndSector = 0xFF;
1055   pmbr->PartitionRecord[0].EndTrack = 0xFF;
1056   pmbr->PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32 (1);
1057   if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
1058     pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (0xFFFFFFFF);
1059   else
1060     pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (dev->length - 1UL);
1061
1062   int write_ok = ped_device_write (dev, pmbr, GPT_PMBR_LBA,
1063                                    GPT_PMBR_SECTORS);
1064   free (s0);
1065   return write_ok;
1066 }
1067
1068 static void
1069 _generate_header (const PedDisk *disk, int alternate, uint32_t ptes_crc,
1070                   GuidPartitionTableHeader_t **gpt_p)
1071 {
1072   GPTDiskData *gpt_disk_data = disk->disk_specific;
1073   GuidPartitionTableHeader_t *gpt;
1074
1075   *gpt_p = pth_new_zeroed (disk->dev);
1076
1077   gpt = *gpt_p;
1078
1079   gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE);
1080   gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00);
1081
1082   /* per 1.00 spec */
1083   gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev));
1084   gpt->HeaderCRC32 = 0;
1085   gpt->Reserved1 = 0;
1086
1087   if (alternate)
1088     {
1089       PedSector ptes_size = gpt_disk_data->entry_count
1090         * sizeof (GuidPartitionEntry_t) / disk->dev->sector_size;
1091
1092       gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1093       gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
1094       gpt->PartitionEntryLBA
1095         = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_size);
1096     }
1097   else
1098     {
1099       gpt->MyLBA = PED_CPU_TO_LE64 (1);
1100       gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1101       gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
1102     }
1103
1104   gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
1105   gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
1106   gpt->DiskGUID = gpt_disk_data->uuid;
1107   gpt->NumberOfPartitionEntries
1108     = PED_CPU_TO_LE32 (gpt_disk_data->entry_count);
1109   gpt->SizeOfPartitionEntry = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t));
1110   gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32 (ptes_crc);
1111   gpt->HeaderCRC32 = PED_CPU_TO_LE32 (pth_crc32 (disk->dev, gpt));
1112 }
1113
1114 static void
1115 _partition_generate_part_entry (PedPartition *part, GuidPartitionEntry_t *pte)
1116 {
1117   GPTPartitionData *gpt_part_data = part->disk_specific;
1118   unsigned int i;
1119
1120   PED_ASSERT (gpt_part_data != NULL, return);
1121
1122   pte->PartitionTypeGuid = gpt_part_data->type;
1123   pte->UniquePartitionGuid = gpt_part_data->uuid;
1124   pte->StartingLBA = PED_CPU_TO_LE64 (part->geom.start);
1125   pte->EndingLBA = PED_CPU_TO_LE64 (part->geom.end);
1126   memset (&pte->Attributes, 0, sizeof (GuidPartitionEntryAttributes_t));
1127
1128   if (gpt_part_data->hidden)
1129     pte->Attributes.RequiredToFunction = 1;
1130
1131   for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
1132     pte->PartitionName[i]
1133       = (efi_char16_t) PED_CPU_TO_LE16 ((uint16_t) gpt_part_data->name[i]);
1134 }
1135
1136 static int
1137 gpt_write (const PedDisk *disk)
1138 {
1139   GPTDiskData *gpt_disk_data;
1140   GuidPartitionEntry_t *ptes;
1141   uint32_t ptes_crc;
1142   uint8_t *pth_raw;
1143   GuidPartitionTableHeader_t *gpt;
1144   PedPartition *part;
1145   int ptes_size;
1146
1147   PED_ASSERT (disk != NULL, goto error);
1148   PED_ASSERT (disk->dev != NULL, goto error);
1149   PED_ASSERT (disk->disk_specific != NULL, goto error);
1150
1151   gpt_disk_data = disk->disk_specific;
1152
1153   ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
1154   ptes = (GuidPartitionEntry_t *) ped_malloc (ptes_size);
1155   if (!ptes)
1156     goto error;
1157   memset (ptes, 0, ptes_size);
1158   for (part = ped_disk_next_partition (disk, NULL); part;
1159        part = ped_disk_next_partition (disk, part))
1160     {
1161       if (part->type != 0)
1162         continue;
1163       _partition_generate_part_entry (part, &ptes[part->num - 1]);
1164     }
1165
1166   ptes_crc = efi_crc32 (ptes, ptes_size);
1167
1168   /* Write protective MBR */
1169   if (!_write_pmbr (disk->dev))
1170     goto error_free_ptes;
1171
1172   /* Write PTH and PTEs */
1173   _generate_header (disk, 0, ptes_crc, &gpt);
1174   pth_raw = pth_get_raw (disk->dev, gpt);
1175   pth_free (gpt);
1176   bool write_ok = ped_device_write (disk->dev, pth_raw, 1, 1);
1177   free (pth_raw);
1178   if (!write_ok)
1179     goto error_free_ptes;
1180   if (!ped_device_write (disk->dev, ptes, 2,
1181                          ptes_size / disk->dev->sector_size))
1182     goto error_free_ptes;
1183
1184   /* Write Alternate PTH & PTEs */
1185   _generate_header (disk, 1, ptes_crc, &gpt);
1186   pth_raw = pth_get_raw (disk->dev, gpt);
1187   pth_free (gpt);
1188   write_ok = ped_device_write (disk->dev, pth_raw, disk->dev->length - 1, 1);
1189   free (pth_raw);
1190   if (!write_ok)
1191     goto error_free_ptes;
1192   if (!ped_device_write (disk->dev, ptes,
1193                          disk->dev->length - 1 -
1194                          ptes_size / disk->dev->sector_size,
1195                          ptes_size / disk->dev->sector_size))
1196     goto error_free_ptes;
1197
1198   free (ptes);
1199   return ped_device_sync (disk->dev);
1200
1201   free (pth_raw);
1202 error_free_ptes:
1203   free (ptes);
1204 error:
1205   return 0;
1206 }
1207 #endif /* !DISCOVER_ONLY */
1208
1209 static int
1210 add_metadata_part (PedDisk *disk, PedSector start, PedSector length)
1211 {
1212   PedPartition *part;
1213   PedConstraint *constraint_exact;
1214   PED_ASSERT (disk != NULL, return 0);
1215
1216   part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1217                             start, start + length - 1);
1218   if (!part)
1219     goto error;
1220
1221   constraint_exact = ped_constraint_exact (&part->geom);
1222   if (!ped_disk_add_partition (disk, part, constraint_exact))
1223     goto error_destroy_constraint;
1224   ped_constraint_destroy (constraint_exact);
1225   return 1;
1226
1227 error_destroy_constraint:
1228   ped_constraint_destroy (constraint_exact);
1229   ped_partition_destroy (part);
1230 error:
1231   return 0;
1232 }
1233
1234 static PedPartition *
1235 gpt_partition_new (const PedDisk *disk,
1236                    PedPartitionType part_type,
1237                    const PedFileSystemType *fs_type, PedSector start,
1238                    PedSector end)
1239 {
1240   PedPartition *part;
1241   GPTPartitionData *gpt_part_data;
1242
1243   part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1244   if (!part)
1245     goto error;
1246
1247   if (part_type != 0)
1248     return part;
1249
1250   gpt_part_data = part->disk_specific =
1251     ped_malloc (sizeof (GPTPartitionData));
1252   if (!gpt_part_data)
1253     goto error_free_part;
1254
1255   gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1256   gpt_part_data->lvm = 0;
1257   gpt_part_data->raid = 0;
1258   gpt_part_data->boot = 0;
1259   gpt_part_data->bios_grub = 0;
1260   gpt_part_data->hp_service = 0;
1261   gpt_part_data->hidden = 0;
1262   gpt_part_data->msftres = 0;
1263   uuid_generate ((unsigned char *) &gpt_part_data->uuid);
1264   swap_uuid_and_efi_guid ((unsigned char *) (&gpt_part_data->uuid));
1265   memset (gpt_part_data->name, 0, sizeof gpt_part_data->name);
1266   return part;
1267
1268 error_free_part:
1269   _ped_partition_free (part);
1270 error:
1271   return NULL;
1272 }
1273
1274 static PedPartition *
1275 gpt_partition_duplicate (const PedPartition *part)
1276 {
1277   PedPartition *result;
1278   GPTPartitionData *part_data = part->disk_specific;
1279   GPTPartitionData *result_data;
1280
1281   result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
1282                                  part->geom.start, part->geom.end);
1283   if (!result)
1284     goto error;
1285   result->num = part->num;
1286
1287   if (result->type != 0)
1288     return result;
1289
1290   result_data = result->disk_specific =
1291     ped_malloc (sizeof (GPTPartitionData));
1292   if (!result_data)
1293     goto error_free_part;
1294
1295   result_data->type = part_data->type;
1296   result_data->uuid = part_data->uuid;
1297   strcpy (result_data->name, part_data->name);
1298   return result;
1299
1300 error_free_part:
1301   _ped_partition_free (result);
1302 error:
1303   return NULL;
1304 }
1305
1306 static void
1307 gpt_partition_destroy (PedPartition *part)
1308 {
1309   if (part->type == 0)
1310     {
1311       PED_ASSERT (part->disk_specific != NULL, return);
1312       free (part->disk_specific);
1313     }
1314
1315   _ped_partition_free (part);
1316 }
1317
1318 static int
1319 gpt_partition_set_system (PedPartition *part,
1320                           const PedFileSystemType *fs_type)
1321 {
1322   GPTPartitionData *gpt_part_data = part->disk_specific;
1323
1324   PED_ASSERT (gpt_part_data != NULL, return 0);
1325
1326   part->fs_type = fs_type;
1327
1328   if (gpt_part_data->lvm)
1329     {
1330       gpt_part_data->type = PARTITION_LVM_GUID;
1331       return 1;
1332     }
1333   if (gpt_part_data->raid)
1334     {
1335       gpt_part_data->type = PARTITION_RAID_GUID;
1336       return 1;
1337     }
1338   if (gpt_part_data->boot)
1339     {
1340       gpt_part_data->type = PARTITION_SYSTEM_GUID;
1341       return 1;
1342     }
1343   if (gpt_part_data->bios_grub)
1344     {
1345       gpt_part_data->type = PARTITION_BIOS_GRUB_GUID;
1346       return 1;
1347     }
1348   if (gpt_part_data->hp_service)
1349     {
1350       gpt_part_data->type = PARTITION_HPSERVICE_GUID;
1351       return 1;
1352     }
1353   if (gpt_part_data->msftres)
1354     {
1355       gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1356       return 1;
1357     }
1358
1359   if (fs_type)
1360     {
1361       if (strncmp (fs_type->name, "fat", 3) == 0
1362           || strcmp (fs_type->name, "ntfs") == 0)
1363         {
1364           gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1365           return 1;
1366         }
1367       if (strncmp (fs_type->name, "hfs", 3) == 0)
1368         {
1369           gpt_part_data->type = PARTITION_APPLE_HFS_GUID;
1370           return 1;
1371         }
1372       if (strstr (fs_type->name, "swap"))
1373         {
1374           gpt_part_data->type = PARTITION_SWAP_GUID;
1375           return 1;
1376         }
1377     }
1378
1379   gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1380   return 1;
1381 }
1382
1383 /* Allocate metadata partitions for the GPTH and PTES */
1384 static int
1385 gpt_alloc_metadata (PedDisk *disk)
1386 {
1387   PedSector gptlength, pteslength = 0;
1388   GPTDiskData *gpt_disk_data;
1389
1390   PED_ASSERT (disk != NULL, return 0);
1391   PED_ASSERT (disk->dev != NULL, return 0);
1392   PED_ASSERT (disk->disk_specific != NULL, return 0);
1393   gpt_disk_data = disk->disk_specific;
1394
1395   gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t),
1396                                 disk->dev->sector_size);
1397   pteslength = ped_div_round_up (gpt_disk_data->entry_count
1398                                  * sizeof (GuidPartitionEntry_t),
1399                                  disk->dev->sector_size);
1400
1401   /* metadata at the start of the disk includes the MBR */
1402   if (!add_metadata_part (disk, GPT_PMBR_LBA,
1403                           GPT_PMBR_SECTORS + gptlength + pteslength))
1404     return 0;
1405
1406   /* metadata at the end of the disk */
1407   if (!add_metadata_part (disk, disk->dev->length - gptlength - pteslength,
1408                           gptlength + pteslength))
1409     return 0;
1410
1411   return 1;
1412 }
1413
1414 /* Does nothing, as the read/new/destroy functions maintain part->num */
1415 static int
1416 gpt_partition_enumerate (PedPartition *part)
1417 {
1418   GPTDiskData *gpt_disk_data = part->disk->disk_specific;
1419   int i;
1420
1421   /* never change the partition numbers */
1422   if (part->num != -1)
1423     return 1;
1424
1425   for (i = 1; i <= gpt_disk_data->entry_count; i++)
1426     {
1427       if (!ped_disk_get_partition (part->disk, i))
1428         {
1429           part->num = i;
1430           return 1;
1431         }
1432     }
1433
1434   PED_ASSERT (0, return 0);
1435
1436   return 0;                     /* used if debug is disabled */
1437 }
1438
1439 static int
1440 gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
1441 {
1442   GPTPartitionData *gpt_part_data;
1443   PED_ASSERT (part != NULL, return 0);
1444   PED_ASSERT (part->disk_specific != NULL, return 0);
1445   gpt_part_data = part->disk_specific;
1446
1447   switch (flag)
1448     {
1449     case PED_PARTITION_BOOT:
1450       gpt_part_data->boot = state;
1451       if (state)
1452         gpt_part_data->raid
1453           = gpt_part_data->lvm
1454           = gpt_part_data->bios_grub
1455           = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
1456       return gpt_partition_set_system (part, part->fs_type);
1457     case PED_PARTITION_BIOS_GRUB:
1458       gpt_part_data->bios_grub = state;
1459       if (state)
1460         gpt_part_data->raid
1461           = gpt_part_data->lvm
1462           = gpt_part_data->boot
1463           = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
1464       return gpt_partition_set_system (part, part->fs_type);
1465     case PED_PARTITION_RAID:
1466       gpt_part_data->raid = state;
1467       if (state)
1468         gpt_part_data->boot
1469           = gpt_part_data->lvm
1470           = gpt_part_data->bios_grub
1471           = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
1472       return gpt_partition_set_system (part, part->fs_type);
1473     case PED_PARTITION_LVM:
1474       gpt_part_data->lvm = state;
1475       if (state)
1476         gpt_part_data->boot
1477           = gpt_part_data->raid
1478           = gpt_part_data->bios_grub
1479           = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
1480       return gpt_partition_set_system (part, part->fs_type);
1481     case PED_PARTITION_HPSERVICE:
1482       gpt_part_data->hp_service = state;
1483       if (state)
1484         gpt_part_data->boot
1485           = gpt_part_data->raid
1486           = gpt_part_data->lvm
1487           = gpt_part_data->bios_grub = gpt_part_data->msftres = 0;
1488       return gpt_partition_set_system (part, part->fs_type);
1489     case PED_PARTITION_MSFT_RESERVED:
1490       gpt_part_data->msftres = state;
1491       if (state)
1492         gpt_part_data->boot
1493           = gpt_part_data->raid
1494           = gpt_part_data->lvm
1495           = gpt_part_data->bios_grub = gpt_part_data->hp_service = 0;
1496       return gpt_partition_set_system (part, part->fs_type);
1497     case PED_PARTITION_HIDDEN:
1498       gpt_part_data->hidden = state;
1499       return 1;
1500     case PED_PARTITION_SWAP:
1501     case PED_PARTITION_ROOT:
1502     case PED_PARTITION_LBA:
1503     default:
1504       return 0;
1505     }
1506   return 1;
1507 }
1508
1509 static int
1510 gpt_partition_get_flag (const PedPartition *part, PedPartitionFlag flag)
1511 {
1512   GPTPartitionData *gpt_part_data;
1513   PED_ASSERT (part->disk_specific != NULL, return 0);
1514   gpt_part_data = part->disk_specific;
1515
1516   switch (flag)
1517     {
1518     case PED_PARTITION_RAID:
1519       return gpt_part_data->raid;
1520     case PED_PARTITION_LVM:
1521       return gpt_part_data->lvm;
1522     case PED_PARTITION_BOOT:
1523       return gpt_part_data->boot;
1524     case PED_PARTITION_BIOS_GRUB:
1525       return gpt_part_data->bios_grub;
1526     case PED_PARTITION_HPSERVICE:
1527       return gpt_part_data->hp_service;
1528     case PED_PARTITION_MSFT_RESERVED:
1529       return gpt_part_data->msftres;
1530     case PED_PARTITION_HIDDEN:
1531       return gpt_part_data->hidden;
1532     case PED_PARTITION_SWAP:
1533     case PED_PARTITION_LBA:
1534     case PED_PARTITION_ROOT:
1535     default:
1536       return 0;
1537     }
1538   return 0;
1539 }
1540
1541 static int
1542 gpt_partition_is_flag_available (const PedPartition *part,
1543                                  PedPartitionFlag flag)
1544 {
1545   switch (flag)
1546     {
1547     case PED_PARTITION_RAID:
1548     case PED_PARTITION_LVM:
1549     case PED_PARTITION_BOOT:
1550     case PED_PARTITION_BIOS_GRUB:
1551     case PED_PARTITION_HPSERVICE:
1552     case PED_PARTITION_MSFT_RESERVED:
1553     case PED_PARTITION_HIDDEN:
1554       return 1;
1555     case PED_PARTITION_SWAP:
1556     case PED_PARTITION_ROOT:
1557     case PED_PARTITION_LBA:
1558     default:
1559       return 0;
1560     }
1561   return 0;
1562 }
1563
1564 static void
1565 gpt_partition_set_name (PedPartition *part, const char *name)
1566 {
1567   GPTPartitionData *gpt_part_data = part->disk_specific;
1568
1569   strncpy (gpt_part_data->name, name, 36);
1570   gpt_part_data->name[36] = 0;
1571 }
1572
1573 static const char *
1574 gpt_partition_get_name (const PedPartition *part)
1575 {
1576   GPTPartitionData *gpt_part_data = part->disk_specific;
1577   return gpt_part_data->name;
1578 }
1579
1580 static int
1581 gpt_get_max_primary_partition_count (const PedDisk *disk)
1582 {
1583   const GPTDiskData *gpt_disk_data = disk->disk_specific;
1584   return gpt_disk_data->entry_count;
1585 }
1586
1587 /*
1588  * From (http://developer.apple.com/technotes/tn2006/tn2166.html Chapter 5).
1589  * According to the specs the first LBA (LBA0) is not relevant (it exists
1590  * to maintain compatibility).  on the second LBA(LBA1) gpt places the
1591  * header.  The header is as big as the block size.  After the header we
1592  * find the Entry array.  Each element of said array, describes each
1593  * partition.  One can have as much elements as can fit between the end of
1594  * the second LBA (where the header ends) and the FirstUsableLBA.
1595  * FirstUsableLBA is the first logical block that is used for contents
1596  * and is defined in header.
1597  *
1598  * /---------------------------------------------------\
1599  * | BLOCK0 | HEADER | Entry Array | First Usable LBA  |
1600  * |        | BLOCK1 |             |                   |
1601  * \---------------------------------------------------/
1602  *                  /              \
1603  *     /----------/                  \----------\
1604  *     /-----------------------------------------\
1605  *     |  E1  |  E2  |  E3  |...............| EN |
1606  *     \-----------------------------------------/
1607  *
1608  * The number of possible partitions or supported partitions is:
1609  * SP = FirstUsableLBA*Blocksize - 2*Blocksize / SizeOfPartitionEntry
1610  * SP = Blocksize(FirstusableLBA - 2) / SizeOfPartitoinEntry
1611  */
1612 static bool
1613 gpt_get_max_supported_partition_count (const PedDisk *disk, int *max_n)
1614 {
1615   GuidPartitionTableHeader_t *pth = NULL;
1616   uint8_t *pth_raw = ped_malloc (pth_get_size (disk->dev));
1617
1618   if (ped_device_read (disk->dev, pth_raw, 1, GPT_HEADER_SECTORS)
1619       || ped_device_read (disk->dev, pth_raw,
1620                           disk->dev->length, GPT_HEADER_SECTORS))
1621     pth = pth_new_from_raw (disk->dev, pth_raw);
1622   free (pth_raw);
1623
1624   if (pth == NULL)
1625     return false;
1626
1627   *max_n = (disk->dev->sector_size * (pth->FirstUsableLBA - 2)
1628             / PED_LE32_TO_CPU (pth->SizeOfPartitionEntry));
1629   pth_free (pth);
1630   return true;
1631 }
1632
1633 static PedConstraint *
1634 _non_metadata_constraint (const PedDisk *disk)
1635 {
1636   GPTDiskData *gpt_disk_data = disk->disk_specific;
1637
1638   return ped_constraint_new_from_max (&gpt_disk_data->data_area);
1639 }
1640
1641 static int
1642 gpt_partition_align (PedPartition *part, const PedConstraint *constraint)
1643 {
1644   PED_ASSERT (part != NULL, return 0);
1645
1646   if (_ped_partition_attempt_align (part, constraint,
1647                                     _non_metadata_constraint (part->disk)))
1648     return 1;
1649
1650 #ifndef DISCOVER_ONLY
1651   ped_exception_throw (PED_EXCEPTION_ERROR,
1652                        PED_EXCEPTION_CANCEL,
1653                        _("Unable to satisfy all constraints on the partition."));
1654 #endif
1655   return 0;
1656 }
1657
1658 static bool
1659 gpt_partition_check (const PedPartition *part)
1660 {
1661   return true;
1662 }
1663
1664 #ifdef DISCOVER_ONLY
1665 # define NULL_IF_DISCOVER_ONLY(val) NULL
1666 #else
1667 # define NULL_IF_DISCOVER_ONLY(val) val
1668 #endif
1669
1670 static PedDiskOps gpt_disk_ops =
1671 {
1672   probe:                        gpt_probe,
1673   clobber:                      NULL_IF_DISCOVER_ONLY (gpt_clobber),
1674   alloc:                        gpt_alloc,
1675   duplicate:                    gpt_duplicate,
1676   free:                         gpt_free,
1677   read:                         gpt_read,
1678   write:                        NULL_IF_DISCOVER_ONLY (gpt_write),
1679   partition_new:                gpt_partition_new,
1680   partition_duplicate:          gpt_partition_duplicate,
1681   partition_destroy:            gpt_partition_destroy,
1682   partition_set_system:         gpt_partition_set_system,
1683   partition_set_flag:           gpt_partition_set_flag,
1684   partition_get_flag:           gpt_partition_get_flag,
1685   partition_is_flag_available:  gpt_partition_is_flag_available,
1686   partition_set_name:           gpt_partition_set_name,
1687   partition_get_name:           gpt_partition_get_name,
1688   partition_align:              gpt_partition_align,
1689   partition_enumerate:          gpt_partition_enumerate,
1690   partition_check:              gpt_partition_check,
1691   alloc_metadata:               gpt_alloc_metadata,
1692   get_max_primary_partition_count: gpt_get_max_primary_partition_count,
1693   get_max_supported_partition_count: gpt_get_max_supported_partition_count
1694 };
1695
1696 static PedDiskType gpt_disk_type =
1697 {
1698   next:         NULL,
1699   name:         "gpt",
1700   ops:          &gpt_disk_ops,
1701   features:     PED_DISK_TYPE_PARTITION_NAME
1702 };
1703
1704 void
1705 ped_disk_gpt_init ()
1706 {
1707   PED_ASSERT (sizeof (GuidPartitionEntryAttributes_t) == 8, return);
1708   PED_ASSERT (sizeof (GuidPartitionEntry_t) == 128, return);
1709
1710   ped_disk_type_register (&gpt_disk_type);
1711 }
1712
1713 void
1714 ped_disk_gpt_done ()
1715 {
1716   ped_disk_type_unregister (&gpt_disk_type);
1717 }