summaryrefslogtreecommitdiff
path: root/lib9p/9p.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib9p/9p.c')
-rw-r--r--lib9p/9p.c164
1 files changed, 39 insertions, 125 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;
-}