diff options
-rw-r--r-- | include/libimobiledevice/afc.h | 29 | ||||
-rw-r--r-- | src/afc.c | 118 |
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); LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info(afc_client_t client, char ***device_information); /** + * Get device information for a connected client. The device information + * returned is the device model as well as the free space, the total capacity + * and blocksize on the accessed disk partition. + * + * @param client The client to get device info for. + * @param device_information A pointer to a plist_t that will be populated + * with key-value pairs (dictionary) representing the device’s + * storage and model information. Free with plist_free(). + * + * @return AFC_E_SUCCESS on success or an AFC_E_* error value. + */ +LIBIMOBILEDEVICE_API afc_error_t afc_get_device_info_plist(afc_client_t client, plist_t *device_information); + +/** * Gets a directory listing of the directory requested. * * @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 * @param client The client to use to get the information of the file. * @param path The fully-qualified path to the file. * @param file_information Pointer to a buffer that will be filled with a - * NULL-terminated list of strings with the file information. Set to NULL + * NULL-terminated list of strings with the file attributes. Set to NULL * before calling this function. Free with afc_dictionary_free(). * * @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 LIBIMOBILEDEVICE_API afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***file_information); /** + * Gets information about a specific file. + * + * @param client The client to use to get the information of the file. + * @param path The fully-qualified path to the file. + * @param file_information A pointer to a plist_t that will be populated + * with key-value pairs (dictionary) representing the file attributes. + * Free with plist_free(). + * + * @return AFC_E_SUCCESS on success or an AFC_E_* error value. + */ +LIBIMOBILEDEVICE_API afc_error_t afc_get_file_info_plist(afc_client_t client, const char *path, plist_t *file_information); + +/** * Opens a file on the device. * * @param client The client to use to open the file. @@ -402,6 +402,50 @@ static char **make_strings_list(char *tokens, uint32_t length) return list; } +static plist_t *make_dictionary(char *tokens, size_t length) +{ + size_t j = 0; + plist_t dict = NULL; + + if (!tokens || !length) + return NULL; + + dict = plist_new_dict(); + + while (j < length) { + size_t key_len = strnlen(tokens + j, length - j); + if (j + key_len >= length) { + plist_free(dict); + return NULL; + } + char* key = tokens + j; + j += key_len + 1; + + if (j >= length) { + plist_free(dict); + return NULL; + } + + size_t val_len = strnlen(tokens + j, length - j); + if (j + val_len >= length) { + plist_free(dict); + return NULL; + } + char* val = tokens + j; + j += val_len + 1; + + char* endp = NULL; + unsigned long long u64val = strtoull(val, &endp, 10); + if (endp && *endp == '\0') { + plist_dict_set_item(dict, key, plist_new_uint(u64val)); + } else { + plist_dict_set_item(dict, key, plist_new_string(val)); + } + } + + return dict; +} + static int _afc_check_packet_buffer(afc_client_t client, uint32_t data_len) { if (data_len > client->packet_extra) { @@ -498,6 +542,40 @@ afc_error_t afc_get_device_info(afc_client_t client, char ***device_information) return ret; } +afc_error_t afc_get_device_info_plist(afc_client_t client, plist_t *device_information) +{ + uint32_t bytes = 0; + char *data = NULL; + afc_error_t ret = AFC_E_UNKNOWN_ERROR; + + if (!client || !device_information) + return AFC_E_INVALID_ARG; + + afc_lock(client); + + /* Send the command */ + ret = afc_dispatch_packet(client, AFC_OP_GET_DEVINFO, 0, NULL, 0, &bytes); + if (ret != AFC_E_SUCCESS) { + afc_unlock(client); + return AFC_E_NOT_ENOUGH_DATA; + } + /* Receive the data */ + ret = afc_receive_data(client, &data, &bytes); + if (ret != AFC_E_SUCCESS) { + if (data) + free(data); + afc_unlock(client); + return ret; + } + /* Parse the data */ + *device_information = make_dictionary(data, bytes); + free(data); + + afc_unlock(client); + + return ret; +} + afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char **value) { 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 return AFC_E_NO_MEM; } - debug_info("We got %p and %p", client->afc_packet, AFC_PACKET_DATA_PTR); - /* Send command */ memcpy(AFC_PACKET_DATA_PTR, path, data_len); 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 return ret; } +afc_error_t afc_get_file_info_plist(afc_client_t client, const char *path, plist_t *file_information) +{ + char *received = NULL; + uint32_t bytes = 0; + afc_error_t ret = AFC_E_UNKNOWN_ERROR; + + if (!client || !path || !file_information) + return AFC_E_INVALID_ARG; + + afc_lock(client); + + uint32_t data_len = (uint32_t)strlen(path)+1; + if (_afc_check_packet_buffer(client, data_len) < 0) { + afc_unlock(client); + debug_info("Failed to realloc packet buffer"); + return AFC_E_NO_MEM; + } + + /* Send command */ + memcpy(AFC_PACKET_DATA_PTR, path, data_len); + ret = afc_dispatch_packet(client, AFC_OP_GET_FILE_INFO, data_len, NULL, 0, &bytes); + if (ret != AFC_E_SUCCESS) { + afc_unlock(client); + return AFC_E_NOT_ENOUGH_DATA; + } + + /* Receive data */ + ret = afc_receive_data(client, &received, &bytes); + if (received) { + *file_information = make_dictionary(received, bytes); + free(received); + } + + afc_unlock(client); + + return ret; +} + afc_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle) { if (!client || !client->parent || !client->afc_packet) |