summaryrefslogtreecommitdiffstats
path: root/tools/idevicebackup.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/idevicebackup.c')
-rw-r--r--tools/idevicebackup.c664
1 files changed, 333 insertions, 331 deletions
diff --git a/tools/idevicebackup.c b/tools/idevicebackup.c
index 867eaad..c0537b8 100644
--- a/tools/idevicebackup.c
+++ b/tools/idevicebackup.c
@@ -9,31 +9,41 @@
* 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;
}