]>
git.proxmox.com Git - mirror_qemu.git/blob - tests/qtest/libqos/virtio-9p-client.c
2 * 9P network client for VirtIO 9P test cases (based on QTest)
4 * Copyright (c) 2014 SUSE LINUX Products GmbH
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
11 * Not so fast! You might want to read the 9p developer docs first:
12 * https://wiki.qemu.org/Documentation/9p
15 #include "qemu/osdep.h"
16 #include "virtio-9p-client.h"
18 #define QVIRTIO_9P_TIMEOUT_US (10 * 1000 * 1000)
19 static QGuestAllocator
*alloc
;
21 void v9fs_set_allocator(QGuestAllocator
*t_alloc
)
27 * Used to auto generate new fids. Start with arbitrary high value to avoid
28 * collision with hard coded fids in basic test code.
30 static uint32_t fid_generator
= 1000;
32 static uint32_t genfid(void)
34 return fid_generator
++;
38 * Splits the @a in string by @a delim into individual (non empty) strings
39 * and outputs them to @a out. The output array @a out is NULL terminated.
41 * Output array @a out must be freed by calling split_free().
43 * @returns number of individual elements in output array @a out (without the
44 * final NULL terminating element)
46 static int split(const char *in
, const char *delim
, char ***out
)
52 for (p
= strtok(tmp
, delim
); p
!= NULL
; p
= strtok(NULL
, delim
)) {
59 *out
= g_new0(char *, n
+ 1); /* last element NULL delimiter */
62 for (p
= strtok(tmp
, delim
); p
!= NULL
; p
= strtok(NULL
, delim
)) {
64 (*out
)[i
++] = g_strdup(p
);
72 static void split_free(char ***out
)
78 for (i
= 0; (*out
)[i
]; ++i
) {
85 void v9fs_memwrite(P9Req
*req
, const void *addr
, size_t len
)
87 qtest_memwrite(req
->qts
, req
->t_msg
+ req
->t_off
, addr
, len
);
91 void v9fs_memskip(P9Req
*req
, size_t len
)
96 void v9fs_memread(P9Req
*req
, void *addr
, size_t len
)
98 qtest_memread(req
->qts
, req
->r_msg
+ req
->r_off
, addr
, len
);
102 void v9fs_uint8_read(P9Req
*req
, uint8_t *val
)
104 v9fs_memread(req
, val
, 1);
107 void v9fs_uint16_write(P9Req
*req
, uint16_t val
)
109 uint16_t le_val
= cpu_to_le16(val
);
111 v9fs_memwrite(req
, &le_val
, 2);
114 void v9fs_uint16_read(P9Req
*req
, uint16_t *val
)
116 v9fs_memread(req
, val
, 2);
120 void v9fs_uint32_write(P9Req
*req
, uint32_t val
)
122 uint32_t le_val
= cpu_to_le32(val
);
124 v9fs_memwrite(req
, &le_val
, 4);
127 void v9fs_uint64_write(P9Req
*req
, uint64_t val
)
129 uint64_t le_val
= cpu_to_le64(val
);
131 v9fs_memwrite(req
, &le_val
, 8);
134 void v9fs_uint32_read(P9Req
*req
, uint32_t *val
)
136 v9fs_memread(req
, val
, 4);
140 void v9fs_uint64_read(P9Req
*req
, uint64_t *val
)
142 v9fs_memread(req
, val
, 8);
146 /* len[2] string[len] */
147 uint16_t v9fs_string_size(const char *string
)
149 size_t len
= strlen(string
);
151 g_assert_cmpint(len
, <=, UINT16_MAX
- 2);
156 void v9fs_string_write(P9Req
*req
, const char *string
)
158 int len
= strlen(string
);
160 g_assert_cmpint(len
, <=, UINT16_MAX
);
162 v9fs_uint16_write(req
, (uint16_t) len
);
163 v9fs_memwrite(req
, string
, len
);
166 void v9fs_string_read(P9Req
*req
, uint16_t *len
, char **string
)
170 v9fs_uint16_read(req
, &local_len
);
175 *string
= g_malloc(local_len
+ 1);
176 v9fs_memread(req
, *string
, local_len
);
177 (*string
)[local_len
] = 0;
179 v9fs_memskip(req
, local_len
);
189 P9Req
*v9fs_req_init(QVirtio9P
*v9p
, uint32_t size
, uint8_t id
,
192 P9Req
*req
= g_new0(P9Req
, 1);
193 uint32_t total_size
= 7; /* 9P header has well-known size of 7 bytes */
196 .tag
= cpu_to_le16(tag
)
199 g_assert_cmpint(total_size
, <=, UINT32_MAX
- size
);
201 hdr
.size
= cpu_to_le32(total_size
);
203 g_assert_cmpint(total_size
, <=, P9_MAX_SIZE
);
205 req
->qts
= global_qtest
;
207 req
->t_size
= total_size
;
208 req
->t_msg
= guest_alloc(alloc
, req
->t_size
);
209 v9fs_memwrite(req
, &hdr
, 7);
214 void v9fs_req_send(P9Req
*req
)
216 QVirtio9P
*v9p
= req
->v9p
;
218 req
->r_msg
= guest_alloc(alloc
, P9_MAX_SIZE
);
219 req
->free_head
= qvirtqueue_add(req
->qts
, v9p
->vq
, req
->t_msg
, req
->t_size
,
221 qvirtqueue_add(req
->qts
, v9p
->vq
, req
->r_msg
, P9_MAX_SIZE
, true, false);
222 qvirtqueue_kick(req
->qts
, v9p
->vdev
, v9p
->vq
, req
->free_head
);
226 static const char *rmessage_name(uint8_t id
)
229 id
== P9_RLERROR
? "RLERROR" :
230 id
== P9_RVERSION
? "RVERSION" :
231 id
== P9_RATTACH
? "RATTACH" :
232 id
== P9_RWALK
? "RWALK" :
233 id
== P9_RLOPEN
? "RLOPEN" :
234 id
== P9_RWRITE
? "RWRITE" :
235 id
== P9_RMKDIR
? "RMKDIR" :
236 id
== P9_RLCREATE
? "RLCREATE" :
237 id
== P9_RSYMLINK
? "RSYMLINK" :
238 id
== P9_RLINK
? "RLINK" :
239 id
== P9_RUNLINKAT
? "RUNLINKAT" :
240 id
== P9_RFLUSH
? "RFLUSH" :
241 id
== P9_RREADDIR
? "READDIR" :
245 void v9fs_req_wait_for_reply(P9Req
*req
, uint32_t *len
)
247 QVirtio9P
*v9p
= req
->v9p
;
249 qvirtio_wait_used_elem(req
->qts
, v9p
->vdev
, v9p
->vq
, req
->free_head
, len
,
250 QVIRTIO_9P_TIMEOUT_US
);
253 void v9fs_req_recv(P9Req
*req
, uint8_t id
)
257 v9fs_memread(req
, &hdr
, 7);
258 hdr
.size
= ldl_le_p(&hdr
.size
);
259 hdr
.tag
= lduw_le_p(&hdr
.tag
);
261 g_assert_cmpint(hdr
.size
, >=, 7);
262 g_assert_cmpint(hdr
.size
, <=, P9_MAX_SIZE
);
263 g_assert_cmpint(hdr
.tag
, ==, req
->tag
);
266 g_printerr("Received response %d (%s) instead of %d (%s)\n",
267 hdr
.id
, rmessage_name(hdr
.id
), id
, rmessage_name(id
));
269 if (hdr
.id
== P9_RLERROR
) {
271 v9fs_uint32_read(req
, &err
);
272 g_printerr("Rlerror has errno %d (%s)\n", err
, strerror(err
));
275 g_assert_cmpint(hdr
.id
, ==, id
);
278 void v9fs_req_free(P9Req
*req
)
280 guest_free(alloc
, req
->t_msg
);
281 guest_free(alloc
, req
->r_msg
);
285 /* size[4] Rlerror tag[2] ecode[4] */
286 void v9fs_rlerror(P9Req
*req
, uint32_t *err
)
288 v9fs_req_recv(req
, P9_RLERROR
);
289 v9fs_uint32_read(req
, err
);
293 /* size[4] Tversion tag[2] msize[4] version[s] */
294 TVersionRes
v9fs_tversion(TVersionOpt opt
)
298 uint32_t body_size
= 4;
299 uint16_t string_size
;
301 g_autofree
char *server_version
= NULL
;
303 g_assert(opt
.client
);
306 opt
.msize
= P9_MAX_SIZE
;
314 opt
.version
= "9P2000.L";
317 string_size
= v9fs_string_size(opt
.version
);
318 g_assert_cmpint(body_size
, <=, UINT32_MAX
- string_size
);
319 body_size
+= string_size
;
320 req
= v9fs_req_init(opt
.client
, body_size
, P9_TVERSION
, opt
.tag
);
322 v9fs_uint32_write(req
, opt
.msize
);
323 v9fs_string_write(req
, opt
.version
);
326 if (!opt
.requestOnly
) {
327 v9fs_req_wait_for_reply(req
, NULL
);
329 v9fs_rlerror(req
, &err
);
330 g_assert_cmpint(err
, ==, opt
.expectErr
);
332 v9fs_rversion(req
, &server_len
, &server_version
);
333 g_assert_cmpmem(server_version
, server_len
,
334 opt
.version
, strlen(opt
.version
));
336 req
= NULL
; /* request was freed */
339 return (TVersionRes
) {
344 /* size[4] Rversion tag[2] msize[4] version[s] */
345 void v9fs_rversion(P9Req
*req
, uint16_t *len
, char **version
)
349 v9fs_req_recv(req
, P9_RVERSION
);
350 v9fs_uint32_read(req
, &msize
);
352 g_assert_cmpint(msize
, ==, P9_MAX_SIZE
);
354 if (len
|| version
) {
355 v9fs_string_read(req
, len
, version
);
361 /* size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s] n_uname[4] */
362 TAttachRes
v9fs_tattach(TAttachOpt opt
)
365 const char *uname
= ""; /* ignored by QEMU */
366 const char *aname
= ""; /* ignored by QEMU */
368 g_assert(opt
.client
);
369 /* expecting either Rattach or Rlerror, but obviously not both */
370 g_assert(!opt
.expectErr
|| !opt
.rattach
.qid
);
372 if (!opt
.requestOnly
) {
373 v9fs_tversion((TVersionOpt
) { .client
= opt
.client
});
377 opt
.n_uname
= getuid();
380 P9Req
*req
= v9fs_req_init(opt
.client
, 4 + 4 + 2 + 2 + 4, P9_TATTACH
,
383 v9fs_uint32_write(req
, opt
.fid
);
384 v9fs_uint32_write(req
, P9_NOFID
);
385 v9fs_string_write(req
, uname
);
386 v9fs_string_write(req
, aname
);
387 v9fs_uint32_write(req
, opt
.n_uname
);
390 if (!opt
.requestOnly
) {
391 v9fs_req_wait_for_reply(req
, NULL
);
393 v9fs_rlerror(req
, &err
);
394 g_assert_cmpint(err
, ==, opt
.expectErr
);
396 v9fs_rattach(req
, opt
.rattach
.qid
);
398 req
= NULL
; /* request was freed */
401 return (TAttachRes
) {
406 /* size[4] Rattach tag[2] qid[13] */
407 void v9fs_rattach(P9Req
*req
, v9fs_qid
*qid
)
409 v9fs_req_recv(req
, P9_RATTACH
);
411 v9fs_memread(req
, qid
, 13);
416 /* size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s]) */
417 TWalkRes
v9fs_twalk(TWalkOpt opt
)
421 uint32_t body_size
= 4 + 4 + 2;
423 char **wnames
= NULL
;
425 g_assert(opt
.client
);
426 /* expecting either high- or low-level path, both not both */
427 g_assert(!opt
.path
|| !(opt
.nwname
|| opt
.wnames
));
428 /* expecting either Rwalk or Rlerror, but obviously not both */
429 g_assert(!opt
.expectErr
|| !(opt
.rwalk
.nwqid
|| opt
.rwalk
.wqid
));
432 opt
.newfid
= genfid();
436 opt
.nwname
= split(opt
.path
, "/", &wnames
);
440 for (i
= 0; i
< opt
.nwname
; i
++) {
441 uint16_t wname_size
= v9fs_string_size(opt
.wnames
[i
]);
443 g_assert_cmpint(body_size
, <=, UINT32_MAX
- wname_size
);
444 body_size
+= wname_size
;
446 req
= v9fs_req_init(opt
.client
, body_size
, P9_TWALK
, opt
.tag
);
447 v9fs_uint32_write(req
, opt
.fid
);
448 v9fs_uint32_write(req
, opt
.newfid
);
449 v9fs_uint16_write(req
, opt
.nwname
);
450 for (i
= 0; i
< opt
.nwname
; i
++) {
451 v9fs_string_write(req
, opt
.wnames
[i
]);
455 if (!opt
.requestOnly
) {
456 v9fs_req_wait_for_reply(req
, NULL
);
458 v9fs_rlerror(req
, &err
);
459 g_assert_cmpint(err
, ==, opt
.expectErr
);
461 v9fs_rwalk(req
, opt
.rwalk
.nwqid
, opt
.rwalk
.wqid
);
463 req
= NULL
; /* request was freed */
469 .newfid
= opt
.newfid
,
474 /* size[4] Rwalk tag[2] nwqid[2] nwqid*(wqid[13]) */
475 void v9fs_rwalk(P9Req
*req
, uint16_t *nwqid
, v9fs_qid
**wqid
)
477 uint16_t local_nwqid
;
479 v9fs_req_recv(req
, P9_RWALK
);
480 v9fs_uint16_read(req
, &local_nwqid
);
482 *nwqid
= local_nwqid
;
485 *wqid
= g_malloc(local_nwqid
* 13);
486 v9fs_memread(req
, *wqid
, local_nwqid
* 13);
491 /* size[4] Tgetattr tag[2] fid[4] request_mask[8] */
492 TGetAttrRes
v9fs_tgetattr(TGetAttrOpt opt
)
497 g_assert(opt
.client
);
498 /* expecting either Rgetattr or Rlerror, but obviously not both */
499 g_assert(!opt
.expectErr
|| !opt
.rgetattr
.attr
);
501 if (!opt
.request_mask
) {
502 opt
.request_mask
= P9_GETATTR_ALL
;
505 req
= v9fs_req_init(opt
.client
, 4 + 8, P9_TGETATTR
, opt
.tag
);
506 v9fs_uint32_write(req
, opt
.fid
);
507 v9fs_uint64_write(req
, opt
.request_mask
);
510 if (!opt
.requestOnly
) {
511 v9fs_req_wait_for_reply(req
, NULL
);
513 v9fs_rlerror(req
, &err
);
514 g_assert_cmpint(err
, ==, opt
.expectErr
);
516 v9fs_rgetattr(req
, opt
.rgetattr
.attr
);
518 req
= NULL
; /* request was freed */
521 return (TGetAttrRes
) { .req
= req
};
525 * size[4] Rgetattr tag[2] valid[8] qid[13] mode[4] uid[4] gid[4] nlink[8]
526 * rdev[8] size[8] blksize[8] blocks[8]
527 * atime_sec[8] atime_nsec[8] mtime_sec[8] mtime_nsec[8]
528 * ctime_sec[8] ctime_nsec[8] btime_sec[8] btime_nsec[8]
529 * gen[8] data_version[8]
531 void v9fs_rgetattr(P9Req
*req
, v9fs_attr
*attr
)
533 v9fs_req_recv(req
, P9_RGETATTR
);
535 v9fs_uint64_read(req
, &attr
->valid
);
536 v9fs_memread(req
, &attr
->qid
, 13);
537 v9fs_uint32_read(req
, &attr
->mode
);
538 v9fs_uint32_read(req
, &attr
->uid
);
539 v9fs_uint32_read(req
, &attr
->gid
);
540 v9fs_uint64_read(req
, &attr
->nlink
);
541 v9fs_uint64_read(req
, &attr
->rdev
);
542 v9fs_uint64_read(req
, &attr
->size
);
543 v9fs_uint64_read(req
, &attr
->blksize
);
544 v9fs_uint64_read(req
, &attr
->blocks
);
545 v9fs_uint64_read(req
, &attr
->atime_sec
);
546 v9fs_uint64_read(req
, &attr
->atime_nsec
);
547 v9fs_uint64_read(req
, &attr
->mtime_sec
);
548 v9fs_uint64_read(req
, &attr
->mtime_nsec
);
549 v9fs_uint64_read(req
, &attr
->ctime_sec
);
550 v9fs_uint64_read(req
, &attr
->ctime_nsec
);
551 v9fs_uint64_read(req
, &attr
->btime_sec
);
552 v9fs_uint64_read(req
, &attr
->btime_nsec
);
553 v9fs_uint64_read(req
, &attr
->gen
);
554 v9fs_uint64_read(req
, &attr
->data_version
);
559 /* size[4] Treaddir tag[2] fid[4] offset[8] count[4] */
560 TReadDirRes
v9fs_treaddir(TReadDirOpt opt
)
565 g_assert(opt
.client
);
566 /* expecting either Rreaddir or Rlerror, but obviously not both */
567 g_assert(!opt
.expectErr
|| !(opt
.rreaddir
.count
||
568 opt
.rreaddir
.nentries
|| opt
.rreaddir
.entries
));
570 req
= v9fs_req_init(opt
.client
, 4 + 8 + 4, P9_TREADDIR
, opt
.tag
);
571 v9fs_uint32_write(req
, opt
.fid
);
572 v9fs_uint64_write(req
, opt
.offset
);
573 v9fs_uint32_write(req
, opt
.count
);
576 if (!opt
.requestOnly
) {
577 v9fs_req_wait_for_reply(req
, NULL
);
579 v9fs_rlerror(req
, &err
);
580 g_assert_cmpint(err
, ==, opt
.expectErr
);
582 v9fs_rreaddir(req
, opt
.rreaddir
.count
, opt
.rreaddir
.nentries
,
583 opt
.rreaddir
.entries
);
585 req
= NULL
; /* request was freed */
588 return (TReadDirRes
) { .req
= req
};
591 /* size[4] Rreaddir tag[2] count[4] data[count] */
592 void v9fs_rreaddir(P9Req
*req
, uint32_t *count
, uint32_t *nentries
,
593 struct V9fsDirent
**entries
)
595 uint32_t local_count
;
596 struct V9fsDirent
*e
= NULL
;
600 v9fs_req_recv(req
, P9_RREADDIR
);
601 v9fs_uint32_read(req
, &local_count
);
604 *count
= local_count
;
607 for (int32_t togo
= (int32_t)local_count
;
608 togo
>= 13 + 8 + 1 + 2;
609 togo
-= 13 + 8 + 1 + 2 + slen
, ++n
)
612 e
= g_new(struct V9fsDirent
, 1);
617 e
= e
->next
= g_new(struct V9fsDirent
, 1);
620 /* qid[13] offset[8] type[1] name[s] */
621 v9fs_memread(req
, &e
->qid
, 13);
622 v9fs_uint64_read(req
, &e
->offset
);
623 v9fs_uint8_read(req
, &e
->type
);
624 v9fs_string_read(req
, &slen
, &e
->name
);
634 void v9fs_free_dirents(struct V9fsDirent
*e
)
636 struct V9fsDirent
*next
= NULL
;
638 for (; e
; e
= next
) {
645 /* size[4] Tlopen tag[2] fid[4] flags[4] */
646 TLOpenRes
v9fs_tlopen(TLOpenOpt opt
)
651 g_assert(opt
.client
);
652 /* expecting either Rlopen or Rlerror, but obviously not both */
653 g_assert(!opt
.expectErr
|| !(opt
.rlopen
.qid
|| opt
.rlopen
.iounit
));
655 req
= v9fs_req_init(opt
.client
, 4 + 4, P9_TLOPEN
, opt
.tag
);
656 v9fs_uint32_write(req
, opt
.fid
);
657 v9fs_uint32_write(req
, opt
.flags
);
660 if (!opt
.requestOnly
) {
661 v9fs_req_wait_for_reply(req
, NULL
);
663 v9fs_rlerror(req
, &err
);
664 g_assert_cmpint(err
, ==, opt
.expectErr
);
666 v9fs_rlopen(req
, opt
.rlopen
.qid
, opt
.rlopen
.iounit
);
668 req
= NULL
; /* request was freed */
671 return (TLOpenRes
) { .req
= req
};
674 /* size[4] Rlopen tag[2] qid[13] iounit[4] */
675 void v9fs_rlopen(P9Req
*req
, v9fs_qid
*qid
, uint32_t *iounit
)
677 v9fs_req_recv(req
, P9_RLOPEN
);
679 v9fs_memread(req
, qid
, 13);
681 v9fs_memskip(req
, 13);
684 v9fs_uint32_read(req
, iounit
);
689 /* size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count] */
690 P9Req
*v9fs_twrite(QVirtio9P
*v9p
, uint32_t fid
, uint64_t offset
,
691 uint32_t count
, const void *data
, uint16_t tag
)
694 uint32_t body_size
= 4 + 8 + 4;
696 g_assert_cmpint(body_size
, <=, UINT32_MAX
- count
);
698 req
= v9fs_req_init(v9p
, body_size
, P9_TWRITE
, tag
);
699 v9fs_uint32_write(req
, fid
);
700 v9fs_uint64_write(req
, offset
);
701 v9fs_uint32_write(req
, count
);
702 v9fs_memwrite(req
, data
, count
);
707 /* size[4] Rwrite tag[2] count[4] */
708 void v9fs_rwrite(P9Req
*req
, uint32_t *count
)
710 v9fs_req_recv(req
, P9_RWRITE
);
712 v9fs_uint32_read(req
, count
);
717 /* size[4] Tflush tag[2] oldtag[2] */
718 P9Req
*v9fs_tflush(QVirtio9P
*v9p
, uint16_t oldtag
, uint16_t tag
)
722 req
= v9fs_req_init(v9p
, 2, P9_TFLUSH
, tag
);
723 v9fs_uint32_write(req
, oldtag
);
728 /* size[4] Rflush tag[2] */
729 void v9fs_rflush(P9Req
*req
)
731 v9fs_req_recv(req
, P9_RFLUSH
);
735 /* size[4] Tmkdir tag[2] dfid[4] name[s] mode[4] gid[4] */
736 P9Req
*v9fs_tmkdir(QVirtio9P
*v9p
, uint32_t dfid
, const char *name
,
737 uint32_t mode
, uint32_t gid
, uint16_t tag
)
741 uint32_t body_size
= 4 + 4 + 4;
742 uint16_t string_size
= v9fs_string_size(name
);
744 g_assert_cmpint(body_size
, <=, UINT32_MAX
- string_size
);
745 body_size
+= string_size
;
747 req
= v9fs_req_init(v9p
, body_size
, P9_TMKDIR
, tag
);
748 v9fs_uint32_write(req
, dfid
);
749 v9fs_string_write(req
, name
);
750 v9fs_uint32_write(req
, mode
);
751 v9fs_uint32_write(req
, gid
);
756 /* size[4] Rmkdir tag[2] qid[13] */
757 void v9fs_rmkdir(P9Req
*req
, v9fs_qid
*qid
)
759 v9fs_req_recv(req
, P9_RMKDIR
);
761 v9fs_memread(req
, qid
, 13);
763 v9fs_memskip(req
, 13);
768 /* size[4] Tlcreate tag[2] fid[4] name[s] flags[4] mode[4] gid[4] */
769 P9Req
*v9fs_tlcreate(QVirtio9P
*v9p
, uint32_t fid
, const char *name
,
770 uint32_t flags
, uint32_t mode
, uint32_t gid
,
775 uint32_t body_size
= 4 + 4 + 4 + 4;
776 uint16_t string_size
= v9fs_string_size(name
);
778 g_assert_cmpint(body_size
, <=, UINT32_MAX
- string_size
);
779 body_size
+= string_size
;
781 req
= v9fs_req_init(v9p
, body_size
, P9_TLCREATE
, tag
);
782 v9fs_uint32_write(req
, fid
);
783 v9fs_string_write(req
, name
);
784 v9fs_uint32_write(req
, flags
);
785 v9fs_uint32_write(req
, mode
);
786 v9fs_uint32_write(req
, gid
);
791 /* size[4] Rlcreate tag[2] qid[13] iounit[4] */
792 void v9fs_rlcreate(P9Req
*req
, v9fs_qid
*qid
, uint32_t *iounit
)
794 v9fs_req_recv(req
, P9_RLCREATE
);
796 v9fs_memread(req
, qid
, 13);
798 v9fs_memskip(req
, 13);
801 v9fs_uint32_read(req
, iounit
);
806 /* size[4] Tsymlink tag[2] fid[4] name[s] symtgt[s] gid[4] */
807 P9Req
*v9fs_tsymlink(QVirtio9P
*v9p
, uint32_t fid
, const char *name
,
808 const char *symtgt
, uint32_t gid
, uint16_t tag
)
812 uint32_t body_size
= 4 + 4;
813 uint16_t string_size
= v9fs_string_size(name
) + v9fs_string_size(symtgt
);
815 g_assert_cmpint(body_size
, <=, UINT32_MAX
- string_size
);
816 body_size
+= string_size
;
818 req
= v9fs_req_init(v9p
, body_size
, P9_TSYMLINK
, tag
);
819 v9fs_uint32_write(req
, fid
);
820 v9fs_string_write(req
, name
);
821 v9fs_string_write(req
, symtgt
);
822 v9fs_uint32_write(req
, gid
);
827 /* size[4] Rsymlink tag[2] qid[13] */
828 void v9fs_rsymlink(P9Req
*req
, v9fs_qid
*qid
)
830 v9fs_req_recv(req
, P9_RSYMLINK
);
832 v9fs_memread(req
, qid
, 13);
834 v9fs_memskip(req
, 13);
839 /* size[4] Tlink tag[2] dfid[4] fid[4] name[s] */
840 P9Req
*v9fs_tlink(QVirtio9P
*v9p
, uint32_t dfid
, uint32_t fid
,
841 const char *name
, uint16_t tag
)
845 uint32_t body_size
= 4 + 4;
846 uint16_t string_size
= v9fs_string_size(name
);
848 g_assert_cmpint(body_size
, <=, UINT32_MAX
- string_size
);
849 body_size
+= string_size
;
851 req
= v9fs_req_init(v9p
, body_size
, P9_TLINK
, tag
);
852 v9fs_uint32_write(req
, dfid
);
853 v9fs_uint32_write(req
, fid
);
854 v9fs_string_write(req
, name
);
859 /* size[4] Rlink tag[2] */
860 void v9fs_rlink(P9Req
*req
)
862 v9fs_req_recv(req
, P9_RLINK
);
866 /* size[4] Tunlinkat tag[2] dirfd[4] name[s] flags[4] */
867 P9Req
*v9fs_tunlinkat(QVirtio9P
*v9p
, uint32_t dirfd
, const char *name
,
868 uint32_t flags
, uint16_t tag
)
872 uint32_t body_size
= 4 + 4;
873 uint16_t string_size
= v9fs_string_size(name
);
875 g_assert_cmpint(body_size
, <=, UINT32_MAX
- string_size
);
876 body_size
+= string_size
;
878 req
= v9fs_req_init(v9p
, body_size
, P9_TUNLINKAT
, tag
);
879 v9fs_uint32_write(req
, dirfd
);
880 v9fs_string_write(req
, name
);
881 v9fs_uint32_write(req
, flags
);
886 /* size[4] Runlinkat tag[2] */
887 void v9fs_runlinkat(P9Req
*req
)
889 v9fs_req_recv(req
, P9_RUNLINKAT
);