static int get_cluster_offset(BlockDriverState *bs,

                              uint64_t offset, int allocate,

                              int compressed_size,

                              int n_start, int n_end, uint64_t *result)

{

    BDRVQcowState *s = bs->opaque;

    int min_index, i, j, l1_index, l2_index, ret;

    uint64_t l2_offset, *l2_table, cluster_offset, tmp;

    uint32_t min_count;

    int new_l2_table;



    *result = 0;

    l1_index = offset >> (s->l2_bits + s->cluster_bits);

    l2_offset = s->l1_table[l1_index];

    new_l2_table = 0;

    if (!l2_offset) {

        if (!allocate)

            return 0;

        /* allocate a new l2 entry */

        l2_offset = bdrv_getlength(bs->file->bs);

        /* round to cluster size */

        l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);

        /* update the L1 entry */

        s->l1_table[l1_index] = l2_offset;

        tmp = cpu_to_be64(l2_offset);

        ret = bdrv_pwrite_sync(bs->file,

                               s->l1_table_offset + l1_index * sizeof(tmp),

                               &tmp, sizeof(tmp));

        if (ret < 0) {

            return ret;

        }

        new_l2_table = 1;

    }

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

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

            /* increment the hit count */

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

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

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

                }

            }

            l2_table = s->l2_cache + (i << s->l2_bits);

            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 (s->l2_cache_counts[i] < min_count) {

            min_count = s->l2_cache_counts[i];

            min_index = i;

        }

    }

    l2_table = s->l2_cache + (min_index << s->l2_bits);

    if (new_l2_table) {

        memset(l2_table, 0, s->l2_size * sizeof(uint64_t));

        ret = bdrv_pwrite_sync(bs->file, l2_offset, l2_table,

                               s->l2_size * sizeof(uint64_t));

        if (ret < 0) {

            return ret;

        }

    } else {

        ret = bdrv_pread(bs->file, l2_offset, l2_table,

                         s->l2_size * sizeof(uint64_t));

        if (ret < 0) {

            return ret;

        }

    }

    s->l2_cache_offsets[min_index] = l2_offset;

    s->l2_cache_counts[min_index] = 1;

 found:

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

    cluster_offset = be64_to_cpu(l2_table[l2_index]);

    if (!cluster_offset ||

        ((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1)) {

        if (!allocate)

            return 0;

        /* allocate a new cluster */

        if ((cluster_offset & QCOW_OFLAG_COMPRESSED) &&

            (n_end - n_start) < s->cluster_sectors) {

            /* if the cluster is already compressed, we must

               decompress it in the case it is not completely

               overwritten */

            if (decompress_cluster(bs, cluster_offset) < 0) {

                return -EIO;

            }

            cluster_offset = bdrv_getlength(bs->file->bs);

            cluster_offset = (cluster_offset + s->cluster_size - 1) &

                ~(s->cluster_size - 1);

            /* write the cluster content */

            ret = bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache,

                              s->cluster_size);

            if (ret < 0) {

                return ret;

            }

        } else {

            cluster_offset = bdrv_getlength(bs->file->bs);

            if (allocate == 1) {

                /* round to cluster size */

                cluster_offset = (cluster_offset + s->cluster_size - 1) &

                    ~(s->cluster_size - 1);

                bdrv_truncate(bs->file, cluster_offset + s->cluster_size,

                              PREALLOC_MODE_OFF, NULL);

                /* if encrypted, we must initialize the cluster

                   content which won't be written */

                if (bs->encrypted &&

                    (n_end - n_start) < s->cluster_sectors) {

                    uint64_t start_sect;

                    assert(s->crypto);

                    start_sect = (offset & ~(s->cluster_size - 1)) >> 9;

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

                        if (i < n_start || i >= n_end) {

                            memset(s->cluster_data, 0x00, 512);

                            if (qcrypto_block_encrypt(s->crypto, start_sect + i,

                                                      s->cluster_data,

                                                      BDRV_SECTOR_SIZE,

                                                      NULL) < 0) {

                                return -EIO;

                            }

                            ret = bdrv_pwrite(bs->file,

                                              cluster_offset + i * 512,

                                              s->cluster_data, 512);

                            if (ret < 0) {

                                return ret;

                            }

                        }

                    }

                }

            } else if (allocate == 2) {

                cluster_offset |= QCOW_OFLAG_COMPRESSED |

                    (uint64_t)compressed_size << (63 - s->cluster_bits);

            }

        }

        /* update L2 table */

        tmp = cpu_to_be64(cluster_offset);

        l2_table[l2_index] = tmp;

        ret = bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp),

                               &tmp, sizeof(tmp));

        if (ret < 0) {

            return ret;

        }

    }

    *result = cluster_offset;

    return 1;

}

