diff -burN parted-1.4.16/AUTHORS parted-1.4.16-gpt/AUTHORS
--- parted-1.4.16/AUTHORS	Fri Jun 29 02:57:09 2001
+++ parted-1.4.16-gpt/AUTHORS	Wed Jul 18 16:10:31 2001
@@ -96,3 +96,8 @@
 Thomas Roelz		<tom@suse.de>
 	* misc bug fixes
 
+Matt Domsch		<Matt_Domsch@dell.com>
+	* GUID Partition Table (GPT) support (disk_gpt.[ch],
+					      device_diskioctl.[ch],
+					      crc32.[ch])
+	* misc bug fixes
diff -burN parted-1.4.16/include/parted/Makefile.am parted-1.4.16-gpt/include/parted/Makefile.am
--- parted-1.4.16/include/parted/Makefile.am	Sat Apr  7 17:04:39 2001
+++ parted-1.4.16-gpt/include/parted/Makefile.am	Wed Jul 18 16:10:31 2001
@@ -6,6 +6,7 @@
 			exception.h	\
 			filesys.h	\
 			natmath.h	\
+			crc32.h		\
 			parted.h
 
 noinst_HEADERS	      = disk_bsd.h	\
@@ -13,6 +14,7 @@
 			disk_loop.h	\
 			disk_mac.h	\
 			disk_pc98.h	\
+			disk_gpt.h	\
 			disk_sun.h	\
 			endian.h
 
