static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, uint64_t end_offset, void **p_feature_table, Error **errp) { BDRVQcowState *s = bs->opaque; QCowExtension ext; uint64_t offset; int ret; #ifdef DEBUG_EXT printf("qcow2_read_extensions: start=%ld end=%ld\n", start_offset, end_offset); #endif offset = start_offset; while (offset < end_offset) { #ifdef DEBUG_EXT /* Sanity check */ if (offset > s->cluster_size) printf("qcow2_read_extension: suspicious offset %lu\n", offset); printf("attempting to read extended header in offset %lu\n", offset); #endif ret = bdrv_pread(bs->file, offset, &ext, sizeof(ext)); if (ret < 0) { error_setg_errno(errp, -ret, "qcow2_read_extension: ERROR: " "pread fail from offset %" PRIu64, offset); return 1; } be32_to_cpus(&ext.magic); be32_to_cpus(&ext.len); offset += sizeof(ext); #ifdef DEBUG_EXT printf("ext.magic = 0x%x\n", ext.magic); #endif if (ext.len > end_offset - offset) { error_setg(errp, "Header extension too large"); return -EINVAL; } switch (ext.magic) { case QCOW2_EXT_MAGIC_END: return 0; case QCOW2_EXT_MAGIC_BACKING_FORMAT: if (ext.len >= sizeof(bs->backing_format)) { error_setg(errp, "ERROR: ext_backing_format: len=%" PRIu32 " too large (>=%zu)", ext.len, sizeof(bs->backing_format)); return 2; } ret = bdrv_pread(bs->file, offset, bs->backing_format, ext.len); if (ret < 0) { error_setg_errno(errp, -ret, "ERROR: ext_backing_format: " "Could not read format name"); return 3; } bs->backing_format[ext.len] = '\0'; #ifdef DEBUG_EXT printf("Qcow2: Got format extension %s\n", bs->backing_format); #endif break; case QCOW2_EXT_MAGIC_FEATURE_TABLE: if (p_feature_table != NULL) { void* feature_table = g_malloc0(ext.len + 2 * sizeof(Qcow2Feature)); ret = bdrv_pread(bs->file, offset , feature_table, ext.len); if (ret < 0) { error_setg_errno(errp, -ret, "ERROR: ext_feature_table: " "Could not read table"); return ret; } *p_feature_table = feature_table; } break; default: /* unknown magic - save it in case we need to rewrite the header */ { Qcow2UnknownHeaderExtension *uext; uext = g_malloc0(sizeof(*uext) + ext.len); uext->magic = ext.magic; uext->len = ext.len; QLIST_INSERT_HEAD(&s->unknown_header_ext, uext, next); ret = bdrv_pread(bs->file, offset , uext->data, uext->len); if (ret < 0) { error_setg_errno(errp, -ret, "ERROR: unknown extension: " "Could not read data"); return ret; } } break; } offset += ((ext.len + 7) & ~7); } return 0; }