static int get_cluster_offset(BlockDriverState *bs,

                              uint64_t offset, int allocate,

                              int compressed_size,

                              int n_start, int n_end, uint64_t *result)

{

    BDRVQcowState *s = bs->opaque;

    int min_index, i, j, l1_index, l2_index, ret;

    uint64_t l2_offset, *l2_table, cluster_offset, tmp;

    uint32_t min_count;

    int new_l2_table;



    *result = 0;

    l1_index = offset >> (s->l2_bits + s->cluster_bits);

    l2_offset = s->l1_table[l1_index];

    new_l2_table = 0;

    if (!l2_offset) {

        if (!allocate)

            return 0;

        

        l2_offset = bdrv_getlength(bs->file->bs);

        

        l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);

        

        s->l1_table[l1_index] = l2_offset;

        tmp = cpu_to_be64(l2_offset);

        ret = bdrv_pwrite_sync(bs->file,

                               s->l1_table_offset + l1_index * sizeof(tmp),

                               &tmp, sizeof(tmp));

        if (ret < 0) {

            return ret;

        }

        new_l2_table = 1;

    }

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

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

            

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

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

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

                }

            }

            l2_table = s->l2_cache + (i << s->l2_bits);

            goto found;

        }

    }

    

    min_index = 0;

    min_count = 0xffffffff;

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

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

            min_count = s->l2_cache_counts[i];

            min_index = i;

        }

    }

    l2_table = s->l2_cache + (min_index << s->l2_bits);

    if (new_l2_table) {

        memset(l2_table, 0, s->l2_size * sizeof(uint64_t));

        ret = bdrv_pwrite_sync(bs->file, l2_offset, l2_table,

                               s->l2_size * sizeof(uint64_t));

        if (ret < 0) {

            return ret;

        }

    } else {

        ret = bdrv_pread(bs->file, l2_offset, l2_table,

                         s->l2_size * sizeof(uint64_t));

        if (ret < 0) {

            return ret;

        }

    }

    s->l2_cache_offsets[min_index] = l2_offset;

    s->l2_cache_counts[min_index] = 1;

 found:

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

    cluster_offset = be64_to_cpu(l2_table[l2_index]);

    if (!cluster_offset ||

        ((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1)) {

        if (!allocate)

            return 0;

        

        if ((cluster_offset & QCOW_OFLAG_COMPRESSED) &&

            (n_end - n_start) < s->cluster_sectors) {

            





            if (decompress_cluster(bs, cluster_offset) < 0) {

                return -EIO;

            }

            cluster_offset = bdrv_getlength(bs->file->bs);

            cluster_offset = (cluster_offset + s->cluster_size - 1) &

                ~(s->cluster_size - 1);

            

            ret = bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache,

                              s->cluster_size);

            if (ret < 0) {

                return ret;

            }

        } else {

            cluster_offset = bdrv_getlength(bs->file->bs);

            if (allocate == 1) {

                

                cluster_offset = (cluster_offset + s->cluster_size - 1) &

                    ~(s->cluster_size - 1);

                bdrv_truncate(bs->file, cluster_offset + s->cluster_size,

                              PREALLOC_MODE_OFF, NULL);

                



                if (bs->encrypted &&

                    (n_end - n_start) < s->cluster_sectors) {

                    uint64_t start_sect;

                    assert(s->crypto);

                    start_sect = (offset & ~(s->cluster_size - 1)) >> 9;

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

                        if (i < n_start || i >= n_end) {

                            memset(s->cluster_data, 0x00, 512);

                            if (qcrypto_block_encrypt(s->crypto, start_sect + i,

                                                      s->cluster_data,

                                                      BDRV_SECTOR_SIZE,

                                                      NULL) < 0) {

                                return -EIO;

                            }

                            ret = bdrv_pwrite(bs->file,

                                              cluster_offset + i * 512,

                                              s->cluster_data, 512);

                            if (ret < 0) {

                                return ret;

                            }

                        }

                    }

                }

            } else if (allocate == 2) {

                cluster_offset |= QCOW_OFLAG_COMPRESSED |

                    (uint64_t)compressed_size << (63 - s->cluster_bits);

            }

        }

        

        tmp = cpu_to_be64(cluster_offset);

        l2_table[l2_index] = tmp;

        ret = bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp),

                               &tmp, sizeof(tmp));

        if (ret < 0) {

            return ret;

        }

    }

    *result = cluster_offset;

    return 1;

}

    uint64_t l2_offset, *l2_table, cluster_offset, tmp;         l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);             cluster_offset = (cluster_offset + s->cluster_size - 1) &                 ~(s->cluster_size - 1);                 cluster_offset = (cluster_offset + s->cluster_size - 1) &                     ~(s->cluster_size - 1);                 bdrv_truncate(bs->file, cluster_offset + s->cluster_size,                               PREALLOC_MODE_OFF, NULL);
