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);
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.
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)
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)