qemu-ga patch queue for 2.5
* include additional w32 MSI install components needed for guest-exec * fix 'make install' when compiling with --disable-tools * fix potential data corruption/loss when accessing files bi-directionally via guest-file-{read,write} * explicitly document how integer args for guest-file-seek map to SEEK_SET/SEEK_CUR/etc to avoid platform-specific differences v2: * fixed missing SoB -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJWVks1AAoJEDNTyc7xCLWE0/oH/3q9DtEGB5dDUMCn3BPo+FCO M7R4uL1MB2CSXHPZxpoueZL2ZNlCpWJgidOEfVTyVrPUI68qsEcPm2vmKAQu5y7e Dxu+yD+qA3wWqgNRhH6O7X7owq+e5cM8ZZFPZ2T89wgsQbs+TwyrOfJfypIP/cAW cjnowxVz9kB9f0qpOJViPN0lfbtc+n5pZOm2VNluHtEWCHS8X9tqvSDtHgIU/BKV 39y/UeSKNmvl7UlTeRi6dVUbKPo1eZSExjvHoWZjXBOu3Ky75wineVMASxuC632y IQG+1YIBl5vv84he29U6O5lW2rcbld6vff8QqvR8HzNIxnD8kfykkpmxHlxWDIA= =bIkC -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/mdroth/tags/qga-pull-2015-11-25-v2-tag' into staging qemu-ga patch queue for 2.5 * include additional w32 MSI install components needed for guest-exec * fix 'make install' when compiling with --disable-tools * fix potential data corruption/loss when accessing files bi-directionally via guest-file-{read,write} * explicitly document how integer args for guest-file-seek map to SEEK_SET/SEEK_CUR/etc to avoid platform-specific differences v2: * fixed missing SoB # gpg: Signature made Wed 25 Nov 2015 23:58:45 GMT using RSA key ID F108B584 # gpg: Good signature from "Michael Roth <flukshun@gmail.com>" # gpg: aka "Michael Roth <mdroth@utexas.edu>" # gpg: aka "Michael Roth <mdroth@linux.vnet.ibm.com>" * remotes/mdroth/tags/qga-pull-2015-11-25-v2-tag: qga: added another non-interactive gspawn() helper file. qga: Better mapping of SEEK_* in guest-file-seek tests: add file-write-read test qga: flush explicitly when needed qga: gspawn() console helper to Windows guest agent msi build makefile: fix qemu-ga make install for --disable-tools Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
b8b0ee0ea3
5
Makefile
5
Makefile
@ -440,10 +440,7 @@ endif
|
||||
install: all $(if $(BUILD_DOCS),install-doc) \
|
||||
install-datadir install-localstatedir
|
||||
ifneq ($(TOOLS),)
|
||||
$(call install-prog,$(filter-out qemu-ga,$(TOOLS)),$(DESTDIR)$(bindir))
|
||||
ifneq (,$(findstring qemu-ga,$(TOOLS)))
|
||||
$(call install-prog,qemu-ga$(EXESUF),$(DESTDIR)$(bindir))
|
||||
endif
|
||||
$(call install-prog,$(subst qemu-ga,qemu-ga$(EXESUF),$(TOOLS)),$(DESTDIR)$(bindir))
|
||||
endif
|
||||
ifneq ($(CONFIG_MODULES),)
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_moddir)"
|
||||
|
@ -216,9 +216,16 @@ void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
RW_STATE_NEW,
|
||||
RW_STATE_READING,
|
||||
RW_STATE_WRITING,
|
||||
} RwState;
|
||||
|
||||
typedef struct GuestFileHandle {
|
||||
uint64_t id;
|
||||
FILE *fh;
|
||||
RwState state;
|
||||
QTAILQ_ENTRY(GuestFileHandle) next;
|
||||
} GuestFileHandle;
|
||||
|
||||
@ -460,6 +467,17 @@ struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
|
||||
}
|
||||
|
||||
fh = gfh->fh;
|
||||
|
||||
/* explicitly flush when switching from writing to reading */
|
||||
if (gfh->state == RW_STATE_WRITING) {
|
||||
int ret = fflush(fh);
|
||||
if (ret == EOF) {
|
||||
error_setg_errno(errp, errno, "failed to flush file");
|
||||
return NULL;
|
||||
}
|
||||
gfh->state = RW_STATE_NEW;
|
||||
}
|
||||
|
||||
buf = g_malloc0(count+1);
|
||||
read_count = fread(buf, 1, count, fh);
|
||||
if (ferror(fh)) {
|
||||
@ -473,6 +491,7 @@ struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
|
||||
if (read_count) {
|
||||
read_data->buf_b64 = g_base64_encode(buf, read_count);
|
||||
}
|
||||
gfh->state = RW_STATE_READING;
|
||||
}
|
||||
g_free(buf);
|
||||
clearerr(fh);
|
||||
@ -496,6 +515,16 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
|
||||
}
|
||||
|
||||
fh = gfh->fh;
|
||||
|
||||
if (gfh->state == RW_STATE_READING) {
|
||||
int ret = fseek(fh, 0, SEEK_CUR);
|
||||
if (ret == -1) {
|
||||
error_setg_errno(errp, errno, "failed to seek file");
|
||||
return NULL;
|
||||
}
|
||||
gfh->state = RW_STATE_NEW;
|
||||
}
|
||||
|
||||
buf = g_base64_decode(buf_b64, &buf_len);
|
||||
|
||||
if (!has_count) {
|
||||
@ -515,6 +544,7 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
|
||||
write_data = g_new0(GuestFileWrite, 1);
|
||||
write_data->count = write_count;
|
||||
write_data->eof = feof(fh);
|
||||
gfh->state = RW_STATE_WRITING;
|
||||
}
|
||||
g_free(buf);
|
||||
clearerr(fh);
|
||||
@ -523,25 +553,47 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
|
||||
}
|
||||
|
||||
struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
|
||||
int64_t whence, Error **errp)
|
||||
int64_t whence_code, Error **errp)
|
||||
{
|
||||
GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
|
||||
GuestFileSeek *seek_data = NULL;
|
||||
FILE *fh;
|
||||
int ret;
|
||||
int whence;
|
||||
|
||||
if (!gfh) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We stupidly exposed 'whence':'int' in our qapi */
|
||||
switch (whence_code) {
|
||||
case QGA_SEEK_SET:
|
||||
whence = SEEK_SET;
|
||||
break;
|
||||
case QGA_SEEK_CUR:
|
||||
whence = SEEK_CUR;
|
||||
break;
|
||||
case QGA_SEEK_END:
|
||||
whence = SEEK_END;
|
||||
break;
|
||||
default:
|
||||
error_setg(errp, "invalid whence code %"PRId64, whence_code);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fh = gfh->fh;
|
||||
ret = fseek(fh, offset, whence);
|
||||
if (ret == -1) {
|
||||
error_setg_errno(errp, errno, "failed to seek file");
|
||||
if (errno == ESPIPE) {
|
||||
/* file is non-seekable, stdio shouldn't be buffering anyways */
|
||||
gfh->state = RW_STATE_NEW;
|
||||
}
|
||||
} else {
|
||||
seek_data = g_new0(GuestFileSeek, 1);
|
||||
seek_data->position = ftell(fh);
|
||||
seek_data->eof = feof(fh);
|
||||
gfh->state = RW_STATE_NEW;
|
||||
}
|
||||
clearerr(fh);
|
||||
|
||||
@ -562,6 +614,8 @@ void qmp_guest_file_flush(int64_t handle, Error **errp)
|
||||
ret = fflush(fh);
|
||||
if (ret == EOF) {
|
||||
error_setg_errno(errp, errno, "failed to flush file");
|
||||
} else {
|
||||
gfh->state = RW_STATE_NEW;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -382,7 +382,7 @@ done:
|
||||
}
|
||||
|
||||
GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
|
||||
int64_t whence, Error **errp)
|
||||
int64_t whence_code, Error **errp)
|
||||
{
|
||||
GuestFileHandle *gfh;
|
||||
GuestFileSeek *seek_data;
|
||||
@ -390,11 +390,29 @@ GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
|
||||
LARGE_INTEGER new_pos, off_pos;
|
||||
off_pos.QuadPart = offset;
|
||||
BOOL res;
|
||||
int whence;
|
||||
|
||||
gfh = guest_file_handle_find(handle, errp);
|
||||
if (!gfh) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We stupidly exposed 'whence':'int' in our qapi */
|
||||
switch (whence_code) {
|
||||
case QGA_SEEK_SET:
|
||||
whence = SEEK_SET;
|
||||
break;
|
||||
case QGA_SEEK_CUR:
|
||||
whence = SEEK_CUR;
|
||||
break;
|
||||
case QGA_SEEK_END:
|
||||
whence = SEEK_END;
|
||||
break;
|
||||
default:
|
||||
error_setg(errp, "invalid whence code %"PRId64, whence_code);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fh = gfh->fh;
|
||||
res = SetFilePointerEx(fh, off_pos, &new_pos, whence);
|
||||
if (!res) {
|
||||
|
@ -15,6 +15,13 @@
|
||||
|
||||
#define QGA_READ_COUNT_DEFAULT 4096
|
||||
|
||||
/* Mapping of whence codes used by guest-file-seek. */
|
||||
enum {
|
||||
QGA_SEEK_SET = 0,
|
||||
QGA_SEEK_CUR = 1,
|
||||
QGA_SEEK_END = 2,
|
||||
};
|
||||
|
||||
typedef struct GAState GAState;
|
||||
typedef struct GACommandState GACommandState;
|
||||
extern GAState *ga_state;
|
||||
|
@ -91,6 +91,22 @@
|
||||
<File Id="qga_vss.tlb" Name="qga-vss.tlb" Source="$(env.BUILD_DIR)/qga/vss-win32/qga-vss.tlb" KeyPath="yes" DiskId="1"/>
|
||||
</Component>
|
||||
<?endif?>
|
||||
<?if $(var.Arch) = "32"?>
|
||||
<Component Id="gspawn-helper-console" Guid="{446185B3-87BE-43D2-96B8-0FEFD9E8696D}">
|
||||
<File Id="gspawn-win32-helper-console.exe" Name="gspawn-win32-helper-console.exe" Source="$(var.Mingw_bin)/gspawn-win32-helper-console.exe" KeyPath="yes" DiskId="1"/>
|
||||
</Component>
|
||||
<Component Id="gspawn-helper" Guid="{CD67A5A3-2DB1-4DA1-A67A-8D71E797B466}">
|
||||
<File Id="gspawn-win32-helper.exe" Name="gspawn-win32-helper.exe" Source="$(var.Mingw_bin)/gspawn-win32-helper.exe" KeyPath="yes" DiskId="1"/>
|
||||
</Component>
|
||||
<?endif?>
|
||||
<?if $(var.Arch) = "64"?>
|
||||
<Component Id="gspawn-helper-console" Guid="{9E615A9F-349A-4992-A5C2-C10BAD173660}">
|
||||
<File Id="gspawn-win64-helper-console.exe" Name="gspawn-win64-helper-console.exe" Source="$(var.Mingw_bin)/gspawn-win64-helper-console.exe" KeyPath="yes" DiskId="1"/>
|
||||
</Component>
|
||||
<Component Id="gspawn-helper" Guid="{D201AD22-1846-4E4F-B6E1-C7A908ED2457}">
|
||||
<File Id="gspawn-win64-helper.exe" Name="gspawn-win64-helper.exe" Source="$(var.Mingw_bin)/gspawn-win64-helper.exe" KeyPath="yes" DiskId="1"/>
|
||||
</Component>
|
||||
<?endif?>
|
||||
<Component Id="iconv" Guid="{35EE3558-D34B-4F0A-B8BD-430FF0775246}">
|
||||
<File Id="iconv.dll" Name="iconv.dll" Source="$(var.Mingw_bin)/iconv.dll" KeyPath="yes" DiskId="1"/>
|
||||
</Component>
|
||||
@ -148,6 +164,8 @@
|
||||
<ComponentRef Id="qga_vss_dll" />
|
||||
<ComponentRef Id="qga_vss_tlb" />
|
||||
<?endif?>
|
||||
<ComponentRef Id="gspawn-helper-console" />
|
||||
<ComponentRef Id="gspawn-helper" />
|
||||
<ComponentRef Id="iconv" />
|
||||
<ComponentRef Id="libgcc_arch_lib" />
|
||||
<ComponentRef Id="libglib" />
|
||||
|
@ -318,13 +318,13 @@
|
||||
#
|
||||
# Seek to a position in the file, as with fseek(), and return the
|
||||
# current file position afterward. Also encapsulates ftell()'s
|
||||
# functionality, just Set offset=0, whence=SEEK_CUR.
|
||||
# functionality, with offset=0 and whence=1.
|
||||
#
|
||||
# @handle: filehandle returned by guest-file-open
|
||||
#
|
||||
# @offset: bytes to skip over in the file stream
|
||||
#
|
||||
# @whence: SEEK_SET, SEEK_CUR, or SEEK_END, as with fseek()
|
||||
# @whence: 0 for SEEK_SET, 1 for SEEK_CUR, or 2 for SEEK_END
|
||||
#
|
||||
# Returns: @GuestFileSeek on success.
|
||||
#
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "libqtest.h"
|
||||
#include "config-host.h"
|
||||
#include "qga/guest-agent-core.h"
|
||||
|
||||
typedef struct {
|
||||
char *test_dir;
|
||||
@ -352,10 +353,10 @@ static void test_qga_network_get_interfaces(gconstpointer fix)
|
||||
static void test_qga_file_ops(gconstpointer fix)
|
||||
{
|
||||
const TestFixture *fixture = fix;
|
||||
const guchar helloworld[] = "Hello World!\n";
|
||||
const unsigned char helloworld[] = "Hello World!\n";
|
||||
const char *b64;
|
||||
gchar *cmd, *path, *enc;
|
||||
guchar *dec;
|
||||
unsigned char *dec;
|
||||
QDict *ret, *val;
|
||||
int64_t id, eof;
|
||||
gsize count;
|
||||
@ -457,7 +458,7 @@ static void test_qga_file_ops(gconstpointer fix)
|
||||
cmd = g_strdup_printf("{'execute': 'guest-file-seek',"
|
||||
" 'arguments': { 'handle': %" PRId64 ", "
|
||||
" 'offset': %d, 'whence': %d } }",
|
||||
id, 6, SEEK_SET);
|
||||
id, 6, QGA_SEEK_SET);
|
||||
ret = qmp_fd(fixture->fd, cmd);
|
||||
qmp_assert_no_error(ret);
|
||||
val = qdict_get_qdict(ret, "return");
|
||||
@ -496,6 +497,96 @@ static void test_qga_file_ops(gconstpointer fix)
|
||||
g_free(cmd);
|
||||
}
|
||||
|
||||
static void test_qga_file_write_read(gconstpointer fix)
|
||||
{
|
||||
const TestFixture *fixture = fix;
|
||||
const unsigned char helloworld[] = "Hello World!\n";
|
||||
const char *b64;
|
||||
gchar *cmd, *enc;
|
||||
QDict *ret, *val;
|
||||
int64_t id, eof;
|
||||
gsize count;
|
||||
|
||||
/* open */
|
||||
ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
|
||||
" 'arguments': { 'path': 'foo', 'mode': 'w+' } }");
|
||||
g_assert_nonnull(ret);
|
||||
qmp_assert_no_error(ret);
|
||||
id = qdict_get_int(ret, "return");
|
||||
QDECREF(ret);
|
||||
|
||||
enc = g_base64_encode(helloworld, sizeof(helloworld));
|
||||
/* write */
|
||||
cmd = g_strdup_printf("{'execute': 'guest-file-write',"
|
||||
" 'arguments': { 'handle': %" PRId64 ","
|
||||
" 'buf-b64': '%s' } }", id, enc);
|
||||
ret = qmp_fd(fixture->fd, cmd);
|
||||
g_assert_nonnull(ret);
|
||||
qmp_assert_no_error(ret);
|
||||
|
||||
val = qdict_get_qdict(ret, "return");
|
||||
count = qdict_get_int(val, "count");
|
||||
eof = qdict_get_bool(val, "eof");
|
||||
g_assert_cmpint(count, ==, sizeof(helloworld));
|
||||
g_assert_cmpint(eof, ==, 0);
|
||||
QDECREF(ret);
|
||||
g_free(cmd);
|
||||
|
||||
/* read (check implicit flush) */
|
||||
cmd = g_strdup_printf("{'execute': 'guest-file-read',"
|
||||
" 'arguments': { 'handle': %" PRId64 "} }",
|
||||
id);
|
||||
ret = qmp_fd(fixture->fd, cmd);
|
||||
val = qdict_get_qdict(ret, "return");
|
||||
count = qdict_get_int(val, "count");
|
||||
eof = qdict_get_bool(val, "eof");
|
||||
b64 = qdict_get_str(val, "buf-b64");
|
||||
g_assert_cmpint(count, ==, 0);
|
||||
g_assert(eof);
|
||||
g_assert_cmpstr(b64, ==, "");
|
||||
QDECREF(ret);
|
||||
g_free(cmd);
|
||||
|
||||
/* seek to 0 */
|
||||
cmd = g_strdup_printf("{'execute': 'guest-file-seek',"
|
||||
" 'arguments': { 'handle': %" PRId64 ", "
|
||||
" 'offset': %d, 'whence': %d } }",
|
||||
id, 0, QGA_SEEK_SET);
|
||||
ret = qmp_fd(fixture->fd, cmd);
|
||||
qmp_assert_no_error(ret);
|
||||
val = qdict_get_qdict(ret, "return");
|
||||
count = qdict_get_int(val, "position");
|
||||
eof = qdict_get_bool(val, "eof");
|
||||
g_assert_cmpint(count, ==, 0);
|
||||
g_assert(!eof);
|
||||
QDECREF(ret);
|
||||
g_free(cmd);
|
||||
|
||||
/* read */
|
||||
cmd = g_strdup_printf("{'execute': 'guest-file-read',"
|
||||
" 'arguments': { 'handle': %" PRId64 "} }",
|
||||
id);
|
||||
ret = qmp_fd(fixture->fd, cmd);
|
||||
val = qdict_get_qdict(ret, "return");
|
||||
count = qdict_get_int(val, "count");
|
||||
eof = qdict_get_bool(val, "eof");
|
||||
b64 = qdict_get_str(val, "buf-b64");
|
||||
g_assert_cmpint(count, ==, sizeof(helloworld));
|
||||
g_assert(eof);
|
||||
g_assert_cmpstr(b64, ==, enc);
|
||||
QDECREF(ret);
|
||||
g_free(cmd);
|
||||
g_free(enc);
|
||||
|
||||
/* close */
|
||||
cmd = g_strdup_printf("{'execute': 'guest-file-close',"
|
||||
" 'arguments': {'handle': %" PRId64 "} }",
|
||||
id);
|
||||
ret = qmp_fd(fixture->fd, cmd);
|
||||
QDECREF(ret);
|
||||
g_free(cmd);
|
||||
}
|
||||
|
||||
static void test_qga_get_time(gconstpointer fix)
|
||||
{
|
||||
const TestFixture *fixture = fix;
|
||||
@ -762,6 +853,7 @@ int main(int argc, char **argv)
|
||||
g_test_add_data_func("/qga/get-memory-blocks", &fix,
|
||||
test_qga_get_memory_blocks);
|
||||
g_test_add_data_func("/qga/file-ops", &fix, test_qga_file_ops);
|
||||
g_test_add_data_func("/qga/file-write-read", &fix, test_qga_file_write_read);
|
||||
g_test_add_data_func("/qga/get-time", &fix, test_qga_get_time);
|
||||
g_test_add_data_func("/qga/invalid-cmd", &fix, test_qga_invalid_cmd);
|
||||
g_test_add_data_func("/qga/fsfreeze-status", &fix,
|
||||
|
Loading…
x
Reference in New Issue
Block a user