summaryrefslogtreecommitdiffstats
path: root/tools/idevicebackup2.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/idevicebackup2.c')
-rw-r--r--tools/idevicebackup2.c261
1 files changed, 174 insertions, 87 deletions
diff --git a/tools/idevicebackup2.c b/tools/idevicebackup2.c
index 5d067bf..6e35abd 100644
--- a/tools/idevicebackup2.c
+++ b/tools/idevicebackup2.c
@@ -25,13 +25,9 @@
#include <errno.h>
#include <stdlib.h>
#include <signal.h>
-#include <glib.h>
-#include <glib/gstdio.h>
#include <unistd.h>
-
-#if !GLIB_CHECK_VERSION(2,25,0)
-typedef struct stat GStatBuf;
-#endif
+#include <dirent.h>
+#include <libgen.h>
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
@@ -39,6 +35,8 @@ typedef struct stat GStatBuf;
#include <libimobiledevice/notification_proxy.h>
#include <libimobiledevice/afc.h>
+#include <endianness.h>
+
#define MOBILEBACKUP2_SERVICE_NAME "com.apple.mobilebackup2"
#define NP_SERVICE_NAME "com.apple.mobile.notification_proxy"
@@ -156,10 +154,95 @@ static void mobilebackup_afc_get_file_contents(const char *filename, char **data
afc_file_close(afc, f);
}
+static char *str_toupper(char* str)
+{
+ char *res = strdup(str);
+ int i;
+ for (i = 0; i < strlen(res); i++) {
+ res[i] = toupper(res[i]);
+ }
+ return res;
+}
+
+static int __mkdir(const char* path, int mode)
+{
+#ifdef WIN32
+ return mkdir(path);
+#else
+ return mkdir(path, mode);
+#endif
+}
+
+int mkdir_with_parents(const char *dir, int mode)
+{
+ if (!dir) return -1;
+ if (__mkdir(dir, mode) == 0) {
+ return 0;
+ } else {
+ if (errno == EEXIST) return 0;
+ }
+ int res;
+ char *parent = strdup(dir);
+ parent = dirname(parent);
+ if (parent) {
+ res = mkdir_with_parents(parent, mode);
+ } else {
+ res = -1;
+ }
+ free(parent);
+ if (res == 0) {
+ mkdir_with_parents(dir, mode);
+ }
+ return res;
+}
+
+char* build_path(const char* elem, ...)
+{
+ if (!elem) return NULL;
+ va_list args;
+ int len = strlen(elem)+1;
+ va_start(args, elem);
+ char *arg = va_arg(args, char*);
+ while (arg) {
+ len += strlen(arg)+1;
+ arg = va_arg(args, char*);
+ }
+ va_end(args);
+
+ char* out = (char*)malloc(len);
+ strcpy(out, elem);
+
+ va_start(args, elem);
+ arg = va_arg(args, char*);
+ while (arg) {
+ strcat(out, "/");
+ strcat(out, arg);
+ arg = va_arg(args, char*);
+ }
+ va_end(args);
+ return out;
+}
+
+static char* format_size_for_display(uint64_t size)
+{
+ char buf[32];
+ double sz;
+ if (size >= 1000000000LL) {
+ sz = ((double)size / 1000000000.0f);
+ sprintf(buf, "%0.1f GB", sz);
+ } else if (size >= 1000000LL) {
+ sz = ((double)size / 1000000.0f);
+ sprintf(buf, "%0.1f MB", sz);
+ } else if (size >= 1000LL) {
+ sz = ((double)size / 1000.0f);
+ sprintf(buf, "%0.1f kB", sz);
+ }
+ return strdup(buf);
+}
+
static plist_t mobilebackup_factory_info_plist_new()
{
/* gather data from lockdown */
- GTimeVal tv = {0, 0};
plist_t value_node = NULL;
plist_t root_node = NULL;
char *uuid = NULL;
@@ -189,8 +272,7 @@ static plist_t mobilebackup_factory_info_plist_new()
if (value_node)
plist_dict_insert_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, 0));
+ plist_dict_insert_item(ret, "Last Backup Date", plist_new_date(time(NULL), 0));
value_node = plist_dict_get_item(root_node, "PhoneNumber");
if (value_node && (plist_get_node_type(value_node) == PLIST_STRING)) {
@@ -215,7 +297,7 @@ static plist_t mobilebackup_factory_info_plist_new()
plist_dict_insert_item(ret, "Target Type", plist_new_string("Device"));
/* uppercase */
- uuid_uppercase = g_ascii_strup(uuid, -1);
+ uuid_uppercase = str_toupper(uuid);
plist_dict_insert_item(ret, "Unique Identifier", plist_new_string(uuid_uppercase));
free(uuid_uppercase);
free(uuid);
@@ -246,9 +328,11 @@ static plist_t mobilebackup_factory_info_plist_new()
for (i = 0; itunesfiles[i]; i++) {
data_buf = NULL;
data_size = 0;
- gchar *fname = g_strconcat("/iTunes_Control/iTunes/", itunesfiles[i], NULL);
+ char *fname = (char*)malloc(strlen("/iTunes_Control/iTunes/") + strlen(itunesfiles[i]) + 1);
+ strcpy(fname, "/iTunes_Control/iTunes/");
+ strcat(fname, itunesfiles[i]);
mobilebackup_afc_get_file_contents(fname, &data_buf, &data_size);
- g_free(fname);
+ free(fname);
if (data_buf) {
plist_dict_insert_item(files, itunesfiles[i], plist_new_data(data_buf, data_size));
free(data_buf);
@@ -358,10 +442,10 @@ static int mb2_status_check_snapshot_state(const char *path, const char *uuid, c
{
int ret = -1;
plist_t status_plist = NULL;
- gchar *file_path = g_build_path(G_DIR_SEPARATOR_S, path, uuid, "Status.plist", NULL);
+ char *file_path = build_path(path, uuid, "Status.plist", NULL);
plist_read_from_filename(&status_plist, file_path);
- g_free(file_path);
+ free(file_path);
if (!status_plist) {
printf("Could not read Status.plist!\n");
return ret;
@@ -486,7 +570,7 @@ static void print_progress_real(double progress, int flush)
static void print_progress(uint64_t current, uint64_t total)
{
- gchar *format_size = NULL;
+ char *format_size = NULL;
double progress = ((double)current/(double)total)*100;
if (progress < 0)
return;
@@ -496,12 +580,12 @@ static void print_progress(uint64_t current, uint64_t total)
print_progress_real((double)progress, 0);
- format_size = g_format_size_for_display(current);
+ format_size = format_size_for_display(current);
PRINT_VERBOSE(1, " (%s", format_size);
- g_free(format_size);
- format_size = g_format_size_for_display(total);
+ free(format_size);
+ format_size = format_size_for_display(total);
PRINT_VERBOSE(1, "/%s) ", format_size);
- g_free(format_size);
+ free(format_size);
fflush(stdout);
if (progress == 100)
@@ -534,7 +618,7 @@ static int mb2_handle_send_file(const char *backup_dir, const char *path, plist_
uint32_t nlen = 0;
uint32_t pathlen = strlen(path);
uint32_t bytes = 0;
- gchar *localfile = g_build_path(G_DIR_SEPARATOR_S, backup_dir, path, NULL);
+ char *localfile = build_path(backup_dir, path, NULL);
char buf[32768];
struct stat fst;
@@ -549,7 +633,7 @@ static int mb2_handle_send_file(const char *backup_dir, const char *path, plist_
mobilebackup2_error_t err;
/* send path length */
- nlen = GUINT32_TO_BE(pathlen);
+ nlen = htobe32(pathlen);
err = mobilebackup2_send_raw(mobilebackup2, (const char*)&nlen, sizeof(nlen), &bytes);
if (err != MOBILEBACKUP2_E_SUCCESS) {
goto leave_proto_err;
@@ -578,9 +662,9 @@ static int mb2_handle_send_file(const char *backup_dir, const char *path, plist_
total = fst.st_size;
- gchar *format_size = g_format_size_for_display(total);
+ char *format_size = format_size_for_display(total);
PRINT_VERBOSE(1, "Sending '%s' (%s)\n", path, format_size);
- g_free(format_size);
+ free(format_size);
if (total == 0) {
errcode = 0;
@@ -598,7 +682,7 @@ static int mb2_handle_send_file(const char *backup_dir, const char *path, plist_
do {
length = ((total-sent) < (off_t)sizeof(buf)) ? (uint32_t)total-sent : (uint32_t)sizeof(buf);
/* send data size (file size + 1) */
- nlen = GUINT32_TO_BE(length+1);
+ nlen = htobe32(length+1);
memcpy(buf, &nlen, sizeof(nlen));
buf[4] = CODE_FILE_DATA;
err = mobilebackup2_send_raw(mobilebackup2, (const char*)buf, 5, &bytes);
@@ -634,7 +718,7 @@ leave:
if (errcode == 0) {
result = 0;
nlen = 1;
- nlen = GUINT32_TO_BE(nlen);
+ nlen = htobe32(nlen);
memcpy(buf, &nlen, 4);
buf[4] = CODE_SUCCESS;
mobilebackup2_send_raw(mobilebackup2, buf, 5, &bytes);
@@ -646,7 +730,7 @@ leave:
mb2_multi_status_add_file_error(*errplist, path, errno_to_device_error(errcode), errdesc);
length = strlen(errdesc);
- nlen = GUINT32_TO_BE(length+1);
+ nlen = htobe32(length+1);
memcpy(buf, &nlen, 4);
buf[4] = CODE_ERROR_LOCAL;
slen = 5;
@@ -664,7 +748,7 @@ leave:
leave_proto_err:
if (f)
fclose(f);
- g_free(localfile);
+ free(localfile);
return result;
}
@@ -726,7 +810,7 @@ static int mb2_handle_receive_files(plist_t message, const char *backup_dir)
char buf[32768];
char *fname = NULL;
char *dname = NULL;
- gchar *bname = NULL;
+ char *bname = NULL;
char code = 0;
char last_code = 0;
plist_t node = NULL;
@@ -748,7 +832,7 @@ static int mb2_handle_receive_files(plist_t message, const char *backup_dir)
break;
r = 0;
mobilebackup2_receive_raw(mobilebackup2, (char*)&nlen, 4, &r);
- nlen = GUINT32_FROM_BE(nlen);
+ nlen = be32toh(nlen);
if (nlen == 0) {
// we're done here
break;
@@ -769,7 +853,7 @@ static int mb2_handle_receive_files(plist_t message, const char *backup_dir)
dname[r] = 0;
nlen = 0;
mobilebackup2_receive_raw(mobilebackup2, (char*)&nlen, 4, &r);
- nlen = GUINT32_FROM_BE(nlen);
+ nlen = be32toh(nlen);
if (nlen == 0) {
printf("ERROR: %s: zero-length backup filename!\n", __func__);
break;
@@ -785,8 +869,8 @@ static int mb2_handle_receive_files(plist_t message, const char *backup_dir)
}
fname[r] = 0;
if (bname != NULL)
- g_free(bname);
- bname = g_build_path(G_DIR_SEPARATOR_S, backup_dir, fname, NULL);
+ free(bname);
+ bname = build_path(backup_dir, fname, NULL);
free(fname);
nlen = 0;
mobilebackup2_receive_raw(mobilebackup2, (char*)&nlen, 4, &r);
@@ -794,7 +878,7 @@ static int mb2_handle_receive_files(plist_t message, const char *backup_dir)
printf("ERROR: %s: could not receive code length!\n", __func__);
break;
}
- nlen = GUINT32_FROM_BE(nlen);
+ nlen = be32toh(nlen);
last_code = code;
code = 0;
mobilebackup2_receive_raw(mobilebackup2, &code, 1, &r);
@@ -837,7 +921,7 @@ static int mb2_handle_receive_files(plist_t message, const char *backup_dir)
break;
nlen = 0;
mobilebackup2_receive_raw(mobilebackup2, (char*)&nlen, 4, &r);
- nlen = GUINT32_FROM_BE(nlen);
+ nlen = be32toh(nlen);
if (nlen > 0) {
last_code = code;
mobilebackup2_receive_raw(mobilebackup2, &code, 1, &r);
@@ -880,7 +964,7 @@ static int mb2_handle_receive_files(plist_t message, const char *backup_dir)
/* clean up */
if (bname != NULL)
- g_free(bname);
+ free(bname);
if (dname != NULL)
free(dname);
@@ -905,37 +989,37 @@ static void mb2_handle_list_directory(plist_t message, const char *backup_dir)
return;
}
- gchar *path = g_build_path(G_DIR_SEPARATOR_S, backup_dir, str, NULL);
+ char *path = build_path(backup_dir, str, NULL);
free(str);
plist_t dirlist = plist_new_dict();
- GDir *cur_dir = g_dir_open(path, 0, NULL);
+ DIR* cur_dir = opendir(path);
if (cur_dir) {
- gchar *dir_file;
- while ((dir_file = (gchar *)g_dir_read_name(cur_dir))) {
- gchar *fpath = g_build_filename(path, dir_file, NULL);
+ struct dirent* ep;
+ while ((ep = readdir(cur_dir))) {
+ char *fpath = build_path(path, ep->d_name, NULL);
if (fpath) {
plist_t fdict = plist_new_dict();
- GStatBuf st;
- g_stat(fpath, &st);
+ struct stat st;
+ stat(fpath, &st);
const char *ftype = "DLFileTypeUnknown";
- if (g_file_test(fpath, G_FILE_TEST_IS_DIR)) {
+ if (S_ISDIR(st.st_mode)) {
ftype = "DLFileTypeDirectory";
- } else if (g_file_test(fpath, G_FILE_TEST_IS_REGULAR)) {
+ } else if (S_ISREG(st.st_mode)) {
ftype = "DLFileTypeRegular";
}
plist_dict_insert_item(fdict, "DLFileType", plist_new_string(ftype));
plist_dict_insert_item(fdict, "DLFileSize", plist_new_uint(st.st_size));
plist_dict_insert_item(fdict, "DLFileModificationDate", plist_new_date(st.st_mtime, 0));
- plist_dict_insert_item(dirlist, dir_file, fdict);
- g_free(fpath);
+ plist_dict_insert_item(dirlist, ep->d_name, fdict);
+ free(fpath);
}
}
- g_dir_close(cur_dir);
+ closedir(cur_dir);
}
- g_free(path);
+ free(path);
/* TODO error handling */
mobilebackup2_error_t err = mobilebackup2_send_status_response(mobilebackup2, 0, NULL, dirlist);
@@ -955,24 +1039,24 @@ static void mb2_handle_make_directory(plist_t message, const char *backup_dir)
char *errdesc = NULL;
plist_get_string_val(dir, &str);
- gchar *newpath = g_build_path(G_DIR_SEPARATOR_S, backup_dir, str, NULL);
- g_free(str);
+ char *newpath = build_path(backup_dir, str, NULL);
+ free(str);
- if (g_mkdir_with_parents(newpath, 0755) < 0) {
+ if (mkdir_with_parents(newpath, 0755) < 0) {
errdesc = strerror(errno);
if (errno != EEXIST) {
printf("mkdir: %s (%d)\n", errdesc, errno);
}
errcode = errno_to_device_error(errno);
}
- g_free(newpath);
+ free(newpath);
mobilebackup2_error_t err = mobilebackup2_send_status_response(mobilebackup2, errcode, errdesc, NULL);
if (err != MOBILEBACKUP2_E_SUCCESS) {
printf("Could not send status response, error %d\n", err);
}
}
-static void mb2_copy_file_by_path(const gchar *src, const gchar *dst)
+static void mb2_copy_file_by_path(const char *src, const char *dst)
{
FILE *from, *to;
char buf[BUFSIZ];
@@ -1004,43 +1088,45 @@ static void mb2_copy_file_by_path(const gchar *src, const gchar *dst)
}
}
-static void mb2_copy_directory_by_path(const gchar *src, const gchar *dst)
+static void mb2_copy_directory_by_path(const char *src, const char *dst)
{
if (!src || !dst) {
return;
}
+ struct stat st;
+
/* if src does not exist */
- if (!g_file_test(src, G_FILE_TEST_EXISTS)) {
+ if ((stat(src, &st) < 0) || !S_ISDIR(st.st_mode)) {
printf("ERROR: Source directory does not exist '%s': %s (%d)\n", src, strerror(errno), errno);
return;
}
/* if dst directory does not exist */
- if (!g_file_test(dst, G_FILE_TEST_IS_DIR)) {
+ if ((stat(dst, &st) < 0) || !S_ISDIR(st.st_mode)) {
/* create it */
- if (g_mkdir_with_parents(dst, 0755) < 0) {
+ if (mkdir_with_parents(dst, 0755) < 0) {
printf("ERROR: Unable to create destination directory '%s': %s (%d)\n", dst, strerror(errno), errno);
return;
}
}
/* loop over src directory contents */
- GDir *cur_dir = g_dir_open(src, 0, NULL);
+ DIR *cur_dir = opendir(src);
if (cur_dir) {
- gchar *dir_file;
- while ((dir_file = (gchar *)g_dir_read_name(cur_dir))) {
- gchar *srcpath = g_build_filename(src, dir_file, NULL);
- gchar *dstpath = g_build_filename(dst, dir_file, NULL);
+ struct dirent* ep;
+ while ((ep = readdir(cur_dir))) {
+ char *srcpath = build_path(src, ep->d_name, NULL);
+ char *dstpath = build_path(dst, ep->d_name, NULL);
if (srcpath && dstpath) {
/* copy file */
mb2_copy_file_by_path(srcpath, dstpath);
- g_free(srcpath);
- g_free(dstpath);
+ free(srcpath);
+ free(dstpath);
}
}
- g_dir_close(cur_dir);
+ closedir(cur_dir);
}
}
@@ -1196,10 +1282,10 @@ int main(int argc, char *argv[])
}
/* backup directory must contain an Info.plist */
- gchar *info_path = g_build_path(G_DIR_SEPARATOR_S, backup_directory, uuid, "Info.plist", NULL);
+ char *info_path = build_path(backup_directory, uuid, "Info.plist", NULL);
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 for UUID %s.\n", backup_directory, uuid);
return -1;
}
@@ -1328,9 +1414,9 @@ checkpoint:
PRINT_VERBOSE(1, "Starting backup...\n");
/* make sure backup device sub-directory exists */
- gchar *devbackupdir = g_build_path(G_DIR_SEPARATOR_S, backup_directory, uuid, NULL);
- g_mkdir(devbackupdir, 0755);
- g_free(devbackupdir);
+ char *devbackupdir = build_path(backup_directory, uuid, NULL);
+ __mkdir(devbackupdir, 0755);
+ free(devbackupdir);
/* TODO: check domain com.apple.mobile.backup key RequiresEncrypt and WillEncrypt with lockdown */
/* TODO: verify battery on AC enough battery remaining */
@@ -1343,7 +1429,7 @@ checkpoint:
info_plist = mobilebackup_factory_info_plist_new();
remove(info_path);
plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML);
- g_free(info_path);
+ free(info_path);
plist_free(info_plist);
info_plist = NULL;
@@ -1493,9 +1579,9 @@ checkpoint:
char *str = NULL;
plist_get_string_val(val, &str);
if (str) {
- gchar *newpath = g_build_path(G_DIR_SEPARATOR_S, backup_directory, str, NULL);
- g_free(str);
- gchar *oldpath = g_build_path(G_DIR_SEPARATOR_S, backup_directory, key, NULL);
+ char *newpath = build_path(backup_directory, str, NULL);
+ free(str);
+ char *oldpath = build_path(backup_directory, key, NULL);
remove(newpath);
if (rename(oldpath, newpath) < 0) {
@@ -1504,8 +1590,8 @@ checkpoint:
errdesc = strerror(errno);
break;
}
- g_free(oldpath);
- g_free(newpath);
+ free(oldpath);
+ free(newpath);
}
free(key);
key = NULL;
@@ -1534,14 +1620,14 @@ checkpoint:
char *str = NULL;
plist_get_string_val(val, &str);
if (str) {
- gchar *newpath = g_build_path(G_DIR_SEPARATOR_S, backup_directory, str, NULL);
- g_free(str);
+ char *newpath = build_path(backup_directory, str, NULL);
+ free(str);
if (remove(newpath) < 0) {
printf("Could not remove '%s': %s (%d)\n", newpath, strerror(errno), errno);
errcode = errno_to_device_error(errno);
errdesc = strerror(errno);
}
- g_free(newpath);
+ free(newpath);
}
}
}
@@ -1560,23 +1646,24 @@ checkpoint:
plist_get_string_val(srcpath, &src);
plist_get_string_val(dstpath, &dst);
if (src && dst) {
- gchar *oldpath = g_build_path(G_DIR_SEPARATOR_S, backup_directory, src, NULL);
- gchar *newpath = g_build_path(G_DIR_SEPARATOR_S, backup_directory, dst, NULL);
+ char *oldpath = build_path(backup_directory, src, NULL);
+ char *newpath = build_path(backup_directory, dst, NULL);
+ struct stat st;
PRINT_VERBOSE(1, "Copying '%s' to '%s'\n", src, dst);
/* check that src exists */
- if (g_file_test(oldpath, G_FILE_TEST_IS_DIR)) {
+ if ((stat(oldpath, &st) == 0) && S_ISDIR(st.st_mode)) {
mb2_copy_directory_by_path(oldpath, newpath);
- } else if (g_file_test(oldpath, G_FILE_TEST_IS_REGULAR)) {
+ } else if ((stat(oldpath, &st) == 0) && S_ISREG(st.st_mode)) {
mb2_copy_file_by_path(oldpath, newpath);
}
- g_free(newpath);
- g_free(oldpath);
+ free(newpath);
+ free(oldpath);
}
- g_free(src);
- g_free(dst);
+ free(src);
+ free(dst);
}
err = mobilebackup2_send_status_response(mobilebackup2, errcode, errdesc, plist_new_dict());