diff options
Diffstat (limited to 'lib9p')
-rw-r--r-- | lib9p/types.c | 6 | ||||
-rwxr-xr-x | lib9p/types.gen | 111 |
2 files changed, 65 insertions, 52 deletions
diff --git a/lib9p/types.c b/lib9p/types.c index 071e3c8..f4718b6 100644 --- a/lib9p/types.c +++ b/lib9p/types.c @@ -805,6 +805,12 @@ struct _vtable_version _lib9p_vtables[LIB9P_VER_NUM] = { .unmarshal = (_unmarshal_fn_t)unmarshal_Rversion, .marshal = (_marshal_fn_t)marshal_Rversion, }, + [LIB9P_TYP_Rerror] = { + .unmarshal_basesize = sizeof(struct lib9p_msg_Rerror), + .unmarshal_extrasize = checksize_Rerror, + .unmarshal = (_unmarshal_fn_t)unmarshal_Rerror, + .marshal = (_marshal_fn_t)marshal_Rerror, + }, }}, [LIB9P_VER_9P2000] = { .msgs = { [LIB9P_TYP_Tversion] = { diff --git a/lib9p/types.gen b/lib9p/types.gen index 44eebbe..70f4697 100755 --- a/lib9p/types.gen +++ b/lib9p/types.gen @@ -10,6 +10,10 @@ import os.path import re from typing import Callable +# This strives to be "general-purpose" in that it just acts on the +# *.txt inputs; but (unfortunately?) there are a few special-cases in +# this script, marked with "SPECIAL". + # Parse *.txt ################################################################## @@ -392,54 +396,54 @@ static inline bool _checksize_list(struct _checksize_ctx *ctx, ret += "}\n" continue + if struct.name == "d": # SPECIAL + # Optimize... maybe the compiler could figure out to do + # this, but let's make it obvious. + ret += "\n" + ret += "\tuint32_t base_offset = ctx->net_offset;\n" + ret += "\tif (checksize_4(ctx))\n" + ret += "\t\treturn true;\n" + ret += "\tuint32_t len = decode_u32le(&ctx->net_bytes[base_offset]);\n" + ret += "\treturn _checksize_net(ctx, len) || _checksize_host(ctx, len);\n" + ret += "}\n" + continue + if struct.name == "s": # SPECIAL + # Add an extra nul-byte on the host, and validate UTF-8 + # (also, similar optimization to "d"). + ret += "\n" + ret += "\tuint32_t base_offset = ctx->net_offset;\n" + ret += "\tif (checksize_2(ctx))\n" + ret += "\t\treturn true;\n" + ret += "\tuint16_t len = decode_u16le(&ctx->net_bytes[base_offset]);\n" + ret += "\tif (_checksize_net(ctx, len) || _checksize_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 + prefix0 = "\treturn " prefix1 = "\t || " - match struct.name: - case "d": - # Optimize... maybe the compiler could figure out to do - # this, but let's make it obvious. - ret += "\n" - ret += "\tuint32_t base_offset = ctx->net_offset;\n" - ret += "\tif (checksize_4(ctx))\n" - ret += "\t\treturn true;\n" - ret += "\tuint32_t len = decode_u32le(&ctx->net_bytes[base_offset]);\n" - ret += ( - "\treturn _checksize_net(ctx, len) || _checksize_host(ctx, len);\n" - ) - ret += "}\n" - case "s": - # Add an extra nul-byte on the host, and validate - # UTF-8 (also, similar optimization to "d"). - ret += "\n" - ret += "\tuint32_t base_offset = ctx->net_offset;\n" - ret += "\tif (checksize_2(ctx))\n" - ret += "\t\treturn true;\n" - ret += "\tuint16_t len = decode_u16le(&ctx->net_bytes[base_offset]);\n" - ret += "\tif (_checksize_net(ctx, len) || _checksize_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" - case _: - struct_versions = struct.members[0].ver - prefix = prefix0 - prev_size: int | None = None - for member in struct.members: - ret += f"\n{prefix}" - if member.ver != struct_versions: - ret += "( " + c_vercond(idprefix, member.ver) + " && " - if member.cnt is not None: - assert prev_size - ret += f"_checksize_list(ctx, decode_u{prev_size*8}le(&ctx->net_bytes[ctx->net_offset-{prev_size}]), checksize_{member.typ.name}, sizeof({c_typename(idprefix, member.typ)}))" - else: - ret += f"checksize_{member.typ.name}(ctx)" - if member.ver != struct_versions: - ret += " )" - prefix = prefix1 - prev_size = member.static_size - ret += ";\n}\n" + struct_versions = struct.members[0].ver + + prefix = prefix0 + prev_size: int | None = None + for member in struct.members: + ret += f"\n{prefix}" + if member.ver != struct_versions: + ret += "( " + c_vercond(idprefix, member.ver) + " && " + if member.cnt is not None: + assert prev_size + ret += f"_checksize_list(ctx, decode_u{prev_size*8}le(&ctx->net_bytes[ctx->net_offset-{prev_size}]), checksize_{member.typ.name}, sizeof({c_typename(idprefix, member.typ)}))" + else: + ret += f"checksize_{member.typ.name}(ctx)" + if member.ver != struct_versions: + ret += " )" + prefix = prefix1 + prev_size = member.static_size + ret += ";\n}\n" # unmarshal_* ############################################################## ret += """ @@ -547,7 +551,7 @@ static inline bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) { ret += "}\n" continue - if struct.name == "Rerror": + if struct.name == "Rerror": # SPECIAL ret += "\n\t/* Truncate the error-string if necessary to avoid returning ERANGE. */" ret += "\n\tif (((uint32_t)val->ename.len) + ctx->ctx->Rerror_overhead > ctx->ctx->max_msg_size)" ret += "\n\t\tval->ename.len = ctx->ctx->max_msg_size - ctx->ctx->Rerror_overhead;" @@ -584,24 +588,27 @@ static inline bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) { ret += f"\t\t\t.unmarshal_extrasize = checksize_{msg.name},\n" ret += f"\t\t\t.unmarshal = (_unmarshal_fn_t)unmarshal_{msg.name},\n" ret += f"\t\t\t.marshal = (_marshal_fn_t)marshal_{msg.name},\n" - ret += "\t\t}" + ret += "\t\t},\n" return ret ret += f""" /* vtables ********************************************************************/ struct _vtable_version _{idprefix}vtables[LIB9P_VER_NUM] = {{ - [{idprefix.upper()}VER_UNINITIALIZED] = {{ .msgs = {{ -{msg_entry(next(msg for msg in structs if msg.name == 'Tversion'))}, -{msg_entry(next(msg for msg in structs if msg.name == 'Rversion'))}, - }}}}, """ + + ret += f"\t[{idprefix.upper()}VER_UNINITIALIZED] = {{ .msgs = {{\n" + for msg in structs: + if msg.name in ["Tversion", "Rversion", "Rerror"]: # SPECIAL + ret += msg_entry(msg) + ret += "\t}},\n" + for ver in sorted(versions): ret += f"\t[{c_verenum(idprefix, ver)}] = {{ .msgs = {{\n" for msg in structs: if ver not in msg.msgver: continue - ret += msg_entry(msg) + ",\n" + ret += msg_entry(msg) ret += "\t}},\n" ret += "};\n" |