Magic constants are a pain to use, especially when we run the
risk that our choice of '1' for QGA_SEEK_CUR might differ from
the host or guest's choice of SEEK_CUR.  Better is to use an
enum value, via a qapi alternate type for back-compatibility.

With this,
 {"command":"guest-file-seek", "arguments":{"handle":1,
  "offset":0, "whence":"cur"}}
becomes a synonym for the older
 {"command":"guest-file-seek", "arguments":{"handle":1,
  "offset":0, "whence":1}}

Signed-off-by: Eric Blake <ebl...@redhat.com>

---
v2: rebase on top of qapi work
---
v3: rebase to latest
v2 was here: https://lists.gnu.org/archive/html/qemu-devel/2015-12/msg03565.html
v1 was here: https://lists.gnu.org/archive/html/qemu-devel/2015-11/msg05730.html

 qga/guest-agent-core.h |  9 ++-------
 qga/commands-posix.c   | 19 ++++++-------------
 qga/commands-win32.c   | 19 ++++++-------------
 qga/commands.c         | 21 +++++++++++++++++++++
 tests/test-qga.c       |  9 ++++-----
 qga/qapi-schema.json   | 33 +++++++++++++++++++++++++++++++--
 6 files changed, 70 insertions(+), 40 deletions(-)

diff --git a/qga/guest-agent-core.h b/qga/guest-agent-core.h
index 238dc6b..0a49516 100644
--- a/qga/guest-agent-core.h
+++ b/qga/guest-agent-core.h
@@ -12,16 +12,10 @@
  */
 #include "qapi/qmp/dispatch.h"
 #include "qemu-common.h"
+#include "qga-qmp-commands.h"

 #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;
@@ -44,6 +38,7 @@ void ga_set_frozen(GAState *s);
 void ga_unset_frozen(GAState *s);
 const char *ga_fsfreeze_hook(GAState *s);
 int64_t ga_get_fd_handle(GAState *s, Error **errp);
+int ga_parse_whence(GuestFileWhence *whence, Error **errp);

 #ifndef _WIN32
 void reopen_fd_to_null(int fd);
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 9589b2d..9f51fae 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -550,31 +550,24 @@ 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_code, Error **errp)
+                                          GuestFileWhence *whence_code,
+                                          Error **errp)
 {
     GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
     GuestFileSeek *seek_data = NULL;
     FILE *fh;
     int ret;
     int whence;
+    Error *err = NULL;

     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);
+    whence = ga_parse_whence(whence_code, &err);
+    if (err) {
+        error_propagate(errp, err);
         return NULL;
     }

diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index cf0757c..2799f5f 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -385,7 +385,8 @@ done:
 }

 GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
