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
;
597 /* only used to avoid a leak if entries was NULL */
598 struct V9fsDirent
*unused_entries
= NULL
;
602 v9fs_req_recv(req
, P9_RREADDIR
);
603 v9fs_uint32_read(req
, &local_count
);
606 *count
= local_count
;
609 for (int32_t togo
= (int32_t)local_count
;
610 togo
>= 13 + 8 + 1 + 2;
611 togo
-= 13 + 8 + 1 + 2 + slen
, ++n
)
614 e
= g_new(struct V9fsDirent
, 1);
621 e
= e
->next
= g_new(struct V9fsDirent
, 1);
624 /* qid[13] offset[8] type[1] name[s] */
625 v9fs_memread(req
, &e
->qid
, 13);
626 v9fs_uint64_read(req
, &e
->offset
);
627 v9fs_uint8_read(req
, &e
->type
);
628 v9fs_string_read(req
, &slen
, &e
->name
);
635 v9fs_free_dirents(unused_entries
);
639 void v9fs_free_dirents(struct V9fsDirent
*e
)
641 struct V9fsDirent
*next
= NULL
;
643 for (; e
; e
= next
) {
650 /* size[4] Tlopen tag[2] fid[4] flags[4] */
651 TLOpenRes
v9fs_tlopen(TLOpenOpt opt
)
656 g_assert(opt
.client
);
657 /* expecting either Rlopen or Rlerror, but obviously not both */
658 g_assert(!opt
.expectErr
|| !(opt
.rlopen
.qid
|| opt
.rlopen
.iounit
));
660 req
= v9fs_req_init(opt
.client
, 4 + 4, P9_TLOPEN
, opt
.tag
);
661 v9fs_uint32_write(req
, opt
.fid
);
662 v9fs_uint32_write(req
, opt
.flags
);
665 if (!opt
.requestOnly
) {
666 v9fs_req_wait_for_reply(req
, NULL
);
668 v9fs_rlerror(req
, &err
);
669 g_assert_cmpint(err
, ==, opt
.expectErr
);
671 v9fs_rlopen(req
, opt
.rlopen
.qid
, opt
.rlopen
.iounit
);
673 req
= NULL
; /* request was freed */
676 return (TLOpenRes
) { .req
= req
};
679 /* size[4] Rlopen tag[2] qid[13] iounit[4] */
680 void v9fs_rlopen(P9Req
*req
, v9fs_qid
*qid
, uint32_t *iounit
)
682 v9fs_req_recv(req
, P9_RLOPEN
);
684 v9fs_memread(req
, qid
, 13);
686 v9fs_memskip(req
, 13);
689 v9fs_uint32_read(req
, iounit
);
694 /* size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count] */
695 TWriteRes
v9fs_twrite(TWriteOpt opt
)
699 uint32_t body_size
= 4 + 8 + 4;
700 uint32_t written
= 0;
702 g_assert(opt
.client
);
704 g_assert_cmpint(body_size
, <=, UINT32_MAX
- opt
.count
);
705 body_size
+= opt
.count
;
706 req
= v9fs_req_init(opt
.client
, body_size
, P9_TWRITE
, opt
.tag
);
707 v9fs_uint32_write(req
, opt
.fid
);
708 v9fs_uint64_write(req
, opt
.offset
);
709 v9fs_uint32_write(req
, opt
.count
);
710 v9fs_memwrite(req
, opt
.data
, opt
.count
);
713 if (!opt
.requestOnly
) {
714 v9fs_req_wait_for_reply(req
, NULL
);
716 v9fs_rlerror(req
, &err
);
717 g_assert_cmpint(err
, ==, opt
.expectErr
);
719 v9fs_rwrite(req
, &written
);
721 req
= NULL
; /* request was freed */
730 /* size[4] Rwrite tag[2] count[4] */
731 void v9fs_rwrite(P9Req
*req
, uint32_t *count
)
733 v9fs_req_recv(req
, P9_RWRITE
);
735 v9fs_uint32_read(req
, count
);
740 /* size[4] Tflush tag[2] oldtag[2] */
741 TFlushRes
v9fs_tflush(TFlushOpt opt
)
746 g_assert(opt
.client
);
748 req
= v9fs_req_init(opt
.client
, 2, P9_TFLUSH
, opt
.tag
);
749 v9fs_uint32_write(req
, opt
.oldtag
);
752 if (!opt
.requestOnly
) {
753 v9fs_req_wait_for_reply(req
, NULL
);
755 v9fs_rlerror(req
, &err
);
756 g_assert_cmpint(err
, ==, opt
.expectErr
);
760 req
= NULL
; /* request was freed */
763 return (TFlushRes
) { .req
= req
};
766 /* size[4] Rflush tag[2] */
767 void v9fs_rflush(P9Req
*req
)
769 v9fs_req_recv(req
, P9_RFLUSH
);
773 /* size[4] Tmkdir tag[2] dfid[4] name[s] mode[4] gid[4] */
774 TMkdirRes
v9fs_tmkdir(TMkdirOpt opt
)
779 g_assert(opt
.client
);
780 /* expecting either hi-level atPath or low-level dfid, but not both */
781 g_assert(!opt
.atPath
|| !opt
.dfid
);
782 /* expecting either Rmkdir or Rlerror, but obviously not both */
783 g_assert(!opt
.expectErr
|| !opt
.rmkdir
.qid
);
786 opt
.dfid
= v9fs_twalk((TWalkOpt
) { .client
= opt
.client
,
787 .path
= opt
.atPath
}).newfid
;
794 uint32_t body_size
= 4 + 4 + 4;
795 uint16_t string_size
= v9fs_string_size(opt
.name
);
797 g_assert_cmpint(body_size
, <=, UINT32_MAX
- string_size
);
798 body_size
+= string_size
;
800 req
= v9fs_req_init(opt
.client
, body_size
, P9_TMKDIR
, opt
.tag
);
801 v9fs_uint32_write(req
, opt
.dfid
);
802 v9fs_string_write(req
, opt
.name
);
803 v9fs_uint32_write(req
, opt
.mode
);
804 v9fs_uint32_write(req
, opt
.gid
);
807 if (!opt
.requestOnly
) {
808 v9fs_req_wait_for_reply(req
, NULL
);
810 v9fs_rlerror(req
, &err
);
811 g_assert_cmpint(err
, ==, opt
.expectErr
);
813 v9fs_rmkdir(req
, opt
.rmkdir
.qid
);
815 req
= NULL
; /* request was freed */
818 return (TMkdirRes
) { .req
= req
};
821 /* size[4] Rmkdir tag[2] qid[13] */
822 void v9fs_rmkdir(P9Req
*req
, v9fs_qid
*qid
)
824 v9fs_req_recv(req
, P9_RMKDIR
);
826 v9fs_memread(req
, qid
, 13);
828 v9fs_memskip(req
, 13);
833 /* size[4] Tlcreate tag[2] fid[4] name[s] flags[4] mode[4] gid[4] */
834 TlcreateRes
v9fs_tlcreate(TlcreateOpt opt
)
839 g_assert(opt
.client
);
840 /* expecting either hi-level atPath or low-level fid, but not both */
841 g_assert(!opt
.atPath
|| !opt
.fid
);
842 /* expecting either Rlcreate or Rlerror, but obviously not both */
843 g_assert(!opt
.expectErr
|| !(opt
.rlcreate
.qid
|| opt
.rlcreate
.iounit
));
846 opt
.fid
= v9fs_twalk((TWalkOpt
) { .client
= opt
.client
,
847 .path
= opt
.atPath
}).newfid
;
854 uint32_t body_size
= 4 + 4 + 4 + 4;
855 uint16_t string_size
= v9fs_string_size(opt
.name
);
857 g_assert_cmpint(body_size
, <=, UINT32_MAX
- string_size
);
858 body_size
+= string_size
;
860 req
= v9fs_req_init(opt
.client
, body_size
, P9_TLCREATE
, opt
.tag
);
861 v9fs_uint32_write(req
, opt
.fid
);
862 v9fs_string_write(req
, opt
.name
);
863 v9fs_uint32_write(req
, opt
.flags
);
864 v9fs_uint32_write(req
, opt
.mode
);
865 v9fs_uint32_write(req
, opt
.gid
);
868 if (!opt
.requestOnly
) {
869 v9fs_req_wait_for_reply(req
, NULL
);
871 v9fs_rlerror(req
, &err
);
872 g_assert_cmpint(err
, ==, opt
.expectErr
);
874 v9fs_rlcreate(req
, opt
.rlcreate
.qid
, opt
.rlcreate
.iounit
);
876 req
= NULL
; /* request was freed */
879 return (TlcreateRes
) { .req
= req
};
882 /* size[4] Rlcreate tag[2] qid[13] iounit[4] */
883 void v9fs_rlcreate(P9Req
*req
, v9fs_qid
*qid
, uint32_t *iounit
)
885 v9fs_req_recv(req
, P9_RLCREATE
);
887 v9fs_memread(req
, qid
, 13);
889 v9fs_memskip(req
, 13);
892 v9fs_uint32_read(req
, iounit
);
897 /* size[4] Tsymlink tag[2] fid[4] name[s] symtgt[s] gid[4] */
898 TsymlinkRes
v9fs_tsymlink(TsymlinkOpt opt
)
903 g_assert(opt
.client
);
904 /* expecting either hi-level atPath or low-level fid, but not both */
905 g_assert(!opt
.atPath
|| !opt
.fid
);
906 /* expecting either Rsymlink or Rlerror, but obviously not both */
907 g_assert(!opt
.expectErr
|| !opt
.rsymlink
.qid
);
910 opt
.fid
= v9fs_twalk((TWalkOpt
) { .client
= opt
.client
,
911 .path
= opt
.atPath
}).newfid
;
914 uint32_t body_size
= 4 + 4;
915 uint16_t string_size
= v9fs_string_size(opt
.name
) +
916 v9fs_string_size(opt
.symtgt
);
918 g_assert_cmpint(body_size
, <=, UINT32_MAX
- string_size
);
919 body_size
+= string_size
;
921 req
= v9fs_req_init(opt
.client
, body_size
, P9_TSYMLINK
, opt
.tag
);
922 v9fs_uint32_write(req
, opt
.fid
);
923 v9fs_string_write(req
, opt
.name
);
924 v9fs_string_write(req
, opt
.symtgt
);
925 v9fs_uint32_write(req
, opt
.gid
);
928 if (!opt
.requestOnly
) {
929 v9fs_req_wait_for_reply(req
, NULL
);
931 v9fs_rlerror(req
, &err
);
932 g_assert_cmpint(err
, ==, opt
.expectErr
);
934 v9fs_rsymlink(req
, opt
.rsymlink
.qid
);
936 req
= NULL
; /* request was freed */
939 return (TsymlinkRes
) { .req
= req
};
942 /* size[4] Rsymlink tag[2] qid[13] */
943 void v9fs_rsymlink(P9Req
*req
, v9fs_qid
*qid
)
945 v9fs_req_recv(req
, P9_RSYMLINK
);
947 v9fs_memread(req
, qid
, 13);
949 v9fs_memskip(req
, 13);
954 /* size[4] Tlink tag[2] dfid[4] fid[4] name[s] */
955 TlinkRes
v9fs_tlink(TlinkOpt opt
)
960 g_assert(opt
.client
);
961 /* expecting either hi-level atPath or low-level dfid, but not both */
962 g_assert(!opt
.atPath
|| !opt
.dfid
);
963 /* expecting either hi-level toPath or low-level fid, but not both */
964 g_assert(!opt
.toPath
|| !opt
.fid
);
967 opt
.dfid
= v9fs_twalk((TWalkOpt
) { .client
= opt
.client
,
968 .path
= opt
.atPath
}).newfid
;
971 opt
.fid
= v9fs_twalk((TWalkOpt
) { .client
= opt
.client
,
972 .path
= opt
.toPath
}).newfid
;
975 uint32_t body_size
= 4 + 4;
976 uint16_t string_size
= v9fs_string_size(opt
.name
);
978 g_assert_cmpint(body_size
, <=, UINT32_MAX
- string_size
);
979 body_size
+= string_size
;
981 req
= v9fs_req_init(opt
.client
, body_size
, P9_TLINK
, opt
.tag
);
982 v9fs_uint32_write(req
, opt
.dfid
);
983 v9fs_uint32_write(req
, opt
.fid
);
984 v9fs_string_write(req
, opt
.name
);
987 if (!opt
.requestOnly
) {
988 v9fs_req_wait_for_reply(req
, NULL
);
990 v9fs_rlerror(req
, &err
);
991 g_assert_cmpint(err
, ==, opt
.expectErr
);
995 req
= NULL
; /* request was freed */
998 return (TlinkRes
) { .req
= req
};
1001 /* size[4] Rlink tag[2] */
1002 void v9fs_rlink(P9Req
*req
)
1004 v9fs_req_recv(req
, P9_RLINK
);
1008 /* size[4] Tunlinkat tag[2] dirfd[4] name[s] flags[4] */
1009 TunlinkatRes
v9fs_tunlinkat(TunlinkatOpt opt
)
1014 g_assert(opt
.client
);
1015 /* expecting either hi-level atPath or low-level dirfd, but not both */
1016 g_assert(!opt
.atPath
|| !opt
.dirfd
);
1019 opt
.dirfd
= v9fs_twalk((TWalkOpt
) { .client
= opt
.client
,
1020 .path
= opt
.atPath
}).newfid
;
1023 uint32_t body_size
= 4 + 4;
1024 uint16_t string_size
= v9fs_string_size(opt
.name
);
1026 g_assert_cmpint(body_size
, <=, UINT32_MAX
- string_size
);
1027 body_size
+= string_size
;
1029 req
= v9fs_req_init(opt
.client
, body_size
, P9_TUNLINKAT
, opt
.tag
);
1030 v9fs_uint32_write(req
, opt
.dirfd
);
1031 v9fs_string_write(req
, opt
.name
);
1032 v9fs_uint32_write(req
, opt
.flags
);
1035 if (!opt
.requestOnly
) {
1036 v9fs_req_wait_for_reply(req
, NULL
);
1037 if (opt
.expectErr
) {
1038 v9fs_rlerror(req
, &err
);
1039 g_assert_cmpint(err
, ==, opt
.expectErr
);
1041 v9fs_runlinkat(req
);
1043 req
= NULL
; /* request was freed */
1046 return (TunlinkatRes
) { .req
= req
};
1049 /* size[4] Runlinkat tag[2] */
1050 void v9fs_runlinkat(P9Req
*req
)
1052 v9fs_req_recv(req
, P9_RUNLINKAT
);