summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/libimobiledevice/afc.h29
-rw-r--r--src/afc.c118
2 files changed, 144 insertions, 3 deletions
diff --git a/include/libimobiledevice/afc.h b/include/libimobiledevice/afc.h
index 4ad3dbd..3dcb5da 100644
--- a/include/libimobiledevice/afc.h
+++ b/include/libimobiledevice/afc.h
@@ -145,6 +145,20 @@ LIBIMOBILEDEVICE_API afc_error_t afc_client_free(afc_client_t client);
145LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info(afc_client_t client, char ***device_information); 145LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info(afc_client_t client, char ***device_information);
146 146
147/** 147/**
148 * Get device information for a connected client. The device information
149 * returned is the device model as well as the free space, the total capacity
150 * and blocksize on the accessed disk partition.
151 *
152 * @param client The client to get device info for.
153 * @param device_information A pointer to a plist_t that will be populated
154 * with key-value pairs (dictionary) representing the device’s
155 * storage and model information. Free with plist_free().
156 *
157 * @return AFC_E_SUCCESS on success or an AFC_E_* error value.
158 */
159LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info_plist(afc_client_t client, plist_t *device_information);
160
161/**
148 * Gets a directory listing of the directory requested. 162 * Gets a directory listing of the directory requested.
149 * 163 *
150 * @param client The client to get a directory listing from. 164 * @param client The client to get a directory listing from.
@@ -163,7 +177,7 @@ LIBIMOBILEDEVICE_API afc_error_t afc_read_directory(afc_client_t client, const c
163 * @param client The client to use to get the information of the file. 177 * @param client The client to use to get the information of the file.
164 * @param path The fully-qualified path to the file. 178 * @param path The fully-qualified path to the file.
165 * @param file_information Pointer to a buffer that will be filled with a 179 * @param file_information Pointer to a buffer that will be filled with a
166 * NULL-terminated list of strings with the file information. Set to NULL 180 * NULL-terminated list of strings with the file attributes. Set to NULL
167 * before calling this function. Free with afc_dictionary_free(). 181 * before calling this function. Free with afc_dictionary_free().
168 * 182 *
169 * @return AFC_E_SUCCESS on success or an AFC_E_* error value. 183 * @return AFC_E_SUCCESS on success or an AFC_E_* error value.
@@ -171,6 +185,19 @@ LIBIMOBILEDEVICE_API afc_error_t afc_read_directory(afc_client_t client, const c
171LIBIMOBILEDEVICE_API afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***file_information); 185LIBIMOBILEDEVICE_API afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***file_information);
172 186
173/** 187/**
188 * Gets information about a specific file.
189 *
190 * @param client The client to use to get the information of the file.
191 * @param path The fully-qualified path to the file.
192 * @param file_information A pointer to a plist_t that will be populated
193 * with key-value pairs (dictionary) representing the file attributes.
194 * Free with plist_free().
195 *
196 * @return AFC_E_SUCCESS on success or an AFC_E_* error value.
197 */
198LIBIMOBILEDEVICE_API afc_error_t afc_get_file_info_plist(afc_client_t client, const char *path, plist_t *file_information);
199
200/**
174 * Opens a file on the device. 201 * Opens a file on the device.
175 * 202 *
176 * @param client The client to use to open the file. 203 * @param client The client to use to open the file.
diff --git a/src/afc.c b/src/afc.c
index c0314bc..c7eed5c 100644
--- a/src/afc.c
+++ b/src/afc.c
@@ -402,6 +402,50 @@ static char **make_strings_list(char *tokens, uint32_t length)
402 return list; 402 return list;
403} 403}
404 404
405static 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
405static int _afc_check_packet_buffer(afc_client_t client, uint32_t data_len) 449static 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
545afc_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
501afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char **value) 579afc_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
748afc_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
672afc_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle) 786afc_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)