int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,

                             unsigned int *bytes, uint64_t *cluster_offset)

{

    BDRVQcow2State *s = bs->opaque;

    unsigned int l2_index;

    uint64_t l1_index, l2_offset, *l2_table;

    int l1_bits, c;

    unsigned int offset_in_cluster;

    uint64_t bytes_available, bytes_needed, nb_clusters;

    int ret;



    offset_in_cluster = offset_into_cluster(s, offset);

    bytes_needed = (uint64_t) *bytes + offset_in_cluster;



    l1_bits = s->l2_bits + s->cluster_bits;



    /* compute how many bytes there are between the start of the cluster

     * containing offset and the end of the l1 entry */

    bytes_available = (1ULL << l1_bits) - (offset & ((1ULL << l1_bits) - 1))

                    + offset_in_cluster;



    if (bytes_needed > bytes_available) {

        bytes_needed = bytes_available;

    }



    *cluster_offset = 0;



    /* seek to the l2 offset in the l1 table */



    l1_index = offset >> l1_bits;

    if (l1_index >= s->l1_size) {

        ret = QCOW2_CLUSTER_UNALLOCATED;

        goto out;

    }



    l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;

    if (!l2_offset) {

        ret = QCOW2_CLUSTER_UNALLOCATED;

        goto out;

    }



    if (offset_into_cluster(s, l2_offset)) {

        qcow2_signal_corruption(bs, true, -1, -1, "L2 table offset %#" PRIx64

                                " unaligned (L1 index: %#" PRIx64 ")",

                                l2_offset, l1_index);

        return -EIO;

    }



    /* load the l2 table in memory */



    ret = l2_load(bs, l2_offset, &l2_table);

    if (ret < 0) {

        return ret;

    }



    /* find the cluster offset for the given disk offset */



    l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);

    *cluster_offset = be64_to_cpu(l2_table[l2_index]);



    nb_clusters = size_to_clusters(s, bytes_needed);

    /* bytes_needed <= *bytes + offset_in_cluster, both of which are unsigned

     * integers; the minimum cluster size is 512, so this assertion is always

     * true */

    assert(nb_clusters <= INT_MAX);



    ret = qcow2_get_cluster_type(*cluster_offset);

    switch (ret) {

    case QCOW2_CLUSTER_COMPRESSED:

        /* Compressed clusters can only be processed one by one */

        c = 1;

        *cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK;

        break;

    case QCOW2_CLUSTER_ZERO:

        if (s->qcow_version < 3) {

            qcow2_signal_corruption(bs, true, -1, -1, "Zero cluster entry found"

                                    " in pre-v3 image (L2 offset: %#" PRIx64

                                    ", L2 index: %#x)", l2_offset, l2_index);

            ret = -EIO;

            goto fail;

        }

        c = count_contiguous_clusters_by_type(nb_clusters, &l2_table[l2_index],

                                              QCOW2_CLUSTER_ZERO);

        *cluster_offset = 0;

        break;

    case QCOW2_CLUSTER_UNALLOCATED:

        /* how many empty clusters ? */

        c = count_contiguous_clusters_by_type(nb_clusters, &l2_table[l2_index],

                                              QCOW2_CLUSTER_UNALLOCATED);

        *cluster_offset = 0;

        break;

    case QCOW2_CLUSTER_NORMAL:

        /* how many allocated clusters ? */

        c = count_contiguous_clusters(nb_clusters, s->cluster_size,

                &l2_table[l2_index], QCOW_OFLAG_ZERO);

        *cluster_offset &= L2E_OFFSET_MASK;

        if (offset_into_cluster(s, *cluster_offset)) {

            qcow2_signal_corruption(bs, true, -1, -1, "Data cluster offset %#"

                                    PRIx64 " unaligned (L2 offset: %#" PRIx64

                                    ", L2 index: %#x)", *cluster_offset,

                                    l2_offset, l2_index);

            ret = -EIO;

            goto fail;

        }

        break;

    default:

        abort();

    }



    qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);



    bytes_available = (int64_t)c * s->cluster_size;



out:

    if (bytes_available > bytes_needed) {

        bytes_available = bytes_needed;

    }



    /* bytes_available <= bytes_needed <= *bytes + offset_in_cluster;

     * subtracting offset_in_cluster will therefore definitely yield something

     * not exceeding UINT_MAX */

    assert(bytes_available - offset_in_cluster <= UINT_MAX);

    *bytes = bytes_available - offset_in_cluster;



    return ret;



