summaryrefslogtreecommitdiff
path: root/lib9p
diff options
context:
space:
mode:
Diffstat (limited to 'lib9p')
-rw-r--r--lib9p/9p.c29
-rw-r--r--lib9p/9p.generated.c4
-rwxr-xr-xlib9p/idl.gen17
-rw-r--r--lib9p/include/lib9p/9p.generated.h8
-rw-r--r--lib9p/include/lib9p/9p.h10
-rw-r--r--lib9p/include/lib9p/srv.h12
-rw-r--r--lib9p/srv.c45
-rw-r--r--lib9p/tests/test_server/config/config.h4
-rw-r--r--lib9p/tests/test_server/main.c2
9 files changed, 78 insertions, 53 deletions
diff --git a/lib9p/9p.c b/lib9p/9p.c
index de6f05b..5bea9f9 100644
--- a/lib9p/9p.c
+++ b/lib9p/9p.c
@@ -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;
}