PageRenderTime 80ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/libimobiledevice-tools/idevicebackup2/idevicebackup2.cpp

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