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" {
38#define MOBILE_IMAGE_MOUNTER_E_INVALID_ARG -1 38#define MOBILE_IMAGE_MOUNTER_E_INVALID_ARG -1
39#define MOBILE_IMAGE_MOUNTER_E_PLIST_ERROR -2 39#define MOBILE_IMAGE_MOUNTER_E_PLIST_ERROR -2
40#define MOBILE_IMAGE_MOUNTER_E_CONN_FAILED -3 40#define MOBILE_IMAGE_MOUNTER_E_CONN_FAILED -3
41#define MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED -4
41 42
42#define MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR -256 43#define MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR -256
43/*@}*/ 44/*@}*/
@@ -48,12 +49,16 @@ typedef int16_t mobile_image_mounter_error_t;
48typedef struct mobile_image_mounter_client_private mobile_image_mounter_client_private; 49typedef struct mobile_image_mounter_client_private mobile_image_mounter_client_private;
49typedef mobile_image_mounter_client_private *mobile_image_mounter_client_t; /**< The client handle. */ 50typedef mobile_image_mounter_client_private *mobile_image_mounter_client_t; /**< The client handle. */
50 51
52/** callback for image upload */
53typedef ssize_t (*mobile_image_mounter_upload_cb_t) (void* buffer, size_t length, void *user_data);
54
51/* Interface */ 55/* Interface */
52mobile_image_mounter_error_t mobile_image_mounter_new(idevice_t device, lockdownd_service_descriptor_t service, mobile_image_mounter_client_t *client); 56mobile_image_mounter_error_t mobile_image_mounter_new(idevice_t device, lockdownd_service_descriptor_t service, mobile_image_mounter_client_t *client);
53mobile_image_mounter_error_t mobile_image_mounter_start_service(idevice_t device, mobile_image_mounter_client_t* client, const char* label); 57mobile_image_mounter_error_t mobile_image_mounter_start_service(idevice_t device, mobile_image_mounter_client_t* client, const char* label);
54mobile_image_mounter_error_t mobile_image_mounter_free(mobile_image_mounter_client_t client); 58mobile_image_mounter_error_t mobile_image_mounter_free(mobile_image_mounter_client_t client);
55 59
56mobile_image_mounter_error_t mobile_image_mounter_lookup_image(mobile_image_mounter_client_t client, const char *image_type, plist_t *result); 60mobile_image_mounter_error_t mobile_image_mounter_lookup_image(mobile_image_mounter_client_t client, const char *image_type, plist_t *result);
61mobile_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);
57mobile_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); 62mobile_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);
58mobile_image_mounter_error_t mobile_image_mounter_hangup(mobile_image_mounter_client_t client); 63mobile_image_mounter_error_t mobile_image_mounter_hangup(mobile_image_mounter_client_t client);
59 64
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:
190} 190}
191 191
192/** 192/**
193 * Uploads an image to the device.
194 *
195 * @param client The connected mobile_image_mounter client.
196 * @param image_type Type of image that is being uploaded.
197 * @param image_size Total size of the image.
198 * @param upload_cb Callback function that gets the data chunks for uploading
199 * the image.
200 * @param userdata User defined data for the upload callback function.
201 *
202 * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on succes, or a
203 * MOBILE_IMAGE_MOUNTER_E_* error code otherwise.
204 */
205mobile_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)
206{
207 if (!client || !image_type || (image_size == 0) || !upload_cb) {
208 return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG;
209 }
210 mobile_image_mounter_lock(client);
211 plist_t result = NULL;
212
213 plist_t dict = plist_new_dict();
214 plist_dict_insert_item(dict, "Command", plist_new_string("ReceiveBytes"));
215 plist_dict_insert_item(dict, "ImageSize", plist_new_uint(image_size));
216 plist_dict_insert_item(dict, "ImageType", plist_new_string(image_type));
217
218 mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict));
219 plist_free(dict);
220
221 if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
222 debug_info("Error sending XML plist to device!");
223 goto leave_unlock;
224 }
225
226 res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &result));
227 if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
228 debug_info("Error receiving response from device!");
229 goto leave_unlock;
230 }
231 res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED;
232
233 char* strval = NULL;
234 plist_t node = plist_dict_get_item(result, "Status");
235 if (node && plist_get_node_type(node) == PLIST_STRING) {
236 plist_get_string_val(node, &strval);
237 }
238 if (!strval) {
239 debug_info("Error: Unexpected response received!");
240 goto leave_unlock;
241 }
242 if (strcmp(strval, "ReceiveBytesAck") != 0) {
243 debug_info("Error: didn't get ReceiveBytesAck but %s", strval);
244 free(strval);
245 goto leave_unlock;
246 }
247 free(strval);
248
249 size_t tx = 0;
250 size_t bufsize = 65536;
251 unsigned char *buf = (unsigned char*)malloc(bufsize);
252 if (!buf) {
253 debug_info("Out of memory");
254 res = MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR;
255 goto leave_unlock;
256 }
257 debug_info("uploading image (%d bytes)", (int)image_size);
258 while (tx < image_size) {
259 size_t remaining = image_size - tx;
260 size_t amount = (remaining < bufsize) ? remaining : bufsize;
261 ssize_t r = upload_cb(buf, amount, userdata);
262 if (r < 0) {
263 debug_info("upload_cb returned %d", (int)r);
264 break;
265 }
266 uint32_t sent = 0;
267 if (service_send(client->parent->parent, (const char*)buf, (uint32_t)r, &sent) != SERVICE_E_SUCCESS) {
268 debug_info("service_send failed");
269 break;
270 }
271 tx += r;
272 }
273 free(buf);
274 if (tx < image_size) {
275 debug_info("Error: failed to upload image");
276 goto leave_unlock;
277 }
278 debug_info("image uploaded");
279
280 res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &result));
281 if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
282 debug_info("Error receiving response from device!");
283 goto leave_unlock;
284 }
285 res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED;
286
287 strval = NULL;
288 node = plist_dict_get_item(result, "Status");
289 if (node && plist_get_node_type(node) == PLIST_STRING) {
290 plist_get_string_val(node, &strval);
291 }
292 if (!strval) {
293 debug_info("Error: Unexpected response received!");
294 goto leave_unlock;
295 }
296 if (strcmp(strval, "Complete") != 0) {
297 debug_info("Error: didn't get Complete but %s", strval);
298 free(strval);
299 goto leave_unlock;
300 } else {
301 res = MOBILE_IMAGE_MOUNTER_E_SUCCESS;
302 }
303 free(strval);
304
305
306leave_unlock:
307 mobile_image_mounter_unlock(client);
308 if (result)
309 plist_free(result);
310 return res;
311
312}
313
314/**
193 * Mounts an image on the device. 315 * Mounts an image on the device.
194 * 316 *
195 * @param client The connected mobile_image_mounter client. 317 * @param client The connected mobile_image_mounter client.