Unified · Split
| @@ -1,8 +1,25 @@ | ||
| 1 | 1 | # c9 |
| 2 | 2 | |
| 3 | −Low level 9p client and server. | |
| 3 | +NOTE (2022-06-27): the library's (yep, it's going to be a library) | |
| 4 | +API is getting completely revamped, and examples are being added. | |
| 5 | +Use either an older version, or expect API breakage. | |
| 4 | 6 | |
| 5 | −## Examples | |
| 7 | +A lightweight library for implmeneting 9p clients and servers in C. | |
| 6 | 8 | |
| 7 | −Until I have time to write a minimal example you could take a look at | |
| 8 | −https://git.sr.ht/~ft/9pro/blob/master/9pex.c | |
| 9 | +This is 9p client and server implementation which aims to be correct, | |
| 10 | +small and secure, targetting mainly low-resource MCUs. | |
| 11 | + | |
| 12 | +`proto.[ch]`: lowest level of the library, contains nothing but | |
| 13 | +(de)serealization of the protocol messages and tag (de)allocation. | |
| 14 | + | |
| 15 | +`fs.h`: higher level, blocking file API based on POSIX. | |
| 16 | + | |
| 17 | +`fs9p.[ch]`: blocking file API implementation for 9p - having a | |
| 18 | +context created with `proto.[ch]` one can use POSIX-like file API to | |
| 19 | +work with a remote filesystem. | |
| 20 | + | |
| 21 | +Goals: | |
| 22 | + | |
| 23 | +* portability: zero external dependencies, no POSIX, just C | |
| 24 | +* no dynamic memory allocation | |
| 25 | +* security: no crashes due to incoming data | |
| @@ -0,0 +1,50 @@ | ||
| 1 | +#include <string.h> | |
| 2 | +#include <stdio.h> | |
| 3 | +#include <sys/types.h> | |
| 4 | +#include <sys/socket.h> | |
| 5 | +#include <netdb.h> | |
| 6 | +#include <unistd.h> | |
| 7 | + | |
| 8 | +int | |
| 9 | +dial(const char *s) | |
| 10 | +{ | |
| 11 | + struct addrinfo *r, *a, hint = {.ai_flags = AI_ADDRCONFIG, .ai_family = AF_UNSPEC, 0}; | |
| 12 | + char host[128], *port; | |
| 13 | + int e, f; | |
| 14 | + | |
| 15 | + if(strncmp(s, "udp!", 4) == 0){ | |
| 16 | + hint.ai_socktype = SOCK_DGRAM; | |
| 17 | + hint.ai_protocol = IPPROTO_UDP; | |
| 18 | + }else if(strncmp(s, "tcp!", 4) == 0){ | |
| 19 | + hint.ai_socktype = SOCK_STREAM; | |
| 20 | + hint.ai_protocol = IPPROTO_TCP; | |
| 21 | + }else{ | |
| 22 | + fprintf(stderr, "invalid dial string: %s\n", s); | |
| 23 | + return -1; | |
| 24 | + } | |
| 25 | + if((port = strchr(s+4, '!')) == NULL){ | |
| 26 | + fprintf(stderr, "invalid dial string: %s\n", s); | |
| 27 | + return -1; | |
| 28 | + } | |
| 29 | + if(snprintf(host, sizeof(host), "%.*s", (int)(port-s-4), s+4) >= (int)sizeof(host)){ | |
| 30 | + fprintf(stderr, "host name too large: %s\n", s); | |
| 31 | + return -1; | |
| 32 | + } | |
| 33 | + port++; | |
| 34 | + if((e = getaddrinfo(host, port, &hint, &r)) != 0){ | |
| 35 | + fprintf(stderr, "%s: %s\n", gai_strerror(e), s); | |
| 36 | + return -1; | |
| 37 | + } | |
| 38 | + f = -1; | |
| 39 | + for(a = r; a != NULL; a = a->ai_next){ | |
| 40 | + if((f = socket(a->ai_family, a->ai_socktype, a->ai_protocol)) < 0) | |
| 41 | + continue; | |
| 42 | + if(connect(f, a->ai_addr, a->ai_addrlen) == 0) | |
| 43 | + break; | |
| 44 | + close(f); | |
| 45 | + f = -1; | |
| 46 | + } | |
| 47 | + freeaddrinfo(r); | |
| 48 | + | |
| 49 | + return f; | |
| 50 | +} | |
| @@ -0,0 +1,52 @@ | ||
| 1 | +#include <stdio.h> | |
| 2 | +#include <stdint.h> | |
| 3 | +#include <stdarg.h> | |
| 4 | +#include "c9/proto.h" | |
| 5 | +#include "c9/fs.h" | |
| 6 | +#include "c9/fs9p.h" | |
| 7 | + | |
| 8 | +int dial(const char *s); | |
| 9 | +C9ctx *init9p(int f); | |
| 10 | + | |
| 11 | +static FS9pfd fds[8]; | |
| 12 | + | |
| 13 | +static void | |
| 14 | +fserror(FS *fs, const char *fmt, ...) | |
| 15 | +{ | |
| 16 | + va_list ap; | |
| 17 | + | |
| 18 | + (void)fs; | |
| 19 | + va_start(ap, fmt); | |
| 20 | + vfprintf(stderr, fmt, ap); | |
| 21 | + fprintf(stderr, "\n"); | |
| 22 | + va_end(ap); | |
| 23 | +} | |
| 24 | + | |
| 25 | +int | |
| 26 | +main(int argc, char **argv) | |
| 27 | +{ | |
| 28 | + C9ctx *ctx; | |
| 29 | + FSstat st; | |
| 30 | + FS fs; | |
| 31 | + FS9p fs9 = { | |
| 32 | + .fds = fds, | |
| 33 | + .numfds = sizeof(fds)/sizeof(fds[0]), | |
| 34 | + }; | |
| 35 | + int f; | |
| 36 | + | |
| 37 | + (void)argc; (void)argv; | |
| 38 | + | |
| 39 | + fs.error = fserror; | |
| 40 | + fs.aux = (void*)&fs9; | |
| 41 | + if((f = dial("tcp!ftrv.se!564")) < 0) | |
| 42 | + return 1; | |
| 43 | + ctx = init9p(f); | |
| 44 | + fs9.ctx = ctx; | |
| 45 | + if(fs9pinit(&fs, 8192) != 0) | |
| 46 | + return 1; | |
| 47 | + if(fs.fstat(&fs, FS9proot, &st) != 0) | |
| 48 | + return 1; | |
| 49 | + printf("%s %d %s %o\n", st.name, (int)st.size, st.uid, st.mode&0777); | |
| 50 | + | |
| 51 | + return 0; | |
| 52 | +} | |
| @@ -0,0 +1,127 @@ | ||
| 1 | +#include <stdio.h> | |
| 2 | +#include <stdint.h> | |
| 3 | +#include <stdarg.h> | |
| 4 | +#include <errno.h> | |
| 5 | +#include <unistd.h> | |
| 6 | +#include <stdlib.h> | |
| 7 | +#include "c9/proto.h" | |
| 8 | + | |
| 9 | +enum { | |
| 10 | + Msize = 8192, | |
| 11 | + | |
| 12 | + Disconnected = 1<<0, | |
| 13 | +}; | |
| 14 | + | |
| 15 | +typedef struct C9aux C9aux; | |
| 16 | + | |
| 17 | +struct C9aux { | |
| 18 | + C9ctx c; | |
| 19 | + int f; | |
| 20 | + int flags; | |
| 21 | + uint8_t rdbuf[Msize]; | |
| 22 | + uint8_t wrbuf[Msize]; | |
| 23 | + uint32_t wroff; | |
| 24 | +}; | |
| 25 | + | |
| 26 | +static uint8_t * | |
| 27 | +ctxread(C9ctx *ctx, uint32_t size, int *err) | |
| 28 | +{ | |
| 29 | + uint32_t n; | |
| 30 | + int r; | |
| 31 | + C9aux *a; | |
| 32 | + | |
| 33 | + a = ctx->aux; | |
| 34 | + *err = 0; | |
| 35 | + for(n = 0; n < size; n += r){ | |
| 36 | + if((r = read(a->f, a->rdbuf+n, size-n)) <= 0){ | |
| 37 | + if(errno == EINTR) | |
| 38 | + continue; | |
| 39 | + a->flags |= Disconnected; | |
| 40 | + close(a->f); | |
| 41 | + return NULL; | |
| 42 | + } | |
| 43 | + } | |
| 44 | + | |
| 45 | + return a->rdbuf; | |
| 46 | +} | |
| 47 | + | |
| 48 | +static int | |
| 49 | +wrsend(C9aux *a) | |
| 50 | +{ | |
| 51 | + uint32_t n; | |
| 52 | + int w; | |
| 53 | + | |
| 54 | + for(n = 0; n < a->wroff; n += w){ | |
| 55 | + if((w = write(a->f, a->wrbuf+n, a->wroff-n)) <= 0){ | |
| 56 | + if(errno == EINTR) | |
| 57 | + continue; | |
| 58 | + if(errno != EPIPE) /* remote end closed */ | |
| 59 | + perror("write"); | |
| 60 | + return -1; | |
| 61 | + } | |
| 62 | + } | |
| 63 | + a->wroff = 0; | |
| 64 | + | |
| 65 | + return 0; | |
| 66 | +} | |
| 67 | + | |
| 68 | +static uint8_t * | |
| 69 | +ctxbegin(C9ctx *ctx, uint32_t size) | |
| 70 | +{ | |
| 71 | + uint8_t *b; | |
| 72 | + C9aux *a; | |
| 73 | + | |
| 74 | + a = ctx->aux; | |
| 75 | + if(a->wroff + size > sizeof(a->wrbuf)){ | |
| 76 | + if(wrsend(a) != 0 || a->wroff + size > sizeof(a->wrbuf)) | |
| 77 | + return NULL; | |
| 78 | + } | |
| 79 | + b = a->wrbuf + a->wroff; | |
| 80 | + a->wroff += size; | |
| 81 | + | |
| 82 | + return b; | |
| 83 | +} | |
| 84 | + | |
| 85 | +static int | |
| 86 | +ctxend(C9ctx *ctx) | |
| 87 | +{ | |
| 88 | + C9aux *a; | |
| 89 | + | |
| 90 | + /* | |
| 91 | + * To batch up requests and instead flush them all at once just return 0 | |
| 92 | + * here and call wrsend yourself when needed. | |
| 93 | + */ | |
| 94 | + a = ctx->aux; | |
| 95 | + return wrsend(a); | |
| 96 | +} | |
| 97 | + | |
| 98 | +static void | |
| 99 | +ctxerror(C9ctx *ctx, const char *fmt, ...) | |
| 100 | +{ | |
| 101 | + va_list ap; | |
| 102 | + | |
| 103 | + (void)ctx; | |
| 104 | + va_start(ap, fmt); | |
| 105 | + vfprintf(stderr, fmt, ap); | |
| 106 | + fprintf(stderr, "\n"); | |
| 107 | + va_end(ap); | |
| 108 | +} | |
| 109 | + | |
| 110 | +C9aux * | |
| 111 | +init9p(int f) | |
| 112 | +{ | |
| 113 | + C9aux *c; | |
| 114 | + | |
| 115 | + if((c = calloc(1, sizeof(*c))) == NULL){ | |
| 116 | + close(f); | |
| 117 | + return NULL; | |
| 118 | + } | |
| 119 | + c->f = f; | |
| 120 | + c->c.read = ctxread; | |
| 121 | + c->c.begin = ctxbegin; | |
| 122 | + c->c.end = ctxend; | |
| 123 | + c->c.error = ctxerror; | |
| 124 | + c->c.aux = c; | |
| 125 | + | |
| 126 | + return c; | |
| 127 | +} | |
| @@ -0,0 +1,301 @@ | ||
| 1 | +#include <stdint.h> | |
| 2 | +#include <string.h> | |
| 3 | +#include "c9/proto.h" | |
| 4 | +#include "c9/fs.h" | |
| 5 | +#include "c9/fs9p.h" | |
| 6 | + | |
| 7 | +enum | |
| 8 | +{ | |
| 9 | + Flinit = 1<<0, | |
| 10 | + Flerror = 1<<1, | |
| 11 | + | |
| 12 | + F9init = 0, | |
| 13 | + F9chdir, | |
| 14 | + F9open, | |
| 15 | + F9create, | |
| 16 | + F9read, | |
| 17 | + F9readdir, | |
| 18 | + F9write, | |
| 19 | + F9seek, | |
| 20 | + F9stat, | |
| 21 | + F9fstat, | |
| 22 | + F9close, | |
| 23 | + F9remove, | |
| 24 | + F9rename, | |
| 25 | +}; | |
| 26 | + | |
| 27 | +static const FS9pfd freefd = | |
| 28 | +{ | |
| 29 | + .offset = ~0ULL, | |
| 30 | +}; | |
| 31 | + | |
| 32 | +#define isfree(fd) ((fd).offset == ~0ULL) | |
| 33 | + | |
| 34 | +static const char *f2s[] = | |
| 35 | +{ | |
| 36 | + [F9init] = "init", | |
| 37 | + [F9chdir] = "chdir", | |
| 38 | + [F9open] = "open", | |
| 39 | + [F9create] = "create", | |
| 40 | + [F9read] = "read", | |
| 41 | + [F9readdir] = "readdir", | |
| 42 | + [F9write] = "write", | |
| 43 | + [F9seek] = "seek", | |
| 44 | + [F9stat] = "stat", | |
| 45 | + [F9fstat] = "fstat", | |
| 46 | + [F9close] = "close", | |
| 47 | + [F9remove] = "remove", | |
| 48 | + [F9rename] = "rename", | |
| 49 | +}; | |
| 50 | + | |
| 51 | +static int | |
| 52 | +fs9pchdir(FS *fs, const char *path) | |
| 53 | +{ | |
| 54 | + FS9p *aux = (void*)fs->aux; | |
| 55 | + | |
| 56 | + aux->f = F9chdir; | |
| 57 | + | |
| 58 | + return -1; | |
| 59 | +} | |
| 60 | + | |
| 61 | +static int | |
| 62 | +fs9popen(FS *fs, const char *name, FSmode mode) | |
| 63 | +{ | |
| 64 | + FS9p *aux = (void*)fs->aux; | |
| 65 | + | |
| 66 | + aux->f = F9open; | |
| 67 | + | |
| 68 | + return -1; | |
| 69 | +} | |
| 70 | + | |
| 71 | +static int | |
| 72 | +fs9pcreate(FS *fs, const char *path, int perm) | |
| 73 | +{ | |
| 74 | + FS9p *aux = (void*)fs->aux; | |
| 75 | + | |
| 76 | + aux->f = F9create; | |
| 77 | + | |
| 78 | + return -1; | |
| 79 | +} | |
| 80 | + | |
| 81 | +static int64_t | |
| 82 | +fs9pread(FS *fs, int fd, void *buf, uint64_t count) | |
| 83 | +{ | |
| 84 | + FS9p *aux = (void*)fs->aux; | |
| 85 | + | |
| 86 | + aux->f = F9read; | |
| 87 | + | |
| 88 | + return -1; | |
| 89 | +} | |
| 90 | + | |
| 91 | +static int64_t | |
| 92 | +fs9preaddir(FS *fs, int fd, FSstat *st, int nst) | |
| 93 | +{ | |
| 94 | + FS9p *aux = (void*)fs->aux; | |
| 95 | + | |
| 96 | + aux->f = F9readdir; | |
| 97 | + | |
| 98 | + return -1; | |
| 99 | +} | |
| 100 | + | |
| 101 | +static int64_t | |
| 102 | +fs9pwrite(FS *fs, int fd, const void *buf, uint64_t count) | |
| 103 | +{ | |
| 104 | + FS9p *aux = (void*)fs->aux; | |
| 105 | + | |
| 106 | + aux->f = F9write; | |
| 107 | + | |
| 108 | + return -1; | |
| 109 | +} | |
| 110 | + | |
| 111 | +static int64_t | |
| 112 | +fs9pseek(FS *fs, int fd, int64_t offset, int whence) | |
| 113 | +{ | |
| 114 | + FS9p *aux = (void*)fs->aux; | |
| 115 | + | |
| 116 | + aux->f = F9seek; | |
| 117 | + | |
| 118 | + return -1; | |
| 119 | +} | |
| 120 | + | |
| 121 | +static int | |
| 122 | +fs9pstat(FS *fs, const char *path, FSstat *st) | |
| 123 | +{ | |
| 124 | + FS9p *aux = (void*)fs->aux; | |
| 125 | + | |
| 126 | + aux->f = F9stat; | |
| 127 | + | |
| 128 | + return -1; | |
| 129 | +} | |
| 130 | + | |
| 131 | +static int | |
| 132 | +fs9pfstat(FS *fs, int fd, FSstat *st) | |
| 133 | +{ | |
| 134 | + FS9p *aux = (void*)fs->aux; | |
| 135 | + C9tag tag; | |
| 136 | + int e; | |
| 137 | + | |
| 138 | + aux->f = F9fstat; | |
| 139 | + aux->p = st; | |
| 140 | + if((e = c9stat(aux->ctx, &tag, fd)) < 0) | |
| 141 | + return e; | |
| 142 | + while(aux->f != -F9fstat) | |
| 143 | + c9proc(aux->ctx); | |
| 144 | + | |
| 145 | + return 0; | |
| 146 | +} | |
| 147 | + | |
| 148 | +static int | |
| 149 | +fs9pclose(FS *fs, int fd) | |
| 150 | +{ | |
| 151 | + FS9p *aux = (void*)fs->aux; | |
| 152 | + | |
| 153 | + aux->f = F9close; | |
| 154 | + | |
| 155 | + return -1; | |
| 156 | +} | |
| 157 | + | |
| 158 | +static int | |
| 159 | +fs9premove(FS *fs, const char *name) | |
| 160 | +{ | |
| 161 | + FS9p *aux = (void*)fs->aux; | |
| 162 | + | |
| 163 | + aux->f = F9remove; | |
| 164 | + | |
| 165 | + return -1; | |
| 166 | +} | |
| 167 | + | |
| 168 | +static int | |
| 169 | +fs9prename(FS *fs, const char *oldpath, const char *newpath) | |
| 170 | +{ | |
| 171 | + FS9p *aux = (void*)fs->aux; | |
| 172 | + | |
| 173 | + aux->f = F9rename; | |
| 174 | + | |
| 175 | + return -1; | |
| 176 | +} | |
| 177 | + | |
| 178 | +static void | |
| 179 | +fs9pr(C9ctx *ctx, C9r *r) | |
| 180 | +{ | |
| 181 | + FSstat *st; | |
| 182 | + C9tag tag; | |
| 183 | + FS9p *aux; | |
| 184 | + FS *fs; | |
| 185 | + | |
| 186 | + fs = ctx->paux; | |
| 187 | + aux = (void*)fs->aux; | |
| 188 | + | |
| 189 | + switch(r->type){ | |
| 190 | + case Rversion: | |
| 191 | + c9attach(ctx, &tag, FS9proot, C9nofid, "none", NULL); /* FIXME those need to be configurable */ | |
| 192 | + break; | |
| 193 | + | |
| 194 | + case Rauth: | |
| 195 | + break; | |
| 196 | + | |
| 197 | + case Rattach: | |
| 198 | + aux->flags |= Flinit; | |
| 199 | + break; | |
| 200 | + | |
| 201 | + case Rerror: | |
| 202 | + fs->error(fs, "%s: %s", f2s[aux->f], r->error); | |
| 203 | + aux->flags |= Flerror; | |
| 204 | + break; | |
| 205 | + | |
| 206 | + case Rflush: | |
| 207 | + break; | |
| 208 | + | |
| 209 | + case Rwalk: | |
| 210 | + break; | |
| 211 | + | |
| 212 | + case Ropen: | |
| 213 | + break; | |
| 214 | + | |
| 215 | + case Rcreate: | |
| 216 | + break; | |
| 217 | + | |
| 218 | + case Rread: | |
| 219 | + break; | |
| 220 | + | |
| 221 | + case Rwrite: | |
| 222 | + break; | |
| 223 | + | |
| 224 | + case Rclunk: | |
| 225 | + break; | |
| 226 | + | |
| 227 | + case Rremove: | |
| 228 | + break; | |
| 229 | + | |
| 230 | + case Rstat: | |
| 231 | + if(aux->f == F9stat || aux->f == F9fstat){ | |
| 232 | + st = aux->p; | |
| 233 | + st->size = r->stat.size; | |
| 234 | + st->name = r->stat.name; | |
| 235 | + st->uid = r->stat.uid; | |
| 236 | + st->gid = r->stat.gid; | |
| 237 | + st->mode = r->stat.mode; | |
| 238 | + st->mtime = r->stat.mtime; | |
| 239 | + aux->f = -aux->f; | |
| 240 | + } | |
| 241 | + break; | |
| 242 | + | |
| 243 | + case Rwstat: | |
| 244 | + break; | |
| 245 | + } | |
| 246 | +} | |
| 247 | + | |
| 248 | +int | |
| 249 | +fs9pinit(FS *fs, uint32_t msize) | |
| 250 | +{ | |
| 251 | + FS9p *aux = (void*)fs->aux; | |
| 252 | + C9error err; | |
| 253 | + C9tag tag; | |
| 254 | + int i; | |
| 255 | + | |
| 256 | + if(fs->error == NULL) | |
| 257 | + return -1; | |
| 258 | + if(aux == NULL || aux->ctx == NULL || aux->fds == NULL || aux->numfds < 1){ | |
| 259 | + fs->error(fs, "fs9pinit: invalid aux"); | |
| 260 | + return -1; | |
| 261 | + } | |
| 262 | + if(aux->ctx == NULL){ | |
| 263 | + fs->error(fs, "fs9pinit: invalid ctx"); | |
| 264 | + return -1; | |
| 265 | + } | |
| 266 | + | |
| 267 | + fs->chdir = fs9pchdir; | |
| 268 | + fs->open = fs9popen; | |
| 269 | + fs->create = fs9pcreate; | |
| 270 | + fs->read = fs9pread; | |
| 271 | + fs->readdir = fs9preaddir; | |
| 272 | + fs->write = fs9pwrite; | |
| 273 | + fs->seek = fs9pseek; | |
| 274 | + fs->stat = fs9pstat; | |
| 275 | + fs->fstat = fs9pfstat; | |
| 276 | + fs->close = fs9pclose; | |
| 277 | + fs->remove = fs9premove; | |
| 278 | + fs->rename = fs9prename; | |
| 279 | + | |
| 280 | + aux->root.offset = 0; | |
| 281 | + for(i = 0; i < aux->numfds; i++) | |
| 282 | + aux->fds[i] = freefd; | |
| 283 | + | |
| 284 | + aux->ctx->r = fs9pr; | |
| 285 | + aux->ctx->paux = fs; | |
| 286 | + aux->f = F9init; | |
| 287 | + aux->flags = 0; | |
| 288 | + | |
| 289 | + if((err = c9version(aux->ctx, &tag, msize)) != 0) | |
| 290 | + return err; | |
| 291 | + for(;;){ | |
| 292 | + if((err = c9proc(aux->ctx)) != 0) | |
| 293 | + return err; | |
| 294 | + if(aux->flags & Flerror) | |
| 295 | + return -1; | |
| 296 | + if(aux->flags & Flinit) | |
| 297 | + break; | |
| 298 | + } | |
| 299 | + | |
| 300 | + return 0; | |
| 301 | +} | |
| @@ -0,0 +1,48 @@ | ||
| 1 | +typedef struct FS FS; | |
| 2 | +typedef struct FSstat FSstat; | |
| 3 | + | |
| 4 | +typedef enum | |
| 5 | +{ | |
| 6 | + FS_OREAD, | |
| 7 | + FS_OWRITE, | |
| 8 | + FS_ORDWR, | |
| 9 | + FS_OEXEC, | |
| 10 | + FS_OTRUNC = 0x10, | |
| 11 | + FS_ORCLOSE = 0x40, | |
| 12 | + FS_OEXCL = 0x1000, | |
| 13 | + FS_DIR = 0x80000000U, /* open/create: it's supposed to be a directory. */ | |
| 14 | +}FSmode; | |
| 15 | + | |
| 16 | +struct FSstat | |
| 17 | +{ | |
| 18 | + uint64_t size; /* Size of the file (in bytes). */ | |
| 19 | + char *name; /* Name of the file. */ | |
| 20 | + char *uid; /* Owner of the file. */ | |
| 21 | + char *gid; /* Group of the file. */ | |
| 22 | + uint32_t mode; /* Permissions. See C9st* and C9perm. */ | |
| 23 | + uint64_t mtime; /* Last modification time. Nanoseconds since epoch. */ | |
| 24 | +}; | |
| 25 | + | |
| 26 | +struct FSaux; | |
| 27 | + | |
| 28 | +struct FS | |
| 29 | +{ | |
| 30 | + /* Callback for error messages. */ | |
| 31 | + void (*error)(FS *fs, const char *fmt, ...) __attribute__((nonnull(1), format(printf, 2, 3))); | |
| 32 | + | |
| 33 | + /* Do not set these. */ | |
| 34 | + int (*chdir)(FS *fs, const char *path) __attribute__((nonnull(1, 2))); | |
| 35 | + int (*open)(FS *fs, const char *name, FSmode mode) __attribute__((nonnull(1, 2))); | |
| 36 | + int (*create)(FS *fs, const char *path, int perm) __attribute__((nonnull(1, 2))); | |
| 37 | + int64_t (*read)(FS *fs, int fd, void *buf, uint64_t count) __attribute__((nonnull(1, 3))); | |
| 38 | + int64_t (*readdir)(FS *fs, int fd, FSstat *st, int nst); | |
| 39 | + int64_t (*write)(FS *fs, int fd, const void *buf, uint64_t count) __attribute__((nonnull(1, 3))); | |
| 40 | + int64_t (*seek)(FS *fs, int fd, int64_t offset, int whence) __attribute__((nonnull(1))); | |
| 41 | + int (*stat)(FS *fs, const char *path, FSstat *st) __attribute__((nonnull(1, 2, 3))); | |
| 42 | + int (*fstat)(FS *fs, int fd, FSstat *st) __attribute__((nonnull(1, 3))); | |
| 43 | + int (*close)(FS *fs, int fd) __attribute__((nonnull(1))); | |
| 44 | + int (*remove)(FS *fs, const char *name) __attribute__((nonnull(1, 2))); | |
| 45 | + int (*rename)(FS *fs, const char *oldpath, const char *newpath) __attribute__((nonnull(1, 2, 3))); | |
| 46 | + | |
| 47 | + struct FSaux *aux; | |
| 48 | +}; | |
| @@ -0,0 +1,31 @@ | ||
| 1 | +enum | |
| 2 | +{ | |
| 3 | + FS9proot = 3, /* '/' file descriptor. */ | |
| 4 | +}; | |
| 5 | + | |
| 6 | +typedef struct FS9p FS9p; | |
| 7 | +typedef struct FS9pfd FS9pfd; | |
| 8 | + | |
| 9 | +struct FS9pfd | |
| 10 | +{ | |
| 11 | + uint64_t offset; | |
| 12 | +}; | |
| 13 | + | |
| 14 | +struct FS9p | |
| 15 | +{ | |
| 16 | + /* The following three fields need to be set before calling fs9pinit. */ | |
| 17 | + | |
| 18 | + C9ctx *ctx; /* Set to a full set up context, except "r" and "t" fields. */ | |
| 19 | + FS9pfd *fds; /* Point at the allocated fds array. */ | |
| 20 | + int numfds; /* Set to the number of entries available in fds array. */ | |
| 21 | + void *aux; /* Optional, user-supplied aux value. */ | |
| 22 | + | |
| 23 | + /* Private, do not touch. */ | |
| 24 | + FS9pfd root; | |
| 25 | + FS9pfd cwd; | |
| 26 | + int f; | |
| 27 | + void *p; | |
| 28 | + int flags; | |
| 29 | +}; | |
| 30 | + | |
| 31 | +extern int fs9pinit(FS *fs, uint32_t msize) __attribute__((nonnull(1))); | |
| @@ -1,12 +1,3 @@ | ||
| 1 | −#ifdef __plan9__ | |
| 2 | −typedef u64int uint64_t; | |
| 3 | −typedef u32int uint32_t; | |
| 4 | −typedef u16int uint16_t; | |
| 5 | −typedef u8int uint8_t; | |
| 6 | −#define __attribute__(...) | |
| 7 | −#define NULL nil | |
| 8 | −#endif | |
| 9 | − | |
| 10 | 1 | struct C9aux; |
| 11 | 2 | |
| 12 | 3 | typedef struct C9r C9r; |
| @@ -295,12 +286,13 @@ struct C9ctx · 282 unmodified lines | ||
| 295 | 286 | void (*t)(C9ctx *ctx, C9t *t) __attribute__((nonnull(1, 2))); |
| 296 | 287 | |
| 297 | 288 | /* Callback for error messages. */ |
| 298 | − void (*error)(const char *fmt, ...) __attribute__((nonnull(1), format(printf, 1, 2))); | |
| 289 | + void (*error)(C9ctx *ctx, const char *fmt, ...) __attribute__((nonnull(1), format(printf, 2, 3))); | |
| 299 | 290 | |
| 300 | 291 | /* Auxiliary data, can be used by any of above callbacks. */ |
| 301 | 292 | struct C9aux *aux; |
| 302 | 293 | |
| 303 | 294 | /* private stuff */ |
| 295 | + void *paux; | |
| 304 | 296 | uint32_t msize; |
| 305 | 297 | #ifndef C9_NO_CLIENT |
| 306 | 298 | uint32_t flush[C9maxflush]; |
| @@ -308,8 +300,12 @@ struct C9ctx · 1 unmodified line | ||
| 308 | 300 | #endif |
| 309 | 301 | union |
| 310 | 302 | { |
| 303 | +#ifndef C9_NO_CLIENT | |
| 311 | 304 | C9tag lowfreetag; |
| 305 | +#endif | |
| 306 | +#ifndef C9_NO_SERVER | |
| 312 | 307 | uint16_t svflags; |
| 308 | +#endif | |
| 313 | 309 | }; |
| 314 | 310 | }; |
| 315 | 311 | |
| @@ -1,18 +1,6 @@ | ||
| 1 | −/* | |
| 2 | − * This is 9p client and server implementation which aims to be | |
| 3 | − * correct, small and secure. It's the lowest level implementation. | |
| 4 | − * It doesn't have much comments, mostly because it doesn't make | |
| 5 | − * any sense to copy-paste protocol documentation, which | |
| 6 | − * you can read at http://man.cat-v.org/plan_9/5/, see 'intro'. | |
| 7 | − */ | |
| 8 | −#ifdef __plan9__ | |
| 9 | −#include <u.h> | |
| 10 | −#include <libc.h> | |
| 11 | −#else | |
| 12 | 1 | #include <stdint.h> |
| 13 | 2 | #include <string.h> |
| 14 | −#endif | |
| 15 | −#include "c9.h" | |
| 3 | +#include "c9/proto.h" | |
| 16 | 4 | |
| 17 | 5 | enum |
| 18 | 6 | { |
| @@ -138,7 +126,7 @@ newtag(C9ctx *c, C9ttype type, C9tag *tag) · 119 unmodified lines | ||
| 138 | 126 | } |
| 139 | 127 | } |
| 140 | 128 | |
| 141 | − c->error("newtag: no free tags"); | |
| 129 | + c->error(c, "newtag: no free tags"); | |
| 142 | 130 | return C9Etag; |
| 143 | 131 | } |
| 144 | 132 | |
| @@ -148,11 +136,11 @@ freetag(C9ctx *c, C9tag tag) · 3 unmodified lines | ||
| 148 | 136 | if(tag != 0xffff){ |
| 149 | 137 | uint32_t d = tag / C9tagsbits, m = tag % C9tagsbits; |
| 150 | 138 | if(tag >= C9maxtags){ |
| 151 | − c->error("freetag: invalid tag %ud", (uint32_t)tag); | |
| 139 | + c->error(c, "freetag: invalid tag %ud", (uint32_t)tag); | |
| 152 | 140 | return -1; |
| 153 | 141 | } |
| 154 | 142 | if((c->tags[d] & 1<<m) != 0){ |
| 155 | − c->error("freetag: double free for tag %ud", (uint32_t)tag); | |
| 143 | + c->error(c, "freetag: double free for tag %ud", (uint32_t)tag); | |
| 156 | 144 | return -1; |
| 157 | 145 | } |
| 158 | 146 | if(c->lowfreetag > tag) |
| @@ -168,12 +156,12 @@ T(C9ctx *c, uint32_t size, C9ttype type, C9tag *tag, C9error *err) · 9 unmodified lines | ||
| 168 | 156 | uint8_t *p = NULL; |
| 169 | 157 | |
| 170 | 158 | if(size > c->msize-4-1-2){ |
| 171 | − c->error("T: invalid size %ud", size); | |
| 159 | + c->error(c, "T: invalid size %ud", size); | |
| 172 | 160 | *err = C9Esize; |
| 173 | 161 | }else if((*err = newtag(c, type, tag)) == 0){ |
| 174 | 162 | size += 4+1+2; |
| 175 | 163 | if((p = c->begin(c, size)) == NULL){ |
| 176 | − c->error("T: no buffer for %ud bytes", size); | |
| 164 | + c->error(c, "T: no buffer for %ud bytes", size); | |
| 177 | 165 | freetag(c, *tag); |
| 178 | 166 | *err = C9Ebuf; |
| 179 | 167 | }else{ |
| @@ -193,7 +181,7 @@ c9version(C9ctx *c, C9tag *tag, uint32_t msize) · 13 unmodified lines | ||
| 193 | 181 | C9error err; |
| 194 | 182 | |
| 195 | 183 | if(msize < C9minmsize){ |
| 196 | − c->error("c9version: msize too small: %ud", msize); | |
| 184 | + c->error(c, "c9version: msize too small: %ud", msize); | |
| 197 | 185 | return C9Einit; |
| 198 | 186 | } |
| 199 | 187 | memset(c->tags, 0xff, sizeof(c->tags)); |
| @@ -217,7 +205,7 @@ c9auth(C9ctx *c, C9tag *tag, C9fid afid, const char *uname, const char *aname) · 17 unmodified lines | ||
| 217 | 205 | C9error err; |
| 218 | 206 | |
| 219 | 207 | if(ulen > C9maxstr || alen > C9maxstr){ |
| 220 | − c->error("c9auth: string too long: %ud chars", ulen > alen ? ulen : alen); | |
| 208 | + c->error(c, "c9auth: string too long: %ud chars", ulen > alen ? ulen : alen); | |
| 221 | 209 | return C9Estr; |
| 222 | 210 | } |
| 223 | 211 | if((b = T(c, 4+2+ulen+2+alen, Tauth, tag, &err)) != NULL){ |
| @@ -238,7 +226,7 @@ c9flush(C9ctx *c, C9tag *tag, C9tag oldtag) · 14 unmodified lines | ||
| 238 | 226 | |
| 239 | 227 | for(i = 0; i < C9maxflush && c->flush[i] != (uint32_t)~0; i++); |
| 240 | 228 | if(i == C9maxflush){ |
| 241 | − c->error("c9flush: no free flush slots"); | |
| 229 | + c->error(c, "c9flush: no free flush slots"); | |
| 242 | 230 | return C9Eflush; |
| 243 | 231 | } |
| 244 | 232 | 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 · 13 unmodified lines | ||
| 258 | 246 | C9error err; |
| 259 | 247 | |
| 260 | 248 | if(ulen > C9maxstr || alen > C9maxstr){ |
| 261 | − c->error("c9attach: string too long: %ud chars", ulen > alen ? ulen : alen); | |
| 249 | + c->error(c, "c9attach: string too long: %ud chars", ulen > alen ? ulen : alen); | |
| 262 | 250 | return C9Estr; |
| 263 | 251 | } |
| 264 | 252 | 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[]) · 17 unmodified lines | ||
| 282 | 270 | for(sz = i = 0; i < (int)sizeof(len)/sizeof(len[0]) && path[i] != NULL; i++){ |
| 283 | 271 | len[i] = safestrlen(path[i]); |
| 284 | 272 | if(len[i] == 0 || len[i] > C9maxstr){ |
| 285 | − c->error("c9walk: invalid path element: %ud chars", len[i]); | |
| 273 | + c->error(c, "c9walk: invalid path element: %ud chars", len[i]); | |
| 286 | 274 | return C9Epath; |
| 287 | 275 | } |
| 288 | 276 | sz += 2 + len[i]; |
| 289 | 277 | } |
| 290 | 278 | if(path[i] != NULL){ |
| 291 | − c->error("c9walk: invalid elements !(0 <= %ud <= %ud)", i, C9maxpathel); | |
| 279 | + c->error(c, "c9walk: invalid elements !(0 <= %ud <= %ud)", i, C9maxpathel); | |
| 292 | 280 | return C9Epath; |
| 293 | 281 | } |
| 294 | 282 | |
| @@ -325,7 +313,7 @@ c9create(C9ctx *c, C9tag *tag, C9fid fid, const char *name, uint32_t perm, C9mod · 30 unmodified lines | ||
| 325 | 313 | C9error err; |
| 326 | 314 | |
| 327 | 315 | if(nlen == 0 || nlen > C9maxstr){ |
| 328 | − c->error("c9create: invalid name: %ud chars", nlen); | |
| 316 | + c->error(c, "c9create: invalid name: %ud chars", nlen); | |
| 329 | 317 | return C9Epath; |
| 330 | 318 | } |
| 331 | 319 | 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) · 91 unmodified lines | ||
| 423 | 411 | C9error err; |
| 424 | 412 | |
| 425 | 413 | if(nlen == 0 || nlen > C9maxstr){ |
| 426 | − c->error("c9wstat: invalid name: %ud chars", nlen); | |
| 414 | + c->error(c, "c9wstat: invalid name: %ud chars", nlen); | |
| 427 | 415 | return C9Epath; |
| 428 | 416 | } |
| 429 | 417 | if(ulen > C9maxstr || glen > C9maxstr){ |
| 430 | − c->error("c9wstat: string too long: %ud chars", ulen > glen ? ulen : glen); | |
| 418 | + c->error(c, "c9wstat: string too long: %ud chars", ulen > glen ? ulen : glen); | |
| 431 | 419 | return C9Estr; |
| 432 | 420 | } |
| 433 | 421 | if((b = T(c, 4+2+2+statsz, Twstat, tag, &err)) != NULL){ |
| @@ -460,20 +448,20 @@ c9proc(C9ctx *c) · 26 unmodified lines | ||
| 460 | 448 | err = -1; |
| 461 | 449 | if((b = c->read(c, 4, &err)) == NULL){ |
| 462 | 450 | if(err != 0) |
| 463 | − c->error("c9proc: short read"); | |
| 451 | + c->error(c, "c9proc: short read"); | |
| 464 | 452 | return err == 0 ? 0 : C9Epkt; |
| 465 | 453 | } |
| 466 | 454 | |
| 467 | 455 | sz = r32(&b); |
| 468 | 456 | if(sz < 7 || sz > c->msize){ |
| 469 | − c->error("c9proc: invalid packet size !(7 <= %ud <= %ud)", sz, c->msize); | |
| 457 | + c->error(c, "c9proc: invalid packet size !(7 <= %ud <= %ud)", sz, c->msize); | |
| 470 | 458 | return C9Epkt; |
| 471 | 459 | } |
| 472 | 460 | sz -= 4; |
| 473 | 461 | err = -1; |
| 474 | 462 | if((b = c->read(c, sz, &err)) == NULL){ |
| 475 | 463 | if(err != 0) |
| 476 | − c->error("c9proc: short read"); | |
| 464 | + c->error(c, "c9proc: short read"); | |
| 477 | 465 | return err == 0 ? 0 : C9Epkt; |
| 478 | 466 | } |
| 479 | 467 | |
| @@ -481,7 +469,7 @@ c9proc(C9ctx *c) · 1 unmodified line | ||
| 481 | 469 | r.tag = r16(&b); |
| 482 | 470 | if(r.type != Rversion){ |
| 483 | 471 | if(r.tag >= C9maxtags){ |
| 484 | − c->error("c9proc: invalid tag %ud", (uint32_t)r.tag); | |
| 472 | + c->error(c, "c9proc: invalid tag %ud", (uint32_t)r.tag); | |
| 485 | 473 | return C9Epkt; |
| 486 | 474 | } |
| 487 | 475 | if(freetag(c, r.tag) != 0) |
| @@ -510,7 +498,7 @@ c9proc(C9ctx *c) · 22 unmodified lines | ||
| 510 | 498 | if(sz < 2 || (cnt = r16(&b))*13 > sz-2) |
| 511 | 499 | goto error; |
| 512 | 500 | if(cnt > C9maxpathel){ |
| 513 | − c->error("c9proc: Rwalk !(%ud <= %ud)", cnt, C9maxpathel); | |
| 501 | + c->error(c, "c9proc: Rwalk !(%ud <= %ud)", cnt, C9maxpathel); | |
| 514 | 502 | return C9Epath; |
| 515 | 503 | } |
| 516 | 504 | for(i = 0; i < cnt; i++){ |
| @@ -580,7 +568,7 @@ c9proc(C9ctx *c) · 63 unmodified lines | ||
| 580 | 568 | if(sz < 4+2 || (msize = r32(&b)) < C9minmsize || (cnt = r16(&b)) > sz-4-2) |
| 581 | 569 | goto error; |
| 582 | 570 | if(cnt < 6 || memcmp(b, "9P2000", 6) != 0){ |
| 583 | − c->error("invalid version"); | |
| 571 | + c->error(c, "invalid version"); | |
| 584 | 572 | return C9Ever; |
| 585 | 573 | } |
| 586 | 574 | if(msize < c->msize) |
| @@ -593,7 +581,7 @@ c9proc(C9ctx *c) · 6 unmodified lines | ||
| 593 | 581 | } |
| 594 | 582 | return 0; |
| 595 | 583 | error: |
| 596 | − c->error("c9proc: invalid packet type %ud", r.type); | |
| 584 | + c->error(c, "c9proc: invalid packet type %ud", r.type); | |
| 597 | 585 | return C9Epkt; |
| 598 | 586 | } |
| 599 | 587 | |
| @@ -633,7 +621,7 @@ c9parsedir(C9ctx *c, C9stat *stat, uint8_t **t, uint32_t *size) · 33 unmodified lines | ||
| 633 | 621 | *t += sz; |
| 634 | 622 | return 0; |
| 635 | 623 | error: |
| 636 | − c->error("c9parsedir: invalid size: size=%ud sz=%ud", *size, sz); | |
| 624 | + c->error(c, "c9parsedir: invalid size: size=%ud sz=%ud", *size, sz); | |
| 637 | 625 | return C9Epkt; |
| 638 | 626 | } |
| 639 | 627 | |
| @@ -645,12 +633,12 @@ R(C9ctx *c, uint32_t size, C9rtype type, C9tag tag, C9error *err) · 5 unmodified lines | ||
| 645 | 633 | uint8_t *p = NULL; |
| 646 | 634 | |
| 647 | 635 | if(size > c->msize-4-1-2){ |
| 648 | − c->error("R: invalid size %ud", size); | |
| 636 | + c->error(c, "R: invalid size %ud", size); | |
| 649 | 637 | *err = C9Esize; |
| 650 | 638 | }else{ |
| 651 | 639 | size += 4+1+2; |
| 652 | 640 | if((p = c->begin(c, size)) == NULL){ |
| 653 | − c->error("R: no buffer for %ud bytes", size); | |
| 641 | + c->error(c, "R: no buffer for %ud bytes", size); | |
| 654 | 642 | *err = C9Ebuf; |
| 655 | 643 | }else{ |
| 656 | 644 | *err = 0; |
| @@ -699,7 +687,7 @@ s9error(C9ctx *c, C9tag tag, const char *ename) · 42 unmodified lines | ||
| 699 | 687 | C9error err; |
| 700 | 688 | |
| 701 | 689 | if(len > C9maxstr){ |
| 702 | − c->error("s9error: invalid ename: %ud chars", len); | |
| 690 | + c->error(c, "s9error: invalid ename: %ud chars", len); | |
| 703 | 691 | return C9Estr; |
| 704 | 692 | } |
| 705 | 693 | if((b = R(c, 2+len, Rerror, tag, &err)) != NULL){ |
| @@ -743,7 +731,7 @@ s9walk(C9ctx *c, C9tag tag, C9qid *qids[]) · 37 unmodified lines | ||
| 743 | 731 | |
| 744 | 732 | for(n = 0; n < C9maxpathel && qids[n] != NULL; n++); |
| 745 | 733 | if(n > C9maxpathel){ |
| 746 | − c->error("s9walk: invalid elements !(0 <= %ud <= %ud)", n, C9maxpathel); | |
| 734 | + c->error(c, "s9walk: invalid elements !(0 <= %ud <= %ud)", n, C9maxpathel); | |
| 747 | 735 | return C9Epath; |
| 748 | 736 | } |
| 749 | 737 | |
| @@ -839,13 +827,13 @@ s9readdir(C9ctx *c, C9tag tag, C9stat *st[], int *num, uint64_t *offset, uint32_ · 89 unmodified lines | ||
| 839 | 827 | mulen = safestrlen(s->muid); |
| 840 | 828 | |
| 841 | 829 | if(nlen == 0 || nlen > C9maxstr){ |
| 842 | − c->error("s9readdir: invalid name: %ud chars", nlen); | |
| 830 | + c->error(c, "s9readdir: invalid name: %ud chars", nlen); | |
| 843 | 831 | return C9Epath; |
| 844 | 832 | } |
| 845 | 833 | if(ulen > C9maxstr || glen > C9maxstr || mulen > C9maxstr){ |
| 846 | 834 | ulen = ulen > glen ? ulen : glen; |
| 847 | 835 | ulen = ulen > mulen ? ulen : mulen; |
| 848 | − c->error("s9readdir: string too long: %ud chars", ulen); | |
| 836 | + c->error(c, "s9readdir: string too long: %ud chars", ulen); | |
| 849 | 837 | return C9Estr; |
| 850 | 838 | } |
| 851 | 839 | |
| @@ -916,13 +904,13 @@ s9stat(C9ctx *c, C9tag tag, const C9stat *s) · 64 unmodified lines | ||
| 916 | 904 | C9error err; |
| 917 | 905 | |
| 918 | 906 | if(nlen == 0 || nlen > C9maxstr){ |
| 919 | − c->error("s9stat: invalid name: %ud chars", nlen); | |
| 907 | + c->error(c, "s9stat: invalid name: %ud chars", nlen); | |
| 920 | 908 | return C9Epath; |
| 921 | 909 | } |
| 922 | 910 | if(ulen > C9maxstr || glen > C9maxstr || mulen > C9maxstr){ |
| 923 | 911 | ulen = ulen > glen ? ulen : glen; |
| 924 | 912 | ulen = ulen > mulen ? ulen : mulen; |
| 925 | − c->error("s9stat: string too long: %ud chars", ulen); | |
| 913 | + c->error(c, "s9stat: string too long: %ud chars", ulen); | |
| 926 | 914 | return C9Estr; |
| 927 | 915 | } |
| 928 | 916 | |
| @@ -969,20 +957,20 @@ s9proc(C9ctx *c) · 40 unmodified lines | ||
| 969 | 957 | readerr = -1; |
| 970 | 958 | if((b = c->read(c, 4, &readerr)) == NULL){ |
| 971 | 959 | if(readerr != 0) |
| 972 | − c->error("s9proc: short read"); | |
| 960 | + c->error(c, "s9proc: short read"); | |
| 973 | 961 | return readerr == 0 ? 0 : C9Epkt; |
| 974 | 962 | } |
| 975 | 963 | |
| 976 | 964 | sz = r32(&b); |
| 977 | 965 | if(sz < 7 || sz > c->msize){ |
| 978 | − c->error("s9proc: invalid packet size !(7 <= %ud <= %ud)", sz, c->msize); | |
| 966 | + c->error(c, "s9proc: invalid packet size !(7 <= %ud <= %ud)", sz, c->msize); | |
| 979 | 967 | return C9Epkt; |
| 980 | 968 | } |
| 981 | 969 | sz -= 4; |
| 982 | 970 | readerr = -1; |
| 983 | 971 | if((b = c->read(c, sz, &readerr)) == NULL){ |
| 984 | 972 | if(readerr != 0) |
| 985 | − c->error("s9proc: short read"); | |
| 973 | + c->error(c, "s9proc: short read"); | |
| 986 | 974 | return readerr == 0 ? 0 : C9Epkt; |
| 987 | 975 | } |
| 988 | 976 | |
| @@ -991,7 +979,7 @@ s9proc(C9ctx *c) · 2 unmodified lines | ||
| 991 | 979 | sz -= 3; |
| 992 | 980 | |
| 993 | 981 | if((c->svflags & Svver) == 0 && t.type != Tversion){ |
| 994 | − c->error("s9proc: expected Tversion, got %ud", t.type); | |
| 982 | + c->error(c, "s9proc: expected Tversion, got %ud", t.type); | |
| 995 | 983 | return C9Epkt; |
| 996 | 984 | } |
| 997 | 985 | |
| @@ -1035,7 +1023,7 @@ s9proc(C9ctx *c) · 37 unmodified lines | ||
| 1035 | 1023 | t.fid = r32(&b); |
| 1036 | 1024 | t.walk.newfid = r32(&b); |
| 1037 | 1025 | if((n = r16(&b)) > 16){ |
| 1038 | − c->error("s9proc: Twalk !(%ud <= 16)", n); | |
| 1026 | + c->error(c, "s9proc: Twalk !(%ud <= 16)", n); | |
| 1039 | 1027 | return C9Epath; |
| 1040 | 1028 | } |
| 1041 | 1029 | sz -= 4+4+2; |
| @@ -1044,7 +1032,7 @@ s9proc(C9ctx *c) · 2 unmodified lines | ||
| 1044 | 1032 | if(sz < 2 || (cnt = r16(&b)) > sz-2) |
| 1045 | 1033 | goto error; |
| 1046 | 1034 | if(cnt < 1){ |
| 1047 | − c->error("s9proc: Twalk invalid element [%ud]", i); | |
| 1035 | + c->error(c, "s9proc: Twalk invalid element [%ud]", i); | |
| 1048 | 1036 | return C9Epath; |
| 1049 | 1037 | } |
| 1050 | 1038 | b[-2] = 0; |
| @@ -1076,7 +1064,7 @@ s9proc(C9ctx *c) · 25 unmodified lines | ||
| 1076 | 1064 | if((cnt = r16(&b)) > sz-4) |
| 1077 | 1065 | goto error; |
| 1078 | 1066 | if((err = c9parsedir(c, &t.wstat, &b, &cnt)) != 0){ |
| 1079 | − c->error("s9proc"); | |
| 1067 | + c->error(c, "s9proc"); | |
| 1080 | 1068 | return err; |
| 1081 | 1069 | } |
| 1082 | 1070 | c->t(c, &t); |
| @@ -1111,7 +1099,7 @@ s9proc(C9ctx *c) · 28 unmodified lines | ||
| 1111 | 1099 | w32(&b, 0); |
| 1112 | 1100 | wcs(&b, "unknown", 7); |
| 1113 | 1101 | err = c->end(c); |
| 1114 | − c->error("s9proc: invalid version"); | |
| 1102 | + c->error(c, "s9proc: invalid version"); | |
| 1115 | 1103 | } |
| 1116 | 1104 | return C9Ever; |
| 1117 | 1105 | } |
| @@ -1169,7 +1157,7 @@ s9proc(C9ctx *c) · 51 unmodified lines | ||
| 1169 | 1157 | } |
| 1170 | 1158 | return 0; |
| 1171 | 1159 | error: |
| 1172 | − c->error("s9proc: invalid packet (type=%ud)", t.type); | |
| 1160 | + c->error(c, "s9proc: invalid packet (type=%ud)", t.type); | |
| 1173 | 1161 | return C9Epkt; |
| 1174 | 1162 | } |
| 1175 | 1163 | |