static int get_cluster_offset(BlockDriverState *bs,

                                    VmdkExtent *extent,

                                    VmdkMetaData *m_data,

                                    uint64_t offset,

                                    int allocate,

                                    uint64_t *cluster_offset)

{

    unsigned int l1_index, l2_offset, l2_index;

    int min_index, i, j;

    uint32_t min_count, *l2_table;

    bool zeroed = false;



    if (m_data) {

        m_data->valid = 0;

    }

    if (extent->flat) {

        *cluster_offset = extent->flat_start_offset;

        return VMDK_OK;

    }



    offset -= (extent->end_sector - extent->sectors) * SECTOR_SIZE;

    l1_index = (offset >> 9) / extent->l1_entry_sectors;

    if (l1_index >= extent->l1_size) {

        return VMDK_ERROR;

    }

    l2_offset = extent->l1_table[l1_index];

    if (!l2_offset) {

        return VMDK_UNALLOC;

    }

    for (i = 0; i < L2_CACHE_SIZE; i++) {

        if (l2_offset == extent->l2_cache_offsets[i]) {

            /* increment the hit count */

            if (++extent->l2_cache_counts[i] == 0xffffffff) {

                for (j = 0; j < L2_CACHE_SIZE; j++) {

                    extent->l2_cache_counts[j] >>= 1;

                }

            }

            l2_table = extent->l2_cache + (i * extent->l2_size);

            goto found;

        }

    }

    /* not found: load a new entry in the least used one */

    min_index = 0;

    min_count = 0xffffffff;

    for (i = 0; i < L2_CACHE_SIZE; i++) {

        if (extent->l2_cache_counts[i] < min_count) {

            min_count = extent->l2_cache_counts[i];

            min_index = i;

        }

    }

    l2_table = extent->l2_cache + (min_index * extent->l2_size);

    if (bdrv_pread(

                extent->file,

                (int64_t)l2_offset * 512,

                l2_table,

                extent->l2_size * sizeof(uint32_t)

            ) != extent->l2_size * sizeof(uint32_t)) {

        return VMDK_ERROR;

    }



    extent->l2_cache_offsets[min_index] = l2_offset;

    extent->l2_cache_counts[min_index] = 1;

 found:

    l2_index = ((offset >> 9) / extent->cluster_sectors) % extent->l2_size;

    *cluster_offset = le32_to_cpu(l2_table[l2_index]);



    if (extent->has_zero_grain && *cluster_offset == VMDK_GTE_ZEROED) {

        zeroed = true;

    }



    if (!*cluster_offset || zeroed) {

        if (!allocate) {

            return zeroed ? VMDK_ZEROED : VMDK_UNALLOC;

        }



        /* Avoid the L2 tables update for the images that have snapshots. */

        *cluster_offset = bdrv_getlength(extent->file);

        if (!extent->compressed) {

            bdrv_truncate(

                extent->file,

                *cluster_offset + (extent->cluster_sectors << 9)

            );

        }



        *cluster_offset >>= 9;

        l2_table[l2_index] = cpu_to_le32(*cluster_offset);



        /* First of all we write grain itself, to avoid race condition

         * that may to corrupt the image.

         * This problem may occur because of insufficient space on host disk

         * or inappropriate VM shutdown.

         */

        if (get_whole_cluster(

                bs, extent, *cluster_offset, offset, allocate) == -1) {

            return VMDK_ERROR;

        }



        if (m_data) {

            m_data->offset = *cluster_offset;

            m_data->l1_index = l1_index;

            m_data->l2_index = l2_index;

            m_data->l2_offset = l2_offset;

            m_data->valid = 1;

        }

    }

    *cluster_offset <<= 9;

    return VMDK_OK;

}

static int get_cluster_offset(BlockDriverState *bs,

                                    VmdkExtent *extent,

                                    VmdkMetaData *m_data,

                                    uint64_t offset,

                                    int allocate,

                                    uint64_t *cluster_offset)

