diff options
| -rw-r--r-- | src/AFC.c | 180 | ||||
| -rw-r--r-- | src/AFC.h | 13 | ||||
| -rw-r--r-- | src/ifuse.c | 131 | ||||
| -rw-r--r-- | src/main.c | 24 |
4 files changed, 306 insertions, 42 deletions
| @@ -29,13 +29,15 @@ extern int debug; | |||
| 29 | 29 | ||
| 30 | /* Locking, for thread-safety (well... kind of, hehe) */ | 30 | /* Locking, for thread-safety (well... kind of, hehe) */ |
| 31 | void afc_lock(AFClient *client) { | 31 | void afc_lock(AFClient *client) { |
| 32 | if (debug) printf("In the midst of a lock...\n"); | ||
| 32 | while (client->lock) { | 33 | while (client->lock) { |
| 33 | sleep(200); | 34 | usleep(500); // they say it's obsolete, but whatever |
| 34 | } | 35 | } |
| 35 | client->lock = 1; | 36 | client->lock = 1; |
| 36 | } | 37 | } |
| 37 | 38 | ||
| 38 | void afc_unlock(AFClient *client) { // just to be pretty | 39 | void afc_unlock(AFClient *client) { // just to be pretty |
| 40 | if (debug) printf("Unlock!\n"); | ||
| 39 | client->lock = 0; | 41 | client->lock = 0; |
| 40 | } | 42 | } |
| 41 | 43 | ||
| @@ -102,13 +104,13 @@ int dispatch_AFC_packet(AFClient *client, const char *data, int length) { | |||
| 102 | if ((length) < (client->afc_packet->entire_length - client->afc_packet->this_length)) { | 104 | if ((length) < (client->afc_packet->entire_length - client->afc_packet->this_length)) { |
| 103 | if (debug) printf("dispatch_AFC_packet: Length did not resemble what it was supposed to based on the packet.\nlength minus offset: %i\nrest of packet: %i\n", length-offset, client->afc_packet->entire_length - client->afc_packet->this_length); | 105 | if (debug) printf("dispatch_AFC_packet: Length did not resemble what it was supposed to based on the packet.\nlength minus offset: %i\nrest of packet: %i\n", length-offset, client->afc_packet->entire_length - client->afc_packet->this_length); |
| 104 | free(buffer); | 106 | free(buffer); |
| 105 | return 0; | 107 | return -1; |
| 106 | } | 108 | } |
| 107 | if (debug) printf("dispatch_AFC_packet: fucked-up packet method (probably a write)\n"); | 109 | if (debug) printf("dispatch_AFC_packet: fucked-up packet method (probably a write)\n"); |
| 108 | memcpy(buffer+sizeof(AFCPacket), data, offset); | 110 | memcpy(buffer+sizeof(AFCPacket), data, offset); |
| 109 | bytes = mux_send(client->connection, buffer, client->afc_packet->this_length); | 111 | bytes = mux_send(client->connection, buffer, client->afc_packet->this_length); |
| 110 | free(buffer); | 112 | free(buffer); |
| 111 | if (bytes <= 0) { return 0; } | 113 | if (bytes <= 0) { return bytes; } |
| 112 | if (debug) { | 114 | if (debug) { |
| 113 | printf("dispatch_AFC_packet: sent the first now go with the second\n"); | 115 | printf("dispatch_AFC_packet: sent the first now go with the second\n"); |
| 114 | printf("Length: %i\n", length-offset); | 116 | printf("Length: %i\n", length-offset); |
| @@ -118,8 +120,7 @@ int dispatch_AFC_packet(AFClient *client, const char *data, int length) { | |||
| 118 | 120 | ||
| 119 | 121 | ||
| 120 | bytes = mux_send(client->connection, data+offset, length-offset); | 122 | bytes = mux_send(client->connection, data+offset, length-offset); |
| 121 | if (bytes <= 0) { return 0; } | 123 | return bytes; |
| 122 | else { return bytes; } | ||
| 123 | } else { | 124 | } else { |
| 124 | if (debug) printf("dispatch_AFC_packet doin things the old way\n"); | 125 | if (debug) printf("dispatch_AFC_packet doin things the old way\n"); |
| 125 | char *buffer = (char*)malloc(sizeof(char) * client->afc_packet->this_length); | 126 | char *buffer = (char*)malloc(sizeof(char) * client->afc_packet->this_length); |
| @@ -130,10 +131,9 @@ int dispatch_AFC_packet(AFClient *client, const char *data, int length) { | |||
| 130 | if (debug) fwrite(buffer, 1, client->afc_packet->this_length, stdout); | 131 | if (debug) fwrite(buffer, 1, client->afc_packet->this_length, stdout); |
| 131 | if (debug) printf("\n"); | 132 | if (debug) printf("\n"); |
| 132 | bytes = mux_send(client->connection, buffer, client->afc_packet->this_length); | 133 | bytes = mux_send(client->connection, buffer, client->afc_packet->this_length); |
| 133 | if (bytes <= 0) return 0; | 134 | return bytes; |
| 134 | else return bytes; | ||
| 135 | } | 135 | } |
| 136 | return 0; | 136 | return -1; |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | int receive_AFC_data(AFClient *client, char **dump_here) { | 139 | int receive_AFC_data(AFClient *client, char **dump_here) { |
| @@ -148,7 +148,7 @@ int receive_AFC_data(AFClient *client, char **dump_here) { | |||
| 148 | free(buffer); | 148 | free(buffer); |
| 149 | printf("Just didn't get enough.\n"); | 149 | printf("Just didn't get enough.\n"); |
| 150 | *dump_here = NULL; | 150 | *dump_here = NULL; |
| 151 | return 0; | 151 | return -1; |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | r_packet = (AFCPacket*)malloc(sizeof(AFCPacket)); | 154 | r_packet = (AFCPacket*)malloc(sizeof(AFCPacket)); |
| @@ -177,19 +177,19 @@ int receive_AFC_data(AFClient *client, char **dump_here) { | |||
| 177 | if(param1 == 0) { | 177 | if(param1 == 0) { |
| 178 | if (debug) printf("... false alarm, but still\n"); | 178 | if (debug) printf("... false alarm, but still\n"); |
| 179 | *dump_here = NULL; | 179 | *dump_here = NULL; |
| 180 | return 1; | 180 | return 0; |
| 181 | } | 181 | } |
| 182 | else { if (debug) printf("Errno %i\n", param1); } | 182 | else { if (debug) printf("Errno %i\n", param1); } |
| 183 | free(r_packet); | 183 | free(r_packet); |
| 184 | *dump_here = NULL; | 184 | *dump_here = NULL; |
| 185 | return 0; | 185 | return -1; |
| 186 | } else { | 186 | } else { |
| 187 | if (debug) printf("Operation code %x\nFull length %i and this length %i\n", r_packet->operation, r_packet->entire_length, r_packet->this_length); | 187 | if (debug) printf("Operation code %x\nFull length %i and this length %i\n", r_packet->operation, r_packet->entire_length, r_packet->this_length); |
| 188 | } | 188 | } |
| 189 | 189 | ||
| 190 | recv_len = r_packet->entire_length - r_packet->this_length; | 190 | recv_len = r_packet->entire_length - r_packet->this_length; |
| 191 | free(r_packet); | 191 | free(r_packet); |
| 192 | if (!recv_len) | 192 | if (!recv_len && r_packet->operation == AFC_SUCCESS_RESPONSE) |
| 193 | { | 193 | { |
| 194 | *dump_here = NULL; | 194 | *dump_here = NULL; |
| 195 | return 0; | 195 | return 0; |
| @@ -240,10 +240,28 @@ char **afc_get_dir_list(AFClient *client, const char *dir) { | |||
| 240 | char *blah = NULL, **list = NULL; | 240 | char *blah = NULL, **list = NULL; |
| 241 | client->afc_packet->entire_length = client->afc_packet->this_length = 0; | 241 | client->afc_packet->entire_length = client->afc_packet->this_length = 0; |
| 242 | bytes = dispatch_AFC_packet(client, dir, strlen(dir)); | 242 | bytes = dispatch_AFC_packet(client, dir, strlen(dir)); |
| 243 | if (!bytes) { afc_unlock(client); return NULL; } | 243 | if (bytes <= 0) { afc_unlock(client); return NULL; } |
| 244 | |||
| 245 | bytes = receive_AFC_data(client, &blah); | ||
| 246 | if (bytes < 0 && !blah) { afc_unlock(client); return NULL; } | ||
| 247 | |||
| 248 | list = make_strings_list(blah, bytes); | ||
| 249 | free(blah); | ||
| 250 | afc_unlock(client); | ||
| 251 | return list; | ||
| 252 | } | ||
| 253 | |||
| 254 | char **afc_get_devinfo(AFClient *client) { | ||
| 255 | afc_lock(client); | ||
| 256 | client->afc_packet->operation = AFC_GET_DEVINFO; | ||
| 257 | int bytes = 0; | ||
| 258 | char *blah = NULL, **list = NULL; | ||
| 259 | client->afc_packet->entire_length = client->afc_packet->this_length = 0; | ||
| 260 | bytes = dispatch_AFC_packet(client, NULL, 0); | ||
| 261 | if (bytes < 0) { afc_unlock(client); return NULL; } | ||
| 244 | 262 | ||
| 245 | bytes = receive_AFC_data(client, &blah); | 263 | bytes = receive_AFC_data(client, &blah); |
| 246 | if (!bytes && !blah) { afc_unlock(client); return NULL; } | 264 | if (bytes < 0 && !blah) { afc_unlock(client); return NULL; } |
| 247 | 265 | ||
| 248 | list = make_strings_list(blah, bytes); | 266 | list = make_strings_list(blah, bytes); |
| 249 | free(blah); | 267 | free(blah); |
| @@ -251,6 +269,7 @@ char **afc_get_dir_list(AFClient *client, const char *dir) { | |||
| 251 | return list; | 269 | return list; |
| 252 | } | 270 | } |
| 253 | 271 | ||
| 272 | |||
| 254 | char **make_strings_list(char *tokens, int true_length) { | 273 | char **make_strings_list(char *tokens, int true_length) { |
| 255 | if (!tokens || !true_length) return NULL; | 274 | if (!tokens || !true_length) return NULL; |
| 256 | int nulls = 0, i = 0, j = 0; | 275 | int nulls = 0, i = 0, j = 0; |
| @@ -279,7 +298,7 @@ int afc_delete_file(AFClient *client, const char *path) { | |||
| 279 | bytes = receive_AFC_data(client, &receive); | 298 | bytes = receive_AFC_data(client, &receive); |
| 280 | free(receive); | 299 | free(receive); |
| 281 | afc_unlock(client); | 300 | afc_unlock(client); |
| 282 | if (bytes <= 0) { return 0; } | 301 | if (bytes < 0) { return 0; } |
| 283 | else return 1; | 302 | else return 1; |
| 284 | } | 303 | } |
| 285 | 304 | ||
| @@ -302,12 +321,28 @@ int afc_rename_file(AFClient *client, const char *from, const char *to) { | |||
| 302 | bytes = receive_AFC_data(client, &receive); | 321 | bytes = receive_AFC_data(client, &receive); |
| 303 | free(receive); | 322 | free(receive); |
| 304 | afc_unlock(client); | 323 | afc_unlock(client); |
| 305 | if (bytes <= 0) return 0; | 324 | if (bytes < 0) return 0; |
| 306 | else return 1; | 325 | else return 1; |
| 307 | } | 326 | } |
| 308 | 327 | ||
| 328 | int afc_mkdir(AFClient *client, const char *dir) { | ||
| 329 | if (!client) return 0; | ||
| 330 | afc_lock(client); | ||
| 331 | int bytes = 0; | ||
| 332 | char *recvd = NULL; | ||
| 309 | 333 | ||
| 334 | client->afc_packet->operation = AFC_MAKE_DIR; | ||
| 335 | client->afc_packet->this_length = client->afc_packet->entire_length = 0; | ||
| 336 | bytes = dispatch_AFC_packet(client, dir, strlen(dir)); | ||
| 337 | if (bytes <= 0) { afc_unlock(client); return 0; } | ||
| 310 | 338 | ||
| 339 | bytes = receive_AFC_data(client, &recvd); | ||
| 340 | afc_unlock(client); | ||
| 341 | if (recvd) { free(recvd); recvd = NULL; } | ||
| 342 | if (bytes == 0) return 1; | ||
| 343 | else return 0; | ||
| 344 | } | ||
| 345 | |||
| 311 | AFCFile *afc_get_file_info(AFClient *client, const char *path) { | 346 | AFCFile *afc_get_file_info(AFClient *client, const char *path) { |
| 312 | client->afc_packet->operation = AFC_GET_INFO; | 347 | client->afc_packet->operation = AFC_GET_INFO; |
| 313 | client->afc_packet->entire_length = client->afc_packet->this_length = 0; | 348 | client->afc_packet->entire_length = client->afc_packet->this_length = 0; |
| @@ -350,7 +385,7 @@ AFCFile *afc_get_file_info(AFClient *client, const char *path) { | |||
| 350 | } | 385 | } |
| 351 | 386 | ||
| 352 | AFCFile *afc_open_file(AFClient *client, const char *filename, uint32 file_mode) { | 387 | AFCFile *afc_open_file(AFClient *client, const char *filename, uint32 file_mode) { |
| 353 | if (file_mode != AFC_FILE_READ && file_mode != AFC_FILE_WRITE) return NULL; | 388 | //if (file_mode != AFC_FILE_READ && file_mode != AFC_FILE_WRITE) return NULL; |
| 354 | if (!client ||!client->connection || !client->afc_packet) return NULL; | 389 | if (!client ||!client->connection || !client->afc_packet) return NULL; |
| 355 | afc_lock(client); | 390 | afc_lock(client); |
| 356 | char *further_data = (char*)malloc(sizeof(char) * (8 + strlen(filename) + 1)); | 391 | char *further_data = (char*)malloc(sizeof(char) * (8 + strlen(filename) + 1)); |
| @@ -372,17 +407,19 @@ AFCFile *afc_open_file(AFClient *client, const char *filename, uint32 file_mode) | |||
| 372 | return NULL; | 407 | return NULL; |
| 373 | } else { | 408 | } else { |
| 374 | length_thing = receive_AFC_data(client, &further_data); | 409 | length_thing = receive_AFC_data(client, &further_data); |
| 375 | if (length_thing && further_data) { | 410 | if (length_thing > 0 && further_data) { |
| 376 | afc_unlock(client); // don't want to hang on the next call... and besides, it'll re-lock, do its thing, and unlock again anyway. | 411 | afc_unlock(client); // don't want to hang on the next call... and besides, it'll re-lock, do its thing, and unlock again anyway. |
| 377 | file_infos = afc_get_file_info(client, filename); | 412 | file_infos = afc_get_file_info(client, filename); |
| 378 | memcpy(&file_infos->filehandle, further_data, 4); | 413 | memcpy(&file_infos->filehandle, further_data, 4); |
| 379 | return file_infos; | 414 | return file_infos; |
| 380 | } else { | 415 | } else { |
| 381 | if (debug) printf("didn't get further data or something\n"); | 416 | if (debug) printf("didn't get further data or something\n"); |
| 417 | afc_unlock(client); | ||
| 382 | return NULL; | 418 | return NULL; |
| 383 | } | 419 | } |
| 384 | } | 420 | } |
| 385 | if (debug) printf("what the fuck\n"); | 421 | if (debug) printf("what the fuck\n"); |
| 422 | afc_unlock(client); | ||
| 386 | return NULL; | 423 | return NULL; |
| 387 | } | 424 | } |
| 388 | 425 | ||
| @@ -408,7 +445,8 @@ int afc_read_file(AFClient *client, AFCFile *file, char *data, int length) { | |||
| 408 | 445 | ||
| 409 | // Looping here to get around the maximum amount of data that recieve_AFC_data can handle | 446 | // Looping here to get around the maximum amount of data that recieve_AFC_data can handle |
| 410 | while (current_count < length){ | 447 | while (current_count < length){ |
| 411 | 448 | if (debug) printf("afc_read_file: current count is %i but length is %i\n", current_count, length); | |
| 449 | |||
| 412 | // Send the read command | 450 | // Send the read command |
| 413 | AFCFilePacket *packet = (AFCFilePacket*)malloc(sizeof(AFCFilePacket)); | 451 | AFCFilePacket *packet = (AFCFilePacket*)malloc(sizeof(AFCFilePacket)); |
| 414 | packet->unknown1 = packet->unknown2 = 0; | 452 | packet->unknown1 = packet->unknown2 = 0; |
| @@ -421,6 +459,7 @@ int afc_read_file(AFClient *client, AFCFile *file, char *data, int length) { | |||
| 421 | // If we get a positive reponse to the command gather the data | 459 | // If we get a positive reponse to the command gather the data |
| 422 | if (bytes > 0) { | 460 | if (bytes > 0) { |
| 423 | bytes = receive_AFC_data(client, &input); | 461 | bytes = receive_AFC_data(client, &input); |
| 462 | if (debug) printf("afc_read_file: bytes returned: %i\n", bytes); | ||
| 424 | if (bytes < 0) { | 463 | if (bytes < 0) { |
| 425 | if (input) free(input); | 464 | if (input) free(input); |
| 426 | afc_unlock(client); | 465 | afc_unlock(client); |
| @@ -431,7 +470,7 @@ int afc_read_file(AFClient *client, AFCFile *file, char *data, int length) { | |||
| 431 | return current_count; | 470 | return current_count; |
| 432 | } else { | 471 | } else { |
| 433 | if (input) { | 472 | if (input) { |
| 434 | printf("afc_read_file: %d\n", bytes); | 473 | if (debug) printf("afc_read_file: %d\n", bytes); |
| 435 | memcpy(data+current_count, input, (bytes > length) ? length : bytes); | 474 | memcpy(data+current_count, input, (bytes > length) ? length : bytes); |
| 436 | free(input); | 475 | free(input); |
| 437 | input = NULL; | 476 | input = NULL; |
| @@ -444,6 +483,7 @@ int afc_read_file(AFClient *client, AFCFile *file, char *data, int length) { | |||
| 444 | } | 483 | } |
| 445 | } | 484 | } |
| 446 | afc_unlock(client); | 485 | afc_unlock(client); |
| 486 | if (debug) printf("afc_read_file: returning current_count as %i\n", current_count); | ||
| 447 | return current_count; | 487 | return current_count; |
| 448 | } | 488 | } |
| 449 | 489 | ||
| @@ -451,29 +491,53 @@ int afc_write_file(AFClient *client, AFCFile *file, const char *data, int length | |||
| 451 | char *acknowledgement = NULL; | 491 | char *acknowledgement = NULL; |
| 452 | if (!client ||!client->afc_packet || !client->connection || !file) return -1; | 492 | if (!client ||!client->afc_packet || !client->connection || !file) return -1; |
| 453 | afc_lock(client); | 493 | afc_lock(client); |
| 454 | client->afc_packet->this_length = sizeof(AFCPacket) + 8; | ||
| 455 | client->afc_packet->entire_length = client->afc_packet->this_length + length; | ||
| 456 | client->afc_packet->operation = AFC_WRITE; | ||
| 457 | if (debug) printf("afc_write_file: Write length: %i\n", length); | 494 | if (debug) printf("afc_write_file: Write length: %i\n", length); |
| 458 | uint32 zero = 0, bytes = 0; | 495 | const int MAXIMUM_WRITE_SIZE = 1 << 16; |
| 459 | 496 | uint32 zero = 0, bytes = 0, segments = (length / MAXIMUM_WRITE_SIZE), current_count = 0, i = 0; | |
| 460 | char *out_buffer = NULL; | 497 | char *out_buffer = NULL; |
| 498 | |||
| 499 | for (i = 0; i < segments; i++) { // Essentially, yeah, divide it into segments. | ||
| 500 | client->afc_packet->this_length = sizeof(AFCPacket) + 8; | ||
| 501 | //client->afc_packet->entire_length = client->afc_packet->this_length + length; | ||
| 502 | client->afc_packet->entire_length = client->afc_packet->this_length + MAXIMUM_WRITE_SIZE; | ||
| 503 | client->afc_packet->operation = AFC_WRITE; | ||
| 504 | out_buffer = (char*)malloc(sizeof(char) * client->afc_packet->entire_length - sizeof(AFCPacket)); | ||
| 505 | memcpy(out_buffer, (char*)&file->filehandle, sizeof(uint32)); | ||
| 506 | memcpy(out_buffer+4, (char*)&zero, sizeof(uint32)); | ||
| 507 | memcpy(out_buffer+8, data+current_count, MAXIMUM_WRITE_SIZE); | ||
| 508 | |||
| 509 | bytes = dispatch_AFC_packet(client, out_buffer, MAXIMUM_WRITE_SIZE + 8); | ||
| 510 | if (bytes < 0) { afc_unlock(client); return bytes; } | ||
| 511 | free(out_buffer); out_buffer = NULL; // cleanup and hope it works | ||
| 512 | current_count += bytes; | ||
| 513 | bytes = receive_AFC_data(client, &acknowledgement); | ||
| 514 | if (bytes < 0) { afc_unlock(client); return current_count; } | ||
| 515 | } | ||
| 516 | |||
| 517 | // By this point, we should be at the end. i.e. the last segment that didn't get sent in the for loop | ||
| 518 | // this length is fine because it's always sizeof(AFCPacket) + 8, but to be sure we do it again | ||
| 519 | if (current_count == length) { afc_unlock(client); return current_count; } | ||
| 520 | client->afc_packet->this_length = sizeof(AFCPacket) + 8; | ||
| 521 | client->afc_packet->entire_length = client->afc_packet->this_length + (length - current_count); | ||
| 522 | // operation is already AFC_WRITE, but set again to be sure | ||
| 523 | client->afc_packet->operation = AFC_WRITE; | ||
| 461 | out_buffer = (char*)malloc(sizeof(char) * client->afc_packet->entire_length - sizeof(AFCPacket)); | 524 | out_buffer = (char*)malloc(sizeof(char) * client->afc_packet->entire_length - sizeof(AFCPacket)); |
| 462 | memcpy(out_buffer, (char*)&file->filehandle, sizeof(uint32)); | 525 | memcpy(out_buffer, (char*)&file->filehandle, sizeof(uint32)); |
| 463 | memcpy(out_buffer+4, (char*)&zero, sizeof(uint32)); | 526 | memcpy(out_buffer+4, (char*)&zero, sizeof(uint32)); |
| 464 | memcpy(out_buffer+8, data, length); | 527 | memcpy(out_buffer+8, data+current_count, (length - current_count)); |
| 465 | 528 | bytes = dispatch_AFC_packet(client, out_buffer, (length - current_count) + 8); | |
| 466 | bytes = dispatch_AFC_packet(client, out_buffer, length + 8); | 529 | free(out_buffer); out_buffer = NULL; |
| 467 | if (!bytes) return -1; | 530 | current_count += bytes; |
| 531 | if (bytes <= 0) { afc_unlock(client); return current_count; } | ||
| 468 | 532 | ||
| 469 | zero = bytes; | 533 | zero = bytes; |
| 470 | bytes = receive_AFC_data(client, &acknowledgement); | 534 | bytes = receive_AFC_data(client, &acknowledgement); |
| 471 | afc_unlock(client); | 535 | afc_unlock(client); |
| 472 | if (bytes <= 0) { | 536 | if (bytes < 0) { |
| 473 | if (debug) printf("afc_write_file: uh oh?\n"); | 537 | if (debug) printf("afc_write_file: uh oh?\n"); |
| 474 | } | 538 | } |
| 475 | 539 | ||
| 476 | return zero; | 540 | return current_count; |
| 477 | } | 541 | } |
| 478 | 542 | ||
| 479 | void afc_close_file(AFClient *client, AFCFile *file) { | 543 | void afc_close_file(AFClient *client, AFCFile *file) { |
| @@ -490,9 +554,61 @@ void afc_close_file(AFClient *client, AFCFile *file) { | |||
| 490 | 554 | ||
| 491 | free(buffer); | 555 | free(buffer); |
| 492 | client->afc_packet->entire_length = client->afc_packet->this_length = 0; | 556 | client->afc_packet->entire_length = client->afc_packet->this_length = 0; |
| 493 | if (!bytes) return; | 557 | if (bytes <= 0) { afc_unlock(client); return; } |
| 494 | 558 | ||
| 495 | bytes = receive_AFC_data(client, &buffer); | 559 | bytes = receive_AFC_data(client, &buffer); |
| 496 | afc_unlock(client); | 560 | afc_unlock(client); |
| 561 | if (buffer) { free(buffer); } | ||
| 497 | return; | 562 | return; |
| 498 | } | 563 | } |
| 564 | |||
| 565 | int afc_seek_file(AFClient *client, AFCFile *file, int seekpos) { | ||
| 566 | afc_lock(client); | ||
| 567 | |||
| 568 | char *buffer = (char*)malloc(sizeof(char) * 24); | ||
| 569 | uint32 seekto = 0, bytes = 0, zero = 0; | ||
| 570 | if (seekpos < 0) seekpos = file->size - abs(seekpos); | ||
| 571 | seekto = seekpos; | ||
| 572 | |||
| 573 | memcpy(buffer, &file->filehandle, sizeof(uint32)); // handle | ||
| 574 | memcpy(buffer+4, &zero, sizeof(uint32)); // pad | ||
| 575 | memcpy(buffer+8, &zero, sizeof(uint32)); // fromwhere | ||
| 576 | memcpy(buffer+12, &zero, sizeof(uint32)); // pad | ||
| 577 | memcpy(buffer+16, &seekto, sizeof(uint32)); // offset | ||
| 578 | memcpy(buffer+20, &zero, sizeof(uint32)); // pad | ||
| 579 | client->afc_packet->operation = AFC_FILE_SEEK; | ||
| 580 | client->afc_packet->this_length = client->afc_packet->entire_length = 0; | ||
| 581 | bytes = dispatch_AFC_packet(client, buffer, 23); | ||
| 582 | free(buffer); buffer = NULL; | ||
| 583 | if (bytes <= 0) { afc_unlock(client); return -1; } | ||
| 584 | |||
| 585 | bytes = receive_AFC_data(client, &buffer); | ||
| 586 | if (buffer) free(buffer); | ||
| 587 | afc_unlock(client); | ||
| 588 | if (bytes >= 0) return 0; | ||
| 589 | else return -1; | ||
| 590 | } | ||
| 591 | |||
| 592 | int afc_truncate_file(AFClient *client, AFCFile *file, uint32 newsize) { | ||
| 593 | afc_lock(client); | ||
| 594 | |||
| 595 | char *buffer = (char*)malloc(sizeof(char) * 16); | ||
| 596 | uint32 bytes = 0, zero = 0; | ||
| 597 | |||
| 598 | memcpy(buffer, &file->filehandle, sizeof(uint32)); // handle | ||
| 599 | memcpy(buffer+4, &zero, sizeof(uint32)); // pad | ||
| 600 | memcpy(buffer+8, &newsize, sizeof(uint32)); // newsize | ||
| 601 | memcpy(buffer+12, &zero, 3); // pad | ||
| 602 | client->afc_packet->operation = AFC_FILE_TRUNCATE; | ||
| 603 | client->afc_packet->this_length = client->afc_packet->entire_length = 0; | ||
| 604 | bytes = dispatch_AFC_packet(client, buffer, 15); | ||
| 605 | free(buffer); buffer = NULL; | ||
| 606 | if (bytes <= 0) { afc_unlock(client); return -1; } | ||
| 607 | |||
| 608 | bytes = receive_AFC_data(client, &buffer); | ||
| 609 | if (buffer) free(buffer); | ||
| 610 | afc_unlock(client); | ||
| 611 | if (bytes >= 0) return 0; | ||
| 612 | else return -1; | ||
| 613 | } | ||
| 614 | |||
| @@ -56,8 +56,14 @@ typedef struct __AFCToken { | |||
| 56 | 56 | ||
| 57 | 57 | ||
| 58 | enum { | 58 | enum { |
| 59 | AFC_FILE_READ = 0x00000002, | 59 | AFC_FILE_READ = 0x00000002, // seems to be able to read and write files |
| 60 | AFC_FILE_WRITE = 0x00000003 | 60 | AFC_FILE_WRITE = 0x00000003, // writes and creates a file, blanks it out, etc. |
| 61 | AFC_FILE_RW = 0x00000005, // seems to do the same as 2. Might even create the file. | ||
| 62 | AFC_FILE_OP4 = 0x00000004, // no idea -- appears to be "write" -- clears file beforehand like 3 | ||
| 63 | AFC_FILE_OP6 = 0x00000006, // no idea yet -- appears to be the same as 5. | ||
| 64 | AFC_FILE_OP1 = 0x00000001, // no idea juuust yet... probably read. | ||
| 65 | AFC_FILE_OP0 = 0x00000000, | ||
| 66 | AFC_FILE_OP10 = 0x0000000a | ||
| 61 | }; | 67 | }; |
| 62 | 68 | ||
| 63 | enum { | 69 | enum { |
| @@ -65,11 +71,14 @@ enum { | |||
| 65 | AFC_GET_INFO = 0x0000000a, | 71 | AFC_GET_INFO = 0x0000000a, |
| 66 | AFC_GET_DEVINFO = 0x0000000b, | 72 | AFC_GET_DEVINFO = 0x0000000b, |
| 67 | AFC_LIST_DIR = 0x00000003, | 73 | AFC_LIST_DIR = 0x00000003, |
| 74 | AFC_MAKE_DIR = 0x00000009, | ||
| 68 | AFC_DELETE = 0x00000008, | 75 | AFC_DELETE = 0x00000008, |
| 69 | AFC_RENAME = 0x00000018, | 76 | AFC_RENAME = 0x00000018, |
| 70 | AFC_SUCCESS_RESPONSE = 0x00000002, | 77 | AFC_SUCCESS_RESPONSE = 0x00000002, |
| 71 | AFC_FILE_OPEN = 0x0000000d, | 78 | AFC_FILE_OPEN = 0x0000000d, |
| 72 | AFC_FILE_CLOSE = 0x00000014, | 79 | AFC_FILE_CLOSE = 0x00000014, |
| 80 | AFC_FILE_SEEK = 0x00000011, | ||
| 81 | AFC_FILE_TRUNCATE = 0x00000015, | ||
| 73 | AFC_FILE_HANDLE = 0x0000000e, | 82 | AFC_FILE_HANDLE = 0x0000000e, |
| 74 | AFC_READ = 0x0000000f, | 83 | AFC_READ = 0x0000000f, |
| 75 | AFC_WRITE = 0x00000010 | 84 | AFC_WRITE = 0x00000010 |
diff --git a/src/ifuse.c b/src/ifuse.c index 3d921fd..9fc1ad8 100644 --- a/src/ifuse.c +++ b/src/ifuse.c | |||
| @@ -41,7 +41,7 @@ | |||
| 41 | GHashTable *file_handles; | 41 | GHashTable *file_handles; |
| 42 | int fh_index = 0; | 42 | int fh_index = 0; |
| 43 | 43 | ||
| 44 | int debug = 1; | 44 | int debug = 0; |
| 45 | 45 | ||
| 46 | static int ifuse_getattr(const char *path, struct stat *stbuf) { | 46 | static int ifuse_getattr(const char *path, struct stat *stbuf) { |
| 47 | int res = 0; | 47 | int res = 0; |
| @@ -53,7 +53,8 @@ static int ifuse_getattr(const char *path, struct stat *stbuf) { | |||
| 53 | if (!file){ | 53 | if (!file){ |
| 54 | res = -ENOENT; | 54 | res = -ENOENT; |
| 55 | } else { | 55 | } else { |
| 56 | stbuf->st_mode = file->type | 0444; | 56 | //stbuf->st_mode = file->type | 0444; // testing write access too now |
| 57 | stbuf->st_mode = file->type | 0644; // but we don't want anything on the iPhone executable, like, ever | ||
| 57 | stbuf->st_size = file->size; | 58 | stbuf->st_size = file->size; |
| 58 | //stbuf->st_nlink = 2; | 59 | //stbuf->st_nlink = 2; |
| 59 | } | 60 | } |
| @@ -81,14 +82,34 @@ static int ifuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler, | |||
| 81 | return 0; | 82 | return 0; |
| 82 | } | 83 | } |
| 83 | 84 | ||
| 84 | static int ifuse_open(const char *path, struct fuse_file_info *fi) { | 85 | static int ifuse_create(const char *path, mode_t mode, struct fuse_file_info *fi) { |
| 86 | // exactly the same as open but using a different mode | ||
| 85 | AFCFile *file; | 87 | AFCFile *file; |
| 86 | AFClient *afc = fuse_get_context()->private_data; | 88 | AFClient *afc = fuse_get_context()->private_data; |
| 89 | |||
| 90 | file = afc_open_file(afc, path, AFC_FILE_WRITE); | ||
| 91 | fh_index++; | ||
| 92 | fi->fh = fh_index; | ||
| 93 | g_hash_table_insert(file_handles, &fh_index, file); | ||
| 94 | return 0; | ||
| 95 | } | ||
| 87 | 96 | ||
| 88 | if((fi->flags & 3) != O_RDONLY) | 97 | static int ifuse_open(const char *path, struct fuse_file_info *fi) { |
| 89 | return -EACCES; | 98 | AFCFile *file; |
| 99 | AFClient *afc = fuse_get_context()->private_data; | ||
| 100 | uint32 mode = 0; | ||
| 101 | /*if((fi->flags & 3) != O_RDONLY) | ||
| 102 | return -EACCES;*/ // trying to test write access here | ||
| 103 | |||
| 104 | if ((fi->flags & 3) == O_RDWR || (fi->flags & 3) == O_WRONLY) { | ||
| 105 | mode = AFC_FILE_READ; | ||
| 106 | } else if ((fi->flags & 3) == O_RDONLY) { | ||
| 107 | mode = AFC_FILE_READ; | ||
| 108 | } else { | ||
| 109 | mode = AFC_FILE_READ; | ||
| 110 | } | ||
| 90 | 111 | ||
| 91 | file = afc_open_file(afc, path, AFC_FILE_READ); | 112 | file = afc_open_file(afc, path, mode); |
| 92 | 113 | ||
| 93 | fh_index++; | 114 | fh_index++; |
| 94 | fi->fh = fh_index; | 115 | fi->fh = fh_index; |
| @@ -111,10 +132,30 @@ static int ifuse_read(const char *path, char *buf, size_t size, off_t offset, | |||
| 111 | return -ENOENT; | 132 | return -ENOENT; |
| 112 | } | 133 | } |
| 113 | 134 | ||
| 135 | bytes = afc_seek_file(afc, file, offset); | ||
| 114 | bytes = afc_read_file(afc, file, buf, size); | 136 | bytes = afc_read_file(afc, file, buf, size); |
| 115 | return bytes; | 137 | return bytes; |
| 116 | } | 138 | } |
| 117 | 139 | ||
| 140 | static int ifuse_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { | ||
| 141 | int bytes = 0; | ||
| 142 | AFCFile *file = NULL; | ||
| 143 | AFClient *afc = fuse_get_context()->private_data; | ||
| 144 | |||
| 145 | if (size == 0) return 0; | ||
| 146 | |||
| 147 | file = g_hash_table_lookup(file_handles, &(fi->fh)); | ||
| 148 | if (!file) return -ENOENT; | ||
| 149 | |||
| 150 | bytes = afc_seek_file(afc, file, offset); | ||
| 151 | bytes = afc_write_file(afc, file, buf, size); | ||
| 152 | return bytes; | ||
| 153 | } | ||
| 154 | |||
| 155 | static int ifuse_fsync(const char *path, int datasync, struct fuse_file_info *fi) { | ||
| 156 | return 0; | ||
| 157 | } | ||
| 158 | |||
| 118 | static int ifuse_release(const char *path, struct fuse_file_info *fi){ | 159 | static int ifuse_release(const char *path, struct fuse_file_info *fi){ |
| 119 | AFCFile *file; | 160 | AFCFile *file; |
| 120 | AFClient *afc = fuse_get_context()->private_data; | 161 | AFClient *afc = fuse_get_context()->private_data; |
| @@ -181,11 +222,89 @@ void ifuse_cleanup(void *data) { | |||
| 181 | } | 222 | } |
| 182 | } | 223 | } |
| 183 | 224 | ||
| 225 | int ifuse_flush(const char *path, struct fuse_file_info *fi) { | ||
| 226 | return 0; | ||
| 227 | } | ||
| 228 | |||
| 229 | int ifuse_statfs(const char *path, struct statvfs *stats) { | ||
| 230 | AFClient *afc = fuse_get_context()->private_data; | ||
| 231 | char **info_raw = afc_get_devinfo(afc); | ||
| 232 | uint32 totalspace = 0, freespace = 0, blocksize = 0, i = 0; | ||
| 233 | |||
| 234 | if (!info_raw) return -ENOENT; | ||
| 235 | |||
| 236 | for (i = 0; strcmp(info_raw[i], ""); i++) { | ||
| 237 | if (!strcmp(info_raw[i], "FSTotalBytes")) { | ||
| 238 | totalspace = atoi(info_raw[i+1]); | ||
| 239 | } else if (!strcmp(info_raw[i], "FSFreeBytes")) { | ||
| 240 | freespace = atoi(info_raw[i+1]); | ||
| 241 | } else if (!strcmp(info_raw[i], "FSBlockSize")) { | ||
| 242 | blocksize = atoi(info_raw[i+1]); | ||
| 243 | } | ||
| 244 | } | ||
| 245 | |||
| 246 | // Now to fill the struct. | ||
| 247 | stats->f_bsize = stats->f_frsize = blocksize; | ||
| 248 | stats->f_blocks = totalspace / blocksize; // gets the blocks by dividing bytes by blocksize | ||
| 249 | stats->f_bfree = stats->f_bavail = freespace / blocksize; // all bytes are free to everyone, I guess. | ||
| 250 | stats->f_namemax = 255; // blah | ||
| 251 | stats->f_files = stats->f_ffree = 1000000000; // make up any old thing, I guess | ||
| 252 | return 0; | ||
| 253 | } | ||
| 254 | |||
| 255 | int ifuse_truncate(const char *path, off_t size) { | ||
| 256 | int result = 0; | ||
| 257 | AFClient *afc = fuse_get_context()->private_data; | ||
| 258 | AFCFile *tfile = afc_open_file(afc, path, AFC_FILE_READ); | ||
| 259 | if (!tfile) return -1; | ||
| 260 | |||
| 261 | result = afc_truncate_file(afc, tfile, size); | ||
| 262 | afc_close_file(afc, tfile); | ||
| 263 | return result; | ||
| 264 | } | ||
| 265 | |||
| 266 | int ifuse_ftruncate(const char *path, off_t size, struct fuse_file_info *fi) { | ||
| 267 | int result = 0; | ||
| 268 | AFClient *afc = fuse_get_context()->private_data; | ||
| 269 | AFCFile *file = g_hash_table_lookup(file_handles, &fi->fh); | ||
| 270 | if (!file) return -ENOENT; | ||
| 271 | |||
| 272 | return afc_truncate_file(afc, file, size); | ||
| 273 | } | ||
| 274 | |||
| 275 | int ifuse_unlink(const char *path) { | ||
| 276 | AFClient *afc = fuse_get_context()->private_data; | ||
| 277 | if (afc_delete_file(afc, path)) return 0; | ||
| 278 | else return -1; | ||
| 279 | } | ||
| 280 | |||
| 281 | int ifuse_rename(const char *from, const char *to) { | ||
| 282 | AFClient *afc = fuse_get_context()->private_data; | ||
| 283 | if (afc_rename_file(afc, from, to)) return 0; | ||
| 284 | else return -1; | ||
| 285 | } | ||
| 286 | |||
| 287 | int ifuse_mkdir(const char *dir, mode_t ignored) { | ||
| 288 | AFClient *afc = fuse_get_context()->private_data; | ||
| 289 | if (afc_mkdir(afc, dir)) return 0; | ||
| 290 | else return -1; | ||
| 291 | } | ||
| 292 | |||
| 184 | static struct fuse_operations ifuse_oper = { | 293 | static struct fuse_operations ifuse_oper = { |
| 185 | .getattr = ifuse_getattr, | 294 | .getattr = ifuse_getattr, |
| 295 | .statfs = ifuse_statfs, | ||
| 186 | .readdir = ifuse_readdir, | 296 | .readdir = ifuse_readdir, |
| 297 | .mkdir = ifuse_mkdir, | ||
| 298 | .rmdir = ifuse_unlink, // AFC uses the same op for both. | ||
| 299 | .create = ifuse_create, | ||
| 187 | .open = ifuse_open, | 300 | .open = ifuse_open, |
| 188 | .read = ifuse_read, | 301 | .read = ifuse_read, |
| 302 | .write = ifuse_write, | ||
| 303 | .truncate = ifuse_truncate, | ||
| 304 | .ftruncate = ifuse_ftruncate, | ||
| 305 | .unlink = ifuse_unlink, | ||
| 306 | .rename = ifuse_rename, | ||
| 307 | .fsync = ifuse_fsync, | ||
| 189 | .release = ifuse_release, | 308 | .release = ifuse_release, |
| 190 | .init = ifuse_init, | 309 | .init = ifuse_init, |
| 191 | .destroy = ifuse_cleanup | 310 | .destroy = ifuse_cleanup |
| @@ -80,6 +80,13 @@ int main(int argc, char *argv[]) { | |||
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | free_dictionary(dirs); | 82 | free_dictionary(dirs); |
| 83 | dirs = afc_get_devinfo(afc); | ||
| 84 | if (dirs) { | ||
| 85 | for (i = 0; strcmp(dirs[i], ""); i+=2) { | ||
| 86 | printf("%s: %s\n", dirs[i], dirs[i+1]); | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 83 | AFCFile *my_file = afc_open_file(afc, "/iTunesOnTheGoPlaylist.plist", AFC_FILE_READ); | 90 | AFCFile *my_file = afc_open_file(afc, "/iTunesOnTheGoPlaylist.plist", AFC_FILE_READ); |
| 84 | if (my_file) { | 91 | if (my_file) { |
| 85 | printf("A file size: %i\n", my_file->size); | 92 | printf("A file size: %i\n", my_file->size); |
| @@ -108,12 +115,25 @@ int main(int argc, char *argv[]) { | |||
| 108 | printf("Deleting a file...\n"); | 115 | printf("Deleting a file...\n"); |
| 109 | bytes = afc_delete_file(afc, "/delme"); | 116 | bytes = afc_delete_file(afc, "/delme"); |
| 110 | if (bytes) printf("Success.\n"); | 117 | if (bytes) printf("Success.\n"); |
| 111 | else printf("Failure.\n"); | 118 | else printf("Failure. (expected unless you have a /delme file on your phone)\n"); |
| 112 | 119 | ||
| 113 | printf("Renaming a file...\n"); | 120 | printf("Renaming a file...\n"); |
| 114 | bytes = afc_rename_file(afc, "/renme", "/renme2"); | 121 | bytes = afc_rename_file(afc, "/renme", "/renme2"); |
| 115 | if (bytes > 0) printf("Success.\n"); | 122 | if (bytes > 0) printf("Success.\n"); |
| 116 | else printf("Failure.\n"); | 123 | else printf("Failure. (expected unless you have a /renme file on your phone)\n"); |
| 124 | |||
| 125 | printf("Seek & read\n"); | ||
| 126 | my_file = afc_open_file(afc, "/readme.libiphone.fx", AFC_FILE_READ); | ||
| 127 | bytes = afc_seek_file(afc, my_file, 5); | ||
| 128 | if (!bytes) printf("WARN: SEEK DID NOT WORK\n"); | ||
| 129 | char *threeletterword = (char*)malloc(sizeof(char) * 5); | ||
| 130 | bytes = afc_read_file(afc, my_file, threeletterword, 3); | ||
| 131 | threeletterword[3] = '\0'; | ||
| 132 | if (bytes > 0) printf("Result: %s\n", threeletterword); | ||
| 133 | else printf("Couldn't read!\n"); | ||
| 134 | free(threeletterword); | ||
| 135 | afc_close_file(afc, my_file); | ||
| 136 | |||
| 117 | } | 137 | } |
| 118 | afc_disconnect(afc); | 138 | afc_disconnect(afc); |
| 119 | } else { | 139 | } else { |
