OSDN Git Service

libparted: fix big-endian bug in gpt_get_max_supported_partition_count
[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         uint32_t time_low;
73         uint16_t time_mid;
74         uint16_t time_hi_and_version;
75         uint8_t  clock_seq_hi_and_reserved;
76         uint8_t  clock_seq_low;
77         uint8_t  node[6];
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
82  * anything :)
83  */
84
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 }})
132
133 struct __attribute__ ((packed)) _GuidPartitionTableHeader_t {
134         uint64_t Signature;
135         uint32_t Revision;
136         uint32_t HeaderSize;
137         uint32_t HeaderCRC32;
138         uint32_t Reserved1;
139         uint64_t MyLBA;
140         uint64_t AlternateLBA;
141         uint64_t FirstUsableLBA;
142         uint64_t LastUsableLBA;
143         efi_guid_t DiskGUID;
144         uint64_t PartitionEntryLBA;
145         uint32_t NumberOfPartitionEntries;
146         uint32_t SizeOfPartitionEntry;
147         uint32_t PartitionEntryArrayCRC32;
148         uint8_t* Reserved2;
149 };
150
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;
156 #else
157 #       warning "Using crippled partition entry type"
158         uint32_t RequiredToFunction:1;
159         uint32_t Reserved:32;
160         uint32_t LOST:5;
161         uint32_t GuidSpecific:16;
162 #endif
163 };
164
165 struct __attribute__ ((packed)) _GuidPartitionEntry_t {
166         efi_guid_t PartitionTypeGuid;
167         efi_guid_t UniquePartitionGuid;
168         uint64_t StartingLBA;
169         uint64_t EndingLBA;
170         GuidPartitionEntryAttributes_t Attributes;
171         efi_char16_t PartitionName[72 / sizeof(efi_char16_t)];
172 };
173
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
179
180 /*
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!
183 */
184
185 #define GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE 16384
186
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))
191
192
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;
197
198         /* Start of partition in CHS address, not used by EFI firmware. */
199         uint8_t StartHead;
200
201         /* Start of partition in CHS address, not used by EFI firmware. */
202         uint8_t StartSector;
203
204         /* Start of partition in CHS address, not used by EFI firmware. */
205         uint8_t StartTrack;
206
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. */
210         uint8_t OSType;
211
212         /* End of partition in CHS address, not used by EFI firmware. */
213         uint8_t EndHead;
214
215         /* End of partition in CHS address, not used by EFI firmware. */
216         uint8_t EndSector;
217
218         /* End of partition in CHS address, not used by EFI firmware. */
219         uint8_t EndTrack;
220
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;
224
225         /* Size of partition in LBA. Used by EFI firmware to determine
226            the size of the partition. */
227         uint32_t SizeInLBA;
228 };
229
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;
235         uint16_t Unknown;
236         PartitionRecord_t PartitionRecord[4];
237         uint16_t Signature;
238 };
239
240 /* uses libparted's disk_specific field in PedDisk, to store our info */
241 struct __attribute__ ((packed)) _GPTDiskData {
242         PedGeometry     data_area;
243         int             entry_count;
244         efi_guid_t      uuid;
245 };
246
247 /* uses libparted's disk_specific field in PedPartition, to store our info */
248 typedef struct _GPTPartitionData {
249         efi_guid_t      type;
250         efi_guid_t      uuid;
251         char            name[37];
252         int             lvm;
253         int             raid;
254         int             boot;
255         int             bios_grub;
256         int             hp_service;
257         int             hidden;
258         int             msftres;
259 } GPTPartitionData;
260
261 static PedDiskType gpt_disk_type;
262
263
264 static inline uint32_t
265 pth_get_size (const PedDevice* dev)
266 {
267         return GPT_HEADER_SECTORS * dev->sector_size;
268 }
269
270
271 static inline uint32_t
272 pth_get_size_static (const PedDevice* dev)
273 {
274         return sizeof (GuidPartitionTableHeader_t) - sizeof (uint8_t*);
275 }
276
277
278 static inline uint32_t
279 pth_get_size_rsv2 (const PedDevice* dev)
280 {
281         return pth_get_size(dev) - pth_get_size_static(dev);
282 }
283
284
285 static GuidPartitionTableHeader_t*
286 pth_new (const PedDevice* dev)
287 {
288         GuidPartitionTableHeader_t* pth = ped_malloc (
289                         sizeof (GuidPartitionTableHeader_t)
290                         + sizeof (uint8_t));
291
292         pth->Reserved2 = ped_malloc ( pth_get_size_rsv2 (dev) );
293
294         return pth;
295 }
296
297
298 static GuidPartitionTableHeader_t*
299 pth_new_zeroed (const PedDevice* dev)
300 {
301         GuidPartitionTableHeader_t* pth = pth_new (dev);
302
303         memset (pth, 0, pth_get_size_static (dev));
304         memset (pth->Reserved2, 0, pth_get_size_rsv2 (dev));
305
306         return (pth);
307 }
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         PED_ASSERT (pth != NULL, return);
328         PED_ASSERT (pth->Reserved2 != NULL, return);
329
330         free (pth->Reserved2);
331         free (pth);
332 }
333
334 static uint8_t*
335 pth_get_raw (const PedDevice* dev, const GuidPartitionTableHeader_t* pth)
336 {
337         uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
338         int size_static = pth_get_size_static (dev);
339
340         PED_ASSERT (pth != NULL, return 0);
341         PED_ASSERT (pth->Reserved2 != NULL, return 0);
342
343         memcpy (pth_raw, pth, size_static);
344         memcpy (pth_raw + size_static, pth->Reserved2, pth_get_size_rsv2 (dev));
345
346         return pth_raw;
347 }
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         uint32_t crc32 = 0;
396
397         PED_ASSERT (dev != NULL, return 0);
398         PED_ASSERT (pth != NULL, return 0);
399
400         crc32 = efi_crc32 (pth_raw, PED_LE32_TO_CPU (pth->HeaderSize));
401
402         free (pth_raw);
403
404         return crc32;
405 }
406
407 static inline int
408 guid_cmp (efi_guid_t left, efi_guid_t right)
409 {
410         return memcmp(&left, &right, sizeof(efi_guid_t));
411 }
412
413 /* checks if 'mbr' is a protective MBR partition table */
414 static inline int
415 _pmbr_is_valid (const LegacyMBR_t* mbr)
416 {
417         int i;
418
419         PED_ASSERT(mbr != NULL, return 0);
420
421         if (mbr->Signature != PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE))
422                 return 0;
423         for (i = 0; i < 4; i++) {
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                 gpt = pth_new_from_raw (dev, pth_raw);
442                 if (gpt->Signature == PED_CPU_TO_LE64(GPT_HEADER_SIGNATURE))
443                         gpt_sig_found = 1;
444         }
445
446         free (pth_raw);
447
448         if (gpt)
449                 pth_free (gpt);
450
451
452         if (!gpt_sig_found)
453                 return 0;
454
455
456         void *label;
457         if (!ptt_read_sector (dev, 0, &label))
458                 return 0;
459
460         int ok = 1;
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 "
472                   "partition table?"),
473                         dev->path);
474                 if (ex_status == PED_EXCEPTION_NO)
475                         ok = 0;
476         }
477
478         free (label);
479         return ok;
480 }
481
482 #ifndef DISCOVER_ONLY
483 /* writes zeros to the PMBR and the primary and alternate GPTHs and PTEs */
484 static int
485 gpt_clobber(PedDevice * dev)
486 {
487         uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
488         GuidPartitionTableHeader_t* gpt;
489
490         PED_ASSERT (dev != NULL, return 0);
491
492         /*
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.
496          */
497         if (!ped_device_read(dev, pth_raw,
498                              GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS)) {
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                 if (!ped_device_write(dev, gpt,
516                                       PED_LE64_TO_CPU (gpt->AlternateLBA),
517                                       GPT_HEADER_SECTORS))
518                         return 0;
519         }
520
521         pth_free (gpt);
522
523         return 1;
524
525 error_free_with_gpt:
526         pth_free (gpt);
527         return 0;
528 }
529 #endif /* !DISCOVER_ONLY */
530
531 static PedDisk *
532 gpt_alloc (const PedDevice * dev)
533 {
534         PedDisk* disk;
535         GPTDiskData *gpt_disk_data;
536         PedSector data_start, data_end;
537
538         disk = _ped_disk_alloc ((PedDevice*)dev, &gpt_disk_type);
539         if (!disk)
540                 goto error;
541         disk->disk_specific = gpt_disk_data = ped_malloc (sizeof (GPTDiskData));
542         if (!disk->disk_specific)
543                 goto error_free_disk;
544
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));
553         return disk;
554
555 error_free_disk:
556         free (disk);
557 error:
558         return NULL;
559 }
560
561 static PedDisk*
562 gpt_duplicate (const PedDisk* disk)
563 {
564         PedDisk* new_disk;
565         GPTDiskData* new_disk_data;
566         GPTDiskData* old_disk_data;
567
568         new_disk = ped_disk_new_fresh (disk->dev, &gpt_disk_type);
569         if (!new_disk)
570                 return NULL;
571
572         old_disk_data = disk->disk_specific;
573         new_disk_data = new_disk->disk_specific;
574
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;
580         return new_disk;
581 }
582
583 static void
584 gpt_free(PedDisk * disk)
585 {
586         ped_disk_delete_all (disk);
587         free (disk->disk_specific);
588         _ped_disk_free (disk);
589 }
590
591 static int
592 _header_is_valid (const PedDevice* dev, GuidPartitionTableHeader_t* gpt)
593 {
594         uint32_t crc, origcrc;
595
596         if (PED_LE64_TO_CPU (gpt->Signature) != GPT_HEADER_SIGNATURE)
597                 return 0;
598         /*
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
602          */
603         if (PED_LE32_TO_CPU (gpt->HeaderSize) < pth_get_size_static (dev)
604             || PED_LE32_TO_CPU (gpt->HeaderSize) > dev->sector_size)
605                 return 0;
606
607         /*
608          * the SizeOfPartitionEntry must be a multiple of 8 and
609          * no smaller than the size of the PartitionEntry structure.
610          */
611         uint32_t sope = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
612         if (sope % 8 != 0
613             || sope < sizeof (GuidPartitionEntry_t)
614             || (UINT32_MAX >> 4) < sope)
615                 return 0;
616
617         origcrc = gpt->HeaderCRC32;
618         gpt->HeaderCRC32 = 0;
619         crc = pth_crc32 (dev, gpt);
620         gpt->HeaderCRC32 = origcrc;
621
622         return crc == PED_LE32_TO_CPU (origcrc);
623 }
624
625 static int
626 _read_header (const PedDevice* dev, GuidPartitionTableHeader_t** gpt,
627               PedSector where)
628 {
629         uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
630
631         PED_ASSERT (dev != NULL, return 0);
632
633         if (!ped_device_read (dev, pth_raw, where, GPT_HEADER_SECTORS)) {
634                 free (pth_raw);
635                 return 0;
636         }
637
638         *gpt = pth_new_from_raw (dev, pth_raw);
639
640         free (pth_raw);
641
642         if (_header_is_valid (dev, *gpt))
643                 return 1;
644
645         pth_free (*gpt);
646         return 0;
647 }
648
649 static int
650 _parse_header (PedDisk* disk, GuidPartitionTableHeader_t* gpt,
651                int *update_needed)
652 {
653         GPTDiskData* gpt_disk_data = disk->disk_specific;
654         PedSector first_usable;
655         PedSector last_usable;
656         PedSector last_usable_if_grown, last_usable_min_default;
657         static int asked_already;
658
659         PED_ASSERT (_header_is_valid (disk->dev, gpt), return 0);
660
661 #ifndef DISCOVER_ONLY
662         if (PED_LE32_TO_CPU (gpt->Revision) > GPT_HEADER_REVISION_V1_02) {
663                 if (ped_exception_throw (
664                         PED_EXCEPTION_WARNING,
665                         PED_EXCEPTION_IGNORE_CANCEL,
666                         _("The format of the GPT partition table is version "
667                           "%x, which is newer than what Parted can "
668                           "recognise.  Please tell us!  bug-parted@gnu.org"),
669                         PED_LE32_TO_CPU (gpt->Revision))
670                                 != PED_EXCEPTION_IGNORE)
671                         return 0;
672         }
673 #endif
674
675         first_usable = PED_LE64_TO_CPU (gpt->FirstUsableLBA);
676         last_usable = PED_LE64_TO_CPU (gpt->LastUsableLBA);
677
678
679 /*
680    Need to check whether the volume has grown, the LastUsableLBA is
681    normally set to disk->dev->length - 2 - ptes_size (at least for parted
682    created volumes), where ptes_size is the number of entries *
683    size of each entry / sector size or 16k / sector size, whatever the greater.
684    If the volume has grown, offer the user the chance to use the new
685    space or continue with the current usable area.  Only ask once per
686    parted invocation.
687 */
688
689         last_usable_if_grown
690                 = (disk->dev->length - 2 -
691                 ((PedSector)(PED_LE32_TO_CPU(gpt->NumberOfPartitionEntries)) *
692                 (PedSector)(PED_LE32_TO_CPU(gpt->SizeOfPartitionEntry)) /
693                 disk->dev->sector_size));
694
695         last_usable_min_default = disk->dev->length - 2 -
696                 GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / disk->dev->sector_size;
697
698         if ( last_usable_if_grown > last_usable_min_default ) {
699
700                 last_usable_if_grown = last_usable_min_default;
701         }
702
703
704         PED_ASSERT (last_usable > first_usable, return 0);
705         PED_ASSERT (last_usable <= disk->dev->length, return 0);
706
707         PED_ASSERT (last_usable_if_grown > first_usable, return 0);
708         PED_ASSERT (last_usable_if_grown <= disk->dev->length, return 0);
709
710         if ( !asked_already && last_usable < last_usable_if_grown ) {
711
712                 PedExceptionOption q;
713
714                 q = ped_exception_throw (PED_EXCEPTION_WARNING,
715                         PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE,
716                         _("Not all of the space available to %s appears "
717                         "to be used, you can fix the GPT to use all of the "
718                         "space (an extra %llu blocks) or continue with the "
719                         "current setting? "), disk->dev->path,
720                         (uint64_t)(last_usable_if_grown - last_usable));
721
722
723                 if (q == PED_EXCEPTION_FIX) {
724
725                         last_usable = last_usable_if_grown;
726                         *update_needed = 1;
727
728                 }
729                 else if (q != PED_EXCEPTION_UNHANDLED ) {
730
731                         asked_already = 1;
732                 }
733         }
734
735         ped_geometry_init (&gpt_disk_data->data_area, disk->dev,
736                            first_usable, last_usable - first_usable + 1);
737
738
739         gpt_disk_data->entry_count
740                 = PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries);
741         PED_ASSERT (gpt_disk_data->entry_count > 0, return 0);
742         PED_ASSERT (gpt_disk_data->entry_count <= 8192, return 0);
743
744         gpt_disk_data->uuid = gpt->DiskGUID;
745
746         return 1;
747 }
748
749 static PedPartition*
750 _parse_part_entry (PedDisk* disk, GuidPartitionEntry_t* pte)
751 {
752         PedPartition* part;
753         GPTPartitionData* gpt_part_data;
754         unsigned int i;
755
756         part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
757                         PED_LE64_TO_CPU(pte->StartingLBA),
758                         PED_LE64_TO_CPU(pte->EndingLBA));
759         if (!part)
760                 return NULL;
761
762         gpt_part_data = part->disk_specific;
763         gpt_part_data->type = pte->PartitionTypeGuid;
764         gpt_part_data->uuid = pte->UniquePartitionGuid;
765         for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
766                 gpt_part_data->name[i] = (efi_char16_t) PED_LE16_TO_CPU(
767                                            (uint16_t) pte->PartitionName[i]);
768         gpt_part_data->name[i] = 0;
769
770         gpt_part_data->lvm = gpt_part_data->raid
771                 = gpt_part_data->boot = gpt_part_data->hp_service
772                 = gpt_part_data->hidden = gpt_part_data->msftres
773                 = gpt_part_data->bios_grub = 0;
774
775         if (pte->Attributes.RequiredToFunction & 0x1)
776                 gpt_part_data->hidden = 1;
777
778         if (!guid_cmp (gpt_part_data->type, PARTITION_SYSTEM_GUID))
779                 gpt_part_data->boot = 1;
780         else if (!guid_cmp (gpt_part_data->type, PARTITION_BIOS_GRUB_GUID))
781                 gpt_part_data->bios_grub = 1;
782         else if (!guid_cmp (gpt_part_data->type, PARTITION_RAID_GUID))
783                 gpt_part_data->raid = 1;
784         else if (!guid_cmp (gpt_part_data->type, PARTITION_LVM_GUID))
785                 gpt_part_data->lvm = 1;
786         else if (!guid_cmp (gpt_part_data->type, PARTITION_HPSERVICE_GUID))
787                 gpt_part_data->hp_service = 1;
788         else if (!guid_cmp (gpt_part_data->type, PARTITION_MSFT_RESERVED_GUID))
789                 gpt_part_data->msftres = 1;
790
791         return part;
792 }
793
794 /************************************************************
795  *  Intel is changing the EFI Spec. (after v1.02) to say that a
796  *  disk is considered to have a GPT label only if the GPT
797  *  structures are correct, and the MBR is actually a Protective
798  *  MBR (has one 0xEE type partition).
799  *  Problem occurs when a GPT-partitioned disk is then
800  *  edited with a legacy (non-GPT-aware) application, such as
801  *  fdisk (which doesn't generally erase the PGPT or AGPT).
802  *  How should such a disk get handled?  As a GPT disk (throwing
803  *  away the fdisk changes), or as an MSDOS disk (throwing away
804  *  the GPT information).  Previously, I've taken the GPT-is-right,
805  *  MBR is wrong, approach, to stay consistent with the EFI Spec.
806  *  Intel disagrees, saying the disk should then be treated
807  *  as having a msdos label, not a GPT label.  If this is true,
808  *  then what's the point of having an AGPT, since if the PGPT
809  *  is screwed up, likely the PMBR is too, and the PMBR becomes
810  *  a single point of failure.
811  *  So, in the Linux kernel, I'm going to test for PMBR, and
812  *  warn if it's not there, and treat the disk as MSDOS, with a note
813  *  for users to use Parted to "fix up" their disk if they
814  *  really want it to be considered GPT.
815  ************************************************************/
816 static int
817 gpt_read (PedDisk * disk)
818 {
819         GPTDiskData *gpt_disk_data = disk->disk_specific;
820         GuidPartitionTableHeader_t* gpt;
821         void* ptes;
822         size_t ptes_sectors;
823         int i;
824 #ifndef DISCOVER_ONLY
825         int write_back = 0;
826 #endif
827
828         ped_disk_delete_all (disk);
829
830         /*
831          * motivation: let the user decide about the pmbr... during
832          * ped_disk_probe(), they probably didn't get a choice...
833          */
834         if (!gpt_probe (disk->dev))
835                 goto error;
836
837         if (_read_header (disk->dev, &gpt, 1)) {
838                 /* There used to be a GPT partition table here, with an
839                    alternate LBA that extended beyond the current
840                    end-of-device.  Treat it as a non-match.   */
841                 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
842                     > disk->dev->length - 1)
843                         goto error_free_gpt;
844
845                 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
846                                 < disk->dev->length - 1) {
847
848 #ifndef DISCOVER_ONLY
849                         switch (ped_exception_throw (
850                                 PED_EXCEPTION_ERROR,
851                                 PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL | PED_EXCEPTION_IGNORE,
852                 _("The backup GPT table is not at the end of the disk, as it "
853                   "should be.  This might mean that another operating system "
854                   "believes the disk is smaller.  Fix, by moving the backup "
855                   "to the end (and removing the old backup)?"))) {
856                                 case PED_EXCEPTION_CANCEL:
857                                         goto error_free_gpt;
858                                 case PED_EXCEPTION_FIX:
859                                         {
860                                         char *zeros =
861                                           ped_malloc (pth_get_size (disk->dev));
862                                         write_back = 1;
863                                         memset (zeros, 0, disk->dev->sector_size);
864                                         ped_device_write (disk->dev, zeros,
865                                                           PED_LE64_TO_CPU (gpt->AlternateLBA),
866                                                           1);
867                                         free (zeros);
868                                         }
869                                         break;
870                                 default:
871                                         break;
872                         }
873
874 #endif /* !DISCOVER_ONLY */
875                 }
876         } else { /* primary GPT *not* ok */
877                 int alternate_ok = 0;
878
879 #ifndef DISCOVER_ONLY
880                 write_back = 1;
881 #endif
882
883                 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
884                                 < disk->dev->length - 1) {
885                         alternate_ok = _read_header (disk->dev, &gpt,
886                                             PED_LE64_TO_CPU(gpt->AlternateLBA));
887                 }
888                 if (!alternate_ok) {
889                         alternate_ok = _read_header (disk->dev, &gpt,
890                                                      disk->dev->length - 1);
891                 }
892
893                 if (alternate_ok) {
894                         if (ped_exception_throw (
895                                 PED_EXCEPTION_ERROR,
896                                 PED_EXCEPTION_OK_CANCEL,
897                                 _("The primary GPT table is corrupt, but the "
898                                   "backup appears OK, so that will be used."))
899                                     == PED_EXCEPTION_CANCEL)
900                                 goto error_free_gpt;
901                 } else {
902                         ped_exception_throw (
903                                 PED_EXCEPTION_ERROR,
904                                 PED_EXCEPTION_CANCEL,
905                                 _("Both the primary and backup GPT tables "
906                                   "are corrupt.  Try making a fresh table, "
907                                   "and using Parted's rescue feature to "
908                                   "recover partitions."));
909                         goto error;
910                 }
911         }
912
913         if (!_parse_header (disk, gpt, &write_back))
914                 goto error_free_gpt;
915
916         uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
917         ptes_sectors = ped_div_round_up (p_ent_size
918                                          * gpt_disk_data->entry_count,
919                                          disk->dev->sector_size);
920
921         if (xalloc_oversized (ptes_sectors, disk->dev->sector_size))
922                 goto error_free_gpt;
923         ptes = ped_malloc (ptes_sectors * disk->dev->sector_size);
924
925         if (!ped_device_read (disk->dev, ptes,
926                               PED_LE64_TO_CPU(gpt->PartitionEntryLBA),
927                               ptes_sectors))
928                 goto error_free_ptes;
929
930         for (i = 0; i < gpt_disk_data->entry_count; i++) {
931                 GuidPartitionEntry_t* pte
932                   = (GuidPartitionEntry_t*) ((char *)ptes + i * p_ent_size);
933                 PedPartition* part;
934                 PedConstraint* constraint_exact;
935
936                 if (!guid_cmp (pte->PartitionTypeGuid, UNUSED_ENTRY_GUID))
937                         continue;
938
939                 part = _parse_part_entry (disk, pte);
940                 if (!part)
941                         goto error_delete_all;
942
943                 part->fs_type = ped_file_system_probe (&part->geom);
944                 part->num = i + 1;
945
946                 constraint_exact = ped_constraint_exact (&part->geom);
947                 if (!ped_disk_add_partition(disk, part, constraint_exact)) {
948                         ped_partition_destroy (part);
949                         goto error_delete_all;
950                 }
951                 ped_constraint_destroy (constraint_exact);
952         }
953         free (ptes);
954
955 #ifndef DISCOVER_ONLY
956         if (write_back)
957                 ped_disk_commit_to_dev (disk);
958 #endif
959
960         pth_free (gpt);
961         return 1;
962
963 error_delete_all:
964         ped_disk_delete_all (disk);
965 error_free_ptes:
966         free (ptes);
967 error_free_gpt:
968         pth_free (gpt);
969 error:
970         return 0;
971 }
972
973 #ifndef DISCOVER_ONLY
974 /* Write the protective MBR (to keep DOS happy) */
975 static int
976 _write_pmbr (PedDevice * dev)
977 {
978         /* The UEFI spec is not clear about what to do with the following
979            elements of the Protective MBR (pmbr): BootCode (0-440B),
980            UniqueMBRSignature (440B-444B) and Unknown (444B-446B).
981            With this in mind, we try not to modify these elements.  */
982         void *s0;
983         if (!ptt_read_sector (dev, 0, &s0))
984                 return 0;
985         LegacyMBR_t *pmbr = s0;
986
987         /* Zero out the legacy partitions.  */
988         memset (pmbr->PartitionRecord, 0, sizeof pmbr->PartitionRecord);
989
990         pmbr->Signature = PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE);
991         pmbr->PartitionRecord[0].OSType      = EFI_PMBR_OSTYPE_EFI;
992         pmbr->PartitionRecord[0].StartSector = 1;
993         pmbr->PartitionRecord[0].EndHead     = 0xFE;
994         pmbr->PartitionRecord[0].EndSector   = 0xFF;
995         pmbr->PartitionRecord[0].EndTrack    = 0xFF;
996         pmbr->PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32(1);
997         if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
998                 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(0xFFFFFFFF);
999         else
1000                 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(dev->length - 1UL);
1001
1002         int write_ok = ped_device_write (dev, pmbr, GPT_PMBR_LBA,
1003                                          GPT_PMBR_SECTORS);
1004         free (s0);
1005         return write_ok;
1006 }
1007
1008 static void
1009 _generate_header (const PedDisk* disk, int alternate, uint32_t ptes_crc,
1010                   GuidPartitionTableHeader_t** gpt_p)
1011 {
1012         GPTDiskData* gpt_disk_data = disk->disk_specific;
1013         GuidPartitionTableHeader_t* gpt;
1014
1015         *gpt_p = pth_new_zeroed (disk->dev);
1016
1017         gpt = *gpt_p;
1018
1019         gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE);
1020         gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00);
1021
1022         /* per 1.00 spec */
1023         gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev));
1024         gpt->HeaderCRC32 = 0;
1025         gpt->Reserved1 = 0;
1026
1027         if (alternate) {
1028                 PedSector ptes_size = gpt_disk_data->entry_count
1029                                       * sizeof (GuidPartitionEntry_t) / disk->dev->sector_size;
1030
1031                 gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1032                 gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
1033                 gpt->PartitionEntryLBA
1034                         = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_size);
1035         } else {
1036                 gpt->MyLBA = PED_CPU_TO_LE64 (1);
1037                 gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1038                 gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
1039         }
1040
1041         gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
1042         gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
1043         gpt->DiskGUID = gpt_disk_data->uuid;
1044         gpt->NumberOfPartitionEntries
1045                 = PED_CPU_TO_LE32 (gpt_disk_data->entry_count);
1046         gpt->SizeOfPartitionEntry
1047                 = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t));
1048         gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32 (ptes_crc);
1049         gpt->HeaderCRC32 = PED_CPU_TO_LE32 (pth_crc32 (disk->dev, gpt));
1050 }
1051
1052 static void
1053 _partition_generate_part_entry (PedPartition* part, GuidPartitionEntry_t* pte)
1054 {
1055         GPTPartitionData* gpt_part_data = part->disk_specific;
1056         unsigned int i;
1057
1058         PED_ASSERT (gpt_part_data != NULL, return);
1059
1060         pte->PartitionTypeGuid = gpt_part_data->type;
1061         pte->UniquePartitionGuid = gpt_part_data->uuid;
1062         pte->StartingLBA = PED_CPU_TO_LE64(part->geom.start);
1063         pte->EndingLBA = PED_CPU_TO_LE64(part->geom.end);
1064         memset (&pte->Attributes, 0, sizeof (GuidPartitionEntryAttributes_t));
1065
1066         if (gpt_part_data->hidden)
1067                 pte->Attributes.RequiredToFunction = 1;
1068
1069         for (i = 0; i < 72 / sizeof(efi_char16_t); i++)
1070                 pte->PartitionName[i]
1071                         = (efi_char16_t) PED_CPU_TO_LE16(
1072                                 (uint16_t) gpt_part_data->name[i]);
1073 }
1074
1075 static int
1076 gpt_write(const PedDisk * disk)
1077 {
1078         GPTDiskData* gpt_disk_data;
1079         GuidPartitionEntry_t* ptes;
1080         uint32_t ptes_crc;
1081         uint8_t* pth_raw;
1082         GuidPartitionTableHeader_t* gpt;
1083         PedPartition* part;
1084         int ptes_size;
1085
1086         PED_ASSERT (disk != NULL, goto error);
1087         PED_ASSERT (disk->dev != NULL, goto error);
1088         PED_ASSERT (disk->disk_specific != NULL, goto error);
1089
1090         gpt_disk_data = disk->disk_specific;
1091
1092         ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
1093         ptes = (GuidPartitionEntry_t*) ped_malloc (ptes_size);
1094         if (!ptes)
1095                 goto error;
1096         memset (ptes, 0, ptes_size);
1097         for (part = ped_disk_next_partition (disk, NULL); part;
1098              part = ped_disk_next_partition (disk, part)) {
1099                 if (part->type != 0)
1100                         continue;
1101                 _partition_generate_part_entry (part, &ptes[part->num - 1]);
1102         }
1103
1104         ptes_crc = efi_crc32 (ptes, ptes_size);
1105
1106         /* Write protective MBR */
1107         if (!_write_pmbr (disk->dev))
1108                 goto error_free_ptes;
1109
1110         /* Write PTH and PTEs */
1111         _generate_header (disk, 0, ptes_crc, &gpt);
1112         pth_raw = pth_get_raw (disk->dev, gpt);
1113         pth_free (gpt);
1114         bool write_ok = ped_device_write (disk->dev, pth_raw, 1, 1);
1115         free (pth_raw);
1116         if (!write_ok)
1117                 goto error_free_ptes;
1118         if (!ped_device_write (disk->dev, ptes, 2,
1119                                ptes_size / disk->dev->sector_size))
1120                 goto error_free_ptes;
1121
1122         /* Write Alternate PTH & PTEs */
1123         _generate_header (disk, 1, ptes_crc, &gpt);
1124         pth_raw = pth_get_raw (disk->dev, gpt);
1125         pth_free (gpt);
1126         write_ok = ped_device_write (disk->dev, pth_raw,
1127                                      disk->dev->length - 1, 1);
1128         free (pth_raw);
1129         if (!write_ok)
1130                 goto error_free_ptes;
1131         if (!ped_device_write (disk->dev, ptes,
1132                                disk->dev->length - 1 - ptes_size / disk->dev->sector_size,
1133                                ptes_size / disk->dev->sector_size))
1134                 goto error_free_ptes;
1135
1136         free (ptes);
1137         return ped_device_sync (disk->dev);
1138
1139         free (pth_raw);
1140 error_free_ptes:
1141         free (ptes);
1142 error:
1143         return 0;
1144 }
1145 #endif /* !DISCOVER_ONLY */
1146
1147 static int
1148 add_metadata_part(PedDisk * disk, PedSector start, PedSector length)
1149 {
1150         PedPartition* part;
1151         PedConstraint* constraint_exact;
1152         PED_ASSERT(disk != NULL, return 0);
1153
1154         part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1155                                   start, start + length - 1);
1156         if (!part)
1157                 goto error;
1158
1159         constraint_exact = ped_constraint_exact (&part->geom);
1160         if (!ped_disk_add_partition (disk, part, constraint_exact))
1161                 goto error_destroy_constraint;
1162         ped_constraint_destroy (constraint_exact);
1163         return 1;
1164
1165 error_destroy_constraint:
1166         ped_constraint_destroy (constraint_exact);
1167         ped_partition_destroy (part);
1168 error:
1169         return 0;
1170 }
1171
1172 static PedPartition*
1173 gpt_partition_new (const PedDisk* disk,
1174                   PedPartitionType part_type, const PedFileSystemType* fs_type,
1175                   PedSector start, PedSector end)
1176 {
1177         PedPartition* part;
1178         GPTPartitionData* gpt_part_data;
1179
1180         part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1181         if (!part)
1182                 goto error;
1183
1184         if (part_type != 0)
1185                 return part;
1186
1187         gpt_part_data = part->disk_specific =
1188                 ped_malloc (sizeof (GPTPartitionData));
1189         if (!gpt_part_data)
1190                 goto error_free_part;
1191
1192         gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1193         gpt_part_data->lvm = 0;
1194         gpt_part_data->raid = 0;
1195         gpt_part_data->boot = 0;
1196         gpt_part_data->bios_grub = 0;
1197         gpt_part_data->hp_service = 0;
1198         gpt_part_data->hidden = 0;
1199         gpt_part_data->msftres = 0;
1200         uuid_generate ((unsigned char*) &gpt_part_data->uuid);
1201         swap_uuid_and_efi_guid((unsigned char*)(&gpt_part_data->uuid));
1202         memset (gpt_part_data->name, 0, sizeof gpt_part_data->name);
1203         return part;
1204
1205 error_free_part:
1206         _ped_partition_free (part);
1207 error:
1208         return NULL;
1209 }
1210
1211 static PedPartition*
1212 gpt_partition_duplicate (const PedPartition* part)
1213 {
1214         PedPartition* result;
1215         GPTPartitionData* part_data = part->disk_specific;
1216         GPTPartitionData* result_data;
1217
1218         result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
1219                                        part->geom.start, part->geom.end);
1220         if (!result)
1221                 goto error;
1222         result->num = part->num;
1223
1224         if (result->type != 0)
1225                 return result;
1226
1227         result_data = result->disk_specific =
1228                 ped_malloc (sizeof (GPTPartitionData));
1229         if (!result_data)
1230                 goto error_free_part;
1231
1232         result_data->type = part_data->type;
1233         result_data->uuid = part_data->uuid;
1234         strcpy (result_data->name, part_data->name);
1235         return result;
1236
1237 error_free_part:
1238         _ped_partition_free (result);
1239 error:
1240         return NULL;
1241 }
1242
1243 static void
1244 gpt_partition_destroy (PedPartition *part)
1245 {
1246         if (part->type == 0) {
1247                 PED_ASSERT (part->disk_specific != NULL, return);
1248                 free (part->disk_specific);
1249         }
1250
1251         _ped_partition_free (part);
1252 }
1253
1254 static int
1255 gpt_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
1256 {
1257         GPTPartitionData* gpt_part_data = part->disk_specific;
1258
1259         PED_ASSERT (gpt_part_data != NULL, return 0);
1260
1261         part->fs_type = fs_type;
1262
1263         if (gpt_part_data->lvm) {
1264                 gpt_part_data->type = PARTITION_LVM_GUID;
1265                 return 1;
1266         }
1267         if (gpt_part_data->raid) {
1268                 gpt_part_data->type = PARTITION_RAID_GUID;
1269                 return 1;
1270         }
1271         if (gpt_part_data->boot) {
1272                 gpt_part_data->type = PARTITION_SYSTEM_GUID;
1273                 return 1;
1274         }
1275         if (gpt_part_data->bios_grub) {
1276                 gpt_part_data->type = PARTITION_BIOS_GRUB_GUID;
1277                 return 1;
1278         }
1279         if (gpt_part_data->hp_service) {
1280                 gpt_part_data->type = PARTITION_HPSERVICE_GUID;
1281                 return 1;
1282         }
1283         if (gpt_part_data->msftres) {
1284                 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1285                 return 1;
1286         }
1287
1288         if (fs_type) {
1289                 if (strncmp (fs_type->name, "fat", 3) == 0
1290                     || strcmp (fs_type->name, "ntfs") == 0) {
1291                         gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1292                         return 1;
1293                 }
1294                 if (strncmp (fs_type->name, "hfs", 3) == 0) {
1295                         gpt_part_data->type = PARTITION_APPLE_HFS_GUID;
1296                         return 1;
1297                 }
1298                 if (strstr (fs_type->name, "swap")) {
1299                         gpt_part_data->type = PARTITION_SWAP_GUID;
1300                         return 1;
1301                 }
1302         }
1303
1304         gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1305         return 1;
1306 }
1307
1308 /* Allocate metadata partitions for the GPTH and PTES */
1309 static int
1310 gpt_alloc_metadata (PedDisk * disk)
1311 {
1312         PedSector gptlength, pteslength = 0;
1313         GPTDiskData *gpt_disk_data;
1314
1315         PED_ASSERT(disk != NULL, return 0);
1316         PED_ASSERT(disk->dev != NULL, return 0);
1317         PED_ASSERT(disk->disk_specific != NULL, return 0);
1318         gpt_disk_data = disk->disk_specific;
1319
1320         gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t),
1321                                       disk->dev->sector_size);
1322         pteslength = ped_div_round_up (gpt_disk_data->entry_count
1323                                        * sizeof (GuidPartitionEntry_t), disk->dev->sector_size);
1324
1325         /* metadata at the start of the disk includes the MBR */
1326         if (!add_metadata_part(disk, GPT_PMBR_LBA,
1327                                GPT_PMBR_SECTORS + gptlength + pteslength))
1328                 return 0;
1329
1330         /* metadata at the end of the disk */
1331         if (!add_metadata_part(disk, disk->dev->length - gptlength - pteslength,
1332                                gptlength + pteslength))
1333                 return 0;
1334
1335         return 1;
1336 }
1337
1338 /* Does nothing, as the read/new/destroy functions maintain part->num */
1339 static int
1340 gpt_partition_enumerate (PedPartition* part)
1341 {
1342         GPTDiskData* gpt_disk_data = part->disk->disk_specific;
1343         int i;
1344
1345         /* never change the partition numbers */
1346         if (part->num != -1)
1347                 return 1;
1348
1349         for (i = 1; i <= gpt_disk_data->entry_count; i++) {
1350                 if (!ped_disk_get_partition (part->disk, i)) {
1351                         part->num = i;
1352                         return 1;
1353                 }
1354         }
1355
1356         PED_ASSERT (0, return 0);
1357
1358         return 0; /* used if debug is disabled */
1359 }
1360
1361 static int
1362 gpt_partition_set_flag(PedPartition *part,
1363                        PedPartitionFlag flag,
1364                        int state)
1365 {
1366         GPTPartitionData *gpt_part_data;
1367         PED_ASSERT(part != NULL, return 0);
1368         PED_ASSERT(part->disk_specific != NULL, return 0);
1369         gpt_part_data = part->disk_specific;
1370
1371         switch (flag) {
1372         case PED_PARTITION_BOOT:
1373                 gpt_part_data->boot = state;
1374                 if (state)
1375                         gpt_part_data->raid
1376                                 = gpt_part_data->lvm
1377                                 = gpt_part_data->bios_grub
1378                                 = gpt_part_data->hp_service
1379                                 = gpt_part_data->msftres = 0;
1380                 return gpt_partition_set_system (part, part->fs_type);
1381         case PED_PARTITION_BIOS_GRUB:
1382                 gpt_part_data->bios_grub = state;
1383                 if (state)
1384                         gpt_part_data->raid
1385                                 = gpt_part_data->lvm
1386                                 = gpt_part_data->boot
1387                                 = gpt_part_data->hp_service
1388                                 = gpt_part_data->msftres = 0;
1389                 return gpt_partition_set_system (part, part->fs_type);
1390         case PED_PARTITION_RAID:
1391                 gpt_part_data->raid = state;
1392                 if (state)
1393                         gpt_part_data->boot
1394                                 = gpt_part_data->lvm
1395                                 = gpt_part_data->bios_grub
1396                                 = gpt_part_data->hp_service
1397                                 = gpt_part_data->msftres = 0;
1398                 return gpt_partition_set_system (part, part->fs_type);
1399         case PED_PARTITION_LVM:
1400                 gpt_part_data->lvm = state;
1401                 if (state)
1402                         gpt_part_data->boot
1403                                 = gpt_part_data->raid
1404                                 = gpt_part_data->bios_grub
1405                                 = gpt_part_data->hp_service
1406                                 = gpt_part_data->msftres = 0;
1407                 return gpt_partition_set_system (part, part->fs_type);
1408         case PED_PARTITION_HPSERVICE:
1409                 gpt_part_data->hp_service = state;
1410                 if (state)
1411                         gpt_part_data->boot
1412                                 = gpt_part_data->raid
1413                                 = gpt_part_data->lvm
1414                                 = gpt_part_data->bios_grub
1415                                 = gpt_part_data->msftres = 0;
1416                 return gpt_partition_set_system (part, part->fs_type);
1417         case PED_PARTITION_MSFT_RESERVED:
1418                 gpt_part_data->msftres = state;
1419                 if (state)
1420                         gpt_part_data->boot
1421                                 = gpt_part_data->raid
1422                                 = gpt_part_data->lvm
1423                                 = gpt_part_data->bios_grub
1424                                 = gpt_part_data->hp_service = 0;
1425                 return gpt_partition_set_system (part, part->fs_type);
1426         case PED_PARTITION_HIDDEN:
1427                 gpt_part_data->hidden = state;
1428                 return 1;
1429         case PED_PARTITION_SWAP:
1430         case PED_PARTITION_ROOT:
1431         case PED_PARTITION_LBA:
1432         default:
1433                 return 0;
1434         }
1435         return 1;
1436 }
1437
1438 static int
1439 gpt_partition_get_flag(const PedPartition *part, PedPartitionFlag flag)
1440 {
1441         GPTPartitionData *gpt_part_data;
1442         PED_ASSERT(part->disk_specific != NULL, return 0);
1443         gpt_part_data = part->disk_specific;
1444
1445         switch (flag) {
1446         case PED_PARTITION_RAID:
1447                 return gpt_part_data->raid;
1448         case PED_PARTITION_LVM:
1449                 return gpt_part_data->lvm;
1450         case PED_PARTITION_BOOT:
1451                 return gpt_part_data->boot;
1452         case PED_PARTITION_BIOS_GRUB:
1453                 return gpt_part_data->bios_grub;
1454         case PED_PARTITION_HPSERVICE:
1455                 return gpt_part_data->hp_service;
1456         case PED_PARTITION_MSFT_RESERVED:
1457                 return gpt_part_data->msftres;
1458         case PED_PARTITION_HIDDEN:
1459                        return gpt_part_data->hidden;
1460         case PED_PARTITION_SWAP:
1461         case PED_PARTITION_LBA:
1462         case PED_PARTITION_ROOT:
1463         default:
1464                 return 0;
1465         }
1466         return 0;
1467 }
1468
1469 static int
1470 gpt_partition_is_flag_available(const PedPartition * part,
1471                                 PedPartitionFlag flag)
1472 {
1473         switch (flag) {
1474         case PED_PARTITION_RAID:
1475         case PED_PARTITION_LVM:
1476         case PED_PARTITION_BOOT:
1477         case PED_PARTITION_BIOS_GRUB:
1478         case PED_PARTITION_HPSERVICE:
1479         case PED_PARTITION_MSFT_RESERVED:
1480         case PED_PARTITION_HIDDEN:
1481                 return 1;
1482         case PED_PARTITION_SWAP:
1483         case PED_PARTITION_ROOT:
1484         case PED_PARTITION_LBA:
1485         default:
1486                 return 0;
1487         }
1488         return 0;
1489 }
1490
1491 static void
1492 gpt_partition_set_name (PedPartition *part, const char *name)
1493 {
1494         GPTPartitionData *gpt_part_data = part->disk_specific;
1495
1496         strncpy (gpt_part_data->name, name, 36);
1497         gpt_part_data->name [36] = 0;
1498 }
1499
1500 static const char *
1501 gpt_partition_get_name (const PedPartition * part)
1502 {
1503         GPTPartitionData* gpt_part_data = part->disk_specific;
1504         return gpt_part_data->name;
1505 }
1506
1507 static int
1508 gpt_get_max_primary_partition_count (const PedDisk *disk)
1509 {
1510         const GPTDiskData* gpt_disk_data = disk->disk_specific;
1511         return gpt_disk_data->entry_count;
1512 }
1513
1514 /*
1515  * From (http://developer.apple.com/technotes/tn2006/tn2166.html Chapter 5).
1516  * According to the specs the first LBA (LBA0) is not relevant (it exists
1517  * to maintain compatibility).  on the second LBA(LBA1) gpt places the
1518  * header.  The header is as big as the block size.  After the header we
1519  * find the Entry array.  Each element of said array, describes each
1520  * partition.  One can have as much elements as can fit between the end of
1521  * the second LBA (where the header ends) and the FirstUsableLBA.
1522  * FirstUsableLBA is the first logical block that is used for contents
1523  * and is defined in header.
1524  *
1525  * /---------------------------------------------------\
1526  * | BLOCK0 | HEADER | Entry Array | First Usable LBA  |
1527  * |        | BLOCK1 |             |                   |
1528  * \---------------------------------------------------/
1529  *                  /              \
1530  *     /----------/                  \----------\
1531  *     /-----------------------------------------\
1532  *     |  E1  |  E2  |  E3  |...............| EN |
1533  *     \-----------------------------------------/
1534  *
1535  * The number of possible partitions or supported partitions is:
1536  * SP = FirstUsableLBA*Blocksize - 2*Blocksize / SizeOfPartitionEntry
1537  * SP = Blocksize(FirstusableLBA - 2) / SizeOfPartitoinEntry
1538  */
1539 static bool
1540 gpt_get_max_supported_partition_count (const PedDisk *disk, int *max_n)
1541 {
1542         GuidPartitionTableHeader_t *pth = NULL;
1543         uint8_t *pth_raw = ped_malloc (pth_get_size (disk->dev));
1544
1545         if (ped_device_read (disk->dev, pth_raw, 1, GPT_HEADER_SECTORS)
1546             || ped_device_read (disk->dev, pth_raw,
1547                                 disk->dev->length, GPT_HEADER_SECTORS))
1548                 pth = pth_new_from_raw (disk->dev, pth_raw);
1549         free (pth_raw);
1550
1551         if (pth == NULL)
1552                 return false;
1553
1554         *max_n = (disk->dev->sector_size * (pth->FirstUsableLBA - 2)
1555                   / PED_LE32_TO_CPU (pth->SizeOfPartitionEntry));
1556         pth_free (pth);
1557         return true;
1558 }
1559
1560 static PedConstraint*
1561 _non_metadata_constraint (const PedDisk* disk)
1562 {
1563         GPTDiskData* gpt_disk_data = disk->disk_specific;
1564
1565         return ped_constraint_new_from_max (&gpt_disk_data->data_area);
1566 }
1567
1568 static int
1569 gpt_partition_align (PedPartition* part, const PedConstraint* constraint)
1570 {
1571         PED_ASSERT (part != NULL, return 0);
1572
1573         if (_ped_partition_attempt_align (part, constraint,
1574                         _non_metadata_constraint (part->disk)))
1575                 return 1;
1576
1577 #ifndef DISCOVER_ONLY
1578         ped_exception_throw (
1579                 PED_EXCEPTION_ERROR,
1580                 PED_EXCEPTION_CANCEL,
1581                 _("Unable to satisfy all constraints on the partition."));
1582 #endif
1583         return 0;
1584 }
1585
1586 static bool
1587 gpt_partition_check (const PedPartition* part)
1588 {
1589         return true;
1590 }
1591
1592 static PedDiskOps gpt_disk_ops = {
1593         probe:          gpt_probe,
1594 #ifndef DISCOVER_ONLY
1595         clobber:        gpt_clobber,
1596 #else
1597         clobber:        NULL,
1598 #endif
1599         alloc:          gpt_alloc,
1600         duplicate:      gpt_duplicate,
1601         free:           gpt_free,
1602         read:           gpt_read,
1603 #ifndef DISCOVER_ONLY
1604         write:          gpt_write,
1605 #else
1606         write:          NULL,
1607 #endif
1608         partition_new:                  gpt_partition_new,
1609         partition_duplicate:            gpt_partition_duplicate,
1610         partition_destroy:              gpt_partition_destroy,
1611         partition_set_system:           gpt_partition_set_system,
1612         partition_set_flag:             gpt_partition_set_flag,
1613         partition_get_flag:             gpt_partition_get_flag,
1614         partition_is_flag_available:    gpt_partition_is_flag_available,
1615         partition_set_name:             gpt_partition_set_name,
1616         partition_get_name:             gpt_partition_get_name,
1617         partition_align:                gpt_partition_align,
1618         partition_enumerate:            gpt_partition_enumerate,
1619         partition_check:                gpt_partition_check,
1620         alloc_metadata:                 gpt_alloc_metadata,
1621         get_max_primary_partition_count: gpt_get_max_primary_partition_count,
1622         get_max_supported_partition_count: gpt_get_max_supported_partition_count
1623 };
1624
1625 static PedDiskType gpt_disk_type = {
1626         next:           NULL,
1627         name:           "gpt",
1628         ops:            &gpt_disk_ops,
1629         features:       PED_DISK_TYPE_PARTITION_NAME
1630 };
1631
1632 void
1633 ped_disk_gpt_init()
1634 {
1635         PED_ASSERT (sizeof (GuidPartitionEntryAttributes_t) == 8, return);
1636         PED_ASSERT (sizeof (GuidPartitionEntry_t) == 128, return);
1637
1638         ped_disk_type_register (&gpt_disk_type);
1639 }
1640
1641 void
1642 ped_disk_gpt_done()
1643 {
1644         ped_disk_type_unregister (&gpt_disk_type);
1645 }