{

    unsigned int l1_index, l2_offset, l2_index;

    int min_index, i, j;

    uint32_t min_count, *l2_table;

    bool zeroed = false;



    if (m_data) {

        m_data->valid = 0;

    }

    if (extent->flat) {

        *cluster_offset = extent->flat_start_offset;

        return VMDK_OK;

    }



    offset -= (extent->end_sector - extent->sectors) * SECTOR_SIZE;

    l1_index = (offset >> 9) / extent->l1_entry_sectors;

    if (l1_index >= extent->l1_size) {

        return VMDK_ERROR;

    }

    l2_offset = extent->l1_table[l1_index];

    if (!l2_offset) {

        return VMDK_UNALLOC;

    }

    for (i = 0; i < L2_CACHE_SIZE; i++) {

        if (l2_offset == extent->l2_cache_offsets[i]) {

            

            if (++extent->l2_cache_counts[i] == 0xffffffff) {

                for (j = 0; j < L2_CACHE_SIZE; j++) {

                    extent->l2_cache_counts[j] >>= 1;

                }

            }

            l2_table = extent->l2_cache + (i * extent->l2_size);

            goto found;

        }

    }

    

    min_index = 0;

    min_count = 0xffffffff;

    for (i = 0; i < L2_CACHE_SIZE; i++) {

        if (extent->l2_cache_counts[i] < min_count) {

            min_count = extent->l2_cache_counts[i];

            min_index = i;

        }

    }

    l2_table = extent->l2_cache + (min_index * extent->l2_size);

    if (bdrv_pread(

                extent->file,

                (int64_t)l2_offset * 512,

                l2_table,

                extent->l2_size * sizeof(uint32_t)

            ) != extent->l2_size * sizeof(uint32_t)) {

        return VMDK_ERROR;

    }



    extent->l2_cache_offsets[min_index] = l2_offset;

    extent->l2_cache_counts[min_index] = 1;

 found:

    l2_index = ((offset >> 9) / extent->cluster_sectors) % extent->l2_size;

    *cluster_offset = le32_to_cpu(l2_table[l2_index]);



    if (extent->has_zero_grain && *cluster_offset == VMDK_GTE_ZEROED) {

        zeroed = true;

    }



    if (!*cluster_offset || zeroed) {

        if (!allocate) {

            return zeroed ? VMDK_ZEROED : VMDK_UNALLOC;

        }



        

        *cluster_offset = bdrv_getlength(extent->file);

        if (!extent->compressed) {

            bdrv_truncate(

                extent->file,

                *cluster_offset + (extent->cluster_sectors << 9)

            );

        }



        *cluster_offset >>= 9;

        l2_table[l2_index] = cpu_to_le32(*cluster_offset);



        









        if (get_whole_cluster(

                bs, extent, *cluster_offset, offset, allocate) == -1) {

            return VMDK_ERROR;

        }



        if (m_data) {

            m_data->offset = *cluster_offset;

            m_data->l1_index = l1_index;

            m_data->l2_index = l2_index;

            m_data->l2_offset = l2_offset;

            m_data->valid = 1;

        }

    }

    *cluster_offset <<= 9;

    return VMDK_OK;

}

            m_data->l1_index = l1_index;             m_data->l2_index = l2_index;             m_data->l2_offset = l2_offset;             m_data->valid = 1;
static int FUNC_0(BlockDriverState *VAR_0,

                                    VmdkExtent *VAR_1,

                                    VmdkMetaData *VAR_2,

                                    uint64_t VAR_3,

                                    int VAR_4,

                                    uint64_t *VAR_5)

{

    unsigned int VAR_6, VAR_7, VAR_8;

    int VAR_9, VAR_10, VAR_11;

    uint32_t min_count, *l2_table;

    bool zeroed = false;



    if (VAR_2) {

        VAR_2->valid = 0;

    }

    if (VAR_1->flat) {

        *VAR_5 = VAR_1->flat_start_offset;

        return VMDK_OK;

    }



    VAR_3 -= (VAR_1->end_sector - VAR_1->sectors) * SECTOR_SIZE;

    VAR_6 = (VAR_3 >> 9) / VAR_1->l1_entry_sectors;

    if (VAR_6 >= VAR_1->l1_size) {

        return VMDK_ERROR;

    }

    VAR_7 = VAR_1->l1_table[VAR_6];

    if (!VAR_7) {

        return VMDK_UNALLOC;

    }

    for (VAR_10 = 0; VAR_10 < L2_CACHE_SIZE; VAR_10++) {

        if (VAR_7 == VAR_1->l2_cache_offsets[VAR_10]) {

            

            if (++VAR_1->l2_cache_counts[VAR_10] == 0xffffffff) {

                for (VAR_11 = 0; VAR_11 < L2_CACHE_SIZE; VAR_11++) {

                    VAR_1->l2_cache_counts[VAR_11] >>= 1;

                }

            }

            l2_table = VAR_1->l2_cache + (VAR_10 * VAR_1->l2_size);

            goto found;

        }

    }

    

    VAR_9 = 0;

    min_count = 0xffffffff;

    for (VAR_10 = 0; VAR_10 < L2_CACHE_SIZE; VAR_10++) {

        if (VAR_1->l2_cache_counts[VAR_10] < min_count) {

            min_count = VAR_1->l2_cache_counts[VAR_10];

            VAR_9 = VAR_10;

        }

    }

    l2_table = VAR_1->l2_cache + (VAR_9 * VAR_1->l2_size);

    if (bdrv_pread(

                VAR_1->file,

                (int64_t)VAR_7 * 512,

                l2_table,

                VAR_1->l2_size * sizeof(uint32_t)

            ) != VAR_1->l2_size * sizeof(uint32_t)) {

        return VMDK_ERROR;

    }



    VAR_1->l2_cache_offsets[VAR_9] = VAR_7;

    VAR_1->l2_cache_counts[VAR_9] = 1;

 found:

    VAR_8 = ((VAR_3 >> 9) / VAR_1->cluster_sectors) % VAR_1->l2_size;

    *VAR_5 = le32_to_cpu(l2_table[VAR_8]);



    if (VAR_1->has_zero_grain && *VAR_5 == VMDK_GTE_ZEROED) {

        zeroed = true;

    }



    if (!*VAR_5 || zeroed) {

        if (!VAR_4) {

            return zeroed ? VMDK_ZEROED : VMDK_UNALLOC;

        }



        

        *VAR_5 = bdrv_getlength(VAR_1->file);

        if (!VAR_1->compressed) {

            bdrv_truncate(

                VAR_1->file,

                *VAR_5 + (VAR_1->cluster_sectors << 9)

            );

        }



        *VAR_5 >>= 9;

        l2_table[VAR_8] = cpu_to_le32(*VAR_5);



        









        if (get_whole_cluster(

                VAR_0, VAR_1, *VAR_5, VAR_3, VAR_4) == -1) {

            return VMDK_ERROR;

        }



        if (VAR_2) {

            VAR_2->VAR_3 = *VAR_5;

            VAR_2->VAR_6 = VAR_6;

            VAR_2->VAR_8 = VAR_8;

            VAR_2->VAR_7 = VAR_7;

            VAR_2->valid = 1;

        }

    }

    *VAR_5 <<= 9;

    return VMDK_OK;

}

