static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,

                                  const uint8_t *buf, int nb_sectors)

{

    BDRVQcowState *s = bs->opaque;

    z_stream strm;

    int ret, out_len;

    uint8_t *out_buf;

    uint64_t cluster_offset;



    if (nb_sectors == 0) {

        /* align end of file to a sector boundary to ease reading with

           sector based I/Os */

        cluster_offset = bdrv_getlength(bs->file);

        cluster_offset = (cluster_offset + 511) & ~511;

        bdrv_truncate(bs->file, cluster_offset);

        return 0;

    }



    if (nb_sectors != s->cluster_sectors) {

        ret = -EINVAL;



        /* Zero-pad last write if image size is not cluster aligned */

        if (sector_num + nb_sectors == bs->total_sectors &&

            nb_sectors < s->cluster_sectors) {

            uint8_t *pad_buf = qemu_blockalign(bs, s->cluster_size);

            memset(pad_buf, 0, s->cluster_size);

            memcpy(pad_buf, buf, nb_sectors * BDRV_SECTOR_SIZE);

            ret = qcow2_write_compressed(bs, sector_num,

                                         pad_buf, s->cluster_sectors);

            qemu_vfree(pad_buf);

        }

        return ret;

    }



    out_buf = g_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);



    /* best compression, small window, no zlib header */

    memset(&strm, 0, sizeof(strm));

    ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,

                       Z_DEFLATED, -12,

                       9, Z_DEFAULT_STRATEGY);

    if (ret != 0) {

        ret = -EINVAL;

        goto fail;

    }



    strm.avail_in = s->cluster_size;

    strm.next_in = (uint8_t *)buf;

    strm.avail_out = s->cluster_size;

    strm.next_out = out_buf;



    ret = deflate(&strm, Z_FINISH);

    if (ret != Z_STREAM_END && ret != Z_OK) {

        deflateEnd(&strm);

        ret = -EINVAL;

        goto fail;

    }

    out_len = strm.next_out - out_buf;



    deflateEnd(&strm);



    if (ret != Z_STREAM_END || out_len >= s->cluster_size) {

        /* could not compress: write normal cluster */



        ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT,

                sector_num * BDRV_SECTOR_SIZE,

                s->cluster_sectors * BDRV_SECTOR_SIZE);

        if (ret < 0) {

            goto fail;

        }



        ret = bdrv_write(bs, sector_num, buf, s->cluster_sectors);

        if (ret < 0) {

            goto fail;

        }

    } else {

        cluster_offset = qcow2_alloc_compressed_cluster_offset(bs,

            sector_num << 9, out_len);

        if (!cluster_offset) {

            ret = -EIO;

            goto fail;

        }

        cluster_offset &= s->cluster_offset_mask;



        ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT,

                cluster_offset, out_len);

        if (ret < 0) {

            goto fail;

        }



        BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);

        ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len);

        if (ret < 0) {

            goto fail;

        }

    }



    ret = 0;

fail:

    g_free(out_buf);

    return ret;

}

static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,

                                  const uint8_t *buf, int nb_sectors)