diff -burN parted-1.4.16/include/parted/crc32.h parted-1.4.16-gpt/include/parted/crc32.h
--- parted-1.4.16/include/parted/crc32.h	Wed Dec 31 18:00:00 1969
+++ parted-1.4.16-gpt/include/parted/crc32.h	Wed Jul 18 16:10:31 2001
@@ -0,0 +1,35 @@
+/*
+    libparted - a library for manipulating disk partitions
+    Copyright (C) 1998-2000 Free Software Foundation, Inc.
+
+    crc32.h
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef _CRC32_H
+#define _CRC32_H
+
+#include <stdint.h>
+
+/*
+ * This computes a 32 bit CRC of the data in the buffer, and returns the CRC.
+ * The polynomial used is 0xedb88320.
+ */
+
+extern uint32_t __efi_crc32 (const void *buf, unsigned long len,
+			     uint32_t seed);
+
+#endif /* _CRC32_H */
diff -burN parted-1.4.16/include/parted/device_diskioctl.h parted-1.4.16-gpt/include/parted/device_diskioctl.h
--- parted-1.4.16/include/parted/device_diskioctl.h	Wed Dec 31 18:00:00 1969
+++ parted-1.4.16-gpt/include/parted/device_diskioctl.h	Wed Jul 18 16:10:31 2001
@@ -0,0 +1,30 @@
+/*
+    libparted - a library for manipulating disk partitions
+
+    device_diskioctl.[ch] by Matt Domsch <Matt_Domsch@dell.com> 
+    Disclaimed into the Public Domain
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "parted/device.h"
+
+int
+ped_device_read_lastoddsector (const PedDevice* dev, void* buffer,
+			       PedSector start, PedSector count);
+int
+ped_device_write_lastoddsector (PedDevice* dev, const void* buffer,
+				PedSector start, PedSector count);
+
diff -burN parted-1.4.16/include/parted/disk_gpt.h parted-1.4.16-gpt/include/parted/disk_gpt.h
--- parted-1.4.16/include/parted/disk_gpt.h	Wed Dec 31 18:00:00 1969
+++ parted-1.4.16-gpt/include/parted/disk_gpt.h	Wed Jul 18 16:10:31 2001
@@ -0,0 +1,204 @@
+/*
+    libparted - a library for manipulating disk partitions
+
+    disk_gpt.[ch] by Matt Domsch <Matt_Domsch@dell.com>
+    Disclaimed into the Public Domain
+
+    EFI GUID Partition Table handling
+    Per Intel EFI Specification v1.02
+    http://developer.intel.com/technology/efi/efi.htm
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef EFI_GPT_H
+#define EFI_GPT_H
+
+
+#include <stdint.h>
+
+#define EFI_PMBR_OSTYPE_EFI 0xEF
+#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
+#define MSDOS_MBR_SIGNATURE 0xaa55
+#define GUID_PT_BLOCK_SIZE 512
+
+
+#define GUID_PT_HEADER_SIGNATURE 0x5452415020494645
+#define GUID_PT_HEADER_REVISION_V1_02 0x00010200
+#define GUID_PT_HEADER_REVISION_V1_00 0x00010000
+#define GUID_PT_HEADER_REVISION_V0_99 0x00009900
+
+typedef uint16_t efi_char16_t;	/* UNICODE character */
+
+typedef struct {
+        uint32_t time_low;
+        uint16_t time_mid;
+        uint16_t time_hi_and_version;
+        uint8_t  clock_seq_hi_and_reserved;
+        uint8_t  clock_seq_low;
+        uint8_t  node[6];
+} __attribute__ ((packed)) efi_guid_t;
+
+
+#define UNUSED_ENTRY_GUID    \
+    ((efi_guid_t) { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
+#define PARTITION_SYSTEM_GUID \
+    ((efi_guid_t) { 0xC12A7328, 0xF81F, 0x11d2, 0xBA, 0x4B, { 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }})
+#define LEGACY_MBR_PARTITION_GUID \
+    ((efi_guid_t) { 0x024DEE41, 0x33E7, 0x11d3, 0x9D, 0x69, { 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }})
+#define PARTITION_MSFT_RESERVED_GUID \
+    ((efi_guid_t) { 0xE3C9E316, 0x0B5C, 0x4DB8, 0x81, 0x7D, { 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE }})
+#define PARTITION_BASIC_DATA_GUID \
+    ((efi_guid_t) { 0xEBD0A0A2, 0xB9E5, 0x4433, 0x87, 0xC0, { 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }})
+#define PARTITION_RAID_GUID \
+    ((efi_guid_t) { 0xa19d880f, 0x05fc, 0x4d3b, 0xa0, 0x06, { 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e }})
+#define PARTITION_SWAP_GUID \
+    ((efi_guid_t) { 0x0657fd6d, 0xa4ab, 0x43c4, 0x84, 0xe5, { 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f }})
+#define PARTITION_LVM_GUID \
+    ((efi_guid_t) { 0xe6d6d379, 0xf507, 0x44c2, 0xa2, 0x3c, { 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 }})
+#define PARTITION_RESERVED_GUID \
+    ((efi_guid_t) { 0x8da63339, 0x0007, 0x60c0, 0xc4, 0x36, { 0x08, 0x3a, 0xc8, 0x23, 0x09, 0x08 }})
+
+typedef struct _GuidPartitionTableHeader_t {
+	uint64_t Signature;
+	uint32_t Revision;
+	uint32_t HeaderSize;
+	uint32_t HeaderCRC32;
+	uint32_t Reserved1;
+	uint64_t MyLBA;
+	uint64_t AlternateLBA;
+	uint64_t FirstUsableLBA;
+	uint64_t LastUsableLBA;
+	efi_guid_t DiskGUID;
+	uint64_t PartitionEntryLBA;
+	uint32_t NumberOfPartitionEntries;
+	uint32_t SizeOfPartitionEntry;
+	uint32_t PartitionEntryArrayCRC32;
+	uint8_t Reserved2[GUID_PT_BLOCK_SIZE - 92];
+} __attribute__ ((packed)) GuidPartitionTableHeader_t;
+
+typedef struct _GuidPartitionEntryAttributes_t {
+	uint64_t RequiredToFunction:1;
+	uint64_t Reserved:47;
+        uint64_t GuidSpecific:16;
+} __attribute__ ((packed)) GuidPartitionEntryAttributes_t;
+
+typedef struct _GuidPartitionEntry_t {
+	efi_guid_t PartitionTypeGuid;
+	efi_guid_t UniquePartitionGuid;
+	uint64_t StartingLBA;
+	uint64_t EndingLBA;
+	GuidPartitionEntryAttributes_t Attributes;
+	efi_char16_t PartitionName[72 / sizeof(efi_char16_t)];
+} __attribute__ ((packed)) GuidPartitionEntry_t;
+
+
+#define GPT_PMBR_LBA 0
+#define GPT_PMBR_SECTORS 1
+#define GPT_PRIMARY_HEADER_LBA 1
+#define GPT_HEADER_SECTORS 1
+#define GPT_PRIMARY_PART_TABLE_LBA 2
+
+/* 
+   These values are only defaults.  The actual on-disk structures
+   may define different sizes, so use those unless creating a new GPT disk!
+*/
+
+#define GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE 16384
+/* 
+   Number of actual partition entries should be calculated
+   as: 
+*/
+#define GPT_DEFAULT_RESERVED_PARTITION_ENTRIES \
+        (GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE / \
+         sizeof(GuidPartitionEntry_t))
+
+
+typedef struct _PartitionRecord_t {
+	uint8_t BootIndicator;	/* Not used by EFI firmware. Set to 0x80 to indicate that this
+				   is the bootable legacy partition. */
+	uint8_t StartHead;		/* Start of partition in CHS address, not used by EFI firmware. */
+	uint8_t StartSector;	/* Start of partition in CHS address, not used by EFI firmware. */
+	uint8_t StartTrack;	/* Start of partition in CHS address, not used by EFI firmware. */
+	uint8_t OSType;		/* OS type. A value of 0xEF defines an EFI system partition.
+				   Other values are reserved for legacy operating systems, and
+				   allocated independently of the EFI specification. */
+	uint8_t EndHead;		/* End of partition in CHS address, not used by EFI firmware. */
+	uint8_t EndSector;		/* End of partition in CHS address, not used by EFI firmware. */
+	uint8_t EndTrack;		/* End of partition in CHS address, not used by EFI firmware. */
+	uint32_t StartingLBA;	/* Starting LBA address of the partition on the disk. Used by
+				   EFI firmware to define the start of the partition. */
+	uint32_t SizeInLBA;	/* Size of partition in LBA. Used by EFI firmware to determine
+				   the size of the partition. */
+} __attribute__ ((packed)) PartitionRecord_t;
+
+/* Protected Master Boot Record  & Legacy MBR share same structure */
+/* Needs to be packed because the u16s force misalignment. */
+
+typedef struct _LegacyMBR_t {
+	uint8_t BootCode[440];
+	uint32_t UniqueMBRSignature;
+	uint16_t Unknown;
+	PartitionRecord_t PartitionRecord[4];
+	uint16_t Signature;
+} __attribute__ ((packed)) LegacyMBR_t;
+
+
+
+
+
+
+
+/* Parted has a PedDisk field disk_specific that we'll keep
+   our own useful info in.
+*/
+typedef struct _GPTDiskData {
+        GuidPartitionTableHeader_t *pgpt;
+ 	GuidPartitionTableHeader_t *agpt;
+ 	GuidPartitionEntry_t       *ptes;
+} GPTDiskData;
+
+/* Parted has a PedPartition field disk_specific that we'll keep
+   our own useful info in.
+*/
+typedef struct _GPTPartitionData {
+        GuidPartitionEntry_t *  pte;
+} GPTPartitionData;
+
+
+#define GPT_NAME	"GPT"
+void ped_disk_gpt_init();
+void ped_disk_gpt_done();
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -burN parted-1.4.16/libparted/Makefile.am parted-1.4.16-gpt/libparted/Makefile.am
--- parted-1.4.16/libparted/Makefile.am	Sun Jul 15 01:19:45 2001
+++ parted-1.4.16-gpt/libparted/Makefile.am	Wed Jul 18 16:10:31 2001
@@ -30,11 +30,15 @@
 			llseek.c		\
 			llseek.h		\
 			natmath.c		\
+			crc32.c			\
 			disk.c			\
 			disk_bsd.c		\
 			disk_dos.c		\
 			disk_loop.c		\
 			disk_mac.c		\
+			disk_gpt.c		\
+			device_diskioctl.c	\
+			device_diskioctl.h	\
 			disk_sun.c
 
 if PC98
diff -burN parted-1.4.16/libparted/crc32.c parted-1.4.16-gpt/libparted/crc32.c
--- parted-1.4.16/libparted/crc32.c	Wed Dec 31 18:00:00 1969
+++ parted-1.4.16-gpt/libparted/crc32.c	Wed Jul 18 16:10:31 2001
@@ -0,0 +1,125 @@
+/* 
+ * Dec 5, 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * - Copied crc32.c from the linux/drivers/net/cipe directory.
+ * - Now pass seed as an arg
+ * - changed unsigned long to uint32_t, added #include<stdint.h>
+ * - changed len to be an unsigned long
+ * - changed crc32val to be a register
+ * - License remains unchanged!  It's still GPL-compatable!
+ */
+
+  /* ============================================================= */
+  /*  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or       */
+  /*  code or tables extracted from it, as desired without restriction.     */
+  /*                                                                        */
+  /*  First, the polynomial itself and its table of feedback terms.  The    */
+  /*  polynomial is                                                         */
+  /*  X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0   */
+  /*                                                                        */
+  /*  Note that we take it "backwards" and put the highest-order term in    */
+  /*  the lowest-order bit.  The X^32 term is "implied"; the LSB is the     */
+  /*  X^31 term, etc.  The X^0 term (usually shown as "+1") results in      */
+  /*  the MSB being 1.                                                      */
+  /*                                                                        */
+  /*  Note that the usual hardware shift register implementation, which     */
+  /*  is what we're using (we're merely optimizing it by doing eight-bit    */
+  /*  chunks at a time) shifts bits into the lowest-order term.  In our     */
+  /*  implementation, that means shifting towards the right.  Why do we     */
+  /*  do it this way?  Because the calculated CRC must be transmitted in    */
+  /*  order from highest-order term to lowest-order term.  UARTs transmit   */
+  /*  characters in order from LSB to MSB.  By storing the CRC this way,    */
+  /*  we hand it to the UART in the order low-byte to high-byte; the UART   */
+  /*  sends each low-bit to hight-bit; and the result is transmission bit   */
+  /*  by bit from highest- to lowest-order term without requiring any bit   */
+  /*  shuffling on our part.  Reception works similarly.                    */
+  /*                                                                        */
+  /*  The feedback terms table consists of 256, 32-bit entries.  Notes:     */
+  /*                                                                        */
+  /*      The table can be generated at runtime if desired; code to do so   */
+  /*      is shown later.  It might not be obvious, but the feedback        */
+  /*      terms simply represent the results of eight shift/xor opera-      */
+  /*      tions for all combinations of data and CRC register values.       */
+  /*                                                                        */
+  /*      The values must be right-shifted by eight bits by the "updcrc"    */
+  /*      logic; the shift must be unsigned (bring in zeroes).  On some     */
+  /*      hardware you could probably optimize the shift in assembler by    */
+  /*      using byte-swap instructions.                                     */
+  /*      polynomial $edb88320                                              */
+  /*                                                                        */
+  /*  --------------------------------------------------------------------  */
+
+#include<stdint.h>
+
+static uint32_t crc32_tab[] = {
+      0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+      0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+      0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+      0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+      0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+      0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+      0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+      0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+      0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+      0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+      0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+      0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+      0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+      0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+      0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+      0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+      0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+      0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+      0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+      0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+      0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+      0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+      0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+      0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+      0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+      0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+      0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+      0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+      0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+      0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+      0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+      0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+      0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+      0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+      0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+      0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+      0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+      0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+      0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+      0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+      0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+      0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+      0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+      0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+      0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+      0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+      0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+      0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+      0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+      0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+      0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+      0x2d02ef8dL
+   };
+
+/* Return a 32-bit CRC of the contents of the buffer. */
+
+uint32_t
+__efi_crc32(const void *buf, unsigned long len, uint32_t seed)
+{
+  unsigned long i;
+  register uint32_t crc32val;
+  const unsigned char *s = buf;
+
+  crc32val = seed;
+  for (i = 0;  i < len;  i ++)
+    {
+      crc32val =
+	crc32_tab[(crc32val ^ s[i]) & 0xff] ^
+	  (crc32val >> 8);
+    }
+  return crc32val;
+}
diff -burN parted-1.4.16/libparted/device.c parted-1.4.16-gpt/libparted/device.c
--- parted-1.4.16/libparted/device.c	Thu Jul  5 16:46:36 2001
+++ parted-1.4.16-gpt/libparted/device.c	Wed Jul 18 16:10:31 2001
@@ -41,6 +41,7 @@
 #include <scsi/scsi.h>
 
 #include <parted/parted.h>
+#include <parted/device_diskioctl.h>
 
 #ifndef SCSI_IOCTL_SEND_COMMAND
 #define SCSI_IOCTL_SEND_COMMAND 1
@@ -905,6 +906,19 @@
 	PED_ASSERT (!dev->external_mode, return 0);
 	PED_ASSERT (buffer != NULL, return 0);
 
+#ifdef linux
+	/* Kludge.  This is necessary to read/write the last
+	   block of an odd-sized disk, until Linux 2.5.x kernel fixes.
+	   This is only used by disk_gpt.c, and only to read/write
+	   one sector, so we don't have to be fancy.
+	*/
+
+	if ((dev->length & 1) &&
+	    (count == 1) &&
+	    start == dev->length - 1) {
+		return ped_device_read_lastoddsector(dev, buffer, start, count);
+	}
+#endif
 	while (1) {
 		if (ped_device_seek (dev, start))
 			break;
@@ -1024,6 +1038,19 @@
 		else
 			return 1;
 	}
+
+#ifdef linux
+	/* Kludge.  This is necessary to read/write the last
+	   block of an odd-sized disk, until Linux 2.5.x kernel fixes.
+	   This is only used by disk_gpt.c, and only to read/write
+	   one sector, so we don't have to be fancy.
+	*/
+	if ((dev->length & 1) &&
+	    (count == 1) &&
+	    start == dev->length - 1) {
+		return ped_device_write_lastoddsector(dev, buffer, start, count);
+	}
+#endif
 
 	while (1) {
 		if (ped_device_seek (dev, start))
diff -burN parted-1.4.16/libparted/device_diskioctl.c parted-1.4.16-gpt/libparted/device_diskioctl.c
--- parted-1.4.16/libparted/device_diskioctl.c	Wed Dec 31 18:00:00 1969
+++ parted-1.4.16-gpt/libparted/device_diskioctl.c	Wed Jul 18 16:10:31 2001
@@ -0,0 +1,81 @@
+/*
+    libparted - a library for manipulating disk partitions
+
+    device_diskioctl.[ch] by Matt Domsch <Matt_Domsch@dell.com> 
+    Disclaimed into the Public Domain
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <parted/parted.h>
+#include <sys/ioctl.h>
+
+#define BLKGETLASTSECT  _IO(0x12,108) /* get last sector of block device */
+#define BLKSETLASTSECT  _IO(0x12,109) /* get last sector of block device */
+
+struct blkdev_ioctl_param {
+	unsigned int block;
+	size_t content_length;
+	char * block_contents;
+};
+
+int
+ped_device_read_lastoddsector (const PedDevice* dev, void* buffer,
+			       PedSector start, PedSector count)
+{
+	int rc;
+	struct blkdev_ioctl_param ioctl_param;
+
+	PED_ASSERT(dev != NULL, return 0);
+	PED_ASSERT(buffer != NULL, return 0);
+	PED_ASSERT(count == 1, return 0);	
+
+	ioctl_param.block = 0; /* read the last sector */
+	ioctl_param.content_length = dev->sector_size;
+	ioctl_param.block_contents = buffer;
+	
+	rc = ioctl(dev->fd, BLKGETLASTSECT, &ioctl_param);
+	if (rc == -1) perror("read failed");
+
+	return !rc;
+}
+
+int
+ped_device_write_lastoddsector (PedDevice* dev, const void* buffer,
+				PedSector start, PedSector count)
+{
+	int rc;
+	struct blkdev_ioctl_param ioctl_param;
+
+	PED_ASSERT(dev != NULL, return 0);
+	PED_ASSERT(buffer != NULL, return 0);
+	PED_ASSERT(count == 1, return 0);	
+
+	ioctl_param.block = 0; /* write the last sector */
+	ioctl_param.block_contents = (char *)buffer;
+	ioctl_param.content_length = dev->sector_size;
+
+	rc = ioctl(dev->fd, BLKSETLASTSECT, &ioctl_param);
+	if (rc == -1) perror("write failed");
+
+	return !rc;
+
+}
diff -burN parted-1.4.16/libparted/disk.c parted-1.4.16-gpt/libparted/disk.c
--- parted-1.4.16/libparted/disk.c	Tue Jun 12 05:09:29 2001
+++ parted-1.4.16-gpt/libparted/disk.c	Wed Jul 18 16:10:31 2001
@@ -182,6 +182,7 @@
 	disk->dev = dev;
 	disk->type = disk_type;
 	disk->update_mode = 0;
+	disk->disk_specific = NULL;
 
 	disk->part_list = ped_partition_new (
 		disk, PED_PARTITION_FREESPACE, NULL,
@@ -591,6 +592,7 @@
 	part->type = type;
 	part->part_list = NULL;
 	part->fs_type = fs_type;
+	part->disk_specific = NULL;
 
 	return part;
 
@@ -609,6 +611,8 @@
 	PedPartition*	part;
 
 	PED_ASSERT (disk != NULL, return NULL);
+	PED_ASSERT (disk->type != NULL, return NULL);
+	PED_ASSERT (disk->type->ops != NULL, return NULL);
 	PED_ASSERT (disk->type->ops->partition_new != NULL, return NULL);
 
 	supports_extended = ped_disk_type_check_feature (disk->type,
@@ -1374,10 +1378,10 @@
 	PED_ASSERT (part != NULL, return 0);
 
 #ifdef VERBOSE
-	printf ("ped_disk_add_partition (dev=\"%s\", start=%d, end=%d,"
+	printf ("ped_disk_add_partition (dev=\"%s\", start=%llx, end=%llx,"
 		" type=%x)\n",
-		disk->dev->path, (int) part->geom.start, (int) part->geom.end,
-		(int) part->system);
+		disk->dev->path, part->geom.start, part->geom.end,
+		part->type);
 #endif
 
 	if (!ped_disk_type_check_feature (disk->type, PED_DISK_TYPE_EXTENDED)
diff -burN parted-1.4.16/libparted/disk_dos.c parted-1.4.16-gpt/libparted/disk_dos.c
--- parted-1.4.16/libparted/disk_dos.c	Sat Jul 14 21:12:22 2001
+++ parted-1.4.16-gpt/libparted/disk_dos.c	Wed Jul 18 16:10:31 2001
@@ -266,6 +266,12 @@
 		}
 	}
 
+	/* If this is a GPT disk, fail here */
+	for (i = 0; i < 4; i++) {
+		if (part_table.partitions[i].type == 0xEE)
+ 			return 0;
+ 	}
+
 	/* HACK: it's impossible to tell PC98 and msdos disk labels apart.
 	 * Someone made the signatures the same (very clever).  Since
 	 * PC98 has some idiosyncracies with it's boot-loader, it's detection
diff -burN parted-1.4.16/libparted/fs_ext2/interface.c parted-1.4.16-gpt/libparted/fs_ext2/interface.c
--- parted-1.4.16/libparted/fs_ext2/interface.c	Tue Jul  3 05:59:30 2001
+++ parted-1.4.16-gpt/libparted/fs_ext2/interface.c	Wed Jul 18 16:10:32 2001
@@ -31,6 +31,7 @@
 #include <parted/disk_pc98.h>
 #include <parted/disk_mac.h>
 #include <parted/disk_bsd.h>
+#include <parted/disk_gpt.h>
 #include <parted/disk_sun.h>
 
 #include <string.h>
@@ -387,6 +388,15 @@
 	if (strcmp (disk_type->name, BSD_NAME) == 0) {
 		BSDPartitionData* bsd_data = part->disk_specific;
 		bsd_data->type = 0x8;
+		return 1;
+	}
+
+	if (strcmp (disk_type->name, GPT_NAME) == 0) {
+		GPTPartitionData *gpt_part_data = part->disk_specific;
+		PED_ASSERT(gpt_part_data      != NULL, return 0);	
+		PED_ASSERT(gpt_part_data->pte != NULL, return 0);
+		gpt_part_data->pte->PartitionTypeGuid =
+			PARTITION_BASIC_DATA_GUID;
 		return 1;
 	}
 
diff -burN parted-1.4.16/libparted/fs_fat/fat.c parted-1.4.16-gpt/libparted/fs_fat/fat.c
--- parted-1.4.16/libparted/fs_fat/fat.c	Sat Apr  7 17:04:38 2001
+++ parted-1.4.16-gpt/libparted/fs_fat/fat.c	Wed Jul 18 16:10:32 2001
@@ -24,6 +24,7 @@
 #include <parted/disk_loop.h>
 #include <parted/disk_pc98.h>
 #include <parted/disk_mac.h>
+#include <parted/disk_gpt.h>
 
 #include "fat.h"
 #include "calc.h"
@@ -767,6 +768,15 @@
 		else
 			strcpy (mac_data->system_name, "FAT");
 		mac_data->status = 0x33;
+		return 1;
+	}
+
+	if (strcmp (disk_type->name, GPT_NAME) == 0) {
+		GPTPartitionData *gpt_part_data = part->disk_specific;
+		PED_ASSERT(gpt_part_data      != NULL, return 0);	
+		PED_ASSERT(gpt_part_data->pte != NULL, return 0);
+		gpt_part_data->pte->PartitionTypeGuid =
+			PARTITION_BASIC_DATA_GUID;
 		return 1;
 	}
 
diff -burN parted-1.4.16/libparted/fs_hfs/hfs.c parted-1.4.16-gpt/libparted/fs_hfs/hfs.c
--- parted-1.4.16/libparted/fs_hfs/hfs.c	Sat Apr  7 17:04:38 2001
+++ parted-1.4.16-gpt/libparted/fs_hfs/hfs.c	Wed Jul 18 16:10:32 2001
@@ -25,6 +25,7 @@
 #include <parted/disk_loop.h>
 #include <parted/disk_pc98.h>
 #include <parted/disk_mac.h>
+#include <parted/disk_gpt.h>
 
 #include <libintl.h>
 #if ENABLE_NLS
@@ -34,7 +35,6 @@
 #endif /* ENABLE_NLS */
 
 #include <unistd.h>
-#include <asm/page.h>
 #include <string.h>
 
 #define HFS_SIGNATURE	0x4244
@@ -151,6 +151,15 @@
 			strcpy (mac_data->system_name, "Apple_HFS");
 			mac_data->status |= 0x7f;
 		}
+		return 1;
+	}
+
+	if (strcmp (disk_type->name, GPT_NAME) == 0) {
+		GPTPartitionData *gpt_part_data = part->disk_specific;
+		PED_ASSERT(gpt_part_data      != NULL, return 0);	
+		PED_ASSERT(gpt_part_data->pte != NULL, return 0);
+		gpt_part_data->pte->PartitionTypeGuid =
+			PARTITION_BASIC_DATA_GUID;
 		return 1;
 	}
 
diff -burN parted-1.4.16/libparted/fs_jfs/jfs.c parted-1.4.16-gpt/libparted/fs_jfs/jfs.c
--- parted-1.4.16/libparted/fs_jfs/jfs.c	Sun Jul 15 01:00:24 2001
+++ parted-1.4.16-gpt/libparted/fs_jfs/jfs.c	Wed Jul 18 16:10:32 2001
@@ -25,6 +25,7 @@
 #include <parted/disk_loop.h>
 #include <parted/disk_mac.h>
 #include <parted/disk_pc98.h>
+#include <parted/disk_gpt.h>
 
 #define _JFS_UTILITY
 #include "jfs_types.h"
@@ -157,6 +158,18 @@
 		mac_data->status = 0x33;
 		return 1;
 	}
+
+	if (strcmp (disk_type->name, GPT_NAME) == 0) {
+		GPTPartitionData *gpt_part_data = part->disk_specific;
+		PED_ASSERT(gpt_part_data      != NULL, return 0);	
+		PED_ASSERT(gpt_part_data->pte != NULL, return 0);
+		gpt_part_data->pte->PartitionTypeGuid =
+			PARTITION_BASIC_DATA_GUID;
+		return 1;
+	}
+
+
+
 
 	return 0;
 }
