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
This commit is contained in:
Ethan Yonker
2015-12-10 10:19:45 -06:00
committed by Dees Troy
parent 56a7a99d8e
commit 66a1949df9
18 changed files with 1427 additions and 53 deletions
+2 -1
View File
@@ -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
+44 -1
View File
@@ -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);
}
+3
View File
@@ -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
+3 -1
View File
@@ -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);
}
Executable
+15
View File
@@ -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)
+675
View File
@@ -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:
*/
+182
View File
@@ -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:
*/
+124
View File
@@ -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;
}
+36
View File
@@ -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 */
+1
View File
@@ -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();
}
}
+6
View File
@@ -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>
+1
View File
@@ -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>
+6
View File
@@ -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>
-1
View File
@@ -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
+201 -36
View File
@@ -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(true) && TWFunc::Path_Exists(Mount_Point + "/media/0")) {
Storage_Path = Mount_Point + "/media/0";
Symlink_Path = Storage_Path;
UnMount(true);
}
}
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);
}
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
}
+120 -12
View File
@@ -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
}
+7 -1
View File
@@ -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;
+1
View File
@@ -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