Skip to content

Commit 9049ffb

Browse files
committed
afc: Add afc_get_file_info_plist and afc_get_device_info_plist functions
These functions are like afc_get_file_info/afc_get_device_info but the data is returned as a plist_t dictionary instead of a string list.
1 parent 39357c0 commit 9049ffb

File tree

2 files changed

+144
-3
lines changed

2 files changed

+144
-3
lines changed

include/libimobiledevice/afc.h

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,20 @@ LIBIMOBILEDEVICE_API afc_error_t afc_client_free(afc_client_t client);
144144
*/
145145
LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info(afc_client_t client, char ***device_information);
146146

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+
*/
159+
LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info_plist(afc_client_t client, plist_t *device_information);
160+
147161
/**
148162
* Gets a directory listing of the directory requested.
149163
*
@@ -163,13 +177,26 @@ LIBIMOBILEDEVICE_API afc_error_t afc_read_directory(afc_client_t client, const c
163177
* @param client The client to use to get the information of the file.
164178
* @param path The fully-qualified path to the file.
165179
* @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
167181
* before calling this function. Free with afc_dictionary_free().
168182
*
169183
* @return AFC_E_SUCCESS on success or an AFC_E_* error value.
170184
*/
171185
LIBIMOBILEDEVICE_API afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***file_information);
172186

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+
*/
198+
LIBIMOBILEDEVICE_API afc_error_t afc_get_file_info_plist(afc_client_t client, const char *path, plist_t *file_information);
199+
173200
/**
174201
* Opens a file on the device.
175202
*

src/afc.c

Lines changed: 116 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,50 @@ static char **make_strings_list(char *tokens, uint32_t length)
402402
return list;
403403
}
404404

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+
405449
static int _afc_check_packet_buffer(afc_client_t client, uint32_t data_len)
406450
{
407451
if (data_len > client->packet_extra) {
@@ -498,6 +542,40 @@ afc_error_t afc_get_device_info(afc_client_t client, char ***device_information)
498542
return ret;
499543
}
500544

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+
501579
afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char **value)
502580
{
503581
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
647725
return AFC_E_NO_MEM;
648726
}
649727

650-
debug_info("We got %p and %p", client->afc_packet, AFC_PACKET_DATA_PTR);
651-
652728
/* Send command */
653729
memcpy(AFC_PACKET_DATA_PTR, path, data_len);
654730
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
669745
return ret;
670746
}
671747

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+
672786
afc_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle)
673787
{
674788
if (!client || !client->parent || !client->afc_packet)

0 commit comments

Comments
 (0)