diff options
Diffstat (limited to 'src/mobile_image_mounter.c')
| -rw-r--r-- | src/mobile_image_mounter.c | 122 |
1 files changed, 122 insertions, 0 deletions
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. |
