static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,

                                                    int64_t sector_num,

                                                    int nb_sectors, int *pnum)

{

    off_t start, data = 0, hole = 0;

    int64_t total_size;

    int ret;



    ret = fd_open(bs);

    if (ret < 0) {

        return ret;

    }



    start = sector_num * BDRV_SECTOR_SIZE;

    total_size = bdrv_getlength(bs);

    if (total_size < 0) {

        return total_size;

    } else if (start >= total_size) {

        *pnum = 0;

        return 0;

    } else if (start + nb_sectors * BDRV_SECTOR_SIZE > total_size) {

        nb_sectors = DIV_ROUND_UP(total_size - start, BDRV_SECTOR_SIZE);

    }



    ret = find_allocation(bs, start, &data, &hole);

    if (ret == -ENXIO) {

        /* Trailing hole */

        *pnum = nb_sectors;

        ret = BDRV_BLOCK_ZERO;

    } else if (ret < 0) {

        /* No info available, so pretend there are no holes */

        *pnum = nb_sectors;

        ret = BDRV_BLOCK_DATA;

    } else if (data == start) {

        /* On a data extent, compute sectors to the end of the extent,

         * possibly including a partial sector at EOF. */

        *pnum = MIN(nb_sectors, DIV_ROUND_UP(hole - start, BDRV_SECTOR_SIZE));

        ret = BDRV_BLOCK_DATA;

    } else {

        /* On a hole, compute sectors to the beginning of the next extent.  */

        assert(hole == start);

        *pnum = MIN(nb_sectors, (data - start) / BDRV_SECTOR_SIZE);

        ret = BDRV_BLOCK_ZERO;

    }

    return ret | BDRV_BLOCK_OFFSET_VALID | start;

}
