summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/libimobiledevice/mobile_image_mounter.h5
-rw-r--r--src/mobile_image_mounter.c122
2 files changed, 127 insertions, 0 deletions
diff --git a/include/libimobiledevice/mobile_image_mounter.h b/include/libimobiledevice/mobile_image_mounter.h
index ceaf0c2..560fec6 100644
--- a/include/libimobiledevice/mobile_image_mounter.h
+++ b/include/libimobiledevice/mobile_image_mounter.h
@@ -38,6 +38,7 @@ extern "C" {
#define MOBILE_IMAGE_MOUNTER_E_INVALID_ARG -1
#define MOBILE_IMAGE_MOUNTER_E_PLIST_ERROR -2
#define MOBILE_IMAGE_MOUNTER_E_CONN_FAILED -3
+#define MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED -4
#define MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR -256
/*@}*/
@@ -48,12 +49,16 @@ typedef int16_t mobile_image_mounter_error_t;
typedef struct mobile_image_mounter_client_private mobile_image_mounter_client_private;
typedef mobile_image_mounter_client_private *mobile_image_mounter_client_t; /**< The client handle. */
+/** callback for image upload */
+typedef ssize_t (*mobile_image_mounter_upload_cb_t) (void* buffer, size_t length, void *user_data);
+
/* Interface */
mobile_image_mounter_error_t mobile_image_mounter_new(idevice_t device, lockdownd_service_descriptor_t service, mobile_image_mounter_client_t *client);
mobile_image_mounter_error_t mobile_image_mounter_start_service(idevice_t device, mobile_image_mounter_client_t* client, const char* label);
mobile_image_mounter_error_t mobile_image_mounter_free(mobile_image_mounter_client_t client);
mobile_image_mounter_error_t mobile_image_mounter_lookup_image(mobile_image_mounter_client_t client, const char *image_type, plist_t *result);
+mobile_image_mounter_error_t mobile_image_mounter_upload_image(mobile_image_mounter_client_t client, const char *image_type, size_t image_size, mobile_image_mounter_upload_cb_t upload_cb, void* userdata);
mobile_image_mounter_error_t mobile_image_mounter_mount_image(mobile_image_mounter_client_t client, const char *image_path, const char *image_signature, uint16_t signature_length, const char *image_type, plist_t *result);
mobile_image_mounter_error_t mobile_image_mounter_hangup(mobile_image_mounter_client_t client);
diff --git a/src/mobile_image_mounter.c b/src/mobile_image_mounter.c
index bc439f9..9e6d8e9 100644
--- a/src/mobile_image_mounter.c
+++ b/src/mobile_image_mounter.c
@@ -190,6 +190,128 @@ leave_unlock:
}
/**
+ * Uploads an image to the device.
+ *
+ * @param client The connected mobile_image_mounter client.
+ * @param image_type Type of image that is being uploaded.
+ * @param image_size Total size of the image.
+ * @param upload_cb Callback function that gets the data chunks for uploading
+ * the image.
+ * @param userdata User defined data for the upload callback function.
+ *
+ * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on succes, or a
+ * MOBILE_IMAGE_MOUNTER_E_* error code otherwise.
+ */
+mobile_image_mounter_error_t mobile_image_mounter_upload_image(mobile_image_mounter_client_t client, const char *image_type, size_t image_size, mobile_image_mounter_upload_cb_t upload_cb, void* userdata)
+{
+ if (!client || !image_type || (image_size == 0) || !upload_cb) {
+ return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG;
+ }
+ mobile_image_mounter_lock(client);
+ plist_t result = NULL;
+
+ plist_t dict = plist_new_dict();
+ plist_dict_insert_item(dict, "Command", plist_new_string("ReceiveBytes"));
+ plist_dict_insert_item(dict, "ImageSize", plist_new_uint(image_size));
+ plist_dict_insert_item(dict, "ImageType", plist_new_string(image_type));
+
+ mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict));
+ plist_free(dict);
+
+ if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
+ debug_info("Error sending XML plist to device!");
+ goto leave_unlock;
+ }
+
+ res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &result));
+ if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
+ debug_info("Error receiving response from device!");
+ goto leave_unlock;
+ }
+ res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED;
+
+ char* strval = NULL;
+ plist_t node = plist_dict_get_item(result, "Status");
+ if (node && plist_get_node_type(node) == PLIST_STRING) {
+ plist_get_string_val(node, &strval);
+ }
+ if (!strval) {
+ debug_info("Error: Unexpected response received!");
+ goto leave_unlock;
+ }
+ if (strcmp(strval, "ReceiveBytesAck") != 0) {
+ debug_info("Error: didn't get ReceiveBytesAck but %s", strval);
+ free(strval);
+ goto leave_unlock;
+ }
+ free(strval);
+
+ size_t tx = 0;
+ size_t bufsize = 65536;
+ unsigned char *buf = (unsigned char*)malloc(bufsize);
+ if (!buf) {
+ debug_info("Out of memory");
+ res = MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR;
+ goto leave_unlock;
+ }
+ debug_info("uploading image (%d bytes)", (int)image_size);
+ while (tx < image_size) {
+ size_t remaining = image_size - tx;
+ size_t amount = (remaining < bufsize) ? remaining : bufsize;
+ ssize_t r = upload_cb(buf, amount, userdata);
+ if (r < 0) {
+ debug_info("upload_cb returned %d", (int)r);
+ break;
+ }
+ uint32_t sent = 0;
+ if (service_send(client->parent->parent, (const char*)buf, (uint32_t)r, &sent) != SERVICE_E_SUCCESS) {
+ debug_info("service_send failed");
+ break;
+ }
+ tx += r;
+ }
+ free(buf);
+ if (tx < image_size) {
+ debug_info("Error: failed to upload image");
+ goto leave_unlock;
+ }
+ debug_info("image uploaded");
+
+ res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &result));
+ if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
+ debug_info("Error receiving response from device!");
+ goto leave_unlock;
+ }
+ res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED;
+
+ strval = NULL;
+ node = plist_dict_get_item(result, "Status");
+ if (node && plist_get_node_type(node) == PLIST_STRING) {
+ plist_get_string_val(node, &strval);
+ }
+ if (!strval) {
+ debug_info("Error: Unexpected response received!");
+ goto leave_unlock;
+ }
+ if (strcmp(strval, "Complete") != 0) {
+ debug_info("Error: didn't get Complete but %s", strval);
+ free(strval);
+ goto leave_unlock;
+ } else {
+ res = MOBILE_IMAGE_MOUNTER_E_SUCCESS;
+ }
+ free(strval);
+
+
+leave_unlock:
+ mobile_image_mounter_unlock(client);
+ if (result)
+ plist_free(result);
+ return res;
+
+}
+
+/**
* Mounts an image on the device.
*
* @param client The connected mobile_image_mounter client.