fail:

    qcow2_cache_put(bs, s->l2_table_cache, (void **)&l2_table);

    return ret;

}

int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,

                             unsigned int *bytes, uint64_t *cluster_offset)

{

    BDRVQcow2State *s = bs->opaque;

    unsigned int l2_index;

    uint64_t l1_index, l2_offset, *l2_table;

    int l1_bits, c;

    unsigned int offset_in_cluster;

    uint64_t bytes_available, bytes_needed, nb_clusters;

    int ret;



    offset_in_cluster = offset_into_cluster(s, offset);

    bytes_needed = (uint64_t) *bytes + offset_in_cluster;



    l1_bits = s->l2_bits + s->cluster_bits;



    



    bytes_available = (1ULL << l1_bits) - (offset & ((1ULL << l1_bits) - 1))

                    + offset_in_cluster;



    if (bytes_needed > bytes_available) {

        bytes_needed = bytes_available;

    }



    *cluster_offset = 0;



    



    l1_index = offset >> l1_bits;

    if (l1_index >= s->l1_size) {

        ret = QCOW2_CLUSTER_UNALLOCATED;

        goto out;

    }



    l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;

    if (!l2_offset) {

        ret = QCOW2_CLUSTER_UNALLOCATED;

        goto out;

    }



    if (offset_into_cluster(s, l2_offset)) {

        qcow2_signal_corruption(bs, true, -1, -1, "L2 table offset %#" PRIx64

                                " unaligned (L1 index: %#" PRIx64 ")",

                                l2_offset, l1_index);

        return -EIO;

    }



    



    ret = l2_load(bs, l2_offset, &l2_table);

    if (ret < 0) {

        return ret;

    }



    



    l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);

    *cluster_offset = be64_to_cpu(l2_table[l2_index]);



    nb_clusters = size_to_clusters(s, bytes_needed);

    





    assert(nb_clusters <= INT_MAX);



    ret = qcow2_get_cluster_type(*cluster_offset);

    switch (ret) {

    case QCOW2_CLUSTER_COMPRESSED:

        

        c = 1;

        *cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK;

        break;

    case QCOW2_CLUSTER_ZERO:

        if (s->qcow_version < 3) {

            qcow2_signal_corruption(bs, true, -1, -1, "Zero cluster entry found"

                                    " in pre-v3 image (L2 offset: %#" PRIx64

                                    ", L2 index: %#x)", l2_offset, l2_index);

            ret = -EIO;

            goto fail;

        }

        c = count_contiguous_clusters_by_type(nb_clusters, &l2_table[l2_index],

                                              QCOW2_CLUSTER_ZERO);

        *cluster_offset = 0;

        break;

    case QCOW2_CLUSTER_UNALLOCATED:

        

        c = count_contiguous_clusters_by_type(nb_clusters, &l2_table[l2_index],

                                              QCOW2_CLUSTER_UNALLOCATED);

        *cluster_offset = 0;

        break;

    case QCOW2_CLUSTER_NORMAL:

        

        c = count_contiguous_clusters(nb_clusters, s->cluster_size,

                &l2_table[l2_index], QCOW_OFLAG_ZERO);

        *cluster_offset &= L2E_OFFSET_MASK;

        if (offset_into_cluster(s, *cluster_offset)) {

            qcow2_signal_corruption(bs, true, -1, -1, "Data cluster offset %#"

                                    PRIx64 " unaligned (L2 offset: %#" PRIx64

                                    ", L2 index: %#x)", *cluster_offset,

                                    l2_offset, l2_index);

            ret = -EIO;

            goto fail;

        }

        break;

    default:

        abort();

    }



    qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);



    bytes_available = (int64_t)c * s->cluster_size;



out:

    if (bytes_available > bytes_needed) {

        bytes_available = bytes_needed;

    }



    





    assert(bytes_available - offset_in_cluster <= UINT_MAX);

    *bytes = bytes_available - offset_in_cluster;



    return ret;



fail:

    qcow2_cache_put(bs, s->l2_table_cache, (void **)&l2_table);

    return ret;

}

