summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorGravatar Martin Szulecki2013-01-07 22:29:24 +0100
committerGravatar Martin Szulecki2013-01-07 22:29:24 +0100
commit9dcab806cc3c136c37e165b03bf2d29c4afaeaa6 (patch)
tree44313e26ae77c34b1494c80b798d722e313ae187 /tools
parent18e24e587d2cce6214a9da111d7d720c196a169a (diff)
downloadlibimobiledevice-9dcab806cc3c136c37e165b03bf2d29c4afaeaa6.tar.gz
libimobiledevice-9dcab806cc3c136c37e165b03bf2d29c4afaeaa6.tar.bz2
idevicebackup2: Fix nasty "too long filename received" bug
If the device is sending files to the host, it sometimes requires a bit more time to process them before sending. This appeared to happen mostly for larger sqlite databases which appear to get some preprocessing on the device. In such a "wait" situation, we receive no data and need to retry reading the filename length again. Due to a code bug though which didn't reset the last read length to zero, this length was incorrectly alternating between 1 and 16777216 due to the byte swapping. This ulitmativly lead to a broken backup process. Now we properly wait for the device to preprocess any file before sending the filename to the host.
Diffstat (limited to 'tools')
-rw-r--r--tools/idevicebackup2.c103
1 files changed, 68 insertions, 35 deletions
diff --git a/tools/idevicebackup2.c b/tools/idevicebackup2.c
index ad3f0f6..c32e2e4 100644
--- a/tools/idevicebackup2.c
+++ b/tools/idevicebackup2.c
@@ -760,6 +760,52 @@ static void mb2_handle_send_files(plist_t message, const char *backup_dir)
}
}
+static int mb2_receive_filename(char** filename)
+{
+ uint32_t nlen = 0;
+ uint32_t rlen = 0;
+
+ do {
+ nlen = 0;
+ rlen = 0;
+ mobilebackup2_receive_raw(mobilebackup2, (char*)&nlen, 4, &rlen);
+ nlen = be32toh(nlen);
+
+ if ((nlen == 0) && (rlen == 4)) {
+ // a zero length means no more files to receive
+ return 0;
+ } else if(rlen == 0) {
+ // device needs more time, waiting...
+ continue;
+ } else if (nlen > 4096) {
+ // filename length is too large
+ printf("ERROR: %s: too large filename length (%d)!\n", __func__, nlen);
+ return 0;
+ }
+
+ if (*filename != NULL) {
+ free(*filename);
+ *filename = NULL;
+ }
+
+ *filename = (char*)malloc(nlen+1);
+
+ rlen = 0;
+ mobilebackup2_receive_raw(mobilebackup2, *filename, nlen, &rlen);
+ if (rlen != nlen) {
+ printf("ERROR: %s: could not read filename\n", __func__);
+ return 0;
+ }
+
+ char* p = *filename;
+ p[rlen] = 0;
+
+ break;
+ } while(1 && !quit_flag);
+
+ return nlen;
+}
+
static int mb2_handle_receive_files(plist_t message, const char *backup_dir)
{
uint64_t backup_real_size = 0;
@@ -792,48 +838,30 @@ static int mb2_handle_receive_files(plist_t message, const char *backup_dir)
do {
if (quit_flag)
break;
- r = 0;
- mobilebackup2_receive_raw(mobilebackup2, (char*)&nlen, 4, &r);
- nlen = be32toh(nlen);
- if (nlen == 0) {
- // we're done here
- break;
- } else if (nlen > 4096) {
- // too very long path
- printf("ERROR: %s: too long device filename (%d)!\n", __func__, nlen);
- break;
- }
- if (dname != NULL)
- free(dname);
- dname = (char*)malloc(nlen+1);
- r = 0;
- mobilebackup2_receive_raw(mobilebackup2, dname, nlen, &r);
- if (r != nlen) {
- printf("ERROR: %s: could not read device filename\n", __func__);
- break;
- }
- dname[r] = 0;
- nlen = 0;
- mobilebackup2_receive_raw(mobilebackup2, (char*)&nlen, 4, &r);
- nlen = be32toh(nlen);
+
+ nlen = mb2_receive_filename(&dname);
if (nlen == 0) {
- printf("ERROR: %s: zero-length backup filename!\n", __func__);
- break;
- } else if (nlen > 4096) {
- printf("ERROR: %s: too long backup filename (%d)!\n", __func__, nlen);
break;
}
- fname = (char*)malloc(nlen+1);
- mobilebackup2_receive_raw(mobilebackup2, fname, nlen, &r);
- if (r != nlen) {
- printf("ERROR: %s: could not receive backup filename!\n", __func__);
+
+ nlen = mb2_receive_filename(&fname);
+ if (!nlen) {
break;
}
- fname[r] = 0;
- if (bname != NULL)
+
+ if (bname != NULL) {
free(bname);
+ bname = NULL;
+ }
+
bname = build_path(backup_dir, fname, NULL);
- free(fname);
+
+ if (fname != NULL) {
+ free(fname);
+ fname = NULL;
+ }
+
+ r = 0;
nlen = 0;
mobilebackup2_receive_raw(mobilebackup2, (char*)&nlen, 4, &r);
if (r != 4) {
@@ -841,8 +869,10 @@ static int mb2_handle_receive_files(plist_t message, const char *backup_dir)
break;
}
nlen = be32toh(nlen);
+
last_code = code;
code = 0;
+
mobilebackup2_receive_raw(mobilebackup2, &code, 1, &r);
if (r != 1) {
printf("ERROR: %s: could not receive code!\n", __func__);
@@ -915,6 +945,9 @@ static int mb2_handle_receive_files(plist_t message, const char *backup_dir)
}
} while (1);
+ if (fname != NULL)
+ free(fname);
+
/* if there are leftovers to read, finish up cleanly */
if ((int)nlen-1 > 0) {
PRINT_VERBOSE(1, "\nDiscarding current data hunk.\n");