Example #1
0
bool TWPartition::Update_Size(bool Display_Error) {
	bool ret = false, Was_Already_Mounted = false;

	if (!Can_Be_Mounted && !Is_Encrypted)
		return false;

	Was_Already_Mounted = Is_Mounted();
	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)) {
			if (!Was_Already_Mounted)
				UnMount(false);
			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 {
			if (!Was_Already_Mounted)
				UnMount(false);
			return false;
		}
	} else if (Has_Android_Secure) {
		if (Mount(Display_Error))
			Backup_Size = TWFunc::Get_Folder_Size(Backup_Path, Display_Error);
		else {
			if (!Was_Already_Mounted)
				UnMount(false);
			return false;
		}
	}
	if (!Was_Already_Mounted)
		UnMount(false);
	return true;
}
Example #2
0
// check size of archive files to get total backed up data size
// find all backup image files of a given partition and increment Backup_Size
// Backup_Size is set to 0 at start of nandroid_restore() process so that we do not print size progress on
void check_restore_size(const char* backup_file_image, const char* backup_path) {
    // refresh target partition size
    if (Get_Size_Via_statfs(backup_path) != 0) {
        Backup_Size = 0;
        return;
    }
    Before_Used_Size = Used_Size;

    char tmp[PATH_MAX];
    char filename[PATH_MAX];
    char** files;
    int numFiles = 0;

    sprintf(tmp, "%s/", DirName(backup_file_image));
    files = gather_files(tmp, "", &numFiles);

    // if it's a twrp multi volume backup, ensure we remove trailing 000: strlen("000") = 3
    if (strlen(backup_file_image) > strlen("win000") && strcmp(backup_file_image + strlen(backup_file_image) - strlen("win000"), "win000") == 0)
        snprintf(tmp, strlen(backup_file_image) - 3, "%s", backup_file_image);
    else
        strcpy(tmp, backup_file_image);
    sprintf(filename, "%s", BaseName(tmp));
    
    int i;
    unsigned long fsize;
    for(i = 0; i < numFiles; i++) {
        if (strstr(files[i], filename) != NULL) {
            fsize = Get_File_Size(files[i]);
            // check if it is a compressed archive and increase size by 45%
            // this needs a better implementation to do later
            if (is_gzip_file(files[i]) > 0)
                fsize += (fsize * 45) / 100;
            Backup_Size += fsize;
        }
    }

    free_string_array(files);
}
Example #3
0
int twrp_backup(const char* backup_path) {
    // keep this for extra security and keep close to stock code
    // refresh_default_backup_handler() mounts /sdcard. We stat it in nandroid_backup_partition_extended() for callback
    nandroid_backup_bitfield = 0;
    refresh_default_backup_handler();

    if (ensure_path_mounted(backup_path) != 0)
        return print_and_error("Can't mount backup path.\n", NANDROID_ERROR_GENERAL);

    int ret;
    struct statfs s;

    // refresh size stats for backup_path
    // this will also ensure volume for backup path != NULL
    if (0 != Get_Size_Via_statfs(backup_path))
        return print_and_error("Unable to stat backup path.\n", NANDROID_ERROR_GENERAL);

    // estimate backup size and ensure we have enough free space available on backup_path
    if (check_backup_size(backup_path) < 0)
        return print_and_error("Not enough free space: backup cancelled.\n", NANDROID_ERROR_GENERAL);

    // moved after backup size check to fix pause before showing low space prompt
    // this is caused by friendly log view triggering on ui_set_background(BACKGROUND_ICON_INSTALLING) call
    // also, it is expected to have the background installing icon when we actually start backup
    ui_set_background(BACKGROUND_ICON_INSTALLING);
    nandroid_start_msec = timenow_msec(); // starts backup monitoring timer for total backup time
#ifdef PHILZ_TOUCH_RECOVERY
    last_key_ev = nandroid_start_msec; // support dim screen timeout during nandroid operation
#endif

    char tmp[PATH_MAX];
    ensure_directory(backup_path, 0755);

    if (backup_boot && volume_for_path(BOOT_PARTITION_MOUNT_POINT) != NULL &&
            0 != (ret = nandroid_backup_partition(backup_path, BOOT_PARTITION_MOUNT_POINT)))
        return print_and_error(NULL, ret);

    if (backup_recovery && volume_for_path("/recovery") != NULL &&
            0 != (ret = nandroid_backup_partition(backup_path, "/recovery")))
        return print_and_error(NULL, ret);

#ifdef BOARD_USE_MTK_LAYOUT
    if ((backup_boot || backup_recovery) && volume_for_path("/uboot") != NULL &&
            0 != (ret = nandroid_backup_partition(backup_path, "/uboot")))
        return print_and_error(NULL, ret);
#endif

    Volume *vol = volume_for_path("/efs");
    if (backup_efs &&  NULL != vol) {
        if (0 != (ret = nandroid_backup_partition(backup_path, "/efs")))
            return print_and_error(NULL, ret);
    }

    vol = volume_for_path("/misc");
    if (backup_misc && NULL != vol) {
        if (0 != (ret = nandroid_backup_partition(backup_path, "/misc")))
            return print_and_error(NULL, ret);
    }

    vol = volume_for_path("/modem");
    if (backup_modem && NULL != vol) {
        if (0 != (ret = nandroid_backup_partition(backup_path, "/modem")))
            return print_and_error(NULL, ret);
    }

    vol = volume_for_path("/radio");
    if (backup_radio && NULL != vol) {
        if (0 != (ret = nandroid_backup_partition(backup_path, "/radio")))
            return print_and_error(NULL, ret);
    }

    if (backup_system && 0 != (ret = nandroid_backup_partition(backup_path, "/system")))
        return print_and_error(NULL, ret);

    vol = volume_for_path("/preload");
    if (backup_preload && NULL != vol) {
        if (0 != (ret = nandroid_backup_partition(backup_path, "/preload")))
            return print_and_error(NULL, ret);
    }

    if (backup_data && 0 != (ret = nandroid_backup_partition(backup_path, "/data")))
        return print_and_error(NULL, ret);

    if (has_datadata()) {
        if (backup_data && 0 != (ret = nandroid_backup_partition(backup_path, "/datadata")))
            return print_and_error(NULL, ret);
    }

    // handle .android_secure on external and internal storage
    set_android_secure_path(tmp);
    if (backup_data && android_secure_ext) {
        if (0 != (ret = nandroid_backup_partition_extended(backup_path, tmp, 0)))
            return print_and_error(NULL, ret);
    }

    if (backup_cache && 0 != (ret = nandroid_backup_partition_extended(backup_path, "/cache", 0)))
        return print_and_error(NULL, ret);

    if (backup_sdext) {
        if (0 != ensure_path_mounted("/sd-ext")) {
            LOGI("No sd-ext found. Skipping backup of sd-ext.\n");
        } else if (0 != (ret = nandroid_backup_partition(backup_path, "/sd-ext"))) {
            return print_and_error(NULL, ret);
        }
    }

    // handle extra partitions
    int i;
    int extra_partitions_num = get_extra_partitions_state();
    for (i = 0; i < extra_partitions_num; ++i) {
        if (extra_partition[i].backup_state && 0 != (ret = nandroid_backup_partition(backup_path, extra_partition[i].mount_point)))
            return print_and_error(NULL, ret);
    }

    if (enable_md5sum.value) {
        if (0 != (ret = gen_twrp_md5sum(backup_path)))
            return print_and_error(NULL, ret);
    }

    sprintf(tmp, "chmod -R 777 %s", backup_path);
    __system(tmp);

    finish_nandroid_job();
    show_backup_stats(backup_path);
    if (reboot_after_nandroid)
        reboot_main_system(ANDROID_RB_RESTART, 0, 0);
    return 0;
}
Example #4
0
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;
}