-                                   int64_t whence_code, Error **errp)
+                                   GuestFileWhence *whence_code,
+                                   Error **errp)
 {
     GuestFileHandle *gfh;
     GuestFileSeek *seek_data;
@@ -394,6 +395,7 @@ GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t 
offset,
     off_pos.QuadPart = offset;
     BOOL res;
     int whence;
+    Error *err = NULL;

     gfh = guest_file_handle_find(handle, errp);
     if (!gfh) {
@@ -401,18 +403,9 @@ GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t 
offset,
     }

     /* 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);
+    whence = ga_parse_whence(whence_code, &err);
+    if (err) {
+        error_propagate(errp, err);
         return NULL;
     }

diff --git a/qga/commands.c b/qga/commands.c
index 5b56786..e091ee1 100644
--- a/qga/commands.c
+++ b/qga/commands.c
@@ -473,3 +473,24 @@ done:

     return ge;
 }
+
+/* Convert GuestFileWhence (either a raw integer or an enum value) into
+ * the guest's SEEK_ constants.  */
+int ga_parse_whence(GuestFileWhence *whence, Error **errp)
+{
+    /* Exploit the fact that we picked values to match QGA_SEEK_*. */
+    if (whence->type == QTYPE_QSTRING) {
+        whence->type = QTYPE_QINT;
+        whence->u.value = whence->u.name;
+    }
+    switch (whence->u.value) {
+    case QGA_SEEK_SET:
+        return SEEK_SET;
+    case QGA_SEEK_CUR:
+        return SEEK_CUR;
+    case QGA_SEEK_END:
+        return SEEK_END;
+    }
+    error_setg(errp, "invalid whence code %"PRId64, whence->u.value);
+    return -1;
+}
diff --git a/tests/test-qga.c b/tests/test-qga.c
index 993b007..4d7542e 100644
--- a/tests/test-qga.c
+++ b/tests/test-qga.c
@@ -7,7 +7,6 @@

 #include "libqtest.h"
 #include "config-host.h"
-#include "qga/guest-agent-core.h"

 typedef struct {
     char *test_dir;
@@ -451,8 +450,8 @@ static void test_qga_file_ops(gconstpointer fix)
     /* seek */
     cmd = g_strdup_printf("{'execute': 'guest-file-seek',"
                           " 'arguments': { 'handle': %" PRId64 ", "
-                          " 'offset': %d, 'whence': %d } }",
-                          id, 6, QGA_SEEK_SET);
+                          " 'offset': %d, 'whence': '%s' } }",
+                          id, 6, "set");
     ret = qmp_fd(fixture->fd, cmd);
     qmp_assert_no_error(ret);
     val = qdict_get_qdict(ret, "return");
@@ -544,8 +543,8 @@ static void test_qga_file_write_read(gconstpointer fix)
     /* seek to 0 */
     cmd = g_strdup_printf("{'execute': 'guest-file-seek',"
                           " 'arguments': { 'handle': %" PRId64 ", "
-                          " 'offset': %d, 'whence': %d } }",
-                          id, 0, QGA_SEEK_SET);
+                          " 'offset': %d, 'whence': '%s' } }",
+                          id, 0, "set");
     ret = qmp_fd(fixture->fd, cmd);
     qmp_assert_no_error(ret);
     val = qdict_get_qdict(ret, "return");
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 01c9ee4..c21f308 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -314,6 +314,34 @@
   'data': { 'position': 'int', 'eof': 'bool' } }

 ##
+# @QGASeek:
+#
+# Symbolic names for use in @guest-file-seek
+#
+# @set: Set to the specified offset (same effect as 'whence':0)
+# @cur: Add offset to the current location (same effect as 'whence':1)
+# @end: Add offset to the end of the file (same effect as 'whence':2)
+#
+# Since: 2.6
+##
+{ 'enum': 'QGASeek', 'data': [ 'set', 'cur', 'end' ] }
+
+##
+# @GuestFileWhence:
+#
+# Controls the meaning of offset to @guest-file-seek.
+#
+# @value: Integral value (0 for set, 1 for cur, 2 for end), available
+#         for historical reasons, and might differ from the host's or
+#         guest's SEEK_* values (since: 0.15)
+# @name: Symbolic name, and preferred interface
+#
+# Since: 2.6
+##
+{ 'alternate': 'GuestFileWhence',
+  'data': { 'value': 'int', 'name': 'QGASeek' } }
+
+##
 # @guest-file-seek:
 #
 # Seek to a position in the file, as with fseek(), and return the
@@ -324,14 +352,15 @@
 #
 # @offset: bytes to skip over in the file stream
 #
-# @whence: 0 for SEEK_SET, 1 for SEEK_CUR, or 2 for SEEK_END
+# @whence: Symbolic or numeric code for interpreting offset
 #
 # Returns: @GuestFileSeek on success.
 #
 # Since: 0.15.0
 ##
 { 'command': 'guest-file-seek',
-  'data':    { 'handle': 'int', 'offset': 'int', 'whence': 'int' },
+  'data':    { 'handle': 'int', 'offset': 'int',
+               'whence': 'GuestFileWhence' },
   'returns': 'GuestFileSeek' }

 ##
-- 
2.5.0


Reply via email to