diff options
Diffstat (limited to 'tools/idevicebackup.c')
-rw-r--r-- | tools/idevicebackup.c | 664 |
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 | |||
44 | static mobilebackup_client_t mobilebackup = NULL; | 59 | static mobilebackup_client_t mobilebackup = NULL; |
45 | static lockdownd_client_t client = NULL; | 60 | static lockdownd_client_t client = NULL; |
46 | static idevice_t phone = NULL; | 61 | static idevice_t device = NULL; |
47 | 62 | ||
48 | static int quit_flag = 0; | 63 | static int quit_flag = 0; |
49 | 64 | ||
@@ -53,22 +68,12 @@ enum cmd_mode { | |||
53 | CMD_LEAVE | 68 | CMD_LEAVE |
54 | }; | 69 | }; |
55 | 70 | ||
56 | enum plist_format_t { | ||
57 | PLIST_FORMAT_XML, | ||
58 | PLIST_FORMAT_BINARY | ||
59 | }; | ||
60 | |||
61 | enum device_link_file_status_t { | 71 | enum 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 | ||
67 | static void sha1_of_data(const char *input, uint32_t size, unsigned char *hash_out) | ||
68 | { | ||
69 | gcry_md_hash_buffer(GCRY_MD_SHA1, hash_out, input, size); | ||
70 | } | ||
71 | |||
72 | static int compare_hash(const unsigned char *hash1, const unsigned char *hash2, int hash_len) | 77 | static 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 | ||
83 | static void compute_datahash(const char *path, const char *destpath, uint8_t greylist, const char *domain, const char *appid, const char *version, unsigned char *hash_out) | 88 | static void compute_datahash(const char *path, const char *destpath, uint8_t greylist, const char *domain, const char *appid, const char *version, unsigned char *hash_out) |
84 | { | 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 | ||
132 | static void print_hash(const unsigned char *hash, int len) | 133 | static 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 | ||
150 | static plist_t mobilebackup_factory_info_plist_new() | 151 | static 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 | ||
211 | static void mobilebackup_info_update_last_backup_date(plist_t info_plist) | 207 | static 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 | ||
226 | static 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 | |||
253 | static 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 | |||
262 | static 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 | |||
287 | static 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 | |||
309 | static int plist_strcmp(plist_t node, const char *str) | 220 | static 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 | ||
324 | static gchar *mobilebackup_build_path(const char *backup_directory, const char *name, const char *extension) | 235 | static 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 | ||
350 | static int mobilebackup_read_status(const char *path) | 264 | static 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) | |||
435 | static int mobilebackup_delete_backup_file_by_hash(const char *backup_directory, const char *hash) | 349 | static 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 | ||
613 | static void do_post_notification(const char *notification) | 527 | static 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 | ||
668 | static void print_usage(int argc, char **argv) | 587 | static 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 | ||
684 | int main(int argc, char *argv[]) | 611 | int 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 | } |