summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk3
-rw-r--r--crypto/lollipop/cryptfs.c45
-rw-r--r--crypto/lollipop/cryptfs.h3
-rw-r--r--data.cpp4
-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
-rw-r--r--gui/action.cpp1
-rwxr-xr-xgui/theme/common/landscape.xml6
-rwxr-xr-xgui/theme/common/languages/en.xml1
-rwxr-xr-xgui/theme/common/portrait.xml6
-rwxr-xr-xmtp/Android.mk1
-rw-r--r--partition.cpp237
-rw-r--r--partitionmanager.cpp132
-rw-r--r--partitions.hpp8
-rw-r--r--prebuilt/Android.mk1
18 files changed, 1427 insertions, 53 deletions
diff --git a/Android.mk b/Android.mk
index 94084d8d8..47c30c425 100644
--- a/Android.mk
+++ b/Android.mk
@@ -284,7 +284,7 @@ ifeq ($(TW_INCLUDE_L_CRYPTO), true)
endif
ifeq ($(TW_INCLUDE_CRYPTO), true)
LOCAL_CFLAGS += -DTW_INCLUDE_CRYPTO
- LOCAL_SHARED_LIBRARIES += libcryptfslollipop
+ LOCAL_SHARED_LIBRARIES += libcryptfslollipop libgpt_twrp
LOCAL_C_INCLUDES += external/boringssl/src/include
endif
ifeq ($(TW_USE_MODEL_HARDWARE_ID_FOR_DEVICE_ID), true)
@@ -592,6 +592,7 @@ include $(commands_recovery_local_path)/injecttwrp/Android.mk \
ifeq ($(TW_INCLUDE_CRYPTO), true)
include $(commands_recovery_local_path)/crypto/lollipop/Android.mk
include $(commands_recovery_local_path)/crypto/scrypt/Android.mk
+ include $(commands_recovery_local_path)/gpt/Android.mk
endif
ifeq ($(BUILD_ID), GINGERBREAD)
TW_NO_EXFAT := true
diff --git a/crypto/lollipop/cryptfs.c b/crypto/lollipop/cryptfs.c
index 1e65a2263..fa440ed17 100644
--- a/crypto/lollipop/cryptfs.c
+++ b/crypto/lollipop/cryptfs.c
@@ -1060,6 +1060,7 @@ static int load_crypto_mapping_table(struct crypt_mnt_ftr *crypt_ftr, unsigned c
if (! ioctl(fd, DM_TABLE_LOAD, io)) {
break;
}
+ printf("%i\n", errno);
usleep(500000);
}
@@ -1145,7 +1146,7 @@ static int create_crypto_blk_dev(struct crypt_mnt_ftr *crypt_ftr, unsigned char
ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
if (ioctl(fd, DM_DEV_CREATE, io)) {
- printf("Cannot create dm-crypt device\n");
+ printf("Cannot create dm-crypt device %i\n", errno);
goto errout;
}
@@ -2017,3 +2018,45 @@ int cryptfs_get_password_type(void)
return crypt_ftr.crypt_type;
}
+
+/*
+ * Called by vold when it's asked to mount an encrypted external
+ * storage volume. The incoming partition has no crypto header/footer,
+ * as any metadata is been stored in a separate, small partition.
+ *
+ * out_crypto_blkdev must be MAXPATHLEN.
+ */
+int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev,
+ const unsigned char* key, int keysize, char* out_crypto_blkdev) {
+ int fd = open(real_blkdev, O_RDONLY|O_CLOEXEC);
+ if (fd == -1) {
+ printf("Failed to open %s: %s", real_blkdev, strerror(errno));
+ return -1;
+ }
+
+ unsigned long nr_sec = 0;
+ nr_sec = get_blkdev_size(fd);
+ close(fd);
+
+ if (nr_sec == 0) {
+ printf("Failed to get size of %s: %s", real_blkdev, strerror(errno));
+ return -1;
+ }
+
+ struct crypt_mnt_ftr ext_crypt_ftr;
+ memset(&ext_crypt_ftr, 0, sizeof(ext_crypt_ftr));
+ ext_crypt_ftr.fs_size = nr_sec;
+ ext_crypt_ftr.keysize = keysize;
+ strcpy((char*) ext_crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256");
+
+ return create_crypto_blk_dev(&ext_crypt_ftr, key, real_blkdev,
+ out_crypto_blkdev, label);
+}
+
+/*
+ * Called by vold when it's asked to unmount an encrypted external
+ * storage volume.
+ */
+int cryptfs_revert_ext_volume(const char* label) {
+ return delete_crypto_blk_dev((char*) label);
+}
diff --git a/crypto/lollipop/cryptfs.h b/crypto/lollipop/cryptfs.h
index 67ebbba95..cd07e5af7 100644
--- a/crypto/lollipop/cryptfs.h
+++ b/crypto/lollipop/cryptfs.h
@@ -221,6 +221,9 @@ extern "C" {
int cryptfs_verify_passwd(char *newpw);
int cryptfs_get_password_type(void);
int delete_crypto_blk_dev(char *name);
+ int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev,
+ const unsigned char* key, int keysize, char* out_crypto_blkdev);
+ int cryptfs_revert_ext_volume(const char* label);
#ifdef __cplusplus
}
#endif
diff --git a/data.cpp b/data.cpp
index cda6828de..77e8f8de4 100644
--- a/data.cpp
+++ b/data.cpp
@@ -744,7 +744,7 @@ void DataManager::SetDefaultValues()
mConstValues.insert(make_pair(TW_HAS_USB_STORAGE, "0"));
} else {
LOGINFO("Lun file '%s'\n", Lun_File_str.c_str());
- mConstValues.insert(make_pair(TW_HAS_USB_STORAGE, "1"));
+ mValues.insert(make_pair(TW_HAS_USB_STORAGE, make_pair("1", 0)));
}
#endif
#ifdef TW_INCLUDE_INJECTTWRP
@@ -923,6 +923,8 @@ void DataManager::SetDefaultValues()
mValues.insert(make_pair("tw_language", make_pair(EXPAND(TW_DEFAULT_LANGUAGE), 1)));
LOGINFO("LANG: %s\n", EXPAND(TW_DEFAULT_LANGUAGE));
+ mValues.insert(make_pair("tw_has_adopted_storage", make_pair("0", 0)));
+
pthread_mutex_unlock(&m_valuesLock);
}
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 */
diff --git a/gui/action.cpp b/gui/action.cpp
index 711f64506..8895e4013 100644
--- a/gui/action.cpp
+++ b/gui/action.cpp
@@ -1466,6 +1466,7 @@ int GUIAction::decrypt(std::string arg __unused)
LOGINFO("Got default contexts and file mode for storage files.\n");
}
}
+ PartitionManager.Decrypt_Adopted();
}
}
diff --git a/gui/theme/common/landscape.xml b/gui/theme/common/landscape.xml
index ff6babe1c..a6b5dca4c 100755
--- a/gui/theme/common/landscape.xml
+++ b/gui/theme/common/landscape.xml
@@ -1120,6 +1120,12 @@
<text>{@format_data_lcp2=removes encryption on internal storage.}</text>
</text>
+ <text style="text_m_fail">
+ <condition var1="tw_has_adopted_storage" var2="1"/>
+ <placement x="%center_x%" y="%row4_y%" placement="5"/>
+ <text>{@format_data_adopted=Including Adopted Storage}</text>
+ </text>
+
<text style="text_m">
<placement x="%center_x%" y="%row5_y%" placement="5"/>
<text>{@format_data_undo=This cannot be undone.}</text>
diff --git a/gui/theme/common/languages/en.xml b/gui/theme/common/languages/en.xml
index 5d7a5ac03..8b36ccfc0 100755
--- a/gui/theme/common/languages/en.xml
+++ b/gui/theme/common/languages/en.xml
@@ -143,6 +143,7 @@
<string name="format_data_ptr1">Format Data will wipe all of your apps,</string>
<string name="format_data_ptr2">backups, pictures, videos, media, and</string>
<string name="format_data_ptr3">removes encryption on internal storage.</string>
+ <string name="format_data_adopted">Including Adopted Storage</string>
<string name="format_data_lcp1">Format Data will wipe all of your apps, backups, pictures, videos, media, and</string>
<string name="format_data_lcp2">removes encryption on internal storage.</string>
<string name="format_data_wtc1">Format Data will wipe all of your apps,</string>
diff --git a/gui/theme/common/portrait.xml b/gui/theme/common/portrait.xml
index 03004aeff..0904c7254 100755
--- a/gui/theme/common/portrait.xml
+++ b/gui/theme/common/portrait.xml
@@ -1077,6 +1077,12 @@
<text>{@format_data_ptr3=removes encryption on internal storage.}</text>
</text>
+ <text style="text_m_fail">
+ <condition var1="tw_has_adopted_storage" var2="1"/>
+ <placement x="%center_x%" y="%row5_y%" placement="5"/>
+ <text>{@format_data_adopted=Including Adopted Storage}</text>
+ </text>
+
<text style="text_m">
<placement x="%center_x%" y="%row6_y%" placement="5"/>
<text>{@format_data_undo=This cannot be undone.}</text>
diff --git a/mtp/Android.mk b/mtp/Android.mk
index 57f0ae35e..34514b8c8 100755
--- a/mtp/Android.mk
+++ b/mtp/Android.mk
@@ -3,7 +3,6 @@ LOCAL_PATH := $(call my-dir)
# Build libtwrpmtp library
include $(CLEAR_VARS)
-
LOCAL_MODULE := libtwrpmtp
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -DMTP_DEVICE -DMTP_HOST -fno-strict-aliasing
diff --git a/partition.cpp b/partition.cpp
index 71d6f22a0..54bf5e179 100644
--- a/partition.cpp
+++ b/partition.cpp
@@ -26,6 +26,7 @@
#include <dirent.h>
#include <iostream>
#include <sstream>
+#include <sys/param.h>
#ifdef TW_INCLUDE_CRYPTO
#include "cutils/properties.h"
@@ -53,6 +54,7 @@ extern "C" {
#ifdef TW_INCLUDE_CRYPTO
#include "crypto/lollipop/cryptfs.h"
+ #include "gpt/gpt.h"
#else
#define CRYPT_FOOTER_OFFSET 0x4000
#endif
@@ -159,6 +161,8 @@ TWPartition::TWPartition() {
MTP_Storage_ID = 0;
Can_Flash_Img = false;
Mount_Read_Only = false;
+ Is_Adopted_Storage = false;
+ Adopted_GUID = "";
}
TWPartition::~TWPartition(void) {
@@ -703,28 +707,40 @@ void TWPartition::Setup_AndSec(void) {
void TWPartition::Setup_Data_Media() {
LOGINFO("Setting up '%s' as data/media emulated storage.\n", Mount_Point.c_str());
- Storage_Name = "Internal Storage";
+ if (Storage_Name.empty() || Storage_Name == "Data")
+ Storage_Name = "Internal Storage";
Has_Data_Media = true;
Is_Storage = true;
- Is_Settings_Storage = true;
- Storage_Path = "/data/media";
+ Storage_Path = Mount_Point + "/media";
Symlink_Path = Storage_Path;
- if (strcmp(EXPAND(TW_EXTERNAL_STORAGE_PATH), "/sdcard") == 0) {
- Make_Dir("/emmc", false);
- Symlink_Mount_Point = "/emmc";
+ if (Mount_Point == "/data") {
+ Is_Settings_Storage = true;
+ if (strcmp(EXPAND(TW_EXTERNAL_STORAGE_PATH), "/sdcard") == 0) {
+ Make_Dir("/emmc", false);
+ Symlink_Mount_Point = "/emmc";
+ } else {
+ Make_Dir("/sdcard", false);
+ Symlink_Mount_Point = "/sdcard";
+ }
+ if (Mount(false) && TWFunc::Path_Exists(Mount_Point + "/media/0")) {
+ Storage_Path = Mount_Point + "/media/0";
+ Symlink_Path = Storage_Path;
+ DataManager::SetValue(TW_INTERNAL_PATH, Mount_Point + "/media/0");
+ UnMount(true);
+ }
+ DataManager::SetValue("tw_has_internal", 1);
+ DataManager::SetValue("tw_has_data_media", 1);
+ du.add_absolute_dir(Mount_Point + "/misc/vold");
+ du.add_absolute_dir(Mount_Point + "/.layout_version");
+ du.add_absolute_dir(Mount_Point + "/system/storage.xml");
} else {
- Make_Dir("/sdcard", false);
- Symlink_Mount_Point = "/sdcard";
- }
- if (Mount(false) && TWFunc::Path_Exists("/data/media/0")) {
- Storage_Path = "/data/media/0";
- Symlink_Path = Storage_Path;
- DataManager::SetValue(TW_INTERNAL_PATH, "/data/media/0");
- UnMount(true);
+ if (Mount(true) && TWFunc::Path_Exists(Mount_Point + "/media/0")) {
+ Storage_Path = Mount_Point + "/media/0";
+ Symlink_Path = Storage_Path;
+ UnMount(true);
+ }
}
- DataManager::SetValue("tw_has_internal", 1);
- DataManager::SetValue("tw_has_data_media", 1);
- du.add_absolute_dir("/data/media");
+ du.add_absolute_dir(Mount_Point + "/media");
}
void TWPartition::Find_Real_Block_Device(string& Block, bool Display_Error) {
@@ -1204,7 +1220,7 @@ bool TWPartition::Wipe(string New_File_System) {
}
}
- if (Mount_Point == "/data" && Has_Data_Media && recreate_media) {
+ if (Has_Data_Media && recreate_media) {
Recreate_Media_Folder();
}
}
@@ -1907,30 +1923,42 @@ bool TWPartition::Wipe_Data_Without_Wiping_Media() {
// In an OEM Build we want to do a full format
return Wipe_Encryption();
#else
- string dir;
+ bool ret = false;
- // This handles wiping data on devices with "sdcard" in /data/media
if (!Mount(true))
return false;
gui_msg("wiping_data=Wiping data without wiping /data/media ...");
+ ret = Wipe_Data_Without_Wiping_Media_Func(Mount_Point + "/");
+ if (ret)
+ gui_msg("done=Done.");
+ return ret;
+#endif // ifdef TW_OEM_BUILD
+}
+
+bool TWPartition::Wipe_Data_Without_Wiping_Media_Func(const string& parent __unused) {
+ string dir;
DIR* d;
- d = opendir("/data");
+ d = opendir(parent.c_str());
if (d != NULL) {
struct dirent* de;
while ((de = readdir(d)) != NULL) {
if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) continue;
- // The media folder is the "internal sdcard"
- // The .layout_version file is responsible for determining whether 4.2 decides up upgrade
- // the media folder for multi-user.
- //TODO: convert this to use twrpDU.cpp
- if (strcmp(de->d_name, "media") == 0 || strcmp(de->d_name, ".layout_version") == 0) continue;
- dir = "/data/";
+ dir = parent;
dir.append(de->d_name);
+ if (du.check_skip_dirs(dir)) {
+ LOGINFO("skipped '%s'\n", dir.c_str());
+ continue;
+ }
if (de->d_type == DT_DIR) {
- TWFunc::removeDir(dir, false);
+ dir.append("/");
+ if (!Wipe_Data_Without_Wiping_Media_Func(dir)) {
+ closedir(d);
+ return false;
+ }
+ rmdir(dir.c_str());
} else if (de->d_type == DT_REG || de->d_type == DT_LNK || de->d_type == DT_FIFO || de->d_type == DT_SOCK) {
if (!unlink(dir.c_str()))
LOGINFO("Unable to unlink '%s'\n", dir.c_str());
@@ -1938,12 +1966,10 @@ bool TWPartition::Wipe_Data_Without_Wiping_Media() {
}
closedir(d);
- gui_msg("done=Done.");
return true;
}
gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(Mount_Point)(strerror(errno)));
return false;
-#endif // ifdef TW_OEM_BUILD
}
bool TWPartition::Backup_Tar(string backup_folder, const unsigned long long *overall_size, const unsigned long long *other_backups_size, pid_t &tar_fork_pid) {
@@ -2200,7 +2226,7 @@ bool TWPartition::Update_Size(bool Display_Error) {
if (Has_Data_Media) {
if (Mount(Display_Error)) {
unsigned long long data_media_used, actual_data;
- Used = du.Get_Folder_Size("/data");
+ Used = du.Get_Folder_Size(Mount_Point);
Backup_Size = Used;
int bak = (int)(Used / 1048576LLU);
int fre = (int)(Free / 1048576LLU);
@@ -2245,13 +2271,14 @@ void TWPartition::Find_Actual_Block_Device(void) {
void TWPartition::Recreate_Media_Folder(void) {
string Command;
+ string Media_Path = Mount_Point + "/media";
if (!Mount(true)) {
- gui_msg(Msg(msg::kError, "recreate_folder_err=Unable to recreate {1} folder.")("/data/media"));
- } else if (!TWFunc::Path_Exists("/data/media")) {
+ gui_msg(Msg(msg::kError, "recreate_folder_err=Unable to recreate {1} folder.")(Media_Path));
+ } else if (!TWFunc::Path_Exists(Media_Path)) {
PartitionManager.Mount_By_Path(Symlink_Mount_Point, true);
- LOGINFO("Recreating /data/media folder.\n");
- mkdir("/data/media", 0770);
+ LOGINFO("Recreating %s folder.\n", Media_Path.c_str());
+ mkdir(Media_Path.c_str(), 0770);
string Internal_path = DataManager::GetStrValue("tw_internal_path");
if (!Internal_path.empty()) {
LOGINFO("Recreating %s folder.\n", Internal_path.c_str());
@@ -2264,7 +2291,7 @@ void TWPartition::Recreate_Media_Folder(void) {
// Afterwards, we will try to set the
// default metadata that we were hopefully able to get during
// early boot.
- tw_set_default_metadata("/data/media");
+ tw_set_default_metadata(Media_Path.c_str());
if (!Internal_path.empty())
tw_set_default_metadata(Internal_path.c_str());
#endif
@@ -2401,3 +2428,141 @@ int TWPartition::Check_Lifetime_Writes() {
Mount_Read_Only = original_read_only;
return ret;
}
+
+int TWPartition::Decrypt_Adopted() {
+#ifdef TW_INCLUDE_CRYPTO
+ int ret = 1;
+ Is_Adopted_Storage = false;
+ string Adopted_Key_File = "";
+
+ if (!Removable)
+ return ret;
+
+ int fd = open(Alternate_Block_Device.c_str(), O_RDONLY);
+ if (fd < 0) {
+ LOGINFO("failed to open '%s'\n", Alternate_Block_Device.c_str());
+ return ret;
+ }
+ char type_guid[80];
+ char part_guid[80];
+
+ if (gpt_disk_get_partition_info(fd, 2, type_guid, part_guid) == 0) {
+ LOGINFO("type: '%s'\n", type_guid);
+ LOGINFO("part: '%s'\n", part_guid);
+ Adopted_GUID = part_guid;
+ LOGINFO("Adopted_GUID '%s'\n", Adopted_GUID.c_str());
+ if (strcmp(type_guid, TWGptAndroidExpand) == 0) {
+ LOGINFO("android_expand found\n");
+ Adopted_Key_File = "/data/misc/vold/expand_";
+ Adopted_Key_File += part_guid;
+ Adopted_Key_File += ".key";
+ if (TWFunc::Path_Exists(Adopted_Key_File)) {
+ Is_Adopted_Storage = true;
+ /* Until we find a use case for this, I think it is safe
+ * to disable USB Mass Storage whenever adopted storage
+ * is present.
+ */
+ LOGINFO("Detected adopted storage, disabling USB mass storage mode\n");
+ DataManager::SetValue("tw_has_usb_storage", 0);
+ }
+ }
+ }
+
+ if (Is_Adopted_Storage) {
+ string Adopted_Block_Device = Alternate_Block_Device + "p2";
+ if (!TWFunc::Path_Exists(Adopted_Block_Device)) {
+ Adopted_Block_Device = Alternate_Block_Device + "2";
+ if (!TWFunc::Path_Exists(Adopted_Block_Device)) {
+ LOGINFO("Adopted block device does not exist\n");
+ goto exit;
+ }
+ }
+ LOGINFO("key file is '%s', block device '%s'\n", Adopted_Key_File.c_str(), Adopted_Block_Device.c_str());
+ char crypto_blkdev[MAXPATHLEN];
+ std::string thekey;
+ int fdkey = open(Adopted_Key_File.c_str(), O_RDONLY);
+ if (fdkey < 0) {
+ LOGINFO("failed to open key file\n");
+ goto exit;
+ }
+ char buf[512];
+ ssize_t n;
+ while ((n = read(fdkey, &buf[0], sizeof(buf))) > 0) {
+ thekey.append(buf, n);
+ }
+ close(fdkey);
+ unsigned char* key = (unsigned char*) thekey.data();
+ cryptfs_revert_ext_volume(part_guid);
+
+ ret = cryptfs_setup_ext_volume(part_guid, Adopted_Block_Device.c_str(), key, thekey.size(), crypto_blkdev);
+ if (ret == 0) {
+ LOGINFO("adopted storage new block device: '%s'\n", crypto_blkdev);
+ Decrypted_Block_Device = crypto_blkdev;
+ Is_Decrypted = true;
+ Is_Encrypted = true;
+ Find_Actual_Block_Device();
+ if (!Mount(false)) {
+ LOGERR("Failed to mount decrypted adopted storage device\n");
+ Is_Decrypted = false;
+ Is_Encrypted = false;
+ cryptfs_revert_ext_volume(part_guid);
+ ret = 1;
+ } else {
+ Setup_Data_Media();
+ Recreate_Media_Folder();
+ Wipe_Available_in_GUI = true;
+ Wipe_During_Factory_Reset = true;
+ Can_Be_Backed_Up = true;
+ Can_Encrypt_Backup = true;
+ Use_Userdata_Encryption = true;
+ Is_Storage = true;
+ Storage_Name = "Adopted Storage";
+ Is_SubPartition = true;
+ SubPartition_Of = "/data";
+ PartitionManager.Add_MTP_Storage(MTP_Storage_ID);
+ DataManager::SetValue("tw_has_adopted_storage", 1);
+ }
+ } else {
+ LOGERR("Failed to setup adopted storage decryption\n");
+ }
+ }
+exit:
+ return ret;
+#else
+ LOGINFO("Decrypt_Adopted: no crypto support\n");
+ return 1;
+#endif
+}
+
+void TWPartition::Revert_Adopted() {
+#ifdef TW_INCLUDE_CRYPTO
+ if (!Adopted_GUID.empty()) {
+ PartitionManager.Remove_MTP_Storage(Mount_Point);
+ UnMount(false);
+ cryptfs_revert_ext_volume(Adopted_GUID.c_str());
+ Is_Adopted_Storage = false;
+ Is_Encrypted = false;
+ Is_Decrypted = false;
+ Decrypted_Block_Device = "";
+ Find_Actual_Block_Device();
+ Wipe_During_Factory_Reset = false;
+ Can_Be_Backed_Up = false;
+ Can_Encrypt_Backup = false;
+ Use_Userdata_Encryption = false;
+ Is_SubPartition = false;
+ SubPartition_Of = "";
+ Has_Data_Media = false;
+ Storage_Path = Mount_Point;
+ if (!Symlink_Mount_Point.empty()) {
+ TWPartition* Dat = PartitionManager.Find_Partition_By_Path("/data");
+ if (Dat) {
+ Dat->UnMount(false);
+ Dat->Symlink_Mount_Point = Symlink_Mount_Point;
+ }
+ Symlink_Mount_Point = "";
+ }
+ }
+#else
+ LOGINFO("Revert_Adopted: no crypto support\n");
+#endif
+}
diff --git a/partitionmanager.cpp b/partitionmanager.cpp
index 00c4f8fdd..81d448dc6 100644
--- a/partitionmanager.cpp
+++ b/partitionmanager.cpp
@@ -57,6 +57,8 @@ extern "C" {
#ifdef TW_INCLUDE_CRYPTO
#include "crypto/lollipop/cryptfs.h"
+ #include "gui/rapidxml.hpp"
+ #include "gui/pages.hpp"
#endif
extern bool datamedia;
@@ -167,6 +169,9 @@ int TWPartitionManager::Process_Fstab(string Fstab_Filename, bool Display_Error)
DataManager::SetValue("TW_CRYPTO_TYPE", password_type);
}
}
+ if (Decrypt_Data && (!Decrypt_Data->Is_Encrypted || Decrypt_Data->Is_Decrypted) && Decrypt_Data->Mount(false)) {
+ Decrypt_Adopted();
+ }
#endif
Update_System_Details();
UnMount_Main_Partitions();
@@ -276,6 +281,8 @@ void TWPartitionManager::Output_Partition(TWPartition* Part) {
printf("Mount_To_Decrypt ");
if (Part->Can_Flash_Img)
printf("Can_Flash_Img ");
+ if (Part->Is_Adopted_Storage)
+ printf("Is_Adopted_Storage ");
printf("\n");
if (!Part->SubPartition_Of.empty())
printf(" SubPartition_Of: %s\n", Part->SubPartition_Of.c_str());
@@ -1504,13 +1511,13 @@ int TWPartitionManager::Fix_Permissions(void) {
return result;
}
-TWPartition* TWPartitionManager::Find_Next_Storage(string Path, string Exclude) {
+TWPartition* TWPartitionManager::Find_Next_Storage(string Path, bool Exclude_Data_Media) {
std::vector<TWPartition*>::iterator iter = Partitions.begin();
if (!Path.empty()) {
string Search_Path = TWFunc::Get_Root_Path(Path);
for (; iter != Partitions.end(); iter++) {
- if ((*iter)->Mount_Point == Search_Path) {
+ if (Exclude_Data_Media && (*iter)->Has_Data_Media) {
iter++;
break;
}
@@ -1518,7 +1525,9 @@ TWPartition* TWPartitionManager::Find_Next_Storage(string Path, string Exclude)
}
for (; iter != Partitions.end(); iter++) {
- if ((*iter)->Is_Storage && (*iter)->Is_Present && (*iter)->Mount_Point != Exclude) {
+ if (Exclude_Data_Media && (*iter)->Has_Data_Media) {
+ // do nothing, do not return this type of partition
+ } else if ((*iter)->Is_Storage && (*iter)->Is_Present) {
return (*iter);
}
}
@@ -1563,7 +1572,7 @@ int TWPartitionManager::usb_storage_enable(void) {
LOGINFO("Device doesn't have multiple lun files, mount current storage\n");
sprintf(lun_file, CUSTOM_LUN_FILE, 0);
if (TWFunc::Get_Root_Path(DataManager::GetCurrentStoragePath()) == "/data") {
- TWPartition* Mount = Find_Next_Storage("", "/data");
+ TWPartition* Mount = Find_Next_Storage("", true);
if (Mount) {
if (!Open_Lun_File(Mount->Mount_Point, lun_file)) {
goto error_handle;
@@ -1580,13 +1589,13 @@ int TWPartitionManager::usb_storage_enable(void) {
TWPartition* Mount1;
TWPartition* Mount2;
sprintf(lun_file, CUSTOM_LUN_FILE, 0);
- Mount1 = Find_Next_Storage("", "/data");
+ Mount1 = Find_Next_Storage("", true);
if (Mount1) {
if (!Open_Lun_File(Mount1->Mount_Point, lun_file)) {
goto error_handle;
}
sprintf(lun_file, CUSTOM_LUN_FILE, 1);
- Mount2 = Find_Next_Storage(Mount1->Mount_Point, "/data");
+ Mount2 = Find_Next_Storage(Mount1->Mount_Point, true);
if (Mount2) {
Open_Lun_File(Mount2->Mount_Point, lun_file);
}
@@ -1668,6 +1677,9 @@ int TWPartitionManager::Partition_SDCard(void) {
// Locate and validate device to partition
TWPartition* SDCard = Find_Partition_By_Path(DataManager::GetCurrentStoragePath());
+ if (SDCard->Is_Adopted_Storage)
+ SDCard->Revert_Adopted();
+
if (SDCard == NULL || !SDCard->Removable || SDCard->Has_Data_Media) {
gui_err("partition_sd_locate=Unable to locate device to partition.");
return false;
@@ -2263,22 +2275,35 @@ bool TWPartitionManager::Flash_Image(string Filename) {
void TWPartitionManager::Translate_Partition(const char* path, const char* resource_name, const char* default_value) {
TWPartition* part = PartitionManager.Find_Partition_By_Path(path);
if (part) {
- part->Display_Name = gui_lookup(resource_name, default_value);
- part->Backup_Display_Name = part->Display_Name;
+ if (part->Is_Adopted_Storage) {
+ part->Display_Name = part->Display_Name + " - " + gui_lookup("data", "Data");
+ part->Backup_Display_Name = part->Display_Name;
+ part->Storage_Name = part->Storage_Name + " - " + gui_lookup("adopted_storage", "Adopted Storage");
+ } else {
+ part->Display_Name = gui_lookup(resource_name, default_value);
+ part->Backup_Display_Name = part->Display_Name;
+ }
}
}
void TWPartitionManager::Translate_Partition(const char* path, const char* resource_name, const char* default_value, const char* storage_resource_name, const char* storage_default_value) {
TWPartition* part = PartitionManager.Find_Partition_By_Path(path);
if (part) {
- part->Display_Name = gui_lookup(resource_name, default_value);
- part->Backup_Display_Name = part->Display_Name;
- if (part->Is_Storage)
- part->Storage_Name = gui_lookup(storage_resource_name, storage_default_value);
+ if (part->Is_Adopted_Storage) {
+ part->Display_Name = part->Display_Name + " - " + gui_lookup("data", "Data");
+ part->Backup_Display_Name = part->Display_Name;
+ part->Storage_Name = part->Storage_Name + " - " + gui_lookup("adopted_storage", "Adopted Storage");
+ } else {
+ part->Display_Name = gui_lookup(resource_name, default_value);
+ part->Backup_Display_Name = part->Display_Name;
+ if (part->Is_Storage)
+ part->Storage_Name = gui_lookup(storage_resource_name, storage_default_value);
+ }
}
}
void TWPartitionManager::Translate_Partition_Display_Names() {
+ LOGINFO("Translating partition display names\n");
Translate_Partition("/system", "system", "System");
Translate_Partition("/system_image", "system_image", "System Image");
Translate_Partition("/vendor", "vendor", "Vendor");
@@ -2306,3 +2331,86 @@ void TWPartitionManager::Translate_Partition_Display_Names() {
// This updates the text on all of the storage selection buttons in the GUI
DataManager::SetBackupFolder();
}
+
+void TWPartitionManager::Decrypt_Adopted() {
+#ifdef TW_INCLUDE_CRYPTO
+ if (!Mount_By_Path("/data", false)) {
+ LOGERR("Cannot decrypt adopted storage because /data will not mount\n");
+ return;
+ }
+ LOGINFO("Decrypt adopted storage starting\n");
+ char* xmlFile = PageManager::LoadFileToBuffer("/data/system/storage.xml", NULL);
+ xml_document<> *doc = NULL;
+ xml_node<>* volumes = NULL;
+ xml_node<>* volume = NULL;
+ string Primary_Storage_UUID = "";
+ if (xmlFile != NULL) {
+ LOGINFO("successfully loaded storage.xml\n");
+ doc = new xml_document<>();
+ doc->parse<0>(xmlFile);
+ volumes = doc->first_node("volumes");
+ if (volumes) {
+ xml_attribute<>* psuuid = volumes->first_attribute("primaryStorageUuid");
+ if (psuuid) {
+ Primary_Storage_UUID = psuuid->value();
+ }
+ }
+ }
+ std::vector<TWPartition*>::iterator adopt;
+ for (adopt = Partitions.begin(); adopt != Partitions.end(); adopt++) {
+ if ((*adopt)->Removable && (*adopt)->Is_Present) {
+ if ((*adopt)->Decrypt_Adopted() == 0) {
+ if (volumes) {
+ xml_node<>* volume = volumes->first_node("volume");
+ while (volume) {
+ xml_attribute<>* guid = volume->first_attribute("partGuid");
+ if (guid) {
+ string GUID = (*adopt)->Adopted_GUID.c_str();
+ GUID.insert(8, "-");
+ GUID.insert(13, "-");
+ GUID.insert(18, "-");
+ GUID.insert(23, "-");
+
+ if (strcasecmp(GUID.c_str(), guid->value()) == 0) {
+ xml_attribute<>* attr = volume->first_attribute("nickname");
+ if (attr) {
+ (*adopt)->Storage_Name = attr->value();
+ (*adopt)->Display_Name = (*adopt)->Storage_Name;
+ (*adopt)->Backup_Display_Name = (*adopt)->Storage_Name;
+ LOGINFO("storage name from storage.xml is '%s'\n", attr->value());
+ }
+ attr = volume->first_attribute("fsUuid");
+ if (attr && !Primary_Storage_UUID.empty() && strcmp(Primary_Storage_UUID.c_str(), attr->value()) == 0) {
+ TWPartition* Dat = Find_Partition_By_Path("/data");
+ if (Dat) {
+ LOGINFO("Internal storage is found on adopted storage '%s'\n", (*adopt)->Display_Name.c_str());
+ LOGINFO("Changing '%s' to point to '%s'\n", Dat->Symlink_Mount_Point.c_str(), (*adopt)->Storage_Path.c_str());
+ (*adopt)->Symlink_Mount_Point = Dat->Symlink_Mount_Point;
+ Dat->Symlink_Mount_Point = "";
+ // Toggle mounts to ensure that the symlink mount point (probably /sdcard) is mounted to the right location
+ Dat->UnMount(false);
+ Dat->Mount(false);
+ (*adopt)->UnMount(false);
+ (*adopt)->Mount(false);
+ Output_Partition((*adopt));
+ }
+ }
+ break;
+ }
+ }
+ volume = volume->next_sibling("volume");
+ }
+ }
+ }
+ }
+ }
+ if (xmlFile) {
+ doc->clear();
+ delete doc;
+ free(xmlFile);
+ }
+#else
+ LOGINFO("Decrypt_Adopted: no crypto support\n");
+ return;
+#endif
+}
diff --git a/partitions.hpp b/partitions.hpp
index e802f3468..bc44384ee 100644
--- a/partitions.hpp
+++ b/partitions.hpp
@@ -74,6 +74,8 @@ public:
bool Flash_Image(string Filename); // Flashes an image to the partition
void Change_Mount_Read_Only(bool new_value); // Changes Mount_Read_Only to new_value
int Check_Lifetime_Writes();
+ int Decrypt_Adopted();
+ void Revert_Adopted();
public:
string Current_File_System; // Current file system
@@ -82,6 +84,7 @@ public:
bool Is_Present; // Indicates if the partition is currently present as a block device
string Crypto_Key_Location; // Location of the crypto key used for decrypting encrypted data partitions
unsigned int MTP_Storage_ID;
+ string Adopted_GUID;
protected:
bool Has_Data_Media; // Indicates presence of /data/media, may affect wiping and backup methods
@@ -111,6 +114,7 @@ private:
bool Wipe_F2FS(); // Uses mkfs.f2fs to wipe
bool Wipe_NTFS(); // Uses mkntfs to wipe
bool Wipe_Data_Without_Wiping_Media(); // Uses rm -rf to wipe but does not wipe /data/media
+ bool Wipe_Data_Without_Wiping_Media_Func(const string& parent); // Uses rm -rf to wipe but does not wipe /data/media
bool Backup_Tar(string backup_folder, const unsigned long long *overall_size, const unsigned long long *other_backups_size, pid_t &tar_fork_pid); // Backs up using tar for file systems
bool Backup_DD(string backup_folder); // Backs up using dd for emmc memory types
bool Backup_Dump_Image(string backup_folder); // Backs up using dump_image for MTD memory types
@@ -174,6 +178,7 @@ private:
bool Retain_Layout_Version; // Retains the .layout_version file during a wipe (needed on devices like Sony Xperia T where /data and /data/media are separate partitions)
bool Can_Flash_Img; // Indicates if this partition can have images flashed to it via the GUI
bool Mount_Read_Only; // Only mount this partition as read-only
+ bool Is_Adopted_Storage; // Indicates that this partition is for adopted storage (android_expand)
friend class TWPartitionManager;
friend class DataManager;
@@ -238,6 +243,7 @@ public:
void Translate_Partition(const char* path, const char* resource_name, const char* default_value);
void Translate_Partition(const char* path, const char* resource_name, const char* default_value, const char* storage_resource_name, const char* storage_default_value);
void Translate_Partition_Display_Names(); // Updates display names based on translations
+ void Decrypt_Adopted();
TWAtomicInt stop_backup;
@@ -250,7 +256,7 @@ private:
void Output_Partition(TWPartition* Part);
TWPartition* Find_Partition_By_MTP_Storage_ID(unsigned int Storage_ID); // Returns a pointer to a partition based on MTP Storage ID
bool Add_Remove_MTP_Storage(TWPartition* Part, int message_type); // Adds or removes an MTP Storage partition
- TWPartition* Find_Next_Storage(string Path, string Exclude);
+ TWPartition* Find_Next_Storage(string Path, bool Exclude_Data_Media);
int Open_Lun_File(string Partition_Path, string Lun_File);
pid_t mtppid;
bool mtp_was_enabled;
diff --git a/prebuilt/Android.mk b/prebuilt/Android.mk
index ea83286c1..825b990ea 100644
--- a/prebuilt/Android.mk
+++ b/prebuilt/Android.mk
@@ -155,6 +155,7 @@ ifeq ($(TW_INCLUDE_CRYPTO), true)
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libcryptfslollipop.so
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libcrypto.so
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libhardware.so
+ RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libgpt_twrp.so
ifeq ($(TARGET_HW_DISK_ENCRYPTION),true)
RELINK_SOURCE_FILES += $(TARGET_OUT_VENDOR_SHARED_LIBRARIES)/libcryptfs_hw.so
endif