Пример #1
0
static void
virConsoleShutdown(virConsolePtr con)
{
    virErrorPtr err = virGetLastError();

    if (con->error.code == VIR_ERR_OK && err)
        virCopyLastError(&con->error);

    if (con->st) {
        virStreamEventRemoveCallback(con->st);
        virStreamAbort(con->st);
        virStreamFree(con->st);
        con->st = NULL;
    }
    VIR_FREE(con->streamToTerminal.data);
    VIR_FREE(con->terminalToStream.data);
    if (con->stdinWatch != -1)
        virEventRemoveHandle(con->stdinWatch);
    if (con->stdoutWatch != -1)
        virEventRemoveHandle(con->stdoutWatch);
    con->stdinWatch = -1;
    con->stdoutWatch = -1;
    if (!con->quit) {
        con->quit = true;
        virCondSignal(&con->cond);
    }
}
/**
 * gvir_storage_vol_upload:
 * @vol: the storage volume to upload
 * @stream: stream to use as input
 * @offset: position in @vol to start to write to
 * @length: limit on amount of data to upload, or 0 for uploading all data
 * @flags: the flags, not set yet, pass 0
 *
 * Returns: #TRUE of success, #FALSE otherwise
 */
gboolean gvir_storage_vol_upload(GVirStorageVol *vol,
                                 GVirStream *stream,
                                 guint64 offset,
                                 guint64 length,
                                 guint flags G_GNUC_UNUSED,
                                 GError **err)
{
    virStreamPtr stream_handle = NULL;
    gboolean ret = FALSE;

    g_object_get(stream, "handle", &stream_handle, NULL);

    g_return_val_if_fail(GVIR_IS_STORAGE_VOL(vol), FALSE);
    g_return_val_if_fail(GVIR_IS_STREAM(stream), FALSE);
    g_return_val_if_fail(err == NULL || *err == NULL, FALSE);

    if (virStorageVolUpload(vol->priv->handle,
                            stream_handle,
                            offset,
                            length,
                            0) < 0) {
        gvir_set_error_literal(err,
                               GVIR_STORAGE_VOL_ERROR,
                               0,
                               "Unable to upload to stream");

        goto cleanup;
    }

    ret = TRUE;
cleanup:
    if (stream_handle != NULL)
        virStreamFree(stream_handle);
    return ret;
}
Пример #3
0
static void
virConsoleDispose(void *obj)
{
    virConsolePtr con = obj;

    if (con->st)
        virStreamFree(con->st);

    virCondDestroy(&con->cond);
    virResetError(&con->error);
}
Пример #4
0
static void
virConsoleFree(virConsolePtr con)
{
    if (!con)
        return;

    if (con->st)
        virStreamFree(con->st);
    virMutexDestroy(&con->lock);
    virCondDestroy(&con->cond);
    VIR_FREE(con);
}
Пример #5
0
    void