diff -burN parted-1.4.16/libparted/fs_linux_swap/linux_swap.c parted-1.4.16-gpt/libparted/fs_linux_swap/linux_swap.c
--- parted-1.4.16/libparted/fs_linux_swap/linux_swap.c	Sat Apr  7 17:04:38 2001
+++ parted-1.4.16-gpt/libparted/fs_linux_swap/linux_swap.c	Wed Jul 18 16:10:32 2001
@@ -28,6 +28,7 @@
 #include <parted/disk_pc98.h>
 #include <parted/disk_mac.h>
 #include <parted/disk_bsd.h>
+#include <parted/disk_gpt.h>
 #include <parted/disk_sun.h>
 
 #include <libintl.h>
@@ -38,7 +39,6 @@
 #endif /* ENABLE_NLS */
 
 #include <unistd.h>
-#include <asm/page.h>
 #include <string.h>
 
 #define SWAP_SPECIFIC(fs) ((SwapSpecific*) (fs->type_specific))
@@ -563,6 +563,15 @@
 	if (strcmp (disk_type->name, BSD_NAME) == 0) {
 		BSDPartitionData* bsd_data = part->disk_specific;
 		bsd_data->type = 0x1;
+		return 1;
+	}
+
+	if (strcmp (disk_type->name, GPT_NAME) == 0) {
+		GPTPartitionData* gpt_part_data = part->disk_specific;
+		PED_ASSERT(gpt_part_data      != NULL, return 0);
+		PED_ASSERT(gpt_part_data->pte != NULL, return 0);
+		gpt_part_data->pte->PartitionTypeGuid =
+			PARTITION_SWAP_GUID;
 		return 1;
 	}
 
diff -burN parted-1.4.16/libparted/fs_ntfs/ntfs.c parted-1.4.16-gpt/libparted/fs_ntfs/ntfs.c
--- parted-1.4.16/libparted/fs_ntfs/ntfs.c	Sat Apr  7 17:04:38 2001
+++ parted-1.4.16-gpt/libparted/fs_ntfs/ntfs.c	Wed Jul 18 16:10:32 2001
@@ -25,6 +25,7 @@
 #include <parted/disk_loop.h>
 #include <parted/disk_pc98.h>
 #include <parted/disk_mac.h>
+#include <parted/disk_gpt.h>
 
 #include <libintl.h>
 #if ENABLE_NLS
@@ -34,7 +35,6 @@
 #endif /* ENABLE_NLS */
 
 #include <unistd.h>
-#include <asm/page.h>
 #include <string.h>
 
 #define NTFS_SIGNATURE	"NTFS"
@@ -147,6 +147,15 @@
 		else
 			strcpy (mac_data->system_name, "Apple_UNIX_SVR2");
 		mac_data->status = 0x33;
+		return 1;
+	}
+
+	if (strcmp (disk_type->name, GPT_NAME) == 0) {
+		GPTPartitionData *gpt_part_data = part->disk_specific;
+		PED_ASSERT(gpt_part_data      != NULL, return 0);	
+		PED_ASSERT(gpt_part_data->pte != NULL, return 0);
+		gpt_part_data->pte->PartitionTypeGuid =
+			PARTITION_BASIC_DATA_GUID;
 		return 1;
 	}
 
diff -burN parted-1.4.16/libparted/fs_reiserfs/reiserfs.c parted-1.4.16-gpt/libparted/fs_reiserfs/reiserfs.c
--- parted-1.4.16/libparted/fs_reiserfs/reiserfs.c	Sat Apr  7 17:04:38 2001
+++ parted-1.4.16-gpt/libparted/fs_reiserfs/reiserfs.c	Wed Jul 18 16:10:32 2001
@@ -25,6 +25,7 @@
 #include <parted/disk_loop.h>
 #include <parted/disk_pc98.h>
 #include <parted/disk_mac.h>
+#include <parted/disk_gpt.h>
 
 #include <libintl.h>
 #if ENABLE_NLS
@@ -34,7 +35,6 @@
 #endif /* ENABLE_NLS */
 
 #include <unistd.h>
-#include <asm/page.h>
 #include <string.h>
 
 #define REISERFS_SIGNATURE	"ReIsErFs"
@@ -181,6 +181,15 @@
 		else
 			strcpy (mac_data->system_name, "Apple_UNIX_SVR2");
 		mac_data->status = 0x33;
+		return 1;
+	}
+
+	if (strcmp (disk_type->name, GPT_NAME) == 0) {
+		GPTPartitionData *gpt_part_data = part->disk_specific;
+		PED_ASSERT(gpt_part_data      != NULL, return 0);	
+		PED_ASSERT(gpt_part_data->pte != NULL, return 0);
+		gpt_part_data->pte->PartitionTypeGuid =
+			PARTITION_BASIC_DATA_GUID;
 		return 1;
 	}
 
diff -burN parted-1.4.16/libparted/fs_ufs/ufs.c parted-1.4.16-gpt/libparted/fs_ufs/ufs.c
--- parted-1.4.16/libparted/fs_ufs/ufs.c	Sat Apr  7 17:04:39 2001
+++ parted-1.4.16-gpt/libparted/fs_ufs/ufs.c	Wed Jul 18 16:10:32 2001
@@ -24,6 +24,7 @@
 #include <parted/parted.h>
 #include <parted/endian.h>
 #include <parted/disk_sun.h>
+#include <parted/disk_gpt.h>
 
 #include <libintl.h>
 #if ENABLE_NLS
@@ -202,6 +203,17 @@
 		sun_data->type = 0x6;
 		return 1;
 	}
+
+	if (strcmp (disk_type->name, GPT_NAME) == 0) {
+		GPTPartitionData *gpt_part_data = part->disk_specific;
+		PED_ASSERT(gpt_part_data      != NULL, return 0);	
+		PED_ASSERT(gpt_part_data->pte != NULL, return 0);
+		gpt_part_data->pte->PartitionTypeGuid =
+			PARTITION_BASIC_DATA_GUID;
+		return 1;
+	}
+
+
 
 	return 0;
 }
diff -burN parted-1.4.16/libparted/fs_xfs/xfs.c parted-1.4.16-gpt/libparted/fs_xfs/xfs.c
--- parted-1.4.16/libparted/fs_xfs/xfs.c	Sun Jul 15 01:07:01 2001
+++ parted-1.4.16-gpt/libparted/fs_xfs/xfs.c	Wed Jul 18 16:10:32 2001
@@ -25,6 +25,7 @@
 #include <parted/disk_loop.h>
 #include <parted/disk_mac.h>
 #include <parted/disk_pc98.h>
+#include <parted/disk_gpt.h>
 
 #include <libintl.h>
 #if ENABLE_NLS
@@ -158,6 +159,16 @@
 		return 1;
 	}
 
+	if (strcmp (disk_type->name, GPT_NAME) == 0) {
+		GPTPartitionData *gpt_part_data = part->disk_specific;
+		PED_ASSERT(gpt_part_data      != NULL, return 0);	
+		PED_ASSERT(gpt_part_data->pte != NULL, return 0);
+		gpt_part_data->pte->PartitionTypeGuid =
+			PARTITION_BASIC_DATA_GUID;
+		return 1;
+	}
+
+	
 	return 0;
 }
 
diff -burN parted-1.4.16/libparted/libparted.c parted-1.4.16-gpt/libparted/libparted.c
--- parted-1.4.16/libparted/libparted.c	Sun Jul 15 01:11:51 2001
+++ parted-1.4.16-gpt/libparted/libparted.c	Wed Jul 18 16:10:32 2001
@@ -26,6 +26,7 @@
 #include <parted/disk_mac.h>
 #include <parted/disk_pc98.h>
 #include <parted/disk_sun.h>
+#include <parted/disk_gpt.h>
 
 #include <grp.h>
 #include <pwd.h>
@@ -104,6 +105,7 @@
 #endif
 	ped_disk_mac_init ();
 	ped_disk_bsd_init ();
+	ped_disk_gpt_init ();
 	ped_disk_sun_init ();
 }
 
@@ -147,6 +149,7 @@
 	ped_disk_loop_done ();
 	ped_disk_mac_done ();
 	ped_disk_bsd_done ();
+	ped_disk_gpt_done ();
 	ped_disk_sun_done ();
 }
 
