summaryrefslogtreecommitdiffstats
path: root/gpt
diff options
context:
space:
mode:
Diffstat (limited to 'gpt')
-rwxr-xr-xgpt/Android.mk15
-rw-r--r--gpt/gpt.c675
-rw-r--r--gpt/gpt.h182
-rw-r--r--gpt/gptcrc32.c124
-rw-r--r--gpt/gptcrc32.h36
5 files changed, 1032 insertions, 0 deletions
diff --git a/gpt/Android.mk b/gpt/Android.mk
new file mode 100755
index 000000000..7369339b3
--- /dev/null
+++ b/gpt/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH := $(call my-dir)
+
+# Build libgpt_twrp library
+
+include $(CLEAR_VARS)
+LOCAL_CLANG := false
+LOCAL_MODULE := libgpt_twrp
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES = \
+ gpt.c \
+ gptcrc32.c
+
+LOCAL_SHARED_LIBRARIES := libc
+include $(BUILD_SHARED_LIBRARY)
diff --git a/gpt/gpt.c b/gpt/gpt.c
new file mode 100644
index 000000000..068a24458
--- /dev/null
+++ b/gpt/gpt.c
@@ -0,0 +1,675 @@
+/*
+ gpt.[ch]
+
+ Copyright (C) 2000-2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+
+ 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
+*/
+
+// For TWRP purposes, we'll be opting for version 3 of the GPL
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/utsname.h>
+#include <asm/byteorder.h>
+#include "gpt.h"
+#include "gptcrc32.h"
+
+#define BLKGETLASTSECT _IO(0x12,108) /* get last sector of block device */
+#define BLKGETSIZE _IO(0x12,96) /* return device size */
+#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
+#define BLKGETSIZE64 _IOR(0x12,114,uint64_t) /* return device size in bytes (u64 *arg) */
+
+struct blkdev_ioctl_param {
+ unsigned int block;
+ size_t content_length;
+ char * block_contents;
+};
+
+static inline int
+efi_guidcmp(efi_guid_t left, efi_guid_t right)
+{
+ return memcmp(&left, &right, sizeof (efi_guid_t));
+}
+
+static int
+get_sector_size(int filedes)
+{
+ int rc, sector_size = 512;
+
+ rc = ioctl(filedes, BLKSSZGET, &sector_size);
+ if (rc)
+ sector_size = 512;
+ return sector_size;
+}
+
+/**
+ * efi_crc32() - EFI version of crc32 function
+ * @buf: buffer to calculate crc32 of
+ * @len - length of buf
+ *
+ * Description: Returns EFI-style CRC32 value for @buf
+ *
+ * This function uses the little endian Ethernet polynomial
+ * but seeds the function with ~0, and xor's with ~0 at the end.
+ * Note, the EFI Specification, v1.02, has a reference to
+ * Dr. Dobbs Journal, May 1994 (actually it's in May 1992).
+ */
+static inline uint32_t
+efi_crc32(const void *buf, unsigned long len)
+{
+ return (gptcrc32(buf, len, ~0L) ^ ~0L);
+}
+
+/**
+ * is_pmbr_valid(): test Protective MBR for validity
+ * @mbr: pointer to a legacy mbr structure
+ *
+ * Description: Returns 1 if PMBR is valid, 0 otherwise.
+ * Validity depends on two things:
+ * 1) MSDOS signature is in the last two bytes of the MBR
+ * 2) One partition of type 0xEE is found
+ */
+static int
+is_pmbr_valid(legacy_mbr *mbr)
+{
+ int i, found = 0, signature = 0;
+ if (!mbr)
+ return 0;
+ signature = (__le16_to_cpu(mbr->signature) == MSDOS_MBR_SIGNATURE);
+ for (i = 0; signature && i < 4; i++) {
+ if (mbr->partition[i].os_type ==
+ EFI_PMBR_OSTYPE_EFI_GPT) {
+ found = 1;
+ break;
+ }
+ }
+ return (signature && found);
+}
+
+/**
+ * kernel_has_blkgetsize64()
+ *
+ * Returns: 0 on false, 1 on true
+ * True means kernel is 2.4.x, x>=18, or
+ * is 2.5.x, x>4, or
+ * is > 2.5
+ */
+static int
+kernel_has_blkgetsize64(void)
+{
+ int major=0, minor=0, patch=0, parsed;
+ int rc;
+ struct utsname u;
+
+ memset(&u, 0, sizeof(u));
+ rc = uname(&u);
+ if (rc) return 0;
+
+ parsed = sscanf(u.release, "%d.%d.%d", &major, &minor, &patch);
+ if (parsed < 3) return 0;
+ if (major > 2) return 1;
+ if (major == 2 && minor > 5) return 1;
+ if (major == 2 && minor == 5 && patch >= 4) return 1;
+ if (major == 2 && minor == 4 && patch >= 18) return 1;
+ return 0;
+}
+
+
+/************************************************************
+ * _get_num_sectors
+ * Requires:
+ * - filedes is an open file descriptor, suitable for reading
+ * Modifies: nothing
+ * Returns:
+ * Last LBA value on success
+ * 0 on error
+ *
+ * Try getting BLKGETSIZE64 and BLKSSZGET first,
+ * then BLKGETSIZE if necessary.
+ * Kernels 2.4.15-2.4.18 and 2.5.0-2.5.3 have a broken BLKGETSIZE64
+ * which returns the number of 512-byte sectors, not the size of
+ * the disk in bytes. Fixed in kernels 2.4.18-pre8 and 2.5.4-pre3.
+ ************************************************************/
+static uint64_t
+_get_num_sectors(int filedes)
+{
+ unsigned long sectors=0;
+ uint64_t bytes=0;
+ int rc;
+ if (kernel_has_blkgetsize64()) {
+ rc = ioctl(filedes, BLKGETSIZE64, &bytes);
+ if (!rc)
+ return bytes / get_sector_size(filedes);
+ }
+
+ rc = ioctl(filedes, BLKGETSIZE, &sectors);
+ if (rc)
+ return 0;
+
+ return sectors;
+}
+
+/************************************************************
+ * last_lba(): return number of last logical block of device
+ *
+ * @fd
+ *
+ * Description: returns Last LBA value on success, 0 on error.
+ * Notes: The value st_blocks gives the size of the file
+ * in 512-byte blocks, which is OK if
+ * EFI_BLOCK_SIZE_SHIFT == 9.
+ ************************************************************/
+
+static uint64_t
+last_lba(int filedes)
+{
+ int rc;
+ uint64_t sectors = 0;
+ struct stat s;
+ memset(&s, 0, sizeof (s));
+ rc = fstat(filedes, &s);
+ if (rc == -1) {
+ fprintf(stderr, "last_lba() could not stat: %s\n",
+ strerror(errno));
+ return 0;
+ }
+
+ if (S_ISBLK(s.st_mode)) {
+ sectors = _get_num_sectors(filedes);
+ } else {
+ fprintf(stderr,
+ "last_lba(): I don't know how to handle files with mode %x\n",
+ s.st_mode);
+ sectors = 1;
+ }
+
+ return sectors - 1;
+}
+
+
+static ssize_t
+read_lastoddsector(int fd, uint64_t lba __unused, void *buffer, size_t count)
+{
+ int rc;
+ struct blkdev_ioctl_param ioctl_param;
+
+ if (!buffer) return 0;
+
+ ioctl_param.block = 0; /* read the last sector */
+ ioctl_param.content_length = count;
+ ioctl_param.block_contents = buffer;
+
+ rc = ioctl(fd, BLKGETLASTSECT, &ioctl_param);
+ if (rc == -1) perror("read failed");
+
+ return !rc;
+}
+
+static ssize_t
+read_lba(int fd, uint64_t lba, void *buffer, size_t bytes)
+{
+ int sector_size = get_sector_size(fd);
+ off_t offset = lba * sector_size;
+ ssize_t bytesread;
+ void *aligned;
+ void *unaligned;
+
+ if (bytes % sector_size)
+ return EINVAL;
+
+ unaligned = malloc(bytes+sector_size-1);
+ aligned = (void *)
+ (((unsigned long)unaligned + sector_size - 1) &
+ ~(unsigned long)(sector_size-1));
+ memset(aligned, 0, bytes);
+
+
+ lseek(fd, offset, SEEK_SET);
+ bytesread = read(fd, aligned, bytes);
+ memcpy(buffer, aligned, bytesread);
+ free(unaligned);
+
+ /* 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 gpt.c, and only to read
+ one sector, so we don't have to be fancy.
+ */
+ if (!bytesread && !(last_lba(fd) & 1) && lba == last_lba(fd)) {
+ bytesread = read_lastoddsector(fd, lba, buffer, bytes);
+ }
+ return bytesread;
+}
+
+/**
+ * alloc_read_gpt_entries(): reads partition entries from disk
+ * @fd is an open file descriptor to the whole disk
+ * @gpt is a buffer into which the GPT will be put
+ * Description: Returns ptes on success, NULL on error.
+ * Allocates space for PTEs based on information found in @gpt.
+ * Notes: remember to free pte when you're done!
+ */
+static gpt_entry *
+alloc_read_gpt_entries(int fd, gpt_header * gpt)
+{
+ gpt_entry *pte;
+ size_t count = __le32_to_cpu(gpt->num_partition_entries) *
+ __le32_to_cpu(gpt->sizeof_partition_entry);
+
+ if (!count) return NULL;
+
+ pte = (gpt_entry *)malloc(count);
+ if (!pte)
+ return NULL;
+ memset(pte, 0, count);
+
+ if (!read_lba(fd, __le64_to_cpu(gpt->partition_entry_lba), pte,
+ count)) {
+ free(pte);
+ return NULL;
+ }
+ return pte;
+}
+
+/**
+ * alloc_read_gpt_header(): Allocates GPT header, reads into it from disk
+ * @fd is an open file descriptor to the whole disk
+ * @lba is the Logical Block Address of the partition table
+ *
+ * Description: returns GPT header on success, NULL on error. Allocates
+ * and fills a GPT header starting at @ from @bdev.
+ * Note: remember to free gpt when finished with it.
+ */
+static gpt_header *
+alloc_read_gpt_header(int fd, uint64_t lba)
+{
+ gpt_header *gpt;
+ gpt = (gpt_header *)
+ malloc(sizeof (gpt_header));
+ if (!gpt)
+ return NULL;
+ memset(gpt, 0, sizeof (*gpt));
+ if (!read_lba(fd, lba, gpt, sizeof (gpt_header))) {
+ free(gpt);
+ return NULL;
+ }
+
+ return gpt;
+}
+
+/**
+ * is_gpt_valid() - tests one GPT header and PTEs for validity
+ * @fd is an open file descriptor to the whole disk
+ * @lba is the logical block address of the GPT header to test
+ * @gpt is a GPT header ptr, filled on return.
+ * @ptes is a PTEs ptr, filled on return.
+ *
+ * Description: returns 1 if valid, 0 on error.
+ * If valid, returns pointers to newly allocated GPT header and PTEs.
+ */
+static int
+is_gpt_valid(int fd, uint64_t lba,
+ gpt_header ** gpt, gpt_entry ** ptes)
+{
+ int rc = 0; /* default to not valid */
+ uint32_t crc, origcrc;
+
+ if (!gpt || !ptes)
+ return 0;
+ if (!(*gpt = alloc_read_gpt_header(fd, lba)))
+ return 0;
+
+ /* Check the GUID Partition Table signature */
+ if (__le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) {
+ /*
+ printf("GUID Partition Table Header signature is wrong: %" PRIx64" != %" PRIx64 "\n",
+ __le64_to_cpu((*gpt)->signature), GUID_PT_HEADER_SIGNATURE);
+ */
+ free(*gpt);
+ *gpt = NULL;
+ return rc;
+ }
+
+ /* Check the GUID Partition Table Header CRC */
+ origcrc = __le32_to_cpu((*gpt)->header_crc32);
+ (*gpt)->header_crc32 = 0;
+ crc = efi_crc32(*gpt, __le32_to_cpu((*gpt)->header_size));
+ if (crc != origcrc) {
+ // printf( "GPTH CRC check failed, %x != %x.\n", origcrc, crc);
+ (*gpt)->header_crc32 = __cpu_to_le32(origcrc);
+ free(*gpt);
+ *gpt = NULL;
+ return 0;
+ }
+ (*gpt)->header_crc32 = __cpu_to_le32(origcrc);
+
+ /* Check that the my_lba entry points to the LBA
+ * that contains the GPT we read */
+ if (__le64_to_cpu((*gpt)->my_lba) != lba) {
+ // printf( "my_lba % PRIx64 "x != lba %"PRIx64 "x.\n", __le64_to_cpu((*gpt)->my_lba), lba);
+ free(*gpt);
+ *gpt = NULL;
+ return 0;
+ }
+
+ if (!(*ptes = alloc_read_gpt_entries(fd, *gpt))) {
+ free(*gpt);
+ *gpt = NULL;
+ return 0;
+ }
+
+ /* Check the GUID Partition Entry Array CRC */
+ crc = efi_crc32(*ptes,
+ __le32_to_cpu((*gpt)->num_partition_entries) *
+ __le32_to_cpu((*gpt)->sizeof_partition_entry));
+ if (crc != __le32_to_cpu((*gpt)->partition_entry_array_crc32)) {
+ // printf("GUID Partitition Entry Array CRC check failed.\n");
+ free(*gpt);
+ *gpt = NULL;
+ free(*ptes);
+ *ptes = NULL;
+ return 0;
+ }
+
+ /* We're done, all's well */
+ return 1;
+}
+/**
+ * compare_gpts() - Search disk for valid GPT headers and PTEs
+ * @pgpt is the primary GPT header
+ * @agpt is the alternate GPT header
+ * @lastlba is the last LBA number
+ * Description: Returns nothing. Sanity checks pgpt and agpt fields
+ * and prints warnings on discrepancies.
+ *
+ */
+static void
+compare_gpts(gpt_header *pgpt, gpt_header *agpt, uint64_t lastlba)
+{
+ int error_found = 0;
+ if (!pgpt || !agpt)
+ return;
+ if (__le64_to_cpu(pgpt->my_lba) != __le64_to_cpu(agpt->alternate_lba)) {
+ fprintf(stderr,
+ "GPT:Primary header LBA != Alt. header alternate_lba\n");
+ fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n",
+ __le64_to_cpu(pgpt->my_lba),
+ __le64_to_cpu(agpt->alternate_lba));
+ error_found++;
+ }
+ if (__le64_to_cpu(pgpt->alternate_lba) != __le64_to_cpu(agpt->my_lba)) {
+ fprintf(stderr,
+ "GPT:Primary header alternate_lba != Alt. header my_lba\n");
+ fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n",
+ __le64_to_cpu(pgpt->alternate_lba),
+ __le64_to_cpu(agpt->my_lba));
+ error_found++;
+ }
+ if (__le64_to_cpu(pgpt->first_usable_lba) !=
+ __le64_to_cpu(agpt->first_usable_lba)) {
+ fprintf(stderr, "GPT:first_usable_lbas don't match.\n");
+ fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n",
+ __le64_to_cpu(pgpt->first_usable_lba),
+ __le64_to_cpu(agpt->first_usable_lba));
+ error_found++;
+ }
+ if (__le64_to_cpu(pgpt->last_usable_lba) !=
+ __le64_to_cpu(agpt->last_usable_lba)) {
+ fprintf(stderr, "GPT:last_usable_lbas don't match.\n");
+ fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n",
+ __le64_to_cpu(pgpt->last_usable_lba),
+ __le64_to_cpu(agpt->last_usable_lba));
+ error_found++;
+ }
+ if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) {
+ fprintf(stderr, "GPT:disk_guids don't match.\n");
+ error_found++;
+ }
+ if (__le32_to_cpu(pgpt->num_partition_entries) !=
+ __le32_to_cpu(agpt->num_partition_entries)) {
+ fprintf(stderr, "GPT:num_partition_entries don't match: "
+ "0x%x != 0x%x\n",
+ __le32_to_cpu(pgpt->num_partition_entries),
+ __le32_to_cpu(agpt->num_partition_entries));
+ error_found++;
+ }
+ if (__le32_to_cpu(pgpt->sizeof_partition_entry) !=
+ __le32_to_cpu(agpt->sizeof_partition_entry)) {
+ fprintf(stderr,
+ "GPT:sizeof_partition_entry values don't match: "
+ "0x%x != 0x%x\n",
+ __le32_to_cpu(pgpt->sizeof_partition_entry),
+ __le32_to_cpu(agpt->sizeof_partition_entry));
+ error_found++;
+ }
+ if (__le32_to_cpu(pgpt->partition_entry_array_crc32) !=
+ __le32_to_cpu(agpt->partition_entry_array_crc32)) {
+ fprintf(stderr,
+ "GPT:partition_entry_array_crc32 values don't match: "
+ "0x%x != 0x%x\n",
+ __le32_to_cpu(pgpt->partition_entry_array_crc32),
+ __le32_to_cpu(agpt->partition_entry_array_crc32));
+ error_found++;
+ }
+ if (__le64_to_cpu(pgpt->alternate_lba) != lastlba) {
+ fprintf(stderr,
+ "GPT:Primary header thinks Alt. header is not at the end of the disk.\n");
+ fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n",
+ __le64_to_cpu(pgpt->alternate_lba), lastlba);
+ error_found++;
+ }
+
+ if (__le64_to_cpu(agpt->my_lba) != lastlba) {
+ fprintf(stderr,
+ "GPT:Alternate GPT header not at the end of the disk.\n");
+ fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n",
+ __le64_to_cpu(agpt->my_lba), lastlba);
+ error_found++;
+ }
+
+ if (error_found)
+ fprintf(stderr,
+ "GPT: Use GNU Parted to correct GPT errors.\n");
+ return;
+}
+
+/**
+ * find_valid_gpt() - Search disk for valid GPT headers and PTEs
+ * @fd is an open file descriptor to the whole disk
+ * @gpt is a GPT header ptr, filled on return.
+ * @ptes is a PTEs ptr, filled on return.
+ * Description: Returns 1 if valid, 0 on error.
+ * If valid, returns pointers to newly allocated GPT header and PTEs.
+ * Validity depends on finding either the Primary GPT header and PTEs valid,
+ * or the Alternate GPT header and PTEs valid, and the PMBR valid.
+ */
+static int
+find_valid_gpt(int fd, gpt_header ** gpt, gpt_entry ** ptes)
+{
+ int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
+ gpt_header *pgpt = NULL, *agpt = NULL;
+ gpt_entry *pptes = NULL, *aptes = NULL;
+ legacy_mbr *legacymbr = NULL;
+ uint64_t lastlba;
+ if (!gpt || !ptes)
+ return 0;
+
+ lastlba = last_lba(fd);
+ good_pgpt = is_gpt_valid(fd, GPT_PRIMARY_PARTITION_TABLE_LBA,
+ &pgpt, &pptes);
+ if (good_pgpt) {
+ good_agpt = is_gpt_valid(fd,
+ __le64_to_cpu(pgpt->alternate_lba),
+ &agpt, &aptes);
+ if (!good_agpt) {
+ good_agpt = is_gpt_valid(fd, lastlba,
+ &agpt, &aptes);
+ }
+ }
+ else {
+ good_agpt = is_gpt_valid(fd, lastlba,
+ &agpt, &aptes);
+ }
+
+ /* The obviously unsuccessful case */
+ if (!good_pgpt && !good_agpt) {
+ goto fail;
+ }
+
+ /* This will be added to the EFI Spec. per Intel after v1.02. */
+ legacymbr = malloc(sizeof (*legacymbr));
+ if (legacymbr) {
+ memset(legacymbr, 0, sizeof (*legacymbr));
+ read_lba(fd, 0, (uint8_t *) legacymbr,
+ sizeof (*legacymbr));
+ good_pmbr = is_pmbr_valid(legacymbr);
+ free(legacymbr);
+ legacymbr=NULL;
+ }
+
+ /* Failure due to bad PMBR */
+ if ((good_pgpt || good_agpt) && !good_pmbr) {
+ fprintf(stderr,
+ " Warning: Disk has a valid GPT signature "
+ "but invalid PMBR.\n"
+ " Assuming this disk is *not* a GPT disk anymore.\n"
+ " Use gpt kernel option to override. "
+ "Use GNU Parted to correct disk.\n");
+ goto fail;
+ }
+
+ /* Would fail due to bad PMBR, but force GPT anyhow */
+ if ((good_pgpt || good_agpt) && !good_pmbr) {
+ fprintf(stderr,
+ " Warning: Disk has a valid GPT signature but "
+ "invalid PMBR.\n"
+ " Use GNU Parted to correct disk.\n"
+ " gpt option taken, disk treated as GPT.\n");
+ }
+
+ compare_gpts(pgpt, agpt, lastlba);
+
+ /* The good cases */
+ if (good_pgpt && (good_pmbr)) {
+ *gpt = pgpt;
+ *ptes = pptes;
+ if (agpt) { free(agpt); agpt = NULL; }
+ if (aptes) { free(aptes); aptes = NULL; }
+ if (!good_agpt) {
+ fprintf(stderr,
+ "Alternate GPT is invalid, "
+ "using primary GPT.\n");
+ }
+ return 1;
+ }
+ else if (good_agpt && (good_pmbr)) {
+ *gpt = agpt;
+ *ptes = aptes;
+ if (pgpt) { free(pgpt); pgpt = NULL; }
+ if (pptes) { free(pptes); pptes = NULL; }
+ fprintf(stderr,
+ "Primary GPT is invalid, using alternate GPT.\n");
+ return 1;
+ }
+
+ fail:
+ if (pgpt) { free(pgpt); pgpt=NULL; }
+ if (agpt) { free(agpt); agpt=NULL; }
+ if (pptes) { free(pptes); pptes=NULL; }
+ if (aptes) { free(aptes); aptes=NULL; }
+ *gpt = NULL;
+ *ptes = NULL;
+ return 0;
+}
+
+void guid_to_ascii(const char *guid, char *s)
+{
+ uint32_t p1;
+ uint16_t p2;
+ uint16_t p3;
+ unsigned char p4[8];
+
+ memcpy(&p1, guid + 0, 4);
+ memcpy(&p2, guid + 4, 2);
+ memcpy(&p3, guid + 6, 2);
+ memcpy(p4, guid + 8, 8);
+
+ sprintf(s, "%08x%04x%04x%02x%02x%02x%02x%02x%02x%02x%02x",
+ p1, p2, p3, p4[0], p4[1],
+ p4[2], p4[3], p4[4], p4[5], p4[6], p4[7]);
+}
+
+
+/************************************************************
+ * gpt_disk_get_partition_info()
+ * Requires:
+ * - open file descriptor fd
+ * - start, size, signature, mbr_type, signature_type
+ * Modifies: all these
+ * Returns:
+ * 0 on success
+ * non-zero on failure
+ *
+ ************************************************************/
+int
+gpt_disk_get_partition_info(int fd, uint32_t num,
+ char *type, char *part)
+{
+ gpt_header *gpt = NULL;
+ gpt_entry *ptes = NULL, *p;
+
+ if (!find_valid_gpt(fd, &gpt, &ptes))
+ return 1;
+
+ if (num > 0 && num <= __le32_to_cpu(gpt->num_partition_entries)) {
+ p = &ptes[num - 1];
+ guid_to_ascii((char*)&p->partition_type_guid, type);
+ guid_to_ascii((char*)&p->unique_partition_guid, part);
+ } else {
+ fprintf (stderr,"partition %d is not valid\n", num);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * 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 --git a/gpt/gpt.h b/gpt/gpt.h
new file mode 100644
index 000000000..9520c8dc4
--- /dev/null
+++ b/gpt/gpt.h
@@ -0,0 +1,182 @@
+/*
+ gpt.[ch]
+
+ Copyright (C) 2000-2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+
+ 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
+*/
+
+// For TWRP purposes, we'll be opting for version 3 of the GPL
+
+#ifndef _GPT_H
+#define _GPT_H
+
+
+#include <inttypes.h>
+//#include "efi.h"
+
+typedef struct {
+ uint8_t b[16];
+} efi_guid_t;
+typedef uint16_t efi_char16_t; /* UNICODE character */
+
+#define EFI_PMBR_OSTYPE_EFI 0xEF
+#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
+#define MSDOS_MBR_SIGNATURE 0xaa55
+#define GPT_BLOCK_SIZE 512
+
+static const char* TWGptAndroidExpand = "193d1ea4b3ca11e4b07510604b889dcf";
+
+#define GPT_HEADER_SIGNATURE ((uint64_t)(0x5452415020494645LL))
+#define GPT_HEADER_REVISION_V1_02 0x00010200
+#define GPT_HEADER_REVISION_V1_00 0x00010000
+#define GPT_HEADER_REVISION_V0_99 0x00009900
+#define GPT_PRIMARY_PARTITION_TABLE_LBA 1
+
+#define PARTITION_SYSTEM_GUID \
+ EFI_GUID( 0xC12A7328, 0xF81F, 0x11d2, \
+ 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B)
+#define LEGACY_MBR_PARTITION_GUID \
+ EFI_GUID( 0x024DEE41, 0x33E7, 0x11d3, \
+ 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F)
+#define PARTITION_MSFT_RESERVED_GUID \
+ EFI_GUID( 0xE3C9E316, 0x0B5C, 0x4DB8, \
+ 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE)
+#define PARTITION_BASIC_DATA_GUID \
+ EFI_GUID( 0xEBD0A0A2, 0xB9E5, 0x4433, \
+ 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7)
+#define PARTITION_LINUX_RAID_GUID \
+ EFI_GUID( 0xa19d880f, 0x05fc, 0x4d3b, \
+ 0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e)
+#define PARTITION_LINUX_SWAP_GUID \
+ EFI_GUID( 0x0657fd6d, 0xa4ab, 0x43c4, \
+ 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f)
+#define PARTITION_LINUX_LVM_GUID \
+ EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \
+ 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28)
+
+typedef struct _gpt_header {
+ uint64_t signature;
+ uint32_t revision;
+ uint32_t header_size;
+ uint32_t header_crc32;
+ uint32_t reserved1;
+ uint64_t my_lba;
+ uint64_t alternate_lba;
+ uint64_t first_usable_lba;
+ uint64_t last_usable_lba;
+ efi_guid_t disk_guid;
+ uint64_t partition_entry_lba;
+ uint32_t num_partition_entries;
+ uint32_t sizeof_partition_entry;
+ uint32_t partition_entry_array_crc32;
+ uint8_t reserved2[GPT_BLOCK_SIZE - 92];
+} __attribute__ ((packed)) gpt_header;
+
+typedef struct _gpt_entry_attributes {
+ uint64_t required_to_function:1;
+ uint64_t reserved:47;
+ uint64_t type_guid_specific:16;
+} __attribute__ ((packed)) gpt_entry_attributes;
+
+typedef struct _gpt_entry {
+ efi_guid_t partition_type_guid;
+ efi_guid_t unique_partition_guid;
+ uint64_t starting_lba;
+ uint64_t ending_lba;
+ gpt_entry_attributes attributes;
+ efi_char16_t partition_name[72 / sizeof(efi_char16_t)];
+} __attribute__ ((packed)) gpt_entry;
+
+
+/*
+ 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(gpt_entry))
+
+
+typedef struct _partition_record {
+ uint8_t boot_indicator; /* Not used by EFI firmware. Set to 0x80 to indicate that this
+ is the bootable legacy partition. */
+ uint8_t start_head; /* Start of partition in CHS address, not used by EFI firmware. */
+ uint8_t start_sector; /* Start of partition in CHS address, not used by EFI firmware. */
+ uint8_t start_track; /* Start of partition in CHS address, not used by EFI firmware. */
+ uint8_t os_type; /* 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 end_head; /* End of partition in CHS address, not used by EFI firmware. */
+ uint8_t end_sector; /* End of partition in CHS address, not used by EFI firmware. */
+ uint8_t end_track; /* End of partition in CHS address, not used by EFI firmware. */
+ uint32_t starting_lba; /* Starting LBA address of the partition on the disk. Used by
+ EFI firmware to define the start of the partition. */
+ uint32_t size_in_lba; /* Size of partition in LBA. Used by EFI firmware to determine
+ the size of the partition. */
+} __attribute__ ((packed)) partition_record;
+
+
+/* Protected Master Boot Record & Legacy MBR share same structure */
+/* Needs to be packed because the u16s force misalignment. */
+
+typedef struct _legacy_mbr {
+ uint8_t bootcode[440];
+ uint32_t unique_mbr_signature;
+ uint16_t unknown;
+ partition_record partition[4];
+ uint16_t signature;
+} __attribute__ ((packed)) legacy_mbr;
+
+
+
+
+#define EFI_GPT_PRIMARY_PARTITION_TABLE_LBA 1
+
+/* Functions */
+int gpt_disk_get_partition_info (int fd, uint32_t num,
+ char *type, char *part);
+
+
+#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 --git a/gpt/gptcrc32.c b/gpt/gptcrc32.c
new file mode 100644
index 000000000..3157e93f1
--- /dev/null
+++ b/gpt/gptcrc32.c
@@ -0,0 +1,124 @@
+/*
+ * 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 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
+gptcrc32(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 --git a/gpt/gptcrc32.h b/gpt/gptcrc32.h
new file mode 100644
index 000000000..0631b7f31
--- /dev/null
+++ b/gpt/gptcrc32.h
@@ -0,0 +1,36 @@
+/*
+ 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
+*/
+
+// For TWRP purposes, we'll be opting for version 3 of the GPL
+
+#ifndef _GPTCRC32_H
+#define _GPTCRC32_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 gptcrc32 (const void *buf, unsigned long len, uint32_t seed);
+
+#endif /* _GPTCRC32_H */