vert_cleanup(ErlNifEnv *env, void *obj)
{
    VERT_RESOURCE *vp = obj;


    if (vp->res == NULL)
        return;

    switch (vp->type) {
        case VERT_RES_CONNECT:
            (void)virConnectClose(vp->res);
            break;
        case VERT_RES_DOMAIN:
            (void)virDomainFree(vp->res);
            break;
        case VERT_RES_INTERFACE:
            (void)virInterfaceFree(vp->res);
            break;
        case VERT_RES_NETWORK:
            (void)virNetworkFree(vp->res);
            break;
        case VERT_RES_NODEDEVICE:
            (void)virNodeDeviceFree(vp->res);
            break;
#if HAVE_NWFILTER
        case VERT_RES_NWFILTER:
            (void)virNWFilterFree(vp->res);
            break;
#endif
        case VERT_RES_SECRET:
            (void)virSecretFree(vp->res);
            break;
        case VERT_RES_STORAGEPOOL:
            (void)virStoragePoolFree(vp->res);
            break;
        case VERT_RES_STORAGEVOL:
            (void)virStorageVolFree(vp->res);
            break;
        case VERT_RES_STREAM:
            (void)virStreamFree(vp->res);
            break;
        default:
            break;
    }

    vp->res = NULL;
}
Пример #6
0
static void
virConsoleShutdown(virConsolePtr con)
{
    if (con->st) {
        virStreamEventRemoveCallback(con->st);
        virStreamAbort(con->st);
        virStreamFree(con->st);
    }
    VIR_FREE(con->streamToTerminal.data);
    VIR_FREE(con->terminalToStream.data);
    if (con->stdinWatch != -1)
        virEventRemoveHandle(con->stdinWatch);
    if (con->stdoutWatch != -1)
        virEventRemoveHandle(con->stdoutWatch);
    con->stdinWatch = -1;
    con->stdoutWatch = -1;
    con->quit = true;
    virCondSignal(&con->cond);
}
static gssize gvir_input_stream_read_finish(GInputStream *stream,
                                            GAsyncResult *result,
                                            GError **error)
{
    GVirInputStream *input_stream = GVIR_INPUT_STREAM(stream);
    virStreamPtr handle;
    gssize count;

    g_return_val_if_fail(GVIR_IS_INPUT_STREAM(stream), -1);
    g_return_val_if_fail(g_task_is_valid(result, stream), -1);
    g_return_val_if_fail(error == NULL || *error == NULL, -1);
    g_object_get(input_stream->priv->stream, "handle", &handle, NULL);

    count = g_task_propagate_int(G_TASK(result), error);

    virStreamFree(handle);

    return count;
}
Пример #8
0
/*
 * @stream: an unused client stream
 *
 * Frees the memory associated with this inactive client
 * stream
 */
void remoteFreeClientStream(struct qemud_client *client,
                            struct qemud_client_stream *stream)
{
    struct qemud_client_message *msg;

    if (!stream)
        return;

    VIR_DEBUG("proc=%d serial=%d", stream->procedure, stream->serial);

    msg = stream->rx;
    while (msg) {
        struct qemud_client_message *tmp = msg->next;
        qemudClientMessageRelease(client, msg);
        msg = tmp;
    }

    virStreamFree(stream->st);
    VIR_FREE(stream);
}
Пример #9
0
/*
 * @stream: an unused client stream
 *
 * Frees the memory associated with this inactive client
 * stream
 */
