summaryrefslogtreecommitdiffstats
path: root/tools/idevicebackup.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/idevicebackup.c')
-rw-r--r--tools/idevicebackup.c664
1 files changed, 333 insertions, 331 deletions
diff --git a/tools/idevicebackup.c b/tools/idevicebackup.c
index 867eaad..c0537b8 100644
--- a/tools/idevicebackup.c
+++ b/tools/idevicebackup.c
@@ -9,31 +9,41 @@
9 * modify it under the terms of the GNU Lesser General Public 9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either 10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version. 11 * version 2.1 of the License, or (at your option) any later version.
12 * 12 *
13 * This library is distributed in the hope that it will be useful, 13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details. 16 * Lesser General Public License for more details.
17 * 17 *
18 * You should have received a copy of the GNU Lesser General Public 18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software 19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */ 21 */
22 22
23#ifdef HAVE_CONFIG_H
24#include <config.h>
25#endif
26
27#define TOOL_NAME "idevicebackup"
28
23#include <stdio.h> 29#include <stdio.h>
24#include <string.h> 30#include <string.h>
25#include <errno.h> 31#include <errno.h>
26#include <stdlib.h> 32#include <stdlib.h>
27#include <signal.h> 33#include <signal.h>
28#include <glib.h> 34#include <getopt.h>
29#include <gcrypt.h>
30#include <unistd.h> 35#include <unistd.h>
36#include <ctype.h>
37#include <time.h>
31 38
32#include <libimobiledevice/libimobiledevice.h> 39#include <libimobiledevice/libimobiledevice.h>
33#include <libimobiledevice/lockdown.h> 40#include <libimobiledevice/lockdown.h>
34#include <libimobiledevice/mobilebackup.h> 41#include <libimobiledevice/mobilebackup.h>
35#include <libimobiledevice/notification_proxy.h> 42#include <libimobiledevice/notification_proxy.h>
36#include <libimobiledevice/afc.h> 43#include <libimobiledevice/afc.h>
44#include <libimobiledevice-glue/sha.h>
45#include <libimobiledevice-glue/utils.h>
46#include <plist/plist.h>
37 47
38#define MOBILEBACKUP_SERVICE_NAME "com.apple.mobilebackup" 48#define MOBILEBACKUP_SERVICE_NAME "com.apple.mobilebackup"
39#define NP_SERVICE_NAME "com.apple.mobile.notification_proxy" 49#define NP_SERVICE_NAME "com.apple.mobile.notification_proxy"
@@ -41,9 +51,14 @@
41#define LOCK_ATTEMPTS 50 51#define LOCK_ATTEMPTS 50
42#define LOCK_WAIT 200000 52#define LOCK_WAIT 200000
43 53
54#ifdef WIN32
55#include <windows.h>
56#define sleep(x) Sleep(x*1000)
57#endif
58
44static mobilebackup_client_t mobilebackup = NULL; 59static mobilebackup_client_t mobilebackup = NULL;
45static lockdownd_client_t client = NULL; 60static lockdownd_client_t client = NULL;
46static idevice_t phone = NULL; 61static idevice_t device = NULL;
47 62
48static int quit_flag = 0; 63static int quit_flag = 0;
49 64
@@ -53,22 +68,12 @@ enum cmd_mode {
53 CMD_LEAVE 68 CMD_LEAVE
54}; 69};
55 70
56enum plist_format_t {
57 PLIST_FORMAT_XML,
58 PLIST_FORMAT_BINARY
59};
60
61enum device_link_file_status_t { 71enum device_link_file_status_t {
62 DEVICE_LINK_FILE_STATUS_NONE = 0, 72 DEVICE_LINK_FILE_STATUS_NONE = 0,
63 DEVICE_LINK_FILE_STATUS_HUNK, 73 DEVICE_LINK_FILE_STATUS_HUNK,
64 DEVICE_LINK_FILE_STATUS_LAST_HUNK 74 DEVICE_LINK_FILE_STATUS_LAST_HUNK
65}; 75};
66 76
67static 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
72static int compare_hash(const unsigned char *hash1, const unsigned char *hash2, int hash_len) 77static int compare_hash(const unsigned char *hash1, const unsigned char *hash2, int hash_len)
73{ 78{
74 int i; 79 int i;
@@ -82,51 +87,47 @@ static int compare_hash(const unsigned char *hash1, const unsigned char *hash2,
82 87
83static 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) 88static 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{ 89{
85 gcry_md_hd_t hd = NULL; 90 sha1_context sha1;
86 gcry_md_open(&hd, GCRY_MD_SHA1, 0); 91 sha1_init(&sha1);
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"); 92 FILE *f = fopen(path, "rb");
94 if (f) { 93 if (f) {
95 unsigned char buf[16384]; 94 unsigned char buf[16384];
96 size_t len; 95 size_t len;
97 while ((len = fread(buf, 1, 16384, f)) > 0) { 96 while ((len = fread(buf, 1, 16384, f)) > 0) {
98 gcry_md_write(hd, buf, len); 97 sha1_update(&sha1, buf, len);
99 } 98 }
100 fclose(f); 99 fclose(f);
101 gcry_md_write(hd, destpath, strlen(destpath)); 100 sha1_update(&sha1, destpath, strlen(destpath));
102 gcry_md_write(hd, ";", 1); 101 sha1_update(&sha1, ";", 1);
102
103 if (greylist == 1) { 103 if (greylist == 1) {
104 gcry_md_write(hd, "true", 4); 104 sha1_update(&sha1, "true", 4);
105 } else { 105 } else {
106 gcry_md_write(hd, "false", 5); 106 sha1_update(&sha1, "false", 5);
107 } 107 }
108 gcry_md_write(hd, ";", 1); 108 sha1_update(&sha1, ";", 1);
109
109 if (domain) { 110 if (domain) {
110 gcry_md_write(hd, domain, strlen(domain)); 111 sha1_update(&sha1, domain, strlen(domain));
111 } else { 112 } else {
112 gcry_md_write(hd, "(null)", 6); 113 sha1_update(&sha1, "(null)", 6);
113 } 114 }
114 gcry_md_write(hd, ";", 1); 115 sha1_update(&sha1, ";", 1);
116
115 if (appid) { 117 if (appid) {
116 gcry_md_write(hd, appid, strlen(appid)); 118 sha1_update(&sha1, appid, strlen(appid));
117 } else { 119 } else {
118 gcry_md_write(hd, "(null)", 6); 120 sha1_update(&sha1, "(null)", 6);
119 } 121 }
120 gcry_md_write(hd, ";", 1); 122 sha1_update(&sha1, ";", 1);
123
121 if (version) { 124 if (version) {
122 gcry_md_write(hd, version, strlen(version)); 125 sha1_update(&sha1, version, strlen(version));
123 } else { 126 } else {
124 gcry_md_write(hd, "(null)", 6); 127 sha1_update(&sha1, "(null)", 6);
125 } 128 }
126 unsigned char *newhash = gcry_md_read(hd, GCRY_MD_SHA1); 129 sha1_final(&sha1, hash_out);
127 memcpy(hash_out, newhash, 20);
128 } 130 }
129 gcry_md_close(hd);
130} 131}
131 132
132static void print_hash(const unsigned char *hash, int len) 133static void print_hash(const unsigned char *hash, int len)
@@ -147,14 +148,12 @@ static void notify_cb(const char *notification, void *userdata)
147 } 148 }
148} 149}
149 150
150static plist_t mobilebackup_factory_info_plist_new() 151static plist_t mobilebackup_factory_info_plist_new(const char* udid)
151{ 152{
152 /* gather data from lockdown */ 153 /* gather data from lockdown */
153 GTimeVal tv = {0, 0};
154 plist_t value_node = NULL; 154 plist_t value_node = NULL;
155 plist_t root_node = NULL; 155 plist_t root_node = NULL;
156 char *uuid = NULL; 156 char *udid_uppercase = NULL;
157 char *uuid_uppercase = NULL;
158 157
159 plist_t ret = plist_new_dict(); 158 plist_t ret = plist_new_dict();
160 159
@@ -163,45 +162,42 @@ static plist_t mobilebackup_factory_info_plist_new()
163 162
164 /* set fields we understand */ 163 /* set fields we understand */
165 value_node = plist_dict_get_item(root_node, "BuildVersion"); 164 value_node = plist_dict_get_item(root_node, "BuildVersion");
166 plist_dict_insert_item(ret, "Build Version", plist_copy(value_node)); 165 plist_dict_set_item(ret, "Build Version", plist_copy(value_node));
167 166
168 value_node = plist_dict_get_item(root_node, "DeviceName"); 167 value_node = plist_dict_get_item(root_node, "DeviceName");
169 plist_dict_insert_item(ret, "Device Name", plist_copy(value_node)); 168 plist_dict_set_item(ret, "Device Name", plist_copy(value_node));
170 plist_dict_insert_item(ret, "Display Name", plist_copy(value_node)); 169 plist_dict_set_item(ret, "Display Name", plist_copy(value_node));
171 170
172 /* FIXME: How is the GUID generated? */ 171 /* FIXME: How is the GUID generated? */
173 plist_dict_insert_item(ret, "GUID", plist_new_string("---")); 172 plist_dict_set_item(ret, "GUID", plist_new_string("---"));
174 173
175 value_node = plist_dict_get_item(root_node, "InternationalMobileEquipmentIdentity"); 174 value_node = plist_dict_get_item(root_node, "InternationalMobileEquipmentIdentity");
176 if (value_node) 175 if (value_node)
177 plist_dict_insert_item(ret, "IMEI", plist_copy(value_node)); 176 plist_dict_set_item(ret, "IMEI", plist_copy(value_node));
178 177
179 g_get_current_time(&tv); 178 plist_dict_set_item(ret, "Last Backup Date", plist_new_date(time(NULL) - MAC_EPOCH, 0));
180 plist_dict_insert_item(ret, "Last Backup Date", plist_new_date(tv.tv_sec, tv.tv_usec));
181 179
182 value_node = plist_dict_get_item(root_node, "ProductType"); 180 value_node = plist_dict_get_item(root_node, "ProductType");
183 plist_dict_insert_item(ret, "Product Type", plist_copy(value_node)); 181 plist_dict_set_item(ret, "Product Type", plist_copy(value_node));
184 182
185 value_node = plist_dict_get_item(root_node, "ProductVersion"); 183 value_node = plist_dict_get_item(root_node, "ProductVersion");
186 plist_dict_insert_item(ret, "Product Version", plist_copy(value_node)); 184 plist_dict_set_item(ret, "Product Version", plist_copy(value_node));
187 185
188 value_node = plist_dict_get_item(root_node, "SerialNumber"); 186 value_node = plist_dict_get_item(root_node, "SerialNumber");
189 plist_dict_insert_item(ret, "Serial Number", plist_copy(value_node)); 187 plist_dict_set_item(ret, "Serial Number", plist_copy(value_node));
190 188
191 value_node = plist_dict_get_item(root_node, "UniqueDeviceID"); 189 value_node = plist_dict_get_item(root_node, "UniqueDeviceID");
192 idevice_get_uuid(phone, &uuid); 190 plist_dict_set_item(ret, "Target Identifier", plist_new_string(udid));
193 plist_dict_insert_item(ret, "Target Identifier", plist_new_string(uuid));
194 191
195 /* uppercase */ 192 /* uppercase */
196 uuid_uppercase = g_ascii_strup(uuid, -1); 193 udid_uppercase = string_toupper((char*)udid);
197 plist_dict_insert_item(ret, "Unique Identifier", plist_new_string(uuid_uppercase)); 194 plist_dict_set_item(ret, "Unique Identifier", plist_new_string(udid_uppercase));
198 free(uuid_uppercase); 195 free(udid_uppercase);
199 free(uuid);
200 196
201 /* FIXME: Embed files as <data> nodes */ 197 /* FIXME: Embed files as <data> nodes */
202 plist_t files = plist_new_dict(); 198 plist_t files = plist_new_dict();
203 plist_dict_insert_item(ret, "iTunes Files", files); 199 plist_dict_set_item(ret, "iTunes Files", files);
204 plist_dict_insert_item(ret, "iTunes Version", plist_new_string("9.0.2")); 200 plist_dict_set_item(ret, "iTunes Version", plist_new_string("9.0.2"));
205 201
206 plist_free(root_node); 202 plist_free(root_node);
207 203
@@ -210,102 +206,17 @@ static plist_t mobilebackup_factory_info_plist_new()
210 206
211static void mobilebackup_info_update_last_backup_date(plist_t info_plist) 207static void mobilebackup_info_update_last_backup_date(plist_t info_plist)
212{ 208{
213 GTimeVal tv = {0, 0};
214 plist_t node = NULL; 209 plist_t node = NULL;
215 210
216 if (!info_plist) 211 if (!info_plist)
217 return; 212 return;
218 213
219 g_get_current_time(&tv);
220 node = plist_dict_get_item(info_plist, "Last Backup Date"); 214 node = plist_dict_get_item(info_plist, "Last Backup Date");
221 plist_set_date_val(node, tv.tv_sec, tv.tv_usec); 215 plist_set_date_val(node, time(NULL) - MAC_EPOCH, 0);
222 216
223 node = NULL; 217 node = NULL;
224} 218}
225 219
226static void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length)
227{
228 FILE *f;
229 uint64_t size;
230
231 *length = 0;
232
233 f = fopen(filename, "rb");
234 if (!f) {
235 return;
236 }
237
238 fseek(f, 0, SEEK_END);
239 size = ftell(f);
240 rewind(f);
241
242 if (size == 0) {
243 return;
244 }
245
246 *buffer = (char*)malloc(sizeof(char)*size);
247 fread(*buffer, sizeof(char), size, f);
248 fclose(f);
249
250 *length = size;
251}
252
253static void buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length)
254{
255 FILE *f;
256
257 f = fopen(filename, "ab");
258 fwrite(buffer, sizeof(char), length, f);
259 fclose(f);
260}
261
262static int plist_read_from_filename(plist_t *plist, const char *filename)
263{
264 char *buffer = NULL;
265 uint64_t length;
266
267 if (!filename)
268 return 0;
269
270 buffer_read_from_filename(filename, &buffer, &length);
271
272 if (!buffer) {
273 return 0;
274 }
275
276 if ((length > 8) && (memcmp(buffer, "bplist00", 8) == 0)) {
277 plist_from_bin(buffer, length, plist);
278 } else {
279 plist_from_xml(buffer, length, plist);
280 }
281
282 free(buffer);
283
284 return 1;
285}
286
287static int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format)
288{
289 char *buffer = NULL;
290 uint32_t length;
291
292 if (!plist || !filename)
293 return 0;
294
295 if (format == PLIST_FORMAT_XML)
296 plist_to_xml(plist, &buffer, &length);
297 else if (format == PLIST_FORMAT_BINARY)
298 plist_to_bin(plist, &buffer, &length);
299 else
300 return 0;
301
302 buffer_write_to_filename(filename, buffer, length);
303
304 free(buffer);
305
306 return 1;
307}
308
309static int plist_strcmp(plist_t node, const char *str) 220static int plist_strcmp(plist_t node, const char *str)
310{ 221{
311 char *buffer = NULL; 222 char *buffer = NULL;
@@ -321,11 +232,14 @@ static int plist_strcmp(plist_t node, const char *str)
321 return ret; 232 return ret;
322} 233}
323 234
324static gchar *mobilebackup_build_path(const char *backup_directory, const char *name, const char *extension) 235static char *mobilebackup_build_path(const char *backup_directory, const char *name, const char *extension)
325{ 236{
326 gchar *filename = g_strconcat(name, extension, NULL); 237 char* filename = (char*)malloc(strlen(name)+(extension == NULL ? 0: strlen(extension))+1);
327 gchar *path = g_build_path(G_DIR_SEPARATOR_S, backup_directory, filename, NULL); 238 strcpy(filename, name);
328 g_free(filename); 239 if (extension != NULL)
240 strcat(filename, extension);
241 char *path = string_build_path(backup_directory, filename, NULL);
242 free(filename);
329 return path; 243 return path;
330} 244}
331 245
@@ -333,28 +247,28 @@ static void mobilebackup_write_status(const char *path, int status)
333{ 247{
334 struct stat st; 248 struct stat st;
335 plist_t status_plist = plist_new_dict(); 249 plist_t status_plist = plist_new_dict();
336 plist_dict_insert_item(status_plist, "Backup Success", plist_new_bool(status)); 250 plist_dict_set_item(status_plist, "Backup Success", plist_new_bool(status));
337 gchar *file_path = mobilebackup_build_path(path, "Status", ".plist"); 251 char *file_path = mobilebackup_build_path(path, "Status", ".plist");
338 252
339 if (stat(file_path, &st) == 0) 253 if (stat(file_path, &st) == 0)
340 remove(file_path); 254 remove(file_path);
341 255
342 plist_write_to_filename(status_plist, file_path, PLIST_FORMAT_XML); 256 plist_write_to_file(status_plist, file_path, PLIST_FORMAT_XML, 0);
343 257
344 plist_free(status_plist); 258 plist_free(status_plist);
345 status_plist = NULL; 259 status_plist = NULL;
346 260
347 g_free(file_path); 261 free(file_path);
348} 262}
349 263
350static int mobilebackup_read_status(const char *path) 264static int mobilebackup_read_status(const char *path)
351{ 265{
352 int ret = -1; 266 int ret = -1;
353 plist_t status_plist = NULL; 267 plist_t status_plist = NULL;
354 gchar *file_path = mobilebackup_build_path(path, "Status", ".plist"); 268 char *file_path = mobilebackup_build_path(path, "Status", ".plist");
355 269
356 plist_read_from_filename(&status_plist, file_path); 270 plist_read_from_file(file_path, &status_plist, NULL);
357 g_free(file_path); 271 free(file_path);
358 if (!status_plist) { 272 if (!status_plist) {
359 printf("Could not read Status.plist!\n"); 273 printf("Could not read Status.plist!\n");
360 return ret; 274 return ret;
@@ -387,7 +301,7 @@ static int mobilebackup_info_is_current_device(plist_t info)
387 /* get basic device information in one go */ 301 /* get basic device information in one go */
388 lockdownd_get_value(client, NULL, NULL, &root_node); 302 lockdownd_get_value(client, NULL, NULL, &root_node);
389 303
390 /* verify UUID */ 304 /* verify UDID */
391 value_node = plist_dict_get_item(root_node, "UniqueDeviceID"); 305 value_node = plist_dict_get_item(root_node, "UniqueDeviceID");
392 node = plist_dict_get_item(info, "Target Identifier"); 306 node = plist_dict_get_item(info, "Target Identifier");
393 307
@@ -435,14 +349,14 @@ static int mobilebackup_info_is_current_device(plist_t info)
435static int mobilebackup_delete_backup_file_by_hash(const char *backup_directory, const char *hash) 349static int mobilebackup_delete_backup_file_by_hash(const char *backup_directory, const char *hash)
436{ 350{
437 int ret = 0; 351 int ret = 0;
438 gchar *path = mobilebackup_build_path(backup_directory, hash, ".mddata"); 352 char *path = mobilebackup_build_path(backup_directory, hash, ".mddata");
439 printf("Removing \"%s\" ", path); 353 printf("Removing \"%s\" ", path);
440 if (!remove( path )) 354 if (!remove( path ))
441 ret = 1; 355 ret = 1;
442 else 356 else
443 ret = 0; 357 ret = 0;
444 358
445 g_free(path); 359 free(path);
446 360
447 if (!ret) 361 if (!ret)
448 return ret; 362 return ret;
@@ -454,7 +368,7 @@ static int mobilebackup_delete_backup_file_by_hash(const char *backup_directory,
454 else 368 else
455 ret = 0; 369 ret = 0;
456 370
457 g_free(path); 371 free(path);
458 372
459 return ret; 373 return ret;
460} 374}
@@ -476,7 +390,7 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const
476 } 390 }
477 391
478 infopath = mobilebackup_build_path(backup_directory, hash, ".mdinfo"); 392 infopath = mobilebackup_build_path(backup_directory, hash, ".mdinfo");
479 plist_read_from_filename(&mdinfo, infopath); 393 plist_read_from_file(infopath, &mdinfo, NULL);
480 free(infopath); 394 free(infopath);
481 if (!mdinfo) { 395 if (!mdinfo) {
482 printf("\r\n"); 396 printf("\r\n");
@@ -521,13 +435,13 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const
521 435
522 char *version = NULL; 436 char *version = NULL;
523 node = plist_dict_get_item(metadata, "Version"); 437 node = plist_dict_get_item(metadata, "Version");
524 if (node && (plist_get_node_type(node) == PLIST_STRING)) { 438 if (node && (plist_get_node_type(node) == PLIST_STRING)) {
525 plist_get_string_val(node, &version); 439 plist_get_string_val(node, &version);
526 } 440 }
527 441
528 char *destpath = NULL; 442 char *destpath = NULL;
529 node = plist_dict_get_item(metadata, "Path"); 443 node = plist_dict_get_item(metadata, "Path");
530 if (node && (plist_get_node_type(node) == PLIST_STRING)) { 444 if (node && (plist_get_node_type(node) == PLIST_STRING)) {
531 plist_get_string_val(node, &destpath); 445 plist_get_string_val(node, &destpath);
532 } 446 }
533 447
@@ -539,7 +453,7 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const
539 453
540 char *domain = NULL; 454 char *domain = NULL;
541 node = plist_dict_get_item(metadata, "Domain"); 455 node = plist_dict_get_item(metadata, "Domain");
542 if (node && (plist_get_node_type(node) == PLIST_STRING)) { 456 if (node && (plist_get_node_type(node) == PLIST_STRING)) {
543 plist_get_string_val(node, &domain); 457 plist_get_string_val(node, &domain);
544 } 458 }
545 459
@@ -550,14 +464,14 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const
550 unsigned char fnhash[20]; 464 unsigned char fnhash[20];
551 char fnamehash[41]; 465 char fnamehash[41];
552 char *p = fnamehash; 466 char *p = fnamehash;
553 sha1_of_data(fnstr, strlen(fnstr), fnhash); 467 sha1((const unsigned char*)fnstr, strlen(fnstr), fnhash);
554 free(fnstr); 468 free(fnstr);
555 int i; 469 int i;
556 for ( i = 0; i < 20; i++, p += 2 ) { 470 for ( i = 0; i < 20; i++, p += 2 ) {
557 snprintf (p, 3, "%02x", (unsigned char)fnhash[i] ); 471 snprintf (p, 3, "%02x", (unsigned char)fnhash[i] );
558 } 472 }
559 if (strcmp(fnamehash, hash)) { 473 if (strcmp(fnamehash, hash) != 0) {
560 printf("\r\n"); 474 printf("\r\n");
561 printf("WARNING: filename hash does not match for entry '%s'\n", hash); 475 printf("WARNING: filename hash does not match for entry '%s'\n", hash);
562 } 476 }
563 477
@@ -567,7 +481,7 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const
567 plist_get_string_val(node, &auth_version); 481 plist_get_string_val(node, &auth_version);
568 } 482 }
569 483
570 if (strcmp(auth_version, "1.0")) { 484 if (strcmp(auth_version, "1.0") != 0) {
571 printf("\r\n"); 485 printf("\r\n");
572 printf("WARNING: Unknown AuthVersion '%s', DataHash cannot be verified!\n", auth_version); 486 printf("WARNING: Unknown AuthVersion '%s', DataHash cannot be verified!\n", auth_version);
573 } 487 }
@@ -591,9 +505,9 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const
591 hash_ok = 1; 505 hash_ok = 1;
592 } 506 }
593 507
594 g_free(domain); 508 free(domain);
595 g_free(version); 509 free(version);
596 g_free(destpath); 510 free(destpath);
597 511
598 if (!hash_ok) { 512 if (!hash_ok) {
599 printf("\r\n"); 513 printf("\r\n");
@@ -605,31 +519,36 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const
605 printf("\n"); 519 printf("\n");
606 res = 0; 520 res = 0;
607 } 521 }
608 g_free(data_hash); 522 free(data_hash);
609 plist_free(mdinfo); 523 plist_free(mdinfo);
610 return res; 524 return res;
611} 525}
612 526
613static void do_post_notification(const char *notification) 527static void do_post_notification(const char *notification)
614{ 528{
615 uint16_t nport = 0; 529 lockdownd_service_descriptor_t service = NULL;
616 np_client_t np; 530 np_client_t np;
617 531
618 if (!client) { 532 if (!client) {
619 if (lockdownd_client_new_with_handshake(phone, &client, "idevicebackup") != LOCKDOWN_E_SUCCESS) { 533 if (lockdownd_client_new_with_handshake(device, &client, TOOL_NAME) != LOCKDOWN_E_SUCCESS) {
620 return; 534 return;
621 } 535 }
622 } 536 }
623 537
624 lockdownd_start_service(client, NP_SERVICE_NAME, &nport); 538 lockdownd_error_t ldret = lockdownd_start_service(client, NP_SERVICE_NAME, &service);
625 if (nport) { 539 if (ldret == LOCKDOWN_E_SUCCESS) {
626 np_client_new(phone, nport, &np); 540 np_client_new(device, service, &np);
627 if (np) { 541 if (np) {
628 np_post_notification(np, notification); 542 np_post_notification(np, notification);
629 np_client_free(np); 543 np_client_free(np);
630 } 544 }
631 } else { 545 } else {
632 printf("Could not start %s\n", NP_SERVICE_NAME); 546 printf("Could not start %s: %s\n", NP_SERVICE_NAME, lockdownd_strerror(ldret));
547 }
548
549 if (service) {
550 lockdownd_service_descriptor_free(service);
551 service = NULL;
633 } 552 }
634} 553}
635 554
@@ -665,29 +584,38 @@ static void clean_exit(int sig)
665 quit_flag++; 584 quit_flag++;
666} 585}
667 586
668static void print_usage(int argc, char **argv) 587static void print_usage(int argc, char **argv, int is_error)
669{ 588{
670 char *name = NULL; 589 char *name = strrchr(argv[0], '/');
671 name = strrchr(argv[0], '/'); 590 fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS] CMD DIRECTORY\n", (name ? name + 1: argv[0]));
672 printf("Usage: %s [OPTIONS] CMD [DIRECTORY]\n", (name ? name + 1: argv[0])); 591 fprintf(is_error ? stderr : stdout,
673 printf("Create or restore backup from the current or specified directory.\n\n"); 592 "\n"
674 printf("commands:\n"); 593 "Create or restore backup in/from the specified directory.\n"
675 printf(" backup\tSaves a device backup into DIRECTORY\n"); 594 "\n"
676 printf(" restore\tRestores a device backup from DIRECTORY.\n\n"); 595 "CMD:\n"
677 printf("options:\n"); 596 " backup Saves a device backup into DIRECTORY\n"
678 printf(" -d, --debug\t\tenable communication debugging\n"); 597 " restore Restores a device backup from DIRECTORY.\n"
679 printf(" -u, --uuid UUID\ttarget specific device by its 40-digit device UUID\n"); 598 "\n"
680 printf(" -h, --help\t\tprints usage information\n"); 599 "OPTIONS:\n"
681 printf("\n"); 600 " -u, --udid UDID target specific device by UDID\n"
601 " -n, --network connect to network device\n"
602 " -d, --debug enable communication debugging\n"
603 " -h, --help prints usage information\n"
604 " -v, --version prints version information\n"
605 "\n"
606 "Homepage: <" PACKAGE_URL ">\n"
607 "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
608 );
682} 609}
683 610
684int main(int argc, char *argv[]) 611int main(int argc, char *argv[])
685{ 612{
686 idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; 613 idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
614 lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR;
687 int i; 615 int i;
688 char uuid[41]; 616 char* udid = NULL;
689 uint16_t port = 0; 617 int use_network = 0;
690 uuid[0] = 0; 618 lockdownd_service_descriptor_t service = NULL;
691 int cmd = -1; 619 int cmd = -1;
692 int is_full_backup = 0; 620 int is_full_backup = 0;
693 char *backup_directory = NULL; 621 char *backup_directory = NULL;
@@ -701,60 +629,77 @@ int main(int argc, char *argv[])
701 uint64_t length = 0; 629 uint64_t length = 0;
702 uint64_t backup_total_size = 0; 630 uint64_t backup_total_size = 0;
703 enum device_link_file_status_t file_status = DEVICE_LINK_FILE_STATUS_NONE; 631 enum device_link_file_status_t file_status = DEVICE_LINK_FILE_STATUS_NONE;
704 uint64_t c = 0; 632 int c = 0;
633 const struct option longopts[] = {
634 { "debug", no_argument, NULL, 'd' },
635 { "help", no_argument, NULL, 'h' },
636 { "udid", required_argument, NULL, 'u' },
637 { "network", no_argument, NULL, 'n' },
638 { "version", no_argument, NULL, 'v' },
639 { NULL, 0, NULL, 0}
640 };
705 641
706 /* we need to exit cleanly on running backups and restores or we cause havok */ 642 /* we need to exit cleanly on running backups and restores or we cause havok */
707 signal(SIGINT, clean_exit); 643 signal(SIGINT, clean_exit);
708 signal(SIGQUIT, clean_exit);
709 signal(SIGTERM, clean_exit); 644 signal(SIGTERM, clean_exit);
645#ifndef WIN32
646 signal(SIGQUIT, clean_exit);
710 signal(SIGPIPE, SIG_IGN); 647 signal(SIGPIPE, SIG_IGN);
648#endif
711 649
712 /* parse cmdline args */ 650 /* parse cmdline args */
713 for (i = 1; i < argc; i++) { 651 while ((c = getopt_long(argc, argv, "dhu:nv", longopts, NULL)) != -1) {
714 if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { 652 switch (c) {
653 case 'd':
715 idevice_set_debug_level(1); 654 idevice_set_debug_level(1);
716 continue; 655 break;
717 } 656 case 'u':
718 else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--uuid")) { 657 if (!*optarg) {
719 i++; 658 fprintf(stderr, "ERROR: UDID must not be empty!\n");
720 if (!argv[i] || (strlen(argv[i]) != 40)) { 659 print_usage(argc, argv, 1);
721 print_usage(argc, argv); 660 return 2;
722 return 0;
723 } 661 }
724 strcpy(uuid, argv[i]); 662 udid = strdup(optarg);
725 continue; 663 break;
726 } 664 case 'n':
727 else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { 665 use_network = 1;
728 print_usage(argc, argv); 666 break;
667 case 'h':
668 print_usage(argc, argv, 0);
729 return 0; 669 return 0;
730 } 670 case 'v':
731 else if (!strcmp(argv[i], "backup")) { 671 printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION);
732 cmd = CMD_BACKUP;
733 }
734 else if (!strcmp(argv[i], "restore")) {
735 cmd = CMD_RESTORE;
736 }
737 else if (backup_directory == NULL) {
738 backup_directory = argv[i];
739 }
740 else {
741 print_usage(argc, argv);
742 return 0; 672 return 0;
673 default:
674 print_usage(argc, argv, 1);
675 return 2;
743 } 676 }
744 } 677 }
678 argc -= optind;
679 argv += optind;
745 680
746 /* verify options */ 681 if (argc < 1) {
747 if (cmd == -1) { 682 fprintf(stderr, "ERROR: Missing command.\n");
748 printf("No command specified.\n"); 683 print_usage(argc+optind, argv-optind, 1);
749 print_usage(argc, argv); 684 return 2;
750 return -1;
751 } 685 }
752 686
753 if (backup_directory == NULL) { 687 if (!strcmp(argv[0], "backup")) {
754 printf("No target backup directory specified.\n"); 688 cmd = CMD_BACKUP;
755 print_usage(argc, argv); 689 } else if (!strcmp(argv[0], "restore")) {
756 return -1; 690 cmd = CMD_RESTORE;
691 } else {
692 fprintf(stderr, "ERROR: Invalid command '%s'.\n", argv[0]);
693 print_usage(argc+optind, argv-optind, 1);
694 return 2;
695 }
696
697 if (argc < 2) {
698 fprintf(stderr, "No target backup directory specified.\n");
699 print_usage(argc+optind, argv-optind, 1);
700 return 2;
757 } 701 }
702 backup_directory = argv[1];
758 703
759 /* verify if passed backup directory exists */ 704 /* verify if passed backup directory exists */
760 if (stat(backup_directory, &st) != 0) { 705 if (stat(backup_directory, &st) != 0) {
@@ -766,7 +711,7 @@ int main(int argc, char *argv[])
766 char *info_path = mobilebackup_build_path(backup_directory, "Info", ".plist"); 711 char *info_path = mobilebackup_build_path(backup_directory, "Info", ".plist");
767 if (cmd == CMD_RESTORE) { 712 if (cmd == CMD_RESTORE) {
768 if (stat(info_path, &st) != 0) { 713 if (stat(info_path, &st) != 0) {
769 g_free(info_path); 714 free(info_path);
770 printf("ERROR: Backup directory \"%s\" is invalid. No Info.plist found.\n", backup_directory); 715 printf("ERROR: Backup directory \"%s\" is invalid. No Info.plist found.\n", backup_directory);
771 return -1; 716 return -1;
772 } 717 }
@@ -774,32 +719,54 @@ int main(int argc, char *argv[])
774 719
775 printf("Backup directory is \"%s\"\n", backup_directory); 720 printf("Backup directory is \"%s\"\n", backup_directory);
776 721
777 if (uuid[0] != 0) { 722 ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX);
778 ret = idevice_new(&phone, uuid); 723 if (ret != IDEVICE_E_SUCCESS) {
779 if (ret != IDEVICE_E_SUCCESS) { 724 if (udid) {
780 printf("No device found with uuid %s, is it plugged in?\n", uuid); 725 printf("No device found with udid %s.\n", udid);
781 return -1; 726 } else {
727 printf("No device found.\n");
782 } 728 }
729 return -1;
783 } 730 }
784 else 731
785 { 732 if (!udid) {
786 ret = idevice_new(&phone, NULL); 733 idevice_get_udid(device, &udid);
787 if (ret != IDEVICE_E_SUCCESS) {
788 printf("No device found, is it plugged in?\n");
789 return -1;
790 }
791 } 734 }
792 735
793 if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(phone, &client, "idevicebackup")) { 736 if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &client, TOOL_NAME))) {
794 idevice_free(phone); 737 printf("ERROR: Could not connect to lockdownd, error code %d\n", ldret);
738 idevice_free(device);
739 free(udid);
795 return -1; 740 return -1;
796 } 741 }
797 742
743 node = NULL;
744 lockdownd_get_value(client, NULL, "ProductVersion", &node);
745 if (node) {
746 char* str = NULL;
747 if (plist_get_node_type(node) == PLIST_STRING) {
748 plist_get_string_val(node, &str);
749 }
750 plist_free(node);
751 node = NULL;
752 if (str) {
753 int maj = strtol(str, NULL, 10);
754 free(str);
755 if (maj > 3) {
756 printf("ERROR: This tool is only compatible with iOS 3 or below. For newer iOS versions please use the idevicebackup2 tool.\n");
757 lockdownd_client_free(client);
758 idevice_free(device);
759 free(udid);
760 return -1;
761 }
762 }
763 }
764
798 /* start notification_proxy */ 765 /* start notification_proxy */
799 np_client_t np = NULL; 766 np_client_t np = NULL;
800 ret = lockdownd_start_service(client, NP_SERVICE_NAME, &port); 767 ldret = lockdownd_start_service(client, NP_SERVICE_NAME, &service);
801 if ((ret == LOCKDOWN_E_SUCCESS) && port) { 768 if ((ldret == LOCKDOWN_E_SUCCESS) && service && service->port) {
802 np_client_new(phone, port, &np); 769 np_client_new(device, service, &np);
803 np_set_notify_callback(np, notify_cb, NULL); 770 np_set_notify_callback(np, notify_cb, NULL);
804 const char *noties[5] = { 771 const char *noties[5] = {
805 NP_SYNC_CANCEL_REQUEST, 772 NP_SYNC_CANCEL_REQUEST,
@@ -810,25 +777,37 @@ int main(int argc, char *argv[])
810 }; 777 };
811 np_observe_notifications(np, noties); 778 np_observe_notifications(np, noties);
812 } else { 779 } else {
813 printf("ERROR: Could not start service %s.\n", NP_SERVICE_NAME); 780 printf("ERROR: Could not start service %s: %s\n", NP_SERVICE_NAME, lockdownd_strerror(ldret));
814 } 781 }
815 782
816 afc_client_t afc = NULL; 783 afc_client_t afc = NULL;
817 if (cmd == CMD_BACKUP) { 784 if (cmd == CMD_BACKUP) {
818 /* start AFC, we need this for the lock file */ 785 /* start AFC, we need this for the lock file */
819 port = 0; 786 service->port = 0;
820 ret = lockdownd_start_service(client, "com.apple.afc", &port); 787 service->ssl_enabled = 0;
821 if ((ret == LOCKDOWN_E_SUCCESS) && port) { 788 ldret = lockdownd_start_service(client, AFC_SERVICE_NAME, &service);
822 afc_client_new(phone, port, &afc); 789 if ((ldret == LOCKDOWN_E_SUCCESS) && service->port) {
790 afc_client_new(device, service, &afc);
791 } else {
792 printf("ERROR: Could not start service %s: %s\n", AFC_SERVICE_NAME, lockdownd_strerror(ldret));
823 } 793 }
824 } 794 }
825 795
796 if (service) {
797 lockdownd_service_descriptor_free(service);
798 service = NULL;
799 }
800
826 /* start mobilebackup service and retrieve port */ 801 /* start mobilebackup service and retrieve port */
827 port = 0; 802 ldret = lockdownd_start_service(client, MOBILEBACKUP_SERVICE_NAME, &service);
828 ret = lockdownd_start_service(client, MOBILEBACKUP_SERVICE_NAME, &port); 803 if ((ldret == LOCKDOWN_E_SUCCESS) && service && service->port) {
829 if ((ret == LOCKDOWN_E_SUCCESS) && port) { 804 printf("Started \"%s\" service on port %d.\n", MOBILEBACKUP_SERVICE_NAME, service->port);
830 printf("Started \"%s\" service on port %d.\n", MOBILEBACKUP_SERVICE_NAME, port); 805 printf("%d\n", mobilebackup_client_new(device, service, &mobilebackup));
831 mobilebackup_client_new(phone, port, &mobilebackup); 806
807 if (service) {
808 lockdownd_service_descriptor_free(service);
809 service = NULL;
810 }
832 811
833 /* check abort conditions */ 812 /* check abort conditions */
834 if (quit_flag > 0) { 813 if (quit_flag > 0) {
@@ -839,7 +818,7 @@ int main(int argc, char *argv[])
839 /* verify existing Info.plist */ 818 /* verify existing Info.plist */
840 if (stat(info_path, &st) == 0) { 819 if (stat(info_path, &st) == 0) {
841 printf("Reading Info.plist from backup.\n"); 820 printf("Reading Info.plist from backup.\n");
842 plist_read_from_filename(&info_plist, info_path); 821 plist_read_from_file(info_path, &info_plist, NULL);
843 822
844 if (!info_plist) { 823 if (!info_plist) {
845 printf("Could not read Info.plist\n"); 824 printf("Could not read Info.plist\n");
@@ -850,7 +829,7 @@ int main(int argc, char *argv[])
850 /* update the last backup time within Info.plist */ 829 /* update the last backup time within Info.plist */
851 mobilebackup_info_update_last_backup_date(info_plist); 830 mobilebackup_info_update_last_backup_date(info_plist);
852 remove(info_path); 831 remove(info_path);
853 plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML); 832 plist_write_to_file(info_plist, info_path, PLIST_FORMAT_XML, 0);
854 } else { 833 } else {
855 printf("Aborting backup. Backup is not compatible with the current device.\n"); 834 printf("Aborting backup. Backup is not compatible with the current device.\n");
856 cmd = CMD_LEAVE; 835 cmd = CMD_LEAVE;
@@ -883,15 +862,16 @@ int main(int argc, char *argv[])
883 if (aerr == AFC_E_SUCCESS) { 862 if (aerr == AFC_E_SUCCESS) {
884 do_post_notification(NP_SYNC_DID_START); 863 do_post_notification(NP_SYNC_DID_START);
885 break; 864 break;
886 } else if (aerr == AFC_E_OP_WOULD_BLOCK) { 865 }
866 if (aerr == AFC_E_OP_WOULD_BLOCK) {
887 usleep(LOCK_WAIT); 867 usleep(LOCK_WAIT);
888 continue; 868 continue;
889 } else {
890 fprintf(stderr, "ERROR: could not lock file! error code: %d\n", aerr);
891 afc_file_close(afc, lockfile);
892 lockfile = 0;
893 cmd = CMD_LEAVE;
894 } 869 }
870
871 fprintf(stderr, "ERROR: could not lock file! error code: %d\n", aerr);
872 afc_file_close(afc, lockfile);
873 lockfile = 0;
874 cmd = CMD_LEAVE;
895 } 875 }
896 if (i == LOCK_ATTEMPTS) { 876 if (i == LOCK_ATTEMPTS) {
897 fprintf(stderr, "ERROR: timeout while locking for sync\n"); 877 fprintf(stderr, "ERROR: timeout while locking for sync\n");
@@ -910,12 +890,12 @@ int main(int argc, char *argv[])
910 case CMD_BACKUP: 890 case CMD_BACKUP:
911 printf("Starting backup...\n"); 891 printf("Starting backup...\n");
912 /* TODO: check domain com.apple.mobile.backup key RequiresEncrypt and WillEncrypt with lockdown */ 892 /* TODO: check domain com.apple.mobile.backup key RequiresEncrypt and WillEncrypt with lockdown */
913 /* TODO: verify battery on AC enough battery remaining */ 893 /* TODO: verify battery on AC enough battery remaining */
914 894
915 /* read the last Manifest.plist */ 895 /* read the last Manifest.plist */
916 if (!is_full_backup) { 896 if (!is_full_backup) {
917 printf("Reading existing Manifest.\n"); 897 printf("Reading existing Manifest.\n");
918 plist_read_from_filename(&manifest_plist, manifest_path); 898 plist_read_from_file(manifest_path, &manifest_plist, NULL);
919 if (!manifest_plist) { 899 if (!manifest_plist) {
920 printf("Could not read Manifest.plist, switching to full backup mode.\n"); 900 printf("Could not read Manifest.plist, switching to full backup mode.\n");
921 is_full_backup = 1; 901 is_full_backup = 1;
@@ -932,10 +912,10 @@ int main(int argc, char *argv[])
932 } 912 }
933 remove(info_path); 913 remove(info_path);
934 printf("Creating Info.plist for new backup.\n"); 914 printf("Creating Info.plist for new backup.\n");
935 info_plist = mobilebackup_factory_info_plist_new(); 915 info_plist = mobilebackup_factory_info_plist_new(udid);
936 plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML); 916 plist_write_to_file(info_plist, info_path, PLIST_FORMAT_XML, 0);
937 } 917 }
938 g_free(info_path); 918 free(info_path);
939 919
940 plist_free(info_plist); 920 plist_free(info_plist);
941 info_plist = NULL; 921 info_plist = NULL;
@@ -965,7 +945,7 @@ int main(int argc, char *argv[])
965 } else if (err == MOBILEBACKUP_E_REPLY_NOT_OK) { 945 } else if (err == MOBILEBACKUP_E_REPLY_NOT_OK) {
966 printf("ERROR: Could not start backup process: device refused to start the backup process.\n"); 946 printf("ERROR: Could not start backup process: device refused to start the backup process.\n");
967 } else { 947 } else {
968 printf("ERROR: Could not start backup process: unspecified error occured\n"); 948 printf("ERROR: Could not start backup process: unspecified error occurred (%d)\n", err);
969 } 949 }
970 break; 950 break;
971 } 951 }
@@ -985,8 +965,9 @@ int main(int argc, char *argv[])
985 char *filename_mddata = NULL; 965 char *filename_mddata = NULL;
986 char *filename_source = NULL; 966 char *filename_source = NULL;
987 char *format_size = NULL; 967 char *format_size = NULL;
988 gboolean is_manifest = FALSE; 968 int is_manifest = 0;
989 uint8_t b = 0; 969 uint8_t b = 0;
970 uint64_t u64val = 0;
990 971
991 /* process series of DLSendFile messages */ 972 /* process series of DLSendFile messages */
992 do { 973 do {
@@ -996,7 +977,7 @@ int main(int argc, char *argv[])
996 sleep(2); 977 sleep(2);
997 goto files_out; 978 goto files_out;
998 } 979 }
999 980
1000 node = plist_array_get_item(message, 0); 981 node = plist_array_get_item(message, 0);
1001 982
1002 /* get out if we don't get a DLSendFile */ 983 /* get out if we don't get a DLSendFile */
@@ -1010,16 +991,16 @@ int main(int argc, char *argv[])
1010 node = plist_dict_get_item(node_tmp, "BackupTotalSizeKey"); 991 node = plist_dict_get_item(node_tmp, "BackupTotalSizeKey");
1011 if (node) { 992 if (node) {
1012 plist_get_uint_val(node, &backup_total_size); 993 plist_get_uint_val(node, &backup_total_size);
1013 format_size = g_format_size_for_display(backup_total_size); 994 format_size = string_format_size(backup_total_size);
1014 printf("Backup data requires %s on the disk.\n", format_size); 995 printf("Backup data requires %s on the disk.\n", format_size);
1015 g_free(format_size); 996 free(format_size);
1016 } 997 }
1017 } 998 }
1018 999
1019 /* check DLFileStatusKey (codes: 1 = Hunk, 2 = Last Hunk) */ 1000 /* check DLFileStatusKey (codes: 1 = Hunk, 2 = Last Hunk) */
1020 node = plist_dict_get_item(node_tmp, "DLFileStatusKey"); 1001 node = plist_dict_get_item(node_tmp, "DLFileStatusKey");
1021 plist_get_uint_val(node, &c); 1002 plist_get_uint_val(node, &u64val);
1022 file_status = c; 1003 file_status = u64val;
1023 1004
1024 /* get source filename */ 1005 /* get source filename */
1025 node = plist_dict_get_item(node_tmp, "BackupManifestKey"); 1006 node = plist_dict_get_item(node_tmp, "BackupManifestKey");
@@ -1027,7 +1008,7 @@ int main(int argc, char *argv[])
1027 if (node) { 1008 if (node) {
1028 plist_get_bool_val(node, &b); 1009 plist_get_bool_val(node, &b);
1029 } 1010 }
1030 is_manifest = (b == 1) ? TRUE: FALSE; 1011 is_manifest = (b == 1) ? 1 : 0;
1031 1012
1032 if ((hunk_index == 0) && (!is_manifest)) { 1013 if ((hunk_index == 0) && (!is_manifest)) {
1033 /* get source filename */ 1014 /* get source filename */
@@ -1040,17 +1021,17 @@ int main(int argc, char *argv[])
1040 plist_get_uint_val(node, &file_size); 1021 plist_get_uint_val(node, &file_size);
1041 backup_real_size += file_size; 1022 backup_real_size += file_size;
1042 1023
1043 format_size = g_format_size_for_display(backup_real_size); 1024 format_size = string_format_size(backup_real_size);
1044 printf("(%s", format_size); 1025 printf("(%s", format_size);
1045 g_free(format_size); 1026 free(format_size);
1046 1027
1047 format_size = g_format_size_for_display(backup_total_size); 1028 format_size = string_format_size(backup_total_size);
1048 printf("/%s): ", format_size); 1029 printf("/%s): ", format_size);
1049 g_free(format_size); 1030 free(format_size);
1050 1031
1051 format_size = g_format_size_for_display(file_size); 1032 format_size = string_format_size(file_size);
1052 printf("Receiving file %s (%s)... \n", filename_source, format_size); 1033 printf("Receiving file %s (%s)... \n", filename_source, format_size);
1053 g_free(format_size); 1034 free(format_size);
1054 1035
1055 if (filename_source) 1036 if (filename_source)
1056 free(filename_source); 1037 free(filename_source);
@@ -1071,9 +1052,9 @@ int main(int argc, char *argv[])
1071 remove(filename_mdinfo); 1052 remove(filename_mdinfo);
1072 1053
1073 node = plist_dict_get_item(node_tmp, "BackupFileInfo"); 1054 node = plist_dict_get_item(node_tmp, "BackupFileInfo");
1074 plist_write_to_filename(node, filename_mdinfo, PLIST_FORMAT_BINARY); 1055 plist_write_to_file(node, filename_mdinfo, PLIST_FORMAT_BINARY, 0);
1075 1056
1076 g_free(filename_mdinfo); 1057 free(filename_mdinfo);
1077 } 1058 }
1078 1059
1079 file_index++; 1060 file_index++;
@@ -1107,15 +1088,14 @@ int main(int argc, char *argv[])
1107 free(buffer); 1088 free(buffer);
1108 buffer = NULL; 1089 buffer = NULL;
1109 1090
1110 g_free(filename_mddata); 1091 free(filename_mddata);
1111 } 1092 }
1112 1093
1113 if ((!is_manifest)) { 1094 if ((!is_manifest)) {
1114 if (hunk_index == 0 && file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) { 1095 if (hunk_index == 0 && file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) {
1115 print_progress(100); 1096 print_progress(100);
1116 } else { 1097 } else if (file_size > 0) {
1117 if (file_size > 0) 1098 print_progress((double)(file_size_current*100)/file_size);
1118 print_progress((double)((file_size_current*100)/file_size));
1119 } 1099 }
1120 } 1100 }
1121 1101
@@ -1145,7 +1125,7 @@ files_out:
1145 1125
1146 /* remove any atomic Manifest.plist.tmp */ 1126 /* remove any atomic Manifest.plist.tmp */
1147 if (manifest_path) 1127 if (manifest_path)
1148 g_free(manifest_path); 1128 free(manifest_path);
1149 1129
1150 manifest_path = mobilebackup_build_path(backup_directory, "Manifest", ".plist.tmp"); 1130 manifest_path = mobilebackup_build_path(backup_directory, "Manifest", ".plist.tmp");
1151 if (stat(manifest_path, &st) == 0) 1131 if (stat(manifest_path, &st) == 0)
@@ -1184,7 +1164,7 @@ files_out:
1184 if (manifest_plist) { 1164 if (manifest_plist) {
1185 remove(manifest_path); 1165 remove(manifest_path);
1186 printf("Storing Manifest.plist...\n"); 1166 printf("Storing Manifest.plist...\n");
1187 plist_write_to_filename(manifest_plist, manifest_path, PLIST_FORMAT_XML); 1167 plist_write_to_file(manifest_plist, manifest_path, PLIST_FORMAT_XML, 0);
1188 } 1168 }
1189 1169
1190 backup_ok = 1; 1170 backup_ok = 1;
@@ -1215,21 +1195,21 @@ files_out:
1215 } 1195 }
1216 /* now make sure backup integrity is ok! verify all files */ 1196 /* now make sure backup integrity is ok! verify all files */
1217 printf("Reading existing Manifest.\n"); 1197 printf("Reading existing Manifest.\n");
1218 plist_read_from_filename(&manifest_plist, manifest_path); 1198 plist_read_from_file(manifest_path, &manifest_plist, NULL);
1219 if (!manifest_plist) { 1199 if (!manifest_plist) {
1220 printf("Could not read Manifest.plist. Aborting.\n"); 1200 printf("Could not read Manifest.plist. Aborting.\n");
1221 break; 1201 break;
1222 } 1202 }
1223 1203
1224 printf("Verifying backup integrity, please wait.\n"); 1204 printf("Verifying backup integrity, please wait.\n");
1225 char *bin = NULL; 1205 unsigned char *bin = NULL;
1226 uint64_t binsize = 0; 1206 uint64_t binsize = 0;
1227 node = plist_dict_get_item(manifest_plist, "Data"); 1207 node = plist_dict_get_item(manifest_plist, "Data");
1228 if (!node || (plist_get_node_type(node) != PLIST_DATA)) { 1208 if (!node || (plist_get_node_type(node) != PLIST_DATA)) {
1229 printf("Could not read Data key from Manifest.plist!\n"); 1209 printf("Could not read Data key from Manifest.plist!\n");
1230 break; 1210 break;
1231 } 1211 }
1232 plist_get_data_val(node, &bin, &binsize); 1212 plist_get_data_val(node, (char**)&bin, &binsize);
1233 plist_t backup_data = NULL; 1213 plist_t backup_data = NULL;
1234 if (bin) { 1214 if (bin) {
1235 char *auth_ver = NULL; 1215 char *auth_ver = NULL;
@@ -1246,7 +1226,7 @@ files_out:
1246 if (auth_sig && (auth_sig_len == 20)) { 1226 if (auth_sig && (auth_sig_len == 20)) {
1247 /* calculate the sha1, then compare */ 1227 /* calculate the sha1, then compare */
1248 unsigned char data_sha1[20]; 1228 unsigned char data_sha1[20];
1249 sha1_of_data(bin, binsize, data_sha1); 1229 sha1(bin, binsize, data_sha1);
1250 if (compare_hash(auth_sig, data_sha1, 20)) { 1230 if (compare_hash(auth_sig, data_sha1, 20)) {
1251 printf("AuthSignature is valid\n"); 1231 printf("AuthSignature is valid\n");
1252 } else { 1232 } else {
@@ -1255,12 +1235,12 @@ files_out:
1255 } else { 1235 } else {
1256 printf("Could not get AuthSignature from manifest!\n"); 1236 printf("Could not get AuthSignature from manifest!\n");
1257 } 1237 }
1258 g_free(auth_sig); 1238 free(auth_sig);
1259 } else if (auth_ver) { 1239 } else if (auth_ver) {
1260 printf("Unknown AuthVersion '%s', cannot verify AuthSignature\n", auth_ver); 1240 printf("Unknown AuthVersion '%s', cannot verify AuthSignature\n", auth_ver);
1261 } 1241 }
1262 plist_from_bin(bin, (uint32_t)binsize, &backup_data); 1242 plist_from_bin((char*)bin, (uint32_t)binsize, &backup_data);
1263 g_free(bin); 1243 free(bin);
1264 } 1244 }
1265 if (!backup_data) { 1245 if (!backup_data) {
1266 printf("Could not read plist from Manifest.plist Data key!\n"); 1246 printf("Could not read plist from Manifest.plist Data key!\n");
@@ -1312,7 +1292,7 @@ files_out:
1312 } else if (err == MOBILEBACKUP_E_REPLY_NOT_OK) { 1292 } else if (err == MOBILEBACKUP_E_REPLY_NOT_OK) {
1313 printf("ERROR: Could not start restore process: device refused to start the restore process.\n"); 1293 printf("ERROR: Could not start restore process: device refused to start the restore process.\n");
1314 } else { 1294 } else {
1315 printf("ERROR: Could not start restore process: unspecified error occured (%d)\n", err); 1295 printf("ERROR: Could not start restore process: unspecified error occurred (%d)\n", err);
1316 } 1296 }
1317 plist_free(backup_data); 1297 plist_free(backup_data);
1318 break; 1298 break;
@@ -1342,7 +1322,7 @@ files_out:
1342 while (node) { 1322 while (node) {
1343 /* TODO: read mddata/mdinfo files and send to device using DLSendFile */ 1323 /* TODO: read mddata/mdinfo files and send to device using DLSendFile */
1344 file_info_path = mobilebackup_build_path(backup_directory, hash, ".mdinfo"); 1324 file_info_path = mobilebackup_build_path(backup_directory, hash, ".mdinfo");
1345 plist_read_from_filename(&file_info, file_info_path); 1325 plist_read_from_file(file_info_path, &file_info, NULL);
1346 1326
1347 /* get encryption state */ 1327 /* get encryption state */
1348 tmp_node = plist_dict_get_item(file_info, "IsEncrypted"); 1328 tmp_node = plist_dict_get_item(file_info, "IsEncrypted");
@@ -1360,42 +1340,62 @@ files_out:
1360 printf("Restoring file %s %d/%d (%d%%)... ", file_path, cur_file, total_files, (cur_file*100/total_files)); 1340 printf("Restoring file %s %d/%d (%d%%)... ", file_path, cur_file, total_files, (cur_file*100/total_files));
1361 1341
1362 /* add additional device link file information keys */ 1342 /* add additional device link file information keys */
1363 plist_dict_insert_item(file_info, "DLFileAttributesKey", plist_copy(node)); 1343 plist_dict_set_item(file_info, "DLFileAttributesKey", plist_copy(node));
1364 plist_dict_insert_item(file_info, "DLFileSource", plist_new_string(file_info_path)); 1344 plist_dict_set_item(file_info, "DLFileSource", plist_new_string(file_info_path));
1365 plist_dict_insert_item(file_info, "DLFileDest", plist_new_string("/tmp/RestoreFile.plist")); 1345 plist_dict_set_item(file_info, "DLFileDest", plist_new_string("/tmp/RestoreFile.plist"));
1366 plist_dict_insert_item(file_info, "DLFileIsEncrypted", plist_new_bool(is_encrypted)); 1346 plist_dict_set_item(file_info, "DLFileIsEncrypted", plist_new_bool(is_encrypted));
1367 plist_dict_insert_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset)); 1347 plist_dict_set_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset));
1368 plist_dict_insert_item(file_info, "DLFileStatusKey", plist_new_uint(file_status)); 1348 plist_dict_set_item(file_info, "DLFileStatusKey", plist_new_uint(file_status));
1369 1349
1370 /* read data from file */ 1350 /* read data from file */
1371 free(file_info_path); 1351 free(file_info_path);
1372 file_info_path = mobilebackup_build_path(backup_directory, hash, ".mddata"); 1352 file_info_path = mobilebackup_build_path(backup_directory, hash, ".mddata");
1373 buffer_read_from_filename(file_info_path, &buffer, &length); 1353
1354 /* determine file size */
1355#ifdef WIN32
1356 struct _stati64 fst;
1357 if (_stati64(file_info_path, &fst) != 0)
1358#else
1359 struct stat fst;
1360 if (stat(file_info_path, &fst) != 0)
1361#endif
1362 {
1363 printf("ERROR: stat() failed for '%s': %s\n", file_info_path, strerror(errno));
1364 free(file_info_path);
1365 break;
1366 }
1367 length = fst.st_size;
1368
1369 FILE *f = fopen(file_info_path, "rb");
1370 if (!f) {
1371 printf("ERROR: could not open local file '%s': %s\n", file_info_path, strerror(errno));
1372 free(file_info_path);
1373 break;
1374 }
1374 free(file_info_path); 1375 free(file_info_path);
1375 1376
1376 /* send DLSendFile messages */ 1377 /* send DLSendFile messages */
1377 file_offset = 0; 1378 file_offset = 0;
1378 do { 1379 do {
1379 if ((length-file_offset) <= 8192) 1380 char buf[8192];
1381 size_t len = fread(buf, 1, sizeof(buf), f);
1382
1383 if ((length-file_offset) <= sizeof(buf))
1380 file_status = DEVICE_LINK_FILE_STATUS_LAST_HUNK; 1384 file_status = DEVICE_LINK_FILE_STATUS_LAST_HUNK;
1381 else 1385 else
1382 file_status = DEVICE_LINK_FILE_STATUS_HUNK; 1386 file_status = DEVICE_LINK_FILE_STATUS_HUNK;
1383 1387
1384 plist_dict_remove_item(file_info, "DLFileOffsetKey"); 1388 plist_dict_remove_item(file_info, "DLFileOffsetKey");
1385 plist_dict_insert_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset)); 1389 plist_dict_set_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset));
1386 1390
1387 plist_dict_remove_item(file_info, "DLFileStatusKey"); 1391 plist_dict_remove_item(file_info, "DLFileStatusKey");
1388 plist_dict_insert_item(file_info, "DLFileStatusKey", plist_new_uint(file_status)); 1392 plist_dict_set_item(file_info, "DLFileStatusKey", plist_new_uint(file_status));
1389 1393
1390 send_file_node = plist_new_array(); 1394 send_file_node = plist_new_array();
1391 1395
1392 plist_array_append_item(send_file_node, plist_new_string("DLSendFile")); 1396 plist_array_append_item(send_file_node, plist_new_string("DLSendFile"));
1393 1397
1394 if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) 1398 plist_array_append_item(send_file_node, plist_new_data(buf, len));
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)); 1399 plist_array_append_item(send_file_node, plist_copy(file_info));
1400 1400
1401 err = mobilebackup_send(mobilebackup, send_file_node); 1401 err = mobilebackup_send(mobilebackup, send_file_node);
@@ -1413,13 +1413,13 @@ files_out:
1413 } 1413 }
1414 } 1414 }
1415 1415
1416 file_offset += 8192; 1416 file_offset += len;
1417 1417
1418 if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) 1418 if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK)
1419 printf("DONE\n"); 1419 printf("DONE\n");
1420 1420
1421 plist_free(send_file_node); 1421 plist_free(send_file_node);
1422 1422
1423 if (file_status == DEVICE_LINK_FILE_STATUS_NONE) 1423 if (file_status == DEVICE_LINK_FILE_STATUS_NONE)
1424 break; 1424 break;
1425 1425
@@ -1466,8 +1466,8 @@ files_out:
1466 tmp_node = plist_dict_get_item(node, "AppInfo"); 1466 tmp_node = plist_dict_get_item(node, "AppInfo");
1467 1467
1468 dict = plist_new_dict(); 1468 dict = plist_new_dict();
1469 plist_dict_insert_item(dict, "AppInfo", plist_copy(tmp_node)); 1469 plist_dict_set_item(dict, "AppInfo", plist_copy(tmp_node));
1470 plist_dict_insert_item(dict, "BackupMessageTypeKey", plist_new_string("BackupMessageRestoreApplicationSent")); 1470 plist_dict_set_item(dict, "BackupMessageTypeKey", plist_new_string("BackupMessageRestoreApplicationSent"));
1471 1471
1472 array = plist_new_array(); 1472 array = plist_new_array();
1473 plist_array_append_item(array, plist_new_string("DLMessageProcessMessage")); 1473 plist_array_append_item(array, plist_new_string("DLMessageProcessMessage"));
@@ -1540,9 +1540,9 @@ files_out:
1540 do_post_notification(NP_SYNC_DID_FINISH); 1540 do_post_notification(NP_SYNC_DID_FINISH);
1541 } 1541 }
1542 if (manifest_path) 1542 if (manifest_path)
1543 g_free(manifest_path); 1543 free(manifest_path);
1544 } else { 1544 } else {
1545 printf("ERROR: Could not start service %s.\n", MOBILEBACKUP_SERVICE_NAME); 1545 printf("ERROR: Could not start service %s: %s\n", MOBILEBACKUP_SERVICE_NAME, lockdownd_strerror(ldret));
1546 lockdownd_client_free(client); 1546 lockdownd_client_free(client);
1547 client = NULL; 1547 client = NULL;
1548 } 1548 }
@@ -1561,7 +1561,9 @@ files_out:
1561 if (mobilebackup) 1561 if (mobilebackup)
1562 mobilebackup_client_free(mobilebackup); 1562 mobilebackup_client_free(mobilebackup);
1563 1563
1564 idevice_free(phone); 1564 idevice_free(device);
1565
1566 free(udid);
1565 1567
1566 return 0; 1568 return 0;
1567} 1569}