Example #1
0
/**
 * Seeks to a given position of a pre-opened file on the device. 
 * 
 * @param client The client to use to seek to the position.
 * @param handle File handle of a previously opened.
 * @param offset Seek offset.
 * @param whence Seeking direction, one of SEEK_SET, SEEK_CUR, or SEEK_END.
 * 
 * @return AFC_E_SUCCESS on success or an AFC_E_* error value.
 */
afc_error_t afc_file_seek(afc_client_t client, uint64_t handle, int64_t offset, int whence)
{
	char *buffer = (char *) malloc(sizeof(char) * 24);
	int64_t offset_loc = (int64_t)htole64(offset);
	uint64_t whence_loc = htole64(whence);
	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 */
	memcpy(buffer + 8, &whence_loc, sizeof(uint64_t));	/* fromwhere */
	memcpy(buffer + 16, &offset_loc, sizeof(uint64_t));	/* offset */
	client->afc_packet->operation = AFC_OP_FILE_SEEK;
	client->afc_packet->this_length = client->afc_packet->entire_length = 0;
	ret = afc_dispatch_packet(client, buffer, 24, &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;
}
/**
 * Get device information for a connected client. The device information
 * returned is the device model as well as the free space, the total capacity
 * and blocksize on the accessed disk partition.
 * 
 * @param client The client to get device info for.
 * @param infos A char ** list of parameters as given by AFC or NULL if there
 *  was an error.
 * 
 * @return AFC_E_SUCCESS on success or an AFC_E_* error value.
 */
afc_error_t afc_get_device_info(afc_client_t client, char ***infos)
{
	uint32_t bytes = 0;
	char *data = NULL, **list = NULL;
	afc_error_t ret = AFC_E_UNKNOWN_ERROR;

	if (!client || !infos)
		return AFC_E_INVALID_ARG;

	afc_lock(client);

	/* Send the command */
	client->afc_packet->operation = AFC_OP_GET_DEVINFO;
	client->afc_packet->entire_length = client->afc_packet->this_length = 0;
	ret = afc_dispatch_packet(client, 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) {
		afc_unlock(client);
		return ret;
	}
	/* Parse the data */
	list = make_strings_list(data, bytes);
	if (data)
		free(data);

	afc_unlock(client);

	*infos = list;

	return ret;
}
/**
 * Gets a directory listing of the directory requested.
 * 
 * @param client The client to get a directory listing from.
 * @param dir The directory to list. (must be a fully-qualified path)
 * @param list A char list of files in that directory, terminated by an empty
 *         string or NULL if there was an error.
 * 
 * @return AFC_E_SUCCESS on success or an AFC_E_* error value.
 */
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 */
	client->afc_packet->operation = AFC_OP_READ_DIR;
	client->afc_packet->entire_length = 0;
	client->afc_packet->this_length = 0;
	ret = afc_dispatch_packet(client, dir, strlen(dir)+1, &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) {
		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;
}
Example #4
0
/** Writes a given number of bytes to a file.
 * 
 * @param client The client to use to write to the file.
 * @param handle File handle of previously opened file. 
 * @param data The data to write to the file.
 * @param length How much data to write.
 * 
 * @return The number of bytes written to the file, or a value less than 0 if
 *         none were written...
 */
iphone_error_t
afc_file_write(afc_client_t client, uint64_t handle,
					  const char *data, int length, uint32_t * bytes)
{
	char *acknowledgement = NULL;
	const int MAXIMUM_WRITE_SIZE = 1 << 15;
	uint32_t zero = 0, current_count = 0, i = 0;
	uint32_t segments = (length / MAXIMUM_WRITE_SIZE);
	int bytes_loc = 0;
	char *out_buffer = NULL;
	afc_error_t ret = AFC_E_SUCCESS;

	if (!client || !client->afc_packet || !client->connection || !bytes || (handle == 0))
		return AFC_E_INVALID_ARGUMENT;

	afc_lock(client);

	log_debug_msg("%s: Write length: %i\n", __func__, length);

	// Divide the file into segments.
	for (i = 0; i < segments; i++) {
		// Send the segment
		client->afc_packet->this_length = sizeof(AFCPacket) + 8;
		client->afc_packet->entire_length = client->afc_packet->this_length + MAXIMUM_WRITE_SIZE;
		client->afc_packet->operation = AFC_OP_WRITE;
		out_buffer = (char *) malloc(sizeof(char) * client->afc_packet->entire_length - sizeof(AFCPacket));
		memcpy(out_buffer, (char *)&handle, sizeof(uint64_t));
		memcpy(out_buffer + 8, data + current_count, MAXIMUM_WRITE_SIZE);
		bytes_loc = afc_dispatch_packet(client, out_buffer, MAXIMUM_WRITE_SIZE + 8);
		if (bytes_loc < 0) {
			afc_unlock(client);
			return AFC_E_NOT_ENOUGH_DATA;
		}
		free(out_buffer);
		out_buffer = NULL;

		current_count += bytes_loc;
		ret = afc_receive_data(client, &acknowledgement, &bytes_loc);
		if (ret != AFC_E_SUCCESS) {
			afc_unlock(client);
			return ret;
		} else {
			free(acknowledgement);
		}
	}

	// By this point, we should be at the end. i.e. the last segment that
	// didn't get sent in the for loop
	// this length is fine because it's always sizeof(AFCPacket) + 8, but
	// to be sure we do it again
	if (current_count == (uint32_t)length) {
		afc_unlock(client);
		*bytes = current_count;
		return ret;
	}

	client->afc_packet->this_length = sizeof(AFCPacket) + 8;
	client->afc_packet->entire_length = client->afc_packet->this_length + (length - current_count);
	client->afc_packet->operation = AFC_OP_WRITE;
	out_buffer = (char *) malloc(sizeof(char) * client->afc_packet->entire_length - sizeof(AFCPacket));
	memcpy(out_buffer, (char *) &handle, sizeof(uint64_t));
	memcpy(out_buffer + 8, data + current_count, (length - current_count));
	bytes_loc = afc_dispatch_packet(client, out_buffer, (length - current_count) + 8);
	free(out_buffer);
	out_buffer = NULL;

	current_count += bytes_loc;

	if (bytes_loc <= 0) {
		afc_unlock(client);
		*bytes = current_count;
		return AFC_E_SUCCESS;
	}

	zero = bytes_loc;
	ret = afc_receive_data(client, &acknowledgement, &bytes_loc);
	afc_unlock(client);
	if (ret != AFC_E_SUCCESS) {
		log_debug_msg("%s: uh oh?\n", __func__);
	} else {
		free(acknowledgement);
	}
	*bytes = current_count;
	return ret;
}
Example #5
0
/** Attempts to the read the given number of bytes from the given file.
 * 
 * @param client The relevant AFC client
 * @param handle File handle of a previously opened file
 * @param data The pointer to the memory region to store the read data
 * @param length The number of bytes to read
 *
 * @return The number of bytes read if successful. If there was an error -1.
 */
iphone_error_t
afc_file_read(afc_client_t client, uint64_t handle, char *data, int length, uint32_t * bytes)
{
	char *input = NULL;
	int current_count = 0, bytes_loc = 0;
	const int MAXIMUM_READ_SIZE = 1 << 16;
	afc_error_t ret = AFC_E_SUCCESS;

	if (!client || !client->afc_packet || !client->connection || handle == 0)
		return AFC_E_INVALID_ARGUMENT;
	log_debug_msg("%s: called for length %i\n", __func__, length);

	afc_lock(client);

	// Looping here to get around the maximum amount of data that
	// afc_receive_data can handle
	while (current_count < length) {
		log_debug_msg("%s: current count is %i but length is %i\n", __func__, current_count, length);

		// Send the read command
		AFCFilePacket *packet = (AFCFilePacket *) malloc(sizeof(AFCFilePacket));
		packet->filehandle = handle;
		packet->size = ((length - current_count) < MAXIMUM_READ_SIZE) ? (length - current_count) : MAXIMUM_READ_SIZE;
		client->afc_packet->operation = AFC_OP_READ;
		client->afc_packet->entire_length = client->afc_packet->this_length = 0;
		bytes_loc = afc_dispatch_packet(client, (char *) packet, sizeof(AFCFilePacket));
		free(packet);

		if (bytes_loc <= 0) {
			afc_unlock(client);
			return AFC_E_NOT_ENOUGH_DATA;
		}
		// Receive the data
		ret = afc_receive_data(client, &input, &bytes_loc);
		log_debug_msg("%s: afc_receive_data returned error: %d\n", __func__, ret);
		log_debug_msg("%s: bytes returned: %i\n", __func__, 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 = current_count;
			/* FIXME: check that's actually a success */
			return ret;
		} else {
			if (input) {
				log_debug_msg("%s: %d\n", __func__, 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;
			}
		}
	}
	log_debug_msg("%s: returning current_count as %i\n", __func__, current_count);

	afc_unlock(client);
	*bytes = current_count;
	return ret;
}
Example #6
0
/**
 * Writes a given number of bytes to a file.
 * 
 * @param client The client to use to write to the file.
 * @param handle File handle of previously opened file. 
 * @param data The data to write to the file.
 * @param length How much data to write.
 * @param bytes_written The number of bytes actually written to the file.
 * 
 * @return AFC_E_SUCCESS on success or an AFC_E_* error value.
 */
idevice_error_t
afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t length, uint32_t *bytes_written)
{
	char *acknowledgement = NULL;
	const uint32_t MAXIMUM_WRITE_SIZE = 1 << 15;
	uint32_t current_count = 0, i = 0;
	uint32_t segments = (length / MAXIMUM_WRITE_SIZE);
	uint32_t bytes_loc = 0;
	char *out_buffer = NULL;
	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);

	/* Divide the file into segments. */
	for (i = 0; i < segments; i++) {
		/* Send the segment */
		client->afc_packet->this_length = sizeof(AFCPacket) + 8;
		client->afc_packet->entire_length = client->afc_packet->this_length + MAXIMUM_WRITE_SIZE;
		client->afc_packet->operation = AFC_OP_WRITE;
		out_buffer = (char *) malloc(size_t(sizeof(char) * client->afc_packet->entire_length - sizeof(AFCPacket)));
		memcpy(out_buffer, (char *)&handle, sizeof(uint64_t));
		memcpy(out_buffer + 8, data + current_count, MAXIMUM_WRITE_SIZE);
		ret = afc_dispatch_packet(client, out_buffer, MAXIMUM_WRITE_SIZE + 8, &bytes_loc);
		if (ret != AFC_E_SUCCESS) {
			afc_unlock(client);
			return AFC_E_NOT_ENOUGH_DATA;
		}
		free(out_buffer);
		out_buffer = NULL;

		current_count += bytes_loc;
		ret = afc_receive_data(client, &acknowledgement, &bytes_loc);
		if (ret != AFC_E_SUCCESS) {
			afc_unlock(client);
			return ret;
		} else {
			free(acknowledgement);
		}
	}

	/* By this point, we should be at the end. i.e. the last segment that didn't
	   get sent in the for loop. This length is fine because it's always
	   sizeof(AFCPacket) + 8, but to be sure we do it again */
	if (current_count == length) {
		afc_unlock(client);
		*bytes_written = current_count;
		return ret;
	}

	client->afc_packet->this_length = sizeof(AFCPacket) + 8;
	client->afc_packet->entire_length = client->afc_packet->this_length + (length - current_count);
	client->afc_packet->operation = AFC_OP_WRITE;
	out_buffer = (char *) malloc(size_t(sizeof(char) * client->afc_packet->entire_length - sizeof(AFCPacket)));
	memcpy(out_buffer, (char *) &handle, sizeof(uint64_t));
	memcpy(out_buffer + 8, data + current_count, (length - current_count));
	ret = afc_dispatch_packet(client, out_buffer, (length - current_count) + 8, &bytes_loc);
	free(out_buffer);
	out_buffer = NULL;

	current_count += bytes_loc;

	if (ret != AFC_E_SUCCESS) {
		afc_unlock(client);
		*bytes_written = current_count;
		return AFC_E_SUCCESS;
	}

	ret = afc_receive_data(client, &acknowledgement, &bytes_loc);
	afc_unlock(client);
	if (ret != AFC_E_SUCCESS) {
		debug_info("uh oh?");
	} else {
		free(acknowledgement);
	}
	*bytes_written = current_count;
	return ret;
}
Example #7
0
/**
 * Attempts to the read the given number of bytes from the given file.
 * 
 * @param client The relevant AFC client
 * @param handle File handle of a previously opened file
 * @param data The pointer to the memory region to store the read data
 * @param length The number of bytes to read
 * @param bytes_read The number of bytes actually read.
 *
 * @return AFC_E_SUCCESS on success or an AFC_E_* error value.
 */
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;
	const uint32_t MAXIMUM_READ_SIZE = 1 << 16;
	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);

	/* Looping here to get around the maximum amount of data that
	   afc_receive_data can handle */
	while (current_count < length) {
		debug_info("current count is %i but length is %i", current_count, length);

		/* Send the read command */
		AFCFilePacket *packet = (AFCFilePacket *) malloc(sizeof(AFCFilePacket));
		packet->filehandle = handle;
		packet->size = htole64(((length - current_count) < MAXIMUM_READ_SIZE) ? (length - current_count) : MAXIMUM_READ_SIZE);
		client->afc_packet->operation = AFC_OP_READ;
		client->afc_packet->entire_length = client->afc_packet->this_length = 0;
		ret = afc_dispatch_packet(client, (char *) packet, sizeof(AFCFilePacket), &bytes_loc);
		free(packet);

		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;
			}
		}
	}
	debug_info("returning current_count as %i", current_count);

	afc_unlock(client);
	*bytes_read = current_count;
	return ret;
}