int check_backup_size(const char* backup_path) { // these are the size stats for backup_path we previously refreshed by calling Get_Size_Via_statfs() int total_mb = (int)(Total_Size / 1048576LLU); int used_mb = (int)(Used_Size / 1048576LLU); int free_mb = (int)(Free_Size / 1048576LLU); int free_percent = free_mb * 100 / total_mb; Before_Used_Size = Used_Size; // save Used_Size to refresh data written stats later Backup_Size = 0; // supported nandroid partitions char* Base_Partitions_List[BASE_PARTITIONS_NUM] = { "/recovery", BOOT_PARTITION_MOUNT_POINT, "/wimax", "/modem", "/radio", "/efs", "/misc", "/system", "/preload", "/data", "/datadata", "/cache", "/sd-ext" }; int items_num = BASE_PARTITIONS_NUM + MAX_EXTRA_NANDROID_PARTITIONS + 1; char* Partitions_List[items_num]; int i; for (i = 0; i < BASE_PARTITIONS_NUM; ++i) { Partitions_List[i] = Base_Partitions_List[i]; } int extra_partitions_num = get_extra_partitions_state(); for (i = 0; i < extra_partitions_num; ++i) { Partitions_List[BASE_PARTITIONS_NUM + i] = extra_partition[i].mount_point; } Partitions_List[BASE_PARTITIONS_NUM + extra_partitions_num] = NULL; int preload_status = 0; if ((is_custom_backup && backup_preload) || (!is_custom_backup && nandroid_add_preload.value)) preload_status = 1; int Base_Partitions_Backup_Status[] = { backup_recovery, backup_boot, backup_wimax, backup_modem, backup_radio, backup_efs, backup_misc, backup_system, preload_status, backup_data, backup_data, backup_cache, backup_sdext, }; LOGI("Checking needed space for backup '%s'\n", backup_path); // calculate needed space for backup // assume recovery and wimax always use a raw backup mode (Is_Image() = 0) char skipped_parts[1024] = ""; int ret = 0; Volume* vol; for (i = 0; Partitions_List[i] != NULL; ++i) { if (i >= BASE_PARTITIONS_NUM) { if (!extra_partition[i - BASE_PARTITIONS_NUM].backup_state) continue; } else if (!Base_Partitions_Backup_Status[i]) { continue; } // size of /data will be calculated later for /data/media devices to subtract sdcard size from it if (strcmp(Partitions_List[i], "/data") == 0 && is_data_media()) continue; // redundant but keep for compatibility: // has_datadata() does a volume_for_path() != NULL check if (strcmp(Partitions_List[i], "/datadata") == 0 && !has_datadata()) continue; vol = volume_for_path(Partitions_List[i]); if (vol == NULL) continue; if (Is_Image(Partitions_List[i]) == 0) { if (Find_Partition_Size(Partitions_List[i]) == 0) { Backup_Size += Total_Size; LOGI("%s backup size (/proc)=%lluMb\n", Partitions_List[i], Total_Size / 1048576LLU); // debug } else { ret++; strcat(skipped_parts, " - "); strcat(skipped_parts, Partitions_List[i]); } } else if (Is_File_System(Partitions_List[i]) == 0) { // Get_Size_Via_statfs() will ensure vol->mount_point != NULL if (0 == ensure_path_mounted(vol->mount_point) && 0 == Get_Size_Via_statfs(vol->mount_point)) { Backup_Size += Used_Size; LOGI("%s backup size (stat)=%lluMb\n", Partitions_List[i], Used_Size / 1048576LLU); // debug } else { ret++; strcat(skipped_parts, " - "); strcat(skipped_parts, Partitions_List[i]); } } else { ret++; strcat(skipped_parts, " - Unknown file system: "); strcat(skipped_parts, Partitions_List[i]); } } // handle special partitions and folders: // handle /data and /data/media partitions size for /data/media devices unsigned long long data_backup_size = 0; unsigned long long data_used_bytes = 0; unsigned long long data_media_size = 0; if (is_data_media() && (backup_data || backup_data_media)) { if (0 == ensure_path_mounted("/data") && 0 == Get_Size_Via_statfs("/data")) { data_media_size = Get_Folder_Size("/data/media"); data_used_bytes = Get_Folder_Size("/data"); data_backup_size = data_used_bytes - data_media_size; LOGI("/data: tot size=%lluMb, free=%lluMb, backup size=%lluMb, used=%lluMb, media=%lluMb\n", Total_Size/1048576LLU, Free_Size/1048576LLU, data_backup_size/1048576LLU, data_used_bytes/1048576LLU, data_media_size/1048576LLU); } else { if (backup_data) { strcat(skipped_parts, " - /data"); ret++; } if (backup_data_media) { strcat(skipped_parts, " - /data/media"); ret++; } } } if (backup_data) Backup_Size += data_backup_size; // check if we are also backing up /data/media // if backup_path is same as /data/media, ignore this as it will not be processed by nandroid_backup_datamedia() if (backup_data_media && !is_data_media_volume_path(backup_path)) { Backup_Size += data_media_size; LOGI("included /data/media size\n"); // debug } // .android_secure size calculation // set_android_secure_path() will mount tmp so no need to remount before calling Get_Folder_Size(tmp) char tmp[PATH_MAX]; set_android_secure_path(tmp); if (backup_data && android_secure_ext) { unsigned long long andsec_size; andsec_size = Get_Folder_Size(tmp); Backup_Size += andsec_size; LOGI("%s backup size=%lluMb\n", tmp, andsec_size / 1048576LLU); // debug } // check if we have the needed space int backup_size_mb = (int)(Backup_Size / 1048576LLU); ui_print("\n>> Free space: %dMb (%d%%)\n", free_mb, free_percent); ui_print(">> Needed space: %dMb\n", backup_size_mb); if (ret) ui_print(">> Unknown partitions size (%d):%s\n", ret, skipped_parts); // dedupe wrapper needs less space than actual backup size (incremental backups) // only check free space in Mb if we use tar or tar.gz as a default format // also, add extra 50 Mb for security measures if (free_percent < 3 || (default_backup_handler != dedupe_compress_wrapper && free_mb < backup_size_mb + 50)) { LOGW("Low space for backup!\n"); if (!ui_is_initialized()) { // do not prompt when it is an "adb shell nandroid backup" command LOGW("\n>>> Backup could fail with I/O error!! <<<\n\n"); } else if (nand_prompt_on_low_space.value && !confirm_selection("Low free space! Continue anyway?", "Yes - Continue Nandroid Job")) return -1; } return 0; }
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'; } Mount_Point = full_line; LOGI("Processing '%s'\n", Mount_Point.c_str()); Backup_Path = Mount_Point; 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") { MTD_Name = ptr; Find_MTD_Block_Device(MTD_Name); } else if (Fstab_File_System == "bml") { if (Mount_Point == "/boot") MTD_Name = "boot"; else if (Mount_Point == "/recovery") MTD_Name = "recovery"; Primary_Block_Device = ptr; if (*ptr != '/') LOGE("Until we get better BML support, you will have to find and provide the full block device path to the BML devices e.g. /dev/block/bml9 instead of the partition name\n"); } 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, line: '%s'\n", ptr, index, Line.c_str()); } } 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; } else if (Mount_Point == "/data") { Display_Name = "Data"; Wipe_Available_in_GUI = true; Wipe_During_Factory_Reset = true; #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", ""); } #ifdef RECOVERY_SDCARD_ON_DATA if (!Is_Encrypted || (Is_Encrypted && Is_Decrypted)) Recreate_Media_Folder(); #endif #else #ifdef RECOVERY_SDCARD_ON_DATA Recreate_Media_Folder(); #endif #endif } else if (Mount_Point == "/cache") { Display_Name = "Cache"; Wipe_Available_in_GUI = true; Wipe_During_Factory_Reset = true; if (Mount(false) && !TWFunc::Path_Exists("/cache/recovery/.")) { string Recreate_Command = "cd /cache && mkdir recovery"; LOGI("Recreating /cache/recovery folder.\n"); system(Recreate_Command.c_str()); } } 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; } else if (Mount_Point == "/boot") { Display_Name = "Boot"; DataManager::SetValue("tw_boot_is_mountable", 1); } #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; #ifndef RECOVERY_SDCARD_ON_DATA Setup_AndSec(); Mount_Storage_Retry(); #endif } #endif #ifdef TW_INTERNAL_STORAGE_PATH if (Mount_Point == EXPAND(TW_INTERNAL_STORAGE_PATH)) { Is_Storage = true; Storage_Path = EXPAND(TW_INTERNAL_STORAGE_PATH); #ifndef RECOVERY_SDCARD_ON_DATA Setup_AndSec(); Mount_Storage_Retry(); #endif } #else if (Mount_Point == "/emmc") { Is_Storage = true; Storage_Path = "/emmc"; #ifndef RECOVERY_SDCARD_ON_DATA Setup_AndSec(); Mount_Storage_Retry(); #endif } #endif } else if (Is_Image(Fstab_File_System)) { Find_Actual_Block_Device(); Setup_Image(Display_Error); } // Process any custom flags if (Flags.size() > 0) Process_Flags(Flags, Display_Error); return true; }