diff options
Diffstat (limited to 'lib9p')
-rw-r--r-- | lib9p/9p.c | 29 | ||||
-rw-r--r-- | lib9p/9p.generated.c | 4 | ||||
-rwxr-xr-x | lib9p/idl.gen | 17 | ||||
-rw-r--r-- | lib9p/include/lib9p/9p.generated.h | 8 | ||||
-rw-r--r-- | lib9p/include/lib9p/9p.h | 10 | ||||
-rw-r--r-- | lib9p/include/lib9p/srv.h | 12 | ||||
-rw-r--r-- | lib9p/srv.c | 45 | ||||
-rw-r--r-- | lib9p/tests/test_server/config/config.h | 4 | ||||
-rw-r--r-- | lib9p/tests/test_server/main.c | 2 |
9 files changed, 78 insertions, 53 deletions
@@ -35,6 +35,35 @@ const char *lib9p_msgtype_str(enum lib9p_version ver, enum lib9p_msg_type typ) { return _lib9p_table_msg_name[ver][typ] ?: const_byte_str(typ); } +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) { diff --git a/lib9p/9p.generated.c b/lib9p/9p.generated.c index 29fa4a6..dca9f8b 100644 --- a/lib9p/9p.generated.c +++ b/lib9p/9p.generated.c @@ -382,7 +382,7 @@ LM_ALWAYS_INLINE static bool validate_s(struct _validate_ctx *ctx) { if (validate_2(ctx)) 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)) + if (_validate_size_net(ctx, len) || _validate_size_host(ctx, ((size_t)len))) 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"); @@ -1878,8 +1878,6 @@ LM_ALWAYS_INLINE static void unmarshal_s(struct _unmarshal_ctx *ctx, struct lib9 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'; } #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_u */ diff --git a/lib9p/idl.gen b/lib9p/idl.gen index 4c3103c..b33ea5f 100755 --- a/lib9p/idl.gen +++ b/lib9p/idl.gen @@ -67,9 +67,11 @@ def c_ver_cond(versions: set[str]) -> str: return "( " + (" || ".join(c_ver_cond({v}) for v in sorted(versions))) + " )" -def c_typename(typ: idl.Type) -> str: +def c_typename(typ: idl.Type, parent: idl.Type | None = None) -> str: match typ: case idl.Primitive(): + if typ.value == 1 and parent and parent.name in ["d", "s"]: # SPECIAL + return "[[gnu::nonstring]] char" return f"uint{typ.value*8}_t" case idl.Number(): return f"{idprefix}{typ.name}_t" @@ -279,16 +281,13 @@ enum {idprefix}version {{ continue ret += "\n" - typewidth = max(len(c_typename(m.typ)) for m in typ.members) + typewidth = max(len(c_typename(m.typ, typ)) for m in typ.members) 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 += f"\t{c_typename(member.typ, typ).ljust(typewidth)} {'*' if member.cnt else ' '}{member.name};\n" ret += ifdef_pop(1) ret += "};\n" ret += ifdef_pop(0) @@ -473,7 +472,7 @@ LM_ALWAYS_INLINE static bool _validate_list(struct _validate_ctx *ctx, 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 += "\tif (_validate_size_net(ctx, len) || _validate_size_host(ctx, ((size_t)len)))\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' @@ -622,6 +621,7 @@ LM_ALWAYS_INLINE static void unmarshal_8(struct _unmarshal_ctx *ctx, uint64_t *o 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 + # Special-case is that we cast from `char` to `uint8_t`. 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" @@ -631,9 +631,6 @@ LM_ALWAYS_INLINE static void unmarshal_8(struct _unmarshal_ctx *ctx, uint64_t *o 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) diff --git a/lib9p/include/lib9p/9p.generated.h b/lib9p/include/lib9p/9p.generated.h index 5b98ba8..da4a578 100644 --- a/lib9p/include/lib9p/9p.generated.h +++ b/lib9p/include/lib9p/9p.generated.h @@ -153,15 +153,15 @@ typedef uint32_t lib9p_fid_t; #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_u struct lib9p_d { - uint32_t len; - char *dat; + uint32_t len; + [[gnu::nonstring]] char *dat; }; #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_u */ #if CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_u struct lib9p_s { - uint16_t len; - char *utf8; + uint16_t len; + [[gnu::nonstring]] char *utf8; }; #endif /* CONFIG_9P_ENABLE_9P2000 || CONFIG_9P_ENABLE_9P2000_L || CONFIG_9P_ENABLE_9P2000_e || CONFIG_9P_ENABLE_9P2000_u */ diff --git a/lib9p/include/lib9p/9p.h b/lib9p/include/lib9p/9p.h index 24bae2b..d4764a2 100644 --- a/lib9p/include/lib9p/9p.h +++ b/lib9p/include/lib9p/9p.h @@ -24,6 +24,12 @@ const char *lib9p_version_str(enum lib9p_version); const char *lib9p_msgtype_str(enum lib9p_version, enum lib9p_msg_type); +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 ************************************************************************/ struct lib9p_ctx { @@ -35,7 +41,7 @@ struct lib9p_ctx { #ifdef CONFIG_9P_ENABLE_9P2000_u uint32_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); @@ -55,7 +61,7 @@ int lib9p_errorf(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *fmt, . * * 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 diff --git a/lib9p/include/lib9p/srv.h b/lib9p/include/lib9p/srv.h index eb0e4f4..55cf5db 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 */ @@ -22,7 +22,7 @@ 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) _lib9p_srv_flushch_t _flushch; @@ -67,9 +67,9 @@ struct lib9p_srv_file_vtable { /* directories - base */ implements_lib9p_srv_file *(*dopen )(implements_lib9p_srv_file *, struct lib9p_srv_ctx *, - char *childname); + struct lib9p_s childname); implements_lib9p_srv_file *(*dcreate)(implements_lib9p_srv_file *, struct lib9p_srv_ctx *, - char *childname, + struct lib9p_s childname, lib9p_dm_t perm, lib9p_o_t flags); /* directories - once opened */ @@ -95,8 +95,8 @@ 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 */ + implements_lib9p_srv_file *(*rootdir)(struct lib9p_srv_ctx *, struct lib9p_s treename); /* For internal use */ BEGIN_PRIVATE(LIB9P_SRV_H) diff --git a/lib9p/srv.c b/lib9p/srv.c index d5b643d..9eb945c 100644 --- a/lib9p/srv.c +++ b/lib9p/srv.c @@ -143,11 +143,8 @@ 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, - }, + .ename = lib9p_strn(req->ctx.basectx.err_msg, + CONFIG_9P_MAX_ERR_SIZE), #if CONFIG_9P_ENABLE_9P2000_u .errno = req->ctx.basectx.err_num, #endif @@ -443,14 +440,14 @@ 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; #if CONFIG_9P_ENABLE_9P2000_u - if (strcmp(&req->version.utf8[6], ".u") == 0) + if (lib9p_str_eq(lib9p_str_sliceleft(req->version, 6), lib9p_str(".u"))) version = LIB9P_VER_9P2000_u; #endif #if CONFIG_9P_ENABLE_9P2000_e - if (strcmp(&req->version.utf8[6], ".e") == 0) + if (lib9p_str_eq(lib9p_str_sliceleft(req->version, 6), lib9p_str(".e"))) version = LIB9P_VER_9P2000_e; #endif } @@ -463,11 +460,7 @@ static void handle_Tversion(struct _lib9p_srv_req *ctx, 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->version = lib9p_str((char *)lib9p_version_str(version)); /* cast to discard "const" qualifier */ resp->max_msg_size = (CONFIG_9P_MAX_MSG_SIZE < req->max_msg_size) ? CONFIG_9P_MAX_MSG_SIZE : req->max_msg_size; @@ -511,7 +504,7 @@ static void handle_Tauth(struct _lib9p_srv_req *ctx, util_handler_common(ctx, req, resp); ctx->ctx.uid = req->n_uid; - ctx->ctx.uname = req->uname.utf8; + ctx->ctx.uname = req->uname; struct lib9p_srv *srv = ctx->parent_sess->parent_conn->parent_srv; if (!srv->auth) { @@ -520,7 +513,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"); } @@ -531,7 +524,7 @@ static void handle_Tattach(struct _lib9p_srv_req *ctx, util_handler_common(ctx, req, resp); ctx->ctx.uid = req->n_uid; - ctx->ctx.uname = req->uname.utf8; + ctx->ctx.uname = req->uname; struct lib9p_srv *srv = ctx->parent_sess->parent_conn->parent_srv; if (srv->auth) { @@ -543,14 +536,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"); @@ -575,7 +570,7 @@ static void handle_Tattach(struct _lib9p_srv_req *ctx, return; } - implements_lib9p_srv_file *rootdir = srv->rootdir(&ctx->ctx, req->aname.utf8); + implements_lib9p_srv_file *rootdir = srv->rootdir(&ctx->ctx, req->aname); assert((rootdir == NULL) == lib9p_ctx_has_error(&ctx->ctx.basectx)); if (lib9p_ctx_has_error(&ctx->ctx.basectx)) return; @@ -647,7 +642,7 @@ static void handle_Twalk(struct _lib9p_srv_req *ctx, 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) { + if (lib9p_str_eq(req->wname[resp->nwqid], lib9p_str(".."))) { member = dir->_parent_dir; } else { if (!isdir) { @@ -656,7 +651,7 @@ static void handle_Twalk(struct _lib9p_srv_req *ctx, break; } - member = VCALL(dir, dopen, &ctx->ctx, req->wname[resp->nwqid].utf8); + member = VCALL(dir, dopen, &ctx->ctx, req->wname[resp->nwqid]); assert((member == NULL) == lib9p_ctx_has_error(&ctx->ctx.basectx)); if (lib9p_ctx_has_error(&ctx->ctx.basectx)) break; diff --git a/lib9p/tests/test_server/config/config.h b/lib9p/tests/test_server/config/config.h index e207f7e..971dda2 100644 --- a/lib9p/tests/test_server/config/config.h +++ b/lib9p/tests/test_server/config/config.h @@ -1,6 +1,6 @@ /* config.h - Compile-time configuration for srv9p * - * 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 */ @@ -33,7 +33,7 @@ /** * Maximum host-data-structure size. A message may be larger in * unmarshaled-host-structures than marshaled-net-bytes due to (1) - * struct padding, (2) nul-terminator byes for strings. + * struct padding, (2) array pointers. */ #define CONFIG_9P_MAX_HOSTMSG_SIZE CONFIG_9P_MAX_MSG_SIZE+16 #define CONFIG_9P_MAX_FIDS 16 diff --git a/lib9p/tests/test_server/main.c b/lib9p/tests/test_server/main.c index a6e4eeb..8e5011a 100644 --- a/lib9p/tests/test_server/main.c +++ b/lib9p/tests/test_server/main.c @@ -78,7 +78,7 @@ static struct util9p_static_dir root = { }, }; -static implements_lib9p_srv_file *get_root(struct lib9p_srv_ctx *LM_UNUSED(ctx), char *LM_UNUSED(treename)) { +static implements_lib9p_srv_file *get_root(struct lib9p_srv_ctx *LM_UNUSED(ctx), struct lib9p_s LM_UNUSED(treename)) { return &root; } |