1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
/* lib9p/internal.h - TODO
*
* Copyright (C) 2024-2025 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, not set by newlib */
#ifndef SSIZE_MAX
#define SSIZE_MAX (SIZE_MAX >> 1)
#endif
#include <libmisc/endian.h>
#include <libmisc/macro.h>
#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_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_ */
|