--- /dev/null	Thu Aug 24 04:00:32 2000
+++ parted-1.4.16-gpt/libparted/disk_gpt.c	Sat Jul 21 09:46:50 2001
@@ -0,0 +1,1795 @@
+/*
+    libparted - a library for manipulating disk partitions
+
+    disk_gpt.[ch] by Matt Domsch <Matt_Domsch@dell.com>
+    Disclaimed into the Public Domain
+
+    EFI GUID Partition Table handling
+    Per Intel EFI Specification v1.02
+    http://developer.intel.com/technology/efi/efi.htm
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+/* 
+   TODO:
+   - Make partition labels get/set properly
+*/
+
+#include "config.h"
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/crc32.h>
+#include <parted/disk_gpt.h>
+#include <parted/natmath.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <uuid/uuid.h>
+
+#include <libintl.h>
+#if ENABLE_NLS
+#  define _(String) gettext (String)
+#else
+#  define _(String) (String)
+#endif				/* ENABLE_NLS */
+
+#define MIN_FREESPACE		(150 * 2)	/* 150k */
+
+
+static int gpt_probe(const PedDevice * dev);
+static PedDisk *gpt_open(PedDevice * dev);
+static PedDisk *gpt_create(PedDevice * dev);
+static int gpt_clobber(PedDevice * dev);
+static int gpt_close(PedDisk * disk);
+static int gpt_read(PedDisk * disk);
+static int gpt_write(PedDisk * disk);
+
+
+static PedPartition *gpt_partition_new(const PedDisk *disk,
+                             PedPartitionType part_type,
+                             const PedFileSystemType* fs_type,
+                             PedSector start,
+                             PedSector end);
+static void gpt_partition_destroy(PedPartition *part);
+static int gpt_partition_set_flag(PedPartition *part,
+                                  PedPartitionFlag flag,
+                                  int state);
+static int gpt_partition_get_flag(const PedPartition *part,
+                                  PedPartitionFlag flag);
+static int gpt_partition_is_flag_available(const PedPartition * part,
+                                           PedPartitionFlag flag);
+static void gpt_partition_set_name(PedPartition *part,
+                                   const char *name);
+static const char * gpt_partition_get_name (const PedPartition * part);
+static int gpt_partition_align(PedPartition * part,
+                               const PedConstraint * constraint);
+static int gpt_partition_enumerate(PedPartition * part);
+
+static int gpt_alloc_metadata(PedDisk * disk);
+static int gpt_get_max_primary_partition_count(const PedDisk *disk);
+
+/* gpt private function */
+static PedDisk * gpt_new(PedDisk * disk);
+
+static PedDiskOps gpt_disk_ops = {
+	probe                           : gpt_probe,
+	open                            : gpt_open,
+	create                          : gpt_create,
+        clobber                         : gpt_clobber,
+	close                           : gpt_close,
+	read                            : gpt_read,
+	write                           : gpt_write,
+        partition_new                   : gpt_partition_new,
+        partition_destroy               : gpt_partition_destroy,
+        partition_set_flag              : gpt_partition_set_flag,
+        partition_get_flag              : gpt_partition_get_flag,
+        partition_is_flag_available     : gpt_partition_is_flag_available,
+        partition_set_name              : gpt_partition_set_name,
+        partition_get_name              : gpt_partition_get_name,
+	partition_align                 : gpt_partition_align,
+	partition_enumerate             : gpt_partition_enumerate,
+	partition_set_extended_system   : NULL,
+	alloc_metadata                  : gpt_alloc_metadata,
+        get_max_primary_partition_count : gpt_get_max_primary_partition_count
+
+};
+
+static PedDiskType gpt_disk_type = {
+	next:NULL,
+	name:GPT_NAME,
+	ops:&gpt_disk_ops,
+        features: PED_DISK_TYPE_PARTITION_NAME
+};
+
+
+
+static void
+gpt_le_guid_to_cpu(efi_guid_t *guid)
+{
+        guid->time_low            = PED_LE32_TO_CPU(guid->time_low);
+        guid->time_mid            = PED_LE16_TO_CPU(guid->time_mid);
+        guid->time_hi_and_version = PED_LE16_TO_CPU(guid->time_hi_and_version);
+        /* no need to change clock_seq and node[6].
+           They're already arrays of chars */
+        return;
+}
+
+static void
+gpt_cpu_to_le_guid(efi_guid_t *guid)
+{
+        guid->time_low            = PED_CPU_TO_LE32(guid->time_low);
+        guid->time_mid            = PED_CPU_TO_LE16(guid->time_mid);
+        guid->time_hi_and_version = PED_CPU_TO_LE16(guid->time_hi_and_version);
+        /* no need to change clock_seq and node[6].
+           They're already arrays of chars */
+        return;
+}
+
+static void
+gpt_le_part_attributes_to_cpu(GuidPartitionEntryAttributes_t *a)
+{
+  uint64_t *b = (uint64_t *)a;
+  *b = PED_LE64_TO_CPU(*b);
+}
+
+static void
+gpt_cpu_to_le_part_attributes(GuidPartitionEntryAttributes_t *a)
+{
+  uint64_t *b = (uint64_t *)a;
+  *b = PED_CPU_TO_LE64(*b);
+}
+
+
+/************************************************************
+ * efi_crc32()
+ * Requires:
+ *  - a buffer of length len
+ * Modifies: nothing
+ * Returns:
+ *  EFI-style CRC32 value for buf
+ *  
+ * This function uses the crc32 function by Gary S. Brown,
+ * but seeds the function with ~0, and xor's with ~0 at the end.
+ ************************************************************/
+
+static inline uint32_t
+efi_crc32(const void *buf, unsigned long len)
+{
+  return (__efi_crc32(buf, len, ~0L) ^ ~0L);
+}
+
+
+static inline int
+is_legacy_mbr_valid(LegacyMBR_t * mbr)
+{
+	return (mbr ? (mbr->Signature == MSDOS_MBR_SIGNATURE) : 0);
+}
+
+static inline int
+efi_guidcmp(efi_guid_t left, efi_guid_t right)
+{
+	return memcmp(&left, &right, sizeof(efi_guid_t));
+}
+
+
+/************************************************************
+ * last_lba()
+ * Requires:
+ *  - dev
+ * Modifies: nothing
+ * Returns:
+ *  Last LBA value on success 
+ *  0 on error
+ ************************************************************/
+
+
+static uint64_t
+last_lba(const PedDevice * dev)
+{
+	PED_ASSERT(dev != NULL, return 0);
+        return dev->length - 1;
+}
+
+/************************************************************
+ * gpt_read_part_entries()
+ * Requires:
+ *  - dev
+ *  - lba is the Logical Block Address of the partition table
+ *  - gpt is a buffer into which the GPT will be put  
+ * Modifies:
+ *  - dev
+ *  - gpt
+ * Returns:
+ *   pte on success
+ *   NULL on error
+ * Notes: remember to free pte when you're done!
+ ************************************************************/
+static GuidPartitionEntry_t *
+gpt_read_part_entries(const PedDevice * dev,
+                      GuidPartitionTableHeader_t * gpt)
+{
+	GuidPartitionEntry_t *ptes;
+        unsigned int i, j;
+
+	PED_ASSERT(dev != NULL, return NULL);
+        PED_ASSERT(dev->sector_size != 0, return NULL);
+	PED_ASSERT(gpt != NULL, return NULL);
+
+	ptes = (GuidPartitionEntry_t *)
+                ped_malloc(gpt->NumberOfPartitionEntries *
+                           gpt->SizeOfPartitionEntry);
+
+        PED_ASSERT(ptes != NULL, return NULL);
+
+        memset(ptes, 0, gpt->NumberOfPartitionEntries *
+               gpt->SizeOfPartitionEntry);
+
+
+	if (!ped_device_read(dev, ptes, gpt->PartitionEntryLBA,
+		     gpt->NumberOfPartitionEntries *
+		     gpt->SizeOfPartitionEntry / dev->sector_size)) {
+		ped_free(ptes);
+		return NULL;
+	}
+
+        /* Fixup endianness */
+        for (i=0; i<gpt->NumberOfPartitionEntries; i++) {
+                gpt_le_guid_to_cpu(&ptes[i].PartitionTypeGuid);
+                gpt_le_guid_to_cpu(&ptes[i].UniquePartitionGuid);
+                ptes[i].StartingLBA = PED_LE64_TO_CPU(ptes[i].StartingLBA);
+                ptes[i].EndingLBA   = PED_LE64_TO_CPU(ptes[i].EndingLBA);
+                gpt_le_part_attributes_to_cpu(&ptes[i].Attributes);
+                for (j=0; j<(72/sizeof(efi_char16_t)); j++) {
+                        ptes[i].PartitionName[j] = (efi_char16_t)(PED_LE16_TO_CPU((uint16_t)(ptes[i].PartitionName[j])));
+                }
+        }
+
+	return ptes;
+}
+
+/************************************************************
+ * gpt_write_part_entries()
+ * Requires:
+ *  - PedDevice *dev
+ *  - gpt 
+ *  - pte is a buffer that will be written
+ * Modifies:
+ *  - dev
+ *  - gpt
+ * Returns:
+ *   pte on success
+ *   NULL on error
+ * Notes: remember to free pte when you're done!
+ ************************************************************/
+static GuidPartitionEntry_t *
+gpt_write_part_entries(PedDevice * dev,
+                       GuidPartitionTableHeader_t * gpt,
+                       GuidPartitionEntry_t *ptes)
+{
+        GuidPartitionEntry_t *new_ptes;
+        unsigned long ptes_size;
+        int rc;
+        unsigned int i, j;
+
+        PED_ASSERT(gpt != NULL, return NULL);
+        PED_ASSERT(ptes != NULL, return NULL);
+        PED_ASSERT(dev != NULL, return NULL);
+        PED_ASSERT(dev->sector_size != 0, return NULL);
+
+        ptes_size = gpt->NumberOfPartitionEntries *
+                gpt->SizeOfPartitionEntry;
+
+        new_ptes = ped_malloc(ptes_size);
+        if (!new_ptes) return NULL;
+        memcpy(new_ptes, ptes, ptes_size);
+
+        /* Fixup endianness */
+        for (i=0; i<gpt->NumberOfPartitionEntries; i++) {
+                gpt_cpu_to_le_guid(&new_ptes->PartitionTypeGuid);
+                gpt_cpu_to_le_guid(&new_ptes->UniquePartitionGuid);
+                new_ptes[i].StartingLBA = PED_CPU_TO_LE64(new_ptes[i].StartingLBA);
+                new_ptes[i].EndingLBA   = PED_CPU_TO_LE64(new_ptes[i].EndingLBA);
+                gpt_cpu_to_le_part_attributes(&new_ptes[i].Attributes);
+
+                for (j=0; j<(72/sizeof(efi_char16_t)); j++) {
+                        new_ptes[i].PartitionName[j] = (efi_char16_t)(PED_CPU_TO_LE16((uint16_t)(new_ptes[i].PartitionName[j])));
+                }
+        }
+
+        rc = ped_device_write(dev, new_ptes, gpt->PartitionEntryLBA,
+                              ptes_size / dev->sector_size);
+        ped_free(new_ptes);
+        if (!rc) return NULL;
+	return ptes;
+}
+
+
+static void
+gpt_print_part_entry(GuidPartitionEntry_t * pte, int i)
+{
+	efi_guid_t unused_guid = UNUSED_ENTRY_GUID;
+	char uuid_buffer[40];
+	uuid_t uuid;
+        PED_ASSERT(pte != NULL, return);
+	if (!efi_guidcmp(pte->PartitionTypeGuid, unused_guid)) {
+		// printf("UNUSED_ENTRY_GUID\n");
+		return;
+	}
+	printf("GUID Partition Entry %d:\n", i);
+	memcpy(uuid, &pte->PartitionTypeGuid, sizeof(uuid_t));
+	uuid_unparse(uuid, uuid_buffer);
+	printf("\tPartitionTypeGuid : %s\n", uuid_buffer);
+	memcpy(uuid, &pte->UniquePartitionGuid, sizeof(uuid_t));
+	uuid_unparse(uuid, uuid_buffer);
+	printf("\tUniquePartitionGuid : %s\n", uuid_buffer);
+	printf("\tStartingLBA : %llx\n", pte->StartingLBA);
+	printf("\tEndingLBA   : %llx\n", pte->EndingLBA);
+	printf("\tAttributes  : ");
+	printf("\tRequiredToFunction: %x",
+	       pte->Attributes.RequiredToFunction);
+	printf("\tGuidSpecific: %x\n",
+	       pte->Attributes.GuidSpecific);
+        
+	//  printf("\tPartitionName : Unicode string.\n");
+	return;
+}
+
+static void
+gpt_print_header(GuidPartitionTableHeader_t * gpt)
+{
+	char uuid_buffer[40];
+	uuid_t uuid;
+	printf("GUID Partition Table Header\n");
+        PED_ASSERT(gpt != NULL, return);
+	printf("Signature      : 0x%llx\n", gpt->Signature);
+	printf("Revision       : 0x%x\n", gpt->Revision);
+	printf("HeaderSize     : 0x%x\n", gpt->HeaderSize);
+	printf("HeaderCRC32    : 0x%x\n", gpt->HeaderCRC32);
+	printf("MyLBA          : 0x%llx\n", gpt->MyLBA);
+	printf("AlternateLBA   : 0x%llx\n", gpt->AlternateLBA);
+	printf("FirstUsableLBA : 0x%llx\n", gpt->FirstUsableLBA);
+	printf("LastUsableLBA  : 0x%llx\n", gpt->LastUsableLBA);
+	memcpy(uuid, &gpt->DiskGUID, sizeof(uuid_t));
+	uuid_unparse(uuid, uuid_buffer);
+	printf("DiskGUID : %s\n", uuid_buffer);
+	printf("PartitionEntryLBA : %llx\n", gpt->PartitionEntryLBA);
+	printf("NumberOfPartitionEntries : %x\n",
+	       gpt->NumberOfPartitionEntries);
+	printf("SizeOfPartitionEntry : %x\n", gpt->SizeOfPartitionEntry);
+	printf("PartitionEntryArrayCRC32 : %x\n",
+	       gpt->PartitionEntryArrayCRC32); return;
+}
+
+
+/************************************************************
+ * gpt_read_header()
+ * Requires:
+ *  - dev
+ *  - lba is the Logical Block Address of the partition table
+ * Modifies:
+ *  - dev
+ * Returns:
+ *   GPTH on success
+ *   NULL on error
+ ************************************************************/
+static GuidPartitionTableHeader_t *
+gpt_read_header(const PedDevice * dev,
+                uint64_t lba)
+{
+	GuidPartitionTableHeader_t *gpt;
+	PED_ASSERT(dev != NULL, return 0);
+	gpt = (GuidPartitionTableHeader_t *)
+	    ped_malloc(sizeof(GuidPartitionTableHeader_t));
+        if (!gpt) return NULL;
+        memset(gpt, 0, sizeof (*gpt));
+	if (!ped_device_read(dev, gpt, lba, 1)) {
+		ped_free(gpt);
+		return NULL;
+	}
+
+
+        /* Fixup endianness */
+        gpt->Signature                = PED_LE64_TO_CPU(gpt->Signature);
+        gpt->Revision                 = PED_LE32_TO_CPU(gpt->Revision);
+        gpt->HeaderSize               = PED_LE32_TO_CPU(gpt->HeaderSize);
+        gpt->HeaderCRC32              = PED_LE32_TO_CPU(gpt->HeaderCRC32);
+        gpt->Reserved1                = PED_LE32_TO_CPU(gpt->Reserved1);
+        gpt->MyLBA                    = PED_LE64_TO_CPU(gpt->MyLBA);
+        gpt->AlternateLBA             = PED_LE64_TO_CPU(gpt->AlternateLBA);
+        gpt->FirstUsableLBA           = PED_LE64_TO_CPU(gpt->FirstUsableLBA);
+        gpt->LastUsableLBA            = PED_LE64_TO_CPU(gpt->LastUsableLBA);
+        gpt->PartitionEntryLBA        = PED_LE64_TO_CPU(gpt->PartitionEntryLBA);
+        gpt->NumberOfPartitionEntries = PED_LE32_TO_CPU(gpt->NumberOfPartitionEntries);
+        gpt->SizeOfPartitionEntry     = PED_LE32_TO_CPU(gpt->SizeOfPartitionEntry);
+        gpt->PartitionEntryArrayCRC32 = PED_LE32_TO_CPU(gpt->PartitionEntryArrayCRC32);
+        gpt_le_guid_to_cpu(&gpt->DiskGUID);
+        /* Ignore the reserved bytes */
+
+	return gpt;
+}
+
+/************************************************************
+ * gpt_write_header()
+ * Requires:
+ *  - dev
+ *  - lba is the Logical Block Address of the partition table
+ *  - gpt is a buffer into which the GPT will be put  
+ * Modifies:
+ *  - dev
+ * Returns:
+ *   1 on success
+ *   0 on error
+ ************************************************************/
+static int
+gpt_write_header(PedDevice *dev,
+                 GuidPartitionTableHeader_t * gpt)
+{
+        GuidPartitionTableHeader_t *new_gpt;
+        int rc;
+
+        PED_ASSERT(gpt != NULL, return 0);
+
+        new_gpt = ped_malloc(sizeof(*gpt));
+        if (!new_gpt) return 0;
+        memcpy(new_gpt, gpt, sizeof(*gpt));
+
+        /* Fixup endianness */
+        new_gpt->Signature                = PED_CPU_TO_LE64(gpt->Signature);
+        new_gpt->Revision                 = PED_CPU_TO_LE32(gpt->Revision);
+        new_gpt->HeaderSize               = PED_CPU_TO_LE32(gpt->HeaderSize);
+        new_gpt->HeaderCRC32              = PED_CPU_TO_LE32(gpt->HeaderCRC32);
+        new_gpt->Reserved1                = PED_CPU_TO_LE32(gpt->Reserved1);
+        new_gpt->MyLBA                    = PED_CPU_TO_LE64(gpt->MyLBA);
+        new_gpt->AlternateLBA             = PED_CPU_TO_LE64(gpt->AlternateLBA);
+        new_gpt->FirstUsableLBA           = PED_CPU_TO_LE64(gpt->FirstUsableLBA);
+        new_gpt->LastUsableLBA            = PED_CPU_TO_LE64(gpt->LastUsableLBA);
+        new_gpt->PartitionEntryLBA        = PED_CPU_TO_LE64(gpt->PartitionEntryLBA);
+        new_gpt->NumberOfPartitionEntries = PED_CPU_TO_LE32(gpt->NumberOfPartitionEntries);
+        new_gpt->SizeOfPartitionEntry = PED_CPU_TO_LE32(gpt->SizeOfPartitionEntry);
+        new_gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32(gpt->PartitionEntryArrayCRC32);
+        gpt_cpu_to_le_guid(&new_gpt->DiskGUID);
+        /* Ignore the reserved bytes */
+
+        rc = ped_device_write(dev, new_gpt, gpt->MyLBA, GPT_HEADER_SECTORS);
+        ped_free(new_gpt);
+        return rc;
+}
+
+
+/************************************************************
+ * gpt_is_valid()
+ * Requires:
+ *  - dev
+ *  - lba is the Logical Block Address of the partition table
+ * Modifies:
+ *  - dev
+ *  - gpt  - reads data into gpt
+ *  - ptes - reads data into ptes
+ * Returns:
+ *   1 if valid
+ *   0 on error
+ ************************************************************/
+
+
+static int
+gpt_is_valid(const PedDevice * dev, uint64_t lba,
+             GuidPartitionTableHeader_t ** gpt,
+             GuidPartitionEntry_t ** ptes)
+{
+	int rc = 0;		/* default to not valid */
+	uint32_t crc, origcrc;
+	PED_ASSERT(gpt != NULL, return 0);
+	PED_ASSERT(ptes != NULL, return 0);
+        // printf("IsGuidPartitionTableValid(%llx)\n", lba);
+	if (!(*gpt = gpt_read_header(dev, lba)))
+		return rc;
+	/* Check the GUID Partition Table Signature */
+	if ((*gpt)->Signature != GUID_PT_HEADER_SIGNATURE) {
+                /* 
+                printf("GUID Partition Table Header Signature is wrong: %llx != %llx\n",
+			(*gpt)->Signature, GUID_PT_HEADER_SIGNATURE);
+                */
+		ped_free(*gpt);
+		*gpt = NULL;
+		return rc;
+	}
+
+	/* Check the GUID Partition Table Header CRC */
+	origcrc = (*gpt)->HeaderCRC32;
+	(*gpt)->HeaderCRC32 = 0;
+	crc = efi_crc32(*gpt, (*gpt)->HeaderSize);
+	if (crc != origcrc) {
+		printf( "GPT Header CRC check failed, %x != %x.\n", origcrc, crc);
+		(*gpt)->HeaderCRC32 = origcrc;
+		gpt_print_header(*gpt);
+		ped_free(*gpt);
+		*gpt = NULL;
+		return rc;
+	}
+	(*gpt)->HeaderCRC32 = origcrc;
+	/* Check that the MyLBA entry points to the LBA
+	   that contains the GPT we read */
+	if ((*gpt)->MyLBA != lba) {
+		// printf( "MyLBA %llx != lba %llx.\n", (*gpt)->MyLBA, lba);
+		ped_free(*gpt);
+		*gpt = NULL;
+		return rc;
+	}
+
+	if (!(*ptes = gpt_read_part_entries(dev, *gpt))) {
+		ped_free(*gpt);
+		*gpt = NULL;
+		return rc;
+	}
+
+
+	/* Check the GUID Partition Entry Array CRC */
+	crc = efi_crc32(*ptes, (*gpt)->NumberOfPartitionEntries *
+			   (*gpt)->SizeOfPartitionEntry);
+	if (crc != (*gpt)->PartitionEntryArrayCRC32) {
+		// printf("GUID Partitition Entry Array CRC check failed.\n");
+		ped_free(*gpt);
+		*gpt = NULL;
+		ped_free(*ptes);
+		*ptes = NULL;
+		return rc;
+	}
+
+	/* We're done, all's well */
+	return 1;
+}
+
+/************************************************************
+ * gpt_write_pmbr()
+ * Requires:
+ *  - dev
+ * Modifies:
+ *  - dev
+ * Returns:
+ *   1 on success
+ *   0 on error
+ ************************************************************/
+
+
+static int
+gpt_write_pmbr(PedDevice * dev)
+{
+	LegacyMBR_t pmbr;
+	memset(&pmbr, 0, sizeof(pmbr));
+	pmbr.Signature = PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE);
+	pmbr.PartitionRecord[0].OSType      = EFI_PMBR_OSTYPE_EFI_GPT;
+	pmbr.PartitionRecord[0].EndHead     = 0xFE;
+	pmbr.PartitionRecord[0].EndSector   = 0xFF;
+	pmbr.PartitionRecord[0].EndTrack    = 0xFF;
+	pmbr.PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32(1);
+	pmbr.PartitionRecord[0].SizeInLBA   = PED_CPU_TO_LE32(last_lba(dev));
+
+	return ped_device_write(dev, &pmbr, GPT_PMBR_LBA, GPT_PMBR_SECTORS);
+}
+
+
+
+/************************************************************n
+ * gpt_update_headers()
+ * Updates the CRC fields for both primary and alternate GPTs
+ *
+ */
+static int
+gpt_update_headers(GuidPartitionTableHeader_t *pgpt,
+                   GuidPartitionTableHeader_t *agpt,
+                   GuidPartitionEntry_t *ptes)
+{
+
+        // printf("in UpdateGuidPartitionTableHeaders()\n");
+        PED_ASSERT(pgpt != NULL, return 0);
+        PED_ASSERT(agpt != NULL, return 0);
+        PED_ASSERT(ptes != NULL, return 0);
+
+	pgpt->PartitionEntryArrayCRC32 =
+                agpt->PartitionEntryArrayCRC32 =
+                efi_crc32(ptes, pgpt->NumberOfPartitionEntries *
+                          pgpt->SizeOfPartitionEntry);
+        
+	pgpt->HeaderCRC32 = 0;
+	pgpt->HeaderCRC32 = efi_crc32(pgpt, pgpt->HeaderSize);
+	agpt->HeaderCRC32 = 0;
+	agpt->HeaderCRC32 = efi_crc32(agpt, agpt->HeaderSize);
+        return 1;
+}
+
+
+
+static int
+gpt_write_new(PedDevice *dev)
+{
+	uint64_t size;
+	uuid_t uuid;
+	GuidPartitionTableHeader_t gpt, agpt;
+	GuidPartitionEntry_t ptes[GPT_DEFAULT_RESERVED_PARTITION_ENTRIES];
+	int count;
+
+        // printf("in CreateNewGuidPartitionTableHeader()\n");
+	memset(&gpt, 0, sizeof(gpt));
+	gpt.Signature = GUID_PT_HEADER_SIGNATURE;
+	gpt.Revision = GUID_PT_HEADER_REVISION_V1_02;
+	gpt.HeaderSize = 92; /* per 1.02 spec */
+	gpt.MyLBA = 1;
+	gpt.AlternateLBA = last_lba(dev);
+	gpt.FirstUsableLBA = (GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE /
+                              dev->sector_size) + 2;
+	gpt.LastUsableLBA =
+                gpt.AlternateLBA -
+                (GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE /
+                 dev->sector_size) - 1;
+	uuid_generate(uuid);
+	memcpy(&(gpt.DiskGUID), uuid, sizeof(uuid));
+	gpt.PartitionEntryLBA = 2;
+	gpt.NumberOfPartitionEntries = GPT_DEFAULT_RESERVED_PARTITION_ENTRIES;
+	gpt.SizeOfPartitionEntry = sizeof(GuidPartitionEntry_t);
+
+	memset(ptes, 0,
+	       gpt.NumberOfPartitionEntries * gpt.SizeOfPartitionEntry);
+
+	/* Fix up Alternate GPT */
+	memcpy(&agpt, &gpt, sizeof(gpt));
+	agpt.MyLBA        = gpt.AlternateLBA;
+	agpt.AlternateLBA = gpt.MyLBA;
+	agpt.PartitionEntryLBA = agpt.MyLBA -
+                (GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE /
+                 dev->sector_size);
+
+        if (!gpt_update_headers(&gpt, &agpt, ptes))
+                return 0;
+
+	/* Before the writes */
+	/* Write PTH and PTEs */
+	if (!gpt_write_header(dev, &gpt))
+		return 0;
+	if (!gpt_write_part_entries(dev, &gpt, ptes))
+		return 0;
+
+
+	/* Write Alternate PTH & PTEs */
+	if (!gpt_write_part_entries(dev, &agpt, ptes))
+		return 0;
+	if (!gpt_write_header(dev, &agpt))
+		return 0;
+
+	return 1;
+}
+
+
+
+static int
+gpt_write_new_disk(PedDevice * dev)
+{
+	if (!gpt_write_pmbr(dev))
+		return 0;
+	if (!gpt_write_new(dev))
+		return 0;
+	return 1;
+}
+
+
+/************************************************************
+ * gpt_fix_broken_header()
+ * Uses values from alternate GPT and puts them in primary GPT.
+ * Requires:
+ * pgpt, agpt, ptes.
+ *  
+ * Modifies:
+ * pgpt
+ * 
+ * Returns:
+ *   1 if valid
+ *   0 on error
+ ************************************************************/
+
+static int
+gpt_fix_broken_header(PedDevice *dev,
+                      GuidPartitionTableHeader_t **badgpt,
+                      GuidPartitionTableHeader_t *goodgpt,
+                      GuidPartitionEntry_t     *ptes)
+{
+
+        PED_ASSERT(badgpt != NULL, return 0);
+        PED_ASSERT(goodgpt != NULL, return 0);
+        PED_ASSERT(ptes != NULL, return 0);
+
+        printf("GPT: Fixing broken header.\n");
+
+	*badgpt = (GuidPartitionTableHeader_t *)
+                ped_malloc(sizeof(GuidPartitionTableHeader_t));
+	if (!*badgpt) return 0;
+        memset(*badgpt, 0, sizeof(**badgpt));
+
+	memcpy(*badgpt, goodgpt, sizeof(*goodgpt));
+
+	/* Change badgpt values */
+	(*badgpt)->MyLBA        = goodgpt->AlternateLBA;
+	(*badgpt)->AlternateLBA = goodgpt->MyLBA;
+
+        
+        if ((*badgpt)->MyLBA == 1) 
+                (*badgpt)->PartitionEntryLBA = (*badgpt)->MyLBA + 1;
+        else
+                (*badgpt)->PartitionEntryLBA = (*badgpt)->MyLBA - 
+                        (GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE /
+                         dev->sector_size);
+        
+        return gpt_update_headers(*badgpt, goodgpt, ptes);
+}
+
+
+
+
+static void
+gpt_print_legacy_part(PartitionRecord_t * pr, int i)
+{
+	if (!pr)
+		return;
+	if (!(pr->OSType))
+		return;
+	printf("Legacy Partition Record %d\n", i);
+	printf("\tBootInd %02x", pr->BootIndicator);
+	printf("\tSHead %02x", pr->StartHead);
+	printf("\tSSector %02x", pr->StartSector);
+	printf("\tSTrack %02x\n", pr->StartTrack);
+	printf("\tOSType %02x", pr->OSType);
+	printf("\tEHead %02x", pr->EndHead);
+	printf("\tESector %02x", pr->EndSector);
+	printf("\tETrack %02x\n", pr->EndTrack);
+	printf("\tStartingLBA : %x", pr->StartingLBA);
+	printf("\tSizeInLBA : %x\n", pr->SizeInLBA);
+	return;
+}
+
+static void
+gpt_print_mbr(LegacyMBR_t * mbr)
+{
+	int i;
+	if (!mbr)
+		return;
+	if (!is_legacy_mbr_valid(mbr)) {
+		printf("MBR is invalid.\n");
+		return;
+	}
+
+	printf("UniqueMBRSignature: %x\n", mbr->UniqueMBRSignature);
+	for (i = 0; i < 4; i++)
+		gpt_print_legacy_part(&(mbr->PartitionRecord[i]), i);
+	printf("Signature: %x\n", mbr->Signature);
+	return;
+}
+
+
+
+/************************************************************
+ * gpt_find_valid()
+ * Requires:
+ *  - dev 
+ *  - pgpt is a GPTH if it's valid
+ *  - agpt is a GPTH if it's valid
+ *  - ptes is a PTE
+ * Modifies:
+ *  - gpt & ptes
+ * Returns:
+ *   1 if valid
+ *   0 on error
+ ************************************************************/
+static int
+gpt_find_valid(const PedDevice * dev,
+               GuidPartitionTableHeader_t ** pgpt,
+               GuidPartitionTableHeader_t ** agpt,
+               GuidPartitionEntry_t       ** ptes)
+{
+	int rc = 0;
+	GuidPartitionEntry_t *pptes = NULL, *aptes = NULL;
+	uint64_t lastlba;
+
+        PED_ASSERT(dev  != NULL, return 0);
+        PED_ASSERT(pgpt != NULL, return 0);
+        PED_ASSERT(agpt != NULL, return 0);
+        PED_ASSERT(ptes != NULL, return 0);
+
+	lastlba = last_lba(dev);
+	/* Check the Primary GPT */
+	rc = gpt_is_valid(dev, 1, pgpt, &pptes);
+	if (rc) {
+		/* Primary GPT is OK, check the alternate and warn if bad */
+		rc = gpt_is_valid(dev, (*pgpt)->AlternateLBA,
+                                  agpt, &aptes);
+
+		if (!rc) {
+                        *agpt = NULL;
+                        printf("Alternate GPT is invalid, using primary GPT.\n");
+		}
+		if (aptes) ped_free(aptes);
+		*ptes = pptes;
+		return 1;
+	} /* if primary is valid */
+	else {
+		/* Primary GPT is bad, check the Alternate GPT */
+                *pgpt = NULL;
+		rc = gpt_is_valid(dev, lastlba,
+                                  agpt, &aptes);
+		if (rc) {
+			/* Primary is bad, alternate is good.
+			   Return values from the alternate and warn.
+			 */
+			printf
+			    ("Primary GPT is invalid, using alternate GPT.\n");
+			*ptes = aptes;
+			return 1;
+		}
+	}
+	/* Both primary and alternate GPTs are bad.
+	 * This isn't our disk, return 0.
+	 */
+        *pgpt = NULL;
+        *agpt = NULL;
+        *ptes = NULL;
+	return 0;
+}
+
+#ifdef GPT_DEBUG
+static void
+print_disk_info(PedDevice *dev)
+{
+	unsigned int i;
+	LegacyMBR_t mbr;
+	GuidPartitionTableHeader_t *pgpt = NULL, *agpt = NULL, *gpt = NULL;
+	GuidPartitionEntry_t *pte = NULL, zeropte;
+
+	memset(&zeropte, 0, sizeof(zeropte));
+	if (!ped_device_read(dev, &mbr, GPT_PMBR_LBA, GPT_PMBR_SECTORS)) {
+		printf("print_disk_info error: ped_device_read(mbr) error.\n");
+		return;
+	}
+
+	if (mbr.PartitionRecord[0].OSType == EFI_PMBR_OSTYPE_EFI_GPT) {
+		/* This is an EFI GPT disk */
+		if (!ped_device_read(dev, &pgpt,
+                                     GPT_PRIMARY_HEADER_LBA,
+                                     GPT_HEADER_SECTORS)) {
+			printf("print_disk_info error: ped_device_read(gpt) error.\n");
+			return;
+		}
+		printf("This is an EFI GPT disk.\n");
+                if (gpt_find_valid(dev, &pgpt, &agpt, &pte)) {
+                        if (pgpt) gpt = pgpt;
+                        else if (agpt) gpt = agpt;
+                }
+                else {
+			printf("GUID Partition Table is invalid.\n");
+			return;
+		}
+		for (i = 0; pte && i < gpt->NumberOfPartitionEntries; i++) {
+			/* Partition entry is unused if all bytes are 0 */
+			if (memcmp(&zeropte, &pte[i], sizeof(zeropte)))
+				gpt_print_part_entry(&pte[i], i);
+		}
+		if (pgpt) ped_free(pgpt);
+		if (agpt) ped_free(agpt);
+		if (pte)  ped_free(pte);
+	} else {
+		printf("This is not an EFI GPT disk.  Try using vanilla msdos partition tables.\n");
+	}
+	return;
+}
+#endif
+
+
+
+
+
+void
+ped_disk_gpt_init()
+{
+	PED_ASSERT(sizeof(GuidPartitionTableHeader_t) == 512, return);
+	PED_ASSERT(sizeof(GuidPartitionEntryAttributes_t) == 8, return);
+	PED_ASSERT(sizeof(GuidPartitionEntry_t) == 128, return);
+
+	ped_register_disk_type(&gpt_disk_type);
+}
+
+void
+ped_disk_gpt_done()
+{
+	ped_unregister_disk_type(&gpt_disk_type);
+}
+
+static int
+gpt_probe(const PedDevice * dev)
+{
+	GuidPartitionTableHeader_t *pgpt = NULL, *agpt = NULL;
+	GuidPartitionEntry_t *ptes = NULL;
+
+	PED_ASSERT(dev != NULL, return 0);
+
+	if (!ped_device_open((PedDevice *) dev))
+		return 0;
+
+	if (!(gpt_find_valid(dev, &pgpt, &agpt, &ptes))) {
+		ped_device_close((PedDevice *) dev);
+		return 0;
+	}
+
+	ped_device_close((PedDevice *) dev);
+
+	if (pgpt) ped_free(pgpt);
+	if (agpt) ped_free(agpt);
+	if (ptes) ped_free(ptes);
+	return 1;
+}
+
+static PedDisk *
+gpt_open(PedDevice * dev)
+{
+	PedDisk *disk;
+
+	PED_ASSERT(dev != NULL, return 0);
+
+	if (!gpt_probe(dev))
+		goto error;
+        
+
+	ped_device_open((PedDevice *) dev);
+
+	disk = ped_disk_alloc(dev, &gpt_disk_type);
+
+	if (!disk)
+		goto error;
+
+	if (!gpt_read(disk))
+          goto error_free_disk_specific;
+
+	return disk;
+
+      error_free_disk_specific:
+        ped_free(disk->disk_specific);
+      error_free_disk:
+	ped_free(disk);
+      error:
+	return NULL;
+}
+
+static PedDisk *
+gpt_create(PedDevice * dev)
+{
+        PedDisk *newdisk;
+	PED_ASSERT(dev != NULL, return 0);
+
+	if (!ped_device_open(dev))
+		goto error;
+
+
+	gpt_write_new_disk(dev);
+
+	if (!ped_device_sync(dev))
+		goto error_close_dev;
+
+	ped_device_close(dev);
+        newdisk = gpt_open(dev);
+        return newdisk;
+
+      error_close_dev:
+	ped_device_close(dev);
+      error:
+	return 0;
+}
+
+static int
+gpt_close(PedDisk * disk)
+{
+	PED_ASSERT(disk != NULL, return 0);
+
+	ped_device_close(disk->dev);
+	ped_disk_delete_all(disk);
+        if (disk->disk_specific) ped_free(disk->disk_specific);
+	ped_free(disk);
+	return 1;
+}
+
+
+
+
+
+
+static int
+gpt_read(PedDisk * disk)
+{
+	PedPartition *part;
+	unsigned int i;
+        GPTDiskData *gpt_disk_data;
+        GPTPartitionData *gpt_part_data;
+	PedConstraint*		constraint_exact;
+        efi_guid_t unused = UNUSED_ENTRY_GUID;
+
+	PED_ASSERT(disk != NULL, return 0);
+	PED_ASSERT(disk->dev != NULL, return 0);
+
+
+	ped_disk_delete_all(disk);
+
+        if (!disk->disk_specific) gpt_new(disk);
+        PED_ASSERT(disk->disk_specific != NULL, return 0);
+        gpt_disk_data = disk->disk_specific;
+
+
+	if (!gpt_find_valid(disk->dev, &(gpt_disk_data->pgpt), &(gpt_disk_data->agpt), &(gpt_disk_data->ptes)))
+		return 0;
+
+        /* If one of the gpts are broken, fix it. */
+        if (!gpt_disk_data->pgpt) {
+                gpt_fix_broken_header(disk->dev,
+                                      &gpt_disk_data->pgpt,
+                                      gpt_disk_data->agpt,
+                                      gpt_disk_data->ptes);
+        }
+        else if (!gpt_disk_data->agpt) {
+                gpt_fix_broken_header(disk->dev,
+                                      &gpt_disk_data->agpt,
+                                      gpt_disk_data->pgpt,
+                                      gpt_disk_data->ptes);
+        }
+        
+	for (i = 0; i < gpt_disk_data->pgpt->NumberOfPartitionEntries; i++) {
+                
+                if (!efi_guidcmp(gpt_disk_data->ptes[i].PartitionTypeGuid,
+                                 unused)) continue;
+
+		part = ped_partition_alloc(disk, PED_PARTITION_PRIMARY, NULL,
+                                           gpt_disk_data->ptes[i].StartingLBA,
+                                           gpt_disk_data->ptes[i].EndingLBA);
+		if (!part)
+			return 0;
+
+		part->fs_type = ped_file_system_probe(&part->geom);
+                part->num = i+1;
+
+                gpt_part_data = part->disk_specific =
+                        ped_malloc(sizeof(GPTPartitionData));
+                if (!gpt_part_data) {
+                        ped_free(part);
+                        return 0;
+                }
+                memset(gpt_part_data, 0, sizeof(*gpt_part_data));
+                
+                gpt_part_data->pte  = &(gpt_disk_data->ptes[i]);
+
+		constraint_exact = ped_constraint_exact (&part->geom);
+		if (!ped_disk_add_partition(disk, part, constraint_exact)) {
+			ped_free(gpt_part_data);
+                        ped_free(part);
+                        return 0;
+                }
+		ped_constraint_destroy (constraint_exact);
+
+	}
+	return 1;
+}
+
+
+static int
+gpt_write(PedDisk * disk)
+{
+
+        GPTDiskData *gpt_disk_data;
+        PedPartition *part = NULL;
+
+	PED_ASSERT(disk != NULL, return 0);
+	PED_ASSERT(disk->dev != NULL, return 0);
+        PED_ASSERT(disk->disk_specific != NULL, return 0);
+        gpt_disk_data = disk->disk_specific;
+
+        if (!gpt_write_pmbr(disk->dev)) return 0;
+
+        gpt_update_headers(gpt_disk_data->pgpt,
+                           gpt_disk_data->agpt,
+                           gpt_disk_data->ptes);
+
+	/* Write PTH and PTEs */
+	if (!gpt_write_header(disk->dev, gpt_disk_data->pgpt))
+		return 0;
+	if (!gpt_write_part_entries(disk->dev, gpt_disk_data->pgpt, gpt_disk_data->ptes))
+		return 0;
+
+
+	/* Write Alternate PTH & PTEs */
+	if (!gpt_write_part_entries(disk->dev, gpt_disk_data->agpt, gpt_disk_data->ptes))
+		return 0;
+	if (!gpt_write_header(disk->dev, gpt_disk_data->agpt))
+		return 0;
+
+	if (!ped_device_sync(disk->dev))
+		return 0;
+
+	return 1;
+}
+
+
+
+static int
+add_metadata_part(PedDisk * disk, PedPartitionType type, PedSector start,
+		  PedSector length)
+{
+	PedPartition *new_part;
+        PedConstraint * constraint_exact;
+	PED_ASSERT(disk != NULL, return 0);
+
+
+	new_part =
+	    ped_partition_new(disk, type | PED_PARTITION_METADATA, NULL,
+			      start, start + length - 1);
+	if (!new_part)
+		goto error;
+
+        constraint_exact = ped_constraint_exact (&new_part->geom);
+
+	if (!ped_disk_add_partition(disk, new_part, constraint_exact))
+		goto error_destroy_new_part;
+
+	return 1;
+
+      error_destroy_new_part:
+	ped_partition_destroy(new_part);
+      error:
+	return 0;
+}
+
+static PedPartition *
+gpt_partition_new(const PedDisk *disk,
+                  PedPartitionType part_type,
+                  const PedFileSystemType* fs_type,
+                  PedSector start,
+                  PedSector end)
+{
+        unsigned int i;
+	uuid_t uuid;
+	efi_guid_t unused_entry_guid = UNUSED_ENTRY_GUID;
+        GPTDiskData *gpt_disk_data;
+        GPTPartitionData *gpt_part_data;
+        PedPartition *part;
+        
+        PED_ASSERT(disk != NULL, return NULL);
+
+
+	part = ped_partition_alloc (disk, part_type, fs_type, start, end);
+	if (!part) return NULL;
+
+        if (part_type != PED_PARTITION_PRIMARY)
+                return part;
+
+#if 0
+        if (!ped_disk_check_overlap(disk, part)) {
+		ped_exception_throw (
+			PED_EXCEPTION_ERROR,
+			PED_EXCEPTION_CANCEL,
+			_("The new partition overlaps with another "
+			  "partition."));
+                ped_free(part);
+                return NULL;
+        }
+#endif
+
+        PED_ASSERT(disk->disk_specific != NULL, return NULL);
+
+        gpt_disk_data = disk->disk_specific;
+
+
+        PED_ASSERT(gpt_disk_data->pgpt != NULL, return NULL);
+        PED_ASSERT(gpt_disk_data->agpt != NULL, return NULL);
+        PED_ASSERT(gpt_disk_data->ptes != NULL, return NULL);
+
+
+        for (i = 0; i < gpt_disk_data->pgpt->NumberOfPartitionEntries; i++) {
+		if (!efi_guidcmp
+		    (gpt_disk_data->ptes[i].PartitionTypeGuid, unused_entry_guid)) {
+			break;
+		}
+	}
+	/* No unused entries */
+	if (i == gpt_disk_data->pgpt->NumberOfPartitionEntries){
+                ped_free(part);
+		return NULL;
+        }
+
+        part->num = i + 1;
+	gpt_disk_data->ptes[i].StartingLBA = part->geom.start;
+	gpt_disk_data->ptes[i].EndingLBA = part->geom.end;
+	uuid_generate(uuid);
+	memcpy(&(gpt_disk_data->ptes[i].UniquePartitionGuid), uuid, sizeof(uuid));
+
+        gpt_disk_data->ptes[i].PartitionTypeGuid = PARTITION_BASIC_DATA_GUID;
+
+        if (fs_type && fs_type->name && !strcmp(fs_type->name, "linux-swap"))
+                gpt_disk_data->ptes[i].PartitionTypeGuid = 
+                        PARTITION_SWAP_GUID;
+
+        
+        gpt_part_data = part->disk_specific =
+                ped_malloc(sizeof(GPTPartitionData));
+        if (!gpt_part_data) return part;
+        memset(gpt_part_data, 0, sizeof(*gpt_part_data));
+
+        gpt_part_data->pte = &(gpt_disk_data->ptes[i]);
+
+        return part;
+}
+
+static void
+gpt_partition_destroy(PedPartition *part)
+{
+        GPTPartitionData *gpt_part_data;
+
+        PED_ASSERT(part != NULL, return);
+
+        if (part->type != PED_PARTITION_PRIMARY)
+                return;
+
+        PED_ASSERT(part->disk_specific != NULL, return);
+        gpt_part_data = part->disk_specific;
+        if (gpt_part_data->pte)
+                memset(gpt_part_data->pte, 0, sizeof(*(gpt_part_data->pte)));
+
+        ped_free(part->disk_specific);
+        part->disk_specific = NULL;
+        ped_free(part);
+}
+
+/**********************************************************
+ * Allocate metadata partitions for the GPTH and PTES.
+ *
+ */
+static int
+_alloc_metadata_unknown(PedDisk * disk)
+{
+        uint64_t pte_reserved_blocks;
+	PED_ASSERT(disk != NULL, return 0);
+        PED_ASSERT(disk->dev != NULL, return 0);
+
+        pte_reserved_blocks = 
+                (GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE /
+                 disk->dev->sector_size);
+
+        
+	/* metadata at the start of the disk includes the MBR */
+	if (!add_metadata_part(disk, PED_PARTITION_PRIMARY,
+			       GPT_PMBR_LBA,
+                               GPT_PMBR_SECTORS
+                               + GPT_HEADER_SECTORS
+                               + pte_reserved_blocks))
+		return 0;
+
+	/* metadata at the end of the disk */
+	if (!add_metadata_part(disk, PED_PARTITION_PRIMARY,
+			       last_lba(disk->dev) -
+                               pte_reserved_blocks,
+                               GPT_HEADER_SECTORS
+                               + pte_reserved_blocks))
+                return 0;
+
+        return 1;
+}
+
+
+/**********************************************************
+ * Allocate metadata partitions for the GPTH and PTES
+ * when we know the actual metadata size
+ */
+static int
+_alloc_metadata_known(PedDisk * disk)
+{
+	int i;
+	PedSector gptlength, pteslength = 0;
+        GPTDiskData *gpt_disk_data;
+        
+	PED_ASSERT(disk != NULL, return 0);
+	PED_ASSERT(disk->dev != NULL, return 0);
+        PED_ASSERT(disk->disk_specific != NULL, return 0);
+        gpt_disk_data = disk->disk_specific;
+
+	/* allocate space for the header */
+	gptlength = gpt_disk_data->pgpt->HeaderSize / disk->dev->sector_size;
+	if (gpt_disk_data->pgpt->HeaderSize % disk->dev->sector_size)
+		gptlength++;
+	/* allocate space for the ptes */
+	pteslength =
+	    (gpt_disk_data->pgpt->NumberOfPartitionEntries *
+	     gpt_disk_data->pgpt->SizeOfPartitionEntry) /
+                disk->dev->sector_size;
+	if ((gpt_disk_data->pgpt->NumberOfPartitionEntries *
+	     gpt_disk_data->pgpt->SizeOfPartitionEntry) %
+            disk->dev->sector_size)
+		pteslength++;
+
+	/* metadata at the start of the disk includes the MBR */
+	if (!add_metadata_part(disk, PED_PARTITION_PRIMARY,
+			       GPT_PMBR_LBA,
+                               GPT_PMBR_SECTORS + gptlength + pteslength))
+		return 0;
+
+	/* metadata at the end of the disk */
+	if (!add_metadata_part(disk, PED_PARTITION_PRIMARY,
+			       last_lba(disk->dev) - gptlength - pteslength + 1,
+                               gptlength + pteslength))
+                return 0;
+
+        return 1;
+}
+
+
+
+
+/**********************************************************
+ * Allocate metadata partitions for the GPTH and PTES.
+ *
+ */
+static int
+gpt_alloc_metadata(PedDisk * disk)
+{
+        GPTDiskData *gpt_disk_data;
+	PED_ASSERT(disk != NULL, return 0);
+	PED_ASSERT(disk->dev != NULL, return 0);
+
+        gpt_disk_data = disk->disk_specific;
+
+	if (!gpt_disk_data ||
+            !gpt_disk_data->pgpt ||
+            !gpt_disk_data->agpt ||
+            !gpt_disk_data->ptes)
+                return _alloc_metadata_unknown(disk);
+        
+        return _alloc_metadata_known(disk);
+}
+
+/************************************************************
+ * gpt_partition_enumerate()
+ * Requires:
+ *  - part 
+ * Modifies:
+ *  - part->num
+ * Returns:
+ *   1 if valid
+ *   0 on error
+ * Actions:
+ *   Does nothing, as the read/new/destroy functions maintain
+ *   part->num.
+ *   
+ *   
+ ************************************************************/
+static int
+gpt_partition_enumerate(PedPartition * part)
+{
+        return 1;
+}
+
+
+/************************************************************
+ * gpt_clobber()
+ * Requires:
+ *  - dev 
+ * Modifies:
+ *  - dev
+ * Returns: (per gpt_msdos.c)
+ *   1 if valid
+ *   0 on error
+ * Actions:
+ *   This writes zeros to the PMBR and the primary and
+ *   alternate GPTHs and PTEs.
+ ************************************************************/
+static int
+gpt_clobber(PedDevice * dev)
+{
+	LegacyMBR_t pmbr;
+        GuidPartitionTableHeader_t gpt;
+        GuidPartitionEntry_t ptes[GPT_DEFAULT_RESERVED_PARTITION_ENTRIES];
+        uint64_t lastLBA, pte_sectors;
+        
+
+        PED_ASSERT (dev != NULL, return 0);
+        PED_ASSERT (gpt_probe(dev), return 0);
+
+        if (!ped_device_open(dev)) return 0;
+
+        PED_ASSERT(dev->sector_size != 0, return 0);
+        pte_sectors = GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE /
+                dev->sector_size;
+
+
+	memset(&pmbr, 0, sizeof(pmbr));
+        memset(&gpt, 0, sizeof(gpt));
+        memset(ptes, 0, sizeof(ptes));
+
+        lastLBA = last_lba(dev);
+               
+	if (!ped_device_write(dev, &pmbr, GPT_PMBR_LBA, GPT_PMBR_SECTORS)) {
+		printf("gpt_clobber(): Unable to write empty PMBR.\n");
+		return 0;
+	}
+	if (!ped_device_write(dev, &gpt,
+                              GPT_PRIMARY_HEADER_LBA,
+                              GPT_HEADER_SECTORS)) {
+		printf("gpt_clobber(): Unable to write empty PGPTH.\n");
+		return 0;
+	}
+        if (!ped_device_write(dev, &ptes,
+                              GPT_PRIMARY_PART_TABLE_LBA,
+                              pte_sectors)) {
+		printf("gpt_clobber(): Unable to write empty PPTES.\n");
+		return 0;
+	}
+        
+
+        if (!ped_device_write(dev, &ptes, lastLBA - pte_sectors,
+                              pte_sectors)) {
+		printf("gpt_clobber(): Unable to write empty APTES.\n");
+		return 0;
+	}
+        
+	if (!ped_device_write(dev, &gpt, lastLBA, GPT_HEADER_SECTORS)) {
+		printf("gpt_clobber(): Unable to write empty AGPTH.\n");
+		return 0;
+	}
+        return 1;
+}
+
+
+static int
+gpt_partition_set_flag(PedPartition *part,
+                       PedPartitionFlag flag,
+                       int state)
+{
+        GPTPartitionData *gpt_part_data;
+        PED_ASSERT(part != NULL, return 0);
+        PED_ASSERT(part->disk_specific != NULL, return 0);
+        gpt_part_data = part->disk_specific;
+        PED_ASSERT(gpt_part_data->pte != NULL, return 0);
+
+
+	switch (flag) {
+	case PED_PARTITION_RAID:
+                if (state)
+                        gpt_part_data->pte->PartitionTypeGuid =
+                                PARTITION_RAID_GUID;
+                else
+                        gpt_part_data->pte->PartitionTypeGuid =
+                                PARTITION_BASIC_DATA_GUID;
+                break;
+	case PED_PARTITION_LVM:
+                if (state)
+                        gpt_part_data->pte->PartitionTypeGuid =
+                                PARTITION_LVM_GUID;
+                else
+                        gpt_part_data->pte->PartitionTypeGuid =
+                                PARTITION_BASIC_DATA_GUID;
+
+                break;
+	case PED_PARTITION_BOOT:
+                if (state)
+                        gpt_part_data->pte->PartitionTypeGuid = 
+                                PARTITION_SYSTEM_GUID;
+                else
+                        gpt_part_data->pte->PartitionTypeGuid = 
+                                PARTITION_BASIC_DATA_GUID;
+
+                break;
+	case PED_PARTITION_LBA:
+                if (!state) return 0;
+		break;
+	case PED_PARTITION_HIDDEN:
+	default:
+		return 0;
+        }
+
+        if (part->fs_type && part->fs_type->name &&
+            !strcmp(part->fs_type->name, "linux-swap"))
+                        gpt_part_data->pte->PartitionTypeGuid = 
+                                PARTITION_SWAP_GUID;
+                
+
+        return 1;
+}
+
+static int
+gpt_partition_get_flag(const PedPartition *part,
+                       PedPartitionFlag flag)
+{
+        GPTPartitionData *gpt_part_data = NULL;
+        PED_ASSERT(part->disk_specific != NULL, return 0);
+        gpt_part_data = part->disk_specific;
+
+	switch (flag) {
+	case PED_PARTITION_RAID:
+                return (!efi_guidcmp(gpt_part_data->pte->PartitionTypeGuid, 
+                                     PARTITION_RAID_GUID));
+	case PED_PARTITION_LVM:
+                return (!efi_guidcmp(gpt_part_data->pte->PartitionTypeGuid, 
+                                     PARTITION_LVM_GUID));
+	case PED_PARTITION_BOOT:
+                return (!efi_guidcmp(gpt_part_data->pte->PartitionTypeGuid,
+                                     PARTITION_SYSTEM_GUID));
+	case PED_PARTITION_LBA:
+		return 1;
+	case PED_PARTITION_HIDDEN:
+	default:
+		return 0;
+        }
+        return 0;
+}
+
+static int
+gpt_partition_is_flag_available(const PedPartition * part,
+                                PedPartitionFlag flag)
+{
+	switch (flag) {
+	case PED_PARTITION_RAID:
+	case PED_PARTITION_LVM:
+	case PED_PARTITION_LBA:
+	case PED_PARTITION_BOOT:
+		return 1;
+	case PED_PARTITION_HIDDEN:
+	default:
+		return 0;
+        }
+        return 0;
+}
+
+static void
+gpt_partition_set_name(PedPartition *part,
+                       const char *name)
+{
+        unsigned int i;
+        GPTPartitionData *gpt_part_data = NULL;
+        PED_ASSERT(part->disk_specific != NULL, return);
+        gpt_part_data = part->disk_specific;
+
+        if (!gpt_part_data->pte) return;
+
+        memset(gpt_part_data->pte->PartitionName, 0, sizeof(gpt_part_data->pte->PartitionName));
+
+        for (i=0; i < (72 / sizeof(efi_char16_t)) && i < strlen(name); i++) {
+                gpt_part_data->pte->PartitionName[i] = name[i];
+        }
+        return;
+}
+static const char *
+gpt_partition_get_name (const PedPartition * part)
+{
+        /* The name is stored in Unicode in the GPT entry */
+        char *name;
+        unsigned int i, namelen = (72 / sizeof(efi_char16_t));
+        GPTPartitionData *gpt_part_data = NULL;
+        PED_ASSERT(part->disk_specific != NULL, return 0);
+        gpt_part_data = part->disk_specific;
+
+        if (!gpt_part_data->pte) return NULL;
+
+        name = ped_malloc(namelen);
+        if (!name) return NULL;
+
+        memset(name, 0, namelen);
+
+        for (i=0; i < namelen ; i++) {
+                name[i] = gpt_part_data->pte->PartitionName[i];
+        }
+
+        return name;
+}
+
+
+static int
+gpt_get_max_primary_partition_count(const PedDisk *disk)
+{
+        int rc = GPT_DEFAULT_RESERVED_PARTITION_ENTRIES; /* 128 */
+        GPTDiskData *gpt_disk_data;
+        PED_ASSERT(disk != NULL, return 0);
+        gpt_disk_data = disk->disk_specific;
+        
+        if (gpt_disk_data  && gpt_disk_data->pgpt)
+                rc = gpt_disk_data->pgpt->NumberOfPartitionEntries;
+        return rc;
+}
+
+
+static PedConstraint*
+_non_metadata_constraint (PedDisk* disk)
+{
+	PedGeometry	max_geom;
+        GPTDiskData    *gpt_disk_data;
+        GuidPartitionTableHeader_t *gpt;
+
+	PED_ASSERT(disk != NULL, return 0);
+	PED_ASSERT(disk->dev != NULL, return 0);
+        PED_ASSERT(disk->disk_specific != NULL, return 0);
+        gpt_disk_data = disk->disk_specific;
+        PED_ASSERT(gpt_disk_data->pgpt != NULL, return 0);
+        gpt = gpt_disk_data->pgpt;
+
+        /* Alignments can be on any sector */
+        /* Geometry must reside within the usable LBAs */
+	if (!ped_geometry_init (&max_geom, disk,
+                                gpt->FirstUsableLBA,
+                                gpt->LastUsableLBA - gpt->FirstUsableLBA + 1))
+		return NULL;
+
+	return ped_constraint_new (ped_alignment_any, ped_alignment_any,
+                                   &max_geom,
+				   &max_geom, 1);
+}
+
+/*  _try_constraint() copied verbatim from disk_mac.c
+ *  per Clausen's recommendation
+ */
+
+static int
+_try_constraint (PedPartition* part, const PedConstraint* external,
+		 PedConstraint* internal)
+{
+	PedConstraint*		intersection;
+	PedGeometry*		solution;
+
+	intersection = ped_constraint_intersect (external, internal);
+	ped_constraint_destroy (internal);
+	if (!intersection)
+		goto fail;
+
+	solution = ped_constraint_solve_nearest (intersection, &part->geom);
+	if (!solution)
+		goto fail_free_intersection;
+	ped_geometry_set (&part->geom, solution->start, solution->length);
+	ped_geometry_destroy (solution);
+	ped_constraint_destroy (intersection);
+	return 1;
+
+fail_free_intersection:
+	ped_constraint_destroy (intersection);
+fail:
+	return 0;
+}
+
+
+/* YUCK! FIXME (err, the whole new-then-add thing sucks) */
+static PedPartition*
+_find_left_part (PedPartition* part)
+{
+	PedPartition*	walk;
+
+	for (walk = part->geom.disk->part_list; walk && walk->next;
+	     walk = walk->next) {
+		if (walk->geom.end < part->geom.start
+		    && walk->next->geom.end >= part->geom.start)
+			break;
+	}
+	if (walk && walk->geom.end < part->geom.start)
+		return walk;
+	else
+		return NULL;
+}
+
+static PedPartition*
+_find_right_part (PedPartition* part, PedPartition* left)
+{
+	PedPartition*	walk = left;
+
+	for (walk = left; walk; walk = walk->next) {
+		if (walk->geom.start > part->geom.end)
+			break;
+	}
+	return walk;
+}
+
+/* if the gap between the new partition and the partition-to-be-aligned is
+ * less than MIN_FREESPACE, then gobble up the gap!  (Only does this if it
+ * still satisfies the constraint)
+ */
+static int
+_grow_over_small_freespace (PedPartition* part, const PedConstraint* constraint)
+{
+	PedPartition*	left;
+	PedPartition*	right;
+
+	/* there should always be a partition on the left - if nothing else -
+	 * the partition map.  Unless "part" is the partition map ;-)
+	 */
+	left = _find_left_part (part);
+	if (!left)
+		return 1;
+	right = _find_right_part (part, left);
+	PED_ASSERT (left->geom.end < part->geom.start, return 0);
+	if (right)
+		PED_ASSERT (part->geom.end < right->geom.start, return 0);
+
+	if (part->geom.start - left->geom.end < MIN_FREESPACE
+	    && ped_alignment_is_aligned (constraint->start_align, NULL,
+					 left->geom.end + 1)
+	    && ped_geometry_test_sector_inside (constraint->start_range,
+		    				left->geom.end + 1)) {
+		if (!ped_geometry_set_start (&part->geom, left->geom.end + 1))
+			return 0;
+	}
+	if (right
+	    && right->geom.start - part->geom.end < MIN_FREESPACE
+	    && ped_alignment_is_aligned (constraint->end_align, NULL,
+					 right->geom.start - 1)
+	    && ped_geometry_test_sector_inside (constraint->end_range,
+		    				right->geom.start - 1)) {
+		if (!ped_geometry_set_end (&part->geom, right->geom.start - 1))
+			return 0;
+	}
+
+	return 1;
+}
+
+static int
+gpt_partition_align(PedPartition * part,
+                    const PedConstraint * constraint)
+{
+	PED_ASSERT (part != NULL, return 0);
+
+	if (!_try_constraint (part, constraint,
+                              _non_metadata_constraint (part->geom.disk))) {
+		ped_exception_throw (
+			PED_EXCEPTION_ERROR,
+			PED_EXCEPTION_CANCEL,
+			_("Unable to align partition."));
+		return 0;
+	}
+
+	if (!_grow_over_small_freespace (part, constraint))
+		return 0;
+
+
+	return 1;
+}
+
+static PedDisk *
+gpt_new(PedDisk * disk)
+{
+        PED_ASSERT(disk != NULL, return NULL);
+        if (disk->disk_specific) return disk;
+
+        disk->disk_specific = ped_malloc(sizeof(GPTDiskData));
+        PED_ASSERT(disk->disk_specific != NULL, return NULL);
+        memset(disk->disk_specific, 0, sizeof(GPTDiskData));
+        return disk;
+}  
+
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
