diff options
| author | 2010-06-09 02:09:40 +0200 | |
|---|---|---|
| committer | 2010-06-09 02:09:40 +0200 | |
| commit | 7d15f1a2a74c1ea3f16d5f7cab923bc6844ba214 (patch) | |
| tree | 16d052ec67678ca57d6d833c7b925d2724893f62 | |
| parent | e08b61eb2d9af499e3f154c6c1c37312cbd55a37 (diff) | |
| download | libimobiledevice-7d15f1a2a74c1ea3f16d5f7cab923bc6844ba214.tar.gz libimobiledevice-7d15f1a2a74c1ea3f16d5f7cab923bc6844ba214.tar.bz2 | |
idevicebackup: Implement restore command for files and make restore work
| -rw-r--r-- | tools/idevicebackup.c | 154 |
1 files changed, 128 insertions, 26 deletions
diff --git a/tools/idevicebackup.c b/tools/idevicebackup.c index 0994e47..d287085 100644 --- a/tools/idevicebackup.c +++ b/tools/idevicebackup.c | |||
| @@ -219,7 +219,7 @@ static void mobilebackup_info_update_last_backup_date(plist_t info_plist) | |||
| 219 | node = NULL; | 219 | node = NULL; |
| 220 | } | 220 | } |
| 221 | 221 | ||
| 222 | static void buffer_read_from_filename(const char *filename, char **buffer, uint32_t *length) | 222 | static void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length) |
| 223 | { | 223 | { |
| 224 | FILE *f; | 224 | FILE *f; |
| 225 | uint64_t size; | 225 | uint64_t size; |
| @@ -243,10 +243,10 @@ static void buffer_read_from_filename(const char *filename, char **buffer, uint3 | |||
| 243 | fread(*buffer, sizeof(char), size, f); | 243 | fread(*buffer, sizeof(char), size, f); |
| 244 | fclose(f); | 244 | fclose(f); |
| 245 | 245 | ||
| 246 | *length = (uint32_t)size; | 246 | *length = size; |
| 247 | } | 247 | } |
| 248 | 248 | ||
| 249 | static void buffer_write_to_filename(const char *filename, const char *buffer, uint32_t length) | 249 | static void buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length) |
| 250 | { | 250 | { |
| 251 | FILE *f; | 251 | FILE *f; |
| 252 | 252 | ||
| @@ -258,7 +258,7 @@ static void buffer_write_to_filename(const char *filename, const char *buffer, u | |||
| 258 | static int plist_read_from_filename(plist_t *plist, const char *filename) | 258 | static int plist_read_from_filename(plist_t *plist, const char *filename) |
| 259 | { | 259 | { |
| 260 | char *buffer = NULL; | 260 | char *buffer = NULL; |
| 261 | uint32_t length; | 261 | uint64_t length; |
| 262 | 262 | ||
| 263 | if (!filename) | 263 | if (!filename) |
| 264 | return 0; | 264 | return 0; |
| @@ -432,7 +432,7 @@ static int mobilebackup_delete_backup_file_by_hash(const char *backup_directory, | |||
| 432 | { | 432 | { |
| 433 | int ret = 0; | 433 | int ret = 0; |
| 434 | gchar *path = mobilebackup_build_path(backup_directory, hash, ".mddata"); | 434 | gchar *path = mobilebackup_build_path(backup_directory, hash, ".mddata"); |
| 435 | printf("Removing \"%s\"... ", path); | 435 | printf("Removing \"%s\" ", path); |
| 436 | if (!remove( path )) | 436 | if (!remove( path )) |
| 437 | ret = 1; | 437 | ret = 1; |
| 438 | else | 438 | else |
| @@ -444,7 +444,7 @@ static int mobilebackup_delete_backup_file_by_hash(const char *backup_directory, | |||
| 444 | return ret; | 444 | return ret; |
| 445 | 445 | ||
| 446 | path = mobilebackup_build_path(backup_directory, hash, ".mdinfo"); | 446 | path = mobilebackup_build_path(backup_directory, hash, ".mdinfo"); |
| 447 | printf("Removing \"%s\"... ", path); | 447 | printf("and \"%s\"... ", path); |
| 448 | if (!remove( path )) | 448 | if (!remove( path )) |
| 449 | ret = 1; | 449 | ret = 1; |
| 450 | else | 450 | else |
| @@ -670,9 +670,10 @@ int main(int argc, char *argv[]) | |||
| 670 | plist_t manifest_plist = NULL; | 670 | plist_t manifest_plist = NULL; |
| 671 | plist_t info_plist = NULL; | 671 | plist_t info_plist = NULL; |
| 672 | char *buffer = NULL; | 672 | char *buffer = NULL; |
| 673 | char *file_path = NULL; | ||
| 673 | uint64_t length = 0; | 674 | uint64_t length = 0; |
| 674 | uint64_t backup_total_size = 0; | 675 | uint64_t backup_total_size = 0; |
| 675 | enum device_link_file_status_t file_status; | 676 | enum device_link_file_status_t file_status = DEVICE_LINK_FILE_STATUS_NONE; |
| 676 | uint64_t c = 0; | 677 | uint64_t c = 0; |
| 677 | 678 | ||
| 678 | /* we need to exit cleanly on running backups and restores or we cause havok */ | 679 | /* we need to exit cleanly on running backups and restores or we cause havok */ |
| @@ -934,7 +935,6 @@ int main(int argc, char *argv[]) | |||
| 934 | int file_index = 0; | 935 | int file_index = 0; |
| 935 | int hunk_index = 0; | 936 | int hunk_index = 0; |
| 936 | uint64_t backup_real_size = 0; | 937 | uint64_t backup_real_size = 0; |
| 937 | char *file_path = NULL; | ||
| 938 | char *file_ext = NULL; | 938 | char *file_ext = NULL; |
| 939 | char *filename_mdinfo = NULL; | 939 | char *filename_mdinfo = NULL; |
| 940 | char *filename_mddata = NULL; | 940 | char *filename_mddata = NULL; |
| @@ -1212,7 +1212,7 @@ int main(int argc, char *argv[]) | |||
| 1212 | node = NULL; | 1212 | node = NULL; |
| 1213 | plist_dict_next_item(files, iter, &hash, &node); | 1213 | plist_dict_next_item(files, iter, &hash, &node); |
| 1214 | while (node) { | 1214 | while (node) { |
| 1215 | printf("Verifying files %d/%d (%d%%) \r", cur_file, total_files, (cur_file*100/total_files)); | 1215 | printf("Verifying file %d/%d (%d%%) \r", cur_file, total_files, (cur_file*100/total_files)); |
| 1216 | cur_file++; | 1216 | cur_file++; |
| 1217 | /* make sure both .mddata/.mdinfo files are available for each entry */ | 1217 | /* make sure both .mddata/.mdinfo files are available for each entry */ |
| 1218 | file_ok = mobilebackup_check_file_integrity(backup_directory, hash, node); | 1218 | file_ok = mobilebackup_check_file_integrity(backup_directory, hash, node); |
| @@ -1233,6 +1233,9 @@ int main(int argc, char *argv[]) | |||
| 1233 | printf("All backup files appear to be valid\n"); | 1233 | printf("All backup files appear to be valid\n"); |
| 1234 | } | 1234 | } |
| 1235 | } | 1235 | } |
| 1236 | |||
| 1237 | printf("Requesting restore from device...\n"); | ||
| 1238 | |||
| 1236 | /* request restore from device with manifest (BackupMessageRestoreMigrate) */ | 1239 | /* request restore from device with manifest (BackupMessageRestoreMigrate) */ |
| 1237 | int restore_flags = MB_RESTORE_NOTIFY_SPRINGBOARD | MB_RESTORE_PRESERVE_SETTINGS | MB_RESTORE_PRESERVE_CAMERA_ROLL; | 1240 | int restore_flags = MB_RESTORE_NOTIFY_SPRINGBOARD | MB_RESTORE_PRESERVE_SETTINGS | MB_RESTORE_PRESERVE_CAMERA_ROLL; |
| 1238 | err = mobilebackup_request_restore(mobilebackup, manifest_plist, restore_flags, "1.6"); | 1241 | err = mobilebackup_request_restore(mobilebackup, manifest_plist, restore_flags, "1.6"); |
| @@ -1248,38 +1251,129 @@ int main(int argc, char *argv[]) | |||
| 1248 | break; | 1251 | break; |
| 1249 | } | 1252 | } |
| 1250 | 1253 | ||
| 1254 | printf("Entered restore mode.\n"); | ||
| 1255 | |||
| 1256 | int restore_ok = 0; | ||
| 1257 | |||
| 1251 | if (files && (plist_get_node_type(files) == PLIST_DICT)) { | 1258 | if (files && (plist_get_node_type(files) == PLIST_DICT)) { |
| 1252 | plist_dict_iter iter = NULL; | 1259 | plist_dict_iter iter = NULL; |
| 1253 | plist_dict_new_iter(files, &iter); | 1260 | plist_dict_new_iter(files, &iter); |
| 1254 | if (iter) { | 1261 | if (iter) { |
| 1255 | /* loop over Files entries in Manifest data plist */ | 1262 | /* loop over Files entries in Manifest data plist */ |
| 1256 | char *hash = NULL; | 1263 | char *hash = NULL; |
| 1257 | int file_ok = 0; | 1264 | plist_t file_info = NULL; |
| 1265 | char *file_info_path = NULL; | ||
| 1258 | int total_files = plist_dict_get_size(files); | 1266 | int total_files = plist_dict_get_size(files); |
| 1259 | int cur_file = 1; | 1267 | int cur_file = 0; |
| 1268 | uint64_t file_offset = 0; | ||
| 1269 | uint8_t is_encrypted = 0; | ||
| 1270 | plist_t tmp_node = NULL; | ||
| 1271 | plist_t file_path_node = NULL; | ||
| 1272 | plist_t send_file_node = NULL; | ||
| 1260 | node = NULL; | 1273 | node = NULL; |
| 1261 | plist_dict_next_item(files, iter, &hash, &node); | 1274 | plist_dict_next_item(files, iter, &hash, &node); |
| 1262 | while (node) { | 1275 | while (node) { |
| 1263 | printf("Sending files %d/%d (%d%%) \r", cur_file, total_files, (cur_file*100/total_files)); | ||
| 1264 | cur_file++; | ||
| 1265 | |||
| 1266 | /* TODO: read mddata/mdinfo files and send to device using DLSendFile */ | 1276 | /* TODO: read mddata/mdinfo files and send to device using DLSendFile */ |
| 1267 | /* TODO: if all hunks of a file are sent, device must send ack */ | 1277 | file_info_path = mobilebackup_build_path(backup_directory, hash, ".mdinfo"); |
| 1268 | /* err = mobilebackup_receive_restore_file_received(mobilebackup, &result); */ | 1278 | plist_read_from_filename(&file_info, file_info_path); |
| 1269 | node = NULL; | 1279 | |
| 1280 | /* get encryption state */ | ||
| 1281 | tmp_node = plist_dict_get_item(file_info, "IsEncrypted"); | ||
| 1282 | plist_get_bool_val(tmp_node, &is_encrypted); | ||
| 1283 | tmp_node = NULL; | ||
| 1284 | |||
| 1285 | /* get real file path from metadata */ | ||
| 1286 | tmp_node = plist_dict_get_item(file_info, "Metadata"); | ||
| 1287 | plist_get_data_val(tmp_node, &buffer, &length); | ||
| 1288 | tmp_node = NULL; | ||
| 1289 | plist_from_bin(buffer, length, &tmp_node); | ||
| 1290 | file_path_node = plist_dict_get_item(tmp_node, "Path"); | ||
| 1291 | plist_get_string_val(file_path_node, &file_path); | ||
| 1292 | |||
| 1293 | printf("Sending file %s %d/%d (%d%%)... ", file_path, cur_file, total_files, (cur_file*100/total_files)); | ||
| 1294 | |||
| 1295 | /* add additional device link file information keys */ | ||
| 1296 | plist_dict_insert_item(file_info, "DLFileAttributesKey", plist_copy(node)); | ||
| 1297 | plist_dict_insert_item(file_info, "DLFileSource", plist_new_string(file_info_path)); | ||
| 1298 | plist_dict_insert_item(file_info, "DLFileDest", plist_new_string("/tmp/RestoreFile.plist")); | ||
| 1299 | plist_dict_insert_item(file_info, "DLFileIsEncrypted", plist_new_bool(is_encrypted)); | ||
| 1300 | plist_dict_insert_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset)); | ||
| 1301 | plist_dict_insert_item(file_info, "DLFileStatusKey", plist_new_uint(file_status)); | ||
| 1302 | |||
| 1303 | /* read data from file */ | ||
| 1304 | free(file_info_path); | ||
| 1305 | file_info_path = mobilebackup_build_path(backup_directory, hash, ".mddata"); | ||
| 1306 | buffer_read_from_filename(file_info_path, &buffer, &length); | ||
| 1307 | free(file_info_path); | ||
| 1308 | |||
| 1309 | /* send DLSendFile messages */ | ||
| 1310 | file_offset = 0; | ||
| 1311 | do { | ||
| 1312 | if ((length-file_offset) <= 8192) | ||
| 1313 | file_status = DEVICE_LINK_FILE_STATUS_LAST_HUNK; | ||
| 1314 | else | ||
| 1315 | file_status = DEVICE_LINK_FILE_STATUS_HUNK; | ||
| 1316 | |||
| 1317 | plist_dict_remove_item(file_info, "DLFileOffsetKey"); | ||
| 1318 | plist_dict_insert_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset)); | ||
| 1319 | |||
| 1320 | plist_dict_remove_item(file_info, "DLFileStatusKey"); | ||
| 1321 | plist_dict_insert_item(file_info, "DLFileStatusKey", plist_new_uint(file_status)); | ||
| 1322 | |||
| 1323 | send_file_node = plist_new_array(); | ||
| 1324 | |||
| 1325 | plist_array_append_item(send_file_node, plist_new_string("DLSendFile")); | ||
| 1326 | |||
| 1327 | if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) | ||
| 1328 | plist_array_append_item(send_file_node, plist_new_data(buffer+file_offset, length-file_offset)); | ||
| 1329 | else | ||
| 1330 | plist_array_append_item(send_file_node, plist_new_data(buffer+file_offset, 8192)); | ||
| 1331 | |||
| 1332 | plist_array_append_item(send_file_node, plist_copy(file_info)); | ||
| 1333 | |||
| 1334 | err = mobilebackup_send(mobilebackup, send_file_node); | ||
| 1335 | if (err != MOBILEBACKUP_E_SUCCESS) { | ||
| 1336 | printf("ERROR: Unable to send file hunk due to error %d. Aborting...\n", err); | ||
| 1337 | file_status = DEVICE_LINK_FILE_STATUS_NONE; | ||
| 1338 | } | ||
| 1339 | |||
| 1340 | if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) { | ||
| 1341 | /* TODO: if all hunks of a file are sent, device must send ack */ | ||
| 1342 | err = mobilebackup_receive_restore_file_received(mobilebackup, NULL); | ||
| 1343 | if (err != MOBILEBACKUP_E_SUCCESS) { | ||
| 1344 | printf("ERROR: Did not receive an ack for the sent file due to error %d. Aborting...\n", err); | ||
| 1345 | file_status = DEVICE_LINK_FILE_STATUS_NONE; | ||
| 1346 | } | ||
| 1347 | } | ||
| 1348 | |||
| 1349 | file_offset += 8192; | ||
| 1350 | |||
| 1351 | if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) | ||
| 1352 | printf("DONE\n"); | ||
| 1353 | |||
| 1354 | plist_free(send_file_node); | ||
| 1355 | |||
| 1356 | if (file_status == DEVICE_LINK_FILE_STATUS_NONE) | ||
| 1357 | break; | ||
| 1358 | |||
| 1359 | } while((file_offset < length)); | ||
| 1360 | |||
| 1270 | free(hash); | 1361 | free(hash); |
| 1362 | node = NULL; | ||
| 1271 | hash = NULL; | 1363 | hash = NULL; |
| 1272 | if (!file_ok) { | 1364 | |
| 1365 | restore_ok = 1; | ||
| 1366 | if (file_status == DEVICE_LINK_FILE_STATUS_NONE) { | ||
| 1367 | restore_ok = 0; | ||
| 1273 | break; | 1368 | break; |
| 1274 | } | 1369 | } |
| 1370 | |||
| 1371 | cur_file++; | ||
| 1275 | plist_dict_next_item(files, iter, &hash, &node); | 1372 | plist_dict_next_item(files, iter, &hash, &node); |
| 1276 | } | 1373 | } |
| 1277 | printf("\n"); | ||
| 1278 | free(iter); | 1374 | free(iter); |
| 1279 | if (!file_ok) { | 1375 | |
| 1280 | plist_free(backup_data); | 1376 | printf("Restored %d files on device.\n", cur_file); |
| 1281 | break; | ||
| 1282 | } | ||
| 1283 | } | 1377 | } |
| 1284 | } | 1378 | } |
| 1285 | /* TODO: observe notification_proxy id com.apple.mobile.application_installed */ | 1379 | /* TODO: observe notification_proxy id com.apple.mobile.application_installed */ |
| @@ -1290,9 +1384,17 @@ int main(int argc, char *argv[]) | |||
| 1290 | plist_free(backup_data); | 1384 | plist_free(backup_data); |
| 1291 | 1385 | ||
| 1292 | /* signal restore finished message to device; BackupMessageRestoreComplete */ | 1386 | /* signal restore finished message to device; BackupMessageRestoreComplete */ |
| 1293 | err = mobilebackup_send_restore_complete(mobilebackup); | 1387 | if (restore_ok) { |
| 1294 | if (err != MOBILEBACKUP_E_SUCCESS) { | 1388 | err = mobilebackup_send_restore_complete(mobilebackup); |
| 1295 | printf("ERROR: Could not send BackupMessageRestoreComplete, error code %d\n", err); | 1389 | if (err != MOBILEBACKUP_E_SUCCESS) { |
| 1390 | printf("ERROR: Could not send BackupMessageRestoreComplete, error code %d\n", err); | ||
| 1391 | } | ||
| 1392 | } | ||
| 1393 | |||
| 1394 | if (restore_ok) { | ||
| 1395 | printf("Restore Successful.\n"); | ||
| 1396 | } else { | ||
| 1397 | printf("Restore Failed.\n"); | ||
| 1296 | } | 1398 | } |
| 1297 | break; | 1399 | break; |
| 1298 | case CMD_LEAVE: | 1400 | case CMD_LEAVE: |
