summaryrefslogtreecommitdiffstats
path: root/tools/idevicebackup.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/idevicebackup.c')
-rw-r--r--tools/idevicebackup.c675
1 files changed, 344 insertions, 331 deletions
diff --git a/tools/idevicebackup.c b/tools/idevicebackup.c
index 867eaad..363abad 100644
--- a/tools/idevicebackup.c
+++ b/tools/idevicebackup.c
@@ -9,31 +9,42 @@
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>
38#include <sys/stat.h>
31 39
32#include <libimobiledevice/libimobiledevice.h> 40#include <libimobiledevice/libimobiledevice.h>
33#include <libimobiledevice/lockdown.h> 41#include <libimobiledevice/lockdown.h>
34#include <libimobiledevice/mobilebackup.h> 42#include <libimobiledevice/mobilebackup.h>
35#include <libimobiledevice/notification_proxy.h> 43#include <libimobiledevice/notification_proxy.h>
36#include <libimobiledevice/afc.h> 44#include <libimobiledevice/afc.h>
45#include <libimobiledevice-glue/sha.h>
46#include <libimobiledevice-glue/utils.h>
47#include <plist/plist.h>
37 48
38#define MOBILEBACKUP_SERVICE_NAME "com.apple.mobilebackup" 49#define MOBILEBACKUP_SERVICE_NAME "com.apple.mobilebackup"
39#define NP_SERVICE_NAME "com.apple.mobile.notification_proxy" 50#define NP_SERVICE_NAME "com.apple.mobile.notification_proxy"
@@ -41,9 +52,14 @@
41#define LOCK_ATTEMPTS 50 52#define LOCK_ATTEMPTS 50
42#define LOCK_WAIT 200000 53#define LOCK_WAIT 200000
43 54
55#ifdef _WIN32
56#include <windows.h>
57#define sleep(x) Sleep(x*1000)
58#endif
59
44static mobilebackup_client_t mobilebackup = NULL; 60static mobilebackup_client_t mobilebackup = NULL;
45static lockdownd_client_t client = NULL; 61static lockdownd_client_t client = NULL;
46static idevice_t phone = NULL; 62static idevice_t device = NULL;
47 63
48static int quit_flag = 0; 64static int quit_flag = 0;
49 65
@@ -53,22 +69,12 @@ enum cmd_mode {
53 CMD_LEAVE 69 CMD_LEAVE
54}; 70};
55 71
56enum plist_format_t {
57 PLIST_FORMAT_XML,
58 PLIST_FORMAT_BINARY
59};
60
61enum device_link_file_status_t { 72enum device_link_file_status_t {
62 DEVICE_LINK_FILE_STATUS_NONE = 0, 73 DEVICE_LINK_FILE_STATUS_NONE = 0,
63 DEVICE_LINK_FILE_STATUS_HUNK, 74 DEVICE_LINK_FILE_STATUS_HUNK,
64 DEVICE_LINK_FILE_STATUS_LAST_HUNK 75 DEVICE_LINK_FILE_STATUS_LAST_HUNK
65}; 76};
66 77
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) 78static int compare_hash(const unsigned char *hash1, const unsigned char *hash2, int hash_len)
73{ 79{
74 int i; 80 int i;
@@ -82,51 +88,47 @@ static int compare_hash(const unsigned char *hash1, const unsigned char *hash2,
82 88
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) 89static 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{ 90{
85 gcry_md_hd_t hd = NULL; 91 sha1_context sha1;
86 gcry_md_open(&hd, GCRY_MD_SHA1, 0); 92 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"); 93 FILE *f = fopen(path, "rb");
94 if (f) { 94 if (f) {
95 unsigned char buf[16384]; 95 unsigned char buf[16384];
96 size_t len; 96 size_t len;
97 while ((len = fread(buf, 1, 16384, f)) > 0) { 97 while ((len = fread(buf, 1, 16384, f)) > 0) {
98 gcry_md_write(hd, buf, len); 98 sha1_update(&sha1, buf, len);
99 } 99 }
100 fclose(f); 100 fclose(f);
101 gcry_md_write(hd, destpath, strlen(destpath)); 101 sha1_update(&sha1, destpath, strlen(destpath));
102 gcry_md_write(hd, ";", 1); 102 sha1_update(&sha1, ";", 1);
103
103 if (greylist == 1) { 104 if (greylist == 1) {
104 gcry_md_write(hd, "true", 4); 105 sha1_update(&sha1, "true", 4);
105 } else { 106 } else {
106 gcry_md_write(hd, "false", 5); 107 sha1_update(&sha1, "false", 5);
107 } 108 }
108 gcry_md_write(hd, ";", 1); 109 sha1_update(&sha1, ";", 1);
110
109 if (domain) { 111 if (domain) {
110 gcry_md_write(hd, domain, strlen(domain)); 112 sha1_update(&sha1, domain, strlen(domain));
111 } else { 113 } else {
112 gcry_md_write(hd, "(null)", 6); 114 sha1_update(&sha1, "(null)", 6);
113 } 115 }
114 gcry_md_write(hd, ";", 1); 116 sha1_update(&sha1, ";", 1);
117
115 if (appid) { 118 if (appid) {
116 gcry_md_write(hd, appid, strlen(appid)); 119 sha1_update(&sha1, appid, strlen(appid));
117 } else { 120 } else {
118 gcry_md_write(hd, "(null)", 6); 121 sha1_update(&sha1, "(null)", 6);
119 } 122 }
120 gcry_md_write(hd, ";", 1); 123 sha1_update(&sha1, ";", 1);
124
121 if (version) { 125 if (version) {
122 gcry_md_write(hd, version, strlen(version)); 126 sha1_update(&sha1, version, strlen(version));
123 } else { 127 } else {
124 gcry_md_write(hd, "(null)", 6); 128 sha1_update(&sha1, "(null)", 6);
125 } 129 }
126 unsigned char *newhash = gcry_md_read(hd, GCRY_MD_SHA1); 130 sha1_final(&sha1, hash_out);
127 memcpy(hash_out, newhash, 20);
128 } 131 }
129 gcry_md_close(hd);
130} 132}
131 133
132static void print_hash(const unsigned char *hash, int len) 134static void print_hash(const unsigned char *hash, int len)
@@ -147,14 +149,12 @@ static void notify_cb(const char *notification, void *userdata)
147 } 149 }
148} 150}
149 151
150static plist_t mobilebackup_factory_info_plist_new() 152static plist_t mobilebackup_factory_info_plist_new(const char* udid)
151{ 153{
152 /* gather data from lockdown */ 154 /* gather data from lockdown */
153 GTimeVal tv = {0, 0};
154 plist_t value_node = NULL; 155 plist_t value_node = NULL;
155 plist_t root_node = NULL; 156 plist_t root_node = NULL;
156 char *uuid = NULL; 157 char *udid_uppercase = NULL;
157 char *uuid_uppercase = NULL;
158 158
159 plist_t ret = plist_new_dict(); 159 plist_t ret = plist_new_dict();
160 160
@@ -163,45 +163,48 @@ static plist_t mobilebackup_factory_info_plist_new()
163 163
164 /* set fields we understand */ 164 /* set fields we understand */
165 value_node = plist_dict_get_item(root_node, "BuildVersion"); 165 value_node = plist_dict_get_item(root_node, "BuildVersion");
166 plist_dict_insert_item(ret, "Build Version", plist_copy(value_node)); 166 plist_dict_set_item(ret, "Build Version", plist_copy(value_node));
167 167
168 value_node = plist_dict_get_item(root_node, "DeviceName"); 168 value_node = plist_dict_get_item(root_node, "DeviceName");
169 plist_dict_insert_item(ret, "Device Name", plist_copy(value_node)); 169 plist_dict_set_item(ret, "Device Name", plist_copy(value_node));
170 plist_dict_insert_item(ret, "Display Name", plist_copy(value_node)); 170 plist_dict_set_item(ret, "Display Name", plist_copy(value_node));
171 171
172 /* FIXME: How is the GUID generated? */ 172 /* FIXME: How is the GUID generated? */
173 plist_dict_insert_item(ret, "GUID", plist_new_string("---")); 173 plist_dict_set_item(ret, "GUID", plist_new_string("---"));
174 174
175 value_node = plist_dict_get_item(root_node, "InternationalMobileEquipmentIdentity"); 175 value_node = plist_dict_get_item(root_node, "InternationalMobileEquipmentIdentity");
176 if (value_node) 176 if (value_node)
177 plist_dict_insert_item(ret, "IMEI", plist_copy(value_node)); 177 plist_dict_set_item(ret, "IMEI", plist_copy(value_node));
178 178
179 g_get_current_time(&tv); 179 plist_dict_set_item(ret, "Last Backup Date",
180 plist_dict_insert_item(ret, "Last Backup Date", plist_new_date(tv.tv_sec, tv.tv_usec)); 180#ifdef HAVE_PLIST_UNIX_DATE
181 plist_new_unix_date(time(NULL))
182#else
183 plist_new_date(time(NULL) - MAC_EPOCH, 0)
184#endif
185 );
181 186
182 value_node = plist_dict_get_item(root_node, "ProductType"); 187 value_node = plist_dict_get_item(root_node, "ProductType");
183 plist_dict_insert_item(ret, "Product Type", plist_copy(value_node)); 188 plist_dict_set_item(ret, "Product Type", plist_copy(value_node));
184 189
185 value_node = plist_dict_get_item(root_node, "ProductVersion"); 190 value_node = plist_dict_get_item(root_node, "ProductVersion");
186 plist_dict_insert_item(ret, "Product Version", plist_copy(value_node)); 191 plist_dict_set_item(ret, "Product Version", plist_copy(value_node));
187 192
188 value_node = plist_dict_get_item(root_node, "SerialNumber"); 193 value_node = plist_dict_get_item(root_node, "SerialNumber");
189 plist_dict_insert_item(ret, "Serial Number", plist_copy(value_node)); 194 plist_dict_set_item(ret, "Serial Number", plist_copy(value_node));
190 195
191 value_node = plist_dict_get_item(root_node, "UniqueDeviceID"); 196 value_node = plist_dict_get_item(root_node, "UniqueDeviceID");
192 idevice_get_uuid(phone, &uuid); 197 plist_dict_set_item(ret, "Target Identifier", plist_new_string(udid));
193 plist_dict_insert_item(ret, "Target Identifier", plist_new_string(uuid));
194 198
195 /* uppercase */ 199 /* uppercase */
196 uuid_uppercase = g_ascii_strup(uuid, -1); 200 udid_uppercase = string_toupper((char*)udid);
197 plist_dict_insert_item(ret, "Unique Identifier", plist_new_string(uuid_uppercase)); 201 plist_dict_set_item(ret, "Unique Identifier", plist_new_string(udid_uppercase));
198 free(uuid_uppercase); 202 free(udid_uppercase);
199 free(uuid);
200 203
201 /* FIXME: Embed files as <data> nodes */ 204 /* FIXME: Embed files as <data> nodes */
202 plist_t files = plist_new_dict(); 205 plist_t files = plist_new_dict();
203 plist_dict_insert_item(ret, "iTunes Files", files); 206 plist_dict_set_item(ret, "iTunes Files", files);
204 plist_dict_insert_item(ret, "iTunes Version", plist_new_string("9.0.2")); 207 plist_dict_set_item(ret, "iTunes Version", plist_new_string("9.0.2"));
205 208
206 plist_free(root_node); 209 plist_free(root_node);
207 210
@@ -210,102 +213,21 @@ static plist_t mobilebackup_factory_info_plist_new()
210 213
211static void mobilebackup_info_update_last_backup_date(plist_t info_plist) 214static void mobilebackup_info_update_last_backup_date(plist_t info_plist)
212{ 215{
213 GTimeVal tv = {0, 0};
214 plist_t node = NULL; 216 plist_t node = NULL;
215 217
216 if (!info_plist) 218 if (!info_plist)
217 return; 219 return;
218 220
219 g_get_current_time(&tv);
220 node = plist_dict_get_item(info_plist, "Last Backup Date"); 221 node = plist_dict_get_item(info_plist, "Last Backup Date");
221 plist_set_date_val(node, tv.tv_sec, tv.tv_usec); 222#ifdef HAVE_PLIST_UNIX_DATE
223 plist_set_unix_date_val(node, time(NULL));
224#else
225 plist_set_date_val(node, time(NULL) - MAC_EPOCH, 0);
226#endif
222 227
223 node = NULL; 228 node = NULL;
224} 229}
225 230
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) 231static int plist_strcmp(plist_t node, const char *str)
310{ 232{
311 char *buffer = NULL; 233 char *buffer = NULL;
@@ -321,11 +243,14 @@ static int plist_strcmp(plist_t node, const char *str)
321 return ret; 243 return ret;
322} 244}
323 245
324static gchar *mobilebackup_build_path(const char *backup_directory, const char *name, const char *extension) 246static char *mobilebackup_build_path(const char *backup_directory, const char *name, const char *extension)
325{ 247{
326 gchar *filename = g_strconcat(name, extension, NULL); 248 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); 249 strcpy(filename, name);
328 g_free(filename); 250 if (extension != NULL)
251 strcat(filename, extension);
252 char *path = string_build_path(backup_directory, filename, NULL);
253 free(filename);
329 return path; 254 return path;
330} 255}
331 256
@@ -333,28 +258,28 @@ static void mobilebackup_write_status(const char *path, int status)
333{ 258{
334 struct stat st; 259 struct stat st;
335 plist_t status_plist = plist_new_dict(); 260 plist_t status_plist = plist_new_dict();
336 plist_dict_insert_item(status_plist, "Backup Success", plist_new_bool(status)); 261 plist_dict_set_item(status_plist, "Backup Success", plist_new_bool(status));
337 gchar *file_path = mobilebackup_build_path(path, "Status", ".plist"); 262 char *file_path = mobilebackup_build_path(path, "Status", ".plist");
338 263
339 if (stat(file_path, &st) == 0) 264 if (stat(file_path, &st) == 0)
340 remove(file_path); 265 remove(file_path);
341 266
342 plist_write_to_filename(status_plist, file_path, PLIST_FORMAT_XML); 267 plist_write_to_file(status_plist, file_path, PLIST_FORMAT_XML, 0);
343 268
344 plist_free(status_plist); 269 plist_free(status_plist);
345 status_plist = NULL; 270 status_plist = NULL;
346 271
347 g_free(file_path); 272 free(file_path);
348} 273}
349 274
350static int mobilebackup_read_status(const char *path) 275static int mobilebackup_read_status(const char *path)
351{ 276{
352 int ret = -1; 277 int ret = -1;
353 plist_t status_plist = NULL; 278 plist_t status_plist = NULL;
354 gchar *file_path = mobilebackup_build_path(path, "Status", ".plist"); 279 char *file_path = mobilebackup_build_path(path, "Status", ".plist");
355 280
356 plist_read_from_filename(&status_plist, file_path); 281 plist_read_from_file(file_path, &status_plist, NULL);
357 g_free(file_path); 282 free(file_path);
358 if (!status_plist) { 283 if (!status_plist) {
359 printf("Could not read Status.plist!\n"); 284 printf("Could not read Status.plist!\n");
360 return ret; 285 return ret;
@@ -387,7 +312,7 @@ static int mobilebackup_info_is_current_device(plist_t info)
387 /* get basic device information in one go */ 312 /* get basic device information in one go */
388 lockdownd_get_value(client, NULL, NULL, &root_node); 313 lockdownd_get_value(client, NULL, NULL, &root_node);
389 314
390 /* verify UUID */ 315 /* verify UDID */
391 value_node = plist_dict_get_item(root_node, "UniqueDeviceID"); 316 value_node = plist_dict_get_item(root_node, "UniqueDeviceID");
392 node = plist_dict_get_item(info, "Target Identifier"); 317 node = plist_dict_get_item(info, "Target Identifier");
393 318
@@ -435,14 +360,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) 360static int mobilebackup_delete_backup_file_by_hash(const char *backup_directory, const char *hash)
436{ 361{
437 int ret = 0; 362 int ret = 0;
438 gchar *path = mobilebackup_build_path(backup_directory, hash, ".mddata"); 363 char *path = mobilebackup_build_path(backup_directory, hash, ".mddata");
439 printf("Removing \"%s\" ", path); 364 printf("Removing \"%s\" ", path);
440 if (!remove( path )) 365 if (!remove( path ))
441 ret = 1; 366 ret = 1;
442 else 367 else
443 ret = 0; 368 ret = 0;
444 369
445 g_free(path); 370 free(path);
446 371
447 if (!ret) 372 if (!ret)
448 return ret; 373 return ret;
@@ -454,7 +379,7 @@ static int mobilebackup_delete_backup_file_by_hash(const char *backup_directory,
454 else 379 else
455 ret = 0; 380 ret = 0;
456 381
457 g_free(path); 382 free(path);
458 383
459 return ret; 384 return ret;
460} 385}
@@ -476,7 +401,7 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const
476 } 401 }
477 402
478 infopath = mobilebackup_build_path(backup_directory, hash, ".mdinfo"); 403 infopath = mobilebackup_build_path(backup_directory, hash, ".mdinfo");
479 plist_read_from_filename(&mdinfo, infopath); 404 plist_read_from_file(infopath, &mdinfo, NULL);
480 free(infopath); 405 free(infopath);
481 if (!mdinfo) { 406 if (!mdinfo) {
482 printf("\r\n"); 407 printf("\r\n");
@@ -521,13 +446,13 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const
521 446
522 char *version = NULL; 447 char *version = NULL;
523 node = plist_dict_get_item(metadata, "Version"); 448 node = plist_dict_get_item(metadata, "Version");
524 if (node && (plist_get_node_type(node) == PLIST_STRING)) { 449 if (node && (plist_get_node_type(node) == PLIST_STRING)) {
525 plist_get_string_val(node, &version); 450 plist_get_string_val(node, &version);
526 } 451 }
527 452
528 char *destpath = NULL; 453 char *destpath = NULL;
529 node = plist_dict_get_item(metadata, "Path"); 454 node = plist_dict_get_item(metadata, "Path");
530 if (node && (plist_get_node_type(node) == PLIST_STRING)) { 455 if (node && (plist_get_node_type(node) == PLIST_STRING)) {
531 plist_get_string_val(node, &destpath); 456 plist_get_string_val(node, &destpath);
532 } 457 }
533 458
@@ -539,7 +464,7 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const
539 464
540 char *domain = NULL; 465 char *domain = NULL;
541 node = plist_dict_get_item(metadata, "Domain"); 466 node = plist_dict_get_item(metadata, "Domain");
542 if (node && (plist_get_node_type(node) == PLIST_STRING)) { 467 if (node && (plist_get_node_type(node) == PLIST_STRING)) {
543 plist_get_string_val(node, &domain); 468 plist_get_string_val(node, &domain);
544 } 469 }
545 470
@@ -550,14 +475,14 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const
550 unsigned char fnhash[20]; 475 unsigned char fnhash[20];
551 char fnamehash[41]; 476 char fnamehash[41];
552 char *p = fnamehash; 477 char *p = fnamehash;
553 sha1_of_data(fnstr, strlen(fnstr), fnhash); 478 sha1((const unsigned char*)fnstr, strlen(fnstr), fnhash);
554 free(fnstr); 479 free(fnstr);
555 int i; 480 int i;
556 for ( i = 0; i < 20; i++, p += 2 ) { 481 for ( i = 0; i < 20; i++, p += 2 ) {
557 snprintf (p, 3, "%02x", (unsigned char)fnhash[i] ); 482 snprintf (p, 3, "%02x", (unsigned char)fnhash[i] );
558 } 483 }
559 if (strcmp(fnamehash, hash)) { 484 if (strcmp(fnamehash, hash) != 0) {
560 printf("\r\n"); 485 printf("\r\n");
561 printf("WARNING: filename hash does not match for entry '%s'\n", hash); 486 printf("WARNING: filename hash does not match for entry '%s'\n", hash);
562 } 487 }
563 488
@@ -567,7 +492,7 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const
567 plist_get_string_val(node, &auth_version); 492 plist_get_string_val(node, &auth_version);
568 } 493 }
569 494
570 if (strcmp(auth_version, "1.0")) { 495 if (strcmp(auth_version, "1.0") != 0) {
571 printf("\r\n"); 496 printf("\r\n");
572 printf("WARNING: Unknown AuthVersion '%s', DataHash cannot be verified!\n", auth_version); 497 printf("WARNING: Unknown AuthVersion '%s', DataHash cannot be verified!\n", auth_version);
573 } 498 }
@@ -591,9 +516,9 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const
591 hash_ok = 1; 516 hash_ok = 1;
592 } 517 }
593 518
594 g_free(domain); 519 free(domain);
595 g_free(version); 520 free(version);
596 g_free(destpath); 521 free(destpath);
597 522
598 if (!hash_ok) { 523 if (!hash_ok) {
599 printf("\r\n"); 524 printf("\r\n");
@@ -605,31 +530,36 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const
605 printf("\n"); 530 printf("\n");
606 res = 0; 531 res = 0;
607 } 532 }
608 g_free(data_hash); 533 free(data_hash);
609 plist_free(mdinfo); 534 plist_free(mdinfo);
610 return res; 535 return res;
611} 536}
612 537
613static void do_post_notification(const char *notification) 538static void do_post_notification(const char *notification)
614{ 539{
615 uint16_t nport = 0; 540 lockdownd_service_descriptor_t service = NULL;
616 np_client_t np; 541 np_client_t np;
617 542
618 if (!client) { 543 if (!client) {
619 if (lockdownd_client_new_with_handshake(phone, &client, "idevicebackup") != LOCKDOWN_E_SUCCESS) { 544 if (lockdownd_client_new_with_handshake(device, &client, TOOL_NAME) != LOCKDOWN_E_SUCCESS) {
620 return; 545 return;
621 } 546 }
622 } 547 }
623 548
624 lockdownd_start_service(client, NP_SERVICE_NAME, &nport); 549 lockdownd_error_t ldret = lockdownd_start_service(client, NP_SERVICE_NAME, &service);
625 if (nport) { 550 if (ldret == LOCKDOWN_E_SUCCESS) {
626 np_client_new(phone, nport, &np); 551 np_client_new(device, service, &np);
627 if (np) { 552 if (np) {
628 np_post_notification(np, notification); 553 np_post_notification(np, notification);
629 np_client_free(np); 554 np_client_free(np);
630 } 555 }
631 } else { 556 } else {
632 printf("Could not start %s\n", NP_SERVICE_NAME); 557 printf("Could not start %s: %s\n", NP_SERVICE_NAME, lockdownd_strerror(ldret));
558 }
559
560 if (service) {
561 lockdownd_service_descriptor_free(service);
562 service = NULL;
633 } 563 }
634} 564}
635 565
@@ -665,29 +595,38 @@ static void clean_exit(int sig)
665 quit_flag++; 595 quit_flag++;
666} 596}
667 597
668static void print_usage(int argc, char **argv) 598static void print_usage(int argc, char **argv, int is_error)
669{ 599{
670 char *name = NULL; 600 char *name = strrchr(argv[0], '/');
671 name = strrchr(argv[0], '/'); 601 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])); 602 fprintf(is_error ? stderr : stdout,
673 printf("Create or restore backup from the current or specified directory.\n\n"); 603 "\n"
674 printf("commands:\n"); 604 "Create or restore backup in/from the specified directory.\n"
675 printf(" backup\tSaves a device backup into DIRECTORY\n"); 605 "\n"
676 printf(" restore\tRestores a device backup from DIRECTORY.\n\n"); 606 "CMD:\n"
677 printf("options:\n"); 607 " backup Saves a device backup into DIRECTORY\n"
678 printf(" -d, --debug\t\tenable communication debugging\n"); 608 " restore Restores a device backup from DIRECTORY.\n"
679 printf(" -u, --uuid UUID\ttarget specific device by its 40-digit device UUID\n"); 609 "\n"
680 printf(" -h, --help\t\tprints usage information\n"); 610 "OPTIONS:\n"
681 printf("\n"); 611 " -u, --udid UDID target specific device by UDID\n"
612 " -n, --network connect to network device\n"
613 " -d, --debug enable communication debugging\n"
614 " -h, --help prints usage information\n"
615 " -v, --version prints version information\n"
616 "\n"
617 "Homepage: <" PACKAGE_URL ">\n"
618 "Bug Reports: <" PACKAGE_BUGREPORT ">\n"
619 );
682} 620}
683 621
684int main(int argc, char *argv[]) 622int main(int argc, char *argv[])
685{ 623{
686 idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; 624 idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
625 lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR;
687 int i; 626 int i;
688 char uuid[41]; 627 char* udid = NULL;
689 uint16_t port = 0; 628 int use_network = 0;
690 uuid[0] = 0; 629 lockdownd_service_descriptor_t service = NULL;
691 int cmd = -1; 630 int cmd = -1;
692 int is_full_backup = 0; 631 int is_full_backup = 0;
693 char *backup_directory = NULL; 632 char *backup_directory = NULL;
@@ -701,60 +640,77 @@ int main(int argc, char *argv[])
701 uint64_t length = 0; 640 uint64_t length = 0;
702 uint64_t backup_total_size = 0; 641 uint64_t backup_total_size = 0;
703 enum device_link_file_status_t file_status = DEVICE_LINK_FILE_STATUS_NONE; 642 enum device_link_file_status_t file_status = DEVICE_LINK_FILE_STATUS_NONE;
704 uint64_t c = 0; 643 int c = 0;
644 const struct option longopts[] = {
645 { "debug", no_argument, NULL, 'd' },
646 { "help", no_argument, NULL, 'h' },
647 { "udid", required_argument, NULL, 'u' },
648 { "network", no_argument, NULL, 'n' },
649 { "version", no_argument, NULL, 'v' },
650 { NULL, 0, NULL, 0}
651 };
705 652
706 /* we need to exit cleanly on running backups and restores or we cause havok */ 653 /* we need to exit cleanly on running backups and restores or we cause havok */
707 signal(SIGINT, clean_exit); 654 signal(SIGINT, clean_exit);
708 signal(SIGQUIT, clean_exit);
709 signal(SIGTERM, clean_exit); 655 signal(SIGTERM, clean_exit);
656#ifndef _WIN32
657 signal(SIGQUIT, clean_exit);
710 signal(SIGPIPE, SIG_IGN); 658 signal(SIGPIPE, SIG_IGN);
659#endif
711 660
712 /* parse cmdline args */ 661 /* parse cmdline args */
713 for (i = 1; i < argc; i++) { 662 while ((c = getopt_long(argc, argv, "dhu:nv", longopts, NULL)) != -1) {
714 if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { 663 switch (c) {
664 case 'd':
715 idevice_set_debug_level(1); 665 idevice_set_debug_level(1);
716 continue; 666 break;
717 } 667 case 'u':
718 else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--uuid")) { 668 if (!*optarg) {
719 i++; 669 fprintf(stderr, "ERROR: UDID must not be empty!\n");
720 if (!argv[i] || (strlen(argv[i]) != 40)) { 670 print_usage(argc, argv, 1);
721 print_usage(argc, argv); 671 return 2;
722 return 0;
723 } 672 }
724 strcpy(uuid, argv[i]); 673 udid = strdup(optarg);
725 continue; 674 break;
726 } 675 case 'n':
727 else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { 676 use_network = 1;
728 print_usage(argc, argv); 677 break;
678 case 'h':
679 print_usage(argc, argv, 0);
729 return 0; 680 return 0;
730 } 681 case 'v':
731 else if (!strcmp(argv[i], "backup")) { 682 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; 683 return 0;
684 default:
685 print_usage(argc, argv, 1);
686 return 2;
743 } 687 }
744 } 688 }
689 argc -= optind;
690 argv += optind;
745 691
746 /* verify options */ 692 if (argc < 1) {
747 if (cmd == -1) { 693 fprintf(stderr, "ERROR: Missing command.\n");
748 printf("No command specified.\n"); 694 print_usage(argc+optind, argv-optind, 1);
749 print_usage(argc, argv); 695 return 2;
750 return -1;
751 } 696 }
752 697
753 if (backup_directory == NULL) { 698 if (!strcmp(argv[0], "backup")) {
754 printf("No target backup directory specified.\n"); 699 cmd = CMD_BACKUP;
755 print_usage(argc, argv); 700 } else if (!strcmp(argv[0], "restore")) {
756 return -1; 701 cmd = CMD_RESTORE;
702 } else {
703 fprintf(stderr, "ERROR: Invalid command '%s'.\n", argv[0]);
704 print_usage(argc+optind, argv-optind, 1);
705 return 2;
706 }
707
708 if (argc < 2) {
709 fprintf(stderr, "No target backup directory specified.\n");
710 print_usage(argc+optind, argv-optind, 1);
711 return 2;
757 } 712 }
713 backup_directory = argv[1];
758 714
759 /* verify if passed backup directory exists */ 715 /* verify if passed backup directory exists */
760 if (stat(backup_directory, &st) != 0) { 716 if (stat(backup_directory, &st) != 0) {
@@ -766,7 +722,7 @@ int main(int argc, char *argv[])
766 char *info_path = mobilebackup_build_path(backup_directory, "Info", ".plist"); 722 char *info_path = mobilebackup_build_path(backup_directory, "Info", ".plist");
767 if (cmd == CMD_RESTORE) { 723 if (cmd == CMD_RESTORE) {
768 if (stat(info_path, &st) != 0) { 724 if (stat(info_path, &st) != 0) {
769 g_free(info_path); 725 free(info_path);
770 printf("ERROR: Backup directory \"%s\" is invalid. No Info.plist found.\n", backup_directory); 726 printf("ERROR: Backup directory \"%s\" is invalid. No Info.plist found.\n", backup_directory);
771 return -1; 727 return -1;
772 } 728 }
@@ -774,32 +730,54 @@ int main(int argc, char *argv[])
774 730
775 printf("Backup directory is \"%s\"\n", backup_directory); 731 printf("Backup directory is \"%s\"\n", backup_directory);
776 732
777 if (uuid[0] != 0) { 733 ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX);
778 ret = idevice_new(&phone, uuid); 734 if (ret != IDEVICE_E_SUCCESS) {
779 if (ret != IDEVICE_E_SUCCESS) { 735 if (udid) {
780 printf("No device found with uuid %s, is it plugged in?\n", uuid); 736 printf("No device found with udid %s.\n", udid);
781 return -1; 737 } else {
738 printf("No device found.\n");
782 } 739 }
740 return -1;
783 } 741 }
784 else 742
785 { 743 if (!udid) {
786 ret = idevice_new(&phone, NULL); 744 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 } 745 }
792 746
793 if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(phone, &client, "idevicebackup")) { 747 if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &client, TOOL_NAME))) {
794 idevice_free(phone); 748 printf("ERROR: Could not connect to lockdownd, error code %d\n", ldret);
749 idevice_free(device);
750 free(udid);
795 return -1; 751 return -1;
796 } 752 }
797 753
754 node = NULL;
755 lockdownd_get_value(client, NULL, "ProductVersion", &node);
756 if (node) {
757 char* str = NULL;
758 if (plist_get_node_type(node) == PLIST_STRING) {
759 plist_get_string_val(node, &str);
760 }
761 plist_free(node);
762 node = NULL;
763 if (str) {
764 int maj = strtol(str, NULL, 10);
765 free(str);
766 if (maj > 3) {
767 printf("ERROR: This tool is only compatible with iOS 3 or below. For newer iOS versions please use the idevicebackup2 tool.\n");
768 lockdownd_client_free(client);
769 idevice_free(device);
770 free(udid);
771 return -1;
772 }
773 }
774 }
775
798 /* start notification_proxy */ 776 /* start notification_proxy */
799 np_client_t np = NULL; 777 np_client_t np = NULL;
800 ret = lockdownd_start_service(client, NP_SERVICE_NAME, &port); 778 ldret = lockdownd_start_service(client, NP_SERVICE_NAME, &service);
801 if ((ret == LOCKDOWN_E_SUCCESS) && port) { 779 if ((ldret == LOCKDOWN_E_SUCCESS) && service && service->port) {
802 np_client_new(phone, port, &np); 780 np_client_new(device, service, &np);
803 np_set_notify_callback(np, notify_cb, NULL); 781 np_set_notify_callback(np, notify_cb, NULL);
804 const char *noties[5] = { 782 const char *noties[5] = {
805 NP_SYNC_CANCEL_REQUEST, 783 NP_SYNC_CANCEL_REQUEST,
@@ -810,25 +788,37 @@ int main(int argc, char *argv[])
810 }; 788 };
811 np_observe_notifications(np, noties); 789 np_observe_notifications(np, noties);
812 } else { 790 } else {
813 printf("ERROR: Could not start service %s.\n", NP_SERVICE_NAME); 791 printf("ERROR: Could not start service %s: %s\n", NP_SERVICE_NAME, lockdownd_strerror(ldret));
814 } 792 }
815 793
816 afc_client_t afc = NULL; 794 afc_client_t afc = NULL;
817 if (cmd == CMD_BACKUP) { 795 if (cmd == CMD_BACKUP) {
818 /* start AFC, we need this for the lock file */ 796 /* start AFC, we need this for the lock file */
819 port = 0; 797 service->port = 0;
820 ret = lockdownd_start_service(client, "com.apple.afc", &port); 798 service->ssl_enabled = 0;
821 if ((ret == LOCKDOWN_E_SUCCESS) && port) { 799 ldret = lockdownd_start_service(client, AFC_SERVICE_NAME, &service);
822 afc_client_new(phone, port, &afc); 800 if ((ldret == LOCKDOWN_E_SUCCESS) && service->port) {
801 afc_client_new(device, service, &afc);
802 } else {
803 printf("ERROR: Could not start service %s: %s\n", AFC_SERVICE_NAME, lockdownd_strerror(ldret));
823 } 804 }
824 } 805 }
825 806
807 if (service) {
808 lockdownd_service_descriptor_free(service);
809 service = NULL;
810 }
811
826 /* start mobilebackup service and retrieve port */ 812 /* start mobilebackup service and retrieve port */
827 port = 0; 813 ldret = lockdownd_start_service(client, MOBILEBACKUP_SERVICE_NAME, &service);
828 ret = lockdownd_start_service(client, MOBILEBACKUP_SERVICE_NAME, &port); 814 if ((ldret == LOCKDOWN_E_SUCCESS) && service && service->port) {
829 if ((ret == LOCKDOWN_E_SUCCESS) && port) { 815 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); 816 printf("%d\n", mobilebackup_client_new(device, service, &mobilebackup));
831 mobilebackup_client_new(phone, port, &mobilebackup); 817
818 if (service) {
819 lockdownd_service_descriptor_free(service);
820 service = NULL;
821 }
832 822
833 /* check abort conditions */ 823 /* check abort conditions */
834 if (quit_flag > 0) { 824 if (quit_flag > 0) {
@@ -839,7 +829,7 @@ int main(int argc, char *argv[])
839 /* verify existing Info.plist */ 829 /* verify existing Info.plist */
840 if (stat(info_path, &st) == 0) { 830 if (stat(info_path, &st) == 0) {
841 printf("Reading Info.plist from backup.\n"); 831 printf("Reading Info.plist from backup.\n");
842 plist_read_from_filename(&info_plist, info_path); 832 plist_read_from_file(info_path, &info_plist, NULL);
843 833
844 if (!info_plist) { 834 if (!info_plist) {
845 printf("Could not read Info.plist\n"); 835 printf("Could not read Info.plist\n");
@@ -850,7 +840,7 @@ int main(int argc, char *argv[])
850 /* update the last backup time within Info.plist */ 840 /* update the last backup time within Info.plist */
851 mobilebackup_info_update_last_backup_date(info_plist); 841 mobilebackup_info_update_last_backup_date(info_plist);
852 remove(info_path); 842 remove(info_path);
853 plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML); 843 plist_write_to_file(info_plist, info_path, PLIST_FORMAT_XML, 0);
854 } else { 844 } else {
855 printf("Aborting backup. Backup is not compatible with the current device.\n"); 845 printf("Aborting backup. Backup is not compatible with the current device.\n");
856 cmd = CMD_LEAVE; 846 cmd = CMD_LEAVE;
@@ -883,15 +873,16 @@ int main(int argc, char *argv[])
883 if (aerr == AFC_E_SUCCESS) { 873 if (aerr == AFC_E_SUCCESS) {
884 do_post_notification(NP_SYNC_DID_START); 874 do_post_notification(NP_SYNC_DID_START);
885 break; 875 break;
886 } else if (aerr == AFC_E_OP_WOULD_BLOCK) { 876 }
877 if (aerr == AFC_E_OP_WOULD_BLOCK) {
887 usleep(LOCK_WAIT); 878 usleep(LOCK_WAIT);
888 continue; 879 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 } 880 }
881
882 fprintf(stderr, "ERROR: could not lock file! error code: %d\n", aerr);
883 afc_file_close(afc, lockfile);
884 lockfile = 0;
885 cmd = CMD_LEAVE;
895 } 886 }
896 if (i == LOCK_ATTEMPTS) { 887 if (i == LOCK_ATTEMPTS) {
897 fprintf(stderr, "ERROR: timeout while locking for sync\n"); 888 fprintf(stderr, "ERROR: timeout while locking for sync\n");
@@ -910,12 +901,12 @@ int main(int argc, char *argv[])
910 case CMD_BACKUP: 901 case CMD_BACKUP:
911 printf("Starting backup...\n"); 902 printf("Starting backup...\n");
912 /* TODO: check domain com.apple.mobile.backup key RequiresEncrypt and WillEncrypt with lockdown */ 903 /* TODO: check domain com.apple.mobile.backup key RequiresEncrypt and WillEncrypt with lockdown */
913 /* TODO: verify battery on AC enough battery remaining */ 904 /* TODO: verify battery on AC enough battery remaining */
914 905
915 /* read the last Manifest.plist */ 906 /* read the last Manifest.plist */
916 if (!is_full_backup) { 907 if (!is_full_backup) {
917 printf("Reading existing Manifest.\n"); 908 printf("Reading existing Manifest.\n");
918 plist_read_from_filename(&manifest_plist, manifest_path); 909 plist_read_from_file(manifest_path, &manifest_plist, NULL);
919 if (!manifest_plist) { 910 if (!manifest_plist) {
920 printf("Could not read Manifest.plist, switching to full backup mode.\n"); 911 printf("Could not read Manifest.plist, switching to full backup mode.\n");
921 is_full_backup = 1; 912 is_full_backup = 1;
@@ -932,10 +923,10 @@ int main(int argc, char *argv[])
932 } 923 }
933 remove(info_path); 924 remove(info_path);
934 printf("Creating Info.plist for new backup.\n"); 925 printf("Creating Info.plist for new backup.\n");
935 info_plist = mobilebackup_factory_info_plist_new(); 926 info_plist = mobilebackup_factory_info_plist_new(udid);
936 plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML); 927 plist_write_to_file(info_plist, info_path, PLIST_FORMAT_XML, 0);
937 } 928 }
938 g_free(info_path); 929 free(info_path);
939 930
940 plist_free(info_plist); 931 plist_free(info_plist);
941 info_plist = NULL; 932 info_plist = NULL;
@@ -965,7 +956,7 @@ int main(int argc, char *argv[])
965 } else if (err == MOBILEBACKUP_E_REPLY_NOT_OK) { 956 } else if (err == MOBILEBACKUP_E_REPLY_NOT_OK) {
966 printf("ERROR: Could not start backup process: device refused to start the backup process.\n"); 957 printf("ERROR: Could not start backup process: device refused to start the backup process.\n");
967 } else { 958 } else {
968 printf("ERROR: Could not start backup process: unspecified error occured\n"); 959 printf("ERROR: Could not start backup process: unspecified error occurred (%d)\n", err);
969 } 960 }
970 break; 961 break;
971 } 962 }
@@ -985,8 +976,9 @@ int main(int argc, char *argv[])
985 char *filename_mddata = NULL; 976 char *filename_mddata = NULL;
986 char *filename_source = NULL; 977 char *filename_source = NULL;
987 char *format_size = NULL; 978 char *format_size = NULL;
988 gboolean is_manifest = FALSE; 979 int is_manifest = 0;
989 uint8_t b = 0; 980 uint8_t b = 0;
981 uint64_t u64val = 0;
990 982
991 /* process series of DLSendFile messages */ 983 /* process series of DLSendFile messages */
992 do { 984 do {
@@ -996,7 +988,7 @@ int main(int argc, char *argv[])
996 sleep(2); 988 sleep(2);
997 goto files_out; 989 goto files_out;
998 } 990 }
999 991
1000 node = plist_array_get_item(message, 0); 992 node = plist_array_get_item(message, 0);
1001 993
1002 /* get out if we don't get a DLSendFile */ 994 /* get out if we don't get a DLSendFile */
@@ -1010,16 +1002,16 @@ int main(int argc, char *argv[])
1010 node = plist_dict_get_item(node_tmp, "BackupTotalSizeKey"); 1002 node = plist_dict_get_item(node_tmp, "BackupTotalSizeKey");
1011 if (node) { 1003 if (node) {
1012 plist_get_uint_val(node, &backup_total_size); 1004 plist_get_uint_val(node, &backup_total_size);
1013 format_size = g_format_size_for_display(backup_total_size); 1005 format_size = string_format_size(backup_total_size);
1014 printf("Backup data requires %s on the disk.\n", format_size); 1006 printf("Backup data requires %s on the disk.\n", format_size);
1015 g_free(format_size); 1007 free(format_size);
1016 } 1008 }
1017 } 1009 }
1018 1010
1019 /* check DLFileStatusKey (codes: 1 = Hunk, 2 = Last Hunk) */ 1011 /* check DLFileStatusKey (codes: 1 = Hunk, 2 = Last Hunk) */
1020 node = plist_dict_get_item(node_tmp, "DLFileStatusKey"); 1012 node = plist_dict_get_item(node_tmp, "DLFileStatusKey");
1021 plist_get_uint_val(node, &c); 1013 plist_get_uint_val(node, &u64val);
1022 file_status = c; 1014 file_status = u64val;
1023 1015
1024 /* get source filename */ 1016 /* get source filename */
1025 node = plist_dict_get_item(node_tmp, "BackupManifestKey"); 1017 node = plist_dict_get_item(node_tmp, "BackupManifestKey");
@@ -1027,7 +1019,7 @@ int main(int argc, char *argv[])
1027 if (node) { 1019 if (node) {
1028 plist_get_bool_val(node, &b); 1020 plist_get_bool_val(node, &b);
1029 } 1021 }
1030 is_manifest = (b == 1) ? TRUE: FALSE; 1022 is_manifest = (b == 1) ? 1 : 0;
1031 1023
1032 if ((hunk_index == 0) && (!is_manifest)) { 1024 if ((hunk_index == 0) && (!is_manifest)) {
1033 /* get source filename */ 1025 /* get source filename */
@@ -1040,17 +1032,17 @@ int main(int argc, char *argv[])
1040 plist_get_uint_val(node, &file_size); 1032 plist_get_uint_val(node, &file_size);
1041 backup_real_size += file_size; 1033 backup_real_size += file_size;
1042 1034
1043 format_size = g_format_size_for_display(backup_real_size); 1035 format_size = string_format_size(backup_real_size);
1044 printf("(%s", format_size); 1036 printf("(%s", format_size);
1045 g_free(format_size); 1037 free(format_size);
1046 1038
1047 format_size = g_format_size_for_display(backup_total_size); 1039 format_size = string_format_size(backup_total_size);
1048 printf("/%s): ", format_size); 1040 printf("/%s): ", format_size);
1049 g_free(format_size); 1041 free(format_size);
1050 1042
1051 format_size = g_format_size_for_display(file_size); 1043 format_size = string_format_size(file_size);
1052 printf("Receiving file %s (%s)... \n", filename_source, format_size); 1044 printf("Receiving file %s (%s)... \n", filename_source, format_size);
1053 g_free(format_size); 1045 free(format_size);
1054 1046
1055 if (filename_source) 1047 if (filename_source)
1056 free(filename_source); 1048 free(filename_source);
@@ -1071,9 +1063,9 @@ int main(int argc, char *argv[])
1071 remove(filename_mdinfo); 1063 remove(filename_mdinfo);
1072 1064
1073 node = plist_dict_get_item(node_tmp, "BackupFileInfo"); 1065 node = plist_dict_get_item(node_tmp, "BackupFileInfo");
1074 plist_write_to_filename(node, filename_mdinfo, PLIST_FORMAT_BINARY); 1066 plist_write_to_file(node, filename_mdinfo, PLIST_FORMAT_BINARY, 0);
1075 1067
1076 g_free(filename_mdinfo); 1068 free(filename_mdinfo);
1077 } 1069 }
1078 1070
1079 file_index++; 1071 file_index++;
@@ -1107,15 +1099,14 @@ int main(int argc, char *argv[])
1107 free(buffer); 1099 free(buffer);
1108 buffer = NULL; 1100 buffer = NULL;
1109 1101
1110 g_free(filename_mddata); 1102 free(filename_mddata);
1111 } 1103 }
1112 1104
1113 if ((!is_manifest)) { 1105 if ((!is_manifest)) {
1114 if (hunk_index == 0 && file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) { 1106 if (hunk_index == 0 && file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) {
1115 print_progress(100); 1107 print_progress(100);
1116 } else { 1108 } else if (file_size > 0) {
1117 if (file_size > 0) 1109 print_progress((double)(file_size_current*100)/file_size);
1118 print_progress((double)((file_size_current*100)/file_size));
1119 } 1110 }
1120 } 1111 }
1121 1112
@@ -1145,7 +1136,7 @@ files_out:
1145 1136
1146 /* remove any atomic Manifest.plist.tmp */ 1137 /* remove any atomic Manifest.plist.tmp */
1147 if (manifest_path) 1138 if (manifest_path)
1148 g_free(manifest_path); 1139 free(manifest_path);
1149 1140
1150 manifest_path = mobilebackup_build_path(backup_directory, "Manifest", ".plist.tmp"); 1141 manifest_path = mobilebackup_build_path(backup_directory, "Manifest", ".plist.tmp");
1151 if (stat(manifest_path, &st) == 0) 1142 if (stat(manifest_path, &st) == 0)
@@ -1184,7 +1175,7 @@ files_out:
1184 if (manifest_plist) { 1175 if (manifest_plist) {
1185 remove(manifest_path); 1176 remove(manifest_path);
1186 printf("Storing Manifest.plist...\n"); 1177 printf("Storing Manifest.plist...\n");
1187 plist_write_to_filename(manifest_plist, manifest_path, PLIST_FORMAT_XML); 1178 plist_write_to_file(manifest_plist, manifest_path, PLIST_FORMAT_XML, 0);
1188 } 1179 }
1189 1180
1190 backup_ok = 1; 1181 backup_ok = 1;
@@ -1215,21 +1206,21 @@ files_out:
1215 } 1206 }
1216 /* now make sure backup integrity is ok! verify all files */ 1207 /* now make sure backup integrity is ok! verify all files */
1217 printf("Reading existing Manifest.\n"); 1208 printf("Reading existing Manifest.\n");
1218 plist_read_from_filename(&manifest_plist, manifest_path); 1209 plist_read_from_file(manifest_path, &manifest_plist, NULL);
1219 if (!manifest_plist) { 1210 if (!manifest_plist) {
1220 printf("Could not read Manifest.plist. Aborting.\n"); 1211 printf("Could not read Manifest.plist. Aborting.\n");
1221 break; 1212 break;
1222 } 1213 }
1223 1214
1224 printf("Verifying backup integrity, please wait.\n"); 1215 printf("Verifying backup integrity, please wait.\n");
1225 char *bin = NULL; 1216 unsigned char *bin = NULL;
1226 uint64_t binsize = 0; 1217 uint64_t binsize = 0;
1227 node = plist_dict_get_item(manifest_plist, "Data"); 1218 node = plist_dict_get_item(manifest_plist, "Data");
1228 if (!node || (plist_get_node_type(node) != PLIST_DATA)) { 1219 if (!node || (plist_get_node_type(node) != PLIST_DATA)) {
1229 printf("Could not read Data key from Manifest.plist!\n"); 1220 printf("Could not read Data key from Manifest.plist!\n");
1230 break; 1221 break;
1231 } 1222 }
1232 plist_get_data_val(node, &bin, &binsize); 1223 plist_get_data_val(node, (char**)&bin, &binsize);
1233 plist_t backup_data = NULL; 1224 plist_t backup_data = NULL;
1234 if (bin) { 1225 if (bin) {
1235 char *auth_ver = NULL; 1226 char *auth_ver = NULL;
@@ -1246,7 +1237,7 @@ files_out:
1246 if (auth_sig && (auth_sig_len == 20)) { 1237 if (auth_sig && (auth_sig_len == 20)) {
1247 /* calculate the sha1, then compare */ 1238 /* calculate the sha1, then compare */
1248 unsigned char data_sha1[20]; 1239 unsigned char data_sha1[20];
1249 sha1_of_data(bin, binsize, data_sha1); 1240 sha1(bin, binsize, data_sha1);
1250 if (compare_hash(auth_sig, data_sha1, 20)) { 1241 if (compare_hash(auth_sig, data_sha1, 20)) {
1251 printf("AuthSignature is valid\n"); 1242 printf("AuthSignature is valid\n");
1252 } else { 1243 } else {
@@ -1255,12 +1246,12 @@ files_out:
1255 } else { 1246 } else {
1256 printf("Could not get AuthSignature from manifest!\n"); 1247 printf("Could not get AuthSignature from manifest!\n");
1257 } 1248 }
1258 g_free(auth_sig); 1249 free(auth_sig);
1259 } else if (auth_ver) { 1250 } else if (auth_ver) {
1260 printf("Unknown AuthVersion '%s', cannot verify AuthSignature\n", auth_ver); 1251 printf("Unknown AuthVersion '%s', cannot verify AuthSignature\n", auth_ver);
1261 } 1252 }
1262 plist_from_bin(bin, (uint32_t)binsize, &backup_data); 1253 plist_from_bin((char*)bin, (uint32_t)binsize, &backup_data);
1263 g_free(bin); 1254 free(bin);
1264 } 1255 }
1265 if (!backup_data) { 1256 if (!backup_data) {
1266 printf("Could not read plist from Manifest.plist Data key!\n"); 1257 printf("Could not read plist from Manifest.plist Data key!\n");
@@ -1312,7 +1303,7 @@ files_out:
1312 } else if (err == MOBILEBACKUP_E_REPLY_NOT_OK) { 1303 } else if (err == MOBILEBACKUP_E_REPLY_NOT_OK) {
1313 printf("ERROR: Could not start restore process: device refused to start the restore process.\n"); 1304 printf("ERROR: Could not start restore process: device refused to start the restore process.\n");
1314 } else { 1305 } else {
1315 printf("ERROR: Could not start restore process: unspecified error occured (%d)\n", err); 1306 printf("ERROR: Could not start restore process: unspecified error occurred (%d)\n", err);
1316 } 1307 }
1317 plist_free(backup_data); 1308 plist_free(backup_data);
1318 break; 1309 break;
@@ -1342,7 +1333,7 @@ files_out:
1342 while (node) { 1333 while (node) {
1343 /* TODO: read mddata/mdinfo files and send to device using DLSendFile */ 1334 /* TODO: read mddata/mdinfo files and send to device using DLSendFile */
1344 file_info_path = mobilebackup_build_path(backup_directory, hash, ".mdinfo"); 1335 file_info_path = mobilebackup_build_path(backup_directory, hash, ".mdinfo");
1345 plist_read_from_filename(&file_info, file_info_path); 1336 plist_read_from_file(file_info_path, &file_info, NULL);
1346 1337
1347 /* get encryption state */ 1338 /* get encryption state */
1348 tmp_node = plist_dict_get_item(file_info, "IsEncrypted"); 1339 tmp_node = plist_dict_get_item(file_info, "IsEncrypted");
@@ -1360,42 +1351,62 @@ files_out:
1360 printf("Restoring file %s %d/%d (%d%%)... ", file_path, cur_file, total_files, (cur_file*100/total_files)); 1351 printf("Restoring file %s %d/%d (%d%%)... ", file_path, cur_file, total_files, (cur_file*100/total_files));
1361 1352
1362 /* add additional device link file information keys */ 1353 /* add additional device link file information keys */
1363 plist_dict_insert_item(file_info, "DLFileAttributesKey", plist_copy(node)); 1354 plist_dict_set_item(file_info, "DLFileAttributesKey", plist_copy(node));
1364 plist_dict_insert_item(file_info, "DLFileSource", plist_new_string(file_info_path)); 1355 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")); 1356 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)); 1357 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)); 1358 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)); 1359 plist_dict_set_item(file_info, "DLFileStatusKey", plist_new_uint(file_status));
1369 1360
1370 /* read data from file */ 1361 /* read data from file */
1371 free(file_info_path); 1362 free(file_info_path);
1372 file_info_path = mobilebackup_build_path(backup_directory, hash, ".mddata"); 1363 file_info_path = mobilebackup_build_path(backup_directory, hash, ".mddata");
1373 buffer_read_from_filename(file_info_path, &buffer, &length); 1364
1365 /* determine file size */
1366#ifdef _WIN32
1367 struct _stati64 fst;
1368 if (_stati64(file_info_path, &fst) != 0)
1369#else
1370 struct stat fst;
1371 if (stat(file_info_path, &fst) != 0)
1372#endif
1373 {
1374 printf("ERROR: stat() failed for '%s': %s\n", file_info_path, strerror(errno));
1375 free(file_info_path);
1376 break;
1377 }
1378 length = fst.st_size;
1379
1380 FILE *f = fopen(file_info_path, "rb");
1381 if (!f) {
1382 printf("ERROR: could not open local file '%s': %s\n", file_info_path, strerror(errno));
1383 free(file_info_path);
1384 break;
1385 }
1374 free(file_info_path); 1386 free(file_info_path);
1375 1387
1376 /* send DLSendFile messages */ 1388 /* send DLSendFile messages */
1377 file_offset = 0; 1389 file_offset = 0;
1378 do { 1390 do {
1379 if ((length-file_offset) <= 8192) 1391 char buf[8192];
1392 size_t len = fread(buf, 1, sizeof(buf), f);
1393
1394 if ((length-file_offset) <= sizeof(buf))
1380 file_status = DEVICE_LINK_FILE_STATUS_LAST_HUNK; 1395 file_status = DEVICE_LINK_FILE_STATUS_LAST_HUNK;
1381 else 1396 else
1382 file_status = DEVICE_LINK_FILE_STATUS_HUNK; 1397 file_status = DEVICE_LINK_FILE_STATUS_HUNK;
1383 1398
1384 plist_dict_remove_item(file_info, "DLFileOffsetKey"); 1399 plist_dict_remove_item(file_info, "DLFileOffsetKey");
1385 plist_dict_insert_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset)); 1400 plist_dict_set_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset));
1386 1401
1387 plist_dict_remove_item(file_info, "DLFileStatusKey"); 1402 plist_dict_remove_item(file_info, "DLFileStatusKey");
1388 plist_dict_insert_item(file_info, "DLFileStatusKey", plist_new_uint(file_status)); 1403 plist_dict_set_item(file_info, "DLFileStatusKey", plist_new_uint(file_status));
1389 1404
1390 send_file_node = plist_new_array(); 1405 send_file_node = plist_new_array();
1391 1406
1392 plist_array_append_item(send_file_node, plist_new_string("DLSendFile")); 1407 plist_array_append_item(send_file_node, plist_new_string("DLSendFile"));
1393 1408
1394 if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) 1409 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)); 1410 plist_array_append_item(send_file_node, plist_copy(file_info));
1400 1411
1401 err = mobilebackup_send(mobilebackup, send_file_node); 1412 err = mobilebackup_send(mobilebackup, send_file_node);
@@ -1413,13 +1424,13 @@ files_out:
1413 } 1424 }
1414 } 1425 }
1415 1426
1416 file_offset += 8192; 1427 file_offset += len;
1417 1428
1418 if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) 1429 if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK)
1419 printf("DONE\n"); 1430 printf("DONE\n");
1420 1431
1421 plist_free(send_file_node); 1432 plist_free(send_file_node);
1422 1433
1423 if (file_status == DEVICE_LINK_FILE_STATUS_NONE) 1434 if (file_status == DEVICE_LINK_FILE_STATUS_NONE)
1424 break; 1435 break;
1425 1436
@@ -1466,8 +1477,8 @@ files_out:
1466 tmp_node = plist_dict_get_item(node, "AppInfo"); 1477 tmp_node = plist_dict_get_item(node, "AppInfo");
1467 1478
1468 dict = plist_new_dict(); 1479 dict = plist_new_dict();
1469 plist_dict_insert_item(dict, "AppInfo", plist_copy(tmp_node)); 1480 plist_dict_set_item(dict, "AppInfo", plist_copy(tmp_node));
1470 plist_dict_insert_item(dict, "BackupMessageTypeKey", plist_new_string("BackupMessageRestoreApplicationSent")); 1481 plist_dict_set_item(dict, "BackupMessageTypeKey", plist_new_string("BackupMessageRestoreApplicationSent"));
1471 1482
1472 array = plist_new_array(); 1483 array = plist_new_array();
1473 plist_array_append_item(array, plist_new_string("DLMessageProcessMessage")); 1484 plist_array_append_item(array, plist_new_string("DLMessageProcessMessage"));
@@ -1540,9 +1551,9 @@ files_out:
1540 do_post_notification(NP_SYNC_DID_FINISH); 1551 do_post_notification(NP_SYNC_DID_FINISH);
1541 } 1552 }
1542 if (manifest_path) 1553 if (manifest_path)
1543 g_free(manifest_path); 1554 free(manifest_path);
1544 } else { 1555 } else {
1545 printf("ERROR: Could not start service %s.\n", MOBILEBACKUP_SERVICE_NAME); 1556 printf("ERROR: Could not start service %s: %s\n", MOBILEBACKUP_SERVICE_NAME, lockdownd_strerror(ldret));
1546 lockdownd_client_free(client); 1557 lockdownd_client_free(client);
1547 client = NULL; 1558 client = NULL;
1548 } 1559 }
@@ -1561,7 +1572,9 @@ files_out:
1561 if (mobilebackup) 1572 if (mobilebackup)
1562 mobilebackup_client_free(mobilebackup); 1573 mobilebackup_client_free(mobilebackup);
1563 1574
1564 idevice_free(phone); 1575 idevice_free(device);
1576
1577 free(udid);
1565 1578
1566 return 0; 1579 return 0;
1567} 1580}