OSDN Git Service

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