M README.md => README.md +21 -4
@@ 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
A examples/dial.c => examples/dial.c +50 -0
@@ 0,0 1,50 @@
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <unistd.h>
+
+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;
+}
A examples/fs9ptest.c => examples/fs9ptest.c +52 -0
@@ 0,0 1,52 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+#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;
+}
A examples/sockets.c => examples/sockets.c +127 -0
@@ 0,0 1,127 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#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;
+}
A fs9p.c => fs9p.c +301 -0
@@ 0,0 1,301 @@
+#include <stdint.h>
+#include <string.h>
+#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;
+}
A include/c9/fs.h => include/c9/fs.h +48 -0
@@ 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;
+};
A include/c9/fs9p.h => include/c9/fs9p.h +31 -0
@@ 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)));
R c9.h => include/c9/proto.h +6 -10
@@ 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
};
};
R c9.c => proto.c +40 -52
@@ 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 <u.h>
-#include <libc.h>
-#else
#include <stdint.h>
#include <string.h>
-#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<<m) != 0){
- c->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;
}