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 --- partition.cpp | 237 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 201 insertions(+), 36 deletions(-) (limited to 'partition.cpp') 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 +} -- cgit v1.2.3