}
+int
+virshStreamSource(virStreamPtr st ATTRIBUTE_UNUSED,
+ char *bytes,
+ size_t nbytes,
+ void *opaque)
+{
+ virshStreamCallbackDataPtr cbData = opaque;
+ int fd = cbData->fd;
+
+ return saferead(fd, bytes, nbytes);
+}
+
+
+int
+virshStreamSourceSkip(virStreamPtr st ATTRIBUTE_UNUSED,
+ long long offset,
+ void *opaque)
+{
+ virshStreamCallbackDataPtr cbData = opaque;
+ int fd = cbData->fd;
+ off_t cur;
+
+ if ((cur = lseek(fd, offset, SEEK_CUR)) == (off_t) -1)
+ return -1;
+
+ return 0;
+}
+
+
int
virshStreamSkip(virStreamPtr st ATTRIBUTE_UNUSED,
long long offset,
}
+int
+virshStreamInData(virStreamPtr st ATTRIBUTE_UNUSED,
+ int *inData,
+ long long *offset,
+ void *opaque)
+{
+ virshStreamCallbackDataPtr cbData = opaque;
+ vshControl *ctl = cbData->ctl;
+ int fd = cbData->fd;
+ int ret;
+
+ if ((ret = virFileInData(fd, inData, offset)) < 0)
+ vshError(ctl, "%s", _("Unable to get current position in stream"));
+
+ return ret;
+}
+
+
void
virshDomainFree(virDomainPtr dom)
{
size_t nbytes,
void *opaque);
+typedef struct _virshStreamCallbackData virshStreamCallbackData;
+typedef virshStreamCallbackData *virshStreamCallbackDataPtr;
+struct _virshStreamCallbackData {
+ vshControl *ctl;
+ int fd;
+};
+
+int
+virshStreamSource(virStreamPtr st,
+ char *bytes,
+ size_t nbytes,
+ void *opaque);
+
+int
+virshStreamSourceSkip(virStreamPtr st,
+ long long offset,
+ void *opaque);
+
int
virshStreamSkip(virStreamPtr st,
long long offset,
void *opaque);
+int
+virshStreamInData(virStreamPtr st,
+ int *inData,
+ long long *offset,
+ void *opaque);
+
int
virshDomainGetXMLFromDom(vshControl *ctl,
virDomainPtr dom,
.type = VSH_OT_INT,
.help = N_("amount of data to upload")
},
+ {.name = "sparse",
+ .type = VSH_OT_BOOL,
+ .help = N_("preserve sparseness of volume")
+ },
{.name = NULL}
};
-static int
-cmdVolUploadSource(virStreamPtr st ATTRIBUTE_UNUSED,
- char *bytes, size_t nbytes, void *opaque)
-{
- int *fd = opaque;
-
- return saferead(*fd, bytes, nbytes);
-}
-
static bool
cmdVolUpload(vshControl *ctl, const vshCmd *cmd)
{
const char *name = NULL;
unsigned long long offset = 0, length = 0;
virshControlPtr priv = ctl->privData;
+ unsigned int flags = 0;
+ virshStreamCallbackData cbData;
if (vshCommandOptULongLong(ctl, cmd, "offset", &offset) < 0)
return false;
goto cleanup;
}
+ cbData.ctl = ctl;
+ cbData.fd = fd;
+
+ if (vshCommandOptBool(cmd, "sparse"))
+ flags |= VIR_STORAGE_VOL_UPLOAD_SPARSE_STREAM;
+
if (!(st = virStreamNew(priv->conn, 0))) {
vshError(ctl, _("cannot create a new stream"));
goto cleanup;
}
- if (virStorageVolUpload(vol, st, offset, length, 0) < 0) {
+ if (virStorageVolUpload(vol, st, offset, length, flags) < 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 (flags & VIR_STORAGE_VOL_UPLOAD_SPARSE_STREAM) {
+ if (virStreamSparseSendAll(st, virshStreamSource,
+ virshStreamInData,
+ virshStreamSourceSkip, &cbData) < 0) {
+ vshError(ctl, _("cannot send data to volume %s"), name);
+ goto cleanup;
+ }
+ } else {
+ if (virStreamSendAll(st, virshStreamSource, &cbData) < 0) {
+ vshError(ctl, _("cannot send data to volume %s"), name);
+ goto cleanup;
+ }
}
if (VIR_CLOSE(fd) < 0) {
support this option, presently only rbd.
=item B<vol-upload> [I<--pool> I<pool-or-uuid>] [I<--offset> I<bytes>]
-[I<--length> I<bytes>] I<vol-name-or-key-or-path> I<local-file>
+[I<--length> I<bytes>] [I<--sparse>] I<vol-name-or-key-or-path> I<local-file>
Upload the contents of I<local-file> to a storage volume.
I<--pool> I<pool-or-uuid> is the name or UUID of the storage pool the volume
is in.
I<vol-name-or-key-or-path> is the name or key or path of the volume where the
file will be uploaded.
+If I<--sparse> is specified, this command will preserve volume sparseness.
I<--offset> is the position in the storage volume at which to start writing
the data. The value must be 0 or larger. I<--length> is an upper bound
of the amount of data to be uploaded. A negative value is interpreted