static int FUNC_0(BlockDriverState *VAR_0,

                              uint64_t VAR_1, int VAR_2,

                              int VAR_3,

                              int VAR_4, int VAR_5, uint64_t *VAR_6)

{

    BDRVQcowState *s = VAR_0->opaque;

    int VAR_7, VAR_8, VAR_9, VAR_10, VAR_11, VAR_12;

    uint64_t l2_offset, *l2_table, cluster_offset, tmp;

    uint32_t min_count;

    int VAR_13;



    *VAR_6 = 0;

    VAR_10 = VAR_1 >> (s->l2_bits + s->cluster_bits);

    l2_offset = s->l1_table[VAR_10];

    VAR_13 = 0;

    if (!l2_offset) {

        if (!VAR_2)

            return 0;

        

        l2_offset = bdrv_getlength(VAR_0->file->VAR_0);

        

        l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);

        

        s->l1_table[VAR_10] = l2_offset;

        tmp = cpu_to_be64(l2_offset);

        VAR_12 = bdrv_pwrite_sync(VAR_0->file,

                               s->l1_table_offset + VAR_10 * sizeof(tmp),

                               &tmp, sizeof(tmp));

        if (VAR_12 < 0) {

            return VAR_12;

        }

        VAR_13 = 1;

    }

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

        if (l2_offset == s->l2_cache_offsets[VAR_8]) {

            

            if (++s->l2_cache_counts[VAR_8] == 0xffffffff) {

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

                    s->l2_cache_counts[VAR_9] >>= 1;

                }

            }

            l2_table = s->l2_cache + (VAR_8 << s->l2_bits);

            goto found;

        }

    }

    

    VAR_7 = 0;

    min_count = 0xffffffff;

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

        if (s->l2_cache_counts[VAR_8] < min_count) {

            min_count = s->l2_cache_counts[VAR_8];

            VAR_7 = VAR_8;

        }

    }

    l2_table = s->l2_cache + (VAR_7 << s->l2_bits);

    if (VAR_13) {

        memset(l2_table, 0, s->l2_size * sizeof(uint64_t));

        VAR_12 = bdrv_pwrite_sync(VAR_0->file, l2_offset, l2_table,

                               s->l2_size * sizeof(uint64_t));

        if (VAR_12 < 0) {

            return VAR_12;

        }

    } else {

        VAR_12 = bdrv_pread(VAR_0->file, l2_offset, l2_table,

                         s->l2_size * sizeof(uint64_t));

        if (VAR_12 < 0) {

            return VAR_12;

        }

    }

    s->l2_cache_offsets[VAR_7] = l2_offset;

    s->l2_cache_counts[VAR_7] = 1;

 found:

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

    cluster_offset = be64_to_cpu(l2_table[VAR_11]);

    if (!cluster_offset ||

        ((cluster_offset & QCOW_OFLAG_COMPRESSED) && VAR_2 == 1)) {

        if (!VAR_2)

            return 0;

        

        if ((cluster_offset & QCOW_OFLAG_COMPRESSED) &&

            (VAR_5 - VAR_4) < s->cluster_sectors) {

            





            if (decompress_cluster(VAR_0, cluster_offset) < 0) {

                return -EIO;

            }

            cluster_offset = bdrv_getlength(VAR_0->file->VAR_0);

            cluster_offset = (cluster_offset + s->cluster_size - 1) &

                ~(s->cluster_size - 1);

            

            VAR_12 = bdrv_pwrite(VAR_0->file, cluster_offset, s->cluster_cache,

                              s->cluster_size);

            if (VAR_12 < 0) {

                return VAR_12;

            }

        } else {

            cluster_offset = bdrv_getlength(VAR_0->file->VAR_0);

            if (VAR_2 == 1) {

                

                cluster_offset = (cluster_offset + s->cluster_size - 1) &

                    ~(s->cluster_size - 1);

                bdrv_truncate(VAR_0->file, cluster_offset + s->cluster_size,

                              PREALLOC_MODE_OFF, NULL);

                



                if (VAR_0->encrypted &&

                    (VAR_5 - VAR_4) < s->cluster_sectors) {

                    uint64_t start_sect;

                    assert(s->crypto);

                    start_sect = (VAR_1 & ~(s->cluster_size - 1)) >> 9;

                    for(VAR_8 = 0; VAR_8 < s->cluster_sectors; VAR_8++) {

                        if (VAR_8 < VAR_4 || VAR_8 >= VAR_5) {

                            memset(s->cluster_data, 0x00, 512);

                            if (qcrypto_block_encrypt(s->crypto, start_sect + VAR_8,

                                                      s->cluster_data,

                                                      BDRV_SECTOR_SIZE,

                                                      NULL) < 0) {

                                return -EIO;

                            }

                            VAR_12 = bdrv_pwrite(VAR_0->file,

                                              cluster_offset + VAR_8 * 512,

                                              s->cluster_data, 512);

                            if (VAR_12 < 0) {

                                return VAR_12;

                            }

                        }

                    }

                }

            } else if (VAR_2 == 2) {

                cluster_offset |= QCOW_OFLAG_COMPRESSED |

                    (uint64_t)VAR_3 << (63 - s->cluster_bits);

            }

        }

        

        tmp = cpu_to_be64(cluster_offset);

        l2_table[VAR_11] = tmp;

        VAR_12 = bdrv_pwrite_sync(VAR_0->file, l2_offset + VAR_11 * sizeof(tmp),

                               &tmp, sizeof(tmp));

        if (VAR_12 < 0) {

            return VAR_12;

        }

    }

    *VAR_6 = cluster_offset;

    return 1;

}

