static void choose_default_backup_format() { static char* headers[] = { "Default Backup Format", "", NULL }; char **list; char* list_tar_default[] = { "tar (default)", "dup", NULL }; char* list_dup_default[] = { "tar", "dup (default)", NULL }; if (nandroid_get_default_backup_format() == NANDROID_BACKUP_FORMAT_DUP) { list = list_dup_default; } else { list = list_tar_default; } int chosen_item = get_menu_selection(headers, list, 0, 0); switch (chosen_item) { case 0: write_string_to_file(NANDROID_BACKUP_FORMAT_FILE, "tar"); ui_print("Default backup format set to tar.\n"); break; case 1: write_string_to_file(NANDROID_BACKUP_FORMAT_FILE, "dup"); ui_print("Default backup format set to dedupe.\n"); break; } }
// backup /data/media support // we reach here only if backup_data_media == 1 // backup_data_media can be set to 1 only in "custom backup and restore" menu AND if is_data_media() && !twrp_backup_mode.value int nandroid_backup_datamedia(const char* backup_path) { char tmp[PATH_MAX]; ui_print("\n>> Backing up /data/media...\n"); if (is_data_media_volume_path(backup_path)) { // non fatal failure LOGE(" - can't backup folder to its self, skipping...\n"); return 0; } if (0 != ensure_path_mounted("/data")) return -1; sprintf(tmp, "%s/%s", get_primary_storage_path(), NANDROID_HIDE_PROGRESS_FILE); ensure_path_mounted(tmp); int callback = !file_found(tmp); compute_directory_stats("/data/media"); Volume *v = volume_for_path("/data"); if (v == NULL) return -1; char backup_file_image[PATH_MAX]; sprintf(backup_file_image, "%s/datamedia.%s", backup_path, v->fs_type == NULL ? "auto" : v->fs_type); int fmt; fmt = nandroid_get_default_backup_format(); if (fmt == NANDROID_BACKUP_FORMAT_TAR) { sprintf(tmp, "cd / ; touch %s.tar ; set -o pipefail ; (tar -cpv data/media | split -a 1 -b 1000000000 /proc/self/fd/0 %s.tar.) 2> /proc/self/fd/1 ; exit $?", backup_file_image, backup_file_image); } else if (fmt == NANDROID_BACKUP_FORMAT_TGZ) { sprintf(tmp, "cd / ; touch %s.tar.gz ; set -o pipefail ; (tar -cpv data/media | pigz -c -%d | split -a 1 -b 1000000000 /proc/self/fd/0 %s.tar.gz.) 2> /proc/self/fd/1 ; exit $?", backup_file_image, compression_value.value, backup_file_image); } else { // non fatal failure LOGE(" - backup format must be tar(.gz), skipping...\n"); return 0; } int ret; ret = do_tar_compress(tmp, callback, backup_file_image); ensure_path_unmounted("/data"); if (0 != ret) return print_and_error("Failed to backup /data/media!\n", ret); ui_print("Backup of /data/media completed.\n"); return 0; }
// print backup stats summary at end of a backup void show_backup_stats(const char* backup_path) { long long total_msec = timenow_msec() - nandroid_start_msec; long long minutes = total_msec / 60000LL; long long seconds = (total_msec % 60000LL) / 1000LL; unsigned long long final_size = Get_Folder_Size(backup_path); long double compression; if (Backup_Size == 0 || final_size == 0 || nandroid_get_default_backup_format() != NANDROID_BACKUP_FORMAT_TGZ) compression = 0; else compression = 1 - ((long double)(final_size) / (long double)(Backup_Size)); ui_print("\nBackup complete!\n"); ui_print("Backup time: %02lld:%02lld mn\n", minutes, seconds); ui_print("Backup size: %.2LfMb\n", (long double) final_size / 1048576); // print compression % only if it is a tar / tar.gz backup // keep also for tar to show it is 0% compression if (default_backup_handler != dedupe_compress_wrapper) ui_print("Compression: %.2Lf%%\n", compression * 100); }
int twrp_backup_wrapper(const char* backup_path, const char* backup_file_image, int callback) { Volume *v = volume_for_path(backup_path); if (v == NULL) { ui_print("Unable to find volume.\n"); return -1; } if (!is_path_mounted(backup_path)) { LOGE("Unable to find mounted volume: '%s'\n", v->mount_point); return -1; } // Always use split format (simpler code) - Build lists of files to backup char tmp[PATH_MAX]; int backup_count; ui_print("Breaking backup file into multiple archives...\nGenerating file lists\n"); backup_count = Make_File_List(backup_path); if (backup_count < 1) { LOGE("Error generating file list!\n"); return -1; } // check we are not backing up an empty volume as it would fail to restore (tar: short read) // check first if a filelist was generated. If not, ensure volume is 0 size. Else, it could be an error while if (!file_found("/tmp/list/filelist000")) { ui_print("Nothing to backup. Skipping %s\n", BaseName(backup_path)); return 0; } unsigned long long total_bsize = 0, file_size = 0; int index; int nand_starts = 1; last_size_update = 0; set_perf_mode(1); for (index = 0; index < backup_count; index++) { compute_twrp_backup_stats(index); // folder /data/media and google cached music are excluded from tar by Generate_File_Lists(...) if (nandroid_get_default_backup_format() == NANDROID_BACKUP_FORMAT_TAR) sprintf(tmp, "(tar -cpvf '%s%03i' -T /tmp/list/filelist%03i) 2> /proc/self/fd/1 ; exit $?", backup_file_image, index, index); else sprintf(tmp, "set -o pipefail ; (tar -cpv -T /tmp/list/filelist%03i | pigz -c -%d >'%s%03i') 2> /proc/self/fd/1 ; exit $?", index, compression_value.value, backup_file_image, index); ui_print(" * Backing up archive %i/%i\n", (index + 1), backup_count); FILE *fp = __popen(tmp, "r"); if (fp == NULL) { LOGE("Unable to execute tar.\n"); set_perf_mode(0); return -1; } while (fgets(tmp, PATH_MAX, fp) != NULL) { #ifdef PHILZ_TOUCH_RECOVERY if (user_cancel_nandroid(&fp, backup_file_image, 1, &nand_starts)) { set_perf_mode(0); return -1; } #endif tmp[PATH_MAX - 1] = '\0'; if (callback) { update_size_progress(backup_file_image); nandroid_callback(tmp); } } #ifdef PHILZ_TOUCH_RECOVERY ui_print_preset_colors(0, NULL); #endif if (0 != __pclose(fp)) { set_perf_mode(0); return -1; } sprintf(tmp, "%s%03i", backup_file_image, index); file_size = Get_File_Size(tmp); if (file_size == 0) { LOGE("Backup file size for '%s' is 0 bytes!\n", tmp); set_perf_mode(0); return -1; } total_bsize += file_size; } __system("cd /tmp && rm -rf list"); set_perf_mode(0); ui_print("Total backup size:\n %llu bytes.\n", total_bsize); return 0; }