~ubuntu-branches/ubuntu/quantal/libimobiledevice/quantal-updates

« back to all changes in this revision

Viewing changes to tools/idevicebackup.c

  • Committer: Bazaar Package Importer
  • Author(s): Julien Lavergne
  • Date: 2010-12-19 00:11:04 UTC
  • mfrom: (2.1.7 experimental)
  • Revision ID: james.westby@ubuntu.com-20101219001104-minn5kkcw1die9c3
Tags: 1.1.0-1
* New upstream development release, API is considered unstable.
* debian/libimobiledevice1*, debian/rules, debian/control:
 - Bump SONAME for libimobiledevice library.
* debian/copyright:
 - Update copyright holders.
* debian/libimobiledevice2.symbols:
 - Update with new symbols.
* debian/ideviceenterrecovery.1:
 - Add new manpage.
* debian/libimobiledevice-utils.manpages:
 - Install the new manpage.

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
#include <stdlib.h>
27
27
#include <signal.h>
28
28
#include <glib.h>
 
29
#include <gcrypt.h>
29
30
#include <unistd.h>
30
31
 
31
32
#include <libimobiledevice/libimobiledevice.h>
63
64
        DEVICE_LINK_FILE_STATUS_LAST_HUNK
64
65
};
65
66
 
 
67
static void sha1_of_data(const char *input, uint32_t size, unsigned char *hash_out)
 
68
{
 
69
        gcry_md_hash_buffer(GCRY_MD_SHA1, hash_out, input, size);
 
70
}
 
71
 
 
72
static int compare_hash(const unsigned char *hash1, const unsigned char *hash2, int hash_len)
 
73
{
 
74
        int i;
 
75
        for (i = 0; i < hash_len; i++) {
 
76
                if (hash1[i] != hash2[i]) {
 
77
                        return 0;
 
78
                }
 
79
        }
 
80
        return 1;
 
81
}
 
82
 
 
83
static void compute_datahash(const char *path, const char *destpath, uint8_t greylist, const char *domain, const char *appid, const char *version, unsigned char *hash_out)
 
84
{
 
85
        gcry_md_hd_t hd = NULL;
 
86
        gcry_md_open(&hd, GCRY_MD_SHA1, 0);
 
87
        if (!hd) {
 
88
                printf("ERROR: Could not initialize libgcrypt/SHA1\n");
 
89
                return;
 
90
        }
 
91
        gcry_md_reset(hd);
 
92
 
 
93
        FILE *f = fopen(path, "rb");
 
94
        if (f) {
 
95
                unsigned char buf[16384];
 
96
                size_t len;
 
97
                while ((len = fread(buf, 1, 16384, f)) > 0) {
 
98
                        gcry_md_write(hd, buf, len);
 
99
                }
 
100
                fclose(f);
 
101
                gcry_md_write(hd, destpath, strlen(destpath));
 
102
                gcry_md_write(hd, ";", 1);
 
103
                if (greylist == 1) {
 
104
                        gcry_md_write(hd, "true", 4);
 
105
                } else {
 
106
                        gcry_md_write(hd, "false", 5);
 
107
                }
 
108
                gcry_md_write(hd, ";", 1);
 
109
                if (domain) {
 
110
                        gcry_md_write(hd, domain, strlen(domain));
 
111
                } else {
 
112
                        gcry_md_write(hd, "(null)", 6);
 
113
                }
 
114
                gcry_md_write(hd, ";", 1);
 
115
                if (appid) {
 
116
                        gcry_md_write(hd, appid, strlen(appid));
 
117
                } else {
 
118
                        gcry_md_write(hd, "(null)", 6);
 
119
                }
 
120
                gcry_md_write(hd, ";", 1);
 
121
                if (version) {
 
122
                        gcry_md_write(hd, version, strlen(version));
 
123
                } else {
 
124
                        gcry_md_write(hd, "(null)", 6);
 
125
                }
 
126
                unsigned char *newhash = gcry_md_read(hd, GCRY_MD_SHA1);
 
127
                memcpy(hash_out, newhash, 20);
 
128
        }
 
129
        gcry_md_close(hd);
 
130
}
 
131
 
 
132
static void print_hash(const unsigned char *hash, int len)
 
133
{
 
134
        int i;
 
135
        for (i = 0; i < len; i++) {
 
136
                printf("%02x", hash[i]);
 
137
        }
 
138
}
 
139
 
66
140
static void notify_cb(const char *notification, void *userdata)
67
141
{
68
142
        if (!strcmp(notification, NP_SYNC_CANCEL_REQUEST)) {
149
223
        node = NULL;
150
224
}
151
225
 
152
 
static void buffer_read_from_filename(const char *filename, char **buffer, uint32_t *length)
 
226
static void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length)
153
227
{
154
228
        FILE *f;
155
229
        uint64_t size;
173
247
        fread(*buffer, sizeof(char), size, f);
174
248
        fclose(f);
175
249
 
176
 
        *length = (uint32_t)size;
 
250
        *length = size;
177
251
}
178
252
 