{

    BDRVQcowState *s = bs->opaque;

    z_stream strm;

    int ret, out_len;

    uint8_t *out_buf;

    uint64_t cluster_offset;



    if (nb_sectors == 0) {

        



        cluster_offset = bdrv_getlength(bs->file);

        cluster_offset = (cluster_offset + 511) & ~511;

        bdrv_truncate(bs->file, cluster_offset);

        return 0;

    }



    if (nb_sectors != s->cluster_sectors) {

        ret = -EINVAL;



        

        if (sector_num + nb_sectors == bs->total_sectors &&

            nb_sectors < s->cluster_sectors) {

            uint8_t *pad_buf = qemu_blockalign(bs, s->cluster_size);

            memset(pad_buf, 0, s->cluster_size);

            memcpy(pad_buf, buf, nb_sectors * BDRV_SECTOR_SIZE);

            ret = qcow2_write_compressed(bs, sector_num,

                                         pad_buf, s->cluster_sectors);

            qemu_vfree(pad_buf);

        }

        return ret;

    }



    out_buf = g_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);



    

    memset(&strm, 0, sizeof(strm));

    ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,

                       Z_DEFLATED, -12,

                       9, Z_DEFAULT_STRATEGY);

    if (ret != 0) {

        ret = -EINVAL;

        goto fail;

    }



    strm.avail_in = s->cluster_size;

    strm.next_in = (uint8_t *)buf;

    strm.avail_out = s->cluster_size;

    strm.next_out = out_buf;



    ret = deflate(&strm, Z_FINISH);

    if (ret != Z_STREAM_END && ret != Z_OK) {

        deflateEnd(&strm);

        ret = -EINVAL;

        goto fail;

    }

    out_len = strm.next_out - out_buf;



    deflateEnd(&strm);



    if (ret != Z_STREAM_END || out_len >= s->cluster_size) {

        



        ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT,

                sector_num * BDRV_SECTOR_SIZE,

                s->cluster_sectors * BDRV_SECTOR_SIZE);

        if (ret < 0) {

            goto fail;

        }



        ret = bdrv_write(bs, sector_num, buf, s->cluster_sectors);

        if (ret < 0) {

            goto fail;

        }

    } else {

        cluster_offset = qcow2_alloc_compressed_cluster_offset(bs,

            sector_num << 9, out_len);

        if (!cluster_offset) {

            ret = -EIO;

            goto fail;

        }

        cluster_offset &= s->cluster_offset_mask;



        ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT,

                cluster_offset, out_len);

        if (ret < 0) {

            goto fail;

        }



        BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);

        ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len);

        if (ret < 0) {

            goto fail;

        }

    }



    ret = 0;

fail:

    g_free(out_buf);

    return ret;

}

        ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT,                 sector_num * BDRV_SECTOR_SIZE,                 s->cluster_sectors * BDRV_SECTOR_SIZE);         if (ret < 0) {             goto fail;
static int FUNC_0(BlockDriverState *VAR_0, int64_t VAR_1,

                                  const uint8_t *VAR_2, int VAR_3)

{

    BDRVQcowState *s = VAR_0->opaque;

    z_stream strm;

    int VAR_4, VAR_5;

    uint8_t *out_buf;

    uint64_t cluster_offset;



    if (VAR_3 == 0) {

        



        cluster_offset = bdrv_getlength(VAR_0->file);

        cluster_offset = (cluster_offset + 511) & ~511;

        bdrv_truncate(VAR_0->file, cluster_offset);

        return 0;

    }



    if (VAR_3 != s->cluster_sectors) {

        VAR_4 = -EINVAL;



        

        if (VAR_1 + VAR_3 == VAR_0->total_sectors &&

            VAR_3 < s->cluster_sectors) {

            uint8_t *pad_buf = qemu_blockalign(VAR_0, s->cluster_size);

            memset(pad_buf, 0, s->cluster_size);

            memcpy(pad_buf, VAR_2, VAR_3 * BDRV_SECTOR_SIZE);

            VAR_4 = FUNC_0(VAR_0, VAR_1,

                                         pad_buf, s->cluster_sectors);

            qemu_vfree(pad_buf);

        }

        return VAR_4;

    }



    out_buf = g_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);



    

    memset(&strm, 0, sizeof(strm));

    VAR_4 = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,

                       Z_DEFLATED, -12,

                       9, Z_DEFAULT_STRATEGY);

    if (VAR_4 != 0) {

        VAR_4 = -EINVAL;

        goto fail;

    }



    strm.avail_in = s->cluster_size;

    strm.next_in = (uint8_t *)VAR_2;

    strm.avail_out = s->cluster_size;

    strm.next_out = out_buf;



    VAR_4 = deflate(&strm, Z_FINISH);

    if (VAR_4 != Z_STREAM_END && VAR_4 != Z_OK) {

        deflateEnd(&strm);

        VAR_4 = -EINVAL;

        goto fail;

    }

    VAR_5 = strm.next_out - out_buf;



    deflateEnd(&strm);



    if (VAR_4 != Z_STREAM_END || VAR_5 >= s->cluster_size) {

        



        VAR_4 = qcow2_pre_write_overlap_check(VAR_0, QCOW2_OL_DEFAULT,

                VAR_1 * BDRV_SECTOR_SIZE,

                s->cluster_sectors * BDRV_SECTOR_SIZE);

        if (VAR_4 < 0) {

            goto fail;

        }



        VAR_4 = bdrv_write(VAR_0, VAR_1, VAR_2, s->cluster_sectors);

        if (VAR_4 < 0) {

            goto fail;

        }

    } else {

        cluster_offset = qcow2_alloc_compressed_cluster_offset(VAR_0,

            VAR_1 << 9, VAR_5);

        if (!cluster_offset) {

            VAR_4 = -EIO;

            goto fail;

        }

        cluster_offset &= s->cluster_offset_mask;



        VAR_4 = qcow2_pre_write_overlap_check(VAR_0, QCOW2_OL_DEFAULT,

                cluster_offset, VAR_5);

        if (VAR_4 < 0) {

            goto fail;

        }



        BLKDBG_EVENT(VAR_0->file, BLKDBG_WRITE_COMPRESSED);

        VAR_4 = bdrv_pwrite(VAR_0->file, cluster_offset, out_buf, VAR_5);

        if (VAR_4 < 0) {

            goto fail;

        }

    }



    VAR_4 = 0;

