From 66a1949df91cc558bf5573c395fa9084c1365e81 Mon Sep 17 00:00:00 2001 From: Ethan Yonker Date: Thu, 10 Dec 2015 10:19:45 -0600 Subject: Adopted Storage support -Detects, decrypts, and mounts an adopted SD card if a secondary block device is defined (usually mmcblk1) -Handles unified storage -Displays the adopted storage in MTP along with internal -Factory Reset - wiped just like a data media device, we retain the keys folder and the storage.xml during a factory reset -Backup / Restore -Disable mass storage when adopted storage is present -Read storage nickname from storage.xml and apply it to display names in the GUI -Read storage.xml and determine what storage location is in use for /sdcard and remap accordingly libgpt_twrp is source code mostly kanged from an efimanager project. It is GPL v2 or higher, so we will opt for GPL v3. Change-Id: Ieda0030bec5155ba8d2b9167dc0016cebbf39d55 --- Android.mk | 3 +- crypto/lollipop/cryptfs.c | 45 ++- crypto/lollipop/cryptfs.h | 3 + data.cpp | 4 +- gpt/Android.mk | 15 + gpt/gpt.c | 675 ++++++++++++++++++++++++++++++++++++++ gpt/gpt.h | 182 ++++++++++ gpt/gptcrc32.c | 124 +++++++ gpt/gptcrc32.h | 36 ++ gui/action.cpp | 1 + gui/theme/common/landscape.xml | 6 + gui/theme/common/languages/en.xml | 1 + gui/theme/common/portrait.xml | 6 + mtp/Android.mk | 1 - partition.cpp | 237 +++++++++++-- partitionmanager.cpp | 132 +++++++- partitions.hpp | 8 +- prebuilt/Android.mk | 1 + 18 files changed, 1427 insertions(+), 53 deletions(-) create mode 100755 gpt/Android.mk create mode 100644 gpt/gpt.c create mode 100644 gpt/gpt.h create mode 100644 gpt/gptcrc32.c create mode 100644 gpt/gptcrc32.h 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 + + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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, §or_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, §ors); + 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 + + 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 +//#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 + * - 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 + +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 + +/* + * 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 @@ {@format_data_lcp2=removes encryption on internal storage.} + + + + {@format_data_adopted=Including Adopted Storage} + + {@format_data_undo=This cannot be undone.} 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 @@ Format Data will wipe all of your apps, backups, pictures, videos, media, and removes encryption on internal storage. + Including Adopted Storage Format Data will wipe all of your apps, backups, pictures, videos, media, and removes encryption on internal storage. Format Data will wipe all of your apps, 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 @@ {@format_data_ptr3=removes encryption on internal storage.} + + + + {@format_data_adopted=Including Adopted Storage} + + {@format_data_undo=This cannot be undone.} 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 #include #include +#include #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::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::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 -- cgit v1.2.3