diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/afc.c | 118 |
1 files changed, 116 insertions, 2 deletions
| @@ -402,6 +402,50 @@ static char **make_strings_list(char *tokens, uint32_t length) | |||
| 402 | return list; | 402 | return list; |
| 403 | } | 403 | } |
| 404 | 404 | ||
| 405 | static plist_t *make_dictionary(char *tokens, size_t length) | ||
| 406 | { | ||
| 407 | size_t j = 0; | ||
| 408 | plist_t dict = NULL; | ||
| 409 | |||
| 410 | if (!tokens || !length) | ||
| 411 | return NULL; | ||
| 412 | |||
| 413 | dict = plist_new_dict(); | ||
| 414 | |||
| 415 | while (j < length) { | ||
| 416 | size_t key_len = strnlen(tokens + j, length - j); | ||
| 417 | if (j + key_len >= length) { | ||
| 418 | plist_free(dict); | ||
| 419 | return NULL; | ||
| 420 | } | ||
| 421 | char* key = tokens + j; | ||
| 422 | j += key_len + 1; | ||
| 423 | |||
| 424 | if (j >= length) { | ||
| 425 | plist_free(dict); | ||
| 426 | return NULL; | ||
| 427 | } | ||
| 428 | |||
| 429 | size_t val_len = strnlen(tokens + j, length - j); | ||
| 430 | if (j + val_len >= length) { | ||
| 431 | plist_free(dict); | ||
| 432 | return NULL; | ||
| 433 | } | ||
| 434 | char* val = tokens + j; | ||
| 435 | j += val_len + 1; | ||
| 436 | |||
| 437 | char* endp = NULL; | ||
| 438 | unsigned long long u64val = strtoull(val, &endp, 10); | ||
| 439 | if (endp && *endp == '\0') { | ||
| 440 | plist_dict_set_item(dict, key, plist_new_uint(u64val)); | ||
| 441 | } else { | ||
| 442 | plist_dict_set_item(dict, key, plist_new_string(val)); | ||
| 443 | } | ||
| 444 | } | ||
| 445 | |||
| 446 | return dict; | ||
| 447 | } | ||
| 448 | |||
| 405 | static int _afc_check_packet_buffer(afc_client_t client, uint32_t data_len) | 449 | static int _afc_check_packet_buffer(afc_client_t client, uint32_t data_len) |
| 406 | { | 450 | { |
| 407 | if (data_len > client->packet_extra) { | 451 | if (data_len > client->packet_extra) { |
| @@ -498,6 +542,40 @@ afc_error_t afc_get_device_info(afc_client_t client, char ***device_information) | |||
| 498 | return ret; | 542 | return ret; |
| 499 | } | 543 | } |
| 500 | 544 | ||
| 545 | afc_error_t afc_get_device_info_plist(afc_client_t client, plist_t *device_information) | ||
| 546 | { | ||
| 547 | uint32_t bytes = 0; | ||
| 548 | char *data = NULL; | ||
| 549 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; | ||
| 550 | |||
| 551 | if (!client || !device_information) | ||
| 552 | return AFC_E_INVALID_ARG; | ||
| 553 | |||
| 554 | afc_lock(client); | ||
| 555 | |||
| 556 | /* Send the command */ | ||
| 557 | ret = afc_dispatch_packet(client, AFC_OP_GET_DEVINFO, 0, NULL, 0, &bytes); | ||
| 558 | if (ret != AFC_E_SUCCESS) { | ||
| 559 | afc_unlock(client); | ||
| 560 | return AFC_E_NOT_ENOUGH_DATA; | ||
| 561 | } | ||
| 562 | /* Receive the data */ | ||
| 563 | ret = afc_receive_data(client, &data, &bytes); | ||
| 564 | if (ret != AFC_E_SUCCESS) { | ||
| 565 | if (data) | ||
| 566 | free(data); | ||
| 567 | afc_unlock(client); | ||
| 568 | return ret; | ||
| 569 | } | ||
| 570 | /* Parse the data */ | ||
| 571 | *device_information = make_dictionary(data, bytes); | ||
| 572 | free(data); | ||
| 573 | |||
| 574 | afc_unlock(client); | ||
| 575 | |||
| 576 | return ret; | ||
| 577 | } | ||
| 578 | |||
| 501 | afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char **value) | 579 | afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char **value) |
| 502 | { | 580 | { |
| 503 | afc_error_t ret = AFC_E_INTERNAL_ERROR; | 581 | afc_error_t ret = AFC_E_INTERNAL_ERROR; |
| @@ -647,8 +725,6 @@ afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***fil | |||
| 647 | return AFC_E_NO_MEM; | 725 | return AFC_E_NO_MEM; |
| 648 | } | 726 | } |
| 649 | 727 | ||
| 650 | debug_info("We got %p and %p", client->afc_packet, AFC_PACKET_DATA_PTR); | ||
| 651 | |||
| 652 | /* Send command */ | 728 | /* Send command */ |
| 653 | memcpy(AFC_PACKET_DATA_PTR, path, data_len); | 729 | memcpy(AFC_PACKET_DATA_PTR, path, data_len); |
| 654 | ret = afc_dispatch_packet(client, AFC_OP_GET_FILE_INFO, data_len, NULL, 0, &bytes); | 730 | ret = afc_dispatch_packet(client, AFC_OP_GET_FILE_INFO, data_len, NULL, 0, &bytes); |
| @@ -669,6 +745,44 @@ afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***fil | |||
| 669 | return ret; | 745 | return ret; |
| 670 | } | 746 | } |
| 671 | 747 | ||
| 748 | afc_error_t afc_get_file_info_plist(afc_client_t client, const char *path, plist_t *file_information) | ||
| 749 | { | ||
| 750 | char *received = NULL; | ||
| 751 | uint32_t bytes = 0; | ||
| 752 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; | ||
| 753 | |||
| 754 | if (!client || !path || !file_information) | ||
| 755 | return AFC_E_INVALID_ARG; | ||
| 756 | |||
| 757 | afc_lock(client); | ||
| 758 | |||
| 759 | uint32_t data_len = (uint32_t)strlen(path)+1; | ||
| 760 | if (_afc_check_packet_buffer(client, data_len) < 0) { | ||
| 761 | afc_unlock(client); | ||
| 762 | debug_info("Failed to realloc packet buffer"); | ||
| 763 | return AFC_E_NO_MEM; | ||
| 764 | } | ||
| 765 | |||
| 766 | /* Send command */ | ||
| 767 | memcpy(AFC_PACKET_DATA_PTR, path, data_len); | ||
| 768 | ret = afc_dispatch_packet(client, AFC_OP_GET_FILE_INFO, data_len, NULL, 0, &bytes); | ||
| 769 | if (ret != AFC_E_SUCCESS) { | ||
| 770 | afc_unlock(client); | ||
| 771 | return AFC_E_NOT_ENOUGH_DATA; | ||
| 772 | } | ||
| 773 | |||
| 774 | /* Receive data */ | ||
| 775 | ret = afc_receive_data(client, &received, &bytes); | ||
| 776 | if (received) { | ||
| 777 | *file_information = make_dictionary(received, bytes); | ||
| 778 | free(received); | ||
| 779 | } | ||
| 780 | |||
| 781 | afc_unlock(client); | ||
| 782 | |||
| 783 | return ret; | ||
| 784 | } | ||
| 785 | |||
| 672 | afc_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle) | 786 | afc_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle) |
| 673 | { | 787 | { |
| 674 | if (!client || !client->parent || !client->afc_packet) | 788 | if (!client || !client->parent || !client->afc_packet) |
