diff options
Diffstat (limited to 'tools/idevicebackup.c')
| -rw-r--r-- | tools/idevicebackup.c | 675 |
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 | |||
| 44 | static mobilebackup_client_t mobilebackup = NULL; | 60 | static mobilebackup_client_t mobilebackup = NULL; |
| 45 | static lockdownd_client_t client = NULL; | 61 | static lockdownd_client_t client = NULL; |
| 46 | static idevice_t phone = NULL; | 62 | static idevice_t device = NULL; |
| 47 | 63 | ||
| 48 | static int quit_flag = 0; | 64 | static int quit_flag = 0; |
| 49 | 65 | ||
| @@ -53,22 +69,12 @@ enum cmd_mode { | |||
| 53 | CMD_LEAVE | 69 | CMD_LEAVE |
| 54 | }; | 70 | }; |
| 55 | 71 | ||
| 56 | enum plist_format_t { | ||
| 57 | PLIST_FORMAT_XML, | ||
| 58 | PLIST_FORMAT_BINARY | ||
| 59 | }; | ||
| 60 | |||
| 61 | enum device_link_file_status_t { | 72 | enum 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 | ||
| 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) | 78 | static 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 | ||
| 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) | 89 | 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 | { | 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 | ||
| 132 | static void print_hash(const unsigned char *hash, int len) | 134 | static 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 | ||
| 150 | static plist_t mobilebackup_factory_info_plist_new() | 152 | static 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 | ||
| 211 | static void mobilebackup_info_update_last_backup_date(plist_t info_plist) | 214 | static 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 | ||
| 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) | 231 | static 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 | ||
| 324 | static gchar *mobilebackup_build_path(const char *backup_directory, const char *name, const char *extension) | 246 | static 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 | ||
| 350 | static int mobilebackup_read_status(const char *path) | 275 | static 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) | |||
| 435 | static int mobilebackup_delete_backup_file_by_hash(const char *backup_directory, const char *hash) | 360 | static 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 | ||
| 613 | static void do_post_notification(const char *notification) | 538 | static 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 | ||
| 668 | static void print_usage(int argc, char **argv) | 598 | static 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 | ||
| 684 | int main(int argc, char *argv[]) | 622 | int 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 | } |