int daemonFreeClientStream(virNetServerClientPtr client,
                           daemonClientStream *stream)
{
    virNetMessagePtr msg;
    int ret = 0;

    if (!stream)
        return 0;

    stream->refs--;
    if (stream->refs)
        return 0;

    VIR_DEBUG("client=%p, proc=%d, serial=%d",
              client, stream->procedure, stream->serial);

    virObjectUnref(stream->prog);

    msg = stream->rx;
    while (msg) {
        virNetMessagePtr tmp = msg->next;
        if (client) {
            /* Send a dummy reply to free up 'msg' & unblock client rx */
            virNetMessageClear(msg);
            msg->header.type = VIR_NET_REPLY;
            if (virNetServerClientSendMessage(client, msg) < 0) {
                virNetServerClientImmediateClose(client);
                virNetMessageFree(msg);
                ret = -1;
            }
        } else {
            virNetMessageFree(msg);
        }
        msg = tmp;
    }

    virStreamFree(stream->st);
    VIR_FREE(stream);

    return ret;
}
// here be a compress func
void compressFunc(virConnectPtr conn)
{
	int fd;
	// открываем некомпрессированный файл
	// компрессуем
	
	virStreamPtr st = virStreamNew(conn, 0);
	fd = open("compressed_file", O_RDONLY);
// открываем компрессированный, считываем, передаём стрим - сенд по указателю на поток СТ, буф+смещение, до гот-смещение
	while (1) {
       		char buf[1024];
       		int got;
		got = read(fd, buf, 1024);
	       	if (got < 0) {
          	virStreamAbort(st);
          	break;
       		}
       	if (got == 0) {
       		virStreamFinish(st);
          	break;
       	}
       	int offset = 0;
       	while (offset < got) {
        	int sent;
          	sent = virStreamSend(st, buf+offset, got-offset);
          	if (sent < 0) {
             	virStreamAbort(st);
             	goto done;
        }
        offset += sent;
       }
   }
   if (virStreamFinish(st) < 0)
   	// обработчик ошибки
done:
   virStreamFree(st);
   close(fd);	
}
Пример #11
0
void Server::screenshot()
{
    virConnectPtr conn = NULL; /* the hypervisor connection */
    virDomainPtr dom = NULL; /* the domain to be screenshotted */
    virStreamPtr st = NULL;
    char *mimetype = NULL;
    FILE *fp = NULL;

    conn = virConnectOpen("qemu:///system");
    if (conn == NULL) {
        fprintf(stderr, "Failed to connect to hypervisor\n");

        if(st != NULL)
            virStreamFree(st);

        if(fp != NULL)
            fclose(fp);

        if(mimetype !=NULL)
            free(mimetype);

        if (dom != NULL)
            virDomainFree(dom);

        if (conn != NULL)
            virConnectClose(conn);

        return;
    }

    /* Find the domain of the given id */
    dom = virDomainLookupByName(conn, "win7-1");
    if (dom == NULL) {
        fprintf(stderr, "Failed to connect to hypervisor\n");

        if(st != NULL)
            virStreamFree(st);

        if(fp != NULL)
            fclose(fp);

        if(mimetype !=NULL)
            free(mimetype);

        if (dom != NULL)
            virDomainFree(dom);

        if (conn != NULL)
            virConnectClose(conn);

        return;
    }

    st = virStreamNew(conn, 0);
    mimetype = virDomainScreenshot(dom, st, 0, 0);
    if(mimetype == NULL) {
        fprintf(stderr, "Failed in virDomainScreenshot funcation\n");

        if(st != NULL)
            virStreamFree(st);

        if(fp != NULL)
            fclose(fp);

        if(mimetype !=NULL)
            free(mimetype);

        if (dom != NULL)
            virDomainFree(dom);

        if (conn != NULL)
            virConnectClose(conn);

        return;
    }

    fp = fopen("shot.ppm", "w");
    if(fp == NULL) {
        fprintf(stderr, "Failed in fopen funcation\n");

        if(st != NULL)
            virStreamFree(st);

        if(fp != NULL)
            fclose(fp);

        if(mimetype !=NULL)
            free(mimetype);

        if (dom != NULL)
            virDomainFree(dom);

        if (conn != NULL)
            virConnectClose(conn);

        return;
    }
    if(virStreamRecvAll(st, mysink, fp) < 0) {
        fprintf(stderr, "Failed in virStreamRecvAll funcation\n");

        if(st != NULL)
            virStreamFree(st);

        if(fp != NULL)
            fclose(fp);

        if(mimetype !=NULL)
            free(mimetype);

        if (dom != NULL)
            virDomainFree(dom);

        if (conn != NULL)
            virConnectClose(conn);

        return;
    }

    if (virStreamFinish(st) < 0) {
        fprintf(stderr, "Failed in virStreamFinish funcation\n");

        if(st != NULL)
            virStreamFree(st);

        if(fp != NULL)
            fclose(fp);

        if(mimetype !=NULL)
            free(mimetype);

        if (dom != NULL)
            virDomainFree(dom);

        if (conn != NULL)
            virConnectClose(conn);

        return;
    }

    if(st != NULL)
        virStreamFree(st);

    if(fp != NULL)
        fclose(fp);

    if(mimetype !=NULL)
        free(mimetype);

    if (dom != NULL)
        virDomainFree(dom);

    if (conn != NULL)
        virConnectClose(conn);
}
Пример #12
0
void Server::sendImage()
{
    //screenshot();

    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_0);

    out << (quint32)0;
    /*******************************/
    virConnectPtr conn = NULL; /* the hypervisor connection */
    virDomainPtr dom = NULL; /* the domain to be screenshotted */
    virStreamPtr st = NULL;
    char *mimetype = NULL;

    conn = virConnectOpen("qemu:///system");
    if (conn == NULL) {
        fprintf(stderr, "Failed to connect to hypervisor\n");
        if(st != NULL)
            virStreamFree(st);

        if(mimetype !=NULL)
            free(mimetype);

        if (dom != NULL)
            virDomainFree(dom);

        if (conn != NULL)
            virConnectClose(conn);

        return;
    }

    /* Find the domain of the given id */
    dom = virDomainLookupByName(conn, "win7-1");
    if (dom == NULL) {
        fprintf(stderr, "Failed to connect to hypervisor\n");
        if(st != NULL)
            virStreamFree(st);

        if(mimetype !=NULL)
            free(mimetype);

        if (dom != NULL)
            virDomainFree(dom);

        if (conn != NULL)
            virConnectClose(conn);

        return;
    }

    st = virStreamNew(conn, 0);
    mimetype = virDomainScreenshot(dom, st, 0, 0);
    if(mimetype == NULL) {
        fprintf(stderr, "Failed in virDomainScreenshot funcation\n");
        if(st != NULL)
            virStreamFree(st);

        if(mimetype !=NULL)
            free(mimetype);

        if (dom != NULL)
            virDomainFree(dom);

        if (conn != NULL)
            virConnectClose(conn);

        return;
    }

    if(virStreamRecvAll(st, mysink, &out) < 0) {
        fprintf(stderr, "Failed in virStreamRecvAll funcation\n");
        if(st != NULL)
            virStreamFree(st);

        if(mimetype !=NULL)
            free(mimetype);

        if (dom != NULL)
            virDomainFree(dom);

        if (conn != NULL)
            virConnectClose(conn);

        return;
    }

    if (virStreamFinish(st) < 0) {
        fprintf(stderr, "Failed in virStreamFinish funcation\n");
        if(st != NULL)
            virStreamFree(st);

        if(mimetype !=NULL)
            free(mimetype);

        if (dom != NULL)
            virDomainFree(dom);

        if (conn != NULL)
            virConnectClose(conn);

        return;
    }

    if(st != NULL)
        virStreamFree(st);

    if(mimetype !=NULL)
        free(mimetype);

    if (dom != NULL)
        virDomainFree(dom);

    if (conn != NULL)
        virConnectClose(conn);
    /*******************************/

    out.device()->seek(0);
    out << (quint32)(block.size() - sizeof(quint32));

    QTcpSocket *clientConnection = tcpServer->nextPendingConnection();
    connect(clientConnection, SIGNAL(disconnected()),
            clientConnection, SLOT(deleteLater()));

    clientConnection->write(block);
    clientConnection->disconnectFromHost();

    QTextStream info(stdout);
    info << tr("has sended %1 bytes\n").arg(block.size() - 4);
}
Пример #13
0
static void virFDStreamCallbackFree(void *opaque)
{
    virStreamPtr st = opaque;
    virStreamFree(st);
}
Пример #14
0
static bool
cmdVolUpload(vshControl *ctl, const vshCmd *cmd)
{
    const char *file = NULL;
    virStorageVolPtr vol = NULL;
    bool ret = false;
    int fd = -1;
    virStreamPtr st = NULL;
    const char *name = NULL;
    unsigned long long offset = 0, length = 0;

    if (!vshConnectionUsability(ctl, ctl->conn))
        goto cleanup;

    if (vshCommandOptULongLong(cmd, "offset", &offset) < 0) {
        vshError(ctl, _("Unable to parse integer"));
        return false;
    }

    if (vshCommandOptULongLong(cmd, "length", &length) < 0) {
        vshError(ctl, _("Unable to parse integer"));
        return false;
    }

    if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) {
        return false;
    }

    if (vshCommandOptString(cmd, "file", &file) < 0) {
        vshError(ctl, _("file must not be empty"));
        goto cleanup;
    }

    if ((fd = open(file, O_RDONLY)) < 0) {
        vshError(ctl, _("cannot read %s"), file);
        goto cleanup;
    }

    st = virStreamNew(ctl->conn, 0);
    if (virStorageVolUpload(vol, st, offset, length, 0) < 0) {
        vshError(ctl, _("cannot upload to volume %s"), name);
        goto cleanup;
    }

    if (virStreamSendAll(st, cmdVolUploadSource, &fd) < 0) {
        vshError(ctl, _("cannot send data to volume %s"), name);
        goto cleanup;
    }

    if (VIR_CLOSE(fd) < 0) {
        vshError(ctl, _("cannot close file %s"), file);
        virStreamAbort(st);
        goto cleanup;
    }

    if (virStreamFinish(st) < 0) {
        vshError(ctl, _("cannot close volume %s"), name);
        goto cleanup;
    }

    ret = true;

