static int qcow2_open(BlockDriverState *bs, int flags)

{

    BDRVQcowState *s = bs->opaque;

    int len, i, ret = 0;

    QCowHeader header;

    uint64_t ext_end;



    ret = bdrv_pread(bs->file, 0, &header, sizeof(header));

    if (ret < 0) {

        goto fail;

    }

    be32_to_cpus(&header.magic);

    be32_to_cpus(&header.version);

    be64_to_cpus(&header.backing_file_offset);

    be32_to_cpus(&header.backing_file_size);

    be64_to_cpus(&header.size);

    be32_to_cpus(&header.cluster_bits);

    be32_to_cpus(&header.crypt_method);

    be64_to_cpus(&header.l1_table_offset);

    be32_to_cpus(&header.l1_size);

    be64_to_cpus(&header.refcount_table_offset);

    be32_to_cpus(&header.refcount_table_clusters);

    be64_to_cpus(&header.snapshots_offset);

    be32_to_cpus(&header.nb_snapshots);



    if (header.magic != QCOW_MAGIC) {

        ret = -EINVAL;

        goto fail;

    }

    if (header.version < 2 || header.version > 3) {

        report_unsupported(bs, "QCOW version %d", header.version);

        ret = -ENOTSUP;

        goto fail;

    }



    s->qcow_version = header.version;



    /* Initialise version 3 header fields */

    if (header.version == 2) {

        header.incompatible_features    = 0;

        header.compatible_features      = 0;

        header.autoclear_features       = 0;

        header.refcount_order           = 4;

        header.header_length            = 72;

    } else {

        be64_to_cpus(&header.incompatible_features);

        be64_to_cpus(&header.compatible_features);

        be64_to_cpus(&header.autoclear_features);

        be32_to_cpus(&header.refcount_order);

        be32_to_cpus(&header.header_length);

    }



    if (header.header_length > sizeof(header)) {

        s->unknown_header_fields_size = header.header_length - sizeof(header);

        s->unknown_header_fields = g_malloc(s->unknown_header_fields_size);

        ret = bdrv_pread(bs->file, sizeof(header), s->unknown_header_fields,

                         s->unknown_header_fields_size);

        if (ret < 0) {

            goto fail;

        }

    }



    if (header.backing_file_offset) {

        ext_end = header.backing_file_offset;

    } else {

        ext_end = 1 << header.cluster_bits;

    }



    /* Handle feature bits */

    s->incompatible_features    = header.incompatible_features;

    s->compatible_features      = header.compatible_features;

    s->autoclear_features       = header.autoclear_features;



    if (s->incompatible_features & ~QCOW2_INCOMPAT_MASK) {

        void *feature_table = NULL;

        qcow2_read_extensions(bs, header.header_length, ext_end,

                              &feature_table);

        report_unsupported_feature(bs, feature_table,

                                   s->incompatible_features &

                                   ~QCOW2_INCOMPAT_MASK);

        ret = -ENOTSUP;

        goto fail;

    }



    /* Check support for various header values */

    if (header.refcount_order != 4) {

        report_unsupported(bs, "%d bit reference counts",

                           1 << header.refcount_order);

        ret = -ENOTSUP;

        goto fail;

    }



    if (header.cluster_bits < MIN_CLUSTER_BITS ||

        header.cluster_bits > MAX_CLUSTER_BITS) {

        ret = -EINVAL;

        goto fail;

    }

    if (header.crypt_method > QCOW_CRYPT_AES) {

        ret = -EINVAL;

        goto fail;

    }

    s->crypt_method_header = header.crypt_method;

    if (s->crypt_method_header) {

        bs->encrypted = 1;

    }

    s->cluster_bits = header.cluster_bits;

    s->cluster_size = 1 << s->cluster_bits;

    s->cluster_sectors = 1 << (s->cluster_bits - 9);

    s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */

    s->l2_size = 1 << s->l2_bits;

    bs->total_sectors = header.size / 512;

    s->csize_shift = (62 - (s->cluster_bits - 8));

    s->csize_mask = (1 << (s->cluster_bits - 8)) - 1;

    s->cluster_offset_mask = (1LL << s->csize_shift) - 1;

    s->refcount_table_offset = header.refcount_table_offset;

    s->refcount_table_size =

        header.refcount_table_clusters << (s->cluster_bits - 3);



    s->snapshots_offset = header.snapshots_offset;

    s->nb_snapshots = header.nb_snapshots;



    /* read the level 1 table */

    s->l1_size = header.l1_size;

    s->l1_vm_state_index = size_to_l1(s, header.size);

    /* the L1 table must contain at least enough entries to put

       header.size bytes */

    if (s->l1_size < s->l1_vm_state_index) {

        ret = -EINVAL;

        goto fail;

    }

    s->l1_table_offset = header.l1_table_offset;

    if (s->l1_size > 0) {

        s->l1_table = g_malloc0(

            align_offset(s->l1_size * sizeof(uint64_t), 512));

        ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,

                         s->l1_size * sizeof(uint64_t));

        if (ret < 0) {

            goto fail;

        }

        for(i = 0;i < s->l1_size; i++) {

            be64_to_cpus(&s->l1_table[i]);

        }

    }



    /* alloc L2 table/refcount block cache */

    s->l2_table_cache = qcow2_cache_create(bs, L2_CACHE_SIZE);

    s->refcount_block_cache = qcow2_cache_create(bs, REFCOUNT_CACHE_SIZE);



    s->cluster_cache = g_malloc(s->cluster_size);

    /* one more sector for decompressed data alignment */

    s->cluster_data = qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size

                                  + 512);

    s->cluster_cache_offset = -1;

    s->flags = flags;



    ret = qcow2_refcount_init(bs);

    if (ret != 0) {

        goto fail;

    }



    QLIST_INIT(&s->cluster_allocs);



    /* read qcow2 extensions */

    if (qcow2_read_extensions(bs, header.header_length, ext_end, NULL)) {

        ret = -EINVAL;

        goto fail;

    }



    /* read the backing file name */

    if (header.backing_file_offset != 0) {

        len = header.backing_file_size;

        if (len > 1023) {

            len = 1023;

        }

        ret = bdrv_pread(bs->file, header.backing_file_offset,

                         bs->backing_file, len);

        if (ret < 0) {

            goto fail;

        }

        bs->backing_file[len] = '\0';

    }



    ret = qcow2_read_snapshots(bs);

    if (ret < 0) {

        goto fail;

    }



    /* Clear unknown autoclear feature bits */

    if (!bs->read_only && s->autoclear_features != 0) {

        s->autoclear_features = 0;

        ret = qcow2_update_header(bs);

        if (ret < 0) {

            goto fail;

        }

    }



    /* Initialise locks */

    qemu_co_mutex_init(&s->lock);



    /* Repair image if dirty */

    if ((s->incompatible_features & QCOW2_INCOMPAT_DIRTY) &&

        !bs->read_only) {

        BdrvCheckResult result = {0};



        ret = qcow2_check_refcounts(bs, &result, BDRV_FIX_ERRORS);

        if (ret < 0) {

            goto fail;

        }



        ret = qcow2_mark_clean(bs);

        if (ret < 0) {

            goto fail;

        }

    }



#ifdef DEBUG_ALLOC

    {

        BdrvCheckResult result = {0};

        qcow2_check_refcounts(bs, &result, 0);

    }

#endif

    return ret;



 fail:

    g_free(s->unknown_header_fields);

    cleanup_unknown_header_ext(bs);

    qcow2_free_snapshots(bs);

    qcow2_refcount_close(bs);

    g_free(s->l1_table);

    if (s->l2_table_cache) {

        qcow2_cache_destroy(bs, s->l2_table_cache);

    }

    g_free(s->cluster_cache);

    qemu_vfree(s->cluster_data);

    return ret;

}
