static int vmdk_write(BlockDriverState *bs, int64_t sector_num,

                      const uint8_t *buf, int nb_sectors,

                      bool zeroed, bool zero_dry_run)

{

    BDRVVmdkState *s = bs->opaque;

    VmdkExtent *extent = NULL;

    int n, ret;

    int64_t index_in_cluster;

    uint64_t extent_begin_sector, extent_relative_sector_num;

    uint64_t cluster_offset;

    VmdkMetaData m_data;



    if (sector_num > bs->total_sectors) {

        error_report("Wrong offset: sector_num=0x%" PRIx64

                " total_sectors=0x%" PRIx64 "\n",

                sector_num, bs->total_sectors);

        return -EIO;

    }



    while (nb_sectors > 0) {

        extent = find_extent(s, sector_num, extent);

        if (!extent) {

            return -EIO;

        }

        ret = get_cluster_offset(

                                bs,

                                extent,

                                &m_data,

                                sector_num << 9, !extent->compressed,

                                &cluster_offset);

        if (extent->compressed) {

            if (ret == VMDK_OK) {

                /* Refuse write to allocated cluster for streamOptimized */

                error_report("Could not write to allocated cluster"

                              " for streamOptimized");

                return -EIO;

            } else {

                /* allocate */

                ret = get_cluster_offset(

                                        bs,

                                        extent,

                                        &m_data,

                                        sector_num << 9, 1,

                                        &cluster_offset);

            }

        }

        if (ret == VMDK_ERROR) {

            return -EINVAL;

        }

        extent_begin_sector = extent->end_sector - extent->sectors;

        extent_relative_sector_num = sector_num - extent_begin_sector;

        index_in_cluster = extent_relative_sector_num % extent->cluster_sectors;

        n = extent->cluster_sectors - index_in_cluster;

        if (n > nb_sectors) {

            n = nb_sectors;

        }

        if (zeroed) {

            /* Do zeroed write, buf is ignored */

            if (extent->has_zero_grain &&

                    index_in_cluster == 0 &&

                    n >= extent->cluster_sectors) {

                n = extent->cluster_sectors;

                if (!zero_dry_run) {

                    m_data.offset = VMDK_GTE_ZEROED;

                    /* update L2 tables */

                    if (vmdk_L2update(extent, &m_data) != VMDK_OK) {

                        return -EIO;

                    }

                }

            } else {

                return -ENOTSUP;

            }

        } else {

            ret = vmdk_write_extent(extent,

                            cluster_offset, index_in_cluster * 512,

                            buf, n, sector_num);

            if (ret) {

                return ret;

            }

            if (m_data.valid) {

                /* update L2 tables */

                if (vmdk_L2update(extent, &m_data) != VMDK_OK) {

                    return -EIO;

                }

            }

        }

        nb_sectors -= n;

        sector_num += n;

        buf += n * 512;



        /* update CID on the first write every time the virtual disk is

         * opened */

        if (!s->cid_updated) {

            ret = vmdk_write_cid(bs, time(NULL));

            if (ret < 0) {

                return ret;

            }

            s->cid_updated = true;

        }

    }

    return 0;

}

static int vmdk_write(BlockDriverState *bs, int64_t sector_num,

                      const uint8_t *buf, int nb_sectors,

                      bool zeroed, bool zero_dry_run)