static int FUNC_0(BlockDriverState *VAR_0,
VmdkExtent *VAR_1,
VmdkMetaData *VAR_2,
uint64_t VAR_3,
int VAR_4,
uint64_t *VAR_5)
{ unsigned int VAR_6, VAR_7, VAR_8; int VAR_9, VAR_10, VAR_11; uint32_t min_count, *l2_table; bool zeroed = false; if (VAR_2) { VAR_2->valid = 0; } if (VAR_1->flat) { *VAR_5 = VAR_1->flat_start_offset; return VMDK_OK; } VAR_3 -= (VAR_1->end_sector - VAR_1->sectors) * SECTOR_SIZE; VAR_6 = (VAR_3 >> 9) / VAR_1->l1_entry_sectors; if (VAR_6 >= VAR_1->l1_size) { return VMDK_ERROR; } VAR_7 = VAR_1->l1_table[VAR_6]; if (!VAR_7) { return VMDK_UNALLOC; } for (VAR_10 = 0; VAR_10 < L2_CACHE_SIZE; VAR_10++) { if (VAR_7 == VAR_1->l2_cache_offsets[VAR_10]) { if (++VAR_1->l2_cache_counts[VAR_10] == 0xffffffff) { for (VAR_11 = 0; VAR_11 < L2_CACHE_SIZE; VAR_11++) { VAR_1->l2_cache_counts[VAR_11] >>= 1; } } l2_table = VAR_1->l2_cache + (VAR_10 * VAR_1->l2_size); goto found; } } VAR_9 = 0; min_count = 0xffffffff; for (VAR_10 = 0; VAR_10 < L2_CACHE_SIZE; VAR_10++) { if (VAR_1->l2_cache_counts[VAR_10] < min_count) { min_count = VAR_1->l2_cache_counts[VAR_10]; VAR_9 = VAR_10; } } l2_table = VAR_1->l2_cache + (VAR_9 * VAR_1->l2_size); if (bdrv_pread(
VAR_1->file,
(int64_t)VAR_7 * 512,
l2_table,
VAR_1->l2_size * sizeof(uint32_t)
) != VAR_1->l2_size * sizeof(uint32_t)) { return VMDK_ERROR; } VAR_1->l2_cache_offsets[VAR_9] = VAR_7; VAR_1->l2_cache_counts[VAR_9] = 1; found:
VAR_8 = ((VAR_3 >> 9) / VAR_1->cluster_sectors) % VAR_1->l2_size; *VAR_5 = le32_to_cpu(l2_table[VAR_8]); if (VAR_1->has_zero_grain && *VAR_5 == VMDK_GTE_ZEROED) { zeroed = true; } if (!*VAR_5 || zeroed) { if (!VAR_4) { return zeroed ? VMDK_ZEROED : VMDK_UNALLOC; } *VAR_5 = bdrv_getlength(VAR_1->file); if (!VAR_1->compressed) { bdrv_truncate(
VAR_1->file,
*VAR_5 + (VAR_1->cluster_sectors << 9)
); } *VAR_5 >>= 9; l2_table[VAR_8] = cpu_to_le32(*VAR_5); if (get_whole_cluster(
VAR_0, VAR_1, *VAR_5, VAR_3, VAR_4) == -1) { return VMDK_ERROR; } if (VAR_2) { VAR_2->VAR_3 = *VAR_5; VAR_2->VAR_6 = VAR_6; VAR_2->VAR_8 = VAR_8; VAR_2->VAR_7 = VAR_7; VAR_2->valid = 1; } } *VAR_5 <<= 9; return VMDK_OK; }