qb_rb_create_from_file(int32_t fd, uint32_t flags)
{
	ssize_t n_read;
	size_t n_required;
	size_t total_read = 0;
	uint32_t read_pt;
	uint32_t write_pt;
	struct qb_ringbuffer_s *rb;
	uint32_t word_size = 0;
	uint32_t version = 0;
	uint32_t hash = 0;
	uint32_t calculated_hash = 0;

	if (fd < 0) {
		return NULL;
	}

	/*
	 * 1. word size
	 */
	n_required = sizeof(uint32_t);
	n_read = read(fd, &word_size, n_required);
	if (n_read != n_required) {
		qb_util_perror(LOG_ERR, "Unable to read blackbox file header");
		return NULL;
	}
	total_read += n_read;

	/*
	 * 2. 3. read & write pointers
	 */
	n_read = read(fd, &write_pt, sizeof(uint32_t));
	assert(n_read == sizeof(uint32_t));
	total_read += n_read;

	n_read = read(fd, &read_pt, sizeof(uint32_t));
	assert(n_read == sizeof(uint32_t));
	total_read += n_read;

	/*
	 * 4. version
	 */
	n_required = sizeof(uint32_t);
	n_read = read(fd, &version, n_required);
	if (n_read != n_required) {
		qb_util_perror(LOG_ERR, "Unable to read blackbox file header");
		return NULL;
	}
	total_read += n_read;

	/*
	 * 5. Hash
	 */
	n_required = sizeof(uint32_t);
	n_read = read(fd, &hash, n_required);
	if (n_read != n_required) {
		qb_util_perror(LOG_ERR, "Unable to read blackbox file header");
		return NULL;
	}
	total_read += n_read;

	calculated_hash = word_size + write_pt + read_pt + version;
	if (hash != calculated_hash) {
		qb_util_log(LOG_ERR, "Corrupt blackbox: File header hash (%d) does not match calculated hash (%d)", hash, calculated_hash);
		return NULL;
	} else if (version != QB_RB_FILE_HEADER_VERSION) {
		qb_util_log(LOG_ERR, "Wrong file header version. Expected %d got %d",
			QB_RB_FILE_HEADER_VERSION, version);
		return NULL;
	}

	/*
	 * 6. data
	 */
	n_required = (word_size * sizeof(uint32_t));

	/*
	 * qb_rb_open adds QB_RB_CHUNK_MARGIN + 1 to the requested size.
	 */
	rb = qb_rb_open("create_from_file", n_required - (QB_RB_CHUNK_MARGIN + 1),
			QB_RB_FLAG_CREATE | QB_RB_FLAG_NO_SEMAPHORE, 0);
	if (rb == NULL) {
		return NULL;
	}
	rb->shared_hdr->read_pt = read_pt;
	rb->shared_hdr->write_pt = write_pt;

	n_read = read(fd, rb->shared_data, n_required);
	if (n_read < 0) {
		qb_util_perror(LOG_ERR, "Unable to read blackbox file data");
		goto cleanup_fail;
	}
	total_read += n_read;

	if (n_read != n_required) {
		qb_util_log(LOG_WARNING, "read %zd bytes, but expected %zu",
			    n_read, n_required);
		goto cleanup_fail;
	}

	qb_util_log(LOG_DEBUG, "read total of: %zd", total_read);
	print_header(rb);

	return rb;

cleanup_fail:
	qb_rb_close(rb);
	return NULL;
}
qb_rb_create_from_file(int32_t fd, uint32_t flags)
{
	ssize_t n_read;
	size_t n_required;
	size_t total_read = 0;
	uint32_t read_pt;
	uint32_t write_pt;
	struct qb_ringbuffer_s *rb;
	uint32_t word_size = 0;
	uint32_t version = 0;
	uint32_t hash = 0;
	uint32_t calculated_hash = 0;

	if (fd < 0) {
		return NULL;
	}

	 
	n_required = sizeof(uint32_t);
	n_read = read(fd, &word_size, n_required);
	if (n_read != n_required) {
		qb_util_perror(LOG_ERR, "Unable to read blackbox file header");
		return NULL;
	}
	total_read += n_read;

	 
	n_read = read(fd, &write_pt, sizeof(uint32_t));
	assert(n_read == sizeof(uint32_t));
	total_read += n_read;

	n_read = read(fd, &read_pt, sizeof(uint32_t));
	assert(n_read == sizeof(uint32_t));
	total_read += n_read;

	 
	n_required = sizeof(uint32_t);
	n_read = read(fd, &version, n_required);
	if (n_read != n_required) {
		qb_util_perror(LOG_ERR, "Unable to read blackbox file header");
		return NULL;
	}
	total_read += n_read;

	 
	n_required = sizeof(uint32_t);
	n_read = read(fd, &hash, n_required);
	if (n_read != n_required) {
		qb_util_perror(LOG_ERR, "Unable to read blackbox file header");
		return NULL;
	}
	total_read += n_read;

	calculated_hash = word_size + write_pt + read_pt + version;
	if (hash != calculated_hash) {
		qb_util_log(LOG_ERR, "Corrupt blackbox: File header hash (%d) does not match calculated hash (%d)", hash, calculated_hash);
		return NULL;
	} else if (version != QB_RB_FILE_HEADER_VERSION) {
		qb_util_log(LOG_ERR, "Wrong file header version. Expected %d got %d",
			QB_RB_FILE_HEADER_VERSION, version);
		return NULL;
	}

	 
	n_required = (word_size * sizeof(uint32_t));

	 
	rb = qb_rb_open("create_from_file", n_required - (QB_RB_CHUNK_MARGIN + 1),
			QB_RB_FLAG_CREATE | QB_RB_FLAG_NO_SEMAPHORE, 0);
	if (rb == NULL) {
		return NULL;
	}
	rb->shared_hdr->read_pt = read_pt;
	rb->shared_hdr->write_pt = write_pt;

	n_read = read(fd, rb->shared_data, n_required);
	if (n_read < 0) {
		qb_util_perror(LOG_ERR, "Unable to read blackbox file data");
		goto cleanup_fail;
	}
	total_read += n_read;

	if (n_read != n_required) {
		qb_util_log(LOG_WARNING, "read %zd bytes, but expected %zu",
			    n_read, n_required);
		goto cleanup_fail;
	}

	qb_util_log(LOG_DEBUG, "read total of: %zd", total_read);
	print_header(rb);

	return rb;

cleanup_fail:
	qb_rb_close(rb);
	return NULL;
}