cleanup:
    if (vol)
        virStorageVolFree(vol);
    if (st)
        virStreamFree(st);
    VIR_FORCE_CLOSE(fd);
    return ret;
}
Пример #15
0
int vshRunConsole(virDomainPtr dom,
                  const char *dev_name,
                  const char *escape_seq,
                  unsigned int flags)
{
    int ret = -1;
    struct termios ttyattr;
    void (*old_sigquit)(int);
    void (*old_sigterm)(int);
    void (*old_sigint)(int);
    void (*old_sighup)(int);
    void (*old_sigpipe)(int);
    virConsolePtr con = NULL;

    /* Put STDIN into raw mode so that stuff typed
       does not echo to the screen (the TTY reads will
       result in it being echoed back already), and
       also ensure Ctrl-C, etc is blocked, and misc
       other bits */
    if (vshMakeStdinRaw(&ttyattr, true) < 0)
        goto resettty;

    /* Trap all common signals so that we can safely restore
       the original terminal settings on STDIN before the
       process exits - people don't like being left with a
       messed up terminal ! */
    old_sigquit = signal(SIGQUIT, do_signal);
    old_sigterm = signal(SIGTERM, do_signal);
    old_sigint = signal(SIGINT, do_signal);
    old_sighup = signal(SIGHUP, do_signal);
    old_sigpipe = signal(SIGPIPE, do_signal);
    got_signal = 0;

    if (VIR_ALLOC(con) < 0) {
        virReportOOMError();
        goto cleanup;
    }

    con->escapeChar = vshGetEscapeChar(escape_seq);
    con->st = virStreamNew(virDomainGetConnect(dom),
                           VIR_STREAM_NONBLOCK);
    if (!con->st)
        goto cleanup;

    if (virDomainOpenConsole(dom, dev_name, con->st, flags) < 0)
        goto cleanup;

    if (virCondInit(&con->cond) < 0 || virMutexInit(&con->lock) < 0)
        goto cleanup;

    con->stdinWatch = virEventAddHandle(STDIN_FILENO,
                                        VIR_EVENT_HANDLE_READABLE,
                                        virConsoleEventOnStdin,
                                        con,
                                        NULL);
    con->stdoutWatch = virEventAddHandle(STDOUT_FILENO,
                                         0,
                                         virConsoleEventOnStdout,
                                         con,
                                         NULL);

    virStreamEventAddCallback(con->st,
                              VIR_STREAM_EVENT_READABLE,
                              virConsoleEventOnStream,
                              con,
                              NULL);

    while (!con->quit) {
        if (virCondWait(&con->cond, &con->lock) < 0) {
            VIR_ERROR(_("unable to wait on console condition"));
            goto cleanup;
        }
    }

    ret = 0;

 cleanup:

    if (con) {
        if (con->st)
            virStreamFree(con->st);
        virMutexDestroy(&con->lock);
        ignore_value(virCondDestroy(&con->cond));
        VIR_FREE(con);
    }

    /* Restore original signal handlers */
    signal(SIGPIPE, old_sigpipe);
    signal(SIGHUP, old_sighup);
    signal(SIGINT, old_sigint);
    signal(SIGTERM, old_sigterm);
    signal(SIGQUIT, old_sigquit);

resettty:
    /* Put STDIN back into the (sane?) state we found
       it in before starting */
    tcsetattr(STDIN_FILENO, TCSAFLUSH, &ttyattr);

    return ret;
}
Result StorageVolControlThread::uploadStorageVol()
{
    Result result;
    result.name = QString("%1_%2").arg(task.srcConName).arg(currPoolName);
    QString name, path;
    name = task.object;
    path = task.args.path;
    //qDebug()<<path<<"upload";
    if (currStoragePool!=NULL) {
        virStoragePoolFree(currStoragePool);
        currStoragePool = NULL;
    };
    currStoragePool = virStoragePoolLookupByName(
                *task.srcConnPtr, currPoolName.toUtf8().data());
    QFile *f = new QFile(path);
    f->open(QIODevice::ReadOnly);

    bool uploaded = false;
    virStreamPtr stream = virStreamNew(*task.srcConnPtr, 0);
    unsigned long long offset = 0;
    unsigned long long length = f->size();
    // flags: extra flags; not used yet, so callers should always pass 0
    unsigned int flags = 0;
    virStorageVol *storageVol = virStorageVolLookupByName(
                currStoragePool, name.toUtf8().data());
    if ( storageVol!=NULL ) {
        int ret = virStorageVolUpload(
                    storageVol, stream, offset, length, flags);
        if ( ret<0 ) {
            result.err = sendConnErrors();
        } else {
            uploaded = true;
            length = 0;
            int got, saved, step;
            step = 0;
            char buf[BLOCK_SIZE];
            while ( 1 && keep_alive ) {
                got = f->read(buf, BLOCK_SIZE);
                if (got == 0) break;
                if ( got<0 ) {
                    QString msg = QString("ReadError after (%2): %1 bytes")
                            .arg(length).arg(step);
                    emit errorMsg( msg, number );
                    result.err = msg;
                } else {
                    saved = virStreamSend(stream, buf, got);
                    if (saved < 0) {
                        result.err = sendConnErrors();
                        uploaded = false;
                        break;
                    };
                    step++;
                    length += saved;
                    //qDebug()<<"got<>saved:length"<<got<<saved<<step<<length;
                };
            };
            virStreamFinish(stream);
        };
        virStorageVolFree(storageVol);
    } else
        result.err = sendConnErrors();
    if ( stream!=NULL ) virStreamFree(stream);
    f->close();
    delete f; f = 0;
    result.msg.append(
                QString("'<b>%1</b>' StorageVol %2 Uploaded from %3 (%4).")
                .arg(name).arg((uploaded)?"":"don't")
                .arg(path).arg(length));
    result.result = uploaded;
    return result;
}
Пример #17
0
static bool
cmdVolDownload(vshControl *ctl, const vshCmd *cmd)
{
    const char *file = NULL;
    virStorageVolPtr vol = NULL;
    bool ret = false;
    int fd = -1;
    virStreamPtr st = NULL;
    const char *name = NULL;
    unsigned long long offset = 0, length = 0;
    bool created = false;

    if (!vshConnectionUsability(ctl, ctl->conn))
        return false;

    if (vshCommandOptULongLong(cmd, "offset", &offset) < 0) {
        vshError(ctl, _("Unable to parse integer"));
        return false;
    }

    if (vshCommandOptULongLong(cmd, "length", &length) < 0) {
        vshError(ctl, _("Unable to parse integer"));
        return false;
    }

    if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name)))
        return false;

    if (vshCommandOptString(cmd, "file", &file) < 0) {
        vshError(ctl, _("file must not be empty"));
        goto cleanup;
    }

    if ((fd = open(file, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0) {
        if (errno != EEXIST ||
            (fd = open(file, O_WRONLY|O_TRUNC, 0666)) < 0) {
            vshError(ctl, _("cannot create %s"), file);
            goto cleanup;
        }
    } else {
        created = true;
    }

    st = virStreamNew(ctl->conn, 0);
    if (virStorageVolDownload(vol, st, offset, length, 0) < 0) {
        vshError(ctl, _("cannot download from volume %s"), name);
        goto cleanup;
    }

    if (virStreamRecvAll(st, vshStreamSink, &fd) < 0) {
        vshError(ctl, _("cannot receive data from volume %s"), name);
        goto cleanup;
    }

    if (VIR_CLOSE(fd) < 0) {
        vshError(ctl, _("cannot close file %s"), file);
        virStreamAbort(st);
        goto cleanup;
    }

    if (virStreamFinish(st) < 0) {
        vshError(ctl, _("cannot close volume %s"), name);
        goto cleanup;
    }

    ret = true;

cleanup:
    VIR_FORCE_CLOSE(fd);
    if (!ret && created)
        unlink(file);
    if (vol)
        virStorageVolFree(vol);
    if (st)
        virStreamFree(st);
    return ret;
}
Пример #18
0
static int testFDStreamReadCommon(const char *scratchdir, bool blocking)
{
    int fd = -1;
    char *file = NULL;
    int ret = -1;
    char *pattern = NULL;
    char *buf = NULL;
    virStreamPtr st = NULL;
    size_t i;
    virConnectPtr conn = NULL;
    int flags = 0;

    if (!blocking)
        flags |= VIR_STREAM_NONBLOCK;

    if (!(conn = virConnectOpen("test:///default")))
        goto cleanup;

    if (VIR_ALLOC_N(pattern, PATTERN_LEN) < 0 ||
        VIR_ALLOC_N(buf, PATTERN_LEN) < 0)
        goto cleanup;

    for (i = 0; i < PATTERN_LEN; i++)
        pattern[i] = i;

    if (virAsprintf(&file, "%s/input.data", scratchdir) < 0)
        goto cleanup;

    if ((fd = open(file, O_CREAT|O_WRONLY|O_EXCL, 0600)) < 0)
        goto cleanup;

    for (i = 0; i < 10; i++) {
        if (safewrite(fd, pattern, PATTERN_LEN) != PATTERN_LEN)
            goto cleanup;
    }

    if (VIR_CLOSE(fd) < 0)
        goto cleanup;

    if (!(st = virStreamNew(conn, flags)))
        goto cleanup;

    /* Start reading 1/2 way through first pattern
     * and end 1/2 way through last pattern
     */
    if (virFDStreamOpenFile(st, file,
                            PATTERN_LEN / 2, PATTERN_LEN * 9,
                            O_RDONLY) < 0)
        goto cleanup;

    for (i = 0; i < 10; i++) {
        size_t offset = 0;
        size_t want;
        if (i == 0)
            want = PATTERN_LEN / 2;
        else
            want = PATTERN_LEN;

        while (want > 0) {
            int got;
        reread:
            got = st->driver->streamRecv(st, buf + offset, want);
            if (got < 0) {
                if (got == -2 && !blocking) {
                    usleep(20 * 1000);
                    goto reread;
                }
                virFilePrintf(stderr, "Failed to read stream: %s\n",
                              virGetLastErrorMessage());
                goto cleanup;
            }
            if (got == 0) {
                /* Expect EOF 1/2 through last pattern */
                if (i == 9 && want == (PATTERN_LEN / 2))
                    break;
                virFilePrintf(stderr, "Unexpected EOF block %zu want %zu\n",
                              i, want);
                goto cleanup;
            }
            offset += got;
            want -= got;
        }
        if (i == 0) {
            if (memcmp(buf, pattern + (PATTERN_LEN / 2), PATTERN_LEN / 2) != 0) {
                virFilePrintf(stderr, "Mismatched pattern data iteration %zu\n", i);
                goto cleanup;
            }
        } else if (i == 9) {
            if (memcmp(buf, pattern, PATTERN_LEN / 2) != 0) {
                virFilePrintf(stderr, "Mismatched pattern data iteration %zu\n", i);
                goto cleanup;
            }
        } else {
            if (memcmp(buf, pattern, PATTERN_LEN) != 0) {
                virFilePrintf(stderr, "Mismatched pattern data iteration %zu\n", i);
                goto cleanup;
            }
        }
    }

    if (st->driver->streamFinish(st) != 0) {
        virFilePrintf(stderr, "Failed to finish stream: %s\n",
                      virGetLastErrorMessage());
        goto cleanup;
    }

    ret = 0;
cleanup:
    if (st)
        virStreamFree(st);
    VIR_FORCE_CLOSE(fd);
    if (file != NULL)
        unlink(file);
    if (conn)
        virConnectClose(conn);
    VIR_FREE(file);
    VIR_FREE(pattern);
    VIR_FREE(buf);
    return ret;
}