{

    BDRVVmdkState *s = bs->opaque;

    VmdkExtent *extent = NULL;

    int n, ret;

    int64_t index_in_cluster;

    uint64_t extent_begin_sector, extent_relative_sector_num;

    uint64_t cluster_offset;

    VmdkMetaData m_data;



    if (sector_num > bs->total_sectors) {

        error_report("Wrong offset: sector_num=0x%" PRIx64

                " total_sectors=0x%" PRIx64 "\n",

                sector_num, bs->total_sectors);

        return -EIO;

    }



    while (nb_sectors > 0) {

        extent = find_extent(s, sector_num, extent);

        if (!extent) {

            return -EIO;

        }

        ret = get_cluster_offset(

                                bs,

                                extent,

                                &m_data,

                                sector_num << 9, !extent->compressed,

                                &cluster_offset);

        if (extent->compressed) {

            if (ret == VMDK_OK) {

                

                error_report("Could not write to allocated cluster"

                              " for streamOptimized");

                return -EIO;

            } else {

                

                ret = get_cluster_offset(

                                        bs,

                                        extent,

                                        &m_data,

                                        sector_num << 9, 1,

                                        &cluster_offset);

            }

        }

        if (ret == VMDK_ERROR) {

            return -EINVAL;

        }

        extent_begin_sector = extent->end_sector - extent->sectors;

        extent_relative_sector_num = sector_num - extent_begin_sector;

        index_in_cluster = extent_relative_sector_num % extent->cluster_sectors;

        n = extent->cluster_sectors - index_in_cluster;

        if (n > nb_sectors) {

            n = nb_sectors;

        }

        if (zeroed) {

            

            if (extent->has_zero_grain &&

                    index_in_cluster == 0 &&

                    n >= extent->cluster_sectors) {

                n = extent->cluster_sectors;

                if (!zero_dry_run) {

                    m_data.offset = VMDK_GTE_ZEROED;

                    

                    if (vmdk_L2update(extent, &m_data) != VMDK_OK) {

                        return -EIO;

                    }

                }

            } else {

                return -ENOTSUP;

            }

        } else {

            ret = vmdk_write_extent(extent,

                            cluster_offset, index_in_cluster * 512,

                            buf, n, sector_num);

            if (ret) {

                return ret;

            }

            if (m_data.valid) {

                

                if (vmdk_L2update(extent, &m_data) != VMDK_OK) {

                    return -EIO;

                }

            }

        }

        nb_sectors -= n;

        sector_num += n;

        buf += n * 512;



        



        if (!s->cid_updated) {

            ret = vmdk_write_cid(bs, time(NULL));

            if (ret < 0) {

                return ret;

            }

            s->cid_updated = true;

        }

    }

    return 0;

}

    int n, ret;     int64_t index_in_cluster;
static int FUNC_0(BlockDriverState *VAR_0, int64_t VAR_1,

                      const uint8_t *VAR_2, int VAR_3,

                      bool VAR_4, bool VAR_5)

{

    BDRVVmdkState *s = VAR_0->opaque;

    VmdkExtent *extent = NULL;

    int VAR_6, VAR_7;

    int64_t index_in_cluster;

    uint64_t extent_begin_sector, extent_relative_sector_num;

    uint64_t cluster_offset;

    VmdkMetaData m_data;



    if (VAR_1 > VAR_0->total_sectors) {

        error_report("Wrong offset: VAR_1=0x%" PRIx64

                " total_sectors=0x%" PRIx64 "\VAR_6",

                VAR_1, VAR_0->total_sectors);

        return -EIO;

    }



    while (VAR_3 > 0) {

        extent = find_extent(s, VAR_1, extent);

        if (!extent) {

            return -EIO;

        }

        VAR_7 = get_cluster_offset(

                                VAR_0,

                                extent,

                                &m_data,

                                VAR_1 << 9, !extent->compressed,

                                &cluster_offset);

        if (extent->compressed) {

            if (VAR_7 == VMDK_OK) {

                

                error_report("Could not write to allocated cluster"

                              " for streamOptimized");

                return -EIO;

            } else {

                

                VAR_7 = get_cluster_offset(

                                        VAR_0,

                                        extent,

                                        &m_data,

                                        VAR_1 << 9, 1,

                                        &cluster_offset);

            }

        }

        if (VAR_7 == VMDK_ERROR) {

            return -EINVAL;

        }

        extent_begin_sector = extent->end_sector - extent->sectors;

        extent_relative_sector_num = VAR_1 - extent_begin_sector;

        index_in_cluster = extent_relative_sector_num % extent->cluster_sectors;

        VAR_6 = extent->cluster_sectors - index_in_cluster;

        if (VAR_6 > VAR_3) {

            VAR_6 = VAR_3;

        }

        if (VAR_4) {

            

            if (extent->has_zero_grain &&

                    index_in_cluster == 0 &&

                    VAR_6 >= extent->cluster_sectors) {

                VAR_6 = extent->cluster_sectors;

                if (!VAR_5) {

                    m_data.offset = VMDK_GTE_ZEROED;

                    

                    if (vmdk_L2update(extent, &m_data) != VMDK_OK) {

                        return -EIO;

                    }

                }

            } else {

                return -ENOTSUP;

            }

        } else {

            VAR_7 = vmdk_write_extent(extent,

                            cluster_offset, index_in_cluster * 512,

                            VAR_2, VAR_6, VAR_1);

            if (VAR_7) {

                return VAR_7;

            }

            if (m_data.valid) {

                

                if (vmdk_L2update(extent, &m_data) != VMDK_OK) {

                    return -EIO;

                }

            }

        }

        VAR_3 -= VAR_6;

        VAR_1 += VAR_6;

        VAR_2 += VAR_6 * 512;



        



        if (!s->cid_updated) {

            VAR_7 = vmdk_write_cid(VAR_0, time(NULL));

            if (VAR_7 < 0) {

                return VAR_7;

            }

            s->cid_updated = true;

        }

    }

    return 0;

}