int FUNC_0(BlockDriverState *VAR_0, uint64_t VAR_1,

                             unsigned int *VAR_2, uint64_t *VAR_3)

{

    BDRVQcow2State *s = VAR_0->opaque;

    unsigned int VAR_4;

    uint64_t l1_index, l2_offset, *l2_table;

    int VAR_5, VAR_6;

    unsigned int VAR_7;

    uint64_t bytes_available, bytes_needed, nb_clusters;

    int VAR_8;



    VAR_7 = offset_into_cluster(s, VAR_1);

    bytes_needed = (uint64_t) *VAR_2 + VAR_7;



    VAR_5 = s->l2_bits + s->cluster_bits;



    



    bytes_available = (1ULL << VAR_5) - (VAR_1 & ((1ULL << VAR_5) - 1))

                    + VAR_7;



    if (bytes_needed > bytes_available) {

        bytes_needed = bytes_available;

    }



    *VAR_3 = 0;



    



    l1_index = VAR_1 >> VAR_5;

    if (l1_index >= s->l1_size) {

        VAR_8 = QCOW2_CLUSTER_UNALLOCATED;

        goto out;

    }



    l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;

    if (!l2_offset) {

        VAR_8 = QCOW2_CLUSTER_UNALLOCATED;

        goto out;

    }



    if (offset_into_cluster(s, l2_offset)) {

        qcow2_signal_corruption(VAR_0, true, -1, -1, "L2 table VAR_1 %#" PRIx64

                                " unaligned (L1 index: %#" PRIx64 ")",

                                l2_offset, l1_index);

        return -EIO;

    }



    



    VAR_8 = l2_load(VAR_0, l2_offset, &l2_table);

    if (VAR_8 < 0) {

        return VAR_8;

    }



    



    VAR_4 = (VAR_1 >> s->cluster_bits) & (s->l2_size - 1);

    *VAR_3 = be64_to_cpu(l2_table[VAR_4]);



    nb_clusters = size_to_clusters(s, bytes_needed);

    





    assert(nb_clusters <= INT_MAX);



    VAR_8 = qcow2_get_cluster_type(*VAR_3);

    switch (VAR_8) {

    case QCOW2_CLUSTER_COMPRESSED:

        

        VAR_6 = 1;

        *VAR_3 &= L2E_COMPRESSED_OFFSET_SIZE_MASK;

        break;

    case QCOW2_CLUSTER_ZERO:

        if (s->qcow_version < 3) {

            qcow2_signal_corruption(VAR_0, true, -1, -1, "Zero cluster entry found"

                                    " in pre-v3 image (L2 VAR_1: %#" PRIx64

                                    ", L2 index: %#x)", l2_offset, VAR_4);

            VAR_8 = -EIO;

            goto fail;

        }

        VAR_6 = count_contiguous_clusters_by_type(nb_clusters, &l2_table[VAR_4],

                                              QCOW2_CLUSTER_ZERO);

        *VAR_3 = 0;

        break;

    case QCOW2_CLUSTER_UNALLOCATED:

        

        VAR_6 = count_contiguous_clusters_by_type(nb_clusters, &l2_table[VAR_4],

                                              QCOW2_CLUSTER_UNALLOCATED);

        *VAR_3 = 0;

        break;

    case QCOW2_CLUSTER_NORMAL:

        

        VAR_6 = count_contiguous_clusters(nb_clusters, s->cluster_size,

                &l2_table[VAR_4], QCOW_OFLAG_ZERO);

        *VAR_3 &= L2E_OFFSET_MASK;

        if (offset_into_cluster(s, *VAR_3)) {

            qcow2_signal_corruption(VAR_0, true, -1, -1, "Data cluster VAR_1 %#"

                                    PRIx64 " unaligned (L2 VAR_1: %#" PRIx64

                                    ", L2 index: %#x)", *VAR_3,

                                    l2_offset, VAR_4);

            VAR_8 = -EIO;

            goto fail;

        }

        break;

    default:

        abort();

    }



    qcow2_cache_put(VAR_0, s->l2_table_cache, (void**) &l2_table);



    bytes_available = (int64_t)VAR_6 * s->cluster_size;



out:

    if (bytes_available > bytes_needed) {

        bytes_available = bytes_needed;

    }



    





    assert(bytes_available - VAR_7 <= UINT_MAX);

    *VAR_2 = bytes_available - VAR_7;



    return VAR_8;



fail:

    qcow2_cache_put(VAR_0, s->l2_table_cache, (void **)&l2_table);

    return VAR_8;

}

