diff options
Diffstat (limited to 'partition.cpp')
-rw-r--r-- | partition.cpp | 522 |
1 files changed, 510 insertions, 12 deletions
diff --git a/partition.cpp b/partition.cpp index a01e2a76a..29a20dc9f 100644 --- a/partition.cpp +++ b/partition.cpp @@ -25,11 +25,19 @@ #include <string.h> #include <sys/stat.h> #include <sys/vfs.h> +#include <sys/mount.h> #include <unistd.h> #include "variables.h" #include "common.h" #include "partitions.hpp" +#include "data.hpp" +extern "C" { + #include "extra-functions.h" + int __system(const char *command); + FILE * __popen(const char *program, const char *type); + int __pclose(FILE *iop); +} TWPartition::TWPartition(void) { Can_Be_Mounted = false; @@ -69,31 +77,439 @@ TWPartition::~TWPartition(void) { // Do nothing } -bool TWPartition::Process_Fstab_Line(string Line) { - LOGI("STUB TWPartition::Process_Fstab_Line, Line: '%s'\n", Line.c_str()); +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; + + strncpy(full_line, Line.c_str(), line_len); + + while (index < line_len) { + if (full_line[index] <= 32) + full_line[index] = '\0'; + index++; + } + 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 (*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; + } + Block_Device = ptr; + Find_Real_Block_Device(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 { + // 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)) { + Setup_File_System(Display_Error); + if (Mount_Point == "/system") { + Display_Name = "System"; + Wipe_Available_in_GUI = true; + Update_Size(Display_Error); + int backup_display_size = (int)(Backup_Size / 1048576LLU); + DataManager::SetValue(TW_BACKUP_SYSTEM_SIZE, backup_display_size); + } else if (Mount_Point == "/data") { + Display_Name = "Data"; + Wipe_Available_in_GUI = true; +#ifdef RECOVERY_SDCARD_ON_DATA + Has_Data_Media = true; +#endif +#ifdef TW_INCLUDE_CRYPTO + Can_Be_Encrypted = true; + 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", ""); + } else + Update_Size(Display_Error); +#else + Update_Size(Display_Error); +#endif + int backup_display_size = (int)(Backup_Size / 1048576LLU); + DataManager::SetValue(TW_BACKUP_DATA_SIZE, backup_display_size); + } else if (Mount_Point == "/cache") { + Display_Name = "Cache"; + Wipe_Available_in_GUI = true; + Update_Size(Display_Error); + int backup_display_size = (int)(Backup_Size / 1048576LLU); + DataManager::SetValue(TW_BACKUP_CACHE_SIZE, backup_display_size); + } else if (Mount_Point == "/datadata") { + Display_Name = "DataData"; + Is_SubPartition = true; + SubPartition_Of = "/data"; + Update_Size(Display_Error); + DataManager::SetValue(TW_HAS_DATADATA, 1); + } else if (Mount_Point == "/sd-ext") { + Display_Name = "SD-Ext"; + Wipe_Available_in_GUI = true; + Update_Size(Display_Error); + int backup_display_size = (int)(Backup_Size / 1048576LLU); + DataManager::SetValue(TW_BACKUP_SDEXT_SIZE, backup_display_size); + if (Backup_Size == 0) { + DataManager::SetValue(TW_HAS_SDEXT_PARTITION, 0); + DataManager::SetValue(TW_BACKUP_SDEXT_VAR, 0); + } else + DataManager::SetValue(TW_HAS_SDEXT_PARTITION, 1); + } else + Update_Size(Display_Error); + } else if (Is_Image(Fstab_File_System)) { + Setup_Image(Display_Error); + if (Mount_Point == "/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") { + 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); + } + } + return 1; } +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; +} + +void TWPartition::Setup_File_System(bool Display_Error) { + struct statfs st; + + Can_Be_Mounted = true; + Can_Be_Wiped = true; + + // Check to see if the block device exists + if (Path_Exists(Block_Device)) { + Is_Present = true; + } else if (Alternate_Block_Device != "" && Path_Exists(Alternate_Block_Device)) { + Flip_Block_Device(); + Is_Present = true; + } + // Make the mount point folder if it doesn't exist + if (!Path_Exists(Mount_Point.c_str())) { + if (mkdir(Mount_Point.c_str(), 0777) == -1) { + if (Display_Error) + LOGE("Can not create '%s' folder.\n", Mount_Point.c_str()); + else + LOGI("Can not create '%s' folder.\n", Mount_Point.c_str()); + } else + LOGI("Created '%s' folder.\n", Mount_Point.c_str()); + } + Display_Name = Mount_Point.substr(1, Mount_Point.size() - 1); + Backup_Name = Display_Name; + Backup_Method = FILES; +} + +void TWPartition::Setup_Image(bool Display_Error) { + if (Path_Exists(Block_Device)) { + Is_Present = true; + } else if (Alternate_Block_Device != "" && Path_Exists(Alternate_Block_Device)) { + Flip_Block_Device(); + Is_Present = true; + } + 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", Block_Device.c_str()); + else + LOGI("Unable to find parition size for '%s'\n", Block_Device.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::Get_Size_Via_df(string Path, 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 = Block_Device.size() + 2; + sprintf(command, "df %s", Path.c_str()); + fp = __popen(command, "r"); + if (fp == NULL) + 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; +} + +unsigned long long TWPartition::Get_Size_Via_du(string Path, bool Display_Error) { + char cmd[512]; + sprintf(cmd, "du -sk %s | awk '{ print $1 }'", Path.c_str()); + + FILE *fp; + fp = __popen(cmd, "r"); + + char str[512]; + fgets(str, sizeof(str), fp); + __pclose(fp); + + unsigned long long dusize = atol(str); + dusize *= 1024ULL; + + return dusize; +} + +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 == Block_Device || tmpdevice == Alternate_Block_Device) { + // Adjust block size to byte size + Size = blocks * 1024ULL; + fclose(fp); + return true; + } + } + fclose(fp); + return false; +} + +bool TWPartition::Path_Exists(string Path) { + // Check to see if the Path exists + struct statfs st; + + if (statfs(Path.c_str(), &st) != 0) + return false; + else + return true; +} + +void TWPartition::Flip_Block_Device(void) { + string temp; + + temp = Alternate_Block_Device; + Block_Device = Alternate_Block_Device; + Alternate_Block_Device = temp; +} + bool TWPartition::Is_Mounted(void) { - LOGI("STUB TWPartition::Is_Mounted\n"); - return 1; + 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) { - LOGI("STUB TWPartition::Mount, Display_Error: %i\n", Display_Error); if (Is_Mounted()) { - return 1; - } else { - return 1; + return true; + } else if (!Can_Be_Mounted) { + return false; + } + if (Is_Decrypted) { + if (mount(Decrypted_Block_Device.c_str(), Mount_Point.c_str(), Current_File_System.c_str(), 0, NULL) != 0) { + Check_FS_Type(); + if (mount(Decrypted_Block_Device.c_str(), Mount_Point.c_str(), Current_File_System.c_str(), 0, NULL) != 0) { + if (Display_Error) + LOGE("Unable to mount decrypted block device '%s' to '%s'\n", Decrypted_Block_Device.c_str(), Mount_Point.c_str()); + else + LOGI("Unable to mount decrypted block device '%s' to '%s'\n", Decrypted_Block_Device.c_str(), Mount_Point.c_str()); + return false; + } else + return true; + } else + return true; + } + if (mount(Block_Device.c_str(), Mount_Point.c_str(), Current_File_System.c_str(), 0, NULL) != 0) { + Check_FS_Type(); + if (mount(Block_Device.c_str(), Mount_Point.c_str(), Current_File_System.c_str(), 0, NULL) != 0) { + if (Alternate_Block_Device != "" && Path_Exists(Alternate_Block_Device)) { + Flip_Block_Device(); + Check_FS_Type(); + if (mount(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 + return true; + } else + return false; + } else + return true; } + return true; } bool TWPartition::UnMount(bool Display_Error) { - LOGI("STUB TWPartition::Mount, Display_Error: %i\n", Display_Error); if (Is_Mounted()) { - return 1; + 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 (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 1; + return true; } } @@ -128,7 +544,70 @@ bool TWPartition::Wipe_Encryption() { } void TWPartition::Check_FS_Type() { - LOGI("STUB TWPartition::Check_FS_Type\n"); + 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 + + if (Is_Decrypted) + blkCommand = "blkid " + Decrypted_Block_Device; + else + blkCommand = "blkid " + Block_Device; + fp = __popen(blkCommand.c_str(), "r"); + 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; + } + } + __pclose(fp); return; } @@ -191,3 +670,22 @@ bool TWPartition::Restore_Flash_Image(string restore_folder) { LOGI("STUB TWPartition::Restore_Flash_Image, backup_folder: '%s'\n", restore_folder.c_str()); return 1; } + +bool TWPartition::Update_Size(bool Display_Error) { + if (!Can_Be_Mounted) + return false; + + if (!Get_Size_Via_df(Mount_Point, Display_Error)) + return false; + if (Has_Data_Media) { + if (Mount(Display_Error)) { + unsigned long long data_used, data_media_used, actual_data; + data_used = Get_Size_Via_du("/data/", Display_Error); + data_media_used = Get_Size_Via_du("/data/media/", Display_Error); + actual_data = data_used - data_media_used; + Backup_Size = actual_data; + } else + return false; + } + return true; +}
\ No newline at end of file |