diff options
| author | 2009-04-21 17:20:36 +0200 | |
|---|---|---|
| committer | 2009-05-08 07:57:09 -0700 | |
| commit | 2ce660f06cd9399d8aaf3c585130ba6d410b1d17 (patch) | |
| tree | c1f4301c00b6e1e761d6a7726248b049ea37b40c /src | |
| parent | 7a93c3469de1063e48c8b946fa9ed9019de6934c (diff) | |
| download | libimobiledevice-2ce660f06cd9399d8aaf3c585130ba6d410b1d17.tar.gz libimobiledevice-2ce660f06cd9399d8aaf3c585130ba6d410b1d17.tar.bz2 | |
AFC cleanup and improved error handling
Diffstat (limited to 'src')
| -rw-r--r-- | src/AFC.c | 350 | ||||
| -rw-r--r-- | src/AFC.h | 18 |
2 files changed, 253 insertions, 115 deletions
| @@ -20,12 +20,13 @@ | |||
| 20 | */ | 20 | */ |
| 21 | 21 | ||
| 22 | #include <stdio.h> | 22 | #include <stdio.h> |
| 23 | #include <errno.h> | ||
| 23 | #include "AFC.h" | 24 | #include "AFC.h" |
| 24 | 25 | #include "utils.h" | |
| 25 | 26 | ||
| 26 | 27 | ||
| 27 | // This is the maximum size an AFC data packet can be | 28 | // This is the maximum size an AFC data packet can be |
| 28 | const int MAXIMUM_PACKET_SIZE = (2 << 15) - 32; | 29 | const int MAXIMUM_PACKET_SIZE = (2 << 15); |
| 29 | 30 | ||
| 30 | /** Locks an AFC client, done for thread safety stuff | 31 | /** Locks an AFC client, done for thread safety stuff |
| 31 | * | 32 | * |
| @@ -88,14 +89,9 @@ iphone_error_t iphone_afc_new_client(iphone_device_t device, int src_port, int d | |||
| 88 | } | 89 | } |
| 89 | 90 | ||
| 90 | client_loc->afc_packet->packet_num = 0; | 91 | client_loc->afc_packet->packet_num = 0; |
| 91 | client_loc->afc_packet->unknown1 = 0; | ||
| 92 | client_loc->afc_packet->unknown2 = 0; | ||
| 93 | client_loc->afc_packet->unknown3 = 0; | ||
| 94 | client_loc->afc_packet->unknown4 = 0; | ||
| 95 | client_loc->afc_packet->entire_length = 0; | 92 | client_loc->afc_packet->entire_length = 0; |
| 96 | client_loc->afc_packet->this_length = 0; | 93 | client_loc->afc_packet->this_length = 0; |
| 97 | client_loc->afc_packet->header1 = 0x36414643; | 94 | memcpy(client_loc->afc_packet->magic, AFC_MAGIC, AFC_MAGIC_LEN); |
| 98 | client_loc->afc_packet->header2 = 0x4141504C; | ||
| 99 | client_loc->file_handle = 0; | 95 | client_loc->file_handle = 0; |
| 100 | client_loc->lock = 0; | 96 | client_loc->lock = 0; |
| 101 | client_loc->mutex = g_mutex_new(); | 97 | client_loc->mutex = g_mutex_new(); |
| @@ -115,10 +111,93 @@ iphone_error_t iphone_afc_free_client(iphone_afc_client_t client) | |||
| 115 | 111 | ||
| 116 | iphone_mux_free_client(client->connection); | 112 | iphone_mux_free_client(client->connection); |
| 117 | free(client->afc_packet); | 113 | free(client->afc_packet); |
| 114 | if (client->mutex) { | ||
| 115 | g_mutex_free(client->mutex); | ||
| 116 | } | ||
| 118 | free(client); | 117 | free(client); |
| 119 | return IPHONE_E_SUCCESS; | 118 | return IPHONE_E_SUCCESS; |
| 120 | } | 119 | } |
| 121 | 120 | ||
| 121 | /** | ||
| 122 | * Returns the AFC error code that has been sent by the device if | ||
| 123 | * an error occured (set inside receive_AFC_data) | ||
| 124 | * | ||
| 125 | * @param client AFC client for that the error value is to be retrieved. | ||
| 126 | * | ||
| 127 | * @return AFC error code or -1 on error. | ||
| 128 | */ | ||
| 129 | int iphone_afc_get_afcerror(iphone_afc_client_t client) | ||
| 130 | { | ||
| 131 | int res = -1; | ||
| 132 | if (client) { | ||
| 133 | afc_lock(client); | ||
| 134 | res = client->afcerror; | ||
| 135 | afc_unlock(client); | ||
| 136 | } | ||
| 137 | return res; | ||
| 138 | } | ||
| 139 | |||
| 140 | /** | ||
| 141 | * Tries to convert the AFC error value into a meaningful errno value. | ||
| 142 | * Internally used by iphone_afc_get_errno. | ||
| 143 | * | ||
| 144 | * @param afcerror AFC error value to convert | ||
| 145 | * | ||
| 146 | * @return errno value or -1 if the errno could not be determined. | ||
| 147 | * | ||
| 148 | * @see iphone_afc_get_errno | ||
| 149 | */ | ||
| 150 | static int afcerror_to_errno(int afcerror) | ||
| 151 | { | ||
| 152 | int res = -1; | ||
| 153 | switch (afcerror) { | ||
| 154 | case 0: // ERROR_SUCCESS, this means no error. | ||
| 155 | res = 0; | ||
| 156 | break; | ||
| 157 | case 4: // occurs if you try to open a file as directory | ||
| 158 | res = ENOTDIR; | ||
| 159 | break; | ||
| 160 | case 7: // occurs e.g. if you try to close a file handle that | ||
| 161 | // does not belong to an open file | ||
| 162 | res = EINVAL; | ||
| 163 | break; | ||
| 164 | case 8: // occurs if you try to open a non-existent file | ||
| 165 | res = ENOENT; | ||
| 166 | break; | ||
| 167 | case 9: // occurs if you try to open a directory as file | ||
| 168 | res = EISDIR; | ||
| 169 | break; | ||
| 170 | case 10: // occurs if you try to open a file without permission | ||
| 171 | res = EPERM; | ||
| 172 | break; | ||
| 173 | default: // we'll assume it's an errno value, but report it | ||
| 174 | log_debug_msg("WARNING: unknown AFC error %d, perhaps it's '%s'?\n", afcerror, strerror(afcerror)); | ||
| 175 | res = afcerror; | ||
| 176 | break; | ||
| 177 | } | ||
| 178 | |||
| 179 | log_debug_msg("Mapped AFC error %d to errno %d: %s\n", afcerror, res, strerror(res)); | ||
| 180 | |||
| 181 | return res; | ||
| 182 | } | ||
| 183 | |||
| 184 | /** | ||
| 185 | * Returns the client's AFC error code converted to an errno value. | ||
| 186 | * | ||
| 187 | * @param client AFC client for that the errno value is to be retrieved. | ||
| 188 | * | ||
| 189 | * @return errno value or -1 on error. | ||
| 190 | */ | ||
| 191 | int iphone_afc_get_errno(iphone_afc_client_t client) | ||
| 192 | { | ||
| 193 | int res = -1; | ||
| 194 | if (client) { | ||
| 195 | afc_lock(client); | ||
| 196 | res = afcerror_to_errno(client->afcerror); | ||
| 197 | afc_unlock(client); | ||
| 198 | } | ||
| 199 | return res; | ||
| 200 | } | ||
| 122 | 201 | ||
| 123 | /** Dispatches an AFC packet over a client. | 202 | /** Dispatches an AFC packet over a client. |
| 124 | * | 203 | * |
| @@ -169,7 +248,7 @@ static int dispatch_AFC_packet(iphone_afc_client_t client, const char *data, int | |||
| 169 | return -1; | 248 | return -1; |
| 170 | } | 249 | } |
| 171 | memcpy(buffer + sizeof(AFCPacket), data, offset); | 250 | memcpy(buffer + sizeof(AFCPacket), data, offset); |
| 172 | iphone_mux_send(client->connection, buffer, client->afc_packet->this_length, &bytes); | 251 | iphone_mux_send(client->connection, buffer, client->afc_packet->this_length, (uint32_t*)&bytes); |
| 173 | free(buffer); | 252 | free(buffer); |
| 174 | if (bytes <= 0) { | 253 | if (bytes <= 0) { |
| 175 | return bytes; | 254 | return bytes; |
| @@ -180,11 +259,11 @@ static int dispatch_AFC_packet(iphone_afc_client_t client, const char *data, int | |||
| 180 | log_debug_msg("Buffer: \n"); | 259 | log_debug_msg("Buffer: \n"); |
| 181 | log_debug_buffer(data + offset, length - offset); | 260 | log_debug_buffer(data + offset, length - offset); |
| 182 | 261 | ||
| 183 | iphone_mux_send(client->connection, data + offset, length - offset, &bytes); | 262 | iphone_mux_send(client->connection, data + offset, length - offset, (uint32_t*)&bytes); |
| 184 | return bytes; | 263 | return bytes; |
| 185 | } else { | 264 | } else { |
| 186 | log_debug_msg("dispatch_AFC_packet doin things the old way\n"); | 265 | log_debug_msg("dispatch_AFC_packet doin things the old way\n"); |
| 187 | char *buffer = (char *) malloc(sizeof(char) * client->afc_packet->this_length); | 266 | buffer = (char *) malloc(sizeof(char) * client->afc_packet->this_length); |
| 188 | log_debug_msg("dispatch_AFC_packet packet length = %i\n", client->afc_packet->this_length); | 267 | log_debug_msg("dispatch_AFC_packet packet length = %i\n", client->afc_packet->this_length); |
| 189 | memcpy(buffer, (char *) client->afc_packet, sizeof(AFCPacket)); | 268 | memcpy(buffer, (char *) client->afc_packet, sizeof(AFCPacket)); |
| 190 | log_debug_msg("dispatch_AFC_packet packet data follows\n"); | 269 | log_debug_msg("dispatch_AFC_packet packet data follows\n"); |
| @@ -194,7 +273,7 @@ static int dispatch_AFC_packet(iphone_afc_client_t client, const char *data, int | |||
| 194 | } | 273 | } |
| 195 | log_debug_buffer(buffer, client->afc_packet->this_length); | 274 | log_debug_buffer(buffer, client->afc_packet->this_length); |
| 196 | log_debug_msg("\n"); | 275 | log_debug_msg("\n"); |
| 197 | iphone_mux_send(client->connection, buffer, client->afc_packet->this_length, &bytes); | 276 | iphone_mux_send(client->connection, buffer, client->afc_packet->this_length, (uint32_t*)&bytes); |
| 198 | 277 | ||
| 199 | if (buffer) { | 278 | if (buffer) { |
| 200 | free(buffer); | 279 | free(buffer); |
| @@ -215,91 +294,136 @@ static int dispatch_AFC_packet(iphone_afc_client_t client, const char *data, int | |||
| 215 | * received raised a non-trivial error condition (i.e. non-zero with | 294 | * received raised a non-trivial error condition (i.e. non-zero with |
| 216 | * AFC_ERROR operation) | 295 | * AFC_ERROR operation) |
| 217 | */ | 296 | */ |
| 218 | |||
| 219 | static int receive_AFC_data(iphone_afc_client_t client, char **dump_here) | 297 | static int receive_AFC_data(iphone_afc_client_t client, char **dump_here) |
| 220 | { | 298 | { |
| 221 | AFCPacket *r_packet; | 299 | AFCPacket header; |
| 222 | char *buffer = (char *) malloc(sizeof(AFCPacket) * 4); | 300 | int bytes = 0; |
| 223 | char *final_buffer = NULL; | 301 | uint32_t entire_len = 0; |
| 224 | int bytes = 0, recv_len = 0, current_count = 0; | 302 | uint32_t this_len = 0; |
| 225 | int retval = 0; | 303 | uint32_t current_count = 0; |
| 304 | uint64_t param1 = -1; | ||
| 305 | |||
| 306 | // reset internal afc error value | ||
| 307 | client->afcerror = 0; | ||
| 226 | 308 | ||
| 227 | iphone_mux_recv(client->connection, buffer, sizeof(AFCPacket) * 4, &bytes); | 309 | // first, read the AFC header |
| 310 | iphone_mux_recv(client->connection, (char*)&header, sizeof(AFCPacket), (uint32_t*)&bytes); | ||
| 228 | if (bytes <= 0) { | 311 | if (bytes <= 0) { |
| 229 | free(buffer); | 312 | log_debug_msg("%s: Just didn't get enough.\n", __func__); |
| 230 | log_debug_msg("Just didn't get enough.\n"); | 313 | *dump_here = NULL; |
| 314 | return -1; | ||
| 315 | } else if ((uint32_t)bytes < sizeof(AFCPacket)) { | ||
| 316 | log_debug_msg("%s: Did not even get the AFCPacket header\n", __func__); | ||
| 231 | *dump_here = NULL; | 317 | *dump_here = NULL; |
| 232 | return -1; | 318 | return -1; |
| 233 | } | 319 | } |
| 234 | 320 | ||
| 235 | r_packet = (AFCPacket *) malloc(sizeof(AFCPacket)); | 321 | // check if it's a valid AFC header |
| 236 | memcpy(r_packet, buffer, sizeof(AFCPacket)); | 322 | if (strncmp(header.magic, AFC_MAGIC, AFC_MAGIC_LEN)) { |
| 237 | 323 | log_debug_msg("%s: Invalid AFC packet received (magic != " AFC_MAGIC ")!\n", __func__); | |
| 238 | if (r_packet->entire_length == r_packet->this_length | ||
| 239 | && r_packet->entire_length > sizeof(AFCPacket) && r_packet->operation != AFC_ERROR) { | ||
| 240 | *dump_here = (char *) malloc(sizeof(char) * (r_packet->entire_length - sizeof(AFCPacket))); | ||
| 241 | memcpy(*dump_here, buffer + sizeof(AFCPacket), r_packet->entire_length - sizeof(AFCPacket)); | ||
| 242 | retval = r_packet->entire_length - sizeof(AFCPacket); | ||
| 243 | free(buffer); | ||
| 244 | free(r_packet); | ||
| 245 | return retval; | ||
| 246 | } | 324 | } |
| 247 | 325 | ||
| 248 | uint32_t param1 = buffer[sizeof(AFCPacket)]; | 326 | // check if it has the correct packet number |
| 249 | free(buffer); | 327 | if (header.packet_num != client->afc_packet->packet_num) { |
| 328 | // otherwise print a warning but do not abort | ||
| 329 | log_debug_msg("%s: ERROR: Unexpected packet number (%lld != %lld) aborting.\n", __func__, header.packet_num, client->afc_packet->packet_num); | ||
| 330 | *dump_here = NULL; | ||
| 331 | return -1; | ||
| 332 | } | ||
| 250 | 333 | ||
| 251 | if (r_packet->operation == AFC_ERROR && !(client->afc_packet->operation == AFC_DELETE && param1 == 7)) { | 334 | // then, read the attached packet |
| 252 | log_debug_msg("Oops? Bad operation code received: 0x%X, operation=0x%X, param1=%d\n", | 335 | if (header.this_length < sizeof(AFCPacket)) { |
| 253 | r_packet->operation, client->afc_packet->operation, param1); | 336 | log_debug_msg("%s: Invalid AFCPacket header received!\n", __func__); |
| 254 | recv_len = r_packet->entire_length - r_packet->this_length; | 337 | *dump_here = NULL; |
| 255 | free(r_packet); | 338 | return -1; |
| 256 | log_debug_msg("recv_len=%d\n", recv_len); | 339 | } else if ((header.this_length == header.entire_length) |
| 257 | if (param1 == 0) { | 340 | && header.entire_length == sizeof(AFCPacket)) { |
| 258 | log_debug_msg("... false alarm, but still\n"); | 341 | log_debug_msg("%s: Empty AFCPacket received!\n", __func__); |
| 259 | *dump_here = NULL; | 342 | *dump_here = NULL; |
| 343 | if (header.operation == AFC_SUCCESS_RESPONSE) { | ||
| 260 | return 0; | 344 | return 0; |
| 261 | } else { | 345 | } else { |
| 262 | log_debug_msg("Errno %i\n", param1); | 346 | client->afcerror = EIO; |
| 347 | return -1; | ||
| 263 | } | 348 | } |
| 264 | *dump_here = NULL; | ||
| 265 | return -1; | ||
| 266 | } else { | ||
| 267 | log_debug_msg("Operation code %x\nFull length %i and this length %i\n", | ||
| 268 | r_packet->operation, r_packet->entire_length, r_packet->this_length); | ||
| 269 | } | 349 | } |
| 270 | 350 | ||
| 271 | recv_len = r_packet->entire_length - r_packet->this_length; | 351 | log_debug_msg("%s: received AFC packet, full len=%lld, this len=%lld, operation=%lld\n", __func__, header.entire_length, header.this_length, header.operation); |
| 272 | free(r_packet); | 352 | |
| 273 | if (!recv_len && r_packet->operation == AFC_SUCCESS_RESPONSE) { | 353 | entire_len = (uint32_t)header.entire_length - sizeof(AFCPacket); |
| 354 | this_len = (uint32_t)header.this_length - sizeof(AFCPacket); | ||
| 355 | |||
| 356 | // this is here as a check (perhaps a different upper limit is good?) | ||
| 357 | if (entire_len > (uint32_t)MAXIMUM_PACKET_SIZE) { | ||
| 358 | fprintf(stderr, "%s: entire_len is larger than MAXIMUM_PACKET_SIZE, (%d > %d)!\n", __func__, entire_len, MAXIMUM_PACKET_SIZE); | ||
| 359 | } | ||
| 360 | |||
| 361 | *dump_here = (char*)malloc(entire_len); | ||
| 362 | iphone_mux_recv(client->connection, *dump_here, this_len, (uint32_t*)&bytes); | ||
| 363 | if (bytes <= 0) { | ||
| 364 | free(*dump_here); | ||
| 274 | *dump_here = NULL; | 365 | *dump_here = NULL; |
| 275 | return 0; | 366 | log_debug_msg("%s: Did not get packet contents!\n", __func__); |
| 367 | return -1; | ||
| 368 | } else if ((uint32_t)bytes < this_len) { | ||
| 369 | free(*dump_here); | ||
| 370 | *dump_here = NULL; | ||
| 371 | log_debug_msg("%s: Could not receive this_len=%d bytes\n", __func__, this_len); | ||
| 372 | return -1; | ||
| 276 | } | 373 | } |
| 277 | // Keep collecting packets until we have received the entire file. | 374 | |
| 278 | buffer = (char *) malloc(sizeof(char) * (recv_len < MAXIMUM_PACKET_SIZE) ? recv_len : MAXIMUM_PACKET_SIZE); | 375 | current_count = this_len; |
| 279 | final_buffer = (char *) malloc(sizeof(char) * recv_len); | 376 | |
| 280 | while (current_count < recv_len) { | 377 | if (entire_len > this_len) { |
| 281 | iphone_mux_recv(client->connection, buffer, recv_len - current_count, &bytes); | 378 | while (current_count < entire_len) { |
| 282 | log_debug_msg("receive_AFC_data: still collecting packets\n"); | 379 | iphone_mux_recv(client->connection, (*dump_here)+current_count, entire_len - current_count, (uint32_t*)&bytes); |
| 283 | if (bytes < 0) { | 380 | if (bytes <= 0) { |
| 284 | log_debug_msg("receive_AFC_data: mux_recv failed: %d\n", bytes); | 381 | log_debug_msg("%s: Error receiving data (recv returned %d)\n", __func__, bytes); |
| 285 | break; | 382 | break; |
| 286 | } | 383 | } |
| 287 | if (bytes > recv_len - current_count) { | 384 | current_count += bytes; |
| 288 | log_debug_msg("receive_AFC_data: mux_recv delivered too much data\n"); | ||
| 289 | break; | ||
| 290 | } | 385 | } |
| 291 | if (bytes > 7 && strstr(buffer, "CFA6LPAA")) { | 386 | if (current_count < entire_len) { |
| 292 | log_debug_msg("receive_AFC_data: WARNING: there is AFC data in this packet at %ti\n", | 387 | log_debug_msg("%s: WARNING: could not receive full packet (read %s, size %d)\n", __func__, current_count, entire_len); |
| 293 | strstr(buffer, "CFA6LPAA") - buffer); | ||
| 294 | log_debug_msg("receive_AFC_data: the total packet length is %i\n", bytes); | ||
| 295 | } | 388 | } |
| 389 | } | ||
| 296 | 390 | ||
| 297 | memcpy(final_buffer + current_count, buffer, bytes); | 391 | if (current_count >= sizeof(uint64_t)) { |
| 298 | current_count += bytes; | 392 | param1 = *(uint64_t*)(*dump_here); |
| 299 | } | 393 | } |
| 300 | free(buffer); | ||
| 301 | 394 | ||
| 302 | *dump_here = final_buffer; | 395 | // check for errors |
| 396 | if (header.operation == AFC_SUCCESS_RESPONSE) { | ||
| 397 | // we got a positive response! | ||
| 398 | log_debug_msg("%s: got a success response\n", __func__); | ||
| 399 | } else if (header.operation == AFC_FILE_HANDLE) { | ||
| 400 | // we got a file handle response | ||
| 401 | log_debug_msg("%s: got a file handle response, handle=%lld\n", __func__, param1); | ||
| 402 | } else if (header.operation == AFC_ERROR) { | ||
| 403 | // error message received | ||
| 404 | if (param1 == 0) { | ||
| 405 | // ERROR_SUCCESS, this is not an error! | ||
| 406 | log_debug_msg("%s: ERROR_SUCCESS\n", __func__); | ||
| 407 | } else { | ||
| 408 | // but this is an error! | ||
| 409 | log_debug_msg("%s: ERROR %lld\n", __func__, param1); | ||
| 410 | free(*dump_here); | ||
| 411 | *dump_here = NULL; | ||
| 412 | // store error value | ||
| 413 | client->afcerror = (int)param1; | ||
| 414 | afcerror_to_errno(client->afcerror); | ||
| 415 | return -1; | ||
| 416 | } | ||
| 417 | } else { | ||
| 418 | // unknown operation code received! | ||
| 419 | free(*dump_here); | ||
| 420 | *dump_here = NULL; | ||
| 421 | |||
| 422 | log_debug_msg("%s: WARNING: Unknown operation code received 0x%llx param1=%lld\n", __func__, header.operation, param1); | ||
| 423 | fprintf(stderr, "%s: WARNING: Unknown operation code received 0x%llx param1=%lld\n", __func__, header.operation, param1); | ||
| 424 | |||
| 425 | return -1; | ||
| 426 | } | ||
| 303 | return current_count; | 427 | return current_count; |
| 304 | } | 428 | } |
| 305 | 429 | ||
| @@ -364,9 +488,9 @@ iphone_error_t iphone_afc_get_dir_list(iphone_afc_client_t client, const char *d | |||
| 364 | } | 488 | } |
| 365 | // Receive the data | 489 | // Receive the data |
| 366 | bytes = receive_AFC_data(client, &data); | 490 | bytes = receive_AFC_data(client, &data); |
| 367 | if (bytes < 0 && !data) { | 491 | if (bytes < 0) { |
| 368 | afc_unlock(client); | 492 | afc_unlock(client); |
| 369 | return IPHONE_E_NOT_ENOUGH_DATA; | 493 | return IPHONE_E_AFC_ERROR; |
| 370 | } | 494 | } |
| 371 | // Parse the data | 495 | // Parse the data |
| 372 | list_loc = make_strings_list(data, bytes); | 496 | list_loc = make_strings_list(data, bytes); |
| @@ -408,9 +532,9 @@ iphone_error_t iphone_afc_get_devinfo(iphone_afc_client_t client, char ***infos) | |||
| 408 | } | 532 | } |
| 409 | // Receive the data | 533 | // Receive the data |
| 410 | bytes = receive_AFC_data(client, &data); | 534 | bytes = receive_AFC_data(client, &data); |
| 411 | if (bytes < 0 && !data) { | 535 | if (bytes < 0) { |
| 412 | afc_unlock(client); | 536 | afc_unlock(client); |
| 413 | return IPHONE_E_NOT_ENOUGH_DATA; | 537 | return IPHONE_E_AFC_ERROR; |
| 414 | } | 538 | } |
| 415 | // Parse the data | 539 | // Parse the data |
| 416 | list = make_strings_list(data, bytes); | 540 | list = make_strings_list(data, bytes); |
| @@ -456,10 +580,9 @@ iphone_error_t iphone_afc_delete_file(iphone_afc_client_t client, const char *pa | |||
| 456 | afc_unlock(client); | 580 | afc_unlock(client); |
| 457 | 581 | ||
| 458 | if (bytes < 0) { | 582 | if (bytes < 0) { |
| 459 | return IPHONE_E_NOT_ENOUGH_DATA; | 583 | return IPHONE_E_AFC_ERROR; |
| 460 | } else { | ||
| 461 | return IPHONE_E_SUCCESS; | ||
| 462 | } | 584 | } |
| 585 | return IPHONE_E_SUCCESS; | ||
| 463 | } | 586 | } |
| 464 | 587 | ||
| 465 | /** Renames a file on the phone. | 588 | /** Renames a file on the phone. |
| @@ -501,10 +624,9 @@ iphone_error_t iphone_afc_rename_file(iphone_afc_client_t client, const char *fr | |||
| 501 | afc_unlock(client); | 624 | afc_unlock(client); |
| 502 | 625 | ||
| 503 | if (bytes < 0) { | 626 | if (bytes < 0) { |
| 504 | return IPHONE_E_NOT_ENOUGH_DATA; | 627 | return IPHONE_E_AFC_ERROR; |
| 505 | } else { | ||
| 506 | return IPHONE_E_SUCCESS; | ||
| 507 | } | 628 | } |
| 629 | return IPHONE_E_SUCCESS; | ||
| 508 | } | 630 | } |
| 509 | 631 | ||
| 510 | /** Creates a directory on the phone. | 632 | /** Creates a directory on the phone. |
| @@ -542,10 +664,9 @@ iphone_error_t iphone_afc_mkdir(iphone_afc_client_t client, const char *dir) | |||
| 542 | afc_unlock(client); | 664 | afc_unlock(client); |
| 543 | 665 | ||
| 544 | if (bytes < 0) { | 666 | if (bytes < 0) { |
| 545 | return IPHONE_E_NOT_ENOUGH_DATA; | 667 | return IPHONE_E_AFC_ERROR; |
| 546 | } else { | ||
| 547 | return IPHONE_E_SUCCESS; | ||
| 548 | } | 668 | } |
| 669 | return IPHONE_E_SUCCESS; | ||
| 549 | } | 670 | } |
| 550 | 671 | ||
| 551 | /** Gets information about a specific file. | 672 | /** Gets information about a specific file. |
| @@ -586,7 +707,7 @@ static iphone_afc_file_t afc_get_file_info(iphone_afc_client_t client, const cha | |||
| 586 | my_file = (iphone_afc_file_t) malloc(sizeof(struct iphone_afc_file_int)); | 707 | my_file = (iphone_afc_file_t) malloc(sizeof(struct iphone_afc_file_int)); |
| 587 | for (i = 0; list[i]; i++) { | 708 | for (i = 0; list[i]; i++) { |
| 588 | if (!strcmp(list[i], "st_size")) { | 709 | if (!strcmp(list[i], "st_size")) { |
| 589 | my_file->size = atoi(list[i + 1]); | 710 | my_file->size = atoll(list[i + 1]); |
| 590 | } | 711 | } |
| 591 | 712 | ||
| 592 | if (!strcmp(list[i], "st_blocks")) { | 713 | if (!strcmp(list[i], "st_blocks")) { |
| @@ -595,11 +716,17 @@ static iphone_afc_file_t afc_get_file_info(iphone_afc_client_t client, const cha | |||
| 595 | 716 | ||
| 596 | if (!strcmp(list[i], "st_ifmt")) { | 717 | if (!strcmp(list[i], "st_ifmt")) { |
| 597 | if (!strcmp(list[i + 1], "S_IFREG")) { | 718 | if (!strcmp(list[i + 1], "S_IFREG")) { |
| 598 | my_file->type = S_IFREG; | 719 | my_file->mode = S_IFREG; |
| 599 | } else if (!strcmp(list[i + 1], "S_IFDIR")) { | 720 | } else if (!strcmp(list[i + 1], "S_IFDIR")) { |
| 600 | my_file->type = S_IFDIR; | 721 | my_file->mode = S_IFDIR; |
| 722 | } else if (!strcmp(list[i + 1], "S_IFLNK")) { | ||
| 723 | my_file->mode = S_IFLNK; | ||
| 601 | } | 724 | } |
| 602 | } | 725 | } |
| 726 | |||
| 727 | if (!strcmp(list[i], "st_nlink")) { | ||
| 728 | my_file->nlink = atoi(list[i + 1]); | ||
| 729 | } | ||
| 603 | } | 730 | } |
| 604 | g_strfreev(list); | 731 | g_strfreev(list); |
| 605 | return my_file; | 732 | return my_file; |
| @@ -627,13 +754,14 @@ iphone_error_t iphone_afc_get_file_attr(iphone_afc_client_t client, const char * | |||
| 627 | memset(stbuf, 0, sizeof(struct stat)); | 754 | memset(stbuf, 0, sizeof(struct stat)); |
| 628 | iphone_afc_file_t file = afc_get_file_info(client, filename); | 755 | iphone_afc_file_t file = afc_get_file_info(client, filename); |
| 629 | if (!file) { | 756 | if (!file) { |
| 630 | ret = IPHONE_E_NO_SUCH_FILE; | 757 | ret = IPHONE_E_AFC_ERROR; |
| 631 | } else { | 758 | } else { |
| 632 | stbuf->st_mode = file->type | (S_ISDIR(file->type) ? 0755 : 0644); | 759 | stbuf->st_mode = file->mode | (S_ISDIR(file->mode) ? 0755 : (S_ISLNK(file->mode) ? 0777 : 0644)); |
| 633 | stbuf->st_size = file->size; | 760 | stbuf->st_size = file->size; |
| 634 | stbuf->st_blksize = 2048; // FIXME: Is this the actual block | 761 | stbuf->st_blksize = 2048; // FIXME: Is this the actual block |
| 635 | // size used on the iPhone? | 762 | // size used on the iPhone? |
| 636 | stbuf->st_blocks = file->blocks; | 763 | stbuf->st_blocks = file->blocks; |
| 764 | stbuf->st_nlink = file->nlink; | ||
| 637 | stbuf->st_uid = getuid(); | 765 | stbuf->st_uid = getuid(); |
| 638 | stbuf->st_gid = getgid(); | 766 | stbuf->st_gid = getgid(); |
| 639 | 767 | ||
| @@ -699,7 +827,7 @@ iphone_afc_open_file(iphone_afc_client_t client, const char *filename, | |||
| 699 | } else { | 827 | } else { |
| 700 | log_debug_msg("afc_open_file: Didn't get any further data\n"); | 828 | log_debug_msg("afc_open_file: Didn't get any further data\n"); |
| 701 | afc_unlock(client); | 829 | afc_unlock(client); |
| 702 | return IPHONE_E_NOT_ENOUGH_DATA; | 830 | return IPHONE_E_AFC_ERROR; |
| 703 | } | 831 | } |
| 704 | 832 | ||
| 705 | afc_unlock(client); | 833 | afc_unlock(client); |
| @@ -736,7 +864,6 @@ iphone_afc_read_file(iphone_afc_client_t client, iphone_afc_file_t file, char *d | |||
| 736 | 864 | ||
| 737 | // Send the read command | 865 | // Send the read command |
| 738 | AFCFilePacket *packet = (AFCFilePacket *) malloc(sizeof(AFCFilePacket)); | 866 | AFCFilePacket *packet = (AFCFilePacket *) malloc(sizeof(AFCFilePacket)); |
| 739 | packet->unknown1 = packet->unknown2 = 0; | ||
| 740 | packet->filehandle = file->filehandle; | 867 | packet->filehandle = file->filehandle; |
| 741 | packet->size = ((length - current_count) < MAXIMUM_READ_SIZE) ? (length - current_count) : MAXIMUM_READ_SIZE; | 868 | packet->size = ((length - current_count) < MAXIMUM_READ_SIZE) ? (length - current_count) : MAXIMUM_READ_SIZE; |
| 742 | client->afc_packet->operation = AFC_READ; | 869 | client->afc_packet->operation = AFC_READ; |
| @@ -752,10 +879,8 @@ iphone_afc_read_file(iphone_afc_client_t client, iphone_afc_file_t file, char *d | |||
| 752 | bytes_loc = receive_AFC_data(client, &input); | 879 | bytes_loc = receive_AFC_data(client, &input); |
| 753 | log_debug_msg("afc_read_file: bytes returned: %i\n", bytes_loc); | 880 | log_debug_msg("afc_read_file: bytes returned: %i\n", bytes_loc); |
| 754 | if (bytes_loc < 0) { | 881 | if (bytes_loc < 0) { |
| 755 | if (input) | ||
| 756 | free(input); | ||
| 757 | afc_unlock(client); | 882 | afc_unlock(client); |
| 758 | return IPHONE_E_NOT_ENOUGH_DATA; | 883 | return IPHONE_E_AFC_ERROR; |
| 759 | } else if (bytes_loc == 0) { | 884 | } else if (bytes_loc == 0) { |
| 760 | if (input) | 885 | if (input) |
| 761 | free(input); | 886 | free(input); |
| @@ -830,7 +955,9 @@ iphone_afc_write_file(iphone_afc_client_t client, iphone_afc_file_t file, | |||
| 830 | bytes_loc = receive_AFC_data(client, &acknowledgement); | 955 | bytes_loc = receive_AFC_data(client, &acknowledgement); |
| 831 | if (bytes_loc < 0) { | 956 | if (bytes_loc < 0) { |
| 832 | afc_unlock(client); | 957 | afc_unlock(client); |
| 833 | return IPHONE_E_NOT_ENOUGH_DATA; | 958 | return IPHONE_E_AFC_ERROR; |
| 959 | } else { | ||
| 960 | free(acknowledgement); | ||
| 834 | } | 961 | } |
| 835 | } | 962 | } |
| 836 | 963 | ||
| @@ -838,7 +965,7 @@ iphone_afc_write_file(iphone_afc_client_t client, iphone_afc_file_t file, | |||
| 838 | // didn't get sent in the for loop | 965 | // didn't get sent in the for loop |
| 839 | // this length is fine because it's always sizeof(AFCPacket) + 8, but | 966 | // this length is fine because it's always sizeof(AFCPacket) + 8, but |
| 840 | // to be sure we do it again | 967 | // to be sure we do it again |
| 841 | if (current_count == length) { | 968 | if (current_count == (uint32_t)length) { |
| 842 | afc_unlock(client); | 969 | afc_unlock(client); |
| 843 | *bytes = current_count; | 970 | *bytes = current_count; |
| 844 | return IPHONE_E_SUCCESS; | 971 | return IPHONE_E_SUCCESS; |
| @@ -868,6 +995,8 @@ iphone_afc_write_file(iphone_afc_client_t client, iphone_afc_file_t file, | |||
| 868 | afc_unlock(client); | 995 | afc_unlock(client); |
| 869 | if (bytes_loc < 0) { | 996 | if (bytes_loc < 0) { |
| 870 | log_debug_msg("afc_write_file: uh oh?\n"); | 997 | log_debug_msg("afc_write_file: uh oh?\n"); |
| 998 | } else { | ||
| 999 | free(acknowledgement); | ||
| 871 | } | 1000 | } |
| 872 | *bytes = current_count; | 1001 | *bytes = current_count; |
| 873 | return IPHONE_E_SUCCESS; | 1002 | return IPHONE_E_SUCCESS; |
| @@ -965,12 +1094,14 @@ iphone_error_t iphone_afc_lock_file(iphone_afc_client_t client, iphone_afc_file_ | |||
| 965 | } | 1094 | } |
| 966 | // Receive the response | 1095 | // Receive the response |
| 967 | bytes = receive_AFC_data(client, &buffer); | 1096 | bytes = receive_AFC_data(client, &buffer); |
| 968 | log_debug_msg("%s: receiving response (%d bytes)\n", __func__, bytes); | ||
| 969 | if (buffer) { | 1097 | if (buffer) { |
| 970 | log_debug_buffer(buffer, bytes); | 1098 | log_debug_buffer(buffer, bytes); |
| 971 | free(buffer); | 1099 | free(buffer); |
| 972 | } | 1100 | } |
| 973 | afc_unlock(client); | 1101 | afc_unlock(client); |
| 1102 | if (bytes < 0) { | ||
| 1103 | return IPHONE_E_AFC_ERROR; | ||
| 1104 | } | ||
| 974 | return IPHONE_E_SUCCESS; | 1105 | return IPHONE_E_SUCCESS; |
| 975 | } | 1106 | } |
| 976 | 1107 | ||
| @@ -1019,11 +1150,10 @@ iphone_error_t iphone_afc_seek_file(iphone_afc_client_t client, iphone_afc_file_ | |||
| 1019 | 1150 | ||
| 1020 | afc_unlock(client); | 1151 | afc_unlock(client); |
| 1021 | 1152 | ||
| 1022 | if (bytes >= 0) { | 1153 | if (bytes < 0) { |
| 1023 | return IPHONE_E_SUCCESS; | 1154 | return IPHONE_E_AFC_ERROR; |
| 1024 | } else { | ||
| 1025 | return IPHONE_E_NOT_ENOUGH_DATA; | ||
| 1026 | } | 1155 | } |
| 1156 | return IPHONE_E_SUCCESS; | ||
| 1027 | } | 1157 | } |
| 1028 | 1158 | ||
| 1029 | /** Sets the size of a file on the phone. | 1159 | /** Sets the size of a file on the phone. |
| @@ -1067,11 +1197,10 @@ iphone_error_t iphone_afc_truncate_file(iphone_afc_client_t client, iphone_afc_f | |||
| 1067 | 1197 | ||
| 1068 | afc_unlock(client); | 1198 | afc_unlock(client); |
| 1069 | 1199 | ||
| 1070 | if (bytes >= 0) { | 1200 | if (bytes < 0) { |
| 1071 | return IPHONE_E_SUCCESS; | 1201 | return IPHONE_E_AFC_ERROR; |
| 1072 | } else { | ||
| 1073 | return IPHONE_E_NOT_ENOUGH_DATA; | ||
| 1074 | } | 1202 | } |
| 1203 | return IPHONE_E_SUCCESS; | ||
| 1075 | } | 1204 | } |
| 1076 | 1205 | ||
| 1077 | /** Sets the size of a file on the phone without prior opening it. | 1206 | /** Sets the size of a file on the phone without prior opening it. |
| @@ -1114,10 +1243,9 @@ iphone_error_t iphone_afc_truncate(iphone_afc_client_t client, const char *path, | |||
| 1114 | afc_unlock(client); | 1243 | afc_unlock(client); |
| 1115 | 1244 | ||
| 1116 | if (bytes < 0) { | 1245 | if (bytes < 0) { |
| 1117 | return IPHONE_E_NOT_ENOUGH_DATA; | 1246 | return IPHONE_E_AFC_ERROR; |
| 1118 | } else { | ||
| 1119 | return IPHONE_E_SUCCESS; | ||
| 1120 | } | 1247 | } |
| 1248 | return IPHONE_E_SUCCESS; | ||
| 1121 | } | 1249 | } |
| 1122 | 1250 | ||
| 1123 | 1251 | ||
| @@ -27,14 +27,18 @@ | |||
| 27 | #include <stdlib.h> | 27 | #include <stdlib.h> |
| 28 | #include <sys/stat.h> | 28 | #include <sys/stat.h> |
| 29 | #include <glib.h> | 29 | #include <glib.h> |
| 30 | #include <stdint.h> | ||
| 31 | |||
| 32 | #define AFC_MAGIC "CFA6LPAA" | ||
| 33 | #define AFC_MAGIC_LEN (8) | ||
| 30 | 34 | ||
| 31 | typedef struct { | 35 | typedef struct { |
| 32 | uint32_t header1, header2; | 36 | char magic[AFC_MAGIC_LEN]; |
| 33 | uint32_t entire_length, unknown1, this_length, unknown2, packet_num, unknown3, operation, unknown4; | 37 | uint64_t entire_length, this_length, packet_num, operation; |
| 34 | } AFCPacket; | 38 | } AFCPacket; |
| 35 | 39 | ||
| 36 | typedef struct { | 40 | typedef struct { |
| 37 | uint32_t filehandle, unknown1, size, unknown2; | 41 | uint64_t filehandle, size; |
| 38 | } AFCFilePacket; | 42 | } AFCFilePacket; |
| 39 | 43 | ||
| 40 | typedef struct __AFCToken { | 44 | typedef struct __AFCToken { |
| @@ -47,11 +51,16 @@ struct iphone_afc_client_int { | |||
| 47 | AFCPacket *afc_packet; | 51 | AFCPacket *afc_packet; |
| 48 | int file_handle; | 52 | int file_handle; |
| 49 | int lock; | 53 | int lock; |
| 54 | int afcerror; | ||
| 50 | GMutex *mutex; | 55 | GMutex *mutex; |
| 51 | }; | 56 | }; |
| 52 | 57 | ||
| 53 | struct iphone_afc_file_int { | 58 | struct iphone_afc_file_int { |
| 54 | uint32_t filehandle, blocks, size, type; | 59 | uint32_t filehandle; |
| 60 | uint32_t blocks; | ||
| 61 | off_t size; | ||
| 62 | uint32_t mode; | ||
| 63 | uint32_t nlink; | ||
| 55 | }; | 64 | }; |
| 56 | 65 | ||
| 57 | 66 | ||
| @@ -88,3 +97,4 @@ enum { | |||
| 88 | }; | 97 | }; |
| 89 | 98 | ||
| 90 | uint32_t iphone_afc_get_file_handle(iphone_afc_file_t file); | 99 | uint32_t iphone_afc_get_file_handle(iphone_afc_file_t file); |
| 100 | static int afcerror_to_errno(int afcerror); | ||
