From 18e4f053bced9ead787e23e0526cb758a9979af1 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 22 Nov 2010 23:27:19 +0100 Subject: mobilebackup2: added info and list commands, started restore implementation --- tools/idevicebackup4.c | 388 ++++++------------------------------------------- 1 file changed, 45 insertions(+), 343 deletions(-) diff --git a/tools/idevicebackup4.c b/tools/idevicebackup4.c index a44abb6..8c4fe79 100644 --- a/tools/idevicebackup4.c +++ b/tools/idevicebackup4.c @@ -54,6 +54,8 @@ static int quit_flag = 0; enum cmd_mode { CMD_BACKUP, CMD_RESTORE, + CMD_INFO, + CMD_LIST, CMD_LEAVE }; @@ -1140,6 +1142,12 @@ int main(int argc, char *argv[]) else if (!strcmp(argv[i], "restore")) { cmd = CMD_RESTORE; } + else if (!strcmp(argv[i], "info")) { + cmd = CMD_INFO; + } + else if (!strcmp(argv[i], "list")) { + cmd = CMD_LIST; + } else if (backup_directory == NULL) { backup_directory = argv[i]; } @@ -1369,12 +1377,6 @@ checkpoint: plist_free(info_plist); info_plist = NULL; - /* close down the lockdown connection as it is no longer needed */ - if (client) { - lockdownd_client_free(client); - client = NULL; - } - /* create Status.plist with failed status for now */ //mobilebackup_write_status(backup_directory, 0); @@ -1398,7 +1400,44 @@ checkpoint: } break; } + break; + case CMD_RESTORE: + /* TODO: verify battery on AC enough battery remaining */ + printf("Starting Restore...\n"); + + plist_t opts = plist_new_dict(); + plist_dict_insert_item(opts, "shouldRestoreSystemFiles", plist_new_bool(0)); + err = mobilebackup2_send_request(mobilebackup2, "Restore", uuid, uuid, opts); + plist_free(opts); + if (err != MOBILEBACKUP2_E_SUCCESS) { + cmd = CMD_LEAVE; + } + break; + case CMD_INFO: + printf("Requesting backup info from device...\n"); + err = mobilebackup2_send_request(mobilebackup2, "Info", uuid, NULL, NULL); + if (err != MOBILEBACKUP2_E_SUCCESS) { + cmd = CMD_LEAVE; + } + break; + case CMD_LIST: + printf("Requesting backup list from device...\n"); + err = mobilebackup2_send_request(mobilebackup2, "List", uuid, NULL, NULL); + if (err != MOBILEBACKUP2_E_SUCCESS) { + cmd = CMD_LEAVE; + } + break; + default: + break; + } + /* close down the lockdown connection as it is no longer needed */ + if (client) { + lockdownd_client_free(client); + client = NULL; + } + + if (cmd != CMD_LEAVE) { /* reset backup status */ int backup_ok = 0; plist_t message = NULL; @@ -1769,343 +1808,6 @@ files_out: } else { printf("Backup Failed.\n"); } - - break; - case CMD_RESTORE: - /* close down the lockdown connection as it is no longer needed */ - if (client) { - lockdownd_client_free(client); - client = NULL; - } - - /* TODO: verify battery on AC enough battery remaining */ - - /* verify if Status.plist says we read from an successful backup */ -#if 0 - if (mobilebackup_read_status(backup_directory) <= 0) { - printf("ERROR: Cannot ensure we restore from a successful backup. Aborting.\n"); - break; - } - /* now make sure backup integrity is ok! verify all files */ - printf("Reading existing Manifest.\n"); - plist_read_from_filename(&manifest_plist, manifest_path); - if (!manifest_plist) { - printf("Could not read Manifest.plist. Aborting.\n"); - break; - } - - printf("Verifying backup integrity, please wait.\n"); - char *bin = NULL; - uint64_t binsize = 0; - node = plist_dict_get_item(manifest_plist, "Data"); - if (!node || (plist_get_node_type(node) != PLIST_DATA)) { - printf("Could not read Data key from Manifest.plist!\n"); - break; - } - plist_get_data_val(node, &bin, &binsize); - plist_t backup_data = NULL; - if (bin) { - char *auth_ver = NULL; - unsigned char *auth_sig = NULL; - uint64_t auth_sig_len = 0; - /* verify AuthSignature */ - node = plist_dict_get_item(manifest_plist, "AuthVersion"); - plist_get_string_val(node, &auth_ver); - if (auth_ver && (strcmp(auth_ver, "2.0") == 0)) { - node = plist_dict_get_item(manifest_plist, "AuthSignature"); - if (node && (plist_get_node_type(node) == PLIST_DATA)) { - plist_get_data_val(node, (char**)&auth_sig, &auth_sig_len); - } - if (auth_sig && (auth_sig_len == 20)) { - /* calculate the sha1, then compare */ - unsigned char data_sha1[20]; - sha1_of_data(bin, binsize, data_sha1); - if (compare_hash(auth_sig, data_sha1, 20)) { - printf("AuthSignature is valid\n"); - } else { - printf("ERROR: AuthSignature is NOT VALID\n"); - } - } else { - printf("Could not get AuthSignature from manifest!\n"); - } - g_free(auth_sig); - } else if (auth_ver) { - printf("Unknown AuthVersion '%s', cannot verify AuthSignature\n", auth_ver); - } - plist_from_bin(bin, (uint32_t)binsize, &backup_data); - g_free(bin); - } - if (!backup_data) { - printf("Could not read plist from Manifest.plist Data key!\n"); - break; - } - plist_t files = plist_dict_get_item(backup_data, "Files"); - if (files && (plist_get_node_type(files) == PLIST_DICT)) { - plist_dict_iter iter = NULL; - plist_dict_new_iter(files, &iter); - if (iter) { - /* loop over Files entries in Manifest data plist */ - char *hash = NULL; - int file_ok = 0; - int total_files = plist_dict_get_size(files); - int cur_file = 1; - node = NULL; - plist_dict_next_item(files, iter, &hash, &node); - while (node) { - printf("Verifying file %d/%d (%d%%) \r", cur_file, total_files, (cur_file*100/total_files)); - cur_file++; - /* make sure both .mddata/.mdinfo files are available for each entry */ - file_ok = mobilebackup_check_file_integrity(backup_directory, hash, node); - node = NULL; - free(hash); - hash = NULL; - if (!file_ok) { - break; - } - plist_dict_next_item(files, iter, &hash, &node); - } - printf("\n"); - free(iter); - if (!file_ok) { - plist_free(backup_data); - break; - } - printf("All backup files appear to be valid\n"); - } - } - - printf("Requesting restore from device...\n"); - - /* request restore from device with manifest (BackupMessageRestoreMigrate) */ - int restore_flags = MB_RESTORE_NOTIFY_SPRINGBOARD | MB_RESTORE_PRESERVE_SETTINGS | MB_RESTORE_PRESERVE_CAMERA_ROLL; - err = mobilebackup_request_restore(mobilebackup, manifest_plist, restore_flags, "1.6"); - if (err != MOBILEBACKUP_E_SUCCESS) { - if (err == MOBILEBACKUP_E_BAD_VERSION) { - printf("ERROR: Could not start restore process: backup protocol version mismatch!\n"); - } else if (err == MOBILEBACKUP_E_REPLY_NOT_OK) { - printf("ERROR: Could not start restore process: device refused to start the restore process.\n"); - } else { - printf("ERROR: Could not start restore process: unspecified error occured (%d)\n", err); - } - plist_free(backup_data); - break; - } - - printf("Entered restore mode.\n"); - - int restore_ok = 0; - - if (files && (plist_get_node_type(files) == PLIST_DICT)) { - plist_dict_iter iter = NULL; - plist_dict_new_iter(files, &iter); - if (iter) { - /* loop over Files entries in Manifest data plist */ - char *hash = NULL; - plist_t file_info = NULL; - char *file_info_path = NULL; - int total_files = plist_dict_get_size(files); - int cur_file = 0; - uint64_t file_offset = 0; - uint8_t is_encrypted = 0; - plist_t tmp_node = NULL; - plist_t file_path_node = NULL; - plist_t send_file_node = NULL; - node = NULL; - plist_dict_next_item(files, iter, &hash, &node); - while (node) { - /* TODO: read mddata/mdinfo files and send to device using DLSendFile */ - file_info_path = mobilebackup_build_path(backup_directory, hash, ".mdinfo"); - plist_read_from_filename(&file_info, file_info_path); - - /* get encryption state */ - tmp_node = plist_dict_get_item(file_info, "IsEncrypted"); - plist_get_bool_val(tmp_node, &is_encrypted); - tmp_node = NULL; - - /* get real file path from metadata */ - tmp_node = plist_dict_get_item(file_info, "Metadata"); - plist_get_data_val(tmp_node, &buffer, &length); - tmp_node = NULL; - plist_from_bin(buffer, length, &tmp_node); - file_path_node = plist_dict_get_item(tmp_node, "Path"); - plist_get_string_val(file_path_node, &file_path); - - printf("Restoring file %s %d/%d (%d%%)... ", file_path, cur_file, total_files, (cur_file*100/total_files)); - - /* add additional device link file information keys */ - plist_dict_insert_item(file_info, "DLFileAttributesKey", plist_copy(node)); - plist_dict_insert_item(file_info, "DLFileSource", plist_new_string(file_info_path)); - plist_dict_insert_item(file_info, "DLFileDest", plist_new_string("/tmp/RestoreFile.plist")); - plist_dict_insert_item(file_info, "DLFileIsEncrypted", plist_new_bool(is_encrypted)); - plist_dict_insert_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset)); - plist_dict_insert_item(file_info, "DLFileStatusKey", plist_new_uint(file_status)); - - /* read data from file */ - free(file_info_path); - file_info_path = mobilebackup_build_path(backup_directory, hash, ".mddata"); - buffer_read_from_filename(file_info_path, &buffer, &length); - free(file_info_path); - - /* send DLSendFile messages */ - file_offset = 0; - do { - if ((length-file_offset) <= 8192) - file_status = DEVICE_LINK_FILE_STATUS_LAST_HUNK; - else - file_status = DEVICE_LINK_FILE_STATUS_HUNK; - - plist_dict_remove_item(file_info, "DLFileOffsetKey"); - plist_dict_insert_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset)); - - plist_dict_remove_item(file_info, "DLFileStatusKey"); - plist_dict_insert_item(file_info, "DLFileStatusKey", plist_new_uint(file_status)); - - send_file_node = plist_new_array(); - - plist_array_append_item(send_file_node, plist_new_string("DLSendFile")); - - if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) - plist_array_append_item(send_file_node, plist_new_data(buffer+file_offset, length-file_offset)); - else - plist_array_append_item(send_file_node, plist_new_data(buffer+file_offset, 8192)); - - plist_array_append_item(send_file_node, plist_copy(file_info)); - - err = mobilebackup_send(mobilebackup, send_file_node); - if (err != MOBILEBACKUP_E_SUCCESS) { - printf("ERROR: Unable to send file hunk due to error %d. Aborting...\n", err); - file_status = DEVICE_LINK_FILE_STATUS_NONE; - } - - if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) { - /* TODO: if all hunks of a file are sent, device must send ack */ - err = mobilebackup_receive_restore_file_received(mobilebackup, NULL); - if (err != MOBILEBACKUP_E_SUCCESS) { - printf("ERROR: Did not receive an ack for the sent file due to error %d. Aborting...\n", err); - file_status = DEVICE_LINK_FILE_STATUS_NONE; - } - } - - file_offset += 8192; - - if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) - printf("DONE\n"); - - plist_free(send_file_node); - - if (file_status == DEVICE_LINK_FILE_STATUS_NONE) - break; - - } while((file_offset < length)); - - free(hash); - node = NULL; - hash = NULL; - - restore_ok = 1; - if (file_status == DEVICE_LINK_FILE_STATUS_NONE) { - restore_ok = 0; - break; - } - - cur_file++; - plist_dict_next_item(files, iter, &hash, &node); - } - free(iter); - - printf("Restored %d files on device.\n", cur_file); - } - } - /* TODO: observe notification_proxy id com.apple.mobile.application_installed */ - /* TODO: loop over Applications entries in Manifest data plist */ - plist_t applications = plist_dict_get_item(backup_data, "Applications"); - if (applications && (plist_get_node_type(applications) == PLIST_DICT) && restore_ok) { - plist_dict_iter iter = NULL; - plist_dict_new_iter(applications, &iter); - if (iter) { - /* loop over Application entries in Manifest data plist */ - char *hash = NULL; - int total_files = plist_dict_get_size(applications); - int cur_file = 1; - plist_t tmp_node = NULL; - plist_t dict = NULL; - plist_t array = NULL; - node = NULL; - plist_dict_next_item(applications, iter, &hash, &node); - while (node) { - printf("Restoring Application %s %d/%d (%d%%)...", hash, cur_file, total_files, (cur_file*100/total_files)); - /* FIXME: receive com.apple.mobile.application_installed notification */ - /* send AppInfo entry */ - tmp_node = plist_dict_get_item(node, "AppInfo"); - - dict = plist_new_dict(); - plist_dict_insert_item(dict, "AppInfo", plist_copy(tmp_node)); - plist_dict_insert_item(dict, "BackupMessageTypeKey", plist_new_string("BackupMessageRestoreApplicationSent")); - - array = plist_new_array(); - plist_array_append_item(array, plist_new_string("DLMessageProcessMessage")); - plist_array_append_item(array, dict); - - err = mobilebackup_send(mobilebackup, array); - if (err != MOBILEBACKUP_E_SUCCESS) { - printf("ERROR: Unable to restore application %s due to error %d. Aborting...\n", hash, err); - restore_ok = 0; - } - - plist_free(array); - array = NULL; - dict = NULL; - - /* receive BackupMessageRestoreApplicationReceived from device */ - if (restore_ok) { - err = mobilebackup_receive_restore_application_received(mobilebackup, NULL); - if (err != MOBILEBACKUP_E_SUCCESS) { - printf("ERROR: Failed to receive an ack from the device for this application due to error %d. Aborting...\n", err); - restore_ok = 0; - } - } - - tmp_node = NULL; - node = NULL; - free(hash); - hash = NULL; - - if (restore_ok) { - printf("DONE\n"); - cur_file++; - plist_dict_next_item(applications, iter, &hash, &node); - } else - break; - } - free(iter); - - if (restore_ok) - printf("All applications restored.\n"); - else - printf("Failed to restore applications.\n"); - } - } - - plist_free(backup_data); - - /* signal restore finished message to device; BackupMessageRestoreComplete */ - if (restore_ok) { - err = mobilebackup_send_restore_complete(mobilebackup); - if (err != MOBILEBACKUP_E_SUCCESS) { - printf("ERROR: Could not send BackupMessageRestoreComplete, error code %d\n", err); - } - } - - if (restore_ok) { - printf("Restore Successful.\n"); - } else { - printf("Restore Failed.\n"); - } -#endif - break; - case CMD_LEAVE: - default: - break; } if (lockfile) { afc_file_lock(afc, lockfile, AFC_LOCK_UN); -- cgit v1.1-32-gdbae