OSDN Git Service

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