+
+/*
+ * read qcow2 extension and fill bs
+ * start reading from start_offset
+ * finish reading upon magic of value 0 or when end_offset reached
+ * unknown magic is skipped (future extension this version knows nothing about)
+ * return 0 upon success, non-0 otherwise
+ */
+static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset,
+ uint64_t end_offset)
+{
+ BDRVQcowState *s = bs->opaque;
+ QCowExtension ext;
+ uint64_t offset;
+
+#ifdef DEBUG_EXT
+ printf("qcow_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("qcow_handle_extension: suspicious offset %lu\n", offset);
+
+ printf("attemting to read extended header in offset %lu\n", offset);
+#endif
+
+ if (bdrv_pread(s->hd, offset, &ext, sizeof(ext)) != sizeof(ext)) {
+ fprintf(stderr, "qcow_handle_extension: ERROR: pread fail from offset %llu\n",
+ (unsigned long long)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
+ switch (ext.magic) {
+ case QCOW_EXT_MAGIC_END:
+ return 0;
+
+ case QCOW_EXT_MAGIC_BACKING_FORMAT:
+ if (ext.len >= sizeof(bs->backing_format)) {
+ fprintf(stderr, "ERROR: ext_backing_format: len=%u too large"
+ " (>=%zu)\n",
+ ext.len, sizeof(bs->backing_format));
+ return 2;
+ }
+ if (bdrv_pread(s->hd, offset , bs->backing_format,
+ ext.len) != ext.len)
+ return 3;
+ bs->backing_format[ext.len] = '\0';
+#ifdef DEBUG_EXT
+ printf("Qcow2: Got format extension %s\n", bs->backing_format);
+#endif
+ offset += ((ext.len + 7) & ~7);
+ break;
+
+ default:
+ /* unknown magic -- just skip it */
+ offset += ((ext.len + 7) & ~7);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+