/libimobiledevice-tools/idevicebackup2/idevicebackup2.cpp

https://bitbucket.org/hjwhang/libimobiledevice-win32 · C++ · 2303 lines · 1956 code · 243 blank · 104 comment · 648 complexity · 73371ec58a9f1749a9458a8aa5d986cb MD5 · raw file

  1. /*
  2. * idevicebackup2.c
  3. * Command line interface to use the device's backup and restore service
  4. *
  5. * Copyright (c) 2009-2010 Martin Szulecki All Rights Reserved.
  6. * Copyright (c) 2010 Nikias Bassen All Rights Reserved.
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2.1 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. */
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <errno.h>
  25. #include <stdlib.h>
  26. #include <signal.h>
  27. #include <unistd.h>
  28. #include <dirent.h>
  29. #include <libgen.h>
  30. #include <ctype.h>
  31. #include <time.h>
  32. #include <libimobiledevice/libimobiledevice.h>
  33. #include <libimobiledevice/lockdown.h>
  34. #include <libimobiledevice/mobilebackup2.h>
  35. #include <libimobiledevice/notification_proxy.h>
  36. #include <libimobiledevice/afc.h>
  37. #include <endianness.h>
  38. #define MOBILEBACKUP2_SERVICE_NAME "com.apple.mobilebackup2"
  39. #define NP_SERVICE_NAME "com.apple.mobile.notification_proxy"
  40. #define LOCK_ATTEMPTS 50
  41. #define LOCK_WAIT 200000
  42. #ifdef WIN32
  43. #include <windows.h>
  44. #include <conio.h>
  45. #include <direct.h>
  46. #define sleep(x) Sleep(x*1000)
  47. #else
  48. #include <termios.h>
  49. #include <sys/statvfs.h>
  50. #endif
  51. #ifndef __func__
  52. # define __func__ __FUNCTION__
  53. #endif
  54. #define CODE_SUCCESS 0x00
  55. #define CODE_ERROR_LOCAL 0x06
  56. #define CODE_ERROR_REMOTE 0x0b
  57. #define CODE_FILE_DATA 0x0c
  58. static int verbose = 1;
  59. static int quit_flag = 0;
  60. #define PRINT_VERBOSE(min_level, ...) if (verbose >= min_level) { printf(__VA_ARGS__); };
  61. enum cmd_mode {
  62. CMD_BACKUP,
  63. CMD_RESTORE,
  64. CMD_INFO,
  65. CMD_LIST,
  66. CMD_UNBACK,
  67. CMD_CHANGEPW,
  68. CMD_LEAVE
  69. };
  70. enum plist_format_t {
  71. PLIST_FORMAT_XML,
  72. PLIST_FORMAT_BINARY
  73. };
  74. enum cmd_flags {
  75. CMD_FLAG_RESTORE_SYSTEM_FILES = (1 << 1),
  76. CMD_FLAG_RESTORE_REBOOT = (1 << 2),
  77. CMD_FLAG_RESTORE_COPY_BACKUP = (1 << 3),
  78. CMD_FLAG_RESTORE_SETTINGS = (1 << 4),
  79. CMD_FLAG_RESTORE_REMOVE_ITEMS = (1 << 5),
  80. CMD_FLAG_ENCRYPTION_ENABLE = (1 << 6),
  81. CMD_FLAG_ENCRYPTION_DISABLE = (1 << 7),
  82. CMD_FLAG_ENCRYPTION_CHANGEPW = (1 << 8)
  83. };
  84. static int backup_domain_changed = 0;
  85. static void notify_cb(const char *notification, void *userdata)
  86. {
  87. if (!strcmp(notification, NP_SYNC_CANCEL_REQUEST)) {
  88. PRINT_VERBOSE(1, "User has cancelled the backup process on the device.\n");
  89. quit_flag++;
  90. } else if (!strcmp(notification, NP_BACKUP_DOMAIN_CHANGED)) {
  91. backup_domain_changed = 1;
  92. } else {
  93. PRINT_VERBOSE(1, "Unhandled notification '%s' (TODO: implement)\n", notification);
  94. }
  95. }
  96. static void free_dictionary(char **dictionary)
  97. {
  98. int i = 0;
  99. if (!dictionary)
  100. return;
  101. for (i = 0; dictionary[i]; i++) {
  102. free(dictionary[i]);
  103. }
  104. free(dictionary);
  105. }
  106. static void mobilebackup_afc_get_file_contents(afc_client_t afc, const char *filename, char **data, uint64_t *size)
  107. {
  108. if (!afc || !data || !size) {
  109. return;
  110. }
  111. char **fileinfo = NULL;
  112. uint32_t fsize = 0;
  113. afc_get_file_info(afc, filename, &fileinfo);
  114. if (!fileinfo) {
  115. return;
  116. }
  117. int i;
  118. for (i = 0; fileinfo[i]; i+=2) {
  119. if (!strcmp(fileinfo[i], "st_size")) {
  120. fsize = atol(fileinfo[i+1]);
  121. break;
  122. }
  123. }
  124. free_dictionary(fileinfo);
  125. if (fsize == 0) {
  126. return;
  127. }
  128. uint64_t f = 0;
  129. afc_file_open(afc, filename, AFC_FOPEN_RDONLY, &f);
  130. if (!f) {
  131. return;
  132. }
  133. char *buf = (char*)malloc((uint32_t)fsize);
  134. uint32_t done = 0;
  135. while (done < fsize) {
  136. uint32_t bread = 0;
  137. afc_file_read(afc, f, buf+done, 65536, &bread);
  138. if (bread > 0) {
  139. } else {
  140. break;
  141. }
  142. done += bread;
  143. }
  144. if (done == fsize) {
  145. *size = fsize;
  146. *data = buf;
  147. } else {
  148. free(buf);
  149. }
  150. afc_file_close(afc, f);
  151. }
  152. static char *str_toupper(char* str)
  153. {
  154. char *res = strdup(str);
  155. unsigned int i;
  156. for (i = 0; i < strlen(res); i++) {
  157. res[i] = toupper(res[i]);
  158. }
  159. return res;
  160. }
  161. static int __mkdir(const char* path, int mode)
  162. {
  163. #ifdef WIN32
  164. return _mkdir(path);
  165. #else
  166. return mkdir(path, mode);
  167. #endif
  168. }
  169. static int mkdir_with_parents(const char *dir, int mode)
  170. {
  171. if (!dir) return -1;
  172. if (__mkdir(dir, mode) == 0) {
  173. return 0;
  174. } else {
  175. if (errno == EEXIST) return 0;
  176. }
  177. int res;
  178. char *parent = strdup(dir);
  179. char *parentdir = dirname(parent);
  180. if (parentdir) {
  181. res = mkdir_with_parents(parentdir, mode);
  182. } else {
  183. res = -1;
  184. }
  185. free(parent);
  186. if (res == 0) {
  187. mkdir_with_parents(dir, mode);
  188. }
  189. return res;
  190. }
  191. static char* build_path(const char* elem, ...)
  192. {
  193. if (!elem) return NULL;
  194. va_list args;
  195. int len = strlen(elem)+1;
  196. va_start(args, elem);
  197. char *arg = va_arg(args, char*);
  198. while (arg) {
  199. len += strlen(arg)+1;
  200. arg = va_arg(args, char*);
  201. }
  202. va_end(args);
  203. char* out = (char*)malloc(len);
  204. strcpy(out, elem);
  205. va_start(args, elem);
  206. arg = va_arg(args, char*);
  207. while (arg) {
  208. strcat(out, "/");
  209. strcat(out, arg);
  210. arg = va_arg(args, char*);
  211. }
  212. va_end(args);
  213. return out;
  214. }
  215. static char* format_size_for_display(uint64_t size)
  216. {
  217. char buf[32];
  218. double sz;
  219. if (size >= 1000000000LL) {
  220. sz = ((double)size / 1000000000.0f);
  221. sprintf(buf, "%0.1f GB", sz);
  222. } else if (size >= 1000000LL) {
  223. sz = ((double)size / 1000000.0f);
  224. sprintf(buf, "%0.1f MB", sz);
  225. } else if (size >= 1000LL) {
  226. sz = ((double)size / 1000.0f);
  227. sprintf(buf, "%0.1f kB", sz);
  228. } else {
  229. sprintf(buf, "%d Bytes", (int)size);
  230. }
  231. return strdup(buf);
  232. }
  233. static plist_t mobilebackup_factory_info_plist_new(const char* udid, lockdownd_client_t lockdown, afc_client_t afc)
  234. {
  235. /* gather data from lockdown */
  236. plist_t value_node = NULL;
  237. plist_t root_node = NULL;
  238. char *udid_uppercase = NULL;
  239. plist_t ret = plist_new_dict();
  240. /* get basic device information in one go */
  241. lockdownd_get_value(lockdown, NULL, NULL, &root_node);
  242. /* set fields we understand */
  243. value_node = plist_dict_get_item(root_node, "BuildVersion");
  244. plist_dict_insert_item(ret, "Build Version", plist_copy(value_node));
  245. value_node = plist_dict_get_item(root_node, "DeviceName");
  246. plist_dict_insert_item(ret, "Device Name", plist_copy(value_node));
  247. plist_dict_insert_item(ret, "Display Name", plist_copy(value_node));
  248. /* FIXME: How is the GUID generated? */
  249. plist_dict_insert_item(ret, "GUID", plist_new_string("---"));
  250. value_node = plist_dict_get_item(root_node, "IntegratedCircuitCardIdentity");
  251. if (value_node)
  252. plist_dict_insert_item(ret, "ICCID", plist_copy(value_node));
  253. value_node = plist_dict_get_item(root_node, "InternationalMobileEquipmentIdentity");
  254. if (value_node)
  255. plist_dict_insert_item(ret, "IMEI", plist_copy(value_node));
  256. plist_dict_insert_item(ret, "Last Backup Date", plist_new_date(time(NULL), 0));
  257. value_node = plist_dict_get_item(root_node, "PhoneNumber");
  258. if (value_node && (plist_get_node_type(value_node) == PLIST_STRING)) {
  259. plist_dict_insert_item(ret, "Phone Number", plist_copy(value_node));
  260. }
  261. value_node = plist_dict_get_item(root_node, "ProductType");
  262. plist_dict_insert_item(ret, "Product Type", plist_copy(value_node));
  263. value_node = plist_dict_get_item(root_node, "ProductVersion");
  264. plist_dict_insert_item(ret, "Product Version", plist_copy(value_node));
  265. value_node = plist_dict_get_item(root_node, "SerialNumber");
  266. plist_dict_insert_item(ret, "Serial Number", plist_copy(value_node));
  267. /* FIXME Sync Settings? */
  268. value_node = plist_dict_get_item(root_node, "UniqueDeviceID");
  269. plist_dict_insert_item(ret, "Target Identifier", plist_new_string(udid));
  270. plist_dict_insert_item(ret, "Target Type", plist_new_string("Device"));
  271. /* uppercase */
  272. udid_uppercase = str_toupper((char*)udid);
  273. plist_dict_insert_item(ret, "Unique Identifier", plist_new_string(udid_uppercase));
  274. free(udid_uppercase);
  275. char *data_buf = NULL;
  276. uint64_t data_size = 0;
  277. mobilebackup_afc_get_file_contents(afc, "/Books/iBooksData2.plist", &data_buf, &data_size);
  278. if (data_buf) {
  279. plist_dict_insert_item(ret, "iBooks Data 2", plist_new_data(data_buf, data_size));
  280. free(data_buf);
  281. }
  282. plist_t files = plist_new_dict();
  283. const char *itunesfiles[] = {
  284. "ApertureAlbumPrefs",
  285. "IC-Info.sidb",
  286. "IC-Info.sidv",
  287. "PhotosFolderAlbums",
  288. "PhotosFolderName",
  289. "PhotosFolderPrefs",
  290. "iPhotoAlbumPrefs",
  291. "iTunesApplicationIDs",
  292. "iTunesPrefs",
  293. "iTunesPrefs.plist",
  294. NULL
  295. };
  296. int i = 0;
  297. for (i = 0; itunesfiles[i]; i++) {
  298. data_buf = NULL;
  299. data_size = 0;
  300. char *fname = (char*)malloc(strlen("/iTunes_Control/iTunes/") + strlen(itunesfiles[i]) + 1);
  301. strcpy(fname, "/iTunes_Control/iTunes/");
  302. strcat(fname, itunesfiles[i]);
  303. mobilebackup_afc_get_file_contents(afc, fname, &data_buf, &data_size);
  304. free(fname);
  305. if (data_buf) {
  306. plist_dict_insert_item(files, itunesfiles[i], plist_new_data(data_buf, data_size));
  307. free(data_buf);
  308. }
  309. }
  310. plist_dict_insert_item(ret, "iTunes Files", files);
  311. plist_t itunes_settings = NULL;
  312. lockdownd_get_value(lockdown, "com.apple.iTunes", NULL, &itunes_settings);
  313. plist_dict_insert_item(ret, "iTunes Settings", itunes_settings ? itunes_settings : plist_new_dict());
  314. plist_dict_insert_item(ret, "iTunes Version", plist_new_string("10.0.1"));
  315. plist_free(root_node);
  316. return ret;
  317. }
  318. static void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length)
  319. {
  320. FILE *f;
  321. uint64_t size;
  322. *length = 0;
  323. f = fopen(filename, "rb");
  324. if (!f) {
  325. return;
  326. }
  327. fseek(f, 0, SEEK_END);
  328. size = ftell(f);
  329. rewind(f);
  330. if (size == 0) {
  331. return;
  332. }
  333. *buffer = (char*)malloc(sizeof(char)*size);
  334. fread(*buffer, sizeof(char), size, f);
  335. fclose(f);
  336. *length = size;
  337. }
  338. static void buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length)
  339. {
  340. FILE *f;
  341. f = fopen(filename, "ab");
  342. if (!f)
  343. f = fopen(filename, "wb");
  344. if (f) {
  345. fwrite(buffer, sizeof(char), length, f);
  346. fclose(f);
  347. }
  348. }
  349. static int plist_read_from_filename(plist_t *plist, const char *filename)
  350. {
  351. char *buffer = NULL;
  352. uint64_t length;
  353. if (!filename)
  354. return 0;
  355. buffer_read_from_filename(filename, &buffer, &length);
  356. if (!buffer) {
  357. return 0;
  358. }
  359. if ((length > 8) && (memcmp(buffer, "bplist00", 8) == 0)) {
  360. plist_from_bin(buffer, length, plist);
  361. } else {
  362. plist_from_xml(buffer, length, plist);
  363. }
  364. free(buffer);
  365. return 1;
  366. }
  367. static int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format)
  368. {
  369. char *buffer = NULL;
  370. uint32_t length;
  371. if (!plist || !filename)
  372. return 0;
  373. if (format == PLIST_FORMAT_XML)
  374. plist_to_xml(plist, &buffer, &length);
  375. else if (format == PLIST_FORMAT_BINARY)
  376. plist_to_bin(plist, &buffer, &length);
  377. else
  378. return 0;
  379. buffer_write_to_filename(filename, buffer, length);
  380. free(buffer);
  381. return 1;
  382. }
  383. static int mb2_status_check_snapshot_state(const char *path, const char *udid, const char *matches)
  384. {
  385. int ret = -1;
  386. plist_t status_plist = NULL;
  387. char *file_path = build_path(path, udid, "Status.plist", NULL);
  388. plist_read_from_filename(&status_plist, file_path);
  389. free(file_path);
  390. if (!status_plist) {
  391. printf("Could not read Status.plist!\n");
  392. return ret;
  393. }
  394. plist_t node = plist_dict_get_item(status_plist, "SnapshotState");
  395. if (node && (plist_get_node_type(node) == PLIST_STRING)) {
  396. char* sval = NULL;
  397. plist_get_string_val(node, &sval);
  398. if (sval) {
  399. ret = (strcmp(sval, matches) == 0) ? 1 : 0;
  400. free(sval);
  401. }
  402. } else {
  403. printf("%s: ERROR could not get SnapshotState key from Status.plist!\n", __func__);
  404. }
  405. plist_free(status_plist);
  406. return ret;
  407. }
  408. static void do_post_notification(idevice_t device, const char *notification)
  409. {
  410. lockdownd_service_descriptor_t service = NULL;
  411. np_client_t np;
  412. lockdownd_client_t lockdown = NULL;
  413. if (lockdownd_client_new_with_handshake(device, &lockdown, "idevicebackup") != LOCKDOWN_E_SUCCESS) {
  414. return;
  415. }
  416. lockdownd_start_service(lockdown, NP_SERVICE_NAME, &service);
  417. if (service && service->port) {
  418. np_client_new(device, service, &np);
  419. if (np) {
  420. np_post_notification(np, notification);
  421. np_client_free(np);
  422. }
  423. } else {
  424. printf("Could not start %s\n", NP_SERVICE_NAME);
  425. }
  426. if (service) {
  427. lockdownd_service_descriptor_free(service);
  428. service = NULL;
  429. }
  430. lockdownd_client_free(lockdown);
  431. }
  432. static void print_progress_real(double progress, int flush)
  433. {
  434. int i = 0;
  435. PRINT_VERBOSE(1, "\r[");
  436. for(i = 0; i < 50; i++) {
  437. if(i < progress / 2) {
  438. PRINT_VERBOSE(1, "=");
  439. } else {
  440. PRINT_VERBOSE(1, " ");
  441. }
  442. }
  443. PRINT_VERBOSE(1, "] %3.0f%%", progress);
  444. if (flush > 0) {
  445. fflush(stdout);
  446. if (progress == 100)
  447. PRINT_VERBOSE(1, "\n");
  448. }
  449. }
  450. static void print_progress(uint64_t current, uint64_t total)
  451. {
  452. char *format_size = NULL;
  453. double progress = ((double)current/(double)total)*100;
  454. if (progress < 0)
  455. return;
  456. if (progress > 100)
  457. progress = 100;
  458. print_progress_real((double)progress, 0);
  459. format_size = format_size_for_display(current);
  460. PRINT_VERBOSE(1, " (%s", format_size);
  461. free(format_size);
  462. format_size = format_size_for_display(total);
  463. PRINT_VERBOSE(1, "/%s) ", format_size);
  464. free(format_size);
  465. fflush(stdout);
  466. if (progress == 100)
  467. PRINT_VERBOSE(1, "\n");
  468. }
  469. static double overall_progress = 0;
  470. static void mb2_set_overall_progress(double progress)
  471. {
  472. if (progress > 0.0)
  473. overall_progress = progress;
  474. }
  475. static void mb2_set_overall_progress_from_message(plist_t message, char* identifier)
  476. {
  477. plist_t node = NULL;
  478. double progress = 0.0;
  479. if (!strcmp(identifier, "DLMessageDownloadFiles")) {
  480. node = plist_array_get_item(message, 3);
  481. } else if (!strcmp(identifier, "DLMessageUploadFiles")) {
  482. node = plist_array_get_item(message, 2);
  483. } else if (!strcmp(identifier, "DLMessageMoveFiles") || !strcmp(identifier, "DLMessageMoveItems")) {
  484. node = plist_array_get_item(message, 3);
  485. } else if (!strcmp(identifier, "DLMessageRemoveFiles") || !strcmp(identifier, "DLMessageRemoveItems")) {
  486. node = plist_array_get_item(message, 3);
  487. }
  488. if (node != NULL) {
  489. plist_get_real_val(node, &progress);
  490. mb2_set_overall_progress(progress);
  491. }
  492. }
  493. static void mb2_multi_status_add_file_error(plist_t status_dict, const char *path, int error_code, const char *error_message)
  494. {
  495. if (!status_dict) return;
  496. plist_t filedict = plist_new_dict();
  497. plist_dict_insert_item(filedict, "DLFileErrorString", plist_new_string(error_message));
  498. plist_dict_insert_item(filedict, "DLFileErrorCode", plist_new_uint(error_code));
  499. plist_dict_insert_item(status_dict, path, filedict);
  500. }
  501. static int errno_to_device_error(int errno_value)
  502. {
  503. switch (errno_value) {
  504. case ENOENT:
  505. return -6;
  506. case EEXIST:
  507. return -7;
  508. default:
  509. return -errno_value;
  510. }
  511. }
  512. #ifdef WIN32
  513. static int win32err_to_errno(int err_value)
  514. {
  515. switch (err_value) {
  516. case ERROR_FILE_NOT_FOUND:
  517. return ENOENT;
  518. case ERROR_ALREADY_EXISTS:
  519. return EEXIST;
  520. default:
  521. return EFAULT;
  522. }
  523. }
  524. #endif
  525. static int mb2_handle_send_file(mobilebackup2_client_t mobilebackup2, const char *backup_dir, const char *path, plist_t *errplist)
  526. {
  527. uint32_t nlen = 0;
  528. uint32_t pathlen = strlen(path);
  529. uint32_t bytes = 0;
  530. char *localfile = build_path(backup_dir, path, NULL);
  531. char buf[32768];
  532. struct stat fst;
  533. FILE *f = NULL;
  534. uint32_t slen = 0;
  535. int errcode = -1;
  536. int result = -1;
  537. uint32_t length;
  538. off_t total;
  539. off_t sent;
  540. mobilebackup2_error_t err;
  541. /* send path length */
  542. nlen = htobe32(pathlen);
  543. err = mobilebackup2_send_raw(mobilebackup2, (const char*)&nlen, sizeof(nlen), &bytes);
  544. if (err != MOBILEBACKUP2_E_SUCCESS) {
  545. goto leave_proto_err;
  546. }
  547. if (bytes != (uint32_t)sizeof(nlen)) {
  548. err = MOBILEBACKUP2_E_MUX_ERROR;
  549. goto leave_proto_err;
  550. }
  551. /* send path */
  552. err = mobilebackup2_send_raw(mobilebackup2, path, pathlen, &bytes);
  553. if (err != MOBILEBACKUP2_E_SUCCESS) {
  554. goto leave_proto_err;
  555. }
  556. if (bytes != pathlen) {
  557. err = MOBILEBACKUP2_E_MUX_ERROR;
  558. goto leave_proto_err;
  559. }
  560. if (stat(localfile, &fst) < 0) {
  561. if (errno != ENOENT)
  562. printf("%s: stat failed on '%s': %d\n", __func__, localfile, errno);
  563. errcode = errno;
  564. goto leave;
  565. }
  566. total = fst.st_size;
  567. char *format_size = format_size_for_display(total);
  568. PRINT_VERBOSE(1, "Sending '%s' (%s)\n", path, format_size);
  569. free(format_size);
  570. if (total == 0) {
  571. errcode = 0;
  572. goto leave;
  573. }
  574. f = fopen(localfile, "rb");
  575. if (!f) {
  576. printf("%s: Error opening local file '%s': %d\n", __func__, localfile, errno);
  577. errcode = errno;
  578. goto leave;
  579. }
  580. sent = 0;
  581. do {
  582. length = ((total-sent) < (off_t)sizeof(buf)) ? (uint32_t)total-sent : (uint32_t)sizeof(buf);
  583. /* send data size (file size + 1) */
  584. nlen = htobe32(length+1);
  585. memcpy(buf, &nlen, sizeof(nlen));
  586. buf[4] = CODE_FILE_DATA;
  587. err = mobilebackup2_send_raw(mobilebackup2, (const char*)buf, 5, &bytes);
  588. if (err != MOBILEBACKUP2_E_SUCCESS) {
  589. goto leave_proto_err;
  590. }
  591. if (bytes != 5) {
  592. goto leave_proto_err;
  593. }
  594. /* send file contents */
  595. size_t r = fread(buf, 1, sizeof(buf), f);
  596. if (r <= 0) {
  597. printf("%s: read error\n", __func__);
  598. errcode = errno;
  599. goto leave;
  600. }
  601. err = mobilebackup2_send_raw(mobilebackup2, buf, r, &bytes);
  602. if (err != MOBILEBACKUP2_E_SUCCESS) {
  603. goto leave_proto_err;
  604. }
  605. if (bytes != (uint32_t)r) {
  606. printf("Error: sent only %d of %d bytes\n", bytes, (int)r);
  607. goto leave_proto_err;
  608. }
  609. sent += r;
  610. } while (sent < total);
  611. fclose(f);
  612. f = NULL;
  613. errcode = 0;
  614. leave:
  615. if (errcode == 0) {
  616. result = 0;
  617. nlen = 1;
  618. nlen = htobe32(nlen);
  619. memcpy(buf, &nlen, 4);
  620. buf[4] = CODE_SUCCESS;
  621. mobilebackup2_send_raw(mobilebackup2, buf, 5, &bytes);
  622. } else {
  623. if (!*errplist) {
  624. *errplist = plist_new_dict();
  625. }
  626. char *errdesc = strerror(errcode);
  627. mb2_multi_status_add_file_error(*errplist, path, errno_to_device_error(errcode), errdesc);
  628. length = strlen(errdesc);
  629. nlen = htobe32(length+1);
  630. memcpy(buf, &nlen, 4);
  631. buf[4] = CODE_ERROR_LOCAL;
  632. slen = 5;
  633. memcpy(buf+slen, errdesc, length);
  634. slen += length;
  635. err = mobilebackup2_send_raw(mobilebackup2, (const char*)buf, slen, &bytes);
  636. if (err != MOBILEBACKUP2_E_SUCCESS) {
  637. printf("could not send message\n");
  638. }
  639. if (bytes != slen) {
  640. printf("could only send %d from %d\n", bytes, slen);
  641. }
  642. }
  643. leave_proto_err:
  644. if (f)
  645. fclose(f);
  646. free(localfile);
  647. return result;
  648. }
  649. static void mb2_handle_send_files(mobilebackup2_client_t mobilebackup2, plist_t message, const char *backup_dir)
  650. {
  651. uint32_t cnt;
  652. uint32_t i = 0;
  653. uint32_t sent;
  654. plist_t errplist = NULL;
  655. if (!message || (plist_get_node_type(message) != PLIST_ARRAY) || (plist_array_get_size(message) < 2) || !backup_dir) return;
  656. plist_t files = plist_array_get_item(message, 1);
  657. cnt = plist_array_get_size(files);
  658. if (cnt == 0) return;
  659. for (i = 0; i < cnt; i++) {
  660. plist_t val = plist_array_get_item(files, i);
  661. if (plist_get_node_type(val) != PLIST_STRING) {
  662. continue;
  663. }
  664. char *str = NULL;
  665. plist_get_string_val(val, &str);
  666. if (!str)
  667. continue;
  668. if (mb2_handle_send_file(mobilebackup2, backup_dir, str, &errplist) < 0) {
  669. free(str);
  670. //printf("Error when sending file '%s' to device\n", str);
  671. // TODO: perhaps we can continue, we've got a multi status response?!
  672. break;
  673. }
  674. free(str);
  675. }
  676. /* send terminating 0 dword */
  677. uint32_t zero = 0;
  678. mobilebackup2_send_raw(mobilebackup2, (char*)&zero, 4, &sent);
  679. if (!errplist) {
  680. plist_t emptydict = plist_new_dict();
  681. mobilebackup2_send_status_response(mobilebackup2, 0, NULL, emptydict);
  682. plist_free(emptydict);
  683. } else {
  684. mobilebackup2_send_status_response(mobilebackup2, -13, "Multi status", errplist);
  685. plist_free(errplist);
  686. }
  687. }
  688. static int mb2_receive_filename(mobilebackup2_client_t mobilebackup2, char** filename)
  689. {
  690. uint32_t nlen = 0;
  691. uint32_t rlen = 0;
  692. do {
  693. nlen = 0;
  694. rlen = 0;
  695. mobilebackup2_receive_raw(mobilebackup2, (char*)&nlen, 4, &rlen);
  696. nlen = be32toh(nlen);
  697. if ((nlen == 0) && (rlen == 4)) {
  698. // a zero length means no more files to receive
  699. return 0;
  700. } else if(rlen == 0) {
  701. // device needs more time, waiting...
  702. continue;
  703. } else if (nlen > 4096) {
  704. // filename length is too large
  705. printf("ERROR: %s: too large filename length (%d)!\n", __func__, nlen);
  706. return 0;
  707. }
  708. if (*filename != NULL) {
  709. free(*filename);
  710. *filename = NULL;
  711. }
  712. *filename = (char*)malloc(nlen+1);
  713. rlen = 0;
  714. mobilebackup2_receive_raw(mobilebackup2, *filename, nlen, &rlen);
  715. if (rlen != nlen) {
  716. printf("ERROR: %s: could not read filename\n", __func__);
  717. return 0;
  718. }
  719. char* p = *filename;
  720. p[rlen] = 0;
  721. break;
  722. } while(1 && !quit_flag);
  723. return nlen;
  724. }
  725. static int mb2_handle_receive_files(mobilebackup2_client_t mobilebackup2, plist_t message, const char *backup_dir)
  726. {
  727. uint64_t backup_real_size = 0;
  728. uint64_t backup_total_size = 0;
  729. uint32_t blocksize;
  730. uint32_t bdone;
  731. uint32_t rlen;
  732. uint32_t nlen = 0;
  733. uint32_t r;
  734. char buf[32768];
  735. char *fname = NULL;
  736. char *dname = NULL;
  737. char *bname = NULL;
  738. char code = 0;
  739. char last_code = 0;
  740. plist_t node = NULL;
  741. FILE *f = NULL;
  742. unsigned int file_count = 0;
  743. if (!message || (plist_get_node_type(message) != PLIST_ARRAY) || plist_array_get_size(message) < 4 || !backup_dir) return 0;
  744. node = plist_array_get_item(message, 3);
  745. if (plist_get_node_type(node) == PLIST_UINT) {
  746. plist_get_uint_val(node, &backup_total_size);
  747. }
  748. if (backup_total_size > 0) {
  749. PRINT_VERBOSE(1, "Receiving files\n");
  750. }
  751. do {
  752. if (quit_flag)
  753. break;
  754. nlen = mb2_receive_filename(mobilebackup2, &dname);
  755. if (nlen == 0) {
  756. break;
  757. }
  758. nlen = mb2_receive_filename(mobilebackup2, &fname);
  759. if (!nlen) {
  760. break;
  761. }
  762. if (bname != NULL) {
  763. free(bname);
  764. bname = NULL;
  765. }
  766. bname = build_path(backup_dir, fname, NULL);
  767. if (fname != NULL) {
  768. free(fname);
  769. fname = NULL;
  770. }
  771. r = 0;
  772. nlen = 0;
  773. mobilebackup2_receive_raw(mobilebackup2, (char*)&nlen, 4, &r);
  774. if (r != 4) {
  775. printf("ERROR: %s: could not receive code length!\n", __func__);
  776. break;
  777. }
  778. nlen = be32toh(nlen);
  779. last_code = code;
  780. code = 0;
  781. mobilebackup2_receive_raw(mobilebackup2, &code, 1, &r);
  782. if (r != 1) {
  783. printf("ERROR: %s: could not receive code!\n", __func__);
  784. break;
  785. }
  786. /* TODO remove this */
  787. if ((code != CODE_SUCCESS) && (code != CODE_FILE_DATA) && (code != CODE_ERROR_REMOTE)) {
  788. PRINT_VERBOSE(1, "Found new flag %02x\n", code);
  789. }
  790. remove(bname);
  791. f = fopen(bname, "wb");
  792. while (f && (code == CODE_FILE_DATA)) {
  793. blocksize = nlen-1;
  794. bdone = 0;
  795. rlen = 0;
  796. while (bdone < blocksize) {
  797. if ((blocksize - bdone) < sizeof(buf)) {
  798. rlen = blocksize - bdone;
  799. } else {
  800. rlen = sizeof(buf);
  801. }
  802. mobilebackup2_receive_raw(mobilebackup2, buf, rlen, &r);
  803. if ((int)r <= 0) {
  804. break;
  805. }
  806. fwrite(buf, 1, r, f);
  807. bdone += r;
  808. }
  809. if (bdone == blocksize) {
  810. backup_real_size += blocksize;
  811. }
  812. if (backup_total_size > 0) {
  813. print_progress(backup_real_size, backup_total_size);
  814. }
  815. if (quit_flag)
  816. break;
  817. nlen = 0;
  818. mobilebackup2_receive_raw(mobilebackup2, (char*)&nlen, 4, &r);
  819. nlen = be32toh(nlen);
  820. if (nlen > 0) {
  821. last_code = code;
  822. mobilebackup2_receive_raw(mobilebackup2, &code, 1, &r);
  823. } else {
  824. break;
  825. }
  826. }
  827. if (f) {
  828. fclose(f);
  829. file_count++;
  830. } else {
  831. printf("Error opening '%s' for writing: %s\n", bname, strerror(errno));
  832. }
  833. if (nlen == 0) {
  834. break;
  835. }
  836. /* check if an error message was received */
  837. if (code == CODE_ERROR_REMOTE) {
  838. /* error message */
  839. char *msg = (char*)malloc(nlen);
  840. mobilebackup2_receive_raw(mobilebackup2, msg, nlen-1, &r);
  841. msg[r] = 0;
  842. /* If sent using CODE_FILE_DATA, end marker will be CODE_ERROR_REMOTE which is not an error! */
  843. if (last_code != CODE_FILE_DATA) {
  844. fprintf(stdout, "\nReceived an error message from device: %s\n", msg);
  845. }
  846. free(msg);
  847. }
  848. } while (1);
  849. if (fname != NULL)
  850. free(fname);
  851. /* if there are leftovers to read, finish up cleanly */
  852. if ((int)nlen-1 > 0) {
  853. PRINT_VERBOSE(1, "\nDiscarding current data hunk.\n");
  854. fname = (char*)malloc(nlen-1);
  855. mobilebackup2_receive_raw(mobilebackup2, fname, nlen-1, &r);
  856. free(fname);
  857. remove(bname);
  858. }
  859. /* clean up */
  860. if (bname != NULL)
  861. free(bname);
  862. if (dname != NULL)
  863. free(dname);
  864. // TODO error handling?!
  865. plist_t empty_plist = plist_new_dict();
  866. mobilebackup2_send_status_response(mobilebackup2, 0, NULL, empty_plist);
  867. plist_free(empty_plist);
  868. return file_count;
  869. }
  870. static void mb2_handle_list_directory(mobilebackup2_client_t mobilebackup2, plist_t message, const char *backup_dir)
  871. {
  872. if (!message || (plist_get_node_type(message) != PLIST_ARRAY) || plist_array_get_size(message) < 2 || !backup_dir) return;
  873. plist_t node = plist_array_get_item(message, 1);
  874. char *str = NULL;
  875. if (plist_get_node_type(node) == PLIST_STRING) {
  876. plist_get_string_val(node, &str);
  877. }
  878. if (!str) {
  879. printf("ERROR: Malformed DLContentsOfDirectory message\n");
  880. // TODO error handling
  881. return;
  882. }
  883. char *path = build_path(backup_dir, str, NULL);
  884. free(str);
  885. plist_t dirlist = plist_new_dict();
  886. DIR* cur_dir = opendir(path);
  887. if (cur_dir) {
  888. struct dirent* ep;
  889. while ((ep = readdir(cur_dir))) {
  890. if ((strcmp(ep->d_name, ".") == 0) || (strcmp(ep->d_name, "..") == 0)) {
  891. continue;
  892. }
  893. char *fpath = build_path(path, ep->d_name, NULL);
  894. if (fpath) {
  895. plist_t fdict = plist_new_dict();
  896. struct stat st;
  897. stat(fpath, &st);
  898. const char *ftype = "DLFileTypeUnknown";
  899. if (S_ISDIR(st.st_mode)) {
  900. ftype = "DLFileTypeDirectory";
  901. } else if (S_ISREG(st.st_mode)) {
  902. ftype = "DLFileTypeRegular";
  903. }
  904. plist_dict_insert_item(fdict, "DLFileType", plist_new_string(ftype));
  905. plist_dict_insert_item(fdict, "DLFileSize", plist_new_uint(st.st_size));
  906. plist_dict_insert_item(fdict, "DLFileModificationDate", plist_new_date(st.st_mtime, 0));
  907. plist_dict_insert_item(dirlist, ep->d_name, fdict);
  908. free(fpath);
  909. }
  910. }
  911. closedir(cur_dir);
  912. }
  913. free(path);
  914. /* TODO error handling */
  915. mobilebackup2_error_t err = mobilebackup2_send_status_response(mobilebackup2, 0, NULL, dirlist);
  916. plist_free(dirlist);
  917. if (err != MOBILEBACKUP2_E_SUCCESS) {
  918. printf("Could not send status response, error %d\n", err);
  919. }
  920. }
  921. static void mb2_handle_make_directory(mobilebackup2_client_t mobilebackup2, plist_t message, const char *backup_dir)
  922. {
  923. if (!message || (plist_get_node_type(message) != PLIST_ARRAY) || plist_array_get_size(message) < 2 || !backup_dir) return;
  924. plist_t dir = plist_array_get_item(message, 1);
  925. char *str = NULL;
  926. int errcode = 0;
  927. char *errdesc = NULL;
  928. plist_get_string_val(dir, &str);
  929. char *newpath = build_path(backup_dir, str, NULL);
  930. free(str);
  931. if (mkdir_with_parents(newpath, 0755) < 0) {
  932. errdesc = strerror(errno);
  933. if (errno != EEXIST) {
  934. printf("mkdir: %s (%d)\n", errdesc, errno);
  935. }
  936. errcode = errno_to_device_error(errno);
  937. }
  938. free(newpath);
  939. mobilebackup2_error_t err = mobilebackup2_send_status_response(mobilebackup2, errcode, errdesc, NULL);
  940. if (err != MOBILEBACKUP2_E_SUCCESS) {
  941. printf("Could not send status response, error %d\n", err);
  942. }
  943. }
  944. static void mb2_copy_file_by_path(const char *src, const char *dst)
  945. {
  946. FILE *from, *to;
  947. char buf[BUFSIZ];
  948. size_t length;
  949. /* open source file */
  950. if ((from = fopen(src, "rb")) == NULL) {
  951. printf("Cannot open source path '%s'.\n", src);
  952. return;
  953. }
  954. /* open destination file */
  955. if ((to = fopen(dst, "wb")) == NULL) {
  956. printf("Cannot open destination file '%s'.\n", dst);
  957. return;
  958. }
  959. /* copy the file */
  960. while ((length = fread(buf, 1, BUFSIZ, from)) != 0) {
  961. fwrite(buf, 1, length, to);
  962. }
  963. if(fclose(from) == EOF) {
  964. printf("Error closing source file.\n");
  965. }
  966. if(fclose(to) == EOF) {
  967. printf("Error closing destination file.\n");
  968. }
  969. }
  970. static void mb2_copy_directory_by_path(const char *src, const char *dst)
  971. {
  972. if (!src || !dst) {
  973. return;
  974. }
  975. struct stat st;
  976. /* if src does not exist */
  977. if ((stat(src, &st) < 0) || !S_ISDIR(st.st_mode)) {
  978. printf("ERROR: Source directory does not exist '%s': %s (%d)\n", src, strerror(errno), errno);
  979. return;
  980. }
  981. /* if dst directory does not exist */
  982. if ((stat(dst, &st) < 0) || !S_ISDIR(st.st_mode)) {
  983. /* create it */
  984. if (mkdir_with_parents(dst, 0755) < 0) {
  985. printf("ERROR: Unable to create destination directory '%s': %s (%d)\n", dst, strerror(errno), errno);
  986. return;
  987. }
  988. }
  989. /* loop over src directory contents */
  990. DIR *cur_dir = opendir(src);
  991. if (cur_dir) {
  992. struct dirent* ep;
  993. while ((ep = readdir(cur_dir))) {
  994. if ((strcmp(ep->d_name, ".") == 0) || (strcmp(ep->d_name, "..") == 0)) {
  995. continue;
  996. }
  997. char *srcpath = build_path(src, ep->d_name, NULL);
  998. char *dstpath = build_path(dst, ep->d_name, NULL);
  999. if (srcpath && dstpath) {
  1000. /* copy file */
  1001. mb2_copy_file_by_path(srcpath, dstpath);
  1002. free(srcpath);
  1003. free(dstpath);
  1004. }
  1005. }
  1006. closedir(cur_dir);
  1007. }
  1008. }
  1009. #ifdef WIN32
  1010. #define BS_CC '\b'
  1011. #define my_getch getch
  1012. #else
  1013. #define BS_CC 0x7f
  1014. static int my_getch()
  1015. {
  1016. struct termios oldt, newt;
  1017. int ch;
  1018. tcgetattr(STDIN_FILENO, &oldt);
  1019. newt = oldt;
  1020. newt.c_lflag &= ~(ICANON | ECHO);
  1021. tcsetattr(STDIN_FILENO, TCSANOW, &newt);
  1022. ch = getchar();
  1023. tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
  1024. return ch;
  1025. }
  1026. #endif
  1027. static void get_hidden_input(char *buf, int maxlen)
  1028. {
  1029. int pwlen = 0;
  1030. int c;
  1031. while ((c = my_getch())) {
  1032. if ((c == '\r') || (c == '\n')) {
  1033. break;
  1034. } else if (isprint(c)) {
  1035. if (pwlen < maxlen-1)
  1036. buf[pwlen++] = c;
  1037. fputc('*', stderr);
  1038. } else if (c == BS_CC) {
  1039. if (pwlen > 0) {
  1040. fputs("\b \b", stderr);
  1041. pwlen--;
  1042. }
  1043. }
  1044. }
  1045. buf[pwlen] = 0;
  1046. }
  1047. static char* ask_for_password(const char* msg, int type_again)
  1048. {
  1049. char pwbuf[256];
  1050. fprintf(stderr, "%s: ", msg);
  1051. fflush(stderr);
  1052. get_hidden_input(pwbuf, 256);
  1053. fputc('\n', stderr);
  1054. if (type_again) {
  1055. char pwrep[256];
  1056. fprintf(stderr, "%s (repeat): ", msg);
  1057. fflush(stderr);
  1058. get_hidden_input(pwrep, 256);
  1059. fputc('\n', stderr);
  1060. if (strcmp(pwbuf, pwrep) != 0) {
  1061. printf("ERROR: passwords don't match\n");
  1062. return NULL;
  1063. }
  1064. }
  1065. return strdup(pwbuf);
  1066. }
  1067. /**
  1068. * signal handler function for cleaning up properly
  1069. */
  1070. static void clean_exit(int sig)
  1071. {
  1072. fprintf(stderr, "Exiting...\n");
  1073. quit_flag++;
  1074. }
  1075. static void print_usage(int argc, char **argv)
  1076. {
  1077. char *name = NULL;
  1078. name = strrchr(argv[0], '/');
  1079. printf("Usage: %s [OPTIONS] CMD [CMDOPTIONS] DIRECTORY\n", (name ? name + 1: argv[0]));
  1080. printf("Create or restore backup from the current or specified directory.\n\n");
  1081. printf("commands:\n");
  1082. printf(" backup\tcreate backup for the device\n");
  1083. printf(" restore\trestore last backup to the device\n");
  1084. printf(" --system\t\trestore system files, too.\n");
  1085. printf(" --reboot\t\treboot the system when done.\n");
  1086. printf(" --copy\t\tcreate a copy of backup folder before restoring.\n");
  1087. printf(" --settings\t\trestore device settings from the backup.\n");
  1088. printf(" --remove\t\tremove items which are not being restored\n");
  1089. printf(" --password PWD\tsupply the password of the source backup\n");
  1090. printf(" info\t\tshow details about last completed backup of device\n");
  1091. printf(" list\t\tlist files of last completed backup in CSV format\n");
  1092. printf(" unback\tunpack a completed backup in DIRECTORY/_unback_/\n");
  1093. printf(" encryption on|off [PWD]\tenable or disable backup encryption\n");
  1094. printf(" NOTE: password will be requested in interactive mode if omitted\n");
  1095. printf(" changepw [OLD NEW] change backup password on target device\n");
  1096. printf(" NOTE: passwords will be requested in interactive mode if omitted\n");
  1097. printf("\n");
  1098. printf("options:\n");
  1099. printf(" -d, --debug\t\tenable communication debugging\n");
  1100. printf(" -u, --udid UDID\ttarget specific device by its 40-digit device UDID\n");
  1101. printf(" -s, --source UDID\tuse backup data from device specified by UDID\n");
  1102. printf(" -i, --interactive\trequest passwords interactively\n");
  1103. printf(" -h, --help\t\tprints usage information\n");
  1104. printf("\n");
  1105. }
  1106. int main(int argc, char *argv[])
  1107. {
  1108. idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
  1109. int i;
  1110. char* udid = NULL;
  1111. char* source_udid = NULL;
  1112. lockdownd_service_descriptor_t service = NULL;
  1113. int cmd = -1;
  1114. int cmd_flags = 0;
  1115. int is_full_backup = 0;
  1116. int result_code = -1;
  1117. char* backup_directory = NULL;
  1118. int interactive_mode = 0;
  1119. char* backup_password = NULL;
  1120. char* newpw = NULL;
  1121. struct stat st;
  1122. plist_t node_tmp = NULL;
  1123. plist_t info_plist = NULL;
  1124. plist_t opts = NULL;
  1125. mobilebackup2_error_t err;
  1126. /* we need to exit cleanly on running backups and restores or we cause havok */
  1127. signal(SIGINT, clean_exit);
  1128. signal(SIGTERM, clean_exit);
  1129. #ifndef WIN32
  1130. signal(SIGQUIT, clean_exit);
  1131. signal(SIGPIPE, SIG_IGN);
  1132. #endif
  1133. /* parse cmdline args */
  1134. for (i = 1; i < argc; i++) {
  1135. if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
  1136. idevice_set_debug_level(1);
  1137. continue;
  1138. }
  1139. else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) {
  1140. i++;
  1141. if (!argv[i] || (strlen(argv[i]) != 40)) {
  1142. print_usage(argc, argv);
  1143. return -1;
  1144. }
  1145. udid = strdup(argv[i]);
  1146. continue;
  1147. }
  1148. else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--source")) {
  1149. i++;
  1150. if (!argv[i] || (strlen(argv[i]) != 40)) {
  1151. print_usage(argc, argv);
  1152. return -1;
  1153. }
  1154. source_udid = strdup(argv[i]);
  1155. continue;
  1156. }
  1157. else if (!strcmp(argv[i], "-i") || !strcmp(argv[i], "--interactive")) {
  1158. interactive_mode = 1;
  1159. continue;
  1160. }
  1161. else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
  1162. print_usage(argc, argv);
  1163. return 0;
  1164. }
  1165. else if (!strcmp(argv[i], "backup")) {
  1166. cmd = CMD_BACKUP;
  1167. }
  1168. else if (!strcmp(argv[i], "restore")) {
  1169. cmd = CMD_RESTORE;
  1170. }
  1171. else if (!strcmp(argv[i], "--system")) {
  1172. cmd_flags |= CMD_FLAG_RESTORE_SYSTEM_FILES;
  1173. }
  1174. else if (!strcmp(argv[i], "--reboot")) {
  1175. cmd_flags |= CMD_FLAG_RESTORE_REBOOT;
  1176. }
  1177. else if (!strcmp(argv[i], "--copy")) {
  1178. cmd_flags |= CMD_FLAG_RESTORE_COPY_BACKUP;
  1179. }
  1180. else if (!strcmp(argv[i], "--settings")) {
  1181. cmd_flags |= CMD_FLAG_RESTORE_SETTINGS;
  1182. }
  1183. else if (!strcmp(argv[i], "--remove")) {
  1184. cmd_flags |= CMD_FLAG_RESTORE_REMOVE_ITEMS;
  1185. }
  1186. else if (!strcmp(argv[i], "--password")) {
  1187. i++;
  1188. if (!argv[i]) {
  1189. print_usage(argc, argv);
  1190. return -1;
  1191. }
  1192. if (backup_password)
  1193. free(backup_password);
  1194. backup_password = strdup(argv[i]);
  1195. continue;
  1196. }
  1197. else if (!strcmp(argv[i], "info")) {
  1198. cmd = CMD_INFO;
  1199. verbose = 0;
  1200. }
  1201. else if (!strcmp(argv[i], "list")) {
  1202. cmd = CMD_LIST;
  1203. verbose = 0;
  1204. }
  1205. else if (!strcmp(argv[i], "unback")) {
  1206. cmd = CMD_UNBACK;
  1207. }
  1208. else if (!strcmp(argv[i], "encryption")) {
  1209. cmd = CMD_CHANGEPW;
  1210. i++;
  1211. if (!argv[i]) {
  1212. printf("No argument given for encryption command; requires either 'on' or 'off'.\n");
  1213. print_usage(argc, argv);
  1214. return -1;
  1215. }
  1216. if (!strcmp(argv[i], "on")) {
  1217. cmd_flags |= CMD_FLAG_ENCRYPTION_ENABLE;
  1218. } else if (!strcmp(argv[i], "off")) {
  1219. cmd_flags |= CMD_FLAG_ENCRYPTION_DISABLE;
  1220. } else {
  1221. printf("Invalid argument '%s' for encryption command; must be either 'on' or 'off'.\n", argv[i]);
  1222. }
  1223. // check if a password was given on the command line
  1224. if (newpw) {
  1225. free(newpw);
  1226. newpw = NULL;
  1227. }
  1228. if (backup_password) {
  1229. free(backup_password);
  1230. backup_password = NULL;
  1231. }
  1232. i++;
  1233. if (argv[i]) {
  1234. if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) {
  1235. newpw = strdup(argv[i]);
  1236. } else if (cmd_flags & CMD_FLAG_ENCRYPTION_DISABLE) {
  1237. backup_password = strdup(argv[i]);
  1238. }
  1239. }
  1240. continue;
  1241. }
  1242. else if (!strcmp(argv[i], "changepw")) {
  1243. cmd = CMD_CHANGEPW;
  1244. cmd_flags |= CMD_FLAG_ENCRYPTION_CHANGEPW;
  1245. // check if passwords were given on command line
  1246. if (newpw) {
  1247. free(newpw);
  1248. newpw = NULL;
  1249. }
  1250. if (backup_password) {
  1251. free(backup_password);
  1252. backup_password = NULL;
  1253. }
  1254. i++;
  1255. if (argv[i]) {
  1256. backup_password = strdup(argv[i]);
  1257. i++;
  1258. if (!argv[i]) {
  1259. printf("Old and new passwords have to be passed as arguments for the changepw command\n");
  1260. print_usage(argc, argv);
  1261. return -1;
  1262. }
  1263. newpw = strdup(argv[i]);
  1264. }
  1265. continue;
  1266. }
  1267. else if (backup_directory == NULL) {
  1268. backup_directory = argv[i];
  1269. }
  1270. else {
  1271. print_usage(argc, argv);
  1272. return -1;
  1273. }
  1274. }
  1275. /* verify options */
  1276. if (cmd == -1) {
  1277. printf("No command specified.\n");
  1278. print_usage(argc, argv);
  1279. return -1;
  1280. }
  1281. if (cmd == CMD_CHANGEPW) {
  1282. backup_directory = strdup(".this_folder_is_not_present_on_purpose");
  1283. } else {
  1284. if (backup_directory == NULL) {
  1285. printf("No target backup directory specified.\n");
  1286. print_usage(argc, argv);
  1287. return -1;
  1288. }
  1289. /* verify if passed backup directory exists */
  1290. if (stat(backup_directory, &st) != 0) {
  1291. printf("ERROR: Backup directory \"%s\" does not exist!\n", backup_directory);
  1292. return -1;
  1293. }
  1294. }
  1295. idevice_t device = NULL;
  1296. if (udid) {
  1297. ret = idevice_new(&device, udid);
  1298. if (ret != IDEVICE_E_SUCCESS) {
  1299. printf("No device found with udid %s, is it plugged in?\n", udid);
  1300. return -1;
  1301. }
  1302. }
  1303. else
  1304. {
  1305. ret = idevice_new(&device, NULL);
  1306. if (ret != IDEVICE_E_SUCCESS) {
  1307. printf("No device found, is it plugged in?\n");
  1308. return -1;
  1309. }
  1310. idevice_get_udid(device, &udid);
  1311. }
  1312. if (!source_udid) {
  1313. source_udid = strdup(udid);
  1314. }
  1315. uint8_t is_encrypted = 0;
  1316. char *info_path = NULL;
  1317. if (cmd == CMD_CHANGEPW) {
  1318. if (!interactive_mode && (!backup_password || !newpw)) {
  1319. printf("ERROR: Can't get password input in non-interactive mode. Either pass password(s) on the command line, or enable interactive mode with -i or --interactive.\n");
  1320. return -1;
  1321. }
  1322. } else {
  1323. /* backup directory must contain an Info.plist */
  1324. info_path = build_path(backup_directory, source_udid, "Info.plist", NULL);
  1325. if (cmd == CMD_RESTORE) {
  1326. if (stat(info_path, &st) != 0) {
  1327. free(info_path);
  1328. printf("ERROR: Backup directory \"%s\" is invalid. No Info.plist found for UDID %s.\n", backup_directory, source_udid);
  1329. return -1;
  1330. }
  1331. char* manifest_path = build_path(backup_directory, source_udid, "Manifest.plist", NULL);
  1332. if (stat(manifest_path, &st) != 0) {
  1333. free(info_path);
  1334. }
  1335. plist_t manifest_plist = NULL;
  1336. plist_read_from_filename(&manifest_plist, manifest_path);
  1337. if (!manifest_plist) {
  1338. free(info_path);
  1339. free(manifest_path);
  1340. printf("ERROR: Backup directory \"%s\" is invalid. No Manifest.plist found for UDID %s.\n", backup_directory, source_udid);
  1341. return -1;
  1342. }
  1343. node_tmp = plist_dict_get_item(manifest_plist, "IsEncrypted");
  1344. if (node_tmp && (plist_get_node_type(node_tmp) == PLIST_BOOLEAN)) {
  1345. plist_get_bool_val(node_tmp, &is_encrypted);
  1346. }
  1347. plist_free(manifest_plist);
  1348. free(manifest_path);
  1349. }
  1350. PRINT_VERBOSE(1, "Backup directory is \"%s\"\n", backup_directory);
  1351. }
  1352. if (is_encrypted) {
  1353. PRINT_VERBOSE(1, "This is an encrypted backup.\n");
  1354. if (backup_password == NULL) {
  1355. if (interactive_mode) {
  1356. backup_password = ask_for_password("Enter backup password", 0);
  1357. }
  1358. if (!backup_password || (strlen(backup_password) == 0)) {
  1359. if (backup_password) {
  1360. free(backup_password);
  1361. }
  1362. idevice_free(device);
  1363. printf("ERROR: a backup password is required to restore an encrypted backup. Cannot continue.\n");
  1364. return -1;
  1365. }
  1366. }
  1367. }
  1368. lockdownd_client_t lockdown = NULL;
  1369. if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(device, &lockdown, "idevicebackup")) {
  1370. idevice_free(device);
  1371. return -1;
  1372. }
  1373. /* start notification_proxy */
  1374. np_client_t np = NULL;
  1375. ret = lockdownd_start_service(lockdown, NP_SERVICE_NAME, &service);
  1376. if ((ret == LOCKDOWN_E_SUCCESS) && service && service->port) {
  1377. np_client_new(device, service, &np);
  1378. np_set_notify_callback(np, notify_cb, NULL);
  1379. const char *noties[5] = {
  1380. NP_SYNC_CANCEL_REQUEST,
  1381. NP_SYNC_SUSPEND_REQUEST,
  1382. NP_SYNC_RESUME_REQUEST,
  1383. NP_BACKUP_DOMAIN_CHANGED,
  1384. NULL
  1385. };
  1386. np_observe_notifications(np, noties);
  1387. } else {
  1388. printf("ERROR: Could not start service %s.\n", NP_SERVICE_NAME);
  1389. }
  1390. afc_client_t afc = NULL;
  1391. if (cmd == CMD_BACKUP) {
  1392. /* start AFC, we need this for the lock file */
  1393. service->port = 0;
  1394. service->ssl_enabled = 0;
  1395. ret = lockdownd_start_service(lockdown, "com.apple.afc", &service);
  1396. if ((ret == LOCKDOWN_E_SUCCESS) && service->port) {
  1397. afc_client_new(device, service, &afc);
  1398. }
  1399. }
  1400. if (service) {
  1401. lockdownd_service_descriptor_free(service);
  1402. service = NULL;
  1403. }
  1404. /* start mobilebackup service and retrieve port */
  1405. mobilebackup2_client_t mobilebackup2 = NULL;
  1406. ret = lockdownd_start_service(lockdown, MOBILEBACKUP2_SERVICE_NAME, &service);
  1407. if ((ret == LOCKDOWN_E_SUCCESS) && service && service->port) {
  1408. PRINT_VERBOSE(1, "Started \"%s\" service on port %d.\n", MOBILEBACKUP2_SERVICE_NAME, service->port);
  1409. mobilebackup2_client_new(device, service, &mobilebackup2);
  1410. if (service) {
  1411. lockdownd_service_descriptor_free(service);
  1412. service = NULL;
  1413. }
  1414. /* send Hello message */
  1415. double local_versions[2] = {2.0, 2.1};
  1416. double remote_version = 0.0;
  1417. err = mobilebackup2_version_exchange(mobilebackup2, local_versions, 2, &remote_version);
  1418. if (err != MOBILEBACKUP2_E_SUCCESS) {
  1419. printf("Could not perform backup protocol version exchange, error code %d\n", err);
  1420. cmd = CMD_LEAVE;
  1421. goto checkpoint;
  1422. }
  1423. PRINT_VERBOSE(1, "Negotiated Protocol Version %.1f\n", remote_version);
  1424. /* check abort conditions */
  1425. if (quit_flag > 0) {
  1426. PRINT_VERBOSE(1, "Aborting as requested by user...\n");
  1427. cmd = CMD_LEAVE;
  1428. goto checkpoint;
  1429. }
  1430. /* verify existing Info.plist */
  1431. if (info_path && (stat(info_path, &st) == 0)) {
  1432. PRINT_VERBOSE(1, "Reading Info.plist from backup.\n");
  1433. plist_read_from_filename(&info_plist, info_path);
  1434. if (!info_plist) {
  1435. printf("Could not read Info.plist\n");
  1436. is_full_backup = 1;
  1437. }
  1438. } else {
  1439. if (cmd == CMD_RESTORE) {
  1440. printf("Aborting restore. Info.plist is missing.\n");
  1441. cmd = CMD_LEAVE;
  1442. } else {
  1443. is_full_backup = 1;
  1444. }
  1445. }
  1446. uint64_t lockfile = 0;
  1447. if (cmd == CMD_BACKUP) {
  1448. do_post_notification(device, NP_SYNC_WILL_START);
  1449. afc_file_open(afc, "/com.apple.itunes.lock_sync", AFC_FOPEN_RW, &lockfile);
  1450. }
  1451. if (lockfile) {
  1452. afc_error_t aerr;
  1453. do_post_notification(device, NP_SYNC_LOCK_REQUEST);
  1454. for (i = 0; i < LOCK_ATTEMPTS; i++) {
  1455. aerr = afc_file_lock(afc, lockfile, AFC_LOCK_EX);
  1456. if (aerr == AFC_E_SUCCESS) {
  1457. do_post_notification(device, NP_SYNC_DID_START);
  1458. break;
  1459. } else if (aerr == AFC_E_OP_WOULD_BLOCK) {
  1460. sleep(LOCK_WAIT);
  1461. continue;
  1462. } else {
  1463. fprintf(stderr, "ERROR: could not lock file! error code: %d\n", aerr);
  1464. afc_file_close(afc, lockfile);
  1465. lockfile = 0;
  1466. cmd = CMD_LEAVE;
  1467. }
  1468. }
  1469. if (i == LOCK_ATTEMPTS) {
  1470. fprintf(stderr, "ERROR: timeout while locking for sync\n");
  1471. afc_file_close(afc, lockfile);
  1472. lockfile = 0;
  1473. cmd = CMD_LEAVE;
  1474. }
  1475. }
  1476. uint8_t willEncrypt = 0;
  1477. node_tmp = NULL;
  1478. lockdownd_get_value(lockdown, "com.apple.mobile.backup", "WillEncrypt", &node_tmp);
  1479. if (node_tmp) {
  1480. if (plist_get_node_type(node_tmp) == PLIST_BOOLEAN) {
  1481. plist_get_bool_val(node_tmp, &willEncrypt);
  1482. }
  1483. plist_free(node_tmp);
  1484. node_tmp = NULL;
  1485. }
  1486. checkpoint:
  1487. switch(cmd) {
  1488. case CMD_BACKUP:
  1489. {
  1490. PRINT_VERBOSE(1, "Starting backup...\n");
  1491. /* make sure backup device sub-directory exists */
  1492. char* devbackupdir = build_path(backup_directory, source_udid, NULL);
  1493. __mkdir(devbackupdir, 0755);
  1494. free(devbackupdir);
  1495. if (strcmp(source_udid, udid) != 0) {
  1496. /* handle different source backup directory */
  1497. // make sure target backup device sub-directory exists
  1498. devbackupdir = build_path(backup_directory, udid, NULL);
  1499. __mkdir(devbackupdir, 0755);
  1500. free(devbackupdir);
  1501. // use Info.plist path in target backup folder */
  1502. free(info_path);
  1503. info_path = build_path(backup_directory, udid, "Info.plist", NULL);
  1504. }
  1505. /* TODO: check domain com.apple.mobile.backup key RequiresEncrypt and WillEncrypt with lockdown */
  1506. /* TODO: verify battery on AC enough battery remaining */
  1507. /* re-create Info.plist (Device infos, IC-Info.sidb, photos, app_ids, iTunesPrefs) */
  1508. if (info_plist) {
  1509. plist_free(info_plist);
  1510. info_plist = NULL;
  1511. }
  1512. info_plist = mobilebackup_factory_info_plist_new(udid, lockdown, afc);
  1513. remove(info_path);
  1514. plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML);
  1515. free(info_path);
  1516. plist_free(info_plist);
  1517. info_plist = NULL;
  1518. /* request backup from device with manifest from last backup */
  1519. if (willEncrypt) {
  1520. PRINT_VERBOSE(1, "Backup will be encrypted.\n");
  1521. } else {
  1522. PRINT_VERBOSE(1, "Backup will be unencrypted.\n");
  1523. }
  1524. PRINT_VERBOSE(1, "Requesting backup from device...\n");
  1525. err = mobilebackup2_send_request(mobilebackup2, "Backup", udid, source_udid, NULL);
  1526. if (err == MOBILEBACKUP2_E_SUCCESS) {
  1527. if (is_full_backup) {
  1528. PRINT_VERBOSE(1, "Full backup mode.\n");
  1529. } else {
  1530. PRINT_VERBOSE(1, "Incremental backup mode.\n");
  1531. }
  1532. } else {
  1533. if (err == MOBILEBACKUP2_E_BAD_VERSION) {
  1534. printf("ERROR: Could not start backup process: backup protocol version mismatch!\n");
  1535. } else if (err == MOBILEBACKUP2_E_REPLY_NOT_OK) {
  1536. printf("ERROR: Could not start backup process: device refused to start the backup process.\n");
  1537. } else {
  1538. printf("ERROR: Could not start backup process: unspecified error occured\n");
  1539. }
  1540. cmd = CMD_LEAVE;
  1541. }
  1542. }
  1543. break;
  1544. case CMD_RESTORE:
  1545. {
  1546. /* TODO: verify battery on AC enough battery remaining */
  1547. /* verify if Status.plist says we read from an successful backup */
  1548. if (!mb2_status_check_snapshot_state(backup_directory, source_udid, "finished")) {
  1549. printf("ERROR: Cannot ensure we restore from a successful backup. Aborting.\n");
  1550. cmd = CMD_LEAVE;
  1551. break;
  1552. }
  1553. PRINT_VERBOSE(1, "Starting Restore...\n");
  1554. opts = plist_new_dict();
  1555. plist_dict_insert_item(opts, "RestoreSystemFiles", plist_new_bool(cmd_flags & CMD_FLAG_RESTORE_SYSTEM_FILES));
  1556. PRINT_VERBOSE(1, "Restoring system files: %s\n", (cmd_flags & CMD_FLAG_RESTORE_SYSTEM_FILES ? "Yes":"No"));
  1557. if ((cmd_flags & CMD_FLAG_RESTORE_REBOOT) == 0)
  1558. plist_dict_insert_item(opts, "RestoreShouldReboot", plist_new_bool(0));
  1559. PRINT_VERBOSE(1, "Rebooting after restore: %s\n", (cmd_flags & CMD_FLAG_RESTORE_REBOOT ? "Yes":"No"));
  1560. if ((cmd_flags & CMD_FLAG_RESTORE_COPY_BACKUP) == 0)
  1561. plist_dict_insert_item(opts, "RestoreDontCopyBackup", plist_new_bool(1));
  1562. PRINT_VERBOSE(1, "Don't copy backup: %s\n", ((cmd_flags & CMD_FLAG_RESTORE_COPY_BACKUP) == 0 ? "Yes":"No"));
  1563. plist_dict_insert_item(opts, "RestorePreserveSettings", plist_new_bool((cmd_flags & CMD_FLAG_RESTORE_SETTINGS) == 0));
  1564. PRINT_VERBOSE(1, "Preserve settings of device: %s\n", ((cmd_flags & CMD_FLAG_RESTORE_SETTINGS) == 0 ? "Yes":"No"));
  1565. if (cmd_flags & CMD_FLAG_RESTORE_REMOVE_ITEMS)
  1566. plist_dict_insert_item(opts, "RemoveItemsNotRestored", plist_new_bool(1));
  1567. PRINT_VERBOSE(1, "Remove items that are not restored: %s\n", ((cmd_flags & CMD_FLAG_RESTORE_REMOVE_ITEMS) ? "Yes":"No"));
  1568. if (backup_password != NULL) {
  1569. plist_dict_insert_item(opts, "Password", plist_new_string(backup_password));
  1570. }
  1571. PRINT_VERBOSE(1, "Backup password: %s\n", (backup_password == NULL ? "No":"Yes"));
  1572. err = mobilebackup2_send_request(mobilebackup2, "Restore", udid, source_udid, opts);
  1573. plist_free(opts);
  1574. if (err != MOBILEBACKUP2_E_SUCCESS) {
  1575. if (err == MOBILEBACKUP2_E_BAD_VERSION) {
  1576. printf("ERROR: Could not start restore process: backup protocol version mismatch!\n");
  1577. } else if (err == MOBILEBACKUP2_E_REPLY_NOT_OK) {
  1578. printf("ERROR: Could not start restore process: device refused to start the restore process.\n");
  1579. } else {
  1580. printf("ERROR: Could not start restore process: unspecified error occured\n");
  1581. }
  1582. cmd = CMD_LEAVE;
  1583. }
  1584. }
  1585. break;
  1586. case CMD_INFO:
  1587. {
  1588. PRINT_VERBOSE(1, "Requesting backup info from device...\n");
  1589. err = mobilebackup2_send_request(mobilebackup2, "Info", udid, source_udid, NULL);
  1590. if (err != MOBILEBACKUP2_E_SUCCESS) {
  1591. printf("Error requesting backup info from device, error code %d\n", err);
  1592. cmd = CMD_LEAVE;
  1593. }
  1594. }
  1595. break;
  1596. case CMD_LIST:
  1597. {
  1598. PRINT_VERBOSE(1, "Requesting backup list from device...\n");
  1599. err = mobilebackup2_send_request(mobilebackup2, "List", udid, source_udid, NULL);
  1600. if (err != MOBILEBACKUP2_E_SUCCESS) {
  1601. printf("Error requesting backup list from device, error code %d\n", err);
  1602. cmd = CMD_LEAVE;
  1603. }
  1604. }
  1605. break;
  1606. case CMD_UNBACK:
  1607. {
  1608. PRINT_VERBOSE(1, "Starting to unpack backup...\n");
  1609. err = mobilebackup2_send_request(mobilebackup2, "Unback", udid, source_udid, NULL);
  1610. if (err != MOBILEBACKUP2_E_SUCCESS) {
  1611. printf("Error requesting unback operation from device, error code %d\n", err);
  1612. cmd = CMD_LEAVE;
  1613. }
  1614. }
  1615. break;
  1616. case CMD_CHANGEPW:
  1617. {
  1618. opts = plist_new_dict();
  1619. plist_dict_insert_item(opts, "TargetIdentifier", plist_new_string(udid));
  1620. if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) {
  1621. if (!willEncrypt) {
  1622. if (!newpw) {
  1623. newpw = ask_for_password("Enter new backup password", 1);
  1624. }
  1625. if (!newpw) {
  1626. printf("No backup password given. Aborting.\n");
  1627. }
  1628. } else {
  1629. printf("ERROR: Backup encryption is already enabled. Aborting.\n");
  1630. cmd = CMD_LEAVE;
  1631. if (newpw) {
  1632. free(newpw);
  1633. newpw = NULL;
  1634. }
  1635. }
  1636. } else if (cmd_flags & CMD_FLAG_ENCRYPTION_DISABLE) {
  1637. if (willEncrypt) {
  1638. if (!backup_password) {
  1639. backup_password = ask_for_password("Enter current backup password", 0);
  1640. }
  1641. } else {
  1642. printf("ERROR: Backup encryption is not enabled. Aborting.\n");
  1643. cmd = CMD_LEAVE;
  1644. if (backup_password) {
  1645. free(backup_password);
  1646. backup_password = NULL;
  1647. }
  1648. }
  1649. } else if (cmd_flags & CMD_FLAG_ENCRYPTION_CHANGEPW) {
  1650. if (willEncrypt) {
  1651. if (!backup_password) {
  1652. backup_password = ask_for_password("Enter old backup password", 0);
  1653. newpw = ask_for_password("Enter new backup password", 1);
  1654. }
  1655. } else {
  1656. printf("ERROR: Backup encryption is not enabled so can't change password. Aborting.\n");
  1657. cmd = CMD_LEAVE;
  1658. if (newpw) {
  1659. free(newpw);
  1660. newpw = NULL;
  1661. }
  1662. if (backup_password) {
  1663. free(backup_password);
  1664. backup_password = NULL;
  1665. }
  1666. }
  1667. }
  1668. if (newpw) {
  1669. plist_dict_insert_item(opts, "NewPassword", plist_new_string(newpw));
  1670. }
  1671. if (backup_password) {
  1672. plist_dict_insert_item(opts, "OldPassword", plist_new_string(backup_password));
  1673. }
  1674. if (newpw || backup_password) {
  1675. mobilebackup2_send_message(mobilebackup2, "ChangePassword", opts);
  1676. /*if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) {
  1677. int retr = 10;
  1678. while ((retr-- >= 0) && !backup_domain_changed) {
  1679. sleep(1);
  1680. }
  1681. }*/
  1682. } else {
  1683. cmd = CMD_LEAVE;
  1684. }
  1685. plist_free(opts);
  1686. }
  1687. break;
  1688. default:
  1689. break;
  1690. }
  1691. /* close down the lockdown connection as it is no longer needed */
  1692. if (lockdown) {
  1693. lockdownd_client_free(lockdown);
  1694. lockdown = NULL;
  1695. }
  1696. if (cmd != CMD_LEAVE) {
  1697. /* reset operation success status */
  1698. int operation_ok = 0;
  1699. plist_t message = NULL;
  1700. char *dlmsg = NULL;
  1701. int file_count = 0;
  1702. int errcode = 0;
  1703. const char *errdesc = NULL;
  1704. /* process series of DLMessage* operations */
  1705. do {
  1706. if (dlmsg) {
  1707. free(dlmsg);
  1708. dlmsg = NULL;
  1709. }
  1710. mobilebackup2_receive_message(mobilebackup2, &message, &dlmsg);
  1711. if (!message || !dlmsg) {
  1712. PRINT_VERBOSE(1, "Device is not ready yet. Going to try again in 2 seconds...\n");
  1713. sleep(2);
  1714. goto files_out;
  1715. }
  1716. if (!strcmp(dlmsg, "DLMessageDownloadFiles")) {
  1717. /* device wants to download files from the computer */
  1718. mb2_set_overall_progress_from_message(message, dlmsg);
  1719. mb2_handle_send_files(mobilebackup2, message, backup_directory);
  1720. } else if (!strcmp(dlmsg, "DLMessageUploadFiles")) {
  1721. /* device wants to send files to the computer */
  1722. mb2_set_overall_progress_from_message(message, dlmsg);
  1723. file_count += mb2_handle_receive_files(mobilebackup2, message, backup_directory);
  1724. } else if (!strcmp(dlmsg, "DLMessageGetFreeDiskSpace")) {
  1725. /* device wants to know how much disk space is available on the computer */
  1726. uint64_t freespace = 0;
  1727. int res = -1;
  1728. #ifdef WIN32
  1729. if (GetDiskFreeSpaceEx(backup_directory, (PULARGE_INTEGER)&freespace, NULL, NULL)) {
  1730. res = 0;
  1731. }
  1732. #else
  1733. struct statvfs fs;
  1734. memset(&fs, '\0', sizeof(fs));
  1735. res = statvfs(backup_directory, &fs);
  1736. if (res == 0) {
  1737. freespace = (uint64_t)fs.f_bavail * (uint64_t)fs.f_bsize;
  1738. }
  1739. #endif
  1740. plist_t freespace_item = plist_new_uint(freespace);
  1741. mobilebackup2_send_status_response(mobilebackup2, res, NULL, freespace_item);
  1742. plist_free(freespace_item);
  1743. } else if (!strcmp(dlmsg, "DLContentsOfDirectory")) {
  1744. /* list directory contents */
  1745. mb2_handle_list_directory(mobilebackup2, message, backup_directory);
  1746. } else if (!strcmp(dlmsg, "DLMessageCreateDirectory")) {
  1747. /* make a directory */
  1748. mb2_handle_make_directory(mobilebackup2, message, backup_directory);
  1749. } else if (!strcmp(dlmsg, "DLMessageMoveFiles") || !strcmp(dlmsg, "DLMessageMoveItems")) {
  1750. /* perform a series of rename operations */
  1751. mb2_set_overall_progress_from_message(message, dlmsg);
  1752. plist_t moves = plist_array_get_item(message, 1);
  1753. uint32_t cnt = plist_dict_get_size(moves);
  1754. PRINT_VERBOSE(1, "Moving %d file%s\n", cnt, (cnt == 1) ? "" : "s");
  1755. plist_dict_iter iter = NULL;
  1756. plist_dict_new_iter(moves, &iter);
  1757. errcode = 0;
  1758. errdesc = NULL;
  1759. if (iter) {
  1760. char *key = NULL;
  1761. plist_t val = NULL;
  1762. do {
  1763. plist_dict_next_item(moves, iter, &key, &val);
  1764. if (key && (plist_get_node_type(val) == PLIST_STRING)) {
  1765. char *str = NULL;
  1766. plist_get_string_val(val, &str);
  1767. if (str) {
  1768. char *newpath = build_path(backup_directory, str, NULL);
  1769. free(str);
  1770. char *oldpath = build_path(backup_directory, key, NULL);
  1771. #ifdef WIN32
  1772. if ((stat(newpath, &st) == 0) && S_ISDIR(st.st_mode))
  1773. RemoveDirectory(newpath);
  1774. else
  1775. DeleteFile(newpath);
  1776. #else
  1777. remove(newpath);
  1778. #endif
  1779. if (rename(oldpath, newpath) < 0) {
  1780. printf("Renameing '%s' to '%s' failed: %s (%d)\n", oldpath, newpath, strerror(errno), errno);
  1781. errcode = errno_to_device_error(errno);
  1782. errdesc = strerror(errno);
  1783. break;
  1784. }
  1785. free(oldpath);
  1786. free(newpath);
  1787. }
  1788. free(key);
  1789. key = NULL;
  1790. }
  1791. } while (val);
  1792. free(iter);
  1793. } else {
  1794. errcode = -1;
  1795. errdesc = "Could not create dict iterator";
  1796. printf("Could not create dict iterator\n");
  1797. }
  1798. plist_t empty_dict = plist_new_dict();
  1799. err = mobilebackup2_send_status_response(mobilebackup2, errcode, errdesc, empty_dict);
  1800. plist_free(empty_dict);
  1801. if (err != MOBILEBACKUP2_E_SUCCESS) {
  1802. printf("Could not send status response, error %d\n", err);
  1803. }
  1804. } else if (!strcmp(dlmsg, "DLMessageRemoveFiles") || !strcmp(dlmsg, "DLMessageRemoveItems")) {
  1805. mb2_set_overall_progress_from_message(message, dlmsg);
  1806. plist_t removes = plist_array_get_item(message, 1);
  1807. uint32_t cnt = plist_array_get_size(removes);
  1808. PRINT_VERBOSE(1, "Removing %d file%s\n", cnt, (cnt == 1) ? "" : "s");
  1809. uint32_t ii = 0;
  1810. errcode = 0;
  1811. errdesc = NULL;
  1812. for (ii = 0; ii < cnt; ii++) {
  1813. plist_t val = plist_array_get_item(removes, ii);
  1814. if (plist_get_node_type(val) == PLIST_STRING) {
  1815. char *str = NULL;
  1816. plist_get_string_val(val, &str);
  1817. if (str) {
  1818. const char *checkfile = strchr(str, '/');
  1819. int suppress_warning = 0;
  1820. if (checkfile) {
  1821. if (strcmp(checkfile+1, "Manifest.mbdx") == 0) {
  1822. suppress_warning = 1;
  1823. }
  1824. }
  1825. char *newpath = build_path(backup_directory, str, NULL);
  1826. free(str);
  1827. #ifdef WIN32
  1828. int res = 0;
  1829. if ((stat(newpath, &st) == 0) && S_ISDIR(st.st_mode))
  1830. res = RemoveDirectory(newpath);
  1831. else
  1832. res = DeleteFile(newpath);
  1833. if (!res) {
  1834. int e = win32err_to_errno(GetLastError());
  1835. if (!suppress_warning)
  1836. printf("Could not remove '%s': %s (%d)\n", newpath, strerror(e), e);
  1837. errcode = errno_to_device_error(e);
  1838. errdesc = strerror(e);
  1839. }
  1840. #else
  1841. if (remove(newpath) < 0) {
  1842. if (!suppress_warning)
  1843. printf("Could not remove '%s': %s (%d)\n", newpath, strerror(errno), errno);
  1844. errcode = errno_to_device_error(errno);
  1845. errdesc = strerror(errno);
  1846. }
  1847. #endif
  1848. free(newpath);
  1849. }
  1850. }
  1851. }
  1852. plist_t empty_dict = plist_new_dict();
  1853. err = mobilebackup2_send_status_response(mobilebackup2, errcode, errdesc, empty_dict);
  1854. plist_free(empty_dict);
  1855. if (err != MOBILEBACKUP2_E_SUCCESS) {
  1856. printf("Could not send status response, error %d\n", err);
  1857. }
  1858. } else if (!strcmp(dlmsg, "DLMessageCopyItem")) {
  1859. plist_t srcpath = plist_array_get_item(message, 1);
  1860. plist_t dstpath = plist_array_get_item(message, 2);
  1861. errcode = 0;
  1862. errdesc = NULL;
  1863. if ((plist_get_node_type(srcpath) == PLIST_STRING) && (plist_get_node_type(dstpath) == PLIST_STRING)) {
  1864. char *src = NULL;
  1865. char *dst = NULL;
  1866. plist_get_string_val(srcpath, &src);
  1867. plist_get_string_val(dstpath, &dst);
  1868. if (src && dst) {
  1869. char *oldpath = build_path(backup_directory, src, NULL);
  1870. char *newpath = build_path(backup_directory, dst, NULL);
  1871. PRINT_VERBOSE(1, "Copying '%s' to '%s'\n", src, dst);
  1872. /* check that src exists */
  1873. if ((stat(oldpath, &st) == 0) && S_ISDIR(st.st_mode)) {
  1874. mb2_copy_directory_by_path(oldpath, newpath);
  1875. } else if ((stat(oldpath, &st) == 0) && S_ISREG(st.st_mode)) {
  1876. mb2_copy_file_by_path(oldpath, newpath);
  1877. }
  1878. free(newpath);
  1879. free(oldpath);
  1880. }
  1881. free(src);
  1882. free(dst);
  1883. }
  1884. plist_t empty_dict = plist_new_dict();
  1885. err = mobilebackup2_send_status_response(mobilebackup2, errcode, errdesc, empty_dict);
  1886. plist_free(empty_dict);
  1887. if (err != MOBILEBACKUP2_E_SUCCESS) {
  1888. printf("Could not send status response, error %d\n", err);
  1889. }
  1890. } else if (!strcmp(dlmsg, "DLMessageDisconnect")) {
  1891. break;
  1892. } else if (!strcmp(dlmsg, "DLMessageProcessMessage")) {
  1893. node_tmp = plist_array_get_item(message, 1);
  1894. if (plist_get_node_type(node_tmp) != PLIST_DICT) {
  1895. printf("Unknown message received!\n");
  1896. }
  1897. plist_t nn;
  1898. int error_code = -1;
  1899. nn = plist_dict_get_item(node_tmp, "ErrorCode");
  1900. if (nn && (plist_get_node_type(nn) == PLIST_UINT)) {
  1901. uint64_t ec = 0;
  1902. plist_get_uint_val(nn, &ec);
  1903. error_code = (uint32_t)ec;
  1904. if (error_code == 0) {
  1905. operation_ok = 1;
  1906. result_code = 0;
  1907. } else {
  1908. result_code = -error_code;
  1909. }
  1910. }
  1911. nn = plist_dict_get_item(node_tmp, "ErrorDescription");
  1912. char *str = NULL;
  1913. if (nn && (plist_get_node_type(nn) == PLIST_STRING)) {
  1914. plist_get_string_val(nn, &str);
  1915. }
  1916. if (error_code != 0) {
  1917. if (str) {
  1918. printf("ErrorCode %d: %s\n", error_code, str);
  1919. } else {
  1920. printf("ErrorCode %d: (Unknown)\n", error_code);
  1921. }
  1922. }
  1923. if (str) {
  1924. free(str);
  1925. }
  1926. nn = plist_dict_get_item(node_tmp, "Content");
  1927. if (nn && (plist_get_node_type(nn) == PLIST_STRING)) {
  1928. str = NULL;
  1929. plist_get_string_val(nn, &str);
  1930. PRINT_VERBOSE(1, "Content:\n");
  1931. printf("%s", str);
  1932. free(str);
  1933. }
  1934. break;
  1935. }
  1936. /* print status */
  1937. if (overall_progress > 0) {
  1938. print_progress_real(overall_progress, 0);
  1939. PRINT_VERBOSE(1, " Finished\n");
  1940. }
  1941. if (message)
  1942. plist_free(message);
  1943. message = NULL;
  1944. files_out:
  1945. if (quit_flag > 0) {
  1946. /* need to cancel the backup here */
  1947. //mobilebackup_send_error(mobilebackup, "Cancelling DLSendFile");
  1948. /* remove any atomic Manifest.plist.tmp */
  1949. /*manifest_path = mobilebackup_build_path(backup_directory, "Manifest", ".plist.tmp");
  1950. if (stat(manifest_path, &st) == 0)
  1951. remove(manifest_path);*/
  1952. break;
  1953. }
  1954. } while (1);
  1955. /* report operation status to user */
  1956. switch (cmd) {
  1957. case CMD_BACKUP:
  1958. PRINT_VERBOSE(1, "Received %d files from device.\n", file_count);
  1959. if (operation_ok && mb2_status_check_snapshot_state(backup_directory, udid, "finished")) {
  1960. PRINT_VERBOSE(1, "Backup Successful.\n");
  1961. } else {
  1962. if (quit_flag) {
  1963. PRINT_VERBOSE(1, "Backup Aborted.\n");
  1964. } else {
  1965. PRINT_VERBOSE(1, "Backup Failed (Error Code %d).\n", -result_code);
  1966. }
  1967. }
  1968. break;
  1969. case CMD_UNBACK:
  1970. if (quit_flag) {
  1971. PRINT_VERBOSE(1, "Unback Aborted.\n");
  1972. } else {
  1973. PRINT_VERBOSE(1, "The files can now be found in the \"_unback_\" directory.\n");
  1974. PRINT_VERBOSE(1, "Unback Successful.\n");
  1975. }
  1976. break;
  1977. case CMD_CHANGEPW:
  1978. if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) {
  1979. if (operation_ok) {
  1980. PRINT_VERBOSE(1, "Backup encryption has been enabled successfully.\n");
  1981. } else {
  1982. PRINT_VERBOSE(1, "Could not enable backup encryption.\n");
  1983. }
  1984. } else if (cmd_flags & CMD_FLAG_ENCRYPTION_DISABLE) {
  1985. if (operation_ok) {
  1986. PRINT_VERBOSE(1, "Backup encryption has been disabled successfully.\n");
  1987. } else {
  1988. PRINT_VERBOSE(1, "Could not disable backup encryption.\n");
  1989. }
  1990. } else if (cmd_flags & CMD_FLAG_ENCRYPTION_CHANGEPW) {
  1991. if (operation_ok) {
  1992. PRINT_VERBOSE(1, "Backup encryption password has been changed successfully.\n");
  1993. } else {
  1994. PRINT_VERBOSE(1, "Could not change backup encryption password.\n");
  1995. }
  1996. }
  1997. break;
  1998. case CMD_RESTORE:
  1999. if (cmd_flags & CMD_FLAG_RESTORE_REBOOT)
  2000. PRINT_VERBOSE(1, "The device should reboot now.\n");
  2001. if (operation_ok) {
  2002. PRINT_VERBOSE(1, "Restore Successful.\n");
  2003. } else {
  2004. PRINT_VERBOSE(1, "Restore Failed (Error Code %d).\n", -result_code);
  2005. }
  2006. break;
  2007. case CMD_INFO:
  2008. case CMD_LIST:
  2009. case CMD_LEAVE:
  2010. default:
  2011. if (quit_flag) {
  2012. PRINT_VERBOSE(1, "Operation Aborted.\n");
  2013. } else if (cmd == CMD_LEAVE) {
  2014. PRINT_VERBOSE(1, "Operation Failed.\n");
  2015. } else {
  2016. PRINT_VERBOSE(1, "Operation Successful.\n");
  2017. }
  2018. break;
  2019. }
  2020. }
  2021. if (lockfile) {
  2022. afc_file_lock(afc, lockfile, AFC_LOCK_UN);
  2023. afc_file_close(afc, lockfile);
  2024. lockfile = 0;
  2025. if (cmd == CMD_BACKUP)
  2026. do_post_notification(device, NP_SYNC_DID_FINISH);
  2027. }
  2028. } else {
  2029. printf("ERROR: Could not start service %s.\n", MOBILEBACKUP2_SERVICE_NAME);
  2030. lockdownd_client_free(lockdown);
  2031. lockdown = NULL;
  2032. }
  2033. if (lockdown) {
  2034. lockdownd_client_free(lockdown);
  2035. lockdown = NULL;
  2036. }
  2037. if (mobilebackup2) {
  2038. mobilebackup2_client_free(mobilebackup2);
  2039. mobilebackup2 = NULL;
  2040. }
  2041. if (afc) {
  2042. afc_client_free(afc);
  2043. afc = NULL;
  2044. }
  2045. if (np) {
  2046. np_client_free(np);
  2047. np = NULL;
  2048. }
  2049. idevice_free(device);
  2050. device = NULL;
  2051. if (udid) {
  2052. free(udid);
  2053. udid = NULL;
  2054. }
  2055. if (source_udid) {
  2056. free(source_udid);
  2057. source_udid = NULL;
  2058. }
  2059. return result_code;
  2060. }