diff options
author | Martin Szulecki | 2013-01-07 22:29:24 +0100 |
---|---|---|
committer | Martin Szulecki | 2013-01-07 22:29:24 +0100 |
commit | 9dcab806cc3c136c37e165b03bf2d29c4afaeaa6 (patch) | |
tree | 44313e26ae77c34b1494c80b798d722e313ae187 | |
parent | 18e24e587d2cce6214a9da111d7d720c196a169a (diff) | |
download | libimobiledevice-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.
-rw-r--r-- | tools/idevicebackup2.c | 103 |
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"); |