From e5e39adf2d8810e8a0aca2acf4e825ebcb21e3ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sigrid=20Solveig=20Hafl=C3=ADnud=C3=B3ttir?= Date: Sun, 26 Jun 2022 22:47:35 +0000 Subject: [PATCH] wip revamping --- README.md | 25 ++- examples/dial.c | 50 ++++++ examples/fs9ptest.c | 52 +++++++ examples/sockets.c | 127 ++++++++++++++++ fs9p.c | 301 +++++++++++++++++++++++++++++++++++++ include/c9/fs.h | 48 ++++++ include/c9/fs9p.h | 31 ++++ c9.h => include/c9/proto.h | 16 +- c9.c => proto.c | 92 +++++------- 9 files changed, 676 insertions(+), 66 deletions(-) create mode 100644 examples/dial.c create mode 100644 examples/fs9ptest.c create mode 100644 examples/sockets.c create mode 100644 fs9p.c create mode 100644 include/c9/fs.h create mode 100644 include/c9/fs9p.h rename c9.h => include/c9/proto.h (97%) rename c9.c => proto.c (88%) diff --git a/README.md b/README.md index 2dcde0b..9b39ec6 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,25 @@ # c9 -Low level 9p client and server. +NOTE (2022-06-27): the library's (yep, it's going to be a library) +API is getting completely revamped, and examples are being added. +Use either an older version, or expect API breakage. -## Examples +A lightweight library for implmeneting 9p clients and servers in C. -Until I have time to write a minimal example you could take a look at -https://git.sr.ht/~ft/9pro/blob/master/9pex.c +This is 9p client and server implementation which aims to be correct, +small and secure, targetting mainly low-resource MCUs. + +`proto.[ch]`: lowest level of the library, contains nothing but +(de)serealization of the protocol messages and tag (de)allocation. + +`fs.h`: higher level, blocking file API based on POSIX. + +`fs9p.[ch]`: blocking file API implementation for 9p - having a +context created with `proto.[ch]` one can use POSIX-like file API to +work with a remote filesystem. + +Goals: + +* portability: zero external dependencies, no POSIX, just C +* no dynamic memory allocation +* security: no crashes due to incoming data diff --git a/examples/dial.c b/examples/dial.c new file mode 100644 index 0000000..777be23 --- /dev/null +++ b/examples/dial.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include +#include + +int +dial(const char *s) +{ + struct addrinfo *r, *a, hint = {.ai_flags = AI_ADDRCONFIG, .ai_family = AF_UNSPEC, 0}; + char host[128], *port; + int e, f; + + if(strncmp(s, "udp!", 4) == 0){ + hint.ai_socktype = SOCK_DGRAM; + hint.ai_protocol = IPPROTO_UDP; + }else if(strncmp(s, "tcp!", 4) == 0){ + hint.ai_socktype = SOCK_STREAM; + hint.ai_protocol = IPPROTO_TCP; + }else{ + fprintf(stderr, "invalid dial string: %s\n", s); + return -1; + } + if((port = strchr(s+4, '!')) == NULL){ + fprintf(stderr, "invalid dial string: %s\n", s); + return -1; + } + if(snprintf(host, sizeof(host), "%.*s", (int)(port-s-4), s+4) >= (int)sizeof(host)){ + fprintf(stderr, "host name too large: %s\n", s); + return -1; + } + port++; + if((e = getaddrinfo(host, port, &hint, &r)) != 0){ + fprintf(stderr, "%s: %s\n", gai_strerror(e), s); + return -1; + } + f = -1; + for(a = r; a != NULL; a = a->ai_next){ + if((f = socket(a->ai_family, a->ai_socktype, a->ai_protocol)) < 0) + continue; + if(connect(f, a->ai_addr, a->ai_addrlen) == 0) + break; + close(f); + f = -1; + } + freeaddrinfo(r); + + return f; +} diff --git a/examples/fs9ptest.c b/examples/fs9ptest.c new file mode 100644 index 0000000..e05a5e5 --- /dev/null +++ b/examples/fs9ptest.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include "c9/proto.h" +#include "c9/fs.h" +#include "c9/fs9p.h" + +int dial(const char *s); +C9ctx *init9p(int f); + +static FS9pfd fds[8]; + +static void +fserror(FS *fs, const char *fmt, ...) +{ + va_list ap; + + (void)fs; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +int +main(int argc, char **argv) +{ + C9ctx *ctx; + FSstat st; + FS fs; + FS9p fs9 = { + .fds = fds, + .numfds = sizeof(fds)/sizeof(fds[0]), + }; + int f; + + (void)argc; (void)argv; + + fs.error = fserror; + fs.aux = (void*)&fs9; + if((f = dial("tcp!ftrv.se!564")) < 0) + return 1; + ctx = init9p(f); + fs9.ctx = ctx; + if(fs9pinit(&fs, 8192) != 0) + return 1; + if(fs.fstat(&fs, FS9proot, &st) != 0) + return 1; + printf("%s %d %s %o\n", st.name, (int)st.size, st.uid, st.mode&0777); + + return 0; +} diff --git a/examples/sockets.c b/examples/sockets.c new file mode 100644 index 0000000..d014452 --- /dev/null +++ b/examples/sockets.c @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include +#include +#include "c9/proto.h" + +enum { + Msize = 8192, + + Disconnected = 1<<0, +}; + +typedef struct C9aux C9aux; + +struct C9aux { + C9ctx c; + int f; + int flags; + uint8_t rdbuf[Msize]; + uint8_t wrbuf[Msize]; + uint32_t wroff; +}; + +static uint8_t * +ctxread(C9ctx *ctx, uint32_t size, int *err) +{ + uint32_t n; + int r; + C9aux *a; + + a = ctx->aux; + *err = 0; + for(n = 0; n < size; n += r){ + if((r = read(a->f, a->rdbuf+n, size-n)) <= 0){ + if(errno == EINTR) + continue; + a->flags |= Disconnected; + close(a->f); + return NULL; + } + } + + return a->rdbuf; +} + +static int +wrsend(C9aux *a) +{ + uint32_t n; + int w; + + for(n = 0; n < a->wroff; n += w){ + if((w = write(a->f, a->wrbuf+n, a->wroff-n)) <= 0){ + if(errno == EINTR) + continue; + if(errno != EPIPE) /* remote end closed */ + perror("write"); + return -1; + } + } + a->wroff = 0; + + return 0; +} + +static uint8_t * +ctxbegin(C9ctx *ctx, uint32_t size) +{ + uint8_t *b; + C9aux *a; + + a = ctx->aux; + if(a->wroff + size > sizeof(a->wrbuf)){ + if(wrsend(a) != 0 || a->wroff + size > sizeof(a->wrbuf)) + return NULL; + } + b = a->wrbuf + a->wroff; + a->wroff += size; + + return b; +} + +static int +ctxend(C9ctx *ctx) +{ + C9aux *a; + + /* + * To batch up requests and instead flush them all at once just return 0 + * here and call wrsend yourself when needed. + */ + a = ctx->aux; + return wrsend(a); +} + +static void +ctxerror(C9ctx *ctx, const char *fmt, ...) +{ + va_list ap; + + (void)ctx; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +C9aux * +init9p(int f) +{ + C9aux *c; + + if((c = calloc(1, sizeof(*c))) == NULL){ + close(f); + return NULL; + } + c->f = f; + c->c.read = ctxread; + c->c.begin = ctxbegin; + c->c.end = ctxend; + c->c.error = ctxerror; + c->c.aux = c; + + return c; +} diff --git a/fs9p.c b/fs9p.c new file mode 100644 index 0000000..1d5ffec --- /dev/null +++ b/fs9p.c @@ -0,0 +1,301 @@ +#include +#include +#include "c9/proto.h" +#include "c9/fs.h" +#include "c9/fs9p.h" + +enum +{ + Flinit = 1<<0, + Flerror = 1<<1, + + F9init = 0, + F9chdir, + F9open, + F9create, + F9read, + F9readdir, + F9write, + F9seek, + F9stat, + F9fstat, + F9close, + F9remove, + F9rename, +}; + +static const FS9pfd freefd = +{ + .offset = ~0ULL, +}; + +#define isfree(fd) ((fd).offset == ~0ULL) + +static const char *f2s[] = +{ + [F9init] = "init", + [F9chdir] = "chdir", + [F9open] = "open", + [F9create] = "create", + [F9read] = "read", + [F9readdir] = "readdir", + [F9write] = "write", + [F9seek] = "seek", + [F9stat] = "stat", + [F9fstat] = "fstat", + [F9close] = "close", + [F9remove] = "remove", + [F9rename] = "rename", +}; + +static int +fs9pchdir(FS *fs, const char *path) +{ + FS9p *aux = (void*)fs->aux; + + aux->f = F9chdir; + + return -1; +} + +static int +fs9popen(FS *fs, const char *name, FSmode mode) +{ + FS9p *aux = (void*)fs->aux; + + aux->f = F9open; + + return -1; +} + +static int +fs9pcreate(FS *fs, const char *path, int perm) +{ + FS9p *aux = (void*)fs->aux; + + aux->f = F9create; + + return -1; +} + +static int64_t +fs9pread(FS *fs, int fd, void *buf, uint64_t count) +{ + FS9p *aux = (void*)fs->aux; + + aux->f = F9read; + + return -1; +} + +static int64_t +fs9preaddir(FS *fs, int fd, FSstat *st, int nst) +{ + FS9p *aux = (void*)fs->aux; + + aux->f = F9readdir; + + return -1; +} + +static int64_t +fs9pwrite(FS *fs, int fd, const void *buf, uint64_t count) +{ + FS9p *aux = (void*)fs->aux; + + aux->f = F9write; + + return -1; +} + +static int64_t +fs9pseek(FS *fs, int fd, int64_t offset, int whence) +{ + FS9p *aux = (void*)fs->aux; + + aux->f = F9seek; + + return -1; +} + +static int +fs9pstat(FS *fs, const char *path, FSstat *st) +{ + FS9p *aux = (void*)fs->aux; + + aux->f = F9stat; + + return -1; +} + +static int +fs9pfstat(FS *fs, int fd, FSstat *st) +{ + FS9p *aux = (void*)fs->aux; + C9tag tag; + int e; + + aux->f = F9fstat; + aux->p = st; + if((e = c9stat(aux->ctx, &tag, fd)) < 0) + return e; + while(aux->f != -F9fstat) + c9proc(aux->ctx); + + return 0; +} + +static int +fs9pclose(FS *fs, int fd) +{ + FS9p *aux = (void*)fs->aux; + + aux->f = F9close; + + return -1; +} + +static int +fs9premove(FS *fs, const char *name) +{ + FS9p *aux = (void*)fs->aux; + + aux->f = F9remove; + + return -1; +} + +static int +fs9prename(FS *fs, const char *oldpath, const char *newpath) +{ + FS9p *aux = (void*)fs->aux; + + aux->f = F9rename; + + return -1; +} + +static void +fs9pr(C9ctx *ctx, C9r *r) +{ + FSstat *st; + C9tag tag; + FS9p *aux; + FS *fs; + + fs = ctx->paux; + aux = (void*)fs->aux; + + switch(r->type){ + case Rversion: + c9attach(ctx, &tag, FS9proot, C9nofid, "none", NULL); /* FIXME those need to be configurable */ + break; + + case Rauth: + break; + + case Rattach: + aux->flags |= Flinit; + break; + + case Rerror: + fs->error(fs, "%s: %s", f2s[aux->f], r->error); + aux->flags |= Flerror; + break; + + case Rflush: + break; + + case Rwalk: + break; + + case Ropen: + break; + + case Rcreate: + break; + + case Rread: + break; + + case Rwrite: + break; + + case Rclunk: + break; + + case Rremove: + break; + + case Rstat: + if(aux->f == F9stat || aux->f == F9fstat){ + st = aux->p; + st->size = r->stat.size; + st->name = r->stat.name; + st->uid = r->stat.uid; + st->gid = r->stat.gid; + st->mode = r->stat.mode; + st->mtime = r->stat.mtime; + aux->f = -aux->f; + } + break; + + case Rwstat: + break; + } +} + +int +fs9pinit(FS *fs, uint32_t msize) +{ + FS9p *aux = (void*)fs->aux; + C9error err; + C9tag tag; + int i; + + if(fs->error == NULL) + return -1; + if(aux == NULL || aux->ctx == NULL || aux->fds == NULL || aux->numfds < 1){ + fs->error(fs, "fs9pinit: invalid aux"); + return -1; + } + if(aux->ctx == NULL){ + fs->error(fs, "fs9pinit: invalid ctx"); + return -1; + } + + fs->chdir = fs9pchdir; + fs->open = fs9popen; + fs->create = fs9pcreate; + fs->read = fs9pread; + fs->readdir = fs9preaddir; + fs->write = fs9pwrite; + fs->seek = fs9pseek; + fs->stat = fs9pstat; + fs->fstat = fs9pfstat; + fs->close = fs9pclose; + fs->remove = fs9premove; + fs->rename = fs9prename; + + aux->root.offset = 0; + for(i = 0; i < aux->numfds; i++) + aux->fds[i] = freefd; + + aux->ctx->r = fs9pr; + aux->ctx->paux = fs; + aux->f = F9init; + aux->flags = 0; + + if((err = c9version(aux->ctx, &tag, msize)) != 0) + return err; + for(;;){ + if((err = c9proc(aux->ctx)) != 0) + return err; + if(aux->flags & Flerror) + return -1; + if(aux->flags & Flinit) + break; + } + + return 0; +} diff --git a/include/c9/fs.h b/include/c9/fs.h new file mode 100644 index 0000000..54d7b69 --- /dev/null +++ b/include/c9/fs.h @@ -0,0 +1,48 @@ +typedef struct FS FS; +typedef struct FSstat FSstat; + +typedef enum +{ + FS_OREAD, + FS_OWRITE, + FS_ORDWR, + FS_OEXEC, + FS_OTRUNC = 0x10, + FS_ORCLOSE = 0x40, + FS_OEXCL = 0x1000, + FS_DIR = 0x80000000U, /* open/create: it's supposed to be a directory. */ +}FSmode; + +struct FSstat +{ + uint64_t size; /* Size of the file (in bytes). */ + char *name; /* Name of the file. */ + char *uid; /* Owner of the file. */ + char *gid; /* Group of the file. */ + uint32_t mode; /* Permissions. See C9st* and C9perm. */ + uint64_t mtime; /* Last modification time. Nanoseconds since epoch. */ +}; + +struct FSaux; + +struct FS +{ + /* Callback for error messages. */ + void (*error)(FS *fs, const char *fmt, ...) __attribute__((nonnull(1), format(printf, 2, 3))); + + /* Do not set these. */ + int (*chdir)(FS *fs, const char *path) __attribute__((nonnull(1, 2))); + int (*open)(FS *fs, const char *name, FSmode mode) __attribute__((nonnull(1, 2))); + int (*create)(FS *fs, const char *path, int perm) __attribute__((nonnull(1, 2))); + int64_t (*read)(FS *fs, int fd, void *buf, uint64_t count) __attribute__((nonnull(1, 3))); + int64_t (*readdir)(FS *fs, int fd, FSstat *st, int nst); + int64_t (*write)(FS *fs, int fd, const void *buf, uint64_t count) __attribute__((nonnull(1, 3))); + int64_t (*seek)(FS *fs, int fd, int64_t offset, int whence) __attribute__((nonnull(1))); + int (*stat)(FS *fs, const char *path, FSstat *st) __attribute__((nonnull(1, 2, 3))); + int (*fstat)(FS *fs, int fd, FSstat *st) __attribute__((nonnull(1, 3))); + int (*close)(FS *fs, int fd) __attribute__((nonnull(1))); + int (*remove)(FS *fs, const char *name) __attribute__((nonnull(1, 2))); + int (*rename)(FS *fs, const char *oldpath, const char *newpath) __attribute__((nonnull(1, 2, 3))); + + struct FSaux *aux; +}; diff --git a/include/c9/fs9p.h b/include/c9/fs9p.h new file mode 100644 index 0000000..d1b3a9c --- /dev/null +++ b/include/c9/fs9p.h @@ -0,0 +1,31 @@ +enum +{ + FS9proot = 3, /* '/' file descriptor. */ +}; + +typedef struct FS9p FS9p; +typedef struct FS9pfd FS9pfd; + +struct FS9pfd +{ + uint64_t offset; +}; + +struct FS9p +{ + /* The following three fields need to be set before calling fs9pinit. */ + + C9ctx *ctx; /* Set to a full set up context, except "r" and "t" fields. */ + FS9pfd *fds; /* Point at the allocated fds array. */ + int numfds; /* Set to the number of entries available in fds array. */ + void *aux; /* Optional, user-supplied aux value. */ + + /* Private, do not touch. */ + FS9pfd root; + FS9pfd cwd; + int f; + void *p; + int flags; +}; + +extern int fs9pinit(FS *fs, uint32_t msize) __attribute__((nonnull(1))); diff --git a/c9.h b/include/c9/proto.h similarity index 97% rename from c9.h rename to include/c9/proto.h index 8d87655..1f16d30 100644 --- a/c9.h +++ b/include/c9/proto.h @@ -1,12 +1,3 @@ -#ifdef __plan9__ -typedef u64int uint64_t; -typedef u32int uint32_t; -typedef u16int uint16_t; -typedef u8int uint8_t; -#define __attribute__(...) -#define NULL nil -#endif - struct C9aux; typedef struct C9r C9r; @@ -295,12 +286,13 @@ struct C9ctx void (*t)(C9ctx *ctx, C9t *t) __attribute__((nonnull(1, 2))); /* Callback for error messages. */ - void (*error)(const char *fmt, ...) __attribute__((nonnull(1), format(printf, 1, 2))); + void (*error)(C9ctx *ctx, const char *fmt, ...) __attribute__((nonnull(1), format(printf, 2, 3))); /* Auxiliary data, can be used by any of above callbacks. */ struct C9aux *aux; /* private stuff */ + void *paux; uint32_t msize; #ifndef C9_NO_CLIENT uint32_t flush[C9maxflush]; @@ -308,8 +300,12 @@ struct C9ctx #endif union { +#ifndef C9_NO_CLIENT C9tag lowfreetag; +#endif +#ifndef C9_NO_SERVER uint16_t svflags; +#endif }; }; diff --git a/c9.c b/proto.c similarity index 88% rename from c9.c rename to proto.c index e08919b..befb793 100644 --- a/c9.c +++ b/proto.c @@ -1,18 +1,6 @@ -/* - * This is 9p client and server implementation which aims to be - * correct, small and secure. It's the lowest level implementation. - * It doesn't have much comments, mostly because it doesn't make - * any sense to copy-paste protocol documentation, which - * you can read at http://man.cat-v.org/plan_9/5/, see 'intro'. - */ -#ifdef __plan9__ -#include -#include -#else #include #include -#endif -#include "c9.h" +#include "c9/proto.h" enum { @@ -138,7 +126,7 @@ newtag(C9ctx *c, C9ttype type, C9tag *tag) } } - c->error("newtag: no free tags"); + c->error(c, "newtag: no free tags"); return C9Etag; } @@ -148,11 +136,11 @@ freetag(C9ctx *c, C9tag tag) if(tag != 0xffff){ uint32_t d = tag / C9tagsbits, m = tag % C9tagsbits; if(tag >= C9maxtags){ - c->error("freetag: invalid tag %ud", (uint32_t)tag); + c->error(c, "freetag: invalid tag %ud", (uint32_t)tag); return -1; } if((c->tags[d] & 1<error("freetag: double free for tag %ud", (uint32_t)tag); + c->error(c, "freetag: double free for tag %ud", (uint32_t)tag); return -1; } if(c->lowfreetag > tag) @@ -168,12 +156,12 @@ T(C9ctx *c, uint32_t size, C9ttype type, C9tag *tag, C9error *err) uint8_t *p = NULL; if(size > c->msize-4-1-2){ - c->error("T: invalid size %ud", size); + c->error(c, "T: invalid size %ud", size); *err = C9Esize; }else if((*err = newtag(c, type, tag)) == 0){ size += 4+1+2; if((p = c->begin(c, size)) == NULL){ - c->error("T: no buffer for %ud bytes", size); + c->error(c, "T: no buffer for %ud bytes", size); freetag(c, *tag); *err = C9Ebuf; }else{ @@ -193,7 +181,7 @@ c9version(C9ctx *c, C9tag *tag, uint32_t msize) C9error err; if(msize < C9minmsize){ - c->error("c9version: msize too small: %ud", msize); + c->error(c, "c9version: msize too small: %ud", msize); return C9Einit; } memset(c->tags, 0xff, sizeof(c->tags)); @@ -217,7 +205,7 @@ c9auth(C9ctx *c, C9tag *tag, C9fid afid, const char *uname, const char *aname) C9error err; if(ulen > C9maxstr || alen > C9maxstr){ - c->error("c9auth: string too long: %ud chars", ulen > alen ? ulen : alen); + c->error(c, "c9auth: string too long: %ud chars", ulen > alen ? ulen : alen); return C9Estr; } if((b = T(c, 4+2+ulen+2+alen, Tauth, tag, &err)) != NULL){ @@ -238,7 +226,7 @@ c9flush(C9ctx *c, C9tag *tag, C9tag oldtag) for(i = 0; i < C9maxflush && c->flush[i] != (uint32_t)~0; i++); if(i == C9maxflush){ - c->error("c9flush: no free flush slots"); + c->error(c, "c9flush: no free flush slots"); return C9Eflush; } if((b = T(c, 2, Tflush, tag, &err)) != NULL){ @@ -258,7 +246,7 @@ c9attach(C9ctx *c, C9tag *tag, C9fid fid, C9fid afid, const char *uname, const c C9error err; if(ulen > C9maxstr || alen > C9maxstr){ - c->error("c9attach: string too long: %ud chars", ulen > alen ? ulen : alen); + c->error(c, "c9attach: string too long: %ud chars", ulen > alen ? ulen : alen); return C9Estr; } if((b = T(c, 4+4+2+ulen+2+alen, Tattach, tag, &err)) != NULL){ @@ -282,13 +270,13 @@ c9walk(C9ctx *c, C9tag *tag, C9fid fid, C9fid newfid, const char *path[]) for(sz = i = 0; i < (int)sizeof(len)/sizeof(len[0]) && path[i] != NULL; i++){ len[i] = safestrlen(path[i]); if(len[i] == 0 || len[i] > C9maxstr){ - c->error("c9walk: invalid path element: %ud chars", len[i]); + c->error(c, "c9walk: invalid path element: %ud chars", len[i]); return C9Epath; } sz += 2 + len[i]; } if(path[i] != NULL){ - c->error("c9walk: invalid elements !(0 <= %ud <= %ud)", i, C9maxpathel); + c->error(c, "c9walk: invalid elements !(0 <= %ud <= %ud)", i, C9maxpathel); return C9Epath; } @@ -325,7 +313,7 @@ c9create(C9ctx *c, C9tag *tag, C9fid fid, const char *name, uint32_t perm, C9mod C9error err; if(nlen == 0 || nlen > C9maxstr){ - c->error("c9create: invalid name: %ud chars", nlen); + c->error(c, "c9create: invalid name: %ud chars", nlen); return C9Epath; } if((b = T(c, 4+2+nlen+4+1, Tcreate, tag, &err)) != NULL){ @@ -423,11 +411,11 @@ c9wstat(C9ctx *c, C9tag *tag, C9fid fid, const C9stat *s) C9error err; if(nlen == 0 || nlen > C9maxstr){ - c->error("c9wstat: invalid name: %ud chars", nlen); + c->error(c, "c9wstat: invalid name: %ud chars", nlen); return C9Epath; } if(ulen > C9maxstr || glen > C9maxstr){ - c->error("c9wstat: string too long: %ud chars", ulen > glen ? ulen : glen); + c->error(c, "c9wstat: string too long: %ud chars", ulen > glen ? ulen : glen); return C9Estr; } if((b = T(c, 4+2+2+statsz, Twstat, tag, &err)) != NULL){ @@ -460,20 +448,20 @@ c9proc(C9ctx *c) err = -1; if((b = c->read(c, 4, &err)) == NULL){ if(err != 0) - c->error("c9proc: short read"); + c->error(c, "c9proc: short read"); return err == 0 ? 0 : C9Epkt; } sz = r32(&b); if(sz < 7 || sz > c->msize){ - c->error("c9proc: invalid packet size !(7 <= %ud <= %ud)", sz, c->msize); + c->error(c, "c9proc: invalid packet size !(7 <= %ud <= %ud)", sz, c->msize); return C9Epkt; } sz -= 4; err = -1; if((b = c->read(c, sz, &err)) == NULL){ if(err != 0) - c->error("c9proc: short read"); + c->error(c, "c9proc: short read"); return err == 0 ? 0 : C9Epkt; } @@ -481,7 +469,7 @@ c9proc(C9ctx *c) r.tag = r16(&b); if(r.type != Rversion){ if(r.tag >= C9maxtags){ - c->error("c9proc: invalid tag %ud", (uint32_t)r.tag); + c->error(c, "c9proc: invalid tag %ud", (uint32_t)r.tag); return C9Epkt; } if(freetag(c, r.tag) != 0) @@ -510,7 +498,7 @@ c9proc(C9ctx *c) if(sz < 2 || (cnt = r16(&b))*13 > sz-2) goto error; if(cnt > C9maxpathel){ - c->error("c9proc: Rwalk !(%ud <= %ud)", cnt, C9maxpathel); + c->error(c, "c9proc: Rwalk !(%ud <= %ud)", cnt, C9maxpathel); return C9Epath; } for(i = 0; i < cnt; i++){ @@ -580,7 +568,7 @@ c9proc(C9ctx *c) if(sz < 4+2 || (msize = r32(&b)) < C9minmsize || (cnt = r16(&b)) > sz-4-2) goto error; if(cnt < 6 || memcmp(b, "9P2000", 6) != 0){ - c->error("invalid version"); + c->error(c, "invalid version"); return C9Ever; } if(msize < c->msize) @@ -593,7 +581,7 @@ c9proc(C9ctx *c) } return 0; error: - c->error("c9proc: invalid packet type %ud", r.type); + c->error(c, "c9proc: invalid packet type %ud", r.type); return C9Epkt; } @@ -633,7 +621,7 @@ c9parsedir(C9ctx *c, C9stat *stat, uint8_t **t, uint32_t *size) *t += sz; return 0; error: - c->error("c9parsedir: invalid size: size=%ud sz=%ud", *size, sz); + c->error(c, "c9parsedir: invalid size: size=%ud sz=%ud", *size, sz); return C9Epkt; } @@ -645,12 +633,12 @@ R(C9ctx *c, uint32_t size, C9rtype type, C9tag tag, C9error *err) uint8_t *p = NULL; if(size > c->msize-4-1-2){ - c->error("R: invalid size %ud", size); + c->error(c, "R: invalid size %ud", size); *err = C9Esize; }else{ size += 4+1+2; if((p = c->begin(c, size)) == NULL){ - c->error("R: no buffer for %ud bytes", size); + c->error(c, "R: no buffer for %ud bytes", size); *err = C9Ebuf; }else{ *err = 0; @@ -699,7 +687,7 @@ s9error(C9ctx *c, C9tag tag, const char *ename) C9error err; if(len > C9maxstr){ - c->error("s9error: invalid ename: %ud chars", len); + c->error(c, "s9error: invalid ename: %ud chars", len); return C9Estr; } if((b = R(c, 2+len, Rerror, tag, &err)) != NULL){ @@ -743,7 +731,7 @@ s9walk(C9ctx *c, C9tag tag, C9qid *qids[]) for(n = 0; n < C9maxpathel && qids[n] != NULL; n++); if(n > C9maxpathel){ - c->error("s9walk: invalid elements !(0 <= %ud <= %ud)", n, C9maxpathel); + c->error(c, "s9walk: invalid elements !(0 <= %ud <= %ud)", n, C9maxpathel); return C9Epath; } @@ -839,13 +827,13 @@ s9readdir(C9ctx *c, C9tag tag, C9stat *st[], int *num, uint64_t *offset, uint32_ mulen = safestrlen(s->muid); if(nlen == 0 || nlen > C9maxstr){ - c->error("s9readdir: invalid name: %ud chars", nlen); + c->error(c, "s9readdir: invalid name: %ud chars", nlen); return C9Epath; } if(ulen > C9maxstr || glen > C9maxstr || mulen > C9maxstr){ ulen = ulen > glen ? ulen : glen; ulen = ulen > mulen ? ulen : mulen; - c->error("s9readdir: string too long: %ud chars", ulen); + c->error(c, "s9readdir: string too long: %ud chars", ulen); return C9Estr; } @@ -916,13 +904,13 @@ s9stat(C9ctx *c, C9tag tag, const C9stat *s) C9error err; if(nlen == 0 || nlen > C9maxstr){ - c->error("s9stat: invalid name: %ud chars", nlen); + c->error(c, "s9stat: invalid name: %ud chars", nlen); return C9Epath; } if(ulen > C9maxstr || glen > C9maxstr || mulen > C9maxstr){ ulen = ulen > glen ? ulen : glen; ulen = ulen > mulen ? ulen : mulen; - c->error("s9stat: string too long: %ud chars", ulen); + c->error(c, "s9stat: string too long: %ud chars", ulen); return C9Estr; } @@ -969,20 +957,20 @@ s9proc(C9ctx *c) readerr = -1; if((b = c->read(c, 4, &readerr)) == NULL){ if(readerr != 0) - c->error("s9proc: short read"); + c->error(c, "s9proc: short read"); return readerr == 0 ? 0 : C9Epkt; } sz = r32(&b); if(sz < 7 || sz > c->msize){ - c->error("s9proc: invalid packet size !(7 <= %ud <= %ud)", sz, c->msize); + c->error(c, "s9proc: invalid packet size !(7 <= %ud <= %ud)", sz, c->msize); return C9Epkt; } sz -= 4; readerr = -1; if((b = c->read(c, sz, &readerr)) == NULL){ if(readerr != 0) - c->error("s9proc: short read"); + c->error(c, "s9proc: short read"); return readerr == 0 ? 0 : C9Epkt; } @@ -991,7 +979,7 @@ s9proc(C9ctx *c) sz -= 3; if((c->svflags & Svver) == 0 && t.type != Tversion){ - c->error("s9proc: expected Tversion, got %ud", t.type); + c->error(c, "s9proc: expected Tversion, got %ud", t.type); return C9Epkt; } @@ -1035,7 +1023,7 @@ s9proc(C9ctx *c) t.fid = r32(&b); t.walk.newfid = r32(&b); if((n = r16(&b)) > 16){ - c->error("s9proc: Twalk !(%ud <= 16)", n); + c->error(c, "s9proc: Twalk !(%ud <= 16)", n); return C9Epath; } sz -= 4+4+2; @@ -1044,7 +1032,7 @@ s9proc(C9ctx *c) if(sz < 2 || (cnt = r16(&b)) > sz-2) goto error; if(cnt < 1){ - c->error("s9proc: Twalk invalid element [%ud]", i); + c->error(c, "s9proc: Twalk invalid element [%ud]", i); return C9Epath; } b[-2] = 0; @@ -1076,7 +1064,7 @@ s9proc(C9ctx *c) if((cnt = r16(&b)) > sz-4) goto error; if((err = c9parsedir(c, &t.wstat, &b, &cnt)) != 0){ - c->error("s9proc"); + c->error(c, "s9proc"); return err; } c->t(c, &t); @@ -1111,7 +1099,7 @@ s9proc(C9ctx *c) w32(&b, 0); wcs(&b, "unknown", 7); err = c->end(c); - c->error("s9proc: invalid version"); + c->error(c, "s9proc: invalid version"); } return C9Ever; } @@ -1169,7 +1157,7 @@ s9proc(C9ctx *c) } return 0; error: - c->error("s9proc: invalid packet (type=%ud)", t.type); + c->error(c, "s9proc: invalid packet (type=%ud)", t.type); return C9Epkt; } -- 2.45.2