179
 
static void buffer_write_to_filename(const char *filename, const char *buffer, uint32_t length)
 
253
static void buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length)
180
254
{
181
255
        FILE *f;
182
256
 
188
262
static int plist_read_from_filename(plist_t *plist, const char *filename)
189
263
{
190
264
        char *buffer = NULL;
191
 
        uint32_t length;
 
265
        uint64_t length;
192
266
 
193
267
        if (!filename)
194
268
                return 0;
273
347
        g_free(file_path);
274
348
}
275
349
 
 
350
static int mobilebackup_read_status(const char *path)
 
351
{
 
352
        int ret = -1;
 
353
        plist_t status_plist = NULL;
 
354
        gchar *file_path = mobilebackup_build_path(path, "Status", ".plist");
 
355
 
 
356
        plist_read_from_filename(&status_plist, file_path);
 
357
        g_free(file_path);
 
358
        if (!status_plist) {
 
359
                printf("Could not read Status.plist!\n");
 
360
                return ret;
 
361
        }
 
362
        plist_t node = plist_dict_get_item(status_plist, "Backup Success");
 
363
        if (node && (plist_get_node_type(node) == PLIST_BOOLEAN)) {
 
364
                uint8_t bval = 0;
 
365
                plist_get_bool_val(node, &bval);
 
366
                ret = bval;
 
367
        } else {
 
368
                printf("%s: ERROR could not get Backup Success key from Status.plist!\n", __func__);
 
369
        }
 
370
        plist_free(status_plist);
 
371
        return ret;
 
372
}
 
373
 
276
374
static int mobilebackup_info_is_current_device(plist_t info)
277
375
{
278
376
        plist_t value_node = NULL;
338
436
{
339
437
        int ret = 0;
340
438
        gchar *path = mobilebackup_build_path(backup_directory, hash, ".mddata");
341
 
        printf("Removing \"%s\"... ", path);
 
439
        printf("Removing \"%s\" ", path);
342
440
        if (!remove( path ))
343
441
                ret = 1;
344
442
        else
350
448
                return ret;
351
449
 
352
450
        path = mobilebackup_build_path(backup_directory, hash, ".mdinfo");
353
 
        printf("Removing \"%s\"... ", path);
 
451
        printf("and \"%s\"... ", path);
354
452
        if (!remove( path ))
355
453
                ret = 1;
356
454
        else
361
459
        return ret;
362
460
}
363
461
 
 
462
static int mobilebackup_check_file_integrity(const char *backup_directory, const char *hash, plist_t filedata)
 
463
{
 
464
        char *datapath;
 
465
        char *infopath;
 
466
        plist_t mdinfo = NULL;
 
467
        struct stat st;
 
468
        unsigned char file_hash[20];
 
469
 
 
470
        datapath = mobilebackup_build_path(backup_directory, hash, ".mddata");
 
471
        if (stat(datapath, &st) != 0) {
 
472
                printf("\r\n");
 
473
                printf("ERROR: '%s.mddata' is missing!\n", hash);
 
474
                free(datapath);
 
475
                return 0;
 
476
        }
 
477
 
 
478
        infopath = mobilebackup_build_path(backup_directory, hash, ".mdinfo");
 
479
        plist_read_from_filename(&mdinfo, infopath);
 
480
        free(infopath);
 
481
        if (!mdinfo) {
 
482
                printf("\r\n");
 
483
                printf("ERROR: '%s.mdinfo' is missing or corrupted!\n", hash);
 
484
                free(datapath);
 
485
                return 0;
 
486
        }
 
487
 
 
488
        /* sha1 hash verification */
 
489
        plist_t node = plist_dict_get_item(filedata, "DataHash");
 
490
        if (!node || (plist_get_node_type(node) != PLIST_DATA)) {
 
491
                printf("\r\n");
 
492
                printf("ERROR: Could not get DataHash for file entry '%s'\n", hash);
 
493
                plist_free(mdinfo);
 
494
                free(datapath);
 
495
                return 0;
 
496
        }
 
497
 
 
498
        node = plist_dict_get_item(mdinfo, "Metadata");
 
499
        if (!node && (plist_get_node_type(node) != PLIST_DATA)) {
 
500
                printf("\r\n");
 
501
                printf("ERROR: Could not find Metadata in plist '%s.mdinfo'\n", hash);
 
502
                plist_free(mdinfo);
 
503
                free(datapath);
 
504
                return 0;
 
505
        }
 
506
 
 
507
        char *meta_bin = NULL;
 
508
        uint64_t meta_bin_size = 0;
 
509
        plist_get_data_val(node, &meta_bin, &meta_bin_size);
 
510
        plist_t metadata = NULL;
 
511
        if (meta_bin) {
 
512
                plist_from_bin(meta_bin, (uint32_t)meta_bin_size, &metadata);
 
513
        }
 
514
        if (!metadata) {
 
515
                printf("\r\n");
 
516
                printf("ERROR: Could not get Metadata from plist '%s.mdinfo'\n", hash);
 
517
                plist_free(mdinfo);
 
518
                free(datapath);
 
519
                return 0;
 
520
        }
 
521
 
 
522
        char *version = NULL;
 
523
        node = plist_dict_get_item(metadata, "Version");
 
524
        if (node && (plist_get_node_type(node) == PLIST_STRING)) { 
 
525
                plist_get_string_val(node, &version);
 
526
        }
 
527
 
 
528
        char *destpath = NULL;
 
529
        node = plist_dict_get_item(metadata, "Path");
 
530
        if (node && (plist_get_node_type(node) == PLIST_STRING)) { 
 
531
                plist_get_string_val(node, &destpath);
 
532
        }
 
533
 
 
534
        uint8_t greylist = 0;
 
535
        node = plist_dict_get_item(metadata, "Greylist");
 
536
        if (node && (plist_get_node_type(node) == PLIST_BOOLEAN)) {
 
537
                plist_get_bool_val(node, &greylist);
 
538
        }
 
539
 
 
540
        char *domain = NULL;
 
541
        node = plist_dict_get_item(metadata, "Domain");
 
542
        if (node && (plist_get_node_type(node) == PLIST_STRING)) { 
 
543
                plist_get_string_val(node, &domain);
 
544
        }
 
545
 
 
546
        char *fnstr = malloc(strlen(domain) + 1 + strlen(destpath) + 1);
 
547
        strcpy(fnstr, domain);
 
548
        strcat(fnstr, "-");
 
549
        strcat(fnstr, destpath);
 
550
        unsigned char fnhash[20];
 
551
        char fnamehash[41];
 
552
        char *p = fnamehash;
 
553
        sha1_of_data(fnstr, strlen(fnstr), fnhash);
 
554
        free(fnstr);
 
555
        int i;
 
556
        for ( i = 0; i < 20; i++, p += 2 ) {
 
557
                snprintf (p, 3, "%02x", (unsigned char)fnhash[i] );
 
558
        }
 
559
        if (strcmp(fnamehash, hash)) {
 
560
                printf("\r\n"); 
 
561
                printf("WARNING: filename hash does not match for entry '%s'\n", hash);
 
562
        }
 
563
 
 
564
        char *auth_version = NULL;
 
565
        node = plist_dict_get_item(mdinfo, "AuthVersion");
 
566
        if (node && (plist_get_node_type(node) == PLIST_STRING)) {
 
567
                plist_get_string_val(node, &auth_version);
 
568
        }
 
569
 
 
570
        if (strcmp(auth_version, "1.0")) {
 
571
                printf("\r\n");
 
572
                printf("WARNING: Unknown AuthVersion '%s', DataHash cannot be verified!\n", auth_version);
 
573
        }
 
574
 
 
575
        node = plist_dict_get_item(filedata, "DataHash");
 
576
        if (!node || (plist_get_node_type(node) != PLIST_DATA)) {
 
577
                printf("\r\n");
 
578
                printf("WARNING: Could not get DataHash key from file info data for entry '%s'\n", hash);
 
579
        }
 
580
 
 
581
        int res = 1;
 
582
        unsigned char *data_hash = NULL;
 
583
        uint64_t data_hash_len = 0;
 
584
        plist_get_data_val(node, (char**)&data_hash, &data_hash_len);
 
585
        int hash_ok = 0;
 
586
        if (data_hash && (data_hash_len == 20)) {
 
587
                compute_datahash(datapath, destpath, greylist, domain, NULL, version, file_hash);
 
588
                hash_ok = compare_hash(data_hash, file_hash, 20);
 
589
        } else if (data_hash_len == 0) {
 
590
                /* no datahash present */
 
591
                hash_ok = 1;
 
592
        }
 
593
 
 
594
        g_free(domain);
 
595
        g_free(version);
 
596
        g_free(destpath);
 
597
 
 
598
        if (!hash_ok) {
 
599
                printf("\r\n");
 
600
                printf("ERROR: The hash for '%s.mddata' does not match DataHash entry in Manifest\n", hash);
 
601
                printf("datahash: ");
 
602
                print_hash(data_hash, 20);
 
603
                printf("\nfilehash: ");
 
604
                print_hash(file_hash, 20);
 
605
                printf("\n");
 
606
                res = 0;
 
607
        }
 
608
        g_free(data_hash);
 
609
        plist_free(mdinfo);
 
610
        return res;
 
611
}
 
612
 
364
613
static void do_post_notification(const char *notification)
365
614
{
366
615
        uint16_t nport = 0;
448
697
        plist_t manifest_plist = NULL;
449
698
        plist_t info_plist = NULL;
450
699
        char *buffer = NULL;
 
700
        char *file_path = NULL;
451
701
        uint64_t length = 0;
452
702
        uint64_t backup_total_size = 0;
453
 
        enum device_link_file_status_t file_status;
 
703
        enum device_link_file_status_t file_status = DEVICE_LINK_FILE_STATUS_NONE;
454
704
        uint64_t c = 0;
455
705
 
456
706
        /* we need to exit cleanly on running backups and restores or we cause havok */
563
813
                printf("ERROR: Could not start service %s.\n", NP_SERVICE_NAME);
564
814
        }
565
815
 
566
 
        /* start AFC, we need this for the lock file */
567
816
        afc_client_t afc = NULL;
568
 
        port = 0;
569
 
        ret = lockdownd_start_service(client, "com.apple.afc", &port);
570
 
        if ((ret == LOCKDOWN_E_SUCCESS) && port) {
571
 
                afc_client_new(phone, port, &afc);
 
817
        if (cmd == CMD_BACKUP) {
 
818
                /* start AFC, we need this for the lock file */
 
819
                port = 0;
 
820
                ret = lockdownd_start_service(client, "com.apple.afc", &port);
 
821
                if ((ret == LOCKDOWN_E_SUCCESS) && port) {
 
822
                        afc_client_new(phone, port, &afc);
 
823
                }
572
824
        }
573
825
 
574
 
        /* start syslog_relay service and retrieve port */
 
826
        /* start mobilebackup service and retrieve port */
575
827
        port = 0;
576
828
        ret = lockdownd_start_service(client, MOBILEBACKUP_SERVICE_NAME, &port);
577
829
        if ((ret == LOCKDOWN_E_SUCCESS) && port) {
603
855
                                        printf("Aborting backup. Backup is not compatible with the current device.\n");
604
856
                                        cmd = CMD_LEAVE;
605
857
                                }
 
858
                        } else if (info_plist && (cmd == CMD_RESTORE)) {
 
859
                                if (!mobilebackup_info_is_current_device(info_plist)) {
 
860
                                        printf("Aborting restore. Backup data is not compatible with the current device.\n");
 
861
                                        cmd = CMD_LEAVE;
 
862
                                }
606
863
                        }
607
864
                } else {
608
 
                        is_full_backup = 1;
 
865
                        if (cmd == CMD_RESTORE) {
 
866
                                printf("Aborting restore. Info.plist is missing.\n");
 
867
                                cmd = CMD_LEAVE;
 
868
                        } else {
 
869
                                is_full_backup = 1;
 
870
                        }
609
871
                }
610
872
 
611
 
                do_post_notification(NP_SYNC_WILL_START);
612
873
                uint64_t lockfile = 0;
613
 
                afc_file_open(afc, "/com.apple.itunes.lock_sync", AFC_FOPEN_RW, &lockfile);
 
874
                if (cmd == CMD_BACKUP) {
 
875
                        do_post_notification(NP_SYNC_WILL_START);
 
876
                        afc_file_open(afc, "/com.apple.itunes.lock_sync", AFC_FOPEN_RW, &lockfile);
 
877
                }
614
878
                if (lockfile) {
615
879
                        afc_error_t aerr;
616
880
                        do_post_notification(NP_SYNC_LOCK_REQUEST);
637
901
                        }
638
902
                }
