static int raw_create(const char *filename, QemuOpts *opts, Error **errp)

{

    int fd;

    int result = 0;

    int64_t total_size = 0;

    bool nocow = false;

    PreallocMode prealloc;

    char *buf = NULL;

    Error *local_err = NULL;



    strstart(filename, "file:", &filename);



    /* Read out options */

    total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),

                          BDRV_SECTOR_SIZE);

    nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false);

    buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);

    prealloc = qapi_enum_parse(PreallocMode_lookup, buf,

                               PREALLOC_MODE_MAX, PREALLOC_MODE_OFF,

                               &local_err);

    g_free(buf);

    if (local_err) {

        error_propagate(errp, local_err);

        result = -EINVAL;

        goto out;

    }



    fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,

                   0644);

    if (fd < 0) {

        result = -errno;

        error_setg_errno(errp, -result, "Could not create file");

        goto out;

    }



    if (nocow) {

#ifdef __linux__

        /* Set NOCOW flag to solve performance issue on fs like btrfs.

         * This is an optimisation. The FS_IOC_SETFLAGS ioctl return value

         * will be ignored since any failure of this operation should not

         * block the left work.

         */

        int attr;

        if (ioctl(fd, FS_IOC_GETFLAGS, &attr) == 0) {

            attr |= FS_NOCOW_FL;

            ioctl(fd, FS_IOC_SETFLAGS, &attr);

        }

#endif

    }



    if (ftruncate(fd, total_size) != 0) {

        result = -errno;

        error_setg_errno(errp, -result, "Could not resize file");

        goto out_close;

    }



    switch (prealloc) {

#ifdef CONFIG_POSIX_FALLOCATE

    case PREALLOC_MODE_FALLOC:

        /* posix_fallocate() doesn't set errno. */

        result = -posix_fallocate(fd, 0, total_size);

        if (result != 0) {

            error_setg_errno(errp, -result,

                             "Could not preallocate data for the new file");

        }

        break;

#endif

    case PREALLOC_MODE_FULL:

    {

        int64_t num = 0, left = total_size;

        buf = g_malloc0(65536);



        while (left > 0) {

            num = MIN(left, 65536);

            result = write(fd, buf, num);

            if (result < 0) {

                result = -errno;

                error_setg_errno(errp, -result,

                                 "Could not write to the new file");

                break;

            }

            left -= result;

        }

        fsync(fd);

        g_free(buf);

        break;

    }

    case PREALLOC_MODE_OFF:

        break;

    default:

        result = -EINVAL;

        error_setg(errp, "Unsupported preallocation mode: %s",

                   PreallocMode_lookup[prealloc]);

        break;

    }



out_close:

    if (qemu_close(fd) != 0 && result == 0) {

        result = -errno;

        error_setg_errno(errp, -result, "Could not close the new file");

    }

out:

    return result;

}
