/* lib9p/internal.h - TODO * * Copyright (C) 2024-2025 Luke T. Shumaker * SPDX-License-Identifier: AGPL-3.0-or-later */ #ifndef _LIB9P_INTERNAL_H_ #define _LIB9P_INTERNAL_H_ #include /* for size_t */ #include /* for SSIZE_MAX, not set by newlib */ #ifndef SSIZE_MAX #define SSIZE_MAX (SIZE_MAX >> 1) #endif #include #include #include /* 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_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); /* specialized contexts *******************************************************/ struct _validate_ctx { /* input */ struct lib9p_ctx *ctx; uint32_t net_size; uint8_t *net_bytes; /* output */ 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 { /* input */ struct lib9p_ctx *ctx; uint8_t *net_bytes; /* output */ 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 { /* input */ struct lib9p_ctx *ctx; /* output */ size_t net_iov_cnt; struct iovec *net_iov; size_t net_copied_size; uint8_t *net_copied; }; typedef bool (*_marshal_fn_t)(struct _marshal_ctx *ctx, void *host_val); /* tables / exports ***********************************************************/ struct _lib9p_recv_tentry { size_t basesize; _validate_fn_t validate; _unmarshal_fn_t unmarshal; }; struct _lib9p_send_tentry { _marshal_fn_t marshal; }; extern const char *const _lib9p_table_ver_name[LIB9P_VER_NUM]; extern const char *const _lib9p_table_msg_name[LIB9P_VER_NUM][0x100]; extern const uint32_t _lib9p_table_msg_min_size[LIB9P_VER_NUM]; 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]; bool _lib9p_stat_validate(struct _validate_ctx *ctx); void _lib9p_stat_unmarshal(struct _unmarshal_ctx *ctx, struct lib9p_stat *out); bool _lib9p_stat_marshal(struct _marshal_ctx *ctx, struct lib9p_stat *val); /* unmarshal utilities ********************************************************/ 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_INTERNAL_H_ */