639
903
 
 
904
                mobilebackup_error_t err;
 
905
 
 
906
                /* Manifest.plist (backup manifest (backup state)) */
 
907
                char *manifest_path = mobilebackup_build_path(backup_directory, "Manifest", ".plist");
 
908
 
640
909
                switch(cmd) {
641
910
                        case CMD_BACKUP:
642
911
                        printf("Starting backup...\n");
643
912
                        /* TODO: check domain com.apple.mobile.backup key RequiresEncrypt and WillEncrypt with lockdown */
644
913
                        /* TODO: verify battery on AC enough battery remaining */       
645
914
 
646
 
                        /* Manifest.plist (backup manifest (backup state)) */
647
 
                        char *manifest_path = mobilebackup_build_path(backup_directory, "Manifest", ".plist");
648
 
 
649
915
                        /* read the last Manifest.plist */
650
916
                        if (!is_full_backup) {
651
917
                                printf("Reading existing Manifest.\n");
686
952
                        /* request backup from device with manifest from last backup */
687
953
                        printf("Requesting backup from device...\n");
688
954
 
689
 
                        mobilebackup_error_t err = mobilebackup_request_backup(mobilebackup, manifest_plist, "/", "1.6");
 
955
                        err = mobilebackup_request_backup(mobilebackup, manifest_plist, "/", "1.6");
690
956
                        if (err == MOBILEBACKUP_E_SUCCESS) {
691
957
                                if (is_full_backup)
692
958
                                        printf("Full backup mode.\n");
714
980
                        int file_index = 0;
715
981
                        int hunk_index = 0;
716
982
                        uint64_t backup_real_size = 0;
717
 
                        char *file_path = NULL;
718
983
                        char *file_ext = NULL;
719
984
                        char *filename_mdinfo = NULL;
720
985
                        char *filename_mddata = NULL;
933
1198
                        } else {
934
1199
                                printf("Backup Failed.\n");
935
1200
                        }
936
 
 
937
 
                        if (manifest_path)
938
 
                                g_free(manifest_path);
939
 
 
940
1201
                        break;
941
1202
                        case CMD_RESTORE:
942
 
                        printf("Restoring backup is NOT IMPLEMENTED.\n");
943
 
                        /* verify battery on AC enough battery remaining */
 
1203
                        /* close down the lockdown connection as it is no longer needed */
 
1204
                        if (client) {
 
1205
                                lockdownd_client_free(client);
 
1206
                                client = NULL;
 
1207
                        }
 
1208
 
 
1209
                        /* TODO: verify battery on AC enough battery remaining */
 
1210
 
 
1211
                        /* verify if Status.plist says we read from an successful backup */
 
1212
                        if (mobilebackup_read_status(backup_directory) <= 0) {
 
1213
                                printf("ERROR: Cannot ensure we restore from a successful backup. Aborting.\n");
 
1214
                                break;
 
1215
                        }
 
1216
                        /* now make sure backup integrity is ok! verify all files */
 
1217
                        printf("Reading existing Manifest.\n");
 
1218
                        plist_read_from_filename(&manifest_plist, manifest_path);
 
1219
                        if (!manifest_plist) {
 
1220
                                printf("Could not read Manifest.plist. Aborting.\n");
 
1221
                                break;
 
1222
                        }
 
1223
 
 
1224
                        printf("Verifying backup integrity, please wait.\n");
 
1225
                        char *bin = NULL;
 
1226
                        uint64_t binsize = 0;
 
1227
                        node = plist_dict_get_item(manifest_plist, "Data");
 
1228
                        if (!node || (plist_get_node_type(node) != PLIST_DATA)) {
 
1229
                                printf("Could not read Data key from Manifest.plist!\n");
 
1230
                                break;
 
1231
                        }
 
1232
                        plist_get_data_val(node, &bin, &binsize);
 
1233
                        plist_t backup_data = NULL;
 
1234
                        if (bin) {
 
1235
                                char *auth_ver = NULL;
 
1236
                                unsigned char *auth_sig = NULL;
 
1237
                                uint64_t auth_sig_len = 0;
 
1238
                                /* verify AuthSignature */
 
1239
                                node = plist_dict_get_item(manifest_plist, "AuthVersion");
 
1240
                                plist_get_string_val(node, &auth_ver);
 
1241
                                if (auth_ver && (strcmp(auth_ver, "2.0") == 0)) {
 
1242
                                        node = plist_dict_get_item(manifest_plist, "AuthSignature");
 
1243
                                        if (node && (plist_get_node_type(node) == PLIST_DATA)) {
 
1244
                                                plist_get_data_val(node, (char**)&auth_sig, &auth_sig_len);
 
1245
                                        }
 
1246
                                        if (auth_sig && (auth_sig_len == 20)) {
 
1247
                                                /* calculate the sha1, then compare */
 
1248
                                                unsigned char data_sha1[20];
 
1249
                                                sha1_of_data(bin, binsize, data_sha1);
 
1250
                                                if (compare_hash(auth_sig, data_sha1, 20)) {
 
1251
                                                        printf("AuthSignature is valid\n");
 
1252
                                                } else {
 
1253
                                                        printf("ERROR: AuthSignature is NOT VALID\n");
 
1254
                                                }
 
1255
                                        } else {
 
1256
                                                printf("Could not get AuthSignature from manifest!\n");
 
1257
                                        }
 
1258
                                        g_free(auth_sig);
 
1259
                                } else if (auth_ver) {
 
1260
                                        printf("Unknown AuthVersion '%s', cannot verify AuthSignature\n", auth_ver); 
 
1261
                                }
 
1262
                                plist_from_bin(bin, (uint32_t)binsize, &backup_data);
 
1263
                                g_free(bin);
 
1264
                        }
 
1265
                        if (!backup_data) {
 
1266
                                printf("Could not read plist from Manifest.plist Data key!\n");
 
1267
                                break;
 
1268
                        }
 
1269
                        plist_t files = plist_dict_get_item(backup_data, "Files");
 
1270
                        if (files && (plist_get_node_type(files) == PLIST_DICT)) {
 
1271
                                plist_dict_iter iter = NULL;
 
1272
                                plist_dict_new_iter(files, &iter);
 
1273
                                if (iter) {
 
1274
                                        /* loop over Files entries in Manifest data plist */
 
1275
                                        char *hash = NULL;
 
1276
                                        int file_ok = 0;
 
1277
                                        int total_files = plist_dict_get_size(files);
 
1278
                                        int cur_file = 1;
 
1279
                                        node = NULL;
 
1280
                                        plist_dict_next_item(files, iter, &hash, &node);
 
1281
                                        while (node) {
 
1282
                                                printf("Verifying file %d/%d (%d%%) \r", cur_file, total_files, (cur_file*100/total_files));
 
1283
                                                cur_file++;
 
1284
                                                /* make sure both .mddata/.mdinfo files are available for each entry */
 
1285
                                                file_ok = mobilebackup_check_file_integrity(backup_directory, hash, node);
 
1286
                                                node = NULL;
 
1287
                                                free(hash);
 
1288
                                                hash = NULL;
 
1289
                                                if (!file_ok) {
 
1290
                                                        break;
 
1291
                                                }
 
1292
                                                plist_dict_next_item(files, iter, &hash, &node);
 
1293
                                        }
 
1294
                                        printf("\n");
 
1295
                                        free(iter);
 
1296
                                        if (!file_ok) {
 
1297
                                                plist_free(backup_data);
 
1298
                                                break;
 
1299
                                        }
 
1300
                                        printf("All backup files appear to be valid\n");
 
1301
                                }
 
1302
                        }
 
1303
 
 
1304
                        printf("Requesting restore from device...\n");
 
1305
 
944
1306
                        /* request restore from device with manifest (BackupMessageRestoreMigrate) */
945
 
                        /* read mddata/mdinfo files and send to devices using DLSendFile */
946
 
                        /* signal restore finished message to device */
947
 
                        /* close down lockdown connection as it is no longer needed */
948
 
                        lockdownd_client_free(client);
949
 
                        client = NULL;
 
1307
                        int restore_flags = MB_RESTORE_NOTIFY_SPRINGBOARD | MB_RESTORE_PRESERVE_SETTINGS | MB_RESTORE_PRESERVE_CAMERA_ROLL;
 
1308
                        err = mobilebackup_request_restore(mobilebackup, manifest_plist, restore_flags, "1.6");
 
1309
                        if (err != MOBILEBACKUP_E_SUCCESS) {
 
1310
                                if (err == MOBILEBACKUP_E_BAD_VERSION) {
 
1311
                                        printf("ERROR: Could not start restore process: backup protocol version mismatch!\n");
 
1312
                                } else if (err == MOBILEBACKUP_E_REPLY_NOT_OK) {
 
1313
                                        printf("ERROR: Could not start restore process: device refused to start the restore process.\n");
 
1314
                                } else {
 
1315
                                        printf("ERROR: Could not start restore process: unspecified error occured (%d)\n", err);
 
1316
                                }
 
1317
                                plist_free(backup_data);
 
1318
                                break;
 
1319
                        }
 
1320
 
 
1321
                        printf("Entered restore mode.\n");
 
1322
 
 
1323
                        int restore_ok = 0;
 
1324
 
 
1325
                        if (files && (plist_get_node_type(files) == PLIST_DICT)) {
 
1326
                                plist_dict_iter iter = NULL;
 
1327
                                plist_dict_new_iter(files, &iter);
 
1328
                                if (iter) {
 
1329
                                        /* loop over Files entries in Manifest data plist */
 
1330
                                        char *hash = NULL;
 
1331
                                        plist_t file_info = NULL;
 
1332
                                        char *file_info_path = NULL;
 
1333
                                        int total_files = plist_dict_get_size(files);
 
1334
                                        int cur_file = 0;
 
1335
                                        uint64_t file_offset = 0;
 
1336
                                        uint8_t is_encrypted = 0;
 
1337
                                        plist_t tmp_node = NULL;
 
1338
                                        plist_t file_path_node = NULL;
 
1339
                                        plist_t send_file_node = NULL;
 
1340
                                        node = NULL;
 
1341
                                        plist_dict_next_item(files, iter, &hash, &node);
 
1342
                                        while (node) {
 
1343
                                                /* TODO: read mddata/mdinfo files and send to device using DLSendFile */
 
1344
                                                file_info_path = mobilebackup_build_path(backup_directory, hash, ".mdinfo");
 
1345
                                                plist_read_from_filename(&file_info, file_info_path);
 
1346
 
 
1347
                                                /* get encryption state */
 
1348
                                                tmp_node = plist_dict_get_item(file_info, "IsEncrypted");
 
1349
                                                plist_get_bool_val(tmp_node, &is_encrypted);
 
1350
                                                tmp_node = NULL;
 
1351
 
 
1352
                                                /* get real file path from metadata */
 
1353
                                                tmp_node = plist_dict_get_item(file_info, "Metadata");
 
1354
                                                plist_get_data_val(tmp_node, &buffer, &length);
 
1355
                                                tmp_node = NULL;
 
1356
                                                plist_from_bin(buffer, length, &tmp_node);
 
1357
                                                file_path_node = plist_dict_get_item(tmp_node, "Path");
 
1358
                                                plist_get_string_val(file_path_node, &file_path);
 
1359
 
 
1360
                                                printf("Restoring file %s %d/%d (%d%%)... ", file_path, cur_file, total_files, (cur_file*100/total_files));
 
1361
 
 
1362
                                                /* add additional device link file information keys */
 
1363
                                                plist_dict_insert_item(file_info, "DLFileAttributesKey", plist_copy(node));
 
1364
                                                plist_dict_insert_item(file_info, "DLFileSource", plist_new_string(file_info_path));
 
1365
                                                plist_dict_insert_item(file_info, "DLFileDest", plist_new_string("/tmp/RestoreFile.plist"));
 
1366
                                                plist_dict_insert_item(file_info, "DLFileIsEncrypted", plist_new_bool(is_encrypted));
 
1367
                                                plist_dict_insert_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset));
 
1368
                                                plist_dict_insert_item(file_info, "DLFileStatusKey", plist_new_uint(file_status));
 
1369
 
 
1370
                                                /* read data from file */
 
1371
                                                free(file_info_path);
 
1372
                                                file_info_path = mobilebackup_build_path(backup_directory, hash, ".mddata");
 
1373
                                                buffer_read_from_filename(file_info_path, &buffer, &length);
 
1374
                                                free(file_info_path);
 
1375
 
 
1376
                                                /* send DLSendFile messages */
 
1377
                                                file_offset = 0;
 
1378
                                                do {
 
1379
                                                        if ((length-file_offset) <= 8192)
 
1380
                                                                file_status = DEVICE_LINK_FILE_STATUS_LAST_HUNK;
 
1381
                                                        else
 
1382
                                                                file_status = DEVICE_LINK_FILE_STATUS_HUNK;
 
1383
                                                        
 
1384
                                                        plist_dict_remove_item(file_info, "DLFileOffsetKey");
 
1385
                                                        plist_dict_insert_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset));
 
1386
 
 
1387
                                                        plist_dict_remove_item(file_info, "DLFileStatusKey");
 
1388
                                                        plist_dict_insert_item(file_info, "DLFileStatusKey", plist_new_uint(file_status));
 
1389
 
 
1390
                                                        send_file_node = plist_new_array();
 
1391
 
 
1392
                                                        plist_array_append_item(send_file_node, plist_new_string("DLSendFile"));
 
1393
 
 
1394
                                                        if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK)
 
1395
                                                                plist_array_append_item(send_file_node, plist_new_data(buffer+file_offset, length-file_offset));
 
1396
                                                        else
 
1397
                                                                plist_array_append_item(send_file_node, plist_new_data(buffer+file_offset, 8192));
 
1398
 
 
1399
                                                        plist_array_append_item(send_file_node, plist_copy(file_info));
 
1400
 
 
1401
                                                        err = mobilebackup_send(mobilebackup, send_file_node);
 
1402
                                                        if (err != MOBILEBACKUP_E_SUCCESS) {
 
1403
                                                                printf("ERROR: Unable to send file hunk due to error %d. Aborting...\n", err);
 
1404
                                                                file_status = DEVICE_LINK_FILE_STATUS_NONE;
 
1405
                                                        }
 
1406
 
 
1407
                                                        if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) {
 
1408
                                                                /* TODO: if all hunks of a file are sent, device must send ack */
 
1409
                                                                err = mobilebackup_receive_restore_file_received(mobilebackup, NULL);
 
1410
                                                                if (err != MOBILEBACKUP_E_SUCCESS) {
 
1411
                                                                        printf("ERROR: Did not receive an ack for the sent file due to error %d. Aborting...\n", err);
 
1412
                                                                        file_status = DEVICE_LINK_FILE_STATUS_NONE;
 
1413
                                                                }
 
1414
                                                        }
 
