afc_error_t afc_rename_path(afc_client_t client, const char *from, const char *to) { if (!client || !from || !to || !client->afc_packet || !client->parent) return AFC_E_INVALID_ARG; char *buffer = (char *) malloc(sizeof(char) * (strlen(from) + strlen(to) + 1 + sizeof(uint32_t))); uint32_t bytes = 0; afc_error_t ret = AFC_E_UNKNOWN_ERROR; afc_lock(client); /* Send command */ memcpy(buffer, from, strlen(from) + 1); memcpy(buffer + strlen(from) + 1, to, strlen(to) + 1); ret = afc_dispatch_packet(client, AFC_OP_RENAME_PATH, buffer, strlen(to)+1 + strlen(from)+1, NULL, 0, &bytes); free(buffer); if (ret != AFC_E_SUCCESS) { afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } /* Receive response */ ret = afc_receive_data(client, NULL, &bytes); afc_unlock(client); return ret; }
afc_error_t afc_remove_path(afc_client_t client, const char *path) { uint32_t bytes = 0; afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || !path || !client->afc_packet || !client->parent) return AFC_E_INVALID_ARG; afc_lock(client); /* Send command */ ret = afc_dispatch_packet(client, AFC_OP_REMOVE_PATH, path, strlen(path)+1, NULL, 0, &bytes); if (ret != AFC_E_SUCCESS) { afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } /* Receive response */ ret = afc_receive_data(client, NULL, &bytes); /* special case; unknown error actually means directory not empty */ if (ret == AFC_E_UNKNOWN_ERROR) ret = AFC_E_DIR_NOT_EMPTY; afc_unlock(client); return ret; }
afc_error_t afc_set_file_time(afc_client_t client, const char *path, uint64_t mtime) { if (!client || !path || !client->afc_packet || !client->parent) return AFC_E_INVALID_ARG; char *buffer = (char *) malloc(sizeof(char) * (strlen(path) + 1 + 8)); uint32_t bytes = 0; uint64_t mtime_loc = htole64(mtime); afc_error_t ret = AFC_E_UNKNOWN_ERROR; afc_lock(client); /* Send command */ memcpy(buffer, &mtime_loc, 8); memcpy(buffer + 8, path, strlen(path) + 1); ret = afc_dispatch_packet(client, AFC_OP_SET_FILE_TIME, buffer, 8 + strlen(path) + 1, NULL, 0, &bytes); free(buffer); if (ret != AFC_E_SUCCESS) { afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } /* Receive response */ ret = afc_receive_data(client, NULL, &bytes); afc_unlock(client); return ret; }
/** Creates a directory on the phone. * * @param client The client to use to make a directory. * @param dir The directory's path. (must be a fully-qualified path, I assume * all other mkdir restrictions apply as well) * * @return AFC_E_SUCCESS if everythong went well, AFC_E_INVALID_ARGUMENT * if arguments are NULL or invalid, AFC_E_NOT_ENOUGH_DATA otherwise. */ afc_error_t afc_make_directory(afc_client_t client, const char *dir) { int bytes = 0; char *response = NULL; afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client) return AFC_E_INVALID_ARGUMENT; afc_lock(client); // Send command client->afc_packet->operation = AFC_OP_MAKE_DIR; client->afc_packet->this_length = client->afc_packet->entire_length = 0; bytes = afc_dispatch_packet(client, dir, strlen(dir)+1); if (bytes <= 0) { afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } // Receive response ret = afc_receive_data(client, &response, &bytes); if (response) free(response); afc_unlock(client); return ret; }
/** Gets information about a specific file. * * @param client The client to use to get the information of the file. * @param path The fully-qualified path to the file. * @param infolist Pointer to a buffer that will be filled with a NULL-terminated * list of strings with the file information. * Set to NULL before calling this function. * * @return AFC_E_SUCCESS on success or an AFC_E_* error value * when something went wrong. */ afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***infolist) { char *received = NULL; int bytes; afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || !path || !infolist) return AFC_E_INVALID_ARGUMENT; afc_lock(client); // Send command client->afc_packet->operation = AFC_OP_GET_FILE_INFO; client->afc_packet->entire_length = client->afc_packet->this_length = 0; afc_dispatch_packet(client, path, strlen(path)+1); // Receive data ret = afc_receive_data(client, &received, &bytes); if (received) { *infolist = make_strings_list(received, bytes); free(received); } afc_unlock(client); return ret; }
afc_error_t afc_file_truncate(afc_client_t client, uint64_t handle, uint64_t newsize) { uint32_t bytes = 0; struct { uint64_t handle; uint64_t newsize; } truncinfo; afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || (handle == 0)) return AFC_E_INVALID_ARG; afc_lock(client); /* Send command */ truncinfo.handle = handle; truncinfo.newsize = htole64(newsize); ret = afc_dispatch_packet(client, AFC_OP_FILE_SET_SIZE, (const char*)&truncinfo, sizeof(truncinfo), NULL, 0, &bytes); if (ret != AFC_E_SUCCESS) { afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } /* Receive response */ ret = afc_receive_data(client, NULL, &bytes); afc_unlock(client); return ret; }
afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, const char *target, const char *linkname) { if (!client || !target || !linkname || !client->afc_packet || !client->parent) return AFC_E_INVALID_ARG; char *buffer = (char *) malloc(sizeof(char) * (strlen(target)+1 + strlen(linkname)+1 + 8)); uint32_t bytes = 0; uint64_t type = htole64(linktype); afc_error_t ret = AFC_E_UNKNOWN_ERROR; afc_lock(client); debug_info("link type: %lld", type); debug_info("target: %s, length:%d", target, strlen(target)); debug_info("linkname: %s, length:%d", linkname, strlen(linkname)); /* Send command */ memcpy(buffer, &type, 8); memcpy(buffer + 8, target, strlen(target) + 1); memcpy(buffer + 8 + strlen(target) + 1, linkname, strlen(linkname) + 1); ret = afc_dispatch_packet(client, AFC_OP_MAKE_LINK, buffer, 8 + strlen(linkname) + 1 + strlen(target) + 1, NULL, 0, &bytes); free(buffer); if (ret != AFC_E_SUCCESS) { afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } /* Receive response */ ret = afc_receive_data(client, NULL, &bytes); afc_unlock(client); return ret; }
afc_error_t afc_file_seek(afc_client_t client, uint64_t handle, int64_t offset, int whence) { uint32_t bytes = 0; struct { uint64_t handle; uint64_t whence; int64_t offset; } seekinfo; afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || (handle == 0)) return AFC_E_INVALID_ARG; afc_lock(client); /* Send the command */ seekinfo.handle = handle; seekinfo.whence = htole64(whence); seekinfo.offset = (int64_t)htole64(offset); ret = afc_dispatch_packet(client, AFC_OP_FILE_SEEK, (const char*)&seekinfo, sizeof(seekinfo), NULL, 0, &bytes); if (ret != AFC_E_SUCCESS) { afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } /* Receive response */ ret = afc_receive_data(client, NULL, &bytes); afc_unlock(client); return ret; }
afc_error_t afc_file_tell(afc_client_t client, uint64_t handle, uint64_t *position) { char *buffer = NULL; uint32_t bytes = 0; afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || (handle == 0)) return AFC_E_INVALID_ARG; afc_lock(client); /* Send the command */ ret = afc_dispatch_packet(client, AFC_OP_FILE_TELL, (const char*)&handle, 8, NULL, 0, &bytes); if (ret != AFC_E_SUCCESS) { afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } /* Receive the data */ ret = afc_receive_data(client, &buffer, &bytes); if (bytes > 0 && buffer) { /* Get the position */ memcpy(position, buffer, sizeof(uint64_t)); *position = le64toh(*position); } free(buffer); afc_unlock(client); return ret; }
afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t operation) { uint32_t bytes = 0; struct { uint64_t handle; uint64_t op; } lockinfo; afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || (handle == 0)) return AFC_E_INVALID_ARG; afc_lock(client); debug_info("file handle %i", handle); /* Send command */ lockinfo.handle = handle; lockinfo.op = htole64(operation); ret = afc_dispatch_packet(client, AFC_OP_FILE_LOCK, (const char*)&lockinfo, sizeof(lockinfo), NULL, 0, &bytes); if (ret != AFC_E_SUCCESS) { afc_unlock(client); debug_info("could not send lock command"); return AFC_E_UNKNOWN_ERROR; } /* Receive the response */ ret = afc_receive_data(client, NULL, &bytes); afc_unlock(client); return ret; }
afc_error_t afc_file_close(afc_client_t client, uint64_t handle) { uint32_t bytes = 0; afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || (handle == 0)) return AFC_E_INVALID_ARG; afc_lock(client); debug_info("File handle %i", handle); /* Send command */ ret = afc_dispatch_packet(client, AFC_OP_FILE_CLOSE, (const char*)&handle, 8, NULL, 0, &bytes); if (ret != AFC_E_SUCCESS) { afc_unlock(client); return AFC_E_UNKNOWN_ERROR; } /* Receive the response */ ret = afc_receive_data(client, NULL, &bytes); afc_unlock(client); return ret; }
idevice_error_t afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t length, uint32_t *bytes_written) { uint32_t current_count = 0; uint32_t bytes_loc = 0; afc_error_t ret = AFC_E_SUCCESS; if (!client || !client->afc_packet || !client->parent || !bytes_written || (handle == 0)) return AFC_E_INVALID_ARG; afc_lock(client); debug_info("Write length: %i", length); ret = afc_dispatch_packet(client, AFC_OP_WRITE, (const char*)&handle, 8, data, length, &bytes_loc); current_count += bytes_loc - (sizeof(AFCPacket) + 8); if (ret != AFC_E_SUCCESS) { afc_unlock(client); *bytes_written = current_count; return AFC_E_SUCCESS; } ret = afc_receive_data(client, NULL, &bytes_loc); afc_unlock(client); if (ret != AFC_E_SUCCESS) { debug_info("uh oh?"); } *bytes_written = current_count; return ret; }
/** Renames a file or directory on the phone. * * @param client The client to have rename. * @param from The name to rename from. (must be a fully-qualified path) * @param to The new name. (must also be a fully-qualified path) * * @return AFC_E_SUCCESS if everythong went well, AFC_E_INVALID_ARGUMENT * if arguments are NULL or invalid, AFC_E_NOT_ENOUGH_DATA otherwise. */ afc_error_t afc_rename_path(afc_client_t client, const char *from, const char *to) { char *response = NULL; char *send = (char *) malloc(sizeof(char) * (strlen(from) + strlen(to) + 1 + sizeof(uint32_t))); int bytes = 0; afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || !from || !to || !client->afc_packet || !client->connection) return AFC_E_INVALID_ARGUMENT; afc_lock(client); // Send command memcpy(send, from, strlen(from) + 1); memcpy(send + strlen(from) + 1, to, strlen(to) + 1); client->afc_packet->entire_length = client->afc_packet->this_length = 0; client->afc_packet->operation = AFC_OP_RENAME_PATH; bytes = afc_dispatch_packet(client, send, strlen(to)+1 + strlen(from)+1); free(send); if (bytes <= 0) { afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } // Receive response ret = afc_receive_data(client, &response, &bytes); if (response) free(response); afc_unlock(client); return ret; }
/** * Closes a file on the device. * * @param client The client to close the file with. * @param handle File handle of a previously opened file. */ afc_error_t afc_file_close(afc_client_t client, uint64_t handle) { char *buffer = (char *)malloc(sizeof(char) * 8); uint32_t bytes = 0; afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || (handle == 0)) return AFC_E_INVALID_ARG; afc_lock(client); debug_info("File handle %i", handle); /* Send command */ memcpy(buffer, &handle, sizeof(uint64_t)); client->afc_packet->operation = AFC_OP_FILE_CLOSE; client->afc_packet->entire_length = client->afc_packet->this_length = 0; ret = afc_dispatch_packet(client, buffer, 8, &bytes); free(buffer); buffer = NULL; if (ret != AFC_E_SUCCESS) { afc_unlock(client); return AFC_E_UNKNOWN_ERROR; } /* Receive the response */ ret = afc_receive_data(client, &buffer, &bytes); if (buffer) free(buffer); afc_unlock(client); return ret; }
/** Deletes a file or directory. * * @param client The client to use. * @param path The path to delete. (must be a fully-qualified path) * * @return AFC_E_SUCCESS if everythong went well, AFC_E_INVALID_ARGUMENT * if arguments are NULL or invalid, AFC_E_NOT_ENOUGH_DATA otherwise. */ afc_error_t afc_remove_path(afc_client_t client, const char *path) { char *response = NULL; int bytes; afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || !path || !client->afc_packet || !client->connection) return AFC_E_INVALID_ARGUMENT; afc_lock(client); // Send command client->afc_packet->this_length = client->afc_packet->entire_length = 0; client->afc_packet->operation = AFC_OP_REMOVE_PATH; bytes = afc_dispatch_packet(client, path, strlen(path)+1); if (bytes <= 0) { afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } // Receive response ret = afc_receive_data(client, &response, &bytes); if (response) free(response); /* special case; unknown error actually means directory not empty */ if (ret == AFC_E_UNKNOWN_ERROR) ret = AFC_E_DIR_NOT_EMPTY; afc_unlock(client); return ret; }
/** Sets the size of a file on the phone. * * @param client The client to use to set the file size. * @param handle File handle of a previously opened file. * @param newsize The size to set the file to. * * @return 0 on success, -1 on failure. * * @note This function is more akin to ftruncate than truncate, and truncate * calls would have to open the file before calling this, sadly. */ afc_error_t afc_file_truncate(afc_client_t client, uint64_t handle, uint64_t newsize) { char *buffer = (char *) malloc(sizeof(char) * 16); int bytes = 0; afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || (handle == 0)) return AFC_E_INVALID_ARGUMENT; afc_lock(client); // Send command memcpy(buffer, &handle, sizeof(uint64_t)); // handle memcpy(buffer + 8, &newsize, sizeof(uint64_t)); // newsize client->afc_packet->operation = AFC_OP_FILE_SET_SIZE; client->afc_packet->this_length = client->afc_packet->entire_length = 0; bytes = afc_dispatch_packet(client, buffer, 16); free(buffer); buffer = NULL; if (bytes <= 0) { afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } // Receive response ret = afc_receive_data(client, &buffer, &bytes); if (buffer) free(buffer); afc_unlock(client); return ret; }
afc_error_t afc_read_directory(afc_client_t client, const char *dir, char ***list) { uint32_t bytes = 0; char *data = NULL, **list_loc = NULL; afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || !dir || !list || (list && *list)) return AFC_E_INVALID_ARG; afc_lock(client); /* Send the command */ ret = afc_dispatch_packet(client, AFC_OP_READ_DIR, dir, strlen(dir)+1, NULL, 0, &bytes); if (ret != AFC_E_SUCCESS) { afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } /* Receive the data */ ret = afc_receive_data(client, &data, &bytes); if (ret != AFC_E_SUCCESS) { if (data) free(data); afc_unlock(client); return ret; } /* Parse the data */ list_loc = make_strings_list(data, bytes); if (data) free(data); afc_unlock(client); *list = list_loc; return ret; }
/** Sets the size of a file on the phone without prior opening it. * * @param client The client to use to set the file size. * @param path The path of the file to be truncated. * @param newsize The size to set the file to. * * @return AFC_E_SUCCESS if everything went well, AFC_E_INVALID_ARGUMENT * if arguments are NULL or invalid, AFC_E_NOT_ENOUGH_DATA otherwise. */ afc_error_t afc_truncate(afc_client_t client, const char *path, off_t newsize) { char *response = NULL; char *send = (char *) malloc(sizeof(char) * (strlen(path) + 1 + 8)); int bytes = 0; uint64_t size_requested = newsize; afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || !path || !client->afc_packet || !client->connection) return AFC_E_INVALID_ARGUMENT; afc_lock(client); // Send command memcpy(send, &size_requested, 8); memcpy(send + 8, path, strlen(path) + 1); client->afc_packet->entire_length = client->afc_packet->this_length = 0; client->afc_packet->operation = AFC_OP_TRUNCATE; bytes = afc_dispatch_packet(client, send, 8 + strlen(path) + 1); free(send); if (bytes <= 0) { afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } // Receive response ret = afc_receive_data(client, &response, &bytes); if (response) free(response); afc_unlock(client); return ret; }
/** * Gets information about a specific file. * * @param client The client to use to get the information of the file. * @param path The fully-qualified path to the file. * @param infolist Pointer to a buffer that will be filled with a NULL-terminated * list of strings with the file information. * Set to NULL before calling this function. * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***infolist) { char *received = NULL; uint32_t bytes = 0; afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || !path || !infolist) return AFC_E_INVALID_ARG; afc_lock(client); /* Send command */ client->afc_packet->operation = AFC_OP_GET_FILE_INFO; client->afc_packet->entire_length = client->afc_packet->this_length = 0; ret = afc_dispatch_packet(client, path, strlen(path)+1, &bytes); if (ret != AFC_E_SUCCESS) { afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } /* Receive data */ ret = afc_receive_data(client, &received, &bytes); if (received) { *infolist = make_strings_list(received, bytes); free(received); } afc_unlock(client); return ret; }
/** * Sets the modification time of a file on the device. * * @param client The client to use to set the file size. * @param path Path of the file for which the modification time should be set. * @param mtime The modification time to set in nanoseconds since epoch. * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ afc_error_t afc_set_file_time(afc_client_t client, const char *path, uint64_t mtime) { char *response = NULL; char *send = (char *) malloc(sizeof(char) * (strlen(path) + 1 + 8)); uint32_t bytes = 0; uint64_t mtime_loc = htole64(mtime); afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || !path || !client->afc_packet || !client->parent) return AFC_E_INVALID_ARG; afc_lock(client); /* Send command */ memcpy(send, &mtime_loc, 8); memcpy(send + 8, path, strlen(path) + 1); client->afc_packet->entire_length = client->afc_packet->this_length = 0; client->afc_packet->operation = AFC_OP_SET_FILE_TIME; ret = afc_dispatch_packet(client, send, 8 + strlen(path) + 1, &bytes); free(send); if (ret != AFC_E_SUCCESS) { afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } /* Receive response */ ret = afc_receive_data(client, &response, &bytes); if (response) free(response); afc_unlock(client); return ret; }
/** * Sets the size of a file on the device. * * @param client The client to use to set the file size. * @param handle File handle of a previously opened file. * @param newsize The size to set the file to. * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. * * @note This function is more akin to ftruncate than truncate, and truncate * calls would have to open the file before calling this, sadly. */ afc_error_t afc_file_truncate(afc_client_t client, uint64_t handle, uint64_t newsize) { char *buffer = (char *) malloc(sizeof(char) * 16); uint32_t bytes = 0; uint64_t newsize_loc = htole64(newsize); afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || (handle == 0)) return AFC_E_INVALID_ARG; afc_lock(client); /* Send command */ memcpy(buffer, &handle, sizeof(uint64_t)); /* handle */ memcpy(buffer + 8, &newsize_loc, sizeof(uint64_t)); /* newsize */ client->afc_packet->operation = AFC_OP_FILE_SET_SIZE; client->afc_packet->this_length = client->afc_packet->entire_length = 0; ret = afc_dispatch_packet(client, buffer, 16, &bytes); free(buffer); buffer = NULL; if (ret != AFC_E_SUCCESS) { afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } /* Receive response */ ret = afc_receive_data(client, &buffer, &bytes); if (buffer) free(buffer); afc_unlock(client); return ret; }
/** Closes a file on the phone. * * @param client The client to close the file with. * @param handle File handle of a previously opened file. */ afc_error_t afc_file_close(afc_client_t client, uint64_t handle) { char *buffer = malloc(sizeof(char) * 8); int bytes = 0; afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || (handle == 0)) return AFC_E_INVALID_ARGUMENT; afc_lock(client); log_debug_msg("%s: File handle %i\n", __func__, handle); // Send command memcpy(buffer, &handle, sizeof(uint64_t)); client->afc_packet->operation = AFC_OP_FILE_CLOSE; client->afc_packet->entire_length = client->afc_packet->this_length = 0; bytes = afc_dispatch_packet(client, buffer, 8); free(buffer); buffer = NULL; if (bytes <= 0) { afc_unlock(client); return AFC_E_UNKNOWN_ERROR; } // Receive the response ret = afc_receive_data(client, &buffer, &bytes); if (buffer) free(buffer); afc_unlock(client); return ret; }
idevice_error_t afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length, uint32_t *bytes_read) { char *input = NULL; uint32_t current_count = 0, bytes_loc = 0; afc_error_t ret = AFC_E_SUCCESS; if (!client || !client->afc_packet || !client->parent || handle == 0) return AFC_E_INVALID_ARG; debug_info("called for length %i", length); afc_lock(client); /* Send the read command */ struct { uint64_t handle; uint64_t size; } readinfo; readinfo.handle = handle; readinfo.size = htole64(length); ret = afc_dispatch_packet(client, AFC_OP_READ, (const char*)&readinfo, sizeof(readinfo), NULL, 0, &bytes_loc); if (ret != AFC_E_SUCCESS) { afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } /* Receive the data */ ret = afc_receive_data(client, &input, &bytes_loc); debug_info("afc_receive_data returned error: %d", ret); debug_info("bytes returned: %i", bytes_loc); if (ret != AFC_E_SUCCESS) { afc_unlock(client); return ret; } else if (bytes_loc == 0) { if (input) free(input); afc_unlock(client); *bytes_read = current_count; /* FIXME: check that's actually a success */ return ret; } else { if (input) { debug_info("%d", bytes_loc); memcpy(data + current_count, input, (bytes_loc > length) ? length : bytes_loc); free(input); input = NULL; current_count += (bytes_loc > length) ? length : bytes_loc; } } afc_unlock(client); *bytes_read = current_count; return ret; }
/** Opens a file on the phone. * * @param client The client to use to open the file. * @param filename The file to open. (must be a fully-qualified path) * @param file_mode The mode to use to open the file. Can be AFC_FILE_READ or * AFC_FILE_WRITE; the former lets you read and write, * however, and the second one will *create* the file, * destroying anything previously there. * @param handle Pointer to a uint64_t that will hold the handle of the file * * @return AFC_E_SUCCESS on success or an AFC_E_* error on failure. */ iphone_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle) { uint32_t ag = 0; int bytes = 0; char *data = (char *) malloc(sizeof(char) * (8 + strlen(filename) + 1)); afc_error_t ret = AFC_E_UNKNOWN_ERROR; // set handle to 0 so in case an error occurs, the handle is invalid *handle = 0; if (!client || !client->connection || !client->afc_packet) return AFC_E_INVALID_ARGUMENT; afc_lock(client); // Send command memcpy(data, &file_mode, 4); memcpy(data + 4, &ag, 4); memcpy(data + 8, filename, strlen(filename)); data[8 + strlen(filename)] = '\0'; client->afc_packet->operation = AFC_OP_FILE_OPEN; client->afc_packet->entire_length = client->afc_packet->this_length = 0; bytes = afc_dispatch_packet(client, data, 8 + strlen(filename) + 1); free(data); if (bytes <= 0) { log_debug_msg("%s: Didn't receive a response to the command\n", __func__); afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } // Receive the data ret = afc_receive_data(client, &data, &bytes); if ((ret == AFC_E_SUCCESS) && (bytes > 0) && data) { afc_unlock(client); // Get the file handle memcpy(handle, data, sizeof(uint64_t)); free(data); return ret; } log_debug_msg("%s: Didn't get any further data\n", __func__); afc_unlock(client); return ret; }
idevice_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle) { if (!client || !client->parent || !client->afc_packet) return AFC_E_INVALID_ARG; uint64_t file_mode_loc = htole64(file_mode); uint32_t bytes = 0; char *data = (char *) malloc(sizeof(char) * (8 + strlen(filename) + 1)); afc_error_t ret = AFC_E_UNKNOWN_ERROR; /* set handle to 0 so in case an error occurs, the handle is invalid */ *handle = 0; afc_lock(client); /* Send command */ memcpy(data, &file_mode_loc, 8); memcpy(data + 8, filename, strlen(filename)); data[8 + strlen(filename)] = '\0'; ret = afc_dispatch_packet(client, AFC_OP_FILE_OPEN, data, 8 + strlen(filename) + 1, NULL, 0, &bytes); free(data); if (ret != AFC_E_SUCCESS) { debug_info("Didn't receive a response to the command"); afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } /* Receive the data */ data = NULL; ret = afc_receive_data(client, &data, &bytes); if ((ret == AFC_E_SUCCESS) && (bytes > 0) && data) { afc_unlock(client); /* Get the file handle */ memcpy(handle, data, sizeof(uint64_t)); free(data); return ret; } /* in case memory was allocated but no data received or an error occurred */ free(data); debug_info("Didn't get any further data"); afc_unlock(client); return ret; }
/** * Locks or unlocks a file on the device. * * makes use of flock on the device, see * http://developer.apple.com/documentation/Darwin/Reference/ManPages/man2/flock.2.html * * @param client The client to lock the file with. * @param handle File handle of a previously opened file. * @param operation the lock or unlock operation to perform, this is one of * AFC_LOCK_SH (shared lock), AFC_LOCK_EX (exclusive lock), * or AFC_LOCK_UN (unlock). */ afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t operation) { char *buffer = (char *)malloc(16); uint32_t bytes = 0; uint64_t op = htole64(operation); afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || (handle == 0)) return AFC_E_INVALID_ARG; afc_lock(client); debug_info("file handle %i", handle); /* Send command */ memcpy(buffer, &handle, sizeof(uint64_t)); memcpy(buffer + 8, &op, 8); client->afc_packet->operation = AFC_OP_FILE_LOCK; client->afc_packet->entire_length = client->afc_packet->this_length = 0; ret = afc_dispatch_packet(client, buffer, 16, &bytes); free(buffer); buffer = NULL; if (ret != AFC_E_SUCCESS) { afc_unlock(client); debug_info("could not send lock command"); return AFC_E_UNKNOWN_ERROR; } /* Receive the response */ ret = afc_receive_data(client, &buffer, &bytes); if (buffer) { debug_buffer(buffer, bytes); free(buffer); } afc_unlock(client); return ret; }
/** Locks or unlocks a file on the phone. * * makes use of flock on the device, see * http://developer.apple.com/documentation/Darwin/Reference/ManPages/man2/flock.2.html * * @param client The client to lock the file with. * @param handle File handle of a previously opened file. * @param operation the lock or unlock operation to perform, this is one of * AFC_LOCK_SH (shared lock), AFC_LOCK_EX (exclusive lock), * or AFC_LOCK_UN (unlock). */ afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t operation) { char *buffer = malloc(16); int bytes = 0; uint64_t op = operation; afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || (handle == 0)) return AFC_E_INVALID_ARGUMENT; afc_lock(client); log_debug_msg("%s: file handle %i\n", __func__, handle); // Send command memcpy(buffer, &handle, sizeof(uint64_t)); memcpy(buffer + 8, &op, 8); client->afc_packet->operation = AFC_OP_FILE_LOCK; client->afc_packet->entire_length = client->afc_packet->this_length = 0; bytes = afc_dispatch_packet(client, buffer, 16); free(buffer); buffer = NULL; if (bytes <= 0) { afc_unlock(client); log_debug_msg("%s: could not send lock command\n", __func__); return AFC_E_UNKNOWN_ERROR; } // Receive the response ret = afc_receive_data(client, &buffer, &bytes); if (buffer) { log_debug_buffer(buffer, bytes); free(buffer); } afc_unlock(client); return ret; }
/** * Returns current position in a pre-opened file on the device. * * @param client The client to use. * @param handle File handle of a previously opened file. * @param position Position in bytes of indicator * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ afc_error_t afc_file_tell(afc_client_t client, uint64_t handle, uint64_t *position) { char *buffer = (char *) malloc(sizeof(char) * 8); uint32_t bytes = 0; afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || (handle == 0)) return AFC_E_INVALID_ARG; afc_lock(client); /* Send the command */ memcpy(buffer, &handle, sizeof(uint64_t)); /* handle */ client->afc_packet->operation = AFC_OP_FILE_TELL; client->afc_packet->this_length = client->afc_packet->entire_length = 0; ret = afc_dispatch_packet(client, buffer, 8, &bytes); free(buffer); buffer = NULL; if (ret != AFC_E_SUCCESS) { afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } /* Receive the data */ ret = afc_receive_data(client, &buffer, &bytes); if (bytes > 0 && buffer) { /* Get the position */ memcpy(position, buffer, sizeof(uint64_t)); *position = le64toh(*position); } if (buffer) free(buffer); afc_unlock(client); return ret; }
/** * Creates a hard link or symbolic link on the device. * * @param client The client to use for making a link * @param linktype 1 = hard link, 2 = symlink * @param target The file to be linked. * @param linkname The name of link. * * @return AFC_E_SUCCESS on success or an AFC_E_* error value. */ afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, const char *target, const char *linkname) { char *response = NULL; char *send = (char *) malloc(sizeof(char) * (strlen(target)+1 + strlen(linkname)+1 + 8)); uint32_t bytes = 0; uint64_t type = htole64(linktype); afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || !target || !linkname || !client->afc_packet || !client->connection) return AFC_E_INVALID_ARG; afc_lock(client); debug_info("link type: %lld", type); debug_info("target: %s, length:%d", target, strlen(target)); debug_info("linkname: %s, length:%d", linkname, strlen(linkname)); /* Send command */ memcpy(send, &type, 8); memcpy(send + 8, target, strlen(target) + 1); memcpy(send + 8 + strlen(target) + 1, linkname, strlen(linkname) + 1); client->afc_packet->entire_length = client->afc_packet->this_length = 0; client->afc_packet->operation = AFC_OP_MAKE_LINK; ret = afc_dispatch_packet(client, send, 8 + strlen(linkname) + 1 + strlen(target) + 1, &bytes); free(send); if (ret != AFC_E_SUCCESS) { afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } /* Receive response */ ret = afc_receive_data(client, &response, &bytes); if (response) free(response); afc_unlock(client); return ret; }
/** Creates a hard link or symbolic link on the device. * * @param client The client to use for making a link * @param type 1 = hard link, 2 = symlink * @param target The file to be linked. * @param linkname The name of link. * * @return AFC_E_SUCCESS if everything went well, AFC_E_INVALID_ARGUMENT * if arguments are NULL or invalid, AFC_E_NOT_ENOUGH_DATA otherwise. */ afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, const char *target, const char *linkname) { char *response = NULL; char *send = (char *) malloc(sizeof(char) * (strlen(target)+1 + strlen(linkname)+1 + 8)); int bytes = 0; uint64_t type = linktype; afc_error_t ret = AFC_E_UNKNOWN_ERROR; if (!client || !target || !linkname || !client->afc_packet || !client->connection) return AFC_E_INVALID_ARGUMENT; afc_lock(client); log_debug_msg("%s: link type: %lld\n", __func__, type); log_debug_msg("%s: target: %s, length:%d\n", __func__, target, strlen(target)); log_debug_msg("%s: linkname: %s, length:%d\n", __func__, linkname, strlen(linkname)); // Send command memcpy(send, &type, 8); memcpy(send + 8, target, strlen(target) + 1); memcpy(send + 8 + strlen(target) + 1, linkname, strlen(linkname) + 1); client->afc_packet->entire_length = client->afc_packet->this_length = 0; client->afc_packet->operation = AFC_OP_MAKE_LINK; bytes = afc_dispatch_packet(client, send, 8 + strlen(linkname) + 1 + strlen(target) + 1); free(send); if (bytes <= 0) { afc_unlock(client); return AFC_E_NOT_ENOUGH_DATA; } // Receive response ret = afc_receive_data(client, &response, &bytes); if (response) free(response); afc_unlock(client); return ret; }