diff options
| -rw-r--r-- | include/libimobiledevice/mobile_image_mounter.h | 5 | ||||
| -rw-r--r-- | src/mobile_image_mounter.c | 122 |
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; | |||
| 48 | typedef struct mobile_image_mounter_client_private mobile_image_mounter_client_private; | 49 | typedef struct mobile_image_mounter_client_private mobile_image_mounter_client_private; |
| 49 | typedef mobile_image_mounter_client_private *mobile_image_mounter_client_t; /**< The client handle. */ | 50 | typedef mobile_image_mounter_client_private *mobile_image_mounter_client_t; /**< The client handle. */ |
| 50 | 51 | ||
| 52 | /** callback for image upload */ | ||
| 53 | typedef ssize_t (*mobile_image_mounter_upload_cb_t) (void* buffer, size_t length, void *user_data); | ||
| 54 | |||
| 51 | /* Interface */ | 55 | /* Interface */ |
| 52 | mobile_image_mounter_error_t mobile_image_mounter_new(idevice_t device, lockdownd_service_descriptor_t service, mobile_image_mounter_client_t *client); | 56 | mobile_image_mounter_error_t mobile_image_mounter_new(idevice_t device, lockdownd_service_descriptor_t service, mobile_image_mounter_client_t *client); |
| 53 | mobile_image_mounter_error_t mobile_image_mounter_start_service(idevice_t device, mobile_image_mounter_client_t* client, const char* label); | 57 | mobile_image_mounter_error_t mobile_image_mounter_start_service(idevice_t device, mobile_image_mounter_client_t* client, const char* label); |
| 54 | mobile_image_mounter_error_t mobile_image_mounter_free(mobile_image_mounter_client_t client); | 58 | mobile_image_mounter_error_t mobile_image_mounter_free(mobile_image_mounter_client_t client); |
| 55 | 59 | ||
| 56 | mobile_image_mounter_error_t mobile_image_mounter_lookup_image(mobile_image_mounter_client_t client, const char *image_type, plist_t *result); | 60 | mobile_image_mounter_error_t mobile_image_mounter_lookup_image(mobile_image_mounter_client_t client, const char *image_type, plist_t *result); |
| 61 | 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); | ||
| 57 | 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); | 62 | 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); |
| 58 | mobile_image_mounter_error_t mobile_image_mounter_hangup(mobile_image_mounter_client_t client); | 63 | mobile_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 | */ | ||
| 205 | 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) | ||
| 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 | |||
| 306 | leave_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. |