int FUNC_0(BlockDriverState *VAR_0, uint64_t VAR_1,
unsigned int *VAR_2, uint64_t *VAR_3)
{ BDRVQcow2State *s = VAR_0->opaque; unsigned int VAR_4; uint64_t l1_index, l2_offset, *l2_table; int VAR_5, VAR_6; unsigned int VAR_7; uint64_t bytes_available, bytes_needed, nb_clusters; int VAR_8; VAR_7 = offset_into_cluster(s, VAR_1); bytes_needed = (uint64_t) *VAR_2 + VAR_7; VAR_5 = s->l2_bits + s->cluster_bits; bytes_available = (1ULL << VAR_5) - (VAR_1 & ((1ULL << VAR_5) - 1))
+ VAR_7; if (bytes_needed > bytes_available) { bytes_needed = bytes_available; } *VAR_3 = 0; l1_index = VAR_1 >> VAR_5; if (l1_index >= s->l1_size) { VAR_8 = QCOW2_CLUSTER_UNALLOCATED; goto out; } l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK; if (!l2_offset) { VAR_8 = QCOW2_CLUSTER_UNALLOCATED; goto out; } if (offset_into_cluster(s, l2_offset)) { qcow2_signal_corruption(VAR_0, true, -1, -1, "L2 table VAR_1 %#" PRIx64
" unaligned (L1 index: %#" PRIx64 ")",
l2_offset, l1_index); return -EIO; } VAR_8 = l2_load(VAR_0, l2_offset, &l2_table); if (VAR_8 < 0) { return VAR_8; } VAR_4 = (VAR_1 >> s->cluster_bits) & (s->l2_size - 1); *VAR_3 = be64_to_cpu(l2_table[VAR_4]); nb_clusters = size_to_clusters(s, bytes_needed); assert(nb_clusters <= INT_MAX); VAR_8 = qcow2_get_cluster_type(*VAR_3); switch (VAR_8) { case QCOW2_CLUSTER_COMPRESSED:
VAR_6 = 1; *VAR_3 &= L2E_COMPRESSED_OFFSET_SIZE_MASK; break; case QCOW2_CLUSTER_ZERO:
if (s->qcow_version < 3) { qcow2_signal_corruption(VAR_0, true, -1, -1, "Zero cluster entry found"
" in pre-v3 image (L2 VAR_1: %#" PRIx64
", L2 index: %#x)", l2_offset, VAR_4); VAR_8 = -EIO; goto fail; } VAR_6 = count_contiguous_clusters_by_type(nb_clusters, &l2_table[VAR_4],
QCOW2_CLUSTER_ZERO); *VAR_3 = 0; break; case QCOW2_CLUSTER_UNALLOCATED:
VAR_6 = count_contiguous_clusters_by_type(nb_clusters, &l2_table[VAR_4],
QCOW2_CLUSTER_UNALLOCATED); *VAR_3 = 0; break; case QCOW2_CLUSTER_NORMAL:
VAR_6 = count_contiguous_clusters(nb_clusters, s->cluster_size,
&l2_table[VAR_4], QCOW_OFLAG_ZERO); *VAR_3 &= L2E_OFFSET_MASK; if (offset_into_cluster(s, *VAR_3)) { qcow2_signal_corruption(VAR_0, true, -1, -1, "Data cluster VAR_1 %#"
PRIx64 " unaligned (L2 VAR_1: %#" PRIx64
", L2 index: %#x)", *VAR_3,
l2_offset, VAR_4); VAR_8 = -EIO; goto fail; } break; default:
abort(); } qcow2_cache_put(VAR_0, s->l2_table_cache, (void**) &l2_table); bytes_available = (int64_t)VAR_6 * s->cluster_size; out:
if (bytes_available > bytes_needed) { bytes_available = bytes_needed; } assert(bytes_available - VAR_7 <= UINT_MAX); *VAR_2 = bytes_available - VAR_7; return VAR_8; fail:
qcow2_cache_put(VAR_0, s->l2_table_cache, (void **)&l2_table); return VAR_8; }