1415
 
 
1416
                                                        file_offset += 8192;
 
1417
 
 
1418
                                                        if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK)
 
1419
                                                                printf("DONE\n");
 
1420
 
 
1421
                                                        plist_free(send_file_node);
 
1422
                                                        
 
1423
                                                        if (file_status == DEVICE_LINK_FILE_STATUS_NONE)
 
1424
                                                                break;
 
1425
 
 
1426
                                                } while((file_offset < length));
 
1427
 
 
1428
                                                free(hash);
 
1429
                                                node = NULL;
 
1430
                                                hash = NULL;
 
1431
 
 
1432
                                                restore_ok = 1;
 
1433
                                                if (file_status == DEVICE_LINK_FILE_STATUS_NONE) {
 
1434
                                                        restore_ok = 0;
 
1435
                                                        break;
 
1436
                                                }
 
1437
 
 
1438
                                                cur_file++;
 
1439
                                                plist_dict_next_item(files, iter, &hash, &node);
 
1440
                                        }
 
1441
                                        free(iter);
 
1442
 
 
1443
                                        printf("Restored %d files on device.\n", cur_file);
 
1444
                                }
 
1445
                        }
 
1446
                        /* TODO: observe notification_proxy id com.apple.mobile.application_installed */
 
1447
                        /* TODO: loop over Applications entries in Manifest data plist */
 