static int FUNC_0(BlockDriverState *VAR_0,
uint64_t VAR_1, int VAR_2,
int VAR_3,
int VAR_4, int VAR_5, uint64_t *VAR_6)
{ BDRVQcowState *s = VAR_0->opaque; int VAR_7, VAR_8, VAR_9, VAR_10, VAR_11, VAR_12; uint64_t l2_offset, *l2_table, cluster_offset, tmp; uint32_t min_count; int VAR_13; *VAR_6 = 0; VAR_10 = VAR_1 >> (s->l2_bits + s->cluster_bits); l2_offset = s->l1_table[VAR_10]; VAR_13 = 0; if (!l2_offset) { if (!VAR_2)
return 0; l2_offset = bdrv_getlength(VAR_0->file->VAR_0); l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1); s->l1_table[VAR_10] = l2_offset; tmp = cpu_to_be64(l2_offset); VAR_12 = bdrv_pwrite_sync(VAR_0->file,
s->l1_table_offset + VAR_10 * sizeof(tmp),
&tmp, sizeof(tmp)); if (VAR_12 < 0) { return VAR_12; } VAR_13 = 1; } for(VAR_8 = 0; VAR_8 < L2_CACHE_SIZE; VAR_8++) { if (l2_offset == s->l2_cache_offsets[VAR_8]) { if (++s->l2_cache_counts[VAR_8] == 0xffffffff) { for(VAR_9 = 0; VAR_9 < L2_CACHE_SIZE; VAR_9++) { s->l2_cache_counts[VAR_9] >>= 1; } } l2_table = s->l2_cache + (VAR_8 << s->l2_bits); goto found; } } VAR_7 = 0; min_count = 0xffffffff; for(VAR_8 = 0; VAR_8 < L2_CACHE_SIZE; VAR_8++) { if (s->l2_cache_counts[VAR_8] < min_count) { min_count = s->l2_cache_counts[VAR_8]; VAR_7 = VAR_8; } } l2_table = s->l2_cache + (VAR_7 << s->l2_bits); if (VAR_13) { memset(l2_table, 0, s->l2_size * sizeof(uint64_t)); VAR_12 = bdrv_pwrite_sync(VAR_0->file, l2_offset, l2_table,
s->l2_size * sizeof(uint64_t)); if (VAR_12 < 0) { return VAR_12; } } else { VAR_12 = bdrv_pread(VAR_0->file, l2_offset, l2_table,
s->l2_size * sizeof(uint64_t)); if (VAR_12 < 0) { return VAR_12; } } s->l2_cache_offsets[VAR_7] = l2_offset; s->l2_cache_counts[VAR_7] = 1; found:
VAR_11 = (VAR_1 >> s->cluster_bits) & (s->l2_size - 1); cluster_offset = be64_to_cpu(l2_table[VAR_11]); if (!cluster_offset ||
((cluster_offset & QCOW_OFLAG_COMPRESSED) && VAR_2 == 1)) { if (!VAR_2)
return 0; if ((cluster_offset & QCOW_OFLAG_COMPRESSED) &&
(VAR_5 - VAR_4) < s->cluster_sectors) { if (decompress_cluster(VAR_0, cluster_offset) < 0) { return -EIO; } cluster_offset = bdrv_getlength(VAR_0->file->VAR_0); cluster_offset = (cluster_offset + s->cluster_size - 1) &
~(s->cluster_size - 1); VAR_12 = bdrv_pwrite(VAR_0->file, cluster_offset, s->cluster_cache,
s->cluster_size); if (VAR_12 < 0) { return VAR_12; } } else { cluster_offset = bdrv_getlength(VAR_0->file->VAR_0); if (VAR_2 == 1) { cluster_offset = (cluster_offset + s->cluster_size - 1) &
~(s->cluster_size - 1); bdrv_truncate(VAR_0->file, cluster_offset + s->cluster_size,
PREALLOC_MODE_OFF, NULL); if (VAR_0->encrypted &&
(VAR_5 - VAR_4) < s->cluster_sectors) { uint64_t start_sect; assert(s->crypto); start_sect = (VAR_1 & ~(s->cluster_size - 1)) >> 9; for(VAR_8 = 0; VAR_8 < s->cluster_sectors; VAR_8++) { if (VAR_8 < VAR_4 || VAR_8 >= VAR_5) { memset(s->cluster_data, 0x00, 512); if (qcrypto_block_encrypt(s->crypto, start_sect + VAR_8,
s->cluster_data,
BDRV_SECTOR_SIZE,
NULL) < 0) { return -EIO; } VAR_12 = bdrv_pwrite(VAR_0->file,
cluster_offset + VAR_8 * 512,
s->cluster_data, 512); if (VAR_12 < 0) { return VAR_12; } } } } } else if (VAR_2 == 2) { cluster_offset |= QCOW_OFLAG_COMPRESSED |
(uint64_t)VAR_3 << (63 - s->cluster_bits); } } tmp = cpu_to_be64(cluster_offset); l2_table[VAR_11] = tmp; VAR_12 = bdrv_pwrite_sync(VAR_0->file, l2_offset + VAR_11 * sizeof(tmp),
&tmp, sizeof(tmp)); if (VAR_12 < 0) { return VAR_12; } } *VAR_6 = cluster_offset; return 1; }