fail:

    g_free(out_buf);

    return VAR_4;

}

static int FUNC_0(BlockDriverState *VAR_0, int64_t VAR_1,
const uint8_t *VAR_2, int VAR_3)
{ BDRVQcowState *s = VAR_0->opaque; z_stream strm; int VAR_4, VAR_5; uint8_t *out_buf; uint64_t cluster_offset; if (VAR_3 == 0) { cluster_offset = bdrv_getlength(VAR_0->file); cluster_offset = (cluster_offset + 511) & ~511; bdrv_truncate(VAR_0->file, cluster_offset); return 0; } if (VAR_3 != s->cluster_sectors) { VAR_4 = -EINVAL; if (VAR_1 + VAR_3 == VAR_0->total_sectors &&
VAR_3 < s->cluster_sectors) { uint8_t *pad_buf = qemu_blockalign(VAR_0, s->cluster_size); memset(pad_buf, 0, s->cluster_size); memcpy(pad_buf, VAR_2, VAR_3 * BDRV_SECTOR_SIZE); VAR_4 = FUNC_0(VAR_0, VAR_1,
pad_buf, s->cluster_sectors); qemu_vfree(pad_buf); } return VAR_4; } out_buf = g_malloc(s->cluster_size + (s->cluster_size / 1000) + 128); memset(&strm, 0, sizeof(strm)); VAR_4 = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,
Z_DEFLATED, -12,
9, Z_DEFAULT_STRATEGY); if (VAR_4 != 0) { VAR_4 = -EINVAL; goto fail; } strm.avail_in = s->cluster_size; strm.next_in = (uint8_t *)VAR_2; strm.avail_out = s->cluster_size; strm.next_out = out_buf; VAR_4 = deflate(&strm, Z_FINISH); if (VAR_4 != Z_STREAM_END && VAR_4 != Z_OK) { deflateEnd(&strm); VAR_4 = -EINVAL; goto fail; } VAR_5 = strm.next_out - out_buf; deflateEnd(&strm); if (VAR_4 != Z_STREAM_END || VAR_5 >= s->cluster_size) { VAR_4 = qcow2_pre_write_overlap_check(VAR_0, QCOW2_OL_DEFAULT,
VAR_1 * BDRV_SECTOR_SIZE,
s->cluster_sectors * BDRV_SECTOR_SIZE); if (VAR_4 < 0) { goto fail; } VAR_4 = bdrv_write(VAR_0, VAR_1, VAR_2, s->cluster_sectors); if (VAR_4 < 0) { goto fail; } } else { cluster_offset = qcow2_alloc_compressed_cluster_offset(VAR_0,
VAR_1 << 9, VAR_5); if (!cluster_offset) { VAR_4 = -EIO; goto fail; } cluster_offset &= s->cluster_offset_mask; VAR_4 = qcow2_pre_write_overlap_check(VAR_0, QCOW2_OL_DEFAULT,
cluster_offset, VAR_5); if (VAR_4 < 0) { goto fail; } BLKDBG_EVENT(VAR_0->file, BLKDBG_WRITE_COMPRESSED); VAR_4 = bdrv_pwrite(VAR_0->file, cluster_offset, out_buf, VAR_5); if (VAR_4 < 0) { goto fail; } } VAR_4 = 0; fail:
g_free(out_buf); return VAR_4; }