/* Reads the log header, and subsequent descriptors (if any). This * will allocate all the space for buffer, which must be NULL when * passed into this function. Each descriptor will also be validated, * and error returned if any are invalid. */ static int vhdx_log_read_desc(BlockDriverState *bs, BDRVVHDXState *s, VHDXLogEntries *log, VHDXLogDescEntries **buffer) { int ret = 0; uint32_t desc_sectors; uint32_t sectors_read; VHDXLogEntryHeader hdr; VHDXLogDescEntries *desc_entries = NULL; int i; assert(*buffer == NULL); ret = vhdx_log_peek_hdr(bs, log, &hdr); if (ret < 0) { goto exit; } vhdx_log_entry_hdr_le_import(&hdr); if (vhdx_log_hdr_is_valid(log, &hdr, s) == false) { ret = -EINVAL; goto exit; } desc_sectors = vhdx_compute_desc_sectors(hdr.descriptor_count); desc_entries = qemu_blockalign(bs, desc_sectors * VHDX_LOG_SECTOR_SIZE); ret = vhdx_log_read_sectors(bs, log, §ors_read, desc_entries, desc_sectors, false); if (ret < 0) { goto free_and_exit; } if (sectors_read != desc_sectors) { ret = -EINVAL; goto free_and_exit; } /* put in proper endianness, and validate each desc */ for (i = 0; i < hdr.descriptor_count; i++) { vhdx_log_desc_le_import(&desc_entries->desc[i]); if (vhdx_log_desc_is_valid(&desc_entries->desc[i], &hdr) == false) { ret = -EINVAL; goto free_and_exit; } } *buffer = desc_entries; goto exit; free_and_exit: qemu_vfree(desc_entries); exit: return ret; }
/* Allow peeking at the hdr entry at the beginning of the current * read index, without advancing the read index */ static int vhdx_log_peek_hdr(BlockDriverState *bs, VHDXLogEntries *log, VHDXLogEntryHeader *hdr) { int ret = 0; uint64_t offset; uint32_t read; assert(hdr != NULL); /* peek is only supported on sector boundaries */ if (log->read % VHDX_LOG_SECTOR_SIZE) { ret = -EFAULT; goto exit; } read = log->read; /* we are guaranteed that a) log sectors are 4096 bytes, * and b) the log length is a multiple of 1MB. So, there * is always a round number of sectors in the buffer */ if ((read + sizeof(VHDXLogEntryHeader)) > log->length) { read = 0; } if (read == log->write) { ret = -EINVAL; goto exit; } offset = log->offset + read; ret = bdrv_pread(bs->file->bs, offset, hdr, sizeof(VHDXLogEntryHeader)); if (ret < 0) { goto exit; } vhdx_log_entry_hdr_le_import(hdr); exit: return ret; }