summaryrefslogtreecommitdiff
path: root/lib9p/tests
diff options
context:
space:
mode:
Diffstat (limited to 'lib9p/tests')
-rw-r--r--lib9p/tests/client_config/config.h21
-rw-r--r--lib9p/tests/test_compile.c135
-rwxr-xr-xlib9p/tests/test_compile.c.gen2
-rw-r--r--lib9p/tests/test_compile_config/config.h19
-rw-r--r--lib9p/tests/test_server/CMakeLists.txt3
-rw-r--r--lib9p/tests/test_server/config/config.h33
-rw-r--r--lib9p/tests/test_server/fs_flush.c139
-rw-r--r--lib9p/tests/test_server/fs_flush.h27
-rw-r--r--lib9p/tests/test_server/fs_shutdown.c8
-rw-r--r--lib9p/tests/test_server/fs_slowread.c116
-rw-r--r--lib9p/tests/test_server/fs_slowread.h22
-rw-r--r--lib9p/tests/test_server/fs_whoami.c12
-rw-r--r--lib9p/tests/test_server/main.c26
-rwxr-xr-xlib9p/tests/testclient-p9p7
-rw-r--r--lib9p/tests/testclient-p9p.explog40
-rw-r--r--lib9p/tests/testclient-sess.c97
-rw-r--r--lib9p/tests/testclient-sess.explog120
17 files changed, 560 insertions, 267 deletions
diff --git a/lib9p/tests/client_config/config.h b/lib9p/tests/client_config/config.h
index 65ee9de..bcf030d 100644
--- a/lib9p/tests/client_config/config.h
+++ b/lib9p/tests/client_config/config.h
@@ -7,8 +7,6 @@
#ifndef _CONFIG_H_
#define _CONFIG_H_
-/* 9P *************************************************************************/
-
#define CONFIG_9P_MAX_ERR_SIZE 128
#define CONFIG_9P_MAX_9P2000_e_WELEM 16
@@ -18,23 +16,4 @@
#define CONFIG_9P_ENABLE_9P2000_L 1 /* bool */
#define CONFIG_9P_ENABLE_9P2000_p9p 1 /* bool */
-/* 9P server (unused) *********************************************************/
-
-#define CONFIG_9P_SRV_MAX_MSG_SIZE ((4*1024)+24)
-#define CONFIG_9P_SRV_MAX_HOSTMSG_SIZE CONFIG_9P_SRV_MAX_MSG_SIZE+16
-#define CONFIG_9P_SRV_MAX_FIDS 16
-#define CONFIG_9P_SRV_MAX_REQS 2
-#define CONFIG_9P_SRV_MAX_DEPTH 3
-
-/* COROUTINE (unused) *********************************************************/
-
-#define CONFIG_COROUTINE_STACK_SIZE_DEFAULT (32*1024)
-#define CONFIG_COROUTINE_NAME_LEN 16
-#define CONFIG_COROUTINE_MEASURE_STACK 1 /* bool */
-#define CONFIG_COROUTINE_PROTECT_STACK 1 /* bool */
-#define CONFIG_COROUTINE_DEBUG 0 /* bool */
-#define CONFIG_COROUTINE_VALGRIND 1 /* bool */
-#define CONFIG_COROUTINE_GDB 1 /* bool */
-#define CONFIG_COROUTINE_NUM 2
-
#endif /* _CONFIG_H_ */
diff --git a/lib9p/tests/test_compile.c b/lib9p/tests/test_compile.c
index 8f2445d..4532655 100644
--- a/lib9p/tests/test_compile.c
+++ b/lib9p/tests/test_compile.c
@@ -1,6 +1,6 @@
/* lib9p/tests/test_compile.c - Generated by lib9p/tests/test_compile.c.gen. DO NOT EDIT! */
-#include <lib9p/9p.h>
+#include <lib9p/core.h>
int main(void) {
[[gnu::unused]] uint64_t x;
x = LIB9P_TAG_NOTAG;
@@ -47,7 +47,6 @@ int main(void) {
x = LIB9P_QT_SYMLINK;
x = _LIB9P_QT_UNUSED_0;
x = LIB9P_QT_FILE;
- x = LIB9P_NUID_NONUID;
x = _LIB9P_O_UNUSED_7;
x = LIB9P_O_RCLOSE;
x = _LIB9P_O_RESERVED_CEXEC;
@@ -60,7 +59,139 @@ int main(void) {
x = LIB9P_O_MODE_RDWR;
x = LIB9P_O_MODE_EXEC;
x = LIB9P_O_MODE_MASK;
+ x = LIB9P_NUID_NONUID;
x = LIB9P_ERRNO_NOERROR;
+ x = LIB9P_ERRNO_L_EPERM;
+ x = LIB9P_ERRNO_L_ENOENT;
+ x = LIB9P_ERRNO_L_ESRCH;
+ x = LIB9P_ERRNO_L_EINTR;
+ x = LIB9P_ERRNO_L_EIO;
+ x = LIB9P_ERRNO_L_ENXIO;
+ x = LIB9P_ERRNO_L_E2BIG;
+ x = LIB9P_ERRNO_L_ENOEXEC;
+ x = LIB9P_ERRNO_L_EBADF;
+ x = LIB9P_ERRNO_L_ECHILD;
+ x = LIB9P_ERRNO_L_EAGAIN;
+ x = LIB9P_ERRNO_L_ENOMEM;
+ x = LIB9P_ERRNO_L_EACCES;
+ x = LIB9P_ERRNO_L_EFAULT;
+ x = LIB9P_ERRNO_L_ENOTBLK;
+ x = LIB9P_ERRNO_L_EBUSY;
+ x = LIB9P_ERRNO_L_EEXIST;
+ x = LIB9P_ERRNO_L_EXDEV;
+ x = LIB9P_ERRNO_L_ENODEV;
+ x = LIB9P_ERRNO_L_ENOTDIR;
+ x = LIB9P_ERRNO_L_EISDIR;
+ x = LIB9P_ERRNO_L_EINVAL;
+ x = LIB9P_ERRNO_L_ENFILE;
+ x = LIB9P_ERRNO_L_EMFILE;
+ x = LIB9P_ERRNO_L_ENOTTY;
+ x = LIB9P_ERRNO_L_ETXTBSY;
+ x = LIB9P_ERRNO_L_EFBIG;
+ x = LIB9P_ERRNO_L_ENOSPC;
+ x = LIB9P_ERRNO_L_ESPIPE;
+ x = LIB9P_ERRNO_L_EROFS;
+ x = LIB9P_ERRNO_L_EMLINK;
+ x = LIB9P_ERRNO_L_EPIPE;
+ x = LIB9P_ERRNO_L_EDOM;
+ x = LIB9P_ERRNO_L_ERANGE;
+ x = LIB9P_ERRNO_L_EDEADLK;
+ x = LIB9P_ERRNO_L_ENAMETOOLONG;
+ x = LIB9P_ERRNO_L_ENOLCK;
+ x = LIB9P_ERRNO_L_ENOSYS;
+ x = LIB9P_ERRNO_L_ENOTEMPTY;
+ x = LIB9P_ERRNO_L_ELOOP;
+ x = LIB9P_ERRNO_L_ENOMSG;
+ x = LIB9P_ERRNO_L_EIDRM;
+ x = LIB9P_ERRNO_L_ECHRNG;
+ x = LIB9P_ERRNO_L_EL2NSYNC;
+ x = LIB9P_ERRNO_L_EL3HLT;
+ x = LIB9P_ERRNO_L_EL3RST;
+ x = LIB9P_ERRNO_L_ELNRNG;
+ x = LIB9P_ERRNO_L_EUNATCH;
+ x = LIB9P_ERRNO_L_ENOCSI;
+ x = LIB9P_ERRNO_L_EL2HLT;
+ x = LIB9P_ERRNO_L_EBADE;
+ x = LIB9P_ERRNO_L_EBADR;
+ x = LIB9P_ERRNO_L_EXFULL;
+ x = LIB9P_ERRNO_L_ENOANO;
+ x = LIB9P_ERRNO_L_EBADRQC;
+ x = LIB9P_ERRNO_L_EBADSLT;
+ x = LIB9P_ERRNO_L_EBFONT;
+ x = LIB9P_ERRNO_L_ENOSTR;
+ x = LIB9P_ERRNO_L_ENODATA;
+ x = LIB9P_ERRNO_L_ETIME;
+ x = LIB9P_ERRNO_L_ENOSR;
+ x = LIB9P_ERRNO_L_ENONET;
+ x = LIB9P_ERRNO_L_ENOPKG;
+ x = LIB9P_ERRNO_L_EREMOTE;
+ x = LIB9P_ERRNO_L_ENOLINK;
+ x = LIB9P_ERRNO_L_EADV;
+ x = LIB9P_ERRNO_L_ESRMNT;
+ x = LIB9P_ERRNO_L_ECOMM;
+ x = LIB9P_ERRNO_L_EPROTO;
+ x = LIB9P_ERRNO_L_EMULTIHOP;
+ x = LIB9P_ERRNO_L_EDOTDOT;
+ x = LIB9P_ERRNO_L_EBADMSG;
+ x = LIB9P_ERRNO_L_EOVERFLOW;
+ x = LIB9P_ERRNO_L_ENOTUNIQ;
+ x = LIB9P_ERRNO_L_EBADFD;
+ x = LIB9P_ERRNO_L_EREMCHG;
+ x = LIB9P_ERRNO_L_ELIBACC;
+ x = LIB9P_ERRNO_L_ELIBBAD;
+ x = LIB9P_ERRNO_L_ELIBSCN;
+ x = LIB9P_ERRNO_L_ELIBMAX;
+ x = LIB9P_ERRNO_L_ELIBEXEC;
+ x = LIB9P_ERRNO_L_EILSEQ;
+ x = LIB9P_ERRNO_L_ERESTART;
+ x = LIB9P_ERRNO_L_ESTRPIPE;
+ x = LIB9P_ERRNO_L_EUSERS;
+ x = LIB9P_ERRNO_L_ENOTSOCK;
+ x = LIB9P_ERRNO_L_EDESTADDRREQ;
+ x = LIB9P_ERRNO_L_EMSGSIZE;
+ x = LIB9P_ERRNO_L_EPROTOTYPE;
+ x = LIB9P_ERRNO_L_ENOPROTOOPT;
+ x = LIB9P_ERRNO_L_EPROTONOSUPPORT;
+ x = LIB9P_ERRNO_L_ESOCKTNOSUPPORT;
+ x = LIB9P_ERRNO_L_EOPNOTSUPP;
+ x = LIB9P_ERRNO_L_EPFNOSUPPORT;
+ x = LIB9P_ERRNO_L_EAFNOSUPPORT;
+ x = LIB9P_ERRNO_L_EADDRINUSE;
+ x = LIB9P_ERRNO_L_EADDRNOTAVAIL;
+ x = LIB9P_ERRNO_L_ENETDOWN;
+ x = LIB9P_ERRNO_L_ENETUNREACH;
+ x = LIB9P_ERRNO_L_ENETRESET;
+ x = LIB9P_ERRNO_L_ECONNABORTED;
+ x = LIB9P_ERRNO_L_ECONNRESET;
+ x = LIB9P_ERRNO_L_ENOBUFS;
+ x = LIB9P_ERRNO_L_EISCONN;
+ x = LIB9P_ERRNO_L_ENOTCONN;
+ x = LIB9P_ERRNO_L_ESHUTDOWN;
+ x = LIB9P_ERRNO_L_ETOOMANYREFS;
+ x = LIB9P_ERRNO_L_ETIMEDOUT;
+ x = LIB9P_ERRNO_L_ECONNREFUSED;
+ x = LIB9P_ERRNO_L_EHOSTDOWN;
+ x = LIB9P_ERRNO_L_EHOSTUNREACH;
+ x = LIB9P_ERRNO_L_EALREADY;
+ x = LIB9P_ERRNO_L_EINPROGRESS;
+ x = LIB9P_ERRNO_L_ESTALE;
+ x = LIB9P_ERRNO_L_EUCLEAN;
+ x = LIB9P_ERRNO_L_ENOTNAM;
+ x = LIB9P_ERRNO_L_ENAVAIL;
+ x = LIB9P_ERRNO_L_EISNAM;
+ x = LIB9P_ERRNO_L_EREMOTEIO;
+ x = LIB9P_ERRNO_L_EDQUOT;
+ x = LIB9P_ERRNO_L_ENOMEDIUM;
+ x = LIB9P_ERRNO_L_EMEDIUMTYPE;
+ x = LIB9P_ERRNO_L_ECANCELED;
+ x = LIB9P_ERRNO_L_ENOKEY;
+ x = LIB9P_ERRNO_L_EKEYEXPIRED;
+ x = LIB9P_ERRNO_L_EKEYREVOKED;
+ x = LIB9P_ERRNO_L_EKEYREJECTED;
+ x = LIB9P_ERRNO_L_EOWNERDEAD;
+ x = LIB9P_ERRNO_L_ENOTRECOVERABLE;
+ x = LIB9P_ERRNO_L_ERFKILL;
+ x = LIB9P_ERRNO_L_EHWPOISON;
x = LIB9P_SUPER_MAGIC_V9FS_MAGIC;
x = _LIB9P_LO_UNUSED_31;
x = _LIB9P_LO_UNUSED_30;
diff --git a/lib9p/tests/test_compile.c.gen b/lib9p/tests/test_compile.c.gen
index 47046b3..1289943 100755
--- a/lib9p/tests/test_compile.c.gen
+++ b/lib9p/tests/test_compile.c.gen
@@ -10,7 +10,7 @@ outfile=$2
{
echo "/* ${outfile} - Generated by $0. DO NOT EDIT! */"
echo
- echo "#include <lib9p/9p.h>"
+ echo "#include <lib9p/core.h>"
echo 'int main(void) {'
echo ' [[gnu::unused]] uint64_t x;'
sed -nE 's/^\s*#\s*define\s*(\S[^ (]*)\s.*/ x = \1;/p' <"$generated_h"
diff --git a/lib9p/tests/test_compile_config/config.h b/lib9p/tests/test_compile_config/config.h
index cc8eec1..f899dfa 100644
--- a/lib9p/tests/test_compile_config/config.h
+++ b/lib9p/tests/test_compile_config/config.h
@@ -7,32 +7,13 @@
#ifndef _CONFIG_H_
#define _CONFIG_H_
-/* 9P *************************************************************************/
-
#define CONFIG_9P_MAX_ERR_SIZE 128
#define CONFIG_9P_MAX_9P2000_e_WELEM 16
-#define CONFIG_9P_SRV_MAX_MSG_SIZE ((4*1024)+24)
-#define CONFIG_9P_SRV_MAX_HOSTMSG_SIZE CONFIG_9P_SRV_MAX_MSG_SIZE+16
-#define CONFIG_9P_SRV_MAX_FIDS 16
-#define CONFIG_9P_SRV_MAX_REQS 2
-#define CONFIG_9P_SRV_MAX_DEPTH 3
-
#define CONFIG_9P_ENABLE_9P2000 1 /* bool */
#define CONFIG_9P_ENABLE_9P2000_u 1 /* bool */
#define CONFIG_9P_ENABLE_9P2000_e 1 /* bool */
#define CONFIG_9P_ENABLE_9P2000_L 1 /* bool */
#define CONFIG_9P_ENABLE_9P2000_p9p 1 /* bool */
-/* COROUTINE ******************************************************************/
-
-#define CONFIG_COROUTINE_STACK_SIZE_DEFAULT (32*1024)
-#define CONFIG_COROUTINE_NAME_LEN 16
-#define CONFIG_COROUTINE_MEASURE_STACK 1 /* bool */
-#define CONFIG_COROUTINE_PROTECT_STACK 1 /* bool */
-#define CONFIG_COROUTINE_DEBUG 0 /* bool */
-#define CONFIG_COROUTINE_VALGRIND 1 /* bool */
-#define CONFIG_COROUTINE_GDB 1 /* bool */
-#define CONFIG_COROUTINE_NUM 2
-
#endif /* _CONFIG_H_ */
diff --git a/lib9p/tests/test_server/CMakeLists.txt b/lib9p/tests/test_server/CMakeLists.txt
index 681e583..c61d344 100644
--- a/lib9p/tests/test_server/CMakeLists.txt
+++ b/lib9p/tests/test_server/CMakeLists.txt
@@ -9,8 +9,8 @@ if (PICO_PLATFORM STREQUAL "host")
add_library(test_server_objs OBJECT
main.c
+ fs_flush.c
fs_shutdown.c
- fs_slowread.c
fs_whoami.c
)
target_include_directories(test_server_objs PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/config)
@@ -19,7 +19,6 @@ target_link_libraries(test_server_objs
libcr
libcr_ipc
libmisc
- lib9p
lib9p_util
libhw_cr
)
diff --git a/lib9p/tests/test_server/config/config.h b/lib9p/tests/test_server/config/config.h
index 03143e1..f49894b 100644
--- a/lib9p/tests/test_server/config/config.h
+++ b/lib9p/tests/test_server/config/config.h
@@ -7,13 +7,23 @@
#ifndef _CONFIG_H_
#define _CONFIG_H_
-#define _CONFIG_9P_NUM_SOCKS 8
-#define CONFIG_SRV9P_NUM_CONNS _CONFIG_9P_NUM_SOCKS
+#define _CONFIG_9P_MAX_CONNS 8
+#define _CONFIG_9P_MAX_REQS (2*_CONFIG_9P_MAX_CONNS)
/* 9P *************************************************************************/
#define CONFIG_9P_MAX_ERR_SIZE 128 /* 128 is what Plan 9 4e uses */
+#define CONFIG_9P_ENABLE_9P2000 1 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_u 1 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_e 0 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_L 0 /* bool */
+#define CONFIG_9P_ENABLE_9P2000_p9p 0 /* bool */
+
+/* 9P_SRV *********************************************************************/
+
+#define CONFIG_9P_SRV_DEBUG 1 /* bool */
+
/**
* This max-msg-size is sized so that a Twrite message can return
* 8KiB of data.
@@ -38,15 +48,6 @@
* struct padding, (2) array pointers.
*/
#define CONFIG_9P_SRV_MAX_HOSTMSG_SIZE CONFIG_9P_SRV_MAX_MSG_SIZE+16
-#define CONFIG_9P_SRV_MAX_FIDS 16
-#define CONFIG_9P_SRV_MAX_REQS 2
-#define CONFIG_9P_SRV_MAX_DEPTH 3
-
-#define CONFIG_9P_ENABLE_9P2000 1 /* bool */
-#define CONFIG_9P_ENABLE_9P2000_u 1 /* bool */
-#define CONFIG_9P_ENABLE_9P2000_e 0 /* bool */
-#define CONFIG_9P_ENABLE_9P2000_L 0 /* bool */
-#define CONFIG_9P_ENABLE_9P2000_p9p 0 /* bool */
/* COROUTINE ******************************************************************/
@@ -57,10 +58,10 @@
#define CONFIG_COROUTINE_DEBUG 0 /* bool */
#define CONFIG_COROUTINE_VALGRIND 1 /* bool */
#define CONFIG_COROUTINE_GDB 1 /* bool */
-#define CONFIG_COROUTINE_NUM ( \
- 1 /* usb_common */ + \
- 1 /* usb_keyboard */ + \
- CONFIG_SRV9P_NUM_CONNS /* accept+read */ + \
- (CONFIG_9P_SRV_MAX_REQS*CONFIG_SRV9P_NUM_CONNS) /* work+write */ )
+#define CONFIG_COROUTINE_NUM ( \
+ 1 /* usb_common */ + \
+ 1 /* usb_keyboard */ + \
+ _CONFIG_9P_MAX_CONNS /* accept+read */ + \
+ _CONFIG_9P_MAX_REQS /* work+write */ )
#endif /* _CONFIG_H_ */
diff --git a/lib9p/tests/test_server/fs_flush.c b/lib9p/tests/test_server/fs_flush.c
new file mode 100644
index 0000000..dbed3e7
--- /dev/null
+++ b/lib9p/tests/test_server/fs_flush.c
@@ -0,0 +1,139 @@
+/* lib9p/tests/test_server/fs_flush.c - flush-* API endpoints
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <libmisc/alloc.h>
+
+#define IMPLEMENTATION_FOR_LIB9P_SRV_H YES /* for ctx->flush_ch */
+#include "fs_flush.h"
+
+LO_IMPLEMENTATION_C(lib9p_srv_file, struct flush_file, flush_file, static);
+
+struct flush_fio {
+ struct flush_file *parent;
+};
+LO_IMPLEMENTATION_H(lib9p_srv_fio, struct flush_fio, flush_fio);
+LO_IMPLEMENTATION_C(lib9p_srv_fio, struct flush_fio, flush_fio, static);
+
+/* srv_file *******************************************************************/
+
+static void flush_file_free(struct flush_file *self) {
+ assert(self);
+}
+static struct lib9p_qid flush_file_qid(struct flush_file *self) {
+ assert(self);
+ return (struct lib9p_qid){
+ .type = LIB9P_QT_FILE,
+ .vers = 1,
+ .path = self->pathnum,
+ };
+}
+
+static struct lib9p_stat flush_file_stat(struct flush_file *self, struct lib9p_srv_ctx *ctx) {
+ assert(self);
+ assert(ctx);
+ return (struct lib9p_stat){
+ .kern_type = 0,
+ .kern_dev = 0,
+ .file_qid = flush_file_qid(self),
+ .file_mode = 0444,
+ .file_atime = UTIL9P_ATIME,
+ .file_mtime = UTIL9P_MTIME,
+ .file_size = 6,
+ .file_name = lib9p_str(self->name),
+ .file_owner_uid = lib9p_str("root"),
+ .file_owner_gid = lib9p_str("root"),
+ .file_last_modified_uid = lib9p_str("root"),
+ .file_extension = lib9p_str(NULL),
+ .file_owner_n_uid = 0,
+ .file_owner_n_gid = 0,
+ .file_last_modified_n_uid = 0,
+ };
+}
+static void flush_file_wstat(struct flush_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_stat) {
+ assert(self);
+ assert(ctx);
+ lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "cannot wstat API file");
+}
+static void flush_file_remove(struct flush_file *self, struct lib9p_srv_ctx *ctx) {
+ assert(self);
+ assert(ctx);
+ lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "cannot remove API file");
+}
+
+LIB9P_SRV_NOTDIR(struct flush_file, flush_file)
+
+static lo_interface lib9p_srv_fio flush_file_fopen(struct flush_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) {
+ assert(self);
+ assert(ctx);
+
+ struct flush_fio *ret = heap_alloc(1, struct flush_fio);
+ ret->parent = self;
+
+ return lo_box_flush_fio_as_lib9p_srv_fio(ret);
+}
+
+/* srv_fio ********************************************************************/
+
+static void flush_fio_iofree(struct flush_fio *self) {
+ assert(self);
+ free(self);
+}
+
+static struct lib9p_qid flush_fio_qid(struct flush_fio *self) {
+ assert(self);
+ return flush_file_qid(self->parent);
+}
+
+static uint32_t flush_fio_iounit(struct flush_fio *self) {
+ assert(self);
+ return 0;
+}
+
+static uint32_t flush_fio_pwrite(struct flush_fio *LM_UNUSED(self),
+ struct lib9p_srv_ctx *LM_UNUSED(ctx),
+ void *LM_UNUSED(buf), uint32_t LM_UNUSED(byte_count),
+ uint64_t LM_UNUSED(offset)) {
+ assert_notreached("not writable");
+}
+
+static void flush_fio_pread(struct flush_fio *self, struct lib9p_srv_ctx *ctx,
+ uint32_t byte_count, uint64_t LM_UNUSED(byte_offset),
+ struct iovec *ret) {
+ assert(self);
+ assert(ctx);
+ assert(ret);
+
+ /* Wait for first Tflush */
+ while (cr_chan_num_waiters(&ctx->flush_ch) == 0)
+ cr_yield();
+
+ /* Wait for the specified number of Tflush (may be higher *or*
+ * lower than 1; lower would mean that the first Tflush needs
+ * to be flushed itself). */
+ while (cr_chan_num_waiters(&ctx->flush_ch) != self->parent->flush_cnt)
+ cr_yield();
+
+ /* Return */
+ bool flushed;
+ switch (self->parent->flush_behavior) {
+ case FLUSH_READ:
+ *ret = (struct iovec){
+ .iov_base = "Sloth\n",
+ .iov_len = 6 < byte_count ? 6 : byte_count,
+ };
+ break;
+ case FLUSH_ERROR:
+ flushed = lib9p_srv_accept_flush(ctx);
+ assert(flushed);
+ lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_ECANCELED, "request canceled by flush");
+ break;
+ case FLUSH_SILENT:
+ flushed = lib9p_srv_accept_flush(ctx);
+ assert(flushed);
+ break;
+ }
+ cr_yield();
+}
diff --git a/lib9p/tests/test_server/fs_flush.h b/lib9p/tests/test_server/fs_flush.h
new file mode 100644
index 0000000..a509c4a
--- /dev/null
+++ b/lib9p/tests/test_server/fs_flush.h
@@ -0,0 +1,27 @@
+/* lib9p/tests/test_server/fs_flush.h - flush-* API endpoints
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIB9P_TESTS_TEST_SERVER_FS_FLUSH_H_
+#define _LIB9P_TESTS_TEST_SERVER_FS_FLUSH_H_
+
+#include <util9p/static.h>
+#include <libhw/host_net.h>
+
+struct flush_file {
+ char *name;
+ uint64_t pathnum;
+
+ unsigned int flush_cnt;
+ enum {
+ FLUSH_READ,
+ FLUSH_ERROR,
+ FLUSH_SILENT,
+ } flush_behavior;
+};
+LO_IMPLEMENTATION_H(lib9p_srv_file, struct flush_file, flush_file);
+#define lo_box_flush_file_as_lib9p_srv_file(obj) util9p_box(flush_file, obj)
+
+#endif /* _LIB9P_TESTS_TEST_SERVER_FS_FLUSH_H_ */
diff --git a/lib9p/tests/test_server/fs_shutdown.c b/lib9p/tests/test_server/fs_shutdown.c
index 26a8a10..e7375ef 100644
--- a/lib9p/tests/test_server/fs_shutdown.c
+++ b/lib9p/tests/test_server/fs_shutdown.c
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-#include <stdlib.h>
+#include <libmisc/alloc.h>
#include "fs_shutdown.h"
@@ -54,12 +54,12 @@ static struct lib9p_stat shutdown_file_stat(struct shutdown_file *self, struct l
static void shutdown_file_wstat(struct shutdown_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_stat) {
assert(self);
assert(ctx);
- lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot wstat API file");
+ lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "cannot wstat API file");
}
static void shutdown_file_remove(struct shutdown_file *self, struct lib9p_srv_ctx *ctx) {
assert(self);
assert(ctx);
- lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot remove API file");
+ lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "cannot remove API file");
}
LIB9P_SRV_NOTDIR(struct shutdown_file, shutdown_file)
@@ -68,7 +68,7 @@ static lo_interface lib9p_srv_fio shutdown_file_fopen(struct shutdown_file *self
assert(self);
assert(ctx);
- struct shutdown_fio *ret = malloc(sizeof(struct shutdown_fio));
+ struct shutdown_fio *ret = heap_alloc(1, struct shutdown_fio);
ret->parent = self;
return lo_box_shutdown_fio_as_lib9p_srv_fio(ret);
diff --git a/lib9p/tests/test_server/fs_slowread.c b/lib9p/tests/test_server/fs_slowread.c
deleted file mode 100644
index c5db896..0000000
--- a/lib9p/tests/test_server/fs_slowread.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/* lib9p/tests/test_server/fs_slowread.c - slowread API endpoint
- *
- * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#include <stdlib.h>
-
-#include "fs_slowread.h"
-
-LO_IMPLEMENTATION_C(lib9p_srv_file, struct slowread_file, slowread_file, static);
-
-struct slowread_fio {
- struct slowread_file *parent;
-};
-LO_IMPLEMENTATION_H(lib9p_srv_fio, struct slowread_fio, slowread_fio);
-LO_IMPLEMENTATION_C(lib9p_srv_fio, struct slowread_fio, slowread_fio, static);
-
-/* srv_file *******************************************************************/
-
-static void slowread_file_free(struct slowread_file *self) {
- assert(self);
-}
-static struct lib9p_qid slowread_file_qid(struct slowread_file *self) {
- assert(self);
- return (struct lib9p_qid){
- .type = LIB9P_QT_FILE,
- .vers = 1,
- .path = self->pathnum,
- };
-}
-
-static struct lib9p_stat slowread_file_stat(struct slowread_file *self, struct lib9p_srv_ctx *ctx) {
- assert(self);
- assert(ctx);
- return (struct lib9p_stat){
- .kern_type = 0,
- .kern_dev = 0,
- .file_qid = slowread_file_qid(self),
- .file_mode = 0444,
- .file_atime = UTIL9P_ATIME,
- .file_mtime = UTIL9P_MTIME,
- .file_size = 6,
- .file_name = lib9p_str(self->name),
- .file_owner_uid = lib9p_str("root"),
- .file_owner_gid = lib9p_str("root"),
- .file_last_modified_uid = lib9p_str("root"),
- .file_extension = lib9p_str(NULL),
- .file_owner_n_uid = 0,
- .file_owner_n_gid = 0,
- .file_last_modified_n_uid = 0,
- };
-}
-static void slowread_file_wstat(struct slowread_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_stat) {
- assert(self);
- assert(ctx);
- lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot wstat API file");
-}
-static void slowread_file_remove(struct slowread_file *self, struct lib9p_srv_ctx *ctx) {
- assert(self);
- assert(ctx);
- lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot remove API file");
-}
-
-LIB9P_SRV_NOTDIR(struct slowread_file, slowread_file)
-
-static lo_interface lib9p_srv_fio slowread_file_fopen(struct slowread_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) {
- assert(self);
- assert(ctx);
-
- struct slowread_fio *ret = malloc(sizeof(struct slowread_fio));
- ret->parent = self;
-
- return lo_box_slowread_fio_as_lib9p_srv_fio(ret);
-}
-
-/* srv_fio ********************************************************************/
-
-static void slowread_fio_iofree(struct slowread_fio *self) {
- assert(self);
- free(self);
-}
-
-static struct lib9p_qid slowread_fio_qid(struct slowread_fio *self) {
- assert(self);
- return slowread_file_qid(self->parent);
-}
-
-static uint32_t slowread_fio_iounit(struct slowread_fio *self) {
- assert(self);
- return 0;
-}
-
-static uint32_t slowread_fio_pwrite(struct slowread_fio *LM_UNUSED(self),
- struct lib9p_srv_ctx *LM_UNUSED(ctx),
- void *LM_UNUSED(buf), uint32_t LM_UNUSED(byte_count),
- uint64_t LM_UNUSED(offset)) {
- assert_notreached("not writable");
-}
-static void slowread_fio_pread(struct slowread_fio *self, struct lib9p_srv_ctx *ctx,
- uint32_t byte_count, uint64_t LM_UNUSED(byte_offset),
- struct iovec *ret) {
- assert(self);
- assert(ctx);
- assert(ret);
-
- while (!lib9p_srv_flush_requested(ctx))
- cr_yield();
- if (self->parent->flushable)
- lib9p_srv_acknowledge_flush(ctx);
- else
- *ret = (struct iovec){
- .iov_base = "Sloth\n",
- .iov_len = 6 < byte_count ? 6 : byte_count,
- };
-}
diff --git a/lib9p/tests/test_server/fs_slowread.h b/lib9p/tests/test_server/fs_slowread.h
deleted file mode 100644
index ef4b65f..0000000
--- a/lib9p/tests/test_server/fs_slowread.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* lib9p/tests/test_server/fs_slowread.h - slowread API endpoint
- *
- * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-#ifndef _LIB9P_TESTS_TEST_SERVER_FS_SLOWREAD_H_
-#define _LIB9P_TESTS_TEST_SERVER_FS_SLOWREAD_H_
-
-#include <util9p/static.h>
-#include <libhw/host_net.h>
-
-struct slowread_file {
- char *name;
- uint64_t pathnum;
-
- bool flushable;
-};
-LO_IMPLEMENTATION_H(lib9p_srv_file, struct slowread_file, slowread_file);
-#define lo_box_slowread_file_as_lib9p_srv_file(obj) util9p_box(slowread_file, obj)
-
-#endif /* _LIB9P_TESTS_TEST_SERVER_FS_SLOWREAD_H_ */
diff --git a/lib9p/tests/test_server/fs_whoami.c b/lib9p/tests/test_server/fs_whoami.c
index ff6dd25..653ac4b 100644
--- a/lib9p/tests/test_server/fs_whoami.c
+++ b/lib9p/tests/test_server/fs_whoami.c
@@ -5,7 +5,9 @@
*/
#include <stdio.h> /* for snprintf() */
-#include <stdlib.h> /* for malloc(), realloc(), free() */
+#include <stdlib.h> /* for realloc(), free() */
+
+#include <libmisc/alloc.h>
#include "fs_whoami.h"
@@ -75,12 +77,12 @@ static struct lib9p_stat whoami_file_stat(struct whoami_file *self, struct lib9p
static void whoami_file_wstat(struct whoami_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_stat) {
assert(self);
assert(ctx);
- lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot wstat API file");
+ lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "cannot wstat API file");
}
static void whoami_file_remove(struct whoami_file *self, struct lib9p_srv_ctx *ctx) {
assert(self);
assert(ctx);
- lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot remove API file");
+ lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "cannot remove API file");
}
LIB9P_SRV_NOTDIR(struct whoami_file, whoami_file)
@@ -89,7 +91,7 @@ static lo_interface lib9p_srv_fio whoami_file_fopen(struct whoami_file *self, st
assert(self);
assert(ctx);
- struct whoami_fio *ret = malloc(sizeof(struct whoami_fio));
+ struct whoami_fio *ret = heap_alloc(1, struct whoami_fio);
ret->parent = self;
ret->buf_len = 0;
ret->buf = NULL;
@@ -140,7 +142,7 @@ static void whoami_fio_pread(struct whoami_fio *self, struct lib9p_srv_ctx *ctx,
if (byte_offset > (uint64_t)data_size) {
lib9p_error(&ctx->basectx,
- LINUX_EINVAL, "offset is past end-of-file length");
+ LIB9P_ERRNO_L_EINVAL, "offset is past end-of-file length");
return;
}
diff --git a/lib9p/tests/test_server/main.c b/lib9p/tests/test_server/main.c
index e89a75e..d7819eb 100644
--- a/lib9p/tests/test_server/main.c
+++ b/lib9p/tests/test_server/main.c
@@ -19,16 +19,19 @@
#include <util9p/static.h>
#include "static.h"
+#include "fs_flush.h"
#include "fs_shutdown.h"
-#include "fs_slowread.h"
#include "fs_whoami.h"
/* configuration **************************************************************/
#include "config.h"
-#ifndef CONFIG_SRV9P_NUM_CONNS
- #error config.h must define CONFIG_SRV9P_NUM_CONNS
+#ifndef _CONFIG_9P_MAX_CONNS
+ #error config.h must define _CONFIG_9P_MAX_CONNS
+#endif
+#ifndef _CONFIG_9P_MAX_REQS
+ #error config.h must define _CONFIG_9P_MAX_REQS
#endif
/* globals ********************************************************************/
@@ -39,7 +42,7 @@ const char *hexdig = "0123456789abcdef";
struct {
uint16_t port;
- struct hostnet_tcp_listener listeners[CONFIG_SRV9P_NUM_CONNS];
+ struct hostnet_tcp_listener listeners[_CONFIG_9P_MAX_CONNS];
struct lib9p_srv srv;
FILE *logstream;
} globals = {
@@ -73,11 +76,12 @@ struct lib9p_srv_file root =
API_FILE(5, "shutdown", shutdown,
.listeners = globals.listeners,
.nlisteners = LM_ARRAY_LEN(globals.listeners)),
- API_FILE(6, "slowread", slowread,
- .flushable = false),
- API_FILE(7, "slowread-flushable", slowread,
- .flushable = true),
API_FILE(8, "whoami", whoami),
+ API_FILE(9, "flush-read", flush, .flush_cnt=1, .flush_behavior=FLUSH_READ),
+ API_FILE(10, "flush-error", flush, .flush_cnt=1, .flush_behavior=FLUSH_ERROR),
+ API_FILE(11, "flush-silent", flush, .flush_cnt=1, .flush_behavior=FLUSH_SILENT),
+ API_FILE(12, "flush-slowsilent", flush, .flush_cnt=2, .flush_behavior=FLUSH_SILENT),
+ API_FILE(13, "flush-slowread", flush, .flush_cnt=0, .flush_behavior=FLUSH_READ),
);
static lo_interface lib9p_srv_file get_root(struct lib9p_srv_ctx *LM_UNUSED(ctx), struct lib9p_s LM_UNUSED(treename)) {
@@ -108,14 +112,14 @@ static COROUTINE write_cr(void *) {
static COROUTINE init_cr(void *) {
cr_begin();
- sleep_for_ms(1);
+ sleep_for_ms(1); /* test that sleep works */
- for (int i = 0; i < CONFIG_SRV9P_NUM_CONNS; i++) {
+ for (int i = 0; i < _CONFIG_9P_MAX_CONNS; i++) {
char name[] = {'r', 'e', 'a', 'd', '-', hexdig[i], '\0'};
if (!coroutine_add(name, read_cr, &i))
error(1, 0, "coroutine_add(read_cr, &i)");
}
- for (int i = 0; i < 2*CONFIG_SRV9P_NUM_CONNS; i++) {
+ for (int i = 0; i < _CONFIG_9P_MAX_REQS; i++) {
char name[] = {'w', 'r', 'i', 't', 'e', '-', hexdig[i], '\0'};
if (!coroutine_add(name, write_cr, NULL))
error(1, 0, "coroutine_add(write_cr, NULL)");
diff --git a/lib9p/tests/testclient-p9p b/lib9p/tests/testclient-p9p
index 9c9fb5e..9c9f9f2 100755
--- a/lib9p/tests/testclient-p9p
+++ b/lib9p/tests/testclient-p9p
@@ -25,9 +25,12 @@ out=$("${client[@]}" ls -l '')
expect_lines \
'd-r-xr-xr-x M 0 root root 0 Oct 7 2024 Documentation' \
'--r--r--r-- M 0 root root 166 Oct 7 2024 README.md' \
+ '--r--r--r-- M 0 root root 6 Oct 7 2024 flush-error' \
+ '--r--r--r-- M 0 root root 6 Oct 7 2024 flush-read' \
+ '--r--r--r-- M 0 root root 6 Oct 7 2024 flush-silent' \
+ '--r--r--r-- M 0 root root 6 Oct 7 2024 flush-slowread' \
+ '--r--r--r-- M 0 root root 6 Oct 7 2024 flush-slowsilent' \
'---w--w--w- M 0 root root 0 Oct 7 2024 shutdown' \
- '--r--r--r-- M 0 root root 6 Oct 7 2024 slowread' \
- '--r--r--r-- M 0 root root 6 Oct 7 2024 slowread-flushable' \
'--r--r--r-- M 0 root root 9 Oct 7 2024 whoami'
out=$("${client[@]}" ls -l 'Documentation/')
diff --git a/lib9p/tests/testclient-p9p.explog b/lib9p/tests/testclient-p9p.explog
index 45651a4..7f3953d 100644
--- a/lib9p/tests/testclient-p9p.explog
+++ b/lib9p/tests/testclient-p9p.explog
@@ -5,7 +5,7 @@
> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" }
< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" }
> Tauth { tag=0 afid=0 uname="nobody" aname="" n_uid=0 }
-< Rerror { tag=0 errstr="authentication not required" errnum=95 }
+< Rerror { tag=0 errstr="authentication not required" errnum=L_EOPNOTSUPP }
> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" n_uid=0 }
< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
> Twalk { tag=0 fid=0 newfid=1 nwname=0 wname=[ ] }
@@ -19,25 +19,25 @@
> Topen { tag=0 fid=1 mode=(MODE_READ) }
< Ropen { tag=0 qid={ type=(DIR) vers=1 path=1 } iounit=0 }
> Tread { tag=0 fid=1 offset=0 count=4096 }
-< Rread { tag=0 count=428 data=<bytedata> }
-> Tread { tag=0 fid=1 offset=428 count=4096 }
+< Rread { tag=0 count=648 data=<bytedata> }
+> Tread { tag=0 fid=1 offset=648 count=4096 }
< Rread { tag=0 count=0 data="" }
> Tclunk { tag=0 fid=1 }
< Rclunk { tag=0 }
> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" }
< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" }
> Tauth { tag=0 afid=0 uname="nobody" aname="" n_uid=0 }
-< Rerror { tag=0 errstr="authentication not required" errnum=95 }
+< Rerror { tag=0 errstr="authentication not required" errnum=L_EOPNOTSUPP }
> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" n_uid=0 }
< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
-> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=["Documentation" ] }
-< Rwalk { tag=0 nwqid=1 wqid=[{ type=(DIR) vers=1 path=2 } ] }
+> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=[ "Documentation" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[ { type=(DIR) vers=1 path=2 } ] }
> Tstat { tag=0 fid=1 }
< Rstat { tag=0 stat={ kern_type=0 kern_dev=0 file_qid={ type=(DIR) vers=1 path=2 } file_mode=(DIR|0555) file_atime=1728337905 file_mtime=1728337904 file_size=0 file_name="Documentation" file_owner_uid="root" file_owner_gid="root" file_last_modified_uid="root" file_extension="" file_owner_n_uid=0 file_owner_n_gid=0 file_last_modified_n_uid=0 } }
> Tclunk { tag=0 fid=1 }
< Rclunk { tag=0 }
-> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=["Documentation" ] }
-< Rwalk { tag=0 nwqid=1 wqid=[{ type=(DIR) vers=1 path=2 } ] }
+> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=[ "Documentation" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[ { type=(DIR) vers=1 path=2 } ] }
> Topen { tag=0 fid=1 mode=(MODE_READ) }
< Ropen { tag=0 qid={ type=(DIR) vers=1 path=2 } iounit=0 }
> Tread { tag=0 fid=1 offset=0 count=4096 }
@@ -49,11 +49,11 @@
> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" }
< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" }
> Tauth { tag=0 afid=0 uname="nobody" aname="" n_uid=0 }
-< Rerror { tag=0 errstr="authentication not required" errnum=95 }
+< Rerror { tag=0 errstr="authentication not required" errnum=L_EOPNOTSUPP }
> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" n_uid=0 }
< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
-> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=["README.md" ] }
-< Rwalk { tag=0 nwqid=1 wqid=[{ type=(0) vers=1 path=4 } ] }
+> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=[ "README.md" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=4 } ] }
> Topen { tag=0 fid=1 mode=(MODE_READ) }
< Ropen { tag=0 qid={ type=(0) vers=1 path=4 } iounit=0 }
> Tread { tag=0 fid=1 offset=0 count=4096 }
@@ -65,11 +65,11 @@
> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" }
< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" }
> Tauth { tag=0 afid=0 uname="nobody" aname="" n_uid=0 }
-< Rerror { tag=0 errstr="authentication not required" errnum=95 }
+< Rerror { tag=0 errstr="authentication not required" errnum=L_EOPNOTSUPP }
> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" n_uid=0 }
< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
-> Twalk { tag=0 fid=0 newfid=1 nwname=2 wname=["Documentation", "x" ] }
-< Rwalk { tag=0 nwqid=2 wqid=[{ type=(DIR) vers=1 path=2 }, { type=(0) vers=1 path=3 } ] }
+> Twalk { tag=0 fid=0 newfid=1 nwname=2 wname=[ "Documentation", "x" ] }
+< Rwalk { tag=0 nwqid=2 wqid=[ { type=(DIR) vers=1 path=2 }, { type=(0) vers=1 path=3 } ] }
> Topen { tag=0 fid=1 mode=(MODE_READ) }
< Ropen { tag=0 qid={ type=(0) vers=1 path=3 } iounit=0 }
> Tread { tag=0 fid=1 offset=0 count=4096 }
@@ -81,11 +81,11 @@
> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" }
< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" }
> Tauth { tag=0 afid=0 uname="nobody" aname="" n_uid=0 }
-< Rerror { tag=0 errstr="authentication not required" errnum=95 }
+< Rerror { tag=0 errstr="authentication not required" errnum=L_EOPNOTSUPP }
> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" n_uid=0 }
< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
-> Twalk { tag=0 fid=0 newfid=1 nwname=2 wname=["Documentation", "x" ] }
-< Rwalk { tag=0 nwqid=2 wqid=[{ type=(DIR) vers=1 path=2 }, { type=(0) vers=1 path=3 } ] }
+> Twalk { tag=0 fid=0 newfid=1 nwname=2 wname=[ "Documentation", "x" ] }
+< Rwalk { tag=0 nwqid=2 wqid=[ { type=(DIR) vers=1 path=2 }, { type=(0) vers=1 path=3 } ] }
> Tstat { tag=0 fid=1 }
< Rstat { tag=0 stat={ kern_type=0 kern_dev=0 file_qid={ type=(0) vers=1 path=3 } file_mode=(0444) file_atime=1728337905 file_mtime=1728337904 file_size=166 file_name="x" file_owner_uid="root" file_owner_gid="root" file_last_modified_uid="root" file_extension="" file_owner_n_uid=0 file_owner_n_gid=0 file_last_modified_n_uid=0 } }
> Tclunk { tag=0 fid=1 }
@@ -93,11 +93,11 @@
> Tversion { tag=NOTAG max_msg_size=8192 version="9P2000" }
< Rversion { tag=NOTAG max_msg_size=4120 version="9P2000" }
> Tauth { tag=0 afid=0 uname="nobody" aname="" n_uid=0 }
-< Rerror { tag=0 errstr="authentication not required" errnum=95 }
+< Rerror { tag=0 errstr="authentication not required" errnum=L_EOPNOTSUPP }
> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" n_uid=0 }
< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
-> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=["shutdown" ] }
-< Rwalk { tag=0 nwqid=1 wqid=[{ type=(0) vers=1 path=5 } ] }
+> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=[ "shutdown" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=5 } ] }
> Topen { tag=0 fid=1 mode=(TRUNC|MODE_WRITE) }
< Ropen { tag=0 qid={ type=(0) vers=1 path=5 } iounit=0 }
> Twrite { tag=0 fid=1 offset=0 count=2 data="1\n" }
diff --git a/lib9p/tests/testclient-sess.c b/lib9p/tests/testclient-sess.c
index 437c489..561c0c9 100644
--- a/lib9p/tests/testclient-sess.c
+++ b/lib9p/tests/testclient-sess.c
@@ -15,7 +15,7 @@
#include <libmisc/assert.h>
#include <libmisc/endian.h>
-#include <lib9p/9p.h>
+#include <lib9p/core.h>
#define MAX_MSG_SIZE (8*1024)
@@ -112,6 +112,56 @@ int main(int argc, char *argv[]) {
send9p(Tread, .tag=0, .fid=3, .offset=0, .count=100);
recv9p(); /* Rread */
+ /* walk ***************************************************************/
+ send9p(Tversion, .tag=0, .max_msg_size=(8*1024), .version=lib9p_str("9P2000"));
+ recv9p(); /* Rversion */
+ ctx.version = LIB9P_VER_9P2000;
+ send9p(Tattach, .tag=0, .fid=0, .afid=LIB9P_FID_NOFID, .uname=lib9p_str("nobody"), .aname=lib9p_str(""));
+ recv9p(); /* Rattach */
+
+ /* dup */
+ send9p(Twalk, .tag=0, .fid=0, .newfid=1, .nwname=0);
+ recv9p(); /* Rwalk */
+
+ /* "The walk request carries as arguments an existing fid"... */
+ send9p(Twalk, .tag=0, .fid=2, .newfid=3, .nwname=0);
+ recv9p(); /* Rerror */
+
+ /* ..."and a proposed newfid"... */
+ send9p(Twalk, .tag=0, .fid=1, .newfid=0xffffffff, .nwname=0);
+ recv9p(); /* Rerror */
+
+ /* ..."(which must not be in use"... */
+ send9p(Twalk, .tag=0, .fid=1, .newfid=0, .nwname=0);
+ recv9p(); /* Rerror */
+
+ /* ..."unless it is the same as fid)"... */
+ send9p(Twalk, .tag=0, .fid=1, .newfid=1, .nwname=0);
+ recv9p(); /* Rwalk */
+
+ /* ... "that the client wishes to associate with the result of
+ * traversing the directory hierarchy by `walking' the heierarchy using
+ * the successive path name elements wname."... */
+
+ /* ..."The fid must represent a directory"... */
+ wname[0] = lib9p_str("README.md"); send9p(Twalk, .tag=0, .fid=1, .newfid=2, .nwname=1, .wname=wname);
+ recv9p(); /* Rwalk */
+ wname[0] = lib9p_str(".."); send9p(Twalk, .tag=0, .fid=2, .newfid=3, .nwname=1, .wname=wname);
+ recv9p(); /* Rerror */
+
+ /* ..."unless zero path name elements are specified." */
+ send9p(Twalk, .tag=0, .fid=2, .newfid=3, .nwname=0);
+ recv9p(); /* Rwalk */
+
+ /* "The fid must be valid in the current session" (tested above)... */
+
+ /* ..."and must not have been opened for I/O by an open or create
+ * message."... */
+ send9p(Topen, .tag=0, .fid=3, .mode=LIB9P_O_MODE_READ);
+ recv9p(); /* Ropen */
+ send9p(Twalk, .tag=0, .fid=3, .newfid=4, .nwname=0);
+ recv9p(); /* Rerror */
+
/* flush **************************************************************/
send9p(Tversion, .tag=0, .max_msg_size=(8*1024), .version=lib9p_str("9P2000"));
recv9p(); /* Rversion */
@@ -120,29 +170,62 @@ int main(int argc, char *argv[]) {
recv9p(); /* Rattach */
/* flush, but original response comes back first */
- wname[0] = lib9p_str("slowread"); send9p(Twalk, .tag=0, .fid=0, .newfid=1, .nwname=1, .wname=wname);
+ wname[0] = lib9p_str("flush-read"); send9p(Twalk, .tag=0, .fid=0, .newfid=1, .nwname=1, .wname=wname);
recv9p(); /* Rwalk */
send9p(Topen, .tag=0, .fid=1, .mode=LIB9P_O_MODE_READ);
recv9p(); /* Ropen */
- send9p(Tread, .tag=1, .fid=1, .offset=0, .count=6);
- send9p(Tflush, .tag=2, .oldtag=1);
+ send9p(Tread, .tag=0, .fid=1, .offset=0, .count=10);
+ send9p(Tflush, .tag=1, .oldtag=0);
recv9p(); /* Rread */
recv9p(); /* Rflush */
/* flush, original request is aborted with error */
- wname[0] = lib9p_str("slowread-flushable"); send9p(Twalk, .tag=1, .fid=0, .newfid=2, .nwname=1, .wname=wname);
+ wname[0] = lib9p_str("flush-error"); send9p(Twalk, .tag=0, .fid=0, .newfid=2, .nwname=1, .wname=wname);
recv9p(); /* Rwalk */
send9p(Topen, .tag=0, .fid=2, .mode=LIB9P_O_MODE_READ);
recv9p(); /* Ropen */
- send9p(Tread, .tag=1, .fid=2, .offset=0, .count=6);
- send9p(Tflush, .tag=2, .oldtag=1);
+ send9p(Tread, .tag=0, .fid=2, .offset=0, .count=10);
+ send9p(Tflush, .tag=1, .oldtag=0);
recv9p(); /* Rerror */
recv9p(); /* Rflush */
+ /* flush, original request is aborted without error */
+ wname[0] = lib9p_str("flush-silent"); send9p(Twalk, .tag=0, .fid=0, .newfid=3, .nwname=1, .wname=wname);
+ recv9p(); /* Rwalk */
+ send9p(Topen, .tag=0, .fid=3, .mode=LIB9P_O_MODE_READ);
+ recv9p(); /* Ropen */
+ send9p(Tread, .tag=0, .fid=3, .offset=0, .count=10);
+ send9p(Tflush, .tag=1, .oldtag=0);
+ recv9p(); /* Rflush */
+
+ /* multiflush, original request is aborted without error */
+ wname[0] = lib9p_str("flush-slowsilent"); send9p(Twalk, .tag=0, .fid=0, .newfid=4, .nwname=1, .wname=wname);
+ recv9p(); /* Rwalk */
+ send9p(Topen, .tag=0, .fid=4, .mode=LIB9P_O_MODE_READ);
+ recv9p(); /* Ropen */
+ send9p(Tread, .tag=0, .fid=4, .offset=0, .count=10);
+ send9p(Tflush, .tag=1, .oldtag=0);
+ send9p(Tflush, .tag=2, .oldtag=0);
+ recv9p(); /* Rflush */
+
+ /* flush, but flush is flushed */
+ wname[0] = lib9p_str("flush-slowread"); send9p(Twalk, .tag=0, .fid=0, .newfid=5, .nwname=1, .wname=wname);
+ recv9p(); /* Rwalk */
+ send9p(Topen, .tag=0, .fid=5, .mode=LIB9P_O_MODE_READ);
+ recv9p(); /* Ropen */
+ send9p(Tread, .tag=0, .fid=5, .offset=0, .count=10);
+ send9p(Tflush, .tag=1, .oldtag=0);
+ send9p(Tflush, .tag=2, .oldtag=1);
+ recv9p(); /* Rflush */
+ recv9p(); /* Rread */
+
/* flush, unknown tag */
send9p(Tflush, .tag=0, .oldtag=99);
recv9p(); /* Rflush */
+ /* flushed by Tversion */
+ send9p(Tread, .tag=0, .fid=3, .offset=0, .count=10);
+
/* shutdown ***********************************************************/
send9p(Tversion, .tag=0, .max_msg_size=(8*1024), .version=lib9p_str("9P2000"));
recv9p(); /* Rversion */
diff --git a/lib9p/tests/testclient-sess.explog b/lib9p/tests/testclient-sess.explog
index 6aab242..74a2cd7 100644
--- a/lib9p/tests/testclient-sess.explog
+++ b/lib9p/tests/testclient-sess.explog
@@ -18,10 +18,10 @@
< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
> Tattach { tag=0 fid=1 afid=NOFID uname="bob" aname="" n_uid=1001 }
< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
-> Twalk { tag=0 fid=0 newfid=2 nwname=1 wname=["whoami" ] }
-< Rwalk { tag=0 nwqid=1 wqid=[{ type=(0) vers=1 path=8 } ] }
-> Twalk { tag=0 fid=1 newfid=3 nwname=1 wname=["whoami" ] }
-< Rwalk { tag=0 nwqid=1 wqid=[{ type=(0) vers=1 path=8 } ] }
+> Twalk { tag=0 fid=0 newfid=2 nwname=1 wname=[ "whoami" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=8 } ] }
+> Twalk { tag=0 fid=1 newfid=3 nwname=1 wname=[ "whoami" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=8 } ] }
> Topen { tag=0 fid=2 mode=(MODE_READ) }
< Ropen { tag=0 qid={ type=(0) vers=1 path=8 } iounit=0 }
> Topen { tag=0 fid=3 mode=(MODE_READ) }
@@ -31,6 +31,55 @@
> Tread { tag=0 fid=3 offset=0 count=100 }
< Rread { tag=0 count=9 data="1001 bob\n" }
+# walk #########################################################################
+> Tversion { tag=0 max_msg_size=8192 version="9P2000" }
+< Rversion { tag=0 max_msg_size=4120 version="9P2000" }
+> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" n_uid=0 }
+< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
+
+# dup
+> Twalk { tag=0 fid=0 newfid=1 nwname=0 wname=[ ] }
+< Rwalk { tag=0 nwqid=0 wqid=[ ] }
+
+# "The walk request carries as arguments an existing fid"...
+> Twalk { tag=0 fid=2 newfid=3 nwname=0 wname=[ ] }
+< Rerror { tag=0 errstr="bad file number 2" errnum=L_EBADF }
+
+# ..."and a proposed newfid"...
+> Twalk { tag=0 fid=1 newfid=NOFID nwname=0 wname=[ ] }
+< Rerror { tag=0 errstr="cannot assign to NOFID" errnum=L_EBADF }
+
+# ..."(which must not be in use"...
+> Twalk { tag=0 fid=1 newfid=0 nwname=0 wname=[ ] }
+< Rerror { tag=0 errstr="FID already in use" errnum=L_EBADF }
+
+# ..."unless it is the same as fid)"...
+> Twalk { tag=0 fid=1 newfid=1 nwname=0 wname=[ ] }
+< Rwalk { tag=0 nwqid=0 wqid=[ ] }
+
+# ... "that the client wishes to associate with the result of
+# traversing the directory hierarchy by `walking' the heierarchy using
+# the successive path name elements wname."...
+
+# ..."The fid must represent a directory"...
+> Twalk { tag=0 fid=1 newfid=2 nwname=1 wname=[ "README.md" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=4 } ] }
+> Twalk { tag=0 fid=2 newfid=3 nwname=1 wname=[ ".." ] }
+< Rerror { tag=0 errstr="not a directory" errnum=L_ENOTDIR }
+
+# ..."unless zero path name elements are specified."
+> Twalk { tag=0 fid=2 newfid=3 nwname=0 wname=[ ] }
+< Rwalk { tag=0 nwqid=0 wqid=[ ] }
+
+# "The fid must be valid in the current session" (tested above)...
+
+# ..."and must not have been opened for I/O by an open or create
+# message."...
+> Topen { tag=0 fid=3 mode=(MODE_READ) }
+< Ropen { tag=0 qid={ type=(0) vers=1 path=4 } iounit=0 }
+> Twalk { tag=0 fid=3 newfid=4 nwname=0 wname=[ ] }
+< Rerror { tag=0 errstr="cannot walk on FID open for I/O" errnum=L_EALREADY }
+
# flush ########################################################################
> Tversion { tag=0 max_msg_size=8192 version="9P2000" }
< Rversion { tag=0 max_msg_size=4120 version="9P2000" }
@@ -38,36 +87,69 @@
< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
# flush, but original response comes back first
-> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=["slowread" ] }
-< Rwalk { tag=0 nwqid=1 wqid=[{ type=(0) vers=1 path=6 } ] }
+> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=[ "flush-read" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=9 } ] }
> Topen { tag=0 fid=1 mode=(MODE_READ) }
-< Ropen { tag=0 qid={ type=(0) vers=1 path=6 } iounit=0 }
-> Tread { tag=1 fid=1 offset=0 count=6 }
-> Tflush { tag=2 oldtag=1 }
-< Rread { tag=1 count=6 data="Sloth\n" }
-< Rflush { tag=2 }
+< Ropen { tag=0 qid={ type=(0) vers=1 path=9 } iounit=0 }
+> Tread { tag=0 fid=1 offset=0 count=10 }
+> Tflush { tag=1 oldtag=0 }
+< Rread { tag=0 count=6 data="Sloth\n" }
+< Rflush { tag=1 }
-# flush, succeeds
-> Twalk { tag=1 fid=0 newfid=2 nwname=1 wname=["slowread-flushable" ] }
-< Rwalk { tag=1 nwqid=1 wqid=[{ type=(0) vers=1 path=7 } ] }
+# flush, original request is aborted with error
+> Twalk { tag=0 fid=0 newfid=2 nwname=1 wname=[ "flush-error" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=10 } ] }
> Topen { tag=0 fid=2 mode=(MODE_READ) }
-< Ropen { tag=0 qid={ type=(0) vers=1 path=7 } iounit=0 }
-> Tread { tag=1 fid=2 offset=0 count=6 }
+< Ropen { tag=0 qid={ type=(0) vers=1 path=10 } iounit=0 }
+> Tread { tag=0 fid=2 offset=0 count=10 }
+> Tflush { tag=1 oldtag=0 }
+< Rerror { tag=0 errstr="request canceled by flush" errnum=L_ECANCELED }
+< Rflush { tag=1 }
+
+# flush, original request is aborted without error
+> Twalk { tag=0 fid=0 newfid=3 nwname=1 wname=[ "flush-silent" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=11 } ] }
+> Topen { tag=0 fid=3 mode=(MODE_READ) }
+< Ropen { tag=0 qid={ type=(0) vers=1 path=11 } iounit=0 }
+> Tread { tag=0 fid=3 offset=0 count=10 }
+> Tflush { tag=1 oldtag=0 }
+< Rflush { tag=1 }
+
+# multiflush, original request is aborted without error
+> Twalk { tag=0 fid=0 newfid=4 nwname=1 wname=[ "flush-slowsilent" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=12 } ] }
+> Topen { tag=0 fid=4 mode=(MODE_READ) }
+< Ropen { tag=0 qid={ type=(0) vers=1 path=12 } iounit=0 }
+> Tread { tag=0 fid=4 offset=0 count=10 }
+> Tflush { tag=1 oldtag=0 }
+> Tflush { tag=2 oldtag=0 }
+< Rflush { tag=2 }
+
+# flush, but flush is flushed
+> Twalk { tag=0 fid=0 newfid=5 nwname=1 wname=[ "flush-slowread" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=13 } ] }
+> Topen { tag=0 fid=5 mode=(MODE_READ) }
+< Ropen { tag=0 qid={ type=(0) vers=1 path=13 } iounit=0 }
+> Tread { tag=0 fid=5 offset=0 count=10 }
+> Tflush { tag=1 oldtag=0 }
> Tflush { tag=2 oldtag=1 }
< Rflush { tag=2 }
-< Rerror { tag=1 errstr="request canceled by flush" errnum=125 }
+< Rread { tag=0 count=6 data="Sloth\n" }
# flush, unknown tag
> Tflush { tag=0 oldtag=99 }
< Rflush { tag=0 }
+# flushed by Tversion
+> Tread { tag=0 fid=3 offset=0 count=10 }
+
# shutdown #####################################################################
> Tversion { tag=0 max_msg_size=8192 version="9P2000" }
< Rversion { tag=0 max_msg_size=4120 version="9P2000" }
> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" n_uid=0 }
< Rattach { tag=0 qid={ type=(DIR) vers=1 path=1 } }
-> Twalk { tag=0 fid=0 newfid=0 nwname=1 wname=["shutdown" ] }
-< Rwalk { tag=0 nwqid=1 wqid=[{ type=(0) vers=1 path=5 } ] }
+> Twalk { tag=0 fid=0 newfid=0 nwname=1 wname=[ "shutdown" ] }
+< Rwalk { tag=0 nwqid=1 wqid=[ { type=(0) vers=1 path=5 } ] }
> Topen { tag=0 fid=0 mode=(MODE_WRITE) }
< Ropen { tag=0 qid={ type=(0) vers=1 path=5 } iounit=0 }
> Twrite { tag=0 fid=0 offset=0 count=2 data="1\n" }