Newer
Older
vvd / src / vdisk / qed.c
#include "vdisk.h"
#include "utils.h"
#include "platform.h"
#include <assert.h>

int vdisk_qed_open(VDISK *vd, uint32_t flags, uint32_t internal) {
	if ((vd->meta = malloc(QED_META_ALLOC)) == NULL)
		return vdisk_i_err(vd, VVD_ENOMEM, __LINE__, __func__);

	if (os_fread(vd->fd, &vd->qed->hdr, sizeof(QED_HDR)))
		return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__);

	if (vd->qed->hdr.cluster_size < QED_CLUSTER_MIN ||
		vd->qed->hdr.cluster_size > QED_CLUSTER_MAX ||
		pow2(vd->qed->hdr.cluster_size) == 0)
		return vdisk_i_err(vd, VVD_EVDMISC, __LINE__, __func__);
	if (vd->qed->hdr.table_size < QED_TABLE_MIN ||
		vd->qed->hdr.table_size > QED_TABLE_MAX ||
		pow2(vd->qed->hdr.table_size) == 0)
		return vdisk_i_err(vd, VVD_EVDMISC, __LINE__, __func__);

	if (vd->qed->hdr.features > QED_FEATS)
		return vdisk_i_err(vd, VVD_EVDMISC, __LINE__, __func__);

	// assert(header.image_size <= TABLE_NOFFSETS * TABLE_NOFFSETS * header.cluster_size)

	uint32_t table_size = vd->qed->in.tablesize =
		vd->qed->hdr.cluster_size * vd->qed->hdr.table_size;
	uint32_t table_entries = vd->qed->in.entries = table_size / sizeof(uint64_t);
	uint32_t clusterbits = fpow2(vd->qed->hdr.cluster_size);
	uint32_t tablebits = fpow2(table_entries);

	if ((vd->qed->in.L1.offsets = malloc(table_size)) == NULL)
		return vdisk_i_err(vd, VVD_ENOMEM, __LINE__, __func__);
	if ((vd->qed->in.L2.offsets = malloc(table_size)) == NULL)
		return vdisk_i_err(vd, VVD_ENOMEM, __LINE__, __func__);
	if (os_fseek(vd->fd, vd->qed->hdr.l1_offset, SEEK_SET))
		return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__);
	if (os_fread(vd->fd, vd->qed->in.L1.offsets, table_size))
		return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__);

	// assert(clusterbits + (2 * tablebits) <= 64);

	vd->qed->in.mask	= vd->qed->hdr.cluster_size - 1;
	vd->qed->in.L2.mask 	= (table_entries - 1) << clusterbits;
	vd->qed->in.L2.shift	= clusterbits;
	vd->qed->in.L1.mask 	= (table_entries - 1) << (clusterbits + tablebits);
	vd->qed->in.L1.mask	= clusterbits + tablebits;

	vd->capacity = vd->qed->hdr.capacity;

	vd->cb.lba_read = vdisk_qed_read_sector;

	return 0;
}

int vdisk_qed_L2_load(VDISK *vd, uint64_t offset) {
	if (vd->qed->in.L2.current == offset) // L2 already loaded
		return 0;

	if (os_fseek(vd->fd, offset, SEEK_SET))
		return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__);
	if (os_fread(vd->fd, vd->qed->in.L2.offsets, vd->qed->in.tablesize))
		return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__);

	vd->qed->in.L2.current = offset;

	return 0;
}

int vdisk_qed_read_sector(VDISK *vd, void *buffer, uint64_t index) {
	uint64_t offset = SECTOR_TO_BYTE(index);

	uint32_t l1 = (offset >> vd->qed->in.L1.shift) & vd->qed->in.L1.mask;
	uint32_t l2 = (offset >> vd->qed->in.L2.shift) & vd->qed->in.L2.mask;

	if (l1 >= vd->qed->in.entries || l2 >= vd->qed->in.entries)
		return vdisk_i_err(vd, VVD_EVDMISC, __LINE__, __func__);
	if (vdisk_qed_L2_load(vd, vd->qed->in.L1.offsets[l1]))
		return vd->err.num;

	offset = (uint64_t)vd->qed->in.L2.offsets[l2] + (offset & vd->qed->in.mask);

	if (os_fseek(vd->fd, offset, SEEK_SET))
		return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__);
	if (os_fread(vd->fd, buffer, 512))
		return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__);

	return 0;
}