Files
android_bootable_recovery/partition.cpp
Dees_Troy c51f1f994a Various fixes
Modify AOSP mount and wipe functions to use Partition Manager.
Update wipe code to reset the log file index when wiping cache.
Add ADB sideload to 540x960 theme.
2012-09-20 15:32:50 -04:00

1273 lines
34 KiB
C++

/* Partition class for TWRP
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* The code was written from scratch by Dees_Troy dees_troy at
* yahoo
*
* Copyright (c) 2012
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/vfs.h>
#include <sys/mount.h>
#include <unistd.h>
#include <dirent.h>
#ifdef TW_INCLUDE_CRYPTO
#include "cutils/properties.h"
#endif
#include "variables.h"
#include "common.h"
#include "partitions.hpp"
#include "data.hpp"
#include "twrp-functions.hpp"
extern "C" {
#include "mtdutils/mtdutils.h"
#include "mtdutils/mounts.h"
#include "makelist.h"
#include "extra-functions.h"
}
TWPartition::TWPartition(void) {
Can_Be_Mounted = false;
Can_Be_Wiped = false;
Wipe_During_Factory_Reset = false;
Wipe_Available_in_GUI = false;
Is_SubPartition = false;
SubPartition_Of = "";
Symlink_Path = "";
Symlink_Mount_Point = "";
Mount_Point = "";
Actual_Block_Device = "";
Primary_Block_Device = "";
Alternate_Block_Device = "";
Removable = false;
Is_Present = false;
Length = 0;
Size = 0;
Used = 0;
Free = 0;
Backup_Size = 0;
Can_Be_Encrypted = false;
Is_Encrypted = false;
Is_Decrypted = false;
Decrypted_Block_Device = "";
Display_Name = "";
Backup_Name = "";
Backup_FileName = "";
MTD_Name = "";
Backup_Method = NONE;
Has_Data_Media = false;
Is_Storage = false;
Storage_Path = "";
Current_File_System = "";
Fstab_File_System = "";
Format_Block_Size = 0;
}
TWPartition::~TWPartition(void) {
// Do nothing
}
bool TWPartition::Process_Fstab_Line(string Line, bool Display_Error) {
char full_line[MAX_FSTAB_LINE_LENGTH], item[MAX_FSTAB_LINE_LENGTH];
int line_len = Line.size(), index = 0, item_index = 0;
char* ptr;
string Flags;
strncpy(full_line, Line.c_str(), line_len);
for (index = 0; index < line_len; index++) {
if (full_line[index] <= 32)
full_line[index] = '\0';
}
string mount_pt(full_line);
Mount_Point = mount_pt;
index = Mount_Point.size();
while (index < line_len) {
while (index < line_len && full_line[index] == '\0')
index++;
if (index >= line_len)
continue;
ptr = full_line + index;
if (item_index == 0) {
// File System
Fstab_File_System = ptr;
Current_File_System = ptr;
item_index++;
} else if (item_index == 1) {
// Primary Block Device
if (Fstab_File_System == "mtd" || Fstab_File_System == "yaffs2") {
Primary_Block_Device = ptr;
Find_MTD_Block_Device(Primary_Block_Device);
} else if (*ptr != '/') {
if (Display_Error)
LOGE("Invalid block device on '%s', '%s', %i\n", Line.c_str(), ptr, index);
else
LOGI("Invalid block device on '%s', '%s', %i\n", Line.c_str(), ptr, index);
return 0;
} else {
Primary_Block_Device = ptr;
Find_Real_Block_Device(Primary_Block_Device, Display_Error);
}
item_index++;
} else if (item_index > 1) {
if (*ptr == '/') {
// Alternate Block Device
Alternate_Block_Device = ptr;
Find_Real_Block_Device(Alternate_Block_Device, Display_Error);
} else if (strlen(ptr) > 7 && strncmp(ptr, "length=", 7) == 0) {
// Partition length
ptr += 7;
Length = atoi(ptr);
} else if (strlen(ptr) > 6 && strncmp(ptr, "flags=", 6) == 0) {
// Custom flags, save for later so that new values aren't overwritten by defaults
ptr += 6;
Flags = ptr;
} else if (strlen(ptr) == 4 && (strncmp(ptr, "NULL", 4) == 0 || strncmp(ptr, "null", 4) == 0 || strncmp(ptr, "null", 4) == 0)) {
// Do nothing
} else {
// Unhandled data
LOGI("Unhandled fstab information: '%s', %i\n", ptr, index);
}
}
while (index < line_len && full_line[index] != '\0')
index++;
}
if (!Is_File_System(Fstab_File_System) && !Is_Image(Fstab_File_System)) {
if (Display_Error)
LOGE("Unknown File System: '%s'\n", Fstab_File_System.c_str());
else
LOGI("Unknown File System: '%s'\n", Fstab_File_System.c_str());
return 0;
} else if (Is_File_System(Fstab_File_System)) {
Find_Actual_Block_Device();
Setup_File_System(Display_Error);
if (Mount_Point == "/system") {
Display_Name = "System";
Wipe_Available_in_GUI = true;
MTD_Name = "system";
} else if (Mount_Point == "/data") {
Display_Name = "Data";
Wipe_Available_in_GUI = true;
Wipe_During_Factory_Reset = true;
MTD_Name = "userdata";
#ifdef RECOVERY_SDCARD_ON_DATA
Has_Data_Media = true;
Is_Storage = true;
Storage_Path = "/data/media";
if (strcmp(EXPAND(TW_EXTERNAL_STORAGE_PATH), "/sdcard") == 0) {
Make_Dir("/emmc", Display_Error);
Symlink_Path = "/data/media";
Symlink_Mount_Point = "/emmc";
} else {
Make_Dir("/sdcard", Display_Error);
Symlink_Path = "/data/media";
Symlink_Mount_Point = "/sdcard";
}
#endif
#ifdef TW_INCLUDE_CRYPTO
Can_Be_Encrypted = true;
char crypto_blkdev[255];
property_get("ro.crypto.fs_crypto_blkdev", crypto_blkdev, "error");
if (strcmp(crypto_blkdev, "error") != 0) {
DataManager::SetValue(TW_DATA_BLK_DEVICE, Primary_Block_Device);
DataManager::SetValue(TW_IS_DECRYPTED, 1);
Is_Encrypted = true;
Is_Decrypted = true;
Decrypted_Block_Device = crypto_blkdev;
LOGI("Data already decrypted, new block device: '%s'\n", crypto_blkdev);
} else if (!Mount(false)) {
Is_Encrypted = true;
Is_Decrypted = false;
DataManager::SetValue(TW_IS_ENCRYPTED, 1);
DataManager::SetValue(TW_CRYPTO_PASSWORD, "");
DataManager::SetValue("tw_crypto_display", "");
}
#endif
} else if (Mount_Point == "/cache") {
Display_Name = "Cache";
Wipe_Available_in_GUI = true;
Wipe_During_Factory_Reset = true;
MTD_Name = "cache";
} else if (Mount_Point == "/datadata") {
Wipe_During_Factory_Reset = true;
Display_Name = "DataData";
Is_SubPartition = true;
SubPartition_Of = "/data";
DataManager::SetValue(TW_HAS_DATADATA, 1);
} else if (Mount_Point == "/sd-ext") {
Wipe_During_Factory_Reset = true;
Display_Name = "SD-Ext";
Wipe_Available_in_GUI = true;
Removable = true;
}
#ifdef TW_EXTERNAL_STORAGE_PATH
if (Mount_Point == EXPAND(TW_EXTERNAL_STORAGE_PATH)) {
Is_Storage = true;
Storage_Path = EXPAND(TW_EXTERNAL_STORAGE_PATH);
Removable = true;
}
#else
if (Mount_Point == "/sdcard") {
Is_Storage = true;
Storage_Path = "/sdcard";
Removable = true;
}
#endif
#ifdef TW_INTERNAL_STORAGE_PATH
if (Mount_Point == EXPAND(TW_INTERNAL_STORAGE_PATH)) {
Is_Storage = true;
Storage_Path = EXPAND(TW_INTERNAL_STORAGE_PATH);
}
#else
if (Mount_Point == "/emmc") {
Is_Storage = true;
Storage_Path = "/emmc";
}
#endif
} else if (Is_Image(Fstab_File_System)) {
Find_Actual_Block_Device();
Setup_Image(Display_Error);
if (Mount_Point == "/boot") {
MTD_Name = "boot";
int backup_display_size = (int)(Backup_Size / 1048576LLU);
DataManager::SetValue(TW_BACKUP_BOOT_SIZE, backup_display_size);
if (Backup_Size == 0) {
DataManager::SetValue(TW_HAS_BOOT_PARTITION, 0);
DataManager::SetValue(TW_BACKUP_BOOT_VAR, 0);
} else
DataManager::SetValue(TW_HAS_BOOT_PARTITION, 1);
} else if (Mount_Point == "/recovery") {
MTD_Name = "recovery";
int backup_display_size = (int)(Backup_Size / 1048576LLU);
DataManager::SetValue(TW_BACKUP_RECOVERY_SIZE, backup_display_size);
if (Backup_Size == 0) {
DataManager::SetValue(TW_HAS_RECOVERY_PARTITION, 0);
DataManager::SetValue(TW_BACKUP_RECOVERY_VAR, 0);
} else
DataManager::SetValue(TW_HAS_RECOVERY_PARTITION, 1);
}
}
// Process any custom flags
if (Flags.size() > 0)
Process_Flags(Flags, Display_Error);
return true;
}
bool TWPartition::Process_Flags(string Flags, bool Display_Error) {
char flags[MAX_FSTAB_LINE_LENGTH];
int flags_len, index = 0;
char* ptr;
strcpy(flags, Flags.c_str());
flags_len = Flags.size();
for (index = 0; index < flags_len; index++) {
if (flags[index] == ';')
flags[index] = '\0';
}
index = 0;
while (index < flags_len) {
while (index < flags_len && flags[index] == '\0')
index++;
if (index >= flags_len)
continue;
ptr = flags + index;
if (strcmp(ptr, "removable") == 0) {
Removable = true;
} else if (strcmp(ptr, "storage") == 0) {
Is_Storage = true;
} else if (strcmp(ptr, "canbewiped") == 0) {
Can_Be_Wiped = true;
} else if (strcmp(ptr, "wipeingui") == 0) {
Can_Be_Wiped = true;
Wipe_Available_in_GUI = true;
} else if (strcmp(ptr, "wipeduringfactoryreset") == 0) {
Can_Be_Wiped = true;
Wipe_Available_in_GUI = true;
Wipe_During_Factory_Reset = true;
} else if (strlen(ptr) > 15 && strncmp(ptr, "subpartitionof=", 15) == 0) {
ptr += 13;
Is_SubPartition = true;
SubPartition_Of = ptr;
} else if (strlen(ptr) > 8 && strncmp(ptr, "symlink=", 8) == 0) {
ptr += 8;
Symlink_Path = ptr;
} else if (strlen(ptr) > 8 && strncmp(ptr, "display=", 8) == 0) {
ptr += 8;
Display_Name = ptr;
} else if (strlen(ptr) > 10 && strncmp(ptr, "blocksize=", 10) == 0) {
ptr += 10;
Format_Block_Size = atoi(ptr);
} else if (strlen(ptr) > 7 && strncmp(ptr, "length=", 7) == 0) {
ptr += 7;
Length = atoi(ptr);
} else {
if (Display_Error)
LOGE("Unhandled flag: '%s'\n", ptr);
else
LOGI("Unhandled flag: '%s'\n", ptr);
}
while (index < flags_len && flags[index] != '\0')
index++;
}
return true;
}
bool TWPartition::Is_File_System(string File_System) {
if (File_System == "ext2" ||
File_System == "ext3" ||
File_System == "ext4" ||
File_System == "vfat" ||
File_System == "ntfs" ||
File_System == "yaffs2" ||
File_System == "auto")
return true;
else
return false;
}
bool TWPartition::Is_Image(string File_System) {
if (File_System == "emmc" ||
File_System == "mtd")
return true;
else
return false;
}
bool TWPartition::Make_Dir(string Path, bool Display_Error) {
if (!TWFunc::Path_Exists(Path)) {
if (mkdir(Path.c_str(), 0777) == -1) {
if (Display_Error)
LOGE("Can not create '%s' folder.\n", Path.c_str());
else
LOGI("Can not create '%s' folder.\n", Path.c_str());
return false;
} else {
LOGI("Created '%s' folder.\n", Path.c_str());
return true;
}
}
return true;
}
void TWPartition::Setup_File_System(bool Display_Error) {
struct statfs st;
Can_Be_Mounted = true;
Can_Be_Wiped = true;
// Make the mount point folder if it doesn't exist
Make_Dir(Mount_Point, Display_Error);
Display_Name = Mount_Point.substr(1, Mount_Point.size() - 1);
Backup_Name = Display_Name;
Backup_Method = FILES;
}
void TWPartition::Setup_Image(bool Display_Error) {
Display_Name = Mount_Point.substr(1, Mount_Point.size() - 1);
Backup_Name = Display_Name;
if (Fstab_File_System == "emmc")
Backup_Method = DD;
else if (Fstab_File_System == "mtd")
Backup_Method = FLASH_UTILS;
else
LOGI("Unhandled file system '%s' on image '%s'\n", Fstab_File_System.c_str(), Display_Name.c_str());
if (Find_Partition_Size()) {
Used = Size;
Backup_Size = Size;
} else {
if (Display_Error)
LOGE("Unable to find parition size for '%s'\n", Mount_Point.c_str());
else
LOGI("Unable to find parition size for '%s'\n", Mount_Point.c_str());
}
}
void TWPartition::Find_Real_Block_Device(string& Block, bool Display_Error) {
char device[512], realDevice[512];
strcpy(device, Block.c_str());
memset(realDevice, 0, sizeof(realDevice));
while (readlink(device, realDevice, sizeof(realDevice)) > 0)
{
strcpy(device, realDevice);
memset(realDevice, 0, sizeof(realDevice));
}
if (device[0] != '/') {
if (Display_Error)
LOGE("Invalid symlink path '%s' found on block device '%s'\n", device, Block.c_str());
else
LOGI("Invalid symlink path '%s' found on block device '%s'\n", device, Block.c_str());
return;
} else {
Block = device;
return;
}
}
bool TWPartition::Find_MTD_Block_Device(string MTD_Name) {
FILE *fp = NULL;
char line[255];
fp = fopen("/proc/mtd", "rt");
if (fp == NULL) {
LOGE("Device does not support /proc/mtd\n");
return false;
}
while (fgets(line, sizeof(line), fp) != NULL)
{
char device[32], label[32];
unsigned long size = 0;
char* fstype = NULL;
int deviceId;
sscanf(line, "%s %lx %*s %*c%s", device, &size, label);
// Skip header and blank lines
if ((strcmp(device, "dev:") == 0) || (strlen(line) < 8))
continue;
// Strip off the trailing " from the label
label[strlen(label)-1] = '\0';
if (strcmp(label, MTD_Name.c_str()) == 0) {
// We found our device
// Strip off the trailing : from the device
device[strlen(device)-1] = '\0';
if (sscanf(device,"mtd%d", &deviceId) == 1) {
sprintf(device, "/dev/block/mtdblock%d", deviceId);
Primary_Block_Device = device;
}
}
}
fclose(fp);
return false;
}
bool TWPartition::Get_Size_Via_statfs(bool Display_Error) {
struct statfs st;
string Local_Path = Mount_Point + "/.";
if (!Mount(Display_Error))
return false;
if (statfs(Local_Path.c_str(), &st) != 0) {
if (!Removable) {
if (Display_Error)
LOGE("Unable to statfs '%s'\n", Local_Path.c_str());
else
LOGI("Unable to statfs '%s'\n", Local_Path.c_str());
}
return false;
}
Size = (st.f_blocks * st.f_bsize);
Used = ((st.f_blocks - st.f_bfree) * st.f_bsize);
Free = (st.f_bfree * st.f_bsize);
Backup_Size = Used;
return true;
}
bool TWPartition::Get_Size_Via_df(bool Display_Error) {
FILE* fp;
char command[255], line[512];
int include_block = 1;
unsigned int min_len;
if (!Mount(Display_Error))
return false;
min_len = Actual_Block_Device.size() + 2;
sprintf(command, "df %s > /tmp/dfoutput.txt", Mount_Point.c_str());
system(command);
fp = fopen("/tmp/dfoutput.txt", "rt");
if (fp == NULL) {
LOGI("Unable to open /tmp/dfoutput.txt.\n");
return false;
}
while (fgets(line, sizeof(line), fp) != NULL)
{
unsigned long blocks, used, available;
char device[64];
char tmpString[64];
if (strncmp(line, "Filesystem", 10) == 0)
continue;
if (strlen(line) < min_len) {
include_block = 0;
continue;
}
if (include_block) {
sscanf(line, "%s %lu %lu %lu", device, &blocks, &used, &available);
} else {
// The device block string is so long that the df information is on the next line
int space_count = 0;
while (tmpString[space_count] == 32)
space_count++;
sscanf(line + space_count, "%lu %lu %lu", &blocks, &used, &available);
}
// Adjust block size to byte size
Size = blocks * 1024ULL;
Used = used * 1024ULL;
Free = available * 1024ULL;
Backup_Size = Used;
}
fclose(fp);
return true;
}
bool TWPartition::Find_Partition_Size(void) {
FILE* fp;
char line[512];
string tmpdevice;
// In this case, we'll first get the partitions we care about (with labels)
fp = fopen("/proc/partitions", "rt");
if (fp == NULL)
return false;
while (fgets(line, sizeof(line), fp) != NULL)
{
unsigned long major, minor, blocks;
char device[512];
char tmpString[64];
if (strlen(line) < 7 || line[0] == 'm') continue;
sscanf(line + 1, "%lu %lu %lu %s", &major, &minor, &blocks, device);
tmpdevice = "/dev/block/";
tmpdevice += device;
if (tmpdevice == Primary_Block_Device || tmpdevice == Alternate_Block_Device) {
// Adjust block size to byte size
Size = blocks * 1024ULL;
fclose(fp);
return true;
}
}
fclose(fp);
return false;
}
void TWPartition::Flip_Block_Device(void) {
string temp;
temp = Alternate_Block_Device;
Primary_Block_Device = Alternate_Block_Device;
Alternate_Block_Device = temp;
}
bool TWPartition::Is_Mounted(void) {
if (!Can_Be_Mounted)
return false;
struct stat st1, st2;
string test_path;
// Check to see if the mount point directory exists
test_path = Mount_Point + "/.";
if (stat(test_path.c_str(), &st1) != 0) return false;
// Check to see if the directory above the mount point exists
test_path = Mount_Point + "/../.";
if (stat(test_path.c_str(), &st2) != 0) return false;
// Compare the device IDs -- if they match then we're (probably) using tmpfs instead of an actual device
int ret = (st1.st_dev != st2.st_dev) ? true : false;
return ret;
}
bool TWPartition::Mount(bool Display_Error) {
if (Is_Mounted()) {
return true;
} else if (!Can_Be_Mounted) {
return false;
}
Find_Actual_Block_Device();
// Check the current file system before mounting
Check_FS_Type();
if (mount(Actual_Block_Device.c_str(), Mount_Point.c_str(), Current_File_System.c_str(), 0, NULL) != 0) {
if (Display_Error)
LOGE("Unable to mount '%s'\n", Mount_Point.c_str());
else
LOGI("Unable to mount '%s'\n", Mount_Point.c_str());
return false;
} else {
if (Removable)
Update_Size(Display_Error);
if (!Symlink_Mount_Point.empty()) {
string Command;
Command = "mount " + Symlink_Path + " " + Symlink_Mount_Point;
system(Command.c_str());
}
return true;
}
return true;
}
bool TWPartition::UnMount(bool Display_Error) {
if (Is_Mounted()) {
int never_unmount_system;
DataManager::GetValue(TW_DONT_UNMOUNT_SYSTEM, never_unmount_system);
if (never_unmount_system == 1 && Mount_Point == "/system")
return true; // Never unmount system if you're not supposed to unmount it
if (!Symlink_Mount_Point.empty())
umount(Symlink_Mount_Point.c_str());
if (umount(Mount_Point.c_str()) != 0) {
if (Display_Error)
LOGE("Unable to unmount '%s'\n", Mount_Point.c_str());
else
LOGI("Unable to unmount '%s'\n", Mount_Point.c_str());
return false;
} else
return true;
} else {
return true;
}
}
bool TWPartition::Wipe() {
if (!Can_Be_Wiped) {
LOGE("Partition '%s' cannot be wiped.\n", Mount_Point.c_str());
return false;
}
if (Mount_Point == "/cache")
tmplog_offset = 0;
if (Has_Data_Media)
return Wipe_Data_Without_Wiping_Media();
int check;
DataManager::GetValue(TW_RM_RF_VAR, check);
if (check)
return Wipe_RMRF();
if (Current_File_System == "ext4")
return Wipe_EXT4();
if (Current_File_System == "ext2" || Current_File_System == "ext3")
return Wipe_EXT23();
if (Current_File_System == "vfat")
return Wipe_FAT();
if (Current_File_System == "yaffs2")
return Wipe_MTD();
LOGE("Unable to wipe '%s' -- unknown file system '%s'\n", Mount_Point.c_str(), Current_File_System.c_str());
return false;
}
bool TWPartition::Backup(string backup_folder) {
if (Backup_Method == FILES)
return Backup_Tar(backup_folder);
else if (Backup_Method == DD)
return Backup_DD(backup_folder);
else if (Backup_Method == FLASH_UTILS)
return Backup_Dump_Image(backup_folder);
LOGE("Unknown backup method for '%s'\n", Mount_Point.c_str());
return false;
}
bool TWPartition::Check_MD5(string restore_folder) {
string Full_Filename;
char split_filename[512];
int index = 0;
Full_Filename = restore_folder + "/" + Backup_FileName;
if (!TWFunc::Path_Exists(Full_Filename)) {
// This is a split archive, we presume
sprintf(split_filename, "%s%03i", Full_Filename.c_str(), index);
while (index < 1000 && TWFunc::Path_Exists(split_filename)) {
if (TWFunc::Check_MD5(split_filename) == 0) {
LOGE("MD5 failed to match on '%s'.\n", split_filename);
return false;
}
index++;
sprintf(split_filename, "%s%03i", Full_Filename.c_str(), index);
}
return true;
} else {
// Single file archive
if (TWFunc::Check_MD5(Full_Filename) == 0) {
LOGE("MD5 failed to match on '%s'.\n", split_filename);
return false;
} else
return true;
}
return false;
}
bool TWPartition::Restore(string restore_folder) {
if (Backup_Method == FILES)
return Restore_Tar(restore_folder);
else if (Backup_Method == DD)
return Restore_DD(restore_folder);
else if (Backup_Method == FLASH_UTILS)
return Restore_Flash_Image(restore_folder);
LOGE("Unknown restore method for '%s'\n", Mount_Point.c_str());
return false;
}
string TWPartition::Backup_Method_By_Name() {
if (Backup_Method == NONE)
return "none";
else if (Backup_Method == FILES)
return "files";
else if (Backup_Method == DD)
return "dd";
else if (Backup_Method == FLASH_UTILS)
return "flash_utils";
else
return "undefined";
return "ERROR!";
}
bool TWPartition::Decrypt(string Password) {
LOGI("STUB TWPartition::Decrypt, password: '%s'\n", Password.c_str());
// Is this needed?
return 1;
}
bool TWPartition::Wipe_Encryption() {
bool Save_Data_Media = Has_Data_Media;
if (!UnMount(true))
return false;
Current_File_System = Fstab_File_System;
Is_Encrypted = false;
Is_Decrypted = false;
Decrypted_Block_Device = "";
Has_Data_Media = false;
if (Wipe()) {
Has_Data_Media = Save_Data_Media;
if (Has_Data_Media && !Symlink_Mount_Point.empty()) {
Recreate_Media_Folder();
}
return true;
} else {
Has_Data_Media = Save_Data_Media;
LOGE("Unable to format to remove encryption.\n");
return false;
}
return false;
}
void TWPartition::Check_FS_Type() {
FILE *fp;
string blkCommand;
char blkOutput[255];
char* blk;
char* arg;
char* ptr;
if (Fstab_File_System == "yaffs2" || Fstab_File_System == "mtd")
return; // Running blkid on some mtd devices causes a massive crash
Find_Actual_Block_Device();
if (!Is_Present)
return;
if (TWFunc::Path_Exists("/tmp/blkidoutput.txt"))
system("rm /tmp/blkidoutput.txt");
blkCommand = "blkid " + Actual_Block_Device + " > /tmp/blkidoutput.txt";
system(blkCommand.c_str());
fp = fopen("/tmp/blkidoutput.txt", "rt");
if (fp == NULL)
return;
while (fgets(blkOutput, sizeof(blkOutput), fp) != NULL)
{
blk = blkOutput;
ptr = blkOutput;
while (*ptr > 32 && *ptr != ':') ptr++;
if (*ptr == 0) continue;
*ptr = 0;
// Increment by two, but verify that we don't hit a NULL
ptr++;
if (*ptr != 0) ptr++;
// Now, find the TYPE field
while (1)
{
arg = ptr;
while (*ptr > 32) ptr++;
if (*ptr != 0)
{
*ptr = 0;
ptr++;
}
if (strlen(arg) > 6)
{
if (memcmp(arg, "TYPE=\"", 6) == 0) break;
}
if (*ptr == 0)
{
arg = NULL;
break;
}
}
if (arg && strlen(arg) > 7)
{
arg += 6; // Skip the TYPE=" portion
arg[strlen(arg)-1] = '\0'; // Drop the tail quote
}
else
continue;
if (strcmp(Current_File_System.c_str(), arg) != 0) {
LOGI("'%s' was '%s' now set to '%s'\n", Mount_Point.c_str(), Current_File_System.c_str(), arg);
Current_File_System = arg;
}
}
fclose(fp);
return;
}
bool TWPartition::Wipe_EXT23() {
if (!UnMount(true))
return false;
if (TWFunc::Path_Exists("/sbin/mke2fs")) {
char command[512];
ui_print("Formatting %s using mke2fs...\n", Display_Name.c_str());
Find_Actual_Block_Device();
sprintf(command, "mke2fs -t %s -m 0 %s", Current_File_System.c_str(), Actual_Block_Device.c_str());
LOGI("mke2fs command: %s\n", command);
if (system(command) == 0) {
ui_print("Done.\n");
return true;
} else {
LOGE("Unable to wipe '%s'.\n", Mount_Point.c_str());
return false;
}
} else
return Wipe_RMRF();
return false;
}
bool TWPartition::Wipe_EXT4() {
if (!UnMount(true))
return false;
if (TWFunc::Path_Exists("/sbin/make_ext4fs")) {
string Command;
ui_print("Formatting %s using make_ext4fs...\n", Display_Name.c_str());
Find_Actual_Block_Device();
Command = "make_ext4fs";
if (!Is_Decrypted && Length != 0) {
// Only use length if we're not decrypted
char len[32];
sprintf(len, "%i", Length);
Command += " -l ";
Command += len;
}
Command += " " + Actual_Block_Device;
LOGI("make_ext4fs command: %s\n", Command.c_str());
if (system(Command.c_str()) == 0) {
ui_print("Done.\n");
return true;
} else {
LOGE("Unable to wipe '%s'.\n", Mount_Point.c_str());
return false;
}
} else
return Wipe_EXT23();
return false;
}
bool TWPartition::Wipe_FAT() {
char command[512];
if (Backup_Name == "and-sec") // Don't format if it's android secure
return Wipe_RMRF();
if (TWFunc::Path_Exists("/sbin/mkdosfs")) {
if (!UnMount(true))
return false;
ui_print("Formatting %s using mkdosfs...\n", Display_Name.c_str());
Find_Actual_Block_Device();
sprintf(command,"mkdosfs %s", Actual_Block_Device.c_str()); // use mkdosfs to format it
if (system(command) == 0) {
ui_print("Done.\n");
return true;
} else {
LOGE("Unable to wipe '%s'.\n", Mount_Point.c_str());
return false;
}
return true;
}
else
return Wipe_RMRF();
return false;
}
bool TWPartition::Wipe_MTD() {
if (!UnMount(true))
return false;
ui_print("MTD Formatting \"%s\"\n", MTD_Name.c_str());
mtd_scan_partitions();
const MtdPartition* mtd = mtd_find_partition_by_name(MTD_Name.c_str());
if (mtd == NULL) {
LOGE("No mtd partition named '%s'", MTD_Name.c_str());
return false;
}
MtdWriteContext* ctx = mtd_write_partition(mtd);
if (ctx == NULL) {
LOGE("Can't write '%s', failed to format.", MTD_Name.c_str());
return false;
}
if (mtd_erase_blocks(ctx, -1) == -1) {
mtd_write_close(ctx);
LOGE("Failed to format '%s'", MTD_Name.c_str());
return false;
}
if (mtd_write_close(ctx) != 0) {
LOGE("Failed to close '%s'", MTD_Name.c_str());
return false;
}
ui_print("Done.\n");
return true;
}
bool TWPartition::Wipe_RMRF() {
char cmd[512];
if (!Mount(true))
return false;
if (Backup_Name == "and-sec") {
ui_print("Using rm -rf on .android_secure\n");
sprintf(cmd, "rm -rf %s/.android_secure/* && rm -rf %s/.android_secure/.*", Mount_Point.c_str(), Mount_Point.c_str());
} else {
ui_print("Using rm -rf on '%s'\n", Mount_Point.c_str());
sprintf(cmd, "rm -rf %s/* && rm -rf %s/.*", Mount_Point.c_str(), Mount_Point.c_str());
}
LOGI("rm -rf command is: '%s'\n", cmd);
system(cmd);
return true;
}
bool TWPartition::Wipe_Data_Without_Wiping_Media() {
char cmd[256];
// This handles wiping data on devices with "sdcard" in /data/media
if (!Mount(true))
return false;
ui_print("Wiping data without wiping /data/media ...\n");
system("rm -f /data/*");
system("rm -f /data/.*");
DIR* d;
d = opendir("/data");
if (d != NULL)
{
struct dirent* de;
while ((de = readdir(d)) != NULL) {
if (strcmp(de->d_name, "media") == 0) continue;
sprintf(cmd, "rm -fr /data/%s", de->d_name);
system(cmd);
}
closedir(d);
}
ui_print("Done.\n");
return true;
}
bool TWPartition::Backup_Tar(string backup_folder) {
char back_name[255], split_index[5];
string Full_FileName, Split_FileName, Tar_Args, Command;
int use_compression, index, backup_count;
struct stat st;
unsigned long long total_bsize = 0;
if (!Mount(true))
return false;
ui_print("Backing up %s...\n", Display_Name.c_str());
DataManager::GetValue(TW_USE_COMPRESSION_VAR, use_compression);
if (use_compression)
Tar_Args = "-cz";
else
Tar_Args = "-c";
sprintf(back_name, "%s.%s.win", Backup_Name.c_str(), Current_File_System.c_str());
Backup_FileName = back_name;
if (Backup_Size > MAX_ARCHIVE_SIZE) {
// This backup needs to be split into multiple archives
ui_print("Breaking backup file into multiple archives...\nGenerating file lists\n");
sprintf(back_name, "%s", Mount_Point.c_str());
backup_count = make_file_list(back_name);
if (backup_count < 1) {
LOGE("Error generating file list!\n");
return false;
}
for (index=0; index<backup_count; index++) {
sprintf(split_index, "%03i", index);
Full_FileName = backup_folder + "/" + Backup_FileName + split_index;
Command = "tar " + Tar_Args + " -f '" + Full_FileName + "' -T /tmp/list/filelist" + split_index;
LOGI("Backup command: '%s'\n", Command.c_str());
ui_print("Backup archive %i of %i...\n", (index + 1), backup_count);
system(Command.c_str()); // sending backup command formed earlier above
if (stat(Full_FileName.c_str(), &st) != 0 || st.st_size == 0) {
LOGE("File size is zero bytes. Aborting...\n\n"); // oh noes! file size is 0, abort! abort!
return false;
}
total_bsize += st.st_size;
}
ui_print(" * Total size: %llu bytes.\n", total_bsize);
system("cd /tmp && rm -rf list");
} else {
Full_FileName = backup_folder + "/" + Backup_FileName;
if (Has_Data_Media)
Command = "cd " + Mount_Point + " && tar " + Tar_Args + " ./ --exclude='media*' -f '" + Full_FileName + "'";
else
Command = "cd " + Mount_Point + " && tar " + Tar_Args + " -f '" + Full_FileName + "' ./*";
LOGI("Backup command: '%s'\n", Command.c_str());
system(Command.c_str());
}
return true;
}
bool TWPartition::Backup_DD(string backup_folder) {
char back_name[255];
string Full_FileName, Command;
int use_compression;
ui_print("Backing up %s...\n", Display_Name.c_str());
sprintf(back_name, "%s.%s.win", Backup_Name.c_str(), Current_File_System.c_str());
Backup_FileName = back_name;
Full_FileName = backup_folder + "/" + Backup_FileName;
Command = "dd if=" + Actual_Block_Device + " of='" + Full_FileName + "'";
LOGI("Backup command: '%s'\n", Command.c_str());
system(Command.c_str());
return true;
}
bool TWPartition::Backup_Dump_Image(string backup_folder) {
char back_name[255];
string Full_FileName, Command;
int use_compression;
ui_print("Backing up %s...\n", Display_Name.c_str());
sprintf(back_name, "%s.%s.win", Backup_Name.c_str(), Current_File_System.c_str());
Backup_FileName = back_name;
Full_FileName = backup_folder + "/" + Backup_FileName;
Command = "dump_image " + MTD_Name + " '" + Full_FileName + "'";
LOGI("Backup command: '%s'\n", Command.c_str());
system(Command.c_str());
return true;
}
bool TWPartition::Restore_Tar(string restore_folder) {
size_t first_period, second_period;
string Restore_File_System, Full_FileName, Command;
int index = 0;
char split_index[5];
LOGI("Restore filename is: %s\n", Backup_FileName.c_str());
// Parse backup filename to extract the file system before wiping
first_period = Backup_FileName.find(".");
if (first_period == string::npos) {
LOGE("Unable to find file system (first period).\n");
return false;
}
Restore_File_System = Backup_FileName.substr(first_period + 1, Backup_FileName.size() - first_period - 1);
second_period = Restore_File_System.find(".");
if (second_period == string::npos) {
LOGE("Unable to find file system (second period).\n");
return false;
}
Restore_File_System.resize(second_period);
LOGI("Restore file system is: '%s'.\n", Restore_File_System.c_str());
Current_File_System = Restore_File_System;
ui_print("Wiping %s...\n", Display_Name.c_str());
if (!Wipe())
return false;
if (!Mount(true))
return false;
ui_print("Restoring %s...\n", Display_Name.c_str());
Full_FileName = restore_folder + "/" + Backup_FileName;
if (!TWFunc::Path_Exists(Full_FileName)) {
// Backup is multiple archives
LOGI("Backup is multiple archives.\n");
sprintf(split_index, "%03i", index);
Full_FileName = restore_folder + "/" + Backup_FileName + split_index;
while (TWFunc::Path_Exists(Full_FileName)) {
ui_print("Restoring archive %i...\n", index + 1);
Command = "cd " + Mount_Point + " && tar -xf '" + Full_FileName + "'";
LOGI("Restore command: '%s'\n", Command.c_str());
system(Command.c_str());
index++;
sprintf(split_index, "%03i", index);
Full_FileName = restore_folder + "/" + Backup_FileName + split_index;
}
if (index == 0) {
LOGE("Error locating restore file: '%s'\n", Full_FileName.c_str());
return false;
}
} else {
Command = "cd " + Mount_Point + " && tar -xf '" + Full_FileName + "'";
LOGI("Restore command: '%s'\n", Command.c_str());
system(Command.c_str());
}
return true;
}
bool TWPartition::Restore_DD(string restore_folder) {
string Full_FileName, Command;
ui_print("Restoring %s...\n", Display_Name.c_str());
Full_FileName = restore_folder + "/" + Backup_FileName;
Command = "dd bs=4096 if='" + Full_FileName + "' of=" + Actual_Block_Device;
LOGI("Restore command: '%s'\n", Command.c_str());
system(Command.c_str());
return true;
}
bool TWPartition::Restore_Flash_Image(string restore_folder) {
string Full_FileName, Command;
ui_print("Restoring %s...\n", Display_Name.c_str());
Full_FileName = restore_folder + "/" + Backup_FileName;
// Sometimes flash image doesn't like to flash due to the first 2KB matching, so we erase first to ensure that it flashes
Command = "erase_image " + MTD_Name;
LOGI("Erase command: '%s'\n", Command.c_str());
system(Command.c_str());
Command = "flash_image " + MTD_Name + " '" + Full_FileName + "'";
LOGI("Restore command: '%s'\n", Command.c_str());
system(Command.c_str());
return true;
}
bool TWPartition::Update_Size(bool Display_Error) {
bool ret = false;
if (!Can_Be_Mounted)
return false;
if (Removable || Is_Encrypted) {
if (!Mount(false))
return true;
} else if (!Mount(Display_Error))
return false;
ret = Get_Size_Via_statfs(Display_Error);
if (!ret || Size == 0)
if (!Get_Size_Via_df(Display_Error))
return false;
if (Has_Data_Media) {
if (Mount(Display_Error)) {
unsigned long long data_media_used, actual_data;
Used = TWFunc::Get_Folder_Size("/data", Display_Error);
data_media_used = TWFunc::Get_Folder_Size("/data/media", Display_Error);
actual_data = Used - data_media_used;
Backup_Size = actual_data;
int bak = (int)(Backup_Size / 1048576LLU);
int total = (int)(Size / 1048576LLU);
int us = (int)(Used / 1048576LLU);
int fre = (int)(Free / 1048576LLU);
int datmed = (int)(data_media_used / 1048576LLU);
LOGI("Data backup size is %iMB, size: %iMB, used: %iMB, free: %iMB, in data/media: %iMB.\n", bak, total, us, fre, datmed);
} else
return false;
}
return true;
}
void TWPartition::Find_Actual_Block_Device(void) {
if (Is_Decrypted) {
Actual_Block_Device = Decrypted_Block_Device;
if (TWFunc::Path_Exists(Primary_Block_Device))
Is_Present = true;
} else if (TWFunc::Path_Exists(Primary_Block_Device)) {
Is_Present = true;
Actual_Block_Device = Primary_Block_Device;
} else if (!Alternate_Block_Device.empty() && TWFunc::Path_Exists(Alternate_Block_Device)) {
Flip_Block_Device();
Actual_Block_Device = Primary_Block_Device;
Is_Present = true;
} else
Is_Present = false;
}
void TWPartition::Recreate_Media_Folder(void) {
string Command;
if (!Mount(true)) {
LOGE("Unable to recreate /data/media folder.\n");
} else {
LOGI("Recreating /data/media folder.\n");
system("cd /data && mkdir media && chmod 755 media");
Command = "umount " + Symlink_Mount_Point;
system(Command.c_str());
Command = "mount " + Symlink_Path + " " + Symlink_Mount_Point;
system(Command.c_str());
}
}