summary refs log tree commit diff stats
path: root/tests/qtest/libqos/virtio-9p-client.c
diff options
context:
space:
mode:
authorChristian Schoenebeck <qemu_oss@crudebyte.com>2022-10-04 22:53:23 +0200
committerChristian Schoenebeck <qemu_oss@crudebyte.com>2022-10-24 12:24:32 +0200
commit569f3b63ad5f65d0f86724766fedfffffe0feda3 (patch)
tree216e9409b002b15b583e1126f88ab62df58792e2 /tests/qtest/libqos/virtio-9p-client.c
parentf5265c8f917ea8c71a30e549b7e3017c1038db63 (diff)
downloadfocaccia-qemu-569f3b63ad5f65d0f86724766fedfffffe0feda3.tar.gz
focaccia-qemu-569f3b63ad5f65d0f86724766fedfffffe0feda3.zip
tests/9p: merge *walk*() functions
Introduce declarative function calls.

There are currently 4 different functions for sending a 9p 'Twalk'
request: v9fs_twalk(), do_walk(), do_walk_rqids() and
do_walk_expect_error(). They are all doing the same thing, just in a
slightly different way and with slightly different function arguments.

Merge those 4 functions into a single function by using a struct for
function call arguments and use designated initializers when calling
this function to turn usage into a declarative approach, which is
better readable and easier to maintain.

Also move private functions genfid(), split() and split_free() from
virtio-9p-test.c to virtio-9p-client.c.

Based-on: <E1odrya-0004Fv-97@lizzy.crudebyte.com>
Signed-off-by: Christian Schoenebeck <qemu_oss@crudebyte.com>
Message-Id: <607969dbfbc63c1be008df9131133711b046e979.1664917004.git.qemu_oss@crudebyte.com>
Diffstat (limited to 'tests/qtest/libqos/virtio-9p-client.c')
-rw-r--r--tests/qtest/libqos/virtio-9p-client.c114
1 files changed, 103 insertions, 11 deletions
diff --git a/tests/qtest/libqos/virtio-9p-client.c b/tests/qtest/libqos/virtio-9p-client.c
index f5c35fd722..a95bbad9c8 100644
--- a/tests/qtest/libqos/virtio-9p-client.c
+++ b/tests/qtest/libqos/virtio-9p-client.c
@@ -23,6 +23,65 @@ void v9fs_set_allocator(QGuestAllocator *t_alloc)
     alloc = t_alloc;
 }
 
+/*
+ * Used to auto generate new fids. Start with arbitrary high value to avoid
+ * collision with hard coded fids in basic test code.
+ */
+static uint32_t fid_generator = 1000;
+
+static uint32_t genfid(void)
+{
+    return fid_generator++;
+}
+
+/**
+ * Splits the @a in string by @a delim into individual (non empty) strings
+ * and outputs them to @a out. The output array @a out is NULL terminated.
+ *
+ * Output array @a out must be freed by calling split_free().
+ *
+ * @returns number of individual elements in output array @a out (without the
+ *          final NULL terminating element)
+ */
+static int split(const char *in, const char *delim, char ***out)
+{
+    int n = 0, i = 0;
+    char *tmp, *p;
+
+    tmp = g_strdup(in);
+    for (p = strtok(tmp, delim); p != NULL; p = strtok(NULL, delim)) {
+        if (strlen(p) > 0) {
+            ++n;
+        }
+    }
+    g_free(tmp);
+
+    *out = g_new0(char *, n + 1); /* last element NULL delimiter */
+
+    tmp = g_strdup(in);
+    for (p = strtok(tmp, delim); p != NULL; p = strtok(NULL, delim)) {
+        if (strlen(p) > 0) {
+            (*out)[i++] = g_strdup(p);
+        }
+    }
+    g_free(tmp);
+
+    return n;
+}
+
+static void split_free(char ***out)
+{
+    int i;
+    if (!*out) {
+        return;
+    }
+    for (i = 0; (*out)[i]; ++i) {
+        g_free((*out)[i]);
+    }
+    g_free(*out);
+    *out = NULL;
+}
+
 void v9fs_memwrite(P9Req *req, const void *addr, size_t len)
 {
     qtest_memwrite(req->qts, req->t_msg + req->t_off, addr, len);
@@ -294,28 +353,61 @@ void v9fs_rattach(P9Req *req, v9fs_qid *qid)
 }
 
 /* size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s]) */
-P9Req *v9fs_twalk(QVirtio9P *v9p, uint32_t fid, uint32_t newfid,
-                  uint16_t nwname, char *const wnames[], uint16_t tag)
+TWalkRes v9fs_twalk(TWalkOpt opt)
 {
     P9Req *req;
     int i;
     uint32_t body_size = 4 + 4 + 2;
+    uint32_t err;
+    char **wnames = NULL;
+
+    g_assert(opt.client);
+    /* expecting either high- or low-level path, both not both */
+    g_assert(!opt.path || !(opt.nwname || opt.wnames));
+    /* expecting either Rwalk or Rlerror, but obviously not both */
+    g_assert(!opt.expectErr || !(opt.rwalk.nwqid || opt.rwalk.wqid));
+
+    if (!opt.newfid) {
+        opt.newfid = genfid();
+    }
+
+    if (opt.path) {
+        opt.nwname = split(opt.path, "/", &wnames);
+        opt.wnames = wnames;
+    }
 
-    for (i = 0; i < nwname; i++) {
-        uint16_t wname_size = v9fs_string_size(wnames[i]);
+    for (i = 0; i < opt.nwname; i++) {
+        uint16_t wname_size = v9fs_string_size(opt.wnames[i]);
 
         g_assert_cmpint(body_size, <=, UINT32_MAX - wname_size);
         body_size += wname_size;
     }
-    req = v9fs_req_init(v9p,  body_size, P9_TWALK, tag);
-    v9fs_uint32_write(req, fid);
-    v9fs_uint32_write(req, newfid);
-    v9fs_uint16_write(req, nwname);
-    for (i = 0; i < nwname; i++) {
-        v9fs_string_write(req, wnames[i]);
+    req = v9fs_req_init(opt.client, body_size, P9_TWALK, opt.tag);
+    v9fs_uint32_write(req, opt.fid);
+    v9fs_uint32_write(req, opt.newfid);
+    v9fs_uint16_write(req, opt.nwname);
+    for (i = 0; i < opt.nwname; i++) {
+        v9fs_string_write(req, opt.wnames[i]);
     }
     v9fs_req_send(req);
-    return req;
+
+    if (!opt.requestOnly) {
+        v9fs_req_wait_for_reply(req, NULL);
+        if (opt.expectErr) {
+            v9fs_rlerror(req, &err);
+            g_assert_cmpint(err, ==, opt.expectErr);
+        } else {
+            v9fs_rwalk(req, opt.rwalk.nwqid, opt.rwalk.wqid);
+        }
+        req = NULL; /* request was freed */
+    }
+
+    split_free(&wnames);
+
+    return (TWalkRes) {
+        .newfid = opt.newfid,
+        .req = req,
+    };
 }
 
 /* size[4] Rwalk tag[2] nwqid[2] nwqid*(wqid[13]) */