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 @@ * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define TOOL_NAME "idevicebackup" + #include <stdio.h> #include <string.h> #include <errno.h> #include <stdlib.h> #include <signal.h> -#include <glib.h> -#include <gcrypt.h> +#include <getopt.h> #include <unistd.h> +#include <ctype.h> +#include <time.h> #include <libimobiledevice/libimobiledevice.h> #include <libimobiledevice/lockdown.h> #include <libimobiledevice/mobilebackup.h> #include <libimobiledevice/notification_proxy.h> #include <libimobiledevice/afc.h> +#include <libimobiledevice-glue/sha.h> +#include <libimobiledevice-glue/utils.h> +#include <plist/plist.h> #define MOBILEBACKUP_SERVICE_NAME "com.apple.mobilebackup" #define NP_SERVICE_NAME "com.apple.mobile.notification_proxy" @@ -41,9 +51,14 @@ #define LOCK_ATTEMPTS 50 #define LOCK_WAIT 200000 +#ifdef WIN32 +#include <windows.h> +#define sleep(x) Sleep(x*1000) +#endif + static mobilebackup_client_t mobilebackup = NULL; static lockdownd_client_t client = NULL; -static idevice_t phone = NULL; +static idevice_t device = NULL; static int quit_flag = 0; @@ -53,22 +68,12 @@ enum cmd_mode { CMD_LEAVE }; -enum plist_format_t { - PLIST_FORMAT_XML, - PLIST_FORMAT_BINARY -}; - enum device_link_file_status_t { DEVICE_LINK_FILE_STATUS_NONE = 0, DEVICE_LINK_FILE_STATUS_HUNK, DEVICE_LINK_FILE_STATUS_LAST_HUNK }; -static void sha1_of_data(const char *input, uint32_t size, unsigned char *hash_out) -{ - gcry_md_hash_buffer(GCRY_MD_SHA1, hash_out, input, size); -} - static int compare_hash(const unsigned char *hash1, const unsigned char *hash2, int hash_len) { int i; @@ -82,51 +87,47 @@ static int compare_hash(const unsigned char *hash1, const unsigned char *hash2, 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) { - gcry_md_hd_t hd = NULL; - gcry_md_open(&hd, GCRY_MD_SHA1, 0); - if (!hd) { - printf("ERROR: Could not initialize libgcrypt/SHA1\n"); - return; - } - gcry_md_reset(hd); - + sha1_context sha1; + sha1_init(&sha1); FILE *f = fopen(path, "rb"); if (f) { unsigned char buf[16384]; size_t len; while ((len = fread(buf, 1, 16384, f)) > 0) { - gcry_md_write(hd, buf, len); + sha1_update(&sha1, buf, len); } fclose(f); - gcry_md_write(hd, destpath, strlen(destpath)); - gcry_md_write(hd, ";", 1); + sha1_update(&sha1, destpath, strlen(destpath)); + sha1_update(&sha1, ";", 1); + if (greylist == 1) { - gcry_md_write(hd, "true", 4); + sha1_update(&sha1, "true", 4); } else { - gcry_md_write(hd, "false", 5); + sha1_update(&sha1, "false", 5); } - gcry_md_write(hd, ";", 1); + sha1_update(&sha1, ";", 1); + if (domain) { - gcry_md_write(hd, domain, strlen(domain)); + sha1_update(&sha1, domain, strlen(domain)); } else { - gcry_md_write(hd, "(null)", 6); + sha1_update(&sha1, "(null)", 6); } - gcry_md_write(hd, ";", 1); + sha1_update(&sha1, ";", 1); + if (appid) { - gcry_md_write(hd, appid, strlen(appid)); + sha1_update(&sha1, appid, strlen(appid)); } else { - gcry_md_write(hd, "(null)", 6); + sha1_update(&sha1, "(null)", 6); } - gcry_md_write(hd, ";", 1); + sha1_update(&sha1, ";", 1); + if (version) { - gcry_md_write(hd, version, strlen(version)); + sha1_update(&sha1, version, strlen(version)); } else { - gcry_md_write(hd, "(null)", 6); + sha1_update(&sha1, "(null)", 6); } - unsigned char *newhash = gcry_md_read(hd, GCRY_MD_SHA1); - memcpy(hash_out, newhash, 20); + sha1_final(&sha1, hash_out); } - gcry_md_close(hd); } static void print_hash(const unsigned char *hash, int len) @@ -147,14 +148,12 @@ static void notify_cb(const char *notification, void *userdata) } } -static plist_t mobilebackup_factory_info_plist_new() +static plist_t mobilebackup_factory_info_plist_new(const char* udid) { /* gather data from lockdown */ - GTimeVal tv = {0, 0}; plist_t value_node = NULL; plist_t root_node = NULL; - char *uuid = NULL; - char *uuid_uppercase = NULL; + char *udid_uppercase = NULL; plist_t ret = plist_new_dict(); @@ -163,45 +162,42 @@ static plist_t mobilebackup_factory_info_plist_new() /* set fields we understand */ value_node = plist_dict_get_item(root_node, "BuildVersion"); - plist_dict_insert_item(ret, "Build Version", plist_copy(value_node)); + plist_dict_set_item(ret, "Build Version", plist_copy(value_node)); value_node = plist_dict_get_item(root_node, "DeviceName"); - plist_dict_insert_item(ret, "Device Name", plist_copy(value_node)); - plist_dict_insert_item(ret, "Display Name", plist_copy(value_node)); + plist_dict_set_item(ret, "Device Name", plist_copy(value_node)); + plist_dict_set_item(ret, "Display Name", plist_copy(value_node)); /* FIXME: How is the GUID generated? */ - plist_dict_insert_item(ret, "GUID", plist_new_string("---")); + plist_dict_set_item(ret, "GUID", plist_new_string("---")); value_node = plist_dict_get_item(root_node, "InternationalMobileEquipmentIdentity"); if (value_node) - plist_dict_insert_item(ret, "IMEI", plist_copy(value_node)); + plist_dict_set_item(ret, "IMEI", plist_copy(value_node)); - g_get_current_time(&tv); - plist_dict_insert_item(ret, "Last Backup Date", plist_new_date(tv.tv_sec, tv.tv_usec)); + plist_dict_set_item(ret, "Last Backup Date", plist_new_date(time(NULL) - MAC_EPOCH, 0)); value_node = plist_dict_get_item(root_node, "ProductType"); - plist_dict_insert_item(ret, "Product Type", plist_copy(value_node)); + plist_dict_set_item(ret, "Product Type", plist_copy(value_node)); value_node = plist_dict_get_item(root_node, "ProductVersion"); - plist_dict_insert_item(ret, "Product Version", plist_copy(value_node)); + plist_dict_set_item(ret, "Product Version", plist_copy(value_node)); value_node = plist_dict_get_item(root_node, "SerialNumber"); - plist_dict_insert_item(ret, "Serial Number", plist_copy(value_node)); + plist_dict_set_item(ret, "Serial Number", plist_copy(value_node)); value_node = plist_dict_get_item(root_node, "UniqueDeviceID"); - idevice_get_uuid(phone, &uuid); - plist_dict_insert_item(ret, "Target Identifier", plist_new_string(uuid)); + plist_dict_set_item(ret, "Target Identifier", plist_new_string(udid)); /* uppercase */ - uuid_uppercase = g_ascii_strup(uuid, -1); - plist_dict_insert_item(ret, "Unique Identifier", plist_new_string(uuid_uppercase)); - free(uuid_uppercase); - free(uuid); + udid_uppercase = string_toupper((char*)udid); + plist_dict_set_item(ret, "Unique Identifier", plist_new_string(udid_uppercase)); + free(udid_uppercase); /* FIXME: Embed files as <data> nodes */ plist_t files = plist_new_dict(); - plist_dict_insert_item(ret, "iTunes Files", files); - plist_dict_insert_item(ret, "iTunes Version", plist_new_string("9.0.2")); + plist_dict_set_item(ret, "iTunes Files", files); + plist_dict_set_item(ret, "iTunes Version", plist_new_string("9.0.2")); plist_free(root_node); @@ -210,102 +206,17 @@ static plist_t mobilebackup_factory_info_plist_new() static void mobilebackup_info_update_last_backup_date(plist_t info_plist) { - GTimeVal tv = {0, 0}; plist_t node = NULL; if (!info_plist) return; - g_get_current_time(&tv); node = plist_dict_get_item(info_plist, "Last Backup Date"); - plist_set_date_val(node, tv.tv_sec, tv.tv_usec); + plist_set_date_val(node, time(NULL) - MAC_EPOCH, 0); node = NULL; } -static void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length) -{ - FILE *f; - uint64_t size; - - *length = 0; - - f = fopen(filename, "rb"); - if (!f) { - return; - } - - fseek(f, 0, SEEK_END); - size = ftell(f); - rewind(f); - - if (size == 0) { - return; - } - - *buffer = (char*)malloc(sizeof(char)*size); - fread(*buffer, sizeof(char), size, f); - fclose(f); - - *length = size; -} - -static void buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length) -{ - FILE *f; - - f = fopen(filename, "ab"); - fwrite(buffer, sizeof(char), length, f); - fclose(f); -} - -static int plist_read_from_filename(plist_t *plist, const char *filename) -{ - char *buffer = NULL; - uint64_t length; - - if (!filename) - return 0; - - buffer_read_from_filename(filename, &buffer, &length); - - if (!buffer) { - return 0; - } - - if ((length > 8) && (memcmp(buffer, "bplist00", 8) == 0)) { - plist_from_bin(buffer, length, plist); - } else { - plist_from_xml(buffer, length, plist); - } - - free(buffer); - - return 1; -} - -static int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format) -{ - char *buffer = NULL; - uint32_t length; - - if (!plist || !filename) - return 0; - - if (format == PLIST_FORMAT_XML) - plist_to_xml(plist, &buffer, &length); - else if (format == PLIST_FORMAT_BINARY) - plist_to_bin(plist, &buffer, &length); - else - return 0; - - buffer_write_to_filename(filename, buffer, length); - - free(buffer); - - return 1; -} - static int plist_strcmp(plist_t node, const char *str) { char *buffer = NULL; @@ -321,11 +232,14 @@ static int plist_strcmp(plist_t node, const char *str) return ret; } -static gchar *mobilebackup_build_path(const char *backup_directory, const char *name, const char *extension) +static char *mobilebackup_build_path(const char *backup_directory, const char *name, const char *extension) { - gchar *filename = g_strconcat(name, extension, NULL); - gchar *path = g_build_path(G_DIR_SEPARATOR_S, backup_directory, filename, NULL); - g_free(filename); + char* filename = (char*)malloc(strlen(name)+(extension == NULL ? 0: strlen(extension))+1); + strcpy(filename, name); + if (extension != NULL) + strcat(filename, extension); + char *path = string_build_path(backup_directory, filename, NULL); + free(filename); return path; } @@ -333,28 +247,28 @@ static void mobilebackup_write_status(const char *path, int status) { struct stat st; plist_t status_plist = plist_new_dict(); - plist_dict_insert_item(status_plist, "Backup Success", plist_new_bool(status)); - gchar *file_path = mobilebackup_build_path(path, "Status", ".plist"); + plist_dict_set_item(status_plist, "Backup Success", plist_new_bool(status)); + char *file_path = mobilebackup_build_path(path, "Status", ".plist"); if (stat(file_path, &st) == 0) remove(file_path); - plist_write_to_filename(status_plist, file_path, PLIST_FORMAT_XML); + plist_write_to_file(status_plist, file_path, PLIST_FORMAT_XML, 0); plist_free(status_plist); status_plist = NULL; - g_free(file_path); + free(file_path); } static int mobilebackup_read_status(const char *path) { int ret = -1; plist_t status_plist = NULL; - gchar *file_path = mobilebackup_build_path(path, "Status", ".plist"); + char *file_path = mobilebackup_build_path(path, "Status", ".plist"); - plist_read_from_filename(&status_plist, file_path); - g_free(file_path); + plist_read_from_file(file_path, &status_plist, NULL); + free(file_path); if (!status_plist) { printf("Could not read Status.plist!\n"); return ret; @@ -387,7 +301,7 @@ static int mobilebackup_info_is_current_device(plist_t info) /* get basic device information in one go */ lockdownd_get_value(client, NULL, NULL, &root_node); - /* verify UUID */ + /* verify UDID */ value_node = plist_dict_get_item(root_node, "UniqueDeviceID"); node = plist_dict_get_item(info, "Target Identifier"); @@ -435,14 +349,14 @@ static int mobilebackup_info_is_current_device(plist_t info) static int mobilebackup_delete_backup_file_by_hash(const char *backup_directory, const char *hash) { int ret = 0; - gchar *path = mobilebackup_build_path(backup_directory, hash, ".mddata"); + char *path = mobilebackup_build_path(backup_directory, hash, ".mddata"); printf("Removing \"%s\" ", path); if (!remove( path )) ret = 1; else ret = 0; - g_free(path); + free(path); if (!ret) return ret; @@ -454,7 +368,7 @@ static int mobilebackup_delete_backup_file_by_hash(const char *backup_directory, else ret = 0; - g_free(path); + free(path); return ret; } @@ -476,7 +390,7 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const } infopath = mobilebackup_build_path(backup_directory, hash, ".mdinfo"); - plist_read_from_filename(&mdinfo, infopath); + plist_read_from_file(infopath, &mdinfo, NULL); free(infopath); if (!mdinfo) { printf("\r\n"); @@ -521,13 +435,13 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const char *version = NULL; node = plist_dict_get_item(metadata, "Version"); - if (node && (plist_get_node_type(node) == PLIST_STRING)) { + if (node && (plist_get_node_type(node) == PLIST_STRING)) { plist_get_string_val(node, &version); } char *destpath = NULL; node = plist_dict_get_item(metadata, "Path"); - if (node && (plist_get_node_type(node) == PLIST_STRING)) { + if (node && (plist_get_node_type(node) == PLIST_STRING)) { plist_get_string_val(node, &destpath); } @@ -539,7 +453,7 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const char *domain = NULL; node = plist_dict_get_item(metadata, "Domain"); - if (node && (plist_get_node_type(node) == PLIST_STRING)) { + if (node && (plist_get_node_type(node) == PLIST_STRING)) { plist_get_string_val(node, &domain); } @@ -550,14 +464,14 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const unsigned char fnhash[20]; char fnamehash[41]; char *p = fnamehash; - sha1_of_data(fnstr, strlen(fnstr), fnhash); + sha1((const unsigned char*)fnstr, strlen(fnstr), fnhash); free(fnstr); int i; for ( i = 0; i < 20; i++, p += 2 ) { snprintf (p, 3, "%02x", (unsigned char)fnhash[i] ); } - if (strcmp(fnamehash, hash)) { - printf("\r\n"); + if (strcmp(fnamehash, hash) != 0) { + printf("\r\n"); printf("WARNING: filename hash does not match for entry '%s'\n", hash); } @@ -567,7 +481,7 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const plist_get_string_val(node, &auth_version); } - if (strcmp(auth_version, "1.0")) { + if (strcmp(auth_version, "1.0") != 0) { printf("\r\n"); printf("WARNING: Unknown AuthVersion '%s', DataHash cannot be verified!\n", auth_version); } @@ -591,9 +505,9 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const hash_ok = 1; } - g_free(domain); - g_free(version); - g_free(destpath); + free(domain); + free(version); + free(destpath); if (!hash_ok) { printf("\r\n"); @@ -605,31 +519,36 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const printf("\n"); res = 0; } - g_free(data_hash); + free(data_hash); plist_free(mdinfo); return res; } static void do_post_notification(const char *notification) { - uint16_t nport = 0; + lockdownd_service_descriptor_t service = NULL; np_client_t np; if (!client) { - if (lockdownd_client_new_with_handshake(phone, &client, "idevicebackup") != LOCKDOWN_E_SUCCESS) { + if (lockdownd_client_new_with_handshake(device, &client, TOOL_NAME) != LOCKDOWN_E_SUCCESS) { return; } } - lockdownd_start_service(client, NP_SERVICE_NAME, &nport); - if (nport) { - np_client_new(phone, nport, &np); + lockdownd_error_t ldret = lockdownd_start_service(client, NP_SERVICE_NAME, &service); + if (ldret == LOCKDOWN_E_SUCCESS) { + np_client_new(device, service, &np); if (np) { np_post_notification(np, notification); np_client_free(np); } } else { - printf("Could not start %s\n", NP_SERVICE_NAME); + printf("Could not start %s: %s\n", NP_SERVICE_NAME, lockdownd_strerror(ldret)); + } + + if (service) { + lockdownd_service_descriptor_free(service); + service = NULL; } } @@ -665,29 +584,38 @@ static void clean_exit(int sig) quit_flag++; } -static void print_usage(int argc, char **argv) +static void print_usage(int argc, char **argv, int is_error) { - char *name = NULL; - name = strrchr(argv[0], '/'); - printf("Usage: %s [OPTIONS] CMD [DIRECTORY]\n", (name ? name + 1: argv[0])); - printf("Create or restore backup from the current or specified directory.\n\n"); - printf("commands:\n"); - printf(" backup\tSaves a device backup into DIRECTORY\n"); - printf(" restore\tRestores a device backup from DIRECTORY.\n\n"); - printf("options:\n"); - printf(" -d, --debug\t\tenable communication debugging\n"); - printf(" -u, --uuid UUID\ttarget specific device by its 40-digit device UUID\n"); - printf(" -h, --help\t\tprints usage information\n"); - printf("\n"); + char *name = strrchr(argv[0], '/'); + fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS] CMD DIRECTORY\n", (name ? name + 1: argv[0])); + fprintf(is_error ? stderr : stdout, + "\n" + "Create or restore backup in/from the specified directory.\n" + "\n" + "CMD:\n" + " backup Saves a device backup into DIRECTORY\n" + " restore Restores a device backup from DIRECTORY.\n" + "\n" + "OPTIONS:\n" + " -u, --udid UDID target specific device by UDID\n" + " -n, --network connect to network device\n" + " -d, --debug enable communication debugging\n" + " -h, --help prints usage information\n" + " -v, --version prints version information\n" + "\n" + "Homepage: <" PACKAGE_URL ">\n" + "Bug Reports: <" PACKAGE_BUGREPORT ">\n" + ); } int main(int argc, char *argv[]) { idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; + lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR; int i; - char uuid[41]; - uint16_t port = 0; - uuid[0] = 0; + char* udid = NULL; + int use_network = 0; + lockdownd_service_descriptor_t service = NULL; int cmd = -1; int is_full_backup = 0; char *backup_directory = NULL; @@ -701,60 +629,77 @@ int main(int argc, char *argv[]) uint64_t length = 0; uint64_t backup_total_size = 0; enum device_link_file_status_t file_status = DEVICE_LINK_FILE_STATUS_NONE; - uint64_t c = 0; + int c = 0; + const struct option longopts[] = { + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "udid", required_argument, NULL, 'u' }, + { "network", no_argument, NULL, 'n' }, + { "version", no_argument, NULL, 'v' }, + { NULL, 0, NULL, 0} + }; /* we need to exit cleanly on running backups and restores or we cause havok */ signal(SIGINT, clean_exit); - signal(SIGQUIT, clean_exit); signal(SIGTERM, clean_exit); +#ifndef WIN32 + signal(SIGQUIT, clean_exit); signal(SIGPIPE, SIG_IGN); +#endif /* parse cmdline args */ - for (i = 1; i < argc; i++) { - if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { + while ((c = getopt_long(argc, argv, "dhu:nv", longopts, NULL)) != -1) { + switch (c) { + case 'd': idevice_set_debug_level(1); - continue; - } - else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--uuid")) { - i++; - if (!argv[i] || (strlen(argv[i]) != 40)) { - print_usage(argc, argv); - return 0; + break; + case 'u': + if (!*optarg) { + fprintf(stderr, "ERROR: UDID must not be empty!\n"); + print_usage(argc, argv, 1); + return 2; } - strcpy(uuid, argv[i]); - continue; - } - else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { - print_usage(argc, argv); + udid = strdup(optarg); + break; + case 'n': + use_network = 1; + break; + case 'h': + print_usage(argc, argv, 0); return 0; - } - else if (!strcmp(argv[i], "backup")) { - cmd = CMD_BACKUP; - } - else if (!strcmp(argv[i], "restore")) { - cmd = CMD_RESTORE; - } - else if (backup_directory == NULL) { - backup_directory = argv[i]; - } - else { - print_usage(argc, argv); + case 'v': + printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION); return 0; + default: + print_usage(argc, argv, 1); + return 2; } } + argc -= optind; + argv += optind; - /* verify options */ - if (cmd == -1) { - printf("No command specified.\n"); - print_usage(argc, argv); - return -1; + if (argc < 1) { + fprintf(stderr, "ERROR: Missing command.\n"); + print_usage(argc+optind, argv-optind, 1); + return 2; } - if (backup_directory == NULL) { - printf("No target backup directory specified.\n"); - print_usage(argc, argv); - return -1; + if (!strcmp(argv[0], "backup")) { + cmd = CMD_BACKUP; + } else if (!strcmp(argv[0], "restore")) { + cmd = CMD_RESTORE; + } else { + fprintf(stderr, "ERROR: Invalid command '%s'.\n", argv[0]); + print_usage(argc+optind, argv-optind, 1); + return 2; + } + + if (argc < 2) { + fprintf(stderr, "No target backup directory specified.\n"); + print_usage(argc+optind, argv-optind, 1); + return 2; } + backup_directory = argv[1]; /* verify if passed backup directory exists */ if (stat(backup_directory, &st) != 0) { @@ -766,7 +711,7 @@ int main(int argc, char *argv[]) char *info_path = mobilebackup_build_path(backup_directory, "Info", ".plist"); if (cmd == CMD_RESTORE) { if (stat(info_path, &st) != 0) { - g_free(info_path); + free(info_path); printf("ERROR: Backup directory \"%s\" is invalid. No Info.plist found.\n", backup_directory); return -1; } @@ -774,32 +719,54 @@ int main(int argc, char *argv[]) printf("Backup directory is \"%s\"\n", backup_directory); - if (uuid[0] != 0) { - ret = idevice_new(&phone, uuid); - if (ret != IDEVICE_E_SUCCESS) { - printf("No device found with uuid %s, is it plugged in?\n", uuid); - return -1; + ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX); + if (ret != IDEVICE_E_SUCCESS) { + if (udid) { + printf("No device found with udid %s.\n", udid); + } else { + printf("No device found.\n"); } + return -1; } - else - { - ret = idevice_new(&phone, NULL); - if (ret != IDEVICE_E_SUCCESS) { - printf("No device found, is it plugged in?\n"); - return -1; - } + + if (!udid) { + idevice_get_udid(device, &udid); } - if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(phone, &client, "idevicebackup")) { - idevice_free(phone); + if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &client, TOOL_NAME))) { + printf("ERROR: Could not connect to lockdownd, error code %d\n", ldret); + idevice_free(device); + free(udid); return -1; } + node = NULL; + lockdownd_get_value(client, NULL, "ProductVersion", &node); + if (node) { + char* str = NULL; + if (plist_get_node_type(node) == PLIST_STRING) { + plist_get_string_val(node, &str); + } + plist_free(node); + node = NULL; + if (str) { + int maj = strtol(str, NULL, 10); + free(str); + if (maj > 3) { + printf("ERROR: This tool is only compatible with iOS 3 or below. For newer iOS versions please use the idevicebackup2 tool.\n"); + lockdownd_client_free(client); + idevice_free(device); + free(udid); + return -1; + } + } + } + /* start notification_proxy */ np_client_t np = NULL; - ret = lockdownd_start_service(client, NP_SERVICE_NAME, &port); - if ((ret == LOCKDOWN_E_SUCCESS) && port) { - np_client_new(phone, port, &np); + ldret = lockdownd_start_service(client, NP_SERVICE_NAME, &service); + if ((ldret == LOCKDOWN_E_SUCCESS) && service && service->port) { + np_client_new(device, service, &np); np_set_notify_callback(np, notify_cb, NULL); const char *noties[5] = { NP_SYNC_CANCEL_REQUEST, @@ -810,25 +777,37 @@ int main(int argc, char *argv[]) }; np_observe_notifications(np, noties); } else { - printf("ERROR: Could not start service %s.\n", NP_SERVICE_NAME); + printf("ERROR: Could not start service %s: %s\n", NP_SERVICE_NAME, lockdownd_strerror(ldret)); } afc_client_t afc = NULL; if (cmd == CMD_BACKUP) { /* start AFC, we need this for the lock file */ - port = 0; - ret = lockdownd_start_service(client, "com.apple.afc", &port); - if ((ret == LOCKDOWN_E_SUCCESS) && port) { - afc_client_new(phone, port, &afc); + service->port = 0; + service->ssl_enabled = 0; + ldret = lockdownd_start_service(client, AFC_SERVICE_NAME, &service); + if ((ldret == LOCKDOWN_E_SUCCESS) && service->port) { + afc_client_new(device, service, &afc); + } else { + printf("ERROR: Could not start service %s: %s\n", AFC_SERVICE_NAME, lockdownd_strerror(ldret)); } } + if (service) { + lockdownd_service_descriptor_free(service); + service = NULL; + } + /* start mobilebackup service and retrieve port */ - port = 0; - ret = lockdownd_start_service(client, MOBILEBACKUP_SERVICE_NAME, &port); - if ((ret == LOCKDOWN_E_SUCCESS) && port) { - printf("Started \"%s\" service on port %d.\n", MOBILEBACKUP_SERVICE_NAME, port); - mobilebackup_client_new(phone, port, &mobilebackup); + ldret = lockdownd_start_service(client, MOBILEBACKUP_SERVICE_NAME, &service); + if ((ldret == LOCKDOWN_E_SUCCESS) && service && service->port) { + printf("Started \"%s\" service on port %d.\n", MOBILEBACKUP_SERVICE_NAME, service->port); + printf("%d\n", mobilebackup_client_new(device, service, &mobilebackup)); + + if (service) { + lockdownd_service_descriptor_free(service); + service = NULL; + } /* check abort conditions */ if (quit_flag > 0) { @@ -839,7 +818,7 @@ int main(int argc, char *argv[]) /* verify existing Info.plist */ if (stat(info_path, &st) == 0) { printf("Reading Info.plist from backup.\n"); - plist_read_from_filename(&info_plist, info_path); + plist_read_from_file(info_path, &info_plist, NULL); if (!info_plist) { printf("Could not read Info.plist\n"); @@ -850,7 +829,7 @@ int main(int argc, char *argv[]) /* update the last backup time within Info.plist */ mobilebackup_info_update_last_backup_date(info_plist); remove(info_path); - plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML); + plist_write_to_file(info_plist, info_path, PLIST_FORMAT_XML, 0); } else { printf("Aborting backup. Backup is not compatible with the current device.\n"); cmd = CMD_LEAVE; @@ -883,15 +862,16 @@ int main(int argc, char *argv[]) if (aerr == AFC_E_SUCCESS) { do_post_notification(NP_SYNC_DID_START); break; - } else if (aerr == AFC_E_OP_WOULD_BLOCK) { + } + if (aerr == AFC_E_OP_WOULD_BLOCK) { usleep(LOCK_WAIT); continue; - } else { - fprintf(stderr, "ERROR: could not lock file! error code: %d\n", aerr); - afc_file_close(afc, lockfile); - lockfile = 0; - cmd = CMD_LEAVE; } + + fprintf(stderr, "ERROR: could not lock file! error code: %d\n", aerr); + afc_file_close(afc, lockfile); + lockfile = 0; + cmd = CMD_LEAVE; } if (i == LOCK_ATTEMPTS) { fprintf(stderr, "ERROR: timeout while locking for sync\n"); @@ -910,12 +890,12 @@ int main(int argc, char *argv[]) case CMD_BACKUP: printf("Starting backup...\n"); /* TODO: check domain com.apple.mobile.backup key RequiresEncrypt and WillEncrypt with lockdown */ - /* TODO: verify battery on AC enough battery remaining */ + /* TODO: verify battery on AC enough battery remaining */ /* read the last Manifest.plist */ if (!is_full_backup) { printf("Reading existing Manifest.\n"); - plist_read_from_filename(&manifest_plist, manifest_path); + plist_read_from_file(manifest_path, &manifest_plist, NULL); if (!manifest_plist) { printf("Could not read Manifest.plist, switching to full backup mode.\n"); is_full_backup = 1; @@ -932,10 +912,10 @@ int main(int argc, char *argv[]) } remove(info_path); printf("Creating Info.plist for new backup.\n"); - info_plist = mobilebackup_factory_info_plist_new(); - plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML); + info_plist = mobilebackup_factory_info_plist_new(udid); + plist_write_to_file(info_plist, info_path, PLIST_FORMAT_XML, 0); } - g_free(info_path); + free(info_path); plist_free(info_plist); info_plist = NULL; @@ -965,7 +945,7 @@ int main(int argc, char *argv[]) } else if (err == MOBILEBACKUP_E_REPLY_NOT_OK) { printf("ERROR: Could not start backup process: device refused to start the backup process.\n"); } else { - printf("ERROR: Could not start backup process: unspecified error occured\n"); + printf("ERROR: Could not start backup process: unspecified error occurred (%d)\n", err); } break; } @@ -985,8 +965,9 @@ int main(int argc, char *argv[]) char *filename_mddata = NULL; char *filename_source = NULL; char *format_size = NULL; - gboolean is_manifest = FALSE; + int is_manifest = 0; uint8_t b = 0; + uint64_t u64val = 0; /* process series of DLSendFile messages */ do { @@ -996,7 +977,7 @@ int main(int argc, char *argv[]) sleep(2); goto files_out; } - + node = plist_array_get_item(message, 0); /* get out if we don't get a DLSendFile */ @@ -1010,16 +991,16 @@ int main(int argc, char *argv[]) node = plist_dict_get_item(node_tmp, "BackupTotalSizeKey"); if (node) { plist_get_uint_val(node, &backup_total_size); - format_size = g_format_size_for_display(backup_total_size); + format_size = string_format_size(backup_total_size); printf("Backup data requires %s on the disk.\n", format_size); - g_free(format_size); + free(format_size); } } /* check DLFileStatusKey (codes: 1 = Hunk, 2 = Last Hunk) */ node = plist_dict_get_item(node_tmp, "DLFileStatusKey"); - plist_get_uint_val(node, &c); - file_status = c; + plist_get_uint_val(node, &u64val); + file_status = u64val; /* get source filename */ node = plist_dict_get_item(node_tmp, "BackupManifestKey"); @@ -1027,7 +1008,7 @@ int main(int argc, char *argv[]) if (node) { plist_get_bool_val(node, &b); } - is_manifest = (b == 1) ? TRUE: FALSE; + is_manifest = (b == 1) ? 1 : 0; if ((hunk_index == 0) && (!is_manifest)) { /* get source filename */ @@ -1040,17 +1021,17 @@ int main(int argc, char *argv[]) plist_get_uint_val(node, &file_size); backup_real_size += file_size; - format_size = g_format_size_for_display(backup_real_size); + format_size = string_format_size(backup_real_size); printf("(%s", format_size); - g_free(format_size); + free(format_size); - format_size = g_format_size_for_display(backup_total_size); + format_size = string_format_size(backup_total_size); printf("/%s): ", format_size); - g_free(format_size); + free(format_size); - format_size = g_format_size_for_display(file_size); + format_size = string_format_size(file_size); printf("Receiving file %s (%s)... \n", filename_source, format_size); - g_free(format_size); + free(format_size); if (filename_source) free(filename_source); @@ -1071,9 +1052,9 @@ int main(int argc, char *argv[]) remove(filename_mdinfo); node = plist_dict_get_item(node_tmp, "BackupFileInfo"); - plist_write_to_filename(node, filename_mdinfo, PLIST_FORMAT_BINARY); + plist_write_to_file(node, filename_mdinfo, PLIST_FORMAT_BINARY, 0); - g_free(filename_mdinfo); + free(filename_mdinfo); } file_index++; @@ -1107,15 +1088,14 @@ int main(int argc, char *argv[]) free(buffer); buffer = NULL; - g_free(filename_mddata); + free(filename_mddata); } if ((!is_manifest)) { if (hunk_index == 0 && file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) { print_progress(100); - } else { - if (file_size > 0) - print_progress((double)((file_size_current*100)/file_size)); + } else if (file_size > 0) { + print_progress((double)(file_size_current*100)/file_size); } } @@ -1145,7 +1125,7 @@ files_out: /* remove any atomic Manifest.plist.tmp */ if (manifest_path) - g_free(manifest_path); + free(manifest_path); manifest_path = mobilebackup_build_path(backup_directory, "Manifest", ".plist.tmp"); if (stat(manifest_path, &st) == 0) @@ -1184,7 +1164,7 @@ files_out: if (manifest_plist) { remove(manifest_path); printf("Storing Manifest.plist...\n"); - plist_write_to_filename(manifest_plist, manifest_path, PLIST_FORMAT_XML); + plist_write_to_file(manifest_plist, manifest_path, PLIST_FORMAT_XML, 0); } backup_ok = 1; @@ -1215,21 +1195,21 @@ files_out: } /* now make sure backup integrity is ok! verify all files */ printf("Reading existing Manifest.\n"); - plist_read_from_filename(&manifest_plist, manifest_path); + plist_read_from_file(manifest_path, &manifest_plist, NULL); if (!manifest_plist) { printf("Could not read Manifest.plist. Aborting.\n"); break; } printf("Verifying backup integrity, please wait.\n"); - char *bin = NULL; + unsigned char *bin = NULL; uint64_t binsize = 0; node = plist_dict_get_item(manifest_plist, "Data"); if (!node || (plist_get_node_type(node) != PLIST_DATA)) { printf("Could not read Data key from Manifest.plist!\n"); break; } - plist_get_data_val(node, &bin, &binsize); + plist_get_data_val(node, (char**)&bin, &binsize); plist_t backup_data = NULL; if (bin) { char *auth_ver = NULL; @@ -1246,7 +1226,7 @@ files_out: if (auth_sig && (auth_sig_len == 20)) { /* calculate the sha1, then compare */ unsigned char data_sha1[20]; - sha1_of_data(bin, binsize, data_sha1); + sha1(bin, binsize, data_sha1); if (compare_hash(auth_sig, data_sha1, 20)) { printf("AuthSignature is valid\n"); } else { @@ -1255,12 +1235,12 @@ files_out: } else { printf("Could not get AuthSignature from manifest!\n"); } - g_free(auth_sig); + free(auth_sig); } else if (auth_ver) { - printf("Unknown AuthVersion '%s', cannot verify AuthSignature\n", auth_ver); + printf("Unknown AuthVersion '%s', cannot verify AuthSignature\n", auth_ver); } - plist_from_bin(bin, (uint32_t)binsize, &backup_data); - g_free(bin); + plist_from_bin((char*)bin, (uint32_t)binsize, &backup_data); + free(bin); } if (!backup_data) { printf("Could not read plist from Manifest.plist Data key!\n"); @@ -1312,7 +1292,7 @@ files_out: } else if (err == MOBILEBACKUP_E_REPLY_NOT_OK) { printf("ERROR: Could not start restore process: device refused to start the restore process.\n"); } else { - printf("ERROR: Could not start restore process: unspecified error occured (%d)\n", err); + printf("ERROR: Could not start restore process: unspecified error occurred (%d)\n", err); } plist_free(backup_data); break; @@ -1342,7 +1322,7 @@ files_out: while (node) { /* TODO: read mddata/mdinfo files and send to device using DLSendFile */ file_info_path = mobilebackup_build_path(backup_directory, hash, ".mdinfo"); - plist_read_from_filename(&file_info, file_info_path); + plist_read_from_file(file_info_path, &file_info, NULL); /* get encryption state */ tmp_node = plist_dict_get_item(file_info, "IsEncrypted"); @@ -1360,42 +1340,62 @@ files_out: printf("Restoring file %s %d/%d (%d%%)... ", file_path, cur_file, total_files, (cur_file*100/total_files)); /* add additional device link file information keys */ - plist_dict_insert_item(file_info, "DLFileAttributesKey", plist_copy(node)); - plist_dict_insert_item(file_info, "DLFileSource", plist_new_string(file_info_path)); - plist_dict_insert_item(file_info, "DLFileDest", plist_new_string("/tmp/RestoreFile.plist")); - plist_dict_insert_item(file_info, "DLFileIsEncrypted", plist_new_bool(is_encrypted)); - plist_dict_insert_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset)); - plist_dict_insert_item(file_info, "DLFileStatusKey", plist_new_uint(file_status)); + plist_dict_set_item(file_info, "DLFileAttributesKey", plist_copy(node)); + plist_dict_set_item(file_info, "DLFileSource", plist_new_string(file_info_path)); + plist_dict_set_item(file_info, "DLFileDest", plist_new_string("/tmp/RestoreFile.plist")); + plist_dict_set_item(file_info, "DLFileIsEncrypted", plist_new_bool(is_encrypted)); + plist_dict_set_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset)); + plist_dict_set_item(file_info, "DLFileStatusKey", plist_new_uint(file_status)); /* read data from file */ free(file_info_path); file_info_path = mobilebackup_build_path(backup_directory, hash, ".mddata"); - buffer_read_from_filename(file_info_path, &buffer, &length); + + /* determine file size */ +#ifdef WIN32 + struct _stati64 fst; + if (_stati64(file_info_path, &fst) != 0) +#else + struct stat fst; + if (stat(file_info_path, &fst) != 0) +#endif + { + printf("ERROR: stat() failed for '%s': %s\n", file_info_path, strerror(errno)); + free(file_info_path); + break; + } + length = fst.st_size; + + FILE *f = fopen(file_info_path, "rb"); + if (!f) { + printf("ERROR: could not open local file '%s': %s\n", file_info_path, strerror(errno)); + free(file_info_path); + break; + } free(file_info_path); /* send DLSendFile messages */ file_offset = 0; do { - if ((length-file_offset) <= 8192) + char buf[8192]; + size_t len = fread(buf, 1, sizeof(buf), f); + + if ((length-file_offset) <= sizeof(buf)) file_status = DEVICE_LINK_FILE_STATUS_LAST_HUNK; else file_status = DEVICE_LINK_FILE_STATUS_HUNK; - + plist_dict_remove_item(file_info, "DLFileOffsetKey"); - plist_dict_insert_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset)); + plist_dict_set_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset)); plist_dict_remove_item(file_info, "DLFileStatusKey"); - plist_dict_insert_item(file_info, "DLFileStatusKey", plist_new_uint(file_status)); + plist_dict_set_item(file_info, "DLFileStatusKey", plist_new_uint(file_status)); send_file_node = plist_new_array(); plist_array_append_item(send_file_node, plist_new_string("DLSendFile")); - if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) - plist_array_append_item(send_file_node, plist_new_data(buffer+file_offset, length-file_offset)); - else - plist_array_append_item(send_file_node, plist_new_data(buffer+file_offset, 8192)); - + plist_array_append_item(send_file_node, plist_new_data(buf, len)); plist_array_append_item(send_file_node, plist_copy(file_info)); err = mobilebackup_send(mobilebackup, send_file_node); @@ -1413,13 +1413,13 @@ files_out: } } - file_offset += 8192; + file_offset += len; if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) printf("DONE\n"); plist_free(send_file_node); - + if (file_status == DEVICE_LINK_FILE_STATUS_NONE) break; @@ -1466,8 +1466,8 @@ files_out: tmp_node = plist_dict_get_item(node, "AppInfo"); dict = plist_new_dict(); - plist_dict_insert_item(dict, "AppInfo", plist_copy(tmp_node)); - plist_dict_insert_item(dict, "BackupMessageTypeKey", plist_new_string("BackupMessageRestoreApplicationSent")); + plist_dict_set_item(dict, "AppInfo", plist_copy(tmp_node)); + plist_dict_set_item(dict, "BackupMessageTypeKey", plist_new_string("BackupMessageRestoreApplicationSent")); array = plist_new_array(); plist_array_append_item(array, plist_new_string("DLMessageProcessMessage")); @@ -1540,9 +1540,9 @@ files_out: do_post_notification(NP_SYNC_DID_FINISH); } if (manifest_path) - g_free(manifest_path); + free(manifest_path); } else { - printf("ERROR: Could not start service %s.\n", MOBILEBACKUP_SERVICE_NAME); + printf("ERROR: Could not start service %s: %s\n", MOBILEBACKUP_SERVICE_NAME, lockdownd_strerror(ldret)); lockdownd_client_free(client); client = NULL; } @@ -1561,7 +1561,9 @@ files_out: if (mobilebackup) mobilebackup_client_free(mobilebackup); - idevice_free(phone); + idevice_free(device); + + free(udid); return 0; } |