summaryrefslogtreecommitdiff
path: root/lib9p
diff options
context:
space:
mode:
Diffstat (limited to 'lib9p')
-rw-r--r--lib9p/9p.c164
-rw-r--r--lib9p/9p.generated.c10568
-rw-r--r--lib9p/CMakeLists.txt38
-rwxr-xr-xlib9p/idl.gen1184
-rw-r--r--lib9p/idl/0000-README.md73
-rw-r--r--lib9p/idl/0000-TODO.md11
-rw-r--r--lib9p/idl/1992-9P0.9p.wip166
-rw-r--r--lib9p/idl/1995-9P1.9p.wip141
-rw-r--r--lib9p/idl/1996-Styx.9p.wip66
-rw-r--r--lib9p/idl/2002-9P2000.9p124
-rw-r--r--lib9p/idl/2003-9P2000.p9p.9p49
-rw-r--r--lib9p/idl/2005-9P2000.u.9p35
-rw-r--r--lib9p/idl/2010-9P2000.L.9p230
-rw-r--r--lib9p/idl/2010-9P2000.L.9p.wip56
-rw-r--r--lib9p/idl/2012-9P2000.e.9p8
-rw-r--r--lib9p/idl/__init__.py878
-rw-r--r--lib9p/include/lib9p/9p.generated.h1467
-rw-r--r--lib9p/include/lib9p/9p.h153
-rw-r--r--lib9p/include/lib9p/linux-errno.h2
-rwxr-xr-xlib9p/include/lib9p/linux-errno.h.gen12
-rw-r--r--lib9p/include/lib9p/srv.h190
-rw-r--r--lib9p/internal.h179
-rwxr-xr-xlib9p/linux-errno.txt.gen17
-rw-r--r--lib9p/map.h22
-rwxr-xr-xlib9p/proto.gen15
-rw-r--r--lib9p/protogen/__init__.py57
-rw-r--r--lib9p/protogen/c.py201
-rw-r--r--lib9p/protogen/c9util.py134
-rw-r--r--lib9p/protogen/c_format.py161
-rw-r--r--lib9p/protogen/c_marshal.py403
-rw-r--r--lib9p/protogen/c_unmarshal.py138
-rw-r--r--lib9p/protogen/c_validate.py299
-rw-r--r--lib9p/protogen/cutil.py84
-rw-r--r--lib9p/protogen/h.py535
-rw-r--r--lib9p/protogen/idlutil.py112
-rw-r--r--lib9p/srv.c793
-rw-r--r--lib9p/tables.c188
-rw-r--r--lib9p/tables.h59
-rw-r--r--lib9p/tests/client_config/config.h40
-rwxr-xr-xlib9p/tests/runtest50
-rw-r--r--lib9p/tests/test_compile.c299
-rwxr-xr-xlib9p/tests/test_compile.c.gen19
-rw-r--r--lib9p/tests/test_compile_config/config.h38
-rw-r--r--lib9p/tests/test_server/CMakeLists.txt45
-rw-r--r--lib9p/tests/test_server/config/config.h66
-rw-r--r--lib9p/tests/test_server/fs_shutdown.c93
-rw-r--r--lib9p/tests/test_server/fs_shutdown.h23
-rw-r--r--lib9p/tests/test_server/fs_slowread.c101
-rw-r--r--lib9p/tests/test_server/fs_slowread.h22
-rw-r--r--lib9p/tests/test_server/main.c154
-rw-r--r--lib9p/tests/test_server/static/Documentation/x.txt7
-rw-r--r--lib9p/tests/test_server/static/README.md7
-rwxr-xr-xlib9p/tests/testclient-p9p61
-rw-r--r--lib9p/tests/testclient-p9p.explog106
-rw-r--r--lib9p/tests/testclient-sess.c144
-rw-r--r--lib9p/tests/testclient-sess.explog58
-rw-r--r--lib9p/utf8.h34
57 files changed, 15298 insertions, 5081 deletions
diff --git a/lib9p/9p.c b/lib9p/9p.c
index 9ea0c46..e7b20b5 100644
--- a/lib9p/9p.c
+++ b/lib9p/9p.c
@@ -1,23 +1,53 @@
/* lib9p/9p.c - Base 9P protocol utilities for both clients and servers
*
- * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include <inttypes.h> /* for PRIu{n} */
#include <stdarg.h> /* for va_* */
-#include <stdio.h> /* for vsnprintf() */
#include <string.h> /* for strncpy() */
+#include <libfmt/fmt.h> /* for fmt_vsnprintf() */
+
#include <lib9p/9p.h>
-#include "internal.h"
+/* strings ********************************************************************/
+
+struct lib9p_s lib9p_str(char *s) {
+ if (!s)
+ return (struct lib9p_s){0};
+ return (struct lib9p_s){
+ .len = strlen(s),
+ .utf8 = s,
+ };
+}
+struct lib9p_s lib9p_strn(char *s, size_t maxlen) {
+ if (maxlen == 0 || !s)
+ return (struct lib9p_s){0};
+ return (struct lib9p_s){
+ .len = strnlen(s, maxlen),
+ .utf8 = s,
+ };
+}
+struct lib9p_s lib9p_str_slice(struct lib9p_s s, uint16_t beg, uint16_t end) {
+ assert(s.len == 0 || s.utf8);
+ assert(beg <= end && end <= s.len);
+ return (struct lib9p_s){
+ .len = end - beg,
+ .utf8 = &s.utf8[beg],
+ };
+}
+bool lib9p_str_eq(struct lib9p_s a, struct lib9p_s b) {
+ return a.len == b.len &&
+ (a.len == 0 || memcmp(a.utf8, b.utf8, a.len) == 0);
+}
/* ctx ************************************************************************/
void lib9p_ctx_clear_error(struct lib9p_ctx *ctx) {
assert(ctx);
-#ifdef CONFIG_9P_ENABLE_9P2000_u
+#if CONFIG_9P_ENABLE_9P2000_u
ctx->err_num = 0;
#endif
ctx->err_msg[0] = '\0';
@@ -28,13 +58,13 @@ bool lib9p_ctx_has_error(struct lib9p_ctx *ctx) {
return ctx->err_msg[0];
}
-int lib9p_error(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *msg) {
+int lib9p_error(struct lib9p_ctx *ctx, lib9p_errno_t linux_errno, char const *msg) {
if (lib9p_ctx_has_error(ctx))
return -1;
strncpy(ctx->err_msg, msg, sizeof(ctx->err_msg));
ctx->err_msg[sizeof(ctx->err_msg)-1] = '\0';
-#ifdef CONFIG_9P_ENABLE_9P2000_u
+#if CONFIG_9P_ENABLE_9P2000_u
ctx->err_num = linux_errno;
#else
(void)(linux_errno);
@@ -43,19 +73,19 @@ int lib9p_error(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *msg) {
return -1;
}
-int lib9p_errorf(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *fmt, ...) {
+int lib9p_errorf(struct lib9p_ctx *ctx, lib9p_errno_t linux_errno, char const *fmt, ...) {
int n;
va_list args;
if (lib9p_ctx_has_error(ctx))
return -1;
va_start(args, fmt);
- n = vsnprintf(ctx->err_msg, sizeof(ctx->err_msg), fmt, args);
+ n = fmt_vsnprintf(ctx->err_msg, sizeof(ctx->err_msg), fmt, args);
va_end(args);
if ((size_t)(n+1) < sizeof(ctx->err_msg))
memset(&ctx->err_msg[n+1], 0, sizeof(ctx->err_msg)-(n+1));
-#ifdef CONFIG_9P_ENABLE_9P2000_u
+#if CONFIG_9P_ENABLE_9P2000_u
ctx->err_num = linux_errno;
#else
(void)(linux_errno);
@@ -63,119 +93,3 @@ int lib9p_errorf(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *fmt, .
return -1;
}
-
-const char *lib9p_msg_type_str(struct lib9p_ctx *ctx, enum lib9p_msg_type typ) {
- assert(0 <= typ && typ <= 0xFF);
- return _lib9p_versions[ctx->version].msgs[typ].name;
-}
-
-/* main message functions *****************************************************/
-
-ssize_t lib9p_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes) {
- /* Inspect the first 5 bytes ourselves. */
- struct _validate_ctx subctx = {
- .ctx = ctx,
- .net_size = decode_u32le(net_bytes),
- .net_bytes = net_bytes,
-
- .net_offset = 0,
- .host_extra = 0,
- };
- if (subctx.net_size < 5)
- return lib9p_error(ctx, LINUX_EBADMSG, "message is impossibly short");
- uint8_t typ = net_bytes[4];
- struct _table_msg table = _lib9p_versions[ctx->version].msgs[typ];
- if (!table.validate)
- return lib9p_errorf(ctx, LINUX_EOPNOTSUPP, "unknown message type: %s (protocol_version=%s)",
- lib9p_msg_type_str(ctx, typ), lib9p_version_str(ctx->version));
-
- /* Now use the message-type-specific table to process the whole thing. */
- if (table.validate(&subctx))
- return -1;
- assert(subctx.net_offset <= subctx.net_size);
- if (subctx.net_offset < subctx.net_size)
- return lib9p_errorf(ctx, LINUX_EBADMSG, "message has %"PRIu32" extra bytes",
- subctx.net_size - subctx.net_offset);
-
- /* Return. */
- ssize_t ret;
- if (__builtin_add_overflow(table.basesize, subctx.host_extra, &ret))
- return lib9p_error(ctx, LINUX_EMSGSIZE, "unmarshalled payload overflows SSIZE_MAX");
- return ret;
-}
-
-void lib9p_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
- enum lib9p_msg_type *ret_typ, void *ret_body) {
- struct _unmarshal_ctx subctx = {
- .ctx = ctx,
- .net_bytes = net_bytes,
-
- .net_offset = 0,
- };
-
- *ret_typ = net_bytes[4];
- struct _table_msg table = _lib9p_versions[ctx->version].msgs[*ret_typ];
- subctx.extra = ret_body + table.basesize;
- table.unmarshal(&subctx, ret_body);
-}
-
-bool lib9p_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
- uint8_t *ret_bytes) {
- struct _marshal_ctx subctx = {
- .ctx = ctx,
- .net_bytes = ret_bytes,
- .net_offset = 0,
- };
-
- struct _table_msg table = _lib9p_versions[ctx->version].msgs[typ];
- return table.marshal(&subctx, body);
-}
-
-/* `struct lib9p_stat` helpers ************************************************/
-
-bool lib9p_validate_stat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes,
- uint32_t *ret_net_size, ssize_t *ret_host_size) {
- struct _validate_ctx subctx = {
- .ctx = ctx,
- .net_size = net_size,
- .net_bytes = net_bytes,
-
- .net_offset = 0,
- .host_extra = 0,
- };
- if (_lib9p_validate_stat(&subctx))
- return true;
- if (ret_net_size)
- *ret_net_size = subctx.net_offset;
- if (ret_host_size)
- if (__builtin_add_overflow(sizeof(struct lib9p_stat), subctx.host_extra, ret_host_size))
- return lib9p_error(ctx, LINUX_EMSGSIZE, "unmarshalled stat object overflows SSIZE_MAX");
- return false;
-}
-
-uint32_t lib9p_unmarshal_stat(struct lib9p_ctx *ctx, uint8_t *net_bytes,
- struct lib9p_stat *ret_obj, void *ret_extra) {
- struct _unmarshal_ctx subctx = {
- .ctx = ctx,
- .net_bytes = net_bytes,
- .net_offset = 0,
-
- .extra = ret_extra,
- };
- _lib9p_unmarshal_stat(&subctx, ret_obj);
- return subctx.net_offset;
-}
-
-uint32_t lib9p_marshal_stat(struct lib9p_ctx *ctx, uint32_t max_net_size, struct lib9p_stat *obj,
- uint8_t *ret_bytes) {
- struct lib9p_ctx _ctx = *ctx;
- _ctx.max_msg_size = max_net_size;
- struct _marshal_ctx subctx = {
- .ctx = &_ctx,
- .net_bytes = ret_bytes,
- .net_offset = 0,
- };
- if (_lib9p_marshal_stat(&subctx, obj))
- return 0;
- return subctx.net_offset;
-}
diff --git a/lib9p/9p.generated.c b/lib9p/9p.generated.c
index 6136433..284a0a6 100644
--- a/lib9p/9p.generated.c
+++ b/lib9p/9p.generated.c
@@ -1,2164 +1,7435 @@
-/* Generated by `./lib9p/idl.gen lib9p/idl/2002-9P2000.9p lib9p/idl/2005-9P2000.u.9p lib9p/idl/2012-9P2000.e.9p`. DO NOT EDIT! */
+/* Generated by `lib9p/proto.gen lib9p/idl/2002-9P2000.9p lib9p/idl/2003-9P2000.p9p.9p lib9p/idl/2005-9P2000.u.9p lib9p/idl/2010-9P2000.L.9p lib9p/idl/2012-9P2000.e.9p`. DO NOT EDIT! */
-#include <assert.h>
#include <stdbool.h>
#include <stddef.h> /* for size_t */
#include <inttypes.h> /* for PRI* macros */
#include <string.h> /* for memset() */
+#include <libmisc/assert.h>
+#include <libmisc/endian.h>
+
#include <lib9p/9p.h>
-#include "internal.h"
-
-/* strings ********************************************************************/
-
-static const char *version_strs[LIB9P_VER_NUM] = {
- [LIB9P_VER_unknown] = "unknown",
-#if defined(CONFIG_9P_ENABLE_9P2000)
- [LIB9P_VER_9P2000] = "9P2000",
-#endif /* defined(CONFIG_9P_ENABLE_9P2000) */
-#if defined(CONFIG_9P_ENABLE_9P2000_e)
- [LIB9P_VER_9P2000_e] = "9P2000.e",
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_e) */
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
- [LIB9P_VER_9P2000_u] = "9P2000.u",
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
+#include "tables.h"
+#include "utf8.h"
+
+/* libobj vtables *************************************************************/
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+LO_IMPLEMENTATION_C(fmt_formatter, lib9p_tag_t, lib9p_tag, static);
+LO_IMPLEMENTATION_C(fmt_formatter, lib9p_fid_t, lib9p_fid, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_s, lib9p_s, static);
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+LO_IMPLEMENTATION_C(fmt_formatter, lib9p_dm_t, lib9p_dm, static);
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+LO_IMPLEMENTATION_C(fmt_formatter, lib9p_qt_t, lib9p_qt, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_qid, lib9p_qid, static);
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_stat, lib9p_stat, static);
+LO_IMPLEMENTATION_C(fmt_formatter, lib9p_o_t, lib9p_o, static);
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tversion, lib9p_msg_Tversion, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rversion, lib9p_msg_Rversion, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tauth, lib9p_msg_Tauth, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rauth, lib9p_msg_Rauth, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tattach, lib9p_msg_Tattach, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rattach, lib9p_msg_Rattach, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rerror, lib9p_msg_Rerror, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tflush, lib9p_msg_Tflush, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rflush, lib9p_msg_Rflush, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Twalk, lib9p_msg_Twalk, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rwalk, lib9p_msg_Rwalk, static);
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Topen, lib9p_msg_Topen, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Ropen, lib9p_msg_Ropen, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tcreate, lib9p_msg_Tcreate, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rcreate, lib9p_msg_Rcreate, static);
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tread, lib9p_msg_Tread, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rread, lib9p_msg_Rread, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Twrite, lib9p_msg_Twrite, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rwrite, lib9p_msg_Rwrite, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tclunk, lib9p_msg_Tclunk, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rclunk, lib9p_msg_Rclunk, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tremove, lib9p_msg_Tremove, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rremove, lib9p_msg_Rremove, static);
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tstat, lib9p_msg_Tstat, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rstat, lib9p_msg_Rstat, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Twstat, lib9p_msg_Twstat, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rwstat, lib9p_msg_Rwstat, static);
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Topenfd, lib9p_msg_Topenfd, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Ropenfd, lib9p_msg_Ropenfd, static);
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
+LO_IMPLEMENTATION_C(fmt_formatter, lib9p_nuid_t, lib9p_nuid, static);
+LO_IMPLEMENTATION_C(fmt_formatter, lib9p_errno_t, lib9p_errno, static);
+#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000_L
+LO_IMPLEMENTATION_C(fmt_formatter, lib9p_super_magic_t, lib9p_super_magic, static);
+LO_IMPLEMENTATION_C(fmt_formatter, lib9p_lo_t, lib9p_lo, static);
+LO_IMPLEMENTATION_C(fmt_formatter, lib9p_dt_t, lib9p_dt, static);
+LO_IMPLEMENTATION_C(fmt_formatter, lib9p_mode_t, lib9p_mode, static);
+LO_IMPLEMENTATION_C(fmt_formatter, lib9p_b4_t, lib9p_b4, static);
+LO_IMPLEMENTATION_C(fmt_formatter, lib9p_getattr_t, lib9p_getattr, static);
+LO_IMPLEMENTATION_C(fmt_formatter, lib9p_setattr_t, lib9p_setattr, static);
+LO_IMPLEMENTATION_C(fmt_formatter, lib9p_lock_type_t, lib9p_lock_type, static);
+LO_IMPLEMENTATION_C(fmt_formatter, lib9p_lock_flags_t, lib9p_lock_flags, static);
+LO_IMPLEMENTATION_C(fmt_formatter, lib9p_lock_status_t, lib9p_lock_status, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rlerror, lib9p_msg_Rlerror, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tstatfs, lib9p_msg_Tstatfs, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rstatfs, lib9p_msg_Rstatfs, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tlopen, lib9p_msg_Tlopen, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rlopen, lib9p_msg_Rlopen, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tlcreate, lib9p_msg_Tlcreate, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rlcreate, lib9p_msg_Rlcreate, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tsymlink, lib9p_msg_Tsymlink, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rsymlink, lib9p_msg_Rsymlink, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tmknod, lib9p_msg_Tmknod, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rmknod, lib9p_msg_Rmknod, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Trename, lib9p_msg_Trename, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rrename, lib9p_msg_Rrename, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Treadlink, lib9p_msg_Treadlink, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rreadlink, lib9p_msg_Rreadlink, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tgetattr, lib9p_msg_Tgetattr, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rgetattr, lib9p_msg_Rgetattr, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tsetattr, lib9p_msg_Tsetattr, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rsetattr, lib9p_msg_Rsetattr, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Txattrwalk, lib9p_msg_Txattrwalk, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rxattrwalk, lib9p_msg_Rxattrwalk, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Txattrcreate, lib9p_msg_Txattrcreate, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rxattrcreate, lib9p_msg_Rxattrcreate, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Treaddir, lib9p_msg_Treaddir, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rreaddir, lib9p_msg_Rreaddir, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tfsync, lib9p_msg_Tfsync, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rfsync, lib9p_msg_Rfsync, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tlock, lib9p_msg_Tlock, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rlock, lib9p_msg_Rlock, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tgetlock, lib9p_msg_Tgetlock, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rgetlock, lib9p_msg_Rgetlock, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tlink, lib9p_msg_Tlink, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rlink, lib9p_msg_Rlink, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tmkdir, lib9p_msg_Tmkdir, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rmkdir, lib9p_msg_Rmkdir, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Trenameat, lib9p_msg_Trenameat, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rrenameat, lib9p_msg_Rrenameat, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tunlinkat, lib9p_msg_Tunlinkat, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Runlinkat, lib9p_msg_Runlinkat, static);
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000_e
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tsession, lib9p_msg_Tsession, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rsession, lib9p_msg_Rsession, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tsread, lib9p_msg_Tsread, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rsread, lib9p_msg_Rsread, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Tswrite, lib9p_msg_Tswrite, static);
+LO_IMPLEMENTATION_C(fmt_formatter, struct lib9p_msg_Rswrite, lib9p_msg_Rswrite, static);
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+
+/* utilities ******************************************************************/
+#if CONFIG_9P_ENABLE_9P2000
+ #define _is_ver_9P2000(v) (v == LIB9P_VER_9P2000)
+#else
+ #define _is_ver_9P2000(v) false
+#endif
+#if CONFIG_9P_ENABLE_9P2000_L
+ #define _is_ver_9P2000_L(v) (v == LIB9P_VER_9P2000_L)
+#else
+ #define _is_ver_9P2000_L(v) false
+#endif
+#if CONFIG_9P_ENABLE_9P2000_e
+ #define _is_ver_9P2000_e(v) (v == LIB9P_VER_9P2000_e)
+#else
+ #define _is_ver_9P2000_e(v) false
+#endif
+#if CONFIG_9P_ENABLE_9P2000_p9p
+ #define _is_ver_9P2000_p9p(v) (v == LIB9P_VER_9P2000_p9p)
+#else
+ #define _is_ver_9P2000_p9p(v) false
+#endif
+#if CONFIG_9P_ENABLE_9P2000_u
+ #define _is_ver_9P2000_u(v) (v == LIB9P_VER_9P2000_u)
+#else
+ #define _is_ver_9P2000_u(v) false
+#endif
+
+/**
+ * is_ver(ctx, ver) is essentially `(ctx->version == LIB9P_VER_##ver)`, but
+ * compiles correctly (to `false`) even if `LIB9P_VER_##ver` isn't defined
+ * (because `!CONFIG_9P_ENABLE_##ver`). This is useful when `||`ing
+ * several version checks together.
+ */
+#define is_ver(ctx, ver) _is_ver_##ver((ctx)->version)
+
+/* bitmasks *******************************************************************/
+
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static const lib9p_dm_t dm_masks[LIB9P_VER_NUM] = {
+#if CONFIG_9P_ENABLE_9P2000
+ [LIB9P_VER_9P2000] = 0b11111100000000000000000111111111,
+#endif /* CONFIG_9P_ENABLE_9P2000 */
+#if CONFIG_9P_ENABLE_9P2000_L
+ [LIB9P_VER_9P2000_L] = 0b00000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000_e
+ [LIB9P_VER_9P2000_e] = 0b11111100000000000000000111111111,
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+ [LIB9P_VER_9P2000_p9p] = 0b11111100000000000000000111111111,
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_u
+ [LIB9P_VER_9P2000_u] = 0b11111100101111000000000111111111,
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
};
-const char *lib9p_version_str(enum lib9p_version ver) {
- assert(0 <= ver && ver < LIB9P_VER_NUM);
- return version_strs[ver];
-}
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static const lib9p_qt_t qt_masks[LIB9P_VER_NUM] = {
+#if CONFIG_9P_ENABLE_9P2000
+ [LIB9P_VER_9P2000] = 0b11111100,
+#endif /* CONFIG_9P_ENABLE_9P2000 */
+#if CONFIG_9P_ENABLE_9P2000_L
+ [LIB9P_VER_9P2000_L] = 0b11111100,
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000_e
+ [LIB9P_VER_9P2000_e] = 0b11111100,
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+ [LIB9P_VER_9P2000_p9p] = 0b11111100,
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_u
+ [LIB9P_VER_9P2000_u] = 0b11111110,
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+};
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static const lib9p_o_t o_masks[LIB9P_VER_NUM] = {
+#if CONFIG_9P_ENABLE_9P2000
+ [LIB9P_VER_9P2000] = 0b01010011,
+#endif /* CONFIG_9P_ENABLE_9P2000 */
+#if CONFIG_9P_ENABLE_9P2000_L
+ [LIB9P_VER_9P2000_L] = 0b00000000,
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000_e
+ [LIB9P_VER_9P2000_e] = 0b01010011,
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+ [LIB9P_VER_9P2000_p9p] = 0b01010011,
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_u
+ [LIB9P_VER_9P2000_u] = 0b01010011,
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+};
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000_L
+static const lib9p_lo_t lo_masks[LIB9P_VER_NUM] = {
+#if CONFIG_9P_ENABLE_9P2000
+ [LIB9P_VER_9P2000] = 0b00000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_9P2000 */
+ [LIB9P_VER_9P2000_L] = 0b00000000000111111111111111000011,
+#if CONFIG_9P_ENABLE_9P2000_e
+ [LIB9P_VER_9P2000_e] = 0b00000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+ [LIB9P_VER_9P2000_p9p] = 0b00000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_u
+ [LIB9P_VER_9P2000_u] = 0b00000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+};
+
+static const lib9p_mode_t mode_masks[LIB9P_VER_NUM] = {
+#if CONFIG_9P_ENABLE_9P2000
+ [LIB9P_VER_9P2000] = 0b00000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_9P2000 */
+ [LIB9P_VER_9P2000_L] = 0b00000000000000001111111111111111,
+#if CONFIG_9P_ENABLE_9P2000_e
+ [LIB9P_VER_9P2000_e] = 0b00000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+ [LIB9P_VER_9P2000_p9p] = 0b00000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_u
+ [LIB9P_VER_9P2000_u] = 0b00000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+};
+
+static const lib9p_getattr_t getattr_masks[LIB9P_VER_NUM] = {
+#if CONFIG_9P_ENABLE_9P2000
+ [LIB9P_VER_9P2000] = 0b0000000000000000000000000000000000000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_9P2000 */
+ [LIB9P_VER_9P2000_L] = 0b0000000000000000000000000000000000000000000000000011111111111111,
+#if CONFIG_9P_ENABLE_9P2000_e
+ [LIB9P_VER_9P2000_e] = 0b0000000000000000000000000000000000000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+ [LIB9P_VER_9P2000_p9p] = 0b0000000000000000000000000000000000000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_u
+ [LIB9P_VER_9P2000_u] = 0b0000000000000000000000000000000000000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+};
+
+static const lib9p_setattr_t setattr_masks[LIB9P_VER_NUM] = {
+#if CONFIG_9P_ENABLE_9P2000
+ [LIB9P_VER_9P2000] = 0b00000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_9P2000 */
+ [LIB9P_VER_9P2000_L] = 0b00000000000000000000000111111111,
+#if CONFIG_9P_ENABLE_9P2000_e
+ [LIB9P_VER_9P2000_e] = 0b00000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+ [LIB9P_VER_9P2000_p9p] = 0b00000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_u
+ [LIB9P_VER_9P2000_u] = 0b00000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+};
+
+static const lib9p_lock_flags_t lock_flags_masks[LIB9P_VER_NUM] = {
+#if CONFIG_9P_ENABLE_9P2000
+ [LIB9P_VER_9P2000] = 0b00000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_9P2000 */
+ [LIB9P_VER_9P2000_L] = 0b00000000000000000000000000000011,
+#if CONFIG_9P_ENABLE_9P2000_e
+ [LIB9P_VER_9P2000_e] = 0b00000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+ [LIB9P_VER_9P2000_p9p] = 0b00000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_u
+ [LIB9P_VER_9P2000_u] = 0b00000000000000000000000000000000,
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+};
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
/* validate_* *****************************************************************/
-static ALWAYS_INLINE bool _validate_size_net(struct _validate_ctx *ctx, uint32_t n) {
- if (__builtin_add_overflow(ctx->net_offset, n, &ctx->net_offset))
- /* If needed-net-size overflowed uint32_t, then
- * there's no way that actual-net-size will live up to
- * that. */
- return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content");
- if (ctx->net_offset > ctx->net_size)
- return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content");
+#define VALIDATE_NET_BYTES(n) \
+ if (__builtin_add_overflow(net_offset, n, &net_offset)) \
+ /* If needed-net-size overflowed uint32_t, then \
+ * there's no way that actual-net-size will live up to \
+ * that. */ \
+ return lib9p_error(ctx, LINUX_EBADMSG, "message is too short for content"); \
+ if (net_offset > net_size) \
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "message is too short for content (%"PRIu32" > %"PRIu32") @ %d", net_offset, net_size, __LINE__);
+#define VALIDATE_NET_UTF8(n) \
+ { \
+ size_t len = n; \
+ VALIDATE_NET_BYTES(len); \
+ if (!is_valid_utf8_without_nul(&net_bytes[net_offset-len], len)) \
+ return lib9p_error(ctx, LINUX_EBADMSG, "message contains invalid UTF-8"); \
+ }
+#define RESERVE_HOST_BYTES(n) \
+ if (__builtin_add_overflow(host_size, n, &host_size)) \
+ /* If needed-host-size overflowed ssize_t, then there's \
+ * no way that actual-net-size will live up to \
+ * that. */ \
+ return lib9p_error(ctx, LINUX_EBADMSG, "message is too short for content");
+#define GET_U8LE(off) (net_bytes[off])
+#define GET_U16LE(off) uint16le_decode(&net_bytes[off])
+#define GET_U32LE(off) uint32le_decode(&net_bytes[off])
+#define GET_U64LE(off) uint64le_decode(&net_bytes[off])
+#define LAST_U8LE() GET_U8LE(net_offset-1)
+#define LAST_U16LE() GET_U16LE(net_offset-2)
+#define LAST_U32LE() GET_U32LE(net_offset-4)
+#define LAST_U64LE() GET_U64LE(net_offset-8)
+
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static ssize_t validate_stat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, uint32_t *ret_net_size) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_stat);
+ uint32_t offsetof_stat_size = net_offset + 0;
+ uint32_t offsetof_kern_type = net_offset + 2;
+ uint32_t offsetof_file_qid_type = net_offset + 8;
+ VALIDATE_NET_BYTES(21);
+ if (GET_U8LE(offsetof_file_qid_type) & ~qt_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
+ GET_U8LE(offsetof_file_qid_type) & ~qt_masks[ctx->version]);
+ uint32_t offsetof_file_mode = net_offset + 0;
+ VALIDATE_NET_BYTES(22);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ VALIDATE_NET_BYTES(2);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ VALIDATE_NET_BYTES(2);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ VALIDATE_NET_BYTES(2);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+#if CONFIG_9P_ENABLE_9P2000_u
+ if (is_ver(ctx, 9P2000_u)) {
+ VALIDATE_NET_BYTES(2);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ VALIDATE_NET_BYTES(12);
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_stat_size) != (uint32_t)(offsetof_end - offsetof_kern_type))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "stat->stat_size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_stat_size), (uint32_t)(offsetof_end - offsetof_kern_type));
+ if (GET_U32LE(offsetof_file_mode) & ~dm_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in dm bitfield: %#08"PRIx32,
+ GET_U32LE(offsetof_file_mode) & ~dm_masks[ctx->version]);
+ if (ret_net_size)
+ *ret_net_size = net_offset;
+ return (ssize_t)host_size;
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static ssize_t validate_Tversion(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tversion);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(13);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tversion->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(100))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tversion->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(100));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rversion(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rversion);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(13);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rversion->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(101))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rversion->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(101));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Tauth(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tauth);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(13);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ VALIDATE_NET_BYTES(2);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
+ if (( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) )) {
+ VALIDATE_NET_BYTES(4);
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tauth->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(102))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tauth->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(102));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rauth(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rauth);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_aqid_type = net_offset + 7;
+ VALIDATE_NET_BYTES(20);
+ if (GET_U8LE(offsetof_aqid_type) & ~qt_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
+ GET_U8LE(offsetof_aqid_type) & ~qt_masks[ctx->version]);
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rauth->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(103))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rauth->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(103));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Tattach(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tattach);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(17);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ VALIDATE_NET_BYTES(2);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
+ if (( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) )) {
+ VALIDATE_NET_BYTES(4);
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tattach->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(104))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tattach->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(104));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rattach(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rattach);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_qid_type = net_offset + 7;
+ VALIDATE_NET_BYTES(20);
+ if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
+ GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]);
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rattach->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(105))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rattach->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(105));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rerror(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rerror);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(9);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+#if CONFIG_9P_ENABLE_9P2000_u
+ if (is_ver(ctx, 9P2000_u)) {
+ VALIDATE_NET_BYTES(4);
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rerror->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(107))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rerror->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(107));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Tflush(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tflush);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 9;
+ VALIDATE_NET_BYTES(9);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tflush->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(108))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tflush->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(108));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rflush(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rflush);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 7;
+ VALIDATE_NET_BYTES(7);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rflush->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(109))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rflush->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(109));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Twalk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Twalk);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_nwname = net_offset + 15;
+ VALIDATE_NET_BYTES(17);
+ for (uint16_t i = 0, cnt = LAST_U16LE(); i < cnt; i++) {
+ RESERVE_HOST_BYTES(sizeof(struct lib9p_s));
+ VALIDATE_NET_BYTES(2);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ }
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Twalk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(110))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Twalk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(110));
+ if ((uint16_t)GET_U16LE(offsetof_nwname) > (uint16_t)(16))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Twalk->nwname value is too large: %"PRIu16" > %"PRIu16,
+ (uint16_t)GET_U16LE(offsetof_nwname), (uint16_t)(16));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rwalk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rwalk);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_nwqid = net_offset + 7;
+ VALIDATE_NET_BYTES(9);
+ for (uint16_t i = 0, cnt = LAST_U16LE(); i < cnt; i++) {
+ RESERVE_HOST_BYTES(sizeof(struct lib9p_qid));
+ uint32_t offsetof_wqid_type = net_offset + 0;
+ VALIDATE_NET_BYTES(13);
+ if (GET_U8LE(offsetof_wqid_type) & ~qt_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
+ GET_U8LE(offsetof_wqid_type) & ~qt_masks[ctx->version]);
+ }
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwalk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(111))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwalk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(111));
+ if ((uint16_t)GET_U16LE(offsetof_nwqid) > (uint16_t)(16))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwalk->nwqid value is too large: %"PRIu16" > %"PRIu16,
+ (uint16_t)GET_U16LE(offsetof_nwqid), (uint16_t)(16));
+ return (ssize_t)host_size;
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static ssize_t validate_Topen(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Topen);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_mode = net_offset + 11;
+ uint32_t offsetof_end = net_offset + 12;
+ VALIDATE_NET_BYTES(12);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Topen->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(112))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Topen->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(112));
+ if (GET_U8LE(offsetof_mode) & ~o_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in o bitfield: %#02"PRIx8,
+ GET_U8LE(offsetof_mode) & ~o_masks[ctx->version]);
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Ropen(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Ropen);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_qid_type = net_offset + 7;
+ VALIDATE_NET_BYTES(20);
+ if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
+ GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]);
+ uint32_t offsetof_end = net_offset + 4;
+ VALIDATE_NET_BYTES(4);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Ropen->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(113))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Ropen->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(113));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Tcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tcreate);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(13);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ uint32_t offsetof_perm = net_offset + 0;
+ uint32_t offsetof_mode = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 5;
+ VALIDATE_NET_BYTES(5);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(114))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(114));
+ if (GET_U32LE(offsetof_perm) & ~dm_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in dm bitfield: %#08"PRIx32,
+ GET_U32LE(offsetof_perm) & ~dm_masks[ctx->version]);
+ if (GET_U8LE(offsetof_mode) & ~o_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in o bitfield: %#02"PRIx8,
+ GET_U8LE(offsetof_mode) & ~o_masks[ctx->version]);
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rcreate);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_qid_type = net_offset + 7;
+ VALIDATE_NET_BYTES(20);
+ if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
+ GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]);
+ uint32_t offsetof_end = net_offset + 4;
+ VALIDATE_NET_BYTES(4);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(115))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(115));
+ return (ssize_t)host_size;
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static ssize_t validate_Tread(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tread);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_offset = net_offset + 11;
+ uint32_t offsetof_count = net_offset + 19;
+ uint32_t offsetof_end = net_offset + 23;
+ VALIDATE_NET_BYTES(23);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tread->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(116))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tread->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(116));
+ if ((uint64_t)GET_U64LE(offsetof_offset) > (uint64_t)(INT64_MAX))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tread->offset value is too large: %"PRIu64" > %"PRIu64,
+ (uint64_t)GET_U64LE(offsetof_offset), (uint64_t)(INT64_MAX));
+ if ((uint32_t)GET_U32LE(offsetof_count) > (uint32_t)(INT32_MAX))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tread->count value is too large: %"PRIu32" > %"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_count), (uint32_t)(INT32_MAX));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rread(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rread);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_count = net_offset + 7;
+ VALIDATE_NET_BYTES(11);
+ VALIDATE_NET_BYTES(LAST_U32LE());
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rread->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(117))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rread->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(117));
+ if ((uint32_t)GET_U32LE(offsetof_count) > (uint32_t)(INT32_MAX))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rread->count value is too large: %"PRIu32" > %"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_count), (uint32_t)(INT32_MAX));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Twrite(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Twrite);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_offset = net_offset + 11;
+ uint32_t offsetof_count = net_offset + 19;
+ VALIDATE_NET_BYTES(23);
+ VALIDATE_NET_BYTES(LAST_U32LE());
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Twrite->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(118))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Twrite->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(118));
+ if ((uint64_t)GET_U64LE(offsetof_offset) > (uint64_t)(INT64_MAX))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Twrite->offset value is too large: %"PRIu64" > %"PRIu64,
+ (uint64_t)GET_U64LE(offsetof_offset), (uint64_t)(INT64_MAX));
+ if ((uint32_t)GET_U32LE(offsetof_count) > (uint32_t)(INT32_MAX))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Twrite->count value is too large: %"PRIu32" > %"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_count), (uint32_t)(INT32_MAX));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rwrite(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rwrite);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_count = net_offset + 7;
+ uint32_t offsetof_end = net_offset + 11;
+ VALIDATE_NET_BYTES(11);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwrite->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(119))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwrite->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(119));
+ if ((uint32_t)GET_U32LE(offsetof_count) > (uint32_t)(INT32_MAX))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwrite->count value is too large: %"PRIu32" > %"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_count), (uint32_t)(INT32_MAX));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Tclunk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tclunk);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 11;
+ VALIDATE_NET_BYTES(11);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tclunk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(120))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tclunk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(120));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rclunk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rclunk);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 7;
+ VALIDATE_NET_BYTES(7);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rclunk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(121))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rclunk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(121));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Tremove(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tremove);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 11;
+ VALIDATE_NET_BYTES(11);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tremove->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(122))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tremove->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(122));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rremove(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rremove);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 7;
+ VALIDATE_NET_BYTES(7);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rremove->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(123))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rremove->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(123));
+ return (ssize_t)host_size;
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static ssize_t validate_Tstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tstat);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 11;
+ VALIDATE_NET_BYTES(11);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tstat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(124))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tstat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(124));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rstat);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_nstat = net_offset + 7;
+ uint32_t offsetof_stat = net_offset + 9;
+ uint32_t offsetof_stat_stat_size = net_offset + 9;
+ uint32_t offsetof_stat_kern_type = net_offset + 11;
+ uint32_t offsetof_stat_file_qid_type = net_offset + 17;
+ VALIDATE_NET_BYTES(30);
+ if (GET_U8LE(offsetof_stat_file_qid_type) & ~qt_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
+ GET_U8LE(offsetof_stat_file_qid_type) & ~qt_masks[ctx->version]);
+ uint32_t offsetof_stat_file_mode = net_offset + 0;
+ VALIDATE_NET_BYTES(22);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ VALIDATE_NET_BYTES(2);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ VALIDATE_NET_BYTES(2);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ VALIDATE_NET_BYTES(2);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+#if CONFIG_9P_ENABLE_9P2000_u
+ if (is_ver(ctx, 9P2000_u)) {
+ VALIDATE_NET_BYTES(2);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ VALIDATE_NET_BYTES(12);
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+ uint32_t offsetof_stat_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_stat_stat_size) != (uint32_t)(offsetof_stat_end - offsetof_stat_kern_type))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rstat->stat.stat_size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_stat_stat_size), (uint32_t)(offsetof_stat_end - offsetof_stat_kern_type));
+ if (GET_U32LE(offsetof_stat_file_mode) & ~dm_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in dm bitfield: %#08"PRIx32,
+ GET_U32LE(offsetof_stat_file_mode) & ~dm_masks[ctx->version]);
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rstat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(125))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rstat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(125));
+ if ((uint32_t)GET_U32LE(offsetof_nstat) != (uint32_t)(offsetof_end - offsetof_stat))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rstat->nstat value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_nstat), (uint32_t)(offsetof_end - offsetof_stat));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Twstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Twstat);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_nstat = net_offset + 11;
+ uint32_t offsetof_stat = net_offset + 13;
+ uint32_t offsetof_stat_stat_size = net_offset + 13;
+ uint32_t offsetof_stat_kern_type = net_offset + 15;
+ uint32_t offsetof_stat_file_qid_type = net_offset + 21;
+ VALIDATE_NET_BYTES(34);
+ if (GET_U8LE(offsetof_stat_file_qid_type) & ~qt_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
+ GET_U8LE(offsetof_stat_file_qid_type) & ~qt_masks[ctx->version]);
+ uint32_t offsetof_stat_file_mode = net_offset + 0;
+ VALIDATE_NET_BYTES(22);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ VALIDATE_NET_BYTES(2);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ VALIDATE_NET_BYTES(2);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ VALIDATE_NET_BYTES(2);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+#if CONFIG_9P_ENABLE_9P2000_u
+ if (is_ver(ctx, 9P2000_u)) {
+ VALIDATE_NET_BYTES(2);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ VALIDATE_NET_BYTES(12);
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+ uint32_t offsetof_stat_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_stat_stat_size) != (uint32_t)(offsetof_stat_end - offsetof_stat_kern_type))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Twstat->stat.stat_size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_stat_stat_size), (uint32_t)(offsetof_stat_end - offsetof_stat_kern_type));
+ if (GET_U32LE(offsetof_stat_file_mode) & ~dm_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in dm bitfield: %#08"PRIx32,
+ GET_U32LE(offsetof_stat_file_mode) & ~dm_masks[ctx->version]);
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Twstat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(126))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Twstat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(126));
+ if ((uint32_t)GET_U32LE(offsetof_nstat) != (uint32_t)(offsetof_end - offsetof_stat))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Twstat->nstat value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_nstat), (uint32_t)(offsetof_end - offsetof_stat));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rwstat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rwstat);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 7;
+ VALIDATE_NET_BYTES(7);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwstat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(127))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rwstat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(127));
+ return (ssize_t)host_size;
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+static ssize_t validate_Topenfd(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Topenfd);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_mode = net_offset + 11;
+ uint32_t offsetof_end = net_offset + 12;
+ VALIDATE_NET_BYTES(12);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Topenfd->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(98))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Topenfd->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(98));
+ if (GET_U8LE(offsetof_mode) & ~o_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in o bitfield: %#02"PRIx8,
+ GET_U8LE(offsetof_mode) & ~o_masks[ctx->version]);
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Ropenfd(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Ropenfd);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_qid_type = net_offset + 7;
+ VALIDATE_NET_BYTES(20);
+ if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
+ GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]);
+ uint32_t offsetof_end = net_offset + 8;
+ VALIDATE_NET_BYTES(8);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Ropenfd->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(99))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Ropenfd->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(99));
+ return (ssize_t)host_size;
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_L
+static ssize_t validate_Rlerror(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rlerror);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 11;
+ VALIDATE_NET_BYTES(11);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlerror->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(7))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlerror->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(7));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Tstatfs(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tstatfs);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 11;
+ VALIDATE_NET_BYTES(11);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tstatfs->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(8))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tstatfs->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(8));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rstatfs(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rstatfs);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 67;
+ VALIDATE_NET_BYTES(67);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rstatfs->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(9))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rstatfs->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(9));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Tlopen(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tlopen);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_flags = net_offset + 11;
+ uint32_t offsetof_end = net_offset + 15;
+ VALIDATE_NET_BYTES(15);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlopen->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(12))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlopen->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(12));
+ if (GET_U32LE(offsetof_flags) & ~lo_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in lo bitfield: %#08"PRIx32,
+ GET_U32LE(offsetof_flags) & ~lo_masks[ctx->version]);
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rlopen(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rlopen);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_qid_type = net_offset + 7;
+ VALIDATE_NET_BYTES(20);
+ if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
+ GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]);
+ uint32_t offsetof_end = net_offset + 4;
+ VALIDATE_NET_BYTES(4);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlopen->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(13))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlopen->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(13));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Tlcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tlcreate);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(13);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ uint32_t offsetof_flags = net_offset + 0;
+ uint32_t offsetof_mode = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 12;
+ VALIDATE_NET_BYTES(12);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(14))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(14));
+ if (GET_U32LE(offsetof_flags) & ~lo_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in lo bitfield: %#08"PRIx32,
+ GET_U32LE(offsetof_flags) & ~lo_masks[ctx->version]);
+ if (GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32,
+ GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]);
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rlcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rlcreate);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_qid_type = net_offset + 7;
+ VALIDATE_NET_BYTES(20);
+ if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
+ GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]);
+ uint32_t offsetof_end = net_offset + 4;
+ VALIDATE_NET_BYTES(4);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(15))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(15));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Tsymlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tsymlink);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(13);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ VALIDATE_NET_BYTES(2);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ uint32_t offsetof_end = net_offset + 4;
+ VALIDATE_NET_BYTES(4);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsymlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(16))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsymlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(16));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rsymlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rsymlink);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_qid_type = net_offset + 7;
+ VALIDATE_NET_BYTES(20);
+ if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
+ GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]);
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsymlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(17))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsymlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(17));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Tmknod(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tmknod);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(13);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ uint32_t offsetof_mode = net_offset + 0;
+ uint32_t offsetof_end = net_offset + 16;
+ VALIDATE_NET_BYTES(16);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tmknod->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(18))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tmknod->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(18));
+ if (GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32,
+ GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]);
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rmknod(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rmknod);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_qid_type = net_offset + 7;
+ VALIDATE_NET_BYTES(20);
+ if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
+ GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]);
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rmknod->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(19))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rmknod->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(19));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Trename(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Trename);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(17);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Trename->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(20))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Trename->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(20));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rrename(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rrename);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 7;
+ VALIDATE_NET_BYTES(7);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rrename->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(21))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rrename->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(21));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Treadlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Treadlink);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 11;
+ VALIDATE_NET_BYTES(11);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Treadlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(22))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Treadlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(22));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rreadlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rreadlink);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(9);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rreadlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(23))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rreadlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(23));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Tgetattr(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tgetattr);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_request_mask = net_offset + 11;
+ uint32_t offsetof_end = net_offset + 19;
+ VALIDATE_NET_BYTES(19);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tgetattr->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(24))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tgetattr->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(24));
+ if (GET_U64LE(offsetof_request_mask) & ~getattr_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in getattr bitfield: %#016"PRIx64,
+ GET_U64LE(offsetof_request_mask) & ~getattr_masks[ctx->version]);
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rgetattr(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rgetattr);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_valid = net_offset + 7;
+ uint32_t offsetof_qid_type = net_offset + 15;
+ VALIDATE_NET_BYTES(28);
+ if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
+ GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]);
+ uint32_t offsetof_mode = net_offset + 0;
+ uint32_t offsetof_end = net_offset + 132;
+ VALIDATE_NET_BYTES(132);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rgetattr->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(25))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rgetattr->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(25));
+ if (GET_U64LE(offsetof_valid) & ~getattr_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in getattr bitfield: %#016"PRIx64,
+ GET_U64LE(offsetof_valid) & ~getattr_masks[ctx->version]);
+ if (GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32,
+ GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]);
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Tsetattr(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tsetattr);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_valid = net_offset + 11;
+ uint32_t offsetof_mode = net_offset + 15;
+ uint32_t offsetof_end = net_offset + 67;
+ VALIDATE_NET_BYTES(67);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsetattr->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(26))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsetattr->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(26));
+ if (GET_U32LE(offsetof_valid) & ~setattr_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in setattr bitfield: %#08"PRIx32,
+ GET_U32LE(offsetof_valid) & ~setattr_masks[ctx->version]);
+ if (GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32,
+ GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]);
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rsetattr(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rsetattr);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 7;
+ VALIDATE_NET_BYTES(7);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsetattr->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(27))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsetattr->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(27));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Txattrwalk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Txattrwalk);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(17);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Txattrwalk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(30))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Txattrwalk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(30));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rxattrwalk(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rxattrwalk);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 15;
+ VALIDATE_NET_BYTES(15);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rxattrwalk->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(31))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rxattrwalk->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(31));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Txattrcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Txattrcreate);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(13);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ uint32_t offsetof_end = net_offset + 12;
+ VALIDATE_NET_BYTES(12);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Txattrcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(32))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Txattrcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(32));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rxattrcreate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rxattrcreate);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 7;
+ VALIDATE_NET_BYTES(7);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rxattrcreate->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(33))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rxattrcreate->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(33));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Treaddir(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Treaddir);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 23;
+ VALIDATE_NET_BYTES(23);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Treaddir->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(40))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Treaddir->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(40));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rreaddir(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rreaddir);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(11);
+ VALIDATE_NET_BYTES(LAST_U32LE());
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rreaddir->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(41))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rreaddir->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(41));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Tfsync(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tfsync);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 15;
+ VALIDATE_NET_BYTES(15);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tfsync->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(50))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tfsync->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(50));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rfsync(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rfsync);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 7;
+ VALIDATE_NET_BYTES(7);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rfsync->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(51))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rfsync->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(51));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Tlock(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tlock);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_flags = net_offset + 12;
+ VALIDATE_NET_BYTES(38);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlock->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(52))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlock->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(52));
+ if (GET_U32LE(offsetof_flags) & ~lock_flags_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in lock_flags bitfield: %#08"PRIx32,
+ GET_U32LE(offsetof_flags) & ~lock_flags_masks[ctx->version]);
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rlock(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rlock);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 8;
+ VALIDATE_NET_BYTES(8);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlock->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(53))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlock->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(53));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Tgetlock(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tgetlock);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(34);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tgetlock->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(54))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tgetlock->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(54));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rgetlock(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rgetlock);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(30);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rgetlock->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(55))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rgetlock->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(55));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Tlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tlink);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(17);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(70))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(70));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rlink(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rlink);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 7;
+ VALIDATE_NET_BYTES(7);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlink->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(71))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rlink->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(71));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Tmkdir(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tmkdir);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(13);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ uint32_t offsetof_mode = net_offset + 0;
+ uint32_t offsetof_end = net_offset + 8;
+ VALIDATE_NET_BYTES(8);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tmkdir->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(72))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tmkdir->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(72));
+ if (GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in mode bitfield: %#08"PRIx32,
+ GET_U32LE(offsetof_mode) & ~mode_masks[ctx->version]);
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rmkdir(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rmkdir);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_qid_type = net_offset + 7;
+ VALIDATE_NET_BYTES(20);
+ if (GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version])
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#02"PRIx8,
+ GET_U8LE(offsetof_qid_type) & ~qt_masks[ctx->version]);
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rmkdir->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(73))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rmkdir->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(73));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Trenameat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Trenameat);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(13);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ VALIDATE_NET_BYTES(6);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Trenameat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(74))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Trenameat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(74));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rrenameat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rrenameat);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 7;
+ VALIDATE_NET_BYTES(7);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rrenameat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(75))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rrenameat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(75));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Tunlinkat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tunlinkat);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(13);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ uint32_t offsetof_end = net_offset + 4;
+ VALIDATE_NET_BYTES(4);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tunlinkat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(76))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tunlinkat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(76));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Runlinkat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Runlinkat);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 7;
+ VALIDATE_NET_BYTES(7);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Runlinkat->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(77))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Runlinkat->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(77));
+ return (ssize_t)host_size;
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000_e
+static ssize_t validate_Tsession(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tsession);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 15;
+ VALIDATE_NET_BYTES(15);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsession->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(150))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsession->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(150));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rsession(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rsession);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 7;
+ VALIDATE_NET_BYTES(7);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsession->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(151))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsession->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(151));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Tsread(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tsread);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(13);
+ for (uint16_t i = 0, cnt = LAST_U16LE(); i < cnt; i++) {
+ RESERVE_HOST_BYTES(sizeof(struct lib9p_s));
+ VALIDATE_NET_BYTES(2);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ }
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsread->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(152))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tsread->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(152));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rsread(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rsread);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(11);
+ VALIDATE_NET_BYTES(LAST_U32LE());
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsread->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(153))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rsread->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(153));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Tswrite(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Tswrite);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ VALIDATE_NET_BYTES(13);
+ for (uint16_t i = 0, cnt = LAST_U16LE(); i < cnt; i++) {
+ RESERVE_HOST_BYTES(sizeof(struct lib9p_s));
+ VALIDATE_NET_BYTES(2);
+ VALIDATE_NET_UTF8(LAST_U16LE());
+ }
+ VALIDATE_NET_BYTES(4);
+ VALIDATE_NET_BYTES(LAST_U32LE());
+ uint32_t offsetof_end = net_offset + 0;
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tswrite->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(154))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Tswrite->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(154));
+ return (ssize_t)host_size;
+}
+
+static ssize_t validate_Rswrite(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {
+ uint32_t net_offset = 0;
+ ssize_t host_size = sizeof(struct lib9p_msg_Rswrite);
+ uint32_t offsetof_size = net_offset + 0;
+ uint32_t offsetof_typ = net_offset + 4;
+ uint32_t offsetof_end = net_offset + 11;
+ VALIDATE_NET_BYTES(11);
+ if ((uint32_t)GET_U32LE(offsetof_size) != (uint32_t)(offsetof_end - offsetof_size))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rswrite->size value is wrong: actual: %"PRIu32" != correct:%"PRIu32,
+ (uint32_t)GET_U32LE(offsetof_size), (uint32_t)(offsetof_end - offsetof_size));
+ if ((uint8_t)GET_U8LE(offsetof_typ) != (uint8_t)(155))
+ return lib9p_errorf(ctx, LINUX_EBADMSG, "Rswrite->typ value is wrong: actual: %"PRIu8" != correct:%"PRIu8,
+ (uint8_t)GET_U8LE(offsetof_typ), (uint8_t)(155));
+ return (ssize_t)host_size;
+}
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+
+/* unmarshal_* ****************************************************************/
+
+#define UNMARSHAL_BYTES(ctx, data_lvalue, len) \
+ data_lvalue = (char *)&net_bytes[net_offset]; \
+ net_offset += len;
+#define UNMARSHAL_U8LE(ctx, val_lvalue) \
+ val_lvalue = net_bytes[net_offset]; \
+ net_offset += 1;
+#define UNMARSHAL_U16LE(ctx, val_lvalue) \
+ val_lvalue = uint16le_decode(&net_bytes[net_offset]); \
+ net_offset += 2;
+#define UNMARSHAL_U32LE(ctx, val_lvalue) \
+ val_lvalue = uint32le_decode(&net_bytes[net_offset]); \
+ net_offset += 4;
+#define UNMARSHAL_U64LE(ctx, val_lvalue) \
+ val_lvalue = uint64le_decode(&net_bytes[net_offset]); \
+ net_offset += 8;
+
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static void unmarshal_stat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_stat *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 2;
+ UNMARSHAL_U16LE(ctx, out->kern_type);
+ UNMARSHAL_U32LE(ctx, out->kern_dev);
+ UNMARSHAL_U8LE(ctx, out->file_qid.type);
+ UNMARSHAL_U32LE(ctx, out->file_qid.vers);
+ UNMARSHAL_U64LE(ctx, out->file_qid.path);
+ UNMARSHAL_U32LE(ctx, out->file_mode);
+ UNMARSHAL_U32LE(ctx, out->file_atime);
+ UNMARSHAL_U32LE(ctx, out->file_mtime);
+ UNMARSHAL_U64LE(ctx, out->file_size);
+ UNMARSHAL_U16LE(ctx, out->file_name.len);
+ UNMARSHAL_BYTES(ctx, out->file_name.utf8, out->file_name.len);
+ UNMARSHAL_U16LE(ctx, out->file_owner_uid.len);
+ UNMARSHAL_BYTES(ctx, out->file_owner_uid.utf8, out->file_owner_uid.len);
+ UNMARSHAL_U16LE(ctx, out->file_owner_gid.len);
+ UNMARSHAL_BYTES(ctx, out->file_owner_gid.utf8, out->file_owner_gid.len);
+ UNMARSHAL_U16LE(ctx, out->file_last_modified_uid.len);
+ UNMARSHAL_BYTES(ctx, out->file_last_modified_uid.utf8, out->file_last_modified_uid.len);
+#if CONFIG_9P_ENABLE_9P2000_u
+ if (is_ver(ctx, 9P2000_u)) {
+ UNMARSHAL_U16LE(ctx, out->file_extension.len);
+ UNMARSHAL_BYTES(ctx, out->file_extension.utf8, out->file_extension.len);
+ UNMARSHAL_U32LE(ctx, out->file_owner_n_uid);
+ UNMARSHAL_U32LE(ctx, out->file_owner_n_gid);
+ UNMARSHAL_U32LE(ctx, out->file_last_modified_n_uid);
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static void unmarshal_Tversion([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tversion *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->max_msg_size);
+ UNMARSHAL_U16LE(ctx, out->version.len);
+ UNMARSHAL_BYTES(ctx, out->version.utf8, out->version.len);
+}
+
+static void unmarshal_Rversion([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rversion *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->max_msg_size);
+ UNMARSHAL_U16LE(ctx, out->version.len);
+ UNMARSHAL_BYTES(ctx, out->version.utf8, out->version.len);
+}
+
+static void unmarshal_Tauth([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tauth *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->afid);
+ UNMARSHAL_U16LE(ctx, out->uname.len);
+ UNMARSHAL_BYTES(ctx, out->uname.utf8, out->uname.len);
+ UNMARSHAL_U16LE(ctx, out->aname.len);
+ UNMARSHAL_BYTES(ctx, out->aname.utf8, out->aname.len);
+#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
+ if (( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) )) {
+ UNMARSHAL_U32LE(ctx, out->n_uid);
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
+}
+
+static void unmarshal_Rauth([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rauth *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U8LE(ctx, out->aqid.type);
+ UNMARSHAL_U32LE(ctx, out->aqid.vers);
+ UNMARSHAL_U64LE(ctx, out->aqid.path);
+}
+
+static void unmarshal_Tattach([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tattach *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U32LE(ctx, out->afid);
+ UNMARSHAL_U16LE(ctx, out->uname.len);
+ UNMARSHAL_BYTES(ctx, out->uname.utf8, out->uname.len);
+ UNMARSHAL_U16LE(ctx, out->aname.len);
+ UNMARSHAL_BYTES(ctx, out->aname.utf8, out->aname.len);
+#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
+ if (( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) )) {
+ UNMARSHAL_U32LE(ctx, out->n_uid);
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
+}
+
+static void unmarshal_Rattach([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rattach *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U8LE(ctx, out->qid.type);
+ UNMARSHAL_U32LE(ctx, out->qid.vers);
+ UNMARSHAL_U64LE(ctx, out->qid.path);
+}
+
+static void unmarshal_Rerror([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rerror *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U16LE(ctx, out->errstr.len);
+ UNMARSHAL_BYTES(ctx, out->errstr.utf8, out->errstr.len);
+#if CONFIG_9P_ENABLE_9P2000_u
+ if (is_ver(ctx, 9P2000_u)) {
+ UNMARSHAL_U32LE(ctx, out->errnum);
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+}
+
+static void unmarshal_Tflush([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tflush *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U16LE(ctx, out->oldtag);
+}
+
+static void unmarshal_Rflush([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rflush *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+}
+
+static void unmarshal_Twalk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Twalk *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U32LE(ctx, out->newfid);
+ UNMARSHAL_U16LE(ctx, out->nwname);
+ out->wname = extra;
+ extra += sizeof(out->wname[0]) * out->nwname;
+ for (uint16_t i = 0; i < out->nwname; i++) {
+ UNMARSHAL_U16LE(ctx, out->wname[i].len);
+ UNMARSHAL_BYTES(ctx, out->wname[i].utf8, out->wname[i].len);
+ }
+}
+
+static void unmarshal_Rwalk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rwalk *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U16LE(ctx, out->nwqid);
+ out->wqid = extra;
+ extra += sizeof(out->wqid[0]) * out->nwqid;
+ for (uint16_t i = 0; i < out->nwqid; i++) {
+ UNMARSHAL_U8LE(ctx, out->wqid[i].type);
+ UNMARSHAL_U32LE(ctx, out->wqid[i].vers);
+ UNMARSHAL_U64LE(ctx, out->wqid[i].path);
+ }
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static void unmarshal_Topen([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Topen *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U8LE(ctx, out->mode);
+}
+
+static void unmarshal_Ropen([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Ropen *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U8LE(ctx, out->qid.type);
+ UNMARSHAL_U32LE(ctx, out->qid.vers);
+ UNMARSHAL_U64LE(ctx, out->qid.path);
+ UNMARSHAL_U32LE(ctx, out->iounit);
+}
+
+static void unmarshal_Tcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tcreate *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U16LE(ctx, out->name.len);
+ UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len);
+ UNMARSHAL_U32LE(ctx, out->perm);
+ UNMARSHAL_U8LE(ctx, out->mode);
+}
+
+static void unmarshal_Rcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rcreate *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U8LE(ctx, out->qid.type);
+ UNMARSHAL_U32LE(ctx, out->qid.vers);
+ UNMARSHAL_U64LE(ctx, out->qid.path);
+ UNMARSHAL_U32LE(ctx, out->iounit);
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static void unmarshal_Tread([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tread *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U64LE(ctx, out->offset);
+ UNMARSHAL_U32LE(ctx, out->count);
+}
+
+static void unmarshal_Rread([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rread *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->count);
+ UNMARSHAL_BYTES(ctx, out->data, out->count);
+}
+
+static void unmarshal_Twrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Twrite *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U64LE(ctx, out->offset);
+ UNMARSHAL_U32LE(ctx, out->count);
+ UNMARSHAL_BYTES(ctx, out->data, out->count);
+}
+
+static void unmarshal_Rwrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rwrite *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->count);
+}
+
+static void unmarshal_Tclunk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tclunk *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+}
+
+static void unmarshal_Rclunk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rclunk *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+}
+
+static void unmarshal_Tremove([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tremove *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+}
+
+static void unmarshal_Rremove([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rremove *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static void unmarshal_Tstat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tstat *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+}
+
+static void unmarshal_Rstat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rstat *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ net_offset += 2;
+ net_offset += 2;
+ UNMARSHAL_U16LE(ctx, out->stat.kern_type);
+ UNMARSHAL_U32LE(ctx, out->stat.kern_dev);
+ UNMARSHAL_U8LE(ctx, out->stat.file_qid.type);
+ UNMARSHAL_U32LE(ctx, out->stat.file_qid.vers);
+ UNMARSHAL_U64LE(ctx, out->stat.file_qid.path);
+ UNMARSHAL_U32LE(ctx, out->stat.file_mode);
+ UNMARSHAL_U32LE(ctx, out->stat.file_atime);
+ UNMARSHAL_U32LE(ctx, out->stat.file_mtime);
+ UNMARSHAL_U64LE(ctx, out->stat.file_size);
+ UNMARSHAL_U16LE(ctx, out->stat.file_name.len);
+ UNMARSHAL_BYTES(ctx, out->stat.file_name.utf8, out->stat.file_name.len);
+ UNMARSHAL_U16LE(ctx, out->stat.file_owner_uid.len);
+ UNMARSHAL_BYTES(ctx, out->stat.file_owner_uid.utf8, out->stat.file_owner_uid.len);
+ UNMARSHAL_U16LE(ctx, out->stat.file_owner_gid.len);
+ UNMARSHAL_BYTES(ctx, out->stat.file_owner_gid.utf8, out->stat.file_owner_gid.len);
+ UNMARSHAL_U16LE(ctx, out->stat.file_last_modified_uid.len);
+ UNMARSHAL_BYTES(ctx, out->stat.file_last_modified_uid.utf8, out->stat.file_last_modified_uid.len);
+#if CONFIG_9P_ENABLE_9P2000_u
+ if (is_ver(ctx, 9P2000_u)) {
+ UNMARSHAL_U16LE(ctx, out->stat.file_extension.len);
+ UNMARSHAL_BYTES(ctx, out->stat.file_extension.utf8, out->stat.file_extension.len);
+ UNMARSHAL_U32LE(ctx, out->stat.file_owner_n_uid);
+ UNMARSHAL_U32LE(ctx, out->stat.file_owner_n_gid);
+ UNMARSHAL_U32LE(ctx, out->stat.file_last_modified_n_uid);
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+}
+
+static void unmarshal_Twstat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Twstat *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ net_offset += 2;
+ net_offset += 2;
+ UNMARSHAL_U16LE(ctx, out->stat.kern_type);
+ UNMARSHAL_U32LE(ctx, out->stat.kern_dev);
+ UNMARSHAL_U8LE(ctx, out->stat.file_qid.type);
+ UNMARSHAL_U32LE(ctx, out->stat.file_qid.vers);
+ UNMARSHAL_U64LE(ctx, out->stat.file_qid.path);
+ UNMARSHAL_U32LE(ctx, out->stat.file_mode);
+ UNMARSHAL_U32LE(ctx, out->stat.file_atime);
+ UNMARSHAL_U32LE(ctx, out->stat.file_mtime);
+ UNMARSHAL_U64LE(ctx, out->stat.file_size);
+ UNMARSHAL_U16LE(ctx, out->stat.file_name.len);
+ UNMARSHAL_BYTES(ctx, out->stat.file_name.utf8, out->stat.file_name.len);
+ UNMARSHAL_U16LE(ctx, out->stat.file_owner_uid.len);
+ UNMARSHAL_BYTES(ctx, out->stat.file_owner_uid.utf8, out->stat.file_owner_uid.len);
+ UNMARSHAL_U16LE(ctx, out->stat.file_owner_gid.len);
+ UNMARSHAL_BYTES(ctx, out->stat.file_owner_gid.utf8, out->stat.file_owner_gid.len);
+ UNMARSHAL_U16LE(ctx, out->stat.file_last_modified_uid.len);
+ UNMARSHAL_BYTES(ctx, out->stat.file_last_modified_uid.utf8, out->stat.file_last_modified_uid.len);
+#if CONFIG_9P_ENABLE_9P2000_u
+ if (is_ver(ctx, 9P2000_u)) {
+ UNMARSHAL_U16LE(ctx, out->stat.file_extension.len);
+ UNMARSHAL_BYTES(ctx, out->stat.file_extension.utf8, out->stat.file_extension.len);
+ UNMARSHAL_U32LE(ctx, out->stat.file_owner_n_uid);
+ UNMARSHAL_U32LE(ctx, out->stat.file_owner_n_gid);
+ UNMARSHAL_U32LE(ctx, out->stat.file_last_modified_n_uid);
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+}
+
+static void unmarshal_Rwstat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rwstat *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+static void unmarshal_Topenfd([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Topenfd *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U8LE(ctx, out->mode);
+}
+
+static void unmarshal_Ropenfd([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Ropenfd *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U8LE(ctx, out->qid.type);
+ UNMARSHAL_U32LE(ctx, out->qid.vers);
+ UNMARSHAL_U64LE(ctx, out->qid.path);
+ UNMARSHAL_U32LE(ctx, out->iounit);
+ UNMARSHAL_U32LE(ctx, out->unixfd);
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_L
+static void unmarshal_Rlerror([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rlerror *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->errnum);
+}
+
+static void unmarshal_Tstatfs([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tstatfs *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+}
+
+static void unmarshal_Rstatfs([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rstatfs *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->type);
+ UNMARSHAL_U32LE(ctx, out->bsize);
+ UNMARSHAL_U64LE(ctx, out->blocks);
+ UNMARSHAL_U64LE(ctx, out->bfree);
+ UNMARSHAL_U64LE(ctx, out->bavail);
+ UNMARSHAL_U64LE(ctx, out->files);
+ UNMARSHAL_U64LE(ctx, out->ffree);
+ UNMARSHAL_U64LE(ctx, out->fsid);
+ UNMARSHAL_U32LE(ctx, out->namelen);
+}
+
+static void unmarshal_Tlopen([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tlopen *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U32LE(ctx, out->flags);
+}
+
+static void unmarshal_Rlopen([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rlopen *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U8LE(ctx, out->qid.type);
+ UNMARSHAL_U32LE(ctx, out->qid.vers);
+ UNMARSHAL_U64LE(ctx, out->qid.path);
+ UNMARSHAL_U32LE(ctx, out->iounit);
+}
+
+static void unmarshal_Tlcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tlcreate *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U16LE(ctx, out->name.len);
+ UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len);
+ UNMARSHAL_U32LE(ctx, out->flags);
+ UNMARSHAL_U32LE(ctx, out->mode);
+ UNMARSHAL_U32LE(ctx, out->gid);
+}
+
+static void unmarshal_Rlcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rlcreate *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U8LE(ctx, out->qid.type);
+ UNMARSHAL_U32LE(ctx, out->qid.vers);
+ UNMARSHAL_U64LE(ctx, out->qid.path);
+ UNMARSHAL_U32LE(ctx, out->iounit);
+}
+
+static void unmarshal_Tsymlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tsymlink *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U16LE(ctx, out->name.len);
+ UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len);
+ UNMARSHAL_U16LE(ctx, out->symtgt.len);
+ UNMARSHAL_BYTES(ctx, out->symtgt.utf8, out->symtgt.len);
+ UNMARSHAL_U32LE(ctx, out->gid);
+}
+
+static void unmarshal_Rsymlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rsymlink *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U8LE(ctx, out->qid.type);
+ UNMARSHAL_U32LE(ctx, out->qid.vers);
+ UNMARSHAL_U64LE(ctx, out->qid.path);
+}
+
+static void unmarshal_Tmknod([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tmknod *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->dfid);
+ UNMARSHAL_U16LE(ctx, out->name.len);
+ UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len);
+ UNMARSHAL_U32LE(ctx, out->mode);
+ UNMARSHAL_U32LE(ctx, out->major);
+ UNMARSHAL_U32LE(ctx, out->minor);
+ UNMARSHAL_U32LE(ctx, out->gid);
+}
+
+static void unmarshal_Rmknod([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rmknod *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U8LE(ctx, out->qid.type);
+ UNMARSHAL_U32LE(ctx, out->qid.vers);
+ UNMARSHAL_U64LE(ctx, out->qid.path);
+}
+
+static void unmarshal_Trename([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Trename *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U32LE(ctx, out->dfid);
+ UNMARSHAL_U16LE(ctx, out->name.len);
+ UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len);
+}
+
+static void unmarshal_Rrename([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rrename *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+}
+
+static void unmarshal_Treadlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Treadlink *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+}
+
+static void unmarshal_Rreadlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rreadlink *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U16LE(ctx, out->target.len);
+ UNMARSHAL_BYTES(ctx, out->target.utf8, out->target.len);
+}
+
+static void unmarshal_Tgetattr([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tgetattr *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U64LE(ctx, out->request_mask);
+}
+
+static void unmarshal_Rgetattr([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rgetattr *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U64LE(ctx, out->valid);
+ UNMARSHAL_U8LE(ctx, out->qid.type);
+ UNMARSHAL_U32LE(ctx, out->qid.vers);
+ UNMARSHAL_U64LE(ctx, out->qid.path);
+ UNMARSHAL_U32LE(ctx, out->mode);
+ UNMARSHAL_U32LE(ctx, out->uid);
+ UNMARSHAL_U32LE(ctx, out->gid);
+ UNMARSHAL_U64LE(ctx, out->nlink);
+ UNMARSHAL_U64LE(ctx, out->rdev);
+ UNMARSHAL_U64LE(ctx, out->filesize);
+ UNMARSHAL_U64LE(ctx, out->blksize);
+ UNMARSHAL_U64LE(ctx, out->blocks);
+ UNMARSHAL_U64LE(ctx, out->atime_sec);
+ UNMARSHAL_U64LE(ctx, out->atime_nsec);
+ UNMARSHAL_U64LE(ctx, out->mtime_sec);
+ UNMARSHAL_U64LE(ctx, out->mtime_nsec);
+ UNMARSHAL_U64LE(ctx, out->ctime_sec);
+ UNMARSHAL_U64LE(ctx, out->ctime_nsec);
+ UNMARSHAL_U64LE(ctx, out->btime_sec);
+ UNMARSHAL_U64LE(ctx, out->btime_nsec);
+ UNMARSHAL_U64LE(ctx, out->gen);
+ UNMARSHAL_U64LE(ctx, out->data_version);
+}
+
+static void unmarshal_Tsetattr([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tsetattr *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U32LE(ctx, out->valid);
+ UNMARSHAL_U32LE(ctx, out->mode);
+ UNMARSHAL_U32LE(ctx, out->uid);
+ UNMARSHAL_U32LE(ctx, out->gid);
+ UNMARSHAL_U64LE(ctx, out->filesize);
+ UNMARSHAL_U64LE(ctx, out->atime_sec);
+ UNMARSHAL_U64LE(ctx, out->atime_nsec);
+ UNMARSHAL_U64LE(ctx, out->mtime_sec);
+ UNMARSHAL_U64LE(ctx, out->mtime_nsec);
+}
+
+static void unmarshal_Rsetattr([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rsetattr *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+}
+
+static void unmarshal_Txattrwalk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Txattrwalk *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U32LE(ctx, out->newfid);
+ UNMARSHAL_U16LE(ctx, out->name.len);
+ UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len);
+}
+
+static void unmarshal_Rxattrwalk([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rxattrwalk *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U64LE(ctx, out->attr_size);
+}
+
+static void unmarshal_Txattrcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Txattrcreate *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U16LE(ctx, out->name.len);
+ UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len);
+ UNMARSHAL_U64LE(ctx, out->attr_size);
+ UNMARSHAL_U32LE(ctx, out->flags);
+}
+
+static void unmarshal_Rxattrcreate([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rxattrcreate *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+}
+
+static void unmarshal_Treaddir([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Treaddir *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U64LE(ctx, out->offset);
+ UNMARSHAL_U32LE(ctx, out->count);
+}
+
+static void unmarshal_Rreaddir([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rreaddir *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->count);
+ UNMARSHAL_BYTES(ctx, out->data, out->count);
+}
+
+static void unmarshal_Tfsync([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tfsync *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U32LE(ctx, out->datasync);
+}
+
+static void unmarshal_Rfsync([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rfsync *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+}
+
+static void unmarshal_Tlock([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tlock *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U8LE(ctx, out->type);
+ UNMARSHAL_U32LE(ctx, out->flags);
+ UNMARSHAL_U64LE(ctx, out->start);
+ UNMARSHAL_U64LE(ctx, out->length);
+ UNMARSHAL_U32LE(ctx, out->proc_id);
+ UNMARSHAL_U16LE(ctx, out->client_id.len);
+ UNMARSHAL_BYTES(ctx, out->client_id.utf8, out->client_id.len);
+}
+
+static void unmarshal_Rlock([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rlock *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U8LE(ctx, out->status);
+}
+
+static void unmarshal_Tgetlock([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tgetlock *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U8LE(ctx, out->type);
+ UNMARSHAL_U64LE(ctx, out->start);
+ UNMARSHAL_U64LE(ctx, out->length);
+ UNMARSHAL_U32LE(ctx, out->proc_id);
+ UNMARSHAL_U16LE(ctx, out->client_id.len);
+ UNMARSHAL_BYTES(ctx, out->client_id.utf8, out->client_id.len);
+}
+
+static void unmarshal_Rgetlock([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rgetlock *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U8LE(ctx, out->type);
+ UNMARSHAL_U64LE(ctx, out->start);
+ UNMARSHAL_U64LE(ctx, out->length);
+ UNMARSHAL_U32LE(ctx, out->proc_id);
+ UNMARSHAL_U16LE(ctx, out->client_id.len);
+ UNMARSHAL_BYTES(ctx, out->client_id.utf8, out->client_id.len);
+}
+
+static void unmarshal_Tlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tlink *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->dfid);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U16LE(ctx, out->name.len);
+ UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len);
+}
+
+static void unmarshal_Rlink([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rlink *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+}
+
+static void unmarshal_Tmkdir([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tmkdir *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->dfid);
+ UNMARSHAL_U16LE(ctx, out->name.len);
+ UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len);
+ UNMARSHAL_U32LE(ctx, out->mode);
+ UNMARSHAL_U32LE(ctx, out->gid);
+}
+
+static void unmarshal_Rmkdir([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rmkdir *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U8LE(ctx, out->qid.type);
+ UNMARSHAL_U32LE(ctx, out->qid.vers);
+ UNMARSHAL_U64LE(ctx, out->qid.path);
+}
+
+static void unmarshal_Trenameat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Trenameat *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->olddirfid);
+ UNMARSHAL_U16LE(ctx, out->oldname.len);
+ UNMARSHAL_BYTES(ctx, out->oldname.utf8, out->oldname.len);
+ UNMARSHAL_U32LE(ctx, out->newdirfid);
+ UNMARSHAL_U16LE(ctx, out->newname.len);
+ UNMARSHAL_BYTES(ctx, out->newname.utf8, out->newname.len);
+}
+
+static void unmarshal_Rrenameat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rrenameat *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+}
+
+static void unmarshal_Tunlinkat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tunlinkat *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->dirfd);
+ UNMARSHAL_U16LE(ctx, out->name.len);
+ UNMARSHAL_BYTES(ctx, out->name.utf8, out->name.len);
+ UNMARSHAL_U32LE(ctx, out->flags);
+}
+
+static void unmarshal_Runlinkat([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Runlinkat *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000_e
+static void unmarshal_Tsession([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tsession *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U64LE(ctx, out->key);
+}
+
+static void unmarshal_Rsession([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rsession *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+}
+
+static void unmarshal_Tsread([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tsread *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U16LE(ctx, out->nwname);
+ out->wname = extra;
+ extra += sizeof(out->wname[0]) * out->nwname;
+ for (uint16_t i = 0; i < out->nwname; i++) {
+ UNMARSHAL_U16LE(ctx, out->wname[i].len);
+ UNMARSHAL_BYTES(ctx, out->wname[i].utf8, out->wname[i].len);
+ }
+}
+
+static void unmarshal_Rsread([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rsread *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->count);
+ UNMARSHAL_BYTES(ctx, out->data, out->count);
+}
+
+static void unmarshal_Tswrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Tswrite *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->fid);
+ UNMARSHAL_U16LE(ctx, out->nwname);
+ out->wname = extra;
+ extra += sizeof(out->wname[0]) * out->nwname;
+ for (uint16_t i = 0; i < out->nwname; i++) {
+ UNMARSHAL_U16LE(ctx, out->wname[i].len);
+ UNMARSHAL_BYTES(ctx, out->wname[i].utf8, out->wname[i].len);
+ }
+ UNMARSHAL_U32LE(ctx, out->count);
+ UNMARSHAL_BYTES(ctx, out->data, out->count);
+}
+
+static void unmarshal_Rswrite([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {
+ struct lib9p_msg_Rswrite *out = out_buf;
+ [[gnu::unused]] void *extra = &out[1];
+ uint32_t net_offset = 0;
+ net_offset += 4;
+ net_offset += 1;
+ UNMARSHAL_U16LE(ctx, out->tag);
+ UNMARSHAL_U32LE(ctx, out->count);
+}
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+
+/* marshal_* ******************************************************************/
+
+#define MARSHAL_BYTES_ZEROCOPY(ctx, data, len) \
+ if (ret->net_iov[ret->net_iov_cnt-1].iov_len) \
+ ret->net_iov_cnt++; \
+ ret->net_iov[ret->net_iov_cnt-1].iov_base = data; \
+ ret->net_iov[ret->net_iov_cnt-1].iov_len = len; \
+ ret->net_iov_cnt++;
+#define MARSHAL_BYTES(ctx, data, len) \
+ if (!ret->net_iov[ret->net_iov_cnt-1].iov_base) \
+ ret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size]; \
+ memcpy(&ret->net_copied[ret->net_copied_size], data, len); \
+ ret->net_copied_size += len; \
+ ret->net_iov[ret->net_iov_cnt-1].iov_len += len;
+#define MARSHAL_U8LE(ctx, val) \
+ if (!ret->net_iov[ret->net_iov_cnt-1].iov_base) \
+ ret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size]; \
+ ret->net_copied[ret->net_copied_size] = val; \
+ ret->net_copied_size += 1; \
+ ret->net_iov[ret->net_iov_cnt-1].iov_len += 1;
+#define MARSHAL_U16LE(ctx, val) \
+ if (!ret->net_iov[ret->net_iov_cnt-1].iov_base) \
+ ret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size]; \
+ uint16le_encode(&ret->net_copied[ret->net_copied_size], val); \
+ ret->net_copied_size += 2; \
+ ret->net_iov[ret->net_iov_cnt-1].iov_len += 2;
+#define MARSHAL_U32LE(ctx, val) \
+ if (!ret->net_iov[ret->net_iov_cnt-1].iov_base) \
+ ret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size]; \
+ uint32le_encode(&ret->net_copied[ret->net_copied_size], val); \
+ ret->net_copied_size += 4; \
+ ret->net_iov[ret->net_iov_cnt-1].iov_len += 4;
+#define MARSHAL_U64LE(ctx, val) \
+ if (!ret->net_iov[ret->net_iov_cnt-1].iov_base) \
+ ret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size]; \
+ uint64le_encode(&ret->net_copied[ret->net_copied_size], val); \
+ ret->net_copied_size += 8; \
+ ret->net_iov[ret->net_iov_cnt-1].iov_len += 8;
+
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static bool marshal_stat(struct lib9p_ctx *ctx, struct lib9p_stat *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 49 + val->file_name.len + val->file_owner_uid.len + val->file_owner_gid.len + val->file_last_modified_uid.len;
+#if CONFIG_9P_ENABLE_9P2000_u
+ if is_ver(ctx, 9P2000_u) {
+ needed_size += 14 + val->file_extension.len;
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+ if (needed_size > ctx->max_msg_size) {
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_kern_type = 2;
+ MARSHAL_U16LE(ctx, offsetof_end - offsetof_kern_type);
+ MARSHAL_U16LE(ctx, val->kern_type);
+ MARSHAL_U32LE(ctx, val->kern_dev);
+ MARSHAL_U8LE(ctx, val->file_qid.type & qt_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->file_qid.vers);
+ MARSHAL_U64LE(ctx, val->file_qid.path);
+ MARSHAL_U32LE(ctx, val->file_mode & dm_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->file_atime);
+ MARSHAL_U32LE(ctx, val->file_mtime);
+ MARSHAL_U64LE(ctx, val->file_size);
+ MARSHAL_U16LE(ctx, val->file_name.len);
+ MARSHAL_BYTES(ctx, val->file_name.utf8, val->file_name.len);
+ MARSHAL_U16LE(ctx, val->file_owner_uid.len);
+ MARSHAL_BYTES(ctx, val->file_owner_uid.utf8, val->file_owner_uid.len);
+ MARSHAL_U16LE(ctx, val->file_owner_gid.len);
+ MARSHAL_BYTES(ctx, val->file_owner_gid.utf8, val->file_owner_gid.len);
+ MARSHAL_U16LE(ctx, val->file_last_modified_uid.len);
+ MARSHAL_BYTES(ctx, val->file_last_modified_uid.utf8, val->file_last_modified_uid.len);
+#if CONFIG_9P_ENABLE_9P2000_u
+ if (is_ver(ctx, 9P2000_u)) {
+ MARSHAL_U16LE(ctx, val->file_extension.len);
+ MARSHAL_BYTES(ctx, val->file_extension.utf8, val->file_extension.len);
+ MARSHAL_U32LE(ctx, val->file_owner_n_uid);
+ MARSHAL_U32LE(ctx, val->file_owner_n_gid);
+ MARSHAL_U32LE(ctx, val->file_last_modified_n_uid);
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
return false;
}
-static ALWAYS_INLINE bool _validate_size_host(struct _validate_ctx *ctx, size_t n) {
- if (__builtin_add_overflow(ctx->host_extra, n, &ctx->host_extra))
- /* If needed-host-size overflowed size_t, then there's
- * no way that actual-net-size will live up to
- * that. */
- return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content");
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static bool marshal_Tversion(struct lib9p_ctx *ctx, struct lib9p_msg_Tversion *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 13 + val->version.len;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tversion",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 100);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->max_msg_size);
+ MARSHAL_U16LE(ctx, val->version.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->version.utf8, val->version.len);
return false;
}
-static ALWAYS_INLINE bool _validate_list(struct _validate_ctx *ctx,
- size_t cnt,
- _validate_fn_t item_fn, size_t item_host_size) {
- for (size_t i = 0; i < cnt; i++)
- if (_validate_size_host(ctx, item_host_size) || item_fn(ctx))
- return true;
+static bool marshal_Rversion(struct lib9p_ctx *ctx, struct lib9p_msg_Rversion *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 13 + val->version.len;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rversion",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 101);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->max_msg_size);
+ MARSHAL_U16LE(ctx, val->version.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->version.utf8, val->version.len);
return false;
}
-#define validate_1(ctx) _validate_size_net(ctx, 1)
-#define validate_2(ctx) _validate_size_net(ctx, 2)
-#define validate_4(ctx) _validate_size_net(ctx, 4)
-#define validate_8(ctx) _validate_size_net(ctx, 8)
+static bool marshal_Tauth(struct lib9p_ctx *ctx, struct lib9p_msg_Tauth *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 15 + val->uname.len + val->aname.len;
+#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
+ if ( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) ) {
+ needed_size += 4;
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tauth",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 102);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->afid);
+ MARSHAL_U16LE(ctx, val->uname.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->uname.utf8, val->uname.len);
+ MARSHAL_U16LE(ctx, val->aname.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->aname.utf8, val->aname.len);
+#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
+ if (( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) )) {
+ MARSHAL_U32LE(ctx, val->n_uid);
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
+ return false;
+}
-#if defined(CONFIG_9P_ENABLE_9P2000) || defined(CONFIG_9P_ENABLE_9P2000_e) || defined(CONFIG_9P_ENABLE_9P2000_u)
-static ALWAYS_INLINE bool validate_tag(struct _validate_ctx *ctx) {
- return validate_2(ctx);
+static bool marshal_Rauth(struct lib9p_ctx *ctx, struct lib9p_msg_Rauth *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 20;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rauth",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 103);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U8LE(ctx, val->aqid.type & qt_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->aqid.vers);
+ MARSHAL_U64LE(ctx, val->aqid.path);
+ return false;
}
-static ALWAYS_INLINE bool validate_fid(struct _validate_ctx *ctx) {
- return validate_4(ctx);
+static bool marshal_Tattach(struct lib9p_ctx *ctx, struct lib9p_msg_Tattach *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 19 + val->uname.len + val->aname.len;
+#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
+ if ( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) ) {
+ needed_size += 4;
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tattach",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 104);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U32LE(ctx, val->afid);
+ MARSHAL_U16LE(ctx, val->uname.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->uname.utf8, val->uname.len);
+ MARSHAL_U16LE(ctx, val->aname.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->aname.utf8, val->aname.len);
+#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
+ if (( is_ver(ctx, 9P2000_L) || is_ver(ctx, 9P2000_u) )) {
+ MARSHAL_U32LE(ctx, val->n_uid);
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
+ return false;
}
-static ALWAYS_INLINE bool validate_d(struct _validate_ctx *ctx) {
- uint32_t base_offset = ctx->net_offset;
- if (validate_4(ctx))
+static bool marshal_Rattach(struct lib9p_ctx *ctx, struct lib9p_msg_Rattach *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 20;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rattach",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
return true;
- uint32_t len = decode_u32le(&ctx->net_bytes[base_offset]);
- return _validate_size_net(ctx, len) || _validate_size_host(ctx, len);
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 105);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->qid.vers);
+ MARSHAL_U64LE(ctx, val->qid.path);
+ return false;
}
-static ALWAYS_INLINE bool validate_s(struct _validate_ctx *ctx) {
- uint32_t base_offset = ctx->net_offset;
- if (validate_2(ctx))
+static bool marshal_Rerror(struct lib9p_ctx *ctx, struct lib9p_msg_Rerror *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 9 + val->errstr.len;
+#if CONFIG_9P_ENABLE_9P2000_u
+ if is_ver(ctx, 9P2000_u) {
+ needed_size += 4;
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rerror",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
return true;
- uint16_t len = decode_u16le(&ctx->net_bytes[base_offset]);
- if (_validate_size_net(ctx, len) || _validate_size_host(ctx, ((size_t)len)+1))
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 107);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U16LE(ctx, val->errstr.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->errstr.utf8, val->errstr.len);
+#if CONFIG_9P_ENABLE_9P2000_u
+ if (is_ver(ctx, 9P2000_u)) {
+ MARSHAL_U32LE(ctx, val->errnum);
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+ return false;
+}
+
+static bool marshal_Tflush(struct lib9p_ctx *ctx, struct lib9p_msg_Tflush *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 9;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tflush",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
return true;
- if (!is_valid_utf8_without_nul(&ctx->net_bytes[base_offset+2], len))
- return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message contains invalid UTF-8");
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 108);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U16LE(ctx, val->oldtag);
return false;
}
-static const lib9p_dm_t dm_masks[LIB9P_VER_NUM] = {
-#if defined(CONFIG_9P_ENABLE_9P2000)
- [LIB9P_VER_9P2000] = 0b11101100000000000000000111111111,
-#endif /* defined(CONFIG_9P_ENABLE_9P2000) */
-#if defined(CONFIG_9P_ENABLE_9P2000_e)
- [LIB9P_VER_9P2000_e] = 0b11101100000000000000000111111111,
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_e) */
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
- [LIB9P_VER_9P2000_u] = 0b11101100101111000000000111111111,
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
-};
-static ALWAYS_INLINE bool validate_dm(struct _validate_ctx *ctx) {
- if (validate_4(ctx))
+static bool marshal_Rflush(struct lib9p_ctx *ctx, struct lib9p_msg_Rflush *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 7;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rflush",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
return true;
- lib9p_dm_t mask = dm_masks[ctx->ctx->version];
- lib9p_dm_t val = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]);
- if (val & ~mask)
- return lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "unknown bits in dm bitfield: %#04"PRIx32, val & ~mask);
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 109);
+ MARSHAL_U16LE(ctx, val->tag);
return false;
}
-static const lib9p_qt_t qt_masks[LIB9P_VER_NUM] = {
-#if defined(CONFIG_9P_ENABLE_9P2000)
- [LIB9P_VER_9P2000] = 0b11101100,
-#endif /* defined(CONFIG_9P_ENABLE_9P2000) */
-#if defined(CONFIG_9P_ENABLE_9P2000_e)
- [LIB9P_VER_9P2000_e] = 0b11101100,
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_e) */
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
- [LIB9P_VER_9P2000_u] = 0b11101110,
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
-};
-static ALWAYS_INLINE bool validate_qt(struct _validate_ctx *ctx) {
- if (validate_1(ctx))
- return true;
- lib9p_qt_t mask = qt_masks[ctx->ctx->version];
- lib9p_qt_t val = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]);
- if (val & ~mask)
- return lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "unknown bits in qt bitfield: %#01"PRIx8, val & ~mask);
- return false;
-}
-
-static ALWAYS_INLINE bool validate_qid(struct _validate_ctx *ctx) {
- return false
- || validate_qt(ctx)
- || validate_4(ctx)
- || validate_8(ctx)
- ;
-}
-
-static ALWAYS_INLINE bool validate_stat(struct _validate_ctx *ctx) {
- uint16_t stat_size;
- uint32_t _kern_type_offset;
- return false
- || (validate_2(ctx) || ({ stat_size = decode_u16le(&ctx->net_bytes[ctx->net_offset-2]); false; }))
- || ({ _kern_type_offset = ctx->net_offset; validate_2(ctx); })
- || validate_4(ctx)
- || validate_qid(ctx)
- || validate_dm(ctx)
- || validate_4(ctx)
- || validate_4(ctx)
- || validate_8(ctx)
- || validate_s(ctx)
- || validate_s(ctx)
- || validate_s(ctx)
- || validate_s(ctx)
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
- || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && validate_s(ctx) )
- || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && validate_4(ctx) )
- || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && validate_4(ctx) )
- || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && validate_4(ctx) )
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
- || ({ uint32_t exp = ctx->net_offset - _kern_type_offset; (((uint32_t)stat_size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "stat_size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)stat_size, exp); })
- ;
+static bool marshal_Twalk(struct lib9p_ctx *ctx, struct lib9p_msg_Twalk *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 17;
+ for (uint16_t i = 0; i < val->nwname; i++) {
+ needed_size += 2 + val->wname[i].len;
+ }
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Twalk",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 110);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U32LE(ctx, val->newfid);
+ MARSHAL_U16LE(ctx, val->nwname);
+ for (uint16_t i = 0; i < val->nwname; i++) {
+ MARSHAL_U16LE(ctx, val->wname[i].len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->wname[i].utf8, val->wname[i].len);
+ }
+ return false;
}
-static const lib9p_o_t o_masks[LIB9P_VER_NUM] = {
-#if defined(CONFIG_9P_ENABLE_9P2000)
- [LIB9P_VER_9P2000] = 0b01010011,
-#endif /* defined(CONFIG_9P_ENABLE_9P2000) */
-#if defined(CONFIG_9P_ENABLE_9P2000_e)
- [LIB9P_VER_9P2000_e] = 0b01010011,
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_e) */
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
- [LIB9P_VER_9P2000_u] = 0b01010011,
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
-};
-static ALWAYS_INLINE bool validate_o(struct _validate_ctx *ctx) {
- if (validate_1(ctx))
- return true;
- lib9p_o_t mask = o_masks[ctx->ctx->version];
- lib9p_o_t val = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]);
- if (val & ~mask)
- return lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "unknown bits in o bitfield: %#01"PRIx8, val & ~mask);
- return false;
-}
-
-static FLATTEN bool validate_Tversion(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_4(ctx)
- || validate_s(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 100; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Rversion(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_4(ctx)
- || validate_s(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 101; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Tauth(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_fid(ctx)
- || validate_s(ctx)
- || validate_s(ctx)
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
- || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && validate_4(ctx) )
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 102; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Rauth(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_qid(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 103; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Tattach(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_fid(ctx)
- || validate_fid(ctx)
- || validate_s(ctx)
- || validate_s(ctx)
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
- || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && validate_4(ctx) )
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 104; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Rattach(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_qid(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 105; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Rerror(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_s(ctx)
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
- || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && validate_4(ctx) )
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 107; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Tflush(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_2(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 108; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Rflush(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 109; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Twalk(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint16_t nwname;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_fid(ctx)
- || validate_fid(ctx)
- || (validate_2(ctx) || ({ nwname = decode_u16le(&ctx->net_bytes[ctx->net_offset-2]); false; }))
- || _validate_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), validate_s, sizeof(struct lib9p_s))
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 110; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- || ({ uint32_t max = 16; (((uint32_t)nwname) > max) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "nwname value is too large (%"PRIu32" > %"PRIu32")", nwname, max); })
- ;
-}
-
-static FLATTEN bool validate_Rwalk(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint16_t nwqid;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || (validate_2(ctx) || ({ nwqid = decode_u16le(&ctx->net_bytes[ctx->net_offset-2]); false; }))
- || _validate_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), validate_qid, sizeof(struct lib9p_qid))
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 111; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- || ({ uint32_t max = 16; (((uint32_t)nwqid) > max) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "nwqid value is too large (%"PRIu32" > %"PRIu32")", nwqid, max); })
- ;
-}
-
-static FLATTEN bool validate_Topen(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_fid(ctx)
- || validate_o(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 112; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Ropen(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_qid(ctx)
- || validate_4(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 113; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Tcreate(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_fid(ctx)
- || validate_s(ctx)
- || validate_dm(ctx)
- || validate_o(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 114; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Rcreate(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_qid(ctx)
- || validate_4(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 115; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Tread(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_fid(ctx)
- || validate_8(ctx)
- || validate_4(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 116; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Rread(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_d(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 117; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Twrite(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_fid(ctx)
- || validate_8(ctx)
- || validate_d(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 118; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Rwrite(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_4(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 119; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Tclunk(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_fid(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 120; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Rclunk(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 121; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Tremove(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_fid(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 122; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Rremove(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 123; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Tstat(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_fid(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 124; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Rstat(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint16_t nstat;
- uint32_t _size_offset;
- uint32_t _stat_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || (validate_2(ctx) || ({ nstat = decode_u16le(&ctx->net_bytes[ctx->net_offset-2]); false; }))
- || ({ _stat_offset = ctx->net_offset; validate_stat(ctx); })
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 125; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- || ({ uint32_t exp = ctx->net_offset - _stat_offset; (((uint32_t)nstat) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "nstat value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)nstat, exp); })
- ;
-}
-
-static FLATTEN bool validate_Twstat(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint16_t nstat;
- uint32_t _size_offset;
- uint32_t _stat_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_fid(ctx)
- || (validate_2(ctx) || ({ nstat = decode_u16le(&ctx->net_bytes[ctx->net_offset-2]); false; }))
- || ({ _stat_offset = ctx->net_offset; validate_stat(ctx); })
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 126; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- || ({ uint32_t exp = ctx->net_offset - _stat_offset; (((uint32_t)nstat) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "nstat value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)nstat, exp); })
- ;
-}
-
-static FLATTEN bool validate_Rwstat(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 127; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-#endif /* defined(CONFIG_9P_ENABLE_9P2000) || defined(CONFIG_9P_ENABLE_9P2000_e) || defined(CONFIG_9P_ENABLE_9P2000_u) */
-#if defined(CONFIG_9P_ENABLE_9P2000_e)
-static FLATTEN bool validate_Tsession(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_8(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 150; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Rsession(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 151; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Tsread(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_4(ctx)
- || validate_2(ctx)
- || _validate_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), validate_s, sizeof(struct lib9p_s))
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 152; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Rsread(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_d(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 153; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Tswrite(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_4(ctx)
- || validate_2(ctx)
- || _validate_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), validate_s, sizeof(struct lib9p_s))
- || validate_d(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 154; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-
-static FLATTEN bool validate_Rswrite(struct _validate_ctx *ctx) {
- uint32_t size;
- uint8_t typ;
- uint32_t _size_offset;
- return false
- || (({ _size_offset = ctx->net_offset; validate_4(ctx); }) || ({ size = decode_u32le(&ctx->net_bytes[ctx->net_offset-4]); false; }))
- || (validate_1(ctx) || ({ typ = decode_u8le(&ctx->net_bytes[ctx->net_offset-1]); false; }))
- || validate_tag(ctx)
- || validate_4(ctx)
- || ({ uint32_t exp = ctx->net_offset - _size_offset; (((uint32_t)size) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "size value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)size, exp); })
- || ({ uint32_t exp = 155; (((uint32_t)typ) != exp) &&
- lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "typ value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t)typ, exp); })
- ;
-}
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_e) */
+static bool marshal_Rwalk(struct lib9p_ctx *ctx, struct lib9p_msg_Rwalk *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 9 + (val->nwqid)*13;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rwalk",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 111);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U16LE(ctx, val->nwqid);
+ for (uint16_t i = 0; i < val->nwqid; i++) {
+ MARSHAL_U8LE(ctx, val->wqid[i].type & qt_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->wqid[i].vers);
+ MARSHAL_U64LE(ctx, val->wqid[i].path);
+ }
+ return false;
+}
-/* unmarshal_* ****************************************************************/
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static bool marshal_Topen(struct lib9p_ctx *ctx, struct lib9p_msg_Topen *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 12;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Topen",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 112);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U8LE(ctx, val->mode & o_masks[ctx->version]);
+ return false;
+}
-static ALWAYS_INLINE void unmarshal_1(struct _unmarshal_ctx *ctx, uint8_t *out) {
- *out = decode_u8le(&ctx->net_bytes[ctx->net_offset]);
- ctx->net_offset += 1;
+static bool marshal_Ropen(struct lib9p_ctx *ctx, struct lib9p_msg_Ropen *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 24;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Ropen",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 113);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->qid.vers);
+ MARSHAL_U64LE(ctx, val->qid.path);
+ MARSHAL_U32LE(ctx, val->iounit);
+ return false;
}
-static ALWAYS_INLINE void unmarshal_2(struct _unmarshal_ctx *ctx, uint16_t *out) {
- *out = decode_u16le(&ctx->net_bytes[ctx->net_offset]);
- ctx->net_offset += 2;
+static bool marshal_Tcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Tcreate *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 18 + val->name.len;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tcreate",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 114);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U16LE(ctx, val->name.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len);
+ MARSHAL_U32LE(ctx, val->perm & dm_masks[ctx->version]);
+ MARSHAL_U8LE(ctx, val->mode & o_masks[ctx->version]);
+ return false;
}
-static ALWAYS_INLINE void unmarshal_4(struct _unmarshal_ctx *ctx, uint32_t *out) {
- *out = decode_u32le(&ctx->net_bytes[ctx->net_offset]);
- ctx->net_offset += 4;
+static bool marshal_Rcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Rcreate *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 24;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rcreate",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 115);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->qid.vers);
+ MARSHAL_U64LE(ctx, val->qid.path);
+ MARSHAL_U32LE(ctx, val->iounit);
+ return false;
}
-static ALWAYS_INLINE void unmarshal_8(struct _unmarshal_ctx *ctx, uint64_t *out) {
- *out = decode_u64le(&ctx->net_bytes[ctx->net_offset]);
- ctx->net_offset += 8;
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static bool marshal_Tread(struct lib9p_ctx *ctx, struct lib9p_msg_Tread *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 23;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tread",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 116);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U64LE(ctx, val->offset);
+ MARSHAL_U32LE(ctx, val->count);
+ return false;
}
-#if defined(CONFIG_9P_ENABLE_9P2000) || defined(CONFIG_9P_ENABLE_9P2000_e) || defined(CONFIG_9P_ENABLE_9P2000_u)
-static ALWAYS_INLINE void unmarshal_tag(struct _unmarshal_ctx *ctx, lib9p_tag_t *out) {
- unmarshal_2(ctx, (uint16_t *)out);
+static bool marshal_Rread(struct lib9p_ctx *ctx, struct lib9p_msg_Rread *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 11 + val->count;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rread",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 117);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->count);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->data, val->count);
+ return false;
}
-static ALWAYS_INLINE void unmarshal_fid(struct _unmarshal_ctx *ctx, lib9p_fid_t *out) {
- unmarshal_4(ctx, (uint32_t *)out);
+static bool marshal_Twrite(struct lib9p_ctx *ctx, struct lib9p_msg_Twrite *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 23 + val->count;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Twrite",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 118);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U64LE(ctx, val->offset);
+ MARSHAL_U32LE(ctx, val->count);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->data, val->count);
+ return false;
}
-static ALWAYS_INLINE void unmarshal_d(struct _unmarshal_ctx *ctx, struct lib9p_d *out) {
- memset(out, 0, sizeof(*out));
- unmarshal_4(ctx, &out->len);
- out->dat = ctx->extra;
- ctx->extra += sizeof(out->dat[0]) * out->len;
- for (typeof(out->len) i = 0; i < out->len; i++)
- unmarshal_1(ctx, (uint8_t *)&out->dat[i]);
+static bool marshal_Rwrite(struct lib9p_ctx *ctx, struct lib9p_msg_Rwrite *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 11;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rwrite",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 119);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->count);
+ return false;
}
-static ALWAYS_INLINE void unmarshal_s(struct _unmarshal_ctx *ctx, struct lib9p_s *out) {
- memset(out, 0, sizeof(*out));
- unmarshal_2(ctx, &out->len);
- out->utf8 = ctx->extra;
- ctx->extra += sizeof(out->utf8[0]) * out->len;
- for (typeof(out->len) i = 0; i < out->len; i++)
- unmarshal_1(ctx, (uint8_t *)&out->utf8[i]);
- ctx->extra++;
- out->utf8[out->len] = '\0';
+static bool marshal_Tclunk(struct lib9p_ctx *ctx, struct lib9p_msg_Tclunk *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 11;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tclunk",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 120);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ return false;
}
-static ALWAYS_INLINE void unmarshal_dm(struct _unmarshal_ctx *ctx, lib9p_dm_t *out) {
- unmarshal_4(ctx, (uint32_t *)out);
+static bool marshal_Rclunk(struct lib9p_ctx *ctx, struct lib9p_msg_Rclunk *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 7;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rclunk",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 121);
+ MARSHAL_U16LE(ctx, val->tag);
+ return false;
}
-static ALWAYS_INLINE void unmarshal_qt(struct _unmarshal_ctx *ctx, lib9p_qt_t *out) {
- unmarshal_1(ctx, (uint8_t *)out);
+static bool marshal_Tremove(struct lib9p_ctx *ctx, struct lib9p_msg_Tremove *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 11;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tremove",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 122);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ return false;
}
-static ALWAYS_INLINE void unmarshal_qid(struct _unmarshal_ctx *ctx, struct lib9p_qid *out) {
- memset(out, 0, sizeof(*out));
- unmarshal_qt(ctx, &out->type);
- unmarshal_4(ctx, &out->vers);
- unmarshal_8(ctx, &out->path);
+static bool marshal_Rremove(struct lib9p_ctx *ctx, struct lib9p_msg_Rremove *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 7;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rremove",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 123);
+ MARSHAL_U16LE(ctx, val->tag);
+ return false;
}
-static ALWAYS_INLINE void unmarshal_stat(struct _unmarshal_ctx *ctx, struct lib9p_stat *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 2;
- unmarshal_2(ctx, &out->kern_type);
- unmarshal_4(ctx, &out->kern_dev);
- unmarshal_qid(ctx, &out->file_qid);
- unmarshal_dm(ctx, &out->file_mode);
- unmarshal_4(ctx, &out->file_atime);
- unmarshal_4(ctx, &out->file_mtime);
- unmarshal_8(ctx, &out->file_size);
- unmarshal_s(ctx, &out->file_name);
- unmarshal_s(ctx, &out->file_owner_uid);
- unmarshal_s(ctx, &out->file_owner_gid);
- unmarshal_s(ctx, &out->file_last_modified_uid);
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
- if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_s(ctx, &out->file_extension);
- if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->file_owner_n_uid);
- if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->file_owner_n_gid);
- if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->file_last_modified_n_uid);
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
-}
-
-static ALWAYS_INLINE void unmarshal_o(struct _unmarshal_ctx *ctx, lib9p_o_t *out) {
- unmarshal_1(ctx, (uint8_t *)out);
-}
-
-static FLATTEN void unmarshal_Tversion(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tversion *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_4(ctx, &out->max_msg_size);
- unmarshal_s(ctx, &out->version);
-}
-
-static FLATTEN void unmarshal_Rversion(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rversion *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_4(ctx, &out->max_msg_size);
- unmarshal_s(ctx, &out->version);
-}
-
-static FLATTEN void unmarshal_Tauth(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tauth *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_fid(ctx, &out->afid);
- unmarshal_s(ctx, &out->uname);
- unmarshal_s(ctx, &out->aname);
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
- if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->n_uname);
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
-}
-
-static FLATTEN void unmarshal_Rauth(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rauth *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_qid(ctx, &out->aqid);
-}
-
-static FLATTEN void unmarshal_Tattach(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tattach *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_fid(ctx, &out->fid);
- unmarshal_fid(ctx, &out->afid);
- unmarshal_s(ctx, &out->uname);
- unmarshal_s(ctx, &out->aname);
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
- if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->n_uname);
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
-}
-
-static FLATTEN void unmarshal_Rattach(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rattach *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_qid(ctx, &out->qid);
-}
-
-static FLATTEN void unmarshal_Rerror(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rerror *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_s(ctx, &out->ename);
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
- if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->errno);
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
-}
-
-static FLATTEN void unmarshal_Tflush(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tflush *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_2(ctx, &out->oldtag);
-}
-
-static FLATTEN void unmarshal_Rflush(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rflush *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
-}
-
-static FLATTEN void unmarshal_Twalk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Twalk *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_fid(ctx, &out->fid);
- unmarshal_fid(ctx, &out->newfid);
- unmarshal_2(ctx, &out->nwname);
- out->wname = ctx->extra;
- ctx->extra += sizeof(out->wname[0]) * out->nwname;
- for (typeof(out->nwname) i = 0; i < out->nwname; i++)
- unmarshal_s(ctx, &out->wname[i]);
-}
-
-static FLATTEN void unmarshal_Rwalk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rwalk *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_2(ctx, &out->nwqid);
- out->wqid = ctx->extra;
- ctx->extra += sizeof(out->wqid[0]) * out->nwqid;
- for (typeof(out->nwqid) i = 0; i < out->nwqid; i++)
- unmarshal_qid(ctx, &out->wqid[i]);
-}
-
-static FLATTEN void unmarshal_Topen(struct _unmarshal_ctx *ctx, struct lib9p_msg_Topen *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_fid(ctx, &out->fid);
- unmarshal_o(ctx, &out->mode);
-}
-
-static FLATTEN void unmarshal_Ropen(struct _unmarshal_ctx *ctx, struct lib9p_msg_Ropen *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_qid(ctx, &out->qid);
- unmarshal_4(ctx, &out->iounit);
-}
-
-static FLATTEN void unmarshal_Tcreate(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tcreate *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_fid(ctx, &out->fid);
- unmarshal_s(ctx, &out->name);
- unmarshal_dm(ctx, &out->perm);
- unmarshal_o(ctx, &out->mode);
-}
-
-static FLATTEN void unmarshal_Rcreate(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rcreate *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_qid(ctx, &out->qid);
- unmarshal_4(ctx, &out->iounit);
-}
-
-static FLATTEN void unmarshal_Tread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tread *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_fid(ctx, &out->fid);
- unmarshal_8(ctx, &out->offset);
- unmarshal_4(ctx, &out->count);
-}
-
-static FLATTEN void unmarshal_Rread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rread *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_d(ctx, &out->data);
-}
-
-static FLATTEN void unmarshal_Twrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Twrite *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_fid(ctx, &out->fid);
- unmarshal_8(ctx, &out->offset);
- unmarshal_d(ctx, &out->data);
-}
-
-static FLATTEN void unmarshal_Rwrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rwrite *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_4(ctx, &out->count);
-}
-
-static FLATTEN void unmarshal_Tclunk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tclunk *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_fid(ctx, &out->fid);
-}
-
-static FLATTEN void unmarshal_Rclunk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rclunk *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
-}
-
-static FLATTEN void unmarshal_Tremove(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tremove *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_fid(ctx, &out->fid);
-}
-
-static FLATTEN void unmarshal_Rremove(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rremove *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
-}
-
-static FLATTEN void unmarshal_Tstat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tstat *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_fid(ctx, &out->fid);
-}
-
-static FLATTEN void unmarshal_Rstat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rstat *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- ctx->net_offset += 2;
- unmarshal_stat(ctx, &out->stat);
-}
-
-static FLATTEN void unmarshal_Twstat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Twstat *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_fid(ctx, &out->fid);
- ctx->net_offset += 2;
- unmarshal_stat(ctx, &out->stat);
-}
-
-static FLATTEN void unmarshal_Rwstat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rwstat *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
-}
-
-#endif /* defined(CONFIG_9P_ENABLE_9P2000) || defined(CONFIG_9P_ENABLE_9P2000_e) || defined(CONFIG_9P_ENABLE_9P2000_u) */
-#if defined(CONFIG_9P_ENABLE_9P2000_e)
-static FLATTEN void unmarshal_Tsession(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tsession *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_8(ctx, &out->key);
-}
-
-static FLATTEN void unmarshal_Rsession(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rsession *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
-}
-
-static FLATTEN void unmarshal_Tsread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tsread *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_4(ctx, &out->fid);
- unmarshal_2(ctx, &out->nwname);
- out->wname = ctx->extra;
- ctx->extra += sizeof(out->wname[0]) * out->nwname;
- for (typeof(out->nwname) i = 0; i < out->nwname; i++)
- unmarshal_s(ctx, &out->wname[i]);
-}
-
-static FLATTEN void unmarshal_Rsread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rsread *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_d(ctx, &out->data);
-}
-
-static FLATTEN void unmarshal_Tswrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tswrite *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_4(ctx, &out->fid);
- unmarshal_2(ctx, &out->nwname);
- out->wname = ctx->extra;
- ctx->extra += sizeof(out->wname[0]) * out->nwname;
- for (typeof(out->nwname) i = 0; i < out->nwname; i++)
- unmarshal_s(ctx, &out->wname[i]);
- unmarshal_d(ctx, &out->data);
-}
-
-static FLATTEN void unmarshal_Rswrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rswrite *out) {
- memset(out, 0, sizeof(*out));
- ctx->net_offset += 4;
- ctx->net_offset += 1;
- unmarshal_tag(ctx, &out->tag);
- unmarshal_4(ctx, &out->count);
-}
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_e) */
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static bool marshal_Tstat(struct lib9p_ctx *ctx, struct lib9p_msg_Tstat *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 11;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tstat",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 124);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ return false;
+}
-/* marshal_* ******************************************************************/
+static bool marshal_Rstat(struct lib9p_ctx *ctx, struct lib9p_msg_Rstat *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 58 + val->stat.file_name.len + val->stat.file_owner_uid.len + val->stat.file_owner_gid.len + val->stat.file_last_modified_uid.len;
+#if CONFIG_9P_ENABLE_9P2000_u
+ if is_ver(ctx, 9P2000_u) {
+ needed_size += 14 + val->stat.file_extension.len;
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rstat",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ uint32_t offsetof_stat = 9;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 125);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U16LE(ctx, offsetof_end - offsetof_stat);
+ uint32_t offsetof_stat_end = 49 + val->stat.file_name.len + val->stat.file_owner_uid.len + val->stat.file_owner_gid.len + val->stat.file_last_modified_uid.len;
+#if CONFIG_9P_ENABLE_9P2000_u
+ if is_ver(ctx, 9P2000_u) {
+ offsetof_stat_end += 14 + val->stat.file_extension.len;
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+ uint32_t offsetof_stat_kern_type = 2;
+ MARSHAL_U16LE(ctx, offsetof_stat_end - offsetof_stat_kern_type);
+ MARSHAL_U16LE(ctx, val->stat.kern_type);
+ MARSHAL_U32LE(ctx, val->stat.kern_dev);
+ MARSHAL_U8LE(ctx, val->stat.file_qid.type & qt_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->stat.file_qid.vers);
+ MARSHAL_U64LE(ctx, val->stat.file_qid.path);
+ MARSHAL_U32LE(ctx, val->stat.file_mode & dm_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->stat.file_atime);
+ MARSHAL_U32LE(ctx, val->stat.file_mtime);
+ MARSHAL_U64LE(ctx, val->stat.file_size);
+ MARSHAL_U16LE(ctx, val->stat.file_name.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_name.utf8, val->stat.file_name.len);
+ MARSHAL_U16LE(ctx, val->stat.file_owner_uid.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_owner_uid.utf8, val->stat.file_owner_uid.len);
+ MARSHAL_U16LE(ctx, val->stat.file_owner_gid.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_owner_gid.utf8, val->stat.file_owner_gid.len);
+ MARSHAL_U16LE(ctx, val->stat.file_last_modified_uid.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_last_modified_uid.utf8, val->stat.file_last_modified_uid.len);
+#if CONFIG_9P_ENABLE_9P2000_u
+ if (is_ver(ctx, 9P2000_u)) {
+ MARSHAL_U16LE(ctx, val->stat.file_extension.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_extension.utf8, val->stat.file_extension.len);
+ MARSHAL_U32LE(ctx, val->stat.file_owner_n_uid);
+ MARSHAL_U32LE(ctx, val->stat.file_owner_n_gid);
+ MARSHAL_U32LE(ctx, val->stat.file_last_modified_n_uid);
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+ return false;
+}
+
+static bool marshal_Twstat(struct lib9p_ctx *ctx, struct lib9p_msg_Twstat *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 62 + val->stat.file_name.len + val->stat.file_owner_uid.len + val->stat.file_owner_gid.len + val->stat.file_last_modified_uid.len;
+#if CONFIG_9P_ENABLE_9P2000_u
+ if is_ver(ctx, 9P2000_u) {
+ needed_size += 14 + val->stat.file_extension.len;
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Twstat",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ uint32_t offsetof_stat = 13;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 126);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U16LE(ctx, offsetof_end - offsetof_stat);
+ uint32_t offsetof_stat_end = 49 + val->stat.file_name.len + val->stat.file_owner_uid.len + val->stat.file_owner_gid.len + val->stat.file_last_modified_uid.len;
+#if CONFIG_9P_ENABLE_9P2000_u
+ if is_ver(ctx, 9P2000_u) {
+ offsetof_stat_end += 14 + val->stat.file_extension.len;
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+ uint32_t offsetof_stat_kern_type = 2;
+ MARSHAL_U16LE(ctx, offsetof_stat_end - offsetof_stat_kern_type);
+ MARSHAL_U16LE(ctx, val->stat.kern_type);
+ MARSHAL_U32LE(ctx, val->stat.kern_dev);
+ MARSHAL_U8LE(ctx, val->stat.file_qid.type & qt_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->stat.file_qid.vers);
+ MARSHAL_U64LE(ctx, val->stat.file_qid.path);
+ MARSHAL_U32LE(ctx, val->stat.file_mode & dm_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->stat.file_atime);
+ MARSHAL_U32LE(ctx, val->stat.file_mtime);
+ MARSHAL_U64LE(ctx, val->stat.file_size);
+ MARSHAL_U16LE(ctx, val->stat.file_name.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_name.utf8, val->stat.file_name.len);
+ MARSHAL_U16LE(ctx, val->stat.file_owner_uid.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_owner_uid.utf8, val->stat.file_owner_uid.len);
+ MARSHAL_U16LE(ctx, val->stat.file_owner_gid.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_owner_gid.utf8, val->stat.file_owner_gid.len);
+ MARSHAL_U16LE(ctx, val->stat.file_last_modified_uid.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_last_modified_uid.utf8, val->stat.file_last_modified_uid.len);
+#if CONFIG_9P_ENABLE_9P2000_u
+ if (is_ver(ctx, 9P2000_u)) {
+ MARSHAL_U16LE(ctx, val->stat.file_extension.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->stat.file_extension.utf8, val->stat.file_extension.len);
+ MARSHAL_U32LE(ctx, val->stat.file_owner_n_uid);
+ MARSHAL_U32LE(ctx, val->stat.file_owner_n_gid);
+ MARSHAL_U32LE(ctx, val->stat.file_last_modified_n_uid);
+ }
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+ return false;
+}
+
+static bool marshal_Rwstat(struct lib9p_ctx *ctx, struct lib9p_msg_Rwstat *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 7;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rwstat",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 127);
+ MARSHAL_U16LE(ctx, val->tag);
+ return false;
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+static bool marshal_Topenfd(struct lib9p_ctx *ctx, struct lib9p_msg_Topenfd *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 12;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Topenfd",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 98);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U8LE(ctx, val->mode & o_masks[ctx->version]);
+ return false;
+}
+
+static bool marshal_Ropenfd(struct lib9p_ctx *ctx, struct lib9p_msg_Ropenfd *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 28;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Ropenfd",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 99);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->qid.vers);
+ MARSHAL_U64LE(ctx, val->qid.path);
+ MARSHAL_U32LE(ctx, val->iounit);
+ MARSHAL_U32LE(ctx, val->unixfd);
+ return false;
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_L
+static bool marshal_Rlerror(struct lib9p_ctx *ctx, struct lib9p_msg_Rlerror *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 11;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rlerror",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 7);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->errnum);
+ return false;
+}
+
+static bool marshal_Tstatfs(struct lib9p_ctx *ctx, struct lib9p_msg_Tstatfs *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 11;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tstatfs",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 8);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ return false;
+}
+
+static bool marshal_Rstatfs(struct lib9p_ctx *ctx, struct lib9p_msg_Rstatfs *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 67;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rstatfs",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 9);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->type);
+ MARSHAL_U32LE(ctx, val->bsize);
+ MARSHAL_U64LE(ctx, val->blocks);
+ MARSHAL_U64LE(ctx, val->bfree);
+ MARSHAL_U64LE(ctx, val->bavail);
+ MARSHAL_U64LE(ctx, val->files);
+ MARSHAL_U64LE(ctx, val->ffree);
+ MARSHAL_U64LE(ctx, val->fsid);
+ MARSHAL_U32LE(ctx, val->namelen);
+ return false;
+}
+
+static bool marshal_Tlopen(struct lib9p_ctx *ctx, struct lib9p_msg_Tlopen *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 15;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tlopen",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 12);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U32LE(ctx, val->flags & lo_masks[ctx->version]);
+ return false;
+}
+
+static bool marshal_Rlopen(struct lib9p_ctx *ctx, struct lib9p_msg_Rlopen *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 24;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rlopen",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 13);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->qid.vers);
+ MARSHAL_U64LE(ctx, val->qid.path);
+ MARSHAL_U32LE(ctx, val->iounit);
+ return false;
+}
+
+static bool marshal_Tlcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Tlcreate *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 25 + val->name.len;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tlcreate",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 14);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U16LE(ctx, val->name.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len);
+ MARSHAL_U32LE(ctx, val->flags & lo_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->mode & mode_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->gid);
+ return false;
+}
+
+static bool marshal_Rlcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Rlcreate *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 24;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rlcreate",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 15);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->qid.vers);
+ MARSHAL_U64LE(ctx, val->qid.path);
+ MARSHAL_U32LE(ctx, val->iounit);
+ return false;
+}
+
+static bool marshal_Tsymlink(struct lib9p_ctx *ctx, struct lib9p_msg_Tsymlink *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 19 + val->name.len + val->symtgt.len;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tsymlink",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 16);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U16LE(ctx, val->name.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len);
+ MARSHAL_U16LE(ctx, val->symtgt.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->symtgt.utf8, val->symtgt.len);
+ MARSHAL_U32LE(ctx, val->gid);
+ return false;
+}
+
+static bool marshal_Rsymlink(struct lib9p_ctx *ctx, struct lib9p_msg_Rsymlink *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 20;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rsymlink",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 17);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->qid.vers);
+ MARSHAL_U64LE(ctx, val->qid.path);
+ return false;
+}
+
+static bool marshal_Tmknod(struct lib9p_ctx *ctx, struct lib9p_msg_Tmknod *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 29 + val->name.len;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tmknod",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 18);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->dfid);
+ MARSHAL_U16LE(ctx, val->name.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len);
+ MARSHAL_U32LE(ctx, val->mode & mode_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->major);
+ MARSHAL_U32LE(ctx, val->minor);
+ MARSHAL_U32LE(ctx, val->gid);
+ return false;
+}
-static ALWAYS_INLINE bool _marshal_too_large(struct _marshal_ctx *ctx) {
- lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s too large to marshal into %s limit (limit=%"PRIu32")",
- (ctx->net_bytes[4] % 2 == 0) ? "T-message" : "R-message",
- ctx->ctx->version ? "negotiated" : ((ctx->net_bytes[4] % 2 == 0) ? "client" : "server"),
- ctx->ctx->max_msg_size);
- return true;
+static bool marshal_Rmknod(struct lib9p_ctx *ctx, struct lib9p_msg_Rmknod *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 20;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rmknod",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 19);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->qid.vers);
+ MARSHAL_U64LE(ctx, val->qid.path);
+ return false;
}
-static ALWAYS_INLINE bool marshal_1(struct _marshal_ctx *ctx, uint8_t *val) {
- if (ctx->net_offset + 1 > ctx->ctx->max_msg_size)
- return _marshal_too_large(ctx);
- ctx->net_bytes[ctx->net_offset] = *val;
- ctx->net_offset += 1;
+static bool marshal_Trename(struct lib9p_ctx *ctx, struct lib9p_msg_Trename *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 17 + val->name.len;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Trename",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 20);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U32LE(ctx, val->dfid);
+ MARSHAL_U16LE(ctx, val->name.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len);
return false;
}
-static ALWAYS_INLINE bool marshal_2(struct _marshal_ctx *ctx, uint16_t *val) {
- if (ctx->net_offset + 2 > ctx->ctx->max_msg_size)
- return _marshal_too_large(ctx);
- encode_u16le(*val, &ctx->net_bytes[ctx->net_offset]);
- ctx->net_offset += 2;
+static bool marshal_Rrename(struct lib9p_ctx *ctx, struct lib9p_msg_Rrename *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 7;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rrename",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 21);
+ MARSHAL_U16LE(ctx, val->tag);
return false;
}
-static ALWAYS_INLINE bool marshal_4(struct _marshal_ctx *ctx, uint32_t *val) {
- if (ctx->net_offset + 4 > ctx->ctx->max_msg_size)
+static bool marshal_Treadlink(struct lib9p_ctx *ctx, struct lib9p_msg_Treadlink *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 11;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Treadlink",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
return true;
- encode_u32le(*val, &ctx->net_bytes[ctx->net_offset]);
- ctx->net_offset += 4;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 22);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
return false;
}
-static ALWAYS_INLINE bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) {
- if (ctx->net_offset + 8 > ctx->ctx->max_msg_size)
+static bool marshal_Rreadlink(struct lib9p_ctx *ctx, struct lib9p_msg_Rreadlink *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 9 + val->target.len;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rreadlink",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
return true;
- encode_u64le(*val, &ctx->net_bytes[ctx->net_offset]);
- ctx->net_offset += 8;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 23);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U16LE(ctx, val->target.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->target.utf8, val->target.len);
return false;
}
-#if defined(CONFIG_9P_ENABLE_9P2000) || defined(CONFIG_9P_ENABLE_9P2000_e) || defined(CONFIG_9P_ENABLE_9P2000_u)
-static ALWAYS_INLINE bool marshal_tag(struct _marshal_ctx *ctx, lib9p_tag_t *val) {
- return marshal_2(ctx, (uint16_t *)val);
+static bool marshal_Tgetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Tgetattr *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 19;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tgetattr",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 24);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U64LE(ctx, val->request_mask & getattr_masks[ctx->version]);
+ return false;
}
-static ALWAYS_INLINE bool marshal_fid(struct _marshal_ctx *ctx, lib9p_fid_t *val) {
- return marshal_4(ctx, (uint32_t *)val);
+static bool marshal_Rgetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Rgetattr *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 160;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rgetattr",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 25);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U64LE(ctx, val->valid & getattr_masks[ctx->version]);
+ MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->qid.vers);
+ MARSHAL_U64LE(ctx, val->qid.path);
+ MARSHAL_U32LE(ctx, val->mode & mode_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->uid);
+ MARSHAL_U32LE(ctx, val->gid);
+ MARSHAL_U64LE(ctx, val->nlink);
+ MARSHAL_U64LE(ctx, val->rdev);
+ MARSHAL_U64LE(ctx, val->filesize);
+ MARSHAL_U64LE(ctx, val->blksize);
+ MARSHAL_U64LE(ctx, val->blocks);
+ MARSHAL_U64LE(ctx, val->atime_sec);
+ MARSHAL_U64LE(ctx, val->atime_nsec);
+ MARSHAL_U64LE(ctx, val->mtime_sec);
+ MARSHAL_U64LE(ctx, val->mtime_nsec);
+ MARSHAL_U64LE(ctx, val->ctime_sec);
+ MARSHAL_U64LE(ctx, val->ctime_nsec);
+ MARSHAL_U64LE(ctx, val->btime_sec);
+ MARSHAL_U64LE(ctx, val->btime_nsec);
+ MARSHAL_U64LE(ctx, val->gen);
+ MARSHAL_U64LE(ctx, val->data_version);
+ return false;
}
-static ALWAYS_INLINE bool marshal_d(struct _marshal_ctx *ctx, struct lib9p_d *val) {
- return false
- || marshal_4(ctx, &val->len)
- || ({ bool err = false;
- for (typeof(val->len) i = 0; i < val->len && !err; i++)
- err = marshal_1(ctx, (uint8_t *)&val->dat[i]);
- err; })
- ;
+static bool marshal_Tsetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Tsetattr *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 67;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tsetattr",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 26);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U32LE(ctx, val->valid & setattr_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->mode & mode_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->uid);
+ MARSHAL_U32LE(ctx, val->gid);
+ MARSHAL_U64LE(ctx, val->filesize);
+ MARSHAL_U64LE(ctx, val->atime_sec);
+ MARSHAL_U64LE(ctx, val->atime_nsec);
+ MARSHAL_U64LE(ctx, val->mtime_sec);
+ MARSHAL_U64LE(ctx, val->mtime_nsec);
+ return false;
+}
+
+static bool marshal_Rsetattr(struct lib9p_ctx *ctx, struct lib9p_msg_Rsetattr *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 7;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rsetattr",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 27);
+ MARSHAL_U16LE(ctx, val->tag);
+ return false;
+}
+
+static bool marshal_Txattrwalk(struct lib9p_ctx *ctx, struct lib9p_msg_Txattrwalk *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 17 + val->name.len;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Txattrwalk",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 30);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U32LE(ctx, val->newfid);
+ MARSHAL_U16LE(ctx, val->name.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len);
+ return false;
+}
+
+static bool marshal_Rxattrwalk(struct lib9p_ctx *ctx, struct lib9p_msg_Rxattrwalk *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 15;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rxattrwalk",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 31);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U64LE(ctx, val->attr_size);
+ return false;
+}
+
+static bool marshal_Txattrcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Txattrcreate *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 25 + val->name.len;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Txattrcreate",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 32);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U16LE(ctx, val->name.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len);
+ MARSHAL_U64LE(ctx, val->attr_size);
+ MARSHAL_U32LE(ctx, val->flags);
+ return false;
+}
+
+static bool marshal_Rxattrcreate(struct lib9p_ctx *ctx, struct lib9p_msg_Rxattrcreate *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 7;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rxattrcreate",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 33);
+ MARSHAL_U16LE(ctx, val->tag);
+ return false;
+}
+
+static bool marshal_Treaddir(struct lib9p_ctx *ctx, struct lib9p_msg_Treaddir *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 23;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Treaddir",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 40);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U64LE(ctx, val->offset);
+ MARSHAL_U32LE(ctx, val->count);
+ return false;
+}
+
+static bool marshal_Rreaddir(struct lib9p_ctx *ctx, struct lib9p_msg_Rreaddir *val, struct _marshal_ret *ret) {
+ uint64_t needed_size = 11 + val->count;
+ if (needed_size > (uint64_t)(ctx->max_msg_size)) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rreaddir",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = (uint32_t)needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 41);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->count);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->data, val->count);
+ return false;
+}
+
+static bool marshal_Tfsync(struct lib9p_ctx *ctx, struct lib9p_msg_Tfsync *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 15;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tfsync",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 50);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U32LE(ctx, val->datasync);
+ return false;
+}
+
+static bool marshal_Rfsync(struct lib9p_ctx *ctx, struct lib9p_msg_Rfsync *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 7;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rfsync",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 51);
+ MARSHAL_U16LE(ctx, val->tag);
+ return false;
+}
+
+static bool marshal_Tlock(struct lib9p_ctx *ctx, struct lib9p_msg_Tlock *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 38 + val->client_id.len;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tlock",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 52);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U8LE(ctx, val->type);
+ MARSHAL_U32LE(ctx, val->flags & lock_flags_masks[ctx->version]);
+ MARSHAL_U64LE(ctx, val->start);
+ MARSHAL_U64LE(ctx, val->length);
+ MARSHAL_U32LE(ctx, val->proc_id);
+ MARSHAL_U16LE(ctx, val->client_id.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->client_id.utf8, val->client_id.len);
+ return false;
+}
+
+static bool marshal_Rlock(struct lib9p_ctx *ctx, struct lib9p_msg_Rlock *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 8;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rlock",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 53);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U8LE(ctx, val->status);
+ return false;
+}
+
+static bool marshal_Tgetlock(struct lib9p_ctx *ctx, struct lib9p_msg_Tgetlock *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 34 + val->client_id.len;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tgetlock",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 54);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U8LE(ctx, val->type);
+ MARSHAL_U64LE(ctx, val->start);
+ MARSHAL_U64LE(ctx, val->length);
+ MARSHAL_U32LE(ctx, val->proc_id);
+ MARSHAL_U16LE(ctx, val->client_id.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->client_id.utf8, val->client_id.len);
+ return false;
+}
+
+static bool marshal_Rgetlock(struct lib9p_ctx *ctx, struct lib9p_msg_Rgetlock *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 30 + val->client_id.len;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rgetlock",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 55);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U8LE(ctx, val->type);
+ MARSHAL_U64LE(ctx, val->start);
+ MARSHAL_U64LE(ctx, val->length);
+ MARSHAL_U32LE(ctx, val->proc_id);
+ MARSHAL_U16LE(ctx, val->client_id.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->client_id.utf8, val->client_id.len);
+ return false;
+}
+
+static bool marshal_Tlink(struct lib9p_ctx *ctx, struct lib9p_msg_Tlink *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 17 + val->name.len;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tlink",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 70);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->dfid);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U16LE(ctx, val->name.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len);
+ return false;
+}
+
+static bool marshal_Rlink(struct lib9p_ctx *ctx, struct lib9p_msg_Rlink *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 7;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rlink",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 71);
+ MARSHAL_U16LE(ctx, val->tag);
+ return false;
+}
+
+static bool marshal_Tmkdir(struct lib9p_ctx *ctx, struct lib9p_msg_Tmkdir *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 21 + val->name.len;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tmkdir",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 72);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->dfid);
+ MARSHAL_U16LE(ctx, val->name.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len);
+ MARSHAL_U32LE(ctx, val->mode & mode_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->gid);
+ return false;
+}
+
+static bool marshal_Rmkdir(struct lib9p_ctx *ctx, struct lib9p_msg_Rmkdir *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 20;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rmkdir",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 73);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U8LE(ctx, val->qid.type & qt_masks[ctx->version]);
+ MARSHAL_U32LE(ctx, val->qid.vers);
+ MARSHAL_U64LE(ctx, val->qid.path);
+ return false;
+}
+
+static bool marshal_Trenameat(struct lib9p_ctx *ctx, struct lib9p_msg_Trenameat *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 19 + val->oldname.len + val->newname.len;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Trenameat",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 74);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->olddirfid);
+ MARSHAL_U16LE(ctx, val->oldname.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->oldname.utf8, val->oldname.len);
+ MARSHAL_U32LE(ctx, val->newdirfid);
+ MARSHAL_U16LE(ctx, val->newname.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->newname.utf8, val->newname.len);
+ return false;
+}
+
+static bool marshal_Rrenameat(struct lib9p_ctx *ctx, struct lib9p_msg_Rrenameat *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 7;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rrenameat",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 75);
+ MARSHAL_U16LE(ctx, val->tag);
+ return false;
+}
+
+static bool marshal_Tunlinkat(struct lib9p_ctx *ctx, struct lib9p_msg_Tunlinkat *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 17 + val->name.len;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tunlinkat",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 76);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->dirfd);
+ MARSHAL_U16LE(ctx, val->name.len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->name.utf8, val->name.len);
+ MARSHAL_U32LE(ctx, val->flags);
+ return false;
+}
+
+static bool marshal_Runlinkat(struct lib9p_ctx *ctx, struct lib9p_msg_Runlinkat *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 7;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Runlinkat",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 77);
+ MARSHAL_U16LE(ctx, val->tag);
+ return false;
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000_e
+static bool marshal_Tsession(struct lib9p_ctx *ctx, struct lib9p_msg_Tsession *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 15;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tsession",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 150);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U64LE(ctx, val->key);
+ return false;
+}
+
+static bool marshal_Rsession(struct lib9p_ctx *ctx, struct lib9p_msg_Rsession *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 7;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rsession",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 151);
+ MARSHAL_U16LE(ctx, val->tag);
+ return false;
}
-
-static ALWAYS_INLINE bool marshal_s(struct _marshal_ctx *ctx, struct lib9p_s *val) {
- return false
- || marshal_2(ctx, &val->len)
- || ({ bool err = false;
- for (typeof(val->len) i = 0; i < val->len && !err; i++)
- err = marshal_1(ctx, (uint8_t *)&val->utf8[i]);
- err; })
- ;
-}
-
-static ALWAYS_INLINE bool marshal_dm(struct _marshal_ctx *ctx, lib9p_dm_t *val) {
- lib9p_dm_t masked_val = *val & dm_masks[ctx->ctx->version];
- return marshal_4(ctx, (uint32_t *)&masked_val);
-}
-
-static ALWAYS_INLINE bool marshal_qt(struct _marshal_ctx *ctx, lib9p_qt_t *val) {
- lib9p_qt_t masked_val = *val & qt_masks[ctx->ctx->version];
- return marshal_1(ctx, (uint8_t *)&masked_val);
-}
-
-static ALWAYS_INLINE bool marshal_qid(struct _marshal_ctx *ctx, struct lib9p_qid *val) {
- return false
- || marshal_qt(ctx, &val->type)
- || marshal_4(ctx, &val->vers)
- || marshal_8(ctx, &val->path)
- ;
-}
-
-static ALWAYS_INLINE bool marshal_stat(struct _marshal_ctx *ctx, struct lib9p_stat *val) {
- uint32_t _stat_size_offset;
- uint32_t _kern_type_offset;
- return false
- || ({ _stat_size_offset = ctx->net_offset; ({ ctx->net_offset += 2; false; }); })
- || ({ _kern_type_offset = ctx->net_offset; marshal_2(ctx, &val->kern_type); })
- || marshal_4(ctx, &val->kern_dev)
- || marshal_qid(ctx, &val->file_qid)
- || marshal_dm(ctx, &val->file_mode)
- || marshal_4(ctx, &val->file_atime)
- || marshal_4(ctx, &val->file_mtime)
- || marshal_8(ctx, &val->file_size)
- || marshal_s(ctx, &val->file_name)
- || marshal_s(ctx, &val->file_owner_uid)
- || marshal_s(ctx, &val->file_owner_gid)
- || marshal_s(ctx, &val->file_last_modified_uid)
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
- || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && marshal_s(ctx, &val->file_extension) )
- || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && marshal_4(ctx, &val->file_owner_n_uid) )
- || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && marshal_4(ctx, &val->file_owner_n_gid) )
- || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && marshal_4(ctx, &val->file_last_modified_n_uid) )
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
- || ({ encode_u16le(ctx->net_offset - _kern_type_offset, &ctx->net_bytes[_stat_size_offset]); false; })
- ;
-}
-
-static ALWAYS_INLINE bool marshal_o(struct _marshal_ctx *ctx, lib9p_o_t *val) {
- lib9p_o_t masked_val = *val & o_masks[ctx->ctx->version];
- return marshal_1(ctx, (uint8_t *)&masked_val);
-}
-
-static FLATTEN bool marshal_Tversion(struct _marshal_ctx *ctx, struct lib9p_msg_Tversion *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_4(ctx, &val->max_msg_size)
- || marshal_s(ctx, &val->version)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(100, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Rversion(struct _marshal_ctx *ctx, struct lib9p_msg_Rversion *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_4(ctx, &val->max_msg_size)
- || marshal_s(ctx, &val->version)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(101, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Tauth(struct _marshal_ctx *ctx, struct lib9p_msg_Tauth *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_fid(ctx, &val->afid)
- || marshal_s(ctx, &val->uname)
- || marshal_s(ctx, &val->aname)
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
- || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && marshal_4(ctx, &val->n_uname) )
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(102, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Rauth(struct _marshal_ctx *ctx, struct lib9p_msg_Rauth *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_qid(ctx, &val->aqid)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(103, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Tattach(struct _marshal_ctx *ctx, struct lib9p_msg_Tattach *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_fid(ctx, &val->fid)
- || marshal_fid(ctx, &val->afid)
- || marshal_s(ctx, &val->uname)
- || marshal_s(ctx, &val->aname)
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
- || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && marshal_4(ctx, &val->n_uname) )
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(104, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Rattach(struct _marshal_ctx *ctx, struct lib9p_msg_Rattach *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_qid(ctx, &val->qid)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(105, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Rerror(struct _marshal_ctx *ctx, struct lib9p_msg_Rerror *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_s(ctx, &val->ename)
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
- || ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && marshal_4(ctx, &val->errno) )
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(107, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Tflush(struct _marshal_ctx *ctx, struct lib9p_msg_Tflush *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_2(ctx, &val->oldtag)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(108, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Rflush(struct _marshal_ctx *ctx, struct lib9p_msg_Rflush *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(109, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Twalk(struct _marshal_ctx *ctx, struct lib9p_msg_Twalk *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_fid(ctx, &val->fid)
- || marshal_fid(ctx, &val->newfid)
- || marshal_2(ctx, &val->nwname)
- || ({ bool err = false;
- for (typeof(val->nwname) i = 0; i < val->nwname && !err; i++)
- err = marshal_s(ctx, &val->wname[i]);
- err; })
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(110, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Rwalk(struct _marshal_ctx *ctx, struct lib9p_msg_Rwalk *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_2(ctx, &val->nwqid)
- || ({ bool err = false;
- for (typeof(val->nwqid) i = 0; i < val->nwqid && !err; i++)
- err = marshal_qid(ctx, &val->wqid[i]);
- err; })
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(111, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Topen(struct _marshal_ctx *ctx, struct lib9p_msg_Topen *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_fid(ctx, &val->fid)
- || marshal_o(ctx, &val->mode)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(112, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Ropen(struct _marshal_ctx *ctx, struct lib9p_msg_Ropen *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_qid(ctx, &val->qid)
- || marshal_4(ctx, &val->iounit)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(113, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Tcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Tcreate *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_fid(ctx, &val->fid)
- || marshal_s(ctx, &val->name)
- || marshal_dm(ctx, &val->perm)
- || marshal_o(ctx, &val->mode)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(114, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Rcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Rcreate *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_qid(ctx, &val->qid)
- || marshal_4(ctx, &val->iounit)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(115, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Tread(struct _marshal_ctx *ctx, struct lib9p_msg_Tread *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_fid(ctx, &val->fid)
- || marshal_8(ctx, &val->offset)
- || marshal_4(ctx, &val->count)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(116, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Rread(struct _marshal_ctx *ctx, struct lib9p_msg_Rread *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_d(ctx, &val->data)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(117, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Twrite(struct _marshal_ctx *ctx, struct lib9p_msg_Twrite *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_fid(ctx, &val->fid)
- || marshal_8(ctx, &val->offset)
- || marshal_d(ctx, &val->data)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(118, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Rwrite(struct _marshal_ctx *ctx, struct lib9p_msg_Rwrite *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_4(ctx, &val->count)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(119, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Tclunk(struct _marshal_ctx *ctx, struct lib9p_msg_Tclunk *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_fid(ctx, &val->fid)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(120, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Rclunk(struct _marshal_ctx *ctx, struct lib9p_msg_Rclunk *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(121, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Tremove(struct _marshal_ctx *ctx, struct lib9p_msg_Tremove *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_fid(ctx, &val->fid)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(122, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Rremove(struct _marshal_ctx *ctx, struct lib9p_msg_Rremove *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(123, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Tstat(struct _marshal_ctx *ctx, struct lib9p_msg_Tstat *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_fid(ctx, &val->fid)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(124, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Rstat(struct _marshal_ctx *ctx, struct lib9p_msg_Rstat *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- uint32_t _nstat_offset;
- uint32_t _stat_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || ({ _nstat_offset = ctx->net_offset; ({ ctx->net_offset += 2; false; }); })
- || ({ _stat_offset = ctx->net_offset; marshal_stat(ctx, &val->stat); })
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(125, &ctx->net_bytes[_typ_offset]); false; })
- || ({ encode_u16le(ctx->net_offset - _stat_offset, &ctx->net_bytes[_nstat_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Twstat(struct _marshal_ctx *ctx, struct lib9p_msg_Twstat *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- uint32_t _nstat_offset;
- uint32_t _stat_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_fid(ctx, &val->fid)
- || ({ _nstat_offset = ctx->net_offset; ({ ctx->net_offset += 2; false; }); })
- || ({ _stat_offset = ctx->net_offset; marshal_stat(ctx, &val->stat); })
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(126, &ctx->net_bytes[_typ_offset]); false; })
- || ({ encode_u16le(ctx->net_offset - _stat_offset, &ctx->net_bytes[_nstat_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Rwstat(struct _marshal_ctx *ctx, struct lib9p_msg_Rwstat *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(127, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-#endif /* defined(CONFIG_9P_ENABLE_9P2000) || defined(CONFIG_9P_ENABLE_9P2000_e) || defined(CONFIG_9P_ENABLE_9P2000_u) */
-#if defined(CONFIG_9P_ENABLE_9P2000_e)
-static FLATTEN bool marshal_Tsession(struct _marshal_ctx *ctx, struct lib9p_msg_Tsession *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_8(ctx, &val->key)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(150, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Rsession(struct _marshal_ctx *ctx, struct lib9p_msg_Rsession *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(151, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Tsread(struct _marshal_ctx *ctx, struct lib9p_msg_Tsread *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_4(ctx, &val->fid)
- || marshal_2(ctx, &val->nwname)
- || ({ bool err = false;
- for (typeof(val->nwname) i = 0; i < val->nwname && !err; i++)
- err = marshal_s(ctx, &val->wname[i]);
- err; })
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(152, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Rsread(struct _marshal_ctx *ctx, struct lib9p_msg_Rsread *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_d(ctx, &val->data)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(153, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Tswrite(struct _marshal_ctx *ctx, struct lib9p_msg_Tswrite *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_4(ctx, &val->fid)
- || marshal_2(ctx, &val->nwname)
- || ({ bool err = false;
- for (typeof(val->nwname) i = 0; i < val->nwname && !err; i++)
- err = marshal_s(ctx, &val->wname[i]);
- err; })
- || marshal_d(ctx, &val->data)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(154, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-
-static FLATTEN bool marshal_Rswrite(struct _marshal_ctx *ctx, struct lib9p_msg_Rswrite *val) {
- uint32_t _size_offset;
- uint32_t _typ_offset;
- return false
- || ({ _size_offset = ctx->net_offset; ({ ctx->net_offset += 4; false; }); })
- || ({ _typ_offset = ctx->net_offset; ({ ctx->net_offset += 1; false; }); })
- || marshal_tag(ctx, &val->tag)
- || marshal_4(ctx, &val->count)
- || ({ encode_u32le(ctx->net_offset - _size_offset, &ctx->net_bytes[_size_offset]); false; })
- || ({ encode_u8le(155, &ctx->net_bytes[_typ_offset]); false; })
- ;
-}
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_e) */
-
-/* tables / exports ***********************************************************/
-
-#define _MSG(typ) [LIB9P_TYP_##typ] = { \
- .name = #typ, \
- .basesize = sizeof(struct lib9p_msg_##typ), \
- .validate = validate_##typ, \
- .unmarshal = (_unmarshal_fn_t)unmarshal_##typ, \
- .marshal = (_marshal_fn_t)marshal_##typ, \
- }
-#define _NONMSG(num) [num] = { \
- .name = #num, \
- }
-
-struct _table_version _lib9p_versions[LIB9P_VER_NUM] = {
- [LIB9P_VER_unknown] = { .msgs = {
- _NONMSG(0x00),
- _NONMSG(0x01),
- _NONMSG(0x02),
- _NONMSG(0x03),
- _NONMSG(0x04),
- _NONMSG(0x05),
- _NONMSG(0x06),
- _NONMSG(0x07),
- _NONMSG(0x08),
- _NONMSG(0x09),
- _NONMSG(0x0A),
- _NONMSG(0x0B),
- _NONMSG(0x0C),
- _NONMSG(0x0D),
- _NONMSG(0x0E),
- _NONMSG(0x0F),
- _NONMSG(0x10),
- _NONMSG(0x11),
- _NONMSG(0x12),
- _NONMSG(0x13),
- _NONMSG(0x14),
- _NONMSG(0x15),
- _NONMSG(0x16),
- _NONMSG(0x17),
- _NONMSG(0x18),
- _NONMSG(0x19),
- _NONMSG(0x1A),
- _NONMSG(0x1B),
- _NONMSG(0x1C),
- _NONMSG(0x1D),
- _NONMSG(0x1E),
- _NONMSG(0x1F),
- _NONMSG(0x20),
- _NONMSG(0x21),
- _NONMSG(0x22),
- _NONMSG(0x23),
- _NONMSG(0x24),
- _NONMSG(0x25),
- _NONMSG(0x26),
- _NONMSG(0x27),
- _NONMSG(0x28),
- _NONMSG(0x29),
- _NONMSG(0x2A),
- _NONMSG(0x2B),
- _NONMSG(0x2C),
- _NONMSG(0x2D),
- _NONMSG(0x2E),
- _NONMSG(0x2F),
- _NONMSG(0x30),
- _NONMSG(0x31),
- _NONMSG(0x32),
- _NONMSG(0x33),
- _NONMSG(0x34),
- _NONMSG(0x35),
- _NONMSG(0x36),
- _NONMSG(0x37),
- _NONMSG(0x38),
- _NONMSG(0x39),
- _NONMSG(0x3A),
- _NONMSG(0x3B),
- _NONMSG(0x3C),
- _NONMSG(0x3D),
- _NONMSG(0x3E),
- _NONMSG(0x3F),
- _NONMSG(0x40),
- _NONMSG(0x41),
- _NONMSG(0x42),
- _NONMSG(0x43),
- _NONMSG(0x44),
- _NONMSG(0x45),
- _NONMSG(0x46),
- _NONMSG(0x47),
- _NONMSG(0x48),
- _NONMSG(0x49),
- _NONMSG(0x4A),
- _NONMSG(0x4B),
- _NONMSG(0x4C),
- _NONMSG(0x4D),
- _NONMSG(0x4E),
- _NONMSG(0x4F),
- _NONMSG(0x50),
- _NONMSG(0x51),
- _NONMSG(0x52),
- _NONMSG(0x53),
- _NONMSG(0x54),
- _NONMSG(0x55),
- _NONMSG(0x56),
- _NONMSG(0x57),
- _NONMSG(0x58),
- _NONMSG(0x59),
- _NONMSG(0x5A),
- _NONMSG(0x5B),
- _NONMSG(0x5C),
- _NONMSG(0x5D),
- _NONMSG(0x5E),
- _NONMSG(0x5F),
- _NONMSG(0x60),
- _NONMSG(0x61),
- _NONMSG(0x62),
- _NONMSG(0x63),
+
+static bool marshal_Tsread(struct lib9p_ctx *ctx, struct lib9p_msg_Tsread *val, struct _marshal_ret *ret) {
+ uint64_t needed_size = 13;
+ for (uint16_t i = 0; i < val->nwname; i++) {
+ needed_size += 2 + val->wname[i].len;
+ }
+ if (needed_size > (uint64_t)(ctx->max_msg_size)) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tsread",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = (uint32_t)needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 152);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U16LE(ctx, val->nwname);
+ for (uint16_t i = 0; i < val->nwname; i++) {
+ MARSHAL_U16LE(ctx, val->wname[i].len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->wname[i].utf8, val->wname[i].len);
+ }
+ return false;
+}
+
+static bool marshal_Rsread(struct lib9p_ctx *ctx, struct lib9p_msg_Rsread *val, struct _marshal_ret *ret) {
+ uint64_t needed_size = 11 + val->count;
+ if (needed_size > (uint64_t)(ctx->max_msg_size)) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rsread",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = (uint32_t)needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 153);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->count);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->data, val->count);
+ return false;
+}
+
+static bool marshal_Tswrite(struct lib9p_ctx *ctx, struct lib9p_msg_Tswrite *val, struct _marshal_ret *ret) {
+ uint64_t needed_size = 17 + val->count;
+ for (uint16_t i = 0; i < val->nwname; i++) {
+ needed_size += 2 + val->wname[i].len;
+ }
+ if (needed_size > (uint64_t)(ctx->max_msg_size)) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Tswrite",
+ ctx->version ? "negotiated" : "client",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = (uint32_t)needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 154);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->fid);
+ MARSHAL_U16LE(ctx, val->nwname);
+ for (uint16_t i = 0; i < val->nwname; i++) {
+ MARSHAL_U16LE(ctx, val->wname[i].len);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->wname[i].utf8, val->wname[i].len);
+ }
+ MARSHAL_U32LE(ctx, val->count);
+ MARSHAL_BYTES_ZEROCOPY(ctx, val->data, val->count);
+ return false;
+}
+
+static bool marshal_Rswrite(struct lib9p_ctx *ctx, struct lib9p_msg_Rswrite *val, struct _marshal_ret *ret) {
+ uint32_t needed_size = 11;
+ if (needed_size > ctx->max_msg_size) {
+ lib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",
+ "Rswrite",
+ ctx->version ? "negotiated" : "server",
+ ctx->max_msg_size);
+ return true;
+ }
+ uint32_t offsetof_end = needed_size;
+ uint32_t offsetof_size = 0;
+ MARSHAL_U32LE(ctx, offsetof_end - offsetof_size);
+ MARSHAL_U8LE(ctx, 155);
+ MARSHAL_U16LE(ctx, val->tag);
+ MARSHAL_U32LE(ctx, val->count);
+ return false;
+}
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+
+/* *_format *******************************************************************/
+
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static void lib9p_tag_format(lib9p_tag_t *self, struct fmt_state *state) {
+ switch (*self) {
+ case LIB9P_TAG_NOTAG:
+ fmt_state_puts(state, "NOTAG");
+ break;
+ default:
+ fmt_state_printf(state, "%"PRIu16, *self);
+ }
+}
+
+static void lib9p_fid_format(lib9p_fid_t *self, struct fmt_state *state) {
+ switch (*self) {
+ case LIB9P_FID_NOFID:
+ fmt_state_puts(state, "NOFID");
+ break;
+ default:
+ fmt_state_printf(state, "%"PRIu32, *self);
+ }
+}
+
+static void lib9p_s_format(struct lib9p_s *self, struct fmt_state *state) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat"
+#pragma GCC diagnostic ignored "-Wformat-extra-args"
+ fmt_state_printf(state, "%.*q", self->len, self->utf8);
+#pragma GCC diagnostic pop
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static void lib9p_dm_format(lib9p_dm_t *self, struct fmt_state *state) {
+ bool empty = true;
+ fmt_state_putchar(state, '(');
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<31)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "DIR");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<30)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "APPEND");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<29)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "EXCL");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<28)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "_PLAN9_MOUNT");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<27)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "AUTH");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<26)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "TMP");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<25)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<25");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<24)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<24");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<23)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "DEVICE");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<22)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<22");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<21)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "PIPE");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<20)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "SOCKET");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<19)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "SETUID");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<18)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "SETGID");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<17)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<17");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<16)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<16");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<15)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<15");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<14)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<14");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<13)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<13");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<12)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<12");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<11)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<11");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<10)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<10");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<9)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<9");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<8)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "OWNER_R");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<7)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "OWNER_W");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<6)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "OWNER_X");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<5)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "GROUP_R");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<4)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "GROUP_W");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<3)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "GROUP_X");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<2)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "OTHER_R");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<1)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "OTHER_W");
+ empty = false;
+ }
+ if ((*self & ~((lib9p_dm_t)0777)) & (UINT32_C(1)<<0)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "OTHER_X");
+ empty = false;
+ }
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_printf(state, "%#04"PRIo32, *self & 0777);
+ fmt_state_putchar(state, ')');
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static void lib9p_qt_format(lib9p_qt_t *self, struct fmt_state *state) {
+ bool empty = true;
+ fmt_state_putchar(state, '(');
+ if (*self & (UINT8_C(1)<<7)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "DIR");
+ empty = false;
+ }
+ if (*self & (UINT8_C(1)<<6)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "APPEND");
+ empty = false;
+ }
+ if (*self & (UINT8_C(1)<<5)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "EXCL");
+ empty = false;
+ }
+ if (*self & (UINT8_C(1)<<4)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "_PLAN9_MOUNT");
+ empty = false;
+ }
+ if (*self & (UINT8_C(1)<<3)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "AUTH");
+ empty = false;
+ }
+ if (*self & (UINT8_C(1)<<2)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "TMP");
+ empty = false;
+ }
+ if (*self & (UINT8_C(1)<<1)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "SYMLINK");
+ empty = false;
+ }
+ if (*self & (UINT8_C(1)<<0)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<0");
+ empty = false;
+ }
+ if (empty)
+ fmt_state_putchar(state, '0');
+ fmt_state_putchar(state, ')');
+}
+
+static void lib9p_qid_format(struct lib9p_qid *self, struct fmt_state *state) {
+ fmt_state_putchar(state, '{');
+ fmt_state_puts(state, " type=");
+ lib9p_qt_format(&self->type, state);
+ fmt_state_puts(state, " vers=");
+ fmt_state_printf(state, "%"PRIu32, self->vers);
+ fmt_state_puts(state, " path=");
+ fmt_state_printf(state, "%"PRIu64, self->path);
+ fmt_state_puts(state, " }");
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static void lib9p_stat_format(struct lib9p_stat *self, struct fmt_state *state) {
+ fmt_state_putchar(state, '{');
+ fmt_state_puts(state, " kern_type=");
+ fmt_state_printf(state, "%"PRIu16, self->kern_type);
+ fmt_state_puts(state, " kern_dev=");
+ fmt_state_printf(state, "%"PRIu32, self->kern_dev);
+ fmt_state_puts(state, " file_qid=");
+ lib9p_qid_format(&self->file_qid, state);
+ fmt_state_puts(state, " file_mode=");
+ lib9p_dm_format(&self->file_mode, state);
+ fmt_state_puts(state, " file_atime=");
+ fmt_state_printf(state, "%"PRIu32, self->file_atime);
+ fmt_state_puts(state, " file_mtime=");
+ fmt_state_printf(state, "%"PRIu32, self->file_mtime);
+ fmt_state_puts(state, " file_size=");
+ fmt_state_printf(state, "%"PRIu64, self->file_size);
+ fmt_state_puts(state, " file_name=");
+ lib9p_s_format(&self->file_name, state);
+ fmt_state_puts(state, " file_owner_uid=");
+ lib9p_s_format(&self->file_owner_uid, state);
+ fmt_state_puts(state, " file_owner_gid=");
+ lib9p_s_format(&self->file_owner_gid, state);
+ fmt_state_puts(state, " file_last_modified_uid=");
+ lib9p_s_format(&self->file_last_modified_uid, state);
+#if CONFIG_9P_ENABLE_9P2000_u
+ fmt_state_puts(state, " file_extension=");
+ lib9p_s_format(&self->file_extension, state);
+ fmt_state_puts(state, " file_owner_n_uid=");
+ lib9p_nuid_format(&self->file_owner_n_uid, state);
+ fmt_state_puts(state, " file_owner_n_gid=");
+ lib9p_nuid_format(&self->file_owner_n_gid, state);
+ fmt_state_puts(state, " file_last_modified_n_uid=");
+ lib9p_nuid_format(&self->file_last_modified_n_uid, state);
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_o_format(lib9p_o_t *self, struct fmt_state *state) {
+ bool empty = true;
+ fmt_state_putchar(state, '(');
+ if (*self & (UINT8_C(1)<<7)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<7");
+ empty = false;
+ }
+ if (*self & (UINT8_C(1)<<6)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "RCLOSE");
+ empty = false;
+ }
+ if (*self & (UINT8_C(1)<<5)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "CEXEC");
+ empty = false;
+ }
+ if (*self & (UINT8_C(1)<<4)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "TRUNC");
+ empty = false;
+ }
+ if (*self & (UINT8_C(1)<<3)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<3");
+ empty = false;
+ }
+ if (*self & (UINT8_C(1)<<2)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<2");
+ empty = false;
+ }
+ switch (*self & LIB9P_O_MODE_MASK) {
+ case LIB9P_O_MODE_READ:
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "MODE_READ");
+ empty = false;
+ break;
+ case LIB9P_O_MODE_WRITE:
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "MODE_WRITE");
+ empty = false;
+ break;
+ case LIB9P_O_MODE_RDWR:
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "MODE_RDWR");
+ empty = false;
+ break;
+ case LIB9P_O_MODE_EXEC:
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "MODE_EXEC");
+ empty = false;
+ break;
+ default:
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_printf(state, "%"PRIu8, *self & LIB9P_O_MODE_MASK);
+ empty = false;
+ }
+ if (empty)
+ fmt_state_putchar(state, '0');
+ fmt_state_putchar(state, ')');
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static void lib9p_msg_Tversion_format(struct lib9p_msg_Tversion *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tversion {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " max_msg_size=");
+ fmt_state_printf(state, "%"PRIu32, self->max_msg_size);
+ fmt_state_puts(state, " version=");
+ lib9p_s_format(&self->version, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rversion_format(struct lib9p_msg_Rversion *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rversion {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " max_msg_size=");
+ fmt_state_printf(state, "%"PRIu32, self->max_msg_size);
+ fmt_state_puts(state, " version=");
+ lib9p_s_format(&self->version, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Tauth_format(struct lib9p_msg_Tauth *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tauth {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " afid=");
+ lib9p_fid_format(&self->afid, state);
+ fmt_state_puts(state, " uname=");
+ lib9p_s_format(&self->uname, state);
+ fmt_state_puts(state, " aname=");
+ lib9p_s_format(&self->aname, state);
+#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
+ fmt_state_puts(state, " n_uid=");
+ lib9p_nuid_format(&self->n_uid, state);
+#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rauth_format(struct lib9p_msg_Rauth *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rauth {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " aqid=");
+ lib9p_qid_format(&self->aqid, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Tattach_format(struct lib9p_msg_Tattach *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tattach {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " afid=");
+ lib9p_fid_format(&self->afid, state);
+ fmt_state_puts(state, " uname=");
+ lib9p_s_format(&self->uname, state);
+ fmt_state_puts(state, " aname=");
+ lib9p_s_format(&self->aname, state);
+#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
+ fmt_state_puts(state, " n_uid=");
+ lib9p_nuid_format(&self->n_uid, state);
+#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rattach_format(struct lib9p_msg_Rattach *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rattach {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " qid=");
+ lib9p_qid_format(&self->qid, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rerror_format(struct lib9p_msg_Rerror *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rerror {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " errstr=");
+ lib9p_s_format(&self->errstr, state);
+#if CONFIG_9P_ENABLE_9P2000_u
+ fmt_state_puts(state, " errnum=");
+ lib9p_errno_format(&self->errnum, state);
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Tflush_format(struct lib9p_msg_Tflush *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tflush {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " oldtag=");
+ fmt_state_printf(state, "%"PRIu16, self->oldtag);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rflush_format(struct lib9p_msg_Rflush *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rflush {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Twalk_format(struct lib9p_msg_Twalk *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Twalk {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " newfid=");
+ lib9p_fid_format(&self->newfid, state);
+ fmt_state_puts(state, " nwname=");
+ fmt_state_printf(state, "%"PRIu16, self->nwname);
+ fmt_state_puts(state, " wname=[");
+ for (uint16_t i = 0; i < self->nwname; i++) {
+ if (i)
+ fmt_state_puts(state, ", ");
+ lib9p_s_format(&self->wname[i], state);
+ }
+ fmt_state_puts(state, " ]");
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rwalk_format(struct lib9p_msg_Rwalk *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rwalk {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " nwqid=");
+ fmt_state_printf(state, "%"PRIu16, self->nwqid);
+ fmt_state_puts(state, " wqid=[");
+ for (uint16_t i = 0; i < self->nwqid; i++) {
+ if (i)
+ fmt_state_puts(state, ", ");
+ lib9p_qid_format(&self->wqid[i], state);
+ }
+ fmt_state_puts(state, " ]");
+ fmt_state_puts(state, " }");
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static void lib9p_msg_Topen_format(struct lib9p_msg_Topen *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Topen {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " mode=");
+ lib9p_o_format(&self->mode, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Ropen_format(struct lib9p_msg_Ropen *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Ropen {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " qid=");
+ lib9p_qid_format(&self->qid, state);
+ fmt_state_puts(state, " iounit=");
+ fmt_state_printf(state, "%"PRIu32, self->iounit);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Tcreate_format(struct lib9p_msg_Tcreate *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tcreate {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " name=");
+ lib9p_s_format(&self->name, state);
+ fmt_state_puts(state, " perm=");
+ lib9p_dm_format(&self->perm, state);
+ fmt_state_puts(state, " mode=");
+ lib9p_o_format(&self->mode, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rcreate_format(struct lib9p_msg_Rcreate *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rcreate {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " qid=");
+ lib9p_qid_format(&self->qid, state);
+ fmt_state_puts(state, " iounit=");
+ fmt_state_printf(state, "%"PRIu32, self->iounit);
+ fmt_state_puts(state, " }");
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static void lib9p_msg_Tread_format(struct lib9p_msg_Tread *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tread {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " offset=");
+ fmt_state_printf(state, "%"PRIu64, self->offset);
+ fmt_state_puts(state, " count=");
+ fmt_state_printf(state, "%"PRIu32, self->count);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rread_format(struct lib9p_msg_Rread *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rread {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " count=");
+ fmt_state_printf(state, "%"PRIu32, self->count);
+ if (is_valid_utf8_without_nul((uint8_t *)self->data, (size_t)self->count)) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat"
+#pragma GCC diagnostic ignored "-Wformat-extra-args"
+ fmt_state_printf(state, " data=%.*q%s",
+ (int)(self->count < 50 ? self->count : 50),
+ (char *)self->data,
+ self->count < 50 ? "" : "...");
+#pragma GCC diagnostic pop
+ } else {
+ fmt_state_puts(state, " data=<bytedata>");
+ }
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Twrite_format(struct lib9p_msg_Twrite *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Twrite {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " offset=");
+ fmt_state_printf(state, "%"PRIu64, self->offset);
+ fmt_state_puts(state, " count=");
+ fmt_state_printf(state, "%"PRIu32, self->count);
+ if (is_valid_utf8_without_nul((uint8_t *)self->data, (size_t)self->count)) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat"
+#pragma GCC diagnostic ignored "-Wformat-extra-args"
+ fmt_state_printf(state, " data=%.*q%s",
+ (int)(self->count < 50 ? self->count : 50),
+ (char *)self->data,
+ self->count < 50 ? "" : "...");
+#pragma GCC diagnostic pop
+ } else {
+ fmt_state_puts(state, " data=<bytedata>");
+ }
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rwrite_format(struct lib9p_msg_Rwrite *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rwrite {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " count=");
+ fmt_state_printf(state, "%"PRIu32, self->count);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Tclunk_format(struct lib9p_msg_Tclunk *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tclunk {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rclunk_format(struct lib9p_msg_Rclunk *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rclunk {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Tremove_format(struct lib9p_msg_Tremove *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tremove {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rremove_format(struct lib9p_msg_Rremove *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rremove {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " }");
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+static void lib9p_msg_Tstat_format(struct lib9p_msg_Tstat *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tstat {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rstat_format(struct lib9p_msg_Rstat *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rstat {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " stat=");
+ lib9p_stat_format(&self->stat, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Twstat_format(struct lib9p_msg_Twstat *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Twstat {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " stat=");
+ lib9p_stat_format(&self->stat, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rwstat_format(struct lib9p_msg_Rwstat *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rwstat {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " }");
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+static void lib9p_msg_Topenfd_format(struct lib9p_msg_Topenfd *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Topenfd {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " mode=");
+ lib9p_o_format(&self->mode, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Ropenfd_format(struct lib9p_msg_Ropenfd *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Ropenfd {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " qid=");
+ lib9p_qid_format(&self->qid, state);
+ fmt_state_puts(state, " iounit=");
+ fmt_state_printf(state, "%"PRIu32, self->iounit);
+ fmt_state_puts(state, " unixfd=");
+ fmt_state_printf(state, "%"PRIu32, self->unixfd);
+ fmt_state_puts(state, " }");
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
+static void lib9p_nuid_format(lib9p_nuid_t *self, struct fmt_state *state) {
+ switch (*self) {
+ case LIB9P_NUID_NONUID:
+ fmt_state_puts(state, "NONUID");
+ break;
+ default:
+ fmt_state_printf(state, "%"PRIu32, *self);
+ }
+}
+
+static void lib9p_errno_format(lib9p_errno_t *self, struct fmt_state *state) {
+ switch (*self) {
+ case LIB9P_ERRNO_NOERROR:
+ fmt_state_puts(state, "NOERROR");
+ break;
+ default:
+ fmt_state_printf(state, "%"PRIu32, *self);
+ }
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000_L
+static void lib9p_super_magic_format(lib9p_super_magic_t *self, struct fmt_state *state) {
+ switch (*self) {
+ case LIB9P_SUPER_MAGIC_V9FS_MAGIC:
+ fmt_state_puts(state, "V9FS_MAGIC");
+ break;
+ default:
+ fmt_state_printf(state, "%"PRIu32, *self);
+ }
+}
+
+static void lib9p_lo_format(lib9p_lo_t *self, struct fmt_state *state) {
+ bool empty = true;
+ fmt_state_putchar(state, '(');
+ if (*self & (UINT32_C(1)<<31)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<31");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<30)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<30");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<29)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<29");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<28)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<28");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<27)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<27");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<26)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<26");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<25)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<25");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<24)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<24");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<23)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<23");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<22)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<22");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<21)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<21");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<20)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "SYNC");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<19)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "CLOEXEC");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<18)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "NOATIME");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<17)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "NOFOLLOW");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<16)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "DIRECTORY");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<15)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "LARGEFILE");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<14)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "DIRECT");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<13)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "BSD_FASYNC");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<12)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "DSYNC");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<11)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "NONBLOCK");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<10)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "APPEND");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<9)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "TRUNC");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<8)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "NOCTTY");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<7)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "EXCL");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<6)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "CREATE");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<5)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<5");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<4)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<4");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<3)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<3");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<2)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<2");
+ empty = false;
+ }
+ switch (*self & LIB9P_LO_MODE_MASK) {
+ case LIB9P_LO_MODE_RDONLY:
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "MODE_RDONLY");
+ empty = false;
+ break;
+ case LIB9P_LO_MODE_WRONLY:
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "MODE_WRONLY");
+ empty = false;
+ break;
+ case LIB9P_LO_MODE_RDWR:
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "MODE_RDWR");
+ empty = false;
+ break;
+ case LIB9P_LO_MODE_NOACCESS:
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "MODE_NOACCESS");
+ empty = false;
+ break;
+ default:
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_printf(state, "%"PRIu32, *self & LIB9P_LO_MODE_MASK);
+ empty = false;
+ }
+ if (empty)
+ fmt_state_putchar(state, '0');
+ fmt_state_putchar(state, ')');
+}
+
+static void lib9p_dt_format(lib9p_dt_t *self, struct fmt_state *state) {
+ switch (*self) {
+ case LIB9P_DT_UNKNOWN:
+ fmt_state_puts(state, "UNKNOWN");
+ break;
+ case LIB9P_DT_PIPE:
+ fmt_state_puts(state, "PIPE");
+ break;
+ case LIB9P_DT_CHAR_DEV:
+ fmt_state_puts(state, "CHAR_DEV");
+ break;
+ case LIB9P_DT_DIRECTORY:
+ fmt_state_puts(state, "DIRECTORY");
+ break;
+ case LIB9P_DT_BLOCK_DEV:
+ fmt_state_puts(state, "BLOCK_DEV");
+ break;
+ case LIB9P_DT_REGULAR:
+ fmt_state_puts(state, "REGULAR");
+ break;
+ case LIB9P_DT_SYMLINK:
+ fmt_state_puts(state, "SYMLINK");
+ break;
+ case LIB9P_DT_SOCKET:
+ fmt_state_puts(state, "SOCKET");
+ break;
+ case _LIB9P_DT_WHITEOUT:
+ fmt_state_puts(state, "_WHITEOUT");
+ break;
+ default:
+ fmt_state_printf(state, "%"PRIu8, *self);
+ }
+}
+
+static void lib9p_mode_format(lib9p_mode_t *self, struct fmt_state *state) {
+ bool empty = true;
+ fmt_state_putchar(state, '(');
+ if (*self & (UINT32_C(1)<<31)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<31");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<30)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<30");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<29)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<29");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<28)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<28");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<27)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<27");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<26)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<26");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<25)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<25");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<24)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<24");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<23)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<23");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<22)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<22");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<21)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<21");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<20)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<20");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<19)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<19");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<18)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<18");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<17)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<17");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<16)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<16");
+ empty = false;
+ }
+ switch (*self & LIB9P_MODE_FMT_MASK) {
+ case LIB9P_MODE_FMT_PIPE:
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "FMT_PIPE");
+ empty = false;
+ break;
+ case LIB9P_MODE_FMT_CHAR_DEV:
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "FMT_CHAR_DEV");
+ empty = false;
+ break;
+ case LIB9P_MODE_FMT_DIRECTORY:
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "FMT_DIRECTORY");
+ empty = false;
+ break;
+ case LIB9P_MODE_FMT_BLOCK_DEV:
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "FMT_BLOCK_DEV");
+ empty = false;
+ break;
+ case LIB9P_MODE_FMT_REGULAR:
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "FMT_REGULAR");
+ empty = false;
+ break;
+ case LIB9P_MODE_FMT_SYMLINK:
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "FMT_SYMLINK");
+ empty = false;
+ break;
+ case LIB9P_MODE_FMT_SOCKET:
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "FMT_SOCKET");
+ empty = false;
+ break;
+ default:
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_printf(state, "%"PRIu32, *self & LIB9P_MODE_FMT_MASK);
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<11)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "PERM_SETGROUP");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<10)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "PERM_SETUSER");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<9)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "PERM_STICKY");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<8)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "PERM_OWNER_R");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<7)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "PERM_OWNER_W");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<6)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "PERM_OWNER_X");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<5)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "PERM_GROUP_R");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<4)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "PERM_GROUP_W");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<3)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "PERM_GROUP_X");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<2)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "PERM_OTHER_R");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<1)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "PERM_OTHER_W");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<0)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "PERM_OTHER_X");
+ empty = false;
+ }
+ if (empty)
+ fmt_state_putchar(state, '0');
+ fmt_state_putchar(state, ')');
+}
+
+static void lib9p_b4_format(lib9p_b4_t *self, struct fmt_state *state) {
+ switch (*self) {
+ case LIB9P_B4_FALSE:
+ fmt_state_puts(state, "FALSE");
+ break;
+ case LIB9P_B4_TRUE:
+ fmt_state_puts(state, "TRUE");
+ break;
+ default:
+ fmt_state_printf(state, "%"PRIu32, *self);
+ }
+}
+
+static void lib9p_getattr_format(lib9p_getattr_t *self, struct fmt_state *state) {
+ bool empty = true;
+ fmt_state_putchar(state, '(');
+ if (*self & (UINT64_C(1)<<63)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<63");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<62)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<62");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<61)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<61");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<60)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<60");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<59)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<59");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<58)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<58");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<57)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<57");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<56)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<56");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<55)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<55");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<54)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<54");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<53)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<53");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<52)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<52");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<51)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<51");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<50)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<50");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<49)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<49");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<48)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<48");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<47)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<47");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<46)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<46");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<45)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<45");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<44)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<44");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<43)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<43");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<42)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<42");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<41)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<41");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<40)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<40");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<39)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<39");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<38)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<38");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<37)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<37");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<36)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<36");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<35)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<35");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<34)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<34");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<33)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<33");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<32)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<32");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<31)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<31");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<30)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<30");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<29)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<29");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<28)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<28");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<27)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<27");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<26)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<26");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<25)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<25");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<24)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<24");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<23)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<23");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<22)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<22");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<21)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<21");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<20)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<20");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<19)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<19");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<18)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<18");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<17)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<17");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<16)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<16");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<15)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<15");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<14)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<14");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<13)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "DATA_VERSION");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<12)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "GEN");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<11)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "BTIME");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<10)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "BLOCKS");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<9)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "SIZE");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<8)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "INO");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<7)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "CTIME");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<6)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "MTIME");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<5)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "ATIME");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<4)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "RDEV");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<3)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "GID");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<2)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "UID");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<1)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "NLINK");
+ empty = false;
+ }
+ if (*self & (UINT64_C(1)<<0)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "MODE");
+ empty = false;
+ }
+ if (empty)
+ fmt_state_putchar(state, '0');
+ fmt_state_putchar(state, ')');
+}
+
+static void lib9p_setattr_format(lib9p_setattr_t *self, struct fmt_state *state) {
+ bool empty = true;
+ fmt_state_putchar(state, '(');
+ if (*self & (UINT32_C(1)<<31)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<31");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<30)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<30");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<29)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<29");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<28)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<28");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<27)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<27");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<26)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<26");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<25)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<25");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<24)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<24");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<23)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<23");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<22)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<22");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<21)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<21");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<20)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<20");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<19)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<19");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<18)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<18");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<17)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<17");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<16)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<16");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<15)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<15");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<14)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<14");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<13)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<13");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<12)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<12");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<11)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<11");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<10)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<10");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<9)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<9");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<8)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "MTIME_SET");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<7)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "ATIME_SET");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<6)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "CTIME");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<5)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "MTIME");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<4)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "ATIME");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<3)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "SIZE");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<2)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "GID");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<1)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "UID");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<0)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "MODE");
+ empty = false;
+ }
+ if (empty)
+ fmt_state_putchar(state, '0');
+ fmt_state_putchar(state, ')');
+}
+
+static void lib9p_lock_type_format(lib9p_lock_type_t *self, struct fmt_state *state) {
+ switch (*self) {
+ case LIB9P_LOCK_TYPE_RDLCK:
+ fmt_state_puts(state, "RDLCK");
+ break;
+ case LIB9P_LOCK_TYPE_WRLCK:
+ fmt_state_puts(state, "WRLCK");
+ break;
+ case LIB9P_LOCK_TYPE_UNLCK:
+ fmt_state_puts(state, "UNLCK");
+ break;
+ default:
+ fmt_state_printf(state, "%"PRIu8, *self);
+ }
+}
+
+static void lib9p_lock_flags_format(lib9p_lock_flags_t *self, struct fmt_state *state) {
+ bool empty = true;
+ fmt_state_putchar(state, '(');
+ if (*self & (UINT32_C(1)<<31)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<31");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<30)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<30");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<29)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<29");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<28)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<28");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<27)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<27");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<26)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<26");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<25)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<25");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<24)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<24");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<23)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<23");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<22)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<22");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<21)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<21");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<20)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<20");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<19)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<19");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<18)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<18");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<17)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<17");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<16)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<16");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<15)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<15");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<14)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<14");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<13)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<13");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<12)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<12");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<11)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<11");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<10)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<10");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<9)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<9");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<8)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<8");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<7)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<7");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<6)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<6");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<5)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<5");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<4)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<4");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<3)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<3");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<2)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "1<<2");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<1)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "RECLAIM");
+ empty = false;
+ }
+ if (*self & (UINT32_C(1)<<0)) {
+ if (!empty)
+ fmt_state_putchar(state, '|');
+ fmt_state_puts(state, "BLOCK");
+ empty = false;
+ }
+ if (empty)
+ fmt_state_putchar(state, '0');
+ fmt_state_putchar(state, ')');
+}
+
+static void lib9p_lock_status_format(lib9p_lock_status_t *self, struct fmt_state *state) {
+ switch (*self) {
+ case LIB9P_LOCK_STATUS_SUCCESS:
+ fmt_state_puts(state, "SUCCESS");
+ break;
+ case LIB9P_LOCK_STATUS_BLOCKED:
+ fmt_state_puts(state, "BLOCKED");
+ break;
+ case LIB9P_LOCK_STATUS_ERROR:
+ fmt_state_puts(state, "ERROR");
+ break;
+ case LIB9P_LOCK_STATUS_GRACE:
+ fmt_state_puts(state, "GRACE");
+ break;
+ default:
+ fmt_state_printf(state, "%"PRIu8, *self);
+ }
+}
+
+static void lib9p_msg_Rlerror_format(struct lib9p_msg_Rlerror *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rlerror {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " errnum=");
+ lib9p_errno_format(&self->errnum, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Tstatfs_format(struct lib9p_msg_Tstatfs *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tstatfs {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rstatfs_format(struct lib9p_msg_Rstatfs *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rstatfs {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " type=");
+ lib9p_super_magic_format(&self->type, state);
+ fmt_state_puts(state, " bsize=");
+ fmt_state_printf(state, "%"PRIu32, self->bsize);
+ fmt_state_puts(state, " blocks=");
+ fmt_state_printf(state, "%"PRIu64, self->blocks);
+ fmt_state_puts(state, " bfree=");
+ fmt_state_printf(state, "%"PRIu64, self->bfree);
+ fmt_state_puts(state, " bavail=");
+ fmt_state_printf(state, "%"PRIu64, self->bavail);
+ fmt_state_puts(state, " files=");
+ fmt_state_printf(state, "%"PRIu64, self->files);
+ fmt_state_puts(state, " ffree=");
+ fmt_state_printf(state, "%"PRIu64, self->ffree);
+ fmt_state_puts(state, " fsid=");
+ fmt_state_printf(state, "%"PRIu64, self->fsid);
+ fmt_state_puts(state, " namelen=");
+ fmt_state_printf(state, "%"PRIu32, self->namelen);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Tlopen_format(struct lib9p_msg_Tlopen *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tlopen {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " flags=");
+ lib9p_lo_format(&self->flags, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rlopen_format(struct lib9p_msg_Rlopen *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rlopen {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " qid=");
+ lib9p_qid_format(&self->qid, state);
+ fmt_state_puts(state, " iounit=");
+ fmt_state_printf(state, "%"PRIu32, self->iounit);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Tlcreate_format(struct lib9p_msg_Tlcreate *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tlcreate {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " name=");
+ lib9p_s_format(&self->name, state);
+ fmt_state_puts(state, " flags=");
+ lib9p_lo_format(&self->flags, state);
+ fmt_state_puts(state, " mode=");
+ lib9p_mode_format(&self->mode, state);
+ fmt_state_puts(state, " gid=");
+ lib9p_nuid_format(&self->gid, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rlcreate_format(struct lib9p_msg_Rlcreate *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rlcreate {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " qid=");
+ lib9p_qid_format(&self->qid, state);
+ fmt_state_puts(state, " iounit=");
+ fmt_state_printf(state, "%"PRIu32, self->iounit);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Tsymlink_format(struct lib9p_msg_Tsymlink *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tsymlink {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " name=");
+ lib9p_s_format(&self->name, state);
+ fmt_state_puts(state, " symtgt=");
+ lib9p_s_format(&self->symtgt, state);
+ fmt_state_puts(state, " gid=");
+ lib9p_nuid_format(&self->gid, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rsymlink_format(struct lib9p_msg_Rsymlink *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rsymlink {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " qid=");
+ lib9p_qid_format(&self->qid, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Tmknod_format(struct lib9p_msg_Tmknod *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tmknod {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " dfid=");
+ lib9p_fid_format(&self->dfid, state);
+ fmt_state_puts(state, " name=");
+ lib9p_s_format(&self->name, state);
+ fmt_state_puts(state, " mode=");
+ lib9p_mode_format(&self->mode, state);
+ fmt_state_puts(state, " major=");
+ fmt_state_printf(state, "%"PRIu32, self->major);
+ fmt_state_puts(state, " minor=");
+ fmt_state_printf(state, "%"PRIu32, self->minor);
+ fmt_state_puts(state, " gid=");
+ lib9p_nuid_format(&self->gid, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rmknod_format(struct lib9p_msg_Rmknod *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rmknod {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " qid=");
+ lib9p_qid_format(&self->qid, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Trename_format(struct lib9p_msg_Trename *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Trename {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " dfid=");
+ lib9p_fid_format(&self->dfid, state);
+ fmt_state_puts(state, " name=");
+ lib9p_s_format(&self->name, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rrename_format(struct lib9p_msg_Rrename *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rrename {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Treadlink_format(struct lib9p_msg_Treadlink *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Treadlink {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rreadlink_format(struct lib9p_msg_Rreadlink *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rreadlink {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " target=");
+ lib9p_s_format(&self->target, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Tgetattr_format(struct lib9p_msg_Tgetattr *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tgetattr {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " request_mask=");
+ lib9p_getattr_format(&self->request_mask, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rgetattr_format(struct lib9p_msg_Rgetattr *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rgetattr {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " valid=");
+ lib9p_getattr_format(&self->valid, state);
+ fmt_state_puts(state, " qid=");
+ lib9p_qid_format(&self->qid, state);
+ fmt_state_puts(state, " mode=");
+ lib9p_mode_format(&self->mode, state);
+ fmt_state_puts(state, " uid=");
+ lib9p_nuid_format(&self->uid, state);
+ fmt_state_puts(state, " gid=");
+ lib9p_nuid_format(&self->gid, state);
+ fmt_state_puts(state, " nlink=");
+ fmt_state_printf(state, "%"PRIu64, self->nlink);
+ fmt_state_puts(state, " rdev=");
+ fmt_state_printf(state, "%"PRIu64, self->rdev);
+ fmt_state_puts(state, " filesize=");
+ fmt_state_printf(state, "%"PRIu64, self->filesize);
+ fmt_state_puts(state, " blksize=");
+ fmt_state_printf(state, "%"PRIu64, self->blksize);
+ fmt_state_puts(state, " blocks=");
+ fmt_state_printf(state, "%"PRIu64, self->blocks);
+ fmt_state_puts(state, " atime_sec=");
+ fmt_state_printf(state, "%"PRIu64, self->atime_sec);
+ fmt_state_puts(state, " atime_nsec=");
+ fmt_state_printf(state, "%"PRIu64, self->atime_nsec);
+ fmt_state_puts(state, " mtime_sec=");
+ fmt_state_printf(state, "%"PRIu64, self->mtime_sec);
+ fmt_state_puts(state, " mtime_nsec=");
+ fmt_state_printf(state, "%"PRIu64, self->mtime_nsec);
+ fmt_state_puts(state, " ctime_sec=");
+ fmt_state_printf(state, "%"PRIu64, self->ctime_sec);
+ fmt_state_puts(state, " ctime_nsec=");
+ fmt_state_printf(state, "%"PRIu64, self->ctime_nsec);
+ fmt_state_puts(state, " btime_sec=");
+ fmt_state_printf(state, "%"PRIu64, self->btime_sec);
+ fmt_state_puts(state, " btime_nsec=");
+ fmt_state_printf(state, "%"PRIu64, self->btime_nsec);
+ fmt_state_puts(state, " gen=");
+ fmt_state_printf(state, "%"PRIu64, self->gen);
+ fmt_state_puts(state, " data_version=");
+ fmt_state_printf(state, "%"PRIu64, self->data_version);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Tsetattr_format(struct lib9p_msg_Tsetattr *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tsetattr {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " valid=");
+ lib9p_setattr_format(&self->valid, state);
+ fmt_state_puts(state, " mode=");
+ lib9p_mode_format(&self->mode, state);
+ fmt_state_puts(state, " uid=");
+ lib9p_nuid_format(&self->uid, state);
+ fmt_state_puts(state, " gid=");
+ lib9p_nuid_format(&self->gid, state);
+ fmt_state_puts(state, " filesize=");
+ fmt_state_printf(state, "%"PRIu64, self->filesize);
+ fmt_state_puts(state, " atime_sec=");
+ fmt_state_printf(state, "%"PRIu64, self->atime_sec);
+ fmt_state_puts(state, " atime_nsec=");
+ fmt_state_printf(state, "%"PRIu64, self->atime_nsec);
+ fmt_state_puts(state, " mtime_sec=");
+ fmt_state_printf(state, "%"PRIu64, self->mtime_sec);
+ fmt_state_puts(state, " mtime_nsec=");
+ fmt_state_printf(state, "%"PRIu64, self->mtime_nsec);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rsetattr_format(struct lib9p_msg_Rsetattr *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rsetattr {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Txattrwalk_format(struct lib9p_msg_Txattrwalk *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Txattrwalk {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " newfid=");
+ lib9p_fid_format(&self->newfid, state);
+ fmt_state_puts(state, " name=");
+ lib9p_s_format(&self->name, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rxattrwalk_format(struct lib9p_msg_Rxattrwalk *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rxattrwalk {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " attr_size=");
+ fmt_state_printf(state, "%"PRIu64, self->attr_size);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Txattrcreate_format(struct lib9p_msg_Txattrcreate *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Txattrcreate {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " name=");
+ lib9p_s_format(&self->name, state);
+ fmt_state_puts(state, " attr_size=");
+ fmt_state_printf(state, "%"PRIu64, self->attr_size);
+ fmt_state_puts(state, " flags=");
+ fmt_state_printf(state, "%"PRIu32, self->flags);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rxattrcreate_format(struct lib9p_msg_Rxattrcreate *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rxattrcreate {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Treaddir_format(struct lib9p_msg_Treaddir *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Treaddir {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " offset=");
+ fmt_state_printf(state, "%"PRIu64, self->offset);
+ fmt_state_puts(state, " count=");
+ fmt_state_printf(state, "%"PRIu32, self->count);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rreaddir_format(struct lib9p_msg_Rreaddir *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rreaddir {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " count=");
+ fmt_state_printf(state, "%"PRIu32, self->count);
+ if (is_valid_utf8_without_nul((uint8_t *)self->data, (size_t)self->count)) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat"
+#pragma GCC diagnostic ignored "-Wformat-extra-args"
+ fmt_state_printf(state, " data=%.*q%s",
+ (int)(self->count < 50 ? self->count : 50),
+ (char *)self->data,
+ self->count < 50 ? "" : "...");
+#pragma GCC diagnostic pop
+ } else {
+ fmt_state_puts(state, " data=<bytedata>");
+ }
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Tfsync_format(struct lib9p_msg_Tfsync *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tfsync {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " datasync=");
+ lib9p_b4_format(&self->datasync, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rfsync_format(struct lib9p_msg_Rfsync *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rfsync {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Tlock_format(struct lib9p_msg_Tlock *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tlock {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " type=");
+ lib9p_lock_type_format(&self->type, state);
+ fmt_state_puts(state, " flags=");
+ lib9p_lock_flags_format(&self->flags, state);
+ fmt_state_puts(state, " start=");
+ fmt_state_printf(state, "%"PRIu64, self->start);
+ fmt_state_puts(state, " length=");
+ fmt_state_printf(state, "%"PRIu64, self->length);
+ fmt_state_puts(state, " proc_id=");
+ fmt_state_printf(state, "%"PRIu32, self->proc_id);
+ fmt_state_puts(state, " client_id=");
+ lib9p_s_format(&self->client_id, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rlock_format(struct lib9p_msg_Rlock *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rlock {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " status=");
+ lib9p_lock_status_format(&self->status, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Tgetlock_format(struct lib9p_msg_Tgetlock *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tgetlock {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " type=");
+ lib9p_lock_type_format(&self->type, state);
+ fmt_state_puts(state, " start=");
+ fmt_state_printf(state, "%"PRIu64, self->start);
+ fmt_state_puts(state, " length=");
+ fmt_state_printf(state, "%"PRIu64, self->length);
+ fmt_state_puts(state, " proc_id=");
+ fmt_state_printf(state, "%"PRIu32, self->proc_id);
+ fmt_state_puts(state, " client_id=");
+ lib9p_s_format(&self->client_id, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rgetlock_format(struct lib9p_msg_Rgetlock *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rgetlock {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " type=");
+ lib9p_lock_type_format(&self->type, state);
+ fmt_state_puts(state, " start=");
+ fmt_state_printf(state, "%"PRIu64, self->start);
+ fmt_state_puts(state, " length=");
+ fmt_state_printf(state, "%"PRIu64, self->length);
+ fmt_state_puts(state, " proc_id=");
+ fmt_state_printf(state, "%"PRIu32, self->proc_id);
+ fmt_state_puts(state, " client_id=");
+ lib9p_s_format(&self->client_id, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Tlink_format(struct lib9p_msg_Tlink *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tlink {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " dfid=");
+ lib9p_fid_format(&self->dfid, state);
+ fmt_state_puts(state, " fid=");
+ lib9p_fid_format(&self->fid, state);
+ fmt_state_puts(state, " name=");
+ lib9p_s_format(&self->name, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rlink_format(struct lib9p_msg_Rlink *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rlink {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Tmkdir_format(struct lib9p_msg_Tmkdir *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tmkdir {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " dfid=");
+ lib9p_fid_format(&self->dfid, state);
+ fmt_state_puts(state, " name=");
+ lib9p_s_format(&self->name, state);
+ fmt_state_puts(state, " mode=");
+ lib9p_mode_format(&self->mode, state);
+ fmt_state_puts(state, " gid=");
+ lib9p_nuid_format(&self->gid, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rmkdir_format(struct lib9p_msg_Rmkdir *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rmkdir {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " qid=");
+ lib9p_qid_format(&self->qid, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Trenameat_format(struct lib9p_msg_Trenameat *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Trenameat {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " olddirfid=");
+ lib9p_fid_format(&self->olddirfid, state);
+ fmt_state_puts(state, " oldname=");
+ lib9p_s_format(&self->oldname, state);
+ fmt_state_puts(state, " newdirfid=");
+ lib9p_fid_format(&self->newdirfid, state);
+ fmt_state_puts(state, " newname=");
+ lib9p_s_format(&self->newname, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rrenameat_format(struct lib9p_msg_Rrenameat *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rrenameat {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Tunlinkat_format(struct lib9p_msg_Tunlinkat *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tunlinkat {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " dirfd=");
+ lib9p_fid_format(&self->dirfd, state);
+ fmt_state_puts(state, " name=");
+ lib9p_s_format(&self->name, state);
+ fmt_state_puts(state, " flags=");
+ fmt_state_printf(state, "%"PRIu32, self->flags);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Runlinkat_format(struct lib9p_msg_Runlinkat *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Runlinkat {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " }");
+}
+
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000_e
+static void lib9p_msg_Tsession_format(struct lib9p_msg_Tsession *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tsession {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " key=");
+ fmt_state_printf(state, "%"PRIu64, self->key);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rsession_format(struct lib9p_msg_Rsession *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rsession {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Tsread_format(struct lib9p_msg_Tsread *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tsread {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ fmt_state_printf(state, "%"PRIu32, self->fid);
+ fmt_state_puts(state, " nwname=");
+ fmt_state_printf(state, "%"PRIu16, self->nwname);
+ fmt_state_puts(state, " wname=[");
+ for (uint16_t i = 0; i < self->nwname; i++) {
+ if (i)
+ fmt_state_puts(state, ", ");
+ lib9p_s_format(&self->wname[i], state);
+ }
+ fmt_state_puts(state, " ]");
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rsread_format(struct lib9p_msg_Rsread *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rsread {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " count=");
+ fmt_state_printf(state, "%"PRIu32, self->count);
+ if (is_valid_utf8_without_nul((uint8_t *)self->data, (size_t)self->count)) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat"
+#pragma GCC diagnostic ignored "-Wformat-extra-args"
+ fmt_state_printf(state, " data=%.*q%s",
+ (int)(self->count < 50 ? self->count : 50),
+ (char *)self->data,
+ self->count < 50 ? "" : "...");
+#pragma GCC diagnostic pop
+ } else {
+ fmt_state_puts(state, " data=<bytedata>");
+ }
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Tswrite_format(struct lib9p_msg_Tswrite *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Tswrite {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " fid=");
+ fmt_state_printf(state, "%"PRIu32, self->fid);
+ fmt_state_puts(state, " nwname=");
+ fmt_state_printf(state, "%"PRIu16, self->nwname);
+ fmt_state_puts(state, " wname=[");
+ for (uint16_t i = 0; i < self->nwname; i++) {
+ if (i)
+ fmt_state_puts(state, ", ");
+ lib9p_s_format(&self->wname[i], state);
+ }
+ fmt_state_puts(state, " ]");
+ fmt_state_puts(state, " count=");
+ fmt_state_printf(state, "%"PRIu32, self->count);
+ if (is_valid_utf8_without_nul((uint8_t *)self->data, (size_t)self->count)) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat"
+#pragma GCC diagnostic ignored "-Wformat-extra-args"
+ fmt_state_printf(state, " data=%.*q%s",
+ (int)(self->count < 50 ? self->count : 50),
+ (char *)self->data,
+ self->count < 50 ? "" : "...");
+#pragma GCC diagnostic pop
+ } else {
+ fmt_state_puts(state, " data=<bytedata>");
+ }
+ fmt_state_puts(state, " }");
+}
+
+static void lib9p_msg_Rswrite_format(struct lib9p_msg_Rswrite *self, struct fmt_state *state) {
+ fmt_state_puts(state, "Rswrite {");
+ fmt_state_puts(state, " tag=");
+ lib9p_tag_format(&self->tag, state);
+ fmt_state_puts(state, " count=");
+ fmt_state_printf(state, "%"PRIu32, self->count);
+ fmt_state_puts(state, " }");
+}
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+
+/* tables.h *******************************************************************/
+
+const struct _lib9p_ver_tentry _lib9p_table_ver[LIB9P_VER_NUM] = {
+ [LIB9P_VER_unknown] = {.name="unknown", .min_msg_size=9},
+#if CONFIG_9P_ENABLE_9P2000
+ [LIB9P_VER_9P2000] = {.name="9P2000", .min_msg_size=9},
+#endif /* CONFIG_9P_ENABLE_9P2000 */
+#if CONFIG_9P_ENABLE_9P2000_L
+ [LIB9P_VER_9P2000_L] = {.name="9P2000.L", .min_msg_size=9},
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000_e
+ [LIB9P_VER_9P2000_e] = {.name="9P2000.e", .min_msg_size=9},
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+ [LIB9P_VER_9P2000_p9p] = {.name="9P2000.p9p", .min_msg_size=9},
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_u
+ [LIB9P_VER_9P2000_u] = {.name="9P2000.u", .min_msg_size=13},
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+};
+
+#define _MSG(typ) [LIB9P_TYP_##typ] = { \
+ .name = #typ, \
+ .box_as_fmt_formatter = (_box_as_fmt_formatter_fn_t)lo_box_lib9p_msg_##typ##_as_fmt_formatter, \
+ }
+const struct _lib9p_msg_tentry _lib9p_table_msg[LIB9P_VER_NUM][0x100] = {
+ [LIB9P_VER_unknown] = {
_MSG(Tversion),
_MSG(Rversion),
- _NONMSG(0x66),
- _NONMSG(0x67),
- _NONMSG(0x68),
- _NONMSG(0x69),
- _NONMSG(0x6A),
_MSG(Rerror),
- _NONMSG(0x6C),
- _NONMSG(0x6D),
- _NONMSG(0x6E),
- _NONMSG(0x6F),
- _NONMSG(0x70),
- _NONMSG(0x71),
- _NONMSG(0x72),
- _NONMSG(0x73),
- _NONMSG(0x74),
- _NONMSG(0x75),
- _NONMSG(0x76),
- _NONMSG(0x77),
- _NONMSG(0x78),
- _NONMSG(0x79),
- _NONMSG(0x7A),
- _NONMSG(0x7B),
- _NONMSG(0x7C),
- _NONMSG(0x7D),
- _NONMSG(0x7E),
- _NONMSG(0x7F),
- _NONMSG(0x80),
- _NONMSG(0x81),
- _NONMSG(0x82),
- _NONMSG(0x83),
- _NONMSG(0x84),
- _NONMSG(0x85),
- _NONMSG(0x86),
- _NONMSG(0x87),
- _NONMSG(0x88),
- _NONMSG(0x89),
- _NONMSG(0x8A),
- _NONMSG(0x8B),
- _NONMSG(0x8C),
- _NONMSG(0x8D),
- _NONMSG(0x8E),
- _NONMSG(0x8F),
- _NONMSG(0x90),
- _NONMSG(0x91),
- _NONMSG(0x92),
- _NONMSG(0x93),
- _NONMSG(0x94),
- _NONMSG(0x95),
- _NONMSG(0x96),
- _NONMSG(0x97),
- _NONMSG(0x98),
- _NONMSG(0x99),
- _NONMSG(0x9A),
- _NONMSG(0x9B),
- _NONMSG(0x9C),
- _NONMSG(0x9D),
- _NONMSG(0x9E),
- _NONMSG(0x9F),
- _NONMSG(0xA0),
- _NONMSG(0xA1),
- _NONMSG(0xA2),
- _NONMSG(0xA3),
- _NONMSG(0xA4),
- _NONMSG(0xA5),
- _NONMSG(0xA6),
- _NONMSG(0xA7),
- _NONMSG(0xA8),
- _NONMSG(0xA9),
- _NONMSG(0xAA),
- _NONMSG(0xAB),
- _NONMSG(0xAC),
- _NONMSG(0xAD),
- _NONMSG(0xAE),
- _NONMSG(0xAF),
- _NONMSG(0xB0),
- _NONMSG(0xB1),
- _NONMSG(0xB2),
- _NONMSG(0xB3),
- _NONMSG(0xB4),
- _NONMSG(0xB5),
- _NONMSG(0xB6),
- _NONMSG(0xB7),
- _NONMSG(0xB8),
- _NONMSG(0xB9),
- _NONMSG(0xBA),
- _NONMSG(0xBB),
- _NONMSG(0xBC),
- _NONMSG(0xBD),
- _NONMSG(0xBE),
- _NONMSG(0xBF),
- _NONMSG(0xC0),
- _NONMSG(0xC1),
- _NONMSG(0xC2),
- _NONMSG(0xC3),
- _NONMSG(0xC4),
- _NONMSG(0xC5),
- _NONMSG(0xC6),
- _NONMSG(0xC7),
- _NONMSG(0xC8),
- _NONMSG(0xC9),
- _NONMSG(0xCA),
- _NONMSG(0xCB),
- _NONMSG(0xCC),
- _NONMSG(0xCD),
- _NONMSG(0xCE),
- _NONMSG(0xCF),
- _NONMSG(0xD0),
- _NONMSG(0xD1),
- _NONMSG(0xD2),
- _NONMSG(0xD3),
- _NONMSG(0xD4),
- _NONMSG(0xD5),
- _NONMSG(0xD6),
- _NONMSG(0xD7),
- _NONMSG(0xD8),
- _NONMSG(0xD9),
- _NONMSG(0xDA),
- _NONMSG(0xDB),
- _NONMSG(0xDC),
- _NONMSG(0xDD),
- _NONMSG(0xDE),
- _NONMSG(0xDF),
- _NONMSG(0xE0),
- _NONMSG(0xE1),
- _NONMSG(0xE2),
- _NONMSG(0xE3),
- _NONMSG(0xE4),
- _NONMSG(0xE5),
- _NONMSG(0xE6),
- _NONMSG(0xE7),
- _NONMSG(0xE8),
- _NONMSG(0xE9),
- _NONMSG(0xEA),
- _NONMSG(0xEB),
- _NONMSG(0xEC),
- _NONMSG(0xED),
- _NONMSG(0xEE),
- _NONMSG(0xEF),
- _NONMSG(0xF0),
- _NONMSG(0xF1),
- _NONMSG(0xF2),
- _NONMSG(0xF3),
- _NONMSG(0xF4),
- _NONMSG(0xF5),
- _NONMSG(0xF6),
- _NONMSG(0xF7),
- _NONMSG(0xF8),
- _NONMSG(0xF9),
- _NONMSG(0xFA),
- _NONMSG(0xFB),
- _NONMSG(0xFC),
- _NONMSG(0xFD),
- _NONMSG(0xFE),
- _NONMSG(0xFF),
- }},
-#if defined(CONFIG_9P_ENABLE_9P2000)
- [LIB9P_VER_9P2000] = { .msgs = {
- _NONMSG(0x00),
- _NONMSG(0x01),
- _NONMSG(0x02),
- _NONMSG(0x03),
- _NONMSG(0x04),
- _NONMSG(0x05),
- _NONMSG(0x06),
- _NONMSG(0x07),
- _NONMSG(0x08),
- _NONMSG(0x09),
- _NONMSG(0x0A),
- _NONMSG(0x0B),
- _NONMSG(0x0C),
- _NONMSG(0x0D),
- _NONMSG(0x0E),
- _NONMSG(0x0F),
- _NONMSG(0x10),
- _NONMSG(0x11),
- _NONMSG(0x12),
- _NONMSG(0x13),
- _NONMSG(0x14),
- _NONMSG(0x15),
- _NONMSG(0x16),
- _NONMSG(0x17),
- _NONMSG(0x18),
- _NONMSG(0x19),
- _NONMSG(0x1A),
- _NONMSG(0x1B),
- _NONMSG(0x1C),
- _NONMSG(0x1D),
- _NONMSG(0x1E),
- _NONMSG(0x1F),
- _NONMSG(0x20),
- _NONMSG(0x21),
- _NONMSG(0x22),
- _NONMSG(0x23),
- _NONMSG(0x24),
- _NONMSG(0x25),
- _NONMSG(0x26),
- _NONMSG(0x27),
- _NONMSG(0x28),
- _NONMSG(0x29),
- _NONMSG(0x2A),
- _NONMSG(0x2B),
- _NONMSG(0x2C),
- _NONMSG(0x2D),
- _NONMSG(0x2E),
- _NONMSG(0x2F),
- _NONMSG(0x30),
- _NONMSG(0x31),
- _NONMSG(0x32),
- _NONMSG(0x33),
- _NONMSG(0x34),
- _NONMSG(0x35),
- _NONMSG(0x36),
- _NONMSG(0x37),
- _NONMSG(0x38),
- _NONMSG(0x39),
- _NONMSG(0x3A),
- _NONMSG(0x3B),
- _NONMSG(0x3C),
- _NONMSG(0x3D),
- _NONMSG(0x3E),
- _NONMSG(0x3F),
- _NONMSG(0x40),
- _NONMSG(0x41),
- _NONMSG(0x42),
- _NONMSG(0x43),
- _NONMSG(0x44),
- _NONMSG(0x45),
- _NONMSG(0x46),
- _NONMSG(0x47),
- _NONMSG(0x48),
- _NONMSG(0x49),
- _NONMSG(0x4A),
- _NONMSG(0x4B),
- _NONMSG(0x4C),
- _NONMSG(0x4D),
- _NONMSG(0x4E),
- _NONMSG(0x4F),
- _NONMSG(0x50),
- _NONMSG(0x51),
- _NONMSG(0x52),
- _NONMSG(0x53),
- _NONMSG(0x54),
- _NONMSG(0x55),
- _NONMSG(0x56),
- _NONMSG(0x57),
- _NONMSG(0x58),
- _NONMSG(0x59),
- _NONMSG(0x5A),
- _NONMSG(0x5B),
- _NONMSG(0x5C),
- _NONMSG(0x5D),
- _NONMSG(0x5E),
- _NONMSG(0x5F),
- _NONMSG(0x60),
- _NONMSG(0x61),
- _NONMSG(0x62),
- _NONMSG(0x63),
+ },
+#if CONFIG_9P_ENABLE_9P2000
+ [LIB9P_VER_9P2000] = {
_MSG(Tversion),
_MSG(Rversion),
_MSG(Tauth),
_MSG(Rauth),
_MSG(Tattach),
_MSG(Rattach),
- _NONMSG(0x6A),
_MSG(Rerror),
_MSG(Tflush),
_MSG(Rflush),
@@ -2180,245 +7451,78 @@ struct _table_version _lib9p_versions[LIB9P_VER_NUM] = {
_MSG(Rstat),
_MSG(Twstat),
_MSG(Rwstat),
- _NONMSG(0x80),
- _NONMSG(0x81),
- _NONMSG(0x82),
- _NONMSG(0x83),
- _NONMSG(0x84),
- _NONMSG(0x85),
- _NONMSG(0x86),
- _NONMSG(0x87),
- _NONMSG(0x88),
- _NONMSG(0x89),
- _NONMSG(0x8A),
- _NONMSG(0x8B),
- _NONMSG(0x8C),
- _NONMSG(0x8D),
- _NONMSG(0x8E),
- _NONMSG(0x8F),
- _NONMSG(0x90),
- _NONMSG(0x91),
- _NONMSG(0x92),
- _NONMSG(0x93),
- _NONMSG(0x94),
- _NONMSG(0x95),
- _NONMSG(0x96),
- _NONMSG(0x97),
- _NONMSG(0x98),
- _NONMSG(0x99),
- _NONMSG(0x9A),
- _NONMSG(0x9B),
- _NONMSG(0x9C),
- _NONMSG(0x9D),
- _NONMSG(0x9E),
- _NONMSG(0x9F),
- _NONMSG(0xA0),
- _NONMSG(0xA1),
- _NONMSG(0xA2),
- _NONMSG(0xA3),
- _NONMSG(0xA4),
- _NONMSG(0xA5),
- _NONMSG(0xA6),
- _NONMSG(0xA7),
- _NONMSG(0xA8),
- _NONMSG(0xA9),
- _NONMSG(0xAA),
- _NONMSG(0xAB),
- _NONMSG(0xAC),
- _NONMSG(0xAD),
- _NONMSG(0xAE),
- _NONMSG(0xAF),
- _NONMSG(0xB0),
- _NONMSG(0xB1),
- _NONMSG(0xB2),
- _NONMSG(0xB3),
- _NONMSG(0xB4),
- _NONMSG(0xB5),
- _NONMSG(0xB6),
- _NONMSG(0xB7),
- _NONMSG(0xB8),
- _NONMSG(0xB9),
- _NONMSG(0xBA),
- _NONMSG(0xBB),
- _NONMSG(0xBC),
- _NONMSG(0xBD),
- _NONMSG(0xBE),
- _NONMSG(0xBF),
- _NONMSG(0xC0),
- _NONMSG(0xC1),
- _NONMSG(0xC2),
- _NONMSG(0xC3),
- _NONMSG(0xC4),
- _NONMSG(0xC5),
- _NONMSG(0xC6),
- _NONMSG(0xC7),
- _NONMSG(0xC8),
- _NONMSG(0xC9),
- _NONMSG(0xCA),
- _NONMSG(0xCB),
- _NONMSG(0xCC),
- _NONMSG(0xCD),
- _NONMSG(0xCE),
- _NONMSG(0xCF),
- _NONMSG(0xD0),
- _NONMSG(0xD1),
- _NONMSG(0xD2),
- _NONMSG(0xD3),
- _NONMSG(0xD4),
- _NONMSG(0xD5),
- _NONMSG(0xD6),
- _NONMSG(0xD7),
- _NONMSG(0xD8),
- _NONMSG(0xD9),
- _NONMSG(0xDA),
- _NONMSG(0xDB),
- _NONMSG(0xDC),
- _NONMSG(0xDD),
- _NONMSG(0xDE),
- _NONMSG(0xDF),
- _NONMSG(0xE0),
- _NONMSG(0xE1),
- _NONMSG(0xE2),
- _NONMSG(0xE3),
- _NONMSG(0xE4),
- _NONMSG(0xE5),
- _NONMSG(0xE6),
- _NONMSG(0xE7),
- _NONMSG(0xE8),
- _NONMSG(0xE9),
- _NONMSG(0xEA),
- _NONMSG(0xEB),
- _NONMSG(0xEC),
- _NONMSG(0xED),
- _NONMSG(0xEE),
- _NONMSG(0xEF),
- _NONMSG(0xF0),
- _NONMSG(0xF1),
- _NONMSG(0xF2),
- _NONMSG(0xF3),
- _NONMSG(0xF4),
- _NONMSG(0xF5),
- _NONMSG(0xF6),
- _NONMSG(0xF7),
- _NONMSG(0xF8),
- _NONMSG(0xF9),
- _NONMSG(0xFA),
- _NONMSG(0xFB),
- _NONMSG(0xFC),
- _NONMSG(0xFD),
- _NONMSG(0xFE),
- _NONMSG(0xFF),
- }},
-#endif /* defined(CONFIG_9P_ENABLE_9P2000) */
-#if defined(CONFIG_9P_ENABLE_9P2000_e)
- [LIB9P_VER_9P2000_e] = { .msgs = {
- _NONMSG(0x00),
- _NONMSG(0x01),
- _NONMSG(0x02),
- _NONMSG(0x03),
- _NONMSG(0x04),
- _NONMSG(0x05),
- _NONMSG(0x06),
- _NONMSG(0x07),
- _NONMSG(0x08),
- _NONMSG(0x09),
- _NONMSG(0x0A),
- _NONMSG(0x0B),
- _NONMSG(0x0C),
- _NONMSG(0x0D),
- _NONMSG(0x0E),
- _NONMSG(0x0F),
- _NONMSG(0x10),
- _NONMSG(0x11),
- _NONMSG(0x12),
- _NONMSG(0x13),
- _NONMSG(0x14),
- _NONMSG(0x15),
- _NONMSG(0x16),
- _NONMSG(0x17),
- _NONMSG(0x18),
- _NONMSG(0x19),
- _NONMSG(0x1A),
- _NONMSG(0x1B),
- _NONMSG(0x1C),
- _NONMSG(0x1D),
- _NONMSG(0x1E),
- _NONMSG(0x1F),
- _NONMSG(0x20),
- _NONMSG(0x21),
- _NONMSG(0x22),
- _NONMSG(0x23),
- _NONMSG(0x24),
- _NONMSG(0x25),
- _NONMSG(0x26),
- _NONMSG(0x27),
- _NONMSG(0x28),
- _NONMSG(0x29),
- _NONMSG(0x2A),
- _NONMSG(0x2B),
- _NONMSG(0x2C),
- _NONMSG(0x2D),
- _NONMSG(0x2E),
- _NONMSG(0x2F),
- _NONMSG(0x30),
- _NONMSG(0x31),
- _NONMSG(0x32),
- _NONMSG(0x33),
- _NONMSG(0x34),
- _NONMSG(0x35),
- _NONMSG(0x36),
- _NONMSG(0x37),
- _NONMSG(0x38),
- _NONMSG(0x39),
- _NONMSG(0x3A),
- _NONMSG(0x3B),
- _NONMSG(0x3C),
- _NONMSG(0x3D),
- _NONMSG(0x3E),
- _NONMSG(0x3F),
- _NONMSG(0x40),
- _NONMSG(0x41),
- _NONMSG(0x42),
- _NONMSG(0x43),
- _NONMSG(0x44),
- _NONMSG(0x45),
- _NONMSG(0x46),
- _NONMSG(0x47),
- _NONMSG(0x48),
- _NONMSG(0x49),
- _NONMSG(0x4A),
- _NONMSG(0x4B),
- _NONMSG(0x4C),
- _NONMSG(0x4D),
- _NONMSG(0x4E),
- _NONMSG(0x4F),
- _NONMSG(0x50),
- _NONMSG(0x51),
- _NONMSG(0x52),
- _NONMSG(0x53),
- _NONMSG(0x54),
- _NONMSG(0x55),
- _NONMSG(0x56),
- _NONMSG(0x57),
- _NONMSG(0x58),
- _NONMSG(0x59),
- _NONMSG(0x5A),
- _NONMSG(0x5B),
- _NONMSG(0x5C),
- _NONMSG(0x5D),
- _NONMSG(0x5E),
- _NONMSG(0x5F),
- _NONMSG(0x60),
- _NONMSG(0x61),
- _NONMSG(0x62),
- _NONMSG(0x63),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000 */
+#if CONFIG_9P_ENABLE_9P2000_L
+ [LIB9P_VER_9P2000_L] = {
+ _MSG(Rlerror),
+ _MSG(Tstatfs),
+ _MSG(Rstatfs),
+ _MSG(Tlopen),
+ _MSG(Rlopen),
+ _MSG(Tlcreate),
+ _MSG(Rlcreate),
+ _MSG(Tsymlink),
+ _MSG(Rsymlink),
+ _MSG(Tmknod),
+ _MSG(Rmknod),
+ _MSG(Trename),
+ _MSG(Rrename),
+ _MSG(Treadlink),
+ _MSG(Rreadlink),
+ _MSG(Tgetattr),
+ _MSG(Rgetattr),
+ _MSG(Tsetattr),
+ _MSG(Rsetattr),
+ _MSG(Txattrwalk),
+ _MSG(Rxattrwalk),
+ _MSG(Txattrcreate),
+ _MSG(Rxattrcreate),
+ _MSG(Treaddir),
+ _MSG(Rreaddir),
+ _MSG(Tfsync),
+ _MSG(Rfsync),
+ _MSG(Tlock),
+ _MSG(Rlock),
+ _MSG(Tgetlock),
+ _MSG(Rgetlock),
+ _MSG(Tlink),
+ _MSG(Rlink),
+ _MSG(Tmkdir),
+ _MSG(Rmkdir),
+ _MSG(Trenameat),
+ _MSG(Rrenameat),
+ _MSG(Tunlinkat),
+ _MSG(Runlinkat),
+ _MSG(Tversion),
+ _MSG(Rversion),
+ _MSG(Tauth),
+ _MSG(Rauth),
+ _MSG(Tattach),
+ _MSG(Rattach),
+ _MSG(Rerror),
+ _MSG(Tflush),
+ _MSG(Rflush),
+ _MSG(Twalk),
+ _MSG(Rwalk),
+ _MSG(Tread),
+ _MSG(Rread),
+ _MSG(Twrite),
+ _MSG(Rwrite),
+ _MSG(Tclunk),
+ _MSG(Rclunk),
+ _MSG(Tremove),
+ _MSG(Rremove),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000_e
+ [LIB9P_VER_9P2000_e] = {
_MSG(Tversion),
_MSG(Rversion),
_MSG(Tauth),
_MSG(Rauth),
_MSG(Tattach),
_MSG(Rattach),
- _NONMSG(0x6A),
_MSG(Rerror),
_MSG(Tflush),
_MSG(Rflush),
@@ -2440,245 +7544,55 @@ struct _table_version _lib9p_versions[LIB9P_VER_NUM] = {
_MSG(Rstat),
_MSG(Twstat),
_MSG(Rwstat),
- _NONMSG(0x80),
- _NONMSG(0x81),
- _NONMSG(0x82),
- _NONMSG(0x83),
- _NONMSG(0x84),
- _NONMSG(0x85),
- _NONMSG(0x86),
- _NONMSG(0x87),
- _NONMSG(0x88),
- _NONMSG(0x89),
- _NONMSG(0x8A),
- _NONMSG(0x8B),
- _NONMSG(0x8C),
- _NONMSG(0x8D),
- _NONMSG(0x8E),
- _NONMSG(0x8F),
- _NONMSG(0x90),
- _NONMSG(0x91),
- _NONMSG(0x92),
- _NONMSG(0x93),
- _NONMSG(0x94),
- _NONMSG(0x95),
_MSG(Tsession),
_MSG(Rsession),
_MSG(Tsread),
_MSG(Rsread),
_MSG(Tswrite),
_MSG(Rswrite),
- _NONMSG(0x9C),
- _NONMSG(0x9D),
- _NONMSG(0x9E),
- _NONMSG(0x9F),
- _NONMSG(0xA0),
- _NONMSG(0xA1),
- _NONMSG(0xA2),
- _NONMSG(0xA3),
- _NONMSG(0xA4),
- _NONMSG(0xA5),
- _NONMSG(0xA6),
- _NONMSG(0xA7),
- _NONMSG(0xA8),
- _NONMSG(0xA9),
- _NONMSG(0xAA),
- _NONMSG(0xAB),
- _NONMSG(0xAC),
- _NONMSG(0xAD),
- _NONMSG(0xAE),
- _NONMSG(0xAF),
- _NONMSG(0xB0),
- _NONMSG(0xB1),
- _NONMSG(0xB2),
- _NONMSG(0xB3),
- _NONMSG(0xB4),
- _NONMSG(0xB5),
- _NONMSG(0xB6),
- _NONMSG(0xB7),
- _NONMSG(0xB8),
- _NONMSG(0xB9),
- _NONMSG(0xBA),
- _NONMSG(0xBB),
- _NONMSG(0xBC),
- _NONMSG(0xBD),
- _NONMSG(0xBE),
- _NONMSG(0xBF),
- _NONMSG(0xC0),
- _NONMSG(0xC1),
- _NONMSG(0xC2),
- _NONMSG(0xC3),
- _NONMSG(0xC4),
- _NONMSG(0xC5),
- _NONMSG(0xC6),
- _NONMSG(0xC7),
- _NONMSG(0xC8),
- _NONMSG(0xC9),
- _NONMSG(0xCA),
- _NONMSG(0xCB),
- _NONMSG(0xCC),
- _NONMSG(0xCD),
- _NONMSG(0xCE),
- _NONMSG(0xCF),
- _NONMSG(0xD0),
- _NONMSG(0xD1),
- _NONMSG(0xD2),
- _NONMSG(0xD3),
- _NONMSG(0xD4),
- _NONMSG(0xD5),
- _NONMSG(0xD6),
- _NONMSG(0xD7),
- _NONMSG(0xD8),
- _NONMSG(0xD9),
- _NONMSG(0xDA),
- _NONMSG(0xDB),
- _NONMSG(0xDC),
- _NONMSG(0xDD),
- _NONMSG(0xDE),
- _NONMSG(0xDF),
- _NONMSG(0xE0),
- _NONMSG(0xE1),
- _NONMSG(0xE2),
- _NONMSG(0xE3),
- _NONMSG(0xE4),
- _NONMSG(0xE5),
- _NONMSG(0xE6),
- _NONMSG(0xE7),
- _NONMSG(0xE8),
- _NONMSG(0xE9),
- _NONMSG(0xEA),
- _NONMSG(0xEB),
- _NONMSG(0xEC),
- _NONMSG(0xED),
- _NONMSG(0xEE),
- _NONMSG(0xEF),
- _NONMSG(0xF0),
- _NONMSG(0xF1),
- _NONMSG(0xF2),
- _NONMSG(0xF3),
- _NONMSG(0xF4),
- _NONMSG(0xF5),
- _NONMSG(0xF6),
- _NONMSG(0xF7),
- _NONMSG(0xF8),
- _NONMSG(0xF9),
- _NONMSG(0xFA),
- _NONMSG(0xFB),
- _NONMSG(0xFC),
- _NONMSG(0xFD),
- _NONMSG(0xFE),
- _NONMSG(0xFF),
- }},
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_e) */
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
- [LIB9P_VER_9P2000_u] = { .msgs = {
- _NONMSG(0x00),
- _NONMSG(0x01),
- _NONMSG(0x02),
- _NONMSG(0x03),
- _NONMSG(0x04),
- _NONMSG(0x05),
- _NONMSG(0x06),
- _NONMSG(0x07),
- _NONMSG(0x08),
- _NONMSG(0x09),
- _NONMSG(0x0A),
- _NONMSG(0x0B),
- _NONMSG(0x0C),
- _NONMSG(0x0D),
- _NONMSG(0x0E),
- _NONMSG(0x0F),
- _NONMSG(0x10),
- _NONMSG(0x11),
- _NONMSG(0x12),
- _NONMSG(0x13),
- _NONMSG(0x14),
- _NONMSG(0x15),
- _NONMSG(0x16),
- _NONMSG(0x17),
- _NONMSG(0x18),
- _NONMSG(0x19),
- _NONMSG(0x1A),
- _NONMSG(0x1B),
- _NONMSG(0x1C),
- _NONMSG(0x1D),
- _NONMSG(0x1E),
- _NONMSG(0x1F),
- _NONMSG(0x20),
- _NONMSG(0x21),
- _NONMSG(0x22),
- _NONMSG(0x23),
- _NONMSG(0x24),
- _NONMSG(0x25),
- _NONMSG(0x26),
- _NONMSG(0x27),
- _NONMSG(0x28),
- _NONMSG(0x29),
- _NONMSG(0x2A),
- _NONMSG(0x2B),
- _NONMSG(0x2C),
- _NONMSG(0x2D),
- _NONMSG(0x2E),
- _NONMSG(0x2F),
- _NONMSG(0x30),
- _NONMSG(0x31),
- _NONMSG(0x32),
- _NONMSG(0x33),
- _NONMSG(0x34),
- _NONMSG(0x35),
- _NONMSG(0x36),
- _NONMSG(0x37),
- _NONMSG(0x38),
- _NONMSG(0x39),
- _NONMSG(0x3A),
- _NONMSG(0x3B),
- _NONMSG(0x3C),
- _NONMSG(0x3D),
- _NONMSG(0x3E),
- _NONMSG(0x3F),
- _NONMSG(0x40),
- _NONMSG(0x41),
- _NONMSG(0x42),
- _NONMSG(0x43),
- _NONMSG(0x44),
- _NONMSG(0x45),
- _NONMSG(0x46),
- _NONMSG(0x47),
- _NONMSG(0x48),
- _NONMSG(0x49),
- _NONMSG(0x4A),
- _NONMSG(0x4B),
- _NONMSG(0x4C),
- _NONMSG(0x4D),
- _NONMSG(0x4E),
- _NONMSG(0x4F),
- _NONMSG(0x50),
- _NONMSG(0x51),
- _NONMSG(0x52),
- _NONMSG(0x53),
- _NONMSG(0x54),
- _NONMSG(0x55),
- _NONMSG(0x56),
- _NONMSG(0x57),
- _NONMSG(0x58),
- _NONMSG(0x59),
- _NONMSG(0x5A),
- _NONMSG(0x5B),
- _NONMSG(0x5C),
- _NONMSG(0x5D),
- _NONMSG(0x5E),
- _NONMSG(0x5F),
- _NONMSG(0x60),
- _NONMSG(0x61),
- _NONMSG(0x62),
- _NONMSG(0x63),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+ [LIB9P_VER_9P2000_p9p] = {
+ _MSG(Topenfd),
+ _MSG(Ropenfd),
+ _MSG(Tversion),
+ _MSG(Rversion),
+ _MSG(Tauth),
+ _MSG(Rauth),
+ _MSG(Tattach),
+ _MSG(Rattach),
+ _MSG(Rerror),
+ _MSG(Tflush),
+ _MSG(Rflush),
+ _MSG(Twalk),
+ _MSG(Rwalk),
+ _MSG(Topen),
+ _MSG(Ropen),
+ _MSG(Tcreate),
+ _MSG(Rcreate),
+ _MSG(Tread),
+ _MSG(Rread),
+ _MSG(Twrite),
+ _MSG(Rwrite),
+ _MSG(Tclunk),
+ _MSG(Rclunk),
+ _MSG(Tremove),
+ _MSG(Rremove),
+ _MSG(Tstat),
+ _MSG(Rstat),
+ _MSG(Twstat),
+ _MSG(Rwstat),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_u
+ [LIB9P_VER_9P2000_u] = {
_MSG(Tversion),
_MSG(Rversion),
_MSG(Tauth),
_MSG(Rauth),
_MSG(Tattach),
_MSG(Rattach),
- _NONMSG(0x6A),
_MSG(Rerror),
_MSG(Tflush),
_MSG(Rflush),
@@ -2700,144 +7614,478 @@ struct _table_version _lib9p_versions[LIB9P_VER_NUM] = {
_MSG(Rstat),
_MSG(Twstat),
_MSG(Rwstat),
- _NONMSG(0x80),
- _NONMSG(0x81),
- _NONMSG(0x82),
- _NONMSG(0x83),
- _NONMSG(0x84),
- _NONMSG(0x85),
- _NONMSG(0x86),
- _NONMSG(0x87),
- _NONMSG(0x88),
- _NONMSG(0x89),
- _NONMSG(0x8A),
- _NONMSG(0x8B),
- _NONMSG(0x8C),
- _NONMSG(0x8D),
- _NONMSG(0x8E),
- _NONMSG(0x8F),
- _NONMSG(0x90),
- _NONMSG(0x91),
- _NONMSG(0x92),
- _NONMSG(0x93),
- _NONMSG(0x94),
- _NONMSG(0x95),
- _NONMSG(0x96),
- _NONMSG(0x97),
- _NONMSG(0x98),
- _NONMSG(0x99),
- _NONMSG(0x9A),
- _NONMSG(0x9B),
- _NONMSG(0x9C),
- _NONMSG(0x9D),
- _NONMSG(0x9E),
- _NONMSG(0x9F),
- _NONMSG(0xA0),
- _NONMSG(0xA1),
- _NONMSG(0xA2),
- _NONMSG(0xA3),
- _NONMSG(0xA4),
- _NONMSG(0xA5),
- _NONMSG(0xA6),
- _NONMSG(0xA7),
- _NONMSG(0xA8),
- _NONMSG(0xA9),
- _NONMSG(0xAA),
- _NONMSG(0xAB),
- _NONMSG(0xAC),
- _NONMSG(0xAD),
- _NONMSG(0xAE),
- _NONMSG(0xAF),
- _NONMSG(0xB0),
- _NONMSG(0xB1),
- _NONMSG(0xB2),
- _NONMSG(0xB3),
- _NONMSG(0xB4),
- _NONMSG(0xB5),
- _NONMSG(0xB6),
- _NONMSG(0xB7),
- _NONMSG(0xB8),
- _NONMSG(0xB9),
- _NONMSG(0xBA),
- _NONMSG(0xBB),
- _NONMSG(0xBC),
- _NONMSG(0xBD),
- _NONMSG(0xBE),
- _NONMSG(0xBF),
- _NONMSG(0xC0),
- _NONMSG(0xC1),
- _NONMSG(0xC2),
- _NONMSG(0xC3),
- _NONMSG(0xC4),
- _NONMSG(0xC5),
- _NONMSG(0xC6),
- _NONMSG(0xC7),
- _NONMSG(0xC8),
- _NONMSG(0xC9),
- _NONMSG(0xCA),
- _NONMSG(0xCB),
- _NONMSG(0xCC),
- _NONMSG(0xCD),
- _NONMSG(0xCE),
- _NONMSG(0xCF),
- _NONMSG(0xD0),
- _NONMSG(0xD1),
- _NONMSG(0xD2),
- _NONMSG(0xD3),
- _NONMSG(0xD4),
- _NONMSG(0xD5),
- _NONMSG(0xD6),
- _NONMSG(0xD7),
- _NONMSG(0xD8),
- _NONMSG(0xD9),
- _NONMSG(0xDA),
- _NONMSG(0xDB),
- _NONMSG(0xDC),
- _NONMSG(0xDD),
- _NONMSG(0xDE),
- _NONMSG(0xDF),
- _NONMSG(0xE0),
- _NONMSG(0xE1),
- _NONMSG(0xE2),
- _NONMSG(0xE3),
- _NONMSG(0xE4),
- _NONMSG(0xE5),
- _NONMSG(0xE6),
- _NONMSG(0xE7),
- _NONMSG(0xE8),
- _NONMSG(0xE9),
- _NONMSG(0xEA),
- _NONMSG(0xEB),
- _NONMSG(0xEC),
- _NONMSG(0xED),
- _NONMSG(0xEE),
- _NONMSG(0xEF),
- _NONMSG(0xF0),
- _NONMSG(0xF1),
- _NONMSG(0xF2),
- _NONMSG(0xF3),
- _NONMSG(0xF4),
- _NONMSG(0xF5),
- _NONMSG(0xF6),
- _NONMSG(0xF7),
- _NONMSG(0xF8),
- _NONMSG(0xF9),
- _NONMSG(0xFA),
- _NONMSG(0xFB),
- _NONMSG(0xFC),
- _NONMSG(0xFD),
- _NONMSG(0xFE),
- _NONMSG(0xFF),
- }},
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+};
+
+#define _MSG_RECV(typ) [LIB9P_TYP_##typ/2] = { \
+ .validate = validate_##typ, \
+ .unmarshal = (_unmarshal_fn_t)unmarshal_##typ, \
+ }
+#define _MSG_SEND(typ) [LIB9P_TYP_##typ/2] = { \
+ .marshal = (_marshal_fn_t)marshal_##typ, \
+ }
+
+const struct _lib9p_recv_tentry _lib9p_table_Tmsg_recv[LIB9P_VER_NUM][0x80] = {
+ [LIB9P_VER_unknown] = {
+ _MSG_RECV(Tversion),
+ },
+#if CONFIG_9P_ENABLE_9P2000
+ [LIB9P_VER_9P2000] = {
+ _MSG_RECV(Tversion),
+ _MSG_RECV(Tauth),
+ _MSG_RECV(Tattach),
+ _MSG_RECV(Tflush),
+ _MSG_RECV(Twalk),
+ _MSG_RECV(Topen),
+ _MSG_RECV(Tcreate),
+ _MSG_RECV(Tread),
+ _MSG_RECV(Twrite),
+ _MSG_RECV(Tclunk),
+ _MSG_RECV(Tremove),
+ _MSG_RECV(Tstat),
+ _MSG_RECV(Twstat),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000 */
+#if CONFIG_9P_ENABLE_9P2000_L
+ [LIB9P_VER_9P2000_L] = {
+ _MSG_RECV(Tstatfs),
+ _MSG_RECV(Tlopen),
+ _MSG_RECV(Tlcreate),
+ _MSG_RECV(Tsymlink),
+ _MSG_RECV(Tmknod),
+ _MSG_RECV(Trename),
+ _MSG_RECV(Treadlink),
+ _MSG_RECV(Tgetattr),
+ _MSG_RECV(Tsetattr),
+ _MSG_RECV(Txattrwalk),
+ _MSG_RECV(Txattrcreate),
+ _MSG_RECV(Treaddir),
+ _MSG_RECV(Tfsync),
+ _MSG_RECV(Tlock),
+ _MSG_RECV(Tgetlock),
+ _MSG_RECV(Tlink),
+ _MSG_RECV(Tmkdir),
+ _MSG_RECV(Trenameat),
+ _MSG_RECV(Tunlinkat),
+ _MSG_RECV(Tversion),
+ _MSG_RECV(Tauth),
+ _MSG_RECV(Tattach),
+ _MSG_RECV(Tflush),
+ _MSG_RECV(Twalk),
+ _MSG_RECV(Tread),
+ _MSG_RECV(Twrite),
+ _MSG_RECV(Tclunk),
+ _MSG_RECV(Tremove),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000_e
+ [LIB9P_VER_9P2000_e] = {
+ _MSG_RECV(Tversion),
+ _MSG_RECV(Tauth),
+ _MSG_RECV(Tattach),
+ _MSG_RECV(Tflush),
+ _MSG_RECV(Twalk),
+ _MSG_RECV(Topen),
+ _MSG_RECV(Tcreate),
+ _MSG_RECV(Tread),
+ _MSG_RECV(Twrite),
+ _MSG_RECV(Tclunk),
+ _MSG_RECV(Tremove),
+ _MSG_RECV(Tstat),
+ _MSG_RECV(Twstat),
+ _MSG_RECV(Tsession),
+ _MSG_RECV(Tsread),
+ _MSG_RECV(Tswrite),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+ [LIB9P_VER_9P2000_p9p] = {
+ _MSG_RECV(Topenfd),
+ _MSG_RECV(Tversion),
+ _MSG_RECV(Tauth),
+ _MSG_RECV(Tattach),
+ _MSG_RECV(Tflush),
+ _MSG_RECV(Twalk),
+ _MSG_RECV(Topen),
+ _MSG_RECV(Tcreate),
+ _MSG_RECV(Tread),
+ _MSG_RECV(Twrite),
+ _MSG_RECV(Tclunk),
+ _MSG_RECV(Tremove),
+ _MSG_RECV(Tstat),
+ _MSG_RECV(Twstat),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_u
+ [LIB9P_VER_9P2000_u] = {
+ _MSG_RECV(Tversion),
+ _MSG_RECV(Tauth),
+ _MSG_RECV(Tattach),
+ _MSG_RECV(Tflush),
+ _MSG_RECV(Twalk),
+ _MSG_RECV(Topen),
+ _MSG_RECV(Tcreate),
+ _MSG_RECV(Tread),
+ _MSG_RECV(Twrite),
+ _MSG_RECV(Tclunk),
+ _MSG_RECV(Tremove),
+ _MSG_RECV(Tstat),
+ _MSG_RECV(Twstat),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+};
+
+const struct _lib9p_recv_tentry _lib9p_table_Rmsg_recv[LIB9P_VER_NUM][0x80] = {
+ [LIB9P_VER_unknown] = {
+ _MSG_RECV(Rversion),
+ _MSG_RECV(Rerror),
+ },
+#if CONFIG_9P_ENABLE_9P2000
+ [LIB9P_VER_9P2000] = {
+ _MSG_RECV(Rversion),
+ _MSG_RECV(Rauth),
+ _MSG_RECV(Rattach),
+ _MSG_RECV(Rerror),
+ _MSG_RECV(Rflush),
+ _MSG_RECV(Rwalk),
+ _MSG_RECV(Ropen),
+ _MSG_RECV(Rcreate),
+ _MSG_RECV(Rread),
+ _MSG_RECV(Rwrite),
+ _MSG_RECV(Rclunk),
+ _MSG_RECV(Rremove),
+ _MSG_RECV(Rstat),
+ _MSG_RECV(Rwstat),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000 */
+#if CONFIG_9P_ENABLE_9P2000_L
+ [LIB9P_VER_9P2000_L] = {
+ _MSG_RECV(Rlerror),
+ _MSG_RECV(Rstatfs),
+ _MSG_RECV(Rlopen),
+ _MSG_RECV(Rlcreate),
+ _MSG_RECV(Rsymlink),
+ _MSG_RECV(Rmknod),
+ _MSG_RECV(Rrename),
+ _MSG_RECV(Rreadlink),
+ _MSG_RECV(Rgetattr),
+ _MSG_RECV(Rsetattr),
+ _MSG_RECV(Rxattrwalk),
+ _MSG_RECV(Rxattrcreate),
+ _MSG_RECV(Rreaddir),
+ _MSG_RECV(Rfsync),
+ _MSG_RECV(Rlock),
+ _MSG_RECV(Rgetlock),
+ _MSG_RECV(Rlink),
+ _MSG_RECV(Rmkdir),
+ _MSG_RECV(Rrenameat),
+ _MSG_RECV(Runlinkat),
+ _MSG_RECV(Rversion),
+ _MSG_RECV(Rauth),
+ _MSG_RECV(Rattach),
+ _MSG_RECV(Rerror),
+ _MSG_RECV(Rflush),
+ _MSG_RECV(Rwalk),
+ _MSG_RECV(Rread),
+ _MSG_RECV(Rwrite),
+ _MSG_RECV(Rclunk),
+ _MSG_RECV(Rremove),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000_e
+ [LIB9P_VER_9P2000_e] = {
+ _MSG_RECV(Rversion),
+ _MSG_RECV(Rauth),
+ _MSG_RECV(Rattach),
+ _MSG_RECV(Rerror),
+ _MSG_RECV(Rflush),
+ _MSG_RECV(Rwalk),
+ _MSG_RECV(Ropen),
+ _MSG_RECV(Rcreate),
+ _MSG_RECV(Rread),
+ _MSG_RECV(Rwrite),
+ _MSG_RECV(Rclunk),
+ _MSG_RECV(Rremove),
+ _MSG_RECV(Rstat),
+ _MSG_RECV(Rwstat),
+ _MSG_RECV(Rsession),
+ _MSG_RECV(Rsread),
+ _MSG_RECV(Rswrite),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+ [LIB9P_VER_9P2000_p9p] = {
+ _MSG_RECV(Ropenfd),
+ _MSG_RECV(Rversion),
+ _MSG_RECV(Rauth),
+ _MSG_RECV(Rattach),
+ _MSG_RECV(Rerror),
+ _MSG_RECV(Rflush),
+ _MSG_RECV(Rwalk),
+ _MSG_RECV(Ropen),
+ _MSG_RECV(Rcreate),
+ _MSG_RECV(Rread),
+ _MSG_RECV(Rwrite),
+ _MSG_RECV(Rclunk),
+ _MSG_RECV(Rremove),
+ _MSG_RECV(Rstat),
+ _MSG_RECV(Rwstat),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_u
+ [LIB9P_VER_9P2000_u] = {
+ _MSG_RECV(Rversion),
+ _MSG_RECV(Rauth),
+ _MSG_RECV(Rattach),
+ _MSG_RECV(Rerror),
+ _MSG_RECV(Rflush),
+ _MSG_RECV(Rwalk),
+ _MSG_RECV(Ropen),
+ _MSG_RECV(Rcreate),
+ _MSG_RECV(Rread),
+ _MSG_RECV(Rwrite),
+ _MSG_RECV(Rclunk),
+ _MSG_RECV(Rremove),
+ _MSG_RECV(Rstat),
+ _MSG_RECV(Rwstat),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+};
+
+const struct _lib9p_send_tentry _lib9p_table_Tmsg_send[LIB9P_VER_NUM][0x80] = {
+ [LIB9P_VER_unknown] = {
+ _MSG_SEND(Tversion),
+ },
+#if CONFIG_9P_ENABLE_9P2000
+ [LIB9P_VER_9P2000] = {
+ _MSG_SEND(Tversion),
+ _MSG_SEND(Tauth),
+ _MSG_SEND(Tattach),
+ _MSG_SEND(Tflush),
+ _MSG_SEND(Twalk),
+ _MSG_SEND(Topen),
+ _MSG_SEND(Tcreate),
+ _MSG_SEND(Tread),
+ _MSG_SEND(Twrite),
+ _MSG_SEND(Tclunk),
+ _MSG_SEND(Tremove),
+ _MSG_SEND(Tstat),
+ _MSG_SEND(Twstat),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000 */
+#if CONFIG_9P_ENABLE_9P2000_L
+ [LIB9P_VER_9P2000_L] = {
+ _MSG_SEND(Tstatfs),
+ _MSG_SEND(Tlopen),
+ _MSG_SEND(Tlcreate),
+ _MSG_SEND(Tsymlink),
+ _MSG_SEND(Tmknod),
+ _MSG_SEND(Trename),
+ _MSG_SEND(Treadlink),
+ _MSG_SEND(Tgetattr),
+ _MSG_SEND(Tsetattr),
+ _MSG_SEND(Txattrwalk),
+ _MSG_SEND(Txattrcreate),
+ _MSG_SEND(Treaddir),
+ _MSG_SEND(Tfsync),
+ _MSG_SEND(Tlock),
+ _MSG_SEND(Tgetlock),
+ _MSG_SEND(Tlink),
+ _MSG_SEND(Tmkdir),
+ _MSG_SEND(Trenameat),
+ _MSG_SEND(Tunlinkat),
+ _MSG_SEND(Tversion),
+ _MSG_SEND(Tauth),
+ _MSG_SEND(Tattach),
+ _MSG_SEND(Tflush),
+ _MSG_SEND(Twalk),
+ _MSG_SEND(Tread),
+ _MSG_SEND(Twrite),
+ _MSG_SEND(Tclunk),
+ _MSG_SEND(Tremove),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000_e
+ [LIB9P_VER_9P2000_e] = {
+ _MSG_SEND(Tversion),
+ _MSG_SEND(Tauth),
+ _MSG_SEND(Tattach),
+ _MSG_SEND(Tflush),
+ _MSG_SEND(Twalk),
+ _MSG_SEND(Topen),
+ _MSG_SEND(Tcreate),
+ _MSG_SEND(Tread),
+ _MSG_SEND(Twrite),
+ _MSG_SEND(Tclunk),
+ _MSG_SEND(Tremove),
+ _MSG_SEND(Tstat),
+ _MSG_SEND(Twstat),
+ _MSG_SEND(Tsession),
+ _MSG_SEND(Tsread),
+ _MSG_SEND(Tswrite),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+ [LIB9P_VER_9P2000_p9p] = {
+ _MSG_SEND(Topenfd),
+ _MSG_SEND(Tversion),
+ _MSG_SEND(Tauth),
+ _MSG_SEND(Tattach),
+ _MSG_SEND(Tflush),
+ _MSG_SEND(Twalk),
+ _MSG_SEND(Topen),
+ _MSG_SEND(Tcreate),
+ _MSG_SEND(Tread),
+ _MSG_SEND(Twrite),
+ _MSG_SEND(Tclunk),
+ _MSG_SEND(Tremove),
+ _MSG_SEND(Tstat),
+ _MSG_SEND(Twstat),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_u
+ [LIB9P_VER_9P2000_u] = {
+ _MSG_SEND(Tversion),
+ _MSG_SEND(Tauth),
+ _MSG_SEND(Tattach),
+ _MSG_SEND(Tflush),
+ _MSG_SEND(Twalk),
+ _MSG_SEND(Topen),
+ _MSG_SEND(Tcreate),
+ _MSG_SEND(Tread),
+ _MSG_SEND(Twrite),
+ _MSG_SEND(Tclunk),
+ _MSG_SEND(Tremove),
+ _MSG_SEND(Tstat),
+ _MSG_SEND(Twstat),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+};
+
+const struct _lib9p_send_tentry _lib9p_table_Rmsg_send[LIB9P_VER_NUM][0x80] = {
+ [LIB9P_VER_unknown] = {
+ _MSG_SEND(Rversion),
+ _MSG_SEND(Rerror),
+ },
+#if CONFIG_9P_ENABLE_9P2000
+ [LIB9P_VER_9P2000] = {
+ _MSG_SEND(Rversion),
+ _MSG_SEND(Rauth),
+ _MSG_SEND(Rattach),
+ _MSG_SEND(Rerror),
+ _MSG_SEND(Rflush),
+ _MSG_SEND(Rwalk),
+ _MSG_SEND(Ropen),
+ _MSG_SEND(Rcreate),
+ _MSG_SEND(Rread),
+ _MSG_SEND(Rwrite),
+ _MSG_SEND(Rclunk),
+ _MSG_SEND(Rremove),
+ _MSG_SEND(Rstat),
+ _MSG_SEND(Rwstat),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000 */
+#if CONFIG_9P_ENABLE_9P2000_L
+ [LIB9P_VER_9P2000_L] = {
+ _MSG_SEND(Rlerror),
+ _MSG_SEND(Rstatfs),
+ _MSG_SEND(Rlopen),
+ _MSG_SEND(Rlcreate),
+ _MSG_SEND(Rsymlink),
+ _MSG_SEND(Rmknod),
+ _MSG_SEND(Rrename),
+ _MSG_SEND(Rreadlink),
+ _MSG_SEND(Rgetattr),
+ _MSG_SEND(Rsetattr),
+ _MSG_SEND(Rxattrwalk),
+ _MSG_SEND(Rxattrcreate),
+ _MSG_SEND(Rreaddir),
+ _MSG_SEND(Rfsync),
+ _MSG_SEND(Rlock),
+ _MSG_SEND(Rgetlock),
+ _MSG_SEND(Rlink),
+ _MSG_SEND(Rmkdir),
+ _MSG_SEND(Rrenameat),
+ _MSG_SEND(Runlinkat),
+ _MSG_SEND(Rversion),
+ _MSG_SEND(Rauth),
+ _MSG_SEND(Rattach),
+ _MSG_SEND(Rerror),
+ _MSG_SEND(Rflush),
+ _MSG_SEND(Rwalk),
+ _MSG_SEND(Rread),
+ _MSG_SEND(Rwrite),
+ _MSG_SEND(Rclunk),
+ _MSG_SEND(Rremove),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000_e
+ [LIB9P_VER_9P2000_e] = {
+ _MSG_SEND(Rversion),
+ _MSG_SEND(Rauth),
+ _MSG_SEND(Rattach),
+ _MSG_SEND(Rerror),
+ _MSG_SEND(Rflush),
+ _MSG_SEND(Rwalk),
+ _MSG_SEND(Ropen),
+ _MSG_SEND(Rcreate),
+ _MSG_SEND(Rread),
+ _MSG_SEND(Rwrite),
+ _MSG_SEND(Rclunk),
+ _MSG_SEND(Rremove),
+ _MSG_SEND(Rstat),
+ _MSG_SEND(Rwstat),
+ _MSG_SEND(Rsession),
+ _MSG_SEND(Rsread),
+ _MSG_SEND(Rswrite),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+ [LIB9P_VER_9P2000_p9p] = {
+ _MSG_SEND(Ropenfd),
+ _MSG_SEND(Rversion),
+ _MSG_SEND(Rauth),
+ _MSG_SEND(Rattach),
+ _MSG_SEND(Rerror),
+ _MSG_SEND(Rflush),
+ _MSG_SEND(Rwalk),
+ _MSG_SEND(Ropen),
+ _MSG_SEND(Rcreate),
+ _MSG_SEND(Rread),
+ _MSG_SEND(Rwrite),
+ _MSG_SEND(Rclunk),
+ _MSG_SEND(Rremove),
+ _MSG_SEND(Rstat),
+ _MSG_SEND(Rwstat),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_u
+ [LIB9P_VER_9P2000_u] = {
+ _MSG_SEND(Rversion),
+ _MSG_SEND(Rauth),
+ _MSG_SEND(Rattach),
+ _MSG_SEND(Rerror),
+ _MSG_SEND(Rflush),
+ _MSG_SEND(Rwalk),
+ _MSG_SEND(Ropen),
+ _MSG_SEND(Rcreate),
+ _MSG_SEND(Rread),
+ _MSG_SEND(Rwrite),
+ _MSG_SEND(Rclunk),
+ _MSG_SEND(Rremove),
+ _MSG_SEND(Rstat),
+ _MSG_SEND(Rwstat),
+ },
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
};
-FLATTEN bool _lib9p_validate_stat(struct _validate_ctx *ctx) {
- return validate_stat(ctx);
+LM_FLATTEN ssize_t _lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, uint32_t *ret_net_size) {
+ return validate_stat(ctx, net_size, net_bytes, ret_net_size);
}
-FLATTEN void _lib9p_unmarshal_stat(struct _unmarshal_ctx *ctx, struct lib9p_stat *out) {
- unmarshal_stat(ctx, out);
+LM_FLATTEN void _lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out) {
+ unmarshal_stat(ctx, net_bytes, out);
}
-FLATTEN bool _lib9p_marshal_stat(struct _marshal_ctx *ctx, struct lib9p_stat *val) {
- return marshal_stat(ctx, val);
+LM_FLATTEN bool _lib9p_stat_marshal(struct lib9p_ctx *ctx, struct lib9p_stat *val, struct _marshal_ret *ret) {
+ return marshal_stat(ctx, val, ret);
}
diff --git a/lib9p/CMakeLists.txt b/lib9p/CMakeLists.txt
index 488cff9..949b6d6 100644
--- a/lib9p/CMakeLists.txt
+++ b/lib9p/CMakeLists.txt
@@ -1,17 +1,47 @@
-# lib9p/CMakeLists.txt - TODO
+# lib9p/CMakeLists.txt - A 9P protocol and server library
#
-# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
add_library(lib9p INTERFACE)
-target_include_directories(lib9p SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
+target_include_directories(lib9p PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_sources(lib9p INTERFACE
9p.generated.c
9p.c
+ tables.c
srv.c
)
target_link_libraries(lib9p INTERFACE
libcr_ipc
+ libfmt
+ libhw_generic
libmisc
- libhw
)
+
+if (ENABLE_TESTS)
+ add_subdirectory(tests/test_server)
+
+ function(add_lib9p_executable arg_testname)
+ add_executable("${arg_testname}" "tests/${arg_testname}.c")
+ target_link_libraries("${arg_testname}" lib9p)
+ target_include_directories("${arg_testname}" PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}/tests
+ ${CMAKE_CURRENT_SOURCE_DIR}/tests/client_config
+ )
+ endfunction()
+ function(add_lib9p_test arg_testscript)
+ get_filename_component(tmp_basename "${arg_testscript}" "NAME")
+ add_test(
+ NAME "lib9p/${tmp_basename}"
+ COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/tests/runtest" "${arg_testscript}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/${tmp_basename}.explog"
+ )
+ endfunction()
+
+ add_lib9p_test("${CMAKE_CURRENT_SOURCE_DIR}/tests/testclient-p9p")
+
+ add_lib9p_executable("testclient-sess")
+ add_lib9p_test("./testclient-sess")
+
+ add_lib_test(lib9p test_compile)
+ target_include_directories(test_compile PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_compile_config)
+endif()
diff --git a/lib9p/idl.gen b/lib9p/idl.gen
deleted file mode 100755
index ec42cfd..0000000
--- a/lib9p/idl.gen
+++ /dev/null
@@ -1,1184 +0,0 @@
-#!/usr/bin/env python
-# lib9p/idl.gen - Generate C marshalers/unmarshalers for .9p files
-# defining 9P protocol variants.
-#
-# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-import enum
-import os.path
-import re
-from abc import ABC, abstractmethod
-from typing import Callable, Final, Literal, TypeAlias, TypeVar, cast
-
-# This strives to be "general-purpose" in that it just acts on the
-# *.9p inputs; but (unfortunately?) there are a few special-cases in
-# this script, marked with "SPECIAL".
-
-# Types ########################################################################
-
-
-class Primitive(enum.Enum):
- u8 = 1
- u16 = 2
- u32 = 4
- u64 = 8
-
- @property
- def in_versions(self) -> set[str]:
- return set()
-
- @property
- def name(self) -> str:
- return str(self.value)
-
- @property
- def static_size(self) -> int:
- return self.value
-
-
-class Number:
- name: str
- in_versions: set[str]
-
- prim: Primitive
-
- def __init__(self) -> None:
- self.in_versions = set()
-
- @property
- def static_size(self) -> int:
- return self.prim.static_size
-
-
-class BitfieldVal:
- name: str
- in_versions: set[str]
-
- val: str
-
- def __init__(self) -> None:
- self.in_versions = set()
-
-
-class Bitfield:
- name: str
- in_versions: set[str]
-
- prim: Primitive
-
- bits: list[str] # bitnames
- names: dict[str, BitfieldVal] # bits *and* aliases
-
- def __init__(self) -> None:
- self.in_versions = set()
- self.names = {}
-
- @property
- def static_size(self) -> int:
- return self.prim.static_size
-
- def bit_is_valid(self, bit: str | int, ver: str | None = None) -> bool:
- """Return whether the given bit is valid in the given protocol
- version.
-
- """
- bitname = self.bits[bit] if isinstance(bit, int) else bit
- assert bitname in self.bits
- if not bitname:
- return False
- if bitname.startswith("_"):
- return False
- if ver and (ver not in self.names[bitname].in_versions):
- return False
- return True
-
-
-class ExprLit:
- val: int
-
- def __init__(self, val: int) -> None:
- self.val = val
-
-
-class ExprSym:
- name: str
-
- def __init__(self, name: str) -> None:
- self.name = name
-
-
-class ExprOp:
- op: Literal["-", "+"]
-
- def __init__(self, op: Literal["-", "+"]) -> None:
- self.op = op
-
-
-class Expr:
- tokens: list[ExprLit | ExprSym | ExprOp]
-
- def __init__(self) -> None:
- self.tokens = []
-
- def __bool__(self) -> bool:
- return len(self.tokens) > 0
-
-
-class StructMember:
- # from left-to-right when parsing
- cnt: str | None = None
- name: str
- typ: "Type"
- max: Expr
- val: Expr
-
- in_versions: set[str]
-
- @property
- def static_size(self) -> int | None:
- if self.cnt:
- return None
- return self.typ.static_size
-
-
-class Struct:
- name: str
- in_versions: set[str]
-
- members: list[StructMember]
-
- def __init__(self) -> None:
- self.in_versions = set()
-
- @property
- def static_size(self) -> int | None:
- size = 0
- for member in self.members:
- msize = member.static_size
- if msize is None:
- return None
- size += msize
- return size
-
-
-class Message(Struct):
- @property
- def msgid(self) -> int:
- assert len(self.members) >= 3
- assert self.members[1].name == "typ"
- assert self.members[1].static_size == 1
- assert self.members[1].val
- assert len(self.members[1].val.tokens) == 1
- assert isinstance(self.members[1].val.tokens[0], ExprLit)
- return self.members[1].val.tokens[0].val
-
-
-Type: TypeAlias = Primitive | Number | Bitfield | Struct | Message
-# type Type = Primitive | Number | Bitfield | Struct | Message # Change to this once we have Python 3.13
-T = TypeVar("T", Number, Bitfield, Struct, Message)
-
-# Parse *.9p ###################################################################
-
-re_priname = "(?:1|2|4|8)" # primitive names
-re_symname = "(?:[a-zA-Z_][a-zA-Z_0-9]*)" # "symbol" names; most *.9p-defined names
-re_impname = r"(?:\*|" + re_symname + ")" # names we can import
-re_msgname = r"(?:[TR][a-zA-Z_0-9]*)" # names a message can be
-
-re_memtype = f"(?:{re_symname}|{re_priname})" # typenames that a struct member can be
-
-re_expr = f"(?:(?:-|\\+|[0-9]+|&?{re_symname})+)"
-
-re_bitspec_bit = f"(?P<bit>[0-9]+)\\s*=\\s*(?P<name>{re_symname})"
-re_bitspec_alias = f"(?P<name>{re_symname})\\s*=\\s*(?P<val>\\S+)"
-
-re_memberspec = f"(?:(?P<cnt>{re_symname})\\*\\()?(?P<name>{re_symname})\\[(?P<typ>{re_memtype})(?:,max=(?P<max>{re_expr})|,val=(?P<val>{re_expr}))*\\]\\)?"
-
-
-def parse_bitspec(ver: str, bf: Bitfield, spec: str) -> None:
- spec = spec.strip()
-
- bit: int | None
- val: BitfieldVal
- if m := re.fullmatch(re_bitspec_bit, spec):
- bit = int(m.group("bit"))
- name = m.group("name")
-
- val = BitfieldVal()
- val.name = name
- val.val = f"1<<{bit}"
- val.in_versions.add(ver)
-
- if bit < 0 or bit >= len(bf.bits):
- raise ValueError(f"{bf.name}: bit {bit} is out-of-bounds")
- if bf.bits[bit]:
- raise ValueError(f"{bf.name}: bit {bit} already assigned")
- bf.bits[bit] = val.name
- elif m := re.fullmatch(re_bitspec_alias, spec):
- name = m.group("name")
- valstr = m.group("val")
-
- val = BitfieldVal()
- val.name = name
- val.val = valstr
- val.in_versions.add(ver)
- else:
- raise SyntaxError(f"invalid bitfield spec {repr(spec)}")
-
- if val.name in bf.names:
- raise ValueError(f"{bf.name}: name {val.name} already assigned")
- bf.names[val.name] = val
-
-
-def parse_expr(expr: str) -> Expr:
- assert re.fullmatch(re_expr, expr)
- ret = Expr()
- for tok in re.split("([-+])", expr):
- if tok == "-" or tok == "+":
- # I, for the life of me, do not understand why I need this
- # cast() to keep mypy happy.
- ret.tokens += [ExprOp(cast(Literal["-", "+"], tok))]
- elif re.fullmatch("[0-9]+", tok):
- ret.tokens += [ExprLit(int(tok))]
- else:
- ret.tokens += [ExprSym(tok)]
- return ret
-
-
-def parse_members(ver: str, env: dict[str, Type], struct: Struct, specs: str) -> None:
- for spec in specs.split():
- m = re.fullmatch(re_memberspec, spec)
- if not m:
- raise SyntaxError(f"invalid member spec {repr(spec)}")
-
- member = StructMember()
- member.in_versions = {ver}
-
- member.name = m.group("name")
- if any(x.name == member.name for x in struct.members):
- raise ValueError(f"duplicate member name {repr(member.name)}")
-
- if m.group("typ") not in env:
- raise NameError(f"Unknown type {repr(m.group(2))}")
- member.typ = env[m.group("typ")]
-
- if cnt := m.group("cnt"):
- if len(struct.members) == 0 or struct.members[-1].name != cnt:
- raise ValueError(f"list count must be previous item: {repr(cnt)}")
- if not isinstance(struct.members[-1].typ, Primitive):
- raise ValueError(f"list count must be an integer type: {repr(cnt)}")
- member.cnt = cnt
-
- if maxstr := m.group("max"):
- if (not isinstance(member.typ, Primitive)) or member.cnt:
- raise ValueError("',max=' may only be specified on a non-repeated atom")
- member.max = parse_expr(maxstr)
- else:
- member.max = Expr()
-
- if valstr := m.group("val"):
- if (not isinstance(member.typ, Primitive)) or member.cnt:
- raise ValueError("',val=' may only be specified on a non-repeated atom")
- member.val = parse_expr(valstr)
- else:
- member.val = Expr()
-
- struct.members += [member]
-
-
-def re_string(grpname: str) -> str:
- return f'"(?P<{grpname}>[^"]*)"'
-
-
-re_line_version = f"version\\s+{re_string('version')}"
-re_line_import = f"from\\s+(?P<file>\\S+)\\s+import\\s+(?P<syms>{re_impname}(?:\\s*,\\s*{re_impname})*)"
-re_line_num = f"num\\s+(?P<name>{re_symname})\\s*=\\s*(?P<prim>{re_priname})"
-re_line_bitfield = f"bitfield\\s+(?P<name>{re_symname})\\s*=\\s*(?P<prim>{re_priname})"
-re_line_bitfield_ = (
- f"bitfield\\s+(?P<name>{re_symname})\\s*\\+=\\s*{re_string('member')}"
-)
-re_line_struct = (
- f"struct\\s+(?P<name>{re_symname})\\s*(?P<op>\\+?=)\\s*{re_string('members')}"
-)
-re_line_msg = (
- f"msg\\s+(?P<name>{re_msgname})\\s*(?P<op>\\+?=)\\s*{re_string('members')}"
-)
-re_line_cont = f"\\s+{re_string('specs')}" # could be bitfield/struct/msg
-
-
-def parse_file(
- filename: str, get_include: Callable[[str], tuple[str, list[Type]]]
-) -> tuple[str, list[Type]]:
- version: str | None = None
- env: dict[str, Type] = {
- "1": Primitive.u8,
- "2": Primitive.u16,
- "4": Primitive.u32,
- "8": Primitive.u64,
- }
-
- def get_type(name: str, tc: type[T]) -> T:
- nonlocal env
- if name not in env:
- raise NameError(f"Unknown type {repr(name)}")
- ret = env[name]
- if (not isinstance(ret, tc)) or (ret.__class__.__name__ != tc.__name__):
- raise NameError(f"Type {repr(ret.name)} is not a {tc.__name__}")
- return ret
-
- with open(filename, "r") as fh:
- prev: Type | None = None
- for line in fh:
- line = line.split("#", 1)[0].rstrip()
- if not line:
- continue
- if m := re.fullmatch(re_line_version, line):
- if version:
- raise SyntaxError("must have exactly 1 version line")
- version = m.group("version")
- continue
- if not version:
- raise SyntaxError("must have exactly 1 version line")
-
- if m := re.fullmatch(re_line_import, line):
- other_version, other_typs = get_include(m.group("file"))
- for symname in m.group("syms").split(sep=","):
- symname = symname.strip()
- for typ in other_typs:
- if typ.name == symname or symname == "*":
- match typ:
- case Primitive():
- pass
- case Number():
- typ.in_versions.add(version)
- case Bitfield():
- typ.in_versions.add(version)
- for val in typ.names.values():
- if other_version in val.in_versions:
- val.in_versions.add(version)
- case Struct(): # and Message()
- typ.in_versions.add(version)
- for member in typ.members:
- if other_version in member.in_versions:
- member.in_versions.add(version)
- env[typ.name] = typ
- elif m := re.fullmatch(re_line_num, line):
- num = Number()
- num.name = m.group("name")
- num.in_versions.add(version)
-
- prim = env[m.group("prim")]
- assert isinstance(prim, Primitive)
- num.prim = prim
-
- env[num.name] = num
- prev = num
- elif m := re.fullmatch(re_line_bitfield, line):
- bf = Bitfield()
- bf.name = m.group("name")
- bf.in_versions.add(version)
-
- prim = env[m.group("prim")]
- assert isinstance(prim, Primitive)
- bf.prim = prim
-
- bf.bits = (prim.static_size * 8) * [""]
-
- env[bf.name] = bf
- prev = bf
- elif m := re.fullmatch(re_line_bitfield_, line):
- bf = get_type(m.group("name"), Bitfield)
- parse_bitspec(version, bf, m.group("member"))
-
- prev = bf
- elif m := re.fullmatch(re_line_struct, line):
- match m.group("op"):
- case "=":
- struct = Struct()
- struct.name = m.group("name")
- struct.in_versions.add(version)
- struct.members = []
- parse_members(version, env, struct, m.group("members"))
-
- env[struct.name] = struct
- prev = struct
- case "+=":
- struct = get_type(m.group("name"), Struct)
- parse_members(version, env, struct, m.group("members"))
-
- prev = struct
- elif m := re.fullmatch(re_line_msg, line):
- match m.group("op"):
- case "=":
- msg = Message()
- msg.name = m.group("name")
- msg.in_versions.add(version)
- msg.members = []
- parse_members(version, env, msg, m.group("members"))
-
- env[msg.name] = msg
- prev = msg
- case "+=":
- msg = get_type(m.group("name"), Message)
- parse_members(version, env, msg, m.group("members"))
-
- prev = msg
- elif m := re.fullmatch(re_line_cont, line):
- match prev:
- case Bitfield():
- parse_bitspec(version, prev, m.group("specs"))
- case Struct(): # and Message()
- parse_members(version, env, prev, m.group("specs"))
- case _:
- raise SyntaxError(
- "continuation line must come after a bitfield, struct, or msg line"
- )
- else:
- raise SyntaxError(f"invalid line {repr(line)}")
- if not version:
- raise SyntaxError("must have exactly 1 version line")
-
- typs: list[Type] = [x for x in env.values() if not isinstance(x, Primitive)]
-
- for typ in [typ for typ in typs if isinstance(typ, Struct)]:
- valid_syms = ["end", *["&" + m.name for m in typ.members]]
- for member in typ.members:
- for tok in [*member.max.tokens, *member.val.tokens]:
- if isinstance(tok, ExprSym) and tok.name not in valid_syms:
- raise ValueError(
- f"{typ.name}.{member.name}: invalid sym: {tok.name}"
- )
-
- return version, typs
-
-
-# Generate C ###################################################################
-
-idprefix = "lib9p_"
-
-
-def c_ver_enum(ver: str) -> str:
- return f"{idprefix.upper()}VER_{ver.replace('.', '_')}"
-
-
-def c_ver_ifdef(versions: set[str]) -> str:
- return " || ".join(
- f"defined(CONFIG_9P_ENABLE_{v.replace('.', '_')})" for v in sorted(versions)
- )
-
-
-def c_ver_cond(versions: set[str]) -> str:
- if len(versions) == 1:
- return f"(ctx->ctx->version=={c_ver_enum(next(v for v in versions))})"
- return "( " + (" || ".join(c_ver_cond({v}) for v in sorted(versions))) + " )"
-
-
-def c_typename(typ: Type) -> str:
- match typ:
- case Primitive():
- return f"uint{typ.value*8}_t"
- case Number():
- return f"{idprefix}{typ.name}_t"
- case Bitfield():
- return f"{idprefix}{typ.name}_t"
- case Message():
- return f"struct {idprefix}msg_{typ.name}"
- case Struct():
- return f"struct {idprefix}{typ.name}"
- case _:
- raise ValueError(f"not a type: {typ.__class__.__name__}")
-
-
-_ifdef_stack: list[str | None] = []
-
-
-def ifdef_push(n: int, _newval: str) -> str:
- # Grow the stack as needed
- global _ifdef_stack
- while len(_ifdef_stack) < n:
- _ifdef_stack += [None]
-
- # Set some variables
- parentval: str | None = None
- for x in _ifdef_stack[:-1]:
- if x is not None:
- parentval = x
- oldval = _ifdef_stack[-1]
- newval: str | None = _newval
- if newval == parentval:
- newval = None
-
- # Put newval on the stack.
- _ifdef_stack[-1] = newval
-
- # Build output.
- ret = ""
- if newval != oldval:
- if oldval is not None:
- ret += f"#endif /* {oldval} */\n"
- if newval is not None:
- ret += f"#if {newval}\n"
- return ret
-
-
-def ifdef_pop(n: int) -> str:
- global _ifdef_stack
- ret = ""
- while len(_ifdef_stack) > n:
- if _ifdef_stack[-1] is not None:
- ret += f"#endif /* {_ifdef_stack[-1]} */\n"
- _ifdef_stack = _ifdef_stack[:-1]
- return ret
-
-
-def gen_h(versions: set[str], typs: list[Type]) -> str:
- global _ifdef_stack
- _ifdef_stack = []
-
- ret = f"""/* Generated by `{' '.join(sys.argv)}`. DO NOT EDIT! */
-
-#ifndef _LIB9P_9P_H_
- #error Do not include <lib9p/9p.generated.h> directly; include <lib9p/9p.h> instead
-#endif
-
-#include <stdint.h> /* for uint{{n}}_t types */
-"""
-
- ret += f"""
-/* versions *******************************************************************/
-
-enum {idprefix}version {{
-"""
- fullversions = ["unknown = 0", *sorted(versions)]
- verwidth = max(len(v) for v in fullversions)
- for ver in fullversions:
- if ver in versions:
- ret += ifdef_push(1, c_ver_ifdef({ver}))
- ret += f"\t{c_ver_enum(ver)},"
- ret += (" " * (verwidth - len(ver))) + ' /* "' + ver.split()[0] + '" */\n'
- ret += ifdef_pop(0)
- ret += f"\t{c_ver_enum('NUM')},\n"
- ret += "};\n"
- ret += "\n"
- ret += f"const char *{idprefix}version_str(enum {idprefix}version);\n"
-
- ret += """
-/* non-message types **********************************************************/
-"""
- for typ in [typ for typ in typs if not isinstance(typ, Message)]:
- ret += "\n"
- ret += ifdef_push(1, c_ver_ifdef(typ.in_versions))
- match typ:
- case Number():
- ret += f"typedef {c_typename(typ.prim)} {c_typename(typ)};\n"
- case Bitfield():
- ret += f"typedef {c_typename(typ.prim)} {c_typename(typ)};\n"
- names = [
- *reversed(
- [typ.bits[n] or f" {n}" for n in range(0, len(typ.bits))]
- ),
- "",
- *[k for k in typ.names if k not in typ.bits],
- ]
- namewidth = max(len(name) for name in names)
-
- ret += "\n"
- for name in names:
- if name == "":
- ret += "\n"
- elif name.startswith(" "):
- ret += ifdef_push(2, c_ver_ifdef(typ.in_versions))
- sp = " " * (
- len("# define ")
- + len(idprefix)
- + len(typ.name)
- + 1
- + namewidth
- + 2
- - len("/* unused")
- )
- ret += f"/* unused{sp}(({c_typename(typ)})(1<<{name[1:]})) */\n"
- else:
- ret += ifdef_push(2, c_ver_ifdef(typ.names[name].in_versions))
- if name.startswith("_"):
- c_name = f"_{idprefix.upper()}{typ.name.upper()}_{name[1:]}"
- else:
- c_name = f"{idprefix.upper()}{typ.name.upper()}_{name}"
- sp1 = " " if _ifdef_stack[-1] else ""
- sp2 = " " if _ifdef_stack[-1] else " "
- sp3 = " " * (2 + namewidth - len(name))
- ret += f"#{sp1}define{sp2}{c_name}{sp3}(({c_typename(typ)})({typ.names[name].val}))\n"
- ret += ifdef_pop(1)
- case Struct():
- typewidth = max(len(c_typename(m.typ)) for m in typ.members)
-
- ret += c_typename(typ) + " {\n"
- for member in typ.members:
- if member.val:
- continue
- ret += ifdef_push(2, c_ver_ifdef(member.in_versions))
- c_type = c_typename(member.typ)
- if (typ.name in ["d", "s"]) and member.cnt: # SPECIAL
- c_type = "char"
- ret += f"\t{c_type.ljust(typewidth)} {'*' if member.cnt else ' '}{member.name};\n"
- ret += ifdef_pop(1)
- ret += "};\n"
- ret += ifdef_pop(0)
-
- ret += """
-/* messages *******************************************************************/
-
-"""
- ret += f"enum {idprefix}msg_type {{ /* uint8_t */\n"
- namewidth = max(len(msg.name) for msg in typs if isinstance(msg, Message))
- for msg in [msg for msg in typs if isinstance(msg, Message)]:
- ret += ifdef_push(1, c_ver_ifdef(msg.in_versions))
- ret += f"\t{idprefix.upper()}TYP_{msg.name.ljust(namewidth)} = {msg.msgid},\n"
- ret += ifdef_pop(0)
- ret += "};\n"
-
- for msg in [msg for msg in typs if isinstance(msg, Message)]:
- ret += "\n"
- ret += ifdef_push(1, c_ver_ifdef(msg.in_versions))
- ret += c_typename(msg) + " {"
- if not msg.members:
- ret += "};\n"
- continue
- ret += "\n"
-
- typewidth = max(len(c_typename(m.typ)) for m in msg.members)
-
- for member in msg.members:
- if member.val:
- continue
- ret += ifdef_push(2, c_ver_ifdef(member.in_versions))
- ret += f"\t{c_typename(member.typ).ljust(typewidth)} {'*' if member.cnt else ' '}{member.name};\n"
- ret += ifdef_pop(1)
- ret += "};\n"
- ret += ifdef_pop(0)
-
- return ret
-
-
-def c_expr(expr: Expr) -> str:
- ret: list[str] = []
- for tok in expr.tokens:
- match tok:
- case ExprOp():
- ret += [tok.op]
- case ExprLit():
- ret += [str(tok.val)]
- case ExprSym(name="end"):
- ret += ["ctx->net_offset"]
- case ExprSym():
- ret += [f"_{tok.name[1:]}_offset"]
- return " ".join(ret)
-
-
-def gen_c(versions: set[str], typs: list[Type]) -> str:
- global _ifdef_stack
- _ifdef_stack = []
-
- ret = f"""/* Generated by `{' '.join(sys.argv)}`. DO NOT EDIT! */
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stddef.h> /* for size_t */
-#include <inttypes.h> /* for PRI* macros */
-#include <string.h> /* for memset() */
-
-#include <lib9p/9p.h>
-
-#include "internal.h"
-"""
-
- def used(arg: str) -> str:
- return arg
-
- def unused(arg: str) -> str:
- return f"UNUSED({arg})"
-
- # strings ##################################################################
- ret += f"""
-/* strings ********************************************************************/
-
-static const char *version_strs[{c_ver_enum('NUM')}] = {{
-"""
- for ver in ["unknown", *sorted(versions)]:
- if ver in versions:
- ret += ifdef_push(1, c_ver_ifdef({ver}))
- ret += f'\t[{c_ver_enum(ver)}] = "{ver}",\n'
- ret += ifdef_pop(0)
- ret += "};\n"
- ret += f"""
-const char *{idprefix}version_str(enum {idprefix}version ver) {{
- assert(0 <= ver && ver < {c_ver_enum('NUM')});
- return version_strs[ver];
-}}
-"""
-
- # validate_* ###############################################################
- ret += """
-/* validate_* *****************************************************************/
-
-static ALWAYS_INLINE bool _validate_size_net(struct _validate_ctx *ctx, uint32_t n) {
- if (__builtin_add_overflow(ctx->net_offset, n, &ctx->net_offset))
- /* If needed-net-size overflowed uint32_t, then
- * there's no way that actual-net-size will live up to
- * that. */
- return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content");
- if (ctx->net_offset > ctx->net_size)
- return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content");
- return false;
-}
-
-static ALWAYS_INLINE bool _validate_size_host(struct _validate_ctx *ctx, size_t n) {
- if (__builtin_add_overflow(ctx->host_extra, n, &ctx->host_extra))
- /* If needed-host-size overflowed size_t, then there's
- * no way that actual-net-size will live up to
- * that. */
- return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content");
- return false;
-}
-
-static ALWAYS_INLINE bool _validate_list(struct _validate_ctx *ctx,
- size_t cnt,
- _validate_fn_t item_fn, size_t item_host_size) {
- for (size_t i = 0; i < cnt; i++)
- if (_validate_size_host(ctx, item_host_size) || item_fn(ctx))
- return true;
- return false;
-}
-
-#define validate_1(ctx) _validate_size_net(ctx, 1)
-#define validate_2(ctx) _validate_size_net(ctx, 2)
-#define validate_4(ctx) _validate_size_net(ctx, 4)
-#define validate_8(ctx) _validate_size_net(ctx, 8)
-"""
- for typ in typs:
- inline = "FLATTEN" if isinstance(typ, Message) else "ALWAYS_INLINE"
- argfn = unused if (isinstance(typ, Struct) and not typ.members) else used
- ret += "\n"
- ret += ifdef_push(1, c_ver_ifdef(typ.in_versions))
-
- if isinstance(typ, Bitfield):
- ret += f"static const {c_typename(typ)} {typ.name}_masks[{c_ver_enum('NUM')}] = {{\n"
- verwidth = max(len(ver) for ver in versions)
- for ver in sorted(versions):
- ret += ifdef_push(2, c_ver_ifdef({ver}))
- ret += (
- f"\t[{c_ver_enum(ver)}]{' '*(verwidth-len(ver))} = 0b"
- + "".join(
- "1" if typ.bit_is_valid(bitname, ver) else "0"
- for bitname in reversed(typ.bits)
- )
- + ",\n"
- )
- ret += ifdef_pop(1)
- ret += "};\n"
-
- ret += f"static {inline} bool validate_{typ.name}(struct _validate_ctx *{argfn('ctx')}) {{\n"
-
- if typ.name == "d": # SPECIAL
- # Optimize... maybe the compiler could figure out to do
- # this, but let's make it obvious.
- ret += "\tuint32_t base_offset = ctx->net_offset;\n"
- ret += "\tif (validate_4(ctx))\n"
- ret += "\t\treturn true;\n"
- ret += "\tuint32_t len = decode_u32le(&ctx->net_bytes[base_offset]);\n"
- ret += "\treturn _validate_size_net(ctx, len) || _validate_size_host(ctx, len);\n"
- ret += "}\n"
- continue
- if typ.name == "s": # SPECIAL
- # Add an extra nul-byte on the host, and validate UTF-8
- # (also, similar optimization to "d").
- ret += "\tuint32_t base_offset = ctx->net_offset;\n"
- ret += "\tif (validate_2(ctx))\n"
- ret += "\t\treturn true;\n"
- ret += "\tuint16_t len = decode_u16le(&ctx->net_bytes[base_offset]);\n"
- ret += "\tif (_validate_size_net(ctx, len) || _validate_size_host(ctx, ((size_t)len)+1))\n"
- ret += "\t\treturn true;\n"
- ret += "\tif (!is_valid_utf8_without_nul(&ctx->net_bytes[base_offset+2], len))\n"
- ret += '\t\treturn lib9p_error(ctx->ctx, LINUX_EBADMSG, "message contains invalid UTF-8");\n'
- ret += "\treturn false;\n"
- ret += "}\n"
- continue
-
- match typ:
- case Number():
- ret += f"\treturn validate_{typ.prim.name}(ctx);\n"
- case Bitfield():
- ret += f"\t if (validate_{typ.static_size}(ctx))\n"
- ret += "\t\treturn true;\n"
- ret += (
- f"\t{c_typename(typ)} mask = {typ.name}_masks[ctx->ctx->version];\n"
- )
- ret += f"\t{c_typename(typ)} val = decode_u{typ.static_size*8}le(&ctx->net_bytes[ctx->net_offset-{typ.static_size}]);\n"
- ret += f"\tif (val & ~mask)\n"
- ret += f'\t\treturn lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "unknown bits in {typ.name} bitfield: %#0{typ.static_size}"PRIx{typ.static_size*8}, val & ~mask);\n'
- ret += "\treturn false;\n"
- case Struct(): # and Message()
- if len(typ.members) == 0:
- ret += "\treturn false;\n"
- ret += "}\n"
- continue
-
- # Pass 1 - declare value variables
- for member in typ.members:
- if member.max or member.val:
- ret += ifdef_push(2, c_ver_ifdef(member.in_versions))
- ret += f"\t{c_typename(member.typ)} {member.name};\n"
- ret += ifdef_pop(1)
-
- # Pass 2 - declare offset variables
- mark_offset: set[str] = set()
- for member in typ.members:
- for tok in [*member.max.tokens, *member.val.tokens]:
- if isinstance(tok, ExprSym) and tok.name.startswith("&"):
- if tok.name[1:] not in mark_offset:
- ret += f"\tuint32_t _{tok.name[1:]}_offset;\n"
- mark_offset.add(tok.name[1:])
-
- # Pass 3 - main pass
- ret += "\treturn false\n"
- prev_size: int | None = None
- for member in typ.members:
- ret += ifdef_push(2, c_ver_ifdef(member.in_versions))
- ret += f"\t || "
- if member.in_versions != typ.in_versions:
- ret += "( " + c_ver_cond(member.in_versions) + " && "
- if member.cnt is not None:
- assert prev_size
- ret += f"_validate_list(ctx, decode_u{prev_size*8}le(&ctx->net_bytes[ctx->net_offset-{prev_size}]), validate_{member.typ.name}, sizeof({c_typename(member.typ)}))"
- else:
- if member.max or member.val:
- ret += "("
- if member.name in mark_offset:
- ret += f"({{ _{member.name}_offset = ctx->net_offset; "
- ret += f"validate_{member.typ.name}(ctx)"
- if member.name in mark_offset:
- ret += "; })"
- if member.max or member.val:
- bytes = member.static_size
- assert bytes
- bits = bytes * 8
- ret += f" || ({{ {member.name} = decode_u{bits}le(&ctx->net_bytes[ctx->net_offset-{bytes}]); false; }}))"
- if member.in_versions != typ.in_versions:
- ret += " )"
- ret += "\n"
- prev_size = member.static_size
-
- # Pass 4 - validate ,max= and ,val= constraints
- for member in typ.members:
- if member.max:
- ret += ifdef_push(2, c_ver_ifdef(member.in_versions))
- ret += f"\t || ({{ uint32_t max = {c_expr(member.max)}; (((uint32_t){member.name}) > max) &&\n"
- ret += f'\t lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "{member.name} value is too large (%"PRIu32" > %"PRIu32")", {member.name}, max); }})\n'
- if member.val:
- ret += ifdef_push(2, c_ver_ifdef(member.in_versions))
- ret += f"\t || ({{ uint32_t exp = {c_expr(member.val)}; (((uint32_t){member.name}) != exp) &&\n"
- ret += f'\t lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "{member.name} value is wrong (actual:%"PRIu32" != correct:%"PRIu32")", (uint32_t){member.name}, exp); }})\n'
-
- ret += ifdef_pop(1)
- ret += "\t ;\n"
- ret += "}\n"
- ret += ifdef_pop(0)
-
- # unmarshal_* ##############################################################
- ret += """
-/* unmarshal_* ****************************************************************/
-
-static ALWAYS_INLINE void unmarshal_1(struct _unmarshal_ctx *ctx, uint8_t *out) {
- *out = decode_u8le(&ctx->net_bytes[ctx->net_offset]);
- ctx->net_offset += 1;
-}
-
-static ALWAYS_INLINE void unmarshal_2(struct _unmarshal_ctx *ctx, uint16_t *out) {
- *out = decode_u16le(&ctx->net_bytes[ctx->net_offset]);
- ctx->net_offset += 2;
-}
-
-static ALWAYS_INLINE void unmarshal_4(struct _unmarshal_ctx *ctx, uint32_t *out) {
- *out = decode_u32le(&ctx->net_bytes[ctx->net_offset]);
- ctx->net_offset += 4;
-}
-
-static ALWAYS_INLINE void unmarshal_8(struct _unmarshal_ctx *ctx, uint64_t *out) {
- *out = decode_u64le(&ctx->net_bytes[ctx->net_offset]);
- ctx->net_offset += 8;
-}
-"""
- for typ in typs:
- inline = "FLATTEN" if isinstance(typ, Message) else "ALWAYS_INLINE"
- argfn = unused if (isinstance(typ, Struct) and not typ.members) else used
- ret += "\n"
- ret += ifdef_push(1, c_ver_ifdef(typ.in_versions))
- ret += f"static {inline} void unmarshal_{typ.name}(struct _unmarshal_ctx *{argfn('ctx')}, {c_typename(typ)} *out) {{\n"
- match typ:
- case Number():
- ret += f"\tunmarshal_{typ.prim.name}(ctx, ({c_typename(typ.prim)} *)out);\n"
- case Bitfield():
- ret += f"\tunmarshal_{typ.prim.name}(ctx, ({c_typename(typ.prim)} *)out);\n"
- case Struct():
- ret += "\tmemset(out, 0, sizeof(*out));\n"
-
- for member in typ.members:
- ret += ifdef_push(2, c_ver_ifdef(member.in_versions))
- if member.val:
- ret += f"\tctx->net_offset += {member.static_size};\n"
- continue
- ret += "\t"
-
- prefix = "\t"
- if member.in_versions != typ.in_versions:
- ret += "if ( " + c_ver_cond(member.in_versions) + " ) "
- prefix = "\t\t"
- if member.cnt:
- if member.in_versions != typ.in_versions:
- ret += "{\n"
- ret += prefix
- ret += f"out->{member.name} = ctx->extra;\n"
- ret += f"{prefix}ctx->extra += sizeof(out->{member.name}[0]) * out->{member.cnt};\n"
- ret += f"{prefix}for (typeof(out->{member.cnt}) i = 0; i < out->{member.cnt}; i++)\n"
- if typ.name in ["d", "s"]: # SPECIAL
- ret += f"{prefix}\tunmarshal_{member.typ.name}(ctx, (uint8_t *)&out->{member.name}[i]);\n"
- else:
- ret += f"{prefix}\tunmarshal_{member.typ.name}(ctx, &out->{member.name}[i]);\n"
- if member.in_versions != typ.in_versions:
- ret += "\t}\n"
- else:
- ret += (
- f"unmarshal_{member.typ.name}(ctx, &out->{member.name});\n"
- )
- if typ.name == "s": # SPECIAL
- ret += "\tctx->extra++;\n"
- ret += "\tout->utf8[out->len] = '\\0';\n"
- ret += ifdef_pop(1)
- ret += "}\n"
- ret += ifdef_pop(0)
-
- # marshal_* ################################################################
- ret += """
-/* marshal_* ******************************************************************/
-
-static ALWAYS_INLINE bool _marshal_too_large(struct _marshal_ctx *ctx) {
- lib9p_errorf(ctx->ctx, LINUX_ERANGE, "%s too large to marshal into %s limit (limit=%"PRIu32")",
- (ctx->net_bytes[4] % 2 == 0) ? "T-message" : "R-message",
- ctx->ctx->version ? "negotiated" : ((ctx->net_bytes[4] % 2 == 0) ? "client" : "server"),
- ctx->ctx->max_msg_size);
- return true;
-}
-
-static ALWAYS_INLINE bool marshal_1(struct _marshal_ctx *ctx, uint8_t *val) {
- if (ctx->net_offset + 1 > ctx->ctx->max_msg_size)
- return _marshal_too_large(ctx);
- ctx->net_bytes[ctx->net_offset] = *val;
- ctx->net_offset += 1;
- return false;
-}
-
-static ALWAYS_INLINE bool marshal_2(struct _marshal_ctx *ctx, uint16_t *val) {
- if (ctx->net_offset + 2 > ctx->ctx->max_msg_size)
- return _marshal_too_large(ctx);
- encode_u16le(*val, &ctx->net_bytes[ctx->net_offset]);
- ctx->net_offset += 2;
- return false;
-}
-
-static ALWAYS_INLINE bool marshal_4(struct _marshal_ctx *ctx, uint32_t *val) {
- if (ctx->net_offset + 4 > ctx->ctx->max_msg_size)
- return true;
- encode_u32le(*val, &ctx->net_bytes[ctx->net_offset]);
- ctx->net_offset += 4;
- return false;
-}
-
-static ALWAYS_INLINE bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) {
- if (ctx->net_offset + 8 > ctx->ctx->max_msg_size)
- return true;
- encode_u64le(*val, &ctx->net_bytes[ctx->net_offset]);
- ctx->net_offset += 8;
- return false;
-}
-"""
- for typ in typs:
- inline = "FLATTEN" if isinstance(typ, Message) else "ALWAYS_INLINE"
- argfn = unused if (isinstance(typ, Struct) and not typ.members) else used
- ret += "\n"
- ret += ifdef_push(1, c_ver_ifdef(typ.in_versions))
- ret += f"static {inline} bool marshal_{typ.name}(struct _marshal_ctx *{argfn('ctx')}, {c_typename(typ)} *{argfn('val')}) {{\n"
- match typ:
- case Number():
- ret += f"\treturn marshal_{typ.prim.name}(ctx, ({c_typename(typ.prim)} *)val);\n"
- case Bitfield():
- ret += f"\t{c_typename(typ)} masked_val = *val & {typ.name}_masks[ctx->ctx->version];\n"
- ret += f"\treturn marshal_{typ.prim.name}(ctx, ({c_typename(typ.prim)} *)&masked_val);\n"
- case Struct():
- if len(typ.members) == 0:
- ret += "\treturn false;\n"
- ret += "}\n"
- continue
-
- # Pass 1 - declare offset variables
- mark_offset = set()
- for member in typ.members:
- if member.val:
- if member.name not in mark_offset:
- ret += f"\tuint32_t _{member.name}_offset;\n"
- mark_offset.add(member.name)
- for tok in member.val.tokens:
- if isinstance(tok, ExprSym) and tok.name.startswith("&"):
- if tok.name[1:] not in mark_offset:
- ret += f"\tuint32_t _{tok.name[1:]}_offset;\n"
- mark_offset.add(tok.name[1:])
-
- # Pass 2 - main pass
- ret += "\treturn false\n"
- for member in typ.members:
- ret += ifdef_push(2, c_ver_ifdef(member.in_versions))
- ret += "\t || "
- if member.in_versions != typ.in_versions:
- ret += "( " + c_ver_cond(member.in_versions) + " && "
- if member.name in mark_offset:
- ret += f"({{ _{member.name}_offset = ctx->net_offset; "
- if member.cnt:
- ret += "({ bool err = false;\n"
- ret += f"\t for (typeof(val->{member.cnt}) i = 0; i < val->{member.cnt} && !err; i++)\n"
- ret += "\t \terr = "
- if typ.name in ["d", "s"]: # SPECIAL
- # Special-case is that we cast from `char` to `uint8_t`.
- ret += f"marshal_{member.typ.name}(ctx, (uint8_t *)&val->{member.name}[i]);\n"
- else:
- ret += f"marshal_{member.typ.name}(ctx, &val->{member.name}[i]);\n"
- ret += f"\t err; }})"
- elif member.val:
- # Just increment net_offset, don't actually marsha anything (yet).
- assert member.static_size
- ret += (
- f"({{ ctx->net_offset += {member.static_size}; false; }})"
- )
- else:
- ret += f"marshal_{member.typ.name}(ctx, &val->{member.name})"
- if member.name in mark_offset:
- ret += "; })"
- if member.in_versions != typ.in_versions:
- ret += " )"
- ret += "\n"
-
- # Pass 3 - marshal ,val= members
- for member in typ.members:
- if member.val:
- assert member.static_size
- ret += ifdef_push(2, c_ver_ifdef(member.in_versions))
- ret += f"\t || ({{ encode_u{member.static_size*8}le({c_expr(member.val)}, &ctx->net_bytes[_{member.name}_offset]); false; }})\n"
-
- ret += ifdef_pop(1)
- ret += "\t ;\n"
- ret += "}\n"
- ret += ifdef_pop(0)
-
- # tables / exports #########################################################
- ret += f"""
-/* tables / exports ***********************************************************/
-
-#define _MSG(typ) [{idprefix.upper()}TYP_##typ] = {{ \\
- .name = #typ, \\
- .basesize = sizeof(struct {idprefix}msg_##typ), \\
- .validate = validate_##typ, \\
- .unmarshal = (_unmarshal_fn_t)unmarshal_##typ, \\
- .marshal = (_marshal_fn_t)marshal_##typ, \\
- }}
-#define _NONMSG(num) [num] = {{ \\
- .name = #num, \\
- }}
-
-struct _table_version _{idprefix}versions[{c_ver_enum('NUM')}] = {{
-"""
- id2typ: dict[int, Message] = {}
- for msg in [msg for msg in typs if isinstance(msg, Message)]:
- id2typ[msg.msgid] = msg
-
- for ver in ["unknown", *sorted(versions)]:
- if ver != "unknown":
- ret += ifdef_push(1, c_ver_ifdef({ver}))
- ret += f"\t[{c_ver_enum(ver)}] = {{ .msgs = {{\n"
-
- for n in range(0, 0x100):
- xmsg: Message | None = id2typ.get(n, None)
- if xmsg:
- if ver == "unknown": # SPECIAL
- if xmsg.name not in ["Tversion", "Rversion", "Rerror"]:
- xmsg = None
- else:
- if ver not in xmsg.in_versions:
- xmsg = None
- if xmsg:
- ret += f"\t\t_MSG({xmsg.name}),\n"
- else:
- ret += "\t\t_NONMSG(0x{:02X}),\n".format(n)
- ret += "\t}},\n"
- ret += ifdef_pop(0)
- ret += "};\n"
-
- ret += f"""
-FLATTEN bool _{idprefix}validate_stat(struct _validate_ctx *ctx) {{
- return validate_stat(ctx);
-}}
-FLATTEN void _{idprefix}unmarshal_stat(struct _unmarshal_ctx *ctx, struct lib9p_stat *out) {{
- unmarshal_stat(ctx, out);
-}}
-FLATTEN bool _{idprefix}marshal_stat(struct _marshal_ctx *ctx, struct lib9p_stat *val) {{
- return marshal_stat(ctx, val);
-}}
-"""
-
- ############################################################################
- return ret
-
-
-################################################################################
-
-
-class Parser:
- cache: dict[str, tuple[str, list[Type]]] = {}
-
- def parse_file(self, filename: str) -> tuple[str, list[Type]]:
- filename = os.path.normpath(filename)
- if filename not in self.cache:
-
- def get_include(other_filename: str) -> tuple[str, list[Type]]:
- return self.parse_file(os.path.join(filename, "..", other_filename))
-
- self.cache[filename] = parse_file(filename, get_include)
- return self.cache[filename]
-
- def all(self) -> tuple[set[str], list[Type]]:
- ret_versions: set[str] = set()
- ret_typs: dict[str, Type] = {}
- for version, typs in self.cache.values():
- if version in ret_versions:
- raise ValueError(f"duplicate protocol version {repr(version)}")
- ret_versions.add(version)
- for typ in typs:
- if typ.name in ret_typs:
- if typ != ret_typs[typ.name]:
- raise ValueError(f"duplicate type name {repr(typ.name)}")
- else:
- ret_typs[typ.name] = typ
- return ret_versions, list(ret_typs.values())
-
-
-if __name__ == "__main__":
- import sys
-
- if len(sys.argv) < 2:
- raise ValueError("requires at least 1 .9p filename")
- parser = Parser()
- for txtname in sys.argv[1:]:
- parser.parse_file(txtname)
- versions, typs = parser.all()
- outdir = os.path.normpath(os.path.join(sys.argv[0], ".."))
- with open(os.path.join(outdir, "include/lib9p/9p.generated.h"), "w") as fh:
- fh.write(gen_h(versions, typs))
- with open(os.path.join(outdir, "9p.generated.c"), "w") as fh:
- fh.write(gen_c(versions, typs))
diff --git a/lib9p/idl/0000-README.md b/lib9p/idl/0000-README.md
index cec27e2..84cf865 100644
--- a/lib9p/idl/0000-README.md
+++ b/lib9p/idl/0000-README.md
@@ -1,7 +1,7 @@
<!--
- 0000-README.md - Overview of 9P protocol definitions
+ lib9p/idl/0000-README.md - Overview of 9P protocol definitions
- Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
@@ -17,35 +17,82 @@ client->server requests, and R-messages are server->client responses
type of a message is represented by a u8 ID; T-messages are even and
R-messages are odd.
-Messages are made up of the primitives; unsigned little-endian
-integers, identified with the following single-character mnemonics:
+9P messages are exchanged over a reliable bidirectional in-order octet
+stream. Messages are made up of the primitives; unsigned
+little-endian integers, identified with the following single-character
+mnemonics:
- 1 = u8
- 2 = u16le
- 4 = u32le
- 8 = u16le
-Out of these primitives, we can make other numeric types,
+Out of these primitives, we can make more complex types:
+
+## User-defined types
+
+### Numeric types
num NUMNAME = PRIMITIVE_TYPE
+ "NAME=VAL"...
+
+Besides just being an alias for a primitive type, a numeric type may
+define 0 or more named constants of that type, each wrapped in
+"quotes".
+
+### Bitfields
+
+ bitfield BFNAME = PRIMITIVE_TYPE
+ "bit NBIT=NAME"...
+ "bit NBIT=reserved(NAME)"...
+ "bit NBIT=num(NUMNAME)"...
+ "alias NAME=VAL"...
+ "mask NAME=VAL"...
+ "num(NUMNAME) NAME=VAL"...
-bitfields,
+The same NBIT may not be defined multiple times. The same NAME may
+not be defined multiple times.
- bitfield BFNAME = PRIMITIVE_TYPE "NBIT=NAME... ALIAS=VAL..."
+ - A `reserved(...)` bit indicates that the bit is named but is not
+ allowed to be used.
+ - `num(...)` bits embed a numeric/enumerated field within a set of
+ bits. Once several bits have been allocated to a numeric field
+ with `bit NBIT=num(NUMNAME)`, constant values for that field may be
+ declared with `num(NUMNAME) NAME=VAL`. For each numeric field, a
+ `mask NUMNAME=BITMASK` is automatically declared.
+ - A `mask` defines a bitmask that selects several bits.
+ - An `alias` defines a convenience alias for a bit or set of bits.
-structures,
+### Structures
- struct STRUCTNAME = "FILENAME[FIELDTYPE]..."
+ struct STRUCTNAME = "FIELDNAME[FIELDTYPE]..."
-and messages (which are a special-case of structures).
+Or a special-case for structs that are messages; `msg` has the same
+syntax as `struct`, but has restrictions on the STRUCTNAME and the
+first 3 fields must all be declared in the same way:
msg Tname = "size[4,val=end-&size] typ[1,val=TYP] tag[tag] REST..."
Struct fields that have numeric types (either primitives or `num`
types) can add to their type `,val=` and/or `,max=` to specify what
the exact value must be and/or what the maximum (inclusive) value is.
+A field that is repeated a variable number of times be wrapped in
+parenthesis and prefixed with the fieldname containing that count:
+`OTHERFIELDNAME*(FIELDNAME[FIELDTYPE])`.
`,val=` and `,max` take a string of `+`/`-` tokens and values; a value
-can either be a decimal numeric constant (eg: `107`), the `&fieldname`
-to refer to the offset of a field name in that struct, or the special
-value `end` to refer to the offset of the end of the struct.
+can be
+ - a decimal numeric constant (eg: `107`),
+ - `&fieldname` to refer to the offset of a field name in that struct,
+ - the special value `end` to refer to the offset of the end of the
+ struct,
+ - the special value `u{8,16,32,64}_max` to refer to the constant
+ value `(1<<{n})-1`, or
+ - the special value `s{8,16,32,64}_max` to refer to the constant value
+ `(1<<({n}-1))-1`.
+
+## Parser
+
+A parser for this syntax is given in `__init__.py`. However,
+`__init__.py` places the somewhat arbitrary undocumented restrictions
+on fields referenced as the count of a repeated field.
diff --git a/lib9p/idl/0000-TODO.md b/lib9p/idl/0000-TODO.md
new file mode 100644
index 0000000..e52902f
--- /dev/null
+++ b/lib9p/idl/0000-TODO.md
@@ -0,0 +1,11 @@
+<!--
+ lib9p/idl/0000-TODO.md - Changes I intend to make to idl/__init__.py
+ and proto.gen
+
+ Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ SPDX-License-Identifier: AGPL-3.0-or-later
+ -->
+
+- Decide how to handle duplicate type names from different versions
+- Decide how to handle duplicate `enum lib9p_msg_type` names and
+ values
diff --git a/lib9p/idl/1992-9P0.9p.wip b/lib9p/idl/1992-9P0.9p.wip
index 4278fa3..c9432c9 100644
--- a/lib9p/idl/1992-9P0.9p.wip
+++ b/lib9p/idl/1992-9P0.9p.wip
@@ -1,9 +1,22 @@
-# 1992-9P0.9p - Definitions of 9P0 (Plan 9 1st ed) messages
+# lib9p/idl/1992-9P0.9p - Definitions of 9P0 (Plan 9 1st ed) messages
#
-# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
-# https://man.cat-v.org/plan_9_1st_ed/5/
+# The original 9P protocol ("9P0"), from Plan 9 1st edition.
+#
+# Documentation:
+# - https://github.com/plan9foundation/plan9/tree/1e-1993-01-03/sys/man/5
+# - https://github.com/plan9foundation/plan9/tree/1e-1993-01-03/sys/man/6/auth
+# - https://man.cat-v.org/plan_9_1st_ed/5/
+# - https://man.cat-v.org/plan_9_1st_ed/6/auth
+#
+# Implementation references:
+# - https://github.com/plan9foundation/plan9/blob/1e-1993-01-03/sys/include/fcall.h (MAXFDATA)
+# - https://github.com/plan9foundation/plan9/blob/1e-1993-01-03/sys/include/libc.h (`ch` bits)
+# - https://github.com/plan9foundation/plan9/blob/1e-1993-01-03/sys/src/fs/port/fcall.c (`stat`)
+# - https://github.com/plan9foundation/plan9/blob/1e-1993-01-03/sys/src/fs/port/fs.c (`offset:max`)
+# - https://github.com/plan9foundation/plan9/blob/1e-1993-01-03/sys/src/fs/port/portdata.h (MAXDAT)
version "9P0"
# tag - identify a request/response pair
@@ -15,39 +28,114 @@ num fid = 2
# uni"Q"ue "ID"entification
struct qid = "path[4] version[4]"
-# a nul-padded string
-struct name = 28*(txt[1])
-
-msg Tnop = "typ[1,val=TODO] tag[tag,val=0xFFFF]"
-msg Rnop = "typ[1,val=TODO] tag[tag,val=0xFFFF]"
-msg Tsession = "typ[1,val=TODO] tag[tag,val=0xFFFF]"
-msg Rsession = "typ[1,val=TODO] tag[tag,val=0xFFFF]"
-msg Rerror = "typ[1,val=TODO] tag[tag] ename[64]"
-msg Tflush = "typ[1,val=TODO] tag[tag] oldtag[tag]"
-msg Rflush = "typ[1,val=TODO] tag[tag]"
-msg Tauth = "typ[1,val=TODO] tag[tag] fid[fid] uid[28] chal[36]"
-msg Rauth = "typ[1,val=TODO] tag[tag] fid[fid] chal[30]"
-msg Tattach = "typ[1,val=TODO] tag[tag] fid[fid] uid[28] aname[28] auth[28]"
-msg Rattach = "typ[1,val=TODO] tag[tag] fid[fid] qid[8]"
-msg Tclone = "typ[1,val=TODO] tag[tag] fid[fid] newfid[fid]"
-msg Rclone = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Tclwalk = "typ[1,val=TODO] tag[tag] fid[fid] newfid[fid] name[28]"
-msg Rclwalk = "typ[1,val=TODO] tag[tag] fid[fid] qid[8]"
-msg Twalk = "typ[1,val=TODO] tag[tag] fid[fid] name[28]"
-msg Rwalk = "typ[1,val=TODO] tag[tag] fid[fid] qid[8]"
-msg Topen = "typ[1,val=TODO] tag[tag] fid[fid] mode[1]"
-msg Ropen = "typ[1,val=TODO] tag[tag] fid[fid] qid[8]"
-msg Tcreate = "typ[1,val=TODO] tag[tag] fid[fid] name[28] perm[4] mode[1]"
-msg Rcreate = "typ[1,val=TODO] tag[tag] fid[fid] qid[8]"
-msg Tread = "typ[1,val=TODO] tag[tag] fid[fid] offset[8] count[2,max=8192]"
-msg Rread = "typ[1,val=TODO] tag[tag] fid[fid] count[2,max=8192] pad[1] count*(data[1])"
-msg Twrite = "typ[1,val=TODO] tag[tag] fid[fid] offset[8] count[2,max=8192] pad[1] count*(data[1])"
-msg Rwrite = "typ[1,val=TODO] tag[tag] fid[fid] count[2,max=8192]"
-msg Tclunk = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Rclunk = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Tremove = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Rremove = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Tstat = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Rstat = "typ[1,val=TODO] tag[tag] fid[fid] stat[116]"
-msg Twstat = "typ[1,val=TODO] tag[tag] fid[fid] stat[116]"
-msg Rwstat = "typ[1,val=TODO] tag[tag] fid[fid]"
+# a nul-terminated+padded string
+struct name = "28*(txt[1])"
+
+# a nul-terminated+padded string
+struct errstr = "64*(txt[1])"
+
+# "O"pen flags (flags to pass to Topen and Tcreate)
+# Unused bits are *ignored*.
+bitfield o = 1
+ "bit 0=num(MODE)" # low bit of the 2-bit READ/WRITE/RDWR/EXEC enum
+ "bit 1=num(MODE)" # high bit of the 2-bit READ/WRITE/RDWR/EXEC enum
+ #"bit 2=unused"
+ #"bit 3=unused"
+ "bit 4=TRUNC"
+ "bit 5=reserved(CEXEC)" # close-on-exec
+ "bit 6=RCLOSE" # remove-on-close
+ #"bit 7=unused"
+
+ "num(MODE) READ = 0" # make available for this FID: Tread()
+ "num(MODE) WRITE = 1" # make available for this FID: Twrite()
+ "num(MODE) RDWR = 2" # make available for this FID: Tread() and Twrite()
+ "num(MODE) EXEC = 3" # make available for this FID: Tread()
+
+ "mask FLAG = 0b11111100"
+
+# "CH"annel flags - file permissions and attributes (a "channel" is
+# what a file handle is called inside of the Plan 9 kernel).
+bitfield ch = 4
+ "bit 31=DIR"
+ "bit 30=APPEND"
+ "bit 29=EXCL"
+ #...
+ "bit 8=OWNER_R"
+ "bit 7=OWNER_W"
+ "bit 6=OWNER_X"
+ "bit 5=GROUP_R"
+ "bit 4=GROUP_W"
+ "bit 3=GROUP_X"
+ "bit 2=OTHER_R"
+ "bit 1=OTHER_W"
+ "bit 0=OTHER_X"
+
+ "mask PERM=0777" # {OWNER,GROUP,OTHER}_{R,W,X}
+
+struct stat = "file_name[name]"
+ "file_owner[name]"
+ "file_group[name]"
+ "file_qid[qid]"
+ "file_mode[ch]"
+ "file_atime[4]"
+ "file_mtime[4]"
+ "file_size[8]"
+ "kern_type[2]"
+ "kern_dev[2]"
+
+# Authentication uses symetric-key encryption, using a per-client
+# secret-key. The encryption scheme is beyond the scope of this
+# document.
+struct auth_ticket = "15*(dat[1])"
+struct encrypted_auth_challenge = "36*(ciphertext[1])"
+struct cleartext_auth_challenge = "magic[1,val=1] 7*(client_challenge[1]) server[name]"
+struct encrypted_auth_response = "30*(ciphertext[1])"
+struct cleartext_auth_response = "magic[1,val=4] 7*(client_challenge[1]) ticket[auth_ticket]"
+
+# A 9P0 session goes:
+#
+# [nop()]
+# session()
+# [auth_tok=auth()]
+# attach([auth_tok])
+# ...
+
+msg Tmux = "typ[1,val=48] mux[2]" # Undocumented, but implemented by mux(3) / libmux.a
+#msg Rmux = "typ[1,val=49] illegal"
+msg Tnop = "typ[1,val=50] tag[tag,val=0xFFFF]"
+msg Rnop = "typ[1,val=51] tag[tag,val=0xFFFF]"
+msg Tsession = "typ[1,val=52] tag[tag,val=0xFFFF]"
+msg Rsession = "typ[1,val=53] tag[tag,val=0xFFFF]"
+#msg Terror = "typ[1,val=54] illegal"
+msg Rerror = "typ[1,val=55] tag[tag] errstr[errstr]"
+msg Tflush = "typ[1,val=56] tag[tag] oldtag[tag]"
+msg Rflush = "typ[1,val=57] tag[tag]"
+msg Tattach = "typ[1,val=58] tag[tag] fid[fid] uid[name] aname[name] auth[auth_ticket] 13*(pad[1])" # Pad to allow auth_tickets up to 28 bytes.
+msg Rattach = "typ[1,val=59] tag[tag] fid[fid] qid[qid]"
+msg Tclone = "typ[1,val=60] tag[tag] fid[fid] newfid[fid]"
+msg Rclone = "typ[1,val=61] tag[tag] fid[fid]"
+msg Twalk = "typ[1,val=62] tag[tag] fid[fid] name[name]"
+msg Rwalk = "typ[1,val=63] tag[tag] fid[fid] qid[qid]"
+msg Topen = "typ[1,val=64] tag[tag] fid[fid] mode[o]"
+msg Ropen = "typ[1,val=65] tag[tag] fid[fid] qid[qid]"
+msg Tcreate = "typ[1,val=66] tag[tag] fid[fid] name[name] perm[ch] mode[o]"
+msg Rcreate = "typ[1,val=67] tag[tag] fid[fid] qid[qid]"
+# For `count:max`, see 1e/2e/3e `sys/include/fcall.h:MAXFDATA` or 1e/2e `sys/src/fs/port/portdata.h:MAXDAT`.
+# For read `offset:max`, see 1e/2e/3e `sys/src/fs/port/fs.c:f_read()` or 3e `sys/src/lib9p/srv.c:srv():case Tread`.
+# For write `offset:max`, see 1e/2e/3e `sys/src/fs/port/fs.c:f_write()`.
+msg Tread = "typ[1,val=68] tag[tag] fid[fid] offset[8,max=s64_max] count[2,max=8192]"
+msg Rread = "typ[1,val=69] tag[tag] fid[fid] count[2,max=8192] pad[1] count*(data[1])"
+msg Twrite = "typ[1,val=70] tag[tag] fid[fid] offset[8,max=s64_max] count[2,max=8192] pad[1] count*(data[1])"
+msg Rwrite = "typ[1,val=71] tag[tag] fid[fid] count[2,max=8192]"
+msg Tclunk = "typ[1,val=72] tag[tag] fid[fid]"
+msg Rclunk = "typ[1,val=73] tag[tag] fid[fid]"
+msg Tremove = "typ[1,val=74] tag[tag] fid[fid]"
+msg Rremove = "typ[1,val=75] tag[tag] fid[fid]"
+msg Tstat = "typ[1,val=76] tag[tag] fid[fid]"
+msg Rstat = "typ[1,val=77] tag[tag] fid[fid] stat[stat]"
+msg Twstat = "typ[1,val=78] tag[tag] fid[fid] stat[stat]"
+msg Rwstat = "typ[1,val=79] tag[tag] fid[fid]"
+msg Tclwalk = "typ[1,val=80] tag[tag] fid[fid] newfid[fid] name[name]"
+msg Rclwalk = "typ[1,val=81] tag[tag] fid[fid] qid[qid]"
+msg Tauth = "typ[1,val=82] tag[tag] fid[fid] uid[name] chal[encrypted_auth_challenge]" # chal is an encrypted
+msg Rauth = "typ[1,val=83] tag[tag] fid[fid] chal[encrypted_auth_response]"
diff --git a/lib9p/idl/1995-9P1.9p.wip b/lib9p/idl/1995-9P1.9p.wip
index 55814d4..660e24a 100644
--- a/lib9p/idl/1995-9P1.9p.wip
+++ b/lib9p/idl/1995-9P1.9p.wip
@@ -1,52 +1,107 @@
-# 1995-9P1.9p - Definitions of 9P1 (Plan 9 2nd ed and 3rd ed) messages
+# lib9p/idl/1995-9P1.9p - Definitions of 9P1 (Plan 9 2nd ed and 3rd ed) messages
#
-# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
-# https://man.cat-v.org/plan_9_2nd_ed/5/
-# https://man.cat-v.org/plan_9_3rd_ed/5/
+# Plan 9 2nd and 3rd edition used a version of 9P lightly revised from
+# the 1st edition version, re-thinking authentication.
+#
+# 2nd edition documentation:
+# - https://github.com/plan9foundation/plan9/tree/2e-1995-04-05/sys/man/5
+# - https://github.com/plan9foundation/plan9/tree/2e-1995-04-05/sys/man/6/auth
+# - https://man.cat-v.org/plan_9_2nd_ed/5/
+# - https://man.cat-v.org/plan_9_2nd_ed/6/auth
+#
+# 2nd edition implementation references:
+# - https://github.com/plan9foundation/plan9/blob/2e-1995-04-05/sys/include/fcall.h (MAXFDATA)
+# - https://github.com/plan9foundation/plan9/blob/2e-1995-04-05/sys/include/libc.h (`ch` bits)
+# - https://github.com/plan9foundation/plan9/blob/2e-1995-04-05/sys/include/auth.h (auth matic)
+# - https://github.com/plan9foundation/plan9/blob/2e-1995-04-05/sys/src/fs/port/fcall.c (`stat`)
+# - https://github.com/plan9foundation/plan9/blob/2e-1995-04-05/sys/src/fs/port/fs.c (`offset:max`)
+# - https://github.com/plan9foundation/plan9/blob/2e-1995-04-05/sys/src/fs/port/portdata.h (`MAXDAT`)
+# - https://github.com/plan9foundation/plan9/blob/2e-1995-04-05/sys/src/libauth/convM2T.c (`auth_ticket`)
+#
+# 3rd edition documentation:
+# - https://github.com/plan9foundation/plan9/tree/3e-2001-03-28/sys/man/5
+# - https://github.com/plan9foundation/plan9/tree/3e-2001-03-28/sys/man/6/auth
+# - https://man.cat-v.org/plan_9_3rd_ed/5/
+# - https://man.cat-v.org/plan_9_3rd_ed/6/auth
+#
+# 3rd edition implementation references:
+# - https://github.com/plan9foundation/plan9/blob/3e-2001-03-28/sys/include/fcall.h (MAXFDATA)
+# - https://github.com/plan9foundation/plan9/blob/3e-2001-03-28/sys/include/libc.h (`ch` bits)
+# - https://github.com/plan9foundation/plan9/blob/3e-2001-03-28/sys/include/auth.h (auth magic)
+# - https://github.com/plan9foundation/plan9/blob/3e-2001-03-28/sys/src/fs/port/fcall.c (`stat`)
+# - https://github.com/plan9foundation/plan9/blob/3e-2001-03-28/sys/src/fs/port/fs.c (`offset:max`)
+# - https://github.com/plan9foundation/plan9/blob/3e-2001-03-28/sys/src/lib9p/srv.c (read `offset:max`)
+# - https://github.com/plan9foundation/plan9/blob/3e-2001-03-28/sys/src/libauth/convM2T.c (`auth_ticket`)
version "9P1"
-# tag - identify a request/response pair
-num tag = 2
+from ./1992-9P0.9p import tag, fid, qid, name, errstr, o, ch, stat
-# file identifier - like a UNIX file-descriptor
-num fid = 2
+# CHMOUNT is undocumented (and is explicitly excluded from the 9P2000
+# draft RFC). As I understand it, CHMOUNT indicates that the file is
+# mounted by the kernel as a 9P transport; that the kernel has a lock
+# on doing I/O on it, so userspace can't do I/O on it.
+bitfield ch += "bit 28=_PLAN9_MOUNT"
-# uni"Q"ue "ID"entification
-struct qid = "path[4] version[4]"
+# Authentication uses DES encryption. The client obtains a ticket and
+# a nonce-key from a separate auth-server; how it does this is beyond
+# the scope of this document.
+struct random = "8*(dat[1])"
+struct domain_name = "48*(txt[1])"
+struct des_key = "7*(dat[1])"
+struct encrypted_ticket = "72*(ciphertext[1])" # encrypted by auth-server with server-key
+struct cleartext_ticket = "magic[1,val=64] server_chal[random] client_uid[name] server_uid[name] nonce_key[des_key]"
+struct encrypted_authenticator_challenge = "13*(ciphertext[1])" # encrypted by client with nonce-key obtained from auth-server
+struct cleartext_authenticator_challenge = "magic[1,val=66] server_chal[random] replay_count[4]"
+struct encrypted_authenticator_response = "13*(ciphertext[1])" # encrypted by server with nonce-key obtained from ticket
+struct cleartext_authenticator_response = "magic[1,val=67] client_chal[random] replay_count[4]"
-# a nul-padded string
-struct name = 28*(txt[1])
+# A 9P0 session goes:
+#
+# [nop()]
+# auth_tok=[session()]
+# attach(auth_tok)
+# ...
-msg Tnop = "typ[1,val=TODO] tag[tag,val=0xFFFF]"
-msg Rnop = "typ[1,val=TODO] tag[tag,val=0xFFFF]"
-msg Tsession = "typ[1,val=TODO] tag[tag,val=0xFFFF] chal[8]"
-msg Rsession = "typ[1,val=TODO] tag[tag,val=0xFFFF] chal[8] authid[28] authdom[48]"
-msg Rerror = "typ[1,val=TODO] tag[tag] ename[64]"
-msg Tflush = "typ[1,val=TODO] tag[tag] oldtag[tag]"
-msg Rflush = "typ[1,val=TODO] tag[tag]"
-msg Tattach = "typ[1,val=TODO] tag[tag] fid[fid] uid[28] aname[28] ticket[72] auth[13]"
-msg Rattach = "typ[1,val=TODO] tag[tag] fid[fid] qid[8] rauth[13]"
-msg Tclone = "typ[1,val=TODO] tag[tag] fid[fid] newfid[fid]"
-msg Rclone = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Tclwalk = "typ[1,val=TODO] tag[tag] fid[fid] newfid[fid] name[28]"
-msg Rclwalk = "typ[1,val=TODO] tag[tag] fid[fid] qid[8]"
-msg Twalk = "typ[1,val=TODO] tag[tag] fid[fid] name[28]"
-msg Rwalk = "typ[1,val=TODO] tag[tag] fid[fid] qid[8]"
-msg Topen = "typ[1,val=TODO] tag[tag] fid[fid] mode[1]"
-msg Ropen = "typ[1,val=TODO] tag[tag] fid[fid] qid[8]"
-msg Tcreate = "typ[1,val=TODO] tag[tag] fid[fid] name[28] perm[4] mode[1]"
-msg Rcreate = "typ[1,val=TODO] tag[tag] fid[fid] qid[8]"
-msg Tread = "typ[1,val=TODO] tag[tag] fid[fid] offset[8] count[2,max=8192]"
-msg Rread = "typ[1,val=TODO] tag[tag] fid[fid] count[2,max=8192] pad[1] count*(data[1])"
-msg Twrite = "typ[1,val=TODO] tag[tag] fid[fid] offset[8] count[2,max=8192] pad[1] count*(data[1])"
-msg Rwrite = "typ[1,val=TODO] tag[tag] fid[fid] count[2,max=8192]"
-msg Tclunk = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Rclunk = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Tremove = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Rremove = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Tstat = "typ[1,val=TODO] tag[tag] fid[fid]"
-msg Rstat = "typ[1,val=TODO] tag[tag] fid[fid] stat[116]"
-msg Twstat = "typ[1,val=TODO] tag[tag] fid[fid] stat[116]"
-msg Rwstat = "typ[1,val=TODO] tag[tag] fid[fid]"
+#from ./1992-9P0.9p import Tmux # typ=48 ; removed
+#from ./1992-9P0.9p import Rmux # typ=49 ; removed
+from ./1992-9P0.9p import Tnop # typ=50
+from ./1992-9P0.9p import Rnop # typ=51
+#from ./1992-9P0.9p import Tsession # typ=52 ; revised, now has typ=84
+#from ./1992-9P0.9p import Rsession # typ=53 ; revised, now has typ=85
+#from ./1992-9P0.9p import Terror # typ=54 ; never existed
+from ./1992-9P0.9p import Rerror # typ=55
+from ./1992-9P0.9p import Tflush # typ=56
+from ./1992-9P0.9p import Rflush # typ=57
+#from ./1992-9P0.9p import Tattach # typ=58 ; revised, now has typ=86
+#from ./1992-9P0.9p import Rattach # typ=59 ; revised, now has typ=87
+from ./1992-9P0.9p import Tclone # typ=60
+from ./1992-9P0.9p import Rclone # typ=61
+from ./1992-9P0.9p import Twalk # typ=62
+from ./1992-9P0.9p import Rwalk # typ=63
+from ./1992-9P0.9p import Topen # typ=64
+from ./1992-9P0.9p import Ropen # typ=65
+from ./1992-9P0.9p import Tcreate # typ=66
+from ./1992-9P0.9p import Rcreate # typ=67
+from ./1992-9P0.9p import Tread # typ=68
+from ./1992-9P0.9p import Rread # typ=69
+from ./1992-9P0.9p import Twrite # typ=70
+from ./1992-9P0.9p import Rwrite # typ=71
+from ./1992-9P0.9p import Tclunk # typ=72
+from ./1992-9P0.9p import Rclunk # typ=73
+from ./1992-9P0.9p import Tremove # typ=74
+from ./1992-9P0.9p import Rremove # typ=75
+from ./1992-9P0.9p import Tstat # typ=76
+from ./1992-9P0.9p import Rstat # typ=77
+from ./1992-9P0.9p import Twstat # typ=78
+from ./1992-9P0.9p import Rwstat # typ=79
+from ./1992-9P0.9p import Tclwalk # typ=80
+from ./1992-9P0.9p import Rclwalk # typ=81
+#from ./1992-9P0.9p import Tauth # typ=82 ; merged into Tsession
+#from ./1992-9P0.9p import Rauth # typ=83 ; merged into Rsession
+msg Tsession = "typ[1,val=84] tag[tag,val=0xFFFF] chal[random]"
+msg Rsession = "typ[1,val=85] tag[tag,val=0xFFFF] chal[random] server_name[name] server_domain[domain_name]"
+msg Tattach = "typ[1,val=86] tag[tag] fid[fid] uid[name] aname[name] ticket[encrypted_ticket] auth[encrypted_authenticator_challenge]"
+msg Rattach = "typ[1,val=87] tag[tag] fid[fid] qid[qid] rauth[encrypted_authenticator_response]"
diff --git a/lib9p/idl/1996-Styx.9p.wip b/lib9p/idl/1996-Styx.9p.wip
index 2feb24f..143be83 100644
--- a/lib9p/idl/1996-Styx.9p.wip
+++ b/lib9p/idl/1996-Styx.9p.wip
@@ -1,15 +1,59 @@
-# 1996-Styx.9p - Definitions of Styx messages
+# lib9p/idl/1996-Styx.9p - Definitions of Styx messages
#
-# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
# Styx was a variant of the 9P protocol used by the Inferno operating
-# system. Message framing looks like 9P1 (1995), but semantics look
-# more like 9P2000 (2002). I am not sure whether there are Styx
-# protocol differences between Inferno 1e, 2e, or 3e (4e adopted
-# 9P2000).
-#
-# - 1996 beta
-# - 1997 1.0
-# - 1999 2nd ed
-# - 2001 3rd ed
+# system (before it switched to 9P2000 in 4th edition). It looks
+# exactly like 9P1 but with different message-type numbers and without
+# `clwalk` or `session`, and no authentication in `attach`.
+#
+# There do not appear to be Styx protocol differences between Inferno
+# 1e, 2e, or 3e.
+#
+# - 1996 beta https://github.com/inferno-os/inferno-1e0/blob/main/ see `man/html/proto*.htm`, `include/styx.h`, and `Linux/386/include/lib9.h`
+# - 1997 1e https://github.com/inferno-os/inferno-1e1/blob/master/ see `man/html/mpgs{113..124}.htm`, `include/styx.h`, `os/port/lib.h`, and `os/fs/fs.c`
+# - 1999 2e https://github.com/inferno-os/inferno-2e/blob/master/ see `include/styx.h`, `os/port/lib.h`, and `os/kfs/fs.c` (no public manpages)
+# - 2001 3e https://github.com/inferno-os/inferno-3e/blob/master/ see `include/man/5/`, `include/styx.h`, `os/port/lib.h`, and `os/kfs/fs.c`
+version "Styx"
+
+from ./1992-9P1.9p import tag, fid, qid, name, errstr, o, ch, stat
+
+# A Styx session goes:
+#
+# [nop()]
+# attach()
+# ...
+
+msg Tnop = "typ[1,val=0] tag[tag,val=0xFFFF]"
+msg Rnop = "typ[1,val=1] tag[tag,val=0xFFFF]"
+#msg Terror = "typ[1,val=2] illegal"
+msg Rerror = "typ[1,val=3] tag[tag] errstr[errstr]"
+msg Tflush = "typ[1,val=4] tag[tag] oldtag[tag]"
+msg Rflush = "typ[1,val=5] tag[tag]"
+msg Tclone = "typ[1,val=6] tag[tag] fid[fid] newfid[fid]"
+msg Rclone = "typ[1,val=7] tag[tag] fid[fid]"
+msg Twalk = "typ[1,val=8] tag[tag] fid[fid] name[name]"
+msg Rwalk = "typ[1,val=9] tag[tag] fid[fid] qid[qid]"
+msg Topen = "typ[1,val=10] tag[tag] fid[fid] mode[o]"
+msg Ropen = "typ[1,val=11] tag[tag] fid[fid] qid[qid]"
+msg Tcreate = "typ[1,val=12] tag[tag] fid[fid] name[name] perm[ch] mode[o]"
+msg Rcreate = "typ[1,val=13] tag[tag] fid[fid] qid[qid]"
+# For `offset:max`, see `fs.c` `f_read()` and `f_write()`.
+# For `count:max`, see `styx.h:MAXFDATA`.
+msg Tread = "typ[1,val=14] tag[tag] fid[fid] offset[8,max=s64_max] count[2,max=8192]"
+msg Rread = "typ[1,val=15] tag[tag] fid[fid] count[2,max=8192] pad[1] count*(data[1])"
+msg Twrite = "typ[1,val=16] tag[tag] fid[fid] offset[8,max=s64_max] count[2,max=8192] pad[1] count*(data[1])"
+msg Rwrite = "typ[1,val=17] tag[tag] fid[fid] count[2,max=8192]"
+msg Tclunk = "typ[1,val=18] tag[tag] fid[fid]"
+msg Rclunk = "typ[1,val=19] tag[tag] fid[fid]"
+msg Tremove = "typ[1,val=20] tag[tag] fid[fid]"
+msg Rremove = "typ[1,val=21] tag[tag] fid[fid]"
+msg Tstat = "typ[1,val=22] tag[tag] fid[fid]"
+msg Rstat = "typ[1,val=23] tag[tag] fid[fid] stat[stat]"
+msg Twstat = "typ[1,val=24] tag[tag] fid[fid] stat[stat]"
+msg Rwstat = "typ[1,val=25] tag[tag] fid[fid]"
+#msg Tsession = "typ[1,val=26]" # The 1e kernel used Tsession in structs internally, but never transmitted it.
+#msg Rsession = "typ[1,val=27]" # Implied by Tsession.
+msg Tattach = "typ[1,val=28] tag[tag] fid[fid] uid[name] aname[name]"
+msg Rattach = "typ[1,val=29] tag[tag] fid[fid] qid[qid]"
diff --git a/lib9p/idl/2002-9P2000.9p b/lib9p/idl/2002-9P2000.9p
index 03f00c2..13393c6 100644
--- a/lib9p/idl/2002-9P2000.9p
+++ b/lib9p/idl/2002-9P2000.9p
@@ -1,6 +1,6 @@
-# 2002-9P2000.9p - Definitions of 9P2000 messages
+# lib9p/idl/2002-9P2000.9p - Definitions of 9P2000 messages
#
-# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
# "9P2000" base protocol
@@ -9,74 +9,77 @@
#
# But due to incompleteness of the draft RFC, the Plan 9 manual
# section-5 and the Plan 9 headers (particularly fcall.h) are often
-# better references.
+# better references. The s{32,64}_max limitations are not documented
+# in the draft RFC or the manual pages, but have been enforced by
+# lib9p/srv.c in every release of Plan 9 4e.
#
# https://github.com/plan9foundation/plan9/tree/main/sys/man/5
# https://man.cat-v.org/plan_9/5/
# https://github.com/plan9foundation/plan9/blob/main/sys/include/fcall.h
+# https://github.com/plan9foundation/plan9/blob/main/sys/include/libc.h
+# https://github.com/plan9foundation/plan9/blob/main/sys/src/lib9p/srv.c
version "9P2000"
# tag - identify a request/response pair
num tag = 2
+ "NOTAG = u16_max"
# file identifier - like a UNIX file-descriptor
num fid = 4
-
-# data - u32le `n`, then `n` bytes of data
-struct d = "len[4] len*(dat[1])"
+ "NOFID = u32_max"
# string - u16le `n`, then `n` bytes of UTF-8, without any nul-bytes
struct s = "len[2] len*(utf8[1])"
-# "d"? mode - file permissions and attributes
+# "D"ir-entry "M"ode - file permissions and attributes
bitfield dm = 4
- "31=DIR"
- "30=APPEND"
- "29=EXCL"
- # DMMOUNT has been around in Plan 9 forever, but is
- # undocumented, and is explicitly excluded from the 9P2000
- # draft RFC. As I understand it, DMMOUNT indicates that the
- # file is mounted by the kernel as a 9P transport; that the
- # kernel has a lock on doing I/O on it, so userspace can't do
- # I/O on it.
- "28=_PLAN9_MOUNT"
- "27=AUTH"
- "26=TMP"
+ "bit 31=DIR"
+ "bit 30=APPEND"
+ "bit 29=EXCL"
+ # DMMOUNT has been around in Plan 9 since 2e (CHMOUNT in <4e),
+ # but is undocumented, and is explicitly excluded from the
+ # 9P2000 draft RFC. As I understand it, DMMOUNT indicates
+ # that the file is mounted by the kernel as a 9P transport;
+ # that the kernel has a lock on doing I/O on it, so userspace
+ # can't do I/O on it.
+ "bit 28=_PLAN9_MOUNT"
+ "bit 27=AUTH"
+ "bit 26=TMP"
#...
- "8=OWNER_R"
- "7=OWNER_W"
- "6=OWNER_X"
- "5=GROUP_R"
- "4=GROUP_W"
- "3=GROUP_X"
- "2=OTHER_R"
- "1=OTHER_W"
- "0=OTHER_X"
+ "bit 8=OWNER_R"
+ "bit 7=OWNER_W"
+ "bit 6=OWNER_X"
+ "bit 5=GROUP_R"
+ "bit 4=GROUP_W"
+ "bit 3=GROUP_X"
+ "bit 2=OTHER_R"
+ "bit 1=OTHER_W"
+ "bit 0=OTHER_X"
- "PERM_MASK=0777" # {OWNER,GROUP,OTHER}_{R,W,X}
+ "mask PERM=0777" # {OWNER,GROUP,OTHER}_{R,W,X}
# QID Type - see `struct qid` below
bitfield qt = 1
- "7=DIR"
- "6=APPEND"
- "5=EXCL"
- "4=_PLAN9_MOUNT" # see "MOUNT" in "dm" above
- "3=AUTH"
+ "bit 7=DIR"
+ "bit 6=APPEND"
+ "bit 5=EXCL"
+ "bit 4=_PLAN9_MOUNT" # See "_PLAN9_MOUNT" in "dm" above.
+ "bit 3=AUTH"
# Fun historical fact: QTTMP was a relatively late addition to
# Plan 9, in 2003-12.
- "2=TMP"
- #"1=unused"
+ "bit 2=TMP"
+ #"bit 1=unused"
# "The name QTFILE, defined to be zero, identifies the value
# of the type for a plain file."
- "FILE=0"
+ "alias FILE=0"
# uni"Q"ue "ID"entification - "two files on the same server hierarchy
# are the same if and only if their qids are the same"
#
# - "path" is a unique uint64_t that does most of the work in the
# above statement about files being the same if their QIDs are the
-# same; " If a file is deleted and recreated with the same name in
+# same; "If a file is deleted and recreated with the same name in
# the same directory, the old and new path components of the qids
# should be different"
#
@@ -102,23 +105,30 @@ struct stat = "stat_size[2,val=end-&kern_type]"
"file_last_modified_uid[s]"
# "O"pen flags (flags to pass to Topen and Tcreate)
+# Unused bits *must* be 0.
bitfield o = 1
- "0=mode_0" # low bit of the 2-bit READ/WRITE/RDWR/EXEC enum
- "1=mode_1" # high bit of the 2-bit READ/WRITE/RDWR/EXEC enum"
- #"2=unused"
- #"3=unused"
- "4=TRUNC"
- #"5=unused"
- "6=RCLOSE" # remove-on-close
- #"7=unused"
+ "bit 0=num(MODE)" # low bit of the 2-bit READ/WRITE/RDWR/EXEC enum
+ "bit 1=num(MODE)" # high bit of the 2-bit READ/WRITE/RDWR/EXEC enum
+ #"bit 2=unused"
+ #"bit 3=unused"
+ "bit 4=TRUNC"
+ "bit 5=reserved(CEXEC)" # close-on-exec
+ "bit 6=RCLOSE" # remove-on-close
+ #"bit 7=unused"
+
+ "num(MODE) READ = 0" # make available for this FID: Tread()
+ "num(MODE) WRITE = 1" # make available for this FID: Twrite()
+ "num(MODE) RDWR = 2" # make available for this FID: Tread() and Twrite()
+ "num(MODE) EXEC = 3" # make available for this FID: Tread()
- "READ = 0" # make available for this FID: Tread()
- "WRITE = 1" # make available for this FID: Twrite()
- "RDWR = 2" # make available for this FID: Tread() and Twrite()
- "EXEC = 3" # make available for this FID: Tread()
+ "mask FLAG = 0b11111100"
- "MODE_MASK = 0b00000011"
- "FLAG_MASK = 0b11111100"
+# A 9P2000 session goes:
+#
+# version()
+# [auth_fid=auth]
+# attach([auth_fid])
+# ...
msg Tversion = "size[4,val=end-&size] typ[1,val=100] tag[tag] max_msg_size[4] version[s]"
msg Rversion = "size[4,val=end-&size] typ[1,val=101] tag[tag] max_msg_size[4] version[s]"
@@ -127,7 +137,7 @@ msg Rauth = "size[4,val=end-&size] typ[1,val=103] tag[tag] aqid[qid]"
msg Tattach = "size[4,val=end-&size] typ[1,val=104] tag[tag] fid[fid] afid[fid] uname[s] aname[s]"
msg Rattach = "size[4,val=end-&size] typ[1,val=105] tag[tag] qid[qid]"
#msg Terror = "size[4,val=end-&size] typ[1,val=106] tag[tag] illegal"
-msg Rerror = "size[4,val=end-&size] typ[1,val=107] tag[tag] ename[s]"
+msg Rerror = "size[4,val=end-&size] typ[1,val=107] tag[tag] errstr[s]"
msg Tflush = "size[4,val=end-&size] typ[1,val=108] tag[tag] oldtag[2]"
msg Rflush = "size[4,val=end-&size] typ[1,val=109] tag[tag]"
msg Twalk = "size[4,val=end-&size] typ[1,val=110] tag[tag] fid[fid] newfid[fid] nwname[2,max=16] nwname*(wname[s])"
@@ -136,10 +146,10 @@ msg Topen = "size[4,val=end-&size] typ[1,val=112] tag[tag] fid[fid] mode[o]"
msg Ropen = "size[4,val=end-&size] typ[1,val=113] tag[tag] qid[qid] iounit[4]"
msg Tcreate = "size[4,val=end-&size] typ[1,val=114] tag[tag] fid[fid] name[s] perm[dm] mode[o]"
msg Rcreate = "size[4,val=end-&size] typ[1,val=115] tag[tag] qid[qid] iounit[4]"
-msg Tread = "size[4,val=end-&size] typ[1,val=116] tag[tag] fid[fid] offset[8] count[4]"
-msg Rread = "size[4,val=end-&size] typ[1,val=117] tag[tag] data[d]" # for directories, `data` is the sequence "cnt*(entries[stat])"
-msg Twrite = "size[4,val=end-&size] typ[1,val=118] tag[tag] fid[fid] offset[8] data[d]"
-msg Rwrite = "size[4,val=end-&size] typ[1,val=119] tag[tag] count[4]"
+msg Tread = "size[4,val=end-&size] typ[1,val=116] tag[tag] fid[fid] offset[8,max=s64_max] count[4,max=s32_max]" # See 4e `sys/src/lib9p/srv.c:sread()` for `offset:max` and `count:max`.
+msg Rread = "size[4,val=end-&size] typ[1,val=117] tag[tag] count[4,max=s32_max] count*(data[1])" # `max` is inherited from Tread, for directories `data` is the sequence "cnt*(entries[stat])".
+msg Twrite = "size[4,val=end-&size] typ[1,val=118] tag[tag] fid[fid] offset[8,max=s64_max] count[4,max=s32_max] count*(data[1])" # See 4e `sys/src/lib9p/srv.c:swrite()` for `offset:max` and `count:max`.
+msg Rwrite = "size[4,val=end-&size] typ[1,val=119] tag[tag] count[4,max=s32_max]" # `max` is inherited from Twrite.
msg Tclunk = "size[4,val=end-&size] typ[1,val=120] tag[tag] fid[fid]"
msg Rclunk = "size[4,val=end-&size] typ[1,val=121] tag[tag]"
msg Tremove = "size[4,val=end-&size] typ[1,val=122] tag[tag] fid[fid]"
diff --git a/lib9p/idl/2003-9P2000.p9p.9p b/lib9p/idl/2003-9P2000.p9p.9p
new file mode 100644
index 0000000..3f6a524
--- /dev/null
+++ b/lib9p/idl/2003-9P2000.p9p.9p
@@ -0,0 +1,49 @@
+# lib9p/idl/2003-9P2000.p9p.9p - Definitions of plan9port extension messages
+#
+# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+# Plan 9 from User Space (a.k.a. plan9port)'s lib9pclient:fsopenfd(3)
+# and 9pserve(4) proxy server (which takes the place of the Plan 9
+# kernel) add a special-purpose `openfd` command to 9P2000.
+#
+# https://9fans.github.io/plan9port/man/man9/openfd.htlm
+# https://github.com/9fans/plan9port/blob/master/man/man9/openfd.9p
+# https://github.com/9fans/plan9port/commit/32f69c36e0eec1227934bbd34854bfebd88686f2
+# https://github.com/9fans/plan9port/pull/692
+
+# BUG: There is no version-string for this extension; plan9port still
+# calls it vanilla "9P2000".
+version "9P2000.p9p"
+
+from ./2002-9P2000.9p import *
+
+# On Plan 9 the usual 9P client is the kernel, not normal userspace
+# programs. The kernel multiplexes multiple userspace processes onto
+# a single 9P connection; the userspace programs make 9P calls by
+# making syscalls. plan9port emulates this by having mock syscalls
+# that make 9P client calls over an AF_UNIX socket to a local
+# `9pserve` daemon that does the multiplexing (you add an "fs" prefix;
+# e.g. you replace syscall:`open()` with lib9pclient:`fsopen()`).
+#
+# "Unfortunately", programs in plan9port must deal both with 9P files
+# and native "Unix" files; and need to turn an 9P FID into a native
+# file descriptor. To do this, the `9pserve` program and lib9pclient
+# add an extension call to 9P2000: Topenfd/Ropenfd/fsopenfd().
+#
+# An AF_UNIX socket has the ability to send a file descriptor over it
+# via an out-of-band "socket control message" ("CMSG" or "SCM").
+#
+# Topenfd asks 9pserve to create a socketpair() file descriptor that
+# 9pserve will pump to/from a FID, and then send that pipe file
+# descriptor over a control-message to the client program.
+#
+# When replying, the server sends not just an in-band Ropenfd message,
+# but also an out-of-band control-message with a socketpair() file
+# descriptor. A successful call results in the FID being clunked.
+msg Topenfd = "size[4,val=end-&size] typ[1,val=98] tag[tag] fid[fid] mode[o]"
+msg Ropenfd = "size[4,val=end-&size] typ[1,val=99] tag[tag] qid[qid] iounit[4] unixfd[4]"
+# BUG: The "unixfd" field nominally indicates the the file descriptor
+# of the pipe, but really 9pserve doesn't know which FD it will end up
+# on the client process, and lib9pclient ignores the value here and
+# overwrites it with the file descriptor indicated from the CMSG
diff --git a/lib9p/idl/2005-9P2000.u.9p b/lib9p/idl/2005-9P2000.u.9p
index 8b59efa..1d630f9 100644
--- a/lib9p/idl/2005-9P2000.u.9p
+++ b/lib9p/idl/2005-9P2000.u.9p
@@ -1,6 +1,6 @@
-# 2005-9P2000.u.9p - Definitions of 9P2000.u messages
+# lib9p/idl/2005-9P2000.u.9p - Definitions of 9P2000.u messages
#
-# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
# "9P2000.u" Unix extension
@@ -10,20 +10,27 @@ version "9P2000.u"
from ./2002-9P2000.9p import *
+# numeric user ID
+num nuid = 4
+ "NONUID = u32_max"
+
+num errno = 4
+ "NOERROR = 0"
+
struct stat += "file_extension[s]"
- "file_owner_n_uid[4]"
- "file_owner_n_gid[4]"
- "file_last_modified_n_uid[4]"
+ "file_owner_n_uid[nuid]"
+ "file_owner_n_gid[nuid]"
+ "file_last_modified_n_uid[nuid]"
-msg Tauth += "n_uname[4]"
-msg Tattach += "n_uname[4]"
+msg Tauth += "n_uid[nuid]"
+msg Tattach += "n_uid[nuid]"
-msg Rerror += "errno[4]"
+msg Rerror += "errnum[errno]"
-bitfield dm += "23=DEVICE"
- "21=NAMEDPIPE"
- "20=SOCKET"
- "19=SETUID"
- "18=SETGID"
+bitfield dm += "bit 23=DEVICE"
+ "bit 21=PIPE"
+ "bit 20=SOCKET"
+ "bit 19=SETUID"
+ "bit 18=SETGID"
-bitfield qt += "1=SYMLINK"
+bitfield qt += "bit 1=SYMLINK"
diff --git a/lib9p/idl/2010-9P2000.L.9p b/lib9p/idl/2010-9P2000.L.9p
new file mode 100644
index 0000000..652660c
--- /dev/null
+++ b/lib9p/idl/2010-9P2000.L.9p
@@ -0,0 +1,230 @@
+# lib9p/idl/2010-9P2000.L.9p - Definitions of 9P2000.L messages
+#
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+# "9P2000.L" Linux extension
+# https://github.com/chaos/diod/blob/master/protocol.md
+# https://github.com/chaos/diod/blob/master/src/libnpfs/protocol.h
+version "9P2000.L"
+
+from ./2002-9P2000.9p import tag, fid, s, qt, qid
+from ./2002-9P2000.9p import Rerror
+from ./2002-9P2000.9p import Tversion, Rversion, Tflush, Rflush, Twalk, Rwalk, Tread, Rread, Twrite, Rwrite, Tclunk, Rclunk, Tremove, Rremove
+from ./2005-9P2000.u.9p import nuid, errno, Tauth, Rauth, Tattach, Rattach
+
+#num errno += # TODO
+
+num super_magic = 4
+ # See <linux/magic.h> (linux.git include/uapi/linux/magic.h).
+ #
+ # To quote `util-linux.git:include/statfs_magic.h`:
+ # "Unfortunately, Linux kernel header file <linux/magic.h> is
+ # incomplete mess and kernel returns by statfs f_type many numbers
+ # that are nowhere specified (in API)."
+ #
+ # util-linux <statfs_magic.h> is also incomplete. As is the
+ # statfs(2) man-page.
+ #
+ # I'm working on a patchset to the kernel to get <linux/magic.h>
+ # to be complete, but in the mean-time I'm just not going to
+ # bother with putting a list here.
+ #
+ # TODO
+ "V9FS_MAGIC=0x01021997"
+
+# "L"inux "O"pen flags (flags to pass to Tlopen and Tlcreate)
+#
+# The values are not specified in in protocol.md, but are specified in
+# protocol.h (and are different than the Linux kernel's values, which
+# vary by architecture).
+bitfield lo = 4
+ "bit 0=num(MODE)" # low bit of the 2-bit RDONLY/WRONLY/RDWR/NOACCESS enum
+ "bit 1=num(MODE)" # high bit of the 2-bit RDONLY/WRONLY/RDWR/NOACCESS enum
+ #"bit 2=unused"
+ #"bit 3=unused"
+ #"bit 4=unused"
+ #"bit 5=unused"
+ "bit 6=CREATE"
+ "bit 7=EXCL"
+ "bit 8=NOCTTY"
+ "bit 9=TRUNC"
+ "bit 10=APPEND"
+ "bit 11=NONBLOCK"
+ "bit 12=DSYNC"
+ "bit 13=BSD_FASYNC"
+ "bit 14=DIRECT"
+ "bit 15=LARGEFILE"
+ "bit 16=DIRECTORY"
+ "bit 17=NOFOLLOW"
+ "bit 18=NOATIME"
+ "bit 19=CLOEXEC"
+ "bit 20=SYNC"
+
+ "num(MODE) RDONLY = 0"
+ "num(MODE) WRONLY = 1"
+ "num(MODE) RDWR = 2"
+ "num(MODE) NOACCESS = 3"
+
+ "mask FLAG = 0b111111111111111000000"
+
+# "D"irentry "T"ype
+#
+# These match the Linux kernel's values.
+num dt = 1
+ "UNKNOWN = 0"
+ "PIPE = 1"
+ "CHAR_DEV = 2"
+ "DIRECTORY = 4"
+ "BLOCK_DEV = 6" # proof it's not a bitfield
+ "REGULAR = 8"
+ "SYMLINK = 10" # proof it's not a bitfield
+ "SOCKET = 12" # proof it's not a bitfield
+ "_WHITEOUT = 14" # proof it's not a bitfield
+
+# Mode
+#
+# These match the Linux kernel's values. Why is this 32-bits wide
+# instead of just 16? Who knows?
+bitfield mode = 4
+ #...
+ "bit 15=num(FMT)" # bit of the 4-bit FMT_ enum
+ "bit 14=num(FMT)" # bit of the 4-bit FMT_ enum
+ "bit 13=num(FMT)" # bit of the 4-bit FMT_ enum
+ "bit 12=num(FMT)" # bit of the 4-bit FMT_ enum
+ #...
+ "bit 11=PERM_SETGROUP"
+ "bit 10=PERM_SETUSER"
+ "bit 9=PERM_STICKY"
+ "bit 8=PERM_OWNER_R"
+ "bit 7=PERM_OWNER_W"
+ "bit 6=PERM_OWNER_X"
+ "bit 5=PERM_GROUP_R"
+ "bit 4=PERM_GROUP_W"
+ "bit 3=PERM_GROUP_X"
+ "bit 2=PERM_OTHER_R"
+ "bit 1=PERM_OTHER_W"
+ "bit 0=PERM_OTHER_X"
+
+ "num(FMT) PIPE = dt.PIPE<<12"
+ "num(FMT) CHAR_DEV = dt.CHAR_DEV<<12"
+ "num(FMT) DIRECTORY = dt.DIRECTORY<<12"
+ "num(FMT) BLOCK_DEV = dt.BLOCK_DEV<<12"
+ "num(FMT) REGULAR = dt.REGULAR<<12"
+ "num(FMT) SYMLINK = dt.SYMLINK<<12"
+ "num(FMT) SOCKET = dt.SOCKET<<12"
+
+ "mask PERM = 07777" # PERM_*
+
+# A boolean value that is for some reason 4 bytes wide.
+num b4 = 4
+ "FALSE=0"
+ "TRUE=1"
+ # all other values are true also
+
+bitfield getattr = 8
+ "bit 0=MODE"
+ "bit 1=NLINK"
+ "bit 2=UID"
+ "bit 3=GID"
+ "bit 4=RDEV"
+ "bit 5=ATIME"
+ "bit 6=MTIME"
+ "bit 7=CTIME"
+ "bit 8=INO"
+ "bit 9=SIZE"
+ "bit 10=BLOCKS"
+
+ "bit 11=BTIME"
+ "bit 12=GEN"
+ "bit 13=DATA_VERSION"
+
+ "alias BASIC=0x000007ff" # Mask for fields up to BLOCKS
+ "alias ALL =0x00003fff" # Mask for All fields above
+
+bitfield setattr = 4
+ "bit 0=MODE"
+ "bit 1=UID"
+ "bit 2=GID"
+ "bit 3=SIZE"
+ "bit 4=ATIME"
+ "bit 5=MTIME"
+ "bit 6=CTIME"
+ "bit 7=ATIME_SET"
+ "bit 8=MTIME_SET"
+
+num lock_type = 1
+ "RDLCK=0"
+ "WRLCK=1"
+ "UNLCK=2"
+
+bitfield lock_flags = 4
+ "bit 0=BLOCK"
+ "bit 1=RECLAIM"
+
+num lock_status = 1
+ "SUCCESS=0"
+ "BLOCKED=1"
+ "ERROR=2"
+ "GRACE=3"
+
+#msg Tlerror = "size[4,val=end-&size] typ[1,val=6] tag[tag] illegal" # analogous to 106/Terror
+msg Rlerror = "size[4,val=end-&size] typ[1,val=7] tag[tag] errnum[errno]" # analogous to 107/Rerror
+msg Tstatfs = "size[4,val=end-&size] typ[1,val=8] tag[tag] fid[fid]"
+msg Rstatfs = "size[4,val=end-&size] typ[1,val=9] tag[tag]" # Description | statfs | statvfs
+ "type[super_magic]" # Type of filesystem | f_type | -
+ "bsize[4]" # Block size in bytes | f_bsize | f_bsize
+ # - # Fragment size in bytes | f_frsize (since Linux 2.6) | f_frsize
+ "blocks[8]" # Size of FS in f_frsize units | f_blocks | f_blocks
+ "bfree[8]" # Number of free blocks | f_bfree | f_bfree
+ "bavail[8]" # Number of free blocks for unprivileged users | f_bavail | b_avail
+ "files[8]" # Number of inodes | f_files | f_files
+ "ffree[8]" # Number of free inodes | f_ffree | f_ffree
+ # - # Number of free inodes for unprivileged users | - | f_favail
+ "fsid[8]" # Filesystem instance ID | f_fsid | f_fsid
+ # - # Mount flags | f_flags (since Linux 2.6.36) | f_flag
+ "namelen[4]" # Maximum filename length | f_namemax | f_namemax
+msg Tlopen = "size[4,val=end-&size] typ[1,val=12] tag[tag] fid[fid] flags[lo]" # analogous to 112/Topen
+msg Rlopen = "size[4,val=end-&size] typ[1,val=13] tag[tag] qid[qid] iounit[4]" # analogous to 113/Ropen
+msg Tlcreate = "size[4,val=end-&size] typ[1,val=14] tag[tag] fid[fid] name[s] flags[lo] mode[mode] gid[nuid]" # analogous to 114/Tcreate
+msg Rlcreate = "size[4,val=end-&size] typ[1,val=15] tag[tag] qid[qid] iounit[4]" # analogous to 115/Rcreate
+msg Tsymlink = "size[4,val=end-&size] typ[1,val=16] tag[tag] fid[fid] name[s] symtgt[s] gid[nuid]"
+msg Rsymlink = "size[4,val=end-&size] typ[1,val=17] tag[tag] qid[qid]"
+msg Tmknod = "size[4,val=end-&size] typ[1,val=18] tag[tag] dfid[fid] name[s] mode[mode] major[4] minor[4] gid[nuid]"
+msg Rmknod = "size[4,val=end-&size] typ[1,val=19] tag[tag] qid[qid]"
+msg Trename = "size[4,val=end-&size] typ[1,val=20] tag[tag] fid[fid] dfid[fid] name[s]"
+msg Rrename = "size[4,val=end-&size] typ[1,val=21] tag[tag]"
+msg Treadlink = "size[4,val=end-&size] typ[1,val=22] tag[tag] fid[fid]"
+msg Rreadlink = "size[4,val=end-&size] typ[1,val=23] tag[tag] target[s]"
+msg Tgetattr = "size[4,val=end-&size] typ[1,val=24] tag[tag] fid[fid] request_mask[getattr]"
+msg Rgetattr = "size[4,val=end-&size] typ[1,val=25] tag[tag] valid[getattr] qid[qid] mode[mode] uid[nuid] gid[nuid] nlink[8]"
+ "rdev[8] filesize[8] blksize[8] blocks[8]"
+ "atime_sec[8] atime_nsec[8] mtime_sec[8] mtime_nsec[8]"
+ "ctime_sec[8] ctime_nsec[8] btime_sec[8] btime_nsec[8]"
+ "gen[8] data_version[8]"
+msg Tsetattr = "size[4,val=end-&size] typ[1,val=26] tag[tag] fid[fid] valid[setattr] mode[mode] uid[nuid] gid[nuid] filesize[8] atime_sec[8] atime_nsec[8] mtime_sec[8] mtime_nsec[8]"
+msg Rsetattr = "size[4,val=end-&size] typ[1,val=27] tag[tag]"
+#...
+msg Txattrwalk = "size[4,val=end-&size] typ[1,val=30] tag[tag] fid[fid] newfid[fid] name[s]"
+msg Rxattrwalk = "size[4,val=end-&size] typ[1,val=31] tag[tag] attr_size[8]"
+msg Txattrcreate = "size[4,val=end-&size] typ[1,val=32] tag[tag] fid[fid] name[s] attr_size[8] flags[4]"
+msg Rxattrcreate = "size[4,val=end-&size] typ[1,val=33] tag[tag]"
+#...
+msg Treaddir = "size[4,val=end-&size] typ[1,val=40] tag[tag] fid[fid] offset[8] count[4]"
+msg Rreaddir = "size[4,val=end-&size] typ[1,val=41] tag[tag] count[4] count*(data[1])" # data is "qid[qid] offset[8] type[dt] name[s]"
+#...
+msg Tfsync = "size[4,val=end-&size] typ[1,val=50] tag[tag] fid[fid] datasync[b4]"
+msg Rfsync = "size[4,val=end-&size] typ[1,val=51] tag[tag]"
+msg Tlock = "size[4,val=end-&size] typ[1,val=52] tag[tag] fid[fid] type[lock_type] flags[lock_flags] start[8] length[8] proc_id[4] client_id[s]"
+msg Rlock = "size[4,val=end-&size] typ[1,val=53] tag[tag] status[lock_status]"
+msg Tgetlock = "size[4,val=end-&size] typ[1,val=54] tag[tag] fid[fid] type[lock_type] start[8] length[8] proc_id[4] client_id[s]"
+msg Rgetlock = "size[4,val=end-&size] typ[1,val=55] tag[tag] type[lock_type] start[8] length[8] proc_id[4] client_id[s]"
+# ...
+msg Tlink = "size[4,val=end-&size] typ[1,val=70] tag[tag] dfid[fid] fid[fid] name[s]"
+msg Rlink = "size[4,val=end-&size] typ[1,val=71] tag[tag]"
+msg Tmkdir = "size[4,val=end-&size] typ[1,val=72] tag[tag] dfid[fid] name[s] mode[mode] gid[nuid]"
+msg Rmkdir = "size[4,val=end-&size] typ[1,val=73] tag[tag] qid[qid]"
+msg Trenameat = "size[4,val=end-&size] typ[1,val=74] tag[tag] olddirfid[fid] oldname[s] newdirfid[fid] newname[s]"
+msg Rrenameat = "size[4,val=end-&size] typ[1,val=75] tag[tag]"
+msg Tunlinkat = "size[4,val=end-&size] typ[1,val=76] tag[tag] dirfd[fid] name[s] flags[4]"
+msg Runlinkat = "size[4,val=end-&size] typ[1,val=77] tag[tag]"
diff --git a/lib9p/idl/2010-9P2000.L.9p.wip b/lib9p/idl/2010-9P2000.L.9p.wip
deleted file mode 100644
index 5261f7e..0000000
--- a/lib9p/idl/2010-9P2000.L.9p.wip
+++ /dev/null
@@ -1,56 +0,0 @@
-# 2010-9P2000.L.9p - Definitions of 9P2000.L messages
-#
-# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-# "9P2000.L" Linux extension
-# https://github.com/chaos/diod/blob/master/protocol.md
-version "9P2000.L"
-
-from ./2002-9P2000.9p import *
-from ./2005-9P2000.u.9p import Tauth, Tattach
-
-#msg Tlerror = "size[4,val=end-&size] typ[1,val=6] tag[tag] illegal" # analogous to 106/Terror
-msg Rlerror = "size[4,val=end-&size] typ[1,val=7] tag[tag] ecode[4]" # analogous to 107/Rerror
-msg Tstatfs = "size[4,val=end-&size] typ[1,val=8] tag[tag] TODO"
-msg Rstatfs = "size[4,val=end-&size] typ[1,val=9] tag[tag] TODO"
-msg Tlopen = "size[4,val=end-&size] typ[1,val=12] tag[tag] TODO" # analogous to 112/Topen
-msg Rlopen = "size[4,val=end-&size] typ[1,val=13] tag[tag] TODO" # analogous to 113/Ropen
-msg Tlcreate = "size[4,val=end-&size] typ[1,val=14] tag[tag] TODO" # analogous to 114/Tcreate
-msg Rlcreate = "size[4,val=end-&size] typ[1,val=15] tag[tag] TODO" # analogous to 115/Rcreate
-msg Tsymlink = "size[4,val=end-&size] typ[1,val=16] tag[tag] TODO"
-msg Rsymlink = "size[4,val=end-&size] typ[1,val=17] tag[tag] TODO"
-msg Tmknod = "size[4,val=end-&size] typ[1,val=18] tag[tag] TODO"
-msg Rmknod = "size[4,val=end-&size] typ[1,val=19] tag[tag] TODO"
-msg Trename = "size[4,val=end-&size] typ[1,val=20] tag[tag] TODO"
-msg Rrename = "size[4,val=end-&size] typ[1,val=21] tag[tag] TODO"
-msg Treadlink = "size[4,val=end-&size] typ[1,val=22] tag[tag] TODO"
-msg Rreadlink = "size[4,val=end-&size] typ[1,val=23] tag[tag] TODO"
-msg Tgetattr = "size[4,val=end-&size] typ[1,val=24] tag[tag] TODO"
-msg Rgetattr = "size[4,val=end-&size] typ[1,val=25] tag[tag] TODO"
-msg Tsetattr = "size[4,val=end-&size] typ[1,val=26] tag[tag] TODO"
-msg Rsetattr = "size[4,val=end-&size] typ[1,val=27] tag[tag] TODO"
-#...
-msg Txattrwalk = "size[4,val=end-&size] typ[1,val=30] tag[tag] TODO"
-msg Rxattrwalk = "size[4,val=end-&size] typ[1,val=31] tag[tag] TODO"
-msg Txattrcreate = "size[4,val=end-&size] typ[1,val=32] tag[tag] TODO"
-msg Rxattrcreate = "size[4,val=end-&size] typ[1,val=33] tag[tag] TODO"
-#...
-msg Treaddir = "size[4,val=end-&size] typ[1,val=40] tag[tag] TODO"
-msg Rreaddir = "size[4,val=end-&size] typ[1,val=41] tag[tag] TODO"
-#...
-msg Tfsync = "size[4,val=end-&size] typ[1,val=50] tag[tag] TODO"
-msg Rfsync = "size[4,val=end-&size] typ[1,val=51] tag[tag] TODO"
-msg Tlock = "size[4,val=end-&size] typ[1,val=52] tag[tag] TODO"
-msg Rlock = "size[4,val=end-&size] typ[1,val=53] tag[tag] TODO"
-msg Tgetlock = "size[4,val=end-&size] typ[1,val=54] tag[tag] TODO"
-msg Rgetlock = "size[4,val=end-&size] typ[1,val=55] tag[tag] TODO"
-# ...
-msg Tlink = "size[4,val=end-&size] typ[1,val=70] tag[tag] TODO"
-msg Rlink = "size[4,val=end-&size] typ[1,val=71] tag[tag] TODO"
-msg Tmkdir = "size[4,val=end-&size] typ[1,val=72] tag[tag] TODO"
-msg Tmkdir = "size[4,val=end-&size] typ[1,val=73] tag[tag] TODO"
-msg Trenameat = "size[4,val=end-&size] typ[1,val=74] tag[tag] TODO"
-msg Rrenameat = "size[4,val=end-&size] typ[1,val=75] tag[tag] TODO"
-msg Tunlinkat = "size[4,val=end-&size] typ[1,val=76] tag[tag] TODO"
-msg Runlinkat = "size[4,val=end-&size] typ[1,val=77] tag[tag] TODO"
diff --git a/lib9p/idl/2012-9P2000.e.9p b/lib9p/idl/2012-9P2000.e.9p
index 27db50f..dde9d96 100644
--- a/lib9p/idl/2012-9P2000.e.9p
+++ b/lib9p/idl/2012-9P2000.e.9p
@@ -1,6 +1,6 @@
-# 2012-9P2000.e.9p - Definitions of 9P2000.e messages
+# lib9p/idl/2012-9P2000.e.9p - Definitions of 9P2000.e messages
#
-# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
# "9P2000.e" Erlang extension
@@ -13,6 +13,6 @@ from ./2002-9P2000.9p import *
msg Tsession = "size[4,val=end-&size] typ[1,val=150] tag[tag] key[8]"
msg Rsession = "size[4,val=end-&size] typ[1,val=151] tag[tag]"
msg Tsread = "size[4,val=end-&size] typ[1,val=152] tag[tag] fid[4] nwname[2] nwname*(wname[s])"
-msg Rsread = "size[4,val=end-&size] typ[1,val=153] tag[tag] data[d]"
-msg Tswrite = "size[4,val=end-&size] typ[1,val=154] tag[tag] fid[4] nwname[2] nwname*(wname[s]) data[d]"
+msg Rsread = "size[4,val=end-&size] typ[1,val=153] tag[tag] count[4] count*(data[1])"
+msg Tswrite = "size[4,val=end-&size] typ[1,val=154] tag[tag] fid[4] nwname[2] nwname*(wname[s]) count[4] count*(data[1])"
msg Rswrite = "size[4,val=end-&size] typ[1,val=155] tag[tag] count[4]"
diff --git a/lib9p/idl/__init__.py b/lib9p/idl/__init__.py
new file mode 100644
index 0000000..2d09217
--- /dev/null
+++ b/lib9p/idl/__init__.py
@@ -0,0 +1,878 @@
+# lib9p/idl/__init__.py - A parser for .9p specification files.
+#
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+import enum
+import os.path
+import re
+import typing
+
+# pylint: disable=unused-variable
+__all__ = [
+ # entrypoint
+ "Parser",
+ # types
+ "Type",
+ "Primitive",
+ *["Expr", "ExprTok", "ExprOp", "ExprLit", "ExprSym", "ExprOff", "ExprNum"],
+ "Number",
+ *["Bitfield", "Bit", "BitCat", "BitNum", "BitAlias"],
+ *["Struct", "StructMember"],
+ "Message",
+]
+
+# The syntax that this parses is described in `./0000-README.md`.
+
+# Utilities ####################################################################
+
+
+def get_type(env: dict[str, "Type"], name: str, tc: type["T"]) -> "T":
+ if name not in env:
+ raise NameError(f"Unknown type {name!r}")
+ ret = env[name]
+ if (not isinstance(ret, tc)) or (ret.__class__.__name__ != tc.__name__):
+ raise NameError(f"Type {ret.typname!r} is not a {tc.__name__}")
+ return ret
+
+
+# Types ########################################################################
+
+
+class Primitive(enum.Enum):
+ u8 = 1
+ u16 = 2
+ u32 = 4
+ u64 = 8
+
+ @property
+ def in_versions(self) -> set[str]:
+ return set()
+
+ @property
+ def typname(self) -> str:
+ return str(self.value)
+
+ @property
+ def static_size(self) -> int:
+ return self.value
+
+ def min_size(self, version: str) -> int:
+ return self.value
+
+ def max_size(self, version: str) -> int:
+ return self.value
+
+
+class ExprOp:
+ op: typing.Literal["-", "+", "<<"]
+
+ def __init__(self, op: typing.Literal["-", "+", "<<"]) -> None:
+ self.op = op
+
+
+class ExprLit:
+ val: int
+
+ def __init__(self, val: int) -> None:
+ self.val = val
+
+
+class ExprSym:
+ symname: str
+
+ def __init__(self, name: str) -> None:
+ self.symname = name
+
+
+class ExprOff:
+ membname: str
+
+ def __init__(self, name: str) -> None:
+ self.membname = name
+
+
+class ExprNum:
+ numname: str
+ valname: str
+
+ def __init__(self, numname: str, valname: str) -> None:
+ self.numname = numname
+ self.valname = valname
+
+
+type ExprTok = ExprOp | ExprLit | ExprSym | ExprOff | ExprNum
+
+
+class Expr:
+ tokens: typing.Sequence[ExprTok]
+ const: int | None
+
+ def __init__(
+ self, env: dict[str, "Type"], tokens: typing.Sequence[ExprTok] = ()
+ ) -> None:
+ self.tokens = tokens
+ self.const = self._const(env, tokens)
+
+ def _const(
+ self, env: dict[str, "Type"], toks: typing.Sequence[ExprTok]
+ ) -> int | None:
+ if not toks:
+ return None
+
+ def read_val() -> int | None:
+ nonlocal toks
+ assert toks
+ neg = False
+ match toks[0]:
+ case ExprOp(op="-"):
+ neg = True
+ toks = toks[1:]
+ assert not isinstance(toks[0], ExprOp)
+ val: int
+ match toks[0]:
+ case ExprLit():
+ val = toks[0].val
+ case ExprSym():
+ if m := re.fullmatch(r"^u(8|16|32|64)_max$", toks[0].symname):
+ n = int(m.group(1))
+ val = (1 << n) - 1
+ elif m := re.fullmatch(r"^s(8|16|32|64)_max$", toks[0].symname):
+ n = int(m.group(1))
+ val = (1 << (n - 1)) - 1
+ else:
+ return None
+ case ExprOff():
+ return None
+ case ExprNum():
+ num = get_type(env, toks[0].numname, Number)
+ if toks[0].valname not in num.vals:
+ raise NameError(
+ f"Type {toks[0].numname!r} does not have a value {toks[0].valname!r}"
+ )
+ _val = num.vals[toks[0].valname].const
+ if _val is None:
+ return None
+ val = _val
+ toks = toks[1:]
+ return -val if neg else val
+
+ ret = read_val()
+ if ret is None:
+ return None
+ while toks:
+ assert isinstance(toks[0], ExprOp)
+ op = toks[0].op
+ toks = toks[1:]
+ operand = read_val()
+ if operand is None:
+ return None
+ match op:
+ case "+":
+ ret = ret + operand
+ case "-":
+ ret = ret - operand
+ case "<<":
+ ret = ret << operand
+ return ret
+
+ def __bool__(self) -> bool:
+ return len(self.tokens) > 0
+
+
+class Number:
+ typname: str
+ in_versions: set[str]
+
+ prim: Primitive
+
+ vals: dict[str, Expr]
+
+ def __init__(self) -> None:
+ self.in_versions = set()
+ self.vals = {}
+
+ @property
+ def static_size(self) -> int:
+ return self.prim.static_size
+
+ def min_size(self, version: str) -> int:
+ return self.static_size
+
+ def max_size(self, version: str) -> int:
+ return self.static_size
+
+
+class BitAlias:
+ bitname: str
+ in_versions: set[str]
+ val: Expr
+
+ def __init__(self, name: str, val: Expr) -> None:
+ if val.const is None:
+ raise ValueError(f"{name!r} value is not constant")
+ self.bitname = name
+ self.in_versions = set()
+ self.val = val
+
+
+class BitNum:
+ numname: str
+ mask: int
+ vals: dict[str, BitAlias]
+
+ def __init__(self, name: str) -> None:
+ self.numname = name
+ self.mask = 0
+ self.vals = {}
+
+
+type BitCat = typing.Literal["UNUSED", "USED", "RESERVED"] | BitNum
+
+
+class Bit:
+ bitname: str
+ in_versions: set[str]
+ num: int
+ cat: BitCat
+
+ def __init__(self, num: int) -> None:
+ self.bitname = ""
+ self.in_versions = set()
+ self.num = num
+ self.cat = "UNUSED"
+
+
+class Bitfield:
+ typname: str
+ in_versions: set[str]
+ prim: Primitive
+
+ bits: list[Bit]
+ nums: dict[str, BitNum]
+ masks: dict[str, BitAlias]
+ aliases: dict[str, BitAlias]
+
+ names: set[str]
+
+ def __init__(self, name: str, prim: Primitive) -> None:
+ self.typname = name
+ self.in_versions = set()
+ self.prim = prim
+
+ self.bits = [Bit(i) for i in range(prim.static_size * 8)]
+ self.nums = {}
+ self.masks = {}
+ self.aliases = {}
+
+ self.names = set()
+
+ @property
+ def static_size(self) -> int:
+ return self.prim.static_size
+
+ def min_size(self, version: str) -> int:
+ return self.static_size
+
+ def max_size(self, version: str) -> int:
+ return self.static_size
+
+
+class StructMember:
+ # from left-to-right when parsing
+ cnt: "StructMember| int | None" = None
+ membname: str
+ typ: "Type"
+ max: Expr
+ val: Expr
+
+ in_versions: set[str]
+
+ @property
+ def min_cnt(self) -> int:
+ assert self.cnt
+ if isinstance(self.cnt, int):
+ return self.cnt
+ if not isinstance(self.cnt.typ, Primitive):
+ raise ValueError(
+ f"list count must be an integer type: {self.cnt.membname!r}"
+ )
+ if self.cnt.val: # TODO: allow this?
+ raise ValueError(f"list count may not have ,val=: {self.cnt.membname!r}")
+ return 0
+
+ @property
+ def max_cnt(self) -> int:
+ assert self.cnt
+ if isinstance(self.cnt, int):
+ return self.cnt
+ if not isinstance(self.cnt.typ, Primitive):
+ raise ValueError(
+ f"list count must be an integer type: {self.cnt.membname!r}"
+ )
+ if self.cnt.val: # TODO: allow this?
+ raise ValueError(f"list count may not have ,val=: {self.cnt.membname!r}")
+ if self.cnt.max:
+ # TODO: be more flexible?
+ val = self.cnt.max.const
+ if val is None:
+ raise ValueError(
+ f"list count ,max= must be a constant value: {self.cnt.membname!r}"
+ )
+ return val
+ return (1 << (self.cnt.typ.value * 8)) - 1
+
+ @property
+ def static_size(self) -> int | None:
+ if self.cnt:
+ return None
+ return self.typ.static_size
+
+ def min_size(self, version: str) -> int:
+ cnt = self.min_cnt if self.cnt else 1
+ return cnt * self.typ.min_size(version)
+
+ def max_size(self, version: str) -> int:
+ cnt = self.max_cnt if self.cnt else 1
+ return cnt * self.typ.max_size(version)
+
+
+class Struct:
+ typname: str
+ in_versions: set[str]
+
+ members: list[StructMember]
+
+ def __init__(self) -> None:
+ self.in_versions = set()
+
+ @property
+ def static_size(self) -> int | None:
+ size = 0
+ for member in self.members:
+ if member.in_versions < self.in_versions:
+ return None
+ msize = member.static_size
+ if msize is None:
+ return None
+ size += msize
+ return size
+
+ def min_size(self, version: str) -> int:
+ return sum(
+ member.min_size(version)
+ for member in self.members
+ if (version in member.in_versions)
+ )
+
+ def max_size(self, version: str) -> int:
+ return sum(
+ member.max_size(version)
+ for member in self.members
+ if (version in member.in_versions)
+ )
+
+
+class Message(Struct):
+ @property
+ def msgid(self) -> int:
+ assert len(self.members) >= 3
+ assert self.members[1].membname == "typ"
+ assert self.members[1].static_size == 1
+ assert self.members[1].val
+ assert len(self.members[1].val.tokens) == 1
+ assert isinstance(self.members[1].val.tokens[0], ExprLit)
+ return self.members[1].val.tokens[0].val
+
+
+type Type = Primitive | Number | Bitfield | Struct | Message
+type UserType = Number | Bitfield | Struct | Message
+T = typing.TypeVar("T", Number, Bitfield, Struct, Message)
+
+# Parse ########################################################################
+
+# common elements ######################
+
+re_priname = "(?:1|2|4|8)" # primitive names
+re_symname = "(?:[a-zA-Z_][a-zA-Z_0-9]*)" # "symbol" names; most *.9p-defined names
+re_symname_u = "(?:[A-Z_][A-Z_0-9]*)" # upper-case "symbol" names; bit names
+re_symname_l = "(?:[a-z_][a-z_0-9]*)" # lower-case "symbol" names; bit names
+re_impname = r"(?:\*|" + re_symname + ")" # names we can import
+re_msgname = r"(?:[TR][a-zA-Z_0-9]*)" # names a message can be
+
+re_memtype = f"(?:{re_symname}|{re_priname})" # typenames that a struct member can be
+
+valid_syms = [
+ "end",
+ "u8_max",
+ "u16_max",
+ "u32_max",
+ "u64_max",
+ "s8_max",
+ "s16_max",
+ "s32_max",
+ "s64_max",
+]
+
+_re_expr_op = r"(?:-|\+|<<)"
+
+_res_expr_val = {
+ "lit_2": r"0b[01]+",
+ "lit_8": r"0[0-7]+",
+ "lit_10": r"0(?![0-9bxX])|[1-9][0-9]*",
+ "lit_16": r"0[xX][0-9a-fA-F]+",
+ "sym": "|".join(valid_syms), # pre-defined symbols
+ "off": f"&{re_symname}", # offset of a field this struct
+ "num": f"{re_symname}\\.{re_symname}", # `num` values
+}
+
+re_expr_tok = (
+ "(?:"
+ + "|".join(
+ [
+ f"(?P<op>{_re_expr_op})",
+ *[f"(?P<{k}>{v})" for k, v in _res_expr_val.items()],
+ ]
+ )
+ + ")"
+)
+
+_re_expr_val = "(?:" + "|".join(_res_expr_val.values()) + ")"
+
+re_expr = f"(?:\\s*(?:-\\s*)?{_re_expr_val}\\s*(?:{_re_expr_op}\\s*(?:-\\s*)?{_re_expr_val}\\s*)*)"
+
+
+def parse_expr(env: dict[str, Type], expr: str) -> Expr:
+ assert re.fullmatch(re_expr, expr)
+ tokens: list[ExprTok] = []
+ for m in re.finditer(re_expr_tok, expr):
+ if tok := m.group("op"):
+ tokens.append(ExprOp(typing.cast(typing.Literal["-", "+", "<<"], tok)))
+ elif tok := m.group("lit_2"):
+ tokens.append(ExprLit(int(tok[2:], 2)))
+ elif tok := m.group("lit_8"):
+ tokens.append(ExprLit(int(tok[1:], 8)))
+ elif tok := m.group("lit_10"):
+ tokens.append(ExprLit(int(tok, 10)))
+ elif tok := m.group("lit_16"):
+ tokens.append(ExprLit(int(tok[2:], 16)))
+ elif tok := m.group("sym"):
+ tokens.append(ExprSym(tok))
+ elif tok := m.group("off"):
+ tokens.append(ExprOff(tok[1:]))
+ elif tok := m.group("num"):
+ [numname, valname] = tok.split(".", 1)
+ tokens.append(ExprNum(numname, valname))
+ else:
+ assert False
+ return Expr(env, tokens)
+
+
+# numspec ##############################
+
+re_numspec = f"(?P<name>{re_symname})\\s*=\\s*(?P<val>{re_expr})"
+
+
+def parse_numspec(env: dict[str, Type], ver: str, n: Number, spec: str) -> None:
+ spec = spec.strip()
+
+ if m := re.fullmatch(re_numspec, spec):
+ name = m.group("name")
+ if name in n.vals:
+ raise ValueError(f"{n.typname}: name {name!r} already assigned")
+ val = parse_expr(env, m.group("val"))
+ if val is None:
+ raise ValueError(
+ f"{n.typname}: {name!r} value is not constant: {m.group('val')!r}"
+ )
+ n.vals[name] = val
+ else:
+ raise SyntaxError(f"invalid num spec {spec!r}")
+
+
+# bitspec ##############################
+
+re_bitspec_bit = (
+ "bit\\s+(?P<bitnum>[0-9]+)\\s*=\\s*(?:"
+ + "|".join(
+ [
+ f"(?P<name_used>{re_symname_u})",
+ f"reserved\\((?P<name_reserved>{re_symname_u})\\)",
+ f"num\\((?P<name_num>{re_symname_u})\\)",
+ ]
+ )
+ + ")"
+)
+re_bitspec_mask = f"mask\\s+(?P<name>{re_symname_u})\\s*=\\s*(?P<val>{re_expr})"
+re_bitspec_alias = f"alias\\s+(?P<name>{re_symname_u})\\s*=\\s*(?P<val>{re_expr})"
+re_bitspec_num = f"num\\((?P<num>{re_symname_u})\\)\\s+(?P<name>{re_symname_u})\\s*=\\s*(?P<val>{re_expr})"
+
+
+def parse_bitspec(env: dict[str, Type], ver: str, bf: Bitfield, spec: str) -> None:
+ spec = spec.strip()
+
+ def check_name(name: str, is_num: bool = False) -> None:
+ if name == "MASK":
+ raise ValueError(f"{bf.typname}: bit name may not be {'MASK'!r}: {name!r}")
+ if name.endswith("_MASK"):
+ raise ValueError(
+ f"{bf.typname}: bit name may not end with {'_MASK'!r}: {name!r}"
+ )
+ if name in bf.names and not (is_num and name in bf.nums):
+ raise ValueError(f"{bf.typname}: bit name already assigned: {name!r}")
+
+ if m := re.fullmatch(re_bitspec_bit, spec):
+ bitnum = int(m.group("bitnum"))
+ if bitnum < 0 or bitnum >= len(bf.bits):
+ raise ValueError(f"{bf.typname}: bit num {bitnum} out-of-bounds")
+ bit = bf.bits[bitnum]
+ if bit.cat != "UNUSED":
+ raise ValueError(f"{bf.typname}: bit num {bitnum} already assigned")
+ if name := m.group("name_used"):
+ bit.bitname = name
+ bit.cat = "USED"
+ bit.in_versions.add(ver)
+ elif name := m.group("name_reserved"):
+ bit.bitname = name
+ bit.cat = "RESERVED"
+ bit.in_versions.add(ver)
+ elif name := m.group("name_num"):
+ bit.bitname = name
+ if name not in bf.nums:
+ bf.nums[name] = BitNum(name)
+ bf.nums[name].mask |= 1 << bit.num
+ bit.cat = bf.nums[name]
+ bit.in_versions.add(ver)
+ if bit.bitname:
+ check_name(name, isinstance(bit.cat, BitNum))
+ bf.names.add(bit.bitname)
+ elif m := re.fullmatch(re_bitspec_mask, spec):
+ mask = BitAlias(m.group("name"), parse_expr(env, m.group("val")))
+ mask.in_versions.add(ver)
+ check_name(mask.bitname)
+ bf.masks[mask.bitname] = mask
+ bf.names.add(mask.bitname)
+ elif m := re.fullmatch(re_bitspec_alias, spec):
+ alias = BitAlias(m.group("name"), parse_expr(env, m.group("val")))
+ alias.in_versions.add(ver)
+ check_name(alias.bitname)
+ bf.aliases[alias.bitname] = alias
+ bf.names.add(alias.bitname)
+ elif m := re.fullmatch(re_bitspec_num, spec):
+ numname = m.group("num")
+ alias = BitAlias(m.group("name"), parse_expr(env, m.group("val")))
+ alias.in_versions.add(ver)
+ check_name(alias.bitname)
+ if numname not in bf.nums:
+ raise NameError(
+ f"{bf.typname}: nested num not allocated any bits: {numname!r}"
+ )
+ assert alias.val.const is not None
+ if alias.val.const & ~bf.nums[numname].mask:
+ raise ValueError(
+ f"{bf.typname}: {alias.bitname!r} does not fit within bitmask: val={alias.val.const:b} mask={bf.nums[numname].mask}"
+ )
+ bf.nums[numname].vals[alias.bitname] = alias
+ bf.names.add(alias.bitname)
+ else:
+ raise SyntaxError(f"invalid bitfield spec {spec!r}")
+
+
+# struct members #######################
+
+
+re_memberspec = f"(?:(?P<cnt>{re_symname}|[1-9][0-9]*)\\*\\()?(?P<name>{re_symname})\\[(?P<typ>{re_memtype})(?:,max=(?P<max>{re_expr})|,val=(?P<val>{re_expr}))*\\]\\)?"
+
+
+def parse_members(ver: str, env: dict[str, Type], struct: Struct, specs: str) -> None:
+ for spec in specs.split():
+ m = re.fullmatch(re_memberspec, spec)
+ if not m:
+ raise SyntaxError(f"invalid member spec {spec!r}")
+
+ member = StructMember()
+ member.in_versions = {ver}
+
+ member.membname = m.group("name")
+ if any(x.membname == member.membname for x in struct.members):
+ raise ValueError(f"duplicate member name {member.membname!r}")
+
+ if m.group("typ") not in env:
+ raise NameError(f"Unknown type {m.group('typ')!r}")
+ member.typ = env[m.group("typ")]
+
+ if cnt := m.group("cnt"):
+ if cnt.isnumeric():
+ member.cnt = int(cnt)
+ else:
+ if len(struct.members) == 0 or struct.members[-1].membname != cnt:
+ raise ValueError(f"list count must be previous item: {cnt!r}")
+ member.cnt = struct.members[-1]
+ _ = member.max_cnt # force validation
+
+ if maxstr := m.group("max"):
+ if (
+ not isinstance(member.typ, Primitive)
+ and not isinstance(member.typ, Number)
+ ) or member.cnt:
+ raise ValueError(
+ "',max=' may only be specified on a non-repeated numeric type"
+ )
+ member.max = parse_expr(env, maxstr)
+ else:
+ member.max = Expr(env)
+
+ if valstr := m.group("val"):
+ if (
+ not isinstance(member.typ, Primitive)
+ and not isinstance(member.typ, Number)
+ ) or member.cnt:
+ raise ValueError(
+ "',val=' may only be specified on a non-repeated numeric type"
+ )
+ member.val = parse_expr(env, valstr)
+ else:
+ member.val = Expr(env)
+
+ struct.members += [member]
+
+
+# main parser ##########################
+
+
+def re_string(grpname: str) -> str:
+ return f'"(?P<{grpname}>[^"]*)"'
+
+
+re_line_version = f"version\\s+{re_string('version')}"
+re_line_import = f"from\\s+(?P<file>\\S+)\\s+import\\s+(?P<syms>{re_impname}(?:\\s*,\\s*{re_impname})*)"
+re_line_num = f"num\\s+(?P<name>{re_symname})\\s*=\\s*(?P<prim>{re_priname})"
+re_line_bitfield = f"bitfield\\s+(?P<name>{re_symname})\\s*=\\s*(?P<prim>{re_priname})"
+re_line_bitfield_ = (
+ f"bitfield\\s+(?P<name>{re_symname})\\s*\\+=\\s*{re_string('member')}"
+)
+re_line_struct = (
+ f"struct\\s+(?P<name>{re_symname})\\s*(?P<op>\\+?=)\\s*{re_string('members')}"
+)
+re_line_msg = (
+ f"msg\\s+(?P<name>{re_msgname})\\s*(?P<op>\\+?=)\\s*{re_string('members')}"
+)
+re_line_cont = f"\\s+{re_string('specs')}" # could be bitfield/struct/msg
+
+
+def parse_file(
+ filename: str, get_include: typing.Callable[[str], tuple[str, list[UserType]]]
+) -> tuple[str, list[UserType]]:
+ version: str | None = None
+ env: dict[str, Type] = {
+ "1": Primitive.u8,
+ "2": Primitive.u16,
+ "4": Primitive.u32,
+ "8": Primitive.u64,
+ }
+
+ with open(filename, "r", encoding="utf-8") as fh:
+ prev: Type | None = None
+ for lineno, line in enumerate(fh):
+ try:
+ line = line.split("#", 1)[0].rstrip()
+ if not line:
+ continue
+ if m := re.fullmatch(re_line_version, line):
+ if version:
+ raise SyntaxError("must have exactly 1 version line")
+ version = m.group("version")
+ continue
+ if not version:
+ raise SyntaxError("must have exactly 1 version line")
+
+ if m := re.fullmatch(re_line_import, line):
+ other_version, other_typs = get_include(m.group("file"))
+ for symname in m.group("syms").split(sep=","):
+ symname = symname.strip()
+ found = False
+ for typ in other_typs:
+ if symname in (typ.typname, "*"):
+ found = True
+ match typ:
+ case Primitive():
+ pass
+ case Number():
+ typ.in_versions.add(version)
+ case Bitfield():
+ typ.in_versions.add(version)
+ for bf_bit in typ.bits:
+ if other_version in bf_bit.in_versions:
+ bf_bit.in_versions.add(version)
+ for bf_num in typ.nums.values():
+ for bf_val in bf_num.vals.values():
+ if other_version in bf_val.in_versions:
+ bf_val.in_versions.add(version)
+ for bf_mask in typ.masks.values():
+ if other_version in bf_mask.in_versions:
+ bf_mask.in_versions.add(version)
+ for bf_alias in typ.aliases.values():
+ if other_version in bf_alias.in_versions:
+ bf_alias.in_versions.add(version)
+ case Struct(): # and Message()
+ typ.in_versions.add(version)
+ for member in typ.members:
+ if other_version in member.in_versions:
+ member.in_versions.add(version)
+ if typ.typname in env and env[typ.typname] != typ:
+ raise ValueError(
+ f"duplicate type name {typ.typname!r}"
+ )
+ env[typ.typname] = typ
+ if symname != "*" and not found:
+ raise ValueError(
+ f"import: {m.group('file')}: no symbol {symname!r}"
+ )
+ elif m := re.fullmatch(re_line_num, line):
+ num = Number()
+ num.typname = m.group("name")
+ num.in_versions.add(version)
+
+ prim = env[m.group("prim")]
+ assert isinstance(prim, Primitive)
+ num.prim = prim
+
+ if num.typname in env:
+ raise ValueError(f"duplicate type name {num.typname!r}")
+ env[num.typname] = num
+ prev = num
+ elif m := re.fullmatch(re_line_bitfield, line):
+ prim = env[m.group("prim")]
+ assert isinstance(prim, Primitive)
+
+ bf = Bitfield(m.group("name"), prim)
+ bf.in_versions.add(version)
+
+ if bf.typname in env:
+ raise ValueError(f"duplicate type name {bf.typname!r}")
+ env[bf.typname] = bf
+ prev = bf
+ elif m := re.fullmatch(re_line_bitfield_, line):
+ bf = get_type(env, m.group("name"), Bitfield)
+ parse_bitspec(env, version, bf, m.group("member"))
+
+ prev = bf
+ elif m := re.fullmatch(re_line_struct, line):
+ match m.group("op"):
+ case "=":
+ struct = Struct()
+ struct.typname = m.group("name")
+ struct.in_versions.add(version)
+ struct.members = []
+ parse_members(version, env, struct, m.group("members"))
+
+ if struct.typname in env:
+ raise ValueError(
+ f"duplicate type name {struct.typname!r}"
+ )
+ env[struct.typname] = struct
+ prev = struct
+ case "+=":
+ struct = get_type(env, m.group("name"), Struct)
+ parse_members(version, env, struct, m.group("members"))
+
+ prev = struct
+ elif m := re.fullmatch(re_line_msg, line):
+ match m.group("op"):
+ case "=":
+ msg = Message()
+ msg.typname = m.group("name")
+ msg.in_versions.add(version)
+ msg.members = []
+ parse_members(version, env, msg, m.group("members"))
+
+ if msg.typname in env:
+ raise ValueError(f"duplicate type name {msg.typname!r}")
+ env[msg.typname] = msg
+ prev = msg
+ case "+=":
+ msg = get_type(env, m.group("name"), Message)
+ parse_members(version, env, msg, m.group("members"))
+
+ prev = msg
+ elif m := re.fullmatch(re_line_cont, line):
+ match prev:
+ case Bitfield():
+ parse_bitspec(env, version, prev, m.group("specs"))
+ case Number():
+ parse_numspec(env, version, prev, m.group("specs"))
+ case Struct(): # and Message()
+ parse_members(version, env, prev, m.group("specs"))
+ case _:
+ raise SyntaxError(
+ "continuation line must come after a bitfield, struct, or msg line"
+ )
+ else:
+ raise SyntaxError("invalid line")
+ except (SyntaxError, NameError, ValueError) as e:
+ e2 = SyntaxError(str(e))
+ e2.filename = filename
+ e2.lineno = lineno + 1
+ e2.text = line
+ raise e2 from e
+ if not version:
+ raise SyntaxError("must have exactly 1 version line")
+
+ typs: list[UserType] = [x for x in env.values() if not isinstance(x, Primitive)]
+
+ for typ in [typ for typ in typs if isinstance(typ, Struct)]:
+ for member in typ.members:
+ if (
+ not isinstance(member.typ, Primitive)
+ and member.typ.in_versions < member.in_versions
+ ):
+ raise ValueError(
+ f"{typ.typname}.{member.membname}: type {member.typ.typname} does not exist in {member.in_versions.difference(member.typ.in_versions)}"
+ )
+ for tok in [*member.max.tokens, *member.val.tokens]:
+ if isinstance(tok, ExprOff) and not any(
+ m.membname == tok.membname for m in typ.members
+ ):
+ raise NameError(
+ f"{typ.typname}.{member.membname}: invalid offset: &{tok.membname}"
+ )
+
+ return version, typs
+
+
+# Filesystem ###################################################################
+
+
+class Parser:
+ cache: dict[str, tuple[str, list[UserType]]] = {}
+
+ def parse_file(self, filename: str) -> tuple[str, list[UserType]]:
+ filename = os.path.normpath(filename)
+ if filename not in self.cache:
+
+ def get_include(other_filename: str) -> tuple[str, list[UserType]]:
+ return self.parse_file(os.path.join(filename, "..", other_filename))
+
+ self.cache[filename] = parse_file(filename, get_include)
+ return self.cache[filename]
+
+ def all(self) -> tuple[set[str], list[UserType]]:
+ ret_versions: set[str] = set()
+ ret_typs: dict[str, UserType] = {}
+ for version, typs in self.cache.values():
+ if version in ret_versions:
+ raise ValueError(f"duplicate protocol version {version!r}")
+ ret_versions.add(version)
+ for typ in typs:
+ if typ.typname in ret_typs:
+ if typ != ret_typs[typ.typname]:
+ raise ValueError(f"duplicate type name {typ.typname!r}")
+ else:
+ ret_typs[typ.typname] = typ
+ msgids: set[int] = set()
+ for typ in ret_typs.values():
+ if isinstance(typ, Message):
+ if typ.msgid in msgids:
+ raise ValueError(f"duplicate msgid {typ.msgid!r}")
+ msgids.add(typ.msgid)
+ return ret_versions, list(ret_typs.values())
diff --git a/lib9p/include/lib9p/9p.generated.h b/lib9p/include/lib9p/9p.generated.h
index d5e94d1..a53f117 100644
--- a/lib9p/include/lib9p/9p.generated.h
+++ b/lib9p/include/lib9p/9p.generated.h
@@ -1,4 +1,4 @@
-/* Generated by `./lib9p/idl.gen lib9p/idl/2002-9P2000.9p lib9p/idl/2005-9P2000.u.9p lib9p/idl/2012-9P2000.e.9p`. DO NOT EDIT! */
+/* Generated by `lib9p/proto.gen lib9p/idl/2002-9P2000.9p lib9p/idl/2003-9P2000.p9p.9p lib9p/idl/2005-9P2000.u.9p lib9p/idl/2010-9P2000.L.9p lib9p/idl/2012-9P2000.e.9p`. DO NOT EDIT! */
#ifndef _LIB9P_9P_H_
#error Do not include <lib9p/9p.generated.h> directly; include <lib9p/9p.h> instead
@@ -6,271 +6,947 @@
#include <stdint.h> /* for uint{n}_t types */
-/* versions *******************************************************************/
+#include <libfmt/fmt.h> /* for fmt_formatter */
+#include <libhw/generic/io.h> /* for struct iovec */
+
+/* config *********************************************************************/
+
+#include "config.h"
+
+#ifndef CONFIG_9P_ENABLE_9P2000
+ #error config.h must define CONFIG_9P_ENABLE_9P2000
+#endif
+
+#ifndef CONFIG_9P_ENABLE_9P2000_L
+ #error config.h must define CONFIG_9P_ENABLE_9P2000_L
+#endif
+
+#ifndef CONFIG_9P_ENABLE_9P2000_e
+ #error config.h must define CONFIG_9P_ENABLE_9P2000_e
+#else
+ #if CONFIG_9P_ENABLE_9P2000_e
+ #ifndef CONFIG_9P_MAX_9P2000_e_WELEM
+ #error if CONFIG_9P_ENABLE_9P2000_e then config.h must define CONFIG_9P_MAX_9P2000_e_WELEM
+ #endif
+ static_assert(CONFIG_9P_MAX_9P2000_e_WELEM > 0);
+ #endif
+#endif
+
+#ifndef CONFIG_9P_ENABLE_9P2000_p9p
+ #error config.h must define CONFIG_9P_ENABLE_9P2000_p9p
+#endif
+
+#ifndef CONFIG_9P_ENABLE_9P2000_u
+ #error config.h must define CONFIG_9P_ENABLE_9P2000_u
+#endif
+
+/* enum version ***************************************************************/
enum lib9p_version {
LIB9P_VER_unknown = 0, /* "unknown" */
-#if defined(CONFIG_9P_ENABLE_9P2000)
+#if CONFIG_9P_ENABLE_9P2000
LIB9P_VER_9P2000, /* "9P2000" */
-#endif /* defined(CONFIG_9P_ENABLE_9P2000) */
-#if defined(CONFIG_9P_ENABLE_9P2000_e)
+#endif /* CONFIG_9P_ENABLE_9P2000 */
+#if CONFIG_9P_ENABLE_9P2000_L
+ LIB9P_VER_9P2000_L, /* "9P2000.L" */
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000_e
LIB9P_VER_9P2000_e, /* "9P2000.e" */
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_e) */
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+ LIB9P_VER_9P2000_p9p, /* "9P2000.p9p" */
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_u
LIB9P_VER_9P2000_u, /* "9P2000.u" */
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
LIB9P_VER_NUM,
};
+LO_IMPLEMENTATION_H(fmt_formatter, enum lib9p_version, lib9p_version);
-const char *lib9p_version_str(enum lib9p_version);
+/* enum msg_type **************************************************************/
-/* non-message types **********************************************************/
+enum lib9p_msg_type { /* uint8_t */
+#if CONFIG_9P_ENABLE_9P2000_L
+ LIB9P_TYP_Rlerror = 7,
+ LIB9P_TYP_Tstatfs = 8,
+ LIB9P_TYP_Rstatfs = 9,
+ LIB9P_TYP_Tlopen = 12,
+ LIB9P_TYP_Rlopen = 13,
+ LIB9P_TYP_Tlcreate = 14,
+ LIB9P_TYP_Rlcreate = 15,
+ LIB9P_TYP_Tsymlink = 16,
+ LIB9P_TYP_Rsymlink = 17,
+ LIB9P_TYP_Tmknod = 18,
+ LIB9P_TYP_Rmknod = 19,
+ LIB9P_TYP_Trename = 20,
+ LIB9P_TYP_Rrename = 21,
+ LIB9P_TYP_Treadlink = 22,
+ LIB9P_TYP_Rreadlink = 23,
+ LIB9P_TYP_Tgetattr = 24,
+ LIB9P_TYP_Rgetattr = 25,
+ LIB9P_TYP_Tsetattr = 26,
+ LIB9P_TYP_Rsetattr = 27,
+ LIB9P_TYP_Txattrwalk = 30,
+ LIB9P_TYP_Rxattrwalk = 31,
+ LIB9P_TYP_Txattrcreate = 32,
+ LIB9P_TYP_Rxattrcreate = 33,
+ LIB9P_TYP_Treaddir = 40,
+ LIB9P_TYP_Rreaddir = 41,
+ LIB9P_TYP_Tfsync = 50,
+ LIB9P_TYP_Rfsync = 51,
+ LIB9P_TYP_Tlock = 52,
+ LIB9P_TYP_Rlock = 53,
+ LIB9P_TYP_Tgetlock = 54,
+ LIB9P_TYP_Rgetlock = 55,
+ LIB9P_TYP_Tlink = 70,
+ LIB9P_TYP_Rlink = 71,
+ LIB9P_TYP_Tmkdir = 72,
+ LIB9P_TYP_Rmkdir = 73,
+ LIB9P_TYP_Trenameat = 74,
+ LIB9P_TYP_Rrenameat = 75,
+ LIB9P_TYP_Tunlinkat = 76,
+ LIB9P_TYP_Runlinkat = 77,
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+ LIB9P_TYP_Topenfd = 98,
+ LIB9P_TYP_Ropenfd = 99,
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+ LIB9P_TYP_Tversion = 100,
+ LIB9P_TYP_Rversion = 101,
+ LIB9P_TYP_Tauth = 102,
+ LIB9P_TYP_Rauth = 103,
+ LIB9P_TYP_Tattach = 104,
+ LIB9P_TYP_Rattach = 105,
+ LIB9P_TYP_Rerror = 107,
+ LIB9P_TYP_Tflush = 108,
+ LIB9P_TYP_Rflush = 109,
+ LIB9P_TYP_Twalk = 110,
+ LIB9P_TYP_Rwalk = 111,
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+ LIB9P_TYP_Topen = 112,
+ LIB9P_TYP_Ropen = 113,
+ LIB9P_TYP_Tcreate = 114,
+ LIB9P_TYP_Rcreate = 115,
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+ LIB9P_TYP_Tread = 116,
+ LIB9P_TYP_Rread = 117,
+ LIB9P_TYP_Twrite = 118,
+ LIB9P_TYP_Rwrite = 119,
+ LIB9P_TYP_Tclunk = 120,
+ LIB9P_TYP_Rclunk = 121,
+ LIB9P_TYP_Tremove = 122,
+ LIB9P_TYP_Rremove = 123,
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+ LIB9P_TYP_Tstat = 124,
+ LIB9P_TYP_Rstat = 125,
+ LIB9P_TYP_Twstat = 126,
+ LIB9P_TYP_Rwstat = 127,
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000_e
+ LIB9P_TYP_Tsession = 150,
+ LIB9P_TYP_Rsession = 151,
+ LIB9P_TYP_Tsread = 152,
+ LIB9P_TYP_Rsread = 153,
+ LIB9P_TYP_Tswrite = 154,
+ LIB9P_TYP_Rswrite = 155,
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+};
+LO_IMPLEMENTATION_H(fmt_formatter, enum lib9p_msg_type, lib9p_msg_type);
+
+/* payload types **************************************************************/
-#if defined(CONFIG_9P_ENABLE_9P2000) || defined(CONFIG_9P_ENABLE_9P2000_e) || defined(CONFIG_9P_ENABLE_9P2000_u)
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+/* size = 2 ; max_iov = 1 ; max_copy = 2 */
typedef uint16_t lib9p_tag_t;
+LO_IMPLEMENTATION_H(fmt_formatter, lib9p_tag_t, lib9p_tag);
+#define LIB9P_TAG_NOTAG ((lib9p_tag_t)(UINT16_MAX))
+/* size = 4 ; max_iov = 1 ; max_copy = 4 */
typedef uint32_t lib9p_fid_t;
+LO_IMPLEMENTATION_H(fmt_formatter, lib9p_fid_t, lib9p_fid);
+#define LIB9P_FID_NOFID ((lib9p_fid_t)(UINT32_MAX))
-struct lib9p_d {
- uint32_t len;
- char *dat;
-};
-
+/* min_size = 2 ; exp_size = 29 ; max_size = 65,537 ; max_iov = 2 ; max_copy = 2 */
struct lib9p_s {
- uint16_t len;
- char *utf8;
+ uint16_t len;
+ [[gnu::nonstring]] char *utf8;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_s, lib9p_s);
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+/* size = 4 ; max_iov = 1 ; max_copy = 4 */
typedef uint32_t lib9p_dm_t;
+LO_IMPLEMENTATION_H(fmt_formatter, lib9p_dm_t, lib9p_dm);
+/* bits */
+#define LIB9P_DM_DIR ((lib9p_dm_t)(UINT32_C(1)<<31))
+#define LIB9P_DM_APPEND ((lib9p_dm_t)(UINT32_C(1)<<30))
+#define LIB9P_DM_EXCL ((lib9p_dm_t)(UINT32_C(1)<<29))
+#define _LIB9P_DM_PLAN9_MOUNT ((lib9p_dm_t)(UINT32_C(1)<<28))
+#define LIB9P_DM_AUTH ((lib9p_dm_t)(UINT32_C(1)<<27))
+#define LIB9P_DM_TMP ((lib9p_dm_t)(UINT32_C(1)<<26))
+#define _LIB9P_DM_UNUSED_25 ((lib9p_dm_t)(UINT32_C(1)<<25))
+#define _LIB9P_DM_UNUSED_24 ((lib9p_dm_t)(UINT32_C(1)<<24))
+#if CONFIG_9P_ENABLE_9P2000_u
+# define LIB9P_DM_DEVICE ((lib9p_dm_t)(UINT32_C(1)<<23))
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+#define _LIB9P_DM_UNUSED_22 ((lib9p_dm_t)(UINT32_C(1)<<22))
+#if CONFIG_9P_ENABLE_9P2000_u
+# define LIB9P_DM_PIPE ((lib9p_dm_t)(UINT32_C(1)<<21))
+# define LIB9P_DM_SOCKET ((lib9p_dm_t)(UINT32_C(1)<<20))
+# define LIB9P_DM_SETUID ((lib9p_dm_t)(UINT32_C(1)<<19))
+# define LIB9P_DM_SETGID ((lib9p_dm_t)(UINT32_C(1)<<18))
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+#define _LIB9P_DM_UNUSED_17 ((lib9p_dm_t)(UINT32_C(1)<<17))
+#define _LIB9P_DM_UNUSED_16 ((lib9p_dm_t)(UINT32_C(1)<<16))
+#define _LIB9P_DM_UNUSED_15 ((lib9p_dm_t)(UINT32_C(1)<<15))
+#define _LIB9P_DM_UNUSED_14 ((lib9p_dm_t)(UINT32_C(1)<<14))
+#define _LIB9P_DM_UNUSED_13 ((lib9p_dm_t)(UINT32_C(1)<<13))
+#define _LIB9P_DM_UNUSED_12 ((lib9p_dm_t)(UINT32_C(1)<<12))
+#define _LIB9P_DM_UNUSED_11 ((lib9p_dm_t)(UINT32_C(1)<<11))
+#define _LIB9P_DM_UNUSED_10 ((lib9p_dm_t)(UINT32_C(1)<<10))
+#define _LIB9P_DM_UNUSED_9 ((lib9p_dm_t)(UINT32_C(1)<<9))
+#define LIB9P_DM_OWNER_R ((lib9p_dm_t)(UINT32_C(1)<<8))
+#define LIB9P_DM_OWNER_W ((lib9p_dm_t)(UINT32_C(1)<<7))
+#define LIB9P_DM_OWNER_X ((lib9p_dm_t)(UINT32_C(1)<<6))
+#define LIB9P_DM_GROUP_R ((lib9p_dm_t)(UINT32_C(1)<<5))
+#define LIB9P_DM_GROUP_W ((lib9p_dm_t)(UINT32_C(1)<<4))
+#define LIB9P_DM_GROUP_X ((lib9p_dm_t)(UINT32_C(1)<<3))
+#define LIB9P_DM_OTHER_R ((lib9p_dm_t)(UINT32_C(1)<<2))
+#define LIB9P_DM_OTHER_W ((lib9p_dm_t)(UINT32_C(1)<<1))
+#define LIB9P_DM_OTHER_X ((lib9p_dm_t)(UINT32_C(1)<<0))
+/* masks */
+#define LIB9P_DM_PERM_MASK ((lib9p_dm_t)(0b000000000000000000000111111111))
-#define LIB9P_DM_DIR ((lib9p_dm_t)(1<<31))
-#define LIB9P_DM_APPEND ((lib9p_dm_t)(1<<30))
-#define LIB9P_DM_EXCL ((lib9p_dm_t)(1<<29))
-#define _LIB9P_DM_PLAN9_MOUNT ((lib9p_dm_t)(1<<28))
-#define LIB9P_DM_AUTH ((lib9p_dm_t)(1<<27))
-#define LIB9P_DM_TMP ((lib9p_dm_t)(1<<26))
-/* unused ((lib9p_dm_t)(1<<25)) */
-/* unused ((lib9p_dm_t)(1<<24)) */
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
-# define LIB9P_DM_DEVICE ((lib9p_dm_t)(1<<23))
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
-/* unused ((lib9p_dm_t)(1<<22)) */
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
-# define LIB9P_DM_NAMEDPIPE ((lib9p_dm_t)(1<<21))
-# define LIB9P_DM_SOCKET ((lib9p_dm_t)(1<<20))
-# define LIB9P_DM_SETUID ((lib9p_dm_t)(1<<19))
-# define LIB9P_DM_SETGID ((lib9p_dm_t)(1<<18))
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
-/* unused ((lib9p_dm_t)(1<<17)) */
-/* unused ((lib9p_dm_t)(1<<16)) */
-/* unused ((lib9p_dm_t)(1<<15)) */
-/* unused ((lib9p_dm_t)(1<<14)) */
-/* unused ((lib9p_dm_t)(1<<13)) */
-/* unused ((lib9p_dm_t)(1<<12)) */
-/* unused ((lib9p_dm_t)(1<<11)) */
-/* unused ((lib9p_dm_t)(1<<10)) */
-/* unused ((lib9p_dm_t)(1<<9)) */
-#define LIB9P_DM_OWNER_R ((lib9p_dm_t)(1<<8))
-#define LIB9P_DM_OWNER_W ((lib9p_dm_t)(1<<7))
-#define LIB9P_DM_OWNER_X ((lib9p_dm_t)(1<<6))
-#define LIB9P_DM_GROUP_R ((lib9p_dm_t)(1<<5))
-#define LIB9P_DM_GROUP_W ((lib9p_dm_t)(1<<4))
-#define LIB9P_DM_GROUP_X ((lib9p_dm_t)(1<<3))
-#define LIB9P_DM_OTHER_R ((lib9p_dm_t)(1<<2))
-#define LIB9P_DM_OTHER_W ((lib9p_dm_t)(1<<1))
-#define LIB9P_DM_OTHER_X ((lib9p_dm_t)(1<<0))
-
-#define LIB9P_DM_PERM_MASK ((lib9p_dm_t)(0777))
-
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+/* size = 1 ; max_iov = 1 ; max_copy = 1 */
typedef uint8_t lib9p_qt_t;
+LO_IMPLEMENTATION_H(fmt_formatter, lib9p_qt_t, lib9p_qt);
+/* bits */
+#define LIB9P_QT_DIR ((lib9p_qt_t)(UINT8_C(1)<<7))
+#define LIB9P_QT_APPEND ((lib9p_qt_t)(UINT8_C(1)<<6))
+#define LIB9P_QT_EXCL ((lib9p_qt_t)(UINT8_C(1)<<5))
+#define _LIB9P_QT_PLAN9_MOUNT ((lib9p_qt_t)(UINT8_C(1)<<4))
+#define LIB9P_QT_AUTH ((lib9p_qt_t)(UINT8_C(1)<<3))
+#define LIB9P_QT_TMP ((lib9p_qt_t)(UINT8_C(1)<<2))
+#if CONFIG_9P_ENABLE_9P2000_u
+# define LIB9P_QT_SYMLINK ((lib9p_qt_t)(UINT8_C(1)<<1))
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+#define _LIB9P_QT_UNUSED_0 ((lib9p_qt_t)(UINT8_C(1)<<0))
+/* aliases */
+#define LIB9P_QT_FILE ((lib9p_qt_t)(0))
-#define LIB9P_QT_DIR ((lib9p_qt_t)(1<<7))
-#define LIB9P_QT_APPEND ((lib9p_qt_t)(1<<6))
-#define LIB9P_QT_EXCL ((lib9p_qt_t)(1<<5))
-#define _LIB9P_QT_PLAN9_MOUNT ((lib9p_qt_t)(1<<4))
-#define LIB9P_QT_AUTH ((lib9p_qt_t)(1<<3))
-#define LIB9P_QT_TMP ((lib9p_qt_t)(1<<2))
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
-# define LIB9P_QT_SYMLINK ((lib9p_qt_t)(1<<1))
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
-/* unused ((lib9p_qt_t)(1<<0)) */
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
+/* size = 4 ; max_iov = 1 ; max_copy = 4 */
+typedef uint32_t lib9p_nuid_t;
+LO_IMPLEMENTATION_H(fmt_formatter, lib9p_nuid_t, lib9p_nuid);
+#define LIB9P_NUID_NONUID ((lib9p_nuid_t)(UINT32_MAX))
-#define LIB9P_QT_FILE ((lib9p_qt_t)(0))
+#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+/* size = 1 ; max_iov = 1 ; max_copy = 1 */
+typedef uint8_t lib9p_o_t;
+LO_IMPLEMENTATION_H(fmt_formatter, lib9p_o_t, lib9p_o);
+/* bits */
+#define _LIB9P_O_UNUSED_7 ((lib9p_o_t)(UINT8_C(1)<<7))
+#define LIB9P_O_RCLOSE ((lib9p_o_t)(UINT8_C(1)<<6))
+#define _LIB9P_O_RESERVED_CEXEC ((lib9p_o_t)(UINT8_C(1)<<5))
+#define LIB9P_O_TRUNC ((lib9p_o_t)(UINT8_C(1)<<4))
+#define _LIB9P_O_UNUSED_3 ((lib9p_o_t)(UINT8_C(1)<<3))
+#define _LIB9P_O_UNUSED_2 ((lib9p_o_t)(UINT8_C(1)<<2))
+/* number LIB9P_O_MODE_* ((lib9p_o_t)(UINT8_C(1)<<1)) */
+/* number LIB9P_O_MODE_* ((lib9p_o_t)(UINT8_C(1)<<0)) */
+/* masks */
+#define LIB9P_O_FLAG_MASK ((lib9p_o_t)(0b11111100))
+/* number: MODE */
+#define LIB9P_O_MODE_READ ((lib9p_o_t)(0))
+#define LIB9P_O_MODE_WRITE ((lib9p_o_t)(1))
+#define LIB9P_O_MODE_RDWR ((lib9p_o_t)(2))
+#define LIB9P_O_MODE_EXEC ((lib9p_o_t)(3))
+#define LIB9P_O_MODE_MASK ((lib9p_o_t)(0b000011))
-struct lib9p_qid {
- lib9p_qt_t type;
- uint32_t vers;
- uint64_t path;
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
+/* size = 4 ; max_iov = 1 ; max_copy = 4 */
+typedef uint32_t lib9p_errno_t;
+LO_IMPLEMENTATION_H(fmt_formatter, lib9p_errno_t, lib9p_errno);
+#define LIB9P_ERRNO_NOERROR ((lib9p_errno_t)(0))
+
+#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000_L
+/* size = 4 ; max_iov = 1 ; max_copy = 4 */
+typedef uint32_t lib9p_super_magic_t;
+LO_IMPLEMENTATION_H(fmt_formatter, lib9p_super_magic_t, lib9p_super_magic);
+#define LIB9P_SUPER_MAGIC_V9FS_MAGIC ((lib9p_super_magic_t)(16914839))
+
+/* size = 4 ; max_iov = 1 ; max_copy = 4 */
+typedef uint32_t lib9p_lo_t;
+LO_IMPLEMENTATION_H(fmt_formatter, lib9p_lo_t, lib9p_lo);
+/* bits */
+#define _LIB9P_LO_UNUSED_31 ((lib9p_lo_t)(UINT32_C(1)<<31))
+#define _LIB9P_LO_UNUSED_30 ((lib9p_lo_t)(UINT32_C(1)<<30))
+#define _LIB9P_LO_UNUSED_29 ((lib9p_lo_t)(UINT32_C(1)<<29))
+#define _LIB9P_LO_UNUSED_28 ((lib9p_lo_t)(UINT32_C(1)<<28))
+#define _LIB9P_LO_UNUSED_27 ((lib9p_lo_t)(UINT32_C(1)<<27))
+#define _LIB9P_LO_UNUSED_26 ((lib9p_lo_t)(UINT32_C(1)<<26))
+#define _LIB9P_LO_UNUSED_25 ((lib9p_lo_t)(UINT32_C(1)<<25))
+#define _LIB9P_LO_UNUSED_24 ((lib9p_lo_t)(UINT32_C(1)<<24))
+#define _LIB9P_LO_UNUSED_23 ((lib9p_lo_t)(UINT32_C(1)<<23))
+#define _LIB9P_LO_UNUSED_22 ((lib9p_lo_t)(UINT32_C(1)<<22))
+#define _LIB9P_LO_UNUSED_21 ((lib9p_lo_t)(UINT32_C(1)<<21))
+#define LIB9P_LO_SYNC ((lib9p_lo_t)(UINT32_C(1)<<20))
+#define LIB9P_LO_CLOEXEC ((lib9p_lo_t)(UINT32_C(1)<<19))
+#define LIB9P_LO_NOATIME ((lib9p_lo_t)(UINT32_C(1)<<18))
+#define LIB9P_LO_NOFOLLOW ((lib9p_lo_t)(UINT32_C(1)<<17))
+#define LIB9P_LO_DIRECTORY ((lib9p_lo_t)(UINT32_C(1)<<16))
+#define LIB9P_LO_LARGEFILE ((lib9p_lo_t)(UINT32_C(1)<<15))
+#define LIB9P_LO_DIRECT ((lib9p_lo_t)(UINT32_C(1)<<14))
+#define LIB9P_LO_BSD_FASYNC ((lib9p_lo_t)(UINT32_C(1)<<13))
+#define LIB9P_LO_DSYNC ((lib9p_lo_t)(UINT32_C(1)<<12))
+#define LIB9P_LO_NONBLOCK ((lib9p_lo_t)(UINT32_C(1)<<11))
+#define LIB9P_LO_APPEND ((lib9p_lo_t)(UINT32_C(1)<<10))
+#define LIB9P_LO_TRUNC ((lib9p_lo_t)(UINT32_C(1)<<9))
+#define LIB9P_LO_NOCTTY ((lib9p_lo_t)(UINT32_C(1)<<8))
+#define LIB9P_LO_EXCL ((lib9p_lo_t)(UINT32_C(1)<<7))
+#define LIB9P_LO_CREATE ((lib9p_lo_t)(UINT32_C(1)<<6))
+#define _LIB9P_LO_UNUSED_5 ((lib9p_lo_t)(UINT32_C(1)<<5))
+#define _LIB9P_LO_UNUSED_4 ((lib9p_lo_t)(UINT32_C(1)<<4))
+#define _LIB9P_LO_UNUSED_3 ((lib9p_lo_t)(UINT32_C(1)<<3))
+#define _LIB9P_LO_UNUSED_2 ((lib9p_lo_t)(UINT32_C(1)<<2))
+/* number LIB9P_LO_MODE_* ((lib9p_lo_t)(UINT32_C(1)<<1)) */
+/* number LIB9P_LO_MODE_* ((lib9p_lo_t)(UINT32_C(1)<<0)) */
+/* masks */
+#define LIB9P_LO_FLAG_MASK ((lib9p_lo_t)(0b000000000111111111111111000000))
+/* number: MODE */
+#define LIB9P_LO_MODE_RDONLY ((lib9p_lo_t)(0))
+#define LIB9P_LO_MODE_WRONLY ((lib9p_lo_t)(1))
+#define LIB9P_LO_MODE_RDWR ((lib9p_lo_t)(2))
+#define LIB9P_LO_MODE_NOACCESS ((lib9p_lo_t)(3))
+#define LIB9P_LO_MODE_MASK ((lib9p_lo_t)(0b000000000000000000000000000011))
+
+/* size = 1 ; max_iov = 1 ; max_copy = 1 */
+typedef uint8_t lib9p_dt_t;
+LO_IMPLEMENTATION_H(fmt_formatter, lib9p_dt_t, lib9p_dt);
+#define LIB9P_DT_UNKNOWN ((lib9p_dt_t)(0))
+#define LIB9P_DT_PIPE ((lib9p_dt_t)(1))
+#define LIB9P_DT_CHAR_DEV ((lib9p_dt_t)(2))
+#define LIB9P_DT_DIRECTORY ((lib9p_dt_t)(4))
+#define LIB9P_DT_BLOCK_DEV ((lib9p_dt_t)(6))
+#define LIB9P_DT_REGULAR ((lib9p_dt_t)(8))
+#define LIB9P_DT_SYMLINK ((lib9p_dt_t)(10))
+#define LIB9P_DT_SOCKET ((lib9p_dt_t)(12))
+#define _LIB9P_DT_WHITEOUT ((lib9p_dt_t)(14))
+
+/* size = 4 ; max_iov = 1 ; max_copy = 4 */
+typedef uint32_t lib9p_mode_t;
+LO_IMPLEMENTATION_H(fmt_formatter, lib9p_mode_t, lib9p_mode);
+/* bits */
+#define _LIB9P_MODE_UNUSED_31 ((lib9p_mode_t)(UINT32_C(1)<<31))
+#define _LIB9P_MODE_UNUSED_30 ((lib9p_mode_t)(UINT32_C(1)<<30))
+#define _LIB9P_MODE_UNUSED_29 ((lib9p_mode_t)(UINT32_C(1)<<29))
+#define _LIB9P_MODE_UNUSED_28 ((lib9p_mode_t)(UINT32_C(1)<<28))
+#define _LIB9P_MODE_UNUSED_27 ((lib9p_mode_t)(UINT32_C(1)<<27))
+#define _LIB9P_MODE_UNUSED_26 ((lib9p_mode_t)(UINT32_C(1)<<26))
+#define _LIB9P_MODE_UNUSED_25 ((lib9p_mode_t)(UINT32_C(1)<<25))
+#define _LIB9P_MODE_UNUSED_24 ((lib9p_mode_t)(UINT32_C(1)<<24))
+#define _LIB9P_MODE_UNUSED_23 ((lib9p_mode_t)(UINT32_C(1)<<23))
+#define _LIB9P_MODE_UNUSED_22 ((lib9p_mode_t)(UINT32_C(1)<<22))
+#define _LIB9P_MODE_UNUSED_21 ((lib9p_mode_t)(UINT32_C(1)<<21))
+#define _LIB9P_MODE_UNUSED_20 ((lib9p_mode_t)(UINT32_C(1)<<20))
+#define _LIB9P_MODE_UNUSED_19 ((lib9p_mode_t)(UINT32_C(1)<<19))
+#define _LIB9P_MODE_UNUSED_18 ((lib9p_mode_t)(UINT32_C(1)<<18))
+#define _LIB9P_MODE_UNUSED_17 ((lib9p_mode_t)(UINT32_C(1)<<17))
+#define _LIB9P_MODE_UNUSED_16 ((lib9p_mode_t)(UINT32_C(1)<<16))
+/* number LIB9P_MODE_FMT_* ((lib9p_mode_t)(UINT32_C(1)<<15)) */
+/* number LIB9P_MODE_FMT_* ((lib9p_mode_t)(UINT32_C(1)<<14)) */
+/* number LIB9P_MODE_FMT_* ((lib9p_mode_t)(UINT32_C(1)<<13)) */
+/* number LIB9P_MODE_FMT_* ((lib9p_mode_t)(UINT32_C(1)<<12)) */
+#define LIB9P_MODE_PERM_SETGROUP ((lib9p_mode_t)(UINT32_C(1)<<11))
+#define LIB9P_MODE_PERM_SETUSER ((lib9p_mode_t)(UINT32_C(1)<<10))
+#define LIB9P_MODE_PERM_STICKY ((lib9p_mode_t)(UINT32_C(1)<<9))
+#define LIB9P_MODE_PERM_OWNER_R ((lib9p_mode_t)(UINT32_C(1)<<8))
+#define LIB9P_MODE_PERM_OWNER_W ((lib9p_mode_t)(UINT32_C(1)<<7))
+#define LIB9P_MODE_PERM_OWNER_X ((lib9p_mode_t)(UINT32_C(1)<<6))
+#define LIB9P_MODE_PERM_GROUP_R ((lib9p_mode_t)(UINT32_C(1)<<5))
+#define LIB9P_MODE_PERM_GROUP_W ((lib9p_mode_t)(UINT32_C(1)<<4))
+#define LIB9P_MODE_PERM_GROUP_X ((lib9p_mode_t)(UINT32_C(1)<<3))
+#define LIB9P_MODE_PERM_OTHER_R ((lib9p_mode_t)(UINT32_C(1)<<2))
+#define LIB9P_MODE_PERM_OTHER_W ((lib9p_mode_t)(UINT32_C(1)<<1))
+#define LIB9P_MODE_PERM_OTHER_X ((lib9p_mode_t)(UINT32_C(1)<<0))
+/* masks */
+#define LIB9P_MODE_PERM_MASK ((lib9p_mode_t)(0b000000000000000000111111111111))
+/* number: FMT */
+#define LIB9P_MODE_FMT_PIPE ((lib9p_mode_t)(LIB9P_DT_PIPE << 12))
+#define LIB9P_MODE_FMT_CHAR_DEV ((lib9p_mode_t)(LIB9P_DT_CHAR_DEV << 12))
+#define LIB9P_MODE_FMT_DIRECTORY ((lib9p_mode_t)(LIB9P_DT_DIRECTORY << 12))
+#define LIB9P_MODE_FMT_BLOCK_DEV ((lib9p_mode_t)(LIB9P_DT_BLOCK_DEV << 12))
+#define LIB9P_MODE_FMT_REGULAR ((lib9p_mode_t)(LIB9P_DT_REGULAR << 12))
+#define LIB9P_MODE_FMT_SYMLINK ((lib9p_mode_t)(LIB9P_DT_SYMLINK << 12))
+#define LIB9P_MODE_FMT_SOCKET ((lib9p_mode_t)(LIB9P_DT_SOCKET << 12))
+#define LIB9P_MODE_FMT_MASK ((lib9p_mode_t)(0b000000000000001111000000000000))
+
+/* size = 4 ; max_iov = 1 ; max_copy = 4 */
+typedef uint32_t lib9p_b4_t;
+LO_IMPLEMENTATION_H(fmt_formatter, lib9p_b4_t, lib9p_b4);
+#define LIB9P_B4_FALSE ((lib9p_b4_t)(0))
+#define LIB9P_B4_TRUE ((lib9p_b4_t)(1))
+
+/* size = 8 ; max_iov = 1 ; max_copy = 8 */
+typedef uint64_t lib9p_getattr_t;
+LO_IMPLEMENTATION_H(fmt_formatter, lib9p_getattr_t, lib9p_getattr);
+/* bits */
+#define _LIB9P_GETATTR_UNUSED_63 ((lib9p_getattr_t)(UINT64_C(1)<<63))
+#define _LIB9P_GETATTR_UNUSED_62 ((lib9p_getattr_t)(UINT64_C(1)<<62))
+#define _LIB9P_GETATTR_UNUSED_61 ((lib9p_getattr_t)(UINT64_C(1)<<61))
+#define _LIB9P_GETATTR_UNUSED_60 ((lib9p_getattr_t)(UINT64_C(1)<<60))
+#define _LIB9P_GETATTR_UNUSED_59 ((lib9p_getattr_t)(UINT64_C(1)<<59))
+#define _LIB9P_GETATTR_UNUSED_58 ((lib9p_getattr_t)(UINT64_C(1)<<58))
+#define _LIB9P_GETATTR_UNUSED_57 ((lib9p_getattr_t)(UINT64_C(1)<<57))
+#define _LIB9P_GETATTR_UNUSED_56 ((lib9p_getattr_t)(UINT64_C(1)<<56))
+#define _LIB9P_GETATTR_UNUSED_55 ((lib9p_getattr_t)(UINT64_C(1)<<55))
+#define _LIB9P_GETATTR_UNUSED_54 ((lib9p_getattr_t)(UINT64_C(1)<<54))
+#define _LIB9P_GETATTR_UNUSED_53 ((lib9p_getattr_t)(UINT64_C(1)<<53))
+#define _LIB9P_GETATTR_UNUSED_52 ((lib9p_getattr_t)(UINT64_C(1)<<52))
+#define _LIB9P_GETATTR_UNUSED_51 ((lib9p_getattr_t)(UINT64_C(1)<<51))
+#define _LIB9P_GETATTR_UNUSED_50 ((lib9p_getattr_t)(UINT64_C(1)<<50))
+#define _LIB9P_GETATTR_UNUSED_49 ((lib9p_getattr_t)(UINT64_C(1)<<49))
+#define _LIB9P_GETATTR_UNUSED_48 ((lib9p_getattr_t)(UINT64_C(1)<<48))
+#define _LIB9P_GETATTR_UNUSED_47 ((lib9p_getattr_t)(UINT64_C(1)<<47))
+#define _LIB9P_GETATTR_UNUSED_46 ((lib9p_getattr_t)(UINT64_C(1)<<46))
+#define _LIB9P_GETATTR_UNUSED_45 ((lib9p_getattr_t)(UINT64_C(1)<<45))
+#define _LIB9P_GETATTR_UNUSED_44 ((lib9p_getattr_t)(UINT64_C(1)<<44))
+#define _LIB9P_GETATTR_UNUSED_43 ((lib9p_getattr_t)(UINT64_C(1)<<43))
+#define _LIB9P_GETATTR_UNUSED_42 ((lib9p_getattr_t)(UINT64_C(1)<<42))
+#define _LIB9P_GETATTR_UNUSED_41 ((lib9p_getattr_t)(UINT64_C(1)<<41))
+#define _LIB9P_GETATTR_UNUSED_40 ((lib9p_getattr_t)(UINT64_C(1)<<40))
+#define _LIB9P_GETATTR_UNUSED_39 ((lib9p_getattr_t)(UINT64_C(1)<<39))
+#define _LIB9P_GETATTR_UNUSED_38 ((lib9p_getattr_t)(UINT64_C(1)<<38))
+#define _LIB9P_GETATTR_UNUSED_37 ((lib9p_getattr_t)(UINT64_C(1)<<37))
+#define _LIB9P_GETATTR_UNUSED_36 ((lib9p_getattr_t)(UINT64_C(1)<<36))
+#define _LIB9P_GETATTR_UNUSED_35 ((lib9p_getattr_t)(UINT64_C(1)<<35))
+#define _LIB9P_GETATTR_UNUSED_34 ((lib9p_getattr_t)(UINT64_C(1)<<34))
+#define _LIB9P_GETATTR_UNUSED_33 ((lib9p_getattr_t)(UINT64_C(1)<<33))
+#define _LIB9P_GETATTR_UNUSED_32 ((lib9p_getattr_t)(UINT64_C(1)<<32))
+#define _LIB9P_GETATTR_UNUSED_31 ((lib9p_getattr_t)(UINT64_C(1)<<31))
+#define _LIB9P_GETATTR_UNUSED_30 ((lib9p_getattr_t)(UINT64_C(1)<<30))
+#define _LIB9P_GETATTR_UNUSED_29 ((lib9p_getattr_t)(UINT64_C(1)<<29))
+#define _LIB9P_GETATTR_UNUSED_28 ((lib9p_getattr_t)(UINT64_C(1)<<28))
+#define _LIB9P_GETATTR_UNUSED_27 ((lib9p_getattr_t)(UINT64_C(1)<<27))
+#define _LIB9P_GETATTR_UNUSED_26 ((lib9p_getattr_t)(UINT64_C(1)<<26))
+#define _LIB9P_GETATTR_UNUSED_25 ((lib9p_getattr_t)(UINT64_C(1)<<25))
+#define _LIB9P_GETATTR_UNUSED_24 ((lib9p_getattr_t)(UINT64_C(1)<<24))
+#define _LIB9P_GETATTR_UNUSED_23 ((lib9p_getattr_t)(UINT64_C(1)<<23))
+#define _LIB9P_GETATTR_UNUSED_22 ((lib9p_getattr_t)(UINT64_C(1)<<22))
+#define _LIB9P_GETATTR_UNUSED_21 ((lib9p_getattr_t)(UINT64_C(1)<<21))
+#define _LIB9P_GETATTR_UNUSED_20 ((lib9p_getattr_t)(UINT64_C(1)<<20))
+#define _LIB9P_GETATTR_UNUSED_19 ((lib9p_getattr_t)(UINT64_C(1)<<19))
+#define _LIB9P_GETATTR_UNUSED_18 ((lib9p_getattr_t)(UINT64_C(1)<<18))
+#define _LIB9P_GETATTR_UNUSED_17 ((lib9p_getattr_t)(UINT64_C(1)<<17))
+#define _LIB9P_GETATTR_UNUSED_16 ((lib9p_getattr_t)(UINT64_C(1)<<16))
+#define _LIB9P_GETATTR_UNUSED_15 ((lib9p_getattr_t)(UINT64_C(1)<<15))
+#define _LIB9P_GETATTR_UNUSED_14 ((lib9p_getattr_t)(UINT64_C(1)<<14))
+#define LIB9P_GETATTR_DATA_VERSION ((lib9p_getattr_t)(UINT64_C(1)<<13))
+#define LIB9P_GETATTR_GEN ((lib9p_getattr_t)(UINT64_C(1)<<12))
+#define LIB9P_GETATTR_BTIME ((lib9p_getattr_t)(UINT64_C(1)<<11))
+#define LIB9P_GETATTR_BLOCKS ((lib9p_getattr_t)(UINT64_C(1)<<10))
+#define LIB9P_GETATTR_SIZE ((lib9p_getattr_t)(UINT64_C(1)<<9))
+#define LIB9P_GETATTR_INO ((lib9p_getattr_t)(UINT64_C(1)<<8))
+#define LIB9P_GETATTR_CTIME ((lib9p_getattr_t)(UINT64_C(1)<<7))
+#define LIB9P_GETATTR_MTIME ((lib9p_getattr_t)(UINT64_C(1)<<6))
+#define LIB9P_GETATTR_ATIME ((lib9p_getattr_t)(UINT64_C(1)<<5))
+#define LIB9P_GETATTR_RDEV ((lib9p_getattr_t)(UINT64_C(1)<<4))
+#define LIB9P_GETATTR_GID ((lib9p_getattr_t)(UINT64_C(1)<<3))
+#define LIB9P_GETATTR_UID ((lib9p_getattr_t)(UINT64_C(1)<<2))
+#define LIB9P_GETATTR_NLINK ((lib9p_getattr_t)(UINT64_C(1)<<1))
+#define LIB9P_GETATTR_MODE ((lib9p_getattr_t)(UINT64_C(1)<<0))
+/* aliases */
+#define LIB9P_GETATTR_BASIC ((lib9p_getattr_t)(2047))
+#define LIB9P_GETATTR_ALL ((lib9p_getattr_t)(16383))
+
+/* size = 4 ; max_iov = 1 ; max_copy = 4 */
+typedef uint32_t lib9p_setattr_t;
+LO_IMPLEMENTATION_H(fmt_formatter, lib9p_setattr_t, lib9p_setattr);
+/* bits */
+#define _LIB9P_SETATTR_UNUSED_31 ((lib9p_setattr_t)(UINT32_C(1)<<31))
+#define _LIB9P_SETATTR_UNUSED_30 ((lib9p_setattr_t)(UINT32_C(1)<<30))
+#define _LIB9P_SETATTR_UNUSED_29 ((lib9p_setattr_t)(UINT32_C(1)<<29))
+#define _LIB9P_SETATTR_UNUSED_28 ((lib9p_setattr_t)(UINT32_C(1)<<28))
+#define _LIB9P_SETATTR_UNUSED_27 ((lib9p_setattr_t)(UINT32_C(1)<<27))
+#define _LIB9P_SETATTR_UNUSED_26 ((lib9p_setattr_t)(UINT32_C(1)<<26))
+#define _LIB9P_SETATTR_UNUSED_25 ((lib9p_setattr_t)(UINT32_C(1)<<25))
+#define _LIB9P_SETATTR_UNUSED_24 ((lib9p_setattr_t)(UINT32_C(1)<<24))
+#define _LIB9P_SETATTR_UNUSED_23 ((lib9p_setattr_t)(UINT32_C(1)<<23))
+#define _LIB9P_SETATTR_UNUSED_22 ((lib9p_setattr_t)(UINT32_C(1)<<22))
+#define _LIB9P_SETATTR_UNUSED_21 ((lib9p_setattr_t)(UINT32_C(1)<<21))
+#define _LIB9P_SETATTR_UNUSED_20 ((lib9p_setattr_t)(UINT32_C(1)<<20))
+#define _LIB9P_SETATTR_UNUSED_19 ((lib9p_setattr_t)(UINT32_C(1)<<19))
+#define _LIB9P_SETATTR_UNUSED_18 ((lib9p_setattr_t)(UINT32_C(1)<<18))
+#define _LIB9P_SETATTR_UNUSED_17 ((lib9p_setattr_t)(UINT32_C(1)<<17))
+#define _LIB9P_SETATTR_UNUSED_16 ((lib9p_setattr_t)(UINT32_C(1)<<16))
+#define _LIB9P_SETATTR_UNUSED_15 ((lib9p_setattr_t)(UINT32_C(1)<<15))
+#define _LIB9P_SETATTR_UNUSED_14 ((lib9p_setattr_t)(UINT32_C(1)<<14))
+#define _LIB9P_SETATTR_UNUSED_13 ((lib9p_setattr_t)(UINT32_C(1)<<13))
+#define _LIB9P_SETATTR_UNUSED_12 ((lib9p_setattr_t)(UINT32_C(1)<<12))
+#define _LIB9P_SETATTR_UNUSED_11 ((lib9p_setattr_t)(UINT32_C(1)<<11))
+#define _LIB9P_SETATTR_UNUSED_10 ((lib9p_setattr_t)(UINT32_C(1)<<10))
+#define _LIB9P_SETATTR_UNUSED_9 ((lib9p_setattr_t)(UINT32_C(1)<<9))
+#define LIB9P_SETATTR_MTIME_SET ((lib9p_setattr_t)(UINT32_C(1)<<8))
+#define LIB9P_SETATTR_ATIME_SET ((lib9p_setattr_t)(UINT32_C(1)<<7))
+#define LIB9P_SETATTR_CTIME ((lib9p_setattr_t)(UINT32_C(1)<<6))
+#define LIB9P_SETATTR_MTIME ((lib9p_setattr_t)(UINT32_C(1)<<5))
+#define LIB9P_SETATTR_ATIME ((lib9p_setattr_t)(UINT32_C(1)<<4))
+#define LIB9P_SETATTR_SIZE ((lib9p_setattr_t)(UINT32_C(1)<<3))
+#define LIB9P_SETATTR_GID ((lib9p_setattr_t)(UINT32_C(1)<<2))
+#define LIB9P_SETATTR_UID ((lib9p_setattr_t)(UINT32_C(1)<<1))
+#define LIB9P_SETATTR_MODE ((lib9p_setattr_t)(UINT32_C(1)<<0))
+
+/* size = 1 ; max_iov = 1 ; max_copy = 1 */
+typedef uint8_t lib9p_lock_type_t;
+LO_IMPLEMENTATION_H(fmt_formatter, lib9p_lock_type_t, lib9p_lock_type);
+#define LIB9P_LOCK_TYPE_RDLCK ((lib9p_lock_type_t)(0))
+#define LIB9P_LOCK_TYPE_WRLCK ((lib9p_lock_type_t)(1))
+#define LIB9P_LOCK_TYPE_UNLCK ((lib9p_lock_type_t)(2))
+
+/* size = 4 ; max_iov = 1 ; max_copy = 4 */
+typedef uint32_t lib9p_lock_flags_t;
+LO_IMPLEMENTATION_H(fmt_formatter, lib9p_lock_flags_t, lib9p_lock_flags);
+/* bits */
+#define _LIB9P_LOCK_FLAGS_UNUSED_31 ((lib9p_lock_flags_t)(UINT32_C(1)<<31))
+#define _LIB9P_LOCK_FLAGS_UNUSED_30 ((lib9p_lock_flags_t)(UINT32_C(1)<<30))
+#define _LIB9P_LOCK_FLAGS_UNUSED_29 ((lib9p_lock_flags_t)(UINT32_C(1)<<29))
+#define _LIB9P_LOCK_FLAGS_UNUSED_28 ((lib9p_lock_flags_t)(UINT32_C(1)<<28))
+#define _LIB9P_LOCK_FLAGS_UNUSED_27 ((lib9p_lock_flags_t)(UINT32_C(1)<<27))
+#define _LIB9P_LOCK_FLAGS_UNUSED_26 ((lib9p_lock_flags_t)(UINT32_C(1)<<26))
+#define _LIB9P_LOCK_FLAGS_UNUSED_25 ((lib9p_lock_flags_t)(UINT32_C(1)<<25))
+#define _LIB9P_LOCK_FLAGS_UNUSED_24 ((lib9p_lock_flags_t)(UINT32_C(1)<<24))
+#define _LIB9P_LOCK_FLAGS_UNUSED_23 ((lib9p_lock_flags_t)(UINT32_C(1)<<23))
+#define _LIB9P_LOCK_FLAGS_UNUSED_22 ((lib9p_lock_flags_t)(UINT32_C(1)<<22))
+#define _LIB9P_LOCK_FLAGS_UNUSED_21 ((lib9p_lock_flags_t)(UINT32_C(1)<<21))
+#define _LIB9P_LOCK_FLAGS_UNUSED_20 ((lib9p_lock_flags_t)(UINT32_C(1)<<20))
+#define _LIB9P_LOCK_FLAGS_UNUSED_19 ((lib9p_lock_flags_t)(UINT32_C(1)<<19))
+#define _LIB9P_LOCK_FLAGS_UNUSED_18 ((lib9p_lock_flags_t)(UINT32_C(1)<<18))
+#define _LIB9P_LOCK_FLAGS_UNUSED_17 ((lib9p_lock_flags_t)(UINT32_C(1)<<17))
+#define _LIB9P_LOCK_FLAGS_UNUSED_16 ((lib9p_lock_flags_t)(UINT32_C(1)<<16))
+#define _LIB9P_LOCK_FLAGS_UNUSED_15 ((lib9p_lock_flags_t)(UINT32_C(1)<<15))
+#define _LIB9P_LOCK_FLAGS_UNUSED_14 ((lib9p_lock_flags_t)(UINT32_C(1)<<14))
+#define _LIB9P_LOCK_FLAGS_UNUSED_13 ((lib9p_lock_flags_t)(UINT32_C(1)<<13))
+#define _LIB9P_LOCK_FLAGS_UNUSED_12 ((lib9p_lock_flags_t)(UINT32_C(1)<<12))
+#define _LIB9P_LOCK_FLAGS_UNUSED_11 ((lib9p_lock_flags_t)(UINT32_C(1)<<11))
+#define _LIB9P_LOCK_FLAGS_UNUSED_10 ((lib9p_lock_flags_t)(UINT32_C(1)<<10))
+#define _LIB9P_LOCK_FLAGS_UNUSED_9 ((lib9p_lock_flags_t)(UINT32_C(1)<<9))
+#define _LIB9P_LOCK_FLAGS_UNUSED_8 ((lib9p_lock_flags_t)(UINT32_C(1)<<8))
+#define _LIB9P_LOCK_FLAGS_UNUSED_7 ((lib9p_lock_flags_t)(UINT32_C(1)<<7))
+#define _LIB9P_LOCK_FLAGS_UNUSED_6 ((lib9p_lock_flags_t)(UINT32_C(1)<<6))
+#define _LIB9P_LOCK_FLAGS_UNUSED_5 ((lib9p_lock_flags_t)(UINT32_C(1)<<5))
+#define _LIB9P_LOCK_FLAGS_UNUSED_4 ((lib9p_lock_flags_t)(UINT32_C(1)<<4))
+#define _LIB9P_LOCK_FLAGS_UNUSED_3 ((lib9p_lock_flags_t)(UINT32_C(1)<<3))
+#define _LIB9P_LOCK_FLAGS_UNUSED_2 ((lib9p_lock_flags_t)(UINT32_C(1)<<2))
+#define LIB9P_LOCK_FLAGS_RECLAIM ((lib9p_lock_flags_t)(UINT32_C(1)<<1))
+#define LIB9P_LOCK_FLAGS_BLOCK ((lib9p_lock_flags_t)(UINT32_C(1)<<0))
+
+/* size = 1 ; max_iov = 1 ; max_copy = 1 */
+typedef uint8_t lib9p_lock_status_t;
+LO_IMPLEMENTATION_H(fmt_formatter, lib9p_lock_status_t, lib9p_lock_status);
+#define LIB9P_LOCK_STATUS_SUCCESS ((lib9p_lock_status_t)(0))
+#define LIB9P_LOCK_STATUS_BLOCKED ((lib9p_lock_status_t)(1))
+#define LIB9P_LOCK_STATUS_ERROR ((lib9p_lock_status_t)(2))
+#define LIB9P_LOCK_STATUS_GRACE ((lib9p_lock_status_t)(3))
+
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+/* size = 9 ; max_iov = 1 ; max_copy = 9 */
+struct lib9p_msg_Tflush {
+ lib9p_tag_t tag;
+ uint16_t oldtag;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tflush, lib9p_msg_Tflush);
-struct lib9p_stat {
- uint16_t kern_type;
- uint32_t kern_dev;
- struct lib9p_qid file_qid;
- lib9p_dm_t file_mode;
- uint32_t file_atime;
- uint32_t file_mtime;
- uint64_t file_size;
- struct lib9p_s file_name;
- struct lib9p_s file_owner_uid;
- struct lib9p_s file_owner_gid;
- struct lib9p_s file_last_modified_uid;
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
- struct lib9p_s file_extension;
- uint32_t file_owner_n_uid;
- uint32_t file_owner_n_gid;
- uint32_t file_last_modified_n_uid;
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
+/* size = 7 ; max_iov = 1 ; max_copy = 7 */
+struct lib9p_msg_Rflush {
+ lib9p_tag_t tag;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rflush, lib9p_msg_Rflush);
-typedef uint8_t lib9p_o_t;
+/* min_size = 11 ; exp_size = 8,203 ; max_size = 2,147,483,658 ; max_iov = 2 ; max_copy = 11 */
+struct lib9p_msg_Rread {
+ lib9p_tag_t tag;
+ uint32_t count;
+ [[gnu::nonstring]] char *data;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rread, lib9p_msg_Rread);
-/* unused ((lib9p_o_t)(1<<7)) */
-#define LIB9P_O_RCLOSE ((lib9p_o_t)(1<<6))
-/* unused ((lib9p_o_t)(1<<5)) */
-#define LIB9P_O_TRUNC ((lib9p_o_t)(1<<4))
-/* unused ((lib9p_o_t)(1<<3)) */
-/* unused ((lib9p_o_t)(1<<2)) */
-#define LIB9P_O_mode_1 ((lib9p_o_t)(1<<1))
-#define LIB9P_O_mode_0 ((lib9p_o_t)(1<<0))
-
-#define LIB9P_O_READ ((lib9p_o_t)(0))
-#define LIB9P_O_WRITE ((lib9p_o_t)(1))
-#define LIB9P_O_RDWR ((lib9p_o_t)(2))
-#define LIB9P_O_EXEC ((lib9p_o_t)(3))
-#define LIB9P_O_MODE_MASK ((lib9p_o_t)(0b00000011))
-#define LIB9P_O_FLAG_MASK ((lib9p_o_t)(0b11111100))
-#endif /* defined(CONFIG_9P_ENABLE_9P2000) || defined(CONFIG_9P_ENABLE_9P2000_e) || defined(CONFIG_9P_ENABLE_9P2000_u) */
-
-/* messages *******************************************************************/
+/* size = 11 ; max_iov = 1 ; max_copy = 11 */
+struct lib9p_msg_Rwrite {
+ lib9p_tag_t tag;
+ uint32_t count;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rwrite, lib9p_msg_Rwrite);
-enum lib9p_msg_type { /* uint8_t */
-#if defined(CONFIG_9P_ENABLE_9P2000) || defined(CONFIG_9P_ENABLE_9P2000_e) || defined(CONFIG_9P_ENABLE_9P2000_u)
- LIB9P_TYP_Tversion = 100,
- LIB9P_TYP_Rversion = 101,
- LIB9P_TYP_Tauth = 102,
- LIB9P_TYP_Rauth = 103,
- LIB9P_TYP_Tattach = 104,
- LIB9P_TYP_Rattach = 105,
- LIB9P_TYP_Rerror = 107,
- LIB9P_TYP_Tflush = 108,
- LIB9P_TYP_Rflush = 109,
- LIB9P_TYP_Twalk = 110,
- LIB9P_TYP_Rwalk = 111,
- LIB9P_TYP_Topen = 112,
- LIB9P_TYP_Ropen = 113,
- LIB9P_TYP_Tcreate = 114,
- LIB9P_TYP_Rcreate = 115,
- LIB9P_TYP_Tread = 116,
- LIB9P_TYP_Rread = 117,
- LIB9P_TYP_Twrite = 118,
- LIB9P_TYP_Rwrite = 119,
- LIB9P_TYP_Tclunk = 120,
- LIB9P_TYP_Rclunk = 121,
- LIB9P_TYP_Tremove = 122,
- LIB9P_TYP_Rremove = 123,
- LIB9P_TYP_Tstat = 124,
- LIB9P_TYP_Rstat = 125,
- LIB9P_TYP_Twstat = 126,
- LIB9P_TYP_Rwstat = 127,
-#endif /* defined(CONFIG_9P_ENABLE_9P2000) || defined(CONFIG_9P_ENABLE_9P2000_e) || defined(CONFIG_9P_ENABLE_9P2000_u) */
-#if defined(CONFIG_9P_ENABLE_9P2000_e)
- LIB9P_TYP_Tsession = 150,
- LIB9P_TYP_Rsession = 151,
- LIB9P_TYP_Tsread = 152,
- LIB9P_TYP_Rsread = 153,
- LIB9P_TYP_Tswrite = 154,
- LIB9P_TYP_Rswrite = 155,
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_e) */
-};
-
-#if defined(CONFIG_9P_ENABLE_9P2000) || defined(CONFIG_9P_ENABLE_9P2000_e) || defined(CONFIG_9P_ENABLE_9P2000_u)
+/* size = 7 ; max_iov = 1 ; max_copy = 7 */
+struct lib9p_msg_Rclunk {
+ lib9p_tag_t tag;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rclunk, lib9p_msg_Rclunk);
+
+/* size = 7 ; max_iov = 1 ; max_copy = 7 */
+struct lib9p_msg_Rremove {
+ lib9p_tag_t tag;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rremove, lib9p_msg_Rremove);
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+/* size = 7 ; max_iov = 1 ; max_copy = 7 */
+struct lib9p_msg_Rwstat {
+ lib9p_tag_t tag;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rwstat, lib9p_msg_Rwstat);
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000_L
+/* size = 7 ; max_iov = 1 ; max_copy = 7 */
+struct lib9p_msg_Rrename {
+ lib9p_tag_t tag;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rrename, lib9p_msg_Rrename);
+
+/* size = 7 ; max_iov = 1 ; max_copy = 7 */
+struct lib9p_msg_Rsetattr {
+ lib9p_tag_t tag;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rsetattr, lib9p_msg_Rsetattr);
+
+/* size = 15 ; max_iov = 1 ; max_copy = 15 */
+struct lib9p_msg_Rxattrwalk {
+ lib9p_tag_t tag;
+ uint64_t attr_size;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rxattrwalk, lib9p_msg_Rxattrwalk);
+
+/* size = 7 ; max_iov = 1 ; max_copy = 7 */
+struct lib9p_msg_Rxattrcreate {
+ lib9p_tag_t tag;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rxattrcreate, lib9p_msg_Rxattrcreate);
+
+/* min_size = 11 ; exp_size = 8,203 ; max_size = 4,294,967,306 (warning: >UINT32_MAX) ; max_iov = 2 ; max_copy = 11 */
+struct lib9p_msg_Rreaddir {
+ lib9p_tag_t tag;
+ uint32_t count;
+ [[gnu::nonstring]] char *data;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rreaddir, lib9p_msg_Rreaddir);
+
+/* size = 7 ; max_iov = 1 ; max_copy = 7 */
+struct lib9p_msg_Rfsync {
+ lib9p_tag_t tag;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rfsync, lib9p_msg_Rfsync);
+
+/* size = 7 ; max_iov = 1 ; max_copy = 7 */
+struct lib9p_msg_Rlink {
+ lib9p_tag_t tag;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rlink, lib9p_msg_Rlink);
+
+/* size = 7 ; max_iov = 1 ; max_copy = 7 */
+struct lib9p_msg_Rrenameat {
+ lib9p_tag_t tag;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rrenameat, lib9p_msg_Rrenameat);
+
+/* size = 7 ; max_iov = 1 ; max_copy = 7 */
+struct lib9p_msg_Runlinkat {
+ lib9p_tag_t tag;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Runlinkat, lib9p_msg_Runlinkat);
+
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000_e
+/* size = 15 ; max_iov = 1 ; max_copy = 15 */
+struct lib9p_msg_Tsession {
+ lib9p_tag_t tag;
+ uint64_t key;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tsession, lib9p_msg_Tsession);
+
+/* size = 7 ; max_iov = 1 ; max_copy = 7 */
+struct lib9p_msg_Rsession {
+ lib9p_tag_t tag;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rsession, lib9p_msg_Rsession);
+
+/* min_size = 11 ; exp_size = 8,203 ; max_size = 4,294,967,306 (warning: >UINT32_MAX) ; max_iov = 2 ; max_copy = 11 */
+struct lib9p_msg_Rsread {
+ lib9p_tag_t tag;
+ uint32_t count;
+ [[gnu::nonstring]] char *data;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rsread, lib9p_msg_Rsread);
+
+/* size = 11 ; max_iov = 1 ; max_copy = 11 */
+struct lib9p_msg_Rswrite {
+ lib9p_tag_t tag;
+ uint32_t count;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rswrite, lib9p_msg_Rswrite);
+
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+/* size = 23 ; max_iov = 1 ; max_copy = 23 */
+struct lib9p_msg_Tread {
+ lib9p_tag_t tag;
+ lib9p_fid_t fid;
+ uint64_t offset;
+ uint32_t count;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tread, lib9p_msg_Tread);
+
+/* min_size = 23 ; exp_size = 8,215 ; max_size = 2,147,483,670 ; max_iov = 2 ; max_copy = 23 */
+struct lib9p_msg_Twrite {
+ lib9p_tag_t tag;
+ lib9p_fid_t fid;
+ uint64_t offset;
+ uint32_t count;
+ [[gnu::nonstring]] char *data;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Twrite, lib9p_msg_Twrite);
+
+/* size = 11 ; max_iov = 1 ; max_copy = 11 */
+struct lib9p_msg_Tclunk {
+ lib9p_tag_t tag;
+ lib9p_fid_t fid;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tclunk, lib9p_msg_Tclunk);
+
+/* size = 11 ; max_iov = 1 ; max_copy = 11 */
+struct lib9p_msg_Tremove {
+ lib9p_tag_t tag;
+ lib9p_fid_t fid;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tremove, lib9p_msg_Tremove);
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+/* size = 11 ; max_iov = 1 ; max_copy = 11 */
+struct lib9p_msg_Tstat {
+ lib9p_tag_t tag;
+ lib9p_fid_t fid;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tstat, lib9p_msg_Tstat);
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000_L
+/* size = 11 ; max_iov = 1 ; max_copy = 11 */
+struct lib9p_msg_Tstatfs {
+ lib9p_tag_t tag;
+ lib9p_fid_t fid;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tstatfs, lib9p_msg_Tstatfs);
+
+/* size = 11 ; max_iov = 1 ; max_copy = 11 */
+struct lib9p_msg_Treadlink {
+ lib9p_tag_t tag;
+ lib9p_fid_t fid;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Treadlink, lib9p_msg_Treadlink);
+
+/* size = 23 ; max_iov = 1 ; max_copy = 23 */
+struct lib9p_msg_Treaddir {
+ lib9p_tag_t tag;
+ lib9p_fid_t fid;
+ uint64_t offset;
+ uint32_t count;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Treaddir, lib9p_msg_Treaddir);
+
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+/* min_size = 13 ; exp_size = 40 ; max_size = 65,548 ; max_iov = 2 ; max_copy = 13 */
struct lib9p_msg_Tversion {
lib9p_tag_t tag;
uint32_t max_msg_size;
struct lib9p_s version;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tversion, lib9p_msg_Tversion);
+/* min_size = 13 ; exp_size = 40 ; max_size = 65,548 ; max_iov = 2 ; max_copy = 13 */
struct lib9p_msg_Rversion {
lib9p_tag_t tag;
uint32_t max_msg_size;
struct lib9p_s version;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rversion, lib9p_msg_Rversion);
-struct lib9p_msg_Tauth {
+/* min_size = 17 ; exp_size = 481 ; max_size = 1,048,609 ; max_iov = 32 ; max_copy = 49 */
+struct lib9p_msg_Twalk {
lib9p_tag_t tag;
- lib9p_fid_t afid;
- struct lib9p_s uname;
- struct lib9p_s aname;
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
- uint32_t n_uname;
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
+ lib9p_fid_t fid;
+ lib9p_fid_t newfid;
+ uint16_t nwname;
+ struct lib9p_s *wname;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Twalk, lib9p_msg_Twalk);
-struct lib9p_msg_Rauth {
- lib9p_tag_t tag;
- struct lib9p_qid aqid;
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000_L
+/* min_size = 17 ; exp_size = 44 ; max_size = 65,552 ; max_iov = 2 ; max_copy = 17 */
+struct lib9p_msg_Trename {
+ lib9p_tag_t tag;
+ lib9p_fid_t fid;
+ lib9p_fid_t dfid;
+ struct lib9p_s name;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Trename, lib9p_msg_Trename);
-struct lib9p_msg_Tattach {
+/* min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */
+struct lib9p_msg_Rreadlink {
+ lib9p_tag_t tag;
+ struct lib9p_s target;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rreadlink, lib9p_msg_Rreadlink);
+
+/* min_size = 17 ; exp_size = 44 ; max_size = 65,552 ; max_iov = 2 ; max_copy = 17 */
+struct lib9p_msg_Txattrwalk {
lib9p_tag_t tag;
lib9p_fid_t fid;
- lib9p_fid_t afid;
- struct lib9p_s uname;
- struct lib9p_s aname;
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
- uint32_t n_uname;
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
+ lib9p_fid_t newfid;
+ struct lib9p_s name;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Txattrwalk, lib9p_msg_Txattrwalk);
-struct lib9p_msg_Rattach {
- lib9p_tag_t tag;
- struct lib9p_qid qid;
+/* min_size = 25 ; exp_size = 52 ; max_size = 65,560 ; max_iov = 3 ; max_copy = 25 */
+struct lib9p_msg_Txattrcreate {
+ lib9p_tag_t tag;
+ lib9p_fid_t fid;
+ struct lib9p_s name;
+ uint64_t attr_size;
+ uint32_t flags;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Txattrcreate, lib9p_msg_Txattrcreate);
-struct lib9p_msg_Rerror {
+/* min_size = 17 ; exp_size = 44 ; max_size = 65,552 ; max_iov = 2 ; max_copy = 17 */
+struct lib9p_msg_Tlink {
lib9p_tag_t tag;
- struct lib9p_s ename;
-#if defined(CONFIG_9P_ENABLE_9P2000_u)
- uint32_t errno;
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_u) */
+ lib9p_fid_t dfid;
+ lib9p_fid_t fid;
+ struct lib9p_s name;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tlink, lib9p_msg_Tlink);
-struct lib9p_msg_Tflush {
- lib9p_tag_t tag;
- uint16_t oldtag;
+/* min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 4 ; max_copy = 19 */
+struct lib9p_msg_Trenameat {
+ lib9p_tag_t tag;
+ lib9p_fid_t olddirfid;
+ struct lib9p_s oldname;
+ lib9p_fid_t newdirfid;
+ struct lib9p_s newname;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Trenameat, lib9p_msg_Trenameat);
-struct lib9p_msg_Rflush {
- lib9p_tag_t tag;
+/* min_size = 17 ; exp_size = 44 ; max_size = 65,552 ; max_iov = 3 ; max_copy = 17 */
+struct lib9p_msg_Tunlinkat {
+ lib9p_tag_t tag;
+ lib9p_fid_t dirfd;
+ struct lib9p_s name;
+ uint32_t flags;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tunlinkat, lib9p_msg_Tunlinkat);
-struct lib9p_msg_Twalk {
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000_e
+/* min_size = 13 ; exp_size = 477 ; max_size = 4,294,967,308 (warning: >UINT32_MAX) ; max_iov = 0 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2) ; max_copy = 13 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2) */
+struct lib9p_msg_Tsread {
lib9p_tag_t tag;
- lib9p_fid_t fid;
- lib9p_fid_t newfid;
+ uint32_t fid;
uint16_t nwname;
struct lib9p_s *wname;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tsread, lib9p_msg_Tsread);
-struct lib9p_msg_Rwalk {
- lib9p_tag_t tag;
- uint16_t nwqid;
- struct lib9p_qid *wqid;
+/* min_size = 17 ; exp_size = 8,673 ; max_size = 8,589,934,607 (warning: >UINT32_MAX) ; max_iov = 2 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2) ; max_copy = 17 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2) */
+struct lib9p_msg_Tswrite {
+ lib9p_tag_t tag;
+ uint32_t fid;
+ uint16_t nwname;
+ struct lib9p_s *wname;
+ uint32_t count;
+ [[gnu::nonstring]] char *data;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tswrite, lib9p_msg_Tswrite);
+#endif /* CONFIG_9P_ENABLE_9P2000_e */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+/* size = 13 ; max_iov = 1 ; max_copy = 13 */
+struct lib9p_qid {
+ lib9p_qt_t type;
+ uint32_t vers;
+ uint64_t path;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_qid, lib9p_qid);
+
+/* LIB9P_VER_9P2000 : min_size = 15 ; exp_size = 69 ; max_size = 131,085 ; max_iov = 4 ; max_copy = 15 */
+/* LIB9P_VER_9P2000_L : min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 5 ; max_copy = 19 */
+/* LIB9P_VER_9P2000_e : min_size = 15 ; exp_size = 69 ; max_size = 131,085 ; max_iov = 4 ; max_copy = 15 */
+/* LIB9P_VER_9P2000_p9p: min_size = 15 ; exp_size = 69 ; max_size = 131,085 ; max_iov = 4 ; max_copy = 15 */
+/* LIB9P_VER_9P2000_u : min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 5 ; max_copy = 19 */
+struct lib9p_msg_Tauth {
+ lib9p_tag_t tag;
+ lib9p_fid_t afid;
+ struct lib9p_s uname;
+ struct lib9p_s aname;
+#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
+ lib9p_nuid_t n_uid;
+#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tauth, lib9p_msg_Tauth);
+
+/* LIB9P_VER_9P2000 : min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 4 ; max_copy = 19 */
+/* LIB9P_VER_9P2000_L : min_size = 23 ; exp_size = 77 ; max_size = 131,093 ; max_iov = 5 ; max_copy = 23 */
+/* LIB9P_VER_9P2000_e : min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 4 ; max_copy = 19 */
+/* LIB9P_VER_9P2000_p9p: min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 4 ; max_copy = 19 */
+/* LIB9P_VER_9P2000_u : min_size = 23 ; exp_size = 77 ; max_size = 131,093 ; max_iov = 5 ; max_copy = 23 */
+struct lib9p_msg_Tattach {
+ lib9p_tag_t tag;
+ lib9p_fid_t fid;
+ lib9p_fid_t afid;
+ struct lib9p_s uname;
+ struct lib9p_s aname;
+#if CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u
+ lib9p_nuid_t n_uid;
+#endif /* CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_u */
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tattach, lib9p_msg_Tattach);
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000_L
+/* min_size = 19 ; exp_size = 73 ; max_size = 131,089 ; max_iov = 5 ; max_copy = 19 */
+struct lib9p_msg_Tsymlink {
+ lib9p_tag_t tag;
+ lib9p_fid_t fid;
+ struct lib9p_s name;
+ struct lib9p_s symtgt;
+ lib9p_nuid_t gid;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tsymlink, lib9p_msg_Tsymlink);
+
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+/* size = 12 ; max_iov = 1 ; max_copy = 12 */
struct lib9p_msg_Topen {
lib9p_tag_t tag;
lib9p_fid_t fid;
lib9p_o_t mode;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Topen, lib9p_msg_Topen);
-struct lib9p_msg_Ropen {
- lib9p_tag_t tag;
- struct lib9p_qid qid;
- uint32_t iounit;
-};
-
+/* min_size = 18 ; exp_size = 45 ; max_size = 65,553 ; max_iov = 3 ; max_copy = 18 */
struct lib9p_msg_Tcreate {
lib9p_tag_t tag;
lib9p_fid_t fid;
@@ -278,108 +954,395 @@ struct lib9p_msg_Tcreate {
lib9p_dm_t perm;
lib9p_o_t mode;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tcreate, lib9p_msg_Tcreate);
-struct lib9p_msg_Rcreate {
- lib9p_tag_t tag;
- struct lib9p_qid qid;
- uint32_t iounit;
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+/* size = 12 ; max_iov = 1 ; max_copy = 12 */
+struct lib9p_msg_Topenfd {
+ lib9p_tag_t tag;
+ lib9p_fid_t fid;
+ lib9p_o_t mode;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Topenfd, lib9p_msg_Topenfd);
-struct lib9p_msg_Tread {
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+/* LIB9P_VER_9P2000 : min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */
+/* LIB9P_VER_9P2000_L : min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */
+/* LIB9P_VER_9P2000_e : min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */
+/* LIB9P_VER_9P2000_p9p: min_size = 9 ; exp_size = 36 ; max_size = 65,544 ; max_iov = 2 ; max_copy = 9 */
+/* LIB9P_VER_9P2000_u : min_size = 13 ; exp_size = 40 ; max_size = 65,548 ; max_iov = 3 ; max_copy = 13 */
+struct lib9p_msg_Rerror {
+ lib9p_tag_t tag;
+ struct lib9p_s errstr;
+#if CONFIG_9P_ENABLE_9P2000_u
+ lib9p_errno_t errnum;
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rerror, lib9p_msg_Rerror);
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000_L
+/* size = 11 ; max_iov = 1 ; max_copy = 11 */
+struct lib9p_msg_Rlerror {
+ lib9p_tag_t tag;
+ lib9p_errno_t errnum;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rlerror, lib9p_msg_Rlerror);
+
+/* size = 67 ; max_iov = 1 ; max_copy = 67 */
+struct lib9p_msg_Rstatfs {
+ lib9p_tag_t tag;
+ lib9p_super_magic_t type;
+ uint32_t bsize;
+ uint64_t blocks;
+ uint64_t bfree;
+ uint64_t bavail;
+ uint64_t files;
+ uint64_t ffree;
+ uint64_t fsid;
+ uint32_t namelen;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rstatfs, lib9p_msg_Rstatfs);
+
+/* size = 15 ; max_iov = 1 ; max_copy = 15 */
+struct lib9p_msg_Tlopen {
lib9p_tag_t tag;
lib9p_fid_t fid;
- uint64_t offset;
- uint32_t count;
+ lib9p_lo_t flags;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tlopen, lib9p_msg_Tlopen);
-struct lib9p_msg_Rread {
+/* min_size = 25 ; exp_size = 52 ; max_size = 65,560 ; max_iov = 3 ; max_copy = 25 */
+struct lib9p_msg_Tlcreate {
lib9p_tag_t tag;
- struct lib9p_d data;
+ lib9p_fid_t fid;
+ struct lib9p_s name;
+ lib9p_lo_t flags;
+ lib9p_mode_t mode;
+ lib9p_nuid_t gid;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tlcreate, lib9p_msg_Tlcreate);
-struct lib9p_msg_Twrite {
+/* min_size = 29 ; exp_size = 56 ; max_size = 65,564 ; max_iov = 3 ; max_copy = 29 */
+struct lib9p_msg_Tmknod {
lib9p_tag_t tag;
- lib9p_fid_t fid;
- uint64_t offset;
- struct lib9p_d data;
+ lib9p_fid_t dfid;
+ struct lib9p_s name;
+ lib9p_mode_t mode;
+ uint32_t major;
+ uint32_t minor;
+ lib9p_nuid_t gid;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tmknod, lib9p_msg_Tmknod);
-struct lib9p_msg_Rwrite {
- lib9p_tag_t tag;
- uint32_t count;
+/* min_size = 21 ; exp_size = 48 ; max_size = 65,556 ; max_iov = 3 ; max_copy = 21 */
+struct lib9p_msg_Tmkdir {
+ lib9p_tag_t tag;
+ lib9p_fid_t dfid;
+ struct lib9p_s name;
+ lib9p_mode_t mode;
+ lib9p_nuid_t gid;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tmkdir, lib9p_msg_Tmkdir);
-struct lib9p_msg_Tclunk {
+/* size = 15 ; max_iov = 1 ; max_copy = 15 */
+struct lib9p_msg_Tfsync {
lib9p_tag_t tag;
lib9p_fid_t fid;
+ lib9p_b4_t datasync;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tfsync, lib9p_msg_Tfsync);
-struct lib9p_msg_Rclunk {
- lib9p_tag_t tag;
+/* size = 19 ; max_iov = 1 ; max_copy = 19 */
+struct lib9p_msg_Tgetattr {
+ lib9p_tag_t tag;
+ lib9p_fid_t fid;
+ lib9p_getattr_t request_mask;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tgetattr, lib9p_msg_Tgetattr);
-struct lib9p_msg_Tremove {
- lib9p_tag_t tag;
- lib9p_fid_t fid;
+/* size = 67 ; max_iov = 1 ; max_copy = 67 */
+struct lib9p_msg_Tsetattr {
+ lib9p_tag_t tag;
+ lib9p_fid_t fid;
+ lib9p_setattr_t valid;
+ lib9p_mode_t mode;
+ lib9p_nuid_t uid;
+ lib9p_nuid_t gid;
+ uint64_t filesize;
+ uint64_t atime_sec;
+ uint64_t atime_nsec;
+ uint64_t mtime_sec;
+ uint64_t mtime_nsec;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tsetattr, lib9p_msg_Tsetattr);
-struct lib9p_msg_Rremove {
- lib9p_tag_t tag;
+/* min_size = 34 ; exp_size = 61 ; max_size = 65,569 ; max_iov = 2 ; max_copy = 34 */
+struct lib9p_msg_Tgetlock {
+ lib9p_tag_t tag;
+ lib9p_fid_t fid;
+ lib9p_lock_type_t type;
+ uint64_t start;
+ uint64_t length;
+ uint32_t proc_id;
+ struct lib9p_s client_id;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tgetlock, lib9p_msg_Tgetlock);
-struct lib9p_msg_Tstat {
- lib9p_tag_t tag;
- lib9p_fid_t fid;
+/* min_size = 30 ; exp_size = 57 ; max_size = 65,565 ; max_iov = 2 ; max_copy = 30 */
+struct lib9p_msg_Rgetlock {
+ lib9p_tag_t tag;
+ lib9p_lock_type_t type;
+ uint64_t start;
+ uint64_t length;
+ uint32_t proc_id;
+ struct lib9p_s client_id;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rgetlock, lib9p_msg_Rgetlock);
+
+/* min_size = 38 ; exp_size = 65 ; max_size = 65,573 ; max_iov = 2 ; max_copy = 38 */
+struct lib9p_msg_Tlock {
+ lib9p_tag_t tag;
+ lib9p_fid_t fid;
+ lib9p_lock_type_t type;
+ lib9p_lock_flags_t flags;
+ uint64_t start;
+ uint64_t length;
+ uint32_t proc_id;
+ struct lib9p_s client_id;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Tlock, lib9p_msg_Tlock);
+
+/* size = 8 ; max_iov = 1 ; max_copy = 8 */
+struct lib9p_msg_Rlock {
+ lib9p_tag_t tag;
+ lib9p_lock_status_t status;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rlock, lib9p_msg_Rlock);
+
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+/* LIB9P_VER_9P2000 : min_size = 49 ; exp_size = 157 ; max_size = 262,189 ; max_iov = 8 ; max_copy = 49 */
+/* LIB9P_VER_9P2000_e : min_size = 49 ; exp_size = 157 ; max_size = 262,189 ; max_iov = 8 ; max_copy = 49 */
+/* LIB9P_VER_9P2000_p9p: min_size = 49 ; exp_size = 157 ; max_size = 262,189 ; max_iov = 8 ; max_copy = 49 */
+/* LIB9P_VER_9P2000_u : min_size = 63 ; exp_size = 198 ; max_size = 327,738 ; max_iov = 11 ; max_copy = 63 */
+struct lib9p_stat {
+ uint16_t kern_type;
+ uint32_t kern_dev;
+ struct lib9p_qid file_qid;
+ lib9p_dm_t file_mode;
+ uint32_t file_atime;
+ uint32_t file_mtime;
+ uint64_t file_size;
+ struct lib9p_s file_name;
+ struct lib9p_s file_owner_uid;
+ struct lib9p_s file_owner_gid;
+ struct lib9p_s file_last_modified_uid;
+#if CONFIG_9P_ENABLE_9P2000_u
+ struct lib9p_s file_extension;
+ lib9p_nuid_t file_owner_n_uid;
+ lib9p_nuid_t file_owner_n_gid;
+ lib9p_nuid_t file_last_modified_n_uid;
+#endif /* CONFIG_9P_ENABLE_9P2000_u */
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_stat, lib9p_stat);
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+/* size = 20 ; max_iov = 1 ; max_copy = 20 */
+struct lib9p_msg_Rauth {
+ lib9p_tag_t tag;
+ struct lib9p_qid aqid;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rauth, lib9p_msg_Rauth);
+
+/* size = 20 ; max_iov = 1 ; max_copy = 20 */
+struct lib9p_msg_Rattach {
+ lib9p_tag_t tag;
+ struct lib9p_qid qid;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rattach, lib9p_msg_Rattach);
+
+/* min_size = 9 ; exp_size = 217 ; max_size = 217 ; max_iov = 1 ; max_copy = 217 */
+struct lib9p_msg_Rwalk {
+ lib9p_tag_t tag;
+ uint16_t nwqid;
+ struct lib9p_qid *wqid;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rwalk, lib9p_msg_Rwalk);
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+/* size = 24 ; max_iov = 1 ; max_copy = 24 */
+struct lib9p_msg_Ropen {
+ lib9p_tag_t tag;
+ struct lib9p_qid qid;
+ uint32_t iounit;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Ropen, lib9p_msg_Ropen);
+
+/* size = 24 ; max_iov = 1 ; max_copy = 24 */
+struct lib9p_msg_Rcreate {
+ lib9p_tag_t tag;
+ struct lib9p_qid qid;
+ uint32_t iounit;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rcreate, lib9p_msg_Rcreate);
+
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+/* size = 28 ; max_iov = 1 ; max_copy = 28 */
+struct lib9p_msg_Ropenfd {
+ lib9p_tag_t tag;
+ struct lib9p_qid qid;
+ uint32_t iounit;
+ uint32_t unixfd;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Ropenfd, lib9p_msg_Ropenfd);
+
+#endif /* CONFIG_9P_ENABLE_9P2000_p9p */
+#if CONFIG_9P_ENABLE_9P2000_L
+/* size = 24 ; max_iov = 1 ; max_copy = 24 */
+struct lib9p_msg_Rlopen {
+ lib9p_tag_t tag;
+ struct lib9p_qid qid;
+ uint32_t iounit;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rlopen, lib9p_msg_Rlopen);
+
+/* size = 24 ; max_iov = 1 ; max_copy = 24 */
+struct lib9p_msg_Rlcreate {
+ lib9p_tag_t tag;
+ struct lib9p_qid qid;
+ uint32_t iounit;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rlcreate, lib9p_msg_Rlcreate);
+
+/* size = 20 ; max_iov = 1 ; max_copy = 20 */
+struct lib9p_msg_Rsymlink {
+ lib9p_tag_t tag;
+ struct lib9p_qid qid;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rsymlink, lib9p_msg_Rsymlink);
+
+/* size = 20 ; max_iov = 1 ; max_copy = 20 */
+struct lib9p_msg_Rmknod {
+ lib9p_tag_t tag;
+ struct lib9p_qid qid;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rmknod, lib9p_msg_Rmknod);
+
+/* size = 160 ; max_iov = 1 ; max_copy = 160 */
+struct lib9p_msg_Rgetattr {
+ lib9p_tag_t tag;
+ lib9p_getattr_t valid;
+ struct lib9p_qid qid;
+ lib9p_mode_t mode;
+ lib9p_nuid_t uid;
+ lib9p_nuid_t gid;
+ uint64_t nlink;
+ uint64_t rdev;
+ uint64_t filesize;
+ uint64_t blksize;
+ uint64_t blocks;
+ uint64_t atime_sec;
+ uint64_t atime_nsec;
+ uint64_t mtime_sec;
+ uint64_t mtime_nsec;
+ uint64_t ctime_sec;
+ uint64_t ctime_nsec;
+ uint64_t btime_sec;
+ uint64_t btime_nsec;
+ uint64_t gen;
+ uint64_t data_version;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rgetattr, lib9p_msg_Rgetattr);
+/* size = 20 ; max_iov = 1 ; max_copy = 20 */
+struct lib9p_msg_Rmkdir {
+ lib9p_tag_t tag;
+ struct lib9p_qid qid;
+};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rmkdir, lib9p_msg_Rmkdir);
+
+#endif /* CONFIG_9P_ENABLE_9P2000_L */
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+/* LIB9P_VER_9P2000 : min_size = 58 ; exp_size = 166 ; max_size = 262,198 ; max_iov = 8 ; max_copy = 58 */
+/* LIB9P_VER_9P2000_e : min_size = 58 ; exp_size = 166 ; max_size = 262,198 ; max_iov = 8 ; max_copy = 58 */
+/* LIB9P_VER_9P2000_p9p: min_size = 58 ; exp_size = 166 ; max_size = 262,198 ; max_iov = 8 ; max_copy = 58 */
+/* LIB9P_VER_9P2000_u : min_size = 72 ; exp_size = 207 ; max_size = 327,747 ; max_iov = 11 ; max_copy = 72 */
struct lib9p_msg_Rstat {
lib9p_tag_t tag;
struct lib9p_stat stat;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Rstat, lib9p_msg_Rstat);
+/* LIB9P_VER_9P2000 : min_size = 62 ; exp_size = 170 ; max_size = 262,202 ; max_iov = 8 ; max_copy = 62 */
+/* LIB9P_VER_9P2000_e : min_size = 62 ; exp_size = 170 ; max_size = 262,202 ; max_iov = 8 ; max_copy = 62 */
+/* LIB9P_VER_9P2000_p9p: min_size = 62 ; exp_size = 170 ; max_size = 262,202 ; max_iov = 8 ; max_copy = 62 */
+/* LIB9P_VER_9P2000_u : min_size = 76 ; exp_size = 211 ; max_size = 327,751 ; max_iov = 11 ; max_copy = 76 */
struct lib9p_msg_Twstat {
lib9p_tag_t tag;
lib9p_fid_t fid;
struct lib9p_stat stat;
};
+LO_IMPLEMENTATION_H(fmt_formatter, struct lib9p_msg_Twstat, lib9p_msg_Twstat);
+#endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u */
-struct lib9p_msg_Rwstat {
- lib9p_tag_t tag;
-};
+/* containers *****************************************************************/
-#endif /* defined(CONFIG_9P_ENABLE_9P2000) || defined(CONFIG_9P_ENABLE_9P2000_e) || defined(CONFIG_9P_ENABLE_9P2000_u) */
-#if defined(CONFIG_9P_ENABLE_9P2000_e)
-struct lib9p_msg_Tsession {
- lib9p_tag_t tag;
- uint64_t key;
-};
+#define _LIB9P_MAX(a, b) ((a) > (b)) ? (a) : (b)
-struct lib9p_msg_Rsession {
- lib9p_tag_t tag;
-};
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+ #if CONFIG_9P_ENABLE_9P2000_e
+ #define LIB9P_TMSG_MAX_IOV _LIB9P_MAX(32, 2 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2))
+ #else
+ #define LIB9P_TMSG_MAX_IOV 32
+ #endif
+#endif
-struct lib9p_msg_Tsread {
- lib9p_tag_t tag;
- uint32_t fid;
- uint16_t nwname;
- struct lib9p_s *wname;
-};
+#if CONFIG_9P_ENABLE_9P2000_u
+ #if CONFIG_9P_ENABLE_9P2000_e
+ #define LIB9P_TMSG_MAX_COPY _LIB9P_MAX(76, 17 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2))
+ #else
+ #define LIB9P_TMSG_MAX_COPY 76
+ #endif
+#elif CONFIG_9P_ENABLE_9P2000_L
+ #if CONFIG_9P_ENABLE_9P2000_e
+ #define LIB9P_TMSG_MAX_COPY _LIB9P_MAX(67, 17 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2))
+ #else
+ #define LIB9P_TMSG_MAX_COPY 67
+ #endif
+#elif CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p
+ #if CONFIG_9P_ENABLE_9P2000_e
+ #define LIB9P_TMSG_MAX_COPY _LIB9P_MAX(62, 17 + (CONFIG_9P_MAX_9P2000_e_WELEM * 2))
+ #else
+ #define LIB9P_TMSG_MAX_COPY 62
+ #endif
+#endif
-struct lib9p_msg_Rsread {
- lib9p_tag_t tag;
- struct lib9p_d data;
-};
+#if CONFIG_9P_ENABLE_9P2000_u
+ #define LIB9P_RMSG_MAX_IOV 11
+#elif CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p
+ #define LIB9P_RMSG_MAX_IOV 8
+#elif CONFIG_9P_ENABLE_9P2000_L
+ #define LIB9P_RMSG_MAX_IOV 2
+#endif
-struct lib9p_msg_Tswrite {
- lib9p_tag_t tag;
- uint32_t fid;
- uint16_t nwname;
- struct lib9p_s *wname;
- struct lib9p_d data;
+#if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_p9p || CONFIG_9P_ENABLE_9P2000_u
+ #define LIB9P_RMSG_MAX_COPY 217
+#endif
+
+struct lib9p_Tmsg_send_buf {
+ size_t iov_cnt;
+ struct iovec iov[LIB9P_TMSG_MAX_IOV];
+ uint8_t copied[LIB9P_TMSG_MAX_COPY];
};
-struct lib9p_msg_Rswrite {
- lib9p_tag_t tag;
- uint32_t count;
+struct lib9p_Rmsg_send_buf {
+ size_t iov_cnt;
+ struct iovec iov[LIB9P_RMSG_MAX_IOV];
+ uint8_t copied[LIB9P_RMSG_MAX_COPY];
};
-#endif /* defined(CONFIG_9P_ENABLE_9P2000_e) */
diff --git a/lib9p/include/lib9p/9p.h b/lib9p/include/lib9p/9p.h
index 171ad3b..42381cf 100644
--- a/lib9p/include/lib9p/9p.h
+++ b/lib9p/include/lib9p/9p.h
@@ -1,35 +1,42 @@
/* lib9p/9p.h - Base 9P protocol definitions for both clients and servers
*
- * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#ifndef _LIB9P_9P_H_
#define _LIB9P_9P_H_
-#include <assert.h>
#include <stdbool.h>
#include <sys/types.h> /* for ssize_t */
-#include <lib9p/linux-errno.h>
-
-/* configuration **************************************************************/
+#include <libmisc/assert.h>
-#include "config.h"
+#include <lib9p/linux-errno.h>
+#include <lib9p/9p.generated.h>
#ifndef CONFIG_9P_MAX_ERR_SIZE
#error config.h must define CONFIG_9P_MAX_ERR_SIZE
#endif
-#ifndef CONFIG_9P_ENABLE_9P2000
- #define CONFIG_9P_ENABLE_9P2000
-#endif
+static_assert(CONFIG_9P_MAX_ERR_SIZE <= UINT16_MAX);
+
+/* constants ******************************************************************/
+
+enum {
+ LIB9P_DEFAULT_PORT_9FS = 564,
+ LIB9P_DEFAULT_PORT_STYX = 6666,
+};
-/* protocol definitions *******************************************************/
+/* strings ********************************************************************/
-#include <lib9p/9p.generated.h> /* *after* config.h */
+const char *lib9p_version_str(enum lib9p_version);
+const char *lib9p_msgtype_str(enum lib9p_version, enum lib9p_msg_type);
-#define LIB9P_NOTAG ((uint16_t)~0U)
-#define LIB9P_NOFID ((uint32_t)~0U)
+struct lib9p_s lib9p_str(char *s);
+struct lib9p_s lib9p_strn(char *s, size_t maxlen);
+struct lib9p_s lib9p_str_slice(struct lib9p_s s, uint16_t beg, uint16_t end);
+#define lib9p_str_sliceleft(s, beg) lib9p_str_slice(s, beg, (s).len)
+bool lib9p_str_eq(struct lib9p_s a, struct lib9p_s b);
/* ctx ************************************************************************/
@@ -40,9 +47,9 @@ struct lib9p_ctx {
/* state */
#ifdef CONFIG_9P_ENABLE_9P2000_u
- uint32_t err_num;
+ lib9p_errno_t err_num;
#endif
- char err_msg[CONFIG_9P_MAX_ERR_SIZE];
+ [[gnu::nonstring]] char err_msg[CONFIG_9P_MAX_ERR_SIZE];
};
void lib9p_ctx_clear_error(struct lib9p_ctx *ctx);
@@ -50,21 +57,25 @@ void lib9p_ctx_clear_error(struct lib9p_ctx *ctx);
bool lib9p_ctx_has_error(struct lib9p_ctx *ctx);
/** Write an static error into ctx, return -1. */
-int lib9p_error(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *msg);
+int lib9p_error(struct lib9p_ctx *ctx, lib9p_errno_t linux_errno, char const *msg);
/** Write a printf-style error into ctx, return -1. */
-int lib9p_errorf(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *fmt, ...);
+int lib9p_errorf(struct lib9p_ctx *ctx, lib9p_errno_t linux_errno, char const *fmt, ...) [[gnu::format(printf, 3, 4)]];
-const char *lib9p_msg_type_str(struct lib9p_ctx *, enum lib9p_msg_type);
+/* misc utilities *************************************************************/
-/* main message functions *****************************************************/
+uint32_t lib9p_version_min_msg_size(enum lib9p_version);
+
+lo_interface fmt_formatter lo_box_lib9p_msg_as_fmt_formatter(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body);
+
+/* main T-message functions ***************************************************/
/**
- * Validate a message's structure; it's size, string encodings, enums,
+ * Validate a message's structure; its size, string encodings, enums,
* and bitfields.
*
* Return how much space the message will take when unmarshaled. This
* number may be larger than net_bytes due to (1) struct padding, (2)
- * nul-terminator bytes for strings.
+ * array pointers.
*
* Emits an error (return -1, set ctx->err_num and ctx->err_msg) if
* either the message type is unknown, or if net_bytes is too short
@@ -75,39 +86,37 @@ const char *lib9p_msg_type_str(struct lib9p_ctx *, enum lib9p_msg_type);
*
* @return required size, or -1 on error
*
+ * @errno LINUX_EOPNOTSUPP: message is an R-message
* @errno LINUX_EOPNOTSUPP: message has unknown type
* @errno LINUX_EBADMSG: message is wrong size for content
* @errno LINUX_EBADMSG: message contains invalid UTF-8
* @errno LINUX_EBADMSG: message contains a bitfield with unknown bits
* @errno LINUX_EMSGSIZE: would-be return value overflows SSIZE_MAX
*/
-ssize_t lib9p_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes);
+ssize_t lib9p_Tmsg_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes);
/**
* Unmarshal the 9P message `net_bytes` into the C struct `ret_body`.
*
- * Emits an error (return 0, set ctx->err_num and ctx->err_msg) if a
- * string contains invalid UTF-8 or a nul-byte.
- *
- * lib9p_unmarshal does no validation; you must run lib9p_validate()
- * first.
+ * lib9p_Tmsg_unmarshal does no validation; you must run
+ * lib9p_Tmsg_validate() first.
*
- * @param ctx : negotiated protocol parameters, where to record errors
+ * @param ctx : negotiated protocol parameters
* @param net_bytes : the complete message, starting with the "size[4]"
*
* @return ret_typ : the mesage type
- * @return ret_body : the message body, must be at least lib9p_validate() bytes
+ * @return ret_body : the message body, must be at least lib9p_Tmsg_validate() bytes
*/
-void lib9p_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
- enum lib9p_msg_type *ret_typ, void *ret_body);
+void lib9p_Tmsg_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
+ enum lib9p_msg_type *ret_typ, void *ret_body);
/**
* Marshal a `struct lib9p_msg_{typ}` structure into a byte-array.
*
- * lib9p_marshal does no validation; it trusts that the programmer
- * won't give it garbage input. However, just as it doesn't marshal
- * struct fields that aren't in ctx->version, it won't marshal
- * bitfield bits that aren't in ctx->version; it applies a
+ * lib9p_Tmsg_marshal does no validation; it trusts that the
+ * programmer won't give it garbage input. However, just as it
+ * doesn't marshal struct fields that aren't in ctx->version, it won't
+ * marshal bitfield bits that aren't in ctx->version; it applies a
* version-specific mask to bitfields.
*
* @param ctx : negotiated protocol parameters, where to record errors
@@ -119,47 +128,79 @@ void lib9p_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
*
* @errno LINUX_ERANGE: reply does not fit in ctx->max_msg_size
*/
-bool lib9p_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
- uint8_t *ret_bytes);
+bool lib9p_Tmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
+ struct lib9p_Tmsg_send_buf *ret);
+
+/* main R-message functions ***************************************************/
+
+/** Same as above, but for R-messages instead of T-messages. */
+
+ssize_t lib9p_Rmsg_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes);
+void lib9p_Rmsg_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
+ enum lib9p_msg_type *ret_typ, void *ret_body);
+bool lib9p_Rmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
+ struct lib9p_Rmsg_send_buf *ret);
+
/* `struct lib9p_stat` helpers ************************************************/
/** Assert that a `struct lib9p_stat` object looks valid. */
-static inline void lib9p_assert_stat(struct lib9p_stat stat) {
- assert( ((bool)(stat.file_mode & LIB9P_DM_DIR )) == ((bool)(stat.file_qid.type & LIB9P_QT_DIR )) );
- assert( ((bool)(stat.file_mode & LIB9P_DM_APPEND )) == ((bool)(stat.file_qid.type & LIB9P_QT_APPEND )) );
- assert( ((bool)(stat.file_mode & LIB9P_DM_EXCL )) == ((bool)(stat.file_qid.type & LIB9P_QT_EXCL )) );
- assert( ((bool)(stat.file_mode & _LIB9P_DM_PLAN9_MOUNT)) == ((bool)(stat.file_qid.type & _LIB9P_QT_PLAN9_MOUNT)) );
- assert( ((bool)(stat.file_mode & LIB9P_DM_AUTH )) == ((bool)(stat.file_qid.type & LIB9P_QT_AUTH )) );
- assert( ((bool)(stat.file_mode & LIB9P_DM_TMP )) == ((bool)(stat.file_qid.type & LIB9P_QT_TMP )) );
+static inline void lib9p_stat_assert(struct lib9p_stat stat) {
+ assert( ((bool)(stat.file_mode & LIB9P_DM_DIR )) == ((bool)(stat.file_qid.type & LIB9P_QT_DIR )) );
+ assert( ((bool)(stat.file_mode & LIB9P_DM_APPEND)) == ((bool)(stat.file_qid.type & LIB9P_QT_APPEND)) );
+ assert( ((bool)(stat.file_mode & LIB9P_DM_EXCL )) == ((bool)(stat.file_qid.type & LIB9P_QT_EXCL )) );
+ assert( ((bool)(stat.file_mode & LIB9P_DM_AUTH )) == ((bool)(stat.file_qid.type & LIB9P_QT_AUTH )) );
+ assert( ((bool)(stat.file_mode & LIB9P_DM_TMP )) == ((bool)(stat.file_qid.type & LIB9P_QT_TMP )) );
assert( (stat.file_size == 0) || !(stat.file_mode & LIB9P_DM_DIR) );
}
/**
- * TODO
+ * Validate a message's `stat` structure.
+ *
+ * @param ctx : negotiated protocol parameters, where to record errors
+ * @param net_bytes : network-encoded stat structure
+ * @param net_size : the number of net_bytes that may be read
*
- * @return ret_net_size: number of bytes consumed; <=net_size
- * @return ret_host_size: number of bytes that lib9p_unmarshal_stat would take
+ * @return ret_net_size : number of bytes consumed; <=net_size
+ * @return ret_host_size : number of bytes that lib9p_stat_unmarshal would take
* @return whether there was an error
*/
-bool lib9p_validate_stat(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes,
- uint32_t *ret_net_size, ssize_t *ret_host_size);
+bool lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes,
+ uint32_t *ret_net_size, size_t *ret_host_size);
/**
- * TODO
+ * Unmarshal the 9P `net_bytes` into the C struct `ret_obj`.
+ *
+ * lib9p_stat_unmarshal does no validation; you must run
+ * lib9p_stat_validate() first.
+ *
+ * @param ctx : negotiated protocol parameters
+ * @param net_bytes : network-encoded stat structure
*
- * @return ret_obj : where to put the stat object itself
- * @return ret_extra : where to put strings for the stat object
- * @return consumed net_bytes
+ * @return ret : the stat object, must be at least lib9p_stat_validate()->ret_net_size bytes
*/
-uint32_t lib9p_unmarshal_stat(struct lib9p_ctx *ctx, uint8_t *net_bytes,
- struct lib9p_stat *ret_obj, void *ret_extra);
+void lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
+ struct lib9p_stat *ret);
/**
+ * Marhsal a `struct lib9p_stat` structure into a byte-array.
+ *
+ * lib9p_Tmsg_marshal does no validation; it trusts that the
+ * programmer won't give it garbage input. However, just as it
+ * doesn't marshal struct fields that aren't in ctx->version, it won't
+ * marshal bitfield bits that aren't in ctx->version; it applies a
+ * version-specific mask to bitfields.
+ *
+ * @param ctx : negotiated protocol parameters, where to record errors
+ * @param max_net_size : the maximum network-encoded size to allow
+ * @param obj : the message to encode
+ *
* @return ret_bytes: the buffer to encode into
* @return the number of bytes written, or 0 if the stat object does not fit in max_net_size
+ *
+ * @errno LINUX_ERANGE: reply does not fit in max_net_size
*/
-uint32_t lib9p_marshal_stat(struct lib9p_ctx *ctx, uint32_t max_net_size, struct lib9p_stat *obj,
+uint32_t lib9p_stat_marshal(struct lib9p_ctx *ctx, uint32_t max_net_size, struct lib9p_stat *obj,
uint8_t *ret_bytes);
#endif /* _LIB9P_9P_H_ */
diff --git a/lib9p/include/lib9p/linux-errno.h b/lib9p/include/lib9p/linux-errno.h
index e7c74f5..e864fb6 100644
--- a/lib9p/include/lib9p/linux-errno.h
+++ b/lib9p/include/lib9p/linux-errno.h
@@ -1,5 +1,5 @@
/* lib9p/linux-errno.h - Generated by `lib9p/include/lib9p/linux-errno.h.gen 3rd-party/linux-errno.txt`. DO NOT EDIT! */
-/* 3rd-party/linux-errno.txt - Generated from build-aux/linux-errno.txt.gen and linux.git v6.7. DO NOT EDIT! */
+/* 3rd-party/linux-errno.txt - Generated from lib9p/linux-errno.txt.gen and linux.git v6.14. DO NOT EDIT! */
#ifndef _LIB9P_LINUX_ERRNO_H_
#define _LIB9P_LINUX_ERRNO_H_
diff --git a/lib9p/include/lib9p/linux-errno.h.gen b/lib9p/include/lib9p/linux-errno.h.gen
index 8f4e0c8..2c736a2 100755
--- a/lib9p/include/lib9p/linux-errno.h.gen
+++ b/lib9p/include/lib9p/linux-errno.h.gen
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# lib9p/linux-errno.h.gen - Generate a C header from a list of errno numbers
#
-# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
import sys
@@ -13,7 +13,7 @@ def print_errnos() -> None:
)
errnos: dict[str, tuple[int, str]] = {}
for txtlist in sys.argv[1:]:
- with open(txtlist, "r") as fh:
+ with open(txtlist, "r", encoding="utf-8") as fh:
for line in fh:
if line.startswith("#"):
print(f"/* {line[1:].strip()} */")
@@ -26,12 +26,10 @@ def print_errnos() -> None:
print("#ifndef _LIB9P_LINUX_ERRNO_H_")
print("#define _LIB9P_LINUX_ERRNO_H_")
print()
- namelen = max(len(name) for name in errnos.keys())
+ namelen = max(len(name) for name in errnos)
numlen = max(len(str(num)) for (num, desc) in errnos.values())
- for name in errnos:
- print(
- f"#define LINUX_{name.ljust(namelen)} {str(errnos[name][0]).rjust(numlen)} /* {errnos[name][1]} */"
- )
+ for name, [num, msg] in errnos.items():
+ print(f"#define LINUX_{name:<{namelen}} {num:>{numlen}} /* {msg} */")
print()
print("#endif /* _LIB9P_LINUX_ERRNO_H_ */")
diff --git a/lib9p/include/lib9p/srv.h b/lib9p/include/lib9p/srv.h
index ab7ec43..85fc6bd 100644
--- a/lib9p/include/lib9p/srv.h
+++ b/lib9p/include/lib9p/srv.h
@@ -1,6 +1,6 @@
/* lib9p/srv.h - 9P server
*
- * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
@@ -11,110 +11,170 @@
#include <libcr_ipc/rpc.h>
#include <libcr_ipc/chan.h>
#include <libhw/generic/net.h>
+#include <libmisc/assert.h>
#include <libmisc/private.h>
+#include <libobj/obj.h>
#include <lib9p/9p.h>
/* context ********************************************************************/
-CR_CHAN_DECLARE(_lib9p_srv_flushch, bool)
+CR_CHAN_DECLARE(_lib9p_srv_flushch, bool);
struct lib9p_srv_ctx {
struct lib9p_ctx basectx;
uint32_t uid;
- char *uname;
+ struct lib9p_s uname;
- BEGIN_PRIVATE(LIB9P_SRV_H)
+ BEGIN_PRIVATE(LIB9P_SRV_H);
_lib9p_srv_flushch_t _flushch;
- END_PRIVATE(LIB9P_SRV_H)
+ END_PRIVATE(LIB9P_SRV_H);
};
bool lib9p_srv_flush_requested(struct lib9p_srv_ctx *ctx);
-int lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx);
+void lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx);
/* interface definitions ******************************************************/
-struct lib9p_srv_file_vtable;
-
-struct __lib9p_srv_file;
-typedef struct __lib9p_srv_file {
- struct lib9p_srv_file_vtable *vtable;
-
- BEGIN_PRIVATE(LIB9P_SRV_H)
- /* Managed by srv.c, but should be cloned by ->vtable->clone(). */
- struct __lib9p_srv_file *_parent_dir; /* clone this
-
- /* Managed by srv.c, but should be initialized to 0 by ->vtable->clone(). */
- /* ref type 1: an entry in fidmap
- * ref type 2: ->_parent_dir of another file */
- unsigned int _refcount;
- END_PRIVATE(LIB9P_SRV_H)
-} implements_lib9p_srv_file;
-
-struct lib9p_srv_file_vtable {
- /* all - resource management */
- implements_lib9p_srv_file *(*clone )(implements_lib9p_srv_file *, struct lib9p_srv_ctx *);
- void (*free )(implements_lib9p_srv_file *, struct lib9p_srv_ctx *);
-
- /* all - syscalls */
- uint32_t (*io )(implements_lib9p_srv_file *, struct lib9p_srv_ctx *,
- lib9p_o_t flags);
- struct lib9p_stat (*stat )(implements_lib9p_srv_file *, struct lib9p_srv_ctx *);
- void (*wstat )(implements_lib9p_srv_file *, struct lib9p_srv_ctx *,
- struct lib9p_stat new);
- void (*remove )(implements_lib9p_srv_file *, struct lib9p_srv_ctx *);
-
- /* directories - base */
- implements_lib9p_srv_file *(*dopen )(implements_lib9p_srv_file *, struct lib9p_srv_ctx *,
- char *childname);
- implements_lib9p_srv_file *(*dcreate)(implements_lib9p_srv_file *, struct lib9p_srv_ctx *,
- char *childname,
- lib9p_dm_t perm, lib9p_o_t flags);
-
- /* directories - once opened */
- size_t /* <- obj cnt */ (*dread )(implements_lib9p_srv_file *, struct lib9p_srv_ctx *,
- uint8_t *buf,
- uint32_t byte_count, /* <- num bytes */
- size_t obj_offset); /* <- starting at this object */
-
- /* non-directories - once opened */
- uint32_t (*pread )(implements_lib9p_srv_file *, struct lib9p_srv_ctx *,
- void *buf,
- uint32_t byte_count,
- uint64_t byte_offset);
- uint32_t (*pwrite )(implements_lib9p_srv_file *, struct lib9p_srv_ctx *,
- void *buf,
- uint32_t byte_count,
- uint64_t byte_offset);
-};
+lo_interface lib9p_srv_fio;
+lo_interface lib9p_srv_dio;
+
+/* FIXME: I don't like that the pointers returned by stat() and
+ * pread() have to remain live after they return. Perhaps a
+ * `respond()`-callback? But that just reads as gross in C.
+ *
+ * FIXME: It would be nice if pread() could return more than 1 iovec.
+ */
+#define lib9p_srv_file_LO_IFACE \
+ /* resource management **********************************************/ \
+ \
+ /** \
+ * free() is be called when all FIDs associated with the file are \
+ * clunked. \
+ * \
+ * free() MUST NOT error. \
+ */ \
+ LO_FUNC(void , free ) \
+ \
+ /** \
+ * qid() is called frequently and returns the current QID of the file. \
+ * The .path field MUST never change, the .type field may change in \
+ * response to wstat() calls (but the QT_DIR bit MUST NOT change), and \
+ * the .vers field may change frequently in response to any number of \
+ * things (wstat(), write(), or non-9P events). \
+ * \
+ * qid() MUST NOT error. \
+ */ \
+ LO_FUNC(struct lib9p_qid , qid ) \
+ \
+ /* non-"opened" generic I/O *****************************************/ \
+ \
+ LO_FUNC(struct lib9p_stat , stat , struct lib9p_srv_ctx *) \
+ LO_FUNC(void , wstat , struct lib9p_srv_ctx *, \
+ struct lib9p_stat new) \
+ LO_FUNC(void , remove , struct lib9p_srv_ctx *) \
+ \
+ /* non-"opened" directory I/O ***************************************/ \
+ \
+ LO_FUNC(lo_interface lib9p_srv_file, dwalk , struct lib9p_srv_ctx *, \
+ struct lib9p_s childname) \
+ LO_FUNC(lo_interface lib9p_srv_file, dcreate, struct lib9p_srv_ctx *, \
+ struct lib9p_s childname, \
+ lib9p_dm_t perm, \
+ lib9p_o_t flags) \
+ \
+ /* open() for I/O ***************************************************/ \
+ \
+ LO_FUNC(lo_interface lib9p_srv_fio , fopen , struct lib9p_srv_ctx *, \
+ bool rd, bool wr, \
+ bool trunc) \
+ LO_FUNC(lo_interface lib9p_srv_dio , dopen , struct lib9p_srv_ctx *)
+LO_INTERFACE(lib9p_srv_file);
+
+#define lib9p_srv_fio_LO_IFACE \
+ LO_FUNC(struct lib9p_qid , qid ) \
+ LO_FUNC(void , iofree ) \
+ LO_FUNC(uint32_t , iounit ) \
+ LO_FUNC(void , pread , struct lib9p_srv_ctx *, \
+ uint32_t byte_count, \
+ uint64_t byte_offset, \
+ struct iovec *ret) \
+ LO_FUNC(uint32_t , pwrite , struct lib9p_srv_ctx *, \
+ void *buf, \
+ uint32_t byte_count, \
+ uint64_t byte_offset)
+LO_INTERFACE(lib9p_srv_fio);
+
+/* FIXME: The dio interface just feels clunky. I'm not in a rush to
+ * change it because util9p_static_dir is already implemented and I
+ * don't anticipate the sbc-harness needing another dio
+ * implementation. But if I wanted lib9p to be used outside of
+ * sbc-harness, this is one of the first things that I'd want to
+ * change.
+ */
+#define lib9p_srv_dio_LO_IFACE \
+ LO_FUNC(struct lib9p_qid , qid ) \
+ LO_FUNC(void , iofree ) \
+ LO_FUNC(size_t /* <- obj cnt */ , dread , struct lib9p_srv_ctx *, \
+ uint8_t *buf, \
+ /* num bytes -> */ uint32_t byte_count, \
+ /* starting at this object -> */ size_t obj_offset)
+LO_INTERFACE(lib9p_srv_dio);
+
+#define LIB9P_SRV_NOTDIR(TYP, NAM) \
+ static lo_interface lib9p_srv_file NAM##_dwalk (TYP *, struct lib9p_srv_ctx *, struct lib9p_s) { assert_notreached("not a directory"); } \
+ static lo_interface lib9p_srv_file NAM##_dcreate(TYP *, struct lib9p_srv_ctx *, struct lib9p_s, lib9p_dm_t, lib9p_o_t) { assert_notreached("not a directory"); } \
+ static lo_interface lib9p_srv_dio NAM##_dopen (TYP *, struct lib9p_srv_ctx *) { assert_notreached("not a directory"); }
+
+#define LIB9P_SRV_NOTFILE(TYP, NAM) \
+ static lo_interface lib9p_srv_fio NAM##_fopen (TYP *, struct lib9p_srv_ctx *, bool, bool, bool) { assert_notreached("not a file"); }
/* main server entrypoints ****************************************************/
-CR_RPC_DECLARE(_lib9p_srv_reqch, struct _lib9p_srv_req *, bool)
+CR_RPC_DECLARE(_lib9p_srv_reqch, struct _lib9p_srv_req *, bool);
struct lib9p_srv {
/* Things you provide */
- void /*TODO*/ (*auth )(struct lib9p_srv_ctx *, char *treename); /* optional */
- implements_lib9p_srv_file *(*rootdir)(struct lib9p_srv_ctx *, char *treename);
+ void /*TODO*/ (*auth )(struct lib9p_srv_ctx *, struct lib9p_s treename); /* optional */
+ lo_interface lib9p_srv_file (*rootdir)(struct lib9p_srv_ctx *, struct lib9p_s treename);
+ void (*msglog )(struct lib9p_srv_ctx *, enum lib9p_msg_type, void *hostmsg); /* optional */
/* For internal use */
- BEGIN_PRIVATE(LIB9P_SRV_H)
+ BEGIN_PRIVATE(LIB9P_SRV_H);
+ unsigned int readers;
+ unsigned int writers;
_lib9p_srv_reqch_t _reqch;
- END_PRIVATE(LIB9P_SRV_H)
+ END_PRIVATE(LIB9P_SRV_H);
};
/**
+ * In an infinite loop, accept a connection and read messages from it until
+ * close; dispatching requests to a pool of lib9p_srv_write_cr() coroutines
+ * with the same `srv`.
+ *
* Will just close the connection if a T-message has a size[4] <7.
*
+ * @param srv: The server configuration and state; has an associated pool of
+ * lib9p_srv_write_cr() coroutines.
+ * @param listener: The listener object to accept connections from.
+ *
* @errno LINUX_EMSGSIZE T-message has size[4] bigger than max_msg_size
* @errno LINUX_EDOM Tversion specified an impossibly small max_msg_size
* @errno LINUX_EOPNOTSUPP T-message has an R-message type, or an unrecognized T-message type
* @errno LINUX_EBADMSG T-message has wrong size[4] for its content, or has invalid UTF-8
* @errno LINUX_ERANGE R-message does not fit into max_msg_size
*/
+[[noreturn]] void lib9p_srv_read_cr(struct lib9p_srv *srv, lo_interface net_stream_listener listener);
-__attribute__ ((noreturn)) void lib9p_srv_read_cr(struct lib9p_srv *srv, implements_net_stream_listener *listener);
+/**
+ * Service requests to the `struct lib9p_srv *srv` argument that have been
+ * read by lib9p_srv_read_cr().
+ *
+ * @param struct lib9p_srv *srv: The server configuration and state; has an
+ * associated pool of lib9p_srv_read_cr()
+ * coroutines.
+ */
COROUTINE lib9p_srv_write_cr(void *_srv);
#endif /* _LIB9P_SRV_H_ */
diff --git a/lib9p/internal.h b/lib9p/internal.h
deleted file mode 100644
index 004660a..0000000
--- a/lib9p/internal.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/* lib9p/internal.h - TODO
- *
- * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#ifndef _LIB9P_INTERNAL_H_
-#define _LIB9P_INTERNAL_H_
-
-#include <stddef.h> /* for size_t */
-#include <limits.h> /* for SSIZE_MAX */
-
-#include <lib9p/9p.h>
-
-/* configuration **************************************************************/
-
-#include "config.h"
-
-#ifndef CONFIG_9P_MAX_MSG_SIZE
- #error config.h must define CONFIG_9P_MAX_MSG_SIZE
-#endif
-#ifndef CONFIG_9P_MAX_HOSTMSG_SIZE
- #error config.h must define CONFIG_9P_MAX_HOSTMSG_SIZE
-#endif
-#ifndef CONFIG_9P_MAX_FIDS
- #error config.h must define CONFIG_9P_MAX_FIDS
-#endif
-#ifndef CONFIG_9P_MAX_REQS
- #error config.h must define CONFIG_9P_MAX_REQS
-#endif
-#ifndef CONFIG_9P_MAX_ERR_SIZE
- #error config.h must define CONFIG_9P_MAX_ERR_SIZE
-#endif
-
-static_assert(CONFIG_9P_MAX_ERR_SIZE <= UINT16_MAX);
-static_assert(CONFIG_9P_MAX_MSG_SIZE <= CONFIG_9P_MAX_HOSTMSG_SIZE);
-static_assert(CONFIG_9P_MAX_HOSTMSG_SIZE <= SSIZE_MAX);
-
-/* C language *****************************************************************/
-
-#define UNUSED(name) /* name __attribute__((unused)) */
-#define ALWAYS_INLINE inline __attribute__((always_inline))
-#define FLATTEN __attribute__((flatten))
-#define ARRAY_LEN(arr) (sizeof(arr)/sizeof((arr)[0]))
-#define CAT2(a, b) a##b
-#define CAT3(a, b, c) a##b##c
-
-/* specialized contexts *******************************************************/
-
-struct _validate_ctx {
- struct lib9p_ctx *ctx;
- uint32_t net_size;
- uint8_t *net_bytes;
-
- uint32_t net_offset;
- /* Increment `host_extra` to pre-allocate space that is
- * "extra" beyond sizeof(). */
- size_t host_extra;
-};
-typedef bool (*_validate_fn_t)(struct _validate_ctx *ctx);
-
-struct _unmarshal_ctx {
- struct lib9p_ctx *ctx;
- uint8_t *net_bytes;
-
- uint32_t net_offset;
- /* `extra` points to the beginning of unallocated space. */
- void *extra;
-};
-typedef void (*_unmarshal_fn_t)(struct _unmarshal_ctx *ctx, void *out);
-
-struct _marshal_ctx {
- struct lib9p_ctx *ctx;
-
- uint8_t *net_bytes;
- uint32_t net_offset;
-};
-typedef bool (*_marshal_fn_t)(struct _marshal_ctx *ctx, void *host_val);
-
-/* tables *********************************************************************/
-
-struct _table_msg {
- char *name;
- size_t basesize;
- _validate_fn_t validate;
- _unmarshal_fn_t unmarshal;
- _marshal_fn_t marshal;
-};
-
-struct _table_version {
- struct _table_msg msgs[0x100];
-};
-
-extern struct _table_version _lib9p_versions[LIB9P_VER_NUM];
-
-bool _lib9p_validate_stat(struct _validate_ctx *ctx);
-void _lib9p_unmarshal_stat(struct _unmarshal_ctx *ctx, struct lib9p_stat *out);
-bool _lib9p_marshal_stat(struct _marshal_ctx *ctx, struct lib9p_stat *val);
-
-/* unmarshal utilities ********************************************************/
-
-static ALWAYS_INLINE uint8_t decode_u8le(uint8_t *in) {
- return in[0];
-}
-static ALWAYS_INLINE uint16_t decode_u16le(uint8_t *in) {
- return (((uint16_t)(in[0])) << 0)
- | (((uint16_t)(in[1])) << 8)
- ;
-}
-static ALWAYS_INLINE uint32_t decode_u32le(uint8_t *in) {
- return (((uint32_t)(in[0])) << 0)
- | (((uint32_t)(in[1])) << 8)
- | (((uint32_t)(in[2])) << 16)
- | (((uint32_t)(in[3])) << 24)
- ;
-}
-static ALWAYS_INLINE uint64_t decode_u64le(uint8_t *in) {
- return (((uint64_t)(in[0])) << 0)
- | (((uint64_t)(in[1])) << 8)
- | (((uint64_t)(in[2])) << 16)
- | (((uint64_t)(in[3])) << 24)
- | (((uint64_t)(in[4])) << 32)
- | (((uint64_t)(in[5])) << 40)
- | (((uint64_t)(in[6])) << 48)
- | (((uint64_t)(in[7])) << 56)
- ;
-}
-
-static inline bool _is_valid_utf8(uint8_t *str, size_t len, bool forbid_nul) {
- uint32_t ch;
- uint8_t chlen;
- assert(str);
- for (size_t pos = 0; pos < len;) {
- if ((str[pos] & 0b10000000) == 0b00000000) { ch = str[pos] & 0b01111111; chlen = 1; }
- else if ((str[pos] & 0b11100000) == 0b11000000) { ch = str[pos] & 0b00011111; chlen = 2; }
- else if ((str[pos] & 0b11110000) == 0b11100000) { ch = str[pos] & 0b00001111; chlen = 3; }
- else if ((str[pos] & 0b11111000) == 0b11110000) { ch = str[pos] & 0b00000111; chlen = 4; }
- else return false;
- if ((ch == 0 && (chlen != 1 || forbid_nul)) || pos + chlen > len) return false;
- for (uint8_t i = 1; i < chlen; i++) {
- if ((str[pos+i] & 0b11000000) != 0b10000000) return false;
- ch = (ch << 6) | (str[pos+i] & 0b00111111);
- }
- if (ch > 0x10FFFF) return false;
- pos += chlen;
- }
- return true;
-}
-
-#define is_valid_utf8(str, len) _is_valid_utf8(str, len, false)
-#define is_valid_utf8_without_nul(str, len) _is_valid_utf8(str, len, true)
-
-/* marshal utilities **********************************************************/
-
-static ALWAYS_INLINE void encode_u8le(uint8_t in, uint8_t *out) {
- out[0] = in;
-}
-static ALWAYS_INLINE void encode_u16le(uint16_t in, uint8_t *out) {
- out[0] = (uint8_t)((in >> 0) & 0xFF);
- out[1] = (uint8_t)((in >> 8) & 0xFF);
-}
-static ALWAYS_INLINE void encode_u32le(uint32_t in, uint8_t *out) {
- out[0] = (uint8_t)((in >> 0) & 0xFF);
- out[1] = (uint8_t)((in >> 8) & 0xFF);
- out[2] = (uint8_t)((in >> 16) & 0xFF);
- out[3] = (uint8_t)((in >> 24) & 0xFF);
-}
-static ALWAYS_INLINE void encode_u64le(uint64_t in, uint8_t *out) {
- out[0] = (uint8_t)((in >> 0) & 0xFF);
- out[1] = (uint8_t)((in >> 8) & 0xFF);
- out[2] = (uint8_t)((in >> 16) & 0xFF);
- out[3] = (uint8_t)((in >> 24) & 0xFF);
- out[4] = (uint8_t)((in >> 32) & 0xFF);
- out[5] = (uint8_t)((in >> 40) & 0xFF);
- out[6] = (uint8_t)((in >> 48) & 0xFF);
- out[7] = (uint8_t)((in >> 56) & 0xFF);
-}
-
-#endif /* _LIB9P_INTERNAL_H_ */
diff --git a/lib9p/linux-errno.txt.gen b/lib9p/linux-errno.txt.gen
new file mode 100755
index 0000000..687e58b
--- /dev/null
+++ b/lib9p/linux-errno.txt.gen
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+# lib9p/linux-errno.txt.gen - Generate a listing of Linux kernel errnos
+#
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+set -e
+linux_git=${1:?}
+outfile=${2:?}
+
+(
+ cd "${linux_git}"
+ echo "# ${outfile} - Generated from $0 and linux.git $(git describe). DO NOT EDIT!"
+ git ls-files include/uapi/ | grep errno |
+ xargs sed -nE 's,#\s*define\s+(E[A-Z0-9]+)\s+([0-9]+)\s+/\* (.*) \*/,\2 \1 \3,p' |
+ sort --numeric-sort
+) >"${outfile}"
diff --git a/lib9p/map.h b/lib9p/map.h
index c816bde..c5eab0f 100644
--- a/lib9p/map.h
+++ b/lib9p/map.h
@@ -1,11 +1,9 @@
-/* lib9p/map.h - A really dumb map/dict data structur
+/* lib9p/map.h - A really dumb map/dict data structure
*
- * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include "internal.h"
-
/**
* `#define` `NAME`, `KEY_T`, `VAL_T`, and `CAP`; then `#include
* "map.h".
@@ -25,10 +23,10 @@
#endif
#ifndef MAP_KEY
-#define MAP_KV(TNAME) CAT3(_,TNAME,_kv)
-#define MAP_METHOD(TNAME, MNAME) CAT3(TNAME,_,MNAME)
+#define MAP_KV(TNAME) LM_CAT3(_,TNAME,_kv)
+#define MAP_METHOD(TNAME, MNAME) LM_CAT3(TNAME,_,MNAME)
#define MAP_FOREACH(m, k, v) \
- for (size_t i = 0; i < ARRAY_LEN((m)->items); i++) \
+ for (size_t i = 0; i < LM_ARRAY_LEN((m)->items); i++) \
if ( ({ k = (m)->items[i].key; v = &(m)->items[i].val; (m)->items[i].set; }) )
#endif
@@ -58,7 +56,7 @@ struct NAME {
static VAL_T *MAP_METHOD(NAME,load)(struct NAME *m, KEY_T k) {
if (!m->len)
return NULL;
- for (size_t i = 0; i < ARRAY_LEN(m->items); i++)
+ for (size_t i = 0; i < LM_ARRAY_LEN(m->items); i++)
if (m->items[i].set && m->items[i].key == k)
return &(m->items[i].val);
return NULL;
@@ -74,9 +72,9 @@ static VAL_T *MAP_METHOD(NAME,store)(struct NAME *m, KEY_T k, VAL_T v) {
*old = v;
return old;
}
- if (m->len == ARRAY_LEN(m->items))
+ if (m->len == LM_ARRAY_LEN(m->items))
return NULL;
- for (size_t i = 0; i < ARRAY_LEN(m->items); i++)
+ for (size_t i = 0; i < LM_ARRAY_LEN(m->items); i++)
if (!m->items[i].set) {
m->len++;
m->items[i].set = true;
@@ -84,7 +82,7 @@ static VAL_T *MAP_METHOD(NAME,store)(struct NAME *m, KEY_T k, VAL_T v) {
m->items[i].val = v;
return &(m->items[i].val);
}
- __builtin_unreachable();
+ assert_notreached("should have returned from inside for() loop");
}
/**
@@ -94,7 +92,7 @@ static VAL_T *MAP_METHOD(NAME,store)(struct NAME *m, KEY_T k, VAL_T v) {
static bool MAP_METHOD(NAME,del)(struct NAME *m, KEY_T k) {
if (!m->len)
return NULL;
- for (size_t i = 0; i < ARRAY_LEN(m->items); i++)
+ for (size_t i = 0; i < LM_ARRAY_LEN(m->items); i++)
if (m->items[i].set && m->items[i].key == k) {
m->items[i].set = false;
m->len--;
diff --git a/lib9p/proto.gen b/lib9p/proto.gen
new file mode 100755
index 0000000..60f1347
--- /dev/null
+++ b/lib9p/proto.gen
@@ -0,0 +1,15 @@
+#!/usr/bin/env python
+# lib9p/proto.gen - Generate C marshalers/unmarshalers for .9p files
+# defining 9P protocol variants.
+#
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+import os.path
+import sys
+
+sys.path.insert(0, os.path.normpath(os.path.join(__file__, "..")))
+import protogen # pylint: disable=wrong-import-position
+
+if __name__ == "__main__":
+ protogen.main()
diff --git a/lib9p/protogen/__init__.py b/lib9p/protogen/__init__.py
new file mode 100644
index 0000000..c2c6173
--- /dev/null
+++ b/lib9p/protogen/__init__.py
@@ -0,0 +1,57 @@
+# lib9p/protogen/__init__.py - Generate C marshalers/unmarshalers for
+# .9p files defining 9P protocol variants
+#
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+import os.path
+import sys
+import typing
+
+import idl
+
+from . import c, h
+
+# pylint: disable=unused-variable
+__all__ = ["main"]
+
+
+def main() -> None:
+ if typing.TYPE_CHECKING:
+
+ class ANSIColors:
+ MAGENTA = "\x1b[35m"
+ RED = "\x1b[31m"
+ RESET = "\x1b[0m"
+
+ else:
+ from _colorize import ANSIColors # Present in Python 3.13+
+
+ if len(sys.argv) < 2:
+ raise ValueError("requires at least 1 .9p filename")
+ parser = idl.Parser()
+ for txtname in sys.argv[1:]:
+ try:
+ parser.parse_file(txtname)
+ except SyntaxError as e:
+ print(
+ f"{ANSIColors.RED}{e.filename}{ANSIColors.RESET}:{ANSIColors.MAGENTA}{e.lineno}{ANSIColors.RESET}: {e.msg}",
+ file=sys.stderr,
+ )
+ assert e.text
+ print(f"\t{e.text}", file=sys.stderr)
+ text_suffix = e.text.lstrip()
+ text_prefix = e.text[: -len(text_suffix)]
+ print(
+ f"\t{text_prefix}{ANSIColors.RED}{'~'*len(text_suffix)}{ANSIColors.RESET}",
+ file=sys.stderr,
+ )
+ sys.exit(2)
+ versions, typs = parser.all()
+ outdir = os.path.normpath(os.path.join(sys.argv[0], ".."))
+ with open(
+ os.path.join(outdir, "include/lib9p/9p.generated.h"), "w", encoding="utf-8"
+ ) as fh:
+ fh.write(h.gen_h(versions, typs))
+ with open(os.path.join(outdir, "9p.generated.c"), "w", encoding="utf-8") as fh:
+ fh.write(c.gen_c(versions, typs))
diff --git a/lib9p/protogen/c.py b/lib9p/protogen/c.py
new file mode 100644
index 0000000..a6824ce
--- /dev/null
+++ b/lib9p/protogen/c.py
@@ -0,0 +1,201 @@
+# lib9p/protogen/c.py - Generate 9p.generated.c
+#
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+import sys
+
+import idl
+
+from . import c9util, c_format, c_marshal, c_unmarshal, c_validate, cutil
+
+# This strives to be "general-purpose" in that it just acts on the
+# *.9p inputs; but (unfortunately?) there are a few special-cases in
+# this script, marked with "SPECIAL".
+
+
+# pylint: disable=unused-variable
+__all__ = ["gen_c"]
+
+
+def gen_c(versions: set[str], typs: list[idl.UserType]) -> str:
+ cutil.ifdef_init()
+
+ ret = f"""/* Generated by `{' '.join(sys.argv)}`. DO NOT EDIT! */
+
+#include <stdbool.h>
+#include <stddef.h> /* for size_t */
+#include <inttypes.h> /* for PRI* macros */
+#include <string.h> /* for memset() */
+
+#include <libmisc/assert.h>
+#include <libmisc/endian.h>
+
+#include <lib9p/9p.h>
+
+#include "tables.h"
+#include "utf8.h"
+"""
+ # libobj vtables ###########################################################
+ ret += """
+/* libobj vtables *************************************************************/
+"""
+ for typ in typs:
+ ret += cutil.ifdef_push(1, c9util.ver_ifdef(typ.in_versions))
+ ret += f"LO_IMPLEMENTATION_C(fmt_formatter, {c9util.typename(typ)}, {c9util.basename(typ)}, static);\n"
+ ret += cutil.ifdef_pop(0)
+
+ # utilities ################################################################
+ ret += """
+/* utilities ******************************************************************/
+"""
+
+ id2typ: dict[int, idl.Message] = {}
+ for msg in [msg for msg in typs if isinstance(msg, idl.Message)]:
+ id2typ[msg.msgid] = msg
+
+ for v in sorted(versions):
+ ret += f"#if CONFIG_9P_ENABLE_{v.replace('.', '_')}\n"
+ ret += (
+ f"\t#define _is_ver_{v.replace('.', '_')}(v) (v == {c9util.ver_enum(v)})\n"
+ )
+ ret += "#else\n"
+ ret += f"\t#define _is_ver_{v.replace('.', '_')}(v) false\n"
+ ret += "#endif\n"
+ ret += "\n"
+ ret += "/**\n"
+ ret += f" * is_ver(ctx, ver) is essentially `(ctx->version == {c9util.Ident('VER_')}##ver)`, but\n"
+ ret += f" * compiles correctly (to `false`) even if `{c9util.Ident('VER_')}##ver` isn't defined\n"
+ ret += " * (because `!CONFIG_9P_ENABLE_##ver`). This is useful when `||`ing\n"
+ ret += " * several version checks together.\n"
+ ret += " */\n"
+ ret += "#define is_ver(ctx, ver) _is_ver_##ver((ctx)->version)\n"
+
+ # bitmasks #################################################################
+ ret += """
+/* bitmasks *******************************************************************/
+"""
+ for typ in typs:
+ if not isinstance(typ, idl.Bitfield):
+ continue
+ ret += "\n"
+ ret += cutil.ifdef_push(1, c9util.ver_ifdef(typ.in_versions))
+ ret += f"static const {c9util.typename(typ)} {typ.typname}_masks[{c9util.ver_enum('NUM')}] = {{\n"
+ verwidth = max(len(ver) for ver in versions)
+ for ver in sorted(versions):
+ ret += cutil.ifdef_push(2, c9util.ver_ifdef({ver}))
+ ret += (
+ f"\t[{c9util.ver_enum(ver)}]{' '*(verwidth-len(ver))} = 0b"
+ + "".join(
+ (
+ "1"
+ if (bit.cat == "USED" or isinstance(bit.cat, idl.BitNum))
+ and ver in bit.in_versions
+ else "0"
+ )
+ for bit in reversed(typ.bits)
+ )
+ + ",\n"
+ )
+ ret += cutil.ifdef_pop(1)
+ ret += "};\n"
+ ret += cutil.ifdef_pop(0)
+
+ # validate_* ###############################################################
+ ret += c_validate.gen_c_validate(versions, typs)
+
+ # unmarshal_* ##############################################################
+ ret += c_unmarshal.gen_c_unmarshal(versions, typs)
+
+ # marshal_* ################################################################
+ ret += c_marshal.gen_c_marshal(versions, typs)
+
+ # *_format #################################################################
+ ret += c_format.gen_c_format(versions, typs)
+
+ # tables.h #################################################################
+ ret += """
+/* tables.h *******************************************************************/
+"""
+
+ ret += "\n"
+ ret += f"const struct {c9util.ident('_ver_tentry')} {c9util.ident('_table_ver')}[{c9util.ver_enum('NUM')}] = {{\n"
+ rerror = next(typ for typ in typs if typ.typname == "Rerror")
+ for ver in ["unknown", *sorted(versions)]:
+ if ver == "unknown":
+ min_msg_size = rerror.min_size("9P2000") # SPECIAL (initialization)
+ else:
+ ret += cutil.ifdef_push(1, c9util.ver_ifdef({ver}))
+ min_msg_size = rerror.min_size(ver)
+ ret += f'\t[{c9util.ver_enum(ver)}] = {{.name="{ver}", .min_msg_size={min_msg_size}}},\n'
+ ret += cutil.ifdef_pop(0)
+ ret += "};\n"
+
+ def msg_table(
+ cstruct: str, cname: str, each: str, _range: tuple[int, int, int]
+ ) -> str:
+ ret = f"const struct {c9util.ident(cstruct)} {c9util.ident(cname)}[{c9util.ver_enum('NUM')}][{hex(len(range(*_range)))}] = {{\n"
+ for ver in ["unknown", *sorted(versions)]:
+ if ver != "unknown":
+ ret += cutil.ifdef_push(1, c9util.ver_ifdef({ver}))
+ ret += f"\t[{c9util.ver_enum(ver)}] = {{\n"
+ for n in range(*_range):
+ xmsg: idl.Message | None = id2typ.get(n, None)
+ if xmsg:
+ if ver == "unknown": # SPECIAL (initialization)
+ if xmsg.typname not in ["Tversion", "Rversion", "Rerror"]:
+ xmsg = None
+ else:
+ if ver not in xmsg.in_versions:
+ xmsg = None
+ if xmsg:
+ ret += f"\t\t{each}({xmsg.typname}),\n"
+ ret += "\t},\n"
+ ret += cutil.ifdef_pop(0)
+ ret += "};\n"
+ return ret
+
+ ret += "\n"
+ ret += cutil.macro(
+ f"#define _MSG(typ) [{c9util.Ident('TYP_')}##typ] = {{\n"
+ f"\t\t.name = #typ,\n"
+ f"\t\t.box_as_fmt_formatter = (_box_as_fmt_formatter_fn_t)lo_box_{c9util.ident('msg_')}##typ##_as_fmt_formatter,\n"
+ f"\t}}\n"
+ )
+ ret += msg_table("_msg_tentry", "_table_msg", "_MSG", (0, 0x100, 1))
+
+ ret += "\n"
+ ret += cutil.macro(
+ f"#define _MSG_RECV(typ) [{c9util.Ident('TYP_')}##typ/2] = {{\n"
+ f"\t\t.validate = validate_##typ,\n"
+ f"\t\t.unmarshal = (_unmarshal_fn_t)unmarshal_##typ,\n"
+ f"\t}}\n"
+ )
+ ret += cutil.macro(
+ f"#define _MSG_SEND(typ) [{c9util.Ident('TYP_')}##typ/2] = {{\n"
+ f"\t\t.marshal = (_marshal_fn_t)marshal_##typ,\n"
+ f"\t}}\n"
+ )
+ ret += "\n"
+ ret += msg_table("_recv_tentry", "_table_Tmsg_recv", "_MSG_RECV", (0, 0x100, 2))
+ ret += "\n"
+ ret += msg_table("_recv_tentry", "_table_Rmsg_recv", "_MSG_RECV", (1, 0x100, 2))
+ ret += "\n"
+ ret += msg_table("_send_tentry", "_table_Tmsg_send", "_MSG_SEND", (0, 0x100, 2))
+ ret += "\n"
+ ret += msg_table("_send_tentry", "_table_Rmsg_send", "_MSG_SEND", (1, 0x100, 2))
+
+ ret += f"""
+LM_FLATTEN ssize_t {c9util.ident('_stat_validate')}(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, uint32_t *ret_net_size) {{
+\treturn validate_stat(ctx, net_size, net_bytes, ret_net_size);
+}}
+LM_FLATTEN void {c9util.ident('_stat_unmarshal')}(struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out) {{
+\tunmarshal_stat(ctx, net_bytes, out);
+}}
+LM_FLATTEN bool {c9util.ident('_stat_marshal')}(struct lib9p_ctx *ctx, struct {c9util.ident('stat')} *val, struct _marshal_ret *ret) {{
+\treturn marshal_stat(ctx, val, ret);
+}}
+"""
+
+ ############################################################################
+ return ret
diff --git a/lib9p/protogen/c9util.py b/lib9p/protogen/c9util.py
new file mode 100644
index 0000000..cf91951
--- /dev/null
+++ b/lib9p/protogen/c9util.py
@@ -0,0 +1,134 @@
+# lib9p/protogen/c9util.py - Utilities for generating lib9p-specific C
+#
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+import re
+import typing
+
+import idl
+
+# This strives to be "general-purpose" in that it just acts on the
+# *.9p inputs; but (unfortunately?) there are a few special-cases in
+# this script, marked with "SPECIAL".
+
+# pylint: disable=unused-variable
+__all__ = [
+ "add_prefix",
+ "ident",
+ "Ident",
+ "IDENT",
+ "ver_enum",
+ "ver_ifdef",
+ "ver_cond",
+ "typename",
+ "idl_expr",
+]
+
+# idents #######################################################################
+
+
+def add_prefix(p: str, s: str) -> str:
+ if s.startswith("_"):
+ return "_" + p + s[1:]
+ return p + s
+
+
+def _ident(p: str, s: str) -> str:
+ return add_prefix(p, s.replace(".", "_"))
+
+
+def ident(s: str) -> str:
+ return _ident("lib9p_", s)
+
+
+def Ident(s: str) -> str:
+ return _ident("lib9p_".upper(), s)
+
+
+def IDENT(s: str) -> str:
+ return _ident("lib9p_", s).upper()
+
+
+# versions #####################################################################
+
+
+def ver_enum(ver: str) -> str:
+ return Ident("VER_" + ver)
+
+
+def ver_ifdef(versions: typing.Collection[str]) -> str:
+ return " || ".join(
+ f"CONFIG_9P_ENABLE_{v.replace('.', '_')}" for v in sorted(versions)
+ )
+
+
+def ver_cond(versions: typing.Collection[str]) -> str:
+ if len(versions) == 1:
+ v = next(v for v in versions)
+ return f"is_ver(ctx, {v.replace('.', '_')})"
+ return "( " + (" || ".join(ver_cond({v}) for v in sorted(versions))) + " )"
+
+
+# misc #########################################################################
+
+
+def basename(typ: idl.UserType) -> str:
+ match typ:
+ case idl.Number():
+ return ident(typ.typname)
+ case idl.Bitfield():
+ return ident(typ.typname)
+ case idl.Message():
+ return ident(f"msg_{typ.typname}")
+ case idl.Struct():
+ return ident(typ.typname)
+ case _:
+ raise ValueError(f"not a defined type: {typ.__class__.__name__}")
+
+
+def typename(typ: idl.Type, parent: idl.StructMember | None = None) -> str:
+ match typ:
+ case idl.Primitive():
+ if typ.value == 1 and parent and parent.cnt: # SPECIAL (string)
+ return "[[gnu::nonstring]] char"
+ return f"uint{typ.value*8}_t"
+ case idl.Number():
+ return f"{basename(typ)}_t"
+ case idl.Bitfield():
+ return f"{basename(typ)}_t"
+ case idl.Message():
+ return f"struct {basename(typ)}"
+ case idl.Struct():
+ return f"struct {basename(typ)}"
+ case _:
+ raise ValueError(f"not a type: {typ.__class__.__name__}")
+
+
+def idl_expr(
+ expr: idl.Expr, lookup_sym: typing.Callable[[str], str], bitwidth: int = 0
+) -> str:
+ ret: list[str] = []
+ for tok in expr.tokens:
+ match tok:
+ case idl.ExprOp():
+ ret.append(tok.op)
+ case idl.ExprLit():
+ if bitwidth:
+ ret.append(f"{tok.val:#0{bitwidth}b}")
+ else:
+ ret.append(str(tok.val))
+ case idl.ExprSym():
+ if m := re.fullmatch(r"^u(8|16|32|64)_max$", tok.symname):
+ ret.append(f"UINT{m.group(1)}_MAX")
+ elif m := re.fullmatch(r"^s(8|16|32|64)_max$", tok.symname):
+ ret.append(f"INT{m.group(1)}_MAX")
+ else:
+ ret.append(lookup_sym(tok.symname))
+ case idl.ExprOff():
+ ret.append(lookup_sym("&" + tok.membname))
+ case idl.ExprNum():
+ ret.append(Ident(add_prefix(f"{tok.numname}_".upper(), tok.valname)))
+ case _:
+ assert False
+ return " ".join(ret)
diff --git a/lib9p/protogen/c_format.py b/lib9p/protogen/c_format.py
new file mode 100644
index 0000000..4a809d1
--- /dev/null
+++ b/lib9p/protogen/c_format.py
@@ -0,0 +1,161 @@
+# lib9p/protogen/c_format.py - Generate C pretty-print functions
+#
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+
+import idl
+
+from . import c9util, cutil
+
+# This strives to be "general-purpose" in that it just acts on the
+# *.9p inputs; but (unfortunately?) there are a few special-cases in
+# this script, marked with "SPECIAL".
+
+# pylint: disable=unused-variable
+__all__ = ["gen_c_format"]
+
+
+def bf_numname(typ: idl.Bitfield, num: idl.BitNum, base: str) -> str:
+ prefix = f"{typ.typname}_{num.numname}_".upper()
+ return c9util.Ident(c9util.add_prefix(prefix, base))
+
+
+def ext_printf(line: str) -> str:
+ assert line.startswith("\t")
+ assert line.endswith("\n")
+ # It sucks that %v trips -Wformat and -Wformat-extra-args
+ # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47781
+ ret = "#pragma GCC diagnostic push\n"
+ ret += '#pragma GCC diagnostic ignored "-Wformat"\n'
+ ret += '#pragma GCC diagnostic ignored "-Wformat-extra-args"\n'
+ ret += line
+ ret += "#pragma GCC diagnostic pop\n"
+ return ret
+
+
+def gen_c_format(versions: set[str], typs: list[idl.UserType]) -> str:
+ ret = """
+/* *_format *******************************************************************/
+"""
+ for typ in typs:
+ ret += "\n"
+ ret += cutil.ifdef_push(1, c9util.ver_ifdef(typ.in_versions))
+ ret += f"static void {c9util.basename(typ)}_format({c9util.typename(typ)} *self, struct fmt_state *state) {{\n"
+ match typ:
+ case idl.Number():
+ if typ.vals:
+ ret += "\tswitch (*self) {\n"
+ for name in typ.vals:
+ ret += f"\tcase {c9util.Ident(c9util.add_prefix(f'{typ.typname}_'.upper(), name))}:\n"
+ ret += f'\t\tfmt_state_puts(state, "{name}");\n'
+ ret += "\t\tbreak;\n"
+ ret += "\tdefault:\n"
+ ret += f'\t\tfmt_state_printf(state, "%"PRIu{typ.static_size*8}, *self);\n'
+ ret += "\t}\n"
+ else:
+ ret += f'\t\tfmt_state_printf(state, "%"PRIu{typ.static_size*8}, *self);\n'
+ case idl.Bitfield():
+ val = "*self"
+ if typ.typname == "dm": # SPECIAL (pretty file permissions)
+ val = f"(*self & ~(({c9util.typename(typ)})0777))"
+ ret += "\tbool empty = true;\n"
+ ret += "\tfmt_state_putchar(state, '(');\n"
+ nums: set[str] = set()
+
+ for bit in reversed(typ.bits):
+ match bit.cat:
+ case "UNUSED" | "USED" | "RESERVED":
+ if bit.cat == "UNUSED":
+ bitname = f"1<<{bit.num}"
+ else:
+ bitname = bit.bitname
+ ret += f"\tif ({val} & (UINT{typ.static_size*8}_C(1)<<{bit.num})) {{\n"
+ ret += "\t\tif (!empty)\n"
+ ret += "\t\t\tfmt_state_putchar(state, '|');\n"
+ ret += f'\t\tfmt_state_puts(state, "{bitname}");\n'
+ ret += "\t\tempty = false;\n"
+ ret += "\t}\n"
+ case idl.BitNum():
+ if bit.cat.numname in nums:
+ continue
+ ret += f"\tswitch ({val} & {bf_numname(typ, bit.cat, 'MASK')}) {{\n"
+ for name in bit.cat.vals:
+ ret += f"\tcase {bf_numname(typ, bit.cat, name)}:\n"
+ bitname = c9util.add_prefix(
+ f"{bit.cat.numname}_".upper(), name
+ )
+ ret += "\t\tif (!empty)\n"
+ ret += "\t\t\tfmt_state_putchar(state, '|');\n"
+ ret += f'\t\tfmt_state_puts(state, "{bitname}");\n'
+ ret += "\t\tempty = false;\n"
+ ret += "\t\tbreak;\n"
+ ret += "\tdefault:\n"
+ ret += "\t\tif (!empty)\n"
+ ret += "\t\t\tfmt_state_putchar(state, '|');\n"
+ ret += f'\t\tfmt_state_printf(state, "%"PRIu{typ.static_size*8}, {val} & {bf_numname(typ, bit.cat, 'MASK')});\n'
+ ret += "\t\tempty = false;\n"
+ ret += "\t}\n"
+ nums.add(bit.cat.numname)
+ if typ.typname == "dm": # SPECIAL (pretty file permissions)
+ ret += "\tif (!empty)\n"
+ ret += "\t\tfmt_state_putchar(state, '|');\n"
+ ret += f'\tfmt_state_printf(state, "%#04"PRIo{typ.static_size*8}, *self & 0777);\n'
+ else:
+ ret += "\tif (empty)\n"
+ ret += "\t\tfmt_state_putchar(state, '0');\n"
+ ret += "\tfmt_state_putchar(state, ')');\n"
+ case idl.Struct(typname="s"): # SPECIAL(string)
+ ret += ext_printf(
+ '\tfmt_state_printf(state, "%.*q", self->len, self->utf8);\n'
+ )
+ case idl.Struct(): # and idl.Message():
+ if isinstance(typ, idl.Message):
+ ret += f'\tfmt_state_puts(state, "{typ.typname} {{");\n'
+ else:
+ ret += "\tfmt_state_putchar(state, '{');\n"
+ for member in typ.members:
+ if member.val:
+ continue
+ ret += cutil.ifdef_push(2, c9util.ver_ifdef(member.in_versions))
+ if member.cnt:
+ if isinstance(member.cnt, int):
+ cnt_str = str(member.cnt)
+ cnt_typ = "size_t"
+ else:
+ cnt_str = f"self->{member.cnt.membname}"
+ cnt_typ = c9util.typename(member.cnt.typ)
+ if member.typ.static_size == 1: # SPECIAL (data)
+ ret += f"\tif (is_valid_utf8_without_nul((uint8_t *)self->{member.membname}, (size_t){cnt_str})) {{\n"
+ ret += ext_printf(
+ f'\t\tfmt_state_printf(state, " {member.membname}=%.*q%s",\n'
+ f"\t\t\t(int)({cnt_str} < 50 ? {cnt_str} : 50),\n"
+ f"\t\t\t(char *)self->{member.membname},\n"
+ f'\t\t\t{cnt_str} < 50 ? "" : "...");\n'
+ )
+ ret += "\t} else {\n"
+ ret += f'\t\tfmt_state_puts(state, " {member.membname}=<bytedata>");\n'
+ ret += "\t}\n"
+ continue
+ ret += f'\tfmt_state_puts(state, " {member.membname}=[");\n'
+ ret += f"\tfor ({cnt_typ} i = 0; i < {cnt_str}; i++) {{\n"
+ ret += "\t\tif (i)\n"
+ ret += '\t\t\tfmt_state_puts(state, ", ");\n'
+ if isinstance(member.typ, idl.Primitive):
+ ret += f'\t\tfmt_state_printf(state, "%"PRIu{member.typ.static_size*8}, self->{member.membname}[i]);\n'
+ else:
+ ret += f"\t\t{c9util.basename(member.typ)}_format(&self->{member.membname}[i], state);\n"
+ ret += "\t}\n"
+ ret += '\tfmt_state_puts(state, " ]");\n'
+ else:
+ ret += f'\tfmt_state_puts(state, " {member.membname}=");\n'
+ if isinstance(member.typ, idl.Primitive):
+ ret += f'\tfmt_state_printf(state, "%"PRIu{member.typ.static_size*8}, self->{member.membname});\n'
+ else:
+ ret += f"\t{c9util.basename(member.typ)}_format(&self->{member.membname}, state);\n"
+ ret += cutil.ifdef_pop(1)
+ ret += '\tfmt_state_puts(state, " }");\n'
+ ret += "}\n"
+ ret += cutil.ifdef_pop(0)
+
+ return ret
diff --git a/lib9p/protogen/c_marshal.py b/lib9p/protogen/c_marshal.py
new file mode 100644
index 0000000..4dab864
--- /dev/null
+++ b/lib9p/protogen/c_marshal.py
@@ -0,0 +1,403 @@
+# lib9p/protogen/c_marshal.py - Generate C marshal functions
+#
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+import typing
+
+import idl
+
+from . import c9util, cutil, idlutil
+
+# This strives to be "general-purpose" in that it just acts on the
+# *.9p inputs; but (unfortunately?) there are a few special-cases in
+# this script, marked with "SPECIAL".
+
+
+# pylint: disable=unused-variable
+__all__ = ["gen_c_marshal"]
+
+# get_offset_expr() ############################################################
+
+
+class OffsetExpr:
+ static: int
+ cond: dict[frozenset[str], "OffsetExpr"]
+ rep: list[tuple[idlutil.Path | int, "OffsetExpr"]]
+
+ def __init__(self) -> None:
+ self.static = 0
+ self.rep = []
+ self.cond = {}
+
+ def add(self, other: "OffsetExpr") -> None:
+ self.static += other.static
+ self.rep += other.rep
+ for k, v in other.cond.items():
+ if k in self.cond:
+ self.cond[k].add(v)
+ else:
+ self.cond[k] = v
+
+ def gen_c(
+ self,
+ dsttyp: str,
+ dstvar: str,
+ root: str,
+ indent_depth: int,
+ loop_depth: int,
+ ) -> str:
+ oneline: list[str] = []
+ multiline = ""
+ if self.static:
+ oneline.append(str(self.static))
+ for cnt, sub in self.rep:
+ if isinstance(cnt, int):
+ cnt_str = str(cnt)
+ cnt_typ = "size_t"
+ else:
+ cnt_str = cnt.c_str(root)
+ cnt_typ = c9util.typename(cnt.elems[-1].typ)
+ if not sub.cond and not sub.rep:
+ if sub.static == 1:
+ oneline.append(cnt_str)
+ else:
+ oneline.append(f"({cnt_str})*{sub.static}")
+ continue
+ loopvar = chr(ord("i") + loop_depth)
+ multiline += f"{'\t'*indent_depth}for ({cnt_typ} {loopvar} = 0; {loopvar} < {cnt_str}; {loopvar}++) {{\n"
+ multiline += sub.gen_c("", dstvar, root, indent_depth + 1, loop_depth + 1)
+ multiline += f"{'\t'*indent_depth}}}\n"
+ for vers, sub in self.cond.items():
+ multiline += cutil.ifdef_push(indent_depth + 1, c9util.ver_ifdef(vers))
+ multiline += f"{'\t'*indent_depth}if {c9util.ver_cond(vers)} {{\n"
+ multiline += sub.gen_c("", dstvar, root, indent_depth + 1, loop_depth)
+ multiline += f"{'\t'*indent_depth}}}\n"
+ multiline += cutil.ifdef_pop(indent_depth)
+ ret = ""
+ if dsttyp:
+ if not oneline:
+ oneline.append("0")
+ ret += f"{'\t'*indent_depth}{dsttyp} {dstvar} = {' + '.join(oneline)};\n"
+ elif oneline:
+ ret += f"{'\t'*indent_depth}{dstvar} += {' + '.join(oneline)};\n"
+ ret += multiline
+ return ret
+
+
+type OffsetExprRecursion = typing.Callable[[idlutil.Path], idlutil.WalkCmd]
+
+
+def get_offset_expr(typ: idl.UserType, recurse: OffsetExprRecursion) -> OffsetExpr:
+ if not isinstance(typ, idl.Struct):
+ assert typ.static_size
+ ret = OffsetExpr()
+ ret.static = typ.static_size
+ return ret
+
+ class ExprStackItem(typing.NamedTuple):
+ path: idlutil.Path
+ expr: OffsetExpr
+ pop: typing.Callable[[], None]
+
+ expr_stack: list[ExprStackItem]
+
+ def pop_root() -> None:
+ assert False
+
+ def pop_cond() -> None:
+ nonlocal expr_stack
+ key = frozenset(expr_stack[-1].path.elems[-1].in_versions)
+ if key in expr_stack[-2].expr.cond:
+ expr_stack[-2].expr.cond[key].add(expr_stack[-1].expr)
+ else:
+ expr_stack[-2].expr.cond[key] = expr_stack[-1].expr
+ expr_stack = expr_stack[:-1]
+
+ def pop_rep() -> None:
+ nonlocal expr_stack
+ member_path = expr_stack[-1].path
+ member = member_path.elems[-1]
+ assert member.cnt
+ cnt: idlutil.Path | int
+ if isinstance(member.cnt, int):
+ cnt = member.cnt
+ else:
+ cnt = member_path.parent().add(member.cnt)
+ expr_stack[-2].expr.rep.append((cnt, expr_stack[-1].expr))
+ expr_stack = expr_stack[:-1]
+
+ def handle(
+ path: idlutil.Path,
+ ) -> tuple[idlutil.WalkCmd, typing.Callable[[], None] | None]:
+ nonlocal recurse
+
+ ret = recurse(path)
+ if ret != idlutil.WalkCmd.KEEP_GOING:
+ return ret, None
+
+ nonlocal expr_stack
+ expr_stack_len = len(expr_stack)
+
+ def pop() -> None:
+ nonlocal expr_stack
+ nonlocal expr_stack_len
+ while len(expr_stack) > expr_stack_len:
+ expr_stack[-1].pop()
+
+ if path.elems:
+ child = path.elems[-1]
+ parent = path.elems[-2].typ if len(path.elems) > 1 else path.root
+ if child.in_versions < parent.in_versions:
+ expr_stack.append(
+ ExprStackItem(path=path, expr=OffsetExpr(), pop=pop_cond)
+ )
+ if child.cnt:
+ expr_stack.append(
+ ExprStackItem(path=path, expr=OffsetExpr(), pop=pop_rep)
+ )
+ if not isinstance(child.typ, idl.Struct):
+ assert child.typ.static_size
+ expr_stack[-1].expr.static += child.typ.static_size
+ return ret, pop
+
+ expr_stack = [
+ ExprStackItem(path=idlutil.Path(typ), expr=OffsetExpr(), pop=pop_root)
+ ]
+ idlutil.walk(typ, handle)
+ return expr_stack[0].expr
+
+
+def go_to_end(path: idlutil.Path) -> idlutil.WalkCmd:
+ return idlutil.WalkCmd.KEEP_GOING
+
+
+def go_to_tok(name: str) -> typing.Callable[[idlutil.Path], idlutil.WalkCmd]:
+ def ret(path: idlutil.Path) -> idlutil.WalkCmd:
+ if len(path.elems) == 1 and path.elems[0].membname == name:
+ return idlutil.WalkCmd.ABORT
+ return idlutil.WalkCmd.KEEP_GOING
+
+ return ret
+
+
+# Generate .c ##################################################################
+
+
+def gen_c_marshal(versions: set[str], typs: list[idl.UserType]) -> str:
+ ret = """
+/* marshal_* ******************************************************************/
+
+"""
+ ret += cutil.macro(
+ "#define MARSHAL_BYTES_ZEROCOPY(ctx, data, len)\n"
+ "\tif (ret->net_iov[ret->net_iov_cnt-1].iov_len)\n"
+ "\t\tret->net_iov_cnt++;\n"
+ "\tret->net_iov[ret->net_iov_cnt-1].iov_base = data;\n"
+ "\tret->net_iov[ret->net_iov_cnt-1].iov_len = len;\n"
+ "\tret->net_iov_cnt++;\n"
+ )
+ ret += cutil.macro(
+ "#define MARSHAL_BYTES(ctx, data, len)\n"
+ "\tif (!ret->net_iov[ret->net_iov_cnt-1].iov_base)\n"
+ "\t\tret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size];\n"
+ "\tmemcpy(&ret->net_copied[ret->net_copied_size], data, len);\n"
+ "\tret->net_copied_size += len;\n"
+ "\tret->net_iov[ret->net_iov_cnt-1].iov_len += len;\n"
+ )
+ ret += cutil.macro(
+ "#define MARSHAL_U8LE(ctx, val)\n"
+ "\tif (!ret->net_iov[ret->net_iov_cnt-1].iov_base)\n"
+ "\t\tret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size];\n"
+ "\tret->net_copied[ret->net_copied_size] = val;\n"
+ "\tret->net_copied_size += 1;\n"
+ "\tret->net_iov[ret->net_iov_cnt-1].iov_len += 1;\n"
+ )
+ ret += cutil.macro(
+ "#define MARSHAL_U16LE(ctx, val)\n"
+ "\tif (!ret->net_iov[ret->net_iov_cnt-1].iov_base)\n"
+ "\t\tret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size];\n"
+ "\tuint16le_encode(&ret->net_copied[ret->net_copied_size], val);\n"
+ "\tret->net_copied_size += 2;\n"
+ "\tret->net_iov[ret->net_iov_cnt-1].iov_len += 2;\n"
+ )
+ ret += cutil.macro(
+ "#define MARSHAL_U32LE(ctx, val)\n"
+ "\tif (!ret->net_iov[ret->net_iov_cnt-1].iov_base)\n"
+ "\t\tret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size];\n"
+ "\tuint32le_encode(&ret->net_copied[ret->net_copied_size], val);\n"
+ "\tret->net_copied_size += 4;\n"
+ "\tret->net_iov[ret->net_iov_cnt-1].iov_len += 4;\n"
+ )
+ ret += cutil.macro(
+ "#define MARSHAL_U64LE(ctx, val)\n"
+ "\tif (!ret->net_iov[ret->net_iov_cnt-1].iov_base)\n"
+ "\t\tret->net_iov[ret->net_iov_cnt-1].iov_base = &ret->net_copied[ret->net_copied_size];\n"
+ "\tuint64le_encode(&ret->net_copied[ret->net_copied_size], val);\n"
+ "\tret->net_copied_size += 8;\n"
+ "\tret->net_iov[ret->net_iov_cnt-1].iov_len += 8;\n"
+ )
+
+ class IndentLevel(typing.NamedTuple):
+ ifdef: bool # whether this is both `{` and `#if`, or just `{`
+
+ indent_stack: list[IndentLevel]
+
+ def ifdef_lvl() -> int:
+ return sum(1 if lvl.ifdef else 0 for lvl in indent_stack)
+
+ def indent_lvl() -> int:
+ return len(indent_stack)
+
+ max_size: int
+
+ def handle(
+ path: idlutil.Path,
+ ) -> tuple[idlutil.WalkCmd, typing.Callable[[], None]]:
+ nonlocal ret
+ nonlocal indent_stack
+ nonlocal max_size
+ indent_stack_len = len(indent_stack)
+
+ def pop() -> None:
+ nonlocal ret
+ nonlocal indent_stack
+ nonlocal indent_stack_len
+ while len(indent_stack) > indent_stack_len:
+ if len(indent_stack) == indent_stack_len + 1 and indent_stack[-1].ifdef:
+ break
+ ret += f"{'\t'*(indent_lvl()-1)}}}\n"
+ if indent_stack.pop().ifdef:
+ ret += cutil.ifdef_pop(ifdef_lvl())
+
+ loopdepth = sum(1 for elem in path.elems if elem.cnt)
+ struct = path.elems[-1].typ if path.elems else path.root
+ if isinstance(struct, idl.Struct):
+ offsets: list[str] = []
+ for member in struct.members:
+ if not member.val:
+ continue
+ for tok in member.val.tokens:
+ match tok:
+ case idl.ExprSym(symname="end"):
+ if tok.symname not in offsets:
+ offsets.append(tok.symname)
+ case idl.ExprOff():
+ if f"&{tok.membname}" not in offsets:
+ offsets.append(f"&{tok.membname}")
+ for name in offsets:
+ name_prefix = f"offsetof{''.join('_'+m.membname for m in path.elems)}_"
+ if name == "end":
+ if not path.elems:
+ if max_size > cutil.UINT32_MAX:
+ ret += f"{'\t'*indent_lvl()}uint32_t {name_prefix}end = (uint32_t)needed_size;\n"
+ else:
+ ret += f"{'\t'*indent_lvl()}uint32_t {name_prefix}end = needed_size;\n"
+ continue
+ recurse: OffsetExprRecursion = go_to_end
+ else:
+ assert name.startswith("&")
+ name = name[1:]
+ recurse = go_to_tok(name)
+ expr = get_offset_expr(struct, recurse)
+ expr_prefix = path.c_str("val->", loopdepth)
+ if not expr_prefix.endswith(">"):
+ expr_prefix += "."
+ ret += expr.gen_c(
+ "uint32_t",
+ name_prefix + name,
+ expr_prefix,
+ indent_lvl(),
+ loopdepth,
+ )
+ if not path.elems:
+ return idlutil.WalkCmd.KEEP_GOING, pop
+
+ child = path.elems[-1]
+ parent = path.elems[-2].typ if len(path.elems) > 1 else path.root
+ if child.in_versions < parent.in_versions:
+ if line := cutil.ifdef_push(
+ ifdef_lvl() + 1, c9util.ver_ifdef(child.in_versions)
+ ):
+ ret += line
+ ret += (
+ f"{'\t'*indent_lvl()}if ({c9util.ver_cond(child.in_versions)}) {{\n"
+ )
+ indent_stack.append(IndentLevel(ifdef=True))
+ if child.cnt:
+ if isinstance(child.cnt, int):
+ cnt_str = str(child.cnt)
+ cnt_typ = "size_t"
+ else:
+ cnt_str = path.parent().add(child.cnt).c_str("val->")
+ cnt_typ = c9util.typename(child.cnt.typ)
+ if child.typ.static_size == 1: # SPECIAL (zerocopy)
+ if path.root.typname == "stat": # SPECIAL (stat)
+ ret += f"{'\t'*indent_lvl()}MARSHAL_BYTES(ctx, {path.c_str('val->')[:-3]}, {cnt_str});\n"
+ else:
+ ret += f"{'\t'*indent_lvl()}MARSHAL_BYTES_ZEROCOPY(ctx, {path.c_str('val->')[:-3]}, {cnt_str});\n"
+ return idlutil.WalkCmd.KEEP_GOING, pop
+ loopvar = chr(ord("i") + loopdepth - 1)
+ ret += f"{'\t'*indent_lvl()}for ({cnt_typ} {loopvar} = 0; {loopvar} < {cnt_str}; {loopvar}++) {{\n"
+ indent_stack.append(IndentLevel(ifdef=False))
+ if not isinstance(child.typ, idl.Struct):
+ if child.val:
+
+ def lookup_sym(sym: str) -> str:
+ nonlocal path
+ if sym.startswith("&"):
+ sym = sym[1:]
+ return f"offsetof{''.join('_'+m.membname for m in path.elems[:-1])}_{sym}"
+
+ val = c9util.idl_expr(child.val, lookup_sym)
+ else:
+ val = path.c_str("val->")
+ if isinstance(child.typ, idl.Bitfield):
+ val += f" & {child.typ.typname}_masks[ctx->version]"
+ ret += f"{'\t'*indent_lvl()}MARSHAL_U{child.typ.static_size*8}LE(ctx, {val});\n"
+ return idlutil.WalkCmd.KEEP_GOING, pop
+
+ for typ in typs:
+ if not (
+ isinstance(typ, idl.Message) or typ.typname == "stat"
+ ): # SPECIAL (include stat)
+ continue
+ assert isinstance(typ, idl.Struct)
+ ret += "\n"
+ ret += cutil.ifdef_push(1, c9util.ver_ifdef(typ.in_versions))
+ ret += f"static bool marshal_{typ.typname}(struct lib9p_ctx *ctx, {c9util.typename(typ)} *val, struct _marshal_ret *ret) {{\n"
+
+ # Pass 1 - check size
+ max_size = max(typ.max_size(v) for v in typ.in_versions)
+
+ if max_size > cutil.UINT32_MAX: # SPECIAL (9P2000.e)
+ ret += get_offset_expr(typ, go_to_end).gen_c(
+ "uint64_t", "needed_size", "val->", 1, 0
+ )
+ ret += "\tif (needed_size > (uint64_t)(ctx->max_msg_size)) {\n"
+ else:
+ ret += get_offset_expr(typ, go_to_end).gen_c(
+ "uint32_t", "needed_size", "val->", 1, 0
+ )
+ ret += "\tif (needed_size > ctx->max_msg_size) {\n"
+ if isinstance(typ, idl.Message): # SPECIAL (disable for stat)
+ ret += '\t\tlib9p_errorf(ctx, LINUX_ERANGE, "%s message too large to marshal into %s limit (limit=%"PRIu32")",\n'
+ ret += f'\t\t\t"{typ.typname}",\n'
+ ret += f'\t\t\tctx->version ? "negotiated" : "{'client' if typ.msgid % 2 == 0 else 'server'}",\n'
+ ret += "\t\t\tctx->max_msg_size);\n"
+ ret += "\t\treturn true;\n"
+ ret += "\t}\n"
+
+ # Pass 2 - write data
+ indent_stack = [IndentLevel(ifdef=True)]
+ idlutil.walk(typ, handle)
+ while len(indent_stack) > 1:
+ ret += f"{'\t'*(indent_lvl()-1)}}}\n"
+ if indent_stack.pop().ifdef:
+ ret += cutil.ifdef_pop(ifdef_lvl())
+
+ # Return
+ ret += "\treturn false;\n"
+ ret += "}\n"
+ ret += cutil.ifdef_pop(0)
+ return ret
diff --git a/lib9p/protogen/c_unmarshal.py b/lib9p/protogen/c_unmarshal.py
new file mode 100644
index 0000000..34635f9
--- /dev/null
+++ b/lib9p/protogen/c_unmarshal.py
@@ -0,0 +1,138 @@
+# lib9p/protogen/c_unmarshal.py - Generate C unmarshal functions
+#
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+import typing
+
+import idl
+
+from . import c9util, cutil, idlutil
+
+# This strives to be "general-purpose" in that it just acts on the
+# *.9p inputs; but (unfortunately?) there are a few special-cases in
+# this script, marked with "SPECIAL".
+
+
+# pylint: disable=unused-variable
+__all__ = ["gen_c_unmarshal"]
+
+
+def gen_c_unmarshal(versions: set[str], typs: list[idl.UserType]) -> str:
+ ret = """
+/* unmarshal_* ****************************************************************/
+
+"""
+ ret += cutil.macro(
+ "#define UNMARSHAL_BYTES(ctx, data_lvalue, len)\n"
+ "\tdata_lvalue = (char *)&net_bytes[net_offset];\n"
+ "\tnet_offset += len;\n"
+ )
+ ret += cutil.macro(
+ "#define UNMARSHAL_U8LE(ctx, val_lvalue)\n"
+ "\tval_lvalue = net_bytes[net_offset];\n"
+ "\tnet_offset += 1;\n"
+ )
+ ret += cutil.macro(
+ "#define UNMARSHAL_U16LE(ctx, val_lvalue)\n"
+ "\tval_lvalue = uint16le_decode(&net_bytes[net_offset]);\n"
+ "\tnet_offset += 2;\n"
+ )
+ ret += cutil.macro(
+ "#define UNMARSHAL_U32LE(ctx, val_lvalue)\n"
+ "\tval_lvalue = uint32le_decode(&net_bytes[net_offset]);\n"
+ "\tnet_offset += 4;\n"
+ )
+ ret += cutil.macro(
+ "#define UNMARSHAL_U64LE(ctx, val_lvalue)\n"
+ "\tval_lvalue = uint64le_decode(&net_bytes[net_offset]);\n"
+ "\tnet_offset += 8;\n"
+ )
+
+ class IndentLevel(typing.NamedTuple):
+ ifdef: bool # whether this is both `{` and `#if`, or just `{`
+
+ indent_stack: list[IndentLevel]
+
+ def ifdef_lvl() -> int:
+ return sum(1 if lvl.ifdef else 0 for lvl in indent_stack)
+
+ def indent_lvl() -> int:
+ return len(indent_stack)
+
+ def handle(
+ path: idlutil.Path,
+ ) -> tuple[idlutil.WalkCmd, typing.Callable[[], None]]:
+ nonlocal ret
+ nonlocal indent_stack
+ indent_stack_len = len(indent_stack)
+
+ def pop() -> None:
+ nonlocal ret
+ nonlocal indent_stack
+ nonlocal indent_stack_len
+ while len(indent_stack) > indent_stack_len:
+ if len(indent_stack) == indent_stack_len + 1 and indent_stack[-1].ifdef:
+ break
+ ret += f"{'\t'*(indent_lvl()-1)}}}\n"
+ if indent_stack.pop().ifdef:
+ ret += cutil.ifdef_pop(ifdef_lvl())
+
+ if not path.elems:
+ return idlutil.WalkCmd.KEEP_GOING, pop
+
+ child = path.elems[-1]
+ parent = path.elems[-2].typ if len(path.elems) > 1 else path.root
+ if child.in_versions < parent.in_versions:
+ if line := cutil.ifdef_push(
+ ifdef_lvl() + 1, c9util.ver_ifdef(child.in_versions)
+ ):
+ ret += line
+ ret += (
+ f"{'\t'*indent_lvl()}if ({c9util.ver_cond(child.in_versions)}) {{\n"
+ )
+ indent_stack.append(IndentLevel(ifdef=True))
+ if child.cnt:
+ if isinstance(child.cnt, int):
+ cnt_str = str(child.cnt)
+ cnt_typ = "size_t"
+ else:
+ cnt_str = path.parent().add(child.cnt).c_str("out->")
+ cnt_typ = c9util.typename(child.cnt.typ)
+ if child.typ.static_size == 1: # SPECIAL (zerocopy)
+ ret += f"{'\t'*indent_lvl()}UNMARSHAL_BYTES(ctx, {path.c_str('out->')[:-3]}, {cnt_str});\n"
+ return idlutil.WalkCmd.KEEP_GOING, pop
+ ret += f"{'\t'*indent_lvl()}{path.c_str('out->')[:-3]} = extra;\n"
+ ret += f"{'\t'*indent_lvl()}extra += sizeof({path.c_str('out->')[:-3]}[0]) * {cnt_str};\n"
+ loopdepth = sum(1 for elem in path.elems if elem.cnt)
+ loopvar = chr(ord("i") + loopdepth - 1)
+ ret += f"{'\t'*indent_lvl()}for ({cnt_typ} {loopvar} = 0; {loopvar} < {cnt_str}; {loopvar}++) {{\n"
+ indent_stack.append(IndentLevel(ifdef=False))
+ if not isinstance(child.typ, idl.Struct):
+ if child.val:
+ ret += f"{'\t'*indent_lvl()}net_offset += {child.typ.static_size};\n"
+ else:
+ ret += f"{'\t'*indent_lvl()}UNMARSHAL_U{child.typ.static_size*8}LE(ctx, {path.c_str('out->')});\n"
+ return idlutil.WalkCmd.KEEP_GOING, pop
+
+ for typ in typs:
+ if not (
+ isinstance(typ, idl.Message) or typ.typname == "stat"
+ ): # SPECIAL (include stat)
+ continue
+ assert isinstance(typ, idl.Struct)
+ ret += "\n"
+ ret += cutil.ifdef_push(1, c9util.ver_ifdef(typ.in_versions))
+ ret += f"static void unmarshal_{typ.typname}([[gnu::unused]] struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out_buf) {{\n"
+ ret += f"\t{c9util.typename(typ)} *out = out_buf;\n"
+ ret += "\t[[gnu::unused]] void *extra = &out[1];\n"
+ ret += "\tuint32_t net_offset = 0;\n"
+
+ indent_stack = [IndentLevel(ifdef=True)]
+ idlutil.walk(typ, handle)
+ while len(indent_stack) > 0:
+ ret += f"{'\t'*(indent_lvl()-1)}}}\n"
+ if indent_stack.pop().ifdef and indent_stack:
+ ret += cutil.ifdef_pop(ifdef_lvl())
+ ret += cutil.ifdef_pop(0)
+ return ret
diff --git a/lib9p/protogen/c_validate.py b/lib9p/protogen/c_validate.py
new file mode 100644
index 0000000..535a750
--- /dev/null
+++ b/lib9p/protogen/c_validate.py
@@ -0,0 +1,299 @@
+# lib9p/protogen/c_validate.py - Generate C validation functions
+#
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+import typing
+
+import idl
+
+from . import c9util, cutil, idlutil
+
+# This strives to be "general-purpose" in that it just acts on the
+# *.9p inputs; but (unfortunately?) there are a few special-cases in
+# this script, marked with "SPECIAL".
+
+
+# pylint: disable=unused-variable
+__all__ = ["gen_c_validate"]
+
+
+def should_save_offset(parent: idl.Struct, child: idl.StructMember) -> bool:
+ if child.val or child.max or isinstance(child.typ, idl.Bitfield):
+ return True
+ for sibling in parent.members:
+ if sibling.val:
+ for tok in sibling.val.tokens:
+ if isinstance(tok, idl.ExprOff) and tok.membname == child.membname:
+ return True
+ if sibling.max:
+ for tok in sibling.max.tokens:
+ if isinstance(tok, idl.ExprOff) and tok.membname == child.membname:
+ return True
+ return False
+
+
+def should_save_end_offset(struct: idl.Struct) -> bool:
+ for memb in struct.members:
+ if memb.val:
+ for tok in memb.val.tokens:
+ if isinstance(tok, idl.ExprSym) and tok.symname == "end":
+ return True
+ if memb.max:
+ for tok in memb.max.tokens:
+ if isinstance(tok, idl.ExprSym) and tok.symname == "end":
+ return True
+ return False
+
+
+def gen_c_validate(versions: set[str], typs: list[idl.UserType]) -> str:
+ ret = """
+/* validate_* *****************************************************************/
+
+"""
+ ret += cutil.macro(
+ "#define VALIDATE_NET_BYTES(n)\n"
+ "\tif (__builtin_add_overflow(net_offset, n, &net_offset))\n"
+ "\t\t/* If needed-net-size overflowed uint32_t, then\n"
+ "\t\t * there's no way that actual-net-size will live up to\n"
+ "\t\t * that. */\n"
+ '\t\treturn lib9p_error(ctx, LINUX_EBADMSG, "message is too short for content");\n'
+ "\tif (net_offset > net_size)\n"
+ '\t\treturn lib9p_errorf(ctx, LINUX_EBADMSG, "message is too short for content (%"PRIu32" > %"PRIu32") @ %d", net_offset, net_size, __LINE__);\n'
+ )
+ ret += cutil.macro(
+ "#define VALIDATE_NET_UTF8(n)\n"
+ "\t{\n"
+ "\t\tsize_t len = n;\n"
+ "\t\tVALIDATE_NET_BYTES(len);\n"
+ "\t\tif (!is_valid_utf8_without_nul(&net_bytes[net_offset-len], len))\n"
+ '\t\t\treturn lib9p_error(ctx, LINUX_EBADMSG, "message contains invalid UTF-8");\n'
+ "\t}\n"
+ )
+ ret += cutil.macro(
+ "#define RESERVE_HOST_BYTES(n)\n"
+ "\tif (__builtin_add_overflow(host_size, n, &host_size))\n"
+ "\t\t/* If needed-host-size overflowed ssize_t, then there's\n"
+ "\t\t * no way that actual-net-size will live up to\n"
+ "\t\t * that. */\n"
+ '\t\treturn lib9p_error(ctx, LINUX_EBADMSG, "message is too short for content");\n'
+ )
+
+ ret += "#define GET_U8LE(off) (net_bytes[off])\n"
+ ret += "#define GET_U16LE(off) uint16le_decode(&net_bytes[off])\n"
+ ret += "#define GET_U32LE(off) uint32le_decode(&net_bytes[off])\n"
+ ret += "#define GET_U64LE(off) uint64le_decode(&net_bytes[off])\n"
+
+ ret += "#define LAST_U8LE() GET_U8LE(net_offset-1)\n"
+ ret += "#define LAST_U16LE() GET_U16LE(net_offset-2)\n"
+ ret += "#define LAST_U32LE() GET_U32LE(net_offset-4)\n"
+ ret += "#define LAST_U64LE() GET_U64LE(net_offset-8)\n"
+
+ class IndentLevel(typing.NamedTuple):
+ ifdef: bool # whether this is both `{` and `#if`, or just `{`
+
+ indent_stack: list[IndentLevel]
+
+ def ifdef_lvl() -> int:
+ return sum(1 if lvl.ifdef else 0 for lvl in indent_stack)
+
+ def indent_lvl() -> int:
+ return len(indent_stack)
+
+ incr_buf: int
+
+ def incr_flush() -> None:
+ nonlocal ret
+ nonlocal incr_buf
+ if incr_buf:
+ ret += f"{'\t'*indent_lvl()}VALIDATE_NET_BYTES({incr_buf});\n"
+ incr_buf = 0
+
+ def gen_validate_size(path: idlutil.Path) -> None:
+ nonlocal ret
+ nonlocal incr_buf
+ nonlocal indent_stack
+
+ assert path.elems
+ child = path.elems[-1]
+ parent = path.elems[-2].typ if len(path.elems) > 1 else path.root
+ assert isinstance(parent, idl.Struct)
+
+ if child.in_versions < parent.in_versions:
+ if line := cutil.ifdef_push(
+ ifdef_lvl() + 1, c9util.ver_ifdef(child.in_versions)
+ ):
+ incr_flush()
+ ret += line
+ ret += (
+ f"{'\t'*indent_lvl()}if ({c9util.ver_cond(child.in_versions)}) {{\n"
+ )
+ indent_stack.append(IndentLevel(ifdef=True))
+ if should_save_offset(parent, child):
+ ret += f"{'\t'*indent_lvl()}uint32_t offsetof{''.join('_'+m.membname for m in path.elems)} = net_offset + {incr_buf};\n"
+ if child.cnt:
+ if isinstance(child.cnt, int):
+ cnt_str = str(child.cnt)
+ cnt_typ = "size_t"
+ else:
+ assert child.cnt.typ.static_size
+ incr_flush()
+ cnt_str = f"LAST_U{child.cnt.typ.static_size*8}LE()"
+ cnt_typ = c9util.typename(child.cnt.typ)
+ if child.membname == "utf8": # SPECIAL (string)
+ assert child.typ.static_size == 1
+ # Yes, this is content-validation and "belongs" in
+ # gen_validate_content(), not here. But it's just
+ # easier this way.
+ incr_flush()
+ ret += f"{'\t'*indent_lvl()}VALIDATE_NET_UTF8({cnt_str});\n"
+ return
+ if child.typ.static_size == 1: # SPECIAL (zerocopy)
+ if isinstance(child.cnt, int):
+ incr_buf += child.cnt
+ return
+ incr_flush()
+ ret += f"{'\t'*indent_lvl()}VALIDATE_NET_BYTES({cnt_str});\n"
+ return
+ loopdepth = sum(1 for elem in path.elems if elem.cnt)
+ loopvar = chr(ord("i") + loopdepth - 1)
+ incr_flush()
+ ret += f"{'\t'*indent_lvl()}for ({cnt_typ} {loopvar} = 0, cnt = {cnt_str}; {loopvar} < cnt; {loopvar}++) {{\n"
+ indent_stack.append(IndentLevel(ifdef=False))
+ ret += f"{'\t'*indent_lvl()}RESERVE_HOST_BYTES(sizeof({c9util.typename(child.typ)}));\n"
+ if not isinstance(child.typ, idl.Struct):
+ incr_buf += child.typ.static_size
+
+ def gen_validate_content(path: idlutil.Path) -> None:
+ nonlocal ret
+ nonlocal incr_buf
+ nonlocal indent_stack
+
+ assert path.elems
+ child = path.elems[-1]
+ parent = path.elems[-2].typ if len(path.elems) > 1 else path.root
+ assert isinstance(parent, idl.Struct)
+
+ def lookup_sym(sym: str) -> str:
+ if sym.startswith("&"):
+ sym = sym[1:]
+ return f"offsetof{''.join('_'+m.membname for m in path.elems[:-1])}_{sym}"
+
+ if child.val:
+ incr_flush()
+ assert child.typ.static_size
+ nbits = child.typ.static_size * 8
+ nbits = child.typ.static_size * 8
+ if nbits < 32 and any(
+ isinstance(tok, idl.ExprSym)
+ and (tok.symname == "end" or tok.symname.startswith("&"))
+ for tok in child.val.tokens
+ ):
+ nbits = 32
+ act = f"(uint{nbits}_t)GET_U{nbits}LE({lookup_sym(f'&{child.membname}')})"
+ exp = f"(uint{nbits}_t)({c9util.idl_expr(child.val, lookup_sym)})"
+ ret += f"{'\t'*indent_lvl()}if ({act} != {exp})\n"
+ ret += f'{"\t"*(indent_lvl()+1)}return lib9p_errorf(ctx, LINUX_EBADMSG, "{path} value is wrong: actual: %"PRIu{nbits}" != correct:%"PRIu{nbits},\n'
+ ret += f"{'\t'*(indent_lvl()+2)}{act}, {exp});\n"
+ if child.max:
+ incr_flush()
+ assert child.typ.static_size
+ nbits = child.typ.static_size * 8
+ if nbits < 32 and any(
+ isinstance(tok, idl.ExprSym)
+ and (tok.symname == "end" or tok.symname.startswith("&"))
+ for tok in child.max.tokens
+ ):
+ nbits = 32
+ act = f"(uint{nbits}_t)GET_U{nbits}LE({lookup_sym(f'&{child.membname}')})"
+ exp = f"(uint{nbits}_t)({c9util.idl_expr(child.max, lookup_sym)})"
+ ret += f"{'\t'*indent_lvl()}if ({act} > {exp})\n"
+ ret += f'{"\t"*(indent_lvl()+1)}return lib9p_errorf(ctx, LINUX_EBADMSG, "{path} value is too large: %"PRIu{nbits}" > %"PRIu{nbits},\n'
+ ret += f"{'\t'*(indent_lvl()+2)}{act}, {exp});\n"
+ if isinstance(child.typ, idl.Bitfield):
+ incr_flush()
+ nbytes = child.typ.static_size
+ nbits = nbytes * 8
+ act = f"GET_U{nbits}LE({lookup_sym(f'&{child.membname}')})"
+ ret += f"{'\t'*indent_lvl()}if ({act} & ~{child.typ.typname}_masks[ctx->version])\n"
+ ret += f'{"\t"*(indent_lvl()+1)}return lib9p_errorf(ctx, LINUX_EBADMSG, "unknown bits in {child.typ.typname} bitfield: %#0{nbytes*2}"PRIx{nbits},\n'
+ ret += f"{'\t'*(indent_lvl()+2)}{act} & ~{child.typ.typname}_masks[ctx->version]);\n"
+
+ def handle(
+ path: idlutil.Path,
+ ) -> tuple[idlutil.WalkCmd, typing.Callable[[], None]]:
+ nonlocal ret
+ nonlocal incr_buf
+ nonlocal indent_stack
+ indent_stack_len = len(indent_stack)
+ pop_struct = path.elems[-1].typ if path.elems else path.root
+ pop_path = path
+ pop_indent_stack_len: int
+
+ def pop() -> None:
+ nonlocal ret
+ nonlocal indent_stack
+ nonlocal indent_stack_len
+ nonlocal pop_struct
+ nonlocal pop_path
+ nonlocal pop_indent_stack_len
+ if isinstance(pop_struct, idl.Struct):
+ while len(indent_stack) > pop_indent_stack_len:
+ incr_flush()
+ ret += f"{'\t'*(indent_lvl()-1)}}}\n"
+ if indent_stack.pop().ifdef:
+ ret += cutil.ifdef_pop(ifdef_lvl())
+ parent = pop_struct
+ path = pop_path
+ if should_save_end_offset(parent):
+ ret += f"{'\t'*indent_lvl()}uint32_t offsetof{''.join('_'+m.membname for m in path.elems)}_end = net_offset + {incr_buf};\n"
+ for child in parent.members:
+ gen_validate_content(pop_path.add(child))
+ while len(indent_stack) > indent_stack_len:
+ if len(indent_stack) == indent_stack_len + 1 and indent_stack[-1].ifdef:
+ break
+ incr_flush()
+ ret += f"{'\t'*(indent_lvl()-1)}}}\n"
+ if indent_stack.pop().ifdef:
+ ret += cutil.ifdef_pop(ifdef_lvl())
+
+ if path.elems:
+ gen_validate_size(path)
+
+ pop_indent_stack_len = len(indent_stack)
+
+ return idlutil.WalkCmd.KEEP_GOING, pop
+
+ for typ in typs:
+ if not (
+ isinstance(typ, idl.Message) or typ.typname == "stat"
+ ): # SPECIAL (include stat)
+ continue
+ assert isinstance(typ, idl.Struct)
+ ret += "\n"
+ ret += cutil.ifdef_push(1, c9util.ver_ifdef(typ.in_versions))
+ if typ.typname == "stat": # SPECIAL (stat)
+ ret += f"static ssize_t validate_{typ.typname}(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, uint32_t *ret_net_size) {{\n"
+ else:
+ ret += f"static ssize_t validate_{typ.typname}(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes) {{\n"
+
+ ret += "\tuint32_t net_offset = 0;\n"
+ ret += f"\tssize_t host_size = sizeof({c9util.typename(typ)});\n"
+
+ incr_buf = 0
+ indent_stack = [IndentLevel(ifdef=True)]
+ idlutil.walk(typ, handle)
+ while len(indent_stack) > 1:
+ incr_flush()
+ ret += f"{'\t'*(indent_lvl()-1)}}}\n"
+ if indent_stack.pop().ifdef:
+ ret += cutil.ifdef_pop(ifdef_lvl())
+
+ incr_flush()
+ if typ.typname == "stat": # SPECIAL (stat)
+ ret += "\tif (ret_net_size)\n"
+ ret += "\t\t*ret_net_size = net_offset;\n"
+ ret += "\treturn (ssize_t)host_size;\n"
+ ret += "}\n"
+ ret += cutil.ifdef_pop(0)
+ return ret
diff --git a/lib9p/protogen/cutil.py b/lib9p/protogen/cutil.py
new file mode 100644
index 0000000..8df6db9
--- /dev/null
+++ b/lib9p/protogen/cutil.py
@@ -0,0 +1,84 @@
+# lib9p/protogen/cutil.py - Utilities for generating C code
+#
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+# pylint: disable=unused-variable
+__all__ = [
+ "UINT32_MAX",
+ "UINT64_MAX",
+ "macro",
+ "ifdef_init",
+ "ifdef_push",
+ "ifdef_pop",
+ "ifdef_leaf_is_noop",
+]
+
+UINT32_MAX = (1 << 32) - 1
+UINT64_MAX = (1 << 64) - 1
+
+
+def tab_ljust(s: str, width: int) -> str:
+ cur = len(s.expandtabs(tabsize=8))
+ if cur >= width:
+ return s
+ return s + " " * (width - cur)
+
+
+def macro(full: str) -> str:
+ full = full.rstrip()
+ assert "\n" in full
+ lines = [l.rstrip() for l in full.split("\n")]
+ width = max(len(l.expandtabs(tabsize=8)) for l in lines[:-1])
+ lines = [tab_ljust(l, width) for l in lines]
+ return " \\\n".join(lines).rstrip() + "\n"
+
+
+_ifdef_stack: list[str | None] = []
+
+
+def ifdef_init() -> None:
+ global _ifdef_stack
+ _ifdef_stack = []
+
+
+def ifdef_push(n: int, _newval: str) -> str:
+ # Grow the stack as needed
+ while len(_ifdef_stack) < n:
+ _ifdef_stack.append(None)
+
+ # Set some variables
+ parentval: str | None = None
+ for x in _ifdef_stack[:-1]:
+ if x is not None:
+ parentval = x
+ oldval = _ifdef_stack[-1]
+ newval: str | None = _newval
+ if newval == parentval:
+ newval = None
+
+ # Put newval on the stack.
+ _ifdef_stack[-1] = newval
+
+ # Build output.
+ ret = ""
+ if newval != oldval:
+ if oldval is not None:
+ ret += f"#endif /* {oldval} */\n"
+ if newval is not None:
+ ret += f"#if {newval}\n"
+ return ret
+
+
+def ifdef_pop(n: int) -> str:
+ global _ifdef_stack
+ ret = ""
+ while len(_ifdef_stack) > n:
+ if _ifdef_stack[-1] is not None:
+ ret += f"#endif /* {_ifdef_stack[-1]} */\n"
+ _ifdef_stack = _ifdef_stack[:-1]
+ return ret
+
+
+def ifdef_leaf_is_noop() -> bool:
+ return not _ifdef_stack[-1]
diff --git a/lib9p/protogen/h.py b/lib9p/protogen/h.py
new file mode 100644
index 0000000..8f7fba2
--- /dev/null
+++ b/lib9p/protogen/h.py
@@ -0,0 +1,535 @@
+# lib9p/protogen/h.py - Generate 9p.generated.h
+#
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+import sys
+import typing
+
+import idl
+
+from . import c9util, cutil, idlutil
+
+# This strives to be "general-purpose" in that it just acts on the
+# *.9p inputs; but (unfortunately?) there are a few special-cases in
+# this script, marked with "SPECIAL".
+
+# pylint: disable=unused-variable
+__all__ = ["gen_h"]
+
+# get_buffer_size() ############################################################
+
+
+class BufferSize(typing.NamedTuple):
+ min_size: int # really just here to sanity-check against typ.min_size(version)
+ exp_size: int # "expected" or max-reasonable size
+ max_size: int # really just here to sanity-check against typ.max_size(version)
+ max_copy: int
+ max_copy_extra: str
+ max_iov: int
+ max_iov_extra: str
+
+
+class TmpBufferSize:
+ min_size: int
+ exp_size: int
+ max_size: int
+ max_copy: int
+ max_copy_extra: str
+ max_iov: int
+ max_iov_extra: str
+
+ tmp_starts_with_copy: bool
+ tmp_ends_with_copy: bool
+
+ def __init__(self) -> None:
+ self.min_size = 0
+ self.exp_size = 0
+ self.max_size = 0
+ self.max_copy = 0
+ self.max_copy_extra = ""
+ self.max_iov = 0
+ self.max_iov_extra = ""
+ self.tmp_starts_with_copy = False
+ self.tmp_ends_with_copy = False
+
+
+def _get_buffer_size(typ: idl.Type, version: str) -> TmpBufferSize:
+ assert isinstance(typ, idl.Primitive) or (version in typ.in_versions)
+
+ ret = TmpBufferSize()
+
+ if not isinstance(typ, idl.Struct):
+ assert typ.static_size
+ ret.min_size = typ.static_size
+ ret.exp_size = typ.static_size
+ ret.max_size = typ.static_size
+ ret.max_copy = typ.static_size
+ ret.max_iov = 1
+ ret.tmp_starts_with_copy = True
+ ret.tmp_ends_with_copy = True
+ return ret
+
+ def handle(path: idlutil.Path) -> tuple[idlutil.WalkCmd, None]:
+ nonlocal ret
+ if path.elems:
+ child = path.elems[-1]
+ if version not in child.in_versions:
+ return idlutil.WalkCmd.DONT_RECURSE, None
+ if child.cnt:
+ if child.typ.static_size == 1: # SPECIAL (zerocopy)
+ ret.max_iov += 1
+ # HEURISTIC: 27 for strings (max-strlen from 9P1), 8KiB for other data
+ ret.exp_size += 27 if child.membname == "utf8" else 8192
+ ret.max_size += child.max_cnt
+ ret.tmp_ends_with_copy = False
+ return idlutil.WalkCmd.DONT_RECURSE, None
+ sub = _get_buffer_size(child.typ, version)
+ ret.exp_size += sub.exp_size * 16 # HEURISTIC: MAXWELEM
+ ret.max_size += sub.max_size * child.max_cnt
+ if child.membname == "wname" and path.root.typname in (
+ "Tsread",
+ "Tswrite",
+ ): # SPECIAL (9P2000.e)
+ assert ret.tmp_ends_with_copy
+ assert sub.tmp_starts_with_copy
+ assert not sub.tmp_ends_with_copy
+ ret.max_copy_extra = (
+ f" + (CONFIG_9P_MAX_9P2000_e_WELEM * {sub.max_copy})"
+ )
+ ret.max_iov_extra = (
+ f" + (CONFIG_9P_MAX_9P2000_e_WELEM * {sub.max_iov})"
+ )
+ ret.max_iov -= 1
+ else:
+ ret.max_copy += sub.max_copy * child.max_cnt
+ if sub.max_iov == 1 and sub.tmp_starts_with_copy: # is purely copy
+ ret.max_iov += 1
+ else: # contains zero-copy segments
+ ret.max_iov += sub.max_iov * child.max_cnt
+ if ret.tmp_ends_with_copy and sub.tmp_starts_with_copy:
+ # we can merge this one
+ ret.max_iov -= 1
+ if (
+ sub.tmp_ends_with_copy
+ and sub.tmp_starts_with_copy
+ and sub.max_iov > 1
+ ):
+ # we can merge these
+ ret.max_iov -= child.max_cnt - 1
+ ret.tmp_ends_with_copy = sub.tmp_ends_with_copy
+ return idlutil.WalkCmd.DONT_RECURSE, None
+ if not isinstance(child.typ, idl.Struct):
+ assert child.typ.static_size
+ if not ret.tmp_ends_with_copy:
+ if ret.max_size == 0:
+ ret.tmp_starts_with_copy = True
+ ret.max_iov += 1
+ ret.tmp_ends_with_copy = True
+ ret.min_size += child.typ.static_size
+ ret.exp_size += child.typ.static_size
+ ret.max_size += child.typ.static_size
+ ret.max_copy += child.typ.static_size
+ return idlutil.WalkCmd.KEEP_GOING, None
+
+ idlutil.walk(typ, handle)
+ assert ret.min_size == typ.min_size(version)
+ assert ret.max_size == typ.max_size(version)
+ return ret
+
+
+def get_buffer_size(typ: idl.Type, version: str) -> BufferSize:
+ tmp = _get_buffer_size(typ, version)
+ return BufferSize(
+ min_size=tmp.min_size,
+ exp_size=tmp.exp_size,
+ max_size=tmp.max_size,
+ max_copy=tmp.max_copy,
+ max_copy_extra=tmp.max_copy_extra,
+ max_iov=tmp.max_iov,
+ max_iov_extra=tmp.max_iov_extra,
+ )
+
+
+# Generate .h ##################################################################
+
+
+def gen_h(versions: set[str], typs: list[idl.UserType]) -> str:
+ cutil.ifdef_init()
+
+ ret = f"""/* Generated by `{' '.join(sys.argv)}`. DO NOT EDIT! */
+
+#ifndef _LIB9P_9P_H_
+\t#error Do not include <lib9p/9p.generated.h> directly; include <lib9p/9p.h> instead
+#endif
+
+#include <stdint.h> /* for uint{{n}}_t types */
+
+#include <libfmt/fmt.h> /* for fmt_formatter */
+#include <libhw/generic/io.h> /* for struct iovec */
+"""
+
+ id2typ: dict[int, idl.Message] = {}
+ for msg in [msg for msg in typs if isinstance(msg, idl.Message)]:
+ id2typ[msg.msgid] = msg
+
+ ret += """
+/* config *********************************************************************/
+
+#include "config.h"
+"""
+ for ver in sorted(versions):
+ ret += "\n"
+ ret += f"#ifndef {c9util.ver_ifdef({ver})}\n"
+ ret += f"\t#error config.h must define {c9util.ver_ifdef({ver})}\n"
+ if ver == "9P2000.e": # SPECIAL (9P2000.e)
+ ret += "#else\n"
+ ret += f"\t#if {c9util.ver_ifdef({ver})}\n"
+ ret += "\t\t#ifndef CONFIG_9P_MAX_9P2000_e_WELEM\n"
+ ret += f"\t\t\t#error if {c9util.ver_ifdef({ver})} then config.h must define CONFIG_9P_MAX_9P2000_e_WELEM\n"
+ ret += "\t\t#endif\n"
+ ret += "\t\tstatic_assert(CONFIG_9P_MAX_9P2000_e_WELEM > 0);\n"
+ ret += "\t#endif\n"
+ ret += "#endif\n"
+
+ ret += f"""
+/* enum version ***************************************************************/
+
+enum {c9util.ident('version')} {{
+"""
+ fullversions = ["unknown = 0", *sorted(versions)]
+ verwidth = max(len(v) for v in fullversions)
+ for ver in fullversions:
+ if ver in versions:
+ ret += cutil.ifdef_push(1, c9util.ver_ifdef({ver}))
+ ret += f"\t{c9util.ver_enum(ver)},"
+ ret += (" " * (verwidth - len(ver))) + ' /* "' + ver.split()[0] + '" */\n'
+ ret += cutil.ifdef_pop(0)
+ ret += f"\t{c9util.ver_enum('NUM')},\n"
+ ret += "};\n"
+ ret += f"LO_IMPLEMENTATION_H(fmt_formatter, enum {c9util.ident('version')}, {c9util.ident('version')});\n"
+
+ ret += """
+/* enum msg_type **************************************************************/
+
+"""
+ ret += f"enum {c9util.ident('msg_type')} {{ /* uint8_t */\n"
+ namewidth = max(len(msg.typname) for msg in typs if isinstance(msg, idl.Message))
+ for n in range(0x100):
+ if n not in id2typ:
+ continue
+ msg = id2typ[n]
+ ret += cutil.ifdef_push(1, c9util.ver_ifdef(msg.in_versions))
+ ret += f"\t{c9util.Ident(f'TYP_{msg.typname:<{namewidth}}')} = {msg.msgid},\n"
+ ret += cutil.ifdef_pop(0)
+ ret += "};\n"
+ ret += f"LO_IMPLEMENTATION_H(fmt_formatter, enum {c9util.ident('msg_type')}, {c9util.ident('msg_type')});\n"
+
+ ret += """
+/* payload types **************************************************************/
+"""
+
+ def per_version_comment(
+ typ: idl.UserType, fn: typing.Callable[[idl.UserType, str], str]
+ ) -> str:
+ lines: dict[str, str] = {}
+ for version in sorted(typ.in_versions):
+ lines[version] = fn(typ, version)
+ if len(set(lines.values())) == 1:
+ for _, line in lines.items():
+ return f"/* {line} */\n"
+ assert False
+ else:
+ ret = ""
+ v_width = max(len(c9util.ver_enum(v)) for v in typ.in_versions)
+ for version, line in lines.items():
+ ret += f"/* {c9util.ver_enum(version):<{v_width}}: {line} */\n"
+ return ret
+
+ for typ in idlutil.topo_sorted(typs):
+ ret += "\n"
+ ret += cutil.ifdef_push(1, c9util.ver_ifdef(typ.in_versions))
+
+ def sum_size(typ: idl.UserType, version: str) -> str:
+ sz = get_buffer_size(typ, version)
+ assert (
+ sz.min_size <= sz.exp_size
+ and sz.exp_size <= sz.max_size
+ and sz.max_size < cutil.UINT64_MAX
+ )
+ ret = ""
+ if sz.min_size == sz.max_size:
+ ret += f"size = {sz.min_size:,}"
+ else:
+ ret += f"min_size = {sz.min_size:,} ; exp_size = {sz.exp_size:,} ; max_size = {sz.max_size:,}"
+ if sz.max_size > cutil.UINT32_MAX:
+ ret += " (warning: >UINT32_MAX)"
+ ret += f" ; max_iov = {sz.max_iov:,}{sz.max_iov_extra} ; max_copy = {sz.max_copy:,}{sz.max_copy_extra}"
+ return ret
+
+ ret += per_version_comment(typ, sum_size)
+
+ match typ:
+ case idl.Number():
+ ret += gen_number(typ)
+ case idl.Bitfield():
+ ret += gen_bitfield(typ)
+ case idl.Struct(): # and idl.Message():
+ ret += gen_struct(typ)
+ ret += cutil.ifdef_pop(0)
+
+ ret += """
+/* containers *****************************************************************/
+"""
+ ret += "\n"
+ ret += f"#define {c9util.IDENT('_MAX')}(a, b) ((a) > (b)) ? (a) : (b)\n"
+
+ tmsg_max_iov: dict[str, int] = {}
+ tmsg_max_copy: dict[str, int] = {}
+ rmsg_max_iov: dict[str, int] = {}
+ rmsg_max_copy: dict[str, int] = {}
+ for typ in typs:
+ if not isinstance(typ, idl.Message):
+ continue
+ if typ.typname in ("Tsread", "Tswrite"): # SPECIAL (9P2000.e)
+ continue
+ max_iov = tmsg_max_iov if typ.msgid % 2 == 0 else rmsg_max_iov
+ max_copy = tmsg_max_copy if typ.msgid % 2 == 0 else rmsg_max_copy
+ for version in typ.in_versions:
+ if version not in max_iov:
+ max_iov[version] = 0
+ max_copy[version] = 0
+ sz = get_buffer_size(typ, version)
+ if sz.max_iov > max_iov[version]:
+ max_iov[version] = sz.max_iov
+ if sz.max_copy > max_copy[version]:
+ max_copy[version] = sz.max_copy
+
+ for name, table in [
+ ("tmsg_max_iov", tmsg_max_iov),
+ ("tmsg_max_copy", tmsg_max_copy),
+ ("rmsg_max_iov", rmsg_max_iov),
+ ("rmsg_max_copy", rmsg_max_copy),
+ ]:
+ inv: dict[int, set[str]] = {}
+ for version, maxval in table.items():
+ if maxval not in inv:
+ inv[maxval] = set()
+ inv[maxval].add(version)
+
+ ret += "\n"
+ directive = "if"
+ seen_e = False # SPECIAL (9P2000.e)
+ for maxval in sorted(inv, reverse=True):
+ ret += f"#{directive} {c9util.ver_ifdef(inv[maxval])}\n"
+ indent = 1
+ if name.startswith("tmsg") and not seen_e: # SPECIAL (9P2000.e)
+ typ = next(typ for typ in typs if typ.typname == "Tswrite")
+ sz = get_buffer_size(typ, "9P2000.e")
+ match name:
+ case "tmsg_max_iov":
+ maxexpr = f"{sz.max_iov}{sz.max_iov_extra}"
+ case "tmsg_max_copy":
+ maxexpr = f"{sz.max_copy}{sz.max_copy_extra}"
+ case _:
+ assert False
+ ret += f"\t#if {c9util.ver_ifdef({"9P2000.e"})}\n"
+ ret += f"\t\t#define {c9util.IDENT(name)} {c9util.IDENT('_MAX')}({maxval}, {maxexpr})\n"
+ ret += "\t#else\n"
+ indent += 1
+ ret += f"{'\t'*indent}#define {c9util.IDENT(name)} {maxval}\n"
+ if name.startswith("tmsg") and not seen_e: # SPECIAL (9P2000.e)
+ ret += "\t#endif\n"
+ if "9P2000.e" in inv[maxval]:
+ seen_e = True
+ directive = "elif"
+ ret += "#endif\n"
+
+ ret += "\n"
+ ret += f"struct {c9util.ident('Tmsg_send_buf')} {{\n"
+ ret += "\tsize_t iov_cnt;\n"
+ ret += f"\tstruct iovec iov[{c9util.IDENT('TMSG_MAX_IOV')}];\n"
+ ret += f"\tuint8_t copied[{c9util.IDENT('TMSG_MAX_COPY')}];\n"
+ ret += "};\n"
+
+ ret += "\n"
+ ret += f"struct {c9util.ident('Rmsg_send_buf')} {{\n"
+ ret += "\tsize_t iov_cnt;\n"
+ ret += f"\tstruct iovec iov[{c9util.IDENT('RMSG_MAX_IOV')}];\n"
+ ret += f"\tuint8_t copied[{c9util.IDENT('RMSG_MAX_COPY')}];\n"
+ ret += "};\n"
+
+ return ret
+
+
+def gen_number(typ: idl.Number) -> str:
+ ret = f"typedef {c9util.typename(typ.prim)} {c9util.typename(typ)};\n"
+ ret += f"LO_IMPLEMENTATION_H(fmt_formatter, {c9util.typename(typ)}, {c9util.basename(typ)});\n"
+
+ def lookup_sym(sym: str) -> str:
+ assert False
+
+ def cname(base: str) -> str:
+ prefix = f"{typ.typname}_".upper()
+ return c9util.Ident(c9util.add_prefix(prefix, base))
+
+ namewidth = max(len(cname(name)) for name in typ.vals)
+ for name, val in typ.vals.items():
+ c_name = cname(name)
+ c_val = c9util.idl_expr(val, lookup_sym)
+ ret += f"#define {c_name:<{namewidth}} (({c9util.typename(typ)})({c_val}))\n"
+ return ret
+
+
+def gen_bitfield(typ: idl.Bitfield) -> str:
+ ret = f"typedef {c9util.typename(typ.prim)} {c9util.typename(typ)};\n"
+ ret += f"LO_IMPLEMENTATION_H(fmt_formatter, {c9util.typename(typ)}, {c9util.basename(typ)});\n"
+
+ def lookup_sym(sym: str) -> str:
+ assert False
+
+ # There are 4 parts here: bits, aliases, masks, and numbers.
+
+ # 1. bits
+
+ def bitname(bit: idl.Bit) -> str:
+ prefix = f"{typ.typname}_".upper()
+ base = bit.bitname
+ match bit:
+ case idl.Bit(cat="RESERVED"):
+ base = "_RESERVED_" + base
+ case idl.Bit(cat=idl.BitNum()):
+ base += "_*"
+ case idl.Bit(cat="UNUSED"):
+ base = f"_UNUSED_{bit.num}"
+ return c9util.Ident(c9util.add_prefix(prefix, base))
+
+ namewidth = max(len(bitname(bit)) for bit in typ.bits)
+
+ ret += "/* bits */\n"
+ for bit in reversed(typ.bits):
+ vers = bit.in_versions
+ if bit.cat == "UNUSED":
+ vers = typ.in_versions
+ ret += cutil.ifdef_push(2, c9util.ver_ifdef(vers))
+
+ # It is important all of the `beg` strings have
+ # the same length.
+ end = ""
+ match bit.cat:
+ case "USED" | "RESERVED" | "UNUSED":
+ if cutil.ifdef_leaf_is_noop():
+ beg = "#define "
+ else:
+ beg = "# define"
+ case idl.BitNum():
+ beg = "/* number"
+ end = " */"
+
+ c_name = bitname(bit)
+ c_val = f"UINT{typ.static_size*8}_C(1)<<{bit.num}"
+ ret += (
+ f"{beg} {c_name:<{namewidth}} (({c9util.typename(typ)})({c_val})){end}\n"
+ )
+ ret += cutil.ifdef_pop(1)
+
+ # 2. aliases
+ if typ.aliases:
+
+ def aliasname(alias: idl.BitAlias) -> str:
+ prefix = f"{typ.typname}_".upper()
+ base = alias.bitname
+ return c9util.Ident(c9util.add_prefix(prefix, base))
+
+ ret += "/* aliases */\n"
+ for alias in typ.aliases.values():
+ ret += cutil.ifdef_push(2, c9util.ver_ifdef(alias.in_versions))
+
+ end = ""
+ if cutil.ifdef_leaf_is_noop():
+ beg = "#define "
+ else:
+ beg = "# define"
+
+ c_name = aliasname(alias)
+ c_val = c9util.idl_expr(alias.val, lookup_sym)
+ ret += f"{beg} {c_name:<{namewidth}} (({c9util.typename(typ)})({c_val})){end}\n"
+
+ ret += cutil.ifdef_pop(1)
+
+ # 3. masks
+ if typ.masks:
+
+ def maskname(mask: idl.BitAlias) -> str:
+ prefix = f"{typ.typname}_".upper()
+ base = mask.bitname
+ return c9util.Ident(c9util.add_prefix(prefix, base) + "_MASK")
+
+ ret += "/* masks */\n"
+ for mask in typ.masks.values():
+ ret += cutil.ifdef_push(2, c9util.ver_ifdef(mask.in_versions))
+
+ end = ""
+ if cutil.ifdef_leaf_is_noop():
+ beg = "#define "
+ else:
+ beg = "# define"
+
+ c_name = maskname(mask)
+ c_val = c9util.idl_expr(mask.val, lookup_sym, bitwidth=typ.static_size * 8)
+ ret += f"{beg} {c_name:<{namewidth}} (({c9util.typename(typ)})({c_val})){end}\n"
+
+ ret += cutil.ifdef_pop(1)
+
+ # 4. numbers
+ def numname(num: idl.BitNum, base: str) -> str:
+ prefix = f"{typ.typname}_{num.numname}_".upper()
+ return c9util.Ident(c9util.add_prefix(prefix, base))
+
+ for num in typ.nums.values():
+ namewidth = max(
+ len(numname(num, base))
+ for base in [
+ *[alias.bitname for alias in num.vals.values()],
+ "MASK",
+ ]
+ )
+ ret += f"/* number: {num.numname} */\n"
+ for alias in num.vals.values():
+ ret += cutil.ifdef_push(2, c9util.ver_ifdef(alias.in_versions))
+
+ end = ""
+ if cutil.ifdef_leaf_is_noop():
+ beg = "#define "
+ else:
+ beg = "# define"
+
+ c_name = numname(num, alias.bitname)
+ c_val = c9util.idl_expr(alias.val, lookup_sym)
+ ret += f"{beg} {c_name:<{namewidth}} (({c9util.typename(typ)})({c_val})){end}\n"
+ ret += cutil.ifdef_pop(1)
+ c_name = numname(num, "MASK")
+ c_val = f"{num.mask:#0{typ.static_size*8}b}"
+ ret += (
+ f"{beg} {c_name:<{namewidth}} (({c9util.typename(typ)})({c_val})){end}\n"
+ )
+
+ return ret
+
+
+def gen_struct(typ: idl.Struct) -> str: # and idl.Message
+ ret = c9util.typename(typ) + " {"
+ if typ.members:
+ ret += "\n"
+
+ typewidth = max(len(c9util.typename(m.typ, m)) for m in typ.members)
+
+ for member in typ.members:
+ if member.val:
+ continue
+ ret += cutil.ifdef_push(2, c9util.ver_ifdef(member.in_versions))
+ ret += f"\t{c9util.typename(member.typ, member):<{typewidth}} {'*' if member.cnt else ' '}{member.membname};\n"
+ ret += cutil.ifdef_pop(1)
+ ret += "};\n"
+ ret += f"LO_IMPLEMENTATION_H(fmt_formatter, {c9util.typename(typ)}, {c9util.basename(typ)});\n"
+ return ret
diff --git a/lib9p/protogen/idlutil.py b/lib9p/protogen/idlutil.py
new file mode 100644
index 0000000..dc4d012
--- /dev/null
+++ b/lib9p/protogen/idlutil.py
@@ -0,0 +1,112 @@
+# lib9p/protogen/idlutil.py - Utilities for working with the 9P idl package
+#
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+import enum
+import graphlib
+import typing
+
+import idl
+
+# pylint: disable=unused-variable
+__all__ = [
+ "topo_sorted",
+ "Path",
+ "WalkCmd",
+ "WalkHandler",
+ "walk",
+]
+
+# topo_sorted() ################################################################
+
+
+def topo_sorted(typs: list[idl.UserType]) -> typing.Iterable[idl.UserType]:
+ ts: graphlib.TopologicalSorter[idl.UserType] = graphlib.TopologicalSorter()
+ for typ in typs:
+ match typ:
+ case idl.Number():
+ ts.add(typ)
+ case idl.Bitfield():
+ ts.add(typ)
+ case idl.Struct(): # and idl.Message():
+ deps = [
+ member.typ
+ for member in typ.members
+ if not isinstance(member.typ, idl.Primitive)
+ ]
+ ts.add(typ, *deps)
+ return ts.static_order()
+
+
+# walk() #######################################################################
+
+
+class Path:
+ root: idl.Type
+ elems: list[idl.StructMember]
+
+ def __init__(
+ self, root: idl.Type, elems: list[idl.StructMember] | None = None
+ ) -> None:
+ self.root = root
+ self.elems = elems if elems is not None else []
+
+ def add(self, elem: idl.StructMember) -> "Path":
+ return Path(self.root, self.elems + [elem])
+
+ def parent(self) -> "Path":
+ return Path(self.root, self.elems[:-1])
+
+ def c_str(self, base: str, loopdepth: int = 0) -> str:
+ ret = base
+ for i, elem in enumerate(self.elems):
+ if i > 0:
+ ret += "."
+ ret += elem.membname
+ if elem.cnt:
+ ret += f"[{chr(ord('i')+loopdepth)}]"
+ loopdepth += 1
+ return ret
+
+ def __str__(self) -> str:
+ return self.c_str(self.root.typname + "->")
+
+
+class WalkCmd(enum.Enum):
+ KEEP_GOING = 1
+ DONT_RECURSE = 2
+ ABORT = 3
+
+
+type WalkHandler = typing.Callable[
+ [Path], tuple[WalkCmd, typing.Callable[[], None] | None]
+]
+
+
+def _walk(path: Path, handle: WalkHandler) -> WalkCmd:
+ typ = path.elems[-1].typ if path.elems else path.root
+
+ ret, atexit = handle(path)
+
+ if isinstance(typ, idl.Struct):
+ match ret:
+ case WalkCmd.KEEP_GOING:
+ for member in typ.members:
+ if _walk(path.add(member), handle) == WalkCmd.ABORT:
+ ret = WalkCmd.ABORT
+ break
+ case WalkCmd.DONT_RECURSE:
+ ret = WalkCmd.KEEP_GOING
+ case WalkCmd.ABORT:
+ ret = WalkCmd.ABORT
+ case _:
+ assert False, f"invalid cmd: {ret}"
+
+ if atexit:
+ atexit()
+ return ret
+
+
+def walk(typ: idl.Type, handle: WalkHandler) -> None:
+ _walk(Path(typ), handle)
diff --git a/lib9p/srv.c b/lib9p/srv.c
index 9192794..ea8b932 100644
--- a/lib9p/srv.c
+++ b/lib9p/srv.c
@@ -1,24 +1,54 @@
/* lib9p/srv.c - 9P server
*
- * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <assert.h>
#include <alloca.h>
#include <inttypes.h> /* for PRI* */
-#include <stdio.h> /* for fprintf(), stderr */
-#include <string.h> /* for strerror() */
+#include <limits.h> /* for SSIZE_MAX, not set by newlib */
+#include <stddef.h> /* for size_t */
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy() */
+#ifndef SSIZE_MAX
+#define SSIZE_MAX (SIZE_MAX >> 1)
+#endif
#include <libcr/coroutine.h>
#include <libcr_ipc/chan.h>
#include <libcr_ipc/mutex.h>
-#include <libcr_ipc/select.h>
-#include <libmisc/vcall.h>
+#include <libmisc/assert.h>
+#include <libmisc/endian.h>
+#include <libhw/generic/net.h>
+
+#define LOG_NAME 9P_SRV
+#include <libmisc/log.h>
#define IMPLEMENTATION_FOR_LIB9P_SRV_H YES
#include <lib9p/srv.h>
-#include "internal.h"
+
+/* config *********************************************************************/
+
+#include "config.h"
+
+#ifndef CONFIG_9P_SRV_MAX_FIDS
+ #error config.h must define CONFIG_9P_SRV_MAX_FIDS
+#endif
+#ifndef CONFIG_9P_SRV_MAX_REQS
+ #error config.h must define CONFIG_9P_SRV_MAX_REQS
+#endif
+#ifndef CONFIG_9P_SRV_MAX_DEPTH
+ /* 1=just the root dir, 2=just files in the root dir, 3=1 subdir, ... */
+ #error config.h must define CONFIG_9P_SRV_MAX_DEPTH
+#endif
+#ifndef CONFIG_9P_SRV_MAX_MSG_SIZE
+ #error config.h must define CONFIG_9P_SRV_MAX_MSG_SIZE
+#endif
+#ifndef CONFIG_9P_SRV_MAX_HOSTMSG_SIZE
+ #error config.h must define CONFIG_9P_SRV_MAX_HOSTMSG_SIZE
+#endif
+static_assert(CONFIG_9P_SRV_MAX_MSG_SIZE <= CONFIG_9P_SRV_MAX_HOSTMSG_SIZE);
+static_assert(CONFIG_9P_SRV_MAX_HOSTMSG_SIZE <= SSIZE_MAX);
/* context ********************************************************************/
@@ -27,39 +57,65 @@ bool lib9p_srv_flush_requested(struct lib9p_srv_ctx *ctx) {
return _lib9p_srv_flushch_can_send(&ctx->_flushch);
}
-int lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx) {
+void lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx) {
assert(ctx);
assert(_lib9p_srv_flushch_can_send(&ctx->_flushch));
lib9p_error(&ctx->basectx, LINUX_ECANCELED, "request canceled by flush");
_lib9p_srv_flushch_send(&ctx->_flushch, true);
- return -1;
}
/* structs ********************************************************************/
+typedef typeof( ((struct lib9p_qid){}).path ) srv_path_t;
+
+struct srv_pathinfo {
+ lo_interface lib9p_srv_file file;
+ srv_path_t parent_dir;
+
+ /* References from other srv_pathinfos (via .parent_dir) or
+ * from FIDs. */
+ unsigned int gc_refcount;
+ /* References from fids with FIDFLAG_OPEN_R/FIDFLAG_OPEN_W. */
+ unsigned int io_refcount;
+};
+
+#define NAME pathmap
+#define KEY_T srv_path_t
+#define VAL_T struct srv_pathinfo
+/* ( naive ) + ( working space for walk() ) */
+#define CAP ( (CONFIG_9P_SRV_MAX_FIDS*CONFIG_9P_SRV_MAX_DEPTH) + (CONFIG_9P_SRV_MAX_REQS*2) )
+#include "map.h"
+
#define FIDFLAG_OPEN_R (1<<0)
#define FIDFLAG_OPEN_W (1<<1)
#define FIDFLAG_RCLOSE (1<<2)
-#define FIDFLAG_ISDIR (1<<3)
#define FIDFLAG_OPEN (FIDFLAG_OPEN_R|FIDFLAG_OPEN_W)
struct _srv_fidinfo {
- implements_lib9p_srv_file *file;
- uint8_t flags;
- size_t dir_idx;
- uint32_t dir_off;
+ srv_path_t path;
+ uint8_t flags;
+ union {
+ struct {
+ lo_interface lib9p_srv_fio io;
+ } file;
+ struct {
+ lo_interface lib9p_srv_dio io;
+ size_t idx;
+ uint64_t off;
+ } dir;
+ };
};
#define NAME fidmap
-#define KEY_T uint32_t
+#define KEY_T lib9p_fid_t
#define VAL_T struct _srv_fidinfo
-#define CAP CONFIG_9P_MAX_FIDS
+#define CAP CONFIG_9P_SRV_MAX_FIDS
#include "map.h"
#define NAME reqmap
-#define KEY_T uint32_t
+#define KEY_T lib9p_tag_t
#define VAL_T struct _lib9p_srv_req *
-#define CAP CONFIG_9P_MAX_REQS
+#define CAP CONFIG_9P_SRV_MAX_REQS
#include "map.h"
/* The hierarchy of concepts is:
@@ -73,7 +129,7 @@ struct _srv_fidinfo {
struct _srv_conn {
/* immutable */
struct lib9p_srv *parent_srv;
- implements_net_stream_conn *fd;
+ lo_interface net_stream_conn fd;
cid_t reader; /* the lib9p_srv_read_cr() coroutine */
/* mutable */
cr_mutex_t writelock;
@@ -88,53 +144,49 @@ struct _srv_sess {
/* mutable */
bool initialized;
bool closing;
- struct reqmap reqs;
- struct fidmap fids;
+ struct pathmap paths; /* srv_path_t => lib9p_srv_file + metadata */
+ struct fidmap fids; /* lib9p_fid_t => lib9p_srv_{fio,dio} + metadata */
+ struct reqmap reqs; /* lib9p_tag_t => *_lib9p_srv_req */
};
struct _lib9p_srv_req {
/* immutable */
struct _srv_sess *parent_sess;
uint16_t tag;
+ uint8_t *net_bytes;
/* mutable */
- uint8_t *net_bytes; /* CONFIG_9P_MAX_MSG_SIZE-sized */
struct lib9p_srv_ctx ctx;
};
/* base utilities *************************************************************/
-#define nonrespond_errorf(fmt, ...) \
- fprintf(stderr, "error: " fmt "\n" __VA_OPT__(,) __VA_ARGS__)
-
-static uint32_t rerror_overhead_for_version(enum lib9p_version version,
- uint8_t *scratch) {
- struct lib9p_ctx empty_ctx = {
- .version = version,
- .max_msg_size = CONFIG_9P_MAX_MSG_SIZE,
- };
- struct lib9p_msg_Rerror empty_error = { 0 };
- bool e;
-
- e = lib9p_marshal(&empty_ctx, LIB9P_TYP_Rerror,
- &empty_error, /* host_body */
- scratch); /* net_bytes */
- assert(!e);
-
- uint32_t min_msg_size = decode_u32le(scratch);
+static void msglog(struct _lib9p_srv_req *req, enum lib9p_msg_type typ, void *hostmsg) {
+ struct lib9p_srv *srv = req->parent_sess->parent_conn->parent_srv;
+ if (srv->msglog) {
+ srv->msglog(&req->ctx, typ, hostmsg);
+ return;
+ }
+ /* It sucks that %v trips -Wformat and -Wformat-extra-args
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47781 */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat"
+#pragma GCC diagnostic ignored "-Wformat-extra-args"
+ infof("%c %v", typ % 2 ? '<' : '>', lo_box_lib9p_msg_as_fmt_formatter(&req->ctx.basectx, typ, hostmsg));
+#pragma GCC diagnostic pop
+}
- /* Assert that min_msg_size + biggest_possible_MAX_ERR_SIZE
- * won't overflow uint32... because using
- * __builtin_add_overflow in respond_error() would be a bit
- * much. */
- assert(min_msg_size < (UINT32_MAX - UINT16_MAX));
- /* Assert that min_msg_size doesn't overflow MAX_MSG_SIZE. */
- assert(CONFIG_9P_MAX_MSG_SIZE >= min_msg_size);
+#define nonrespond_errorf errorf
- return min_msg_size;
+static ssize_t write_Rmsg(struct _lib9p_srv_req *req, struct lib9p_Rmsg_send_buf *resp) {
+ ssize_t r;
+ cr_mutex_lock(&req->parent_sess->parent_conn->writelock);
+ r = io_writev(req->parent_sess->parent_conn->fd, resp->iov, resp->iov_cnt);
+ cr_mutex_unlock(&req->parent_sess->parent_conn->writelock);
+ return r;
}
static void respond_error(struct _lib9p_srv_req *req) {
-#ifdef CONFIG_9P_ENABLE_9P2000_u
+#if CONFIG_9P_ENABLE_9P2000_u
assert(req->ctx.basectx.err_num);
#endif
assert(req->ctx.basectx.err_msg[0]);
@@ -142,46 +194,42 @@ static void respond_error(struct _lib9p_srv_req *req) {
ssize_t r;
struct lib9p_msg_Rerror host = {
.tag = req->tag,
- .ename = {
- .len = strnlen(req->ctx.basectx.err_msg,
- CONFIG_9P_MAX_ERR_SIZE),
- .utf8 = req->ctx.basectx.err_msg,
- },
-#ifdef CONFIG_9P_ENABLE_9P2000_u
- .errno = req->ctx.basectx.err_num,
+ .errstr = lib9p_strn(req->ctx.basectx.err_msg,
+ CONFIG_9P_MAX_ERR_SIZE),
+#if CONFIG_9P_ENABLE_9P2000_u
+ .errnum = req->ctx.basectx.err_num,
#endif
};
struct _srv_sess *sess = req->parent_sess;
/* Truncate the error-string if necessary to avoid needing to
- * return LINUX_ERANGE. The assert() in
- * rerror_overhead_for_version() has checked that this
- * addition doesn't overflow. */
- if (((uint32_t)host.ename.len) + sess->rerror_overhead > sess->max_msg_size)
- host.ename.len = sess->max_msg_size - sess->rerror_overhead;
-
- lib9p_marshal(&req->ctx.basectx, LIB9P_TYP_Rerror,
- &host, req->net_bytes);
-
- cr_mutex_lock(&sess->parent_conn->writelock);
- r = VCALL(sess->parent_conn->fd, write,
- req->net_bytes, decode_u32le(req->net_bytes));
- cr_mutex_unlock(&sess->parent_conn->writelock);
+ * return LINUX_ERANGE. */
+ if (((uint32_t)host.errstr.len) + sess->rerror_overhead > sess->max_msg_size)
+ host.errstr.len = sess->max_msg_size - sess->rerror_overhead;
+
+ struct lib9p_Rmsg_send_buf net;
+
+ lib9p_Rmsg_marshal(&req->ctx.basectx,
+ LIB9P_TYP_Rerror, &host,
+ &net);
+
+ msglog(req, LIB9P_TYP_Rerror, &host);
+ r = write_Rmsg(req, &net);
if (r < 0)
- nonrespond_errorf("write: %s", strerror(-r));
+ nonrespond_errorf("write: %s", net_strerror(-r));
}
/* read coroutine *************************************************************/
-static bool read_at_least(implements_net_stream_conn *fd, uint8_t *buf, size_t goal, size_t *done) {
+static bool read_exactly(lo_interface net_stream_conn fd, uint8_t *buf, size_t goal, size_t *done) {
assert(buf);
assert(goal);
assert(done);
while (*done < goal) {
- ssize_t r = VCALL(fd, read, &buf[*done], CONFIG_9P_MAX_MSG_SIZE - *done);
+ ssize_t r = io_read(fd, &buf[*done], goal - *done);
if (r < 0) {
- nonrespond_errorf("read: %s", strerror(-r));
+ nonrespond_errorf("read: %s", net_strerror(-r));
return true;
} else if (r == 0) {
if (*done != 0)
@@ -195,30 +243,34 @@ static bool read_at_least(implements_net_stream_conn *fd, uint8_t *buf, size_t g
static void handle_message(struct _lib9p_srv_req *ctx);
-__attribute__ ((noreturn)) void lib9p_srv_read_cr(struct lib9p_srv *srv, implements_net_stream_listener *listener) {
- uint8_t buf[CONFIG_9P_MAX_MSG_SIZE];
-
+[[noreturn]] void lib9p_srv_read_cr(struct lib9p_srv *srv, lo_interface net_stream_listener listener) {
assert(srv);
assert(srv->rootdir);
- assert(listener);
+ assert(!LO_IS_NULL(listener));
- uint32_t initial_rerror_overhead = rerror_overhead_for_version(0, buf);
+ srv->readers++;
+
+ uint32_t initial_rerror_overhead = lib9p_version_min_msg_size(LIB9P_VER_unknown);
for (;;) {
struct _srv_conn conn = {
.parent_srv = srv,
- .fd = VCALL(listener, accept),
+ .fd = LO_CALL(listener, accept),
.reader = cr_getcid(),
};
- if (!conn.fd) {
+ if (LO_IS_NULL(conn.fd)) {
nonrespond_errorf("accept: error");
- continue;
+ srv->readers--;
+ if (srv->readers == 0)
+ while (srv->writers > 0)
+ _lib9p_srv_reqch_send_req(&srv->_reqch, NULL);
+ cr_exit();
}
struct _srv_sess sess = {
.parent_conn = &conn,
.version = LIB9P_VER_unknown,
- .max_msg_size = CONFIG_9P_MAX_MSG_SIZE,
+ .max_msg_size = CONFIG_9P_SRV_MAX_MSG_SIZE,
.rerror_overhead = initial_rerror_overhead,
.initialized = false,
};
@@ -226,18 +278,19 @@ __attribute__ ((noreturn)) void lib9p_srv_read_cr(struct lib9p_srv *srv, impleme
nextmsg:
/* Read the message. */
size_t done = 0;
- if (read_at_least(conn.fd, buf, 4, &done))
+ uint8_t buf[7];
+ if (read_exactly(conn.fd, buf, 4, &done))
goto close;
- size_t goal = decode_u32le(buf);
+ size_t goal = uint32le_decode(buf);
if (goal < 7) {
nonrespond_errorf("T-message is impossibly small");
goto close;
}
- if (read_at_least(conn.fd, buf, 7, &done))
+ if (read_exactly(conn.fd, buf, 7, &done))
goto close;
struct _lib9p_srv_req req = {
.parent_sess = &sess,
- .tag = decode_u16le(&buf[5]),
+ .tag = uint16le_decode(&buf[5]),
.net_bytes = buf,
.ctx = {
.basectx = {
@@ -255,11 +308,16 @@ __attribute__ ((noreturn)) void lib9p_srv_read_cr(struct lib9p_srv *srv, impleme
respond_error(&req);
goto nextmsg;
}
- if (read_at_least(conn.fd, buf, goal, &done))
+ req.net_bytes = malloc(goal);
+ assert(req.net_bytes);
+ memcpy(req.net_bytes, buf, done);
+ if (read_exactly(conn.fd, req.net_bytes, goal, &done)) {
+ free(req.net_bytes);
goto close;
+ }
/* Handle the message... */
- if (buf[4] == LIB9P_TYP_Tversion)
+ if (req.net_bytes[4] == LIB9P_TYP_Tversion)
/* ...in this coroutine for Tversion, */
handle_message(&req);
else
@@ -267,12 +325,14 @@ __attribute__ ((noreturn)) void lib9p_srv_read_cr(struct lib9p_srv *srv, impleme
_lib9p_srv_reqch_send_req(&srv->_reqch, &req);
}
close:
- VCALL(conn.fd, close, true, sess.reqs.len == 0);
- if (sess.reqs.len) {
+ if (sess.reqs.len == 0)
+ io_close(conn.fd);
+ else {
+ io_close_read(conn.fd);
sess.closing = true;
cr_pause_and_yield();
assert(sess.reqs.len == 0);
- VCALL(conn.fd, close, true, true);
+ io_close_write(conn.fd);
}
}
}
@@ -280,7 +340,6 @@ __attribute__ ((noreturn)) void lib9p_srv_read_cr(struct lib9p_srv *srv, impleme
/* write coroutine ************************************************************/
COROUTINE lib9p_srv_write_cr(void *_srv) {
- uint8_t net[CONFIG_9P_MAX_MSG_SIZE];
struct _lib9p_srv_req req;
_lib9p_srv_reqch_req_t rpc_handle;
@@ -289,14 +348,19 @@ COROUTINE lib9p_srv_write_cr(void *_srv) {
assert(srv->rootdir);
cr_begin();
+ srv->writers++;
+
for (;;) {
/* Receive the request from the reader coroutine. ************/
rpc_handle = _lib9p_srv_reqch_recv_req(&srv->_reqch);
- /* Deep-copy the request from the reader coroutine's
+ if (!rpc_handle.req) {
+ srv->writers--;
+ _lib9p_srv_reqch_send_resp(rpc_handle, 0);
+ cr_exit();
+ }
+ /* Copy the request from the reader coroutine's
* stack to our stack. */
req = *rpc_handle.req;
- memcpy(net, req.net_bytes, decode_u32le(req.net_bytes));
- req.net_bytes = net;
/* Record that we have it. */
reqmap_store(&req.parent_sess->reqs, req.tag, &req);
/* Notify the reader coroutine that we're done with
@@ -334,7 +398,7 @@ _HANDLER_PROTO(clunk);
_HANDLER_PROTO(remove);
_HANDLER_PROTO(stat);
_HANDLER_PROTO(wstat);
-#ifdef CONFIG_9P_ENABLE_9P2000_e
+#if CONFIG_9P_ENABLE_9P2000_e
_HANDLER_PROTO(session);
_HANDLER_PROTO(sread);
_HANDLER_PROTO(swrite);
@@ -356,7 +420,7 @@ static tmessage_handler tmessage_handlers[0x100] = {
[LIB9P_TYP_Tremove] = (tmessage_handler)handle_Tremove,
[LIB9P_TYP_Tstat] = (tmessage_handler)handle_Tstat,
[LIB9P_TYP_Twstat] = (tmessage_handler)handle_Twstat,
-#ifdef CONFIG_9P_ENABLE_9P2000_e
+#if CONFIG_9P_ENABLE_9P2000_e
[LIB9P_TYP_Tsession] = (tmessage_handler)handle_Tsession,
[LIB9P_TYP_Tsread] = (tmessage_handler)handle_Tsread,
[LIB9P_TYP_Tswrite] = (tmessage_handler)handle_Tswrite,
@@ -364,28 +428,19 @@ static tmessage_handler tmessage_handlers[0x100] = {
};
static void handle_message(struct _lib9p_srv_req *ctx) {
- uint8_t host_req[CONFIG_9P_MAX_HOSTMSG_SIZE];
- uint8_t host_resp[CONFIG_9P_MAX_HOSTMSG_SIZE];
+ uint8_t *host_req = NULL;
+ uint8_t host_resp[CONFIG_9P_SRV_MAX_HOSTMSG_SIZE];
/* Unmarshal it. */
- enum lib9p_msg_type typ = ctx->net_bytes[4];
- if (typ % 2 != 0) {
- lib9p_errorf(&ctx->ctx.basectx,
- LINUX_EOPNOTSUPP, "expected a T-message but got an R-message: message_type=%s",
- lib9p_msg_type_str(&ctx->ctx.basectx, typ));
- goto write;
- }
- ssize_t host_size = lib9p_validate(&ctx->ctx.basectx, ctx->net_bytes);
+ ssize_t host_size = lib9p_Tmsg_validate(&ctx->ctx.basectx, ctx->net_bytes);
if (host_size < 0)
goto write;
- if ((size_t)host_size > sizeof(host_req)) {
- lib9p_errorf(&ctx->ctx.basectx,
- LINUX_EMSGSIZE, "unmarshalled payload larger than server limit (%zu > %zu)",
- host_size, sizeof(host_req));
- goto write;
- }
- lib9p_unmarshal(&ctx->ctx.basectx, ctx->net_bytes,
+ host_req = calloc(1, host_size);
+ assert(host_req);
+ enum lib9p_msg_type typ;
+ lib9p_Tmsg_unmarshal(&ctx->ctx.basectx, ctx->net_bytes,
&typ, host_req);
+ msglog(ctx, typ, host_req);
/* Handle it. */
tmessage_handlers[typ](ctx, (void *)host_req, (void *)host_resp);
@@ -394,15 +449,17 @@ static void handle_message(struct _lib9p_srv_req *ctx) {
if (lib9p_ctx_has_error(&ctx->ctx.basectx))
respond_error(ctx);
else {
- if (lib9p_marshal(&ctx->ctx.basectx, typ+1, host_resp,
- ctx->net_bytes))
+ struct lib9p_Rmsg_send_buf net_resp;
+ if (lib9p_Rmsg_marshal(&ctx->ctx.basectx,
+ typ+1, host_resp,
+ &net_resp))
goto write;
-
- cr_mutex_lock(&ctx->parent_sess->parent_conn->writelock);
- VCALL(ctx->parent_sess->parent_conn->fd, write,
- ctx->net_bytes, decode_u32le(ctx->net_bytes));
- cr_mutex_unlock(&ctx->parent_sess->parent_conn->writelock);
+ msglog(ctx, typ+1, &host_resp);
+ write_Rmsg(ctx, &net_resp);
}
+ if (host_req)
+ free(host_req);
+ free(ctx->net_bytes);
}
#define util_handler_common(ctx, req, resp) do { \
@@ -412,7 +469,7 @@ static void handle_message(struct _lib9p_srv_req *ctx) {
resp->tag = req->tag; \
} while (0)
-static inline bool util_check_perm(struct lib9p_srv_ctx *ctx, struct lib9p_stat *stat, uint8_t action) {
+static inline bool srv_util_check_perm(struct _lib9p_srv_req *ctx, struct lib9p_stat *stat, uint8_t action) {
assert(ctx);
assert(stat);
assert(action);
@@ -423,17 +480,110 @@ static inline bool util_check_perm(struct lib9p_srv_ctx *ctx, struct lib9p_stat
return mode & action;
}
-static inline bool util_release(struct lib9p_srv_ctx *ctx, implements_lib9p_srv_file *file) {
- assert(file);
- file->_refcount--;
- if (file->_refcount == 0) {
- if (file->_parent_dir != file)
- util_release(ctx, file->_parent_dir);
- VCALL(file, free, ctx);
+/**
+ * Ensures that `file` is saved into the pathmap, and increments the
+ * gc_refcount by 1 (for presumptive insertion into the fidmap).
+ * parent_path's gc_refcount is also incremented as appropriate.
+ *
+ * Returns a pointer to the stored pathinfo.
+ */
+static inline struct srv_pathinfo *srv_util_pathsave(struct _lib9p_srv_req *ctx,
+ lo_interface lib9p_srv_file file,
+ srv_path_t parent_path) {
+ assert(ctx);
+ assert(!LO_IS_NULL(file));
+
+ struct lib9p_qid qid = LO_CALL(file, qid);
+ struct srv_pathinfo *pathinfo = pathmap_load(&ctx->parent_sess->paths, qid.path);
+ if (pathinfo)
+ assert(LO_EQ(pathinfo->file, file));
+ else {
+ pathinfo = pathmap_store(&ctx->parent_sess->paths, qid.path,
+ (struct srv_pathinfo){
+ .file = file,
+ .parent_dir = parent_path,
+ .gc_refcount = 0,
+ .io_refcount = 0,
+ });
+ assert(pathinfo);
+ if (parent_path != qid.path) {
+ struct srv_pathinfo *parent = pathmap_load(&ctx->parent_sess->paths, parent_path);
+ assert(parent);
+ parent->gc_refcount++;
+ }
}
- return lib9p_ctx_has_error(&ctx->basectx);
+ pathinfo->gc_refcount++;
+ return pathinfo;
}
+/**
+ * Decrement the path's gc_refcount, and trigger garbage collection as
+ * appropriate.
+ */
+static inline void srv_util_pathfree(struct _lib9p_srv_req *ctx, srv_path_t path) {
+ assert(ctx);
+
+ struct srv_pathinfo *pathinfo = pathmap_load(&ctx->parent_sess->paths, path);
+ assert(pathinfo);
+ pathinfo->gc_refcount--;
+ if (pathinfo->gc_refcount == 0) {
+ if (pathinfo->parent_dir != path)
+ srv_util_pathfree(ctx, pathinfo->parent_dir);
+ LO_CALL(pathinfo->file, free);
+ pathmap_del(&ctx->parent_sess->paths, path);
+ }
+}
+
+static inline bool srv_util_pathisdir(struct srv_pathinfo *pathinfo) {
+ assert(pathinfo);
+ return LO_CALL(pathinfo->file, qid).type & LIB9P_QT_DIR;
+}
+
+/**
+ * Store fid as pointing to pathinfo. Assumes that
+ * pathinfo->gc_refcount has already been incremented; does *not*
+ * decrement it on failure.
+ */
+static inline struct _srv_fidinfo *srv_util_fidsave(struct _lib9p_srv_req *ctx, lib9p_fid_t fid, struct srv_pathinfo *pathinfo, bool overwrite) {
+ assert(ctx);
+ assert(fid != LIB9P_FID_NOFID);
+ assert(pathinfo);
+
+ struct lib9p_qid qid = LO_CALL(pathinfo->file, qid);
+
+ struct _srv_fidinfo *fidinfo = fidmap_load(&ctx->parent_sess->fids, fid);
+ if (fidinfo) {
+ if (overwrite) {
+ struct srv_pathinfo *old_pathinfo = pathmap_load(&ctx->parent_sess->paths, fidinfo->path);
+ assert(old_pathinfo);
+ if (srv_util_pathisdir(old_pathinfo)) {
+ if (!LO_IS_NULL(fidinfo->dir.io))
+ LO_CALL(fidinfo->dir.io, iofree);
+ } else {
+ if (!LO_IS_NULL(fidinfo->file.io))
+ LO_CALL(fidinfo->file.io, iofree);
+ }
+ srv_util_pathfree(ctx, fidinfo->path);
+ } else {
+ lib9p_error(&ctx->ctx.basectx,
+ LINUX_EBADF, "FID already in use");
+ return NULL;
+ }
+ } else {
+ fidinfo = fidmap_store(&ctx->parent_sess->fids, fid, (struct _srv_fidinfo){});
+ if (!fidinfo) {
+ lib9p_error(&ctx->ctx.basectx,
+ LINUX_EMFILE, "too many open files");
+ return NULL;
+ }
+ }
+ *fidinfo = (struct _srv_fidinfo){
+ .path = qid.path,
+ };
+ return fidinfo;
+}
+
+
static void handle_Tversion(struct _lib9p_srv_req *ctx,
struct lib9p_msg_Tversion *req,
struct lib9p_msg_Rversion *resp) {
@@ -448,33 +598,29 @@ static void handle_Tversion(struct _lib9p_srv_req *ctx,
'0' <= req->version.utf8[3] && req->version.utf8[3] <= '9' &&
'0' <= req->version.utf8[4] && req->version.utf8[4] <= '9' &&
'0' <= req->version.utf8[5] && req->version.utf8[5] <= '9' &&
- (req->version.utf8[6] == '\0' || req->version.utf8[6] == '.')) {
+ (req->version.len == 6 || req->version.utf8[6] == '.')) {
version = LIB9P_VER_9P2000;
-#ifdef CONFIG_9P_ENABLE_9P2000_u
- if (strcmp(&req->version.utf8[6], ".u") == 0)
+#if CONFIG_9P_ENABLE_9P2000_u
+ if (lib9p_str_eq(lib9p_str_sliceleft(req->version, 6), lib9p_str(".u")))
version = LIB9P_VER_9P2000_u;
#endif
-#ifdef CONFIG_9P_ENABLE_9P2000_e
- if (strcmp(&req->version.utf8[6], ".e") == 0)
+#if CONFIG_9P_ENABLE_9P2000_e
+ if (lib9p_str_eq(lib9p_str_sliceleft(req->version, 6), lib9p_str(".e")))
version = LIB9P_VER_9P2000_e;
#endif
}
- uint32_t min_msg_size = rerror_overhead_for_version(version, ctx->net_bytes);
+ uint32_t min_msg_size = lib9p_version_min_msg_size(version);
if (req->max_msg_size < min_msg_size) {
lib9p_errorf(&ctx->ctx.basectx,
LINUX_EDOM, "requested max_msg_size is less than minimum for %s (%"PRIu32" < %"PRIu32")",
- version, req->max_msg_size, min_msg_size);
+ lib9p_version_str(version), req->max_msg_size, min_msg_size);
return;
}
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
- resp->version.utf8 = lib9p_version_str(version);
-#pragma GCC diagnostic pop
- resp->version.len = strlen(resp->version.utf8);
- resp->max_msg_size = (CONFIG_9P_MAX_MSG_SIZE < req->max_msg_size)
- ? CONFIG_9P_MAX_MSG_SIZE
+ resp->version = lib9p_str((char *)lib9p_version_str(version)); /* cast to discard "const" qualifier */
+ resp->max_msg_size = (CONFIG_9P_SRV_MAX_MSG_SIZE < req->max_msg_size)
+ ? CONFIG_9P_SRV_MAX_MSG_SIZE
: req->max_msg_size;
/* Close the old session. */
@@ -483,7 +629,7 @@ static void handle_Tversion(struct _lib9p_srv_req *ctx,
* to finish. */
struct cr_select_arg *list = alloca(sizeof(struct cr_select_arg) * ctx->parent_sess->reqs.len);
while (ctx->parent_sess->reqs.len) {
- uint16_t tag __attribute__((unused));
+ uint16_t tag [[gnu::unused]];
struct _lib9p_srv_req **reqpp;
size_t i = 0;
bool flushed;
@@ -496,7 +642,7 @@ static void handle_Tversion(struct _lib9p_srv_req *ctx,
if (ctx->parent_sess->fids.len) {
/* Close all FIDs. */
uint32_t fid;
- struct _srv_fidinfo *fidinfo __attribute__((unused));
+ struct _srv_fidinfo *fidinfo [[gnu::unused]];
MAP_FOREACH(&ctx->parent_sess->fids, fid, fidinfo) {
handle_Tclunk(ctx,
&(struct lib9p_msg_Tclunk){.fid = fid},
@@ -515,8 +661,8 @@ static void handle_Tauth(struct _lib9p_srv_req *ctx,
struct lib9p_msg_Rauth *resp) {
util_handler_common(ctx, req, resp);
- ctx->ctx.uid = req->n_uname;
- ctx->ctx.uname = req->uname.utf8;
+ ctx->ctx.uid = req->n_uid;
+ ctx->ctx.uname = req->uname;
struct lib9p_srv *srv = ctx->parent_sess->parent_conn->parent_srv;
if (!srv->auth) {
@@ -525,7 +671,7 @@ static void handle_Tauth(struct _lib9p_srv_req *ctx,
return;
}
- srv->auth(&ctx->ctx, req->aname.utf8);
+ srv->auth(&ctx->ctx, req->aname);
lib9p_error(&ctx->ctx.basectx,
LINUX_EOPNOTSUPP, "TODO: auth not implemented");
}
@@ -535,8 +681,8 @@ static void handle_Tattach(struct _lib9p_srv_req *ctx,
struct lib9p_msg_Rattach *resp) {
util_handler_common(ctx, req, resp);
- ctx->ctx.uid = req->n_uname;
- ctx->ctx.uname = req->uname.utf8;
+ ctx->ctx.uid = req->n_uid;
+ ctx->ctx.uname = req->uname;
struct lib9p_srv *srv = ctx->parent_sess->parent_conn->parent_srv;
if (srv->auth) {
@@ -548,14 +694,16 @@ static void handle_Tattach(struct _lib9p_srv_req *ctx,
else if (fh->type != FH_AUTH)
lib9p_error(&ctx->ctx.basectx,
LINUX_EACCES, "FID provided as auth-file is not an auth-file");
- else if (strcmp(fh->data.auth.uname, req->uname.utf8) != 0)
+ else if (!lib9p_str_eq(fh->data.auth.uname, req->uname))
lib9p_errorf(&ctx->ctx.basectx,
- LINUX_EACCES, "FID provided as auth-file is for user=\"%s\" and cannot be used for user=\"%s\"",
- fh->data.auth.uname, req->uname.utf8);
- else if (strcmp(fh->data.auth.aname, req->aname.utf8) != 0)
+ LINUX_EACCES, "FID provided as auth-file is for user=\"%.*s\" and cannot be used for user=\"%.*s\"",
+ fh->data.auth.uname.len, fh->data.auth.uname.utf8,
+ req->uname.len, req->uname.utf8);
+ else if (!lib9p_str_eq(fh->data.auth.aname, req->aname))
lib9p_errorf(&ctx->ctx.basectx,
- LINUX_EACCES, "FID provided as auth-file is for tree=\"%s\" and cannot be used for tree=\"%s\"",
- fh->data.auth.aname, req->aname.utf8);
+ LINUX_EACCES, "FID provided as auth-file is for tree=\"%.*s\" and cannot be used for tree=\"%.*s\"",
+ fh->data.auth.aname.len, fh->data.auth.aname.utf8,
+ req->aname.len, req->aname.utf8);
else if (!fh->data.auth.authenticated)
lib9p_error(&ctx->ctx.basectx,
LINUX_EACCES, "FID provided as auth-file has not completed authentication");
@@ -564,51 +712,41 @@ static void handle_Tattach(struct _lib9p_srv_req *ctx,
return;
*/
lib9p_error(&ctx->ctx.basectx,
- LINUX_EOPNOTSUPP, "TODO: auth not implemented");
+ LINUX_EOPNOTSUPP, "TODO: auth not (yet?) implemented");
return;
} else {
- if (req->afid != LIB9P_NOFID) {
+ if (req->afid != LIB9P_FID_NOFID) {
lib9p_error(&ctx->ctx.basectx,
LINUX_EACCES, "FID provided as auth-file, but no auth-file is required");
return;
}
}
- if (fidmap_load(&ctx->parent_sess->fids, req->fid)) {
- lib9p_error(&ctx->ctx.basectx,
- LINUX_EBADF, "FID already in use");
- return;
+ if (req->fid == LIB9P_FID_NOFID) {
+ lib9p_error(&ctx->ctx.basectx,
+ LINUX_EBADF, "cannot assign to NOFID");
+ return;
}
- implements_lib9p_srv_file *rootdir = srv->rootdir(&ctx->ctx, req->aname.utf8);
- assert((rootdir == NULL) == lib9p_ctx_has_error(&ctx->ctx.basectx));
+ /* 1. File object */
+ lo_interface lib9p_srv_file root_file = srv->rootdir(&ctx->ctx, req->aname);
+ assert(LO_IS_NULL(root_file) == lib9p_ctx_has_error(&ctx->ctx.basectx));
if (lib9p_ctx_has_error(&ctx->ctx.basectx))
return;
- rootdir->_parent_dir = rootdir;
- rootdir->_refcount++;
- if (!fidmap_store(&ctx->parent_sess->fids, req->fid, (struct _srv_fidinfo){
- .file = rootdir,
- .flags = FIDFLAG_ISDIR,
- })) {
- lib9p_error(&ctx->ctx.basectx,
- LINUX_EMFILE, "too many open files");
- util_release(&ctx->ctx, rootdir);
- return;
- }
+ struct lib9p_qid root_qid = LO_CALL(root_file, qid);
+ assert(root_qid.type & LIB9P_QT_DIR);
+
+ /* 2. pathinfo */
+ struct srv_pathinfo *root_pathinfo = srv_util_pathsave(ctx, root_file, root_qid.path);
- struct lib9p_stat stat = VCALL(rootdir, stat, &ctx->ctx);
- if (lib9p_ctx_has_error(&ctx->ctx.basectx)) {
- handle_Tclunk(ctx,
- &(struct lib9p_msg_Tclunk){.fid = req->fid},
- &(struct lib9p_msg_Rclunk){});
+ /* 3. fidinfo */
+ if (!srv_util_fidsave(ctx, req->fid, root_pathinfo, false)) {
+ srv_util_pathfree(ctx, root_qid.path);
return;
}
- lib9p_assert_stat(stat);
- assert(stat.file_mode & LIB9P_DM_DIR);
-
- resp->qid = stat.file_qid;
+ resp->qid = root_qid;
return;
}
@@ -627,87 +765,68 @@ static void handle_Twalk(struct _lib9p_srv_req *ctx,
struct lib9p_msg_Rwalk *resp) {
util_handler_common(ctx, req, resp);
+ if (req->newfid == LIB9P_FID_NOFID) {
+ lib9p_error(&ctx->ctx.basectx,
+ LINUX_EBADF, "cannot assign to NOFID");
+ return;
+ }
+
struct _srv_fidinfo *fidinfo = fidmap_load(&ctx->parent_sess->fids, req->fid);
if (!fidinfo) {
lib9p_errorf(&ctx->ctx.basectx,
LINUX_EBADF, "bad file number %"PRIu32, req->fid);
return;
}
- if (req->newfid != req->fid && fidmap_load(&ctx->parent_sess->fids, req->newfid)) {
- lib9p_error(&ctx->ctx.basectx,
- LINUX_EBADF, "FID already in use");
- return;
- }
- implements_lib9p_srv_file *dir = fidinfo->file;
- if (req->newfid != req->fid) {
- dir = VCALL(dir, clone, &ctx->ctx);
- assert((dir == NULL) == lib9p_ctx_has_error(&ctx->ctx.basectx));
- if (lib9p_ctx_has_error(&ctx->ctx.basectx))
- return;
- dir->_refcount++; /* ref-A: presumptive insertion into fidmap */
- }
- bool isdir = (fidinfo->flags & FIDFLAG_ISDIR);
+ struct srv_pathinfo *pathinfo = pathmap_load(&ctx->parent_sess->paths, fidinfo->path);
+ assert(pathinfo);
+ pathinfo->gc_refcount++;
resp->wqid = (struct lib9p_qid *)(&resp[1]);
for (resp->nwqid = 0; resp->nwqid < req->nwname; resp->nwqid++) {
- implements_lib9p_srv_file *member;
- if (strcmp(req->wname[resp->nwqid].utf8, "..") == 0) {
- member = dir->_parent_dir;
+ struct srv_pathinfo *new_pathinfo;
+ if (lib9p_str_eq(req->wname[resp->nwqid], lib9p_str(".."))) {
+ new_pathinfo = pathmap_load(&ctx->parent_sess->paths, pathinfo->parent_dir);
+ assert(new_pathinfo);
+ new_pathinfo->gc_refcount++;
} else {
- if (!isdir) {
+ if (!srv_util_pathisdir(pathinfo)) {
lib9p_error(&ctx->ctx.basectx,
LINUX_ENOTDIR, "not a directory");
break;
}
- member = VCALL(dir, dopen, &ctx->ctx, req->wname[resp->nwqid].utf8);
- assert((member == NULL) == lib9p_ctx_has_error(&ctx->ctx.basectx));
+ lo_interface lib9p_srv_file member_file = LO_CALL(pathinfo->file, dwalk, &ctx->ctx, req->wname[resp->nwqid]);
+ assert(LO_IS_NULL(member_file) == lib9p_ctx_has_error(&ctx->ctx.basectx));
if (lib9p_ctx_has_error(&ctx->ctx.basectx))
break;
- member->_parent_dir = dir;
- dir->_refcount++; /* member->_parent_dir */
+ new_pathinfo = srv_util_pathsave(ctx, member_file, LO_CALL(pathinfo->file, qid).path);
}
- member->_refcount++; /* presumptively take ref-A */
- struct lib9p_stat stat = VCALL(member, stat, &ctx->ctx);
- if (lib9p_ctx_has_error(&ctx->ctx.basectx)) {
- util_release(&ctx->ctx, member); /* presumption of taking ref-A failed */
- break;
- }
- lib9p_assert_stat(stat);
- isdir = stat.file_mode & LIB9P_DM_DIR;
- if (isdir && !util_check_perm(&ctx->ctx, &stat, 0b001)) {
- lib9p_error(&ctx->ctx.basectx,
- LINUX_EACCES, "you do not have execute permission on that directory");
- util_release(&ctx->ctx, member); /* presumption of taking ref-A failed */
- break;
+ if (srv_util_pathisdir(new_pathinfo)) {
+ struct lib9p_stat stat = LO_CALL(new_pathinfo->file, stat, &ctx->ctx);
+ if (lib9p_ctx_has_error(&ctx->ctx.basectx))
+ break;
+ lib9p_stat_assert(stat);
+ if (!srv_util_check_perm(ctx, &stat, 0b001)) {
+ lib9p_error(&ctx->ctx.basectx,
+ LINUX_EACCES, "you do not have execute permission on that directory");
+ srv_util_pathfree(ctx, LO_CALL(new_pathinfo->file, qid).path);
+ break;
+ }
}
- resp->wqid[resp->nwqid] = stat.file_qid;
+ resp->wqid[resp->nwqid] = LO_CALL(new_pathinfo->file, qid);
- /* presumption of taking ref-A succeeded */
- util_release(&ctx->ctx, dir);
- dir = member;
+ srv_util_pathfree(ctx, LO_CALL(pathinfo->file, qid).path);
+ pathinfo = new_pathinfo;
}
if (resp->nwqid == req->nwname) {
- if (req->newfid == req->fid) {
- handle_Tclunk(ctx,
- &(struct lib9p_msg_Tclunk){.fid = req->fid},
- &(struct lib9p_msg_Rclunk){});
- }
- if (!fidmap_store(&ctx->parent_sess->fids, req->newfid, (struct _srv_fidinfo){
- .file = dir,
- .flags = isdir ? FIDFLAG_ISDIR : 0,
- })) {
- lib9p_error(&ctx->ctx.basectx,
- LINUX_EMFILE, "too many open files");
- util_release(&ctx->ctx, dir); /* presumption of insertion failed */
- }
+ if (!srv_util_fidsave(ctx, req->newfid, pathinfo, req->newfid == req->fid))
+ srv_util_pathfree(ctx, LO_CALL(pathinfo->file, qid).path);
} else {
assert(lib9p_ctx_has_error(&ctx->ctx.basectx));
- if (req->newfid != req->fid)
- util_release(&ctx->ctx, dir); /* presumption of insertion failed */
+ srv_util_pathfree(ctx, LO_CALL(pathinfo->file, qid).path);
if (resp->nwqid > 0)
lib9p_ctx_clear_error(&ctx->ctx.basectx);
}
@@ -730,8 +849,10 @@ static void handle_Topen(struct _lib9p_srv_req *ctx,
LINUX_EALREADY, "FID is already open");
return;
}
- if (fidinfo->flags & FIDFLAG_ISDIR) {
- if ( ((req->mode & LIB9P_O_MODE_MASK) != LIB9P_O_READ) ||
+ struct srv_pathinfo *pathinfo = pathmap_load(&ctx->parent_sess->paths, fidinfo->path);
+ assert(pathinfo);
+ if (srv_util_pathisdir(pathinfo)) {
+ if ( ((req->mode & LIB9P_O_MODE_MASK) != LIB9P_O_MODE_READ) ||
(req->mode & LIB9P_O_TRUNC) ||
(req->mode & LIB9P_O_RCLOSE) ) {
lib9p_error(&ctx->ctx.basectx,
@@ -741,61 +862,92 @@ static void handle_Topen(struct _lib9p_srv_req *ctx,
}
/* Variables. */
- lib9p_o_t reqmode = req->mode;
- uint8_t fidflags = fidinfo->flags;
- implements_lib9p_srv_file *file = fidinfo->file;
+ lib9p_o_t reqmode = req->mode;
+ uint8_t fidflags = fidinfo->flags;
/* Check permissions. */
if (reqmode & LIB9P_O_RCLOSE) {
- struct lib9p_stat parent_stat = VCALL(file->_parent_dir, stat, &ctx->ctx);
+ struct srv_pathinfo *parent = pathmap_load(&ctx->parent_sess->paths, pathinfo->parent_dir);
+ assert(parent);
+ struct lib9p_stat parent_stat = LO_CALL(parent->file, stat, &ctx->ctx);
if (lib9p_ctx_has_error(&ctx->ctx.basectx))
return;
- lib9p_assert_stat(parent_stat);
- if (!util_check_perm(&ctx->ctx, &parent_stat, 0b010)) {
+ lib9p_stat_assert(parent_stat);
+ if (!srv_util_check_perm(ctx, &parent_stat, 0b010)) {
lib9p_error(&ctx->ctx.basectx,
LINUX_EACCES, "permission denied to remove-on-close");
return;
}
- fidflags = fidflags | FIDFLAG_RCLOSE;
+ fidflags |= FIDFLAG_RCLOSE;
}
- struct lib9p_stat stat = VCALL(file, stat, &ctx->ctx);
+ struct lib9p_stat stat = LO_CALL(pathinfo->file, stat, &ctx->ctx);
if (lib9p_ctx_has_error(&ctx->ctx.basectx))
return;
- lib9p_assert_stat(stat);
- if (stat.file_mode & LIB9P_QT_APPEND)
+ lib9p_stat_assert(stat);
+ if ((stat.file_mode & LIB9P_DM_EXCL) && pathinfo->io_refcount) {
+ lib9p_error(&ctx->ctx.basectx,
+ LINUX_EEXIST, "exclusive file is already opened");
+ return;
+ }
+ if (stat.file_mode & LIB9P_DM_APPEND)
reqmode = reqmode & ~LIB9P_O_TRUNC;
uint8_t perm_bits = 0;
+ bool rd = false, wr = false;
switch (reqmode & LIB9P_O_MODE_MASK) {
- case LIB9P_O_READ:
+ case LIB9P_O_MODE_READ:
perm_bits = 0b100;
- fidflags = fidflags | FIDFLAG_OPEN_R;
+ rd = true;
break;
- case LIB9P_O_WRITE:
+ case LIB9P_O_MODE_WRITE:
perm_bits = 0b010;
- fidflags = fidflags | FIDFLAG_OPEN_W;
+ wr = true;
break;
- case LIB9P_O_RDWR:
+ case LIB9P_O_MODE_RDWR:
perm_bits = 0b110;
- fidflags = fidflags | FIDFLAG_OPEN_R | FIDFLAG_OPEN_W;
+ rd = wr = true;
break;
- case LIB9P_O_EXEC:
+ case LIB9P_O_MODE_EXEC:
perm_bits = 0b001;
- fidflags = fidflags | FIDFLAG_OPEN_R;
+ rd = true;
break;
}
- if (!util_check_perm(&ctx->ctx, &stat, perm_bits)) {
+ if (!srv_util_check_perm(ctx, &stat, perm_bits)) {
lib9p_error(&ctx->ctx.basectx,
LINUX_EACCES, "permission denied");
+ return;
}
/* Actually make the call. */
- uint32_t iounit = VCALL(file, io, &ctx->ctx, reqmode);
- if (lib9p_ctx_has_error(&ctx->ctx.basectx))
- return;
+ uint32_t iounit;
+ struct lib9p_qid qid;
+ if (srv_util_pathisdir(pathinfo)) {
+ fidinfo->dir.io = LO_CALL(pathinfo->file, dopen, &ctx->ctx);
+ assert(LO_IS_NULL(fidinfo->dir.io) == lib9p_ctx_has_error(&ctx->ctx.basectx));
+ if (lib9p_ctx_has_error(&ctx->ctx.basectx))
+ return;
+ fidinfo->dir.idx = 0;
+ fidinfo->dir.off = 0;
+ qid = LO_CALL(fidinfo->dir.io, qid);
+ iounit = 0;
+ } else {
+ fidinfo->file.io = LO_CALL(pathinfo->file, fopen, &ctx->ctx,
+ rd, wr,
+ reqmode & LIB9P_O_TRUNC);
+ assert(LO_IS_NULL(fidinfo->file.io) == lib9p_ctx_has_error(&ctx->ctx.basectx));
+ if (lib9p_ctx_has_error(&ctx->ctx.basectx))
+ return;
+ qid = LO_CALL(fidinfo->file.io, qid);
+ iounit = LO_CALL(fidinfo->file.io, iounit);
+ }
/* Success. */
+ if (rd)
+ fidflags |= FIDFLAG_OPEN_R;
+ if (wr)
+ fidflags |= FIDFLAG_OPEN_W;
+ pathinfo->io_refcount++;
fidinfo->flags = fidflags;
- resp->qid = stat.file_qid;
+ resp->qid = qid;
resp->iounit = iounit;
}
@@ -813,6 +965,8 @@ static void handle_Tread(struct _lib9p_srv_req *ctx,
struct lib9p_msg_Rread *resp) {
util_handler_common(ctx, req, resp);
+ /* TODO: serialize simultaneous reads to the same FID */
+
/* Check that the FID is valid for this. */
struct _srv_fidinfo *fidinfo = fidmap_load(&ctx->parent_sess->fids, req->fid);
if (!fidinfo) {
@@ -827,38 +981,47 @@ static void handle_Tread(struct _lib9p_srv_req *ctx,
}
/* Variables. */
- implements_lib9p_srv_file *file = fidinfo->file;
- resp->data.dat = (char *)(&resp[1]);
+ struct srv_pathinfo *pathinfo = pathmap_load(&ctx->parent_sess->paths, fidinfo->path);
+ assert(pathinfo);
/* Do it. */
- if (fidinfo->flags & FIDFLAG_ISDIR) {
+ if (srv_util_pathisdir(pathinfo)) {
/* Translate byte-offset to object-index. */
size_t idx;
if (req->offset == 0)
idx = 0;
- else if (req->offset == fidinfo->dir_off)
- idx = fidinfo->dir_idx;
+ else if (req->offset == fidinfo->dir.off)
+ idx = fidinfo->dir.idx;
else {
lib9p_errorf(&ctx->ctx.basectx,
- LINUX_EINVAL, "invalid offset (must be 0 or %"PRIu32"): %"PRIu32,
- fidinfo->dir_off, req->offset);
+ LINUX_EINVAL, "invalid offset (must be 0 or %"PRIu64"): %"PRIu64,
+ fidinfo->dir.off, req->offset);
return;
}
/* Do it. */
- size_t num = VCALL(file, dread, &ctx->ctx, (uint8_t *)resp->data.dat, req->count, idx);
+ resp->data = (char *)(&resp[1]);
+ size_t num = LO_CALL(fidinfo->dir.io, dread, &ctx->ctx, (uint8_t *)resp->data, req->count, idx);
/* Translate object-count back to byte-count. */
uint32_t len = 0;
for (size_t i = 0; i < num; i++) {
uint32_t i_len;
- lib9p_validate_stat(&ctx->ctx.basectx, req->count, &((uint8_t *)resp->data.dat)[len], &i_len, NULL);
+ lib9p_stat_validate(&ctx->ctx.basectx, req->count, &((uint8_t *)resp->data)[len], &i_len, NULL);
len += i_len;
}
- resp->data.len = len;
+ resp->count = len;
/* Remember. */
- fidinfo->dir_idx = idx+num;
- fidinfo->dir_off = req->offset + len;
- } else
- resp->data.len = VCALL(file, pread, &ctx->ctx, resp->data.dat, req->count, req->offset);
+ fidinfo->dir.idx = idx+num;
+ fidinfo->dir.off = req->offset + len;
+ } else {
+ struct iovec iov;
+ LO_CALL(fidinfo->file.io, pread, &ctx->ctx, req->count, req->offset, &iov);
+ if (!lib9p_ctx_has_error(&ctx->ctx.basectx)) {
+ resp->count = iov.iov_len;
+ resp->data = iov.iov_base;
+ if (resp->count > req->count)
+ resp->count = req->count;
+ }
+ }
}
static void handle_Twrite(struct _lib9p_srv_req *ctx,
@@ -866,6 +1029,8 @@ static void handle_Twrite(struct _lib9p_srv_req *ctx,
struct lib9p_msg_Rwrite *resp) {
util_handler_common(ctx, req, resp);
+ /* TODO: serialize simultaneous writes to the same FID */
+
/* Check that the FID is valid for this. */
struct _srv_fidinfo *fidinfo = fidmap_load(&ctx->parent_sess->fids, req->fid);
if (!fidinfo) {
@@ -880,41 +1045,69 @@ static void handle_Twrite(struct _lib9p_srv_req *ctx,
}
/* Variables. */
- implements_lib9p_srv_file *file = fidinfo->file;
+ struct srv_pathinfo *pathinfo = pathmap_load(&ctx->parent_sess->paths, fidinfo->path);
+ assert(pathinfo);
/* Do it. */
- resp->count = VCALL(file, pwrite, &ctx->ctx, req->data.dat, req->data.len, req->offset);
+ resp->count = LO_CALL(fidinfo->file.io, pwrite, &ctx->ctx, req->data, req->count, req->offset);
}
-static void handle_Tclunk(struct _lib9p_srv_req *ctx,
- struct lib9p_msg_Tclunk *req,
- struct lib9p_msg_Rclunk *resp) {
- util_handler_common(ctx, req, resp);
-
- struct _srv_fidinfo *fidinfo = fidmap_load(&ctx->parent_sess->fids, req->fid);
+static void clunkremove(struct _lib9p_srv_req *ctx, lib9p_fid_t fid, bool remove) {
+ struct _srv_fidinfo *fidinfo = fidmap_load(&ctx->parent_sess->fids, fid);
if (!fidinfo) {
lib9p_errorf(&ctx->ctx.basectx,
- LINUX_EBADF, "bad file number %"PRIu32, req->fid);
+ LINUX_EBADF, "bad file number %"PRIu32, fid);
return;
}
- if (fidinfo->flags & FIDFLAG_RCLOSE) {
- handle_Tremove(ctx,
- &(struct lib9p_msg_Tremove){.fid = req->fid},
- &(struct lib9p_msg_Rremove){});
- return;
+ if (fidinfo->flags & FIDFLAG_RCLOSE)
+ remove = true;
+ struct srv_pathinfo *pathinfo = pathmap_load(&ctx->parent_sess->paths, fidinfo->path);
+ assert(pathinfo);
+
+ if (remove) {
+ if (pathinfo->parent_dir == fidinfo->path) {
+ lib9p_errorf(&ctx->ctx.basectx,
+ LINUX_EBUSY, "cannot remove root");
+ goto clunk;
+ }
+ struct srv_pathinfo *parent = pathmap_load(&ctx->parent_sess->paths, pathinfo->parent_dir);
+ assert(parent);
+ struct lib9p_stat parent_stat = LO_CALL(parent->file, stat, &ctx->ctx);
+ if (!srv_util_check_perm(ctx, &parent_stat, 0b010)) {
+ lib9p_error(&ctx->ctx.basectx,
+ LINUX_EACCES, "you do not have write permission on the parent directory");
+ goto clunk;
+ }
+ LO_CALL(pathinfo->file, remove, &ctx->ctx);
+ }
+
+ clunk:
+ if (fidinfo->flags & FIDFLAG_OPEN) {
+ if (srv_util_pathisdir(pathinfo))
+ LO_CALL(fidinfo->dir.io, iofree);
+ else
+ LO_CALL(fidinfo->file.io, iofree);
+ pathinfo->io_refcount--;
}
+ srv_util_pathfree(ctx, LO_CALL(pathinfo->file, qid).path);
+ fidmap_del(&ctx->parent_sess->fids, fid);
+}
- VCALL(fidinfo->file, free, &ctx->ctx);
- fidmap_del(&ctx->parent_sess->fids, req->fid);
+static void handle_Tclunk(struct _lib9p_srv_req *ctx,
+ struct lib9p_msg_Tclunk *req,
+ struct lib9p_msg_Rclunk *resp) {
+ util_handler_common(ctx, req, resp);
+
+ clunkremove(ctx, req->fid, false);
}
+
static void handle_Tremove(struct _lib9p_srv_req *ctx,
struct lib9p_msg_Tremove *req,
struct lib9p_msg_Rremove *resp) {
util_handler_common(ctx, req, resp);
- lib9p_error(&ctx->ctx.basectx,
- LINUX_EOPNOTSUPP, "remove not (yet?) implemented");
+ clunkremove(ctx, req->fid, true);
}
static void handle_Tstat(struct _lib9p_srv_req *ctx,
@@ -928,10 +1121,12 @@ static void handle_Tstat(struct _lib9p_srv_req *ctx,
LINUX_EBADF, "bad file number %"PRIu32, req->fid);
return;
}
+ struct srv_pathinfo *pathinfo = pathmap_load(&ctx->parent_sess->paths, fidinfo->path);
+ assert(pathinfo);
- resp->stat = VCALL(fidinfo->file, stat, &ctx->ctx);
+ resp->stat = LO_CALL(pathinfo->file, stat, &ctx->ctx);
if (!lib9p_ctx_has_error(&ctx->ctx.basectx))
- lib9p_assert_stat(resp->stat);
+ lib9p_stat_assert(resp->stat);
}
static void handle_Twstat(struct _lib9p_srv_req *ctx,
@@ -943,7 +1138,7 @@ static void handle_Twstat(struct _lib9p_srv_req *ctx,
LINUX_EOPNOTSUPP, "wstat not (yet?) implemented");
}
-#ifdef CONFIG_9P_ENABLE_9P2000_e
+#if CONFIG_9P_ENABLE_9P2000_e
static void handle_Tsession(struct _lib9p_srv_req *ctx,
struct lib9p_msg_Tsession *req,
struct lib9p_msg_Rsession *resp) {
diff --git a/lib9p/tables.c b/lib9p/tables.c
new file mode 100644
index 0000000..86e3298
--- /dev/null
+++ b/lib9p/tables.c
@@ -0,0 +1,188 @@
+/* lib9p/tables.c - Access tables of version and message information
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <string.h>
+
+#include <libmisc/endian.h>
+#include <libmisc/log.h> /* for const_byte_str() */
+
+#include "tables.h"
+
+/* bounds checks **************************************************************/
+
+static inline void assert_ver(enum lib9p_version ver) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wtype-limits"
+ assert(0 <= ver && ver < LIB9P_VER_NUM);
+#pragma GCC diagnostic pop
+}
+
+static inline void assert_typ(enum lib9p_msg_type typ) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wtype-limits"
+ assert(0 <= typ && typ < 0xFF);
+#pragma GCC diagnostic pop
+}
+
+/* simple lookups *************************************************************/
+
+const char *lib9p_version_str(enum lib9p_version ver) {
+ assert_ver(ver);
+ return _lib9p_table_ver[ver].name;
+}
+
+uint32_t lib9p_version_min_msg_size(enum lib9p_version ver) {
+ assert_ver(ver);
+ return _lib9p_table_ver[ver].min_msg_size;
+}
+
+const char *lib9p_msgtype_str(enum lib9p_version ver, enum lib9p_msg_type typ) {
+ assert_ver(ver);
+ assert_typ(typ);
+ return _lib9p_table_msg[ver][typ].name ?: const_byte_str(typ);
+}
+
+lo_interface fmt_formatter lo_box_lib9p_msg_as_fmt_formatter(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body) {
+ assert(ctx);
+ assert_ver(ctx->version);
+ assert_typ(typ);
+ assert(_lib9p_table_msg[ctx->version][typ].box_as_fmt_formatter);
+ return _lib9p_table_msg[ctx->version][typ].box_as_fmt_formatter(body);
+}
+
+/* main message functions *****************************************************/
+
+static
+ssize_t _lib9p_validate(uint8_t xxx_low_typ_bit,
+ const char *xxx_errmsg,
+ const struct _lib9p_recv_tentry xxx_table[LIB9P_VER_NUM][0x80],
+ struct lib9p_ctx *ctx, uint8_t *net_bytes) {
+ assert_ver(ctx->version);
+ /* Inspect the first 5 bytes ourselves. */
+ uint32_t net_size = uint32le_decode(net_bytes);
+ if (net_size < 5)
+ return lib9p_error(ctx, LINUX_EBADMSG, "message is impossibly short");
+ uint8_t typ = net_bytes[4];
+ if (typ % 2 != xxx_low_typ_bit)
+ return lib9p_errorf(ctx, LINUX_EOPNOTSUPP, "%s: message_type=%s", xxx_errmsg,
+ lib9p_msgtype_str(ctx->version, typ));
+ struct _lib9p_recv_tentry tentry = xxx_table[ctx->version][typ/2];
+ if (!tentry.validate)
+ return lib9p_errorf(ctx, LINUX_EOPNOTSUPP, "unknown message type: %s (protocol_version=%s)",
+ lib9p_msgtype_str(ctx->version, typ), lib9p_version_str(ctx->version));
+
+ /* Now use the message-type-specific tentry to process the whole thing. */
+ return tentry.validate(ctx, net_size, net_bytes);
+}
+
+ssize_t lib9p_Tmsg_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes) {
+ return _lib9p_validate(0, "expected a T-message but got an R-message", _lib9p_table_Tmsg_recv,
+ ctx, net_bytes);
+}
+
+ssize_t lib9p_Rmsg_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes) {
+ return _lib9p_validate(1, "expected an R-message but got a T-message", _lib9p_table_Rmsg_recv,
+ ctx, net_bytes);
+}
+
+static
+void _lib9p_unmarshal(const struct _lib9p_recv_tentry xxx_table[LIB9P_VER_NUM][0x80],
+ struct lib9p_ctx *ctx, uint8_t *net_bytes,
+ enum lib9p_msg_type *ret_typ, void *ret_body) {
+ assert_ver(ctx->version);
+ enum lib9p_msg_type typ = net_bytes[4];
+ *ret_typ = typ;
+ struct _lib9p_recv_tentry tentry = xxx_table[ctx->version][typ/2];
+ assert(tentry.unmarshal);
+
+ tentry.unmarshal(ctx, net_bytes, ret_body);
+}
+
+void lib9p_Tmsg_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
+ enum lib9p_msg_type *ret_typ, void *ret_body) {
+ _lib9p_unmarshal(_lib9p_table_Tmsg_recv,
+ ctx, net_bytes, ret_typ, ret_body);
+}
+
+void lib9p_Rmsg_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
+ enum lib9p_msg_type *ret_typ, void *ret_body) {
+ _lib9p_unmarshal(_lib9p_table_Rmsg_recv,
+ ctx, net_bytes, ret_typ, ret_body);
+}
+
+static
+bool _lib9p_marshal(const struct _lib9p_send_tentry xxx_table[LIB9P_VER_NUM][0x80],
+ struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
+ size_t *ret_iov_cnt, struct iovec *ret_iov, uint8_t *ret_copied) {
+ assert_ver(ctx->version);
+ assert_typ(typ);
+ struct _marshal_ret ret = {
+ .net_iov_cnt = 1,
+ .net_iov = ret_iov,
+ .net_copied_size = 0,
+ .net_copied = ret_copied,
+ };
+ struct _lib9p_send_tentry tentry = xxx_table[ctx->version][typ/2];
+ assert(tentry.marshal);
+
+ bool ret_erred = tentry.marshal(ctx, body, &ret);
+ if (ret_iov[ret.net_iov_cnt-1].iov_len == 0)
+ ret.net_iov_cnt--;
+ *ret_iov_cnt = ret.net_iov_cnt;
+ return ret_erred;
+}
+
+bool lib9p_Tmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
+ struct lib9p_Tmsg_send_buf *ret) {
+ assert(typ % 2 == 0);
+ memset(ret, 0, sizeof(*ret));
+ return _lib9p_marshal(_lib9p_table_Tmsg_send,
+ ctx, typ, body,
+ &ret->iov_cnt, ret->iov, ret->copied);
+}
+
+bool lib9p_Rmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body,
+ struct lib9p_Rmsg_send_buf *ret) {
+ assert(typ % 2 == 1);
+ memset(ret, 0, sizeof(*ret));
+ return _lib9p_marshal(_lib9p_table_Rmsg_send,
+ ctx, typ, body,
+ &ret->iov_cnt, ret->iov, ret->copied);
+}
+
+/* `struct lib9p_stat` helpers ************************************************/
+
+bool lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes,
+ uint32_t *ret_net_size, size_t *ret_host_size) {
+ ssize_t host_size = _lib9p_stat_validate(ctx, net_size, net_bytes, ret_net_size);
+ if (host_size < 0)
+ return true;
+ if (ret_host_size)
+ *ret_host_size = (size_t)host_size;
+ return false;
+}
+
+void lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes,
+ struct lib9p_stat *ret) {
+ _lib9p_stat_unmarshal(ctx, net_bytes, ret);
+}
+
+uint32_t lib9p_stat_marshal(struct lib9p_ctx *ctx, uint32_t max_net_size, struct lib9p_stat *obj,
+ uint8_t *ret_bytes) {
+ struct lib9p_ctx _ctx = *ctx;
+ _ctx.max_msg_size = max_net_size;
+
+ struct iovec iov = {0};
+ struct _marshal_ret ret = {
+ .net_iov_cnt = 1,
+ .net_iov = &iov,
+ .net_copied_size = 0,
+ .net_copied = ret_bytes,
+ };
+ if (_lib9p_stat_marshal(&_ctx, obj, &ret))
+ return 0;
+ return ret.net_iov[0].iov_len;
+}
diff --git a/lib9p/tables.h b/lib9p/tables.h
new file mode 100644
index 0000000..edb402a
--- /dev/null
+++ b/lib9p/tables.h
@@ -0,0 +1,59 @@
+/* lib9p/tables.h - Declare tables of version and message information
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIB9P_TABLES_H_
+#define _LIB9P_TABLES_H_
+
+#include <lib9p/9p.h>
+
+/* version ********************************************************************/
+
+struct _lib9p_ver_tentry {
+ const char *name;
+ uint32_t min_msg_size;
+};
+
+extern const struct _lib9p_ver_tentry _lib9p_table_ver[LIB9P_VER_NUM];
+
+/* message ********************************************************************/
+
+typedef lo_interface fmt_formatter (*_box_as_fmt_formatter_fn_t)(void *host_val);
+struct _lib9p_msg_tentry {
+ const char *name;
+ _box_as_fmt_formatter_fn_t box_as_fmt_formatter;
+};
+
+typedef ssize_t (*_validate_fn_t)(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes);
+typedef void (*_unmarshal_fn_t)(struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out);
+struct _lib9p_recv_tentry {
+ _validate_fn_t validate;
+ _unmarshal_fn_t unmarshal;
+};
+
+struct _marshal_ret {
+ size_t net_iov_cnt;
+ struct iovec *net_iov;
+ size_t net_copied_size;
+ uint8_t *net_copied;
+};
+typedef bool (*_marshal_fn_t)(struct lib9p_ctx *ctx, void *host_val, struct _marshal_ret *ret);
+struct _lib9p_send_tentry {
+ _marshal_fn_t marshal;
+};
+
+extern const struct _lib9p_msg_tentry _lib9p_table_msg[LIB9P_VER_NUM][0x100];
+extern const struct _lib9p_recv_tentry _lib9p_table_Tmsg_recv[LIB9P_VER_NUM][0x80];
+extern const struct _lib9p_recv_tentry _lib9p_table_Rmsg_recv[LIB9P_VER_NUM][0x80];
+extern const struct _lib9p_send_tentry _lib9p_table_Tmsg_send[LIB9P_VER_NUM][0x80];
+extern const struct _lib9p_send_tentry _lib9p_table_Rmsg_send[LIB9P_VER_NUM][0x80];
+
+/* stat ***********************************************************************/
+
+ssize_t _lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, uint32_t *ret_net_size);
+void _lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, void *out);
+bool _lib9p_stat_marshal(struct lib9p_ctx *ctx, struct lib9p_stat *val, struct _marshal_ret *ret);
+
+#endif /* _LIB9P_TABLES_H_ */
diff --git a/lib9p/tests/client_config/config.h b/lib9p/tests/client_config/config.h
new file mode 100644
index 0000000..65ee9de
--- /dev/null
+++ b/lib9p/tests/client_config/config.h
@@ -0,0 +1,40 @@
+/* config.h - Compile-time configuration for lib9p test clients
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+/* 9P *************************************************************************/
+
+#define CONFIG_9P_MAX_ERR_SIZE 128
+#define CONFIG_9P_MAX_9P2000_e_WELEM 16
+
+#define CONFIG_9P_ENABLE_9P2000 1 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_u 1 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_e 1 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_L 1 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_p9p 1 /* bool */
+
+/* 9P server (unused) *********************************************************/
+
+#define CONFIG_9P_SRV_MAX_MSG_SIZE ((4*1024)+24)
+#define CONFIG_9P_SRV_MAX_HOSTMSG_SIZE CONFIG_9P_SRV_MAX_MSG_SIZE+16
+#define CONFIG_9P_SRV_MAX_FIDS 16
+#define CONFIG_9P_SRV_MAX_REQS 2
+#define CONFIG_9P_SRV_MAX_DEPTH 3
+
+/* COROUTINE (unused) *********************************************************/
+
+#define CONFIG_COROUTINE_STACK_SIZE_DEFAULT (32*1024)
+#define CONFIG_COROUTINE_NAME_LEN 16
+#define CONFIG_COROUTINE_MEASURE_STACK 1 /* bool */
+#define CONFIG_COROUTINE_PROTECT_STACK 1 /* bool */
+#define CONFIG_COROUTINE_DEBUG 0 /* bool */
+#define CONFIG_COROUTINE_VALGRIND 1 /* bool */
+#define CONFIG_COROUTINE_GDB 1 /* bool */
+#define CONFIG_COROUTINE_NUM 2
+
+#endif /* _CONFIG_H_ */
diff --git a/lib9p/tests/runtest b/lib9p/tests/runtest
new file mode 100755
index 0000000..6883391
--- /dev/null
+++ b/lib9p/tests/runtest
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+# lib9p/tests/runtest - Test harness for the 9P `test_server`
+#
+# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+set -euE -o pipefail
+
+build_aux=$(realpath --canonicalize-missing -- "${BASH_SOURCE[0]}/../../../build-aux")
+
+if [[ $# != 2 ]]; then
+ echo >&2 "Usage: $0 CLIENTSCRIPT EXPLOG"
+ exit 2
+fi
+clientscript="$1"
+explog="$2"
+
+cleanup=()
+cleanup() {
+ { set +x; } &>/dev/null
+ local i
+ for ((i = ${#cleanup[@]} - 1; i >= 0; i--)); do
+ eval "set -x; ${cleanup[$i]}"
+ { set +x; } &>/dev/null
+ done
+}
+trap cleanup EXIT
+
+logfile=$(mktemp -t lib9p-log.XXXXXXXXXX)
+cleanup+=("rm -f -- ${logfile@Q}")
+
+port=$(python -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()')
+
+set -x
+
+"${build_aux}/valgrind" ./tests/test_server/test_server "$port" "$logfile" &
+server_pid=$!
+cleanup+=("kill $server_pid || true; wait $server_pid || true")
+while [[ -d /proc/$server_pid ]] && ! (readlink /proc/$server_pid/fd/* 2>/dev/null | grep -q ^socket:); do sleep 0.1; done
+
+if [[ "$(head -c2 -- "$clientscript")" == '#!' ]]; then
+ "$clientscript" "$port"
+else
+ "${build_aux}/valgrind" "$clientscript" "$port"
+fi
+
+wait "$server_pid"
+cleanup=("${cleanup[@]::1}")
+
+diff -u -- <(grep -e '^[<>]' -- "$explog") "$logfile"
diff --git a/lib9p/tests/test_compile.c b/lib9p/tests/test_compile.c
new file mode 100644
index 0000000..8f2445d
--- /dev/null
+++ b/lib9p/tests/test_compile.c
@@ -0,0 +1,299 @@
+/* lib9p/tests/test_compile.c - Generated by lib9p/tests/test_compile.c.gen. DO NOT EDIT! */
+
+#include <lib9p/9p.h>
+int main(void) {
+ [[gnu::unused]] uint64_t x;
+ x = LIB9P_TAG_NOTAG;
+ x = LIB9P_FID_NOFID;
+ x = LIB9P_DM_DIR;
+ x = LIB9P_DM_APPEND;
+ x = LIB9P_DM_EXCL;
+ x = _LIB9P_DM_PLAN9_MOUNT;
+ x = LIB9P_DM_AUTH;
+ x = LIB9P_DM_TMP;
+ x = _LIB9P_DM_UNUSED_25;
+ x = _LIB9P_DM_UNUSED_24;
+ x = LIB9P_DM_DEVICE;
+ x = _LIB9P_DM_UNUSED_22;
+ x = LIB9P_DM_PIPE;
+ x = LIB9P_DM_SOCKET;
+ x = LIB9P_DM_SETUID;
+ x = LIB9P_DM_SETGID;
+ x = _LIB9P_DM_UNUSED_17;
+ x = _LIB9P_DM_UNUSED_16;
+ x = _LIB9P_DM_UNUSED_15;
+ x = _LIB9P_DM_UNUSED_14;
+ x = _LIB9P_DM_UNUSED_13;
+ x = _LIB9P_DM_UNUSED_12;
+ x = _LIB9P_DM_UNUSED_11;
+ x = _LIB9P_DM_UNUSED_10;
+ x = _LIB9P_DM_UNUSED_9;
+ x = LIB9P_DM_OWNER_R;
+ x = LIB9P_DM_OWNER_W;
+ x = LIB9P_DM_OWNER_X;
+ x = LIB9P_DM_GROUP_R;
+ x = LIB9P_DM_GROUP_W;
+ x = LIB9P_DM_GROUP_X;
+ x = LIB9P_DM_OTHER_R;
+ x = LIB9P_DM_OTHER_W;
+ x = LIB9P_DM_OTHER_X;
+ x = LIB9P_DM_PERM_MASK;
+ x = LIB9P_QT_DIR;
+ x = LIB9P_QT_APPEND;
+ x = LIB9P_QT_EXCL;
+ x = _LIB9P_QT_PLAN9_MOUNT;
+ x = LIB9P_QT_AUTH;
+ x = LIB9P_QT_TMP;
+ x = LIB9P_QT_SYMLINK;
+ x = _LIB9P_QT_UNUSED_0;
+ x = LIB9P_QT_FILE;
+ x = LIB9P_NUID_NONUID;
+ x = _LIB9P_O_UNUSED_7;
+ x = LIB9P_O_RCLOSE;
+ x = _LIB9P_O_RESERVED_CEXEC;
+ x = LIB9P_O_TRUNC;
+ x = _LIB9P_O_UNUSED_3;
+ x = _LIB9P_O_UNUSED_2;
+ x = LIB9P_O_FLAG_MASK;
+ x = LIB9P_O_MODE_READ;
+ x = LIB9P_O_MODE_WRITE;
+ x = LIB9P_O_MODE_RDWR;
+ x = LIB9P_O_MODE_EXEC;
+ x = LIB9P_O_MODE_MASK;
+ x = LIB9P_ERRNO_NOERROR;
+ x = LIB9P_SUPER_MAGIC_V9FS_MAGIC;
+ x = _LIB9P_LO_UNUSED_31;
+ x = _LIB9P_LO_UNUSED_30;
+ x = _LIB9P_LO_UNUSED_29;
+ x = _LIB9P_LO_UNUSED_28;
+ x = _LIB9P_LO_UNUSED_27;
+ x = _LIB9P_LO_UNUSED_26;
+ x = _LIB9P_LO_UNUSED_25;
+ x = _LIB9P_LO_UNUSED_24;
+ x = _LIB9P_LO_UNUSED_23;
+ x = _LIB9P_LO_UNUSED_22;
+ x = _LIB9P_LO_UNUSED_21;
+ x = LIB9P_LO_SYNC;
+ x = LIB9P_LO_CLOEXEC;
+ x = LIB9P_LO_NOATIME;
+ x = LIB9P_LO_NOFOLLOW;
+ x = LIB9P_LO_DIRECTORY;
+ x = LIB9P_LO_LARGEFILE;
+ x = LIB9P_LO_DIRECT;
+ x = LIB9P_LO_BSD_FASYNC;
+ x = LIB9P_LO_DSYNC;
+ x = LIB9P_LO_NONBLOCK;
+ x = LIB9P_LO_APPEND;
+ x = LIB9P_LO_TRUNC;
+ x = LIB9P_LO_NOCTTY;
+ x = LIB9P_LO_EXCL;
+ x = LIB9P_LO_CREATE;
+ x = _LIB9P_LO_UNUSED_5;
+ x = _LIB9P_LO_UNUSED_4;
+ x = _LIB9P_LO_UNUSED_3;
+ x = _LIB9P_LO_UNUSED_2;
+ x = LIB9P_LO_FLAG_MASK;
+ x = LIB9P_LO_MODE_RDONLY;
+ x = LIB9P_LO_MODE_WRONLY;
+ x = LIB9P_LO_MODE_RDWR;
+ x = LIB9P_LO_MODE_NOACCESS;
+ x = LIB9P_LO_MODE_MASK;
+ x = LIB9P_DT_UNKNOWN;
+ x = LIB9P_DT_PIPE;
+ x = LIB9P_DT_CHAR_DEV;
+ x = LIB9P_DT_DIRECTORY;
+ x = LIB9P_DT_BLOCK_DEV;
+ x = LIB9P_DT_REGULAR;
+ x = LIB9P_DT_SYMLINK;
+ x = LIB9P_DT_SOCKET;
+ x = _LIB9P_DT_WHITEOUT;
+ x = _LIB9P_MODE_UNUSED_31;
+ x = _LIB9P_MODE_UNUSED_30;
+ x = _LIB9P_MODE_UNUSED_29;
+ x = _LIB9P_MODE_UNUSED_28;
+ x = _LIB9P_MODE_UNUSED_27;
+ x = _LIB9P_MODE_UNUSED_26;
+ x = _LIB9P_MODE_UNUSED_25;
+ x = _LIB9P_MODE_UNUSED_24;
+ x = _LIB9P_MODE_UNUSED_23;
+ x = _LIB9P_MODE_UNUSED_22;
+ x = _LIB9P_MODE_UNUSED_21;
+ x = _LIB9P_MODE_UNUSED_20;
+ x = _LIB9P_MODE_UNUSED_19;
+ x = _LIB9P_MODE_UNUSED_18;
+ x = _LIB9P_MODE_UNUSED_17;
+ x = _LIB9P_MODE_UNUSED_16;
+ x = LIB9P_MODE_PERM_SETGROUP;
+ x = LIB9P_MODE_PERM_SETUSER;
+ x = LIB9P_MODE_PERM_STICKY;
+ x = LIB9P_MODE_PERM_OWNER_R;
+ x = LIB9P_MODE_PERM_OWNER_W;
+ x = LIB9P_MODE_PERM_OWNER_X;
+ x = LIB9P_MODE_PERM_GROUP_R;
+ x = LIB9P_MODE_PERM_GROUP_W;
+ x = LIB9P_MODE_PERM_GROUP_X;
+ x = LIB9P_MODE_PERM_OTHER_R;
+ x = LIB9P_MODE_PERM_OTHER_W;
+ x = LIB9P_MODE_PERM_OTHER_X;
+ x = LIB9P_MODE_PERM_MASK;
+ x = LIB9P_MODE_FMT_PIPE;
+ x = LIB9P_MODE_FMT_CHAR_DEV;
+ x = LIB9P_MODE_FMT_DIRECTORY;
+ x = LIB9P_MODE_FMT_BLOCK_DEV;
+ x = LIB9P_MODE_FMT_REGULAR;
+ x = LIB9P_MODE_FMT_SYMLINK;
+ x = LIB9P_MODE_FMT_SOCKET;
+ x = LIB9P_MODE_FMT_MASK;
+ x = LIB9P_B4_FALSE;
+ x = LIB9P_B4_TRUE;
+ x = _LIB9P_GETATTR_UNUSED_63;
+ x = _LIB9P_GETATTR_UNUSED_62;
+ x = _LIB9P_GETATTR_UNUSED_61;
+ x = _LIB9P_GETATTR_UNUSED_60;
+ x = _LIB9P_GETATTR_UNUSED_59;
+ x = _LIB9P_GETATTR_UNUSED_58;
+ x = _LIB9P_GETATTR_UNUSED_57;
+ x = _LIB9P_GETATTR_UNUSED_56;
+ x = _LIB9P_GETATTR_UNUSED_55;
+ x = _LIB9P_GETATTR_UNUSED_54;
+ x = _LIB9P_GETATTR_UNUSED_53;
+ x = _LIB9P_GETATTR_UNUSED_52;
+ x = _LIB9P_GETATTR_UNUSED_51;
+ x = _LIB9P_GETATTR_UNUSED_50;
+ x = _LIB9P_GETATTR_UNUSED_49;
+ x = _LIB9P_GETATTR_UNUSED_48;
+ x = _LIB9P_GETATTR_UNUSED_47;
+ x = _LIB9P_GETATTR_UNUSED_46;
+ x = _LIB9P_GETATTR_UNUSED_45;
+ x = _LIB9P_GETATTR_UNUSED_44;
+ x = _LIB9P_GETATTR_UNUSED_43;
+ x = _LIB9P_GETATTR_UNUSED_42;
+ x = _LIB9P_GETATTR_UNUSED_41;
+ x = _LIB9P_GETATTR_UNUSED_40;
+ x = _LIB9P_GETATTR_UNUSED_39;
+ x = _LIB9P_GETATTR_UNUSED_38;
+ x = _LIB9P_GETATTR_UNUSED_37;
+ x = _LIB9P_GETATTR_UNUSED_36;
+ x = _LIB9P_GETATTR_UNUSED_35;
+ x = _LIB9P_GETATTR_UNUSED_34;
+ x = _LIB9P_GETATTR_UNUSED_33;
+ x = _LIB9P_GETATTR_UNUSED_32;
+ x = _LIB9P_GETATTR_UNUSED_31;
+ x = _LIB9P_GETATTR_UNUSED_30;
+ x = _LIB9P_GETATTR_UNUSED_29;
+ x = _LIB9P_GETATTR_UNUSED_28;
+ x = _LIB9P_GETATTR_UNUSED_27;
+ x = _LIB9P_GETATTR_UNUSED_26;
+ x = _LIB9P_GETATTR_UNUSED_25;
+ x = _LIB9P_GETATTR_UNUSED_24;
+ x = _LIB9P_GETATTR_UNUSED_23;
+ x = _LIB9P_GETATTR_UNUSED_22;
+ x = _LIB9P_GETATTR_UNUSED_21;
+ x = _LIB9P_GETATTR_UNUSED_20;
+ x = _LIB9P_GETATTR_UNUSED_19;
+ x = _LIB9P_GETATTR_UNUSED_18;
+ x = _LIB9P_GETATTR_UNUSED_17;
+ x = _LIB9P_GETATTR_UNUSED_16;
+ x = _LIB9P_GETATTR_UNUSED_15;
+ x = _LIB9P_GETATTR_UNUSED_14;
+ x = LIB9P_GETATTR_DATA_VERSION;
+ x = LIB9P_GETATTR_GEN;
+ x = LIB9P_GETATTR_BTIME;
+ x = LIB9P_GETATTR_BLOCKS;
+ x = LIB9P_GETATTR_SIZE;
+ x = LIB9P_GETATTR_INO;
+ x = LIB9P_GETATTR_CTIME;
+ x = LIB9P_GETATTR_MTIME;
+ x = LIB9P_GETATTR_ATIME;
+ x = LIB9P_GETATTR_RDEV;
+ x = LIB9P_GETATTR_GID;
+ x = LIB9P_GETATTR_UID;
+ x = LIB9P_GETATTR_NLINK;
+ x = LIB9P_GETATTR_MODE;
+ x = LIB9P_GETATTR_BASIC;
+ x = LIB9P_GETATTR_ALL;
+ x = _LIB9P_SETATTR_UNUSED_31;
+ x = _LIB9P_SETATTR_UNUSED_30;
+ x = _LIB9P_SETATTR_UNUSED_29;
+ x = _LIB9P_SETATTR_UNUSED_28;
+ x = _LIB9P_SETATTR_UNUSED_27;
+ x = _LIB9P_SETATTR_UNUSED_26;
+ x = _LIB9P_SETATTR_UNUSED_25;
+ x = _LIB9P_SETATTR_UNUSED_24;
+ x = _LIB9P_SETATTR_UNUSED_23;
+ x = _LIB9P_SETATTR_UNUSED_22;
+ x = _LIB9P_SETATTR_UNUSED_21;
+ x = _LIB9P_SETATTR_UNUSED_20;
+ x = _LIB9P_SETATTR_UNUSED_19;
+ x = _LIB9P_SETATTR_UNUSED_18;
+ x = _LIB9P_SETATTR_UNUSED_17;
+ x = _LIB9P_SETATTR_UNUSED_16;
+ x = _LIB9P_SETATTR_UNUSED_15;
+ x = _LIB9P_SETATTR_UNUSED_14;
+ x = _LIB9P_SETATTR_UNUSED_13;
+ x = _LIB9P_SETATTR_UNUSED_12;
+ x = _LIB9P_SETATTR_UNUSED_11;
+ x = _LIB9P_SETATTR_UNUSED_10;
+ x = _LIB9P_SETATTR_UNUSED_9;
+ x = LIB9P_SETATTR_MTIME_SET;
+ x = LIB9P_SETATTR_ATIME_SET;
+ x = LIB9P_SETATTR_CTIME;
+ x = LIB9P_SETATTR_MTIME;
+ x = LIB9P_SETATTR_ATIME;
+ x = LIB9P_SETATTR_SIZE;
+ x = LIB9P_SETATTR_GID;
+ x = LIB9P_SETATTR_UID;
+ x = LIB9P_SETATTR_MODE;
+ x = LIB9P_LOCK_TYPE_RDLCK;
+ x = LIB9P_LOCK_TYPE_WRLCK;
+ x = LIB9P_LOCK_TYPE_UNLCK;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_31;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_30;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_29;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_28;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_27;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_26;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_25;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_24;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_23;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_22;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_21;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_20;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_19;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_18;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_17;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_16;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_15;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_14;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_13;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_12;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_11;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_10;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_9;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_8;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_7;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_6;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_5;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_4;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_3;
+ x = _LIB9P_LOCK_FLAGS_UNUSED_2;
+ x = LIB9P_LOCK_FLAGS_RECLAIM;
+ x = LIB9P_LOCK_FLAGS_BLOCK;
+ x = LIB9P_LOCK_STATUS_SUCCESS;
+ x = LIB9P_LOCK_STATUS_BLOCKED;
+ x = LIB9P_LOCK_STATUS_ERROR;
+ x = LIB9P_LOCK_STATUS_GRACE;
+ x = LIB9P_TMSG_MAX_IOV;
+ x = LIB9P_TMSG_MAX_IOV;
+ x = LIB9P_TMSG_MAX_COPY;
+ x = LIB9P_TMSG_MAX_COPY;
+ x = LIB9P_TMSG_MAX_COPY;
+ x = LIB9P_TMSG_MAX_COPY;
+ x = LIB9P_TMSG_MAX_COPY;
+ x = LIB9P_TMSG_MAX_COPY;
+ x = LIB9P_RMSG_MAX_IOV;
+ x = LIB9P_RMSG_MAX_IOV;
+ x = LIB9P_RMSG_MAX_IOV;
+ x = LIB9P_RMSG_MAX_COPY;
+ return 0;
+}
diff --git a/lib9p/tests/test_compile.c.gen b/lib9p/tests/test_compile.c.gen
new file mode 100755
index 0000000..47046b3
--- /dev/null
+++ b/lib9p/tests/test_compile.c.gen
@@ -0,0 +1,19 @@
+#!/bin/sh
+# lib9p/tests/test_compile.c.gen - Generate code to make sure all generated macros work
+#
+# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+generated_h=$1
+outfile=$2
+
+{
+ echo "/* ${outfile} - Generated by $0. DO NOT EDIT! */"
+ echo
+ echo "#include <lib9p/9p.h>"
+ echo 'int main(void) {'
+ echo ' [[gnu::unused]] uint64_t x;'
+ sed -nE 's/^\s*#\s*define\s*(\S[^ (]*)\s.*/ x = \1;/p' <"$generated_h"
+ echo ' return 0;'
+ echo '}'
+} >"$outfile"
diff --git a/lib9p/tests/test_compile_config/config.h b/lib9p/tests/test_compile_config/config.h
new file mode 100644
index 0000000..cc8eec1
--- /dev/null
+++ b/lib9p/tests/test_compile_config/config.h
@@ -0,0 +1,38 @@
+/* config.h - Compile-time configuration for lib9p/test/test_compile
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+/* 9P *************************************************************************/
+
+#define CONFIG_9P_MAX_ERR_SIZE 128
+#define CONFIG_9P_MAX_9P2000_e_WELEM 16
+
+#define CONFIG_9P_SRV_MAX_MSG_SIZE ((4*1024)+24)
+#define CONFIG_9P_SRV_MAX_HOSTMSG_SIZE CONFIG_9P_SRV_MAX_MSG_SIZE+16
+#define CONFIG_9P_SRV_MAX_FIDS 16
+#define CONFIG_9P_SRV_MAX_REQS 2
+#define CONFIG_9P_SRV_MAX_DEPTH 3
+
+#define CONFIG_9P_ENABLE_9P2000 1 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_u 1 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_e 1 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_L 1 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_p9p 1 /* bool */
+
+/* COROUTINE ******************************************************************/
+
+#define CONFIG_COROUTINE_STACK_SIZE_DEFAULT (32*1024)
+#define CONFIG_COROUTINE_NAME_LEN 16
+#define CONFIG_COROUTINE_MEASURE_STACK 1 /* bool */
+#define CONFIG_COROUTINE_PROTECT_STACK 1 /* bool */
+#define CONFIG_COROUTINE_DEBUG 0 /* bool */
+#define CONFIG_COROUTINE_VALGRIND 1 /* bool */
+#define CONFIG_COROUTINE_GDB 1 /* bool */
+#define CONFIG_COROUTINE_NUM 2
+
+#endif /* _CONFIG_H_ */
diff --git a/lib9p/tests/test_server/CMakeLists.txt b/lib9p/tests/test_server/CMakeLists.txt
new file mode 100644
index 0000000..eb16165
--- /dev/null
+++ b/lib9p/tests/test_server/CMakeLists.txt
@@ -0,0 +1,45 @@
+# lib9p/tests/test_server/CMakeLists.txt - Build script for test_server executable
+#
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+if (PICO_PLATFORM STREQUAL "host")
+
+# Compile ######################################################################
+
+add_library(test_server_objs OBJECT
+ main.c
+ fs_shutdown.c
+ fs_slowread.c
+)
+target_include_directories(test_server_objs PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/config)
+target_include_directories(test_server_objs PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
+target_link_libraries(test_server_objs
+ libcr
+ libcr_ipc
+ libmisc
+ lib9p
+ lib9p_util
+ libhw_cr
+)
+
+# Analyze the stack ############################################################
+
+add_stack_analysis(test_server_stack.c test_server_objs)
+
+# Link #########################################################################
+
+add_executable(test_server)
+target_sources(test_server PRIVATE
+ test_server_stack.c
+ "$<TARGET_OBJECTS:test_server_objs>"
+)
+
+# Embed ########################################################################
+
+target_embed_sources(test_server_objs test_server static.h
+ static/README.md
+ static/Documentation/x.txt
+)
+
+endif()
diff --git a/lib9p/tests/test_server/config/config.h b/lib9p/tests/test_server/config/config.h
new file mode 100644
index 0000000..03143e1
--- /dev/null
+++ b/lib9p/tests/test_server/config/config.h
@@ -0,0 +1,66 @@
+/* config.h - Compile-time configuration for lib9p/test/test_server
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+#define _CONFIG_9P_NUM_SOCKS 8
+#define CONFIG_SRV9P_NUM_CONNS _CONFIG_9P_NUM_SOCKS
+
+/* 9P *************************************************************************/
+
+#define CONFIG_9P_MAX_ERR_SIZE 128 /* 128 is what Plan 9 4e uses */
+
+/**
+ * This max-msg-size is sized so that a Twrite message can return
+ * 8KiB of data.
+ *
+ * This is the same as the default in Plan 9 4e's lib9p; it has the
+ * comment that "24" is "ample room for Twrite/Rread header
+ * (iounit)". In fact, the Twrite header is only 23 bytes
+ * ("size[4] Twrite[1] tag[2] fid[4] offset[8] count[4]") and the
+ * Rread header is even shorter at 11 bytes ("size[4] Rread[1]
+ * tag[2] count[4]"), so "24" appears to be the size of the Twrite
+ * header rounded up to a nice round number.
+ *
+ * In older versions of 9P ("9P1"), the max message size was
+ * defined as part of the protocol specification rather than
+ * negotiated. In Plan 9 1e it was (8*1024)+128, and was bumped to
+ * (8*1024)+160 in 2e and 3e.
+ */
+#define CONFIG_9P_SRV_MAX_MSG_SIZE ((4*1024)+24)
+/**
+ * Maximum host-data-structure size. A message may be larger in
+ * unmarshaled-host-structures than marshaled-net-bytes due to (1)
+ * struct padding, (2) array pointers.
+ */
+#define CONFIG_9P_SRV_MAX_HOSTMSG_SIZE CONFIG_9P_SRV_MAX_MSG_SIZE+16
+#define CONFIG_9P_SRV_MAX_FIDS 16
+#define CONFIG_9P_SRV_MAX_REQS 2
+#define CONFIG_9P_SRV_MAX_DEPTH 3
+
+#define CONFIG_9P_ENABLE_9P2000 1 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_u 1 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_e 0 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_L 0 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_p9p 0 /* bool */
+
+/* COROUTINE ******************************************************************/
+
+#define CONFIG_COROUTINE_STACK_SIZE_DEFAULT (32*1024)
+#define CONFIG_COROUTINE_NAME_LEN 16
+#define CONFIG_COROUTINE_MEASURE_STACK 1 /* bool */
+#define CONFIG_COROUTINE_PROTECT_STACK 1 /* bool */
+#define CONFIG_COROUTINE_DEBUG 0 /* bool */
+#define CONFIG_COROUTINE_VALGRIND 1 /* bool */
+#define CONFIG_COROUTINE_GDB 1 /* bool */
+#define CONFIG_COROUTINE_NUM ( \
+ 1 /* usb_common */ + \
+ 1 /* usb_keyboard */ + \
+ CONFIG_SRV9P_NUM_CONNS /* accept+read */ + \
+ (CONFIG_9P_SRV_MAX_REQS*CONFIG_SRV9P_NUM_CONNS) /* work+write */ )
+
+#endif /* _CONFIG_H_ */
diff --git a/lib9p/tests/test_server/fs_shutdown.c b/lib9p/tests/test_server/fs_shutdown.c
new file mode 100644
index 0000000..3f88985
--- /dev/null
+++ b/lib9p/tests/test_server/fs_shutdown.c
@@ -0,0 +1,93 @@
+/* lib9p/tests/test_server/fs_shutdown.c - /shutdown API endpoint
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include "fs_shutdown.h"
+
+LO_IMPLEMENTATION_C(lib9p_srv_file, struct shutdown_file, shutdown_file, static);
+
+LO_IMPLEMENTATION_H(lib9p_srv_fio, struct shutdown_file, shutdown_file);
+LO_IMPLEMENTATION_C(lib9p_srv_fio, struct shutdown_file, shutdown_file, static);
+
+/* srv_file *******************************************************************/
+
+static void shutdown_file_free(struct shutdown_file *self) {
+ assert(self);
+}
+static struct lib9p_qid shutdown_file_qid(struct shutdown_file *self) {
+ assert(self);
+ return (struct lib9p_qid){
+ .type = LIB9P_QT_FILE,
+ .vers = 1,
+ .path = self->pathnum,
+ };
+}
+
+static struct lib9p_stat shutdown_file_stat(struct shutdown_file *self, struct lib9p_srv_ctx *ctx) {
+ assert(self);
+ assert(ctx);
+ return (struct lib9p_stat){
+ .kern_type = 0,
+ .kern_dev = 0,
+ .file_qid = shutdown_file_qid(self),
+ .file_mode = 0222,
+ .file_atime = UTIL9P_ATIME,
+ .file_mtime = UTIL9P_MTIME,
+ .file_size = 0,
+ .file_name = lib9p_str(self->name),
+ .file_owner_uid = lib9p_str("root"),
+ .file_owner_gid = lib9p_str("root"),
+ .file_last_modified_uid = lib9p_str("root"),
+ .file_extension = lib9p_str(NULL),
+ .file_owner_n_uid = 0,
+ .file_owner_n_gid = 0,
+ .file_last_modified_n_uid = 0,
+ };
+}
+static void shutdown_file_wstat(struct shutdown_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_stat) {
+ assert(self);
+ assert(ctx);
+ lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot wstat API file");
+}
+static void shutdown_file_remove(struct shutdown_file *self, struct lib9p_srv_ctx *ctx) {
+ assert(self);
+ assert(ctx);
+ lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot remove API file");
+}
+
+LIB9P_SRV_NOTDIR(struct shutdown_file, shutdown_file)
+
+static lo_interface lib9p_srv_fio shutdown_file_fopen(struct shutdown_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) {
+ assert(self);
+ assert(ctx);
+ return lo_box_shutdown_file_as_lib9p_srv_fio(self);
+}
+
+/* srv_fio ********************************************************************/
+
+static void shutdown_file_iofree(struct shutdown_file *self) {
+ assert(self);
+}
+
+static uint32_t shutdown_file_iounit(struct shutdown_file *self) {
+ assert(self);
+ return 0;
+}
+
+static uint32_t shutdown_file_pwrite(struct shutdown_file *self, struct lib9p_srv_ctx *ctx, void *buf, uint32_t byte_count, uint64_t LM_UNUSED(offset)) {
+ assert(self);
+ assert(ctx);
+ assert(buf);
+ if (byte_count == 0)
+ return 0;
+ for (size_t i = 0; i < self->nlisteners; i++)
+ LO_CALL(lo_box_hostnet_tcplist_as_net_stream_listener(&self->listeners[i]), close);
+ return byte_count;
+}
+static void shutdown_file_pread(struct shutdown_file *LM_UNUSED(self), struct lib9p_srv_ctx *LM_UNUSED(ctx),
+ uint32_t LM_UNUSED(byte_count), uint64_t LM_UNUSED(byte_offset),
+ struct iovec *LM_UNUSED(ret)) {
+ assert_notreached("not readable");
+}
diff --git a/lib9p/tests/test_server/fs_shutdown.h b/lib9p/tests/test_server/fs_shutdown.h
new file mode 100644
index 0000000..65956db
--- /dev/null
+++ b/lib9p/tests/test_server/fs_shutdown.h
@@ -0,0 +1,23 @@
+/* lib9p/tests/test_server/fs_shutdown.h - /shutdown API endpoint
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIB9P_TESTS_TEST_SERVER_FS_SHUTDOWN_H_
+#define _LIB9P_TESTS_TEST_SERVER_FS_SHUTDOWN_H_
+
+#include <util9p/static.h>
+#include <libhw/host_net.h>
+
+struct shutdown_file {
+ char *name;
+ uint64_t pathnum;
+
+ struct hostnet_tcp_listener *listeners;
+ size_t nlisteners;
+};
+LO_IMPLEMENTATION_H(lib9p_srv_file, struct shutdown_file, shutdown_file);
+#define lo_box_shutdown_file_as_lib9p_srv_file(obj) util9p_box(shutdown_file, obj)
+
+#endif /* _LIB9P_TESTS_TEST_SERVER_FS_SHUTDOWN_H_ */
diff --git a/lib9p/tests/test_server/fs_slowread.c b/lib9p/tests/test_server/fs_slowread.c
new file mode 100644
index 0000000..520edd2
--- /dev/null
+++ b/lib9p/tests/test_server/fs_slowread.c
@@ -0,0 +1,101 @@
+/* lib9p/tests/test_server/fs_slowread.c - slowread API endpoint
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include "fs_slowread.h"
+
+LO_IMPLEMENTATION_C(lib9p_srv_file, struct slowread_file, slowread_file, static);
+
+LO_IMPLEMENTATION_H(lib9p_srv_fio, struct slowread_file, slowread_file);
+LO_IMPLEMENTATION_C(lib9p_srv_fio, struct slowread_file, slowread_file, static);
+
+/* srv_file *******************************************************************/
+
+static void slowread_file_free(struct slowread_file *self) {
+ assert(self);
+}
+static struct lib9p_qid slowread_file_qid(struct slowread_file *self) {
+ assert(self);
+ return (struct lib9p_qid){
+ .type = LIB9P_QT_FILE,
+ .vers = 1,
+ .path = self->pathnum,
+ };
+}
+
+static struct lib9p_stat slowread_file_stat(struct slowread_file *self, struct lib9p_srv_ctx *ctx) {
+ assert(self);
+ assert(ctx);
+ return (struct lib9p_stat){
+ .kern_type = 0,
+ .kern_dev = 0,
+ .file_qid = slowread_file_qid(self),
+ .file_mode = 0444,
+ .file_atime = UTIL9P_ATIME,
+ .file_mtime = UTIL9P_MTIME,
+ .file_size = 6,
+ .file_name = lib9p_str(self->name),
+ .file_owner_uid = lib9p_str("root"),
+ .file_owner_gid = lib9p_str("root"),
+ .file_last_modified_uid = lib9p_str("root"),
+ .file_extension = lib9p_str(NULL),
+ .file_owner_n_uid = 0,
+ .file_owner_n_gid = 0,
+ .file_last_modified_n_uid = 0,
+ };
+}
+static void slowread_file_wstat(struct slowread_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_stat) {
+ assert(self);
+ assert(ctx);
+ lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot wstat API file");
+}
+static void slowread_file_remove(struct slowread_file *self, struct lib9p_srv_ctx *ctx) {
+ assert(self);
+ assert(ctx);
+ lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot remove API file");
+}
+
+LIB9P_SRV_NOTDIR(struct slowread_file, slowread_file)
+
+static lo_interface lib9p_srv_fio slowread_file_fopen(struct slowread_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) {
+ assert(self);
+ assert(ctx);
+ return lo_box_slowread_file_as_lib9p_srv_fio(self);
+}
+
+/* srv_fio ********************************************************************/
+
+static void slowread_file_iofree(struct slowread_file *self) {
+ assert(self);
+}
+
+static uint32_t slowread_file_iounit(struct slowread_file *self) {
+ assert(self);
+ return 0;
+}
+
+static uint32_t slowread_file_pwrite(struct slowread_file *LM_UNUSED(self),
+ struct lib9p_srv_ctx *LM_UNUSED(ctx),
+ void *LM_UNUSED(buf), uint32_t LM_UNUSED(byte_count),
+ uint64_t LM_UNUSED(offset)) {
+ assert_notreached("not writable");
+}
+static void slowread_file_pread(struct slowread_file *self, struct lib9p_srv_ctx *ctx,
+ uint32_t byte_count, uint64_t LM_UNUSED(byte_offset),
+ struct iovec *ret) {
+ assert(self);
+ assert(ctx);
+ assert(ret);
+
+ while (!lib9p_srv_flush_requested(ctx))
+ cr_yield();
+ if (self->flushable)
+ lib9p_srv_acknowledge_flush(ctx);
+ else
+ *ret = (struct iovec){
+ .iov_base = "Sloth\n",
+ .iov_len = 6 < byte_count ? 6 : byte_count,
+ };
+}
diff --git a/lib9p/tests/test_server/fs_slowread.h b/lib9p/tests/test_server/fs_slowread.h
new file mode 100644
index 0000000..ef4b65f
--- /dev/null
+++ b/lib9p/tests/test_server/fs_slowread.h
@@ -0,0 +1,22 @@
+/* lib9p/tests/test_server/fs_slowread.h - slowread API endpoint
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIB9P_TESTS_TEST_SERVER_FS_SLOWREAD_H_
+#define _LIB9P_TESTS_TEST_SERVER_FS_SLOWREAD_H_
+
+#include <util9p/static.h>
+#include <libhw/host_net.h>
+
+struct slowread_file {
+ char *name;
+ uint64_t pathnum;
+
+ bool flushable;
+};
+LO_IMPLEMENTATION_H(lib9p_srv_file, struct slowread_file, slowread_file);
+#define lo_box_slowread_file_as_lib9p_srv_file(obj) util9p_box(slowread_file, obj)
+
+#endif /* _LIB9P_TESTS_TEST_SERVER_FS_SLOWREAD_H_ */
diff --git a/lib9p/tests/test_server/main.c b/lib9p/tests/test_server/main.c
new file mode 100644
index 0000000..2743629
--- /dev/null
+++ b/lib9p/tests/test_server/main.c
@@ -0,0 +1,154 @@
+/* lib9p/tests/test_server/main.c - Main entry point for test 9P server
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <error.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h> /* for atoi() */
+
+#include <lib9p/srv.h>
+#include <libcr/coroutine.h>
+#include <libhw/generic/net.h>
+#include <libhw/generic/alarmclock.h>
+#include <libhw/host_alarmclock.h>
+#include <libhw/host_net.h>
+#include <libmisc/macro.h>
+#include <util9p/static.h>
+
+#include "static.h"
+#include "fs_shutdown.h"
+#include "fs_slowread.h"
+
+/* configuration **************************************************************/
+
+#include "config.h"
+
+#ifndef CONFIG_SRV9P_NUM_CONNS
+ #error config.h must define CONFIG_SRV9P_NUM_CONNS
+#endif
+
+/* globals ********************************************************************/
+
+static lo_interface lib9p_srv_file get_root(struct lib9p_srv_ctx *, struct lib9p_s);
+
+const char *hexdig = "0123456789abcdef";
+
+struct {
+ uint16_t port;
+ struct hostnet_tcp_listener listeners[CONFIG_SRV9P_NUM_CONNS];
+ struct lib9p_srv srv;
+ FILE *logstream;
+} globals = {
+ .srv = (struct lib9p_srv){
+ .rootdir = get_root,
+ },
+};
+
+/* file tree ******************************************************************/
+
+#define STATIC_FILE(N, STRNAME, SYMNAME) \
+ UTIL9P_STATIC_FILE(N, STRNAME, \
+ .data_start = _binary_static_##SYMNAME##_start, \
+ .data_end = _binary_static_##SYMNAME##_end)
+#define STATIC_DIR(N, STRNAME, ...) \
+ UTIL9P_STATIC_DIR(N, STRNAME, __VA_ARGS__)
+
+#define API_FILE(N, STRNAME, SYMNAME, ...) \
+ lo_box_##SYMNAME##_file_as_lib9p_srv_file(&((struct SYMNAME##_file){ \
+ .name = STRNAME, \
+ .pathnum = N \
+ __VA_OPT__(,) __VA_ARGS__ \
+ }))
+
+struct lib9p_srv_file root =
+ STATIC_DIR(1, "",
+ STATIC_DIR(2, "Documentation",
+ STATIC_FILE(3, "x", Documentation_x_txt),
+ ),
+ STATIC_FILE(4, "README.md", README_md),
+ API_FILE(5, "shutdown", shutdown,
+ .listeners = globals.listeners,
+ .nlisteners = LM_ARRAY_LEN(globals.listeners)),
+ API_FILE(6, "slowread", slowread,
+ .flushable = false),
+ API_FILE(7, "slowread-flushable", slowread,
+ .flushable = true),
+ );
+
+static lo_interface lib9p_srv_file get_root(struct lib9p_srv_ctx *LM_UNUSED(ctx), struct lib9p_s LM_UNUSED(treename)) {
+ return root;
+}
+
+/* main ***********************************************************************/
+
+static COROUTINE read_cr(void *_i) {
+ int i = *((int *)_i);
+ cr_begin();
+
+ hostnet_tcp_listener_init(&globals.listeners[i], globals.port);
+
+ lib9p_srv_read_cr(&globals.srv, lo_box_hostnet_tcplist_as_net_stream_listener(&globals.listeners[i]));
+
+ cr_end();
+}
+
+static COROUTINE init_cr(void *) {
+ cr_begin();
+
+ sleep_for_ms(1);
+
+ for (int i = 0; i < CONFIG_SRV9P_NUM_CONNS; i++) {
+ char name[] = {'r', 'e', 'a', 'd', '-', hexdig[i], '\0'};
+ if (!coroutine_add(name, read_cr, &i))
+ error(1, 0, "coroutine_add(read_cr, &i)");
+ }
+ for (int i = 0; i < 2*CONFIG_SRV9P_NUM_CONNS; i++) {
+ char name[] = {'w', 'r', 'i', 't', 'e', '-', hexdig[i], '\0'};
+ if (!coroutine_add(name, lib9p_srv_write_cr, &globals.srv))
+ error(1, 0, "coroutine_add(lib9p_srv_write_cr, &globals.srv)");
+ }
+
+ cr_exit();
+}
+
+static void log_fct(char character, void *_stream) {
+ FILE *stream = _stream;
+ putc(character, stream);
+ putchar(character);
+}
+
+static void log_msg(struct lib9p_srv_ctx *ctx, enum lib9p_msg_type typ, void *hostmsg) {
+ /* It sucks that %v trips -Wformat and -Wformat-extra-args
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47781 */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat"
+#pragma GCC diagnostic ignored "-Wformat-extra-args"
+ fmt_fctprintf(log_fct, globals.logstream,
+ "%c %v\n", typ % 2 ? '<' : '>',
+ lo_box_lib9p_msg_as_fmt_formatter(&ctx->basectx, typ, hostmsg));
+#pragma GCC diagnostic pop
+ fflush(globals.logstream);
+}
+
+int main(int argc, char *argv[]) {
+ if (argc != 3)
+ error(2, 0, "usage: %s PORT_NUMBER LOGFILE", argv[0]);
+
+ globals.port = atoi(argv[1]);
+ globals.logstream = fopen(argv[2], "w");
+ if (!globals.logstream)
+ error(2, errno, "fopen");
+ globals.srv.msglog = log_msg;
+
+ struct hostclock clock_monotonic = {
+ .clock_id = CLOCK_MONOTONIC,
+ };
+ bootclock = lo_box_hostclock_as_alarmclock(&clock_monotonic);
+ coroutine_add("init", init_cr, NULL);
+ coroutine_main();
+ fclose(globals.logstream);
+ return 0;
+}
diff --git a/lib9p/tests/test_server/static/Documentation/x.txt b/lib9p/tests/test_server/static/Documentation/x.txt
new file mode 100644
index 0000000..e85ee4e
--- /dev/null
+++ b/lib9p/tests/test_server/static/Documentation/x.txt
@@ -0,0 +1,7 @@
+<!--
+ Documentation/x.txt - test static file
+
+ Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ SPDX-License-Identifier: AGPL-3.0-or-later
+-->
+foo
diff --git a/lib9p/tests/test_server/static/README.md b/lib9p/tests/test_server/static/README.md
new file mode 100644
index 0000000..c2d88ed
--- /dev/null
+++ b/lib9p/tests/test_server/static/README.md
@@ -0,0 +1,7 @@
+<!--
+ README.md - test static file
+
+ Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ SPDX-License-Identifier: AGPL-3.0-or-later
+-->
+Hello, world!
diff --git a/lib9p/tests/testclient-p9p b/lib9p/tests/testclient-p9p
new file mode 100755
index 0000000..81a7e50
--- /dev/null
+++ b/lib9p/tests/testclient-p9p
@@ -0,0 +1,61 @@
+#!/usr/bin/env bash
+# lib9p/tests/testclient-p9p - Test the 9P `test_server` against Plan 9 Port's `9p` utility
+#
+# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+set -euE -o pipefail
+
+if [[ $# != 1 ]]; then
+ echo >&2 "Usage: $0 SERVER_PORT"
+ echo >&2 "Usage: ./runtest $0 EXPLOG"
+ exit 2
+fi
+
+expect_lines() (
+ { set +x; } &>/dev/null
+ printf >&2 '+ diff -u expected.txt actual.txt\n'
+ diff -u <(printf '%s\n' "$@") <(printf '%s\n' "$out")
+)
+
+set -x
+client=(9p -a "localhost:${1}")
+
+out=$("${client[@]}" ls -l '')
+expect_lines \
+ 'd-r-xr-xr-x M 0 root root 0 Oct 7 2024 Documentation' \
+ '--r--r--r-- M 0 root root 166 Oct 7 2024 README.md' \
+ '---w--w--w- M 0 root root 0 Oct 7 2024 shutdown' \
+ '--r--r--r-- M 0 root root 6 Oct 7 2024 slowread' \
+ '--r--r--r-- M 0 root root 6 Oct 7 2024 slowread-flushable'
+
+out=$("${client[@]}" ls -l 'Documentation/')
+expect_lines \
+ '--r--r--r-- M 0 root root 166 Oct 7 2024 x'
+
+out=$("${client[@]}" read 'README.md')
+expect_lines \
+ '<!--' \
+ ' README.md - test static file' \
+ '' \
+ ' Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>' \
+ ' SPDX-License-Identifier: AGPL-3.0-or-later' \
+ '-->' \
+ 'Hello, world!'
+
+out=$("${client[@]}" read 'Documentation/x')
+expect_lines \
+ '<!--' \
+ ' Documentation/x.txt - test static file' \
+ '' \
+ ' Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>' \
+ ' SPDX-License-Identifier: AGPL-3.0-or-later' \
+ '-->' \
+ 'foo'
+
+out=$("${client[@]}" stat 'Documentation/x')
+expect_lines \
+ "'x' 'root' 'root' 'root' q (0000000000000003 1 ) m 0444 at 1728337905 mt 1728337904 l 166 t 0 d 0"
+
+out=$("${client[@]}" write 'shutdown' <<<1)
+expect_lines ''
diff --git a/lib9p/tests/testclient-p9p.explog b/lib9p/tests/testclient-p9p.explog
new file mode 100644
index 0000000..3bfb0b0
--- /dev/null
+++ b/lib9p/tests/testclient-p9p.explog
@@ -0,0 +1,106 @@
+# lib9p/tests/testclient-p9p.explog - Expected 9P logfile of testclient-p9p
+#
+# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" }
+< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" }
+> Tauth { tag=0 afid=0 uname="lukeshu" aname="" n_uid=0 }
+< Rerror { tag=0 errstr="authentication not required" errnum=95 }
+> Tattach { tag=0 fid=0 afid=NOFID uname="lukeshu" aname="" n_uid=0 }
+< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
+> Twalk { tag=0 fid=0 newfid=1 nwname=0 wname=[ ] }
+< Rwalk { tag=0 nwqid=0 wqid=[ ] }
+> Tstat { tag=0 fid=1 }
+< Rstat { tag=0 stat={ kern_type=0 kern_dev=0 file_qid={ type=(DIR) vers=1 path=1 } file_mode=(DIR|0555) file_atime=1728337905 file_mtime=1728337904 file_size=0 file_name="" file_owner_uid="root" file_owner_gid="root" file_last_modified_uid="root" file_extension="" file_owner_n_uid=0 file_owner_n_gid=0 file_last_modified_n_uid=0 } }
+> Tclunk { tag=0 fid=1 }
+< Rclunk { tag=0 }
+> Twalk { tag=0 fid=0 newfid=1 nwname=0 wname=[ ] }
+< Rwalk { tag=0 nwqid=0 wqid=[ ] }
+> Topen { tag=0 fid=1 mode=(MODE_READ) }
+< Ropen { tag=0 qid={ type=(DIR) vers=1 path=1 } iounit=0 }
+> Tread { tag=0 fid=1 offset=0 count=4096 }
+< Rread { tag=0 count=361 data=<bytedata> }
+> Tread { tag=0 fid=1 offset=361 count=4096 }
+< Rread { tag=0 count=0 data="" }
+> Tclunk { tag=0 fid=1 }
+< Rclunk { tag=0 }
+> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" }
+< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" }
+> Tauth { tag=0 afid=0 uname="lukeshu" aname="" n_uid=0 }
+< Rerror { tag=0 errstr="authentication not required" errnum=95 }
+> Tattach { tag=0 fid=0 afid=NOFID uname="lukeshu" aname="" n_uid=0 }
+< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
+> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=["Documentation" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[{ type=(DIR) vers=1 path=2 } ] }
+> Tstat { tag=0 fid=1 }
+< Rstat { tag=0 stat={ kern_type=0 kern_dev=0 file_qid={ type=(DIR) vers=1 path=2 } file_mode=(DIR|0555) file_atime=1728337905 file_mtime=1728337904 file_size=0 file_name="Documentation" file_owner_uid="root" file_owner_gid="root" file_last_modified_uid="root" file_extension="" file_owner_n_uid=0 file_owner_n_gid=0 file_last_modified_n_uid=0 } }
+> Tclunk { tag=0 fid=1 }
+< Rclunk { tag=0 }
+> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=["Documentation" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[{ type=(DIR) vers=1 path=2 } ] }
+> Topen { tag=0 fid=1 mode=(MODE_READ) }
+< Ropen { tag=0 qid={ type=(DIR) vers=1 path=2 } iounit=0 }
+> Tread { tag=0 fid=1 offset=0 count=4096 }
+< Rread { tag=0 count=62 data=<bytedata> }
+> Tread { tag=0 fid=1 offset=62 count=4096 }
+< Rread { tag=0 count=0 data="" }
+> Tclunk { tag=0 fid=1 }
+< Rclunk { tag=0 }
+> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" }
+< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" }
+> Tauth { tag=0 afid=0 uname="lukeshu" aname="" n_uid=0 }
+< Rerror { tag=0 errstr="authentication not required" errnum=95 }
+> Tattach { tag=0 fid=0 afid=NOFID uname="lukeshu" aname="" n_uid=0 }
+< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
+> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=["README.md" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[{ type=(0) vers=1 path=4 } ] }
+> Topen { tag=0 fid=1 mode=(MODE_READ) }
+< Ropen { tag=0 qid={ type=(0) vers=1 path=4 } iounit=0 }
+> Tread { tag=0 fid=1 offset=0 count=4096 }
+< Rread { tag=0 count=166 data="<!--\n README.md - test static file\n\n Copyright ("... }
+> Tread { tag=0 fid=1 offset=166 count=4096 }
+< Rread { tag=0 count=0 data="" }
+> Tclunk { tag=0 fid=1 }
+< Rclunk { tag=0 }
+> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" }
+< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" }
+> Tauth { tag=0 afid=0 uname="lukeshu" aname="" n_uid=0 }
+< Rerror { tag=0 errstr="authentication not required" errnum=95 }
+> Tattach { tag=0 fid=0 afid=NOFID uname="lukeshu" aname="" n_uid=0 }
+< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
+> Twalk { tag=0 fid=0 newfid=1 nwname=2 wname=["Documentation", "x" ] }
+< Rwalk { tag=0 nwqid=2 wqid=[{ type=(DIR) vers=1 path=2 }, { type=(0) vers=1 path=3 } ] }
+> Topen { tag=0 fid=1 mode=(MODE_READ) }
+< Ropen { tag=0 qid={ type=(0) vers=1 path=3 } iounit=0 }
+> Tread { tag=0 fid=1 offset=0 count=4096 }
+< Rread { tag=0 count=166 data="<!--\n Documentation/x.txt - test static file\n\n C"... }
+> Tread { tag=0 fid=1 offset=166 count=4096 }
+< Rread { tag=0 count=0 data="" }
+> Tclunk { tag=0 fid=1 }
+< Rclunk { tag=0 }
+> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" }
+< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" }
+> Tauth { tag=0 afid=0 uname="lukeshu" aname="" n_uid=0 }
+< Rerror { tag=0 errstr="authentication not required" errnum=95 }
+> Tattach { tag=0 fid=0 afid=NOFID uname="lukeshu" aname="" n_uid=0 }
+< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
+> Twalk { tag=0 fid=0 newfid=1 nwname=2 wname=["Documentation", "x" ] }
+< Rwalk { tag=0 nwqid=2 wqid=[{ type=(DIR) vers=1 path=2 }, { type=(0) vers=1 path=3 } ] }
+> Tstat { tag=0 fid=1 }
+< Rstat { tag=0 stat={ kern_type=0 kern_dev=0 file_qid={ type=(0) vers=1 path=3 } file_mode=(0444) file_atime=1728337905 file_mtime=1728337904 file_size=166 file_name="x" file_owner_uid="root" file_owner_gid="root" file_last_modified_uid="root" file_extension="" file_owner_n_uid=0 file_owner_n_gid=0 file_last_modified_n_uid=0 } }
+> Tclunk { tag=0 fid=1 }
+< Rclunk { tag=0 }
+> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" }
+< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" }
+> Tauth { tag=0 afid=0 uname="lukeshu" aname="" n_uid=0 }
+< Rerror { tag=0 errstr="authentication not required" errnum=95 }
+> Tattach { tag=0 fid=0 afid=NOFID uname="lukeshu" aname="" n_uid=0 }
+< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
+> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=["shutdown" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[{ type=(0) vers=1 path=5 } ] }
+> Topen { tag=0 fid=1 mode=(TRUNC|MODE_WRITE) }
+< Ropen { tag=0 qid={ type=(0) vers=1 path=5 } iounit=0 }
+> Twrite { tag=0 fid=1 offset=0 count=2 data="1\n" }
+< Rwrite { tag=0 count=2 }
+> Tclunk { tag=0 fid=1 }
+< Rclunk { tag=0 }
diff --git a/lib9p/tests/testclient-sess.c b/lib9p/tests/testclient-sess.c
new file mode 100644
index 0000000..423dc2c
--- /dev/null
+++ b/lib9p/tests/testclient-sess.c
@@ -0,0 +1,144 @@
+/* lib9p/tests/testclient-sess.c - Test the 9P `test_server`'s sessions
+ *
+ * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <arpa/inet.h> /* for htons(), inet_addr() */
+#include <errno.h>
+#include <error.h>
+#include <netinet/in.h> /* for struct sockaddr{,_in} */
+#include <stdlib.h> /* for atoi() */
+#include <sys/socket.h> /* for socket(), connect() */
+#include <sys/uio.h> /* for writev() */
+#include <unistd.h> /* for read() */
+
+#include <libmisc/assert.h>
+#include <libmisc/endian.h>
+#include <lib9p/9p.h>
+
+#define MAX_MSG_SIZE (8*1024)
+
+static void _send9p(int fd, struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body) {
+ struct lib9p_Tmsg_send_buf buf;
+ bool err = lib9p_Tmsg_marshal(ctx, typ, body, &buf);
+ assert(!err);
+ size_t exp = 0;
+ for (size_t i = 0; i < buf.iov_cnt; i++)
+ exp += buf.iov[i].iov_len;
+ ssize_t act = writev(fd, buf.iov, buf.iov_cnt);
+ if (act < 0)
+ error(1, errno, "writev");
+ assert((size_t)act == exp);
+}
+
+#define send9p(typ, ...) _send9p(fd, &ctx, LIB9P_TYP_##typ, &((struct lib9p_msg_##typ){ __VA_ARGS__ }))
+
+static void _recv9p(int fd) {
+ uint8_t buf[MAX_MSG_SIZE];
+ size_t goal = 4;
+ size_t done = 0;
+ while (done < goal) {
+ ssize_t n = read(fd, &buf[done], goal-done);
+ if (n < 0)
+ error(1, errno, "read");
+ done += n;
+ }
+ goal = uint32le_decode(buf);
+ assert(goal <= MAX_MSG_SIZE);
+ while (done < goal) {
+ ssize_t n = read(fd, &buf[done], goal-done);
+ if (n < 0)
+ error(1, errno, "read");
+ done += n;
+ }
+}
+
+#define recv9p() _recv9p(fd)
+
+int main(int argc, char *argv[]) {
+ if (argc != 2)
+ error(2, 0, "Usage: %s SERVER_PORT", argv[0]);
+ uint16_t server_port = atoi(argv[1]);
+
+ union {
+ struct sockaddr gen;
+ struct sockaddr_in in;
+ } server_addr = {};
+ server_addr.in.sin_family = AF_INET;
+ server_addr.in.sin_addr.s_addr = inet_addr("127.0.0.1");
+ server_addr.in.sin_port = htons(server_port);
+
+ int fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (fd < 0)
+ error(1, errno, "socket");
+ if (connect(fd, &server_addr.gen, sizeof(server_addr)) < 0)
+ error(1, errno, "connect");
+
+ struct lib9p_ctx ctx = {
+ .max_msg_size = 16*1024,
+ };
+
+ struct lib9p_s wname[1];
+
+ /* numeric downgrade, unknown ext *************************************/
+ send9p(Tversion, .tag=0, .max_msg_size=57, .version=lib9p_str("9P2025.x"));
+ recv9p(); /* Rversion */
+ ctx.version = LIB9P_VER_9P2000;
+
+ /* numeric downgrade, known ext ***************************************/
+ send9p(Tversion, .tag=0, .max_msg_size=57, .version=lib9p_str("9P2025.u"));
+ recv9p(); /* Rversion */
+ ctx.version = LIB9P_VER_9P2000_u;
+
+ /* ext version ********************************************************/
+ send9p(Tversion, .tag=0, .max_msg_size=57, .version=lib9p_str("9P2000.u"));
+ recv9p(); /* Rversion */
+ ctx.version = LIB9P_VER_9P2000_u;
+
+ /* main session *******************************************************/
+ send9p(Tversion, .tag=0, .max_msg_size=(8*1024), .version=lib9p_str("9P2000"));
+ recv9p(); /* Rversion */
+ ctx.version = LIB9P_VER_9P2000;
+ send9p(Tattach, .tag=0, .fid=0, .afid=LIB9P_FID_NOFID, .uname=lib9p_str("nobody"), .aname=lib9p_str(""));
+ recv9p(); /* Rattach */
+
+ /* flush, but original response comes back first */
+ wname[0] = lib9p_str("slowread"); send9p(Twalk, .tag=0, .fid=0, .newfid=1, .nwname=1, .wname=wname);
+ recv9p(); /* Rwalk */
+ send9p(Topen, .tag=0, .fid=1, .mode=LIB9P_O_MODE_READ);
+ recv9p(); /* Ropen */
+ send9p(Tread, .tag=1, .fid=1, .offset=0, .count=6);
+ send9p(Tflush, .tag=2, .oldtag=1);
+ recv9p(); /* Rread */
+ recv9p(); /* Rflush */
+
+ /* flush, original request is aborted with error */
+ wname[0] = lib9p_str("slowread-flushable"); send9p(Twalk, .tag=1, .fid=0, .newfid=2, .nwname=1, .wname=wname);
+ recv9p(); /* Rwalk */
+ send9p(Topen, .tag=0, .fid=2, .mode=LIB9P_O_MODE_READ);
+ recv9p(); /* Ropen */
+ send9p(Tread, .tag=1, .fid=2, .offset=0, .count=6);
+ send9p(Tflush, .tag=2, .oldtag=1);
+ recv9p(); /* Rerror */
+ recv9p(); /* Rflush */
+
+ /* flush, unknown tag */
+ send9p(Tflush, .tag=0, .oldtag=99);
+ recv9p(); /* Rflush */
+
+ /* shutdown ***********************************************************/
+ send9p(Tversion, .tag=0, .max_msg_size=(8*1024), .version=lib9p_str("9P2000"));
+ recv9p(); /* Rversion */
+ ctx.version = LIB9P_VER_9P2000;
+ send9p(Tattach, .tag=0, .fid=0, .afid=LIB9P_FID_NOFID, .uname=lib9p_str("nobody"), .aname=lib9p_str(""));
+ recv9p(); /* Rattach */
+ /* check the newfid==fid case */
+ wname[0] = lib9p_str("shutdown"); send9p(Twalk, .tag=0, .fid=0, .newfid=0, .nwname=1, .wname=wname);
+ recv9p(); /* Rwalk */
+ send9p(Topen, .tag=0, .fid=0, .mode=LIB9P_O_MODE_WRITE);
+ recv9p(); /* Ropen */
+ send9p(Twrite, .tag=0, .fid=0, .offset=0, .count=2, .data="1\n");
+ recv9p(); /* Rwrite */
+ return 0;
+}
diff --git a/lib9p/tests/testclient-sess.explog b/lib9p/tests/testclient-sess.explog
new file mode 100644
index 0000000..b1f3085
--- /dev/null
+++ b/lib9p/tests/testclient-sess.explog
@@ -0,0 +1,58 @@
+# lib9p/tests/testclient-sess.explog - Expected 9P logfile of testclient-sess.c
+#
+# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+# numeric downgrade, unknown ext ###############################################
+> Tversion { tag=0 max_msg_size=57 version="9P2025.x" }
+< Rversion { tag=0 max_msg_size=57 version="9P2000" }
+
+# numeric downgrade, known ext #################################################
+> Tversion { tag=0 max_msg_size=57 version="9P2025.u" }
+< Rversion { tag=0 max_msg_size=57 version="9P2000.u" }
+
+# ext version ##################################################################
+> Tversion { tag=0 max_msg_size=57 version="9P2000.u" }
+< Rversion { tag=0 max_msg_size=57 version="9P2000.u" }
+
+# main session #################################################################
+> Tversion { tag=0 max_msg_size=8192 version="9P2000" }
+< Rversion { tag=0 max_msg_size=4120 version="9P2000" }
+> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" n_uid=0 }
+< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
+
+# flush, but original response comes back first
+> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=["slowread" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[{ type=(0) vers=1 path=6 } ] }
+> Topen { tag=0 fid=1 mode=(MODE_READ) }
+< Ropen { tag=0 qid={ type=(0) vers=1 path=6 } iounit=0 }
+> Tread { tag=1 fid=1 offset=0 count=6 }
+> Tflush { tag=2 oldtag=1 }
+< Rread { tag=1 count=6 data="Sloth\n" }
+< Rflush { tag=2 }
+
+# flush, succeeds
+> Twalk { tag=1 fid=0 newfid=2 nwname=1 wname=["slowread-flushable" ] }
+< Rwalk { tag=1 nwqid=1 wqid=[{ type=(0) vers=1 path=7 } ] }
+> Topen { tag=0 fid=2 mode=(MODE_READ) }
+< Ropen { tag=0 qid={ type=(0) vers=1 path=7 } iounit=0 }
+> Tread { tag=1 fid=2 offset=0 count=6 }
+> Tflush { tag=2 oldtag=1 }
+< Rflush { tag=2 }
+< Rerror { tag=1 errstr="request canceled by flush" errnum=125 }
+
+# flush, unknown tag
+> Tflush { tag=0 oldtag=99 }
+< Rflush { tag=0 }
+
+# shutdown #####################################################################
+> Tversion { tag=0 max_msg_size=8192 version="9P2000" }
+< Rversion { tag=0 max_msg_size=4120 version="9P2000" }
+> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" n_uid=0 }
+< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
+> Twalk { tag=0 fid=0 newfid=0 nwname=1 wname=["shutdown" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[{ type=(0) vers=1 path=5 } ] }
+> Topen { tag=0 fid=0 mode=(MODE_WRITE) }
+< Ropen { tag=0 qid={ type=(0) vers=1 path=5 } iounit=0 }
+> Twrite { tag=0 fid=0 offset=0 count=2 data="1\n" }
+< Rwrite { tag=0 count=2 }
diff --git a/lib9p/utf8.h b/lib9p/utf8.h
new file mode 100644
index 0000000..5ffd674
--- /dev/null
+++ b/lib9p/utf8.h
@@ -0,0 +1,34 @@
+/* lib9p/utf8.h - Internal UTF-8 validation
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIB9P_UTF8_H_
+#define _LIB9P_UTF8_H_
+
+static inline bool _is_valid_utf8(uint8_t *str, size_t len, bool forbid_nul) {
+ uint32_t ch;
+ uint8_t chlen;
+ assert(str);
+ for (size_t pos = 0; pos < len;) {
+ if ((str[pos] & 0b10000000) == 0b00000000) { ch = str[pos] & 0b01111111; chlen = 1; }
+ else if ((str[pos] & 0b11100000) == 0b11000000) { ch = str[pos] & 0b00011111; chlen = 2; }
+ else if ((str[pos] & 0b11110000) == 0b11100000) { ch = str[pos] & 0b00001111; chlen = 3; }
+ else if ((str[pos] & 0b11111000) == 0b11110000) { ch = str[pos] & 0b00000111; chlen = 4; }
+ else return false;
+ if ((ch == 0 && (chlen != 1 || forbid_nul)) || pos + chlen > len) return false;
+ for (uint8_t i = 1; i < chlen; i++) {
+ if ((str[pos+i] & 0b11000000) != 0b10000000) return false;
+ ch = (ch << 6) | (str[pos+i] & 0b00111111);
+ }
+ if (ch > 0x10FFFF) return false;
+ pos += chlen;
+ }
+ return true;
+}
+
+#define is_valid_utf8(str, len) _is_valid_utf8(str, len, false)
+#define is_valid_utf8_without_nul(str, len) _is_valid_utf8(str, len, true)
+
+#endif /* _LIB9P_UTF8_H_ */