diff options
| author | 2010-01-26 02:03:21 +0100 | |
|---|---|---|
| committer | 2010-01-26 02:03:21 +0100 | |
| commit | b369efa426307bb6e9828c755ccc50c4f213c2e8 (patch) | |
| tree | e9fa13ca2662961af57095d38fe4231faba09fa4 /tools/iphonebackup.c | |
| parent | 90af94845ba841c693e80ac0eec317130c1c416e (diff) | |
| download | libimobiledevice-b369efa426307bb6e9828c755ccc50c4f213c2e8.tar.gz libimobiledevice-b369efa426307bb6e9828c755ccc50c4f213c2e8.tar.bz2 | |
Refactor iphonebackup and implement incremental backup support
Diffstat (limited to 'tools/iphonebackup.c')
| -rw-r--r-- | tools/iphonebackup.c | 293 |
1 files changed, 237 insertions, 56 deletions
diff --git a/tools/iphonebackup.c b/tools/iphonebackup.c index 19acc4e..f0cfa7a 100644 --- a/tools/iphonebackup.c +++ b/tools/iphonebackup.c | |||
| @@ -44,6 +44,17 @@ enum cmd_mode { | |||
| 44 | CMD_LEAVE | 44 | CMD_LEAVE |
| 45 | }; | 45 | }; |
| 46 | 46 | ||
| 47 | enum plist_format_t { | ||
| 48 | PLIST_FORMAT_XML, | ||
| 49 | PLIST_FORMAT_BINARY | ||
| 50 | }; | ||
| 51 | |||
| 52 | enum device_link_file_status_t { | ||
| 53 | DEVICE_LINK_FILE_STATUS_NONE = 0, | ||
| 54 | DEVICE_LINK_FILE_STATUS_HUNK, | ||
| 55 | DEVICE_LINK_FILE_STATUS_LAST_HUNK | ||
| 56 | }; | ||
| 57 | |||
| 47 | static plist_t mobilebackup_factory_info_plist_new() | 58 | static plist_t mobilebackup_factory_info_plist_new() |
| 48 | { | 59 | { |
| 49 | /* gather data from lockdown */ | 60 | /* gather data from lockdown */ |
| @@ -95,20 +106,50 @@ static plist_t mobilebackup_factory_info_plist_new() | |||
| 95 | free(uuid_uppercase); | 106 | free(uuid_uppercase); |
| 96 | free(uuid); | 107 | free(uuid); |
| 97 | 108 | ||
| 98 | plist_t files = plist_new_dict(); | ||
| 99 | /* FIXME: Embed files as <data> nodes */ | 109 | /* FIXME: Embed files as <data> nodes */ |
| 110 | plist_t files = plist_new_dict(); | ||
| 100 | plist_dict_insert_item(ret, "iTunes Files", files); | 111 | plist_dict_insert_item(ret, "iTunes Files", files); |
| 101 | plist_dict_insert_item(ret, "iTunes Version", plist_new_string("9.0.2")); | 112 | plist_dict_insert_item(ret, "iTunes Version", plist_new_string("9.0.2")); |
| 102 | 113 | ||
| 114 | plist_free(root_node); | ||
| 115 | |||
| 103 | return ret; | 116 | return ret; |
| 104 | } | 117 | } |
| 105 | 118 | ||
| 106 | enum plist_format_t { | 119 | static void mobilebackup_info_update_last_backup_date(plist_t info_plist) |
| 107 | PLIST_FORMAT_XML, | 120 | { |
| 108 | PLIST_FORMAT_BINARY | 121 | GTimeVal tv = {0, 0}; |
| 109 | }; | 122 | plist_t node = NULL; |
| 110 | 123 | ||
| 111 | static void buffer_to_filename(char *filename, char *buffer, uint32_t length) | 124 | if (!info_plist) |
| 125 | return; | ||
| 126 | |||
| 127 | g_get_current_time(&tv); | ||
| 128 | node = plist_dict_get_item(info_plist, "Last Backup Date"); | ||
| 129 | plist_set_date_val(node, tv.tv_sec, tv.tv_usec); | ||
| 130 | |||
| 131 | node = NULL; | ||
| 132 | } | ||
| 133 | |||
| 134 | static void buffer_read_from_filename(const char *filename, char **buffer, uint32_t *length) | ||
| 135 | { | ||
| 136 | FILE *f; | ||
| 137 | uint64_t size; | ||
| 138 | |||
| 139 | f = fopen(filename, "rb"); | ||
| 140 | |||
| 141 | fseek(f, 0, SEEK_END); | ||
| 142 | size = ftell(f); | ||
| 143 | rewind(f); | ||
| 144 | |||
| 145 | *buffer = (char*)malloc(sizeof(char)*size); | ||
| 146 | fread(*buffer, sizeof(char), size, f); | ||
| 147 | fclose(f); | ||
| 148 | |||
| 149 | *length = size; | ||
| 150 | } | ||
| 151 | |||
| 152 | static void buffer_write_to_filename(const char *filename, const char *buffer, uint32_t length) | ||
| 112 | { | 153 | { |
| 113 | FILE *f; | 154 | FILE *f; |
| 114 | 155 | ||
| @@ -117,7 +158,32 @@ static void buffer_to_filename(char *filename, char *buffer, uint32_t length) | |||
| 117 | fclose(f); | 158 | fclose(f); |
| 118 | } | 159 | } |
| 119 | 160 | ||
| 120 | static int plist_write_to_filename(plist_t plist, char *filename, enum plist_format_t format) | 161 | static int plist_read_from_filename(plist_t *plist, const char *filename) |
| 162 | { | ||
| 163 | char *buffer = NULL; | ||
| 164 | uint32_t length; | ||
| 165 | |||
| 166 | if (!filename) | ||
| 167 | return 0; | ||
| 168 | |||
| 169 | buffer_read_from_filename(filename, &buffer, &length); | ||
| 170 | |||
| 171 | if (!buffer) { | ||
| 172 | return 0; | ||
| 173 | } | ||
| 174 | |||
| 175 | if (memcmp(buffer, "bplist00", 8) == 0) { | ||
| 176 | plist_from_bin(buffer, length, plist); | ||
| 177 | } else { | ||
| 178 | plist_from_xml(buffer, length, plist); | ||
| 179 | } | ||
| 180 | |||
| 181 | free(buffer); | ||
| 182 | |||
| 183 | return 1; | ||
| 184 | } | ||
| 185 | |||
| 186 | static int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format) | ||
| 121 | { | 187 | { |
| 122 | char *buffer = NULL; | 188 | char *buffer = NULL; |
| 123 | uint32_t length; | 189 | uint32_t length; |
| @@ -132,7 +198,7 @@ static int plist_write_to_filename(plist_t plist, char *filename, enum plist_for | |||
| 132 | else | 198 | else |
| 133 | return 0; | 199 | return 0; |
| 134 | 200 | ||
| 135 | buffer_to_filename(filename, buffer, length); | 201 | buffer_write_to_filename(filename, buffer, length); |
| 136 | 202 | ||
| 137 | free(buffer); | 203 | free(buffer); |
| 138 | 204 | ||
| @@ -183,17 +249,100 @@ static plist_t mobilebackup_factory_backup_file_received_new() | |||
| 183 | return device_link_message_factory_process_message_new(node); | 249 | return device_link_message_factory_process_message_new(node); |
| 184 | } | 250 | } |
| 185 | 251 | ||
| 186 | static void mobilebackup_write_status(char *path, int status) | 252 | static gchar *mobilebackup_build_path(const char *backup_directory, const char *name, const char *extension) |
| 253 | { | ||
| 254 | gchar *filename = g_strconcat(name, extension, NULL); | ||
| 255 | gchar *path = g_build_path(G_DIR_SEPARATOR_S, backup_directory, filename, NULL); | ||
| 256 | g_free(filename); | ||
| 257 | return path; | ||
| 258 | } | ||
| 259 | |||
| 260 | static void mobilebackup_write_status(const char *path, int status) | ||
| 187 | { | 261 | { |
| 188 | struct stat st; | 262 | struct stat st; |
| 189 | plist_t status_plist = plist_new_dict(); | 263 | plist_t status_plist = plist_new_dict(); |
| 190 | plist_dict_insert_item(status_plist, "Backup Success", plist_new_bool(status)); | 264 | plist_dict_insert_item(status_plist, "Backup Success", plist_new_bool(status)); |
| 191 | char *file_path = g_build_path(G_DIR_SEPARATOR_S, path, "Status.plist", NULL); | 265 | gchar *file_path = mobilebackup_build_path(path, "Status", ".plist"); |
| 266 | |||
| 192 | if (stat(file_path, &st) == 0) | 267 | if (stat(file_path, &st) == 0) |
| 193 | remove(file_path); | 268 | remove(file_path); |
| 269 | |||
| 194 | plist_write_to_filename(status_plist, file_path, PLIST_FORMAT_XML); | 270 | plist_write_to_filename(status_plist, file_path, PLIST_FORMAT_XML); |
| 195 | g_free(file_path); | 271 | |
| 196 | plist_free(status_plist); | 272 | plist_free(status_plist); |
| 273 | status_plist = NULL; | ||
| 274 | |||
| 275 | g_free(file_path); | ||
| 276 | } | ||
| 277 | |||
| 278 | static int mobilebackup_info_is_current_device(plist_t info) | ||
| 279 | { | ||
| 280 | plist_t value_node = NULL; | ||
| 281 | plist_t node = NULL; | ||
| 282 | plist_t root_node = NULL; | ||
| 283 | int ret = 0; | ||
| 284 | |||
| 285 | if (!info) | ||
| 286 | return ret; | ||
| 287 | |||
| 288 | if (plist_get_node_type(info) != PLIST_DICT) | ||
| 289 | return ret; | ||
| 290 | |||
| 291 | /* get basic device information in one go */ | ||
| 292 | lockdownd_get_value(client, NULL, NULL, &root_node); | ||
| 293 | |||
| 294 | /* verify UUID */ | ||
| 295 | value_node = plist_dict_get_item(root_node, "UniqueDeviceID"); | ||
| 296 | node = plist_dict_get_item(info, "Target Identifier"); | ||
| 297 | |||
| 298 | if(plist_compare_node_value(value_node, node)) | ||
| 299 | ret = 1; | ||
| 300 | |||
| 301 | /* verify SerialNumber */ | ||
| 302 | if (ret == 1) { | ||
| 303 | value_node = plist_dict_get_item(root_node, "SerialNumber"); | ||
| 304 | node = plist_dict_get_item(info, "Serial Number"); | ||
| 305 | |||
| 306 | if(plist_compare_node_value(value_node, node)) | ||
| 307 | ret = 1; | ||
| 308 | else | ||
| 309 | ret = 0; | ||
| 310 | } | ||
| 311 | |||
| 312 | plist_free(root_node); | ||
| 313 | root_node = NULL; | ||
| 314 | |||
| 315 | value_node = NULL; | ||
| 316 | node = NULL; | ||
| 317 | |||
| 318 | return ret; | ||
| 319 | } | ||
| 320 | |||
| 321 | static int mobilebackup_delete_backup_file_by_hash(const char *backup_directory, const char *hash) | ||
| 322 | { | ||
| 323 | int ret = 0; | ||
| 324 | gchar *path = mobilebackup_build_path(backup_directory, hash, ".mddata"); | ||
| 325 | printf("Removing \"%s\"... ", path); | ||
| 326 | if (!remove( path )) | ||
| 327 | ret = 1; | ||
| 328 | else | ||
| 329 | ret = 0; | ||
| 330 | |||
| 331 | g_free(path); | ||
| 332 | |||
| 333 | if (!ret) | ||
| 334 | return ret; | ||
| 335 | |||
| 336 | path = mobilebackup_build_path(backup_directory, hash, ".mdinfo"); | ||
| 337 | printf("Removing \"%s\"... ", path); | ||
| 338 | if (!remove( path )) | ||
| 339 | ret = 1; | ||
| 340 | else | ||
| 341 | ret = 0; | ||
| 342 | |||
| 343 | g_free(path); | ||
| 344 | |||
| 345 | return ret; | ||
| 197 | } | 346 | } |
| 198 | 347 | ||
| 199 | /** | 348 | /** |
| @@ -229,13 +378,17 @@ int main(int argc, char *argv[]) | |||
| 229 | uint16_t port = 0; | 378 | uint16_t port = 0; |
| 230 | uuid[0] = 0; | 379 | uuid[0] = 0; |
| 231 | int cmd = -1; | 380 | int cmd = -1; |
| 381 | int is_full_backup = 0; | ||
| 232 | char *backup_directory = NULL; | 382 | char *backup_directory = NULL; |
| 233 | struct stat st; | 383 | struct stat st; |
| 234 | plist_t node = NULL; | 384 | plist_t node = NULL; |
| 235 | plist_t node_tmp = NULL; | 385 | plist_t node_tmp = NULL; |
| 386 | plist_t manifest_plist = NULL; | ||
| 387 | plist_t info_plist = NULL; | ||
| 236 | char *buffer = NULL; | 388 | char *buffer = NULL; |
| 237 | uint64_t length = 0; | 389 | uint64_t length = 0; |
| 238 | uint64_t backup_total_size = 0; | 390 | uint64_t backup_total_size = 0; |
| 391 | enum device_link_file_status_t file_status; | ||
| 239 | uint64_t c = 0; | 392 | uint64_t c = 0; |
| 240 | 393 | ||
| 241 | /* we need to exit cleanly on running backups and restores or we cause havok */ | 394 | /* we need to exit cleanly on running backups and restores or we cause havok */ |
| @@ -298,7 +451,7 @@ int main(int argc, char *argv[]) | |||
| 298 | } | 451 | } |
| 299 | 452 | ||
| 300 | /* restore directory must contain an Info.plist */ | 453 | /* restore directory must contain an Info.plist */ |
| 301 | char *info_path = g_build_path(G_DIR_SEPARATOR_S, backup_directory, "Info.plist", NULL); | 454 | char *info_path = mobilebackup_build_path(backup_directory, "Info", ".plist"); |
| 302 | if (cmd == CMD_RESTORE) { | 455 | if (cmd == CMD_RESTORE) { |
| 303 | if (stat(info_path, &st) != 0) { | 456 | if (stat(info_path, &st) != 0) { |
| 304 | g_free(info_path); | 457 | g_free(info_path); |
| @@ -347,27 +500,45 @@ int main(int argc, char *argv[]) | |||
| 347 | /* TODO: check domain com.apple.mobile.backup key RequiresEncrypt and WillEncrypt with lockdown */ | 500 | /* TODO: check domain com.apple.mobile.backup key RequiresEncrypt and WillEncrypt with lockdown */ |
| 348 | /* TODO: verify battery on AC enough battery remaining */ | 501 | /* TODO: verify battery on AC enough battery remaining */ |
| 349 | 502 | ||
| 350 | /* create Info.plist (Device infos, IC-Info.sidb, photos, app_ids, iTunesPrefs) */ | 503 | /* Info.plist (Device infos, IC-Info.sidb, photos, app_ids, iTunesPrefs) */ |
| 351 | printf("Creating Info.plist.\n"); | 504 | |
| 352 | plist_t info_plist = mobilebackup_factory_info_plist_new(); | 505 | /* read existing Info.plist or create new one */ |
| 353 | if (stat(info_path, &st) == 0) | 506 | if (stat(info_path, &st) == 0) { |
| 354 | remove(info_path); | 507 | printf("Reading Info.plist from existing backup.\n"); |
| 355 | plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML); | 508 | plist_read_from_filename(&info_plist, info_path); |
| 509 | |||
| 510 | if(!is_full_backup) { | ||
| 511 | /* update the last backup time within Info.plist */ | ||
| 512 | mobilebackup_info_update_last_backup_date(info_plist); | ||
| 513 | remove(info_path); | ||
| 514 | plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML); | ||
| 515 | } | ||
| 516 | } else { | ||
| 517 | printf("Creating Info.plist for new backup.\n"); | ||
| 518 | info_plist = mobilebackup_factory_info_plist_new(); | ||
| 519 | plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML); | ||
| 520 | is_full_backup = 1; | ||
| 521 | } | ||
| 522 | |||
| 356 | g_free(info_path); | 523 | g_free(info_path); |
| 357 | 524 | ||
| 525 | /* Manifest.plist (backup manifest (backup state)) */ | ||
| 526 | char *manifest_path = mobilebackup_build_path(backup_directory, "Manifest", ".plist"); | ||
| 527 | /* read the last Manifest.plist if the current backup is for this device */ | ||
| 528 | if (!is_full_backup && mobilebackup_info_is_current_device(info_plist)) { | ||
| 529 | printf("Reading existing Manifest.\n"); | ||
| 530 | plist_read_from_filename(&manifest_plist, manifest_path); | ||
| 531 | } | ||
| 532 | |||
| 533 | plist_free(info_plist); | ||
| 534 | info_plist = NULL; | ||
| 535 | |||
| 358 | /* close down the lockdown connection as it is no longer needed */ | 536 | /* close down the lockdown connection as it is no longer needed */ |
| 359 | if (client) { | 537 | if (client) { |
| 360 | lockdownd_client_free(client); | 538 | lockdownd_client_free(client); |
| 361 | client = NULL; | 539 | client = NULL; |
| 362 | } | 540 | } |
| 363 | 541 | ||
| 364 | /* create Manifest.plist (backup manifest (backup state)) */ | ||
| 365 | char *manifest_path = g_build_path(G_DIR_SEPARATOR_S, backup_directory, "Manifest.plist", NULL); | ||
| 366 | /* FIXME: We should read the last Manifest.plist and send it to the device */ | ||
| 367 | plist_t manifest_plist = NULL; | ||
| 368 | if (stat(manifest_path, &st) == 0) | ||
| 369 | remove(manifest_path); | ||
| 370 | |||
| 371 | /* create Status.plist with failed status for now */ | 542 | /* create Status.plist with failed status for now */ |
| 372 | mobilebackup_write_status(backup_directory, 0); | 543 | mobilebackup_write_status(backup_directory, 0); |
| 373 | 544 | ||
| @@ -375,8 +546,10 @@ int main(int argc, char *argv[]) | |||
| 375 | printf("Requesting backup from device...\n"); | 546 | printf("Requesting backup from device...\n"); |
| 376 | 547 | ||
| 377 | node = plist_new_dict(); | 548 | node = plist_new_dict(); |
| 549 | |||
| 378 | if (manifest_plist) | 550 | if (manifest_plist) |
| 379 | plist_dict_insert_item(node, "BackupManifestKey", manifest_plist); | 551 | plist_dict_insert_item(node, "BackupManifestKey", manifest_plist); |
| 552 | |||
| 380 | plist_dict_insert_item(node, "BackupComputerBasePathKey", plist_new_string("/")); | 553 | plist_dict_insert_item(node, "BackupComputerBasePathKey", plist_new_string("/")); |
| 381 | plist_dict_insert_item(node, "BackupMessageTypeKey", plist_new_string("BackupMessageBackupRequest")); | 554 | plist_dict_insert_item(node, "BackupMessageTypeKey", plist_new_string("BackupMessageBackupRequest")); |
| 382 | plist_dict_insert_item(node, "BackupProtocolVersion", plist_new_string("1.6")); | 555 | plist_dict_insert_item(node, "BackupProtocolVersion", plist_new_string("1.6")); |
| @@ -389,6 +562,7 @@ int main(int argc, char *argv[]) | |||
| 389 | /* get response */ | 562 | /* get response */ |
| 390 | int backup_ok = 0; | 563 | int backup_ok = 0; |
| 391 | mobilebackup_receive(mobilebackup, &message); | 564 | mobilebackup_receive(mobilebackup, &message); |
| 565 | |||
| 392 | node = plist_array_get_item(message, 0); | 566 | node = plist_array_get_item(message, 0); |
| 393 | if (!plist_strcmp(node, "DLMessageProcessMessage")) { | 567 | if (!plist_strcmp(node, "DLMessageProcessMessage")) { |
| 394 | node = plist_array_get_item(message, 1); | 568 | node = plist_array_get_item(message, 1); |
| @@ -397,6 +571,10 @@ int main(int argc, char *argv[]) | |||
| 397 | printf("Device accepts manifest and will send backup data now...\n"); | 571 | printf("Device accepts manifest and will send backup data now...\n"); |
| 398 | backup_ok = 1; | 572 | backup_ok = 1; |
| 399 | printf("Acknowledging...\n"); | 573 | printf("Acknowledging...\n"); |
| 574 | if (is_full_backup) | ||
| 575 | printf("Full backup mode.\n"); | ||
| 576 | else | ||
| 577 | printf("Incremental backup mode.\n"); | ||
| 400 | printf("Please wait. Device prepares backup data...\n"); | 578 | printf("Please wait. Device prepares backup data...\n"); |
| 401 | /* send it back for ACK */ | 579 | /* send it back for ACK */ |
| 402 | mobilebackup_send(mobilebackup, message); | 580 | mobilebackup_send(mobilebackup, message); |
| @@ -427,9 +605,13 @@ int main(int argc, char *argv[]) | |||
| 427 | char *format_size = NULL; | 605 | char *format_size = NULL; |
| 428 | gboolean is_manifest = FALSE; | 606 | gboolean is_manifest = FALSE; |
| 429 | uint8_t b = 0; | 607 | uint8_t b = 0; |
| 608 | |||
| 609 | /* process series of DLSendFile messages */ | ||
| 430 | do { | 610 | do { |
| 431 | mobilebackup_receive(mobilebackup, &message); | 611 | mobilebackup_receive(mobilebackup, &message); |
| 432 | node = plist_array_get_item(message, 0); | 612 | node = plist_array_get_item(message, 0); |
| 613 | |||
| 614 | /* get out if we don't get a DLSendFile */ | ||
| 433 | if (plist_strcmp(node, "DLSendFile")) | 615 | if (plist_strcmp(node, "DLSendFile")) |
| 434 | break; | 616 | break; |
| 435 | 617 | ||
| @@ -446,9 +628,10 @@ int main(int argc, char *argv[]) | |||
| 446 | } | 628 | } |
| 447 | } | 629 | } |
| 448 | 630 | ||
| 449 | /* print out "received" if DLFileStatusKey is 2 (last file piece) */ | 631 | /* check DLFileStatusKey (codes: 1 = Hunk, 2 = Last Hunk) */ |
| 450 | node = plist_dict_get_item(node_tmp, "DLFileStatusKey"); | 632 | node = plist_dict_get_item(node_tmp, "DLFileStatusKey"); |
| 451 | plist_get_uint_val(node, &c); | 633 | plist_get_uint_val(node, &c); |
| 634 | file_status = c; | ||
| 452 | 635 | ||
| 453 | /* get source filename */ | 636 | /* get source filename */ |
| 454 | node = plist_dict_get_item(node_tmp, "BackupManifestKey"); | 637 | node = plist_dict_get_item(node_tmp, "BackupManifestKey"); |
| @@ -458,25 +641,26 @@ int main(int argc, char *argv[]) | |||
| 458 | } | 641 | } |
| 459 | is_manifest = (b == 1) ? TRUE: FALSE; | 642 | is_manifest = (b == 1) ? TRUE: FALSE; |
| 460 | 643 | ||
| 461 | /* increased received size for each completed file */ | 644 | /* check if we completed a file */ |
| 462 | if ((c == 2) && (!is_manifest)) { | 645 | if ((file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) && (!is_manifest)) { |
| 463 | /* get source filename */ | 646 | /* get source filename */ |
| 464 | node = plist_dict_get_item(node_tmp, "DLFileSource"); | 647 | node = plist_dict_get_item(node_tmp, "DLFileSource"); |
| 465 | plist_get_string_val(node, &filename_source); | 648 | plist_get_string_val(node, &filename_source); |
| 466 | 649 | ||
| 650 | /* increase received size */ | ||
| 467 | node = plist_dict_get_item(node_tmp, "DLFileAttributesKey"); | 651 | node = plist_dict_get_item(node_tmp, "DLFileAttributesKey"); |
| 468 | node = plist_dict_get_item(node, "FileSize"); | 652 | node = plist_dict_get_item(node, "FileSize"); |
| 469 | plist_get_uint_val(node, &length); | 653 | plist_get_uint_val(node, &length); |
| 470 | |||
| 471 | backup_real_size += length; | 654 | backup_real_size += length; |
| 472 | file_index++; | ||
| 473 | 655 | ||
| 474 | format_size = g_format_size_for_display(backup_real_size); | 656 | format_size = g_format_size_for_display(backup_real_size); |
| 475 | printf("(%s", format_size); | 657 | printf("(%s", format_size); |
| 476 | g_free(format_size); | 658 | g_free(format_size); |
| 659 | |||
| 477 | format_size = g_format_size_for_display(backup_total_size); | 660 | format_size = g_format_size_for_display(backup_total_size); |
| 478 | printf("/%s): ", format_size); | 661 | printf("/%s): ", format_size); |
| 479 | g_free(format_size); | 662 | g_free(format_size); |
| 663 | |||
| 480 | printf("Received file %s... ", filename_source); | 664 | printf("Received file %s... ", filename_source); |
| 481 | 665 | ||
| 482 | if (filename_source) | 666 | if (filename_source) |
| @@ -487,13 +671,20 @@ int main(int argc, char *argv[]) | |||
| 487 | if (node) { | 671 | if (node) { |
| 488 | node = plist_dict_get_item(node_tmp, "DLFileDest"); | 672 | node = plist_dict_get_item(node_tmp, "DLFileDest"); |
| 489 | plist_get_string_val(node, &file_path); | 673 | plist_get_string_val(node, &file_path); |
| 490 | file_ext = (char *)g_strconcat(file_path, ".mdinfo", NULL); | 674 | |
| 491 | filename_mdinfo = g_build_path(G_DIR_SEPARATOR_S, backup_directory, file_ext, NULL); | 675 | filename_mdinfo = mobilebackup_build_path(backup_directory, file_path, ".mdinfo"); |
| 676 | |||
| 677 | /* remove any existing file */ | ||
| 678 | if (stat(filename_mdinfo, &st) != 0) | ||
| 679 | remove(filename_mdinfo); | ||
| 680 | |||
| 492 | node = plist_dict_get_item(node_tmp, "BackupFileInfo"); | 681 | node = plist_dict_get_item(node_tmp, "BackupFileInfo"); |
| 493 | plist_write_to_filename(node, filename_mdinfo, PLIST_FORMAT_BINARY); | 682 | plist_write_to_filename(node, filename_mdinfo, PLIST_FORMAT_BINARY); |
| 494 | g_free(file_ext); | 683 | |
| 495 | g_free(filename_mdinfo); | 684 | g_free(filename_mdinfo); |
| 496 | } | 685 | } |
| 686 | |||
| 687 | file_index++; | ||
| 497 | } | 688 | } |
| 498 | 689 | ||
| 499 | /* save <hash>.mddata */ | 690 | /* save <hash>.mddata */ |
| @@ -502,23 +693,26 @@ int main(int argc, char *argv[]) | |||
| 502 | node = plist_dict_get_item(node_tmp, "DLFileDest"); | 693 | node = plist_dict_get_item(node_tmp, "DLFileDest"); |
| 503 | plist_get_string_val(node, &file_path); | 694 | plist_get_string_val(node, &file_path); |
| 504 | 695 | ||
| 505 | if (!is_manifest) | 696 | filename_mddata = mobilebackup_build_path(backup_directory, file_path, is_manifest ? NULL: ".mddata"); |
| 506 | file_ext = (char *)g_strconcat(file_path, ".mddata", NULL); | 697 | |
| 507 | else | 698 | /* if this is the first hunk, remove any existing file */ |
| 508 | file_ext = g_strdup(file_path); | 699 | if (stat(filename_mddata, &st) != 0) |
| 700 | remove(filename_mddata); | ||
| 509 | 701 | ||
| 510 | filename_mddata = g_build_path(G_DIR_SEPARATOR_S, backup_directory, file_ext, NULL); | 702 | /* get file data hunk */ |
| 511 | node_tmp = plist_array_get_item(message, 1); | 703 | node_tmp = plist_array_get_item(message, 1); |
| 512 | plist_get_data_val(node_tmp, &buffer, &length); | 704 | plist_get_data_val(node_tmp, &buffer, &length); |
| 513 | 705 | ||
| 514 | buffer_to_filename(filename_mddata, buffer, length); | 706 | buffer_write_to_filename(filename_mddata, buffer, length); |
| 515 | 707 | ||
| 516 | /* activate currently sent manifest */ | 708 | /* activate currently sent manifest */ |
| 517 | if ((c == 2) && (is_manifest)) { | 709 | if ((file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) && (is_manifest)) { |
| 518 | rename(filename_mddata, manifest_path); | 710 | rename(filename_mddata, manifest_path); |
| 519 | } | 711 | } |
| 712 | |||
| 520 | free(buffer); | 713 | free(buffer); |
| 521 | buffer = NULL; | 714 | buffer = NULL; |
| 715 | |||
| 522 | g_free(filename_mddata); | 716 | g_free(filename_mddata); |
| 523 | } | 717 | } |
| 524 | 718 | ||
| @@ -531,7 +725,7 @@ int main(int argc, char *argv[]) | |||
| 531 | plist_free(message); | 725 | plist_free(message); |
| 532 | message = NULL; | 726 | message = NULL; |
| 533 | 727 | ||
| 534 | if (c == 2) { | 728 | if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) { |
| 535 | if (!is_manifest) | 729 | if (!is_manifest) |
| 536 | printf("DONE\n"); | 730 | printf("DONE\n"); |
| 537 | 731 | ||
| @@ -566,20 +760,7 @@ int main(int argc, char *argv[]) | |||
| 566 | while ((node_tmp = plist_array_get_item(node, i++)) != NULL) { | 760 | while ((node_tmp = plist_array_get_item(node, i++)) != NULL) { |
| 567 | plist_get_string_val(node_tmp, &file_path); | 761 | plist_get_string_val(node_tmp, &file_path); |
| 568 | 762 | ||
| 569 | file_ext = (char *)g_strconcat(file_path, ".mddata", NULL); | 763 | if (mobilebackup_delete_backup_file_by_hash(backup_directory, file_path)) { |
| 570 | filename_mddata = g_build_path(G_DIR_SEPARATOR_S, backup_directory, file_ext, NULL); | ||
| 571 | g_free(file_ext); | ||
| 572 | printf("Removing \"%s\"... ", filename_mddata); | ||
| 573 | if (!remove( filename_mddata )) { | ||
| 574 | printf("DONE\n"); | ||
| 575 | } else | ||
| 576 | printf("FAILED\n"); | ||
| 577 | |||
| 578 | file_ext = (char *)g_strconcat(file_path, ".mdinfo", NULL); | ||
| 579 | filename_mdinfo = g_build_path(G_DIR_SEPARATOR_S, backup_directory, file_ext, NULL); | ||
| 580 | g_free(file_ext); | ||
| 581 | printf("Removing \"%s\"... ", filename_mdinfo); | ||
| 582 | if (!remove( filename_mdinfo )) { | ||
| 583 | printf("DONE\n"); | 764 | printf("DONE\n"); |
| 584 | } else | 765 | } else |
| 585 | printf("FAILED\n"); | 766 | printf("FAILED\n"); |
| @@ -600,7 +781,7 @@ int main(int argc, char *argv[]) | |||
| 600 | } | 781 | } |
| 601 | 782 | ||
| 602 | if (backup_ok) { | 783 | if (backup_ok) { |
| 603 | /* create: Status.plist (Info on how the backup process turned out) */ | 784 | /* Status.plist (Info on how the backup process turned out) */ |
| 604 | printf("Backup Successful.\n"); | 785 | printf("Backup Successful.\n"); |
| 605 | mobilebackup_write_status(backup_directory, 1); | 786 | mobilebackup_write_status(backup_directory, 1); |
| 606 | } else { | 787 | } else { |