1448
                        plist_t applications = plist_dict_get_item(backup_data, "Applications");
 
1449
                        if (applications && (plist_get_node_type(applications) == PLIST_DICT) && restore_ok) {
 
1450
                                plist_dict_iter iter = NULL;
 
1451
                                plist_dict_new_iter(applications, &iter);
 
1452
                                if (iter) {
 
1453
                                        /* loop over Application entries in Manifest data plist */
 
1454
                                        char *hash = NULL;
 
1455
                                        int total_files = plist_dict_get_size(applications);
 
1456
                                        int cur_file = 1;
 
1457
                                        plist_t tmp_node = NULL;
 
1458
                                        plist_t dict = NULL;
 
1459
                                        plist_t array = NULL;
 
1460
                                        node = NULL;
 
1461
                                        plist_dict_next_item(applications, iter, &hash, &node);
 
1462
                                        while (node) {
 
1463
                                                printf("Restoring Application %s %d/%d (%d%%)...", hash, cur_file, total_files, (cur_file*100/total_files));
 
1464
                                                /* FIXME: receive com.apple.mobile.application_installed notification */
 
1465
                                                /* send AppInfo entry */
 
1466
                                                tmp_node = plist_dict_get_item(node, "AppInfo");
 
1467
 
 
1468
                                                dict = plist_new_dict();
 
1469
                                                plist_dict_insert_item(dict, "AppInfo", plist_copy(tmp_node));
 
1470
                                                plist_dict_insert_item(dict, "BackupMessageTypeKey", plist_new_string("BackupMessageRestoreApplicationSent"));
 
1471
 
 
1472
                                                array = plist_new_array();
 
1473
                                                plist_array_append_item(array, plist_new_string("DLMessageProcessMessage"));
 
1474
                                                plist_array_append_item(array, dict);
 
1475
 
 
1476
                                                err = mobilebackup_send(mobilebackup, array);
 
1477
                                                if (err != MOBILEBACKUP_E_SUCCESS) {
 
1478
                                                        printf("ERROR: Unable to restore application %s due to error %d. Aborting...\n", hash, err);
 
1479
                                                        restore_ok = 0;
 
1480
                                                }
 
1481
 
 
1482
                                                plist_free(array);
 
1483
                                                array = NULL;
 
1484
                                                dict = NULL;
 
1485
 
 
1486
                                                /* receive BackupMessageRestoreApplicationReceived from device */
 
1487
                                                if (restore_ok) {
 
1488
                                                        err = mobilebackup_receive_restore_application_received(mobilebackup, NULL);
 
1489
                                                        if (err != MOBILEBACKUP_E_SUCCESS) {
 
1490
                                                                printf("ERROR: Failed to receive an ack from the device for this application due to error %d. Aborting...\n", err);
 
1491
                                                                restore_ok = 0;
 
1492
                                                        }
 
1493
                                                }
 
1494
 
 
1495
                                                tmp_node = NULL;
 
1496
                                                node = NULL;
 
1497
                                                free(hash);
 
1498
                                                hash = NULL;
 
1499
 
 
1500
                                                if (restore_ok) {
 
1501
                                                        printf("DONE\n");
 
1502
                                                        cur_file++;
 
1503
                                                        plist_dict_next_item(applications, iter, &hash, &node);
 
1504
                                                } else
 
1505
                                                        break;
 
1506
                                        }
 
1507
                                        free(iter);
 
1508
 
 
1509
                                        if (restore_ok)
 
1510
                                                printf("All applications restored.\n");
 
1511
                                        else
 
1512
                                                printf("Failed to restore applications.\n");
 
1513
                                }
 
1514
                        }
 
1515
 
 
1516
                        plist_free(backup_data);
 
1517
 
 
1518
                        /* signal restore finished message to device; BackupMessageRestoreComplete */
 
1519
                        if (restore_ok) {
 
1520
                                err = mobilebackup_send_restore_complete(mobilebackup);
 
1521
                                if (err != MOBILEBACKUP_E_SUCCESS) {
 
1522
                                        printf("ERROR: Could not send BackupMessageRestoreComplete, error code %d\n", err);
 
1523
                                        }
 
1524
                        }
 
1525
 
 
1526
                        if (restore_ok) {
 
1527
                                printf("Restore Successful.\n");
 
1528
                        } else {
 
1529
                                printf("Restore Failed.\n");
 
1530
                        }
950
1531
                        break;
951
1532
                        case CMD_LEAVE:
952
1533
                        default:
958
1539
                        lockfile = 0;
959
1540
                        do_post_notification(NP_SYNC_DID_FINISH);
960
1541
                }
 
1542
                if (manifest_path)
 
1543
                        g_free(manifest_path);
961
1544
        } else {
962
1545
                printf("ERROR: Could not start service %s.\n", MOBILEBACKUP_SERVICE_NAME);
963
1546
                lockdownd_client_free(client);