static int FUNC_0(BlockDriverState *VAR_0, int64_t VAR_1,
const uint8_t *VAR_2, int VAR_3,
bool VAR_4, bool VAR_5)
{ BDRVVmdkState *s = VAR_0->opaque; VmdkExtent *extent = NULL; int VAR_6, VAR_7; int64_t index_in_cluster; uint64_t extent_begin_sector, extent_relative_sector_num; uint64_t cluster_offset; VmdkMetaData m_data; if (VAR_1 > VAR_0->total_sectors) { error_report("Wrong offset: VAR_1=0x%" PRIx64
" total_sectors=0x%" PRIx64 "\VAR_6",
VAR_1, VAR_0->total_sectors); return -EIO; } while (VAR_3 > 0) { extent = find_extent(s, VAR_1, extent); if (!extent) { return -EIO; } VAR_7 = get_cluster_offset(
VAR_0,
extent,
&m_data,
VAR_1 << 9, !extent->compressed,
&cluster_offset); if (extent->compressed) { if (VAR_7 == VMDK_OK) { error_report("Could not write to allocated cluster"
" for streamOptimized"); return -EIO; } else { VAR_7 = get_cluster_offset(
VAR_0,
extent,
&m_data,
VAR_1 << 9, 1,
&cluster_offset); } } if (VAR_7 == VMDK_ERROR) { return -EINVAL; } extent_begin_sector = extent->end_sector - extent->sectors; extent_relative_sector_num = VAR_1 - extent_begin_sector; index_in_cluster = extent_relative_sector_num % extent->cluster_sectors; VAR_6 = extent->cluster_sectors - index_in_cluster; if (VAR_6 > VAR_3) { VAR_6 = VAR_3; } if (VAR_4) { if (extent->has_zero_grain &&
index_in_cluster == 0 &&
VAR_6 >= extent->cluster_sectors) { VAR_6 = extent->cluster_sectors; if (!VAR_5) { m_data.offset = VMDK_GTE_ZEROED; if (vmdk_L2update(extent, &m_data) != VMDK_OK) { return -EIO; } } } else { return -ENOTSUP; } } else { VAR_7 = vmdk_write_extent(extent,
cluster_offset, index_in_cluster * 512,
VAR_2, VAR_6, VAR_1); if (VAR_7) { return VAR_7; } if (m_data.valid) { if (vmdk_L2update(extent, &m_data) != VMDK_OK) { return -EIO; } } } VAR_3 -= VAR_6; VAR_1 += VAR_6; VAR_2 += VAR_6 * 512; if (!s->cid_updated) { VAR_7 = vmdk_write_cid(VAR_0, time(NULL)); if (VAR_7 < 0) { return VAR_7; } s->cid_updated = true; } } return 0; }